Adapt js-client ecosystem to the new API.

This commit is contained in:
Akim Mamedov
2023-11-14 04:55:50 +07:00
parent 426f154377
commit 927277330e
34 changed files with 2467 additions and 2805 deletions

View File

@ -21,28 +21,27 @@ import { fileURLToPath } from "url";
import { compileFromPath } from "@fluencelabs/aqua-api"; import { compileFromPath } from "@fluencelabs/aqua-api";
import aquaToJs from "@fluencelabs/aqua-to-js"; import aquaToJs from "@fluencelabs/aqua-to-js";
const cr = await compileFromPath({ const files = ["smoke_test", "finalize_particle"];
filePath: join(
dirname(fileURLToPath(import.meta.url)),
"_aqua",
"smoke_test.aqua",
),
targetType: "air",
imports: [join(dirname(fileURLToPath(import.meta.url)), "node_modules")],
});
const res = await aquaToJs(cr, "ts"); for (const file of files) {
const cr = await compileFromPath({
filePath: join(
dirname(fileURLToPath(import.meta.url)),
"_aqua",
file + ".aqua",
),
targetType: "air",
imports: [fileURLToPath(new URL("./node_modules", import.meta.url))],
});
if (res == null) { const res = await aquaToJs(cr, "ts");
throw new Error(cr.errors.join("\n"));
if (res == null) {
throw new Error(cr.errors.join("\n"));
}
await writeFile(
fileURLToPath(new URL(join("src", "_aqua", file + ".ts"), import.meta.url)),
res.sources,
);
} }
await writeFile(
join(
dirname(fileURLToPath(import.meta.url)),
"src",
"_aqua",
"smoke_test.ts",
),
res.sources,
);

View File

@ -2,71 +2,182 @@
// @ts-nocheck // @ts-nocheck
/** /**
* *
* This file is auto-generated. Do not edit manually: changes may be erased. * This file is generated using:
* Generated by Aqua compiler: https://github.com/fluencelabs/aqua/. * @fluencelabs/aqua-api version: 0.12.0
* If you find any bugs, please write an issue on GitHub: https://github.com/fluencelabs/aqua/issues * @fluencelabs/aqua-to-js version: 0.2.0
* Aqua version: 0.12.0 * If you find any bugs in generated AIR, please write an issue on GitHub: https://github.com/fluencelabs/aqua/issues
* If you find any bugs in generated JS/TS, please write an issue on GitHub: https://github.com/fluencelabs/js-client/issues
* *
*/ */
import type { import type { IFluenceClient as IFluenceClient$$, ParticleContext as ParticleContext$$ } from '@fluencelabs/js-client';
IFluenceClient as IFluenceClient$$,
CallParams as CallParams$$, import {
} from "@fluencelabs/js-client"; v5_callFunction as callFunction$$,
import { v5_registerService as registerService$$,
v5_callFunction as callFunction$$, FluencePeer as FluencePeer$$
v5_registerService as registerService$$, } from '@fluencelabs/js-client';
} from "@fluencelabs/js-client";
/**
* @typedef {import("@fluencelabs/js-client").NonArrowSimpleType} NonArrowSimpleType
* @typedef {import("@fluencelabs/js-client").JSONValue} JSONValue
*/
/**
* Convert value from its representation in aqua language to representation in typescript
* @param {JSONValue} value - value as represented in aqua
* @param {NonArrowSimpleType} schema - definition of the aqua schema
* @returns {JSONValue} value represented in typescript
*/
export function aqua2ts(value, schema) {
if (schema.tag === "nil") {
return null;
}
else if (schema.tag === "option") {
if (!Array.isArray(value)) {
throw new Error("Bad schema");
}
if (value.length === 0) {
return null;
}
else {
return aqua2ts(value[0], schema.type);
}
}
else if (schema.tag === "scalar" ||
schema.tag === "bottomType" ||
schema.tag === "topType") {
return value;
}
else if (schema.tag === "array") {
if (!Array.isArray(value)) {
throw new Error("Bad schema");
}
return value.map((y) => {
return aqua2ts(y, schema.type);
});
}
else if (schema.tag === "unlabeledProduct") {
if (!Array.isArray(value)) {
throw new Error("Bad schema");
}
return value.map((y, i) => {
return aqua2ts(y, schema.items[i]);
});
}
else if (schema.tag === "struct" || schema.tag === "labeledProduct") {
if (typeof value !== "object" || value == null || Array.isArray(value)) {
throw new Error("Bad schema");
}
return Object.entries(schema.fields).reduce((agg, [key, type]) => {
const val = aqua2ts(value[key], type);
return { ...agg, [key]: val };
}, {});
}
else {
throw new Error("Unexpected tag: " + JSON.stringify(schema));
}
}
/**
* Convert value from its typescript representation to representation in aqua
* @param value {JSONValue} the value as represented in typescript
* @param schema {NonArrowSimpleType} - definition of the aqua type
* @returns {JSONValue} represented in aqua
*/
export function ts2aqua(value, schema) {
if (schema.tag === "nil") {
return null;
}
else if (schema.tag === "option") {
if (!Array.isArray(value)) {
throw new Error("Bad schema");
}
return value === null ? [] : [ts2aqua(value, schema.type)];
}
else if (schema.tag === "scalar" ||
schema.tag === "bottomType" ||
schema.tag === "topType") {
return value;
}
else if (schema.tag === "array") {
if (!Array.isArray(value)) {
throw new Error("Bad schema");
}
return value.map((y) => {
return ts2aqua(y, schema.type);
});
}
else if (schema.tag === "unlabeledProduct") {
if (!Array.isArray(value)) {
throw new Error("Bad schema");
}
return value.map((y, i) => {
return ts2aqua(y, schema.items[i]);
});
}
else if (schema.tag === "struct" || schema.tag === "labeledProduct") {
if (typeof value !== "object" || value == null || Array.isArray(value)) {
throw new Error("Bad schema");
}
return Object.entries(schema.fields).reduce((agg, [key, type]) => {
const val = ts2aqua(value[key], type);
return { ...agg, [key]: val };
}, {});
}
else {
throw new Error("Unexpected tag: " + JSON.stringify(schema));
}
}
// Services
// Functions // Functions
export const test_script = ` export const test_script = `
(seq (seq
(call %init_peer_id% ("getDataSrv" "-relay-") [] -relay-) (call %init_peer_id% ("getDataSrv" "-relay-") [] -relay-)
(xor (xor
(xor (xor
(call -relay- ("op" "noop") []) (call -relay- ("op" "noop") [])
(fail %last_error%) (fail %last_error%)
) )
(call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 0]) (call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 0])
) )
) )
`; `;
export function test(config?: { ttl?: number }): Promise<void>;
export function test( export function test(
peer: IFluenceClient$$, config?: {ttl?: number}
config?: { ttl?: number },
): Promise<void>; ): Promise<void>;
export function test(...args: any) { export function test(
return callFunction$$( peer: IFluenceClient$$,
args, config?: {ttl?: number}
{ ): Promise<void>;
functionName: "test",
arrow: {
tag: "arrow",
domain: {
tag: "labeledProduct",
fields: {},
},
codomain: {
tag: "nil",
},
},
names: {
relay: "-relay-",
getDataSrv: "getDataSrv",
callbackSrv: "callbackSrv",
responseSrv: "callbackSrv",
responseFnName: "response",
errorHandlingSrv: "errorHandlingSrv",
errorFnName: "error",
},
},
test_script,
);
}
/* eslint-enable */ export async function test(...args: any[]) {
const argNames = [];
const argCount = argNames.length;
let peer = undefined;
if (args[0] instanceof FluencePeer$$) {
peer = args[0];
args = args.slice(1);
}
const callArgs = Object.fromEntries(args.slice(0, argCount).map((arg, i) => [argNames[i], arg]));
const params = ({
peer,
args: callArgs,
config: args[argCount]
});
const result = await callFunction$$({
script: test_script,
...params,
});
return aqua2ts(result,
{
"tag": "nil"
}
);
}

File diff suppressed because it is too large Load Diff

View File

@ -77,7 +77,6 @@ const getRelayTime = () => {
return callAquaFunction({ return callAquaFunction({
args, args,
def,
script, script,
config, config,
peer: Fluence.defaultClient, peer: Fluence.defaultClient,

View File

@ -61,13 +61,6 @@ export const startContentServer = (
source: "/js-client.min.js", source: "/js-client.min.js",
destination: "/source/index.min.js", destination: "/source/index.min.js",
}, },
// TODO:
// something like this
// {
// source: "/@fluencelabs/:name(\\w+)@:version([\\d.]+)/:path*",
// destination: "/deps/@fluencelabs/:name/:path",
// }
// not supported for some reason. Need to manually iterate over all possible paths
{ {
source: "/@fluencelabs/:name([\\w-]+)@:version([\\d.]+)/dist/:asset", source: "/@fluencelabs/:name([\\w-]+)@:version([\\d.]+)/dist/:asset",
destination: "/node_modules/@fluencelabs/:name/dist/:asset", destination: "/node_modules/@fluencelabs/:name/dist/:asset",

View File

@ -1,3 +1,3 @@
{ {
"ignorePatterns": ["src/**/__snapshots__/**/*"] "ignorePatterns": ["src/**/__snapshots__/**/*", "src/**/*.js"]
} }

View File

@ -14,9 +14,6 @@
"keywords": [], "keywords": [],
"author": "Fluence Labs", "author": "Fluence Labs",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": {
"ts-pattern": "5.0.5"
},
"devDependencies": { "devDependencies": {
"@fluencelabs/aqua-api": "0.12.0", "@fluencelabs/aqua-api": "0.12.0",
"@fluencelabs/aqua-lib": "0.7.3", "@fluencelabs/aqua-lib": "0.7.3",
@ -24,6 +21,10 @@
"@fluencelabs/registry": "0.8.7", "@fluencelabs/registry": "0.8.7",
"@fluencelabs/spell": "0.5.20", "@fluencelabs/spell": "0.5.20",
"@fluencelabs/trust-graph": "0.4.7", "@fluencelabs/trust-graph": "0.4.7",
"ts-pattern": "5.0.5",
"vitest": "0.34.6" "vitest": "0.34.6"
},
"peerDependencies": {
"@fluencelabs/js-client": "workspace:^"
} }
} }

View File

@ -122,16 +122,7 @@ export function typeToTs(t: NonArrowType | ArrowType): string {
// JS-client argument // JS-client argument
if (domain.tag !== "unlabeledProduct") { if (domain.tag !== "unlabeledProduct") {
const generic = args.push(["callParams", `ParticleContext$$`]);
args.length === 0
? "null"
: args
.map(([name]) => {
return `'${name}'`;
})
.join(" | ");
args.push(["callParams", `CallParams$$<${generic}>`]);
} }
const funcArgs = args const funcArgs = args

View File

@ -0,0 +1,205 @@
/* eslint-disable */
// @ts-nocheck
/**
*
* This file is generated using:
* @fluencelabs/aqua-api version: 0.0.0
* @fluencelabs/aqua-to-js version: 0.0.0
* If you find any bugs in generated AIR, please write an issue on GitHub: https://github.com/fluencelabs/aqua/issues
* If you find any bugs in generated JS/TS, please write an issue on GitHub: https://github.com/fluencelabs/js-client/issues
*
*/
import type { IFluenceClient as IFluenceClient$$, ParticleContext as ParticleContext$$ } from '@fluencelabs/js-client';
import {
v5_callFunction as callFunction$$,
v5_registerService as registerService$$,
FluencePeer as FluencePeer$$
} from '@fluencelabs/js-client';
/**
* @typedef {import("@fluencelabs/js-client").NonArrowSimpleType} NonArrowSimpleType
* @typedef {import("@fluencelabs/js-client").JSONValue} JSONValue
*/
/**
* Convert value from its representation in aqua language to representation in typescript
* @param {JSONValue} value - value as represented in aqua
* @param {NonArrowSimpleType} schema - definition of the aqua schema
* @returns {JSONValue} value represented in typescript
*/
export function aqua2ts(value, schema) {
if (schema.tag === "nil") {
return null;
} else if (schema.tag === "option") {
if (!Array.isArray(value)) {
throw new Error("Bad schema");
}
if (value.length === 0) {
return null;
} else {
return aqua2ts(value[0], schema.type);
}
} else if (
schema.tag === "scalar" ||
schema.tag === "bottomType" ||
schema.tag === "topType"
) {
return value;
} else if (schema.tag === "array") {
if (!Array.isArray(value)) {
throw new Error("Bad schema");
}
return value.map((y) => {
return aqua2ts(y, schema.type);
});
} else if (schema.tag === "unlabeledProduct") {
if (!Array.isArray(value)) {
throw new Error("Bad schema");
}
return value.map((y, i) => {
return aqua2ts(y, schema.items[i]);
});
} else if (schema.tag === "struct" || schema.tag === "labeledProduct") {
if (typeof value !== "object" || value == null || Array.isArray(value)) {
throw new Error("Bad schema");
}
return Object.entries(schema.fields).reduce((agg, [key, type]) => {
const val = aqua2ts(value[key], type);
return { ...agg, [key]: val };
}, {});
} else {
throw new Error("Unexpected tag: " + JSON.stringify(schema));
}
}
/**
* Convert value from its typescript representation to representation in aqua
* @param value {JSONValue} the value as represented in typescript
* @param schema {NonArrowSimpleType} - definition of the aqua type
* @returns {JSONValue} represented in aqua
*/
export function ts2aqua(value, schema) {
if (schema.tag === "nil") {
return null;
} else if (schema.tag === "option") {
if (!Array.isArray(value)) {
throw new Error("Bad schema");
}
return value === null ? [] : [ts2aqua(value, schema.type)];
} else if (
schema.tag === "scalar" ||
schema.tag === "bottomType" ||
schema.tag === "topType"
) {
return value;
} else if (schema.tag === "array") {
if (!Array.isArray(value)) {
throw new Error("Bad schema");
}
return value.map((y) => {
return ts2aqua(y, schema.type);
});
} else if (schema.tag === "unlabeledProduct") {
if (!Array.isArray(value)) {
throw new Error("Bad schema");
}
return value.map((y, i) => {
return ts2aqua(y, schema.items[i]);
});
} else if (schema.tag === "struct" || schema.tag === "labeledProduct") {
if (typeof value !== "object" || value == null || Array.isArray(value)) {
throw new Error("Bad schema");
}
return Object.entries(schema.fields).reduce((agg, [key, type]) => {
const val = ts2aqua(value[key], type);
return { ...agg, [key]: val };
}, {});
} else {
throw new Error("Unexpected tag: " + JSON.stringify(schema));
}
}
// Services
export interface SrvDef {
create: (wasm_b64_content: string, callParams: ParticleContext$$) => { error: string | null; service_id: string | null; success: boolean; } | Promise<{ error: string | null; service_id: string | null; success: boolean; }>;
list: (callParams: ParticleContext$$) => string[] | Promise<string[]>;
remove: (service_id: string, callParams: ParticleContext$$) => { error: string | null; success: boolean; } | Promise<{ error: string | null; success: boolean; }>;
}
export function registerSrv(service: SrvDef): void;
export function registerSrv(serviceId: string, service: SrvDef): void;
export function registerSrv(peer: IFluenceClient$$, service: SrvDef): void;
export function registerSrv(peer: IFluenceClient$$, serviceId: string, service: SrvDef): void;
export interface CalcServiceDef {
add: (num: number, callParams: ParticleContext$$) => number | Promise<number>;
clear_state: (callParams: ParticleContext$$) => void | Promise<void>;
divide: (num: number, callParams: ParticleContext$$) => number | Promise<number>;
multiply: (num: number, callParams: ParticleContext$$) => number | Promise<number>;
state: (callParams: ParticleContext$$) => number | Promise<number>;
subtract: (num: number, callParams: ParticleContext$$) => number | Promise<number>;
test_logs: (callParams: ParticleContext$$) => void | Promise<void>;
}
export function registerCalcService(serviceId: string, service: CalcServiceDef): void;
export function registerCalcService(peer: IFluenceClient$$, serviceId: string, service: CalcServiceDef): void;
export interface HelloWorldDef {
hello: (str: string, callParams: ParticleContext$$) => string | Promise<string>;
}
export function registerHelloWorld(service: HelloWorldDef): void;
export function registerHelloWorld(serviceId: string, service: HelloWorldDef): void;
export function registerHelloWorld(peer: IFluenceClient$$, service: HelloWorldDef): void;
export function registerHelloWorld(peer: IFluenceClient$$, serviceId: string, service: HelloWorldDef): void;
// Functions
export type ResourceTestResult = [string | null, string[]]
export function resourceTest(
label: string,
config?: {ttl?: number}
): Promise<ResourceTestResult>;
export function resourceTest(
peer: IFluenceClient$$,
label: string,
config?: {ttl?: number}
): Promise<ResourceTestResult>;
export function helloTest(
config?: {ttl?: number}
): Promise<string>;
export function helloTest(
peer: IFluenceClient$$,
config?: {ttl?: number}
): Promise<string>;
export function demo_calculation(
service_id: string,
config?: {ttl?: number}
): Promise<number>;
export function demo_calculation(
peer: IFluenceClient$$,
service_id: string,
config?: {ttl?: number}
): Promise<number>;
export function marineTest(
wasm64: string,
config?: {ttl?: number}
): Promise<number>;
export function marineTest(
peer: IFluenceClient$$,
wasm64: string,
config?: {ttl?: number}
): Promise<number>;

View File

@ -0,0 +1,643 @@
/* eslint-disable */
// @ts-nocheck
/**
*
* This file is generated using:
* @fluencelabs/aqua-api version: 0.0.0
* @fluencelabs/aqua-to-js version: 0.0.0
* If you find any bugs in generated AIR, please write an issue on GitHub: https://github.com/fluencelabs/aqua/issues
* If you find any bugs in generated JS/TS, please write an issue on GitHub: https://github.com/fluencelabs/js-client/issues
*
*/
import {
v5_callFunction as callFunction$$,
v5_registerService as registerService$$,
FluencePeer as FluencePeer$$
} from '@fluencelabs/js-client';
/**
* @typedef {import("@fluencelabs/js-client").NonArrowSimpleType} NonArrowSimpleType
* @typedef {import("@fluencelabs/js-client").JSONValue} JSONValue
*/
/**
* Convert value from its representation in aqua language to representation in typescript
* @param {JSONValue} value - value as represented in aqua
* @param {NonArrowSimpleType} schema - definition of the aqua schema
* @returns {JSONValue} value represented in typescript
*/
export function aqua2ts(value, schema) {
if (schema.tag === "nil") {
return null;
} else if (schema.tag === "option") {
if (!Array.isArray(value)) {
throw new Error("Bad schema");
}
if (value.length === 0) {
return null;
} else {
return aqua2ts(value[0], schema.type);
}
} else if (
schema.tag === "scalar" ||
schema.tag === "bottomType" ||
schema.tag === "topType"
) {
return value;
} else if (schema.tag === "array") {
if (!Array.isArray(value)) {
throw new Error("Bad schema");
}
return value.map((y) => {
return aqua2ts(y, schema.type);
});
} else if (schema.tag === "unlabeledProduct") {
if (!Array.isArray(value)) {
throw new Error("Bad schema");
}
return value.map((y, i) => {
return aqua2ts(y, schema.items[i]);
});
} else if (schema.tag === "struct" || schema.tag === "labeledProduct") {
if (typeof value !== "object" || value == null || Array.isArray(value)) {
throw new Error("Bad schema");
}
return Object.entries(schema.fields).reduce((agg, [key, type]) => {
const val = aqua2ts(value[key], type);
return { ...agg, [key]: val };
}, {});
} else {
throw new Error("Unexpected tag: " + JSON.stringify(schema));
}
}
/**
* Convert value from its typescript representation to representation in aqua
* @param value {JSONValue} the value as represented in typescript
* @param schema {NonArrowSimpleType} - definition of the aqua type
* @returns {JSONValue} represented in aqua
*/
export function ts2aqua(value, schema) {
if (schema.tag === "nil") {
return null;
} else if (schema.tag === "option") {
if (!Array.isArray(value)) {
throw new Error("Bad schema");
}
return value === null ? [] : [ts2aqua(value, schema.type)];
} else if (
schema.tag === "scalar" ||
schema.tag === "bottomType" ||
schema.tag === "topType"
) {
return value;
} else if (schema.tag === "array") {
if (!Array.isArray(value)) {
throw new Error("Bad schema");
}
return value.map((y) => {
return ts2aqua(y, schema.type);
});
} else if (schema.tag === "unlabeledProduct") {
if (!Array.isArray(value)) {
throw new Error("Bad schema");
}
return value.map((y, i) => {
return ts2aqua(y, schema.items[i]);
});
} else if (schema.tag === "struct" || schema.tag === "labeledProduct") {
if (typeof value !== "object" || value == null || Array.isArray(value)) {
throw new Error("Bad schema");
}
return Object.entries(schema.fields).reduce((agg, [key, type]) => {
const val = ts2aqua(value[key], type);
return { ...agg, [key]: val };
}, {});
} else {
throw new Error("Unexpected tag: " + JSON.stringify(schema));
}
}
// Services
export function registerSrv(...args) {
const service = args.pop();
const defaultServiceId = "single_module_srv";
const params = args[0] instanceof FluencePeer$$ ? ({
peer: args[0],
serviceId: args[1] ?? defaultServiceId
}) : ({
peer: undefined,
serviceId: args[0] ?? defaultServiceId
});
if (params.serviceId == null) {
throw new Error("Service ID is not provided");
}
registerService$$({
service,
...params
});
}
export function registerCalcService(...args) {
const service = args.pop();
const defaultServiceId = undefined;
const params = args[0] instanceof FluencePeer$$ ? ({
peer: args[0],
serviceId: args[1] ?? defaultServiceId
}) : ({
peer: undefined,
serviceId: args[0] ?? defaultServiceId
});
if (params.serviceId == null) {
throw new Error("Service ID is not provided");
}
registerService$$({
service,
...params
});
}
export function registerHelloWorld(...args) {
const service = args.pop();
const defaultServiceId = "hello-world";
const params = args[0] instanceof FluencePeer$$ ? ({
peer: args[0],
serviceId: args[1] ?? defaultServiceId
}) : ({
peer: undefined,
serviceId: args[0] ?? defaultServiceId
});
if (params.serviceId == null) {
throw new Error("Service ID is not provided");
}
registerService$$({
service,
...params
});
}
// Functions
export const resourceTest_script = `
(seq
(seq
(seq
(seq
(call %init_peer_id% ("getDataSrv" "-relay-") [] -relay-)
(call %init_peer_id% ("getDataSrv" "label") [] label)
)
(xor
(new $resource_id
(seq
(seq
(seq
(call %init_peer_id% ("peer" "timestamp_sec") [] t)
(xor
(seq
(seq
(call -relay- ("registry" "get_key_bytes") [label [] t [] ""] bytes)
(xor
(call %init_peer_id% ("sig" "sign") [bytes] result)
(fail %last_error%)
)
)
(xor
(match result.$.success false
(ap result.$.error.[0] $error)
)
(new $successful
(seq
(seq
(seq
(seq
(seq
(seq
(ap result.$.signature result_flat)
(call -relay- ("registry" "get_key_id") [label %init_peer_id%] id)
)
(call -relay- ("op" "string_to_b58") [id] k)
)
(call -relay- ("kad" "neighborhood") [k [] []] nodes)
)
(par
(fold nodes n-0
(par
(xor
(xor
(seq
(seq
(seq
(call n-0 ("peer" "timestamp_sec") [] t-0)
(call n-0 ("trust-graph" "get_weight") [%init_peer_id% t-0] weight)
)
(call n-0 ("registry" "register_key") [label [] t [] "" result_flat.$.[0] weight t-0] result-0)
)
(xor
(seq
(match result-0.$.success true
(ap true $successful)
)
(new $-ephemeral-stream-
(new #-ephemeral-canon-
(canon -relay- $-ephemeral-stream- #-ephemeral-canon-)
)
)
)
(seq
(ap result-0.$.error $error)
(new $-ephemeral-stream-
(new #-ephemeral-canon-
(canon -relay- $-ephemeral-stream- #-ephemeral-canon-)
)
)
)
)
)
(null)
)
(fail %last_error%)
)
(next n-0)
)
(never)
)
(null)
)
)
(new $status
(new $result-1
(seq
(seq
(seq
(par
(seq
(seq
(seq
(call -relay- ("math" "sub") [1 1] sub)
(new $successful_test
(seq
(seq
(seq
(call -relay- ("math" "add") [sub 1] successful_incr)
(fold $successful successful_fold_var
(seq
(seq
(ap successful_fold_var $successful_test)
(canon -relay- $successful_test #successful_iter_canon)
)
(xor
(match #successful_iter_canon.length successful_incr
(null)
)
(next successful_fold_var)
)
)
(never)
)
)
(canon -relay- $successful_test #successful_result_canon)
)
(ap #successful_result_canon successful_gate)
)
)
)
(call -relay- ("math" "sub") [1 1] sub-0)
)
(ap "ok" $status)
)
(call -relay- ("peer" "timeout") [6000 "timeout"] $status)
)
(new $status_test
(seq
(seq
(seq
(call -relay- ("math" "add") [0 1] status_incr)
(fold $status status_fold_var
(seq
(seq
(ap status_fold_var $status_test)
(canon -relay- $status_test #status_iter_canon)
)
(xor
(match #status_iter_canon.length status_incr
(null)
)
(next status_fold_var)
)
)
(never)
)
)
(canon -relay- $status_test #status_result_canon)
)
(ap #status_result_canon status_gate)
)
)
)
(xor
(match status_gate.$.[0] "ok"
(ap true $result-1)
)
(ap false $result-1)
)
)
(new $result-1_test
(seq
(seq
(seq
(call -relay- ("math" "add") [0 1] result-1_incr)
(fold $result-1 result-1_fold_var
(seq
(seq
(ap result-1_fold_var $result-1_test)
(canon -relay- $result-1_test #result-1_iter_canon)
)
(xor
(match #result-1_iter_canon.length result-1_incr
(null)
)
(next result-1_fold_var)
)
)
(never)
)
)
(canon -relay- $result-1_test #result-1_result_canon)
)
(ap #result-1_result_canon result-1_gate)
)
)
)
)
)
)
(xor
(match result-1_gate.$.[0] false
(ap "resource wasn't created: timeout exceeded" $error)
)
(ap id $resource_id)
)
)
)
)
)
(fail %last_error%)
)
)
(canon %init_peer_id% $resource_id #-resource_id-fix-0)
)
(ap #-resource_id-fix-0 -resource_id-flat-0)
)
)
(call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 0])
)
)
(canon %init_peer_id% $error #error_canon)
)
(call %init_peer_id% ("callbackSrv" "response") [-resource_id-flat-0 #error_canon])
)
`;
export async function resourceTest(...args) {
const argNames = ["label"];
const argCount = argNames.length;
let peer = undefined;
if (args[0] instanceof FluencePeer$$) {
peer = args[0];
args = args.slice(1);
}
const callArgs = Object.fromEntries(args.slice(0, argCount).map((arg, i) => [argNames[i], arg]));
const params = ({
peer,
args: callArgs,
config: args[argCount]
});
const result = await callFunction$$({
script: resourceTest_script,
...params,
});
return aqua2ts(result,
{
"items": [
{
"type": {
"name": "string",
"tag": "scalar"
},
"tag": "option"
},
{
"type": {
"name": "string",
"tag": "scalar"
},
"tag": "array"
}
],
"tag": "unlabeledProduct"
}
);
}
export const helloTest_script = `
(seq
(seq
(call %init_peer_id% ("getDataSrv" "-relay-") [] -relay-)
(xor
(call %init_peer_id% ("hello-world" "hello") ["Fluence user"] hello)
(call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 0])
)
)
(call %init_peer_id% ("callbackSrv" "response") [hello])
)
`;
export async function helloTest(...args) {
const argNames = [];
const argCount = argNames.length;
let peer = undefined;
if (args[0] instanceof FluencePeer$$) {
peer = args[0];
args = args.slice(1);
}
const callArgs = Object.fromEntries(args.slice(0, argCount).map((arg, i) => [argNames[i], arg]));
const params = ({
peer,
args: callArgs,
config: args[argCount]
});
const result = await callFunction$$({
script: helloTest_script,
...params,
});
return aqua2ts(result,
{
"name": "string",
"tag": "scalar"
}
);
}
export const demo_calculation_script = `
(seq
(seq
(seq
(call %init_peer_id% ("getDataSrv" "-relay-") [] -relay-)
(call %init_peer_id% ("getDataSrv" "service_id") [] service_id)
)
(xor
(seq
(seq
(seq
(seq
(seq
(call %init_peer_id% (service_id "test_logs") [])
(call %init_peer_id% (service_id "add") [10])
)
(call %init_peer_id% (service_id "multiply") [5])
)
(call %init_peer_id% (service_id "subtract") [8])
)
(call %init_peer_id% (service_id "divide") [6])
)
(call %init_peer_id% (service_id "state") [] res)
)
(call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 0])
)
)
(call %init_peer_id% ("callbackSrv" "response") [res])
)
`;
export async function demo_calculation(...args) {
const argNames = ["service_id"];
const argCount = argNames.length;
let peer = undefined;
if (args[0] instanceof FluencePeer$$) {
peer = args[0];
args = args.slice(1);
}
const callArgs = Object.fromEntries(args.slice(0, argCount).map((arg, i) => [argNames[i], arg]));
const params = ({
peer,
args: callArgs,
config: args[argCount]
});
const result = await callFunction$$({
script: demo_calculation_script,
...params,
});
return aqua2ts(result,
{
"name": "f64",
"tag": "scalar"
}
);
}
export const marineTest_script = `
(seq
(seq
(seq
(call %init_peer_id% ("getDataSrv" "-relay-") [] -relay-)
(call %init_peer_id% ("getDataSrv" "wasm64") [] wasm64)
)
(xor
(seq
(seq
(seq
(seq
(seq
(seq
(call %init_peer_id% ("single_module_srv" "create") [wasm64] serviceResult)
(call %init_peer_id% (serviceResult.$.service_id.[0] "test_logs") [])
)
(call %init_peer_id% (serviceResult.$.service_id.[0] "add") [10])
)
(call %init_peer_id% (serviceResult.$.service_id.[0] "multiply") [5])
)
(call %init_peer_id% (serviceResult.$.service_id.[0] "subtract") [8])
)
(call %init_peer_id% (serviceResult.$.service_id.[0] "divide") [6])
)
(call %init_peer_id% (serviceResult.$.service_id.[0] "state") [] res)
)
(call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 0])
)
)
(call %init_peer_id% ("callbackSrv" "response") [res])
)
`;
export async function marineTest(...args) {
const argNames = ["wasm64"];
const argCount = argNames.length;
let peer = undefined;
if (args[0] instanceof FluencePeer$$) {
peer = args[0];
args = args.slice(1);
}
const callArgs = Object.fromEntries(args.slice(0, argCount).map((arg, i) => [argNames[i], arg]));
const params = ({
peer,
args: callArgs,
config: args[argCount]
});
const result = await callFunction$$({
script: marineTest_script,
...params,
});
return aqua2ts(result,
{
"name": "f64",
"tag": "scalar"
}
);
}

View File

@ -0,0 +1,707 @@
/* eslint-disable */
// @ts-nocheck
/**
*
* This file is generated using:
* @fluencelabs/aqua-api version: 0.0.0
* @fluencelabs/aqua-to-js version: 0.0.0
* If you find any bugs in generated AIR, please write an issue on GitHub: https://github.com/fluencelabs/aqua/issues
* If you find any bugs in generated JS/TS, please write an issue on GitHub: https://github.com/fluencelabs/js-client/issues
*
*/
import type { IFluenceClient as IFluenceClient$$, ParticleContext as ParticleContext$$ } from '@fluencelabs/js-client';
import {
v5_callFunction as callFunction$$,
v5_registerService as registerService$$,
FluencePeer as FluencePeer$$
} from '@fluencelabs/js-client';
/**
* @typedef {import("@fluencelabs/js-client").NonArrowSimpleType} NonArrowSimpleType
* @typedef {import("@fluencelabs/js-client").JSONValue} JSONValue
*/
/**
* Convert value from its representation in aqua language to representation in typescript
* @param {JSONValue} value - value as represented in aqua
* @param {NonArrowSimpleType} schema - definition of the aqua schema
* @returns {JSONValue} value represented in typescript
*/
export function aqua2ts(value, schema) {
if (schema.tag === "nil") {
return null;
} else if (schema.tag === "option") {
if (!Array.isArray(value)) {
throw new Error("Bad schema");
}
if (value.length === 0) {
return null;
} else {
return aqua2ts(value[0], schema.type);
}
} else if (
schema.tag === "scalar" ||
schema.tag === "bottomType" ||
schema.tag === "topType"
) {
return value;
} else if (schema.tag === "array") {
if (!Array.isArray(value)) {
throw new Error("Bad schema");
}
return value.map((y) => {
return aqua2ts(y, schema.type);
});
} else if (schema.tag === "unlabeledProduct") {
if (!Array.isArray(value)) {
throw new Error("Bad schema");
}
return value.map((y, i) => {
return aqua2ts(y, schema.items[i]);
});
} else if (schema.tag === "struct" || schema.tag === "labeledProduct") {
if (typeof value !== "object" || value == null || Array.isArray(value)) {
throw new Error("Bad schema");
}
return Object.entries(schema.fields).reduce((agg, [key, type]) => {
const val = aqua2ts(value[key], type);
return { ...agg, [key]: val };
}, {});
} else {
throw new Error("Unexpected tag: " + JSON.stringify(schema));
}
}
/**
* Convert value from its typescript representation to representation in aqua
* @param value {JSONValue} the value as represented in typescript
* @param schema {NonArrowSimpleType} - definition of the aqua type
* @returns {JSONValue} represented in aqua
*/
export function ts2aqua(value, schema) {
if (schema.tag === "nil") {
return null;
} else if (schema.tag === "option") {
if (!Array.isArray(value)) {
throw new Error("Bad schema");
}
return value === null ? [] : [ts2aqua(value, schema.type)];
} else if (
schema.tag === "scalar" ||
schema.tag === "bottomType" ||
schema.tag === "topType"
) {
return value;
} else if (schema.tag === "array") {
if (!Array.isArray(value)) {
throw new Error("Bad schema");
}
return value.map((y) => {
return ts2aqua(y, schema.type);
});
} else if (schema.tag === "unlabeledProduct") {
if (!Array.isArray(value)) {
throw new Error("Bad schema");
}
return value.map((y, i) => {
return ts2aqua(y, schema.items[i]);
});
} else if (schema.tag === "struct" || schema.tag === "labeledProduct") {
if (typeof value !== "object" || value == null || Array.isArray(value)) {
throw new Error("Bad schema");
}
return Object.entries(schema.fields).reduce((agg, [key, type]) => {
const val = ts2aqua(value[key], type);
return { ...agg, [key]: val };
}, {});
} else {
throw new Error("Unexpected tag: " + JSON.stringify(schema));
}
}
// Services
export interface SrvDef {
create: (wasm_b64_content: string, callParams: ParticleContext$$) => { error: string | null; service_id: string | null; success: boolean; } | Promise<{ error: string | null; service_id: string | null; success: boolean; }>;
list: (callParams: ParticleContext$$) => string[] | Promise<string[]>;
remove: (service_id: string, callParams: ParticleContext$$) => { error: string | null; success: boolean; } | Promise<{ error: string | null; success: boolean; }>;
}
export function registerSrv(service: SrvDef): void;
export function registerSrv(serviceId: string, service: SrvDef): void;
export function registerSrv(peer: IFluenceClient$$, service: SrvDef): void;
export function registerSrv(peer: IFluenceClient$$, serviceId: string, service: SrvDef): void;
export function registerSrv(...args: any[]) {
const service = args.pop();
const defaultServiceId = "single_module_srv";
const params = args[0] instanceof FluencePeer$$ ? ({
peer: args[0],
serviceId: args[1] ?? defaultServiceId
}) : ({
peer: undefined,
serviceId: args[0] ?? defaultServiceId
});
if (params.serviceId == null) {
throw new Error("Service ID is not provided");
}
registerService$$({
service,
...params
});
}
export interface CalcServiceDef {
add: (num: number, callParams: ParticleContext$$) => number | Promise<number>;
clear_state: (callParams: ParticleContext$$) => void | Promise<void>;
divide: (num: number, callParams: ParticleContext$$) => number | Promise<number>;
multiply: (num: number, callParams: ParticleContext$$) => number | Promise<number>;
state: (callParams: ParticleContext$$) => number | Promise<number>;
subtract: (num: number, callParams: ParticleContext$$) => number | Promise<number>;
test_logs: (callParams: ParticleContext$$) => void | Promise<void>;
}
export function registerCalcService(serviceId: string, service: CalcServiceDef): void;
export function registerCalcService(peer: IFluenceClient$$, serviceId: string, service: CalcServiceDef): void;
export function registerCalcService(...args: any[]) {
const service = args.pop();
const defaultServiceId = undefined;
const params = args[0] instanceof FluencePeer$$ ? ({
peer: args[0],
serviceId: args[1] ?? defaultServiceId
}) : ({
peer: undefined,
serviceId: args[0] ?? defaultServiceId
});
if (params.serviceId == null) {
throw new Error("Service ID is not provided");
}
registerService$$({
service,
...params
});
}
export interface HelloWorldDef {
hello: (str: string, callParams: ParticleContext$$) => string | Promise<string>;
}
export function registerHelloWorld(service: HelloWorldDef): void;
export function registerHelloWorld(serviceId: string, service: HelloWorldDef): void;
export function registerHelloWorld(peer: IFluenceClient$$, service: HelloWorldDef): void;
export function registerHelloWorld(peer: IFluenceClient$$, serviceId: string, service: HelloWorldDef): void;
export function registerHelloWorld(...args: any[]) {
const service = args.pop();
const defaultServiceId = "hello-world";
const params = args[0] instanceof FluencePeer$$ ? ({
peer: args[0],
serviceId: args[1] ?? defaultServiceId
}) : ({
peer: undefined,
serviceId: args[0] ?? defaultServiceId
});
if (params.serviceId == null) {
throw new Error("Service ID is not provided");
}
registerService$$({
service,
...params
});
}
// Functions
export const resourceTest_script = `
(seq
(seq
(seq
(seq
(call %init_peer_id% ("getDataSrv" "-relay-") [] -relay-)
(call %init_peer_id% ("getDataSrv" "label") [] label)
)
(xor
(new $resource_id
(seq
(seq
(seq
(call %init_peer_id% ("peer" "timestamp_sec") [] t)
(xor
(seq
(seq
(call -relay- ("registry" "get_key_bytes") [label [] t [] ""] bytes)
(xor
(call %init_peer_id% ("sig" "sign") [bytes] result)
(fail %last_error%)
)
)
(xor
(match result.$.success false
(ap result.$.error.[0] $error)
)
(new $successful
(seq
(seq
(seq
(seq
(seq
(seq
(ap result.$.signature result_flat)
(call -relay- ("registry" "get_key_id") [label %init_peer_id%] id)
)
(call -relay- ("op" "string_to_b58") [id] k)
)
(call -relay- ("kad" "neighborhood") [k [] []] nodes)
)
(par
(fold nodes n-0
(par
(xor
(xor
(seq
(seq
(seq
(call n-0 ("peer" "timestamp_sec") [] t-0)
(call n-0 ("trust-graph" "get_weight") [%init_peer_id% t-0] weight)
)
(call n-0 ("registry" "register_key") [label [] t [] "" result_flat.$.[0] weight t-0] result-0)
)
(xor
(seq
(match result-0.$.success true
(ap true $successful)
)
(new $-ephemeral-stream-
(new #-ephemeral-canon-
(canon -relay- $-ephemeral-stream- #-ephemeral-canon-)
)
)
)
(seq
(ap result-0.$.error $error)
(new $-ephemeral-stream-
(new #-ephemeral-canon-
(canon -relay- $-ephemeral-stream- #-ephemeral-canon-)
)
)
)
)
)
(null)
)
(fail %last_error%)
)
(next n-0)
)
(never)
)
(null)
)
)
(new $status
(new $result-1
(seq
(seq
(seq
(par
(seq
(seq
(seq
(call -relay- ("math" "sub") [1 1] sub)
(new $successful_test
(seq
(seq
(seq
(call -relay- ("math" "add") [sub 1] successful_incr)
(fold $successful successful_fold_var
(seq
(seq
(ap successful_fold_var $successful_test)
(canon -relay- $successful_test #successful_iter_canon)
)
(xor
(match #successful_iter_canon.length successful_incr
(null)
)
(next successful_fold_var)
)
)
(never)
)
)
(canon -relay- $successful_test #successful_result_canon)
)
(ap #successful_result_canon successful_gate)
)
)
)
(call -relay- ("math" "sub") [1 1] sub-0)
)
(ap "ok" $status)
)
(call -relay- ("peer" "timeout") [6000 "timeout"] $status)
)
(new $status_test
(seq
(seq
(seq
(call -relay- ("math" "add") [0 1] status_incr)
(fold $status status_fold_var
(seq
(seq
(ap status_fold_var $status_test)
(canon -relay- $status_test #status_iter_canon)
)
(xor
(match #status_iter_canon.length status_incr
(null)
)
(next status_fold_var)
)
)
(never)
)
)
(canon -relay- $status_test #status_result_canon)
)
(ap #status_result_canon status_gate)
)
)
)
(xor
(match status_gate.$.[0] "ok"
(ap true $result-1)
)
(ap false $result-1)
)
)
(new $result-1_test
(seq
(seq
(seq
(call -relay- ("math" "add") [0 1] result-1_incr)
(fold $result-1 result-1_fold_var
(seq
(seq
(ap result-1_fold_var $result-1_test)
(canon -relay- $result-1_test #result-1_iter_canon)
)
(xor
(match #result-1_iter_canon.length result-1_incr
(null)
)
(next result-1_fold_var)
)
)
(never)
)
)
(canon -relay- $result-1_test #result-1_result_canon)
)
(ap #result-1_result_canon result-1_gate)
)
)
)
)
)
)
(xor
(match result-1_gate.$.[0] false
(ap "resource wasn't created: timeout exceeded" $error)
)
(ap id $resource_id)
)
)
)
)
)
(fail %last_error%)
)
)
(canon %init_peer_id% $resource_id #-resource_id-fix-0)
)
(ap #-resource_id-fix-0 -resource_id-flat-0)
)
)
(call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 0])
)
)
(canon %init_peer_id% $error #error_canon)
)
(call %init_peer_id% ("callbackSrv" "response") [-resource_id-flat-0 #error_canon])
)
`;
export type ResourceTestResult = [string | null, string[]]
export function resourceTest(
label: string,
config?: {ttl?: number}
): Promise<ResourceTestResult>;
export function resourceTest(
peer: IFluenceClient$$,
label: string,
config?: {ttl?: number}
): Promise<ResourceTestResult>;
export async function resourceTest(...args: any[]) {
const argNames = ["label"];
const argCount = argNames.length;
let peer = undefined;
if (args[0] instanceof FluencePeer$$) {
peer = args[0];
args = args.slice(1);
}
const callArgs = Object.fromEntries(args.slice(0, argCount).map((arg, i) => [argNames[i], arg]));
const params = ({
peer,
args: callArgs,
config: args[argCount]
});
const result = await callFunction$$({
script: resourceTest_script,
...params,
});
return aqua2ts(result,
{
"items": [
{
"type": {
"name": "string",
"tag": "scalar"
},
"tag": "option"
},
{
"type": {
"name": "string",
"tag": "scalar"
},
"tag": "array"
}
],
"tag": "unlabeledProduct"
}
);
}
export const helloTest_script = `
(seq
(seq
(call %init_peer_id% ("getDataSrv" "-relay-") [] -relay-)
(xor
(call %init_peer_id% ("hello-world" "hello") ["Fluence user"] hello)
(call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 0])
)
)
(call %init_peer_id% ("callbackSrv" "response") [hello])
)
`;
export function helloTest(
config?: {ttl?: number}
): Promise<string>;
export function helloTest(
peer: IFluenceClient$$,
config?: {ttl?: number}
): Promise<string>;
export async function helloTest(...args: any[]) {
const argNames = [];
const argCount = argNames.length;
let peer = undefined;
if (args[0] instanceof FluencePeer$$) {
peer = args[0];
args = args.slice(1);
}
const callArgs = Object.fromEntries(args.slice(0, argCount).map((arg, i) => [argNames[i], arg]));
const params = ({
peer,
args: callArgs,
config: args[argCount]
});
const result = await callFunction$$({
script: helloTest_script,
...params,
});
return aqua2ts(result,
{
"name": "string",
"tag": "scalar"
}
);
}
export const demo_calculation_script = `
(seq
(seq
(seq
(call %init_peer_id% ("getDataSrv" "-relay-") [] -relay-)
(call %init_peer_id% ("getDataSrv" "service_id") [] service_id)
)
(xor
(seq
(seq
(seq
(seq
(seq
(call %init_peer_id% (service_id "test_logs") [])
(call %init_peer_id% (service_id "add") [10])
)
(call %init_peer_id% (service_id "multiply") [5])
)
(call %init_peer_id% (service_id "subtract") [8])
)
(call %init_peer_id% (service_id "divide") [6])
)
(call %init_peer_id% (service_id "state") [] res)
)
(call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 0])
)
)
(call %init_peer_id% ("callbackSrv" "response") [res])
)
`;
export function demo_calculation(
service_id: string,
config?: {ttl?: number}
): Promise<number>;
export function demo_calculation(
peer: IFluenceClient$$,
service_id: string,
config?: {ttl?: number}
): Promise<number>;
export async function demo_calculation(...args: any[]) {
const argNames = ["service_id"];
const argCount = argNames.length;
let peer = undefined;
if (args[0] instanceof FluencePeer$$) {
peer = args[0];
args = args.slice(1);
}
const callArgs = Object.fromEntries(args.slice(0, argCount).map((arg, i) => [argNames[i], arg]));
const params = ({
peer,
args: callArgs,
config: args[argCount]
});
const result = await callFunction$$({
script: demo_calculation_script,
...params,
});
return aqua2ts(result,
{
"name": "f64",
"tag": "scalar"
}
);
}
export const marineTest_script = `
(seq
(seq
(seq
(call %init_peer_id% ("getDataSrv" "-relay-") [] -relay-)
(call %init_peer_id% ("getDataSrv" "wasm64") [] wasm64)
)
(xor
(seq
(seq
(seq
(seq
(seq
(seq
(call %init_peer_id% ("single_module_srv" "create") [wasm64] serviceResult)
(call %init_peer_id% (serviceResult.$.service_id.[0] "test_logs") [])
)
(call %init_peer_id% (serviceResult.$.service_id.[0] "add") [10])
)
(call %init_peer_id% (serviceResult.$.service_id.[0] "multiply") [5])
)
(call %init_peer_id% (serviceResult.$.service_id.[0] "subtract") [8])
)
(call %init_peer_id% (serviceResult.$.service_id.[0] "divide") [6])
)
(call %init_peer_id% (serviceResult.$.service_id.[0] "state") [] res)
)
(call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 0])
)
)
(call %init_peer_id% ("callbackSrv" "response") [res])
)
`;
export function marineTest(
wasm64: string,
config?: {ttl?: number}
): Promise<number>;
export function marineTest(
peer: IFluenceClient$$,
wasm64: string,
config?: {ttl?: number}
): Promise<number>;
export async function marineTest(...args: any[]) {
const argNames = ["wasm64"];
const argCount = argNames.length;
let peer = undefined;
if (args[0] instanceof FluencePeer$$) {
peer = args[0];
args = args.slice(1);
}
const callArgs = Object.fromEntries(args.slice(0, argCount).map((arg, i) => [argNames[i], arg]));
const params = ({
peer,
args: callArgs,
config: args[argCount]
});
const result = await callFunction$$({
script: marineTest_script,
...params,
});
return aqua2ts(result,
{
"name": "f64",
"tag": "scalar"
}
);
}

View File

@ -14,46 +14,55 @@
* limitations under the License. * limitations under the License.
*/ */
import url from "url"; import { fileURLToPath } from "url";
import { compileFromPath } from "@fluencelabs/aqua-api"; import { compileFromPath } from "@fluencelabs/aqua-api";
import { describe, expect, it } from "vitest"; import { beforeAll, describe, expect, it } from "vitest";
import { getPackageJsonContent, PackageJson } from "../../utils.js"; import { getPackageJsonContent, PackageJson } from "../../utils.js";
import { generateTypes, generateSources } from "../index.js"; import { generateTypes, generateSources } from "../index.js";
import { CompilationResult } from "../interfaces.js";
let res: Omit<CompilationResult, "funcCall">;
let pkg: PackageJson;
describe("Aqua to js/ts compiler", () => { describe("Aqua to js/ts compiler", () => {
it("compiles smoke tests successfully", async () => { beforeAll(async () => {
const res = await compileFromPath({ res = await compileFromPath({
filePath: url.fileURLToPath( filePath: fileURLToPath(
new URL("./sources/smoke_test.aqua", import.meta.url), new URL("./sources/smoke_test.aqua", import.meta.url),
), ),
imports: ["./node_modules"], imports: ["./node_modules"],
targetType: "air", targetType: "air",
}); });
const pkg: PackageJson = { pkg = {
...(await getPackageJsonContent()), ...(await getPackageJsonContent()),
version: "0.0.0", version: "0.0.0",
devDependencies: { devDependencies: {
"@fluencelabs/aqua-api": "0.0.0", "@fluencelabs/aqua-api": "0.0.0",
}, },
}; };
});
// TODO: see https://github.com/fluencelabs/js-client/pull/366#discussion_r1370567711 it("matches js snapshot", async () => {
// @ts-expect-error don't use compileFromPath directly here
const jsResult = generateSources(res, "js", pkg); const jsResult = generateSources(res, "js", pkg);
// TODO: see https://github.com/fluencelabs/js-client/pull/366#discussion_r1370567711
// @ts-expect-error don't use compileFromPath directly here
const jsTypes = generateTypes(res, pkg); const jsTypes = generateTypes(res, pkg);
expect(jsResult).toMatchSnapshot(); await expect(jsResult).toMatchFileSnapshot(
expect(jsTypes).toMatchSnapshot(); "./__snapshots__/generate.snap.js",
);
// TODO: see https://github.com/fluencelabs/js-client/pull/366#discussion_r1370567711 await expect(jsTypes).toMatchFileSnapshot(
// @ts-expect-error don't use compileFromPath directly here "./__snapshots__/generate.snap.d.ts",
);
});
it("matches ts snapshot", async () => {
const tsResult = generateSources(res, "ts", pkg); const tsResult = generateSources(res, "ts", pkg);
expect(tsResult).toMatchSnapshot(); await expect(tsResult).toMatchFileSnapshot(
"./__snapshots__/generate.snap.ts",
);
}); });
}); });

View File

@ -0,0 +1,110 @@
/**
* @typedef {import("@fluencelabs/js-client").NonArrowSimpleType} NonArrowSimpleType
* @typedef {import("@fluencelabs/js-client").JSONValue} JSONValue
*/
/**
* Convert value from its representation in aqua language to representation in typescript
* @param {JSONValue} value - value as represented in aqua
* @param {NonArrowSimpleType} schema - definition of the aqua schema
* @returns {JSONValue} value represented in typescript
*/
export function aqua2ts(value, schema) {
if (schema.tag === "nil") {
return null;
} else if (schema.tag === "option") {
if (!Array.isArray(value)) {
throw new Error("Bad schema");
}
if (value.length === 0) {
return null;
} else {
return aqua2ts(value[0], schema.type);
}
} else if (
schema.tag === "scalar" ||
schema.tag === "bottomType" ||
schema.tag === "topType"
) {
return value;
} else if (schema.tag === "array") {
if (!Array.isArray(value)) {
throw new Error("Bad schema");
}
return value.map((y) => {
return aqua2ts(y, schema.type);
});
} else if (schema.tag === "unlabeledProduct") {
if (!Array.isArray(value)) {
throw new Error("Bad schema");
}
return value.map((y, i) => {
return aqua2ts(y, schema.items[i]);
});
} else if (schema.tag === "struct" || schema.tag === "labeledProduct") {
if (typeof value !== "object" || value == null || Array.isArray(value)) {
throw new Error("Bad schema");
}
return Object.entries(schema.fields).reduce((agg, [key, type]) => {
const val = aqua2ts(value[key], type);
return { ...agg, [key]: val };
}, {});
} else {
throw new Error("Unexpected tag: " + JSON.stringify(schema));
}
}
/**
* Convert value from its typescript representation to representation in aqua
* @param value {JSONValue} the value as represented in typescript
* @param schema {NonArrowSimpleType} - definition of the aqua type
* @returns {JSONValue} represented in aqua
*/
export function ts2aqua(value, schema) {
if (schema.tag === "nil") {
return null;
} else if (schema.tag === "option") {
if (!Array.isArray(value)) {
throw new Error("Bad schema");
}
return value === null ? [] : [ts2aqua(value, schema.type)];
} else if (
schema.tag === "scalar" ||
schema.tag === "bottomType" ||
schema.tag === "topType"
) {
return value;
} else if (schema.tag === "array") {
if (!Array.isArray(value)) {
throw new Error("Bad schema");
}
return value.map((y) => {
return ts2aqua(y, schema.type);
});
} else if (schema.tag === "unlabeledProduct") {
if (!Array.isArray(value)) {
throw new Error("Bad schema");
}
return value.map((y, i) => {
return ts2aqua(y, schema.items[i]);
});
} else if (schema.tag === "struct" || schema.tag === "labeledProduct") {
if (typeof value !== "object" || value == null || Array.isArray(value)) {
throw new Error("Bad schema");
}
return Object.entries(schema.fields).reduce((agg, [key, type]) => {
const val = ts2aqua(value[key], type);
return { ...agg, [key]: val };
}, {});
} else {
throw new Error("Unexpected tag: " + JSON.stringify(schema));
}
}

View File

@ -29,23 +29,60 @@ export function generateFunctions(
.join("\n\n"); .join("\n\n");
} }
type DeepToType<T> = { [K in keyof T]: DeepToType<T[K]> };
function generateFunction(typeGenerator: TypeGenerator, func: AquaFunction) { function generateFunction(typeGenerator: TypeGenerator, func: AquaFunction) {
const funcDef: DeepToType<typeof func.funcDef> = func.funcDef;
const scriptConstName = func.funcDef.functionName + "_script"; const scriptConstName = func.funcDef.functionName + "_script";
const codomain = func.funcDef.arrow.codomain;
const valueSchema =
codomain.tag === "unlabeledProduct" && codomain.items.length === 1
? codomain.items[0]
: codomain;
const valueSchemaString = JSON.stringify(
recursiveRenameLaquaProps(valueSchema),
null,
4,
);
const domain = func.funcDef.arrow.domain;
const argNames = domain.tag === "nil" ? [] : Object.keys(domain.fields);
return `export const ${scriptConstName} = \` return `export const ${scriptConstName} = \`
${func.script}\`; ${func.script}\`;
${typeGenerator.funcType(func)} ${typeGenerator.funcType(func)}
export function ${func.funcDef.functionName}(${typeGenerator.type( export async function ${func.funcDef.functionName}(${typeGenerator.type(
"...args", "...args",
"any[]", "any[]",
)}) { )}) {
return callFunction$$( const argNames = [${argNames
args, .map((arg) => {
${JSON.stringify(recursiveRenameLaquaProps(funcDef), null, 4)}, return `"${arg}"`;
${scriptConstName} })
); .join(", ")}];
const argCount = argNames.length;
let peer = undefined;
if (args[0] instanceof FluencePeer$$) {
peer = args[0];
args = args.slice(1);
}
const callArgs = Object.fromEntries(args.slice(0, argCount).map((arg, i) => [argNames[i], arg]));
const params = ({
peer,
args: callArgs,
config: args[argCount]
});
const result = await callFunction$$({
script: ${scriptConstName},
...params,
});
return aqua2ts(result,
${valueSchemaString}
);
}`; }`;
} }

View File

@ -14,10 +14,12 @@
* limitations under the License. * limitations under the License.
*/ */
import { PackageJson } from "../utils.js"; import { includeRelative, PackageJson } from "../utils.js";
import { OutputType } from "./interfaces.js"; import { OutputType } from "./interfaces.js";
const converters = await includeRelative(import.meta.url, "./converters.js");
export default function generateHeader( export default function generateHeader(
{ version, devDependencies }: PackageJson, { version, devDependencies }: PackageJson,
outputType: OutputType, outputType: OutputType,
@ -35,12 +37,15 @@ export default function generateHeader(
*/ */
${ ${
outputType === "ts" outputType === "ts"
? "import type { IFluenceClient as IFluenceClient$$, CallParams as CallParams$$ } from '@fluencelabs/js-client';" ? "import type { IFluenceClient as IFluenceClient$$, ParticleContext as ParticleContext$$ } from '@fluencelabs/js-client';"
: "" : ""
} }
import { import {
v5_callFunction as callFunction$$, v5_callFunction as callFunction$$,
v5_registerService as registerService$$, v5_registerService as registerService$$,
} from '@fluencelabs/js-client';`; FluencePeer as FluencePeer$$
} from '@fluencelabs/js-client';
${converters}`;
} }

View File

@ -16,8 +16,6 @@
import { ServiceDef } from "@fluencelabs/interfaces"; import { ServiceDef } from "@fluencelabs/interfaces";
import { recursiveRenameLaquaProps } from "../utils.js";
import { TypeGenerator } from "./interfaces.js"; import { TypeGenerator } from "./interfaces.js";
export interface DefaultServiceId { export interface DefaultServiceId {
@ -42,46 +40,45 @@ function generateService(
srvName: string, srvName: string,
srvDef: ServiceDef, srvDef: ServiceDef,
) { ) {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
const defaultServiceId = (srvDef.defaultServiceId as DefaultServiceId)
.s_Some__f_value;
return [ return [
typeGenerator.serviceType(srvName, srvDef), typeGenerator.serviceType(srvName, srvDef),
generateRegisterServiceOverload(typeGenerator, srvName, srvDef), generateRegisterServiceOverload(typeGenerator, srvName, defaultServiceId),
].join("\n"); ].join("\n");
} }
function generateRegisterServiceOverload( function generateRegisterServiceOverload(
typeGenerator: TypeGenerator, typeGenerator: TypeGenerator,
srvName: string, srvName: string,
srvDef: ServiceDef, srvDefaultId?: string,
) { ) {
return [ return `export function register${srvName}(${typeGenerator.type(
`export function register${srvName}(${typeGenerator.type( "...args",
"...args", "any[]",
"any[]", )}) {
)}) {`, const service = args.pop();
" registerService$$(", const defaultServiceId = ${
" args,", srvDefaultId != null ? `"${srvDefaultId}"` : "undefined"
` ${serviceToJson(srvDef)}`, };
" );",
"}", const params = args[0] instanceof FluencePeer$$ ? ({
].join("\n"); peer: args[0],
} serviceId: args[1] ?? defaultServiceId
}) : ({
function serviceToJson(service: ServiceDef): string { peer: undefined,
return JSON.stringify( serviceId: args[0] ?? defaultServiceId
{ });
// This assertion is required because aqua-api gives bad types
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions if (params.serviceId == null) {
...((service.defaultServiceId as DefaultServiceId).s_Some__f_value != null throw new Error("Service ID is not provided");
? { }
defaultServiceId:
// This assertion is required because aqua-api gives bad types registerService$$({
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions service,
(service.defaultServiceId as DefaultServiceId).s_Some__f_value, ...params
} });
: {}), }`;
functions: recursiveRenameLaquaProps(service.functions),
},
null,
4,
);
} }

View File

@ -16,7 +16,8 @@
import assert from "assert"; import assert from "assert";
import { readFile } from "fs/promises"; import { readFile } from "fs/promises";
import path from "path"; import { join } from "path";
import { fileURLToPath } from "url";
import { import {
ArrowType, ArrowType,
@ -38,7 +39,7 @@ export interface PackageJson {
export async function getPackageJsonContent(): Promise<PackageJson> { export async function getPackageJsonContent(): Promise<PackageJson> {
const content = await readFile( const content = await readFile(
new URL(path.join("..", "package.json"), import.meta.url), new URL(join("..", "package.json"), import.meta.url),
"utf-8", "utf-8",
); );
@ -105,3 +106,8 @@ export function recursiveRenameLaquaProps(obj: JSONValue): unknown {
export function capitalize(str: string) { export function capitalize(str: string) {
return str.slice(0, 1).toUpperCase() + str.slice(1); return str.slice(0, 1).toUpperCase() + str.slice(1);
} }
export async function includeRelative(url: string, file: string) {
const pathToFile = join(fileURLToPath(url), "..", file);
return await readFile(pathToFile, "utf-8");
}

View File

@ -25,6 +25,11 @@ export type SimpleTypes =
export type NonArrowType = SimpleTypes | ProductType; export type NonArrowType = SimpleTypes | ProductType;
export type NonArrowSimpleType =
| SimpleTypes
| UnlabeledProductType
| LabeledProductType<SimpleTypes>;
export type TopType = { export type TopType = {
/** /**
* Type descriptor. Used for pattern-matching * Type descriptor. Used for pattern-matching
@ -262,34 +267,3 @@ export interface ServiceDef {
| LabeledProductType<ArrowType<LabeledProductType<SimpleTypes>>> | LabeledProductType<ArrowType<LabeledProductType<SimpleTypes>>>
| NilType; | NilType;
} }
/**
* Options to configure Aqua function execution
*/
export interface FnConfig {
/**
* Sets the TTL (time to live) for particle responsible for the function execution
* If the option is not set the default TTL from FluencePeer config is used
*/
ttl?: number;
}
export const getArgumentTypes = (
def: FunctionCallDef,
): {
[key: string]: NonArrowType | ArrowWithoutCallbacks;
} => {
if (def.arrow.domain.tag !== "labeledProduct") {
throw new Error("Should be impossible");
}
return def.arrow.domain.fields;
};
export const isReturnTypeVoid = (def: FunctionCallDef): boolean => {
if (def.arrow.codomain.tag === "nil") {
return true;
}
return def.arrow.codomain.items.length === 0;
};

View File

@ -1,103 +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.
*/
import { JSONValue } from "../commonTypes.js";
import {
FnConfig,
FunctionCallDef,
ServiceDef,
} from "./aquaTypeDefinitions.js";
/**
* Type for callback passed as aqua function argument
*/
export type ArgCallbackFunction = (
...args: JSONValue[]
) => JSONValue | Promise<JSONValue>;
/**
* Arguments passed to Aqua function
*/
export type PassedArgs = { [key: string]: JSONValue | ArgCallbackFunction };
/**
* Arguments for callAquaFunction function
*/
// TODO: move to js-client side
export interface CallAquaFunctionArgs {
/**
* Peer to call the function on
*/
peer: unknown;
/**
* Function definition
*/
def: FunctionCallDef;
/**
* Air script used by the aqua function
*/
script: string;
/**
* Function configuration
*/
config: FnConfig;
/**
* Arguments to pass to the function
*/
args: PassedArgs;
}
/**
* Call a function from Aqua script
*/
export type CallAquaFunctionType = (
args: CallAquaFunctionArgs,
) => Promise<unknown>;
/**
* Arguments for registerService function
*/
export interface RegisterServiceArgs {
/**
* Peer to register the service on
*/
peer: unknown;
/**
* Service definition
*/
def: ServiceDef;
/**
* Service id
*/
serviceId: string | undefined;
/**
* Service implementation
*/
service: unknown;
}
/**
* Register a service defined in Aqua on a Fluence peer
*/
export type RegisterServiceType = (args: RegisterServiceArgs) => void;

View File

@ -15,6 +15,5 @@
*/ */
export * from "./compilerSupport/aquaTypeDefinitions.js"; export * from "./compilerSupport/aquaTypeDefinitions.js";
export * from "./compilerSupport/compilerSupportInterface.js";
export * from "./commonTypes.js"; export * from "./commonTypes.js";
export * from "./future.js"; export * from "./future.js";

View File

@ -14,15 +14,8 @@
* limitations under the License. * limitations under the License.
*/ */
import type { import type { CallAquaFunctionArgs } from "./compilerSupport/callFunction.js";
FnConfig, import { ServiceImpl } from "./compilerSupport/types.js";
FunctionCallDef,
ServiceDef,
PassedArgs,
ServiceImpl,
} from "@fluencelabs/interfaces";
import { getArgumentTypes } from "@fluencelabs/interfaces";
import { FluencePeer } from "./jsPeer/FluencePeer.js"; import { FluencePeer } from "./jsPeer/FluencePeer.js";
import { callAquaFunction, Fluence, registerService } from "./index.js"; import { callAquaFunction, Fluence, registerService } from "./index.js";
@ -33,24 +26,37 @@ export const isFluencePeer = (
return fluencePeerCandidate instanceof FluencePeer; return fluencePeerCandidate instanceof FluencePeer;
}; };
type CallAquaFunctionArgsTuned = Pick<CallAquaFunctionArgs, "args" | "script"> &
Partial<Pick<CallAquaFunctionArgs, "config" | "peer">>;
type RegisterServiceArgs = {
peer?: FluencePeer;
service: ServiceImpl;
serviceId: string;
};
/** /**
* Convenience function to support Aqua `func` generation backend * Convenience function to support Aqua `func` generation backend
* The compiler only need to generate a call the function and provide the corresponding definitions and the air script * The compiler only need to generate a call the function and provide the air script
*
* @param rawFnArgs - raw arguments passed by user to the generated function
* @param def - function definition generated by the Aqua compiler
* @param script - air script with function execution logic generated by the Aqua compiler
*/ */
export const v5_callFunction = async ( export const v5_callFunction = async ({
rawFnArgs: unknown[], config = {},
def: FunctionCallDef, peer,
script: string, args,
): Promise<unknown> => { script,
const { args, client: peer, config } = extractFunctionArgs(rawFnArgs, def); }: CallAquaFunctionArgsTuned): Promise<unknown> => {
if (peer == null) {
if (Fluence.defaultClient == null) {
throw new Error(
"Could not register Aqua service because the client is not initialized. Did you forget to call Fluence.connect()?",
);
}
peer = Fluence.defaultClient;
}
return callAquaFunction({ return callAquaFunction({
args, args,
def,
script, script,
config, config,
peer, peer,
@ -59,138 +65,26 @@ export const v5_callFunction = async (
/** /**
* Convenience function to support Aqua `service` generation backend * Convenience function to support Aqua `service` generation backend
* The compiler only need to generate a call the function and provide the corresponding definitions and the air script * The compiler only need to generate a call the function and provide the air script
* @param args - raw arguments passed by user to the generated function
* TODO: dont forget to add jsdoc for new arg
* @param def - service definition generated by the Aqua compiler
*/ */
export const v5_registerService = (args: unknown[], def: ServiceDef): void => { export const v5_registerService = ({
// TODO: Support this in aqua-to-js package serviceId,
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions service,
const service: ServiceImpl = args.pop() as ServiceImpl; peer,
}: RegisterServiceArgs): void => {
if (peer == null) {
if (Fluence.defaultClient == null) {
throw new Error(
"Could not register Aqua service because the client is not initialized. Did you forget to call Fluence.connect()?",
);
}
const { peer, serviceId } = extractServiceArgs(args, def.defaultServiceId); peer = Fluence.defaultClient;
}
registerService({ registerService({
def,
service, service,
serviceId, serviceId,
peer, peer,
}); });
}; };
function isConfig(arg: unknown): arg is FnConfig {
return typeof arg === "object" && arg !== null;
}
/**
* Arguments could be passed in one these configurations:
* [...actualArgs]
* [peer, ...actualArgs]
* [...actualArgs, config]
* [peer, ...actualArgs, config]
*
* This function select the appropriate configuration and returns
* arguments in a structured way of: { peer, config, args }
*/
function extractFunctionArgs(
args: unknown[],
def: FunctionCallDef,
): {
client: FluencePeer;
config: FnConfig;
args: PassedArgs;
} {
const argumentTypes = getArgumentTypes(def);
const argumentNames = Object.keys(argumentTypes);
const numberOfExpectedArgs = argumentNames.length;
let peer: FluencePeer;
let config: FnConfig;
if (isFluencePeer(args[0])) {
peer = args[0];
args = args.slice(1);
} else {
if (Fluence.defaultClient == null) {
throw new Error(
"Could not register Aqua service because the client is not initialized. Did you forget to call Fluence.connect()?",
);
}
peer = Fluence.defaultClient;
}
const maybeConfig = args[numberOfExpectedArgs];
if (isConfig(maybeConfig)) {
config = maybeConfig;
} else {
config = {};
}
const structuredArgs = args.slice(0, numberOfExpectedArgs);
if (structuredArgs.length !== numberOfExpectedArgs) {
throw new Error(
`Incorrect number of arguments. Expecting ${numberOfExpectedArgs}`,
);
}
const argsRes = argumentNames.reduce((acc, name, index) => {
return { ...acc, [name]: structuredArgs[index] };
}, {});
return {
client: peer,
args: argsRes,
config: config,
};
}
/**
* Arguments could be passed in one these configurations:
* [serviceObject]
* [peer, serviceObject]
* [defaultId, serviceObject]
* [peer, defaultId, serviceObject]
*
* Where serviceObject is the raw object with function definitions passed by user
*
* This function select the appropriate configuration and returns
* arguments in a structured way of: { peer, serviceId, service }
*/
const extractServiceArgs = (
args: unknown[],
defaultServiceId?: string,
): {
peer: FluencePeer;
serviceId: string | undefined;
} => {
let peer: FluencePeer;
let serviceId: string | undefined;
if (isFluencePeer(args[0])) {
peer = args[0];
args = args.slice(1);
} else {
if (Fluence.defaultClient == null) {
throw new Error(
"Could not register Aqua service because the client is not initialized. Did you forget to call Fluence.connect()?",
);
}
peer = Fluence.defaultClient;
}
if (typeof args[0] === "string") {
serviceId = args[0];
} else {
serviceId = defaultServiceId;
}
return {
peer,
serviceId,
};
};

View File

@ -17,7 +17,7 @@
import { JSONValue } from "@fluencelabs/interfaces"; import { JSONValue } from "@fluencelabs/interfaces";
import { it, describe, expect } from "vitest"; import { it, describe, expect } from "vitest";
import { SendError } from "../../jsPeer/errors.js"; import { ExpirationError, SendError } from "../../jsPeer/errors.js";
import { CallServiceData } from "../../jsServiceHost/interfaces.js"; import { CallServiceData } from "../../jsServiceHost/interfaces.js";
import { handleTimeout } from "../../particle/Particle.js"; import { handleTimeout } from "../../particle/Particle.js";
import { registerHandlersHelper, withClient } from "../../util/testUtils.js"; import { registerHandlersHelper, withClient } from "../../util/testUtils.js";
@ -26,6 +26,35 @@ import { checkConnection } from "../checkConnection.js";
import { nodes, RELAY } from "./connection.js"; import { nodes, RELAY } from "./connection.js";
describe("FluenceClient usage test suite", () => { describe("FluenceClient usage test suite", () => {
it("Should resolve at TTL when fire and forget behavior is used", async () => {
await withClient(RELAY, { defaultTtlMs: 600 }, async (peer) => {
const script = `
(seq
(call %init_peer_id% ("load" "relay") [] init_relay)
(call init_relay ("peer" "timeout") [60000 "Do you really want to wait for so long?"])
)`;
const particle = await peer.internals.createNewParticle(script);
const now = Date.now();
const promise = new Promise<JSONValue>((resolve, reject) => {
registerHandlersHelper(peer, particle, {
load: {
relay: () => {
return peer.getRelayPeerId();
},
},
});
peer.internals.initiateParticle(particle, resolve, reject);
});
await expect(promise).rejects.toThrow(ExpirationError);
expect(Date.now() - 500).toBeGreaterThanOrEqual(now);
});
});
it("should make a call through network", async () => { it("should make a call through network", async () => {
await withClient(RELAY, {}, async (peer) => { await withClient(RELAY, {}, async (peer) => {
// arrange // arrange
@ -180,7 +209,7 @@ describe("FluenceClient usage test suite", () => {
); );
}); });
it.only("With connection options: defaultTTL", async () => { it("With connection options: defaultTTL", async () => {
await withClient(RELAY, { defaultTtlMs: 1 }, async (peer) => { await withClient(RELAY, { defaultTtlMs: 1 }, async (peer) => {
const isConnected = await checkConnection(peer); const isConnected = await checkConnection(peer);

View File

@ -14,9 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
import assert from "assert"; import { JSONValue } from "@fluencelabs/interfaces";
import { FnConfig, JSONValue } from "@fluencelabs/interfaces";
import { FluencePeer } from "../jsPeer/FluencePeer.js"; import { FluencePeer } from "../jsPeer/FluencePeer.js";
import { logger } from "../util/logger.js"; import { logger } from "../util/logger.js";
@ -46,16 +44,20 @@ const log = logger("aqua");
* @returns * @returns
*/ */
type CallAquaFunctionArgs = { export type CallAquaFunctionArgs = {
script: string; script: string;
config: FnConfig; config?: CallAquaFunctionConfig;
peer: FluencePeer; peer: FluencePeer;
args: { [key: string]: JSONValue | ServiceImpl[string] }; args: { [key: string]: JSONValue | ServiceImpl[string] };
}; };
export type CallAquaFunctionConfig = {
ttl?: number;
};
export const callAquaFunction = async ({ export const callAquaFunction = async ({
script, script,
config, config = {},
peer, peer,
args, args,
}: CallAquaFunctionArgs) => { }: CallAquaFunctionArgs) => {
@ -69,21 +71,8 @@ export const callAquaFunction = async ({
let service: ServiceDescription; let service: ServiceDescription;
if (typeof argVal === "function") { if (typeof argVal === "function") {
// TODO: Add validation here
assert(
typeof argVal === "function",
"Should not be possible, bad types",
);
service = userHandlerService("callbackSrv", name, argVal); service = userHandlerService("callbackSrv", name, argVal);
} else { } else {
// TODO: Add validation here
assert(
typeof argVal !== "function",
"Should not be possible, bad types",
);
console.log("inject service", name, argVal);
service = injectValueService("getDataSrv", name, argVal); service = injectValueService("getDataSrv", name, argVal);
} }

View File

@ -54,7 +54,6 @@ export const registerService = ({
serviceId, serviceId,
service, service,
}: RegisterServiceArgs) => { }: RegisterServiceArgs) => {
// TODO: Need to refactor this. We can compute function types from service implementation, making func more type safe
log.trace("registering aqua service %o", { serviceId, service }); log.trace("registering aqua service %o", { serviceId, service });
if (serviceId == null) { if (serviceId == null) {

View File

@ -139,8 +139,6 @@ export const userHandlerService = (
const result = await userHandler.bind(null)(...args); const result = await userHandler.bind(null)(...args);
console.log(result, "userHandlerService result", serviceId, fnName);
return { return {
retCode: ResultCodes.success, retCode: ResultCodes.success,
result: result, result: result,

View File

@ -91,7 +91,11 @@ describe.skip("Ephemeral networks tests", () => {
}); });
// act // act
client.internals.initiateParticle(particle, () => {}); client.internals.initiateParticle(
particle,
() => {},
() => {},
);
// assert // assert
await expect(promise).resolves.toBe("success"); await expect(promise).resolves.toBe("success");

View File

@ -174,10 +174,14 @@ export type {
KeyPairOptions, KeyPairOptions,
} from "./clientPeer/types.js"; } from "./clientPeer/types.js";
export type { ParticleContext } from "./jsServiceHost/interfaces.js";
export { v5_callFunction, v5_registerService } from "./api.js"; export { v5_callFunction, v5_registerService } from "./api.js";
export { createClient, callAquaFunction, registerService }; export { createClient, callAquaFunction, registerService };
export { ClientPeer } from "./clientPeer/ClientPeer.js";
// Deprecated exports. Later they will be exposed only under js-client/keypair path // Deprecated exports. Later they will be exposed only under js-client/keypair path
export { export {
KeyPair, KeyPair,
@ -186,4 +190,8 @@ export {
fromOpts, fromOpts,
} from "./keypair/index.js"; } from "./keypair/index.js";
export { FluencePeer } from "./jsPeer/FluencePeer.js";
export type { JSONValue, NonArrowSimpleType } from "@fluencelabs/interfaces";
export * from "./network.js"; export * from "./network.js";

View File

@ -531,8 +531,6 @@ export abstract class FluencePeer {
item.result.nextPeerPks.toString(), item.result.nextPeerPks.toString(),
); );
const interpreterResult = item.result;
connectionPromise = this.connection connectionPromise = this.connection
.sendParticle(item.result.nextPeerPks, newParticle) .sendParticle(item.result.nextPeerPks, newParticle)
.then(() => { .then(() => {
@ -540,11 +538,6 @@ export abstract class FluencePeer {
"id %s. send successful", "id %s. send successful",
newParticle.id, newParticle.id,
); );
if (interpreterResult.callRequests.length === 0) {
// Nothing to call, just fire-and-forget behavior
item.onSuccess(null);
}
}) })
.catch((e: unknown) => { .catch((e: unknown) => {
log_particle.error( log_particle.error(
@ -622,9 +615,6 @@ export abstract class FluencePeer {
}); });
}); });
} }
} else {
// Every air instruction executed or particle will go to relay
item.onSuccess(null);
} }
return connectionPromise; return connectionPromise;
@ -637,7 +627,6 @@ export abstract class FluencePeer {
} }
private _expireParticle(item: ParticleQueueItem) { private _expireParticle(item: ParticleQueueItem) {
console.log(item);
const particleId = item.particle.id; const particleId = item.particle.id;
log_particle.debug( log_particle.debug(

View File

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { CallParams } from "@fluencelabs/interfaces"; import { ParticleContext } from "../jsServiceHost/interfaces.js";
import { TracingDef } from "./_aqua/tracing.js"; import { TracingDef } from "./_aqua/tracing.js";
@ -22,7 +22,7 @@ export class Tracing implements TracingDef {
tracingEvent( tracingEvent(
arrowName: string, arrowName: string,
event: string, event: string,
callParams: CallParams<"arrowName" | "event">, callParams: ParticleContext,
): void { ): void {
// This console log is intentional // This console log is intentional
// eslint-disable-next-line no-console // eslint-disable-next-line no-console

View File

@ -42,7 +42,7 @@ describe("Sig service test suite", () => {
aqua = functions; aqua = functions;
}); });
it.only("Use custom sig service, success path", async () => { it("Use custom sig service, success path", async () => {
await withPeer(async (peer) => { await withPeer(async (peer) => {
const customKeyPair = await KeyPair.randomEd25519(); const customKeyPair = await KeyPair.randomEd25519();
const customSig = new Sig(customKeyPair); const customSig = new Sig(customKeyPair);
@ -114,7 +114,7 @@ describe("Sig service test suite", () => {
}); });
}); });
it.only("Default sig service should be resolvable by peer id", async () => { it("Default sig service should be resolvable by peer id", async () => {
await withPeer(async (peer) => { await withPeer(async (peer) => {
const sig = peer.internals.getServices().sig; const sig = peer.internals.getServices().sig;

View File

@ -17,10 +17,11 @@
/** /**
* This compiled aqua file was modified to make it work in monorepo * This compiled aqua file was modified to make it work in monorepo
*/ */
import { CallParams, ServiceImpl } from "@fluencelabs/interfaces";
import { registerService } from "../../compilerSupport/registerService.js"; import { registerService } from "../../compilerSupport/registerService.js";
import { ServiceImpl } from "../../compilerSupport/types.js";
import { FluencePeer } from "../../jsPeer/FluencePeer.js"; import { FluencePeer } from "../../jsPeer/FluencePeer.js";
import { ParticleContext } from "../../jsServiceHost/interfaces.js";
import { Tracing } from "../Tracing.js"; import { Tracing } from "../Tracing.js";
// Services // Services
@ -29,7 +30,7 @@ export interface TracingDef {
tracingEvent: ( tracingEvent: (
arrowName: string, arrowName: string,
event: string, event: string,
callParams: CallParams<"arrowName" | "event">, callParams: ParticleContext,
) => void | Promise<void>; ) => void | Promise<void>;
} }
@ -44,33 +45,6 @@ export function registerTracing(
// TODO: fix this after changing registerService signature // TODO: fix this after changing registerService signature
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
service: service as unknown as ServiceImpl, service: service as unknown as ServiceImpl,
def: {
defaultServiceId: "tracingSrv",
functions: {
tag: "labeledProduct",
fields: {
tracingEvent: {
tag: "arrow",
domain: {
tag: "labeledProduct",
fields: {
arrowName: {
tag: "scalar",
name: "string",
},
event: {
tag: "scalar",
name: "string",
},
},
},
codomain: {
tag: "nil",
},
},
},
},
},
}); });
} }

View File

@ -103,8 +103,6 @@ export const compileAqua = async (aquaFile: string): Promise<CompiledFile> => {
); );
} }
console.log(compilationResult);
const functions = Object.entries(compilationResult.functions) const functions = Object.entries(compilationResult.functions)
.map(([name, fnInfo]: [string, FunctionInfo]) => { .map(([name, fnInfo]: [string, FunctionInfo]) => {
const callFn = (peer: FluencePeer, args: PassedArgs) => { const callFn = (peer: FluencePeer, args: PassedArgs) => {

11
pnpm-lock.yaml generated
View File

@ -162,9 +162,9 @@ importers:
packages/core/aqua-to-js: packages/core/aqua-to-js:
dependencies: dependencies:
ts-pattern: '@fluencelabs/js-client':
specifier: 5.0.5 specifier: workspace:^
version: 5.0.5 version: link:../js-client
devDependencies: devDependencies:
'@fluencelabs/aqua-api': '@fluencelabs/aqua-api':
specifier: 0.12.0 specifier: 0.12.0
@ -184,6 +184,9 @@ importers:
'@fluencelabs/trust-graph': '@fluencelabs/trust-graph':
specifier: 0.4.7 specifier: 0.4.7
version: 0.4.7 version: 0.4.7
ts-pattern:
specifier: 5.0.5
version: 5.0.5
vitest: vitest:
specifier: 0.34.6 specifier: 0.34.6
version: 0.34.6 version: 0.34.6
@ -14063,7 +14066,7 @@ packages:
/ts-pattern@5.0.5: /ts-pattern@5.0.5:
resolution: {integrity: sha512-tL0w8U/pgaacOmkb9fRlYzWEUDCfVjjv9dD4wHTgZ61MjhuMt46VNWTG747NqW6vRzoWIKABVhFSOJ82FvXrfA==} resolution: {integrity: sha512-tL0w8U/pgaacOmkb9fRlYzWEUDCfVjjv9dD4wHTgZ61MjhuMt46VNWTG747NqW6vRzoWIKABVhFSOJ82FvXrfA==}
dev: false dev: true
/tsconfck@2.1.1(typescript@5.1.6): /tsconfck@2.1.1(typescript@5.1.6):
resolution: {integrity: sha512-ZPCkJBKASZBmBUNqGHmRhdhM8pJYDdOXp4nRgj/O0JwUwsMq50lCDRQP/M5GBNAA0elPrq4gAeu4dkaVCuKWww==} resolution: {integrity: sha512-ZPCkJBKASZBmBUNqGHmRhdhM8pJYDdOXp4nRgj/O0JwUwsMq50lCDRQP/M5GBNAA0elPrq4gAeu4dkaVCuKWww==}