Skip to content
This repository was archived by the owner on Jul 10, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 1 addition & 7 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,7 @@
],
"ignorePatterns": ["**/node_modules/", "**/dist/", "**/build/", "**/public/"],
"rules": {
"eqeqeq": [
"error",
"always",
{
"null": "ignore"
}
],
"eqeqeq": ["error", "always"],
"no-console": ["error"],
"arrow-body-style": ["error", "always"],
"no-empty": [
Expand Down
3 changes: 2 additions & 1 deletion .github/release-please/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"packages/core/js-client-isomorphic": {},
"packages/core/marine-worker": {},
"packages/core/aqua-to-js": {},
"packages/core/interfaces": {}
"packages/core/interfaces": {},
"packages/core/npm-aqua-compiler": {}
}
}
3 changes: 2 additions & 1 deletion .github/release-please/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
"packages/core/marine-worker": "0.5.0",
"packages/core/aqua-to-js": "0.3.4",
"packages/core/js-client-isomorphic": "0.3.0",
"packages/core/interfaces": "0.9.0"
"packages/core/interfaces": "0.9.0",
"packages/core/npm-aqua-compiler": "0.0.0"
}
5 changes: 4 additions & 1 deletion packages/@tests/smoke/web/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* limitations under the License.
*/

import assert from "node:assert";
import { dirname, join } from "path";
import { fileURLToPath } from "url";

Expand Down Expand Up @@ -45,6 +46,8 @@ const test = async () => {
const browser = await puppeteer.launch();
const page = (await browser.pages())[0];

assert(page);

page.on("console", (message) => {
console.log(`${message.type().toUpperCase()}: ${message.text()}`);
});
Expand Down Expand Up @@ -77,7 +80,7 @@ const test = async () => {
await browser.close();
await stopServer(localServer);

if (content == null) {
if (content === null || content === undefined) {
throw new Error("smoke test failed!");
}
};
Expand Down
4 changes: 2 additions & 2 deletions packages/core/aqua-to-js/src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export function genTypeName(
const args =
item.tag === "labeledProduct" ? Object.values(item.fields) : item.items;

if (args.length === 1) {
if (args.length === 1 && "0" in args) {
return genTypeName(args[0], name);
}

Expand Down Expand Up @@ -112,7 +112,7 @@ export function typeToTs(t: NonArrowType | ArrowType): string {
const retType =
codomain.tag === "nil"
? "void"
: codomain.items.length === 1
: codomain.items.length === 1 && "0" in codomain.items
? typeToTs(codomain.items[0])
: typeToTs(codomain);

Expand Down
2 changes: 1 addition & 1 deletion packages/core/aqua-to-js/src/generate/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ export class TSTypeGenerator implements TypeGenerator {
];

const registerServiceArgs =
srvDef.defaultServiceId == null
srvDef.defaultServiceId === undefined
? functionOverloadsWithoutDefaultServiceId
: functionOverloadsWithDefaultServiceId;

Expand Down
11 changes: 7 additions & 4 deletions packages/core/aqua-to-js/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
* limitations under the License.
*/

import assert from "assert";
import { readFile } from "fs/promises";
import { join } from "path";

Expand Down Expand Up @@ -86,7 +85,7 @@ export function recursiveRenameLaquaProps(obj: JSONValue): unknown {
// Last part of the property separated by "_" is a correct name
const refinedProperty = prop.split("_").pop();

if (refinedProperty == null) {
if (refinedProperty === undefined) {
throw new Error(`Bad property name: ${prop}.`);
}

Expand All @@ -95,11 +94,15 @@ export function recursiveRenameLaquaProps(obj: JSONValue): unknown {
}
}

assert(accessProp in obj);
const laquaProp = obj[accessProp];

if (laquaProp === undefined) {
return acc;
}

return {
...acc,
[accessProp]: recursiveRenameLaquaProps(obj[accessProp]),
[accessProp]: recursiveRenameLaquaProps(laquaProp),
};
}, {});
}
Expand Down
1 change: 0 additions & 1 deletion packages/core/aqua-to-js/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"esModuleInterop": true,
"resolveJsonModule": true,
"outDir": "./dist"
},
Expand Down
2 changes: 1 addition & 1 deletion packages/core/js-client-isomorphic/src/fetchers/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export const fetchResource: FetchResourceFn = async (pkg, assetPath) => {

const packagePath = matches?.[0];

if (packagePath == null) {
if (packagePath === undefined) {
throw new Error(`Cannot find dependency ${name} in path ${posixPath}`);
}

Expand Down
6 changes: 5 additions & 1 deletion packages/core/js-client/src/api.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { fileURLToPath } from "url";

import { compileFromPath } from "@fluencelabs/aqua-api";
import { ServiceDef } from "@fluencelabs/interfaces";
import { describe, expect, it } from "vitest";
import { assert, describe, expect, it } from "vitest";

import { v5_registerService } from "./api.js";
import { callAquaFunction } from "./compilerSupport/callFunction.js";
Expand Down Expand Up @@ -65,8 +65,12 @@ describe("User API methods", () => {

const typedServices: Record<string, ServiceDef> = services;

assert("demoCalc" in functions);

const { script } = functions["demoCalc"];

assert("Calc" in typedServices);

v5_registerService([peer, "calc", calcService], {
defaultServiceId: "calc",
functions: typedServices["Calc"].functions,
Expand Down
78 changes: 41 additions & 37 deletions packages/core/js-client/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,13 @@ import { z } from "zod";
import { CallAquaFunctionConfig } from "./compilerSupport/callFunction.js";
import {
aqua2js,
SchemaValidationError,
js2aqua,
SchemaValidationError,
wrapJsFunction,
} from "./compilerSupport/conversions.js";
import { ServiceImpl, UserServiceImpl } from "./compilerSupport/types.js";
import { FluencePeer } from "./jsPeer/FluencePeer.js";
import { zip } from "./util/utils.js";

import { callAquaFunction, Fluence, registerService } from "./index.js";

Expand Down Expand Up @@ -74,59 +75,57 @@ export const v5_callFunction = async (
);
}

const argNames = Object.keys(
def.arrow.domain.tag === "nil" ? [] : def.arrow.domain.fields,
);
const schemaFunctionArgs: Record<string, FunctionArg> =
def.arrow.domain.tag === "nil" ? {} : def.arrow.domain.fields;

const schemaArgCount = argNames.length;
const schemaFunctionArgEntries = Object.entries(schemaFunctionArgs);

type FunctionArg = SimpleTypes | ArrowWithoutCallbacks;
const schemaArgCount = schemaFunctionArgEntries.length;

const schemaFunctionArgs: Record<string, FunctionArg> =
def.arrow.domain.tag === "nil" ? {} : def.arrow.domain.fields;
type FunctionArg = SimpleTypes | ArrowWithoutCallbacks;

// if there are more args than expected in schema (schemaArgCount) then last arg is config
const config = schemaArgCount < rest.length ? rest.pop() : undefined;

validateAquaConfig(config);

const callArgs = Object.fromEntries<JSONValue | ServiceImpl[string]>(
rest.slice(0, schemaArgCount).map((arg, i) => {
const argName = argNames[i];
const argSchema = schemaFunctionArgs[argName];
zip(rest.slice(0, schemaArgCount), schemaFunctionArgEntries).map(
([arg, [argName, argType]]) => {
if (argType.tag === "arrow") {
if (typeof arg !== "function") {
throw new SchemaValidationError(
[argName],
argType,
"function",
arg,
);
}

return [argName, wrapJsFunction(arg, argType)];
}

if (argSchema.tag === "arrow") {
if (typeof arg !== "function") {
if (typeof arg === "function") {
throw new SchemaValidationError(
[argName],
argSchema,
"function",
argType,
"non-function value",
arg,
);
}

return [argName, wrapJsFunction(arg, argSchema)];
}

if (typeof arg === "function") {
throw new SchemaValidationError(
[argName],
argSchema,
"non-function value",
arg,
);
}

return [argName, js2aqua(arg, argSchema, { path: [def.functionName] })];
}),
return [argName, js2aqua(arg, argType, { path: [def.functionName] })];
},
),
);

const returnTypeVoid =
def.arrow.codomain.tag === "nil" || def.arrow.codomain.items.length === 0;

const returnSchema =
def.arrow.codomain.tag === "unlabeledProduct" &&
def.arrow.codomain.items.length === 1
def.arrow.codomain.items.length === 1 &&
"0" in def.arrow.codomain.items
? def.arrow.codomain.items[0]
: def.arrow.codomain;
Comment on lines +127 to 130
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't you want to extract this pattern to some function? It is repeated at least 3 times

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably possible with this

function isArrayWithOneElement<T>(arr: Array<T>): arr is [T] {
  return arr.length === 1 && arr[0] !== undefined;
}

Copy link
Contributor Author

@akim-bow akim-bow Dec 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will keep it in mind. This PR already bloated too much, i will do this in the next PR.


Expand All @@ -145,7 +144,7 @@ export const v5_callFunction = async (
};

const getDefaultPeer = (): FluencePeer => {
if (Fluence.defaultClient == null) {
if (Fluence.defaultClient === undefined) {
throw new Error(
"Could not register Aqua service because the client is not initialized. Did you forget to call Fluence.connect()?",
);
Expand All @@ -155,7 +154,7 @@ const getDefaultPeer = (): FluencePeer => {
};

const getDefaultServiceId = (def: ServiceDef) => {
if (def.defaultServiceId == null) {
if (def.defaultServiceId === undefined) {
throw new Error("Service ID is not provided");
}

Expand Down Expand Up @@ -204,13 +203,18 @@ export const v5_registerService = (

// Wrapping service functions, selecting only those listed in schema, to convert their args js -> aqua and backwards
const wrappedServiceImpl = Object.fromEntries(
Object.keys(serviceSchema).map((schemaKey) => {
Object.entries(serviceSchema).map(([schemaKey, schemaValue]) => {
const serviceImplValue = serviceImpl[schemaKey];

if (serviceImplValue === undefined) {
throw new Error(
`Service function ${schemaKey} listed in Aqua schema but wasn't provided in schema implementation object or class instance. Check that your Aqua service definition matches passed service implementation`,
);
}

return [
schemaKey,
wrapJsFunction(
serviceImpl[schemaKey].bind(serviceImpl),
serviceSchema[schemaKey],
),
wrapJsFunction(serviceImplValue.bind(serviceImpl), schemaValue),
] as const;
}),
);
Expand Down
2 changes: 1 addition & 1 deletion packages/core/js-client/src/clientPeer/ClientPeer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export const makeClientPeerConfig = async (
relayConfig: {
peerId: keyPair.getLibp2pPeerId(),
relayAddress: relayAddress,
...(config.connectionOptions?.dialTimeoutMs != null
...(config.connectionOptions?.dialTimeoutMs !== undefined
? {
dialTimeout: config.connectionOptions.dialTimeoutMs,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/

import { JSONValue } from "@fluencelabs/interfaces";
import { it, describe, expect } from "vitest";
import { it, describe, expect, assert } from "vitest";

import { ExpirationError } from "../../jsPeer/errors.js";
import { CallServiceData } from "../../jsServiceHost/interfaces.js";
Expand Down Expand Up @@ -103,6 +103,7 @@ describe("FluenceClient usage test suite", () => {
callback: {
callback: (args): undefined => {
const [val] = args;
assert(val);
resolve(val);
},
error: (args): undefined => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ export const nodes = [
"/ip4/127.0.0.1/tcp/9991/ws/p2p/12D3KooWBM3SdXWqGaawQDGQ6JprtwswEg3FWGvGhmgmMez1vRbR",
peerId: "12D3KooWBM3SdXWqGaawQDGQ6JprtwswEg3FWGvGhmgmMez1vRbR",
},
];
] as const;

export const RELAY = nodes[0].multiaddr;
2 changes: 1 addition & 1 deletion packages/core/js-client/src/clientPeer/checkConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export const checkConnection = async (
const [val] = args;

setTimeout(() => {
resolve(val);
resolve(val ?? null);
}, 0);

return {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ const structs = [
c: [null, 2],
},
},
];
] as const;

const labeledProduct2 = {
tag: "labeledProduct",
Expand Down Expand Up @@ -167,7 +167,7 @@ const nestedStructs = [
c: [],
},
},
];
] as const;

interface ConversionTestArgs {
aqua: JSONValue;
Expand Down
Loading