mirror of
https://github.com/fluencelabs/fluence-js.git
synced 2025-05-16 19:31:18 +00:00
Fix all tests
This commit is contained in:
parent
3a039cd355
commit
d6eb91b76f
@ -22,7 +22,8 @@
|
||||
"@fluencelabs/spell": "0.5.20",
|
||||
"@fluencelabs/trust-graph": "0.4.7",
|
||||
"ts-pattern": "5.0.5",
|
||||
"vitest": "0.34.6"
|
||||
"vitest": "0.34.6",
|
||||
"zod": "3.22.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@fluencelabs/js-client": "workspace:^"
|
||||
|
@ -27,17 +27,14 @@ interface TsOutput {
|
||||
sources: string;
|
||||
}
|
||||
|
||||
type LanguageOutput = {
|
||||
js: JsOutput;
|
||||
ts: TsOutput;
|
||||
};
|
||||
type LanguageOutput = JsOutput | TsOutput;
|
||||
|
||||
type NothingToGenerate = null;
|
||||
|
||||
export default async function aquaToJs<T extends OutputType>(
|
||||
export default async function aquaToJs(
|
||||
res: CompilationResult,
|
||||
outputType: T,
|
||||
): Promise<LanguageOutput[T] | NothingToGenerate> {
|
||||
outputType: OutputType,
|
||||
): Promise<LanguageOutput | NothingToGenerate> {
|
||||
if (
|
||||
Object.keys(res.services).length === 0 &&
|
||||
Object.keys(res.functions).length === 0
|
||||
@ -49,12 +46,10 @@ export default async function aquaToJs<T extends OutputType>(
|
||||
|
||||
return outputType === "js"
|
||||
? {
|
||||
sources: generateSources(res, "js", packageJson),
|
||||
sources: generateSources(res, outputType, packageJson),
|
||||
types: generateTypes(res, packageJson),
|
||||
}
|
||||
: // TODO: probably there is a way to remove this type assert
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
({
|
||||
sources: generateSources(res, "ts", packageJson),
|
||||
} as LanguageOutput[T]);
|
||||
: {
|
||||
sources: generateSources(res, outputType, packageJson),
|
||||
};
|
||||
}
|
||||
|
@ -28,14 +28,17 @@ import {
|
||||
SimpleTypes,
|
||||
UnlabeledProductType,
|
||||
} from "@fluencelabs/interfaces";
|
||||
import { z } from "zod";
|
||||
|
||||
export interface PackageJson {
|
||||
name: string;
|
||||
version: string;
|
||||
devDependencies: {
|
||||
["@fluencelabs/aqua-api"]: string;
|
||||
};
|
||||
}
|
||||
const packageJsonSchema = z.object({
|
||||
name: z.string(),
|
||||
version: z.string(),
|
||||
devDependencies: z.object({
|
||||
["@fluencelabs/aqua-api"]: z.string(),
|
||||
}),
|
||||
});
|
||||
|
||||
export type PackageJson = z.infer<typeof packageJsonSchema>;
|
||||
|
||||
export async function getPackageJsonContent(): Promise<PackageJson> {
|
||||
const content = await readFile(
|
||||
@ -43,9 +46,7 @@ export async function getPackageJsonContent(): Promise<PackageJson> {
|
||||
"utf-8",
|
||||
);
|
||||
|
||||
// TODO: Add validation here
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
return JSON.parse(content) as PackageJson;
|
||||
return packageJsonSchema.parse(JSON.parse(content));
|
||||
}
|
||||
|
||||
export function getFuncArgs(
|
||||
|
@ -24,7 +24,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@fluencelabs/avm": "0.54.0",
|
||||
"@fluencelabs/marine-js": "0.7.2",
|
||||
"@fluencelabs/marine-js": "0.8.0",
|
||||
"@fluencelabs/marine-worker": "0.4.2",
|
||||
"@fluencelabs/threads": "^2.0.0"
|
||||
},
|
||||
|
@ -14,18 +14,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { FetchedPackages, getVersionedPackage } from "../types.js";
|
||||
import { FetchResourceFn, getVersionedPackage } from "../types.js";
|
||||
|
||||
/**
|
||||
* @param pkg name of package with version
|
||||
* @param assetPath path of required asset in given package
|
||||
* @param root CDN domain in browser or file system root in node
|
||||
*/
|
||||
export async function fetchResource(
|
||||
pkg: FetchedPackages,
|
||||
assetPath: string,
|
||||
root: string,
|
||||
) {
|
||||
export const fetchResource: FetchResourceFn = async (pkg, assetPath, root) => {
|
||||
const refinedAssetPath = assetPath.startsWith("/")
|
||||
? assetPath.slice(1)
|
||||
: assetPath;
|
||||
@ -36,4 +32,4 @@ export async function fetchResource(
|
||||
return fetch(url).catch(() => {
|
||||
throw new Error(`Cannot fetch from ${url.toString()}`);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -18,21 +18,14 @@ import { readFile } from "fs/promises";
|
||||
import { createRequire } from "module";
|
||||
import { sep, posix, join } from "path";
|
||||
|
||||
import { FetchedPackages, getVersionedPackage } from "../types.js";
|
||||
import { FetchResourceFn, getVersionedPackage } from "../types.js";
|
||||
|
||||
/**
|
||||
* @param pkg name of package with version
|
||||
* @param assetPath path of required asset in given package
|
||||
* @param root CDN domain in browser or js-client itself in node
|
||||
*/
|
||||
export async function fetchResource(
|
||||
pkg: FetchedPackages,
|
||||
assetPath: string,
|
||||
root: string,
|
||||
) {
|
||||
export const fetchResource: FetchResourceFn = async (pkg, assetPath) => {
|
||||
const { name } = getVersionedPackage(pkg);
|
||||
// TODO: `root` will be handled somehow in the future. For now, we use filesystem root where js-client is running;
|
||||
root = "/";
|
||||
const require = createRequire(import.meta.url);
|
||||
const packagePathIndex = require.resolve(name);
|
||||
|
||||
@ -47,7 +40,7 @@ export async function fetchResource(
|
||||
throw new Error(`Cannot find dependency ${name} in path ${posixPath}`);
|
||||
}
|
||||
|
||||
const pathToResource = join(root, packagePath, assetPath);
|
||||
const pathToResource = join(packagePath, assetPath);
|
||||
|
||||
const file = await readFile(pathToResource);
|
||||
|
||||
@ -60,4 +53,4 @@ export async function fetchResource(
|
||||
: "application/text",
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -20,7 +20,7 @@ import versions from "./versions.js";
|
||||
|
||||
export type FetchedPackages = keyof typeof versions;
|
||||
type VersionedPackage = { name: string; version: string };
|
||||
export type GetWorker = (
|
||||
export type GetWorkerFn = (
|
||||
pkg: FetchedPackages,
|
||||
CDNUrl: string,
|
||||
) => Promise<Worker>;
|
||||
@ -31,3 +31,9 @@ export const getVersionedPackage = (pkg: FetchedPackages): VersionedPackage => {
|
||||
version: versions[pkg],
|
||||
};
|
||||
};
|
||||
|
||||
export type FetchResourceFn = (
|
||||
pkg: FetchedPackages,
|
||||
assetPath: string,
|
||||
root: string,
|
||||
) => Promise<Response>;
|
||||
|
@ -17,9 +17,9 @@
|
||||
import { BlobWorker } from "@fluencelabs/threads/master";
|
||||
|
||||
import { fetchResource } from "../fetchers/browser.js";
|
||||
import type { FetchedPackages, GetWorker } from "../types.js";
|
||||
import type { FetchedPackages, GetWorkerFn } from "../types.js";
|
||||
|
||||
export const getWorker: GetWorker = async (
|
||||
export const getWorker: GetWorkerFn = async (
|
||||
pkg: FetchedPackages,
|
||||
CDNUrl: string,
|
||||
) => {
|
||||
|
@ -20,10 +20,10 @@ import { fileURLToPath } from "url";
|
||||
|
||||
import { Worker } from "@fluencelabs/threads/master";
|
||||
|
||||
import type { FetchedPackages, GetWorker } from "../types.js";
|
||||
import type { FetchedPackages, GetWorkerFn } from "../types.js";
|
||||
import { getVersionedPackage } from "../types.js";
|
||||
|
||||
export const getWorker: GetWorker = (pkg: FetchedPackages) => {
|
||||
export const getWorker: GetWorkerFn = (pkg: FetchedPackages) => {
|
||||
const require = createRequire(import.meta.url);
|
||||
|
||||
const pathToThisFile = dirname(fileURLToPath(import.meta.url));
|
||||
|
@ -43,10 +43,10 @@
|
||||
"@libp2p/peer-id-factory": "3.0.3",
|
||||
"@libp2p/websockets": "7.0.4",
|
||||
"@multiformats/multiaddr": "11.3.0",
|
||||
"assert": "2.1.0",
|
||||
"async": "3.2.4",
|
||||
"bs58": "5.0.0",
|
||||
"buffer": "6.0.3",
|
||||
"class-transformer": "0.5.1",
|
||||
"debug": "4.3.4",
|
||||
"it-length-prefixed": "8.0.4",
|
||||
"it-map": "2.0.0",
|
||||
@ -57,11 +57,12 @@
|
||||
"rxjs": "7.5.5",
|
||||
"uint8arrays": "4.0.3",
|
||||
"uuid": "8.3.2",
|
||||
"zod": "3.22.4"
|
||||
"zod": "3.22.4",
|
||||
"zod-validation-error": "2.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@fluencelabs/aqua-api": "0.9.3",
|
||||
"@fluencelabs/marine-js": "0.7.2",
|
||||
"@fluencelabs/marine-js": "0.8.0",
|
||||
"@rollup/plugin-inject": "5.0.3",
|
||||
"@types/bs58": "4.0.1",
|
||||
"@types/debug": "4.1.7",
|
||||
|
@ -14,6 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { z } from "zod";
|
||||
|
||||
/**
|
||||
* Peer ID's id as a base58 string (multihash/CIDv0).
|
||||
*/
|
||||
@ -33,20 +35,30 @@ export type Node = {
|
||||
* - string: multiaddr in string format
|
||||
* - Node: node structure, @see Node
|
||||
*/
|
||||
export type RelayOptions = string | Node;
|
||||
export const relaySchema = z.union([
|
||||
z.string(),
|
||||
z.object({
|
||||
peerId: z.string(),
|
||||
multiaddr: z.string(),
|
||||
}),
|
||||
]);
|
||||
|
||||
export type RelayOptions = z.infer<typeof relaySchema>;
|
||||
|
||||
/**
|
||||
* Fluence Peer's key pair types
|
||||
*/
|
||||
export type KeyTypes = "RSA" | "Ed25519" | "secp256k1";
|
||||
|
||||
const keyPairOptionsSchema = z.object({
|
||||
type: z.literal("Ed25519"),
|
||||
source: z.union([z.literal("random"), z.instanceof(Uint8Array)]),
|
||||
});
|
||||
|
||||
/**
|
||||
* Options to specify key pair used in Fluence Peer
|
||||
*/
|
||||
export type KeyPairOptions = {
|
||||
type: "Ed25519";
|
||||
source: "random" | Uint8Array;
|
||||
};
|
||||
export type KeyPairOptions = z.infer<typeof keyPairOptionsSchema>;
|
||||
|
||||
/**
|
||||
* Fluence JS Client connection states as string literals
|
||||
@ -63,17 +75,10 @@ export const ConnectionStates = [
|
||||
*/
|
||||
export type ConnectionState = (typeof ConnectionStates)[number];
|
||||
|
||||
export interface IFluenceInternalApi {
|
||||
/**
|
||||
* Internal API
|
||||
*/
|
||||
internals: unknown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public API of Fluence JS Client
|
||||
*/
|
||||
export interface IFluenceClient extends IFluenceInternalApi {
|
||||
export interface IFluenceClient {
|
||||
/**
|
||||
* Connect to the Fluence network
|
||||
*/
|
||||
@ -107,65 +112,66 @@ export interface IFluenceClient extends IFluenceInternalApi {
|
||||
getRelayPeerId(): string;
|
||||
}
|
||||
|
||||
export const configSchema = z
|
||||
.object({
|
||||
/**
|
||||
* Specify the KeyPair to be used to identify the Fluence Peer.
|
||||
* Will be generated randomly if not specified
|
||||
*/
|
||||
keyPair: keyPairOptionsSchema,
|
||||
/**
|
||||
* Options to configure the connection to the Fluence network
|
||||
*/
|
||||
connectionOptions: z
|
||||
.object({
|
||||
/**
|
||||
* When the peer established the connection to the network it sends a ping-like message to check if it works correctly.
|
||||
* The options allows to specify the timeout for that message in milliseconds.
|
||||
* If not specified the default timeout will be used
|
||||
*/
|
||||
skipCheckConnection: z.boolean(),
|
||||
/**
|
||||
* The dialing timeout in milliseconds
|
||||
*/
|
||||
dialTimeoutMs: z.number(),
|
||||
/**
|
||||
* The maximum number of inbound streams for the libp2p node.
|
||||
* Default: 1024
|
||||
*/
|
||||
maxInboundStreams: z.number(),
|
||||
/**
|
||||
* The maximum number of outbound streams for the libp2p node.
|
||||
* Default: 1024
|
||||
*/
|
||||
maxOutboundStreams: z.number(),
|
||||
})
|
||||
.partial(),
|
||||
/**
|
||||
* Sets the default TTL for all particles originating from the peer with no TTL specified.
|
||||
* If the originating particle's TTL is defined then that value will be used
|
||||
* If the option is not set default TTL will be 7000
|
||||
*/
|
||||
defaultTtlMs: z.number(),
|
||||
/**
|
||||
* Property for passing custom CDN Url to load dependencies from browser. https://unpkg.com used by default
|
||||
*/
|
||||
CDNUrl: z.string(),
|
||||
/**
|
||||
* Enables\disabled various debugging features
|
||||
*/
|
||||
debug: z
|
||||
.object({
|
||||
/**
|
||||
* If set to true, newly initiated particle ids will be printed to console.
|
||||
* Useful to see what particle id is responsible for aqua function
|
||||
*/
|
||||
printParticleId: z.boolean(),
|
||||
})
|
||||
.partial(),
|
||||
})
|
||||
.partial();
|
||||
|
||||
/**
|
||||
* Configuration used when initiating Fluence Client
|
||||
*/
|
||||
export interface ClientConfig {
|
||||
/**
|
||||
* Specify the KeyPair to be used to identify the Fluence Peer.
|
||||
* Will be generated randomly if not specified
|
||||
*/
|
||||
keyPair?: KeyPairOptions;
|
||||
|
||||
/**
|
||||
* Options to configure the connection to the Fluence network
|
||||
*/
|
||||
connectionOptions?: {
|
||||
/**
|
||||
* When the peer established the connection to the network it sends a ping-like message to check if it works correctly.
|
||||
* The options allows to specify the timeout for that message in milliseconds.
|
||||
* If not specified the default timeout will be used
|
||||
*/
|
||||
skipCheckConnection?: boolean;
|
||||
|
||||
/**
|
||||
* The dialing timeout in milliseconds
|
||||
*/
|
||||
dialTimeoutMs?: number;
|
||||
|
||||
/**
|
||||
* The maximum number of inbound streams for the libp2p node.
|
||||
* Default: 1024
|
||||
*/
|
||||
maxInboundStreams?: number;
|
||||
|
||||
/**
|
||||
* The maximum number of outbound streams for the libp2p node.
|
||||
* Default: 1024
|
||||
*/
|
||||
maxOutboundStreams?: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the default TTL for all particles originating from the peer with no TTL specified.
|
||||
* If the originating particle's TTL is defined then that value will be used
|
||||
* If the option is not set default TTL will be 7000
|
||||
*/
|
||||
defaultTtlMs?: number;
|
||||
|
||||
/**
|
||||
* Property for passing custom CDN Url to load dependencies from browser. https://unpkg.com used by default
|
||||
*/
|
||||
CDNUrl?: string;
|
||||
|
||||
/**
|
||||
* Enables\disabled various debugging features
|
||||
*/
|
||||
debug?: {
|
||||
/**
|
||||
* If set to true, newly initiated particle ids will be printed to console.
|
||||
* Useful to see what particle id is responsible for aqua function
|
||||
*/
|
||||
printParticleId?: boolean;
|
||||
};
|
||||
}
|
||||
export type ClientConfig = z.infer<typeof configSchema>;
|
||||
|
@ -61,7 +61,6 @@ export const callAquaFunction = async ({
|
||||
peer,
|
||||
args,
|
||||
}: CallAquaFunctionArgs) => {
|
||||
// TODO: this function should be rewritten. We can remove asserts if we wont check definition there
|
||||
log.trace("calling aqua function %j", { script, config, args });
|
||||
|
||||
const particle = await peer.internals.createNewParticle(script, config.ttl);
|
||||
@ -88,15 +87,6 @@ export const callAquaFunction = async ({
|
||||
// 1. The particle is sent to the network (state 'sent')
|
||||
// 2. All CallRequests are executed, e.g., all variable loading and local function calls are completed (state 'localWorkDone')
|
||||
|
||||
// TODO: make test
|
||||
// if (
|
||||
// isReturnTypeVoid(def) &&
|
||||
// (stage.stage === "sent" || stage.stage === "localWorkDone")
|
||||
// ) {
|
||||
// resolve(undefined);
|
||||
// }
|
||||
// },
|
||||
|
||||
peer.internals.initiateParticle(particle, resolve, reject);
|
||||
});
|
||||
};
|
||||
|
@ -1,238 +0,0 @@
|
||||
/**
|
||||
* Copyright 2023 Fluence Labs Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// TODO: This file is a mess. Need to refactor it later
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
|
||||
import assert from "assert";
|
||||
|
||||
import type {
|
||||
ArrowType,
|
||||
ArrowWithoutCallbacks,
|
||||
JSONArray,
|
||||
JSONValue,
|
||||
LabeledProductType,
|
||||
NonArrowType,
|
||||
SimpleTypes,
|
||||
} from "@fluencelabs/interfaces";
|
||||
import { match } from "ts-pattern";
|
||||
|
||||
import { CallServiceData } from "../jsServiceHost/interfaces.js";
|
||||
import { jsonify } from "../util/utils.js";
|
||||
|
||||
/**
|
||||
* Convert value from its representation in aqua language to representation in typescript
|
||||
* @param value - value as represented in aqua
|
||||
* @param type - definition of the aqua type
|
||||
* @returns value represented in typescript
|
||||
*/
|
||||
export const aqua2ts = (value: JSONValue, type: NonArrowType): JSONValue => {
|
||||
const res = match(type)
|
||||
.with({ tag: "nil" }, () => {
|
||||
return null;
|
||||
})
|
||||
.with({ tag: "option" }, (opt) => {
|
||||
assert(Array.isArray(value), "Should not be possible, bad types");
|
||||
|
||||
if (value.length === 0) {
|
||||
return null;
|
||||
} else {
|
||||
return aqua2ts(value[0], opt.type);
|
||||
}
|
||||
})
|
||||
.with({ tag: "scalar" }, { tag: "bottomType" }, { tag: "topType" }, () => {
|
||||
return value;
|
||||
})
|
||||
.with({ tag: "array" }, (arr) => {
|
||||
assert(Array.isArray(value), "Should not be possible, bad types");
|
||||
return value.map((y) => {
|
||||
return aqua2ts(y, arr.type);
|
||||
});
|
||||
})
|
||||
.with({ tag: "struct" }, (x) => {
|
||||
return Object.entries(x.fields).reduce((agg, [key, type]) => {
|
||||
const val = aqua2ts(value[key], type);
|
||||
return { ...agg, [key]: val };
|
||||
}, {});
|
||||
})
|
||||
.with({ tag: "labeledProduct" }, (x) => {
|
||||
return Object.entries(x.fields).reduce((agg, [key, type]) => {
|
||||
const val = aqua2ts(value[key], type);
|
||||
return { ...agg, [key]: val };
|
||||
}, {});
|
||||
})
|
||||
.with({ tag: "unlabeledProduct" }, (x) => {
|
||||
return x.items.map((type, index) => {
|
||||
return aqua2ts(value[index], type);
|
||||
});
|
||||
})
|
||||
// uncomment to check that every pattern in matched
|
||||
// .exhaustive();
|
||||
.otherwise(() => {
|
||||
throw new Error("Unexpected tag: " + jsonify(type));
|
||||
});
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert call service arguments list from their aqua representation to representation in typescript
|
||||
* @param req - call service data
|
||||
* @param arrow - aqua type definition
|
||||
* @returns arguments in typescript representation
|
||||
*/
|
||||
export const aquaArgs2Ts = (
|
||||
req: CallServiceData,
|
||||
arrow: ArrowType<LabeledProductType<SimpleTypes>>,
|
||||
): JSONArray => {
|
||||
const argTypes = match(arrow.domain)
|
||||
.with({ tag: "labeledProduct" }, (x) => {
|
||||
return Object.values(x.fields);
|
||||
})
|
||||
.with({ tag: "unlabeledProduct" }, (x) => {
|
||||
return x.items;
|
||||
})
|
||||
.with({ tag: "nil" }, (x) => {
|
||||
return [];
|
||||
})
|
||||
// uncomment to check that every pattern in matched
|
||||
// .exhaustive()
|
||||
.otherwise(() => {
|
||||
throw new Error("Unexpected tag: " + jsonify(arrow.domain));
|
||||
});
|
||||
|
||||
if (req.args.length !== argTypes.length) {
|
||||
throw new Error(
|
||||
`incorrect number of arguments, expected: ${argTypes.length}, got: ${req.args.length}`,
|
||||
);
|
||||
}
|
||||
|
||||
return req.args.map((arg, index) => {
|
||||
return aqua2ts(arg, argTypes[index]);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert value from its typescript representation to representation in aqua
|
||||
* @param value - the value as represented in typescript
|
||||
* @param type - definition of the aqua type
|
||||
* @returns value represented in aqua
|
||||
*/
|
||||
export const ts2aqua = (value: JSONValue, type: NonArrowType): JSONValue => {
|
||||
const res = match(type)
|
||||
.with({ tag: "nil" }, () => {
|
||||
return null;
|
||||
})
|
||||
.with({ tag: "option" }, (opt) => {
|
||||
if (value === null || value === undefined) {
|
||||
return [];
|
||||
} else {
|
||||
return [ts2aqua(value, opt.type)];
|
||||
}
|
||||
})
|
||||
.with({ tag: "scalar" }, { tag: "bottomType" }, { tag: "topType" }, () => {
|
||||
return value;
|
||||
})
|
||||
.with({ tag: "array" }, (arr) => {
|
||||
assert(Array.isArray(value), "Should not be possible, bad types");
|
||||
return value.map((y) => {
|
||||
return ts2aqua(y, arr.type);
|
||||
});
|
||||
})
|
||||
.with({ tag: "struct" }, (x) => {
|
||||
return Object.entries(x.fields).reduce((agg, [key, type]) => {
|
||||
const val = ts2aqua(value[key], type);
|
||||
return { ...agg, [key]: val };
|
||||
}, {});
|
||||
})
|
||||
.with({ tag: "labeledProduct" }, (x) => {
|
||||
return Object.entries(x.fields).reduce((agg, [key, type]) => {
|
||||
const val = ts2aqua(value[key], type);
|
||||
return { ...agg, [key]: val };
|
||||
}, {});
|
||||
})
|
||||
.with({ tag: "unlabeledProduct" }, (x) => {
|
||||
return x.items.map((type, index) => {
|
||||
return ts2aqua(value[index], type);
|
||||
});
|
||||
})
|
||||
// uncomment to check that every pattern in matched
|
||||
// .exhaustive()
|
||||
.otherwise(() => {
|
||||
throw new Error("Unexpected tag: " + jsonify(type));
|
||||
});
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert return type of the service from it's typescript representation to representation in aqua
|
||||
* @param returnValue - the value as represented in typescript
|
||||
* @param arrowType - the arrow type which describes the service
|
||||
* @returns - value represented in aqua
|
||||
*/
|
||||
export const returnType2Aqua = (
|
||||
returnValue: any,
|
||||
arrowType: ArrowType<NonArrowType>,
|
||||
) => {
|
||||
// TODO: cover with tests
|
||||
if (arrowType.codomain.tag === "nil") {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (arrowType.codomain.items.length === 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (arrowType.codomain.items.length === 1) {
|
||||
return ts2aqua(returnValue, arrowType.codomain.items[0]);
|
||||
}
|
||||
|
||||
return arrowType.codomain.items.map((type, index) => {
|
||||
return ts2aqua(returnValue[index], type);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts response value from aqua its representation to representation in typescript
|
||||
* @param req - call service data
|
||||
* @param arrow - aqua type definition
|
||||
* @returns response value in typescript representation
|
||||
*/
|
||||
export const responseServiceValue2ts = (
|
||||
req: CallServiceData,
|
||||
arrow: ArrowType<any>,
|
||||
) => {
|
||||
return match(arrow.codomain)
|
||||
.with({ tag: "nil" }, () => {
|
||||
return null;
|
||||
})
|
||||
.with({ tag: "unlabeledProduct" }, (x) => {
|
||||
if (x.items.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (x.items.length === 1) {
|
||||
return aqua2ts(req.args[0], x.items[0]);
|
||||
}
|
||||
|
||||
return req.args.map((y, index) => {
|
||||
return aqua2ts(y, x.items[index]);
|
||||
});
|
||||
})
|
||||
.exhaustive();
|
||||
};
|
@ -16,12 +16,15 @@
|
||||
|
||||
import { fetchResource } from "@fluencelabs/js-client-isomorphic/fetcher";
|
||||
import { getWorker } from "@fluencelabs/js-client-isomorphic/worker-resolver";
|
||||
import { ZodError } from "zod";
|
||||
|
||||
import { ClientPeer, makeClientPeerConfig } from "./clientPeer/ClientPeer.js";
|
||||
import {
|
||||
ClientConfig,
|
||||
configSchema,
|
||||
ConnectionState,
|
||||
RelayOptions,
|
||||
relaySchema,
|
||||
} from "./clientPeer/types.js";
|
||||
import { callAquaFunction } from "./compilerSupport/callFunction.js";
|
||||
import { registerService } from "./compilerSupport/registerService.js";
|
||||
@ -33,6 +36,15 @@ const createClient = async (
|
||||
relay: RelayOptions,
|
||||
config: ClientConfig = {},
|
||||
): Promise<ClientPeer> => {
|
||||
try {
|
||||
relay = relaySchema.parse(relay);
|
||||
config = configSchema.parse(config);
|
||||
} catch (e) {
|
||||
if (e instanceof ZodError) {
|
||||
throw new Error(JSON.stringify(e.format()));
|
||||
}
|
||||
}
|
||||
|
||||
const CDNUrl = config.CDNUrl ?? DEFAULT_CDN_URL;
|
||||
|
||||
const fetchMarineJsWasm = async () => {
|
||||
|
@ -14,8 +14,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import assert from "assert";
|
||||
|
||||
import { JSONArray } from "@fluencelabs/interfaces";
|
||||
import { toUint8Array } from "js-base64";
|
||||
import { it, describe, expect, test } from "vitest";
|
||||
@ -28,6 +26,7 @@ import { KeyPair } from "../../keypair/index.js";
|
||||
import { builtInServices } from "../builtins.js";
|
||||
import { allowServiceFn } from "../securityGuard.js";
|
||||
import { Sig, defaultSigGuard } from "../Sig.js";
|
||||
import assert from "assert";
|
||||
|
||||
const a10b20 = `{
|
||||
"a": 10,
|
||||
@ -54,32 +53,32 @@ describe("Tests for default handler", () => {
|
||||
serviceId | fnName | args | retCode | result
|
||||
${"op"} | ${"identity"} | ${[]} | ${0} | ${{}}
|
||||
${"op"} | ${"identity"} | ${[1]} | ${0} | ${1}
|
||||
${"op"} | ${"identity"} | ${[1, 2]} | ${1} | ${"identity accepts up to 1 arguments, received 2 arguments"}
|
||||
${"op"} | ${"identity"} | ${[1, 2]} | ${1} | ${"Expected 1 argument(s). Got 2"}
|
||||
${"op"} | ${"noop"} | ${[1, 2]} | ${0} | ${{}}
|
||||
${"op"} | ${"array"} | ${[1, 2, 3]} | ${0} | ${[1, 2, 3]}
|
||||
${"op"} | ${"array_length"} | ${[[1, 2, 3]]} | ${0} | ${3}
|
||||
${"op"} | ${"array_length"} | ${[]} | ${1} | ${"array_length accepts exactly one argument, found: 0"}
|
||||
${"op"} | ${"array_length"} | ${[]} | ${1} | ${"Expected 1 argument(s). Got 0"}
|
||||
${"op"} | ${"concat"} | ${[[1, 2], [3, 4], [5, 6]]} | ${0} | ${[1, 2, 3, 4, 5, 6]}
|
||||
${"op"} | ${"concat"} | ${[[1, 2]]} | ${0} | ${[1, 2]}
|
||||
${"op"} | ${"concat"} | ${[]} | ${0} | ${[]}
|
||||
${"op"} | ${"concat"} | ${[1, [1, 2], 1]} | ${1} | ${"All arguments of 'concat' must be arrays: arguments 0, 2 are not"}
|
||||
${"op"} | ${"concat"} | ${[1, [1, 2], 1]} | ${1} | ${"Argument 0 expected to be of type array, Got number"}
|
||||
${"op"} | ${"string_to_b58"} | ${["test"]} | ${0} | ${"3yZe7d"}
|
||||
${"op"} | ${"string_to_b58"} | ${["test", 1]} | ${1} | ${"string_to_b58 accepts only one string argument"}
|
||||
${"op"} | ${"string_to_b58"} | ${["test", 1]} | ${1} | ${"Expected 1 argument(s). Got 2"}
|
||||
${"op"} | ${"string_from_b58"} | ${["3yZe7d"]} | ${0} | ${"test"}
|
||||
${"op"} | ${"string_from_b58"} | ${["3yZe7d", 1]} | ${1} | ${"string_from_b58 accepts only one string argument"}
|
||||
${"op"} | ${"string_from_b58"} | ${["3yZe7d", 1]} | ${1} | ${"Expected 1 argument(s). Got 2"}
|
||||
${"op"} | ${"bytes_to_b58"} | ${[[116, 101, 115, 116]]} | ${0} | ${"3yZe7d"}
|
||||
${"op"} | ${"bytes_to_b58"} | ${[[116, 101, 115, 116], 1]} | ${1} | ${"bytes_to_b58 accepts only single argument: array of numbers"}
|
||||
${"op"} | ${"bytes_to_b58"} | ${[[116, 101, 115, 116], 1]} | ${1} | ${"Expected 1 argument(s). Got 2"}
|
||||
${"op"} | ${"bytes_from_b58"} | ${["3yZe7d"]} | ${0} | ${[116, 101, 115, 116]}
|
||||
${"op"} | ${"bytes_from_b58"} | ${["3yZe7d", 1]} | ${1} | ${"bytes_from_b58 accepts only one string argument"}
|
||||
${"op"} | ${"bytes_from_b58"} | ${["3yZe7d", 1]} | ${1} | ${"Expected 1 argument(s). Got 2"}
|
||||
${"op"} | ${"sha256_string"} | ${["hello, world!"]} | ${0} | ${"QmVQ8pg6L1tpoWYeq6dpoWqnzZoSLCh7E96fCFXKvfKD3u"}
|
||||
${"op"} | ${"sha256_string"} | ${["hello, world!", true]} | ${1} | ${"sha256_string accepts 1 argument, found: 2"}
|
||||
${"op"} | ${"sha256_string"} | ${[]} | ${1} | ${"sha256_string accepts 1 argument, found: 0"}
|
||||
${"op"} | ${"sha256_string"} | ${["hello, world!", true]} | ${1} | ${"Expected 1 argument(s). Got 2"}
|
||||
${"op"} | ${"sha256_string"} | ${[]} | ${1} | ${"Expected 1 argument(s). Got 0"}
|
||||
${"op"} | ${"concat_strings"} | ${[]} | ${0} | ${""}
|
||||
${"op"} | ${"concat_strings"} | ${["a", "b", "c"]} | ${0} | ${"abc"}
|
||||
${"peer"} | ${"timeout"} | ${[200, []]} | ${1} | ${"timeout accepts exactly two arguments: timeout duration in ms and a message string"}
|
||||
${"peer"} | ${"timeout"} | ${[200, []]} | ${1} | ${"Argument 1 expected to be of type string, Got array"}
|
||||
${"peer"} | ${"timeout"} | ${[200, "test"]} | ${0} | ${"test"}
|
||||
${"peer"} | ${"timeout"} | ${[]} | ${1} | ${"timeout accepts exactly two arguments: timeout duration in ms and a message string"}
|
||||
${"peer"} | ${"timeout"} | ${[200, "test", 1]} | ${1} | ${"timeout accepts exactly two arguments: timeout duration in ms and a message string"}
|
||||
${"peer"} | ${"timeout"} | ${[]} | ${1} | ${"Expected 2 argument(s). Got 0"}
|
||||
${"peer"} | ${"timeout"} | ${[200, "test", 1]} | ${1} | ${"Expected 2 argument(s). Got 3"}
|
||||
${"debug"} | ${"stringify"} | ${[]} | ${0} | ${'"<empty argument list>"'}
|
||||
${"debug"} | ${"stringify"} | ${[{ a: 10, b: 20 }]} | ${0} | ${a10b20}
|
||||
${"debug"} | ${"stringify"} | ${[1, 2, 3, 4]} | ${0} | ${oneTwoThreeFour}
|
||||
|
@ -20,7 +20,6 @@ import * as url from "url";
|
||||
import { it, describe, expect, beforeAll } from "vitest";
|
||||
|
||||
import { registerService } from "../../compilerSupport/registerService.js";
|
||||
import { ServiceImpl } from "../../compilerSupport/types.js";
|
||||
import { KeyPair } from "../../keypair/index.js";
|
||||
import { compileAqua, CompiledFnCall, withPeer } from "../../util/testUtils.js";
|
||||
import { allowServiceFn } from "../securityGuard.js";
|
||||
@ -48,12 +47,12 @@ describe("Sig service test suite", () => {
|
||||
const customSig = new Sig(customKeyPair);
|
||||
const data = [1, 2, 3, 4, 5];
|
||||
|
||||
const anyService: Record<never, unknown> = customSig;
|
||||
|
||||
registerService({
|
||||
peer,
|
||||
serviceId: "CustomSig",
|
||||
// TODO: fix this after changing registerService signature
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
service: customSig as unknown as ServiceImpl,
|
||||
service: anyService,
|
||||
});
|
||||
|
||||
registerService({
|
||||
@ -89,12 +88,12 @@ describe("Sig service test suite", () => {
|
||||
const customSig = new Sig(customKeyPair);
|
||||
const data = [1, 2, 3, 4, 5];
|
||||
|
||||
const anyService: Record<never, unknown> = customSig;
|
||||
|
||||
registerService({
|
||||
peer,
|
||||
serviceId: "CustomSig",
|
||||
// TODO: fix this after changing registerService signature
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
service: customSig as unknown as ServiceImpl,
|
||||
service: anyService,
|
||||
});
|
||||
|
||||
registerService({
|
||||
|
@ -15,7 +15,6 @@
|
||||
*/
|
||||
|
||||
import { registerService } from "../../compilerSupport/registerService.js";
|
||||
import { ServiceImpl } from "../../compilerSupport/types.js";
|
||||
import { FluencePeer } from "../../jsPeer/FluencePeer.js";
|
||||
import { NodeUtils } from "../NodeUtils.js";
|
||||
|
||||
@ -24,11 +23,11 @@ export function registerNodeUtils(
|
||||
serviceId: string,
|
||||
service: NodeUtils,
|
||||
) {
|
||||
const anyService: Record<never, unknown> = service;
|
||||
|
||||
registerService({
|
||||
peer,
|
||||
// TODO: fix this after changing registerService signature
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
service: service as unknown as ServiceImpl,
|
||||
service: anyService,
|
||||
serviceId,
|
||||
});
|
||||
}
|
||||
|
@ -15,7 +15,6 @@
|
||||
*/
|
||||
|
||||
import { registerService } from "../../compilerSupport/registerService.js";
|
||||
import { ServiceImpl } from "../../compilerSupport/types.js";
|
||||
import { FluencePeer } from "../../jsPeer/FluencePeer.js";
|
||||
import { ParticleContext } from "../../jsServiceHost/interfaces.js";
|
||||
import { Sig } from "../Sig.js";
|
||||
@ -46,11 +45,11 @@ export function registerSig(
|
||||
serviceId: string,
|
||||
service: Sig,
|
||||
) {
|
||||
const anyService: Record<never, unknown> = service;
|
||||
|
||||
registerService({
|
||||
peer,
|
||||
// TODO: fix this after changing registerService signature
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
service: service as unknown as ServiceImpl,
|
||||
service: anyService,
|
||||
serviceId,
|
||||
});
|
||||
}
|
||||
|
@ -15,7 +15,6 @@
|
||||
*/
|
||||
|
||||
import { registerService } from "../../compilerSupport/registerService.js";
|
||||
import { ServiceImpl } from "../../compilerSupport/types.js";
|
||||
import { FluencePeer } from "../../jsPeer/FluencePeer.js";
|
||||
import { Srv } from "../SingleModuleSrv.js";
|
||||
|
||||
@ -24,12 +23,12 @@ export function registerSrv(
|
||||
serviceId: string,
|
||||
service: Srv,
|
||||
) {
|
||||
const anyService: Record<never, unknown> = service;
|
||||
|
||||
registerService({
|
||||
peer,
|
||||
serviceId,
|
||||
// TODO: fix this after changing registerService signature
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
service: service as unknown as ServiceImpl,
|
||||
service: anyService,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -14,74 +14,142 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import assert from "assert";
|
||||
import { Buffer } from "buffer";
|
||||
|
||||
import { JSONValue } from "@fluencelabs/interfaces";
|
||||
import bs58 from "bs58";
|
||||
import { sha256 } from "multiformats/hashes/sha2";
|
||||
import { z } from "zod";
|
||||
|
||||
import {
|
||||
CallServiceData,
|
||||
CallServiceResult,
|
||||
CallServiceResultType,
|
||||
GenericCallServiceHandler,
|
||||
ResultCodes,
|
||||
} from "../jsServiceHost/interfaces.js";
|
||||
import { getErrorMessage, isString, jsonify } from "../util/utils.js";
|
||||
import { getErrorMessage, jsonify } from "../util/utils.js";
|
||||
|
||||
const success = (
|
||||
// TODO: Remove unknown after adding validation to builtin inputs
|
||||
// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
|
||||
result: CallServiceResultType | unknown,
|
||||
): CallServiceResult => {
|
||||
const success = (result: CallServiceResultType): CallServiceResult => {
|
||||
return {
|
||||
// TODO: Remove type assertion after adding validation to builtin inputs
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
result: result as CallServiceResultType,
|
||||
result,
|
||||
retCode: ResultCodes.success,
|
||||
};
|
||||
};
|
||||
|
||||
const error = (
|
||||
// TODO: Remove unknown after adding validation to builtin inputs
|
||||
// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
|
||||
error: CallServiceResultType | unknown,
|
||||
): CallServiceResult => {
|
||||
const error = (error: CallServiceResultType): CallServiceResult => {
|
||||
return {
|
||||
// TODO: Remove type assertion after adding validation to builtin inputs
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
result: error as CallServiceResultType,
|
||||
result: error,
|
||||
retCode: ResultCodes.error,
|
||||
};
|
||||
};
|
||||
|
||||
const chunk = <T>(arr: T[]): T[][] => {
|
||||
const res: T[][] = [];
|
||||
const chunkSize = 2;
|
||||
|
||||
for (let i = 0; i < arr.length; i += chunkSize) {
|
||||
const chunk = arr.slice(i, i + chunkSize);
|
||||
res.push(chunk);
|
||||
}
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
const errorNotImpl = (methodName: string) => {
|
||||
return error(
|
||||
`The JS implementation of Peer does not support "${methodName}"`,
|
||||
);
|
||||
};
|
||||
|
||||
const makeJsonImpl = (args: [Record<string, JSONValue>, ...JSONValue[]]) => {
|
||||
const [obj, ...kvs] = args;
|
||||
const parseWithSchema = <T extends z.ZodTypeAny>(
|
||||
schema: T,
|
||||
req: CallServiceData,
|
||||
): [z.infer<T>, null] | [null, string] => {
|
||||
const result = schema.safeParse(req.args, {
|
||||
errorMap: (issue, ctx) => {
|
||||
if (issue.code === z.ZodIssueCode.invalid_type) {
|
||||
if (issue.path.length === 1 && typeof issue.path[0] === "number") {
|
||||
const [arg] = issue.path;
|
||||
return {
|
||||
message: `Argument ${arg} expected to be of type ${issue.expected}, Got ${issue.received}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const toMerge: Record<string, JSONValue> = {};
|
||||
if (issue.code === z.ZodIssueCode.too_big) {
|
||||
return {
|
||||
message: `Expected ${
|
||||
issue.maximum
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
} argument(s). Got ${ctx.data.length}`,
|
||||
};
|
||||
}
|
||||
|
||||
for (let i = 0; i < kvs.length / 2; i++) {
|
||||
const k = kvs[i * 2];
|
||||
if (issue.code === z.ZodIssueCode.too_small) {
|
||||
return {
|
||||
message: `Expected ${
|
||||
issue.minimum
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
} argument(s). Got ${ctx.data.length}`,
|
||||
};
|
||||
}
|
||||
|
||||
if (!isString(k)) {
|
||||
return error(`Argument ${i * 2 + 1} is expected to be string`);
|
||||
}
|
||||
if (issue.code === z.ZodIssueCode.invalid_union) {
|
||||
return {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
message: `Expected argument(s). Got ${ctx.data.length}`,
|
||||
};
|
||||
}
|
||||
|
||||
const v = kvs[i * 2 + 1];
|
||||
toMerge[k] = v;
|
||||
return { message: ctx.defaultError };
|
||||
},
|
||||
});
|
||||
|
||||
if (result.success) {
|
||||
return [result.data, null];
|
||||
} else {
|
||||
return [null, result.error.errors[0].message];
|
||||
}
|
||||
|
||||
const res = { ...obj, ...toMerge };
|
||||
return success(res);
|
||||
};
|
||||
|
||||
// TODO: These assert made for silencing more stricter ts rules. Will be fixed in DXJ-493
|
||||
const literalSchema = z.union([z.string(), z.number(), z.boolean(), z.null()]);
|
||||
type Literal = z.infer<typeof literalSchema>;
|
||||
type Json = Literal | { [key: string]: Json } | Json[];
|
||||
|
||||
const jsonSchema: z.ZodType<Json> = z.lazy(() => {
|
||||
return z.union([literalSchema, z.array(jsonSchema), z.record(jsonSchema)]);
|
||||
});
|
||||
|
||||
const jsonImplSchema = z
|
||||
.tuple([z.record(jsonSchema)])
|
||||
.rest(z.tuple([z.string(), jsonSchema]));
|
||||
|
||||
const makeJsonImpl = (args: z.infer<typeof jsonImplSchema>) => {
|
||||
const [obj, ...kvs] = args;
|
||||
return success({ ...obj, ...Object.fromEntries(kvs) });
|
||||
};
|
||||
|
||||
type withSchema = <T extends z.ZodTypeAny>(
|
||||
arg: T,
|
||||
) => (
|
||||
arg1: (value: z.infer<T>) => CallServiceResult | Promise<CallServiceResult>,
|
||||
) => (req: CallServiceData) => CallServiceResult | Promise<CallServiceResult>;
|
||||
|
||||
const withSchema: withSchema = <T extends z.ZodTypeAny>(schema: T) => {
|
||||
return (bound) => {
|
||||
return (req) => {
|
||||
const [value, message] = parseWithSchema(schema, req);
|
||||
|
||||
if (message != null) {
|
||||
return error(message);
|
||||
}
|
||||
|
||||
return bound(value);
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
export const builtInServices: Record<
|
||||
string,
|
||||
Record<string, GenericCallServiceHandler>
|
||||
@ -116,29 +184,16 @@ export const builtInServices: Record<
|
||||
return errorNotImpl("peer.get_contact");
|
||||
},
|
||||
|
||||
timeout: (req) => {
|
||||
if (req.args.length !== 2) {
|
||||
return error(
|
||||
"timeout accepts exactly two arguments: timeout duration in ms and a message string",
|
||||
);
|
||||
}
|
||||
|
||||
const durationMs = req.args[0];
|
||||
const message = req.args[1];
|
||||
|
||||
if (typeof durationMs !== "number" || typeof message !== "string") {
|
||||
return error(
|
||||
"timeout accepts exactly two arguments: timeout duration in ms and a message string",
|
||||
);
|
||||
}
|
||||
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
const res = success(message);
|
||||
resolve(res);
|
||||
}, durationMs);
|
||||
});
|
||||
},
|
||||
timeout: withSchema(z.tuple([z.number(), z.string()]))(
|
||||
([durationMs, msg]) => {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
const res = success(msg);
|
||||
resolve(res);
|
||||
}, durationMs);
|
||||
});
|
||||
},
|
||||
),
|
||||
},
|
||||
|
||||
kad: {
|
||||
@ -246,120 +301,48 @@ export const builtInServices: Record<
|
||||
return success(req.args);
|
||||
},
|
||||
|
||||
array_length: (req) => {
|
||||
if (req.args.length !== 1) {
|
||||
return error(
|
||||
"array_length accepts exactly one argument, found: " +
|
||||
req.args.length,
|
||||
);
|
||||
} else {
|
||||
assert(Array.isArray(req.args[0]));
|
||||
return success(req.args[0].length);
|
||||
}
|
||||
},
|
||||
array_length: withSchema(z.tuple([z.array(z.unknown())]))(([arr]) => {
|
||||
return success(arr.length);
|
||||
}),
|
||||
|
||||
identity: (req) => {
|
||||
if (req.args.length > 1) {
|
||||
return error(
|
||||
`identity accepts up to 1 arguments, received ${req.args.length} arguments`,
|
||||
);
|
||||
} else {
|
||||
return success(req.args.length === 0 ? {} : req.args[0]);
|
||||
}
|
||||
},
|
||||
identity: withSchema(z.array(jsonSchema).max(1))((args) => {
|
||||
return success(args.length === 0 ? {} : args[0]);
|
||||
}),
|
||||
|
||||
concat: (req) => {
|
||||
const incorrectArgIndices = req.args //
|
||||
.map((x, i): [boolean, number] => {
|
||||
return [Array.isArray(x), i];
|
||||
})
|
||||
.filter(([isArray]) => {
|
||||
return !isArray;
|
||||
})
|
||||
.map(([, index]) => {
|
||||
return index;
|
||||
});
|
||||
|
||||
if (incorrectArgIndices.length > 0) {
|
||||
const str = incorrectArgIndices.join(", ");
|
||||
return error(
|
||||
`All arguments of 'concat' must be arrays: arguments ${str} are not`,
|
||||
);
|
||||
} else {
|
||||
// TODO: remove after adding validation
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
return success([].concat(...(req.args as never[][])));
|
||||
}
|
||||
},
|
||||
|
||||
string_to_b58: (req) => {
|
||||
if (req.args.length !== 1) {
|
||||
return error("string_to_b58 accepts only one string argument");
|
||||
} else {
|
||||
const [input] = req.args;
|
||||
// TODO: remove after adding validation
|
||||
assert(typeof input === "string");
|
||||
return success(bs58.encode(new TextEncoder().encode(input)));
|
||||
}
|
||||
},
|
||||
|
||||
string_from_b58: (req) => {
|
||||
if (req.args.length !== 1) {
|
||||
return error("string_from_b58 accepts only one string argument");
|
||||
} else {
|
||||
const [input] = req.args;
|
||||
// TODO: remove after adding validation
|
||||
assert(typeof input === "string");
|
||||
return success(new TextDecoder().decode(bs58.decode(input)));
|
||||
}
|
||||
},
|
||||
|
||||
bytes_to_b58: (req) => {
|
||||
if (req.args.length !== 1 || !Array.isArray(req.args[0])) {
|
||||
return error(
|
||||
"bytes_to_b58 accepts only single argument: array of numbers",
|
||||
);
|
||||
} else {
|
||||
// TODO: remove after adding validation
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
const argumentArray = req.args[0] as number[];
|
||||
return success(bs58.encode(new Uint8Array(argumentArray)));
|
||||
}
|
||||
},
|
||||
|
||||
bytes_from_b58: (req) => {
|
||||
if (req.args.length !== 1) {
|
||||
return error("bytes_from_b58 accepts only one string argument");
|
||||
} else {
|
||||
const [input] = req.args;
|
||||
// TODO: remove after adding validation
|
||||
assert(typeof input === "string");
|
||||
return success(Array.from(bs58.decode(input)));
|
||||
}
|
||||
},
|
||||
|
||||
sha256_string: async (req) => {
|
||||
if (req.args.length !== 1) {
|
||||
return error(
|
||||
`sha256_string accepts 1 argument, found: ${req.args.length}`,
|
||||
);
|
||||
} else {
|
||||
const [input] = req.args;
|
||||
// TODO: remove after adding validation
|
||||
assert(typeof input === "string");
|
||||
const inBuffer = Buffer.from(input);
|
||||
const multihash = await sha256.digest(inBuffer);
|
||||
|
||||
return success(bs58.encode(multihash.bytes));
|
||||
}
|
||||
},
|
||||
|
||||
concat_strings: (req) => {
|
||||
// TODO: remove after adding validation
|
||||
concat: withSchema(z.array(z.array(z.unknown())))((args) => {
|
||||
// concat accepts only 'never' type
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
const res = "".concat(...(req.args as string[]));
|
||||
const arr = args as never[][];
|
||||
return success([].concat(...arr));
|
||||
}),
|
||||
|
||||
string_to_b58: withSchema(z.tuple([z.string()]))(([input]) => {
|
||||
return success(bs58.encode(new TextEncoder().encode(input)));
|
||||
}),
|
||||
|
||||
string_from_b58: withSchema(z.tuple([z.string()]))(([input]) => {
|
||||
return success(new TextDecoder().decode(bs58.decode(input)));
|
||||
}),
|
||||
|
||||
bytes_to_b58: withSchema(z.tuple([z.array(z.number())]))(([input]) => {
|
||||
return success(bs58.encode(new Uint8Array(input)));
|
||||
}),
|
||||
|
||||
bytes_from_b58: withSchema(z.tuple([z.string()]))(([input]) => {
|
||||
return success(Array.from(bs58.decode(input)));
|
||||
}),
|
||||
|
||||
sha256_string: withSchema(z.tuple([z.string()]))(async ([input]) => {
|
||||
const inBuffer = Buffer.from(input);
|
||||
const multihash = await sha256.digest(inBuffer);
|
||||
|
||||
return success(bs58.encode(multihash.bytes));
|
||||
}),
|
||||
|
||||
concat_strings: withSchema(z.array(z.string()))((args) => {
|
||||
const res = "".concat(...args);
|
||||
return success(res);
|
||||
},
|
||||
}),
|
||||
},
|
||||
|
||||
debug: {
|
||||
@ -379,365 +362,187 @@ export const builtInServices: Record<
|
||||
},
|
||||
|
||||
math: {
|
||||
add: (req) => {
|
||||
let err;
|
||||
|
||||
if ((err = checkForArgumentsCount(req, 2)) != null) {
|
||||
return err;
|
||||
}
|
||||
|
||||
const [x, y] = req.args;
|
||||
// TODO: Remove after adding validation
|
||||
assert(typeof x === "number" && typeof y === "number");
|
||||
add: withSchema(z.tuple([z.number(), z.number()]))(([x, y]) => {
|
||||
return success(x + y);
|
||||
},
|
||||
}),
|
||||
|
||||
sub: (req) => {
|
||||
let err;
|
||||
|
||||
if ((err = checkForArgumentsCount(req, 2)) != null) {
|
||||
return err;
|
||||
}
|
||||
|
||||
const [x, y] = req.args;
|
||||
// TODO: Remove after adding validation
|
||||
assert(typeof x === "number" && typeof y === "number");
|
||||
sub: withSchema(z.tuple([z.number(), z.number()]))(([x, y]) => {
|
||||
return success(x - y);
|
||||
},
|
||||
}),
|
||||
|
||||
mul: (req) => {
|
||||
let err;
|
||||
|
||||
if ((err = checkForArgumentsCount(req, 2)) != null) {
|
||||
return err;
|
||||
}
|
||||
|
||||
const [x, y] = req.args;
|
||||
// TODO: Remove after adding validation
|
||||
assert(typeof x === "number" && typeof y === "number");
|
||||
mul: withSchema(z.tuple([z.number(), z.number()]))(([x, y]) => {
|
||||
return success(x * y);
|
||||
},
|
||||
}),
|
||||
|
||||
fmul: (req) => {
|
||||
let err;
|
||||
|
||||
if ((err = checkForArgumentsCount(req, 2)) != null) {
|
||||
return err;
|
||||
}
|
||||
|
||||
const [x, y] = req.args;
|
||||
// TODO: Remove after adding validation
|
||||
assert(typeof x === "number" && typeof y === "number");
|
||||
fmul: withSchema(z.tuple([z.number(), z.number()]))(([x, y]) => {
|
||||
return success(Math.floor(x * y));
|
||||
},
|
||||
}),
|
||||
|
||||
div: (req) => {
|
||||
let err;
|
||||
|
||||
if ((err = checkForArgumentsCount(req, 2)) != null) {
|
||||
return err;
|
||||
}
|
||||
|
||||
const [x, y] = req.args;
|
||||
// TODO: Remove after adding validation
|
||||
assert(typeof x === "number" && typeof y === "number");
|
||||
div: withSchema(z.tuple([z.number(), z.number()]))(([x, y]) => {
|
||||
return success(Math.floor(x / y));
|
||||
},
|
||||
}),
|
||||
|
||||
rem: (req) => {
|
||||
let err;
|
||||
|
||||
if ((err = checkForArgumentsCount(req, 2)) != null) {
|
||||
return err;
|
||||
}
|
||||
|
||||
const [x, y] = req.args;
|
||||
// TODO: Remove after adding validation
|
||||
assert(typeof x === "number" && typeof y === "number");
|
||||
rem: withSchema(z.tuple([z.number(), z.number()]))(([x, y]) => {
|
||||
return success(x % y);
|
||||
},
|
||||
}),
|
||||
|
||||
pow: (req) => {
|
||||
let err;
|
||||
|
||||
if ((err = checkForArgumentsCount(req, 2)) != null) {
|
||||
return err;
|
||||
}
|
||||
|
||||
const [x, y] = req.args;
|
||||
// TODO: Remove after adding validation
|
||||
assert(typeof x === "number" && typeof y === "number");
|
||||
pow: withSchema(z.tuple([z.number(), z.number()]))(([x, y]) => {
|
||||
return success(Math.pow(x, y));
|
||||
},
|
||||
}),
|
||||
|
||||
log: (req) => {
|
||||
let err;
|
||||
|
||||
if ((err = checkForArgumentsCount(req, 2)) != null) {
|
||||
return err;
|
||||
}
|
||||
|
||||
const [x, y] = req.args;
|
||||
// TODO: Remove after adding validation
|
||||
assert(typeof x === "number" && typeof y === "number");
|
||||
log: withSchema(z.tuple([z.number(), z.number()]))(([x, y]) => {
|
||||
return success(Math.log(y) / Math.log(x));
|
||||
},
|
||||
}),
|
||||
},
|
||||
|
||||
cmp: {
|
||||
gt: (req) => {
|
||||
let err;
|
||||
|
||||
if ((err = checkForArgumentsCount(req, 2)) != null) {
|
||||
return err;
|
||||
}
|
||||
|
||||
const [x, y] = req.args;
|
||||
// TODO: Remove after adding validation
|
||||
assert(typeof x === "number" && typeof y === "number");
|
||||
gt: withSchema(z.tuple([z.number(), z.number()]))(([x, y]) => {
|
||||
return success(x > y);
|
||||
},
|
||||
}),
|
||||
|
||||
gte: (req) => {
|
||||
let err;
|
||||
|
||||
if ((err = checkForArgumentsCount(req, 2)) != null) {
|
||||
return err;
|
||||
}
|
||||
|
||||
const [x, y] = req.args;
|
||||
// TODO: Remove after adding validation
|
||||
assert(typeof x === "number" && typeof y === "number");
|
||||
gte: withSchema(z.tuple([z.number(), z.number()]))(([x, y]) => {
|
||||
return success(x >= y);
|
||||
},
|
||||
}),
|
||||
|
||||
lt: (req) => {
|
||||
let err;
|
||||
|
||||
if ((err = checkForArgumentsCount(req, 2)) != null) {
|
||||
return err;
|
||||
}
|
||||
|
||||
const [x, y] = req.args;
|
||||
// TODO: Remove after adding validation
|
||||
assert(typeof x === "number" && typeof y === "number");
|
||||
lt: withSchema(z.tuple([z.number(), z.number()]))(([x, y]) => {
|
||||
return success(x < y);
|
||||
},
|
||||
}),
|
||||
|
||||
lte: (req) => {
|
||||
let err;
|
||||
|
||||
if ((err = checkForArgumentsCount(req, 2)) != null) {
|
||||
return err;
|
||||
}
|
||||
|
||||
const [x, y] = req.args;
|
||||
// TODO: Remove after adding validation
|
||||
assert(typeof x === "number" && typeof y === "number");
|
||||
lte: withSchema(z.tuple([z.number(), z.number()]))(([x, y]) => {
|
||||
return success(x <= y);
|
||||
},
|
||||
}),
|
||||
|
||||
cmp: (req) => {
|
||||
let err;
|
||||
|
||||
if ((err = checkForArgumentsCount(req, 2)) != null) {
|
||||
return err;
|
||||
}
|
||||
|
||||
const [x, y] = req.args;
|
||||
// TODO: Remove after adding validation
|
||||
assert(typeof x === "number" && typeof y === "number");
|
||||
cmp: withSchema(z.tuple([z.number(), z.number()]))(([x, y]) => {
|
||||
return success(x === y ? 0 : x > y ? 1 : -1);
|
||||
},
|
||||
}),
|
||||
},
|
||||
|
||||
array: {
|
||||
sum: (req) => {
|
||||
let err;
|
||||
|
||||
if ((err = checkForArgumentsCount(req, 1)) != null) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// TODO: Remove after adding validation
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
const [xs] = req.args as [number[]];
|
||||
sum: withSchema(z.tuple([z.array(z.number())]))(([xs]) => {
|
||||
return success(
|
||||
xs.reduce((agg, cur) => {
|
||||
return agg + cur;
|
||||
}, 0),
|
||||
);
|
||||
},
|
||||
}),
|
||||
|
||||
dedup: (req) => {
|
||||
let err;
|
||||
|
||||
if ((err = checkForArgumentsCount(req, 1)) != null) {
|
||||
return err;
|
||||
}
|
||||
|
||||
const [xs] = req.args;
|
||||
// TODO: Remove after adding validation
|
||||
assert(Array.isArray(xs));
|
||||
dedup: withSchema(z.tuple([z.array(z.any())]))(([xs]) => {
|
||||
const set = new Set(xs);
|
||||
return success(Array.from(set));
|
||||
},
|
||||
}),
|
||||
|
||||
intersect: (req) => {
|
||||
let err;
|
||||
intersect: withSchema(z.tuple([z.array(z.any()), z.array(z.any())]))(
|
||||
([xs, ys]) => {
|
||||
const intersection = xs.filter((x) => {
|
||||
return ys.includes(x);
|
||||
});
|
||||
|
||||
if ((err = checkForArgumentsCount(req, 2)) != null) {
|
||||
return err;
|
||||
}
|
||||
return success(intersection);
|
||||
},
|
||||
),
|
||||
|
||||
const [xs, ys] = req.args;
|
||||
// TODO: Remove after adding validation
|
||||
assert(Array.isArray(xs) && Array.isArray(ys));
|
||||
diff: withSchema(z.tuple([z.array(z.any()), z.array(z.any())]))(
|
||||
([xs, ys]) => {
|
||||
const diff = xs.filter((x) => {
|
||||
return !ys.includes(x);
|
||||
});
|
||||
|
||||
const intersection = xs.filter((x) => {
|
||||
return ys.includes(x);
|
||||
});
|
||||
return success(diff);
|
||||
},
|
||||
),
|
||||
|
||||
return success(intersection);
|
||||
},
|
||||
sdiff: withSchema(z.tuple([z.array(z.any()), z.array(z.any())]))(
|
||||
([xs, ys]) => {
|
||||
const sdiff = [
|
||||
xs.filter((y) => {
|
||||
return !ys.includes(y);
|
||||
}),
|
||||
ys.filter((x) => {
|
||||
return !xs.includes(x);
|
||||
}),
|
||||
].flat();
|
||||
|
||||
diff: (req) => {
|
||||
let err;
|
||||
|
||||
if ((err = checkForArgumentsCount(req, 2)) != null) {
|
||||
return err;
|
||||
}
|
||||
|
||||
const [xs, ys] = req.args;
|
||||
// TODO: Remove after adding validation
|
||||
assert(Array.isArray(xs) && Array.isArray(ys));
|
||||
|
||||
const diff = xs.filter((x) => {
|
||||
return !ys.includes(x);
|
||||
});
|
||||
|
||||
return success(diff);
|
||||
},
|
||||
|
||||
sdiff: (req) => {
|
||||
let err;
|
||||
|
||||
if ((err = checkForArgumentsCount(req, 2)) != null) {
|
||||
return err;
|
||||
}
|
||||
|
||||
const [xs, ys] = req.args;
|
||||
// TODO: Remove after adding validation
|
||||
assert(Array.isArray(xs) && Array.isArray(ys));
|
||||
|
||||
const sdiff = [
|
||||
// force new line
|
||||
...xs.filter((y) => {
|
||||
return !ys.includes(y);
|
||||
}),
|
||||
...ys.filter((x) => {
|
||||
return !xs.includes(x);
|
||||
}),
|
||||
];
|
||||
|
||||
return success(sdiff);
|
||||
},
|
||||
return success(sdiff);
|
||||
},
|
||||
),
|
||||
},
|
||||
|
||||
json: {
|
||||
obj: (req) => {
|
||||
let err;
|
||||
obj: withSchema(
|
||||
z
|
||||
.array(z.unknown())
|
||||
.refine(
|
||||
(arr) => {
|
||||
return arr.length % 2 === 0;
|
||||
},
|
||||
(arr) => {
|
||||
return {
|
||||
message: "Expected even number of argument(s). Got " + arr.length,
|
||||
};
|
||||
},
|
||||
)
|
||||
.transform((args) => {
|
||||
return chunk(args);
|
||||
})
|
||||
.pipe(z.array(z.tuple([z.string(), jsonSchema]))),
|
||||
)((args) => {
|
||||
return makeJsonImpl([{}, ...args]);
|
||||
}),
|
||||
|
||||
if ((err = checkForArgumentsCountEven(req)) != null) {
|
||||
return err;
|
||||
}
|
||||
put: withSchema(
|
||||
z
|
||||
.tuple([z.record(jsonSchema), z.string(), jsonSchema])
|
||||
.transform(
|
||||
([obj, name, value]): [{ [key: string]: Json }, [string, Json]] => {
|
||||
return [obj, [name, value]];
|
||||
},
|
||||
),
|
||||
)(makeJsonImpl),
|
||||
|
||||
// TODO: remove after adding validation
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
return makeJsonImpl([{}, ...req.args] as [
|
||||
Record<string, JSONValue>,
|
||||
...JSONValue[],
|
||||
]);
|
||||
},
|
||||
puts: withSchema(
|
||||
z
|
||||
.array(z.unknown())
|
||||
.refine(
|
||||
(arr) => {
|
||||
return arr.length >= 3;
|
||||
},
|
||||
(value) => {
|
||||
return {
|
||||
message: `Expected more than 3 argument(s). Got ${value.length}`,
|
||||
};
|
||||
},
|
||||
)
|
||||
.refine(
|
||||
(arr) => {
|
||||
return arr.length % 2 === 1;
|
||||
},
|
||||
{
|
||||
message: "Argument count must be odd.",
|
||||
},
|
||||
)
|
||||
.transform((args) => {
|
||||
return [args[0], ...chunk(args.slice(1))];
|
||||
})
|
||||
.pipe(jsonImplSchema),
|
||||
)(makeJsonImpl),
|
||||
|
||||
put: (req) => {
|
||||
let err;
|
||||
|
||||
if ((err = checkForArgumentsCount(req, 3)) != null) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((err = checkForArgumentType(req, 0, "object")) != null) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return makeJsonImpl(
|
||||
// TODO: remove after adding validation
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
req.args as [Record<string, JSONValue>, ...JSONValue[]],
|
||||
);
|
||||
},
|
||||
|
||||
puts: (req) => {
|
||||
let err;
|
||||
|
||||
if ((err = checkForArgumentsCountOdd(req)) != null) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((err = checkForArgumentsCountMoreThan(req, 3)) != null) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((err = checkForArgumentType(req, 0, "object")) != null) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return makeJsonImpl(
|
||||
// TODO: remove after adding validation
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
req.args as [Record<string, JSONValue>, ...JSONValue[]],
|
||||
);
|
||||
},
|
||||
|
||||
stringify: (req) => {
|
||||
let err;
|
||||
|
||||
if ((err = checkForArgumentsCount(req, 1)) != null) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((err = checkForArgumentType(req, 0, "object")) != null) {
|
||||
return err;
|
||||
}
|
||||
|
||||
const [json] = req.args;
|
||||
const res = JSON.stringify(json);
|
||||
return success(res);
|
||||
},
|
||||
|
||||
parse: (req) => {
|
||||
let err;
|
||||
|
||||
if ((err = checkForArgumentsCount(req, 1)) != null) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((err = checkForArgumentType(req, 0, "string")) != null) {
|
||||
return err;
|
||||
}
|
||||
|
||||
const [raw] = req.args;
|
||||
stringify: withSchema(z.tuple([z.record(z.string(), jsonSchema)]))(
|
||||
([json]) => {
|
||||
const res = JSON.stringify(json);
|
||||
return success(res);
|
||||
},
|
||||
),
|
||||
|
||||
parse: withSchema(z.tuple([z.string()]))(([raw]) => {
|
||||
try {
|
||||
// TODO: Remove after adding validation
|
||||
assert(typeof raw === "string");
|
||||
const json = JSON.parse(raw);
|
||||
// Parsing any argument here yields JSONValue
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
const json = JSON.parse(raw) as JSONValue;
|
||||
return success(json);
|
||||
} catch (err: unknown) {
|
||||
return error(getErrorMessage(err));
|
||||
}
|
||||
},
|
||||
}),
|
||||
},
|
||||
|
||||
"run-console": {
|
||||
@ -749,59 +554,3 @@ export const builtInServices: Record<
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
const checkForArgumentsCount = (
|
||||
req: { args: Array<unknown> },
|
||||
count: number,
|
||||
) => {
|
||||
if (req.args.length !== count) {
|
||||
return error(`Expected ${count} argument(s). Got ${req.args.length}`);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const checkForArgumentsCountMoreThan = (
|
||||
req: { args: Array<unknown> },
|
||||
count: number,
|
||||
) => {
|
||||
if (req.args.length < count) {
|
||||
return error(
|
||||
`Expected more than ${count} argument(s). Got ${req.args.length}`,
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const checkForArgumentsCountEven = (req: { args: Array<unknown> }) => {
|
||||
if (req.args.length % 2 === 1) {
|
||||
return error(`Expected even number of argument(s). Got ${req.args.length}`);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const checkForArgumentsCountOdd = (req: { args: Array<unknown> }) => {
|
||||
if (req.args.length % 2 === 0) {
|
||||
return error(`Expected odd number of argument(s). Got ${req.args.length}`);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const checkForArgumentType = (
|
||||
req: { args: Array<unknown> },
|
||||
index: number,
|
||||
type: string,
|
||||
) => {
|
||||
const actual = typeof req.args[index];
|
||||
|
||||
if (actual !== type) {
|
||||
return error(
|
||||
`Argument ${index} expected to be of type ${type}, Got ${actual}`,
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
28
packages/core/js-client/src/test.ts
Normal file
28
packages/core/js-client/src/test.ts
Normal file
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright 2023 Fluence Labs Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { classToPlain } from "class-transformer";
|
||||
|
||||
import { NodeUtils } from "./services/NodeUtils.js";
|
||||
|
||||
import { Fluence } from "./index.js";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
console.log(classToPlain(new NodeUtils(Fluence.defaultClient!)));
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
console.log(
|
||||
Object.getPrototypeOf(classToPlain(new NodeUtils(Fluence.defaultClient!))),
|
||||
);
|
@ -24,7 +24,7 @@
|
||||
"vitest": "0.34.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fluencelabs/marine-js": "0.7.2",
|
||||
"@fluencelabs/marine-js": "0.8.0",
|
||||
"observable-fns": "0.6.1",
|
||||
"@fluencelabs/threads": "^2.0.0"
|
||||
}
|
||||
|
@ -28,7 +28,6 @@ import type {
|
||||
} from "@fluencelabs/marine-js/dist/types";
|
||||
import {
|
||||
defaultCallParameters,
|
||||
JSONValue,
|
||||
logLevelToEnv,
|
||||
} from "@fluencelabs/marine-js/dist/types";
|
||||
import { expose } from "@fluencelabs/threads/worker";
|
||||
@ -140,9 +139,7 @@ const toExpose = {
|
||||
throw new Error(`service with id=${serviceId} not found`);
|
||||
}
|
||||
|
||||
// TODO: Make MarineService return JSONValue type
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
return srv.call(functionName, args, callParams) as JSONValue;
|
||||
return srv.call(functionName, args, callParams);
|
||||
},
|
||||
|
||||
onLogMessage() {
|
||||
|
55
pnpm-lock.yaml
generated
55
pnpm-lock.yaml
generated
@ -190,6 +190,9 @@ importers:
|
||||
vitest:
|
||||
specifier: 0.34.6
|
||||
version: 0.34.6
|
||||
zod:
|
||||
specifier: 3.22.4
|
||||
version: 3.22.4
|
||||
|
||||
packages/core/interfaces:
|
||||
devDependencies:
|
||||
@ -244,9 +247,6 @@ importers:
|
||||
'@multiformats/multiaddr':
|
||||
specifier: 11.3.0
|
||||
version: 11.3.0
|
||||
assert:
|
||||
specifier: 2.1.0
|
||||
version: 2.1.0
|
||||
async:
|
||||
specifier: 3.2.4
|
||||
version: 3.2.4
|
||||
@ -256,6 +256,9 @@ importers:
|
||||
buffer:
|
||||
specifier: 6.0.3
|
||||
version: 6.0.3
|
||||
class-transformer:
|
||||
specifier: 0.5.1
|
||||
version: 0.5.1
|
||||
debug:
|
||||
specifier: 4.3.4
|
||||
version: 4.3.4
|
||||
@ -289,13 +292,16 @@ importers:
|
||||
zod:
|
||||
specifier: 3.22.4
|
||||
version: 3.22.4
|
||||
zod-validation-error:
|
||||
specifier: 2.1.0
|
||||
version: 2.1.0(zod@3.22.4)
|
||||
devDependencies:
|
||||
'@fluencelabs/aqua-api':
|
||||
specifier: 0.9.3
|
||||
version: 0.9.3
|
||||
'@fluencelabs/marine-js':
|
||||
specifier: 0.7.2
|
||||
version: 0.7.2
|
||||
specifier: 0.8.0
|
||||
version: 0.8.0
|
||||
'@rollup/plugin-inject':
|
||||
specifier: 5.0.3
|
||||
version: 5.0.3
|
||||
@ -333,8 +339,8 @@ importers:
|
||||
specifier: 0.54.0
|
||||
version: 0.54.0
|
||||
'@fluencelabs/marine-js':
|
||||
specifier: 0.7.2
|
||||
version: 0.7.2
|
||||
specifier: 0.8.0
|
||||
version: 0.8.0
|
||||
'@fluencelabs/marine-worker':
|
||||
specifier: 0.4.2
|
||||
version: link:../marine-worker
|
||||
@ -345,8 +351,8 @@ importers:
|
||||
packages/core/marine-worker:
|
||||
dependencies:
|
||||
'@fluencelabs/marine-js':
|
||||
specifier: 0.7.2
|
||||
version: 0.7.2
|
||||
specifier: 0.8.0
|
||||
version: 0.8.0
|
||||
'@fluencelabs/threads':
|
||||
specifier: ^2.0.0
|
||||
version: 2.0.0
|
||||
@ -3714,8 +3720,8 @@ packages:
|
||||
/@fluencelabs/avm@0.54.0:
|
||||
resolution: {integrity: sha512-5GgROVly/vC7gasltr6/3TIY8vfV6b+SPfWUAGWnyXdbWt4jJANLO2YtXdaUsdNk9PiwOep7TMjLnypljdyMjQ==}
|
||||
|
||||
/@fluencelabs/marine-js@0.7.2:
|
||||
resolution: {integrity: sha512-etjbXDgzyZkK82UZvtuIU3bfy5f52siDUy1m+T5Y5r70k82xYdZZ8vgWVgB6ivi2f3aDyQjgNTfzWQjKFpAReQ==}
|
||||
/@fluencelabs/marine-js@0.8.0:
|
||||
resolution: {integrity: sha512-exxp0T0Dk69dxnbpAiVc/qp66s8Jq/P71TRB9aeQZLZy3EQtVAMCBJvwQY8LzVVlYEyVjmqQkFG/N0rAeYU1vg==}
|
||||
dependencies:
|
||||
'@wasmer/wasi': 0.12.0
|
||||
'@wasmer/wasmfs': 0.12.0
|
||||
@ -5910,16 +5916,6 @@ packages:
|
||||
util: 0.12.5
|
||||
dev: true
|
||||
|
||||
/assert@2.1.0:
|
||||
resolution: {integrity: sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==}
|
||||
dependencies:
|
||||
call-bind: 1.0.2
|
||||
is-nan: 1.3.2
|
||||
object-is: 1.1.5
|
||||
object.assign: 4.1.4
|
||||
util: 0.12.5
|
||||
dev: false
|
||||
|
||||
/assertion-error@1.1.0:
|
||||
resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==}
|
||||
dev: true
|
||||
@ -6675,6 +6671,10 @@ packages:
|
||||
resolution: {integrity: sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==}
|
||||
dev: false
|
||||
|
||||
/class-transformer@0.5.1:
|
||||
resolution: {integrity: sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==}
|
||||
dev: false
|
||||
|
||||
/clean-css@5.3.2:
|
||||
resolution: {integrity: sha512-JVJbM+f3d3Q704rF4bqQ5UUyTtuJ0JRKNbTKVEeujCCBoMdkEi+V+e8oktO9qGQNSvHrFTM6JZRXrUvGR1czww==}
|
||||
engines: {node: '>= 10.0'}
|
||||
@ -9351,6 +9351,7 @@ packages:
|
||||
engines: {node: '>= 0.4'}
|
||||
dependencies:
|
||||
has-tostringtag: 1.0.0
|
||||
dev: true
|
||||
|
||||
/is-glob@4.0.3:
|
||||
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
|
||||
@ -9376,6 +9377,7 @@ packages:
|
||||
dependencies:
|
||||
call-bind: 1.0.2
|
||||
define-properties: 1.2.0
|
||||
dev: true
|
||||
|
||||
/is-negative-zero@2.0.2:
|
||||
resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==}
|
||||
@ -14375,6 +14377,7 @@ packages:
|
||||
is-generator-function: 1.0.10
|
||||
is-typed-array: 1.1.12
|
||||
which-typed-array: 1.1.11
|
||||
dev: true
|
||||
|
||||
/utila@0.4.0:
|
||||
resolution: {integrity: sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==}
|
||||
@ -15218,6 +15221,14 @@ packages:
|
||||
engines: {node: '>=12.20'}
|
||||
dev: true
|
||||
|
||||
/zod-validation-error@2.1.0(zod@3.22.4):
|
||||
resolution: {integrity: sha512-VJh93e2wb4c3tWtGgTa0OF/dTt/zoPCPzXq4V11ZjxmEAFaPi/Zss1xIZdEB5RD8GD00U0/iVXgqkF77RV7pdQ==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
peerDependencies:
|
||||
zod: ^3.18.0
|
||||
dependencies:
|
||||
zod: 3.22.4
|
||||
dev: false
|
||||
|
||||
/zod@3.22.4:
|
||||
resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==}
|
||||
dev: false
|
||||
|
Loading…
x
Reference in New Issue
Block a user