From baac1be8f5ba54d89c6fec8c0b65e45a9c7c2f10 Mon Sep 17 00:00:00 2001 From: Akim Mamedov Date: Mon, 2 Oct 2023 21:55:19 +0700 Subject: [PATCH 01/45] introduce eslint --- .eslintrc.json | 161 +++ .prettierrc.cjs | 8 - package.json | 24 +- .../aqua/src/_aqua/finalize_particle.ts | 68 +- packages/@tests/aqua/src/_aqua/smoke_test.ts | 904 +++++++-------- packages/@tests/aqua/src/index.ts | 91 +- packages/@tests/aqua/src/wasmb64.ts | 19 +- packages/@tests/smoke/node/src/index.ts | 24 +- packages/@tests/smoke/web-cra-ts/package.json | 1 - packages/@tests/smoke/web-cra-ts/src/App.css | 42 +- packages/@tests/smoke/web-cra-ts/src/App.tsx | 25 +- .../@tests/smoke/web-cra-ts/src/index.css | 16 +- .../@tests/smoke/web-cra-ts/src/index.tsx | 14 +- .../smoke/web-cra-ts/src/reportWebVitals.ts | 22 +- .../@tests/smoke/web-cra-ts/src/setupTests.ts | 2 +- packages/@tests/smoke/web/src/index.ts | 65 +- packages/@tests/smoke/web/tsconfig.json | 2 +- packages/@tests/test-utils/src/index.ts | 74 +- packages/core/aqua-to-js/package.json | 1 - packages/core/aqua-to-js/src/common.ts | 194 ++-- packages/core/aqua-to-js/src/constants.ts | 4 +- packages/core/aqua-to-js/src/future.ts | 72 +- .../src/generate/__test__/generate.spec.ts | 42 +- .../core/aqua-to-js/src/generate/function.ts | 29 +- .../core/aqua-to-js/src/generate/header.ts | 22 +- .../core/aqua-to-js/src/generate/index.ts | 92 +- .../aqua-to-js/src/generate/interfaces.ts | 101 +- .../core/aqua-to-js/src/generate/service.ts | 80 +- packages/core/aqua-to-js/src/index.ts | 38 +- packages/core/aqua-to-js/src/utils.ts | 61 +- packages/core/interfaces/src/commonTypes.ts | 9 +- .../compilerSupport/aquaTypeDefinitions.ts | 71 +- .../compilerSupportInterface.ts | 16 +- packages/core/interfaces/src/fluenceClient.ts | 26 +- packages/core/interfaces/src/index.ts | 11 +- packages/core/js-client/src/api.ts | 66 +- .../js-client/src/clientPeer/ClientPeer.ts | 76 +- .../src/clientPeer/__test__/client.spec.ts | 121 +- .../src/clientPeer/__test__/connection.ts | 21 +- .../src/clientPeer/checkConnection.ts | 54 +- .../src/compilerSupport/__test__/v3.spec.ts | 56 +- .../src/compilerSupport/callFunction.ts | 87 +- .../src/compilerSupport/conversions.ts | 112 +- .../src/compilerSupport/registerService.ts | 58 +- .../js-client/src/compilerSupport/services.ts | 94 +- .../src/connection/RelayConnection.ts | 207 ++-- .../js-client/src/connection/interfaces.ts | 12 +- .../src/ephemeral/__test__/ephemeral.spec.ts | 61 +- .../core/js-client/src/ephemeral/client.ts | 48 +- .../core/js-client/src/ephemeral/network.ts | 180 +-- .../core/js-client/src/fetchers/browser.ts | 42 +- packages/core/js-client/src/fetchers/index.ts | 12 +- packages/core/js-client/src/fetchers/node.ts | 38 +- packages/core/js-client/src/index.ts | 210 ++-- .../core/js-client/src/jsPeer/FluencePeer.ts | 442 +++++--- .../js-client/src/jsPeer/__test__/avm.spec.ts | 76 +- .../js-client/src/jsPeer/__test__/par.spec.ts | 68 +- .../src/jsPeer/__test__/parseAst.spec.ts | 28 +- .../src/jsPeer/__test__/peer.spec.ts | 90 +- .../src/jsServiceHost/JsServiceHost.ts | 39 +- .../js-client/src/jsServiceHost/interfaces.ts | 28 +- .../src/jsServiceHost/serviceUtils.ts | 32 +- .../src/keypair/__test__/KeyPair.spec.ts | 43 +- packages/core/js-client/src/keypair/index.ts | 32 +- .../src/marine/__test__/marine-js.spec.ts | 50 +- .../src/marine/deps-loader/common.ts | 15 +- .../js-client/src/marine/deps-loader/node.ts | 39 +- .../js-client/src/marine/deps-loader/web.ts | 25 +- .../core/js-client/src/marine/interfaces.ts | 36 +- .../src/marine/worker-script/workerLoader.ts | 16 +- .../core/js-client/src/marine/worker/index.ts | 68 +- .../core/js-client/src/particle/Particle.ts | 119 +- .../core/js-client/src/particle/interfaces.ts | 5 +- .../core/js-client/src/services/NodeUtils.ts | 31 +- packages/core/js-client/src/services/Sig.ts | 51 +- .../js-client/src/services/SingleModuleSrv.ts | 37 +- .../core/js-client/src/services/Tracing.ts | 15 +- .../services/__test__/builtInHandler.spec.ts | 320 +++--- .../src/services/__test__/jsonBuiltin.spec.ts | 50 +- .../src/services/__test__/sigService.spec.ts | 110 +- .../src/services/__test__/srv.spec.ts | 90 +- .../src/services/_aqua/node-utils.ts | 69 +- .../js-client/src/services/_aqua/services.ts | 107 +- .../src/services/_aqua/single-module-srv.ts | 111 +- .../js-client/src/services/_aqua/tracing.ts | 47 +- .../core/js-client/src/services/builtins.ts | 265 +++-- .../js-client/src/services/securityGuard.ts | 43 +- packages/core/js-client/src/util/bytes.ts | 10 +- .../core/js-client/src/util/commonTypes.ts | 12 +- .../core/js-client/src/util/libp2pUtils.ts | 15 +- .../core/js-client/src/util/loadClient.ts | 19 +- packages/core/js-client/src/util/logger.ts | 4 +- packages/core/js-client/src/util/testUtils.ts | 122 +- packages/core/js-client/src/util/utils.ts | 8 +- packages/core/marine-worker/src/index.ts | 90 +- pnpm-lock.yaml | 1003 ++++++++++++----- reset.d.ts | 1 + resources/license-header.js | 15 + tsconfig.json | 7 +- 99 files changed, 5196 insertions(+), 2693 deletions(-) create mode 100644 .eslintrc.json delete mode 100644 .prettierrc.cjs create mode 100644 reset.d.ts create mode 100644 resources/license-header.js diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 000000000..5aaa57f71 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,161 @@ +{ + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": 2022, + "project": [ + "./tsconfig.json", + "./tsconfig.eslint.json", + "./test/tsconfig.json" + ] + }, + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:@typescript-eslint/recommended-requiring-type-checking", + "plugin:import/recommended", + "plugin:import/typescript", + "prettier" + ], + "plugins": [ + "@typescript-eslint", + "import", + "license-header", + "unused-imports" + ], + "rules": { + "eqeqeq": [ + "error", + "always" + ], + "no-console": [ + "error" + ], + "arrow-body-style": [ + "error", + "always" + ], + "no-empty": [ + "error", + { + "allowEmptyCatch": true + } + ], + "no-plusplus": "error", + "operator-assignment": [ + "error", + "never" + ], + "curly": [ + "error", + "all" + ], + "no-unused-expressions": [ + "error" + ], + "dot-notation": [ + "off" + ], + "object-curly-spacing": [ + "error", + "always" + ], + "padding-line-between-statements": [ + "error", + { + "blankLine": "always", + "prev": "multiline-expression", + "next": "*" + }, + { + "blankLine": "always", + "prev": "*", + "next": "multiline-expression" + }, + { + "blankLine": "always", + "prev": "multiline-block-like", + "next": "*" + }, + { + "blankLine": "always", + "prev": "*", + "next": "multiline-block-like" + }, + { + "blankLine": "always", + "prev": "multiline-const", + "next": "*" + }, + { + "blankLine": "always", + "prev": "*", + "next": "multiline-const" + }, + { + "blankLine": "always", + "prev": "multiline-let", + "next": "*" + }, + { + "blankLine": "always", + "prev": "*", + "next": "multiline-let" + }, + { + "blankLine": "any", + "prev": "case", + "next": "case" + } + ], + "import/extensions": [ + "error", + "always" + ], + "import/no-unresolved": "off", + "import/no-cycle": [ + "error" + ], + "import/order": [ + "error", + { + "newlines-between": "always", + "alphabetize": { + "order": "asc", + "caseInsensitive": true + } + } + ], + "node/no-unsupported-features/es-syntax": "off", + "node/no-unpublished-import": "off", + "node/no-missing-import": "off", + "@typescript-eslint/explicit-member-accessibility": [ + "error", + { + "accessibility": "no-public" + } + ], + "@typescript-eslint/strict-boolean-expressions": [ + "error", + { + "allowString": false, + "allowNumber": false, + "allowNullableObject": false, + "allowNullableBoolean": false, + "allowNullableString": false, + "allowNullableNumber": false, + "allowAny": false + } + ], + "@typescript-eslint/consistent-type-assertions": [ + "error", + { + "assertionStyle": "never" + } + ], + "unused-imports/no-unused-imports": "error", + "license-header/header": [ + "error", + "./resources/license-header.js" + ] + } +} \ No newline at end of file diff --git a/.prettierrc.cjs b/.prettierrc.cjs deleted file mode 100644 index 36f36b84e..000000000 --- a/.prettierrc.cjs +++ /dev/null @@ -1,8 +0,0 @@ -module.exports = { - semi: true, - trailingComma: 'all', - singleQuote: true, - printWidth: 120, - tabWidth: 4, - useTabs: false, -}; diff --git a/package.json b/package.json index faae3fd14..57e671d97 100644 --- a/package.json +++ b/package.json @@ -8,15 +8,31 @@ "node": ">=10", "pnpm": ">=3" }, + "scripts": { + "lint-check": "pnpm run prettier --check && pnpm run eslint", + "lint-fix": "pnpm run prettier --write && pnpm run eslint --fix", + "prettier": "prettier \"**/src/**/*.{js,ts}\"", + "eslint": "eslint --ext .js,.ts --cache \"**/src/**\"" + }, "author": "Fluence Labs", "license": "Apache-2.0", "devDependencies": { + "@fluencelabs/aqua": "0.9.1-374", + "@fluencelabs/aqua-lib": "0.6.0", + "@total-typescript/ts-reset": "0.5.1", + "@tsconfig/strictest": "2.0.2", + "@types/node": "18.13.0", + "@typescript-eslint/eslint-plugin": "6.7.3", + "@typescript-eslint/parser": "6.7.3", + "eslint": "8.50.0", + "eslint-config-prettier": "9.0.0", + "eslint-plugin-import": "2.28.1", + "eslint-plugin-license-header": "0.6.0", + "eslint-plugin-unused-imports": "3.0.0", "http-server": "14.1.1", + "prettier": "3.0.3", "puppeteer": "19.7.2", - "@types/node": "18.13.0", "ts-node": "10.9.1", - "typescript": "4.7", - "@fluencelabs/aqua-lib": "0.6.0", - "@fluencelabs/aqua": "0.9.1-374" + "typescript": "5.1.6" } } \ No newline at end of file diff --git a/packages/@tests/aqua/src/_aqua/finalize_particle.ts b/packages/@tests/aqua/src/_aqua/finalize_particle.ts index f4f7c6485..f6d29bb7f 100644 --- a/packages/@tests/aqua/src/_aqua/finalize_particle.ts +++ b/packages/@tests/aqua/src/_aqua/finalize_particle.ts @@ -8,13 +8,14 @@ * Aqua version: 0.12.0 * */ -import type { IFluenceClient as IFluenceClient$$, CallParams as CallParams$$ } from '@fluencelabs/js-client'; +import type { + IFluenceClient as IFluenceClient$$, + CallParams as CallParams$$, +} from "@fluencelabs/js-client"; import { v5_callFunction as callFunction$$, v5_registerService as registerService$$, -} from '@fluencelabs/js-client'; - - +} from "@fluencelabs/js-client"; // Services @@ -30,49 +31,42 @@ export const test_script = ` (call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 0]) ) ) - ` - + `; -export function test( - config?: {ttl?: number} -): Promise; +export function test(config?: { ttl?: number }): Promise; export function test( peer: IFluenceClient$$, - config?: {ttl?: number} + config?: { ttl?: number }, ): Promise; export function test(...args: any) { - - return callFunction$$( args, { - "functionName" : "test", - "arrow" : { - "tag" : "arrow", - "domain" : { - "tag" : "labeledProduct", - "fields" : { - - } + 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", + }, }, - "codomain" : { - "tag" : "nil" - } - }, - "names" : { - "relay" : "-relay-", - "getDataSrv" : "getDataSrv", - "callbackSrv" : "callbackSrv", - "responseSrv" : "callbackSrv", - "responseFnName" : "response", - "errorHandlingSrv" : "errorHandlingSrv", - "errorFnName" : "error" - } -}, - test_script - ) + test_script, + ); } -/* eslint-enable */ \ No newline at end of file +/* eslint-enable */ diff --git a/packages/@tests/aqua/src/_aqua/smoke_test.ts b/packages/@tests/aqua/src/_aqua/smoke_test.ts index f4949e557..c098703eb 100644 --- a/packages/@tests/aqua/src/_aqua/smoke_test.ts +++ b/packages/@tests/aqua/src/_aqua/smoke_test.ts @@ -8,325 +8,360 @@ * Aqua version: 0.12.0 * */ -import type { IFluenceClient as IFluenceClient$$, CallParams as CallParams$$ } from '@fluencelabs/js-client'; +import type { + IFluenceClient as IFluenceClient$$, + CallParams as CallParams$$, +} from "@fluencelabs/js-client"; import { v5_callFunction as callFunction$$, v5_registerService as registerService$$, -} from '@fluencelabs/js-client'; - - +} from "@fluencelabs/js-client"; // Services export interface SrvDef { - create: (wasm_b64_content: string, callParams: CallParams$$<'wasm_b64_content'>) => { error: string | null; service_id: string | null; success: boolean; } | Promise<{ error: string | null; service_id: string | null; success: boolean; }>; + create: ( + wasm_b64_content: string, + callParams: CallParams$$<"wasm_b64_content">, + ) => + | { error: string | null; service_id: string | null; success: boolean } + | Promise<{ + error: string | null; + service_id: string | null; + success: boolean; + }>; list: (callParams: CallParams$$) => string[] | Promise; - remove: (service_id: string, callParams: CallParams$$<'service_id'>) => { error: string | null; success: boolean; } | Promise<{ error: string | null; success: boolean; }>; + remove: ( + service_id: string, + callParams: CallParams$$<"service_id">, + ) => + | { 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( + peer: IFluenceClient$$, + serviceId: string, + service: SrvDef, +): void; export function registerSrv(...args: any) { - registerService$$( - args, - { - "defaultServiceId" : "single_module_srv", - "functions" : { - "tag" : "labeledProduct", - "fields" : { - "create" : { - "tag" : "arrow", - "domain" : { - "tag" : "labeledProduct", - "fields" : { - "wasm_b64_content" : { - "tag" : "scalar", - "name" : "string" - } - } + registerService$$(args, { + defaultServiceId: "single_module_srv", + functions: { + tag: "labeledProduct", + fields: { + create: { + tag: "arrow", + domain: { + tag: "labeledProduct", + fields: { + wasm_b64_content: { + tag: "scalar", + name: "string", + }, + }, + }, + codomain: { + tag: "unlabeledProduct", + items: [ + { + tag: "struct", + name: "ServiceCreationResult", + fields: { + error: { + tag: "option", + type: { + tag: "scalar", + name: "string", + }, + }, + service_id: { + tag: "option", + type: { + tag: "scalar", + name: "string", + }, + }, + success: { + tag: "scalar", + name: "bool", + }, + }, + }, + ], + }, }, - "codomain" : { - "tag" : "unlabeledProduct", - "items" : [ - { - "tag" : "struct", - "name" : "ServiceCreationResult", - "fields" : { - "error" : { - "tag" : "option", - "type" : { - "tag" : "scalar", - "name" : "string" - } + list: { + tag: "arrow", + domain: { + tag: "nil", + }, + codomain: { + tag: "unlabeledProduct", + items: [ + { + tag: "array", + type: { + tag: "scalar", + name: "string", }, - "service_id" : { - "tag" : "option", - "type" : { - "tag" : "scalar", - "name" : "string" - } + }, + ], + }, + }, + remove: { + tag: "arrow", + domain: { + tag: "labeledProduct", + fields: { + service_id: { + tag: "scalar", + name: "string", + }, + }, + }, + codomain: { + tag: "unlabeledProduct", + items: [ + { + tag: "struct", + name: "RemoveResult", + fields: { + error: { + tag: "option", + type: { + tag: "scalar", + name: "string", + }, + }, + success: { + tag: "scalar", + name: "bool", + }, }, - "success" : { - "tag" : "scalar", - "name" : "bool" - } - } - } - ] - } - }, - "list" : { - "tag" : "arrow", - "domain" : { - "tag" : "nil" + }, + ], + }, }, - "codomain" : { - "tag" : "unlabeledProduct", - "items" : [ - { - "tag" : "array", - "type" : { - "tag" : "scalar", - "name" : "string" - } - } - ] - } }, - "remove" : { - "tag" : "arrow", - "domain" : { - "tag" : "labeledProduct", - "fields" : { - "service_id" : { - "tag" : "scalar", - "name" : "string" - } - } - }, - "codomain" : { - "tag" : "unlabeledProduct", - "items" : [ - { - "tag" : "struct", - "name" : "RemoveResult", - "fields" : { - "error" : { - "tag" : "option", - "type" : { - "tag" : "scalar", - "name" : "string" - } - }, - "success" : { - "tag" : "scalar", - "name" : "bool" - } - } - } - ] - } - } - } - } -} - ); + }, + }); } - - export interface CalcServiceDef { - add: (num: number, callParams: CallParams$$<'num'>) => number | Promise; + add: ( + num: number, + callParams: CallParams$$<"num">, + ) => number | Promise; clear_state: (callParams: CallParams$$) => void | Promise; - divide: (num: number, callParams: CallParams$$<'num'>) => number | Promise; - multiply: (num: number, callParams: CallParams$$<'num'>) => number | Promise; + divide: ( + num: number, + callParams: CallParams$$<"num">, + ) => number | Promise; + multiply: ( + num: number, + callParams: CallParams$$<"num">, + ) => number | Promise; state: (callParams: CallParams$$) => number | Promise; - subtract: (num: number, callParams: CallParams$$<'num'>) => number | Promise; + subtract: ( + num: number, + callParams: CallParams$$<"num">, + ) => number | Promise; test_logs: (callParams: CallParams$$) => void | Promise; } -export function registerCalcService(serviceId: string, service: CalcServiceDef): void; -export function registerCalcService(peer: IFluenceClient$$, serviceId: string, service: CalcServiceDef): void; - +export function registerCalcService( + serviceId: string, + service: CalcServiceDef, +): void; +export function registerCalcService( + peer: IFluenceClient$$, + serviceId: string, + service: CalcServiceDef, +): void; export function registerCalcService(...args: any) { - registerService$$( - args, - { - "functions" : { - "tag" : "labeledProduct", - "fields" : { - "add" : { - "tag" : "arrow", - "domain" : { - "tag" : "labeledProduct", - "fields" : { - "num" : { - "tag" : "scalar", - "name" : "f64" - } - } + registerService$$(args, { + functions: { + tag: "labeledProduct", + fields: { + add: { + tag: "arrow", + domain: { + tag: "labeledProduct", + fields: { + num: { + tag: "scalar", + name: "f64", + }, + }, + }, + codomain: { + tag: "unlabeledProduct", + items: [ + { + tag: "scalar", + name: "f64", + }, + ], + }, }, - "codomain" : { - "tag" : "unlabeledProduct", - "items" : [ - { - "tag" : "scalar", - "name" : "f64" - } - ] - } - }, - "clear_state" : { - "tag" : "arrow", - "domain" : { - "tag" : "nil" + clear_state: { + tag: "arrow", + domain: { + tag: "nil", + }, + codomain: { + tag: "nil", + }, }, - "codomain" : { - "tag" : "nil" - } - }, - "divide" : { - "tag" : "arrow", - "domain" : { - "tag" : "labeledProduct", - "fields" : { - "num" : { - "tag" : "scalar", - "name" : "f64" - } - } + divide: { + tag: "arrow", + domain: { + tag: "labeledProduct", + fields: { + num: { + tag: "scalar", + name: "f64", + }, + }, + }, + codomain: { + tag: "unlabeledProduct", + items: [ + { + tag: "scalar", + name: "f64", + }, + ], + }, }, - "codomain" : { - "tag" : "unlabeledProduct", - "items" : [ - { - "tag" : "scalar", - "name" : "f64" - } - ] - } - }, - "multiply" : { - "tag" : "arrow", - "domain" : { - "tag" : "labeledProduct", - "fields" : { - "num" : { - "tag" : "scalar", - "name" : "f64" - } - } + multiply: { + tag: "arrow", + domain: { + tag: "labeledProduct", + fields: { + num: { + tag: "scalar", + name: "f64", + }, + }, + }, + codomain: { + tag: "unlabeledProduct", + items: [ + { + tag: "scalar", + name: "f64", + }, + ], + }, }, - "codomain" : { - "tag" : "unlabeledProduct", - "items" : [ - { - "tag" : "scalar", - "name" : "f64" - } - ] - } - }, - "state" : { - "tag" : "arrow", - "domain" : { - "tag" : "nil" + state: { + tag: "arrow", + domain: { + tag: "nil", + }, + codomain: { + tag: "unlabeledProduct", + items: [ + { + tag: "scalar", + name: "f64", + }, + ], + }, }, - "codomain" : { - "tag" : "unlabeledProduct", - "items" : [ - { - "tag" : "scalar", - "name" : "f64" - } - ] - } - }, - "subtract" : { - "tag" : "arrow", - "domain" : { - "tag" : "labeledProduct", - "fields" : { - "num" : { - "tag" : "scalar", - "name" : "f64" - } - } + subtract: { + tag: "arrow", + domain: { + tag: "labeledProduct", + fields: { + num: { + tag: "scalar", + name: "f64", + }, + }, + }, + codomain: { + tag: "unlabeledProduct", + items: [ + { + tag: "scalar", + name: "f64", + }, + ], + }, }, - "codomain" : { - "tag" : "unlabeledProduct", - "items" : [ - { - "tag" : "scalar", - "name" : "f64" - } - ] - } - }, - "test_logs" : { - "tag" : "arrow", - "domain" : { - "tag" : "nil" + test_logs: { + tag: "arrow", + domain: { + tag: "nil", + }, + codomain: { + tag: "nil", + }, }, - "codomain" : { - "tag" : "nil" - } - } - } - } -} - ); + }, + }, + }); } - - export interface HelloWorldDef { - hello: (str: string, callParams: CallParams$$<'str'>) => string | Promise; + hello: ( + str: string, + callParams: CallParams$$<"str">, + ) => string | Promise; } 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( + 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) { - registerService$$( - args, - { - "defaultServiceId" : "hello-world", - "functions" : { - "tag" : "labeledProduct", - "fields" : { - "hello" : { - "tag" : "arrow", - "domain" : { - "tag" : "labeledProduct", - "fields" : { - "str" : { - "tag" : "scalar", - "name" : "string" - } - } + registerService$$(args, { + defaultServiceId: "hello-world", + functions: { + tag: "labeledProduct", + fields: { + hello: { + tag: "arrow", + domain: { + tag: "labeledProduct", + fields: { + str: { + tag: "scalar", + name: "string", + }, + }, + }, + codomain: { + tag: "unlabeledProduct", + items: [ + { + tag: "scalar", + name: "string", + }, + ], + }, }, - "codomain" : { - "tag" : "unlabeledProduct", - "items" : [ - { - "tag" : "scalar", - "name" : "string" - } - ] - } - } - } - } -} - ); + }, + }, + }); } - + // Functions export const resourceTest_script = ` (seq @@ -546,70 +581,68 @@ export const resourceTest_script = ` ) (call %init_peer_id% ("callbackSrv" "response") [-resource_id-flat-0 #error_canon]) ) - ` - -export type ResourceTestResult = [string | null, string[]] + `; + +export type ResourceTestResult = [string | null, string[]]; export function resourceTest( label: string, - config?: {ttl?: number} + config?: { ttl?: number }, ): Promise; export function resourceTest( peer: IFluenceClient$$, label: string, - config?: {ttl?: number} + config?: { ttl?: number }, ): Promise; export function resourceTest(...args: any) { - - return callFunction$$( args, { - "functionName" : "resourceTest", - "arrow" : { - "tag" : "arrow", - "domain" : { - "tag" : "labeledProduct", - "fields" : { - "label" : { - "tag" : "scalar", - "name" : "string" - } - } - }, - "codomain" : { - "tag" : "unlabeledProduct", - "items" : [ - { - "tag" : "option", - "type" : { - "tag" : "scalar", - "name" : "string" - } + functionName: "resourceTest", + arrow: { + tag: "arrow", + domain: { + tag: "labeledProduct", + fields: { + label: { + tag: "scalar", + name: "string", + }, + }, + }, + codomain: { + tag: "unlabeledProduct", + items: [ + { + tag: "option", + type: { + tag: "scalar", + name: "string", + }, + }, + { + tag: "array", + type: { + tag: "scalar", + name: "string", + }, + }, + ], }, - { - "tag" : "array", - "type" : { - "tag" : "scalar", - "name" : "string" - } - } - ] - } - }, - "names" : { - "relay" : "-relay-", - "getDataSrv" : "getDataSrv", - "callbackSrv" : "callbackSrv", - "responseSrv" : "callbackSrv", - "responseFnName" : "response", - "errorHandlingSrv" : "errorHandlingSrv", - "errorFnName" : "error" - } -}, - resourceTest_script - ) + }, + names: { + relay: "-relay-", + getDataSrv: "getDataSrv", + callbackSrv: "callbackSrv", + responseSrv: "callbackSrv", + responseFnName: "response", + errorHandlingSrv: "errorHandlingSrv", + errorFnName: "error", + }, + }, + resourceTest_script, + ); } export const helloTest_script = ` @@ -623,55 +656,48 @@ export const helloTest_script = ` ) (call %init_peer_id% ("callbackSrv" "response") [hello]) ) - ` - + `; -export function helloTest( - config?: {ttl?: number} -): Promise; +export function helloTest(config?: { ttl?: number }): Promise; export function helloTest( peer: IFluenceClient$$, - config?: {ttl?: number} + config?: { ttl?: number }, ): Promise; export function helloTest(...args: any) { - - return callFunction$$( args, { - "functionName" : "helloTest", - "arrow" : { - "tag" : "arrow", - "domain" : { - "tag" : "labeledProduct", - "fields" : { - - } + functionName: "helloTest", + arrow: { + tag: "arrow", + domain: { + tag: "labeledProduct", + fields: {}, + }, + codomain: { + tag: "unlabeledProduct", + items: [ + { + tag: "scalar", + name: "string", + }, + ], + }, + }, + names: { + relay: "-relay-", + getDataSrv: "getDataSrv", + callbackSrv: "callbackSrv", + responseSrv: "callbackSrv", + responseFnName: "response", + errorHandlingSrv: "errorHandlingSrv", + errorFnName: "error", + }, }, - "codomain" : { - "tag" : "unlabeledProduct", - "items" : [ - { - "tag" : "scalar", - "name" : "string" - } - ] - } - }, - "names" : { - "relay" : "-relay-", - "getDataSrv" : "getDataSrv", - "callbackSrv" : "callbackSrv", - "responseSrv" : "callbackSrv", - "responseFnName" : "response", - "errorHandlingSrv" : "errorHandlingSrv", - "errorFnName" : "error" - } -}, - helloTest_script - ) + helloTest_script, + ); } export const demo_calculation_script = ` @@ -703,60 +729,57 @@ export const demo_calculation_script = ` ) (call %init_peer_id% ("callbackSrv" "response") [res]) ) - ` - + `; export function demo_calculation( service_id: string, - config?: {ttl?: number} + config?: { ttl?: number }, ): Promise; export function demo_calculation( peer: IFluenceClient$$, service_id: string, - config?: {ttl?: number} + config?: { ttl?: number }, ): Promise; export function demo_calculation(...args: any) { - - return callFunction$$( args, { - "functionName" : "demo_calculation", - "arrow" : { - "tag" : "arrow", - "domain" : { - "tag" : "labeledProduct", - "fields" : { - "service_id" : { - "tag" : "scalar", - "name" : "string" - } - } + functionName: "demo_calculation", + arrow: { + tag: "arrow", + domain: { + tag: "labeledProduct", + fields: { + service_id: { + tag: "scalar", + name: "string", + }, + }, + }, + codomain: { + tag: "unlabeledProduct", + items: [ + { + tag: "scalar", + name: "f64", + }, + ], + }, + }, + names: { + relay: "-relay-", + getDataSrv: "getDataSrv", + callbackSrv: "callbackSrv", + responseSrv: "callbackSrv", + responseFnName: "response", + errorHandlingSrv: "errorHandlingSrv", + errorFnName: "error", + }, }, - "codomain" : { - "tag" : "unlabeledProduct", - "items" : [ - { - "tag" : "scalar", - "name" : "f64" - } - ] - } - }, - "names" : { - "relay" : "-relay-", - "getDataSrv" : "getDataSrv", - "callbackSrv" : "callbackSrv", - "responseSrv" : "callbackSrv", - "responseFnName" : "response", - "errorHandlingSrv" : "errorHandlingSrv", - "errorFnName" : "error" - } -}, - demo_calculation_script - ) + demo_calculation_script, + ); } export const marineTest_script = ` @@ -791,60 +814,57 @@ export const marineTest_script = ` ) (call %init_peer_id% ("callbackSrv" "response") [res]) ) - ` - + `; export function marineTest( wasm64: string, - config?: {ttl?: number} + config?: { ttl?: number }, ): Promise; export function marineTest( peer: IFluenceClient$$, wasm64: string, - config?: {ttl?: number} + config?: { ttl?: number }, ): Promise; export function marineTest(...args: any) { - - return callFunction$$( args, { - "functionName" : "marineTest", - "arrow" : { - "tag" : "arrow", - "domain" : { - "tag" : "labeledProduct", - "fields" : { - "wasm64" : { - "tag" : "scalar", - "name" : "string" - } - } + functionName: "marineTest", + arrow: { + tag: "arrow", + domain: { + tag: "labeledProduct", + fields: { + wasm64: { + tag: "scalar", + name: "string", + }, + }, + }, + codomain: { + tag: "unlabeledProduct", + items: [ + { + tag: "scalar", + name: "f64", + }, + ], + }, + }, + names: { + relay: "-relay-", + getDataSrv: "getDataSrv", + callbackSrv: "callbackSrv", + responseSrv: "callbackSrv", + responseFnName: "response", + errorHandlingSrv: "errorHandlingSrv", + errorFnName: "error", + }, }, - "codomain" : { - "tag" : "unlabeledProduct", - "items" : [ - { - "tag" : "scalar", - "name" : "f64" - } - ] - } - }, - "names" : { - "relay" : "-relay-", - "getDataSrv" : "getDataSrv", - "callbackSrv" : "callbackSrv", - "responseSrv" : "callbackSrv", - "responseFnName" : "response", - "errorHandlingSrv" : "errorHandlingSrv", - "errorFnName" : "error" - } -}, - marineTest_script - ) + marineTest_script, + ); } -/* eslint-enable */ \ No newline at end of file +/* eslint-enable */ diff --git a/packages/@tests/aqua/src/index.ts b/packages/@tests/aqua/src/index.ts index 3cdb9ee62..81491472c 100644 --- a/packages/@tests/aqua/src/index.ts +++ b/packages/@tests/aqua/src/index.ts @@ -1,84 +1,117 @@ -import { fromByteArray } from 'base64-js'; -import { Fluence } from '@fluencelabs/js-client'; -import type { ClientConfig } from '@fluencelabs/js-client'; -import { registerHelloWorld, helloTest, marineTest, resourceTest } from './_aqua/smoke_test.js'; -import { test as particleTest } from './_aqua/finalize_particle.js'; -import { wasm } from './wasmb64.js'; +/** + * 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 { Fluence } from "@fluencelabs/js-client"; +import type { ClientConfig } from "@fluencelabs/js-client"; +import { fromByteArray } from "base64-js"; + +import { test as particleTest } from "./_aqua/finalize_particle.js"; +import { + registerHelloWorld, + helloTest, + marineTest, +} from "./_aqua/smoke_test.js"; +import { wasm } from "./wasmb64.js"; const relay = { - multiaddr: '/ip4/127.0.0.1/tcp/9991/ws/p2p/12D3KooWBM3SdXWqGaawQDGQ6JprtwswEg3FWGvGhmgmMez1vRbR', - peerId: '12D3KooWBM3SdXWqGaawQDGQ6JprtwswEg3FWGvGhmgmMez1vRbR', + multiaddr: + "/ip4/127.0.0.1/tcp/9991/ws/p2p/12D3KooWBM3SdXWqGaawQDGQ6JprtwswEg3FWGvGhmgmMez1vRbR", + peerId: "12D3KooWBM3SdXWqGaawQDGQ6JprtwswEg3FWGvGhmgmMez1vRbR", }; function generateRandomUint8Array() { const uint8Array = new Uint8Array(32); + for (let i = 0; i < uint8Array.length; i++) { uint8Array[i] = Math.floor(Math.random() * 256); } + return uint8Array; } const optsWithRandomKeyPair = (): ClientConfig => { return { keyPair: { - type: 'Ed25519', + type: "Ed25519", source: generateRandomUint8Array(), }, } as const; }; -export type TestResult = { type: 'success'; data: string } | { type: 'failure'; error: string }; +export type TestResult = + | { type: "success"; data: string } + | { type: "failure"; error: string }; export const runTest = async (): Promise => { try { - Fluence.onConnectionStateChange((state) => console.info('connection state changed: ', state)); + Fluence.onConnectionStateChange((state) => { + return console.info("connection state changed: ", state); + }); - console.log('connecting to Fluence Network...'); - console.log('multiaddr: ', relay.multiaddr); + console.log("connecting to Fluence Network..."); + console.log("multiaddr: ", relay.multiaddr); await Fluence.connect(relay, optsWithRandomKeyPair()); - console.log('connected'); + console.log("connected"); const relayPeerId = (await Fluence.getClient()).getRelayPeerId(); - console.log('relay:', relayPeerId); + console.log("relay:", relayPeerId); await registerHelloWorld({ hello(str) { - return 'Hello, ' + str + '!'; + return "Hello, " + str + "!"; }, }); const client = await Fluence.getClient(); - console.log('my peer id: ', client.getPeerId()); - console.log('my sk id: ', fromByteArray(client.getPeerSecretKey())); + console.log("my peer id: ", client.getPeerId()); + console.log("my sk id: ", fromByteArray(client.getPeerSecretKey())); - console.log('running hello test...'); + console.log("running hello test..."); const hello = await helloTest(); - console.log('hello test finished, result: ', hello); + console.log("hello test finished, result: ", hello); - console.log('running marine test...'); + console.log("running marine test..."); const marine = await marineTest(wasm); - console.log('running particle test...'); + console.log("running particle test..."); await particleTest(); - - console.log('marine test finished, result: ', marine); + + console.log("marine test finished, result: ", marine); const returnVal = { hello, marine, }; - return { type: 'success', data: JSON.stringify(returnVal) }; + + return { type: "success", data: JSON.stringify(returnVal) }; } finally { - console.log('disconnecting from Fluence Network...'); + console.log("disconnecting from Fluence Network..."); await Fluence.disconnect(); - console.log('disconnected'); + console.log("disconnected"); } }; export const runMain = () => { runTest() - .then(() => console.log('done!')) - .catch((err) => console.error('error: ', err)); + .then(() => { + return console.log("done!"); + }) + .catch((err) => { + return console.error("error: ", err); + }); }; diff --git a/packages/@tests/aqua/src/wasmb64.ts b/packages/@tests/aqua/src/wasmb64.ts index 884eb1bab..e1e88fa3c 100644 --- a/packages/@tests/aqua/src/wasmb64.ts +++ b/packages/@tests/aqua/src/wasmb64.ts @@ -1 +1,18 @@ -export const wasm = "AGFzbQEAAAABmIGAgAAWYAAAYAABf2AAAXxgAX8AYAF/AX9gAX8BfmACf38AYAJ/fwF/YAN/f38AYAN/f38Bf2ADf39/AX5gBH9/f38AYAR/f39/AX9gBX9/f39/AGAFf39/f38Bf2AGf39/f39/AX9gB39/f39/f38AYAd/f39/f39/AX9gCX9/f39/f35+fgBgBH98f38Bf2ADfn9/AX9gAXwBfALRgYCAAAYEaG9zdA9sb2dfdXRmOF9zdHJpbmcACxZ3YXNpX3NuYXBzaG90X3ByZXZpZXcxCGZkX3dyaXRlAAwWd2FzaV9zbmFwc2hvdF9wcmV2aWV3MQpyYW5kb21fZ2V0AAcWd2FzaV9zbmFwc2hvdF9wcmV2aWV3MQtlbnZpcm9uX2dldAAHFndhc2lfc25hcHNob3RfcHJldmlldzERZW52aXJvbl9zaXplc19nZXQABxZ3YXNpX3NuYXBzaG90X3ByZXZpZXcxCXByb2NfZXhpdAADA9iCgIAA1gILBA0HCwgDBgkJBwsHDQcHCRMPCQ0DCwgJEwgIBw0JBwAEBgsKBwcSBwgHCw4QBhAJEQ4GBAcHBwcHBwsUBgQHCQcDBggAAwcHCQMMBgcHCAcHBwgICAYRDgEDDQsVBggIBgYVFRUEAwQDBAYGCwsLBwcHBwcHAAkHBwgEBw0LBAcHBwcDCAYGBggHBwYICAcHBwcHBwcHBwsHAgMLAAcGCQkJCwkLCQQDAwwJDAcDBwgGBgcDAAYABwcHBwcHAQQEAwgNCAsGBwYECAMIBwYGBAMDBwYGBggHBAMHBwcEAAwDAwcABwcHBwYHCwcEBAgHCQcHAwcHBwgJCQcHBwcGBwcHBwcGBgYGBgYGBggICAYGBgYJBxUVFRUDAwEGBgMDAwMAAAACAQEAAwAACAQEBAMABAQEAQEAAAcHBQUFBQQEBAAABQMDAwMDAwYDAwMDAwADAwMEhYCAgAABcAF0dAWDgICAAAEAEQaZgICAAAN/AUGAgMAAC38AQaCBwQALfwBBmIHBAAsH7oGAgAASBm1lbW9yeQIAC19faGVhcF9iYXNlAwEKX19kYXRhX2VuZAMCBl9zdGFydACpAgRtYWluAIMCCXRlc3RfbG9ncwCqAgNhZGQAnAIIc3VidHJhY3QAnQIIbXVsdGlwbHkAngIGZGl2aWRlAJ8CC2Ns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AAAgA0EGaiABQQZqLQAAOgAAIANBB2ogAUEHai0AADoAACADQQhqIQMgAUEIaiEBIARBeGoiBA0ACwsgAAuvCQEHfwJAAkAgAUH/CUsNACABQQV2IQICQAJAAkACQCAAKAIAIgNFDQAgACADQQJ0aiEEIAAgAyACakECdGohBSADQX9qIgNBJ0shBgNAIAYNBCACIANqIgdBKE8NAiAFIAQoAgA2AgAgBUF8aiEFIARBfGohBCADQX9qIgNBf0cNAAsLIAFBIEkNBCAAQQA2AgQgAUHAAE8NAQwECyAHQShB3PHAABCPAQALIABBCGpBADYCACACQQEgAkEBSxsiA0ECRg0CIABBDGpBADYCACADQQNGDQIgAEEQakEANgIAIANBBEYNAiAAQRRqQQA2AgAgA0EFRg0CIABBGGpBADYCACADQQZGDQIgAEEcakEANgIAIANBB0YNAiAAQSBqQQA2AgAgA0EIRg0CIABBJGpBADYCACADQQlGDQIgAEEoakEANgIAIANBCkYNAiAAQSxqQQA2AgAgA0ELRg0CIABBMGpBADYCACADQQxGDQIgAEE0akEANgIAIANBDUYNAiAAQThqQQA2AgAgA0EORg0CIABBPGpBADYCACADQQ9GDQIgAEHAAGpBADYCACADQRBGDQIgAEHEAGpBADYCACADQRFGDQIgAEHIAGpBADYCACADQRJGDQIgAEHMAGpBADYCACADQRNGDQIgAEHQAGpBADYCACADQRRGDQIgAEHUAGpBADYCACADQRVGDQIgAEHYAGpBADYCACADQRZGDQIgAEHcAGpBADYCACADQRdGDQIgAEHgAGpBADYCACADQRhGDQIgAEHkAGpBADYCACADQRlGDQIgAEHoAGpBADYCACADQRpGDQIgAEHsAGpBADYCACADQRtGDQIgAEHwAGpBADYCACADQRxGDQIgAEH0AGpBADYCACADQR1GDQIgAEH4AGpBADYCACADQR5GDQIgAEH8AGpBADYCACADQR9GDQIgAEGAAWpBADYCACADQSBGDQIgAEGEAWpBADYCACADQSFGDQIgAEGIAWpBADYCACADQSJGDQIgAEGMAWpBADYCACADQSNGDQIgAEGQAWpBADYCACADQSRGDQIgAEGUAWpBADYCACADQSVGDQIgAEGYAWpBADYCACADQSZGDQIgAEGcAWpBADYCACADQSdGDQIgAEGgAWpBADYCACADQShGDQJBKEEoQdzxwAAQjwEACyADQShB3PHAABCPAQALQYbywABBHUHc8cAAELYBAAsgACgCACACaiEEAkAgAUEfcSIGDQAgACAENgIAIAAPCwJAAkAgBEF/aiIDQSdLDQAgBCEIIAAgA0ECdGpBBGooAgAiBUEAIAFrIgF2IgNFDQECQCAEQSdLDQAgACAEQQJ0akEEaiADNgIAIARBAWohCAwCCyAEQShB3PHAABCPAQALIANBKEHc8cAAEI8BAAsCQAJAIAJBAWoiByAETw0AIAFBH3EhASAEQQJ0IABqQXxqIQMDQCAEQX5qQShPDQIgA0EEaiAFIAZ0IAMoAgAiBSABdnI2AgAgA0F8aiEDIAcgBEF/aiIESQ0ACwsgACACQQJ0akEEaiIDIAMoAgAgBnQ2AgAgACAINgIAIAAPC0F/QShB3PHAABCPAQAL5QkBBX8jAEHwAGsiBCQAIAQgAzYCDCAEIAI2AggCQAJAAkACQAJAAkACQAJAIAFBgQJJDQBBgAIhBQJAIAAsAIACQb9/Sg0AQf8BIQUgACwA/wFBv39KDQBB/gEhBSAALAD+AUG/f0oNAEH9ASEFCyAFIAFJDQEgBSABRw0DCyAEIAE2AhQgBCAANgIQQQAhBUG4wsAAIQYMAQsgBCAFNgIUIAQgADYCEEEFIQVBn+PAACEGCyAEIAU2AhwgBCAGNgIYIAIgAUsiBQ0BIAMgAUsNAQJAIAIgA0sNAAJAAkAgAkUNAAJAIAIgAUkNACABIAJGDQEMAgsgACACaiwAAEFASA0BCyADIQILIAQgAjYCICABIQMCQCACIAFPDQAgAkEBaiIFQQAgAkF9aiIDIAMgAksbIgNJDQQCQCADIAVGDQAgACAFaiAAIANqIgdrIQUCQCAAIAJqIggsAABBv39MDQAgBUF/aiEGDAELIAMgAkYNAAJAIAhBf2oiAiwAAEG/f0wNACAFQX5qIQYMAQsgByACRg0AAkAgCEF+aiICLAAAQb9/TA0AIAVBfWohBgwBCyAHIAJGDQACQCAIQX1qIgIsAABBv39MDQAgBUF8aiEGDAELIAcgAkYNACAFQXtqIQYLIAYgA2ohAwsCQCADRQ0AAkAgAyABSQ0AIAMgAUYNAQwHCyAAIANqLAAAQb9/TA0GCyADIAFGDQQCQAJAAkACQCAAIANqIgIsAAAiAUF/Sg0AIAItAAFBP3EhACABQR9xIQUgAUFfSw0BIAVBBnQgAHIhAgwCCyAEIAFB/wFxNgIkQQEhAQwCCyAAQQZ0IAItAAJBP3FyIQACQCABQXBPDQAgACAFQQx0ciECDAELIABBBnQgAi0AA0E/cXIgBUESdEGAgPAAcXIiAkGAgMQARg0GCyAEIAI2AiRBASEBIAJBgAFJDQBBAiEBIAJBgBBJDQBBA0EEIAJBgIAESRshAQsgBCADNgIoIAQgASADajYCLCAEQTBqQRRqQQU2AgAgBEHsAGpB4QA2AgAgBEHkAGpB4QA2AgAgBEHIAGpBFGpB4gA2AgAgBEHUAGpB4wA2AgAgBEIFNwI0IARBiOXAADYCMCAEQSI2AkwgBCAEQcgAajYCQCAEIARBGGo2AmggBCAEQRBqNgJgIAQgBEEoajYCWCAEIARBJGo2AlAgBCAEQSBqNgJIIARBMGpBsOXAABC8AQALIARB5ABqQeEANgIAIARByABqQRRqQeEANgIAIARB1ABqQSI2AgAgBEEwakEUakEENgIAIARCBDcCNCAEQZTkwAA2AjAgBEEiNgJMIAQgBEHIAGo2AkAgBCAEQRhqNgJgIAQgBEEQajYCWCAEIARBDGo2AlAgBCAEQQhqNgJIIARBMGpBtOTAABC8AQALIAAgAUEAIAUgBBDJAQALIAQgAiADIAUbNgIoIARBMGpBFGpBAzYCACAEQcgAakEUakHhADYCACAEQdQAakHhADYCACAEQgM3AjQgBEHI48AANgIwIARBIjYCTCAEIARByABqNgJAIAQgBEEYajYCWCAEIARBEGo2AlAgBCAEQShqNgJIIARBMGpB4OPAABC8AQALIAMgBSAEEJUCAAtBgNrAAEErQcTkwAAQtgEACyAAIAEgAyABIAQQyQEAC6MIAQl/AkACQCAAQQNqQXxxIgIgAGsiAyABSw0AIANBBEsNACABIANrIgRBBEkNACAEQQNxIQVBACEGQQAhAQJAIANFDQAgA0EDcSEHAkACQCACIABBf3NqQQNPDQBBACEBIAAhAgwBCyADQXxxIQhBACEBIAAhAgNAIAEgAiwAAEG/f0pqIAJBAWosAABBv39KaiACQQJqLAAAQb9/SmogAkEDaiwAAEG/f0pqIQEgAkEEaiECIAhBfGoiCA0ACwsgB0UNAANAIAEgAiwAAEG/f0pqIQEgAkEBaiECIAdBf2oiBw0ACwsgACADaiEAAkAgBUUNACAAIARBfHFqIgIsAABBv39KIQYgBUEBRg0AIAYgAiwAAUG/f0pqIQYgBUECRg0AIAYgAiwAAkG/f0pqIQYLIARBAnYhAyAGIAFqIQgDQCAAIQYgA0UNAiADQcABIANBwAFJGyIEQQNxIQUgBEECdCEJAkACQCAEQfwBcSIKQQJ0IgANAEEAIQIMAQsgBiAAaiEHQQAhAiAGIQADQCAAQQxqKAIAIgFBf3NBB3YgAUEGdnJBgYKECHEgAEEIaigCACIBQX9zQQd2IAFBBnZyQYGChAhxIABBBGooAgAiAUF/c0EHdiABQQZ2ckGBgoQIcSAAKAIAIgFBf3NBB3YgAUEGdnJBgYKECHEgAmpqamohAiAAQRBqIgAgB0cNAAsLIAYgCWohACADIARrIQMgAkEIdkH/gfwHcSACQf+B/AdxakGBgARsQRB2IAhqIQggBUUNAAsgBiAKQQJ0aiEAIAVB/////wNqIgRB/////wNxIgJBAWoiAUEDcSEDAkACQCACQQNPDQBBACECDAELIAFB/P///wdxIQFBACECA0AgAEEMaigCACIHQX9zQQd2IAdBBnZyQYGChAhxIABBCGooAgAiB0F/c0EHdiAHQQZ2ckGBgoQIcSAAQQRqKAIAIgdBf3NBB3YgB0EGdnJBgYKECHEgACgCACIHQX9zQQd2IAdBBnZyQYGChAhxIAJqampqIQIgAEEQaiEAIAFBfGoiAQ0ACwsCQCADRQ0AIARBgYCAgHxqIQEDQCAAKAIAIgdBf3NBB3YgB0EGdnJBgYKECHEgAmohAiAAQQRqIQAgAUF/aiIBDQALCyACQQh2Qf+B/AdxIAJB/4H8B3FqQYGABGxBEHYgCGoPCwJAIAENAEEADwsgAUEDcSECAkACQCABQX9qQQNPDQBBACEIDAELIAFBfHEhAUEAIQgDQCAIIAAsAABBv39KaiAAQQFqLAAAQb9/SmogAEECaiwAAEG/f0pqIABBA2osAABBv39KaiEIIABBBGohACABQXxqIgENAAsLIAJFDQADQCAIIAAsAABBv39KaiEIIABBAWohACACQX9qIgINAAsLIAgLywgCCH8HfgJAAkACQAJAAkACQAJAIAEpAwAiDVANACANQv//////////H1YNASADRQ0DQaB/IAEvARgiAUFgaiABIA1CgICAgBBUIgUbIgFBcGogASANQiCGIA0gBRsiDUKAgICAgIDAAFQiBRsiAUF4aiABIA1CEIYgDSAFGyINQoCAgICAgICAAVQiBRsiAUF8aiABIA1CCIYgDSAFGyINQoCAgICAgICAEFQiBRsiAUF+aiABIA1CBIYgDSAFGyINQoCAgICAgICAwABUIgUbIA1CAoYgDSAFGyINQj+Hp0F/c2oiBWtBEHRBEHVB0ABsQbCnBWpBzhBtIgFB0QBPDQIgAUEEdCIBQeLJwABqLwEAIQYCQAJAAkACQCABQdjJwABqKQMAIg5C/////w+DIg8gDSANQn+FQj+IhiINQiCIIhB+IhFCIIggDkIgiCIOIBB+fCAOIA1C/////w+DIg1+Ig5CIIh8IBFC/////w+DIA8gDX5CIIh8IA5C/////w+DfEKAgICACHxCIIh8Ig1BQCAFIAFB4MnAAGovAQBqayIBQT9xrSIQiKciB0GQzgBJDQAgB0HAhD1JDQEgB0GAwtcvSQ0CQQhBCSAHQYCU69wDSSIFGyEIQYDC1y9BgJTr3AMgBRshBQwDCwJAIAdB5ABJDQBBAkEDIAdB6AdJIgUbIQhB5ABB6AcgBRshBQwDC0EBQQogB0EKSRshBSAHQQlLIQgMAgtBBEEFIAdBoI0GSSIFGyEIQZDOAEGgjQYgBRshBQwBC0EGQQcgB0GAreIESSIFGyEIQcCEPUGAreIEIAUbIQULQgEgEIYhEgJAAkAgCCAGa0EQdEGAgARqQRB1IgkgBEEQdEEQdSIGTA0AIA0gEkJ/fCIRgyEOIAFB//8DcSEKIAkgBGtBEHRBEHUgAyAJIAZrIANJGyILQX9qIQxBACEBA0AgByAFbiEGIAMgAUYNByAHIAYgBWxrIQcgAiABaiAGQTBqOgAAIAwgAUYNCCAIIAFGDQIgAUEBaiEBIAVBCkkhBiAFQQpuIQUgBkUNAAtB4NXAAEEZQZTXwAAQtgEACyAAIAIgA0EAIAkgBCANQgqAIAWtIBCGIBIQLQ8LIAFBAWoiASADIAEgA0sbIQUgCkF/akE/ca0hE0IBIQ0DQAJAIA0gE4hQDQAgAEEANgIADwsgBSABRg0HIA1CCn4hDSAOQgp+Ig8gEYMhDiACIAFqIA8gEIinQTBqOgAAIAsgAUEBaiIBRw0ACyAAIAIgAyALIAkgBCAOIBIgDRAtDwtB78XAAEEcQcDWwAAQtgEAC0HQ1sAAQSRB9NbAABC2AQALIAFB0QBBmNTAABCPAQALQZzWwABBIUGE18AAELYBAAsgAyADQaTXwAAQjwEACyAAIAIgAyALIAkgBCAHrSAQhiAOfCAFrSAQhiASEC0PCyAFIANBtNfAABCPAQALsQgBC38CQCAADQAgARAHDwsCQCABQUBJDQBBAEEwNgLwgEFBAA8LQRAgAUETakFwcSABQQtJGyECIABBfGoiAygCACIEQXhxIQUCQAJAAkAgBEEDcQ0AIAJBgAJJDQEgBSACQQRySQ0BIAUgAmtBACgC4IBBQQF0TQ0CDAELIABBeGoiBiAFaiEHAkAgBSACSQ0AIAUgAmsiAUEQSQ0CIAMgAiAEQQFxckECcjYCACAGIAJqIgIgAUEDcjYCBCAHIAcoAgRBAXI2AgQgAiABEA0gAA8LAkBBACgCmP1AIAdHDQBBACgCjP1AIAVqIgUgAk0NASADIAIgBEEBcXJBAnI2AgBBACAGIAJqIgE2Apj9QEEAIAUgAmsiAjYCjP1AIAEgAkEBcjYCBCAADwsCQEEAKAKU/UAgB0cNAEEAKAKI/UAgBWoiBSACSQ0BAkACQCAFIAJrIgFBEEkNACADIAIgBEEBcXJBAnI2AgAgBiACaiICIAFBAXI2AgQgBiAFaiIFIAE2AgAgBSAFKAIEQX5xNgIEDAELIAMgBEEBcSAFckECcjYCACAGIAVqIgEgASgCBEEBcjYCBEEAIQFBACECC0EAIAI2ApT9QEEAIAE2Aoj9QCAADwsgBygCBCIIQQJxDQAgCEF4cSAFaiIJIAJJDQAgCSACayEKAkACQCAIQf8BSw0AIAcoAggiASAIQQN2IgtBA3RBqP3AAGoiCEYaAkAgBygCDCIFIAFHDQBBAEEAKAKA/UBBfiALd3E2AoD9QAwCCyAFIAhGGiAFIAE2AgggASAFNgIMDAELIAcoAhghDAJAAkAgBygCDCIIIAdGDQBBACgCkP1AIAcoAggiAUsaIAggATYCCCABIAg2AgwMAQsCQCAHQRRqIgEoAgAiBQ0AIAdBEGoiASgCACIFDQBBACEIDAELA0AgASELIAUiCEEUaiIBKAIAIgUNACAIQRBqIQEgCCgCECIFDQALIAtBADYCAAsgDEUNAAJAAkAgBygCHCIFQQJ0QbD/wABqIgEoAgAgB0cNACABIAg2AgAgCA0BQQBBACgChP1AQX4gBXdxNgKE/UAMAgsgDEEQQRQgDCgCECAHRhtqIAg2AgAgCEUNAQsgCCAMNgIYAkAgBygCECIBRQ0AIAggATYCECABIAg2AhgLIAcoAhQiAUUNACAIQRRqIAE2AgAgASAINgIYCwJAIApBD0sNACADIARBAXEgCXJBAnI2AgAgBiAJaiIBIAEoAgRBAXI2AgQgAA8LIAMgAiAEQQFxckECcjYCACAGIAJqIgEgCkEDcjYCBCAGIAlqIgIgAigCBEEBcjYCBCABIAoQDSAADwsCQCABEAciAg0AQQAPCyACIABBfEF4IAMoAgAiBUEDcRsgBUF4cWoiBSABIAUgAUkbEA4hASAAEAwgASEACyAAC+sHAQF/AkACQAJAAkACQAJAAkAgAUF9ag4DAAIBAwsgAC0AACIBQWBqIAEgAUGff2pB/wFxQRpJG0H/AXFBzwBHDQIgAC0AASIBQWBqIAEgAUGff2pB/wFxQRpJG0H/AXFBxgBHDQJBACECIAAtAAIiAEFgaiAAIABBn39qQf8BcUEaSRtB/wFxQcYARw0CDAULAkAgAC0AACIBQWBqIAEgAUGff2pB/wFxQRpJG0H/AXFBxQBHDQAgAC0AASIBQWBqIAEgAUGff2pB/wFxQRpJG0H/AXFB0gBHDQAgAC0AAiIBQWBqIAEgAUGff2pB/wFxQRpJG0H/AXFB0gBHDQAgAC0AAyIBQWBqIAEgAUGff2pB/wFxQRpJG0H/AXFBzwBHDQBBASECIAAtAAQiAUFgaiABIAFBn39qQf8BcUEaSRtB/wFxQdIARg0FC0EGIQIgAC0AACIBQWBqIAEgAUGff2pB/wFxQRpJG0H/AXFBvH9qDhECBAQEBAQEBAQEBAQEBAQEAwQLAkACQCAALQAAIgFBYGogASABQZ9/akH/AXFBGkkbQf8BcUG3f2oODwECAgICAgICAgICAgICAAILIAAtAAEiAUFgaiABIAFBn39qQf8BcUEaSRtB/wFxQcEARw0BIAAtAAIiAUFgaiABIAFBn39qQf8BcUEaSRtB/wFxQdIARw0BQQIhAiAALQADIgBBYGogACAAQZ9/akH/AXFBGkkbQf8BcUHOAEcNAQwECyAALQABIgFBYGogASABQZ9/akH/AXFBGkkbQf8BcUHOAEcNACAALQACIgFBYGogASABQZ9/akH/AXFBGkkbQf8BcUHGAEcNAEEDIQIgAC0AAyIAQWBqIAAgAEGff2pB/wFxQRpJG0H/AXFBzwBGDQMLQQYPCwJAIAAtAAEiAUFgaiABIAFBn39qQf8BcUEaSRtB/wFxQcUARw0AIAAtAAIiAUFgaiABIAFBn39qQf8BcUEaSRtB/wFxQcIARw0AIAAtAAMiAUFgaiABIAFBn39qQf8BcUEaSRtB/wFxQdUARw0AQQQhAiAALQAEIgBBYGogACAAQZ9/akH/AXFBGkkbQf8BcUHHAEYNAgtBBg8LAkAgAC0AASIBQWBqIAEgAUGff2pB/wFxQRpJG0H/AXFB0gBGDQBBBg8LAkAgAC0AAiIBQWBqIAEgAUGff2pB/wFxQRpJG0H/AXFBwQBGDQBBBg8LQQYhAiAALQADIgFBYGogASABQZ9/akH/AXFBGkkbQf8BcUHDAEcNAEEFQQYgAC0ABCIAQWBqIAAgAEGff2pB/wFxQRpJG0H/AXFBxQBGGyECCyACC7wHAQZ/IAAoAhAhAwJAAkACQAJAAkACQCAAKAIIIgRBAUYNACADQQFHDQELIANBAUcNAyABIAJqIQUgAEEUaigCACIGDQFBACEHIAEhCAwCCyAAKAIYIAEgAiAAQRxqKAIAKAIMEQkAIQMMAwtBACEHIAEhCANAIAgiAyAFRg0CAkACQCADLAAAIghBf0wNACADQQFqIQgMAQsCQCAIQWBPDQAgA0ECaiEIDAELAkAgCEFwTw0AIANBA2ohCAwBCyADLQACQT9xQQZ0IAMtAAFBP3FBDHRyIAMtAANBP3FyIAhB/wFxQRJ0QYCA8ABxckGAgMQARg0DIANBBGohCAsgByADayAIaiEHIAZBf2oiBg0ACwsgCCAFRg0AAkAgCCwAACIDQX9KDQAgA0FgSQ0AIANBcEkNACAILQACQT9xQQZ0IAgtAAFBP3FBDHRyIAgtAANBP3FyIANB/wFxQRJ0QYCA8ABxckGAgMQARg0BCwJAAkACQCAHDQBBACEIDAELAkAgByACSQ0AQQAhAyACIQggByACRg0BDAILQQAhAyAHIQggASAHaiwAAEFASA0BCyAIIQcgASEDCyAHIAIgAxshAiADIAEgAxshAQsCQCAEDQAgACgCGCABIAIgAEEcaigCACgCDBEJAA8LIABBDGooAgAhBQJAAkAgAkEQSQ0AIAEgAhASIQgMAQsCQCACDQBBACEIDAELIAJBA3EhBwJAAkAgAkF/akEDTw0AQQAhCCABIQMMAQsgAkF8cSEGQQAhCCABIQMDQCAIIAMsAABBv39KaiADQQFqLAAAQb9/SmogA0ECaiwAAEG/f0pqIANBA2osAABBv39KaiEIIANBBGohAyAGQXxqIgYNAAsLIAdFDQADQCAIIAMsAABBv39KaiEIIANBAWohAyAHQX9qIgcNAAsLAkAgBSAITQ0AQQAhAyAFIAhrIgchBgJAAkACQEEAIAAtACAiCCAIQQNGG0EDcQ4DAgABAgtBACEGIAchAwwBCyAHQQF2IQMgB0EBakEBdiEGCyADQQFqIQMgAEEcaigCACEHIAAoAgQhCCAAKAIYIQACQANAIANBf2oiA0UNASAAIAggBygCEBEHAEUNAAtBAQ8LQQEhAyAIQYCAxABGDQEgACABIAIgBygCDBEJAA0BQQAhAwNAAkAgBiADRw0AIAYgBkkPCyADQQFqIQMgACAIIAcoAhARBwBFDQALIANBf2ogBkkPCyAAKAIYIAEgAiAAQRxqKAIAKAIMEQkADwsgAwvnCAIFfwZ+IwBB8AhrIgQkACABvSEJAkACQCABIAFhDQBBAiEFDAELIAlC/////////weDIgpCgICAgICAgAiEIAlCAYZC/v///////w+DIAlCNIinQf8PcSIGGyILQgGDIQxBAyEFAkACQAJAQQFBAkEEIAlCgICAgICAgPj/AIMiDVAiBxsgDUKAgICAgICA+P8AURtBA0EEIAcbIApQG0F/ag4EAwABAgMLQQQhBQwCCyAGQc13aiEIIAynQQFzIQVCASEODAELQoCAgICAgIAgIAtCAYYgC0KAgICAgICACFEiCBshC0ICQgEgCBshDiAMp0EBcyEFQct3Qcx3IAgbIAZqIQgLIAQgCDsB6AggBCAONwPgCCAEQgE3A9gIIAQgCzcD0AggBCAFOgDqCAJAAkAgBUECRw0AQbjCwAAhB0EAIQIMAQsCQCACDQBB49jAAEG4wsAAIAlCAFMbIQcgCUI/iKchAgwBC0Hj2MAAQeTYwAAgCUIAUxshB0EBIQILAkACQAJAAkACQAJAAkAgBUF+aiIFQQMgBUEDSRtB/wFxDgQAAQMCAAsgBEEDNgKYCCAEQenYwAA2ApQIIARBAjsBkAggBCACNgLECCAEIAc2AsAIIAQgBEGQCGo2AsgIQQEhBQwFCyAEQQM2ApgIIARB5tjAADYClAggBEECOwGQCCAEIAI2AsQIIAQgBzYCwAggBCAEQZAIajYCyAhBASEFDAQLQXRBBSAIQRB0QRB1IgVBAEgbIAVsIgVBv/0ASw0BIARBkAhqIARB0AhqIARBEGogBUEEdkEVaiIIQQAgA2tBgIB+IANBgIACSRsiBRATIAVBEHRBEHUhBQJAAkAgBCgCkAgNACAEQcAIaiAEQdAIaiAEQRBqIAggBRAIDAELIARBwAhqQQhqIARBkAhqQQhqKAIANgIAIAQgBCkDkAg3A8AICwJAIAQuAcgIIgggBUwNACAEQQhqIAQoAsAIIAQoAsQIIAggAyAEQZAIakEEEDMgBCACNgLECCAEIAc2AsAIIAQgBCgCCDYCyAggBCgCDCEFDAQLQQIhBSAEQQI7AZAIAkAgAw0AQQEhBSAEQQE2ApgIIARB5djAADYClAggBCACNgLECCAEIAc2AsAIIAQgBEGQCGo2AsgIDAQLIARBoAhqIAM2AgAgBEEAOwGcCCAEQQI2ApgIIARB4NjAADYClAggBCACNgLECCAEIAc2AsAIIAQgBEGQCGo2AsgIDAMLQQIhBSAEQQI7AZAIIANFDQEgBEGgCGogAzYCACAEQQA7AZwIIARBAjYCmAggBEHg2MAANgKUCCAEIAI2AsQIIAQgBzYCwAggBCAEQZAIajYCyAgMAgtB7NjAAEElQZTZwAAQtgEAC0EBIQUgBEEBNgKYCCAEQeXYwAA2ApQIIAQgAjYCxAggBCAHNgLACCAEIARBkAhqNgLICAsgBEHMCGogBTYCACAAIARBwAhqECUhBSAEQfAIaiQAIAUL1AcBB38CQAJAIAFFDQBBK0GAgMQAIAAoAgAiAUEBcSIGGyEHIAYgBWohCAwBCyAFQQFqIQggACgCACEBQS0hBwsCQAJAIAFBBHENAEEAIQIMAQsCQAJAIANBEEkNACACIAMQEiEGDAELAkAgAw0AQQAhBgwBCyADQQNxIQkCQAJAIANBf2pBA08NAEEAIQYgAiEBDAELIANBfHEhCkEAIQYgAiEBA0AgBiABLAAAQb9/SmogAUEBaiwAAEG/f0pqIAFBAmosAABBv39KaiABQQNqLAAAQb9/SmohBiABQQRqIQEgCkF8aiIKDQALCyAJRQ0AA0AgBiABLAAAQb9/SmohBiABQQFqIQEgCUF/aiIJDQALCyAGIAhqIQgLAkACQCAAKAIIDQBBASEBIAAgByACIAMQsgENASAAKAIYIAQgBSAAQRxqKAIAKAIMEQkADwsCQAJAAkACQAJAIABBDGooAgAiBiAITQ0AIAAtAABBCHENBEEAIQEgBiAIayIJIQhBASAALQAgIgYgBkEDRhtBA3EOAwMBAgMLQQEhASAAIAcgAiADELIBDQQgACgCGCAEIAUgAEEcaigCACgCDBEJAA8LQQAhCCAJIQEMAQsgCUEBdiEBIAlBAWpBAXYhCAsgAUEBaiEBIABBHGooAgAhCSAAKAIEIQYgACgCGCEKAkADQCABQX9qIgFFDQEgCiAGIAkoAhARBwBFDQALQQEPC0EBIQEgBkGAgMQARg0BIAAgByACIAMQsgENASAAKAIYIAQgBSAAKAIcKAIMEQkADQEgACgCHCEJIAAoAhghAEEAIQECQANAAkAgCCABRw0AIAghAQwCCyABQQFqIQEgACAGIAkoAhARBwBFDQALIAFBf2ohAQsgASAISSEBDAELIAAoAgQhCyAAQTA2AgQgAC0AICEMQQEhASAAQQE6ACAgACAHIAIgAxCyAQ0AQQAhASAGIAhrIgkhAwJAAkACQEEBIAAtACAiBiAGQQNGG0EDcQ4DAgABAgtBACEDIAkhAQwBCyAJQQF2IQEgCUEBakEBdiEDCyABQQFqIQEgAEEcaigCACEJIAAoAgQhBiAAKAIYIQoCQANAIAFBf2oiAUUNASAKIAYgCSgCEBEHAEUNAAtBAQ8LQQEhASAGQYCAxABGDQAgACgCGCAEIAUgACgCHCgCDBEJAA0AIAAoAhwhASAAKAIYIQpBACEJAkADQCADIAlGDQEgCUEBaiEJIAogBiABKAIQEQcARQ0AC0EBIQEgCUF/aiADSQ0BCyAAIAw6ACAgACALNgIEQQAPCyABC/wHAgx/AX5BASEDAkACQCACKAIYIgRBIiACQRxqKAIAIgUoAhAiBhEHAA0AAkACQCABDQBBACEHDAELIAAgAWohCEEAIQcgACEJIAAhCkEAIQsCQANAAkACQCAKLAAAIgJBf0wNACAKQQFqIQogAkH/AXEhDAwBCyAKLQABQT9xIQ0gAkEfcSEDAkAgAkFfSw0AIANBBnQgDXIhDCAKQQJqIQoMAQsgDUEGdCAKLQACQT9xciENAkAgAkFwTw0AIA0gA0EMdHIhDCAKQQNqIQoMAQsgDUEGdCAKLQADQT9xciADQRJ0QYCA8ABxciIMQYCAxABGDQIgCkEEaiEKC0EwIQ5BAiECAkACQAJAAkACQAJAAkACQAJAAkAgDA4jBwEBAQEBAQEBAgQBAQMBAQEBAQEBAQEBAQEBAQEBAQEBAQUACyAMQdwARg0ECwJAIAwQOg0AIAwQbg0HCyAMQQFyZ0ECdkEHc61CgICAgNAAhCEPQQMhAiAMIQ4MBQtB9AAhDgwDC0HyACEODAILQe4AIQ4MAQsgDCEOCwsgCyAHSQ0BAkAgB0UNAAJAIAcgAUkNACAHIAFGDQEMAwsgACAHaiwAAEFASA0CCwJAIAtFDQACQCALIAFJDQAgCyABRw0DDAELIAAgC2osAABBv39MDQILAkAgBCAAIAdqIAsgB2sgBSgCDBEJAEUNAEEBDwsDQCACIQ1BASEDQdwAIQdBASECAkACQAJAAkACQAJAIA0OBAIBBQACCwJAAkACQAJAIA9CIIinQf8BcQ4GBQYDAAECBQsgD0L/////j2CDQoCAgIAghCEPQQMhAkH7ACEHDAcLIA9C/////49gg0KAgICAMIQhD0EDIQJB9QAhBwwGCyAPQv////+PYINCgICAgMAAhCEPQQMhAgwFC0EwQdcAIA4gD6ciAkECdHZBD3EiB0EKSRsgB2ohByACRQ0DIA9Cf3xC/////w+DIA9CgICAgHCDhCEPQQMhAgwEC0EAIQIgDiEHDAMLQQEhAgJAIAxBgAFJDQBBAiECIAxBgBBJDQBBA0EEIAxBgIAESRshAgsgAiALaiEHDAQLIA9C/////49ggyEPQQMhAkH9ACEHDAELIA9C/////49gg0KAgICAEIQhD0EDIQILIAQgByAGEQcARQ0ADAYLCyALIAlrIApqIQsgCiEJIAogCEcNAQwCCwsgACABIAcgCyACEMkBAAsCQCAHDQBBACEHDAELAkAgByABSQ0AIAcgAUYNAQwDCyAAIAdqLAAAQb9/TA0CC0EBIQMgBCAAIAdqIAEgB2sgBSgCDBEJAA0AIARBIiAGEQcADwsgAw8LIAAgASAHIAEgAhDJAQALiwgBA38jAEHwAGsiBSQAQQBBACgCyPxAIgZBAWo2Asj8QEEAQQAoAvz8QEEBaiIHNgL8/EACQAJAAkACQCAGQQBIDQAgB0ECSw0AIAUgBDoAICAFIAM2AhwgBSACNgIYQQAoArz8QCIGQX9MDQJBACAGQQFqNgK8/EBBACgCxPxAIgZFDQFBACgCwPxAIQIgBUEIaiAAIAEoAhARBgAgBSAFKQMINwMQIAIgBUEQaiAGKAIUEQYADAMLAkACQCAHQQJLDQAgBSAEOgBAIAUgAzYCPCAFIAI2AjggBUGIjMAANgI0IAVB+IvAADYCMCAFQSc2AkwgBSAFQTBqNgJIIAVBBDoAFCAFIAVB6ABqNgIQIAVB5ABqQQE2AgAgBUICNwJUIAVBvJ7AADYCUCAFIAVByABqNgJgAkAgBUEQakHslMAAIAVB0ABqECRFDQAgBS0AFEEERg0CIAUtABRBA0cNAiAFQRhqKAIAIgUoAgAgBSgCBCgCABEDAAJAIAUoAgQiBygCBCIGRQ0AIAUoAgAgBiAHKAIIEPUBCyAFQQxBBBD1ARCxAgALIAUtABRBA0cNASAFQRhqKAIAIgcoAgAgBygCBCgCABEDAAJAIAcoAgQiBigCBCIERQ0AIAcoAgAgBCAGKAIIEPUBCyAFKAIYQQxBBBD1ARCxAgALIAVBBDoANCAFIAVB6ABqNgIwIAVB5ABqQQA2AgAgBUH4i8AANgJgIAVCATcCVCAFQYCewAA2AlACQCAFQTBqQeyUwAAgBUHQAGoQJEUNACAFLQA0QQRGDQEgBS0ANEEDRw0BIAVBOGooAgAiBSgCACAFKAIEKAIAEQMAAkAgBSgCBCIHKAIEIgZFDQAgBSgCACAGIAcoAggQ9QELIAVBDEEEEPUBELECAAsgBS0ANEEDRw0AIAVBOGooAgAiBygCACAHKAIEKAIAEQMAAkAgBygCBCIGKAIEIgRFDQAgBygCACAEIAYoAggQ9QELIAUoAjhBDEEEEPUBCxCxAgALIAUgACABKAIQEQYAIAUgBSkDADcDECAFQRBqEBsMAQsgBUEwakEUakEBNgIAIAVB0ABqQRRqQQA2AgAgBUICNwI0IAVBiI/AADYCMCAFQSA2AkwgBUH4i8AANgJgIAVCATcCVCAFQfyhwAA2AlAgBSAFQcgAajYCQCAFIAVB0ABqNgJIIAVBKGogBUHoAGogBUEwahBaIAVBKGoQrgEQsQIAC0EAQQAoArz8QEF/ajYCvPxAAkAgB0EBSw0AIARFDQAgACABEHIACyAFQeQAakEANgIAIAVB+IvAADYCYCAFQgE3AlQgBUH4nsAANgJQIAVBMGogBUHoAGogBUHQAGoQWiAFQTBqEK4BELECAAvOBwIFfwF+IwBB4ABrIgEkAEEBIQICQEEAKAL8/EBBAUsNABBfQf8BcSECCyABIAI6ABsCQAJAAkACQAJAAkAgABC6AiICRQ0AIAEgAjYCHCABQRBqIAAQmQIgASgCECICIAEoAhQoAgwRBQAhBgJAAkACQCACRQ0AIAZCi+TnlfK4j9e4f1ENAQsgAUEIaiAAEJkCQeiawAAhA0EMIQAgASgCCCICIAEoAgwoAgwRBQAhBgJAIAJFDQAgBkLJ2d2oxoHTuNYAUg0AIAJBCGooAgAhACACKAIAIQMLIAEgAzYCIAwBCyABIAIoAgA2AiAgAigCBCEACyABIAA2AiRBACgC9PxADQFBAEF/NgL0/EACQEEAKAL4/EAiAA0AQQBBACABEFMiADYC+PxACyAAIAAoAgAiAkEBajYCACACQX9MDQJBAEEAKAL0/EBBAWo2AvT8QAJAAkAgAA0AQQAhAgwBCyAAQRRqKAIAQX9qIQMgACgCECECCyABIANBCSACGzYCLCABIAJB9JrAACACGzYCKCABIAFBG2o2AjwgASABQRxqNgI4IAEgAUEgajYCNCABIAFBKGo2AjACQEEALQCJ/EBFDQBBAEEBOgCJ/EACQEEAKALo/EANAEEAQgE3Auj8QAwBC0EAKALs/EAhAkEAQQA2Auz8QCACDQQLIAFBMGogAUHIAGpBgJvAABAdQQAhA0EAIQIMBAtBmIzAAEErQdiawAAQtgEAC0H4i8AAQRAgAUHIAGpBxIzAAEGQmcAAEIMBAAsACyACLQAIIQMgAkEBOgAIIAEgA0EBcSIDOgBHIAMNAQJAAkACQEEAKALI/EBB/////wdxDQAgAUEwaiACQQxqQaibwAAQHQwBCxCiAiEDIAFBMGogAkEMakGom8AAEB0gA0UNAQtBACgCyPxAQf////8HcUUNABCiAg0AIAJBAToACQtBASEDQQBBAToAifxAIAJBADoACAJAQQAoAuj8QA0AQQAgAjYC7PxAQQEhA0EAQQE2Auj8QAwBC0EAKALs/EAhBEEAIAI2Auz8QCAERQ0AIAQgBCgCACIFQX9qNgIAQQEhAyAFQQFHDQAgBBC0AQsCQCAARQ0AIAAgACgCACIEQX9qNgIAIARBAUcNACAAEKEBCwJAIANBf3MgAkEAR3FFDQAgAiACKAIAIgBBf2o2AgAgAEEBRw0AIAIQtAELIAFB4ABqJAAPCyABQdwAakEANgIAIAFB2ABqQfiLwAA2AgAgAUIBNwJMIAFBkKHAADYCSCABQccAaiABQcgAahCSAQALtgYBCX8jAEEgayIEJAACQAJAAkAgAw0AQQAhBQwBCyACQQRqIQYgA0F/akH/////AXFBAWohB0EAIQUCQANAIAYoAgANASAGQQhqIQYgByAFQQFqIgVHDQALIAchBQsgBSADSw0BCwJAAkACQAJAIAMgBWsiCEUNACACIAVBA3RqIQkgAUEEaiEKA0AgCEF/akH/////AXEiBkEBaiILQQdxIQUCQAJAIAZBB08NAEEAIQMgCSEGDAELIAlBPGohBiALQfj///8DcSEHQQAhAwNAIAYoAgAgBkF4aigCACAGQXBqKAIAIAZBaGooAgAgBkFgaigCACAGQVhqKAIAIAZBUGooAgAgBkFIaigCACADampqampqamohAyAGQcAAaiEGIAdBeGoiBw0ACyAGQURqIQYLAkAgBUUNACAGQQRqIQYDQCAGKAIAIANqIQMgBkEIaiEGIAVBf2oiBQ0ACwsgCEEDdCEFAkAgCigCACABKAIIIgZrIANPDQAgASAGIAMQZiABKAIIIQYLIAkgBWohDCAJIQUDQCAFKAIAIQICQCAKKAIAIAZrIAVBBGooAgAiB08NACABIAYgBxBmIAEoAgghBgsgASgCACAGaiACIAcQDhogASAGIAdqIgY2AgggDCAFQQhqIgVHDQALAkAgAw0AIABBhJPAAK1CIIZCAoQ3AgAMAwsgCUEEaiEGQQAhBUEAIQcCQANAIAYoAgAgB2oiAiADSw0BIAZBCGohBiACIQcgCyAFQQFqIgVHDQALIAIhByALIQULIAggBUkNAwJAIAggBWsiCA0AIAMgB0YNAiAEQRxqQQA2AgAgBEH4i8AANgIYIARCATcCDCAEQZCUwAA2AgggBEEIakGYlMAAELwBAAsgCSAFQQN0IgVqIgIoAgQiDCADIAdrIgZJDQQgAkEEaiAMIAZrNgIAIAkgBWoiCSAJKAIAIAZqNgIADAALCyAAQQQ6AAALIARBIGokAA8LIAUgCEHYk8AAEJMCAAsgBEEcakEANgIAIARB+IvAADYCGCAEQgE3AgwgBEHMn8AANgIIIARBCGpB9J/AABC8AQALIAUgA0HYk8AAEJMCAAvxBgEEfyMAQcAAayIDJAAgA0EUakEDNgIAIANBIGpBFGpBJDYCACADQSxqQSU2AgAgA0IENwIEIANB7JvAADYCACADQSU2AiQgAyAAKAIINgIwIAMgACgCBDYCKCADIAAoAgA2AiAgAyADQSBqNgIQIANBGGogASADIAIoAiQiBBEIAAJAIAMtABhBA0cNACADKAIcIgIoAgAgAigCBCgCABEDAAJAIAIoAgQiBSgCBCIGRQ0AIAIoAgAgBiAFKAIIEPUBCyACQQxBBBD1AQsCQAJAAkAgACgCDC0AACIAQQNGDQACQAJAAkAgAA4DAAECAAtBAC0AtPxAIQBBAEEBOgC0/EAgAyAAOgAAIAANAyADQTRqQQE2AgAgA0IBNwIkIANB+JHAADYCICADQSY2AgQgA0EAOgA/IAMgAzYCMCADIANBP2o2AgAgA0EYaiABIANBIGogBBEIAEEAQQA6ALT8QCADLQAYQQNHDQIgAygCHCIAKAIAIAAoAgQoAgARAwACQCAAKAIEIgEoAgQiAkUNACAAKAIAIAIgASgCCBD1AQsgAEEMQQQQ9QEMAgtBAC0AtPxAIQBBAEEBOgC0/EAgAyAAOgAAIAANAyADQTRqQQE2AgAgA0IBNwIkIANB+JHAADYCICADQSY2AgQgA0EBOgA/IAMgAzYCMCADIANBP2o2AgAgA0EYaiABIANBIGogBBEIAEEAQQA6ALT8QCADLQAYQQNHDQEgAygCHCIAKAIAIAAoAgQoAgARAwACQCAAKAIEIgEoAgQiAkUNACAAKAIAIAIgASgCCBD1AQsgAEEMQQQQ9QEMAQtBAC0A6PtAIQBBAEEAOgDo+0AgAEUNACADQTRqQQA2AgAgA0H4i8AANgIwIANCATcCJCADQdycwAA2AiAgAyABIANBIGogBBEIACADLQAAQQNHDQAgAygCBCIAKAIAIAAoAgQoAgARAwACQCAAKAIEIgEoAgQiAkUNACAAKAIAIAIgASgCCBD1AQsgAEEMQQQQ9QELIANBwABqJAAPCyADQTRqQQA2AgAgA0EwakH4i8AANgIAIANCATcCJCADQZChwAA2AiAgAyADQSBqEJIBAAsgA0E0akEANgIAIANBMGpB+IvAADYCACADQgE3AiQgA0GQocAANgIgIAMgA0EgahCSAQAL6wUBCX8CQAJAIAJFDQAgACgCBCEDIAAoAgAhBCAAKAIIIQUDQAJAIAUtAABFDQAgBEHE3MAAQQQgAygCDBEJAEUNAEEBDwtBACEGIAIhBwJAAkACQAJAA0AgASAGaiEIAkACQAJAAkACQCAHQQhJDQACQCAIQQNqQXxxIAhrIgANACAHQXhqIQlBACEADAMLIAcgACAAIAdLGyEAQQAhCgNAIAggCmotAABBCkYNBSAAIApBAWoiCkYNAgwACwsgB0UNBUEAIQogCC0AAEEKRg0DIAdBAUYNBUEBIQogCC0AAUEKRg0DIAdBAkYNBUECIQogCC0AAkEKRg0DIAdBA0YNBUEDIQogCC0AA0EKRg0DIAdBBEYNBUEEIQogCC0ABEEKRg0DIAdBBUYNBUEFIQogCC0ABUEKRg0DIAdBBkYNBUEGIQogCC0ABkEKRw0FDAMLIAAgB0F4aiIJSw0BCwJAA0AgCCAAaiIKKAIAIgtBf3MgC0GKlKjQAHNB//37d2pxIApBBGooAgAiCkF/cyAKQYqUqNAAc0H//ft3anFyQYCBgoR4cQ0BIABBCGoiACAJTQ0ACwsgACAHTQ0AIAAgByAAEJMCAAsgACAHRg0CIAAgB2shCyAIIABqIQhBACEKAkADQCAIIApqLQAAQQpGDQEgCyAKQQFqIgpqDQAMBAsLIAAgCmohCgsCQCAKIAZqIgBBAWoiBiAASQ0AIAIgBkkNACABIABqLQAAQQpHDQAgBUEBOgAAIAIgBk0NAyAGIQAgASAGaiwAAEG/f0wNBAwFCyACIAZrIQcgAiAGTw0ACwsgBUEAOgAAIAIhBgsgAiEAIAIgBkYNAQsgASACQQAgBiAAEMkBAAsCQCAEIAEgACADKAIMEQkARQ0AQQEPCwJAAkAgAiAASw0AIAIgAEYNAQwECyABIABqLAAAQb9/TA0DCyABIABqIQEgAiAAayICDQALC0EADwsgASACIAAgAiAAEMkBAAvGBgIFfwZ+IwBBgAFrIgQkACABvSEJAkACQCABIAFhDQBBAiEFDAELIAlC/////////weDIgpCgICAgICAgAiEIAlCAYZC/v///////w+DIAlCNIinQf8PcSIGGyILQgGDIQxBAyEFAkACQAJAQQFBAkEEIAlCgICAgICAgPj/AIMiDVAiBxsgDUKAgICAgICA+P8AURtBA0EEIAcbIApQG0F/ag4EAwABAgMLQQQhBQwCCyAGQc13aiEIIAynQQFzIQVCASEODAELQoCAgICAgIAgIAtCAYYgC0KAgICAgICACFEiCBshC0ICQgEgCBshDiAMp0EBcyEFQct3Qcx3IAgbIAZqIQgLIAQgCDsBeCAEIA43A3AgBEIBNwNoIAQgCzcDYCAEIAU6AHoCQAJAIAVBAkcNAEG4wsAAIQhBACEHDAELAkAgAg0AQePYwABBuMLAACAJQgBTGyEIIAlCP4inIQcMAQtB49jAAEHk2MAAIAlCAFMbIQhBASEHCwJAAkACQAJAAkAgBUF+aiIFQQMgBUEDSRtB/wFxDgQAAQMCAAsgBEEDNgIoIARB6djAADYCJCAEQQI7ASAgBCAHNgJUIAQgCDYCUCAEIARBIGo2AlhBASEFDAMLIARBAzYCKCAEQebYwAA2AiQgBEECOwEgIAQgBzYCVCAEIAg2AlAgBCAEQSBqNgJYQQEhBQwCCyAEQSBqIARB4ABqIARBD2pBERAKAkACQCAEKAIgDQAgBEHQAGogBEHgAGogBEEPakEREAYMAQsgBEHQAGpBCGogBEEgakEIaigCADYCACAEIAQpAyA3A1ALIAQgBCgCUCAEKAJUIAQvAVggAyAEQSBqQQQQMyAEIAc2AlQgBCAINgJQIAQgBCgCADYCWCAEKAIEIQUMAQtBAiEFIARBAjsBIAJAIANFDQAgBEEwakEBNgIAIARBADsBLCAEQQI2AiggBEHg2MAANgIkIAQgBzYCVCAEIAg2AlAgBCAEQSBqNgJYDAELQQEhBSAEQQE2AiggBEHl2MAANgIkIAQgBzYCVCAEIAg2AlAgBCAEQSBqNgJYCyAEQdwAaiAFNgIAIAAgBEHQAGoQJSEFIARBgAFqJAAgBQv/BQIGfwJ+AkAgAkUNAEEAIAJBeWoiAyADIAJLGyEEIAFBA2pBfHEgAWshBUEAIQMCQAJAAkACQANAAkACQAJAIAEgA2otAAAiBkEYdEEYdSIHQQBIDQAgBUF/Rg0BIAUgA2tBA3ENAQJAIAMgBE8NAANAIAEgA2oiBigCACAGQQRqKAIAckGAgYKEeHENASADQQhqIgMgBEkNAAsLIAMgAk8NAgNAIAEgA2osAABBAEgNAyACIANBAWoiA0cNAAwJCwtCgICAgIAgIQlCgICAgBAhCgJAAkACQAJAAkACQAJAAkACQCAGQYThwABqLQAAQX5qDgMAAQIPCyADQQFqIgYgAkkNBkIAIQkMDQtCACEJIANBAWoiCCACTw0MIAEgCGosAAAhCCAGQaB+ag4OAQMDAwMDAwMDAwMDAwIDC0IAIQkgA0EBaiIIIAJPDQsgASAIaiwAACEIAkACQAJAAkAgBkGQfmoOBQEAAAACAAsgB0EPakH/AXFBAksNDSAIQX9KDQ0gCEFATw0NDAILIAhB8ABqQf8BcUEwTw0MDAELIAhBj39KDQsLIANBAmoiBiACTw0LIAEgBmosAABBv39KDQlCACEKIANBA2oiBiACTw0MIAEgBmosAABBv39MDQVCgICAgIDgACEJQoCAgIAQIQoMDAsgCEFgcUGgf0cNCQwCCyAIQaB/Tg0IDAELAkAgB0EfakH/AXFBDEkNACAHQX5xQW5HDQggCEF/Sg0IIAhBQE8NCAwBCyAIQb9/Sg0HC0IAIQogA0ECaiIGIAJPDQggASAGaiwAAEG/f0oNBQwBC0KAgICAgCAhCUKAgICAECEKIAEgBmosAABBv39KDQcLIAZBAWohAwwBCyADQQFqIQMLIAMgAkkNAAwFCwtCgICAgIDAACEJQoCAgIAQIQoMAgtCgICAgIAgIQlCgICAgBAhCgwBC0IAIQoLIAAgCSADrYQgCoQ3AgQgAEEBNgIADwsgACABNgIEIABBCGogAjYCACAAQQA2AgALhAUCBH8GfiAAIAAoAjggAmo2AjgCQAJAAkACQAJAIAAoAjwiAw0AQQAhBAwBCwJAAkBBCCADayIEIAIgBCACSRsiBUEDSw0AQgAhB0EAIQYMAQsgATUAACEHQQQhBgsCQCAGQQFyIAVPDQAgASAGajMAACAGQQN0rYYgB4QhByAGQQJyIQYLAkAgBiAFTw0AIAEgBmoxAAAgBkEDdK2GIAeEIQcLIAAgACkDMCAHIANBA3RBOHGthoQiBzcDMCAEIAJLDQEgAEEgaiIGIABBGGoiAykDACAAQShqIgUpAwAgB4UiCHwiCSAGKQMAIgpCDYkgCiAAKQMQfCIKhSILfCIMIAtCEYmFNwMAIAMgDEIgiTcDACAFIAkgCEIQiYUiCEIViSAIIApCIIl8IgiFNwMAIAAgCCAHhTcDEAsgAiAEayICQQdxIQYCQCAEIAJBeHEiAk8NACAAQRhqKQMAIQggAEEgaikDACEHIABBKGopAwAhCSAAKQMQIQoDQCABIARqKQAAIgsgCYUiCSAIfCIIIAogB3wiCiAHQg2JhSIHfCIMIAdCEYmFIQcgCUIQiSAIhSIIQhWJIAggCkIgiXwiCoUhCSAMQiCJIQggCiALhSEKIARBCGoiBCACSQ0ACyAAIAc3AyAgACAKNwMQIAAgCTcDKCAAIAg3AxgLIAZBA0sNAUIAIQdBACECDAILIAAgAyACajYCPA8LIAEgBGo1AAAhB0EEIQILAkAgAkEBciAGTw0AIAEgAiAEamozAAAgAkEDdK2GIAeEIQcgAkECciECCwJAIAIgBk8NACABIAIgBGpqMQAAIAJBA3SthiAHhCEHCyAAIAc3AzAgACAGNgI8C60FAQl/IwBBEGsiAiQAAkACQCABKAIEIgNFDQBBASEEIAAoAhggASgCACADIABBHGooAgAoAgwRCQANAQsCQCABQQxqKAIAIgQNAEEAIQQMAQsgASgCCCIFIARBDGxqIQYgAEEcaigCACEHIAAoAhghCCACQQhqQQRqIQkDQAJAAkACQAJAIAUvAQAOAwACAQALAkACQCAFKAIEIgFBwQBJDQAgBygCDCEAA0ACQCAIQdDewABBwAAgABEJAEUNAEEBIQQMCAsgAUFAaiIBQcAASw0ADAILCyABRQ0DCwJAAkAgAUE/Sw0AIAFB0N7AAGosAABBv39MDQELIAhB0N7AACABIAcoAgwRCQBFDQNBASEEDAULQdDewABBwABBACABIAEQyQEACyAIIAUoAgQgBSgCCCAHKAIMEQkARQ0BQQEhBAwDCyAFLwECIQEgCUEAOgAAIAJBADYCCEEBIQACQAJAAkACQAJAIAUvAQAOAwIAAQILAkAgBS8BAiIAQegHSQ0AQQRBBSAAQZDOAEkbIQoMAwtBASEKIABBCkkNAkECQQMgAEHkAEkbIQoMAgtBAiEACwJAIAUgAEECdGooAgAiCkEGTw0AIAoNAUEAIQoMAgsgCkEFIAEQlAIACyACQQhqIApqIQQCQAJAIApBAXENACABIQAMAQsgBEF/aiIEIAEgAUH//wNxQQpuIgBBCmxrQTByOgAACyAKQQFGDQAgBEF+aiEBA0AgASAAQf//A3EiBEEKbiIDQQpwQTByOgAAIAFBAWogACADQQpsa0EwcjoAACAEQeQAbiEAIAEgAkEIakYhBCABQX5qIQEgBEUNAAsLIAggAkEIaiAKIAcoAgwRCQBFDQBBASEEDAILIAYgBUEMaiIFRw0AC0EAIQQLIAJBEGokACAEC90FAQV/IwBBIGsiBSQAIAVBCGpBAnIhBiAAKAIAIQcDQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkAgBw4EAQACBQILIAFFDQILIABBAiAAKAIAIgggCCAHRiIJGzYCACAJDQIgCCEHDAwLAkAgB0EDcUECRw0AA0AgByEJQQAoAvT8QA0FQQBBfzYC9PxAAkBBACgC+PxAIggNAEEAQQAgBxBTIgg2Avj8QAsgCCAIKAIAIgdBAWo2AgAgB0F/TA0GQQBBACgC9PxAQQFqNgL0/EAgCEUNByAAIAYgACgCACIHIAcgCUYbNgIAIAVBADoAECAFIAg2AgggBSAJQXxxNgIMAkAgByAJRw0AIAUtABBFDQkMDAsCQCAFKAIIIghFDQAgCCAIKAIAIglBf2o2AgAgCUEBRw0AIAUoAggQoQELIAdBA3FBAkYNAAwMCwtB7JXAAEHAACAEELYBAAsgBUEcakEANgIAIAVB+IvAADYCGCAFQgE3AgwgBUHYlsAANgIIIAVBCGogBBC8AQALIAUgB0EBRjoADCAFQQM2AgggAiAFQQhqIAMoAhARBgAgACgCACEHIAAgBSgCCDYCACAFIAdBA3EiCDYCACAIQQJHDQUgB0F+aiIIRQ0AA0AgCCgCACEHIAhBADYCACAHRQ0HIAgoAgQhCSAIQQE6AAggB0EYahBMIAcgBygCACIIQX9qNgIAAkAgCEEBRw0AIAcQoQELIAkhCCAJDQALCyAFQSBqJAAPC0H4i8AAQRAgBUHEjMAAQZCZwAAQgwEACwALQfuPwABB3gBB+JDAABD+AQALA0AQJiAFLQAQRQ0ADAMLCyAFQQA2AgggBSAFQQhqQeSWwAAQkwEAC0GYjMAAQStB9JbAABC2AQALIAUoAggiB0UNACAHIAcoAgAiCEF/ajYCACAIQQFHDQAgBSgCCBChASAAKAIAIQcMAQsgACgCACEHDAALC5cFAQp/IwBBMGsiAyQAIANBJGogATYCACADQQM6ACggA0KAgICAgAQ3AwggAyAANgIgQQAhBCADQQA2AhggA0EANgIQAkACQAJAAkAgAigCCCIFDQAgAkEUaigCACIGRQ0BIAIoAgAhASACKAIQIQAgBkF/akH/////AXFBAWoiBCEGA0ACQCABQQRqKAIAIgdFDQAgAygCICABKAIAIAcgAygCJCgCDBEJAA0ECyAAKAIAIANBCGogAEEEaigCABEHAA0DIABBCGohACABQQhqIQEgBkF/aiIGDQAMAgsLIAJBDGooAgAiAEUNACAAQQV0IQggAEF/akH///8/cUEBaiEEIAIoAgAhAUEAIQYDQAJAIAFBBGooAgAiAEUNACADKAIgIAEoAgAgACADKAIkKAIMEQkADQMLIAMgBSAGaiIAQRxqLQAAOgAoIAMgAEEEaikCAEIgiTcDCCAAQRhqKAIAIQkgAigCECEKQQAhC0EAIQcCQAJAAkAgAEEUaigCAA4DAQACAQsgCUEDdCEMQQAhByAKIAxqIgwoAgRB5ABHDQEgDCgCACgCACEJC0EBIQcLIAMgCTYCFCADIAc2AhAgAEEQaigCACEHAkACQAJAIABBDGooAgAOAwEAAgELIAdBA3QhCSAKIAlqIgkoAgRB5ABHDQEgCSgCACgCACEHC0EBIQsLIAMgBzYCHCADIAs2AhggCiAAKAIAQQN0aiIAKAIAIANBCGogACgCBBEHAA0CIAFBCGohASAIIAZBIGoiBkcNAAsLQQAhACAEIAIoAgRJIgFFDQEgAygCICACKAIAIARBA3RqQQAgARsiASgCACABKAIEIAMoAiQoAgwRCQBFDQELQQEhAAsgA0EwaiQAIAAL8AQBCn8jAEEQayICJAACQAJAAkACQAJAIAAoAghBAUcNACAAQQxqKAIAIQMgAkEMaiABQQxqKAIAIgQ2AgAgAiABQQhqKAIAIgU2AgggAiABQQRqKAIAIgY2AgQgAiABKAIAIgE2AgAgAC0AICEHIAAoAgQhCCAALQAAQQhxDQEgCCEJIAYhASAHIQoMAgsgACABECIhBQwDCyAAKAIYIAEgBiAAQRxqKAIAKAIMEQkADQFBASEKIABBAToAIEEwIQkgAEEwNgIEQQAhASACQQA2AgQgAkG4wsAANgIAQQAgAyAGayIGIAYgA0sbIQMLAkAgBEUNACAEQQxsIQQDQAJAAkACQAJAIAUvAQAOAwACAQALIAVBBGooAgAhBgwCCyAFQQhqKAIAIQYMAQsCQCAFQQJqLwEAIgtB6AdJDQBBBEEFIAtBkM4ASRshBgwBC0EBIQYgC0EKSQ0AQQJBAyALQeQASRshBgsgBUEMaiEFIAYgAWohASAEQXRqIgQNAAsLAkACQAJAIAMgAU0NAEEAIQUgAyABayIBIQQCQAJAAkAgCkEDcQ4EAgABAAILQQAhBCABIQUMAQsgAUEBdiEFIAFBAWpBAXYhBAsgBUEBaiEFIABBHGooAgAhASAAKAIYIQYDQCAFQX9qIgVFDQIgBiAJIAEoAhARBwBFDQAMBAsLIAAgAhAiIQUMAQsgACACECINAUEAIQUDQAJAIAQgBUcNACAEIARJIQUMAgsgBUEBaiEFIAYgCSABKAIQEQcARQ0ACyAFQX9qIARJIQULIAAgBzoAICAAIAg2AgQMAQtBASEFCyACQRBqJAAgBQujBQEGfyMAQSBrIgAkAAJAAkACQAJAAkACQAJAAkBBACgC9PxADQBBAEF/NgL0/EACQEEAKAL4/EAiAQ0AQQBBACABEFMiATYC+PxACyABIAEoAgAiAkEBajYCACACQX9MDQFBAEEAKAL0/EBBAWo2AvT8QCABRQ0CIAFBACABKAIYIgIgAkECRiICGzYCGAJAIAINACABQRhqIgItAAQhAyACQQE6AAQgACADQQFxIgM6AAQgAw0EIAJBBGohBEEAIQUCQEEAKALI/EBB/////wdxRQ0AEKICQQFzIQULIAQtAAENBSACIAIoAgAiA0EBIAMbNgIAIANFDQggA0ECRw0GIAIoAgAhAyACQQA2AgAgACADNgIEIANBAkcNBwJAIAUNAEEAKALI/EBB/////wdxRQ0AEKICDQAgBEEBOgABCyAEQQA6AAALIAEgASgCACICQX9qNgIAAkAgAkEBRw0AIAEQoQELIABBIGokAA8LQfiLwABBECAAQQhqQcSMwABBkJnAABCDAQALAAtB+4/AAEHeAEH4kMAAEP4BAAsgAEEcakEANgIAIABBGGpB+IvAADYCACAAQgE3AgwgAEGQocAANgIIIABBBGogAEEIahCSAQALIAAgBToADCAAIAQ2AghB5IzAAEErIABBCGpBkI3AAEGgo8AAEIMBAAsgAEEcakEANgIAIABB+IvAADYCGCAAQgE3AgwgAEHIo8AANgIIIABBCGpB0KPAABC8AQALIABBHGpBADYCACAAQRhqQfiLwAA2AgAgAEIBNwIMIABBgKTAADYCCCAAQQRqIABBCGpBiKTAABCTAQALIABBHGpBADYCACAAQfiLwAA2AhggAEIBNwIMIABBoKDAADYCCCAAQQhqQeCgwAAQvAEAC6MEAQl/IwBBEGsiASQAIAAoAiAhAkEAIQMCQCAAQShqKAIAIgRBBHQiBUUNACACQQxqKAIAIgZBBkYNAAJAIARBAUcNACAGIQMMAQsgBEH+////AGpB/////wBxIQcCQAJAIARBf2pBB3EiAw0AIAJBEGohCAwBCyACQRxqIQgDQCAGIAgoAgAiCSAGIAlLGyEGIAhBEGohCCADQX9qIgMNAAsgCEF0aiEIIAYhAwsgB0EHSQ0AIAIgBWohCSAIQfwAaiEIIAYhAwNAIAMgCEGQf2ooAgAiBiADIAZLGyIGIAhBoH9qKAIAIgMgBiADSxsiBiAIQbB/aigCACIDIAYgA0sbIgYgCEFAaigCACIDIAYgA0sbIgYgCEFQaigCACIDIAYgA0sbIgYgCEFgaigCACIDIAYgA0sbIgYgCEFwaigCACIDIAYgA0sbIgYgCCgCACIDIAYgA0sbIQMgCEEEaiEGIAhBgAFqIQggBiAJRw0ACwsgACgCLCEGIAIgBCABQQhqEAsCQEEwQQgQ7AEiCEUNACAIIAApAwA3AwAgCEEoaiAAQShqKQMANwMAIAhBIGogAEEgaikDADcDACAIQRhqIABBGGopAwA3AwAgCEEQaiAAQRBqKQMANwMAIAhBCGogAEEIaikDADcDAAJAIAhB7IjAABCbASIIDQBBACAGIAMgBiADSxs2AoD8QAsgAUEQaiQAIAgPC0EwQQgQjgIAC8gEAgp/A34jAEHQAGsiAiQAIAFBCGooAgAhAyABQQRqKAIAIQQCQAJAAkAgAEEoaigCACIFRQ0AIAAoAiAhBiAFQQR0IQUDQAJAIAZBCGooAgAiByADSw0AIAYoAgAgBCAHELEBRQ0DCyAGQRBqIQYgBUFwaiIFDQALCyAAQSxqIQYMAQsgBkEMaiEGCwJAAkAgASgCACIIIAYoAgBLDQAgAkEANgIMQQAhBgJAIABBHGooAgBFDQAgACAEIAMQKiEMIABBEGooAgAiByAMp3EhBSAMQhmIQv8Ag0KBgoSIkKDAgAF+IQ0gAEEUaigCACIJQXRqIQBBACEKA0ACQCAJIAVqKQAAIg4gDYUiDEJ/hSAMQv/9+/fv37//fnyDQoCBgoSIkKDAgH+DIgxQDQACQANAAkAgAyAAQQAgDHqnQQN2IAVqIAdxayILQQxsaiIGKAIERw0AIAQgBigCACADELEBRQ0CCyAMQn98IAyDIgxQDQIMAAsLIAkgC0EMbGpBdGohBgwCCwJAIA4gDkIBhoNCgIGChIiQoMCAf4NQDQBBACEGDAILIAUgCkEIaiIKaiAHcSEFDAALCyAGQQhqIAJBDGogBhsoAgAhBiACQQA2AhggAkIBNwMQIAJBIGogAkEQakGch8AAEMoBIAFBDGogAkEgahCQAQ0BIAggBiACKAIQIAIoAhgQACACKAIUIgZFDQAgAigCECAGQQEQ9QELIAJB0ABqJAAPC0G0h8AAQTcgAkHIAGpByIjAAEG4iMAAEIMBAAuqBAEHfyMAQSBrIgQkAAJAAkACQCADDQBBACEFDAELIAJBBGohBiADQX9qQf////8BcUEBaiEHQQAhBQJAA0AgBigCAA0BIAZBCGohBiAHIAVBAWoiBUcNAAsgByEFCyAFIANLDQELAkACQAJAAkAgAyAFayIHRQ0AIAIgBUEDdGohBQNAIARBCGpBAiAFIAcQqwECQAJAIAQvAQgNACAEKAIMIggNASAAQYSTwACtQiCGQgKENwIADAQLIAQgBC8BCjsBBiAEQQZqELUCQf//A3EiBhBEQf8BcUEjRg0BIABBADYCACAAQQRqIAY2AgAMAwsgBUEEaiEGIAdBf2pB/////wFxQQFqIQlBACEDQQAhAgJAA0AgBigCACACaiIKIAhLDQEgBkEIaiEGIAohAiAJIANBAWoiA0cNAAsgCiECIAkhAwsgByADSQ0DAkAgByADayIHDQAgCCACRg0CIARBHGpBADYCACAEQfiLwAA2AhggBEIBNwIMIARBkJTAADYCCCAEQQhqQZiUwAAQvAEACyAFIANBA3RqIgUoAgQiAyAIIAJrIgZJDQQgBUEEaiADIAZrNgIAIAUgBSgCACAGajYCAAwACwsgAEEEOgAACyAEQSBqJAAPCyADIAdB2JPAABCTAgALIARBHGpBADYCACAEQfiLwAA2AhggBEIBNwIMIARBzJ/AADYCCCAEQQhqQfSfwAAQvAEACyAFIANB2JPAABCTAgAL3wMCBH8GfiMAQdAAayIDJAAgA0HAAGoiBEIANwMAIANBIGoiBSAAKQMAIgdC4eSV89bs2bzsAIU3AwAgA0EwaiIGIABBCGopAwAiCELzytHLp4zZsvQAhTcDACADQShqIgAgCELt3pHzlszct+QAhTcDACADQgA3AzggAyAHNwMIIAMgB0L1ys2D16zbt/MAhTcDGCADIAg3AxAgA0EIaiABIAIQISADQf8BOgBPIANBCGogA0HPAGpBARAhIAQ1AgAhCCADKQM4IQkgBikDACEKIAUpAwAhCyAAKQMAIQcgAykDGCEMIANB0ABqJAAgCiAJIAhCOIaEIgiFIglCEIkgCSALfCIJhSIKIAcgDHwiC0IgiXwiDCAIhSAJIAdCDYkgC4UiB3wiCCAHQhGJhSIHfCIJIAdCDYmFIgcgCkIViSAMhSIKIAhCIIlC/wGFfCIIfCILIAdCEYmFIgdCDYkgByAKQhCJIAiFIgggCUIgiXwiCXwiB4UiCkIRiSAKIAhCFYkgCYUiCCALQiCJfCIJfCIKhSILQg2JIAsgCEIQiSAJhSIIIAdCIIl8Igd8hSIJIAhCFYkgB4UiByAKQiCJfCIIfCIKIAdCEIkgCIVCFYmFIAlCEYmFIApCIImFC/cDAQF/QQAhAgJAAkACQCAARQ0AAkACQAJAAkACQAJAAkACQAJAAkACQCABDgsAAQIDBAUGBwgJCgsLIABBAEgNCyAAQQEQ7AEiAg0KIABBARCOAgALIABBAEgNCiAAQQEQ7AEiAg0JIABBARCOAgALIAAgAGoiASAASQ0JIAFBAEgNCSABQQIQ7AEiAg0IIAFBAhCOAgALIABB/////wNxIABHDQggAEECdCIAQQBIDQggAEEEEOwBIgINByAAQQQQjgIACyAAQf////8BcSAARw0HIABBA3QiAEEASA0HIABBCBDsASICDQYgAEEIEI4CAAsgAEEASA0GIABBARDsASICDQUgAEEBEI4CAAsgACAAaiIBIABJDQUgAUEASA0FIAFBAhDsASICDQQgAUECEI4CAAsgAEH/////A3EgAEcNBCAAQQJ0IgBBAEgNBCAAQQQQ7AEiAg0DIABBBBCOAgALIABB/////wFxIABHDQMgAEEDdCIAQQBIDQMgAEEIEOwBIgINAiAAQQgQjgIACyAAQf////8DcSAARw0CIABBAnQiAEEASA0CIABBBBDsASICDQEgAEEEEI4CAAsgAEH/////AXEgAEcNASAAQQN0IgBBAEgNASAAQQgQ7AEiAkUNAgsgAg8LELsBAAsgAEEIEI4CAAvXAwIEfwF+IwBBgAFrIgIkAAJAAkACQAJAAkAgASgCACIDQRBxDQAgA0EgcQ0BIAApAwBBASABEEIhAAwECyAAKQMAIQZBgAEhACACQYABaiEDAkACQANAAkAgAA0AQQAhAAwDCyADQX9qQTBB1wAgBqciBEEPcSIFQQpJGyAFajoAAAJAIAZCEFQNACADQX5qIgNBMEHXACAEQf8BcSIFQaABSRsgBUEEdmo6AAAgAEF+aiEAIAZCgAJUIQUgBkIIiCEGIAVFDQEMAgsLIABBf2ohAAsgAEGBAU8NAgsgAUEBQezcwABBAiACIABqQYABIABrEBghAAwDCyAAKQMAIQZBgAEhACACQYABaiEDAkACQANAAkAgAA0AQQAhAAwDCyADQX9qQTBBNyAGpyIEQQ9xIgVBCkkbIAVqOgAAAkAgBkIQVA0AIANBfmoiA0EwQTcgBEH/AXEiBUGgAUkbIAVBBHZqOgAAIABBfmohACAGQoACVCEFIAZCCIghBiAFRQ0BDAILCyAAQX9qIQALIABBgQFPDQILIAFBAUHs3MAAQQIgAiAAakGAASAAaxAYIQAMAgsgAEGAASAAEJMCAAsgAEGAASAAEJMCAAsgAkGAAWokACAAC7YDAQV/AkACQAJAAkACQAJAAkAgByAIWA0AIAcgCH0gCFgNAQJAIAcgBn0gBlgNACAHIAZCAYZ9IAhCAYZaDQMLAkAgBiAIWA0AIAcgBiAIfSIIfSAIWA0ECyAAQQA2AgAPCyAAQQA2AgAPCyAAQQA2AgAPCyADIAJLDQEgACADNgIEIAAgATYCACAAQQhqIAQ7AQAPCyADIAJLDQEgASADaiEJQQAhCiABIQsCQANAIAMgCkYNASAKQQFqIQogCyADaiEMIAtBf2oiDSELIAxBf2otAABBOUYNAAsgDSADaiILIAstAABBAWo6AAAgAyAKa0EBaiADTw0DIAtBAWpBMCAKQX9qEDYaDAMLAkACQCADDQBBMSEKDAELIAFBMToAAEEwIQogA0EBRg0AQTAhCiABQQFqQTAgA0F/ahA2GgsgBEEQdEGAgARqQRB1IgQgBUEQdEEQdUwNAiADIAJPDQIgCSAKOgAAIANBAWohAwwCCyADIAIgAxCUAgALIAMgAiADEJQCAAsCQCADIAJLDQAgACADNgIEIAAgATYCACAAQQhqIAQ7AQAPCyADIAIgAxCUAgALvAQCBX8BfkEBIQICQCABKAIYIgNBJyABQRxqKAIAKAIQIgQRBwANAEECIQFBMCEFAkACQAJAAkACQAJAAkACQAJAIAAoAgAiAA4oCAEBAQEBAQEBAgQBAQMBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBBQALIABB3ABGDQQLIAAQOkUNBCAAQQFyZ0ECdkEHc61CgICAgNAAhCEHDAULQfQAIQVBAiEBDAULQfIAIQVBAiEBDAQLQe4AIQVBAiEBDAMLQQIhASAAIQUMAgsCQCAAEG5FDQBBASEBIAAhBQwCCyAAQQFyZ0ECdkEHc61CgICAgNAAhCEHC0EDIQEgACEFCwNAIAEhBkEAIQEgBSEAAkACQAJAAkACQCAGDgQBBAIAAQsCQAJAAkACQAJAIAdCIIinQf8BcQ4GBQAEAQIDBQsgB0L/////j2CDIQdB/QAhAEEDIQEMBwsgB0L/////j2CDQoCAgIAghCEHQfsAIQBBAyEBDAYLIAdC/////49gg0KAgICAMIQhB0H1ACEAQQMhAQwFCyAHQv////+PYINCgICAgMAAhCEHQdwAIQBBAyEBDAQLQTBB1wAgBSAHpyIBQQJ0dkEPcSIAQQpJGyAAaiEAIAFFDQIgB0J/fEL/////D4MgB0KAgICAcIOEIQdBAyEBDAMLIANBJyAEEQcAIQIMBAtB3AAhAEEBIQEMAQsgB0L/////j2CDQoCAgIAQhCEHQQMhAQsgAyAAIAQRBwBFDQALCyACC9ADAQZ/IwBBIGsiAyQAAkACQAJAIAJBAWoiBCACSQ0AIARBf0wNASAEQQEQ7AEiBUUNAiAFIAEgAhAOIQYCQAJAIAJBCEkNACADQQhqQQAgASACEEEgAygCDCEHIAMoAgghBQwBCwJAIAINAEEAIQdBACEFDAELAkACQCABLQAADQBBACEIDAELQQEhCEEAIQUCQCACQQFHDQAgAiEHDAILIAEtAAFFDQBBAiEIAkAgAkECRw0AIAIhBwwCCyABLQACRQ0AQQMhCAJAIAJBA0cNACACIQcMAgsgAS0AA0UNAEEEIQgCQCACQQRHDQAgAiEHDAILIAEtAARFDQBBBSEIAkAgAkEFRw0AIAIhBwwCCyABLQAFRQ0AQQYhCAJAIAJBBkcNACACIQcMAgsgAiEHIAEtAAYNAQtBASEFIAghBwsCQAJAIAUNACADIAI2AhggAyAENgIUIAMgBjYCECADIANBEGoQSSAAIAMpAwA3AgRBACECDAELIABBEGogAjYCACAAQQxqIAQ2AgAgAEEIaiAGNgIAIAAgBzYCBEEBIQILIAAgAjYCACADQSBqJAAPC0GswMAAQStBvMHAABC2AQALELsBAAsgBEEBEI4CAAufAwEFfwJAAkAgAEEQIABBEEsbIgIgAkF/anENACACIQAMAQtBICEDA0AgAyIAQQF0IQMgACACSQ0ACwsCQEFAIABrIAFLDQBBAEEwNgLwgEFBAA8LAkAgAEEQIAFBE2pBcHEgAUELSRsiAWpBDGoQByIDDQBBAA8LIANBeGohAgJAAkAgAEF/aiADcQ0AIAIhAAwBCyADQXxqIgQoAgAiBUF4cSADIABqQX9qQQAgAGtxQXhqIgNBACAAIAMgAmtBD0sbaiIAIAJrIgNrIQYCQCAFQQNxDQAgACAGNgIEIAAgAigCACADajYCAAwBCyAAIAYgACgCBEEBcXJBAnI2AgQgACAGaiIGIAYoAgRBAXI2AgQgBCADIAQoAgBBAXFyQQJyNgIAIAIgA2oiBiAGKAIEQQFyNgIEIAIgAxANCwJAIAAoAgQiA0EDcUUNACADQXhxIgIgAUEQak0NACAAIAEgA0EBcXJBAnI2AgQgACABaiIDIAIgAWsiAUEDcjYCBCAAIAJqIgIgAigCBEEBcjYCBCADIAEQDQsgAEEIagufAwEGfwJAAkACQAJAIANBA3QiBEUNACADQX9qQf////8BcSIFQQFqIgZBB3EhByAFQQdPDQFBACEGIAIhBQwCCyABQQRqIQggAUEIaiEFQQAhBgwCCyACQTxqIQUgBkH4////A3EhCUEAIQYDQCAFKAIAIAVBeGooAgAgBUFwaigCACAFQWhqKAIAIAVBYGooAgAgBUFYaigCACAFQVBqKAIAIAVBSGooAgAgBmpqampqampqIQYgBUHAAGohBSAJQXhqIgkNAAsgBUFEaiEFCwJAIAdFDQAgBUEEaiEFA0AgBSgCACAGaiEGIAVBCGohBSAHQX9qIgcNAAsLIAFBCGohBSABQQRqIggoAgAgASgCCCIHayAGTw0AIAEgByAGEGYLAkAgA0UNACACIARqIQMgBSgCACEFA0AgAigCACEJAkAgCCgCACAFayACQQRqKAIAIgdPDQAgASAFIAcQZiABKAIIIQULIAEoAgAgBWogCSAHEA4aIAEgBSAHaiIFNgIIIAMgAkEIaiICRw0ACwsgAEEANgIAIAAgBjYCBAuUAwIKfwJ+IAEgAkECdGohBQJAAkAgBEUNACAEQQFqIQYgBEECdCEHQQAhCEEAIQkDQCAAIAhBAnRqIQoDQCAIIQsgCiECIAEgBUYNAyACQQRqIQogC0EBaiEIIAEoAgAhDCABQQRqIg0hASAMRQ0ACyALQSggC0EoSRtBWGohDiAMrSEPQgAhEEEAIQEgByEMIAMhCgJAAkACQANAIA4gAUYNASACIBAgAjUCAHwgCjUCACAPfnwiED4CACAQQiCIIRAgAkEEaiECIAFBf2ohASAKQQRqIQogDEF8aiIMDQALIAQhASAQpyICDQEMAgsgAUF/cyAIakEoQdzxwAAQjwEACwJAIAsgBGoiAUEnSw0AIAAgAUECdGogAjYCACAGIQEMAQsgAUEoQdzxwAAQjwEACyABIAtqIgEgCSAJIAFJGyEJIA0hAQwACwtBACEJQQAhAgNAIAEgBUYNASACQQFqIQIgASgCACEKIAFBBGoiCyEBIApFDQAgAkF/aiIBIAkgCSABSRshCSALIQEMAAsLIAkLtgMBAX8CQAJAAkACQAJAIAJFDQAgAS0AAEExSQ0BIAZBBEkNAgJAAkAgA0EQdEEQdSIHQQFIDQAgBSABNgIEQQIhBiAFQQI7AQAgA0H//wNxIgMgAk8NASAFQQI7ARggBUECOwEMIAUgAzYCCCAFQSBqIAIgA2siAjYCACAFQRxqIAEgA2o2AgAgBUEUakEBNgIAIAVBEGpB4tjAADYCAEEDIQYgAiAETw0GIAQgAmshBAwFCyAFQQI7ARggBUEAOwEMIAVBAjYCCCAFQeDYwAA2AgQgBUECOwEAIAVBIGogAjYCACAFQRxqIAE2AgAgBUEQakEAIAdrIgE2AgBBAyEGIAQgAk0NBSAEIAJrIgIgAU0NBSACIAdqIQQMBAsgBUEAOwEMIAUgAjYCCCAFQRBqIAMgAms2AgAgBEUNBCAFQQI7ARggBUEgakEBNgIAIAVBHGpB4tjAADYCAAwDC0Gc1sAAQSFB6NfAABC2AQALQfjXwABBIUGc2MAAELYBAAtBrNjAAEEiQdDYwAAQtgEACyAFQQA7ASQgBUEoaiAENgIAQQQhBgsgACAGNgIEIAAgBTYCAAucAwEIfyMAQSBrIgIkAAJAAkACQCABQQhqKAIAIgMNACAAQQQ6AAAMAQsgASgCACEEQQAhBQNAAkACQAJAIAMgBUkNACACIAMgBWsiBjYCDCACIAQgBWoiBzYCCCACQRBqQQEgAkEIakEBEKsBAkACQAJAAkAgAi8BEA0AIAIoAhQhCAwBCyACIAIvARI7AR4gBiEIIAJBHmoQtQJB//8DcSIJQYSiwAAQtQJB//8DcUcNAQsgAUEAOgAMIAhFDQEgCCAFaiEFDAQLIAFBADoADCAJEERB/wFxQSNGDQMgAEEANgIAIABBBGogCTYCAAwCCyAAQaSSwACtQiCGQgKENwIADAELIAUgA0HYksAAEJMCAAsgBUUNAiABQQhqIgVBADYCACAGRQ0CIAQgByAGEA8aIAUgBjYCAAwCCyADIAVLDQALIABBBDoAACAFRQ0AIAMgBUkNASABQQhqIghBADYCACADIAVrIgNFDQAgASgCACIGIAYgBWogAxAPGiAIIAM2AgALIAJBIGokAA8LIAUgA0G0jsAAEJQCAAuwAwEBfyMAQfAAayIHJAAgByACNgIMIAcgATYCCCAHIAQ2AhQgByADNgIQAkACQAJAAkAgAEH/AXEOAwABAgALIAdBldvAADYCGEECIQAMAgsgB0GT28AANgIYQQIhAAwBCyAHQYzbwAA2AhhBByEACyAHIAA2AhwCQCAFKAIADQAgB0E4akEUakHnADYCACAHQcQAakHnADYCACAHQdgAakEUakEDNgIAIAdCBDcCXCAHQfjbwAA2AlggB0HhADYCPCAHIAdBOGo2AmggByAHQRBqNgJIIAcgB0EIajYCQCAHIAdBGGo2AjggB0HYAGogBhC8AQALIAdBIGpBEGogBUEQaikCADcDACAHQSBqQQhqIAVBCGopAgA3AwAgByAFKQIANwMgIAdB2ABqQRRqQQQ2AgAgB0HUAGpBIDYCACAHQThqQRRqQecANgIAIAdBxABqQecANgIAIAdCBDcCXCAHQdTbwAA2AlggB0HhADYCPCAHIAdBOGo2AmggByAHQSBqNgJQIAcgB0EQajYCSCAHIAdBCGo2AkAgByAHQRhqNgI4IAdB2ABqIAYQvAEAC/sCAgN/AX4CQCACRQ0AIAAgAToAACACIABqIgNBf2ogAToAACACQQNJDQAgACABOgACIAAgAToAASADQX1qIAE6AAAgA0F+aiABOgAAIAJBB0kNACAAIAE6AAMgA0F8aiABOgAAIAJBCUkNACAAQQAgAGtBA3EiBGoiAyABQf8BcUGBgoQIbCIBNgIAIAMgAiAEa0F8cSIEaiICQXxqIAE2AgAgBEEJSQ0AIAMgATYCCCADIAE2AgQgAkF4aiABNgIAIAJBdGogATYCACAEQRlJDQAgAyABNgIYIAMgATYCFCADIAE2AhAgAyABNgIMIAJBcGogATYCACACQWxqIAE2AgAgAkFoaiABNgIAIAJBZGogATYCACAEIANBBHFBGHIiBWsiAkEgSQ0AIAGtQoGAgIAQfiEGIAMgBWohAQNAIAEgBjcDACABQRhqIAY3AwAgAUEQaiAGNwMAIAFBCGogBjcDACABQSBqIQEgAkFgaiICQR9LDQALCyAAC/UCAQd/QQEhBwJAAkAgAkUNACABIAJBAXRqIQggAEGA/gNxQQh2IQlBACEKIABB/wFxIQsCQANAIAFBAmohDCAKIAEtAAEiAmohDQJAIAEtAAAiASAJRg0AIAEgCUsNAyANIQogDCEBIAwgCEcNAQwDCwJAIA0gCkkNACANIARLDQIgAyAKaiEBAkADQCACRQ0BIAJBf2ohAiABLQAAIQogAUEBaiEBIAogC0cNAAtBACEHDAULIA0hCiAMIQEgDCAIRw0BDAMLCyAKIA0gAhCVAgALIA0gBCACEJQCAAsgBkUNACAFIAZqIQsgAEH//wNxIQFBASEHAkADQCAFQQFqIQoCQAJAIAUtAAAiAkEYdEEYdSINQQBIDQAgCiEFDAELIAogC0YNAiANQf8AcUEIdCAFLQABciECIAVBAmohBQsgASACayIBQQBIDQIgB0EBcyEHIAUgC0cNAAwCCwtBgNrAAEErQejlwAAQtgEACyAHQQFxC7QDAgV/An4jAEHAAGsiBSQAQQEhBgJAIAAtAAQNACAALQAFIQcCQCAAKAIAIggoAgAiCUEEcQ0AQQEhBiAIKAIYQc3cwABBz9zAACAHQf8BcSIHG0ECQQMgBxsgCEEcaigCACgCDBEJAA0BQQEhBiAIKAIYIAEgAiAIKAIcKAIMEQkADQFBASEGIAgoAhhBmNzAAEECIAgoAhwoAgwRCQANASADIAggBCgCDBEHACEGDAELAkAgB0H/AXENAEEBIQYgCCgCGEHI3MAAQQMgCEEcaigCACgCDBEJAA0BIAgoAgAhCQtBASEGIAVBAToAFyAFQTRqQazcwAA2AgAgBUEQaiAFQRdqNgIAIAUgCTYCGCAFIAgpAhg3AwggCCkCCCEKIAgpAhAhCyAFIAgtACA6ADggBSAIKAIENgIcIAUgCzcDKCAFIAo3AyAgBSAFQQhqNgIwIAVBCGogASACEB4NACAFQQhqQZjcwABBAhAeDQAgAyAFQRhqIAQoAgwRBwANACAFKAIwQcvcwABBAiAFKAI0KAIMEQkAIQYLIABBAToABSAAIAY6AAQgBUHAAGokACAAC8kDAQR/IwBBEGsiAiQAIAAoAgAiAC0AACEDIABBADoAAAJAAkACQCADQQFxRQ0AAkBBACgCjPxAIgBBA0cNAAJAAkBBkPzAAEEAIABBA0YbIgMoAgBB8PzAAEYNAEEALQCs/EAhBEEBIQBBAEEBOgCs/EAgBEEBcQ0CIANB8PzAADYCAAwBC0EAKAKU/EAiBEEBaiIAIARJDQMLQQAgADYClPxAQQAoApj8QA0DQQBBfzYCmPxAAkBBAC0AqPxADQAgAkGc/MAAEDQgAi0AAEEDRw0AIAIoAgQiACgCACAAKAIEKAIAEQMAAkAgACgCBCIEKAIEIgVFDQAgACgCACAFIAQoAggQ9QELIABBDEEEEPUBCwJAQQAoAqD8QCIARQ0AQQAoApz8QCAAQQEQ9QELQQBCADcCoPxAQQBBATYCnPxAQQBBACgCmPxAQQFqNgKY/EBBAEEAKAKU/EBBf2oiADYClPxAQQBBADoAqPxAIAANACADQQA2AgBBAEEAOgCs/EALIAJBEGokAA8LQZiMwABBK0HclcAAELYBAAtBiJjAAEEmQdSYwAAQ/gEAC0H4i8AAQRAgAkEIakHEjMAAQayTwAAQgwEAC/ACAQV/IABBC3QhAUEAIQJBICEDQSAhBAJAAkADQAJAAkAgA0EBdiACaiIDQQJ0QcTywABqKAIAQQt0IgUgAUkNACAFIAFGDQMgAyEEDAELIANBAWohAgsgBCACayEDIAQgAksNAAwCCwsgA0EBaiECCwJAAkACQCACQR9LDQAgAkECdCEDQcMFIQQCQCACQR9GDQAgA0HI8sAAaigCAEEVdiEEC0EAIQECQCACQX9qIgUgAksNACAFQSBPDQIgBUECdEHE8sAAaigCAEH///8AcSEBCwJAIAQgA0HE8sAAaigCAEEVdiICQX9zakUNACAAIAFrIQEgAkHDBSACQcMFSxshAyAEQX9qIQVBACEEA0AgAyACRg0EIAQgAkHE88AAai0AAGoiBCABSw0BIAUgAkEBaiICRw0ACyAFIQILIAJBAXEPCyACQSBBjPHAABCPAQALIAVBIEGs8cAAEI8BAAsgA0HDBUGc8cAAEI8BAAvpAgEDfyMAQRBrIgIkACAAKAIAIQACQAJAAkACQAJAIAFBgAFJDQAgAkEANgIMIAFBgBBJDQEgAUGAgARPDQIgAiABQT9xQYABcjoADiACIAFBDHZB4AFyOgAMIAIgAUEGdkE/cUGAAXI6AA1BAyEBDAMLAkAgACgCCCIDIABBBGooAgBHDQAgACADEGQgACgCCCEDCyAAKAIAIANqIAE6AAAgACAAKAIIQQFqNgIIDAMLIAIgAUE/cUGAAXI6AA0gAiABQQZ2QcABcjoADEECIQEMAQsgAiABQT9xQYABcjoADyACIAFBEnZB8AFyOgAMIAIgAUEGdkE/cUGAAXI6AA4gAiABQQx2QT9xQYABcjoADUEEIQELAkAgAEEEaigCACAAQQhqIgQoAgAiA2sgAU8NACAAIAMgARBlIAQoAgAhAwsgACgCACADaiACQQxqIAEQDhogBCADIAFqNgIACyACQRBqJABBAAuJAwEDfyMAQcAAayICJABBASEDAkAgASgCGCIEQdTawABBDCABQRxqKAIAIgEoAgwRCQANAAJAAkAgACgCCCIDRQ0AIAIgAzYCDCACQeUANgIUIAIgAkEMajYCEEEBIQMgAkE8akEBNgIAIAJCAjcCLCACQeTawAA2AiggAiACQRBqNgI4IAQgASACQShqECRFDQEMAgsgACgCACIDIAAoAgQoAgwRBQBCi+TnlfK4j9e4f1INACACIAM2AgwgAkHmADYCFCACIAJBDGo2AhBBASEDIAJBPGpBATYCACACQgI3AiwgAkHk2sAANgIoIAIgAkEQajYCOCAEIAEgAkEoahAkDQELIAAoAgwhAyACQRBqQRRqQSI2AgAgAkEQakEMakEiNgIAIAIgA0EMajYCICACIANBCGo2AhggAkHhADYCFCACIAM2AhAgAkEoakEUakEDNgIAIAJCAzcCLCACQazawAA2AiggAiACQRBqNgI4IAQgASACQShqECQhAwsgAkHAAGokACADC+ICAQN/IwBBEGsiAiQAAkACQAJAAkACQCABQYABSQ0AIAJBADYCDCABQYAQSQ0BIAFBgIAETw0CIAIgAUE/cUGAAXI6AA4gAiABQQx2QeABcjoADCACIAFBBnZBP3FBgAFyOgANQQMhAQwDCwJAIAAoAggiAyAAQQRqKAIARw0AIAAgAxBkIAAoAgghAwsgACgCACADaiABOgAAIAAgACgCCEEBajYCCAwDCyACIAFBP3FBgAFyOgANIAIgAUEGdkHAAXI6AAxBAiEBDAELIAIgAUE/cUGAAXI6AA8gAiABQRJ2QfABcjoADCACIAFBBnZBP3FBgAFyOgAOIAIgAUEMdkE/cUGAAXI6AA1BBCEBCwJAIABBBGooAgAgAEEIaiIEKAIAIgNrIAFPDQAgACADIAEQZSAEKAIAIQMLIAAoAgAgA2ogAkEMaiABEA4aIAQgAyABajYCAAsgAkEQaiQAQQAL5AIBAn8CQAJAAkAgASAAc0EDcUUNACAAIQIMAQsCQAJAIAFBA3ENACAAIQIMAQsgACABLQAAIgI6AAACQCACDQAgAA8LIABBAWohAgJAIAFBAWoiA0EDcQ0AIAMhAQwBCyACIAMtAAAiAzoAACADRQ0CIABBAmohAgJAIAFBAmoiA0EDcQ0AIAMhAQwBCyACIAMtAAAiAzoAACADRQ0CIABBA2ohAgJAIAFBA2oiA0EDcQ0AIAMhAQwBCyACIAMtAAAiAzoAACADRQ0CIABBBGohAiABQQRqIQELIAEoAgAiAEF/cyAAQf/9+3dqcUGAgYKEeHENAANAIAIgADYCACACQQRqIQIgAUEEaiIBKAIAIgBBf3MgAEH//ft3anFBgIGChHhxRQ0ACwsgAiABLQAAIgA6AAAgAEUNACABQQFqIQEDQCACQQFqIgIgAS0AACIAOgAAIAFBAWohASAADQALCyACC98CAQN/IwBBEGsiAiQAAkACQAJAAkACQCABQYABSQ0AIAJBADYCDCABQYAQSQ0BIAFBgIAETw0CIAIgAUE/cUGAAXI6AA4gAiABQQx2QeABcjoADCACIAFBBnZBP3FBgAFyOgANQQMhAQwDCwJAIAAoAggiAyAAQQRqKAIARw0AIAAgAxBnIAAoAgghAwsgACADQQFqNgIIIAAoAgAgA2ogAToAAAwDCyACIAFBP3FBgAFyOgANIAIgAUEGdkHAAXI6AAxBAiEBDAELIAIgAUE/cUGAAXI6AA8gAiABQRJ2QfABcjoADCACIAFBBnZBP3FBgAFyOgAOIAIgAUEMdkE/cUGAAXI6AA1BBCEBCwJAIABBBGooAgAgAEEIaiIEKAIAIgNrIAFPDQAgACADIAEQZiAEKAIAIQMLIAAoAgAgA2ogAkEMaiABEA4aIAQgAyABajYCAAsgAkEQaiQAQQAL3QIBA38CQAJAAkACQCABQf8BcSICRQ0AIABBA3FFDQICQCAALQAAIgMNACAADwsgAyABQf8BcUcNASAADwsgACAAEGxqDwsCQCAAQQFqIgNBA3ENACADIQAMAQsgAy0AACIERQ0BIAQgAUH/AXFGDQECQCAAQQJqIgNBA3ENACADIQAMAQsgAy0AACIERQ0BIAQgAUH/AXFGDQECQCAAQQNqIgNBA3ENACADIQAMAQsgAy0AACIERQ0BIAQgAUH/AXFGDQEgAEEEaiEACwJAIAAoAgAiA0F/cyADQf/9+3dqcUGAgYKEeHENACACQYGChAhsIQIDQCADIAJzIgNBf3MgA0H//ft3anFBgIGChHhxDQEgAEEEaiIAKAIAIgNBf3MgA0H//ft3anFBgIGChHhxRQ0ACwsgAEF/aiEDA0AgA0EBaiIDLQAAIgBFDQEgACABQf8BcUcNAAsLIAMLyAIBBX8CQAJAAkACQCACQQNqQXxxIAJrIgRFDQAgAyAEIAQgA0sbIgRFDQBBACEFIAFB/wFxIQZBASEHA0AgAiAFai0AACAGRg0EIAQgBUEBaiIFRw0ACyAEIANBeGoiCEsNAgwBCyADQXhqIQhBACEECyABQf8BcUGBgoQIbCEFAkADQCACIARqIgYoAgAgBXMiB0F/cyAHQf/9+3dqcSAGQQRqKAIAIAVzIgZBf3MgBkH//ft3anFyQYCBgoR4cQ0BIARBCGoiBCAITQ0ACwsgBCADTQ0AIAQgAyAEEJMCAAsCQCAEIANGDQAgBCADayEIIAIgBGohBkEAIQUgAUH/AXEhBwJAA0AgBiAFai0AACAHRg0BIAggBUEBaiIFakUNAgwACwsgBCAFaiEFQQEhBwwBC0EAIQcLIAAgBTYCBCAAIAc2AgAL0gICBX8BfiMAQTBrIgMkAEEnIQQCQAJAIABCkM4AWg0AIAAhCAwBC0EnIQQDQCADQQlqIARqIgVBfGogACAAQpDOAIAiCEKQzgB+faciBkH//wNxQeQAbiIHQQF0Qe7cwABqLwAAOwAAIAVBfmogBiAHQeQAbGtB//8DcUEBdEHu3MAAai8AADsAACAEQXxqIQQgAEL/wdcvViEFIAghACAFDQALCwJAIAinIgVB4wBNDQAgA0EJaiAEQX5qIgRqIAinIgUgBUH//wNxQeQAbiIFQeQAbGtB//8DcUEBdEHu3MAAai8AADsAAAsCQAJAIAVBCkkNACADQQlqIARBfmoiBGogBUEBdEHu3MAAai8AADsAAAwBCyADQQlqIARBf2oiBGogBUEwajoAAAsgAiABQbjCwABBACADQQlqIARqQScgBGsQGCEEIANBMGokACAEC/cCAQN/IwBBwABrIgIkAAJAQQAtAPj7QA0AIAJBIjYCBCACIAA2AgwgAiACQQxqNgIAIAJBBDoAFCACIAJBOGo2AhAgAkE0akEBNgIAIAJCAjcCJCACQYSawAA2AiAgAiACNgIwAkACQCACQRBqQeyUwAAgAkEgahAkRQ0AIAItABRBBEYNASACLQAUQQNHDQEgAkEYaigCACIAKAIAIAAoAgQoAgARAwACQCAAKAIEIgMoAgQiBEUNACAAKAIAIAQgAygCCBD1AQsgAEEMQQQQ9QEMAQsgAi0AFEEDRw0AIAJBGGooAgAiACgCACAAKAIEKAIAEQMAAkAgACgCBCIDKAIEIgRFDQAgACgCACAEIAMoAggQ9QELIAIoAhhBDEEEEPUBCyACQcAAaiQADwsgAkE0akEBNgIAIAJCAjcCJCACQYSawAA2AiAgAkEiNgIUIAIgADYCACACIAJBEGo2AjAgAiACNgIQIAJBIGpBrJrAABC8AQALiQMBAX9BKCEBAkAgAEH//wNLDQBBAiEBQYaiwAAQtQJB//8DcSAARg0AQQMhAUGIosAAELUCQf//A3EgAEYNAEEBIQFBiqLAABC1AkH//wNxIABGDQBBjKLAABC1AkH//wNxIABGDQBBCyEBQY6iwAAQtQJB//8DcSAARg0AQQchAUGQosAAELUCQf//A3EgAEYNAEEGIQFBkqLAABC1AkH//wNxIABGDQBBCSEBQZSiwAAQtQJB//8DcSAARg0AQQghAUGWosAAELUCQf//A3EgAEYNAEEAIQFBmKLAABC1AkH//wNxIABGDQBBIyEBQZqiwAAQtQJB//8DcSAARg0AQRQhAUGcosAAELUCQf//A3EgAEYNAEEWIQFBnqLAABC1AkH//wNxIABGDQBBDCEBQaCiwAAQtQJB//8DcSAARg0AQQ0hAUGiosAAELUCQf//A3EgAEYNAEEkIQFBpKLAABC1AkH//wNxIABGDQBBJkEoQaaiwAAQtQJB//8DcSAARhshAQsgAQvEAgEDfyMAQYABayICJAACQAJAAkACQAJAIAEoAgAiA0EQcQ0AIANBIHENASAANQIAQQEgARBCIQAMBAsgACgCACEAQQAhAwNAIAIgA2pB/wBqQTBB1wAgAEEPcSIEQQpJGyAEajoAACADQX9qIQMgAEEPSyEEIABBBHYhACAEDQALIANBgAFqIgBBgQFPDQEgAUEBQezcwABBAiACIANqQYABakEAIANrEBghAAwDCyAAKAIAIQBBACEDA0AgAiADakH/AGpBMEE3IABBD3EiBEEKSRsgBGo6AAAgA0F/aiEDIABBD0shBCAAQQR2IQAgBA0ACyADQYABaiIAQYEBTw0BIAFBAUHs3MAAQQIgAiADakGAAWpBACADaxAYIQAMAgsgAEGAASAAEJMCAAsgAEGAASAAEJMCAAsgAkGAAWokACAAC/ACAgV/An4jAEHAAGsiAyQAAkACQCAALQAIRQ0AIAAoAgQhBEEBIQUMAQsgACgCBCEEAkAgACgCACIGKAIAIgdBBHENAEEBIQUgBigCGEHN3MAAQefcwAAgBBtBAkEBIAQbIAZBHGooAgAoAgwRCQANASABIAYgAigCDBEHACEFDAELAkAgBA0AAkAgBigCGEHl3MAAQQIgBkEcaigCACgCDBEJAEUNAEEBIQVBACEEDAILIAYoAgAhBwtBASEFIANBAToAFyADQTRqQazcwAA2AgAgA0EQaiADQRdqNgIAIAMgBzYCGCADIAYpAhg3AwggBikCCCEIIAYpAhAhCSADIAYtACA6ADggAyAGKAIENgIcIAMgCTcDKCADIAg3AyAgAyADQQhqNgIwIAEgA0EYaiACKAIMEQcADQAgAygCMEHL3MAAQQIgAygCNCgCDBEJACEFCyAAIAU6AAggACAEQQFqNgIEIANBwABqJAAgAAuzAgEDfyMAQRBrIgIkACACQQA2AgwCQAJAAkACQCABQYABSQ0AIAFBgBBJDQEgAUGAgARPDQIgAiABQT9xQYABcjoADiACIAFBDHZB4AFyOgAMIAIgAUEGdkE/cUGAAXI6AA1BAyEBDAMLIAIgAToADEEBIQEMAgsgAiABQT9xQYABcjoADSACIAFBBnZBwAFyOgAMQQIhAQwBCyACIAFBP3FBgAFyOgAPIAIgAUESdkHwAXI6AAwgAiABQQZ2QT9xQYABcjoADiACIAFBDHZBP3FBgAFyOgANQQQhAQsCQCAAKAIAIgNBBGooAgAgA0EIaiIEKAIAIgBrIAFPDQAgAyAAIAEQZiAEKAIAIQALIAMoAgAgAGogAkEMaiABEA4aIAQgACABajYCACACQRBqJABBAAvWAgEFfyMAQRBrIgEkAEGABCECAkACQAJAAkBBgARBARDsASIDRQ0AIAFBgAQ2AgQgASADNgIAIANBgAQQswENAQJAAkACQEEAKALwgEEiAkHEAEcNAEGABCECDAELIABCATcCACAAQQhqIAI2AgBBgAQhAgwBCwNAIAEgAjYCCCABIAJBARBmIAEoAgAiAyABKAIEIgIQswENA0EAKALwgEEiBEHEAEYNAAsgAEIBNwIAIABBCGogBDYCACACRQ0DCyADIAJBARD1AQwCC0GABEEBEI4CAAsgASADEGwiBDYCCAJAIAIgBE0NAAJAAkAgBA0AQQEhBSADIAJBARD1AQwBCyADIAJBASAEEOYBIgVFDQMLIAEgBDYCBCABIAU2AgALIAAgASkDADcCBCAAQQA2AgAgAEEMaiABQQhqKAIANgIACyABQRBqJAAPCyAEQQEQjgIAC8ACAQR/IwBBIGsiAiQAAkACQAJAAkACQAJAIAFBBGooAgAiAyABKAIIIgRHDQAgBEEBaiIDIARJDQQCQAJAIAQNAEEAIQUMAQsgAiAENgIUIAIgASgCADYCEEEBIQULIAIgBTYCGCACIANBASACQRBqEHQgAigCAA0BIAIoAgQhBSABQQRqIAM2AgAgASAFNgIACwJAIAQgA0cNACABIAQQaCABQQRqKAIAIQMgASgCCCEECyABIARBAWoiBTYCCCABKAIAIgEgBGpBADoAACADIAVLDQEgASEEDAILIAJBCGooAgAiAUUNAiACKAIEIAEQjgIACwJAIAUNAEEBIQQgASADQQEQ9QEMAQsgASADQQEgBRDmASIERQ0CCyAAIAU2AgQgACAENgIAIAJBIGokAA8LELsBAAsgBUEBEI4CAAvgAgIEfwJ+IwBBwABrIgMkAEEBIQQCQCAALQAEDQAgAC0ABSEEAkACQAJAAkAgACgCACIFKAIAIgZBBHENACAEQf8BcQ0BDAMLIARB/wFxDQFBASEEIAUoAhhB6dzAAEEBIAVBHGooAgAoAgwRCQANAyAFKAIAIQYMAQtBASEEIAUoAhhBzdzAAEECIAVBHGooAgAoAgwRCQBFDQEMAgtBASEEIANBAToAFyADQTRqQazcwAA2AgAgA0EQaiADQRdqNgIAIAMgBjYCGCADIAUpAhg3AwggBSkCCCEHIAUpAhAhCCADIAUtACA6ADggAyAFKAIENgIcIAMgCDcDKCADIAc3AyAgAyADQQhqNgIwIAEgA0EYaiACKAIMEQcADQEgAygCMEHL3MAAQQIgAygCNCgCDBEJACEEDAELIAEgBSACKAIMEQcAIQQLIABBAToABSAAIAQ6AAQgA0HAAGokAAvwAgEBfyMAQSBrIgAkAAJAQQAoAoD8QEEDSQ0AIABBHGpBADYCACAAQdiAwAA2AhggAEIBNwIMIABB3IDAADYCCCAAQQhqQQNBhIHAAEEAIAAQYQsCQEEAKAKA/EBBBUkNACAAQRxqQQA2AgAgAEHYgMAANgIYIABCATcCDCAAQaiBwAA2AgggAEEIakEFQbCBwABBACAAEGELAkBBACgCgPxAQQRJDQAgAEEcakEANgIAIABB2IDAADYCGCAAQgE3AgwgAEHUgcAANgIIIABBCGpBBEHcgcAAQQAgABBhCwJAQQAoAoD8QEECSQ0AIABBHGpBADYCACAAQdiAwAA2AhggAEIBNwIMIABB/IHAADYCCCAAQQhqQQJBhILAAEEAIAAQYQsCQEEAKAKA/EBFDQAgAEEcakEANgIAIABB2IDAADYCGCAAQgE3AgwgAEGogsAANgIIIABBCGpBAUGwgsAAQQAgABBhCyAAQSBqJAAL2AIBAn8jAEEgayIBJAAgACgCACECIABBAjYCAAJAAkACQAJAIAIOAwIBAgALIAFBHGpBADYCACABQfiLwAA2AhggAUIBNwIMIAFBtKTAADYCCCABQQhqQbykwAAQvAEACyAALQAEIQIgAEEBOgAEIAEgAkEBcSICOgAHIAINASAAQQRqIQBBACECAkACQAJAAkACQEEAKALI/EBB/////wdxRQ0AEKICIQIgAC0AAUUNAiACQQFzIQIMAQsgAC0AAUUNAgsgASACOgAMIAEgADYCCEHkjMAAQSsgAUEIakGQjcAAQcykwAAQgwEACyACRQ0BC0EAKALI/EBB/////wdxRQ0AEKICDQAgAEEBOgABCyAAQQA6AAALIAFBIGokAA8LIAFBHGpBADYCACABQRhqQfiLwAA2AgAgAUIBNwIMIAFBkKHAADYCCCABQQdqIAFBCGoQkgEAC7QCAQV/IwBBIGsiAiQAIAAtAAAhAyACQQhqEEgCQAJAIAIoAggNACACQRBqKAIAIQQgAigCDCEADAELQQAhAAJAIAItAAxBA0cNACACQRBqKAIAIgQoAgAgBCgCBCgCABEDAAJAIAQoAgQiBSgCBCIGRQ0AIAQoAgAgBiAFKAIIEPUBCyAEQQxBBBD1AQsLIAJBHGpBADYCACACQfiLwAA2AhggAkIBNwIMIAJBoJfAADYCCAJAAkACQCABIAJBCGoQkQENAAJAIANB/wFxDQAgAkEcakEANgIAIAJB+IvAADYCGCACQgE3AgwgAkGAmMAANgIIIAEgAkEIahCRAQ0BC0EAIQEgAEUNAiAERQ0CDAELQQEhASAARQ0BIARFDQELIAAgBEEBEPUBCyACQSBqJAAgAQukAgEGf0EEIQICQAJAIAENAEEAIQNBACEEQQAhBQwBCyABKAIAIQZBACEDIAFBADYCAEEAIQRBACEFIAZBAUcNACABKAIQIQMgASgCDCEEIAEoAgghAiABKAIEIQULIAAgBTYCBCAAKAIAIQcgAEEBNgIAIABBEGoiBSgCACEBIAUgAzYCACAAQQxqIgMoAgAhBiADIAQ2AgAgAEEIaiIDKAIAIQUgAyACNgIAAkAgB0UNAAJAIAFFDQAgBSABQQN0aiEEIAUhAQNAIAEoAgAgAUEEaiICKAIAKAIAEQMAAkAgAigCACICKAIEIgNFDQAgASgCACADIAIoAggQ9QELIAFBCGoiASAERw0ACwsgBkUNACAFIAZBA3RBBBD1AQsgAEEEagupAgIDfwF+IwBBIGsiAyQAQQAhBAJAIAJFDQACQAJAA0AgAyACNgIMIAMgATYCCCADQRBqQQIgA0EIakEBEKsBAkACQAJAIAMvARANACADKAIUIgUNAUGEk8AAIQVCAiEGDAULIAMgAy8BEjsBHiADQR5qELUCQf//A3EiBRBEQf8BcUEjRg0BQgAhBgwECyACIAVJDQIgASAFaiEBIAIgBWshAgsgAg0ADAMLCyAFIAJBqJTAABCTAgALIAWtQiCGIAaEIQYCQCAALQAEQQNHDQAgAEEIaigCACICKAIAIAIoAgQoAgARAwACQCACKAIEIgEoAgQiBUUNACACKAIAIAUgASgCCBD1AQsgAkEMQQQQ9QELIAAgBjcCBEEBIQQLIANBIGokACAEC7ICAgR/An4jAEEgayIBJAAgAUEQakHYiMAAQQgQVQJAAkAgASgCEA0AIAFBEGpBCGooAgAhAkEDIAEoAhQiAyABQRxqKAIAEBUiBCAEQQZGGyEEIAJFDQEgAyACQQEQ9QEMAQtBAyEEIAEoAhQiAkUNACABQRhqKAIAIgNFDQAgAiADQQEQ9QELAkACQEEAKQPQ/EBQDQBBACkD4PxAIQVBACkD2PxAIQZB2PzAACECDAELIAEQigFBAEIBNwPQ/EBBACABKQMIIgU3A+D8QEHY/MAAIQIgASkDACEGCyAAIAQ2AiwgAEIENwMgIABBADYCECAAIAU3AwggACAGNwMAIABBKGpBADYCACAAQRhqQgA3AwAgAEEUakHAhcAANgIAIAIgBkIBfDcDACABQSBqJAALqAIBAX8jAEHwAGsiBCQAIARBCGpB7I7AAEEEEC8CQCAEKAIIDQAgBCgCDCAEQRBqKAIAEFMQbSAAIAEoAhQRBAAhAAJAQQAoAoT8QEEDRg0AIARBAToAKCAEIARBKGo2AkhBhPzAAEEAIARByABqQayVwABB4I/AABAjCyAEQfAAaiQAIAAPCyAEIARBCGpBBHI2AhwgBEEoakEUakEBNgIAIARByABqQRRqQQE2AgAgBEICNwIsIARBiI/AADYCKCAEQSA2AkQgBEIBNwJMIARBwI/AADYCSCAEQSE2AmQgBCAEQcAAajYCOCAEIARByABqNgJAIAQgBEHgAGo2AlggBCAEQRxqNgJgIARBIGogBEHoAGogBEEoahBaIARBIGoQrgEQsQIAC5kCAgR/AX4jAEEwayICJAAgAUEEaiEDAkAgASgCBA0AIAEoAgAhBCACQQhqQQhqIgVBADYCACACQgE3AwggAiACQQhqNgIUIAJBGGpBEGogBEEQaikCADcDACACQRhqQQhqIARBCGopAgA3AwAgAiAEKQIANwMYIAJBFGpB4IvAACACQRhqECQaIANBCGogBSgCADYCACADIAIpAwg3AgALIAJBGGpBCGoiBCADQQhqKAIANgIAIAFBDGpBADYCACADKQIAIQYgAUIBNwIEIAIgBjcDGAJAQQxBBBDsASIBDQBBDEEEEI4CAAsgASACKQMYNwIAIAFBCGogBCgCADYCACAAQYSdwAA2AgQgACABNgIAIAJBMGokAAuvAgICfwF+IwBBIGsiAiQAAkACQEEgQQgQ7AEiA0UNACADIAA2AhAgA0KBgICAEDcDACADQRRqIAE2AgBBAC0AiPxAIQBBAEEBOgCI/EAgAiAAOgAHIAANAQJAAkBBACkD4PtAIgRCf1ENAEEAIARCAXw3A+D7QCAEQgBSDQFBmIzAAEErQdiRwAAQtgEAC0EAQQA6AIj8QCACQRxqQQA2AgAgAkH4i8AANgIYIAJCATcCDCACQcCRwAA2AgggAkEIakHIkcAAELwBAAsgA0IANwMYIAMgBDcDCEEAQQA6AIj8QCACQSBqJAAgAw8LQSBBCBCOAgALIAJBCGpBFGpBADYCACACQRhqQfiLwAA2AgAgAkIBNwIMIAJBkKHAADYCCCACQQdqIAJBCGoQkgEAC/oBAQF/IwBBEGsiAiQAIAAoAgAhACACQQA2AgwCQAJAAkACQCABQYABSQ0AIAFBgBBJDQEgAUGAgARPDQIgAiABQT9xQYABcjoADiACIAFBDHZB4AFyOgAMIAIgAUEGdkE/cUGAAXI6AA1BAyEBDAMLIAIgAToADEEBIQEMAgsgAiABQT9xQYABcjoADSACIAFBBnZBwAFyOgAMQQIhAQwBCyACIAFBP3FBgAFyOgAPIAIgAUESdkHwAXI6AAwgAiABQQZ2QT9xQYABcjoADiACIAFBDHZBP3FBgAFyOgANQQQhAQsgACACQQxqIAEQTyEBIAJBEGokACABC4UCAQJ/IwBB0ABrIgMkACADQQhqIAEgAhBZAkACQCADKAIIIgENACAAQgE3AgAMAQsgAygCDCECIANBOGogASADQQhqQQhqKAIAIgQQIAJAAkAgAygCOA0AIANBKGpBCGogAjYCACADQRhqQQhqIAQ2AgAgAyABNgIsIAMgAykCLDcDGEEAIQEMAQsgAyADKQI8NwJEIAMgBDYCQCADIAI2AjwgAyABNgI4IANBKGpBBHIgA0E4ahDbASADQRhqQQhqIANBNGooAgA2AgAgAyADKQIsNwMYQQEhAQsgACADKQMYNwIEIAAgATYCACAAQQxqIANBIGooAgA2AgALIANB0ABqJAAL+gEBAX8jAEEQayICJAAgACgCACEAIAJBADYCDAJAAkACQAJAIAFBgAFJDQAgAUGAEEkNASABQYCABE8NAiACIAFBP3FBgAFyOgAOIAIgAUEMdkHgAXI6AAwgAiABQQZ2QT9xQYABcjoADUEDIQEMAwsgAiABOgAMQQEhAQwCCyACIAFBP3FBgAFyOgANIAIgAUEGdkHAAXI6AAxBAiEBDAELIAIgAUE/cUGAAXI6AA8gAiABQRJ2QfABcjoADCACIAFBBnZBP3FBgAFyOgAOIAIgAUEMdkE/cUGAAXI6AA1BBCEBCyAAIAJBDGogARAeIQEgAkEQaiQAIAEL8wEBAX8jAEEQayICJAAgAkEANgIMAkACQAJAAkAgAUGAAUkNACABQYAQSQ0BIAFBgIAETw0CIAIgAUE/cUGAAXI6AA4gAiABQQx2QeABcjoADCACIAFBBnZBP3FBgAFyOgANQQMhAQwDCyACIAE6AAxBASEBDAILIAIgAUE/cUGAAXI6AA0gAiABQQZ2QcABcjoADEECIQEMAQsgAiABQT9xQYABcjoADyACIAFBEnZB8AFyOgAMIAIgAUEGdkE/cUGAAXI6AA4gAiABQQx2QT9xQYABcjoADUEEIQELIAAgAkEMaiABEE8hASACQRBqJAAgAQvzAQEBfyMAQRBrIgIkACACQQA2AgwCQAJAAkACQCABQYABSQ0AIAFBgBBJDQEgAUGAgARPDQIgAiABQT9xQYABcjoADiACIAFBDHZB4AFyOgAMIAIgAUEGdkE/cUGAAXI6AA1BAyEBDAMLIAIgAToADEEBIQEMAgsgAiABQT9xQYABcjoADSACIAFBBnZBwAFyOgAMQQIhAQwBCyACIAFBP3FBgAFyOgAPIAIgAUESdkHwAXI6AAwgAiABQQZ2QT9xQYABcjoADiACIAFBDHZBP3FBgAFyOgANQQQhAQsgACACQQxqIAEQHiEBIAJBEGokACABC+4BAQR/IwBBIGsiAyQAIANBCGogASACEC8CQAJAAkACQCADKAIIRQ0AAkAgA0EUaigCACIBRQ0AIANBEGooAgAgAUEBEPUBCyAAQQA2AgAMAQsgA0EQaigCACEEAkACQCADKAIMIgIQgQEiBUUNAAJAAkAgBRBsIgENAEEBIQYMAQsgAUEASA0EIAFBARDsASIGRQ0FCyAGIAUgARAOIQUgAEEIaiABNgIAIAAgATYCBCAAIAU2AgAMAQsgAEEANgIACyACQQA6AAAgBEUNACACIARBARD1AQsgA0EgaiQADwsQuwEACyABQQEQjgIAC+4BAQF/IwBBMGsiAyQAIANBBDoADCADIAE2AgggA0EYakEQaiACQRBqKQIANwMAIANBGGpBCGogAkEIaikCADcDACADIAIpAgA3AxgCQAJAIANBCGpB7JTAACADQRhqECRFDQACQCADLQAMQQRHDQAgAEHIlMAArUIghkIChDcCAAwCCyAAIAMpAgw3AgAMAQsgAEEEOgAAIAMtAAxBA0cNACADQRBqKAIAIgIoAgAgAigCBCgCABEDAAJAIAIoAgQiASgCBCIARQ0AIAIoAgAgACABKAIIEPUBCyADKAIQQQxBBBD1AQsgA0EwaiQAC+4BAQF/IwBBMGsiAyQAIANBBDoADCADIAE2AgggA0EYakEQaiACQRBqKQIANwMAIANBGGpBCGogAkEIaikCADcDACADIAIpAgA3AxgCQAJAIANBCGpB1JTAACADQRhqECRFDQACQCADLQAMQQRHDQAgAEHIlMAArUIghkIChDcCAAwCCyAAIAMpAgw3AgAMAQsgAEEEOgAAIAMtAAxBA0cNACADQRBqKAIAIgIoAgAgAigCBCgCABEDAAJAIAIoAgQiASgCBCIARQ0AIAIoAgAgACABKAIIEPUBCyADKAIQQQxBBBD1AQsgA0EwaiQAC9gBAQV/IwBBIGsiAiQAAkAgAUEBaiIDIAFJDQBBBCEEIABBBGooAgAiBUEBdCIBIAMgASADSxsiAUEEIAFBBEsbIgFB/////wFxIAFGQQJ0IQMgAUEDdCEGAkACQCAFDQBBACEEDAELIAIgBUEDdDYCFCACIAAoAgA2AhALIAIgBDYCGCACIAYgAyACQRBqEHUCQCACKAIARQ0AIAJBCGooAgAiAEUNASACKAIEIAAQjgIACyACKAIEIQMgAEEEaiABNgIAIAAgAzYCACACQSBqJAAPCxC7AQAL5QEBAX8jAEEQayIHJAAgByAAKAIYIAEgAiAAQRxqKAIAKAIMEQkAOgAIIAcgADYCACAHIAJFOgAJIAdBADYCBCAHIAMgBBBGIAUgBhBGGiAHLQAIIQACQCAHKAIEIgNFDQAgAEH/AXEhAkEBIQAgAg0AIAcoAgAhAgJAIANBAUcNACAHLQAJQf8BcUUNACACLQAAQQRxDQBBASEAIAIoAhhB6NzAAEEBIAJBHGooAgAoAgwRCQANAQsgAigCGEGk2cAAQQEgAkEcaigCACgCDBEJACEACyAHQRBqJAAgAEH/AXFBAEcL3wEBAX8jAEEQayIFJAAgBSAAKAIYIAEgAiAAQRxqKAIAKAIMEQkAOgAIIAUgADYCACAFIAJFOgAJIAVBADYCBCAFIAMgBBBGGiAFLQAIIQACQCAFKAIEIgNFDQAgAEH/AXEhAkEBIQAgAg0AIAUoAgAhAgJAIANBAUcNACAFLQAJQf8BcUUNACACLQAAQQRxDQBBASEAIAIoAhhB6NzAAEEBIAJBHGooAgAoAgwRCQANAQsgAigCGEGk2cAAQQEgAkEcaigCACgCDBEJACEACyAFQRBqJAAgAEH/AXFBAEcL9QEBBH8jAEEQayIAJABBACEBAkACQAJAAkACQEEAKAKw/EAOBAMEAQIAC0HAjcAAQShBnJXAABC2AQALQQEhAQwCC0ECIQEMAQsgAEHokcAAQQ4QWQJAAkAgACgCACIBRQ0AQQAhAiAAKAIEIQMCQAJAAkAgAEEIaigCAEF/ag4EAAICAQILQX5BACABLQAAQTBGGyECDAELIAEoAABB5uqx4wZGIQILAkAgA0UNACABIANBARD1AQtBASEDQQAhAQJAIAJBA3EOAwIAAQILQQIhA0EBIQEMAQtBAyEDQQIhAQtBACADNgKw/EALIABBEGokACABC+sBAQR/IwBBEGsiASQAAkBBACAAKAIAEQQAIgBFDQACQCAAKAIADQAgAEF/NgIAAkACQCAAKAIMIgINAEEAIQIMAQsCQANAIAAgAkF/aiICNgIMIAAoAgQgAkEDdGoiAygCACICRQ0BIAIgAygCBCIDKAIAEQMAAkAgAygCBCIERQ0AIAIgBCADKAIIEPUBCyAAKAIMIgINAAsLIAAoAgBBAWohAgsgACACNgIAIAFBEGokAA8LQaz6wABBECABQQhqQbz6wABBwPvAABCDAQALQYf5wABBxgAgAUEIakHM+sAAQZz6wAAQgwEAC+4BAgN/A34jAEHQAGsiBSQAAkAgAw0AQQAoAtz7QCEDQQAoAtj7QCEGQQAoAvz7QCEHIAIpAgAhCCACKQIIIQkgAikCECEKIAVByABqIAIoAhg2AgAgBUE8aiAKNwIAIAVBMGogCTcDACAFQSRqIAApAhA3AgAgBUEcaiAAKQIINwIAIAVBATYCRCAFQQA2AjggBUEANgIsIAUgCDcCDCAFIAE2AgggBSAAKQIANwIUIAZBiInAACAHQQJGIgIbIAVBCGogA0GUicAAIAIbKAIUEQYAIAVB0ABqJAAPC0GBisAAQdUAQdiKwAAQ0AEAC9UBAQJ/IwBBIGsiBCQAAkACQAJAIANFDQADQCAEIAM2AgwgBCACNgIIIARBEGpBAiAEQQhqQQEQqwECQAJAAkAgBC8BEA0AIAQoAhQiBQ0BIABBhJPAAK1CIIZCAoQ3AgAMBQsgBCAELwESOwEeIARBHmoQtQJB//8DcSIFEERB/wFxQSNGDQEgAEEANgIAIABBBGogBTYCAAwECyADIAVJDQQgAiAFaiECIAMgBWshAwsgAw0ACwsgAEEEOgAACyAEQSBqJAAPCyAFIANBqJTAABCTAgAL3wECAX8BfCMAQdAAayIBJAAgASAAOQMIIAFBACsD8PtAIgI5AxACQCAARAAAAAAAAAAAYQ0AQQAgAiAAoyICOQPw+0AgASACOQMYQQAoAoD8QEECTQ0AIAFBOGpBFGpBBDYCACABQcQAakEENgIAIAFBIGpBFGpBAzYCACABQgM3AiQgAUH8g8AANgIgIAFBBDYCPCABIAFBOGo2AjAgASABQRhqNgJIIAEgAUEIajYCQCABIAFBEGo2AjggAUEgakEDQZSEwABBACABEGEgASsDGCECCyABQdAAaiQAIAILvwEBA38jAEEgayICJAACQCABQQFqIgMgAUkNACAAQQRqKAIAIgRBAXQiASADIAEgA0sbIgFBCCABQQhLGyEBAkACQCAEDQBBACEDDAELIAIgBDYCFCACIAAoAgA2AhBBASEDCyACIAM2AhggAiABQQEgAkEQahB1AkAgAigCAEUNACACQQhqKAIAIgBFDQEgAigCBCAAEI4CAAsgAigCBCEDIABBBGogATYCACAAIAM2AgAgAkEgaiQADwsQuwEAC78BAQJ/IwBBIGsiAyQAAkAgASACaiICIAFJDQAgAEEEaigCACIEQQF0IgEgAiABIAJLGyIBQQggAUEISxshAQJAAkAgBA0AQQAhAgwBCyADIAQ2AhQgAyAAKAIANgIQQQEhAgsgAyACNgIYIAMgAUEBIANBEGoQdQJAIAMoAgBFDQAgA0EIaigCACIARQ0BIAMoAgQgABCOAgALIAMoAgQhAiAAQQRqIAE2AgAgACACNgIAIANBIGokAA8LELsBAAu/AQECfyMAQSBrIgMkAAJAIAEgAmoiAiABSQ0AIABBBGooAgAiBEEBdCIBIAIgASACSxsiAUEIIAFBCEsbIQECQAJAIAQNAEEAIQIMAQsgAyAENgIUIAMgACgCADYCEEEBIQILIAMgAjYCGCADIAFBASADQRBqEHMCQCADKAIARQ0AIANBCGooAgAiAEUNASADKAIEIAAQjgIACyADKAIEIQIgAEEEaiABNgIAIAAgAjYCACADQSBqJAAPCxC7AQALvwEBA38jAEEgayICJAACQCABQQFqIgMgAUkNACAAQQRqKAIAIgRBAXQiASADIAEgA0sbIgFBCCABQQhLGyEBAkACQCAEDQBBACEDDAELIAIgBDYCFCACIAAoAgA2AhBBASEDCyACIAM2AhggAiABQQEgAkEQahBzAkAgAigCAEUNACACQQhqKAIAIgBFDQEgAigCBCAAEI4CAAsgAigCBCEDIABBBGogATYCACAAIAM2AgAgAkEgaiQADwsQuwEAC78BAQN/IwBBIGsi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IgBBCGooAgAhAyAAKAIAIQAgAiABEMwBAkAgA0UNAANAIAIgADYCDCACIAJBDGpBnMDAABD/ARogAEEBaiEAIANBf2oiAw0ACwsgAhDPASEAIAJBEGokACAAC3QBAX8jAEEgayIBJAAgAUEQakIANwMAIAFCADcDCCABIAFBCGpBEBDdAQJAIAEvAQBFDQAgASABLwECOwEeQaiiwABBEiABQR5qQdSMwABB3KLAABCDAQALIAAgASkDEDcDCCAAIAEpAwg3AwAgAUEgaiQAC20BAX8jAEEwayIDJAAgAyABNgIEIAMgADYCACADQRxqQQI2AgAgA0EsakEiNgIAIANCAzcCDCADQfjBwAA2AgggA0EiNgIkIAMgA0EgajYCGCADIANBBGo2AiggAyADNgIgIANBCGogAhC8AQALcAEBfyMAQTBrIgIkACACIAE2AgQgAiAANgIAIAJBHGpBAjYCACACQSxqQSI2AgAgAkICNwIMIAJB0N/AADYCCCACQSI2AiQgAiACQSBqNgIYIAIgAkEEajYCKCACIAI2AiAgAkEIakGA4MAAELwBAAtwAQF/IwBBMGsiAiQAIAIgATYCBCACIAA2AgAgAkEcakECNgIAIAJBLGpBIjYCACACQgI3AgwgAkGg4MAANgIIIAJBIjYCJCACIAJBIGo2AhggAiACQQRqNgIoIAIgAjYCICACQQhqQbDgwAAQvAEAC3ABAX8jAEEwayICJAAgAiABNgIEIAIgADYCACACQRxqQQI2AgAgAkEsakEiNgIAIAJCAjcCDCACQeTgwAA2AgggAkEiNgIkIAIgAkEgajYCGCACIAJBBGo2AiggAiACNgIgIAJBCGpB9ODAABC8AQALbQEBfyMAQTBrIgMkACADIAE2AgQgAyAANgIAIANBHGpBAjYCACADQSxqQSI2AgAgA0ICNwIMIANB8NnAADYCCCADQSI2AiQgAyADQSBqNgIYIAMgAzYCKCADIANBBGo2AiAgA0EIaiACELwBAAtkAQJ/IwBBIGsiAiQAIAFBHGooAgAhAyABKAIYIQEgAkEIakEQaiAAQRBqKQIANwMAIAJBCGpBCGogAEEIaikCADcDACACIAApAgA3AwggASADIAJBCGoQJCEAIAJBIGokACAAC2QBAn8jAEEgayICJAAgAEEcaigCACEDIAAoAhghACACQQhqQRBqIAFBEGopAgA3AwAgAkEIakEIaiABQQhqKQIANwMAIAIgASkCADcDCCAAIAMgAkEIahAkIQEgAkEgaiQAIAELbgEBfyMAQSBrIgIkACACQYCSwAA2AgQgAiAANgIAIAJBCGpBEGogAUEQaikCADcDACACQQhqQQhqIAFBCGopAgA3AwAgAiABKQIANwMIQQAgAkGwjcAAIAJBBGpBsI3AACACQQhqQdChwAAQNQALawEBfyMAQSBrIgMkACADQeCWwAA2AgQgAyAANgIAIANBCGpBEGogAUEQaikCADcDACADQQhqQQhqIAFBCGopAgA3AwAgAyABKQIANwMIQQAgA0GgjcAAIANBBGpBoI3AACADQQhqIAIQNQALawEBfyMAQSBrIgMkACADIAE2AgQgAyAANgIAIANBCGpBEGogAkEQaikCADcDACADQQhqQQhqIAJBCGopAgA3AwAgAyACKQIANwMIQQAgA0H82sAAIANBBGpB/NrAACADQQhqQYjDwAAQNQALYwEBfyMAQSBrIgIkACACIAAoAgA2AgQgAkEIakEQaiABQRBqKQIANwMAIAJBCGpBCGogAUEIaikCADcDACACIAEpAgA3AwggAkEEakGEh8AAIAJBCGoQJCEBIAJBIGokACABC2MBAX8jAEEgayICJAAgAiAAKAIANgIEIAJBCGpBEGogAUEQaikCADcDACACQQhqQQhqIAFBCGopAgA3AwAgAiABKQIANwMIIAJBBGpBsIvAACACQQhqECQhASACQSBqJAAgAQtjAQF/IwBBIGsiAiQAIAIgACgCADYCBCACQQhqQRBqIAFBEGopAgA3AwAgAkEIakEIaiABQQhqKQIANwMAIAIgASkCADcDCCACQQRqQeCLwAAgAkEIahAkIQEgAkEgaiQAIAELYwEBfyMAQSBrIgIkACACIAAoAgA2AgQgAkEIakEQaiABQRBqKQIANwMAIAJBCGpBCGogAUEIaikCADcDACACIAEpAgA3AwggAkEEakHIi8AAIAJBCGoQJCEBIAJBIGokACABC2MBAX8jAEEgayICJAAgAiAAKAIANgIEIAJBCGpBEGogAUEQaikCADcDACACQQhqQQhqIAFBCGopAgA3AwAgAiABKQIANwMIIAJBBGpBuN7AACACQQhqECQhASACQSBqJAAgAQtgAQF/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ACEDAkAgASgCEEEBRw0AIAEgAyACIAFBFGooAgAQFw8LIAEgAyACQQAQHwtBAQN/IwBBEGsiASQAIAAQugJB5JzAABDjASECIAAQuQIQ5AEhAyABIAI2AgggASAANgIEIAEgAzYCACABEOgBAAtAAQF/IwBBIGsiACQAIABBHGpBADYCACAAQazAwAA2AhggAEIBNwIMIABBhMHAADYCCCAAQQhqQYzBwAAQvAEACz8BAX8jAEEgayICJAAgAkEBOgAYIAIgATYCFCACIAA2AhAgAkHE2sAANgIMIAJBuMLAADYCCCACQQhqELoBAAs5AQF/IwBBMGsiACQAIAAQUAJAIAAQJ0UNAEGAgMAAQSsgAEGsgMAAQciAwAAQgwEACyAAQTBqJAALNAEBfyMAQRBrIgIkACACIAA2AgwgAUHoisAAQQ4gAkEMakH4isAAEF4hASACQRBqJAAgAQsyACAAKAIAIQACQCABEPMBDQACQCABEPQBDQAgACABEP0BDwsgACABEHsPCyAAIAEQegsxAQF/IwBBEGsiAiQAIAJBCGogAUHwj8AAQQsQywEgAkEIahCFASEBIAJBEGokACABCzABAX8jAEEQayICJAAgAkEIaiABQYSXwABBCxDLASACQQhqEHAhASACQRBqJAAgAQsyACAAKAIAIQACQCABEPMBDQACQCABEPQBDQAgACABEP0BDwsgACABEHsPCyAAIAEQegsyACAAKAIAIQACQCABEPMBDQACQCABEPQBDQAgACABEIECDwsgACABEHgPCyAAIAEQdwsvAQJ/IwBBEGsiACQAIABBATYCDCAAQQxqQaSFwABBAEEAEFEhASAAQRBqJAAgAQsvAQF/IwBBEGsiASQAIAAoAgAQsAIgAUEAOgAPIAFBD2oQtAIhACABQRBqJAAgAAsvAQF/IwBBEGsiASQAIAAoAgAQsAIgAUEAOgAPIAFBD2oQtAIhACABQRBqJAAgAAs5AQF/IAAoAgAhAQJAIAAtAAQNAEEAKALI/EBB/////wdxRQ0AEKICDQAgAUEBOgABCyABQQA6AAALLgEBfyMAQRBrIgMkACADIAE2AgwgAyAANgIIIANBCGpBiIvAAEEAIAJBARAaAAsvAQF/IwBBEGsiBSQAIAUgAzYCDCAFIAI2AgggBSABNgIEIAUgADYCACAFEOABAAs0ACAAQQM6ACAgAEKAgICAgAQ3AgAgACABNgIYIABBADYCECAAQQA2AgggAEEcaiACNgIACzAAIAEoAhggAiADIAFBHGooAgAoAgwRCQAhAiAAQQA6AAUgACACOgAEIAAgATYCAAs1AQF/IAEoAhhB6tzAAEEBIAFBHGooAgAoAgwRCQAhAiAAQQA6AAUgACACOgAEIAAgATYCAAsrAAJAAkAgARDzAQ0AIAEQ9AENASAAIAEQggIPCyAAIAEQdg8LIAAgARB5CycBAX8jAEEQayICJAAgAiAAKAIANgIMIAJBDGogARA5IAJBEGokAAsyAQF/QQEhAQJAIAAtAAQNACAAKAIAIgAoAhhB69zAAEEBIAAoAhwoAgwRCQAhAQsgAQsoAQF/IwBBEGsiAyQAIAMgAjYCCCADIAE2AgQgAyAANgIAIAMQ5wEACycBAX8CQCAAKAIEIgFFDQAgAEEIaigCACIARQ0AIAEgAEEBEPUBCwsmAQF/IwBBEGsiAyQAIAMgATYCDCADIAA2AgggA0EIaiACELcBAAsjAAJAAkAgAUEISw0AIAEgAE0NAQsgASAAEN4BDwsgABC2AgsqACAAIAEuAQBBAnQiAUHItsAAaigCADYCBCAAIAFB/LjAAGooAgA2AgALKgAgACABLgEAQQJ0IgFBsLvAAGooAgA2AgQgACABQeS9wABqKAIANgIACyMBAn8CQCAAEGxBAWoiARC2AiICRQ0AIAIgACABEA4aCyACCyABAX8CQCAAQQRqKAIAIgFFDQAgACgCACABQQEQ9QELCyABAX8CQCAAQQRqKAIAIgFFDQAgACgCACABQQEQ9QELCyMAAkAgAC0AAA0AIAFBlN/AAEEFEBYPCyABQZDfwABBBBAWCyEAAkAgASgCAA0AELICAAsgAEGci8AANgIEIAAgATYCAAscACAAIAEpAgA3AgAgAEEIaiABQQhqKAIANgIACx0BAX8gACABQQAoArj8QCICQSMgAhsRBgAQsgIACxkAIAAgASACEAIiATsBAiAAIAFBAEc7AQALFwACQCAAQRBLDQAgARAHDwsgACABEDALJAEBf0GIgcEAIQECQEEAKAKEgUENAEGEgcEAIAAQTiEBCyABCxoAIAAoAgAgACgCBCAAKAIIIAAoAgwQ8QEACxwAIAEoAhhBsNnAAEEOIAFBHGooAgAoAgwRCQALHAAgASgCGEG+8sAAQQUgAUEcaigCACgCDBEJAAsYAAJAIAANAEGYjMAAQSsgARC2AQALIAALGwACQCAADQBBmIzAAEErQfScwAAQtgEACyAACxUBAX8CQBDEASIARQ0AIAAQ+gEACwsUAQF/IAAgASACIAMQsAEhBCAEDwsVACAAKAIAIAAoAgQgACgCCBDIAQALFQAgACgCACAAKAIEIAAoAggQgAEACxUAIAEgACgCACIAKAIAIAAoAgQQFgsTAAJAQQAoAvSAQUF/Rw0AEHwLCxQAIAAoAgAgASAAKAIEKAIMEQcACxABAX8gACABENMBIQIgAg8LEQAgACgCACAAKAIEIAEQmgILDgAgACgCACABED8aQQALEwAgAEGUncAANgIEIAAgATYCAAsQACAAKAIAIAAoAgQgARAZCw0AIAAgASACIAMQEQALEAAgASAAKAIAIAAoAgQQFgsNACAALQAAQRBxQQR2Cw0AIAAtAABBIHFBBXYLDAAgACABIAIQswIPCw8AIAAoAgAoAgAgARC1AQsNACAAKAIAIAEgAhBPCw0AIAAgARADQf//A3ELDQAgACABEARB//8DcQsOABDYAhDYAiAAEKYCAAsLACAAIAEQPhogAAsNACAAKAIAGgN/DAALCw0AIAA1AgBBASABEEILDAAgACABIAIQ0gEACwwAIAAgASACEEogAAsNACAAKAIAIAEgAhAeCw0AIAAxAABBASABEEILDQAgADMBAEEBIAEQQgsPABC/AiAAIAEQwAIQuAILDgAQvwIgACABECsQuAILCgAgACABEI8CDwsNACABQayLwABBAhAWCw0AIAFBrovAAEECEBYLDAAgACgCACABENkBCwsAIAAoAgAgARB/CwsAIAAoAgAgARBHCwoAIAAgARCMAgALCgAgACABEI0CAAsKACAAIAEQhQIACwoAIAAgARCLAgALCgAgACABENwBAAsKACAAIAEQjAEACwoAIAAgARCNAQALCgAgACABEI4BAAsKACAAIAEQlwIACwoAIAAgARCYAgALCgAgACABEJYCAAsKACAAIAEQkgIACwoAIAAgARCQAgALCgAgACABEJECAAsMACAAIAEpAgA3AwALCgAgAiAAIAEQFgsLACAAKAIAIAEQLAsMABC/AiAAEGkQuAILDAAQvwIgABBqELgC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IGdlbmVyYXRlIHVuaXF1ZSB0aHJlYWQgSUQ6IGJpdHNwYWNlIGV4aGF1c3RlZACICBAANwAAAFkIEAAdAAAAEwQAABEAAABZCBAAHQAAABkEAAAqAAAAUlVTVF9CQUNLVFJBQ0UAAPgFEAAAAAAAAGZhaWxlZCB0byB3cml0ZSB0aGUgYnVmZmVyZWQgZGF0YQAAAQkQACEAAAAXAAAAbGlicmFyeS9zdGQvc3JjL2lvL2J1ZmZlcmVkL2J1ZndyaXRlci5yczAJEAAoAAAAjQAAABIAAABmYWlsZWQgdG8gd3JpdGUgd2hvbGUgYnVmZmVyaAkQABwAAAAXAAAAbGlicmFyeS9zdGQvc3JjL2lvL3N0ZGlvLnJzAJAJEAAbAAAAbgIAABMAAABsaWJyYXJ5L3N0ZC9zcmMvaW8vbW9kLnJzAAAAvAkQABkAAAAaBQAAFgAAAGFkdmFuY2luZyBpbyBzbGljZXMgYmV5b25kIHRoZWlyIGxlbmd0aADoCRAAJwAAALwJEAAZAAAAHAUAAA0AAAC8CRAAGQAAAAMGAAAhAAAAZm9ybWF0dGVyIGVycm9yADgKEAAPAAAAKAAAADsAAAAMAAAABAAAADwAAAA9AAAAPgAAADsAAAAMAAAABAAAAD8AAABAAAAAQQAAAGxpYnJhcnkvc3RkL3NyYy9wYW5pYy5yc4QKEAAYAAAA8AAAABIAAAAoAAAABAAAAAQAAABCAAAAQwAAAGxpYnJhcnkvc3RkL3NyYy9zeW5jL29uY2UucnPAChAAHAAAABQBAAAyAAAAYXNzZXJ0aW9uIGZhaWxlZDogc3RhdGVfYW5kX3F1ZXVlLmFkZHIoKSAmIFNUQVRFX01BU0sgPT0gUlVOTklOR09uY2UgaW5zdGFuY2UgaGFzIHByZXZpb3VzbHkgYmVlbiBwb2lzb25lZAAALAsQACoAAAACAAAAwAoQABwAAAD/AQAACQAAAMAKEAAcAAAADAIAADUAAABQb2lzb25FcnJvcnN0YWNrIGJhY2t0cmFjZToKjwsQABEAAABub3RlOiBTb21lIGRldGFpbHMgYXJlIG9taXR0ZWQsIHJ1biB3aXRoIGBSVVNUX0JBQ0tUUkFDRT1mdWxsYCBmb3IgYSB2ZXJib3NlIGJhY2t0cmFjZS4KqAsQAFgAAABsb2NrIGNvdW50IG92ZXJmbG93IGluIHJlZW50cmFudCBtdXRleGxpYnJhcnkvc3RkL3NyYy9zeXNfY29tbW9uL3JlbXV0ZXgucnMALgwQACUAAACnAAAADgAAAGxpYnJhcnkvc3RkL3NyYy9zeXNfY29tbW9uL3RocmVhZF9pbmZvLnJzAAAAZAwQACkAAAAWAAAAMwAAAGQMEAApAAAAKwAAACsAAABhc3NlcnRpb24gZmFpbGVkOiB0aHJlYWRfaW5mby5pc19ub25lKCkAsAwQACcAAABtZW1vcnkgYWxsb2NhdGlvbiBvZiAgYnl0ZXMgZmFpbGVkCgDgDBAAFQAAAPUMEAAOAAAAbGlicmFyeS9zdGQvc3JjL2FsbG9jLnJzFA0QABgAAABSAQAACQAAAGxpYnJhcnkvc3RkL3NyYy9wYW5pY2tpbmcucnM8DRAAHAAAABEBAAAkAAAAQm94PGR5biBBbnk+PHVubmFtZWQ+AAAAKAAAAAAAAAABAAAARAAAAEUAAABGAAAARwAAAEgAAABJAAAASgAAAEsAAAAMAAAABAAAAEwAAABNAAAATgAAAE8AAABQAAAAUQAAAFIAAAB0aHJlYWQgJycgcGFuaWNrZWQgYXQgJycsIAAA0A0QAAgAAADYDRAADwAAAOcNEAADAAAAhQcQAAEAAABub3RlOiBydW4gd2l0aCBgUlVTVF9CQUNLVFJBQ0U9MWAgZW52aXJvbm1lbnQgdmFyaWFibGUgdG8gZGlzcGxheSBhIGJhY2t0cmFjZQoAAAwOEABOAAAAPA0QABwAAABGAgAAHwAAADwNEAAcAAAARwIAAB4AAABLAAAADAAAAAQAAABTAAAAKAAAAAgAAAAEAAAAVAAAAFUAAAAQAAAABAAAAFYAAABXAAAAKAAAAAgAAAAEAAAAWAAAAFkAAAB0aHJlYWQgcGFuaWNrZWQgd2hpbGUgcHJvY2Vzc2luZyBwYW5pYy4gYWJvcnRpbmcuCgAAzA4QADIAAAAKcGFuaWNrZWQgYWZ0ZXIgcGFuaWM6OmFsd2F5c19hYm9ydCgpLCBhYm9ydGluZy4KAAAA+AUQAAAAAAAIDxAAMQAAAHRocmVhZCBwYW5pY2tlZCB3aGlsZSBwYW5pY2tpbmcuIGFib3J0aW5nLgoATA8QACsAAABmYWlsZWQgdG8gaW5pdGlhdGUgcGFuaWMsIGVycm9yIIAPEAAgAAAAYWR2YW5jaW5nIElvU2xpY2UgYmV5b25kIGl0cyBsZW5ndGgAqA8QACMAAABsaWJyYXJ5L3N0ZC9zcmMvc3lzL3dhc2kvaW8ucnMAANQPEAAeAAAAFgAAAA0AAABjb25kdmFyIHdhaXQgbm90IHN1cHBvcnRlZAAABBAQABoAAABsaWJyYXJ5L3N0ZC9zcmMvc3lzL3dhc2kvLi4vdW5zdXBwb3J0ZWQvbG9ja3MvY29uZHZhci5ycygQEAA4AAAAFQAAAAkAAABjYW5ub3QgcmVjdXJzaXZlbHkgYWNxdWlyZSBtdXRleHAQEAAgAAAAbGlicmFyeS9zdGQvc3JjL3N5cy93YXNpLy4uL3Vuc3VwcG9ydGVkL2xvY2tzL211dGV4LnJzAACYEBAANgAAABgAAAAJAAAAcndsb2NrIGxvY2tlZCBmb3Igd3JpdGluZwAAAOAQEAAZAAAACAAOAA8APwACAEAANQANAAQAAwAsABsAHABJABQABgA0ADAAcmFuZG9tX2dldCBmYWlsdXJlbGlicmFyeS9zdGQvc3JjL3N5cy93YXNpL21vZC5ycwAAADoREAAfAAAAXQAAACUAAABsaWJyYXJ5L3N0ZC9zcmMvc3lzX2NvbW1vbi90aHJlYWRfcGFya2VyL2dlbmVyaWMucnMAbBEQADMAAAAnAAAAJgAAAGluY29uc2lzdGVudCBwYXJrIHN0YXRlALAREAAXAAAAbBEQADMAAAA1AAAAFwAAAHBhcmsgc3RhdGUgY2hhbmdlZCB1bmV4cGVjdGVkbHkA4BEQAB8AAABsERAAMwAAADIAAAARAAAAaW5jb25zaXN0ZW50IHN0YXRlIGluIHVucGFyaxgSEAAcAAAAbBEQADMAAABsAAAAEgAAAGwREAAzAAAAegAAAB8AAABjb2RlbmFtZVoAAAAIAAAABAAAAFsAAABtZXNzYWdlTk9UQ0FQQUJMRVhERVZUWFRCU1lUSU1FRE9VVFNUQUxFU1JDSFNQSVBFUk9GU1JBTkdFUFJPVE9UWVBFUFJPVE9OT1NVUFBPUlRQUk9UT1BJUEVQRVJNT1dORVJERUFET1ZFUkZMT1dOWElPTk9UVFlOT1RTVVBOT1RTT0NLTk9UUkVDT1ZFUkFCTEVOT1RFTVBUWU5PVERJUk5PVENPTk5OT1NZU05PU1BDTk9QUk9UT09QVE5PTVNHTk9NRU1OT0xJTktOT0xDS05PRVhFQ05PRU5UTk9ERVZOT0JVRlNORklMRU5FVFVOUkVBQ0hORVRSRVNFVE5FVERPV05OQU1FVE9PTE9OR01VTFRJSE9QTVNHU0laRU1MSU5LTUZJTEVMT09QSVNESVJJU0NPTk5JT0lOVkFMSU5UUklOUFJPR1JFU1NJTFNFUUlEUk1IT1NUVU5SRUFDSEZCSUdGQVVMVEVYSVNURFFVT1RET01ERVNUQUREUlJFUURFQURMS0NPTk5SRVNFVENPTk5SRUZVU0VEQ09OTkFCT1JURURDSElMRENBTkNFTEVEQlVTWUJBRE1TR0JBREZBTFJFQURZQUdBSU5BRk5PU1VQUE9SVEFERFJOT1RBVkFJTEFERFJJTlVTRUFDQ0VTMkJJR1NVQ0NFU1NFeHRlbnNpb246IENhcGFiaWxpdGllcyBpbnN1ZmZpY2llbnQuQ3Jvc3MtZGV2aWNlIGxpbmsuVGV4dCBmaWxlIGJ1c3kuQ29ubmVjdGlvbiB0aW1lZCBvdXQuUmVzZXJ2ZWQuTm8gc3VjaCBwcm9jZXNzLkludmFsaWQgc2Vlay5SZWFkLW9ubHkgZmlsZSBzeXN0ZW0uUmVzdWx0IHRvbyBsYXJnZS5Qcm90b2NvbCB3cm9uZyB0eXBlIGZvciBzb2NrZXQuUHJvdG9jb2wgbm90IHN1cHBvcnRlZC5Qcm90b2NvbCBlcnJvci5Ccm9rZW4gcGlwZS5PcGVyYXRpb24gbm90IHBlcm1pdHRlZC5QcmV2aW91cyBvd25lciBkaWVkLlZhbHVlIHRvbyBsYXJnZSB0byBiZSBzdG9yZWQgaW4gZGF0YSB0eXBlLk5vIHN1Y2ggZGV2aWNlIG9yIGFkZHJlc3MuSW5hcHByb3ByaWF0ZSBJL08gY29udHJvbCBvcGVyYXRpb24uTm90IHN1cHBvcnRlZCwgb3Igb3BlcmF0aW9uIG5vdCBzdXBwb3J0ZWQgb24gc29ja2V0Lk5vdCBhIHNvY2tldC5TdGF0ZSBub3QgcmVjb3ZlcmFibGUuRGlyZWN0b3J5IG5vdCBlbXB0eS5Ob3QgYSBkaXJlY3Rvcnkgb3IgYSBzeW1ib2xpYyBsaW5rIHRvIGEgZGlyZWN0b3J5LlRoZSBzb2NrZXQgaXMgbm90IGNvbm5lY3RlZC5GdW5jdGlvbiBub3Qgc3VwcG9ydGVkLk5vIHNwYWNlIGxlZnQgb24gZGV2aWNlLlByb3RvY29sIG5vdCBhdmFpbGFibGUuTm8gbWVzc2FnZSBvZiB0aGUgZGVzaXJlZCB0eXBlLk5vdCBlbm91Z2ggc3BhY2UuTm8gbG9ja3MgYXZhaWxhYmxlLkV4ZWN1dGFibGUgZmlsZSBmb3JtYXQgZXJyb3IuTm8gc3VjaCBmaWxlIG9yIGRpcmVjdG9yeS5ObyBzdWNoIGRldmljZS5ObyBidWZmZXIgc3BhY2UgYXZhaWxhYmxlLlRvbyBtYW55IGZpbGVzIG9wZW4gaW4gc3lzdGVtLk5ldHdvcmsgdW5yZWFjaGFibGUuQ29ubmVjdGlvbiBhYm9ydGVkIGJ5IG5ldHdvcmsuTmV0d29yayBpcyBkb3duLkZpbGVuYW1lIHRvbyBsb25nLk1lc3NhZ2UgdG9vIGxhcmdlLlRvbyBtYW55IGxpbmtzLkZpbGUgZGVzY3JpcHRvciB2YWx1ZSB0b28gbGFyZ2UuVG9vIG1hbnkgbGV2ZWxzIG9mIHN5bWJvbGljIGxpbmtzLklzIGEgZGlyZWN0b3J5LlNvY2tldCBpcyBjb25uZWN0ZWQuSS9PIGVycm9yLkludmFsaWQgYXJndW1lbnQuSW50ZXJydXB0ZWQgZnVuY3Rpb24uT3BlcmF0aW9uIGluIHByb2dyZXNzLklsbGVnYWwgYnl0ZSBzZXF1ZW5jZS5JZGVudGlmaWVyIHJlbW92ZWQuSG9zdCBpcyB1bnJlYWNoYWJsZS5GaWxlIHRvbyBsYXJnZS5CYWQgYWRkcmVzcy5GaWxlIGV4aXN0cy5NYXRoZW1hdGljcyBhcmd1bWVudCBvdXQgb2YgZG9tYWluIG9mIGZ1bmN0aW9uLkRlc3RpbmF0aW9uIGFkZHJlc3MgcmVxdWlyZWQuUmVzb3VyY2UgZGVhZGxvY2sgd291bGQgb2NjdXIuQ29ubmVjdGlvbiByZXNldC5Db25uZWN0aW9uIHJlZnVzZWQuQ29ubmVjdGlvbiBhYm9ydGVkLk5vIGNoaWxkIHByb2Nlc3Nlcy5PcGVyYXRpb24gY2FuY2VsZWQuRGV2aWNlIG9yIHJlc291cmNlIGJ1c3kuQmFk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AAAAAAAAAAEAAAByAAAAL2hvbWUvcGF2ZWwvLmNhcmdvL3JlZ2lzdHJ5L3NyYy9naXRodWIuY29tLTFlY2M2Mjk5ZGI5ZWM4MjMvbWFyaW5lLXJzLXNkay1tYWluLTAuNi4xNS9zcmMvcmVzdWx0LnJzAFw9EABjAAAAQwAAACMAAABzAAAAAEHY+8AACxiIBBAAlAQQAAEAAAAAAAAAAQAAABggEAAA362BgAAEbmFtZQHUrYGAANwCAEhfWk4xOG1hcmluZV9yc19zZGtfbWFpbjZsb2dnZXIyMGxvZ191dGY4X3N0cmluZ19pbXBsMTdoZGQ5NGY0NzFjMzYyZjE3ZUUBTF9aTjR3YXNpMTNsaWJfZ2VuZXJhdGVkMjJ3YXNpX3NuYXBzaG90X3ByZXZpZXcxOGZkX3dyaXRlMTdoODFlNzQwZmI4NjZkMmMxOUUCT19aTjR3YXNpMTNsaWJfZ2VuZXJhdGVkMjJ3YXNpX3NuYXBzaG90X3ByZXZpZXcxMTByYW5kb21fZ2V0MTdoNjE2NGI5NmNjZGRmYzcxYUUDLV9faW1wb3J0ZWRfd2FzaV9zbmFwc2hvdF9wcmV2aWV3MV9lbnZpcm9uX2dldAQzX19pbXBvcnRlZF93YXNpX3NuYXBzaG90X3ByZXZpZXcxX2Vudmlyb25fc2l6ZXNfZ2V0BStfX2ltcG9ydGVkX3dhc2lfc25hcHNob3RfcHJldmlldzFfcHJvY19leGl0BklfWk40Y29yZTNudW03Zmx0MmRlYzhzdHJhdGVneTZkcmFnb24xNWZvcm1hdF9zaG9ydGVzdDE3aGVkN2VhYzBiMWFiNzg2ODBFBwhkbG1hbGxvYwhGX1pONGNvcmUzbnVtN2ZsdDJkZWM4c3RyYXRlZ3k2ZHJhZ29uMTJmb3JtYXRfZXhhY3QxN2hhNzZkNGM5NjlmN2U5MDkyRQlCX1pONGNvcmUzbnVtN2ZsdDJkZWM4c3RyYXRlZ3k2ZHJhZ29uOW11bF9wb3cxMDE3aDI1NGI5MDc2OWE4M2ZlMGVFCkxfWk40Y29yZTNudW03Zmx0MmRlYzhzdHJhdGVneTVncmlzdTE5Zm9ybWF0X3Nob3J0ZXN0X29wdDE3aGU4ZjFlYjFjNGExYmUyZDNFCy9fWk41YWxsb2M1c2xpY2UxMG1lcmdlX3NvcnQxN2gwMzAzNWY0MDk4M2RhODRhRQwGZGxmcmVlDQ1kaXNwb3NlX2NodW5rDgZtZW1jcHkPB21lbW1vdmUQOV9aTjRjb3JlM251bTZiaWdudW04QmlnMzJ4NDA4bXVsX3BvdzIxN2gzMWFiZGI4ZTA4NTdmMTE2RRE1X1pONGNvcmUzc3RyMTlzbGljZV9lcnJvcl9mYWlsX3J0MTdoNjcwNDcyNjc5ZTFlNDgxMUUSNl9aTjRjb3JlM3N0cjVjb3VudDE0ZG9fY291bnRfY2hhcnMxN2g4MDZiZDU1NTI1NDc0ZDk2RRNJX1pONGNvcmUzbnVtN2ZsdDJkZWM4c3RyYXRlZ3k1Z3Jpc3UxNmZvcm1hdF9leGFjdF9vcHQxN2gyOGRhYzg4MDU0M2FhMTFmRRQHcmVhbGxvYxVhX1pONjNfJExUJGxvZy4uTGV2ZWxGaWx0ZXIkdTIwJGFzJHUyMCRjb3JlLi5zdHIuLnRyYWl0cy4uRnJvbVN0ciRHVCQ4ZnJvbV9zdHIxN2gzYmEwMzMwYmM5NGM4ZWU5RRYuX1pONGNvcmUzZm10OUZvcm1hdHRlcjNwYWQxN2hiOWZkYzQzNGNiYjBjM2E4RRdFX1pONGNvcmUzZm10NWZsb2F0MjlmbG9hdF90b19kZWNpbWFsX2NvbW1vbl9leGFjdDE3aDA4NDZiYzU2YmM0NDU0ZThFGDhfWk40Y29yZTNmbXQ5Rm9ybWF0dGVyMTJwYWRfaW50ZWdyYWwxN2hiYTUzODI4NTNlOTliOGYzRRlFX1pONDBfJExUJHN0ciR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uRGVidWckR1QkM2ZtdDE3aDYzYjYyZWI4NDZiMzg1YzVFGjtfWk4zc3RkOXBhbmlja2luZzIwcnVzdF9wYW5pY193aXRoX2hvb2sxN2hjY2IwNGUwZDg2ODExNmIwRRszX1pOM3N0ZDlwYW5pY2tpbmcxMmRlZmF1bHRfaG9vazE3aGZjNjA2MWQxZDM0NWIzOGVFHDhfWk4zc3RkMmlvNVdyaXRlMTh3cml0ZV9hbGxfdmVjdG9yZWQxN2hjOTA2MDUxYzRiMjgwZDFkRR1RX1pOM3N0ZDlwYW5pY2tpbmcxMmRlZmF1bHRfaG9vazI4XyR1N2IkJHU3YiRjbG9zdXJlJHU3ZCQkdTdkJDE3aDFjOWRhZWViOGU5MDQ0NDVFHmdfWk42OF8kTFQkY29yZS4uZm10Li5idWlsZGVycy4uUGFkQWRhcHRlciR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uV3JpdGUkR1QkOXdyaXRlX3N0cjE3aDViZTYzNjcyNmFkMTEzZmVFH0hfWk40Y29yZTNmbXQ1ZmxvYXQzMmZsb2F0X3RvX2RlY2ltYWxfY29tbW9uX3Nob3J0ZXN0MTdoOGRjNDI5NzIzZDBhNmRlNEUgM19aTjRjb3JlM3N0cjhjb252ZXJ0czlmcm9tX3V0ZjgxN2g5MDZkMmZiMGNiYTdiOTA5RSFmX1pONzFfJExUJGNvcmUuLmhhc2guLnNpcC4uSGFzaGVyJExUJFMkR1QkJHUyMCRhcyR1MjAkY29yZS4uaGFzaC4uSGFzaGVyJEdUJDV3cml0ZTE3aGIxMTk4ZDI3YjkxYjk5OTNFIkFfWk40Y29yZTNmbXQ5Rm9ybWF0dGVyMjF3cml0ZV9mb3JtYXR0ZWRfcGFydHMxN2g2ZjA3NzNkYzljZGQyYWZiRSM2X1pOM3N0ZDRzeW5jNG9uY2U0T25jZTEwY2FsbF9pbm5lcjE3aDE4ZDE4YzAzMTI0NTg5ZTZFJCZfWk40Y29yZTNmbXQ1d3JpdGUxN2g3NWZlNWEyYmI2YjFmYzAyRSU/X1pONGNvcmUzZm10OUZvcm1hdHRlcjE5cGFkX2Zvcm1hdHRlZF9wYXJ0czE3aGM1NDcxZTM3ODI5MDk4MjlFJidfWk4zc3RkNnRocmVhZDRwYXJrMTdoNzk1NzI5MmVlYTk1ZTk1OUUnS19aTjE4bWFyaW5lX3JzX3Nka19tYWluNmxvZ2dlcjE3V2FzbUxvZ2dlckJ1aWxkZXI1YnVpbGQxN2g4ODc3Njg5ZDg5NzE2ZTQzRShgX1pONjdfJExUJG1hcmluZV9yc19zZGtfbWFpbi4ubG9nZ2VyLi5XYXNtTG9nZ2VyJHUyMCRhcyR1MjAkbG9nLi5Mb2ckR1QkM2xvZzE3aDI0NTc5NzllNGRjZWIxMGZFKThfWk4zc3RkMmlvNVdyaXRlMTh3cml0ZV9hbGxfdmVjdG9yZWQxN2g5NDY1OGU4NWY3YjNmZjVhRSo3X1pONGNvcmU0aGFzaDExQnVpbGRIYXNoZXI4aGFzaF9vbmUxN2g2ZGMyMTI5MzA5ZDFkOTVmRSsIYWxsb2NhdGUsXF9aTjRjb3JlM2ZtdDNudW01MF8kTFQkaW1wbCR1MjAkY29yZS4uZm10Li5EZWJ1ZyR1MjAkZm9yJHUyMCR1NjQkR1QkM2ZtdDE3aDRkOTU4MjBmNWUxNzg2YzNFLVlfWk40Y29yZTNudW03Zmx0MmRlYzhzdHJhdGVneTVncmlzdTE2Zm9ybWF0X2V4YWN0X29wdDE0cG9zc2libHlfcm91bmQxN2gwODY5MWYwOTJjYjNjMmYyRS5GX1pONDFfJExUJGNoYXIkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2g3OGNjMWYxMjdjNmQ1YzU2RS9wX1pONzJfJExUJCRSRiRzdHIkdTIwJGFzJHUyMCRhbGxvYy4uZmZpLi5jX3N0ci4uQ1N0cmluZy4ubmV3Li5TcGVjTmV3SW1wbCRHVCQxM3NwZWNfbmV3X2ltcGwxN2g0MGE1ZjQ3ZDczY2E5MTI2RTARaW50ZXJuYWxfbWVtYWxpZ24xgAFfWk4zc3RkMmlvNWltcGxzNzRfJExUJGltcGwkdTIwJHN0ZC4uaW8uLldyaXRlJHUyMCRmb3IkdTIwJGFsbG9jLi52ZWMuLlZlYyRMVCR1OCRDJEEkR1QkJEdUJDE0d3JpdGVfdmVjdG9yZWQxN2g5ZGY3MmU1NjNiZTNjM2RiRTJGX1pONGNvcmUzbnVtNmJpZ251bThCaWczMng0MDEwbXVsX2RpZ2l0czltdWxfaW5uZXIxN2gzNTk4MWU3NDdmZjIwODFmRTM7X1pONGNvcmUzbnVtN2ZsdDJkZWMxN2RpZ2l0c190b19kZWNfc3RyMTdoODE4MmYzZWM0YTk0NDM2MUU0T19aTjNzdGQyaW84YnVmZmVyZWQ5YnVmd3JpdGVyMThCdWZXcml0ZXIkTFQkVyRHVCQ5Zmx1c2hfYnVmMTdoOTJiZTVhMGVkZDA5MGE0ZEU1O19aTjRjb3JlOXBhbmlja2luZzE5YXNzZXJ0X2ZhaWxlZF9pbm5lcjE3aDI0MmM1ZDY5NGI3ZDZmYjdFNgZtZW1zZXQ3NF9aTjRjb3JlN3VuaWNvZGU5cHJpbnRhYmxlNWNoZWNrMTdoNTk4MDM1ZmYxODliM2E3YUU4PF9aTjRjb3JlM2ZtdDhidWlsZGVyczExRGVidWdTdHJ1Y3Q1ZmllbGQxN2g2ZGQ1MmNlYjYzMWEwODEzRTlSX1pOM3N0ZDRzeW5jNG9uY2U0T25jZTljYWxsX29uY2UyOF8kdTdiJCR1N2IkY2xvc3VyZSR1N2QkJHU3ZCQxN2gzNGE2ODVlMzhjYzg5Y2NhRTpKX1pONGNvcmU3dW5pY29kZTEydW5pY29kZV9kYXRhMTVncmFwaGVtZV9leHRlbmQ2bG9va3VwMTdoZDU5NzU5MTdiNzY5OWYwZUU7V19aTjUwXyRMVCQkUkYkbXV0JHUyMCRXJHUyMCRhcyR1MjAkY29yZS4uZm10Li5Xcml0ZSRHVCQxMHdyaXRlX2NoYXIxN2hmNTc5MDg4ZDJhZWZmODhhRTxmX1pONzNfJExUJGNvcmUuLnBhbmljLi5wYW5pY19pbmZvLi5QYW5pY0luZm8kdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRpc3BsYXkkR1QkM2ZtdDE3aDVhNWY2NWFjZjgzNjczODFFPV9fWk41OF8kTFQkYWxsb2MuLnN0cmluZy4uU3RyaW5nJHUyMCRhcyR1MjAkY29yZS4uZm10Li5Xcml0ZSRHVCQxMHdyaXRlX2NoYXIxN2g1NzU1NjFlNjQyZjg1ODYzRT4IX19zdHBjcHk/X19aTjU4XyRMVCRhbGxvYy4uc3RyaW5nLi5TdHJpbmckdTIwJGFzJHUyMCRjb3JlLi5mbXQuLldyaXRlJEdUJDEwd3JpdGVfY2hhcjE3aDU3NTU2MWU2NDJmODU4NjNFQAtfX3N0cmNocm51bEE+X1pONGNvcmU1c2xpY2U2bWVtY2hyMTltZW1jaHJfZ2VuZXJhbF9jYXNlMTdoY2E1MDhkMGUxZWNmNmQ0Y0VCMF9aTjRjb3JlM2ZtdDNudW0zaW1wN2ZtdF91NjQxN2hiMGNhYmI1NTdjMDZjMWRiRUM7X1pOM3N0ZDVhbGxvYzI0ZGVmYXVsdF9hbGxvY19lcnJvcl9ob29rMTdoYjFmYmM1NTA2ZTkxMzMwZkVEN19aTjNzdGQzc3lzNHdhc2kxN2RlY29kZV9lcnJvcl9raW5kMTdoODUyZGE4ZjU5YWU5NzI3Y0VFXF9aTjRjb3JlM2ZtdDNudW01MF8kTFQkaW1wbCR1MjAkY29yZS4uZm10Li5EZWJ1ZyR1MjAkZm9yJHUyMCR1MzIkR1QkM2ZtdDE3aGEwYzIxYTYxZmY0MmNmMGFFRjtfWk40Y29yZTNmbXQ4YnVpbGRlcnMxMERlYnVnVHVwbGU1ZmllbGQxN2gxZTU2MTBiYWE3NDhjNDA5RUcyX1pONGNvcmUzZm10NVdyaXRlMTB3cml0ZV9jaGFyMTdoMzE2NjBhNDk3ZjE1ZDI3MUVILF9aTjNzdGQzZW52MTFjdXJyZW50X2RpcjE3aGM0MzU4ODc3M2Q2OGViZGNFSURfWk41YWxsb2MzZmZpNWNfc3RyN0NTdHJpbmcxOV9mcm9tX3ZlY191bmNoZWNrZWQxN2g4ZmMzNDk1NjlmZTYyNDQwRUo7X1pONGNvcmUzZm10OGJ1aWxkZXJzMTBEZWJ1Z0lubmVyNWVudHJ5MTdoNjA3MjA4OTI2MGI0ZjUxYUVLCXRlc3RfbG9nc0xMX1pOM3N0ZDEwc3lzX2NvbW1vbjEzdGhyZWFkX3BhcmtlcjdnZW5lcmljNlBhcmtlcjZ1bnBhcmsxN2hjZGE4MWYyNmYwNjFmYzQzRU14X1pOOTFfJExUJHN0ZC4uc3lzX2NvbW1vbi4uYmFja3RyYWNlLi5fcHJpbnQuLkRpc3BsYXlCYWNrdHJhY2UkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRpc3BsYXkkR1QkM2ZtdDE3aGVkMmNkODQ4MWRlOGFjYjFFTlBfWk4zc3RkNnRocmVhZDVsb2NhbDRsYXp5MjFMYXp5S2V5SW5uZXIkTFQkVCRHVCQxMGluaXRpYWxpemUxN2g1MmZmZmE1YWM0MzBlMzNlRU9zX1pOODBfJExUJHN0ZC4uaW8uLldyaXRlLi53cml0ZV9mbXQuLkFkYXB0ZXIkTFQkVCRHVCQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLldyaXRlJEdUJDl3cml0ZV9zdHIxN2hhMzc3ZjYxNmM2NDRkMTU3RVBJX1pOMThtYXJpbmVfcnNfc2RrX21haW42bG9nZ2VyMTdXYXNtTG9nZ2VyQnVpbGRlcjNuZXcxN2hhNWZmYmYwNWU1MDdiZjY4RVEzX1pOM3N0ZDJydDE5bGFuZ19zdGFydF9pbnRlcm5hbDE3aDcwODg1NmRiYTBkMGUzMjBFUnxfWk45MF8kTFQkc3RkLi5wYW5pY2tpbmcuLmJlZ2luX3BhbmljX2hhbmRsZXIuLlBhbmljUGF5bG9hZCR1MjAkYXMkdTIwJGNvcmUuLnBhbmljLi5Cb3hNZVVwJEdUJDh0YWtlX2JveDE3aDFjNGE5MWU2NjNlN2VkNWNFUy1fWk4zc3RkNnRocmVhZDZUaHJlYWQzbmV3MTdoZWMxNDVkNTM2YjE3NjZmNUVUV19aTjUwXyRMVCQkUkYkbXV0JHUyMCRXJHUyMCRhcyR1MjAkY29yZS4uZm10Li5Xcml0ZSRHVCQxMHdyaXRlX2NoYXIxN2hiOGRlMWU2YzcyMDVmMjNiRVUkX1pOM3N0ZDNlbnY0X3ZhcjE3aDNiM2Y0MDIzYzZhZTMxNGVFVldfWk41MF8kTFQkJFJGJG11dCR1MjAkVyR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uV3JpdGUkR1QkMTB3cml0ZV9jaGFyMTdoOTBjOTc3NzQ0ZjkzMmM0MEVXMl9aTjRjb3JlM2ZtdDVXcml0ZTEwd3JpdGVfY2hhcjE3aDk1NWYzNWY1NGY2ZGNhYzBFWDJfWk40Y29yZTNmbXQ1V3JpdGUxMHdyaXRlX2NoYXIxN2g3NDQ3MTNlN2I5ZDJiNDVkRVknX1pOM3N0ZDNlbnY3X3Zhcl9vczE3aGJjOGZlOTNiMTQwZGM4NGJFWi5fWk4zc3RkMmlvNVdyaXRlOXdyaXRlX2ZtdDE3aGYyNTgwZjg3OWYyMjI0NDhFWy5fWk4zc3RkMmlvNVdyaXRlOXdyaXRlX2ZtdDE3aDc3NjI5YWQ2YmY4NTQ5Y2FFXExfWk41YWxsb2M3cmF3X3ZlYzE5UmF3VmVjJExUJFQkQyRBJEdUJDE2cmVzZXJ2ZV9mb3JfcHVzaDE3aDI5ZjYyNmY4YjY5YWZlYWRFXUVfWk40Y29yZTNmbXQ5Rm9ybWF0dGVyMjVkZWJ1Z190dXBsZV9maWVsZDJfZmluaXNoMTdoMzM1OTVhZDAwNmFlYTZhNUVeRV9aTjRjb3JlM2ZtdDlGb3JtYXR0ZXIyNWRlYnVnX3R1cGxlX2ZpZWxkMV9maW5pc2gxN2hiZTYyNjY4NTNkM2JmNmZmRV82X1pOM3N0ZDVwYW5pYzE5Z2V0X2JhY2t0cmFjZV9zdHlsZTE3aDdlYmE3Y2FlYjZkNDIyZmNFYEBfWk4zc3RkNnRocmVhZDVsb2NhbDE3TG9jYWxLZXkkTFQkVCRHVCQ0d2l0aDE3aDY2ODAyNWNhYmJkMTliYjBFYS5fWk4zbG9nMTdfX3ByaXZhdGVfYXBpX2xvZzE3aGI4ODc0MjgwYTIyNzQ5ZTVFYi5fWk4zc3RkMmlvNVdyaXRlOXdyaXRlX2FsbDE3aGE3NTY5OWEwNGE1ZmU3YTZFYwZkaXZpZGVkTF9aTjVhbGxvYzdyYXdfdmVjMTlSYXdWZWMkTFQkVCRDJEEkR1QkMTZyZXNlcnZlX2Zvcl9wdXNoMTdoNDg2MDE1YWZkYjI2YTFmZkVlWV9aTjVhbGxvYzdyYXdfdmVjMTlSYXdWZWMkTFQkVCRDJEEkR1QkN3Jlc2VydmUyMWRvX3Jlc2VydmVfYW5kX2hhbmRsZTE3aGExM2QxYzE4YjYxOWRiZTJFZllfWk41YWxsb2M3cmF3X3ZlYzE5UmF3VmVjJExUJFQkQyRBJEdUJDdyZXNlcnZlMjFkb19yZXNlcnZlX2FuZF9oYW5kbGUxN2g2ZjI0NmE5NTRkZWU0YTZlRWdMX1pONWFsbG9jN3Jhd192ZWMxOVJhd1ZlYyRMVCRUJEMkQSRHVCQxNnJlc2VydmVfZm9yX3B1c2gxN2hkNmFiMWVkMDJhMTA1YTFkRWhMX1pONWFsbG9jN3Jhd192ZWMxOVJhd1ZlYyRMVCRUJEMkQSRHVCQxNnJlc2VydmVfZm9yX3B1c2gxN2gwZTdmMDE3OGU2MjU5MGJhRWkDYWRkaghzdWJ0cmFjdGsIbXVsdGlwbHlsBnN0cmxlbm04X1pOM3N0ZDEwc3lzX2NvbW1vbjExdGhyZWFkX2luZm8zc2V0MTdoZDVmMDUyMWE4ZDg3NzYyNUVuPF9aTjRjb3JlN3VuaWNvZGU5cHJpbnRhYmxlMTJpc19wcmludGFibGUxN2g4M2M4ZDAxMjkxZDViZmZjRW9dX1pONGNvcmUzcHRyNTlkcm9wX2luX3BsYWNlJExUJG1hcmluZV9yc19zZGtfbWFpbi4ubG9nZ2VyLi5XYXNtTG9nZ2VyJEdUJDE3aDkzMTIyNzY4ZjBlMDkxZTFFcE1fWk40Y29yZTNmbXQ4YnVpbGRlcnMxMURlYnVnU3RydWN0MjFmaW5pc2hfbm9uX2V4aGF1c3RpdmUxN2g4MzJkNjEwYTg0YzU2NzZhRXF3X1pOOTBfJExUJHN0ZC4ucGFuaWNraW5nLi5iZWdpbl9wYW5pY19oYW5kbGVyLi5QYW5pY1BheWxvYWQkdTIwJGFzJHUyMCRjb3JlLi5wYW5pYy4uQm94TWVVcCRHVCQzZ2V0MTdoYzhkNmQ2NGQ0Mzg2YTM3NkVyCnJ1c3RfcGFuaWNzMl9aTjVhbGxvYzdyYXdfdmVjMTFmaW5pc2hfZ3JvdzE3aDc2Y2JiMzFiM2VmYjFhZDlFdDJfWk41YWxsb2M3cmF3X3ZlYzExZmluaXNoX2dyb3cxN2g4MWRjYjY1NWI2YWY2YzYzRXVLX1pONWFsbG9jN3Jhd192ZWMxMWZpbmlzaF9ncm93MTdoMDliNzk0ODExZWZkMGRkNEUubGx2bS43MDQzNDUzNjExMTg5NzYzNzExdl9fWk40Y29yZTNmbXQzbnVtNTNfJExUJGltcGwkdTIwJGNvcmUuLmZtdC4uTG93ZXJIZXgkdTIwJGZvciR1MjAkaTE2JEdUJDNmbXQxN2hmZjVjYzMzMWExYmI0MzgzRXdeX1pONGNvcmUzZm10M251bTUyXyRMVCRpbXBsJHUyMCRjb3JlLi5mbXQuLkxvd2VySGV4JHUyMCRmb3IkdTIwJGk4JEdUJDNmbXQxN2hmZmI4NmQ0NWQxNzEwNDI4RXheX1pONGNvcmUzZm10M251bTUyXyRMVCRpbXBsJHUyMCRjb3JlLi5mbXQuLlVwcGVySGV4JHUyMCRmb3IkdTIwJGk4JEdUJDNmbXQxN2hkOGFjY2IxYmUxMjJkZTVkRXlfX1pONGNvcmUzZm10M251bTUzXyRMVCRpbXBsJHUyMCRjb3JlLi5mbXQuLlVwcGVySGV4JHUyMCRmb3IkdTIwJGkxNiRHVCQzZm10MTdoYjZiODQ4OWQ3NzUxOGM2N0V6X19aTjRjb3JlM2ZtdDNudW01M18kTFQkaW1wbCR1MjAkY29yZS4uZm10Li5Mb3dlckhleCR1MjAkZm9yJHUyMCRpMzIkR1QkM2ZtdDE3aGM5ZTIxNjEzNTIxNjlkOTBFe19fWk40Y29yZTNmbXQzbnVtNTNfJExUJGltcGwkdTIwJGNvcmUuLmZtdC4uVXBwZXJIZXgkdTIwJGZvciR1MjAkaTMyJEdUJDNmbXQxN2g2YjdkOWFiMDdlYWVjZmNhRXwdX193YXNpbGliY19pbml0aWFsaXplX2Vudmlyb259B3N0cm5jbXB+ZF9aTjY3XyRMVCRtYXJpbmVfcnNfc2RrX21haW4uLmxvZ2dlci4uV2FzbUxvZ2dlciR1MjAkYXMkdTIwJGxvZy4uTG9nJEdUJDdlbmFibGVkMTdoN2ExMjgwZTRhNzRkYTBlZkV/Y19aTjcwXyRMVCRjb3JlLi5wYW5pYy4ubG9jYXRpb24uLkxvY2F0aW9uJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EaXNwbGF5JEdUJDNmbXQxN2gxZjM3Mzc4YzAyYzI2OTA3RYABWF9aTjNzdGQ5cGFuaWNraW5nMTliZWdpbl9wYW5pY19oYW5kbGVyMjhfJHU3YiQkdTdiJGNsb3N1cmUkdTdkJCR1N2QkMTdoNTU0MWY3NGEwMzMxYTFkY0WBAQZnZXRlbnaCAVxfWk42M18kTFQkd2FzaS4ubGliX2dlbmVyYXRlZC4uRXJybm8kdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2g4ZTQwN2U5ZTIwYmNlMDQzRYMBMl9aTjRjb3JlNnJlc3VsdDEzdW53cmFwX2ZhaWxlZDE3aDg2OGEwMDYwMWEzZWI2ODdFhAFfX1pONjRfJExUJHN0ZC4uc3lzLi53YXNpLi5zdGRpby4uU3RkZXJyJHUyMCRhcyR1MjAkc3RkLi5pby4uV3JpdGUkR1QkNXdyaXRlMTdoOGRlNzk5NjUyNGZiM2FkZkWFAT1fWk40Y29yZTNmbXQ4YnVpbGRlcnMxMURlYnVnU3RydWN0NmZpbmlzaDE3aDE1ODY1OWZjZjc5YzU5ZjlFhgFkX1pONzFfJExUJGNvcmUuLm9wcy4ucmFuZ2UuLlJhbmdlJExUJElkeCRHVCQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2g2NzQzYWVkNmQyMzZhMzlhRYcBBmNhbGxvY4gBSV9aTjQ0XyRMVCQkUkYkVCR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uRGlzcGxheSRHVCQzZm10MTdoMjMwZDVhOTZjNzhkZDRlN0WJAUdfWk40Ml8kTFQkJFJGJFQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2gxZmM4NGJmMDZlOTFkZWUwRYoBOV9aTjNzdGQzc3lzNHdhc2kxOWhhc2htYXBfcmFuZG9tX2tleXMxN2gxYzBjMGM4ZGQ1ZDQ3YmE4RYsBSV9aTjVhbGxvYzN2ZWMxNlZlYyRMVCRUJEMkQSRHVCQ2cmVtb3ZlMTNhc3NlcnRfZmFpbGVkMTdoYWYyNmM2ODIzNjUyOGZkNkWMAUdfWk40Y29yZTVzbGljZTVpbmRleDI5c2xpY2Vfc3RhcnRfaW5kZXhfbGVuX2ZhaWxfcnQxN2hhNGE1MTA5MTg5YmU2MDBiRY0BRV9aTjRjb3JlNXNsaWNlNWluZGV4MjdzbGljZV9lbmRfaW5kZXhfbGVuX2ZhaWxfcnQxN2gxYjk4OWE3YjkyYmY2Y2Y1RY4BQ19aTjRjb3JlNXNsaWNlNWluZGV4MjVzbGljZV9pbmRleF9vcmRlcl9mYWlsX3J0MTdoNTlmZTk3Mzc0MzdiZTljMUWPATpfWk40Y29yZTlwYW5pY2tpbmcxOHBhbmljX2JvdW5kc19jaGVjazE3aDk4NDRlNDZjMzM5YjliZmZFkAFYX1pONTlfJExUJGNvcmUuLmZtdC4uQXJndW1lbnRzJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EaXNwbGF5JEdUJDNmbXQxN2hhNjM1MjMyMTQxNzYyYTVlRZEBNF9aTjRjb3JlM2ZtdDlGb3JtYXR0ZXI5d3JpdGVfZm10MTdoNTVhZGViODYxNTYzM2VkMUWSATVfWk40Y29yZTlwYW5pY2tpbmcxM2Fzc2VydF9mYWlsZWQxN2g4OTZkODFlMmU3ZDI3MjAwRZMBNV9aTjRjb3JlOXBhbmlja2luZzEzYXNzZXJ0X2ZhaWxlZDE3aDRhNzEyZTM2ZmQwN2U5ZDdFlAE1X1pONGNvcmU5cGFuaWNraW5nMTNhc3NlcnRfZmFpbGVkMTdoM2NmYmY5MWI2NGRiMzljMEWVAVVfWk41MF8kTFQkJFJGJG11dCR1MjAkVyR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uV3JpdGUkR1QkOXdyaXRlX2ZtdDE3aDBmMzMwMTcwODg4OGU2ZTNFlgFVX1pONTBfJExUJCRSRiRtdXQkdTIwJFckdTIwJGFzJHUyMCRjb3JlLi5mbXQuLldyaXRlJEdUJDl3cml0ZV9mbXQxN2gzYzY0ODYzMzk5NmZlMDc3RZcBVV9aTjUwXyRMVCQkUkYkbXV0JHUyMCRXJHUyMCRhcyR1MjAkY29yZS4uZm10Li5Xcml0ZSRHVCQ5d3JpdGVfZm10MTdoNjA5Zjc0NDg3MTYwNWU4YUWYAVVfWk41MF8kTFQkJFJGJG11dCR1MjAkVyR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uV3JpdGUkR1QkOXdyaXRlX2ZtdDE3aGU5ZThmNDI3ZGJhMWU1N2ZFmQFVX1pONTBfJExUJCRSRiRtdXQkdTIwJFckdTIwJGFzJHUyMCRjb3JlLi5mbXQuLldyaXRlJEdUJDl3cml0ZV9mbXQxN2gwZTQ3NWRiNzM1NDYxZTQ5RZoBMF9aTjRjb3JlM2ZtdDVXcml0ZTl3cml0ZV9mbXQxN2hkMmIzMGJjOGFhNTczYzQ3RZsBLV9aTjNsb2cxNnNldF9ib3hlZF9sb2dnZXIxN2g1YzA4OTg2YmQxZDc2MDNkRZwBMF9aTjRjb3JlM2ZtdDVXcml0ZTl3cml0ZV9mbXQxN2g0OGE0MmFkNzU4OGY0ZWU5RZ0BMF9aTjRjb3JlM2ZtdDVXcml0ZTl3cml0ZV9mbXQxN2g2ZWE0NzQ0ZmU2M2IyMTk1RZ4BaV9aTjY0XyRMVCRzdGQuLnN5cy4ud2FzaS4uc3RkaW8uLlN0ZGVyciR1MjAkYXMkdTIwJHN0ZC4uaW8uLldyaXRlJEdUJDE0d3JpdGVfdmVjdG9yZWQxN2g2OWRkZjM2YTk3OTdhOWFiRZ8BMF9aTjRjb3JlM2ZtdDVXcml0ZTl3cml0ZV9mbXQxN2hjZWU1ZjNmZTQ1M2ZiZmQxRaABBXN0YXRloQE6X1pONWFsbG9jNHN5bmMxMkFyYyRMVCRUJEdUJDlkcm9wX3Nsb3cxN2gxOTI4YzYyNTVmYTMzMDdkRaIBdl9aTjNzdGQyaW81aW1wbHM3NF8kTFQkaW1wbCR1MjAkc3RkLi5pby4uV3JpdGUkdTIwJGZvciR1MjAkYWxsb2MuLnZlYy4uVmVjJExUJHU4JEMkQSRHVCQkR1QkNXdyaXRlMTdoMzk5MTU1OWFhYzY0NzBmMkWjAQtjbGVhcl9zdGF0ZaQBY19aTjcwXyRMVCRjb3JlLi5yZXN1bHQuLlJlc3VsdCRMVCRUJEMkRSRHVCQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2hiZjI5ODBhYmFjYmMxZGU4RaUBfV9aTjkxXyRMVCRzdGQuLnBhbmlja2luZy4uYmVnaW5fcGFuaWMuLlBhbmljUGF5bG9hZCRMVCRBJEdUJCR1MjAkYXMkdTIwJGNvcmUuLnBhbmljLi5Cb3hNZVVwJEdUJDh0YWtlX2JveDE3aGUyYTNiMTY3ZGZhYjliNjBFpgFVX1pONTBfJExUJCRSRiRtdXQkdTIwJFckdTIwJGFzJHUyMCRjb3JlLi5mbXQuLldyaXRlJEdUJDl3cml0ZV9zdHIxN2g4YjdhNTE4MzA2ZWM2M2RiRacBVV9aTjUwXyRMVCQkUkYkbXV0JHUyMCRXJHUyMCRhcyR1MjAkY29yZS4uZm10Li5Xcml0ZSRHVCQ5d3JpdGVfc3RyMTdoMWI2MWEwMjJhZGMyNWRkYkWoAVVfWk41MF8kTFQkJFJGJG11dCR1MjAkVyR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uV3JpdGUkR1QkOXdyaXRlX3N0cjE3aDQ0ODczYjQ2ODNjZjk0M2FFqQF6X1pOM3N0ZDJpbzVpbXBsczc0XyRMVCRpbXBsJHUyMCRzdGQuLmlvLi5Xcml0ZSR1MjAkZm9yJHUyMCRhbGxvYy4udmVjLi5WZWMkTFQkdTgkQyRBJEdUJCRHVCQ5d3JpdGVfYWxsMTdoZThjYzI2MjMwNDQwNmUwYkWqAXNfWk44MF8kTFQkc3RkLi5pby4uV3JpdGUuLndyaXRlX2ZtdC4uQWRhcHRlciRMVCRUJEdUJCR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uV3JpdGUkR1QkOXdyaXRlX3N0cjE3aDkzNmQ4ZTkxYTE1NjhmNThFqwE0X1pONHdhc2kxM2xpYl9nZW5lcmF0ZWQ4ZmRfd3JpdGUxN2g1MDZlNmUxNGE4MGEwYmJiRawBXV9aTjU4XyRMVCRhbGxvYy4uc3RyaW5nLi5TdHJpbmckdTIwJGFzJHUyMCRjb3JlLi5mbXQuLldyaXRlJEdUJDl3cml0ZV9zdHIxN2g1MTY4MGQyM2NjMWU2ZWIxRa0BBHNicmuuAXNfWk40Y29yZTNwdHI4MWRyb3BfaW5fcGxhY2UkTFQkY29yZS4ucmVzdWx0Li5SZXN1bHQkTFQkJExQJCRSUCQkQyRzdGQuLmlvLi5lcnJvci4uRXJyb3IkR1QkJEdUJDE3aGQ4NGFkYWIyYThlNWVjYmFFrwF5X1pONGNvcmUzcHRyODdkcm9wX2luX3BsYWNlJExUJHN0ZC4uaW8uLldyaXRlLi53cml0ZV9mbXQuLkFkYXB0ZXIkTFQkJFJGJG11dCR1MjAkJHU1YiR1OCR1NWQkJEdUJCRHVCQxN2g0ZjQzY2EyMGEwY2JhNmM0RbABDV9fcmRsX3JlYWxsb2OxAQZtZW1jbXCyAUZfWk40Y29yZTNmbXQ5Rm9ybWF0dGVyMTJwYWRfaW50ZWdyYWwxMndyaXRlX3ByZWZpeDE3aDhmMmU0ZmMzZGFhMjYzNzVFswEGZ2V0Y3dktAE6X1pONWFsbG9jNHN5bmMxMkFyYyRMVCRUJEdUJDlkcm9wX3Nsb3cxN2g2YzFmZGI4NjZlMmFlZmQ3RbUBXV9aTjY0XyRMVCRhbGxvYy4uZmZpLi5jX3N0ci4uTnVsRXJyb3IkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2hlOGFiOTlhZDhmZDZiOTA4RbYBLF9aTjRjb3JlOXBhbmlja2luZzVwYW5pYzE3aGVkZjQzNzhlMjA0NjFiMjVFtwE1X1pONGNvcmU5cGFuaWNraW5nMTNwYW5pY19kaXNwbGF5MTdoNjE0YmNmYTcyMzZmOTFhYUW4AX9fWk45M18kTFQkc3RkLi5wYW5pY2tpbmcuLmJlZ2luX3BhbmljX2hhbmRsZXIuLlN0clBhbmljUGF5bG9hZCR1MjAkYXMkdTIwJGNvcmUuLnBhbmljLi5Cb3hNZVVwJEdUJDh0YWtlX2JveDE3aGNmODc3ZmRiMGZjY2Q1NjFFuQFgX1pONGNvcmUzZm10NWZsb2F0NTJfJExUJGltcGwkdTIwJGNvcmUuLmZtdC4uRGlzcGxheSR1MjAkZm9yJHUyMCRmNjQkR1QkM2ZtdDE3aDY1NDMyN2NkNmY5ZWM1YTJFugERcnVzdF9iZWdpbl91bndpbmS7AThfWk41YWxsb2M3cmF3X3ZlYzE3Y2FwYWNpdHlfb3ZlcmZsb3cxN2hjYTIzZTA2MDBhOTUzNGY2RbwBMF9aTjRjb3JlOXBhbmlja2luZzlwYW5pY19mbXQxN2g3YTY1MWM3MGE5NDkyMjhjRb0BKl9aTjEyY2FsY19zZXJ2aWNlNG1haW4xN2gwY2E3NWE5OTZkODFiYTczRb4BVV9aTjU2XyRMVCRsb2cuLlNldExvZ2dlckVycm9yJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EZWJ1ZyRHVCQzZm10MTdoNjUyYzYxNzYzODg0NTJhMkW/AUdfWk40Ml8kTFQkJFJGJFQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2gzZWJjMzNmYzA3ZjQwZmRmRcABYV9aTjY4XyRMVCRzdGQuLnRocmVhZC4ubG9jYWwuLkFjY2Vzc0Vycm9yJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EZWJ1ZyRHVCQzZm10MTdoNTE3ZjAxOTlmNzk2OWU0ZEXBAWlfWk43Nl8kTFQkc3RkLi5zeW5jLi5wb2lzb24uLlBvaXNvbkVycm9yJExUJFQkR1QkJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EZWJ1ZyRHVCQzZm10MTdoMTdhNDJkMjNlOGVjMWJjZEXCAUdfWk40Ml8kTFQkJFJGJFQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2g1Y2M3Njk4N2QxYWY4YzljRcMBR19aTjQyXyRMVCQkUkYkVCR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uRGVidWckR1QkM2ZtdDE3aGMxOGRkNjA0OTVjZWZlMDBFxAEPX19vcmlnaW5hbF9tYWluxQFhX1pOM3N0ZDJydDEwbGFuZ19zdGFydDI4XyR1N2IkJHU3YiRjbG9zdXJlJHU3ZCQkdTdkJDE3aDY5ZmNlMWZmZGI2ZjVhOThFLmxsdm0uNzEzOTI0MTQxMTY3NDgxMjc1M8YBc19aTjRjb3JlM29wczhmdW5jdGlvbjZGbk9uY2U0MGNhbGxfb25jZSR1N2IkJHU3YiR2dGFibGUuc2hpbSR1N2QkJHU3ZCQxN2gyMjFjZWNjMmEwOGQ2ZTM4RS5sbHZtLjcxMzkyNDE0MTE2NzQ4MTI3NTPHAYoBX1pONGNvcmUzcHRyMTAzZHJvcF9pbl9wbGFjZSRMVCRzdGQuLnN5bmMuLnBvaXNvbi4uUG9pc29uRXJyb3IkTFQkc3RkLi5zeW5jLi5tdXRleC4uTXV0ZXhHdWFyZCRMVCQkTFAkJFJQJCRHVCQkR1QkJEdUJDE3aGEzYjY1YzIyMDJlZDhjOWNFyAFQX1pOM3N0ZDlwYW5pY2tpbmcxMWJlZ2luX3BhbmljMjhfJHU3YiQkdTdiJGNsb3N1cmUkdTdkJCR1N2QkMTdoM2ZhOWYwYzVkM2JkNzBmZEXJATJfWk40Y29yZTNzdHIxNnNsaWNlX2Vycm9yX2ZhaWwxN2hkNGY4MTcyYTA1YjExYTk5RcoBLl9aTjRjb3JlM2ZtdDlGb3JtYXR0ZXIzbmV3MTdoNDkxOGE3OWU1NTQyN2Y4OEXLAThfWk40Y29yZTNmbXQ5Rm9ybWF0dGVyMTJkZWJ1Z19zdHJ1Y3QxN2g5N2UxYzNkYjQ0YzU5YmE3RcwBNl9aTjRjb3JlM2ZtdDlGb3JtYXR0ZXIxMGRlYnVnX2xpc3QxN2hjZmE0NmI2NDgxODczMjEyRc0BXF9aTjRjb3JlM2ZtdDNudW01MF8kTFQkaW1wbCR1MjAkY29yZS4uZm10Li5EZWJ1ZyR1MjAkZm9yJHUyMCR1MTYkR1QkM2ZtdDE3aGRjNTNlOTE1M2E4MGM4ZWFFzgFaX1pONGNvcmUzb3BzOGZ1bmN0aW9uNkZuT25jZTQwY2FsbF9vbmNlJHU3YiQkdTdiJHZ0YWJsZS5zaGltJHU3ZCQkdTdkJDE3aGIwYzFkNzhjYWUyM2M5ODFFzwE6X1pONGNvcmUzZm10OGJ1aWxkZXJzOURlYnVnTGlzdDZmaW5pc2gxN2hjNmJlNTZkZDZiZDQxYWVkRdABMl9aTjNzdGQ5cGFuaWNraW5nMTFiZWdpbl9wYW5pYzE3aGQ2N2I5NTY5NmM3ZjRmZjVF0QFoX1pONGNvcmUzcHRyNzBkcm9wX2luX3BsYWNlJExUJHN0ZC4ucGFuaWNraW5nLi5iZWdpbl9wYW5pY19oYW5kbGVyLi5QYW5pY1BheWxvYWQkR1QkMTdoNGI1ODNhYTM0NDIzYzUwMkXSATBfWk40Y29yZTlwYW5pY2tpbmc5cGFuaWNfc3RyMTdoZTE2NDQzMDcwMTk4OGU1YUXTAQtfX3JkbF9hbGxvY9QBNl9aTjR3YXNpMTNsaWJfZ2VuZXJhdGVkNUVycm5vNG5hbWUxN2hmZDJlOWQ1YjM5NGFhNzljRdUBOV9aTjR3YXNpMTNsaWJfZ2VuZXJhdGVkNUVycm5vN21lc3NhZ2UxN2hlNjQ0MWI5OTQ1ZjI4YjM0RdYBBnN0cmR1cNcBTF9aTjRjb3JlM3B0cjQyZHJvcF9pbl9wbGFjZSRMVCRhbGxvYy4uc3RyaW5nLi5TdHJpbmckR1QkMTdoYzI0MWFmNWJhYTA2M2RkM0XYAYUCX1pONGNvcmUzcHRyMjI2ZHJvcF9pbl9wbGFjZSRMVCRzdGQuLmVycm9yLi4kTFQkaW1wbCR1MjAkY29yZS4uY29udmVydC4uRnJvbSRMVCRhbGxvYy4uc3RyaW5nLi5TdHJpbmckR1QkJHUyMCRmb3IkdTIwJGFsbG9jLi5ib3hlZC4uQm94JExUJGR5biR1MjAkc3RkLi5lcnJvci4uRXJyb3IkdTJiJGNvcmUuLm1hcmtlci4uU3luYyR1MmIkY29yZS4ubWFya2VyLi5TZW5kJEdUJCRHVCQuLmZyb20uLlN0cmluZ0Vycm9yJEdUJDE3aGU0NzcyOTQ5NTNmOTJhZWNF2QFIX1pONDNfJExUJGJvb2wkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRpc3BsYXkkR1QkM2ZtdDE3aGExY2M5ZWEzZDEyZGRjNDJF2gF4X1pOOTFfJExUJHN0ZC4ucGFuaWNraW5nLi5iZWdpbl9wYW5pYy4uUGFuaWNQYXlsb2FkJExUJEEkR1QkJHUyMCRhcyR1MjAkY29yZS4ucGFuaWMuLkJveE1lVXAkR1QkM2dldDE3aDliMDdiZjIyZThiZTZkYjdF2wE/X1pONWFsbG9jNnN0cmluZzEzRnJvbVV0ZjhFcnJvcjEwaW50b19ieXRlczE3aGExN2RmMTk0OGI3Njc4NGVF3AEIcnVzdF9vb23dATdfWk40d2FzaTEzbGliX2dlbmVyYXRlZDEwcmFuZG9tX2dldDE3aDkxN2JjYWNhOWU5YWY4MGNF3gENYWxpZ25lZF9hbGxvY98BTl9aTjE4bWFyaW5lX3JzX3Nka19tYWluNnJlc3VsdDE4T0JKRUNUU19UT19SRUxFQVNFN19fZ2V0aXQxN2hjYjA2MGU1MmVlNWY5NTU4ReABO19aTjRjb3JlMTBpbnRyaW5zaWNzMTdjb25zdF9ldmFsX3NlbGVjdDE3aGQ1YWZmYTBjOWNlZTZlY2VF4QFcX1pONjNfJExUJGNvcmUuLmNlbGwuLkJvcnJvd011dEVycm9yJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EZWJ1ZyRHVCQzZm10MTdoMTI0MmQ5MTEyNjQ3MTI4MkXiAVJfWk41M18kTFQkY29yZS4uZm10Li5FcnJvciR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uRGVidWckR1QkM2ZtdDE3aGE2MGRhOGViOWMxMzQ5MThF4wE7X1pONGNvcmU2b3B0aW9uMTVPcHRpb24kTFQkVCRHVCQ2dW53cmFwMTdoNDRhNDBjZDU2YTcyNGUxY0XkATtfWk40Y29yZTZvcHRpb24xNU9wdGlvbiRMVCRUJEdUJDZ1bndyYXAxN2hiYzljMDJjZGNkZGNlMDE0ReUBBl9zdGFydOYBDl9fcnVzdF9yZWFsbG9j5wFNX1pOM3N0ZDEwc3lzX2NvbW1vbjliYWNrdHJhY2UyNl9fcnVzdF9lbmRfc2hvcnRfYmFja3RyYWNlMTdoODU1MzJmMzkwZGFlYWM0ZUXoAU1fWk4zc3RkMTBzeXNfY29tbW9uOWJhY2t0cmFjZTI2X19ydXN0X2VuZF9zaG9ydF9iYWNrdHJhY2UxN2g3M2E0M2YzOGI1ZTZlZTA5RekBSV9aTjQ0XyRMVCQkUkYkVCR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uRGlzcGxheSRHVCQzZm10MTdoMDY3YzhlZGUyYTNmYmQ3YkXqARlfX3dhc2lsaWJjX2Vuc3VyZV9lbnZpcm9u6wFHX1pONDJfJExUJCRSRiRUJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EZWJ1ZyRHVCQzZm10MTdoMjAwNWIzMWM4OTYxOTIxOUXsAQxfX3J1c3RfYWxsb2PtAUlfWk40NF8kTFQkJFJGJFQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRpc3BsYXkkR1QkM2ZtdDE3aGEwOGZhZjdmN2M3MTgyNzNF7gFXX1pONTBfJExUJCRSRiRtdXQkdTIwJFckdTIwJGFzJHUyMCRjb3JlLi5mbXQuLldyaXRlJEdUJDEwd3JpdGVfY2hhcjE3aDQyNTAzNDBiM2FjZTQyYzJF7wF6X1pOOTNfJExUJHN0ZC4ucGFuaWNraW5nLi5iZWdpbl9wYW5pY19oYW5kbGVyLi5TdHJQYW5pY1BheWxvYWQkdTIwJGFzJHUyMCRjb3JlLi5wYW5pYy4uQm94TWVVcCRHVCQzZ2V0MTdoN2VkNjU2ZThmZjhjNmIzZkXwAUdfWk40Ml8kTFQkJFJGJFQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2g0MWQzYTA2OTc1OTMzNTc1RfEBOl9aTjRjb3JlM29wczhmdW5jdGlvbjZGbk9uY2U5Y2FsbF9vbmNlMTdoYjdiZDgyYzY0MzM2OTI0Y0XyAUlfWk40NF8kTFQkJFJGJFQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRpc3BsYXkkR1QkM2ZtdDE3aGFjMGZkZjAzZWE5ODFmMmVF8wE7X1pONGNvcmUzZm10OUZvcm1hdHRlcjE1ZGVidWdfbG93ZXJfaGV4MTdoMzVkZWQxZDc5NGVhNWQ3MkX0ATtfWk40Y29yZTNmbXQ5Rm9ybWF0dGVyMTVkZWJ1Z191cHBlcl9oZXgxN2hmOWY5MmFjYTFlNTBkZDExRfUBDl9fcnVzdF9kZWFsbG9j9gFHX1pONDJfJExUJCRSRiRUJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EZWJ1ZyRHVCQzZm10MTdoNGNmYzczNWI4NDgyYmNjYUX3AVVfWk41MF8kTFQkJFJGJG11dCR1MjAkVyR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uV3JpdGUkR1QkOXdyaXRlX3N0cjE3aDRjMmI3MDQ4N2EzZmQxMzVF+AESX193YXNpX2Vudmlyb25fZ2V0+QEYX193YXNpX2Vudmlyb25fc2l6ZXNfZ2V0+gEEZXhpdPsBBnN0cmNwefwBOl9aTjRjb3JlM29wczhmdW5jdGlvbjZGbk9uY2U5Y2FsbF9vbmNlMTdoYzVhODdmYmI0MDFhN2VlZUX9AWJfWk40Y29yZTNmbXQzbnVtM2ltcDUyXyRMVCRpbXBsJHUyMCRjb3JlLi5mbXQuLkRpc3BsYXkkdTIwJGZvciR1MjAkdTMyJEdUJDNmbXQxN2hkNGI2ZmZjOGEwYzdlMzUyRf4BMl9aTjRjb3JlNm9wdGlvbjEzZXhwZWN0X2ZhaWxlZDE3aGI3ZWRkYzVhMTkzN2U2YmJF/wE4X1pONGNvcmUzZm10OGJ1aWxkZXJzOERlYnVnU2V0NWVudHJ5MTdoMDE0ZjlkNmYyZGMyZTQ2Y0WAAlVfWk41MF8kTFQkJFJGJG11dCR1MjAkVyR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uV3JpdGUkR1QkOXdyaXRlX3N0cjE3aDIxODAyY2EzZjM4MTRlZGZFgQJhX1pONGNvcmUzZm10M251bTNpbXA1MV8kTFQkaW1wbCR1MjAkY29yZS4uZm10Li5EaXNwbGF5JHUyMCRmb3IkdTIwJHU4JEdUJDNmbXQxN2g0MDBmMWYyNmZmMzI2Y2I2RYICYl9aTjRjb3JlM2ZtdDNudW0zaW1wNTJfJExUJGltcGwkdTIwJGNvcmUuLmZtdC4uRGlzcGxheSR1MjAkZm9yJHUyMCR1MTYkR1QkM2ZtdDE3aDI1NDk4MTU3MWU3OTU5NThFgwITbWFpbi5jb21tYW5kX2V4cG9ydIQCF2FsbG9jYXRlLmNvbW1hbmRfZXhwb3J0hQIaX19ydXN0X2FsbG9jX2Vycm9yX2hhbmRsZXKGAkdfWk40Ml8kTFQkJFJGJFQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2gzYTIzMzM0ODlkZDVlNjM4RYcCR19aTjQyXyRMVCQkUkYkVCR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uRGVidWckR1QkM2ZtdDE3aDBlOGZhNTFlM2UyYzJkZDBFiAJHX1pONDJfJExUJCRSRiRUJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EZWJ1ZyRHVCQzZm10MTdoZmNmMWQ4NDAxZWIxNzQwZkWJAklfWk40NF8kTFQkJFJGJFQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRpc3BsYXkkR1QkM2ZtdDE3aGI5ODMxNTk5NGYxODYwMmVFigJXX1pONTBfJExUJCRSRiRtdXQkdTIwJFckdTIwJGFzJHUyMCRjb3JlLi5mbXQuLldyaXRlJEdUJDEwd3JpdGVfY2hhcjE3aDZkOTY1Mjc3MmE3ZmE1YjhFiwI7X1pONGNvcmUxMGludHJpbnNpY3MxN2NvbnN0X2V2YWxfc2VsZWN0MTdoNzRlNzg5ZDUzNmFlMDYyYkWMAjpfWk40Y29yZTNvcHM4ZnVuY3Rpb242Rm5PbmNlOWNhbGxfb25jZTE3aGViYTk2ODMwZjRlYzc1YzdFjQJAX1pONWFsbG9jNWFsbG9jMThoYW5kbGVfYWxsb2NfZXJyb3I4cnRfZXJyb3IxN2hmMjhjYTFkNDc1YWU3OTQ4RY4CN19aTjVhbGxvYzVhbGxvYzE4aGFuZGxlX2FsbG9jX2Vycm9yMTdoMWVlMWNjZmRhZmU2YTQwYUWPAghfX3JnX29vbZACOl9aTjRjb3JlM29wczhmdW5jdGlvbjZGbk9uY2U5Y2FsbF9vbmNlMTdoMjQ4ZGJjYjIwNGNjMTRlNUWRAjpfWk40Y29yZTNvcHM4ZnVuY3Rpb242Rm5PbmNlOWNhbGxfb25jZTE3aDM4ZjFhYjY0YjJjZWM1MTRFkgI6X1pONGNvcmUzb3BzOGZ1bmN0aW9uNkZuT25jZTljYWxsX29uY2UxN2hkNWU1NThhODE1YzU0YWU3RZMCRF9aTjRjb3JlNXNsaWNlNWluZGV4MjZzbGljZV9zdGFydF9pbmRleF9sZW5fZmFpbDE3aDIzMWE0NDJlYWUyMDBkNmJFlAJCX1pONGNvcmU1c2xpY2U1aW5kZXgyNHNsaWNlX2VuZF9pbmRleF9sZW5fZmFpbDE3aGM5Mjg4ZWViMTkyN2M4ZDdFlQJAX1pONGNvcmU1c2xpY2U1aW5kZXgyMnNsaWNlX2luZGV4X29yZGVyX2ZhaWwxN2hmMTc0ZTA1NWFlNTMzNzNmRZYCO19aTjRjb3JlMTBpbnRyaW5zaWNzMTdjb25zdF9ldmFsX3NlbGVjdDE3aDA0MzllMDIyMmZhMjQ3MGFFlwI7X1pONGNvcmUxMGludHJpbnNpY3MxN2NvbnN0X2V2YWxfc2VsZWN0MTdoNDExYTg0ZjM2ODM4NWFmYUWYAjtfWk40Y29yZTEwaW50cmluc2ljczE3Y29uc3RfZXZhbF9zZWxlY3QxN2hlMDQxN2M3NjBiNGFhOTA3RZkCQF9aTjRjb3JlNXBhbmljMTBwYW5pY19pbmZvOVBhbmljSW5mbzdwYXlsb2FkMTdoNjk5YTNkYmZlZDIxMGQyNkWaAkdfWk40Ml8kTFQkc3RyJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EaXNwbGF5JEdUJDNmbXQxN2hiYTZmZTJhY2Q1NTE0YzJkRZsCR19aTjQyXyRMVCQkUkYkVCR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uRGVidWckR1QkM2ZtdDE3aDdiMWQzZDMzMGE3YTgxMzFFnAISYWRkLmNvbW1hbmRfZXhwb3J0nQIXc3VidHJhY3QuY29tbWFuZF9leHBvcnSeAhdtdWx0aXBseS5jb21tYW5kX2V4cG9ydJ8CFWRpdmlkZS5jb21tYW5kX2V4cG9ydKACHXNldF9yZXN1bHRfcHRyLmNvbW1hbmRfZXhwb3J0oQIec2V0X3Jlc3VsdF9zaXplLmNvbW1hbmRfZXhwb3J0ogJFX1pOM3N0ZDlwYW5pY2tpbmcxMXBhbmljX2NvdW50MTdpc196ZXJvX3Nsb3dfcGF0aDE3aGZmNzI3ZTc1ODE2MThkNTVFowJ2X1pOM3N0ZDJpbzVpbXBsczc0XyRMVCRpbXBsJHUyMCRzdGQuLmlvLi5Xcml0ZSR1MjAkZm9yJHUyMCRhbGxvYy4udmVjLi5WZWMkTFQkdTgkQyRBJEdUJCRHVCQ1Zmx1c2gxN2hiNDY5NDA3NmQwNWYyYjhiRaQCX19aTjY0XyRMVCRzdGQuLnN5cy4ud2FzaS4uc3RkaW8uLlN0ZGVyciR1MjAkYXMkdTIwJHN0ZC4uaW8uLldyaXRlJEdUJDVmbHVzaDE3aDgzMzY1ZTNiMTQ1ZDA4NzZFpQIQX193YXNpX3Byb2NfZXhpdKYCBV9FeGl0pwIOc2V0X3Jlc3VsdF9wdHKoAg9zZXRfcmVzdWx0X3NpemWpAhVfc3RhcnQuY29tbWFuZF9leHBvcnSqAhh0ZXN0X2xvZ3MuY29tbWFuZF9leHBvcnSrAhpjbGVhcl9zdGF0ZS5jb21tYW5kX2V4cG9ydKwCFHN0YXRlLmNvbW1hbmRfZXhwb3J0rQIdZ2V0X3Jlc3VsdF9wdHIuY29tbWFuZF9leHBvcnSuAh5nZXRfcmVzdWx0X3NpemUuY29tbWFuZF9leHBvcnSvAh5yZWxlYXNlX29iamVjdHMuY29tbWFuZF9leHBvcnSwAk9fWk4zc3RkMTBzeXNfY29tbW9uOWJhY2t0cmFjZTI4X19ydXN0X2JlZ2luX3Nob3J0X2JhY2t0cmFjZTE3aDNkMTVlZmZkMDg2MzYzOTJFsQI0X1pOM3N0ZDNzeXM0d2FzaTE0YWJvcnRfaW50ZXJuYWwxN2hlMjU0NWYwYjAyYmQzNjJkRbICKV9aTjNzdGQ3cHJvY2VzczVhYm9ydDE3aDRjYzRjY2QwZjViZGM4OTFFswINX19yZGxfZGVhbGxvY7QCPF9aTjNzdGQzc3lzNHdhc2k3cHJvY2VzczhFeGl0Q29kZTZhc19pMzIxN2g2OWY4NTg2MjEzYzJlNmQ3RbUCNV9aTjR3YXNpMTNsaWJfZ2VuZXJhdGVkNUVycm5vM3JhdzE3aDg4MzgzNDkzOTY4NGE4YTlFtgIGbWFsbG9jtwIEZnJlZbgCEV9fd2FzbV9jYWxsX2R0b3JzuQJAX1pONGNvcmU1cGFuaWMxMHBhbmljX2luZm85UGFuaWNJbmZvN21lc3NhZ2UxN2hhMDI2YTM3Zjc1MTM1NGFjRboCQV9aTjRjb3JlNXBhbmljMTBwYW5pY19pbmZvOVBhbmljSW5mbzhsb2NhdGlvbjE3aDU5NzNiODU1YTE4N2E5ZDZFuwJEX1pONGNvcmU1cGFuaWMxMHBhbmljX2luZm85UGFuaWNJbmZvMTBjYW5fdW53aW5kMTdoMjFiZGQ3NTAyZDZlMzVlZkW8Ag5nZXRfcmVzdWx0X3B0cr0CD2dldF9yZXN1bHRfc2l6Zb4CD3JlbGVhc2Vfb2JqZWN0c78CEV9fd2FzbV9jYWxsX2N0b3JzwAIEbWFpbsECTF9aTjQzXyRMVCRsb2cuLk5vcExvZ2dlciR1MjAkYXMkdTIwJGxvZy4uTG9nJEdUJDdlbmFibGVkMTdoNzAwNDJmODk4NmE2NWU5N0XCAkVfWk4zNl8kTFQkVCR1MjAkYXMkdTIwJGNvcmUuLmFueS4uQW55JEdUJDd0eXBlX2lkMTdoZDg0ZjVlZGUwYzY3ZTAxZUXDAkVfWk4zNl8kTFQkVCR1MjAkYXMkdTIwJGNvcmUuLmFueS4uQW55JEdUJDd0eXBlX2lkMTdoMzAyYzRiYTdiZTViNzY4NUXEAkVfWk4zNl8kTFQkVCR1MjAkYXMkdTIwJGNvcmUuLmFueS4uQW55JEdUJDd0eXBlX2lkMTdoM2RmZjNmOTA0ZTRlMmJiMkXFAkVfWk4zNl8kTFQkVCR1MjAkYXMkdTIwJGNvcmUuLmFueS4uQW55JEdUJDd0eXBlX2lkMTdoNjc4M2NkNzgyNGFlZDY4NEXGAoMBX1pOM3N0ZDJpbzVpbXBsczc0XyRMVCRpbXBsJHUyMCRzdGQuLmlvLi5Xcml0ZSR1MjAkZm9yJHUyMCRhbGxvYy4udmVjLi5WZWMkTFQkdTgkQyRBJEdUJCRHVCQxN2lzX3dyaXRlX3ZlY3RvcmVkMTdoNzIzMmUyNTQwZWU5MjVjOEXHAmxfWk42NF8kTFQkc3RkLi5zeXMuLndhc2kuLnN0ZGlvLi5TdGRlcnIkdTIwJGFzJHUyMCRzdGQuLmlvLi5Xcml0ZSRHVCQxN2lzX3dyaXRlX3ZlY3RvcmVkMTdoMDY5YjFmODgzMGU4MzZkZUXIAhJfX3J1c3Rfc3RhcnRfcGFuaWPJAiVfX3dhc2lsaWJjX2luaXRpYWxpemVfZW52aXJvbl9lYWdlcmx5ygIFYWJvcnTLAkVfWk4zNl8kTFQkVCR1MjAkYXMkdTIwJGNvcmUuLmFueS4uQW55JEdUJDd0eXBlX2lkMTdoYTc4MjMzN2Y2YzZlYWNmOUXMAkpfWk40Y29yZTNwdHI0MGRyb3BfaW5fcGxhY2UkTFQkbG9nLi5TZXRMb2dnZXJFcnJvciRHVCQxN2hhOWVlYTFjZGFhNmZkNGVmRc0CkAFfWk40Y29yZTNwdHI4NWRyb3BfaW5fcGxhY2UkTFQkc3RkLi5ydC4ubGFuZ19zdGFydCRMVCQkTFAkJFJQJCRHVCQuLiR1N2IkJHU3YiRjbG9zdXJlJHU3ZCQkdTdkJCRHVCQxN2gxNWUxZWJkMGFkYzg5ZWIyRS5sbHZtLjcxMzkyNDE0MTE2NzQ4MTI3NTPOAlhfWk40Y29yZTNwdHI1NGRyb3BfaW5fcGxhY2UkTFQkJFJGJG11dCR1MjAkYWxsb2MuLnN0cmluZy4uU3RyaW5nJEdUJDE3aDI2OWU0NDFiNTA0NmVjMjlFzwJHX1pONGNvcmUzcHRyMzdkcm9wX2luX3BsYWNlJExUJGNvcmUuLmZtdC4uRXJyb3IkR1QkMTdoZGM2NzQxY2U1YjMyZGVmM0XQAmJfWk42N18kTFQkbWFyaW5lX3JzX3Nka19tYWluLi5sb2dnZXIuLldhc21Mb2dnZXIkdTIwJGFzJHUyMCRsb2cuLkxvZyRHVCQ1Zmx1c2gxN2hjNTU5OWU5YWZhMDQ3YTg3RdECQl9aTjRjb3JlM3B0cjMyZHJvcF9pbl9wbGFjZSRMVCQkUkYkJFJGJHN0ciRHVCQxN2g5YzYyM2JkNTFiNzk1YTYxRdICSF9aTjQzXyRMVCRsb2cuLk5vcExvZ2dlciR1MjAkYXMkdTIwJGxvZy4uTG9nJEdUJDNsb2cxN2g4NzI1YjgwOTY1NWJjMjEyRdMCSl9aTjQzXyRMVCRsb2cuLk5vcExvZ2dlciR1MjAkYXMkdTIwJGxvZy4uTG9nJEdUJDVmbHVzaDE3aDQ4MmNhZTIzZWMzYWZiNTRF1AJvX1pONGNvcmUzcHRyNzdkcm9wX2luX3BsYWNlJExUJHN0ZC4ucGFuaWNraW5nLi5iZWdpbl9wYW5pYy4uUGFuaWNQYXlsb2FkJExUJCRSRiRzdHIkR1QkJEdUJDE3aGIyMTFiMWMzNmZlYzM2ZThF1QI+X1pONGNvcmUzcHRyMjhkcm9wX2luX3BsYWNlJExUJCRSRiRzdHIkR1QkMTdoNjJiZTY3ZWM0ODNiMGVhZUXWAocBX1pONGNvcmUzcHRyMTAwZHJvcF9pbl9wbGFjZSRMVCQkUkYkbXV0JHUyMCRzdGQuLmlvLi5Xcml0ZS4ud3JpdGVfZm10Li5BZGFwdGVyJExUJGFsbG9jLi52ZWMuLlZlYyRMVCR1OCRHVCQkR1QkJEdUJDE3aDU4Y2JlYzFiOGUyNGE4MDZF1wI5X1pONGNvcmUzcHRyMjNkcm9wX2luX3BsYWNlJExUJHU4JEdUJDE3aDExMjIyOTU3MGNhOWEwMTZF2AIFZHVtbXnZAj1fWk40Y29yZTNwdHIyN2Ryb3BfaW5fcGxhY2UkTFQkJFJGJHU4JEdUJDE3aGE0YmY1OGZjMWU2YmI5YzhF2gKJAV9aTjRjb3JlM3B0cjEwMmRyb3BfaW5fcGxhY2UkTFQkJFJGJGNvcmUuLml0ZXIuLmFkYXB0ZXJzLi5jb3BpZWQuLkNvcGllZCRMVCRjb3JlLi5zbGljZS4uaXRlci4uSXRlciRMVCR1OCRHVCQkR1QkJEdUJDE3aGRkZDAxNjVkMjVmNWVjNTRF2wJrX1pONGNvcmUzcHRyNDdkcm9wX2luX3BsYWNlJExUJGNvcmUuLmNlbGwuLkJvcnJvd011dEVycm9yJEdUJDE3aDdjNWJmNDRiNmE2ZDBiOTZFLmxsdm0uMTU3Nzc2NDg0NDA1MzUyNzMyMTQA8ICAgAAJcHJvZHVjZXJzAghsYW5ndWFnZQEEUnVzdAAMcHJvY2Vzc2VkLWJ5AwVjbGFuZwYxNC4wLjAFcnVzdGMlMS42NC4wLW5pZ2h0bHkgKDgzMDg4MDY0MCAyMDIyLTA2LTI4KQZ3YWxydXMGMC4xOS4wAKqBgIAAHV9fbV9nZW5lcmF0ZWRfc2VjdGlvbl9fZGl2aWRleyJhc3RfdHlwZSI6IkZ1bmN0aW9uIiwic2lnbmF0dXJlIjp7Im5hbWUiOiJkaXZpZGUiLCJhcmd1bWVudHMiOlt7Im5hbWUiOiJudW0iLCJ0eSI6eyJGNjQiOiJCeVZhbHVlIn19XSwib3V0cHV0X3R5cGVzIjpbeyJGNjQiOiJCeVZhbHVlIn1dfX0AroGAgAAfX19tX2dlbmVyYXRlZF9zZWN0aW9uX19tdWx0aXBseXsiYXN0X3R5cGUiOiJGdW5jdGlvbiIsInNpZ25hdHVyZSI6eyJuYW1lIjoibXVsdGlwbHkiLCJhcmd1bWVudHMiOlt7Im5hbWUiOiJudW0iLCJ0eSI6eyJGNjQiOiJCeVZhbHVlIn19XSwib3V0cHV0X3R5cGVzIjpbeyJGNjQiOiJCeVZhbHVlIn1dfX0Ag4GAgAAcX19tX2dlbmVyYXRlZF9zZWN0aW9uX19zdGF0ZXsiYXN0X3R5cGUiOiJGdW5jdGlvbiIsInNpZ25hdHVyZSI6eyJuYW1lIjoic3RhdGUiLCJhcmd1bWVudHMiOltdLCJvdXRwdXRfdHlwZXMiOlt7IkY2NCI6IkJ5VmFsdWUifV19fQD+gICAACJfX21fZ2VuZXJhdGVkX3NlY3Rpb25fX2NsZWFyX3N0YXRleyJhc3RfdHlwZSI6IkZ1bmN0aW9uIiwic2lnbmF0dXJlIjp7Im5hbWUiOiJjbGVhcl9zdGF0ZSIsImFyZ3VtZW50cyI6W10sIm91dHB1dF90eXBlcyI6W119fQCugYCAAB9fX21fZ2VuZXJhdGVkX3NlY3Rpb25fX3N1YnRyYWN0eyJhc3RfdHlwZSI6IkZ1bmN0aW9uIiwic2lnbmF0dXJlIjp7Im5hbWUiOiJzdWJ0cmFjdCIsImFyZ3VtZW50cyI6W3sibmFtZSI6Im51bSIsInR5Ijp7IkY2NCI6IkJ5VmFsdWUifX1dLCJvdXRwdXRfdHlwZXMiOlt7IkY2NCI6IkJ5VmFsdWUifV19fQCkgYCAABpfX21fZ2VuZXJhdGVkX3NlY3Rpb25fX2FkZHsiYXN0X3R5cGUiOiJGdW5jdGlvbiIsInNpZ25hdHVyZSI6eyJuYW1lIjoiYWRkIiwiYXJndW1lbnRzIjpbeyJuYW1lIjoibnVtIiwidHkiOnsiRjY0IjoiQnlWYWx1ZSJ9fV0sIm91dHB1dF90eXBlcyI6W3siRjY0IjoiQnlWYWx1ZSJ9XX19APqAgIAAIF9fbV9nZW5lcmF0ZWRfc2VjdGlvbl9fdGVzdF9sb2dzeyJhc3RfdHlwZSI6IkZ1bmN0aW9uIiwic2lnbmF0dXJlIjp7Im5hbWUiOiJ0ZXN0X2xvZ3MiLCJhcmd1bWVudHMiOltdLCJvdXRwdXRfdHlwZXMiOltdfX0A/4KAgAAPaW50ZXJmYWNlLXR5cGVzBQYwLjI0LjEAFAABBHNpemUMAQwAAAAAAAEMAAABDAABC3Jlc3VsdF9zaXplDAAAAQpyZXN1bHRfcHRyDAAAAQNudW0JAQkAAQNudW0JAQkAAQNudW0JAQkAAQNudW0JAQkAAAEJAAABCQAAAAAAAAABA251bQkBCQABA251bQkBCQABA251bQkBCQABA251bQkBCQAAAAAAAAIHBgIAAAEGCAIAAAEHCgEBCAwBAQkOAgAAAQoQAgAAAQsSAQEMAw0IYWxsb2NhdGUAD3JlbGVhc2Vfb2JqZWN0cwEPZ2V0X3Jlc3VsdF9zaXplAg5nZXRfcmVzdWx0X3B0cgMPc2V0X3Jlc3VsdF9zaXplBA5zZXRfcmVzdWx0X3B0cgUGZGl2aWRlBwhtdWx0aXBseQkFc3RhdGULC2NsZWFyX3N0YXRlDQhzdWJ0cmFjdA8DYWRkEQl0ZXN0X2xvZ3MTBAcHBgkICwoNDA8OERATEgCcgICAABVfX2ZsdWVuY2Vfc2RrX3ZlcnNpb24wLjYuMTU="; \ No newline at end of file +/** + * 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. + */ + +export const wasm = + "AGFzbQEAAAABmIGAgAAWYAAAYAABf2AAAXxgAX8AYAF/AX9gAX8BfmACf38AYAJ/fwF/YAN/f38AYAN/f38Bf2ADf39/AX5gBH9/f38AYAR/f39/AX9gBX9/f39/AGAFf39/f38Bf2AGf39/f39/AX9gB39/f39/f38AYAd/f39/f39/AX9gCX9/f39/f35+fgBgBH98f38Bf2ADfn9/AX9gAXwBfALRgYCAAAYEaG9zdA9sb2dfdXRmOF9zdHJpbmcACxZ3YXNpX3NuYXBzaG90X3ByZXZpZXcxCGZkX3dyaXRlAAwWd2FzaV9zbmFwc2hvdF9wcmV2aWV3MQpyYW5kb21fZ2V0AAcWd2FzaV9zbmFwc2hvdF9wcmV2aWV3MQtlbnZpcm9uX2dldAAHFndhc2lfc25hcHNob3RfcHJldmlldzERZW52aXJvbl9zaXplc19nZXQABxZ3YXNpX3NuYXBzaG90X3ByZXZpZXcxCXByb2NfZXhpdAADA9iCgIAA1gILBA0HCwgDBgkJBwsHDQcHCRMPCQ0DCwgJEwgIBw0JBwAEBgsKBwcSBwgHCw4QBhAJEQ4GBAcHBwcHBwsUBgQHCQcDBggAAwcHCQMMBgcHCAcHBwgICAYRDgEDDQsVBggIBgYVFRUEAwQDBAYGCwsLBwcHBwcHAAkHBwgEBw0LBAcHBwcDCAYGBggHBwYICAcHBwcHBwcHBwsHAgMLAAcGCQkJCwkLCQQDAwwJDAcDBwgGBgcDAAYABwcHBwcHAQQEAwgNCAsGBwYECAMIBwYGBAMDBwYGBggHBAMHBwcEAAwDAwcABwcHBwYHCwcEBAgHCQcHAwcHBwgJCQcHBwcGBwcHBwcGBgYGBgYGBggICAYGBgYJBxUVFRUDAwEGBgMDAwMAAAACAQEAAwAACAQEBAMABAQEAQEAAAcHBQUFBQQEBAAABQMDAwMDAwYDAwMDAwADAwMEhYCAgAABcAF0dAWDgICAAAEAEQaZgICAAAN/AUGAgMAAC38AQaCBwQALfwBBmIHBAAsH7oGAgAASBm1lbW9yeQIAC19faGVhcF9iYXNlAwEKX19kYXRhX2VuZAMCBl9zdGFydACpAgRtYWluAIMCCXRlc3RfbG9ncwCqAgNhZGQAnAIIc3VidHJhY3QAnQIIbXVsdGlwbHkAngIGZGl2aWRlAJ8CC2Ns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AAAgA0EGaiABQQZqLQAAOgAAIANBB2ogAUEHai0AADoAACADQQhqIQMgAUEIaiEBIARBeGoiBA0ACwsgAAuvCQEHfwJAAkAgAUH/CUsNACABQQV2IQICQAJAAkACQCAAKAIAIgNFDQAgACADQQJ0aiEEIAAgAyACakECdGohBSADQX9qIgNBJ0shBgNAIAYNBCACIANqIgdBKE8NAiAFIAQoAgA2AgAgBUF8aiEFIARBfGohBCADQX9qIgNBf0cNAAsLIAFBIEkNBCAAQQA2AgQgAUHAAE8NAQwECyAHQShB3PHAABCPAQALIABBCGpBADYCACACQQEgAkEBSxsiA0ECRg0CIABBDGpBADYCACADQQNGDQIgAEEQakEANgIAIANBBEYNAiAAQRRqQQA2AgAgA0EFRg0CIABBGGpBADYCACADQQZGDQIgAEEcakEANgIAIANBB0YNAiAAQSBqQQA2AgAgA0EIRg0CIABBJGpBADYCACADQQlGDQIgAEEoakEANgIAIANBCkYNAiAAQSxqQQA2AgAgA0ELRg0CIABBMGpBADYCACADQQxGDQIgAEE0akEANgIAIANBDUYNAiAAQThqQQA2AgAgA0EORg0CIABBPGpBADYCACADQQ9GDQIgAEHAAGpBADYCACADQRBGDQIgAEHEAGpBADYCACADQRFGDQIgAEHIAGpBADYCACADQRJGDQIgAEHMAGpBADYCACADQRNGDQIgAEHQAGpBADYCACADQRRGDQIgAEHUAGpBADYCACADQRVGDQIgAEHYAGpBADYCACADQRZGDQIgAEHcAGpBADYCACADQRdGDQIgAEHgAGpBADYCACADQRhGDQIgAEHkAGpBADYCACADQRlGDQIgAEHoAGpBADYCACADQRpGDQIgAEHsAGpBADYCACADQRtGDQIgAEHwAGpBADYCACADQRxGDQIgAEH0AGpBADYCACADQR1GDQIgAEH4AGpBADYCACADQR5GDQIgAEH8AGpBADYCACADQR9GDQIgAEGAAWpBADYCACADQSBGDQIgAEGEAWpBADYCACADQSFGDQIgAEGIAWpBADYCACADQSJGDQIgAEGMAWpBADYCACADQSNGDQIgAEGQAWpBADYCACADQSRGDQIgAEGUAWpBADYCACADQSVGDQIgAEGYAWpBADYCACADQSZGDQIgAEGc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NgIAIAFBIGpBFGpBAzYCACABQgM3AiQgAUH8g8AANgIgIAFBBDYCPCABIAFBOGo2AjAgASABQRhqNgJIIAEgAUEIajYCQCABIAFBEGo2AjggAUEgakEDQZSEwABBACABEGEgASsDGCECCyABQdAAaiQAIAILvwEBA38jAEEgayICJAACQCABQQFqIgMgAUkNACAAQQRqKAIAIgRBAXQiASADIAEgA0sbIgFBCCABQQhLGyEBAkACQCAEDQBBACEDDAELIAIgBDYCFCACIAAoAgA2AhBBASEDCyACIAM2AhggAiABQQEgAkEQahB1AkAgAigCAEUNACACQQhqKAIAIgBFDQEgAigCBCAAEI4CAAsgAigCBCEDIABBBGogATYCACAAIAM2AgAgAkEgaiQADwsQuwEAC78BAQJ/IwBBIGsiAyQAAkAgASACaiICIAFJDQAgAEEEaigCACIEQQF0IgEgAiABIAJLGyIBQQggAUEISxshAQJAAkAgBA0AQQAhAgwBCyADIAQ2AhQgAyAAKAIANgIQQQEhAgsgAyACNgIYIAMgAUEBIANBEGoQdQJAIAMoAgBFDQAgA0EIaigCACIARQ0BIAMoAgQgABCOAgALIAMoAgQhAiAAQQRqIAE2AgAgACACNgIAIANBIGokAA8LELsBAAu/AQECfyMAQSBrIgMkAAJAIAEgAmoiAiABSQ0AIABBBGooAgAiBEEBdCIBIAIgASACSxsiAUEIIAFBCEsbIQECQAJAIAQNAEEAIQIMAQsgAyAENgIUIAMgACgCADYCEEEBIQILIAMgAjYCGCADIAFBASADQRBqEHMCQCADKAIARQ0AIANBCGooAgAiAEUNASADKAIEIAAQjgIACyADKAIEIQIgAEEEaiABNgIAIAAgAjYCACADQSBqJAAPCxC7AQALvwEBA38jAEEgayICJAACQCABQQFqIgMgAUkNACAAQQRqKAIAIgRBAXQiASADIAEgA0sbIgFBCCABQQhLGyEBAkACQCAEDQBBACEDDAELIAIgBDYCFCACIAAoAgA2AhBBASEDCyACIAM2AhggAiABQQEgAkEQahBzAkAgAigCAEUNACACQQhqKAIAIgBFDQEgAigCBCAAEI4CAAsgAigCBCEDIABBBGogATYCACAAIAM2AgAgAkEgaiQADwsQuwEAC78BAQN/IwBBIGsiAiQAAkAgAUEBaiIDIAFJDQAgAEEEaigCACIEQQF0IgEgAyABIANLGyIBQQggAUEISxshAQJAAkAgBA0AQQAhAwwBCyACIAQ2AhQgAiAAKAIANgIQQQEhAwsgAiADNgIYIAIgAUEBIAJBEGoQdAJAIAIoAgBFDQAgAkEIaigCACIARQ0BIAIoAgQgABCOAgALIAIoAgQhAyAAQQRqIAE2AgAgACADNgIAIAJBIGokAA8LELsBAAvTAQIBfwF8IwBB0ABrIgEkAEEAKwPw+0AhAiABIAA5AwhBACACIACgIgA5A/D7QCABIAI5AxggASAAOQMQAkBBACgCgPxAQQNJDQAgAUE4akEUakEENgIAIAFBxABqQQQ2AgAgAUEgakEUakEDNgIAIAFCAzcCJCABQdSCwAA2AiAgAUEENgI8IAEgAUE4ajYCMCABIAFBEGo2AkggASABQQhqNgJAIAEgAUEYajYCOCABQSBqQQNB7ILAAEEAIAEQYSABKwMQIQALIAFB0ABqJAAgAAvTAQIBfwF8IwBB0ABrIgEkAEEAKwPw+0AhAiABIAA5AwhBACACIAChIgA5A/D7QCABIAI5AxggASAAOQMQAkBBACgCgPxAQQNJDQAgAUE4akEUakEENgIAIAFBxABqQQQ2AgAgAUEgakEUakEDNgIAIAFCAzcCJCABQYyDwAA2AiAgAUEENgI8IAEgAUE4ajYCMCABIAFBEGo2AkggASABQQhqNgJAIAEgAUEYajYCOCABQSBqQQNBpIPAAEEAIAEQYSABKwMQIQALIAFB0ABqJAAgAAvTAQIBfwF8IwBB0ABrIgEkAEEAKwPw+0AhAiABIAA5AwhBACACIACiIgA5A/D7QCABIAI5AxggASAAOQMQAkBBACgCgPxAQQNJDQAgAUE4akEUakEENgIAIAFBxABqQQQ2AgAgAUEgakEUakEDNgIAIAFCAzcCJCABQcSDwAA2AiAgAUEENgI8IAEgAUE4ajYCMCABIAFBEGo2AkggASABQQhqNgJAIAEgAUEYajYCOCABQSBqQQNB3IPAAEEAIAEQYSABKwMQIQALIAFB0ABqJAAgAAuxAQECfyAAIQECQAJAIABBA3FFDQAgACEBIAAtAABFDQEgAEEBaiIBQQNxRQ0AIAEtAABFDQEgAEECaiIBQQNxRQ0AIAEtAABFDQEgAEEDaiIBQQNxRQ0AIAEtAABFDQEgAEEEaiEBCyABQXxqIQEDQCABQQRqIgEoAgAiAkF/cyACQf/9+3dqcUGAgYKEeHFFDQALIAJB/wFxRQ0AA0AgAUEBaiIBLQAADQALCyABIABrC9wBAQF/IwBBwABrIgEkAAJAAkBBACgC9PxADQBBAEF/NgL0/EBBACgC+PxADQFBACAANgL4/EBBAEEANgL0/EAgAUHAAGokAA8LQfiLwABBECABQShqQcSMwABBoJnAABCDAQALIAFBCGpBFGpBATYCACABQShqQRRqQQA2AgAgAUICNwIMIAFBiI/AADYCCCABQSA2AiQgAUH4i8AANgI4IAFCATcCLCABQdiZwAA2AiggASABQSBqNgIYIAEgAUEoajYCICABIAFBKGogAUEIahBaIAEQrgEQsQIAC9ABAQF/QQAhAQJAAkAgAEEgSQ0AQQEhASAAQf8ASQ0AIABBgIAESQ0BAkAgAEGAgAhJDQAgAEH+//8AcUGe8ApHIABB4P//AHFB4M0KRyAAQceRdWpBBktxcSAAQdDidGpBcklxIABBgJB0akHhZ0lxIABBgIB0akGedElxIABBgP5HakHLpFRJcSAAQfCDOElxDwsgAEGX68AAQSpB6+vAAEHAAUGr7cAAQbYDEDchAQsgAQ8LIABB+OXAAEEoQcjmwABBoAJB6OjAAEGvAhA3C6wBAQN/AkAgACgCECIBRQ0AIAEgAUEBaq1CDH6nQQdqQXhxIgJqQQlqIgFFDQAgAEEUaigCACACayABQQgQ9QELAkAgAEEoaigCACICRQ0AIAAoAiAhASACQQR0IQIDQAJAIAFBBGooAgAiA0UNACABKAIAIANBARD1AQsgAUEQaiEBIAJBcGoiAg0ACwsCQCAAQSRqKAIAIgFFDQAgACgCICABQQR0QQQQ9QELC80BAQN/IwBBEGsiASQAQQEhAgJAIAAtAAQNACAAKAIAIQMCQCAALQAFDQAgAygCGEHc3MAAQQcgA0EcaigCACgCDBEJACECDAELAkAgAy0AAEEEcQ0AIAMoAhhB1tzAAEEGIANBHGooAgAoAgwRCQAhAgwBC0EBIQIgAUEBOgAPIAFBCGogAUEPajYCACABIAMpAhg3AwAgAUHS3MAAQQMQHg0AIAMoAhhB1dzAAEEBIAMoAhwoAgwRCQAhAgsgACACOgAEIAFBEGokACACC7YBAQN/IwBBMGsiAiQAIAFBBGohAwJAIAEoAgQNACABKAIAIQEgAkEIakEIaiIEQQA2AgAgAkIBNwMIIAIgAkEIajYCFCACQRhqQRBqIAFBEGopAgA3AwAgAkEYakEIaiABQQhqKQIANwMAIAIgASkCADcDGCACQRRqQeCLwAAgAkEYahAkGiADQQhqIAQoAgA2AgAgAyACKQMINwIACyAAQYSdwAA2AgQgACADNgIAIAJBMGokAAu3AQEBfyMAQeAAayICJAAgAiABNgIEIAIgADYCACACIAIQyAI2AgwgAkEYakEUakEBNgIAIAJBOGpBFGpBATYCACACQgI3AhwgAkGIj8AANgIYIAJBIDYCNCACQgE3AjwgAkGgn8AANgI4IAJBIjYCVCACIAJBMGo2AiggAiACQThqNgIwIAIgAkHQAGo2AkggAiACQQxqNgJQIAJBEGogAkHYAGogAkEYahBaIAJBEGoQrgEQsQIAC6sBAQJ/AkACQAJAAkACQAJAAkAgAkUNAEEBIQQgAUEASA0BIAMoAghFDQMgAygCBCIFDQIgAQ0EIAIhAwwFCyAAIAE2AgRBASEEC0EAIQEMBAsgAygCACAFIAIgARDmASEDDAILIAENACACIQMMAQsgASACEOwBIQMLAkAgA0UNACAAIAM2AgRBACEEDAELIAAgATYCBCACIQELIAAgBDYCACAAQQhqIAE2AgALqwEBAn8CQAJAAkACQAJAAkACQCACRQ0AQQEhBCABQQBIDQEgAygCCEUNAyADKAIEIgUNAiABDQQgAiEDDAULIAAgATYCBEEBIQQLQQAhAQwECyADKAIAIAUgAiABEOYBIQMMAgsgAQ0AIAIhAwwBCyABIAIQ7AEhAwsCQCADRQ0AIAAgAzYCBEEAIQQMAQsgACABNgIEIAIhAQsgACAENgIAIABBCGogATYCAAupAQECfwJAAkACQAJAAkACQAJAAkACQCACRQ0AQQEhBCABQQBIDQEgAygCCEUNAyADKAIEIgUNAiABDQQMBgsgACABNgIEQQEhBAtBACEBDAYLIAMoAgAgBSACIAEQ5gEiA0UNAgwECyABRQ0CCyABIAIQ7AEiAw0CCyAAIAE2AgQgAiEBDAILIAIhAwsgACADNgIEQQAhBAsgACAENgIAIABBCGogATYCAAuaAQEDfyMAQYABayICJAAgAC8BACEDQQAhAANAIAIgAGpB/wBqQTBB1wAgA0EPcSIEQQpJGyAEajoAACAAQX9qIQAgA0H//wNxIgRBBHYhAyAEQQ9LDQALAkAgAEGAAWoiA0GBAUkNACADQYABIAAQkwIACyABQQFB7NzAAEECIAIgAGpBgAFqQQAgAGsQGCEAIAJBgAFqJAAgAAuZAQEDfyMAQYABayICJAAgAC0AACEDQQAhAANAIAIgAGpB/wBqQTBB1wAgA0EPcSIEQQpJGyAEajoAACAAQX9qIQAgA0H/AXEiBEEEdiEDIARBD0sNAAsCQCAAQYABaiIDQYEBSQ0AIANBgAEgABCTAgALIAFBAUHs3MAAQQIgAiAAakGAAWpBACAAaxAYIQAgAkGAAWokACAAC5gBAQN/IwBBgAFrIgIkACAALQAAIQNBACEAA0AgAiAAakH/AGpBMEE3IANBD3EiBEEKSRsgBGo6AAAgAEF/aiEAIANB/wFxIgRBBHYhAyAEQQ9LDQALAkAgAEGAAWoiA0GBAUkNACADQYABIAAQkwIACyABQQFB7NzAAEECIAIgAGpBgAFqQQAgAGsQGCEAIAJBgAFqJAAgAAuZAQEDfyMAQYABayICJAAgAC8BACEDQQAhAANAIAIgAGpB/wBqQTBBNyADQQ9xIgRBCkkbIARqOgAAIABBf2ohACADQf//A3EiBEEEdiEDIARBD0sNAAsCQCAAQYABaiIDQYEBSQ0AIANBgAEgABCTAgALIAFBAUHs3MAAQQIgAiAAakGAAWpBACAAaxAYIQAgAkGAAWokACAAC5cBAQN/IwBBgAFrIgIkACAAKAIAIQBBACEDA0AgAiADakH/AGpBMEHXACAAQQ9xIgRBCkkbIARqOgAAIANBf2ohAyAAQQ9LIQQgAEEEdiEAIAQNAAsCQCADQYABaiIAQYEBSQ0AIABBgAEgABCTAgALIAFBAUHs3MAAQQIgAiADakGAAWpBACADaxAYIQAgAkGAAWokACAAC5YBAQN/IwBBgAFrIgIkACAAKAIAIQBBACEDA0AgAiADakH/AGpBMEE3IABBD3EiBEEKSRsgBGo6AAAgA0F/aiEDIABBD0shBCAAQQR2IQAgBA0ACwJAIANBgAFqIgBBgQFJDQAgAEGAASAAEJMCAAsgAUEBQezcwABBAiACIANqQYABakEAIANrEBghACACQYABaiQAIAALoAEBBH8jAEEQayIAJAACQAJAAkAgAEEMaiAAQQhqEPkBDQACQCAAKAIMIgENAEEAQfiAwQA2AvSAQQwDCwJAAkAgAUEBaiICIAFJDQAgACgCCBC2AiIDRQ0AIAJBBBCHASIBDQEgAxC3AgtBxgAQpgIACyABIAMQ+AFFDQEgAxC3AiABELcCC0HHABCmAgALQQAgATYC9IBBCyAAQRBqJAALjwEBA38CQCACDQBBAA8LQQAhAwJAIAAtAAAiBEUNACAAQQFqIQAgAkF/aiECA0ACQCABLQAAIgUNACAEIQMMAgsCQCACDQAgBCEDDAILAkAgBEH/AXEgBUYNACAEIQMMAgsgAkF/aiECIAFBAWohASAALQAAIQQgAEEBaiEAIAQNAAsLIANB/wFxIAEtAABrC4sBAQV/AkACQAJAIABBKGooAgAiAkUNACABQQhqKAIAIQMgACgCICEEIAJBBHQhAiABQQRqKAIAIQUDQAJAIARBCGooAgAiBiADSw0AIAQoAgAgBSAGELEBRQ0DCyAEQRBqIQQgAkFwaiICDQALCyAAQSxqIQQMAQsgBEEMaiEECyABKAIAIAQoAgBNC5ABAQF/IwBBMGsiAiQAIAJBFGpBIjYCACACQQxqQSI2AgAgAkHhADYCBCACIAA2AgAgAiAAQQxqNgIQIAIgAEEIajYCCCABQRxqKAIAIQAgASgCGCEBIAJBGGpBFGpBAzYCACACQgM3AhwgAkGs2sAANgIYIAIgAjYCKCABIAAgAkEYahAkIQAgAkEwaiQAIAALoAEBAn8jAEEQayIDJAAgAEEUaigCACEEAkACQAJAAkAgAEEEaigCAA4CAAEDCyAEDQJB+IvAACEAQQAhBAwBCyAEDQEgACgCACIAKAIEIQQgACgCACEACyADIAQ2AgQgAyAANgIAIANBuJ3AACABELkCIAIgARC7AhAaAAsgA0EANgIEIAMgADYCACADQaSdwAAgARC5AiACIAEQuwIQGgALhwEBBH8Q6gECQCAAQT0QQCAAayIBDQBBAA8LQQAhAgJAIAAgAWotAAANAEEAKAL0gEEiA0UNACADKAIAIgRFDQAgA0EEaiEDAkADQAJAIAAgBCABEH0NACAEIAFqIgQtAABBPUYNAgsgAygCACEEIANBBGohAyAEDQAMAgsLIARBAWohAgsgAguXAQEBfyMAQTBrIgIkACACQRhqIAFBsbbAAEEFEMsBIAJBGGpB3KTAAEEEIABBuLbAABA4IQEgAkEQaiAAENQBIAIgAikDEDcDICABQeCkwABBBCACQSBqQeSkwAAQOCEBIAJBCGogABDVASACIAIpAwg3AyggAUH0pMAAQQcgAkEoakHkpMAAEDgQhQEhACACQTBqJAAgAAuBAQEBfyMAQcAAayIFJAAgBSABNgIMIAUgADYCCCAFIAM2AhQgBSACNgIQIAVBLGpBAjYCACAFQTxqQecANgIAIAVCAjcCHCAFQZzcwAA2AhggBUHhADYCNCAFIAVBMGo2AiggBSAFQRBqNgI4IAUgBUEIajYCMCAFQRhqIAQQvAEAC3sBAX8jAEEgayIEJAAgBCADNgIMIAQgAjYCCEEBIQIgBEEQakECIARBCGpBARCrAQJAAkAgBC8BEA0AIAAgBCgCFDYCBEEAIQIMAQsgBCAELwESOwEeIAAgBEEeahC1Aq1C//8Dg0IghjcCBAsgACACNgIAIARBIGokAAuFAQECfyAALQAEIQECQCAALQAFRQ0AIAFB/wFxIQJBASEBAkAgAg0AAkAgACgCACIBLQAAQQRxDQAgASgCGEHj3MAAQQIgAUEcaigCACgCDBEJACEBDAELIAEoAhhB1dzAAEEBIAFBHGooAgAoAgwRCQAhAQsgACABOgAECyABQf8BcUEARwtzAQR/IwBBIGsiAiQAQQEhAwJAIAAgARBFDQAgAUEcaigCACEEIAEoAhghBSACQRxqQQA2AgAgAkG4wsAANgIYIAJCATcCDCACQajZwAA2AgggBSAEIAJBCGoQJA0AIABBBGogARBFIQMLIAJBIGokACADC2MCAX8BfgJAAkAgAA0AQQAhAgwBCyAArSABrX4iA6chAiABIAByQYCABEkNAEF/IAIgA0IgiKdBAEcbIQILAkAgAhAHIgBFDQAgAEF8ai0AAEEDcUUNACAAQQAgAhA2GgsgAAtpAQN/IwBBIGsiAiQAIAFBHGooAgAhAyABKAIYIQQgAkEIakEQaiAAKAIAIgFBEGopAgA3AwAgAkEIakEIaiABQQhqKQIANwMAIAIgASkCADcDCCAEIAMgAkEIahAkIQEgAkEgaiQAIAELbAECfyMAQRBrIgIkACAAKAIAIgBBCGooAgAhAyAAKAIAIQAgAiABEMwBAkAgA0UNAANAIAIgADYCDCACIAJBDGpBnMDAABD/ARogAEEBaiEAIANBf2oiAw0ACwsgAhDPASEAIAJBEGokACAAC3QBAX8jAEEgayIBJAAgAUEQakIANwMAIAFCADcDCCABIAFBCGpBEBDdAQJAIAEvAQBFDQAgASABLwECOwEeQaiiwABBEiABQR5qQdSMwABB3KLAABCDAQALIAAgASkDEDcDCCAAIAEpAwg3AwAgAUEgaiQAC20BAX8jAEEwayIDJAAgAyABNgIEIAMgADYCACADQRxqQQI2AgAgA0EsakEiNgIAIANCAzcCDCADQfjBwAA2AgggA0EiNgIkIAMgA0EgajYCGCADIANBBGo2AiggAyADNgIgIANBCGogAhC8AQALcAEBfyMAQTBrIgIkACACIAE2AgQgAiAANgIAIAJBHGpBAjYCACACQSxqQSI2AgAgAkICNwIMIAJB0N/AADYCCCACQSI2AiQgAiACQSBqNgIYIAIgAkEEajYCKCACIAI2AiAgAkEIakGA4MAAELwBAAtwAQF/IwBBMGsiAiQAIAIgATYCBCACIAA2AgAgAkEcakECNgIAIAJBLGpBIjYCACACQgI3AgwgAkGg4MAANgIIIAJBIjYCJCACIAJBIGo2AhggAiACQQRqNgIoIAIgAjYCICACQQhqQbDgwAAQvAEAC3ABAX8jAEEwayICJAAgAiABNgIEIAIgADYCACACQRxqQQI2AgAgAkEsakEiNgIAIAJCAjcCDCACQeTgwAA2AgggAkEiNgIkIAIgAkEgajYCGCACIAJBBGo2AiggAiACNgIgIAJBCGpB9ODAABC8AQALbQEBfyMAQTBrIgMkACADIAE2AgQgAyAANgIAIANBHGpBAjYCACADQSxqQSI2AgAgA0ICNwIMIANB8NnAADYCCCADQSI2AiQgAyADQSBqNgIYIAMgAzYCKCADIANBBGo2AiAgA0EIaiACELwBAAtkAQJ/IwBBIGsiAiQAIAFBHGooAgAhAyABKAIYIQEgAkEIakEQaiAAQRBqKQIANwMAIAJBCGpBCGogAEEIaikCADcDACACIAApAgA3AwggASADIAJBCGoQJCEAIAJBIGokACAAC2QBAn8jAEEgayICJAAgAEEcaigCACEDIAAoAhghACACQQhqQRBqIAFBEGopAgA3AwAgAkEIakEIaiABQQhqKQIANwMAIAIgASkCADcDCCAAIAMgAkEIahAkIQEgAkEgaiQAIAELbgEBfyMAQSBrIgIkACACQYCSwAA2AgQgAiAANgIAIAJBCGpBEGogAUEQaikCADcDACACQQhqQQhqIAFBCGopAgA3AwAgAiABKQIANwMIQQAgAkGwjcAAIAJBBGpBsI3AACACQQhqQdChwAAQNQALawEBfyMAQSBrIgMkACADQeCWwAA2AgQgAyAANgIAIANBCGpBEGogAUEQaikCADcDACADQQhqQQhqIAFBCGopAgA3AwAgAyABKQIANwMIQQAgA0GgjcAAIANBBGpBoI3AACADQQhqIAIQNQALawEBfyMAQSBrIgMkACADIAE2AgQgAyAANgIAIANBCGpBEGogAkEQaikCADcDACADQQhqQQhqIAJBCGopAgA3AwAgAyACKQIANwMIQQAgA0H82sAAIANBBGpB/NrAACADQQhqQYjDwAAQNQALYwEBfyMAQSBrIgIkACACIAAoAgA2AgQgAkEIakEQaiABQRBqKQIANwMAIAJBCGpBCGogAUEIaikCADcDACACIAEpAgA3AwggAkEEakGEh8AAIAJBCGoQJCEBIAJBIGokACABC2MBAX8jAEEgayICJAAgAiAAKAIANgIEIAJBCGpBEGogAUEQaikCADcDACACQQhqQQhqIAFBCGopAgA3AwAgAiABKQIANwMIIAJBBGpBsIvAACACQQhqECQhASACQSBqJAAgAQtjAQF/IwBBIGsiAiQAIAIgACgCADYCBCACQQhqQRBqIAFBEGopAgA3AwAgAkEIakEIaiABQQhqKQIANwMAIAIgASkCADcDCCACQQRqQeCLwAAgAkEIahAkIQEgAkEgaiQAIAELYwEBfyMAQSBrIgIkACACIAAoAgA2AgQgAkEIakEQaiABQRBqKQIANwMAIAJBCGpBCGogAUEIaikCADcDACACIAEpAgA3AwggAkEEakHIi8AAIAJBCGoQJCEBIAJBIGokACABC2MBAX8jAEEgayICJAAgAiAAKAIANgIEIAJBCGpBEGogAUEQaikCADcDACACQQhqQQhqIAFBCGopAgA3AwAgAiABKQIANwMIIAJBBGpBuN7AACACQQhqECQhASACQSBqJAAgAQtgAQF/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ACEDAkAgASgCEEEBRw0AIAEgAyACIAFBFGooAgAQFw8LIAEgAyACQQAQHwtBAQN/IwBBEGsiASQAIAAQugJB5JzAABDjASECIAAQuQIQ5AEhAyABIAI2AgggASAANgIEIAEgAzYCACABEOgBAAtAAQF/IwBBIGsiACQAIABBHGpBADYCACAAQazAwAA2AhggAEIBNwIMIABBhMHAADYCCCAAQQhqQYzBwAAQvAEACz8BAX8jAEEgayICJAAgAkEBOgAYIAIgATYCFCACIAA2AhAgAkHE2sAANgIMIAJBuMLAADYCCCACQQhqELoBAAs5AQF/IwBBMGsiACQAIAAQUAJAIAAQJ0UNAEGAgMAAQSsgAEGsgMAAQciAwAAQgwEACyAAQTBqJAALNAEBfyMAQRBrIgIkACACIAA2AgwgAUHoisAAQQ4gAkEMakH4isAAEF4hASACQRBqJAAgAQsyACAAKAIAIQACQCABEPMBDQACQCABEPQBDQAgACABEP0BDwsgACABEHsPCyAAIAEQegsxAQF/IwBBEGsiAiQAIAJBCGogAUHwj8AAQQsQywEgAkEIahCFASEBIAJBEGokACABCzABAX8jAEEQayICJAAgAkEIaiABQYSXwABBCxDLASACQQhqEHAhASACQRBqJAAgAQsyACAAKAIAIQACQCABEPMBDQACQCABEPQBDQAgACABEP0BDwsgACABEHsPCyAAIAEQegsyACAAKAIAIQACQCABEPMBDQACQCABEPQBDQAgACABEIECDwsgACABEHgPCyAAIAEQdwsvAQJ/IwBBEGsiACQAIABBATYCDCAAQQxqQaSFwABBAEEAEFEhASAAQRBqJAAgAQsvAQF/IwBBEGsiASQAIAAoAgAQsAIgAUEAOgAPIAFBD2oQtAIhACABQRBqJAAgAAsvAQF/IwBBEGsiASQAIAAoAgAQsAIgAUEAOgAPIAFBD2oQtAIhACABQRBqJAAgAAs5AQF/IAAoAgAhAQJAIAAtAAQNAEEAKALI/EBB/////wdxRQ0AEKICDQAgAUEBOgABCyABQQA6AAALLgEBfyMAQRBrIgMkACADIAE2AgwgAyAANgIIIANBCGpBiIvAAEEAIAJBARAaAAsvAQF/IwBBEGsiBSQAIAUgAzYCDCAFIAI2AgggBSABNgIEIAUgADYCACAFEOABAAs0ACAAQQM6ACAgAEKAgICAgAQ3AgAgACABNgIYIABBADYCECAAQQA2AgggAEEcaiACNgIACzAAIAEoAhggAiADIAFBHGooAgAoAgwRCQAhAiAAQQA6AAUgACACOgAEIAAgATYCAAs1AQF/IAEoAhhB6tzAAEEBIAFBHGooAgAoAgwRCQAhAiAAQQA6AAUgACACOgAEIAAgATYCAAsrAAJAAkAgARDzAQ0AIAEQ9AENASAAIAEQggIPCyAAIAEQdg8LIAAgARB5CycBAX8jAEEQayICJAAgAiAAKAIANgIMIAJBDGogARA5IAJBEGokAAsyAQF/QQEhAQJAIAAtAAQNACAAKAIAIgAoAhhB69zAAEEBIAAoAhwoAgwRCQAhAQsgAQsoAQF/IwBBEGsiAyQAIAMgAjYCCCADIAE2AgQgAyAANgIAIAMQ5wEACycBAX8CQCAAKAIEIgFFDQAgAEEIaigCACIARQ0AIAEgAEEBEPUBCwsmAQF/IwBBEGsiAyQAIAMgATYCDCADIAA2AgggA0EIaiACELcBAAsjAAJAAkAgAUEISw0AIAEgAE0NAQsgASAAEN4BDwsgABC2AgsqACAAIAEuAQBBAnQiAUHItsAAaigCADYCBCAAIAFB/LjAAGooAgA2AgALKgAgACABLgEAQQJ0IgFBsLvAAGooAgA2AgQgACABQeS9wABqKAIANgIACyMBAn8CQCAAEGxBAWoiARC2AiICRQ0AIAIgACABEA4aCyACCyABAX8CQCAAQQRqKAIAIgFFDQAgACgCACABQQEQ9QELCyABAX8CQCAAQQRqKAIAIgFFDQAgACgCACABQQEQ9QELCyMAAkAgAC0AAA0AIAFBlN/AAEEFEBYPCyABQZDfwABBBBAWCyEAAkAgASgCAA0AELICAAsgAEGci8AANgIEIAAgATYCAAscACAAIAEpAgA3AgAgAEEIaiABQQhqKAIANgIACx0BAX8gACABQQAoArj8QCICQSMgAhsRBgAQsgIACxkAIAAgASACEAIiATsBAiAAIAFBAEc7AQALFwACQCAAQRBLDQAgARAHDwsgACABEDALJAEBf0GIgcEAIQECQEEAKAKEgUENAEGEgcEAIAAQTiEBCyABCxoAIAAoAgAgACgCBCAAKAIIIAAoAgwQ8QEACxwAIAEoAhhBsNnAAEEOIAFBHGooAgAoAgwRCQALHAAgASgCGEG+8sAAQQUgAUEcaigCACgCDBEJAAsYAAJAIAANAEGYjMAAQSsgARC2AQALIAALGwACQCAADQBBmIzAAEErQfScwAAQtgEACyAACxUBAX8CQBDEASIARQ0AIAAQ+gEACwsUAQF/IAAgASACIAMQsAEhBCAEDwsVACAAKAIAIAAoAgQgACgCCBDIAQALFQAgACgCACAAKAIEIAAoAggQgAEACxUAIAEgACgCACIAKAIAIAAoAgQQFgsTAAJAQQAoAvSAQUF/Rw0AEHwLCxQAIAAoAgAgASAAKAIEKAIMEQcACxABAX8gACABENMBIQIgAg8LEQAgACgCACAAKAIEIAEQmgILDgAgACgCACABED8aQQALEwAgAEGUncAANgIEIAAgATYCAAsQACAAKAIAIAAoAgQgARAZCw0AIAAgASACIAMQEQALEAAgASAAKAIAIAAoAgQQFgsNACAALQAAQRBxQQR2Cw0AIAAtAABBIHFBBXYLDAAgACABIAIQswIPCw8AIAAoAgAoAgAgARC1AQsNACAAKAIAIAEgAhBPCw0AIAAgARADQf//A3ELDQAgACABEARB//8DcQsOABDYAhDYAiAAEKYCAAsLACAAIAEQPhogAAsNACAAKAIAGgN/DAALCw0AIAA1AgBBASABEEILDAAgACABIAIQ0gEACwwAIAAgASACEEogAAsNACAAKAIAIAEgAhAeCw0AIAAxAABBASABEEILDQAgADMBAEEBIAEQQgsPABC/AiAAIAEQwAIQuAILDgAQvwIgACABECsQuAILCgAgACABEI8CDwsNACABQayLwABBAhAWCw0AIAFBrovAAEECEBYLDAAgACgCACABENkBCwsAIAAoAgAgARB/CwsAIAAoAgAgARBHCwoAIAAgARCMAgALCgAgACABEI0CAAsKACAAIAEQhQIACwoAIAAgARCLAgALCgAgACABENwBAAsKACAAIAEQjAEACwoAIAAgARCNAQALCgAgACABEI4BAAsKACAAIAEQlwIACwoAIAAgARCYAgALCgAgACABEJYCAAsKACAAIAEQkgIACwoAIAAgARCQAgALCgAgACABEJECAAsMACAAIAEpAgA3AwALCgAgAiAAIAEQFgsLACAAKAIAIAEQLAsMABC/AiAAEGkQuAILDAAQvwIgABBqELgC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IGdlbmVyYXRlIHVuaXF1ZSB0aHJlYWQgSUQ6IGJpdHNwYWNlIGV4aGF1c3RlZACICBAANwAAAFkIEAAdAAAAEwQAABEAAABZCBAAHQAAABkEAAAqAAAAUlVTVF9CQUNLVFJBQ0UAAPgFEAAAAAAAAGZhaWxlZCB0byB3cml0ZSB0aGUgYnVmZmVyZWQgZGF0YQAAAQkQACEAAAAXAAAAbGlicmFyeS9zdGQvc3JjL2lvL2J1ZmZlcmVkL2J1ZndyaXRlci5yczAJEAAoAAAAjQAAABIAAABmYWlsZWQgdG8gd3JpdGUgd2hvbGUgYnVmZmVyaAkQABwAAAAXAAAAbGlicmFyeS9zdGQvc3JjL2lvL3N0ZGlvLnJzAJAJEAAbAAAAbgIAABMAAABsaWJyYXJ5L3N0ZC9zcmMvaW8vbW9kLnJzAAAAvAkQABkAAAAaBQAAFgAAAGFkdmFuY2luZyBpbyBzbGljZXMgYmV5b25kIHRoZWlyIGxlbmd0aADoCRAAJwAAALwJEAAZAAAAHAUAAA0AAAC8CRAAGQAAAAMGAAAhAAAAZm9ybWF0dGVyIGVycm9yADgKEAAPAAAAKAAAADsAAAAMAAAABAAAADwAAAA9AAAAPgAAADsAAAAMAAAABAAAAD8AAABAAAAAQQAAAGxpYnJhcnkvc3RkL3NyYy9wYW5pYy5yc4QKEAAYAAAA8AAAABIAAAAoAAAABAAAAAQAAABCAAAAQwAAAGxpYnJhcnkvc3RkL3NyYy9zeW5jL29uY2UucnPAChAAHAAAABQBAAAyAAAAYXNzZXJ0aW9uIGZhaWxlZDogc3RhdGVfYW5kX3F1ZXVlLmFkZHIoKSAmIFNUQVRFX01BU0sgPT0gUlVOTklOR09uY2UgaW5zdGFuY2UgaGFzIHByZXZpb3VzbHkgYmVlbiBwb2lzb25lZAAALAsQACoAAAACAAAAwAoQABwAAAD/AQAACQAAAMAKEAAcAAAADAIAADUAAABQb2lzb25FcnJvcnN0YWNrIGJhY2t0cmFjZToKjwsQABEAAABub3RlOiBTb21lIGRldGFpbHMgYXJlIG9taXR0ZWQsIHJ1biB3aXRoIGBSVVNUX0JBQ0tUUkFDRT1mdWxsYCBmb3IgYSB2ZXJib3NlIGJhY2t0cmFjZS4KqAsQAFgAAABsb2NrIGNvdW50IG92ZXJmbG93IGluIHJlZW50cmFudCBtdXRleGxpYnJhcnkvc3RkL3NyYy9zeXNfY29tbW9uL3JlbXV0ZXgucnMALgwQACUAAACnAAAADgAAAGxpYnJhcnkvc3RkL3NyYy9zeXNfY29tbW9uL3RocmVhZF9pbmZvLnJzAAAAZAwQACkAAAAWAAAAMwAAAGQMEAApAAAAKwAAACsAAABhc3NlcnRpb24gZmFpbGVkOiB0aHJlYWRfaW5mby5pc19ub25lKCkAsAwQACcAAABtZW1vcnkgYWxsb2NhdGlvbiBvZiAgYnl0ZXMgZmFpbGVkCgDgDBAAFQAAAPUMEAAOAAAAbGlicmFyeS9zdGQvc3JjL2FsbG9jLnJzFA0QABgAAABSAQAACQAAAGxpYnJhcnkvc3RkL3NyYy9wYW5pY2tpbmcucnM8DRAAHAAAABEBAAAkAAAAQm94PGR5biBBbnk+PHVubmFtZWQ+AAAAKAAAAAAAAAABAAAARAAAAEUAAABGAAAARwAAAEgAAABJAAAASgAAAEsAAAAMAAAABAAAAEwAAABNAAAATgAAAE8AAABQAAAAUQAAAFIAAAB0aHJlYWQgJycgcGFuaWNrZWQgYXQgJycsIAAA0A0QAAgAAADYDRAADwAAAOcNEAADAAAAhQcQAAEAAABub3RlOiBydW4gd2l0aCBgUlVTVF9CQUNLVFJBQ0U9MWAgZW52aXJvbm1lbnQgdmFyaWFibGUgdG8gZGlzcGxheSBhIGJhY2t0cmFjZQoAAAwOEABOAAAAPA0QABwAAABGAgAAHwAAADwNEAAcAAAARwIAAB4AAABLAAAADAAAAAQAAABTAAAAKAAAAAgAAAAEAAAAVAAAAFUAAAAQAAAABAAAAFYAAABXAAAAKAAAAAgAAAAEAAAAWAAAAFkAAAB0aHJlYWQgcGFuaWNrZWQgd2hpbGUgcHJvY2Vzc2luZyBwYW5pYy4gYWJvcnRpbmcuCgAAzA4QADIAAAAKcGFuaWNrZWQgYWZ0ZXIgcGFuaWM6OmFsd2F5c19hYm9ydCgpLCBhYm9ydGluZy4KAAAA+AUQAAAAAAAIDxAAMQAAAHRocmVhZCBwYW5pY2tlZCB3aGlsZSBwYW5pY2tpbmcuIGFib3J0aW5nLgoATA8QACsAAABmYWlsZWQgdG8gaW5pdGlhdGUgcGFuaWMsIGVycm9yIIAPEAAgAAAAYWR2YW5jaW5nIElvU2xpY2UgYmV5b25kIGl0cyBsZW5ndGgAqA8QACMAAABsaWJyYXJ5L3N0ZC9zcmMvc3lzL3dhc2kvaW8ucnMAANQPEAAeAAAAFgAAAA0AAABjb25kdmFyIHdhaXQgbm90IHN1cHBvcnRlZAAABBAQABoAAABsaWJyYXJ5L3N0ZC9zcmMvc3lzL3dhc2kvLi4vdW5zdXBwb3J0ZWQvbG9ja3MvY29uZHZhci5ycygQEAA4AAAAFQAAAAkAAABjYW5ub3QgcmVjdXJzaXZlbHkgYWNxdWlyZSBtdXRleHAQEAAgAAAAbGlicmFyeS9zdGQvc3JjL3N5cy93YXNpLy4uL3Vuc3VwcG9ydGVkL2xvY2tzL211dGV4LnJzAACYEBAANgAAABgAAAAJAAAAcndsb2NrIGxvY2tlZCBmb3Igd3JpdGluZwAAAOAQEAAZAAAACAAOAA8APwACAEAANQANAAQAAwAsABsAHABJABQABgA0ADAAcmFuZG9tX2dldCBmYWlsdXJlbGlicmFyeS9zdGQvc3JjL3N5cy93YXNpL21vZC5ycwAAADoREAAfAAAAXQAAACUAAABsaWJyYXJ5L3N0ZC9zcmMvc3lzX2NvbW1vbi90aHJlYWRfcGFya2VyL2dlbmVyaWMucnMAbBEQADMAAAAnAAAAJgAAAGluY29uc2lzdGVudCBwYXJrIHN0YXRlALAREAAXAAAAbBEQADMAAAA1AAAAFwAAAHBhcmsgc3RhdGUgY2hhbmdlZCB1bmV4cGVjdGVkbHkA4BEQAB8AAABsERAAMwAAADIAAAARAAAAaW5jb25zaXN0ZW50IHN0YXRlIGluIHVucGFyaxgSEAAcAAAAbBEQADMAAABsAAAAEgAAAGwREAAzAAAAegAAAB8AAABjb2RlbmFtZVoAAAAIAAAABAAAAFsAAABtZXNzYWdlTk9UQ0FQQUJMRVhERVZUWFRCU1lUSU1FRE9VVFNUQUxFU1JDSFNQSVBFUk9GU1JBTkdFUFJPVE9UWVBFUFJPVE9OT1NVUFBPUlRQUk9UT1BJUEVQRVJNT1dORVJERUFET1ZFUkZMT1dOWElPTk9UVFlOT1RTVVBOT1RTT0NLTk9UUkVDT1ZFUkFCTEVOT1RFTVBUWU5PVERJUk5PVENPTk5OT1NZU05PU1BDTk9QUk9UT09QVE5PTVNHTk9NRU1OT0xJTktOT0xDS05PRVhFQ05PRU5UTk9ERVZOT0JVRlNORklMRU5FVFVOUkVBQ0hORVRSRVNFVE5FVERPV05OQU1FVE9PTE9OR01VTFRJSE9QTVNHU0laRU1MSU5LTUZJTEVMT09QSVNESVJJU0NPTk5JT0lOVkFMSU5UUklOUFJPR1JFU1NJTFNFUUlEUk1IT1NUVU5SRUFDSEZCSUdGQVVMVEVYSVNURFFVT1RET01ERVNUQUREUlJFUURFQURMS0NPTk5SRVNFVENPTk5SRUZVU0VEQ09OTkFCT1JURURDSElMRENBTkNFTEVEQlVTWUJBRE1TR0JBREZBTFJFQURZQUdBSU5BRk5PU1VQUE9SVEFERFJOT1RBVkFJTEFERFJJTlVTRUFDQ0VTMkJJR1NVQ0NFU1NFeHRlbnNpb246IENhcGFiaWxpdGllcyBpbnN1ZmZpY2llbnQuQ3Jvc3MtZGV2aWNlIGxpbmsuVGV4dCBmaWxlIGJ1c3kuQ29ubmVjdGlvbiB0aW1lZCBvdXQuUmVzZXJ2ZWQuTm8gc3VjaCBwcm9jZXNzLkludmFsaWQgc2Vlay5SZWFkLW9ubHkgZmlsZSBzeXN0ZW0uUmVzdWx0IHRvbyBsYXJnZS5Qcm90b2NvbCB3cm9uZyB0eXBlIGZvciBzb2NrZXQuUHJvdG9jb2wgbm90IHN1cHBvcnRlZC5Qcm90b2NvbCBlcnJvci5Ccm9rZW4gcGlwZS5PcGVyYXRpb24gbm90IHBlcm1pdHRlZC5QcmV2aW91cyBvd25lciBkaWVkLlZhbHVlIHRvbyBsYXJnZSB0byBiZSBzdG9yZWQgaW4gZGF0YSB0eXBlLk5vIHN1Y2ggZGV2aWNlIG9yIGFkZHJlc3MuSW5hcHByb3ByaWF0ZSBJL08gY29udHJvbCBvcGVyYXRpb24uTm90IHN1cHBvcnRlZCwgb3Igb3BlcmF0aW9uIG5vdCBzdXBwb3J0ZWQgb24gc29ja2V0Lk5vdCBhIHNvY2tldC5TdGF0ZSBub3QgcmVjb3ZlcmFibGUuRGlyZWN0b3J5IG5vdCBlbXB0eS5Ob3QgYSBkaXJlY3Rvcnkgb3IgYSBzeW1ib2xpYyBsaW5rIHRvIGEgZGlyZWN0b3J5LlRoZSBzb2NrZXQgaXMgbm90IGNvbm5lY3RlZC5GdW5jdGlvbiBub3Qgc3VwcG9ydGVkLk5vIHNwYWNlIGxlZnQgb24gZGV2aWNlLlByb3RvY29sIG5vdCBhdmFpbGFibGUuTm8gbWVzc2FnZSBvZiB0aGUgZGVzaXJlZCB0eXBlLk5vdCBlbm91Z2ggc3BhY2UuTm8gbG9ja3MgYXZhaWxhYmxlLkV4ZWN1dGFibGUgZmlsZSBmb3JtYXQgZXJyb3IuTm8gc3VjaCBmaWxlIG9yIGRpcmVjdG9yeS5ObyBzdWNoIGRldmljZS5ObyBidWZmZXIgc3BhY2UgYXZhaWxhYmxlLlRvbyBtYW55IGZpbGVzIG9wZW4gaW4gc3lzdGVtLk5ldHdvcmsgdW5yZWFjaGFibGUuQ29ubmVjdGlvbiBhYm9ydGVkIGJ5IG5ldHdvcmsuTmV0d29yayBpcyBkb3duLkZpbGVuYW1lIHRvbyBsb25nLk1lc3NhZ2UgdG9vIGxhcmdlLlRvbyBtYW55IGxpbmtzLkZpbGUgZGVzY3JpcHRvciB2YWx1ZSB0b28gbGFyZ2UuVG9vIG1hbnkgbGV2ZWxzIG9mIHN5bWJvbGljIGxpbmtzLklzIGEgZGlyZWN0b3J5LlNvY2tldCBpcyBjb25uZWN0ZWQuSS9PIGVycm9yLkludmFsaWQgYXJndW1lbnQuSW50ZXJydXB0ZWQgZnVuY3Rpb24uT3BlcmF0aW9uIGluIHByb2dyZXNzLklsbGVnYWwgYnl0ZSBzZXF1ZW5jZS5JZGVudGlmaWVyIHJlbW92ZWQuSG9zdCBpcyB1bnJlYWNoYWJsZS5GaWxlIHRvbyBsYXJnZS5CYWQgYWRkcmVzcy5GaWxlIGV4aXN0cy5NYXRoZW1hdGljcyBhcmd1bWVudCBvdXQgb2YgZG9tYWluIG9mIGZ1bmN0aW9uLkRlc3RpbmF0aW9uIGFkZHJlc3MgcmVxdWlyZWQuUmVzb3VyY2UgZGVhZGxvY2sgd291bGQgb2NjdXIuQ29ubmVjdGlvbiByZXNldC5Db25uZWN0aW9uIHJlZnVzZWQuQ29ubmVjdGlvbiBhYm9ydGVkLk5vIGNoaWxkIHByb2Nlc3Nlcy5PcGVyYXRpb24gY2FuY2VsZWQuRGV2aWNlIG9yIHJlc291cmNlIGJ1c3kuQmFk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AAAAAAAAAAEAAAByAAAAL2hvbWUvcGF2ZWwvLmNhcmdvL3JlZ2lzdHJ5L3NyYy9naXRodWIuY29tLTFlY2M2Mjk5ZGI5ZWM4MjMvbWFyaW5lLXJzLXNkay1tYWluLTAuNi4xNS9zcmMvcmVzdWx0LnJzAFw9EABjAAAAQwAAACMAAABzAAAAAEHY+8AACxiIBBAAlAQQAAEAAAAAAAAAAQAAABggEAAA362BgAAEbmFtZQHUrYGAANwCAEhfWk4xOG1hcmluZV9yc19zZGtfbWFpbjZsb2dnZXIyMGxvZ191dGY4X3N0cmluZ19pbXBsMTdoZGQ5NGY0NzFjMzYyZjE3ZUUBTF9aTjR3YXNpMTNsaWJfZ2VuZXJhdGVkMjJ3YXNpX3NuYXBzaG90X3ByZXZpZXcxOGZkX3dyaXRlMTdoODFlNzQwZmI4NjZkMmMxOUUCT19aTjR3YXNpMTNsaWJfZ2VuZXJhdGVkMjJ3YXNpX3NuYXBzaG90X3ByZXZpZXcxMTByYW5kb21fZ2V0MTdoNjE2NGI5NmNjZGRmYzcxYUUDLV9faW1wb3J0ZWRfd2FzaV9zbmFwc2hvdF9wcmV2aWV3MV9lbnZpcm9uX2dldAQzX19pbXBvcnRlZF93YXNpX3NuYXBzaG90X3ByZXZpZXcxX2Vudmlyb25fc2l6ZXNfZ2V0BStfX2ltcG9ydGVkX3dhc2lfc25hcHNob3RfcHJldmlldzFfcHJvY19leGl0BklfWk40Y29yZTNudW03Zmx0MmRlYzhzdHJhdGVneTZkcmFnb24xNWZvcm1hdF9zaG9ydGVzdDE3aGVkN2VhYzBiMWFiNzg2ODBFBwhkbG1hbGxvYwhGX1pONGNvcmUzbnVtN2ZsdDJkZWM4c3RyYXRlZ3k2ZHJhZ29uMTJmb3JtYXRfZXhhY3QxN2hhNzZkNGM5NjlmN2U5MDkyRQlCX1pONGNvcmUzbnVtN2ZsdDJkZWM4c3RyYXRlZ3k2ZHJhZ29uOW11bF9wb3cxMDE3aDI1NGI5MDc2OWE4M2ZlMGVFCkxfWk40Y29yZTNudW03Zmx0MmRlYzhzdHJhdGVneTVncmlzdTE5Zm9ybWF0X3Nob3J0ZXN0X29wdDE3aGU4ZjFlYjFjNGExYmUyZDNFCy9fWk41YWxsb2M1c2xpY2UxMG1lcmdlX3NvcnQxN2gwMzAzNWY0MDk4M2RhODRhRQwGZGxmcmVlDQ1kaXNwb3NlX2NodW5rDgZtZW1jcHkPB21lbW1vdmUQOV9aTjRjb3JlM251bTZiaWdudW04QmlnMzJ4NDA4bXVsX3BvdzIxN2gzMWFiZGI4ZTA4NTdmMTE2RRE1X1pONGNvcmUzc3RyMTlzbGljZV9lcnJvcl9mYWlsX3J0MTdoNjcwNDcyNjc5ZTFlNDgxMUUSNl9aTjRjb3JlM3N0cjVjb3VudDE0ZG9fY291bnRfY2hhcnMxN2g4MDZiZDU1NTI1NDc0ZDk2RRNJX1pONGNvcmUzbnVtN2ZsdDJkZWM4c3RyYXRlZ3k1Z3Jpc3UxNmZvcm1hdF9leGFjdF9vcHQxN2gyOGRhYzg4MDU0M2FhMTFmRRQHcmVhbGxvYxVhX1pONjNfJExUJGxvZy4uTGV2ZWxGaWx0ZXIkdTIwJGFzJHUyMCRjb3JlLi5zdHIuLnRyYWl0cy4uRnJvbVN0ciRHVCQ4ZnJvbV9zdHIxN2gzYmEwMzMwYmM5NGM4ZWU5RRYuX1pONGNvcmUzZm10OUZvcm1hdHRlcjNwYWQxN2hiOWZkYzQzNGNiYjBjM2E4RRdFX1pONGNvcmUzZm10NWZsb2F0MjlmbG9hdF90b19kZWNpbWFsX2NvbW1vbl9leGFjdDE3aDA4NDZiYzU2YmM0NDU0ZThFGDhfWk40Y29yZTNmbXQ5Rm9ybWF0dGVyMTJwYWRfaW50ZWdyYWwxN2hiYTUzODI4NTNlOTliOGYzRRlFX1pONDBfJExUJHN0ciR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uRGVidWckR1QkM2ZtdDE3aDYzYjYyZWI4NDZiMzg1YzVFGjtfWk4zc3RkOXBhbmlja2luZzIwcnVzdF9wYW5pY193aXRoX2hvb2sxN2hjY2IwNGUwZDg2ODExNmIwRRszX1pOM3N0ZDlwYW5pY2tpbmcxMmRlZmF1bHRfaG9vazE3aGZjNjA2MWQxZDM0NWIzOGVFHDhfWk4zc3RkMmlvNVdyaXRlMTh3cml0ZV9hbGxfdmVjdG9yZWQxN2hjOTA2MDUxYzRiMjgwZDFkRR1RX1pOM3N0ZDlwYW5pY2tpbmcxMmRlZmF1bHRfaG9vazI4XyR1N2IkJHU3YiRjbG9zdXJlJHU3ZCQkdTdkJDE3aDFjOWRhZWViOGU5MDQ0NDVFHmdfWk42OF8kTFQkY29yZS4uZm10Li5idWlsZGVycy4uUGFkQWRhcHRlciR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uV3JpdGUkR1QkOXdyaXRlX3N0cjE3aDViZTYzNjcyNmFkMTEzZmVFH0hfWk40Y29yZTNmbXQ1ZmxvYXQzMmZsb2F0X3RvX2RlY2ltYWxfY29tbW9uX3Nob3J0ZXN0MTdoOGRjNDI5NzIzZDBhNmRlNEUgM19aTjRjb3JlM3N0cjhjb252ZXJ0czlmcm9tX3V0ZjgxN2g5MDZkMmZiMGNiYTdiOTA5RSFmX1pONzFfJExUJGNvcmUuLmhhc2guLnNpcC4uSGFzaGVyJExUJFMkR1QkJHUyMCRhcyR1MjAkY29yZS4uaGFzaC4uSGFzaGVyJEdUJDV3cml0ZTE3aGIxMTk4ZDI3YjkxYjk5OTNFIkFfWk40Y29yZTNmbXQ5Rm9ybWF0dGVyMjF3cml0ZV9mb3JtYXR0ZWRfcGFydHMxN2g2ZjA3NzNkYzljZGQyYWZiRSM2X1pOM3N0ZDRzeW5jNG9uY2U0T25jZTEwY2FsbF9pbm5lcjE3aDE4ZDE4YzAzMTI0NTg5ZTZFJCZfWk40Y29yZTNmbXQ1d3JpdGUxN2g3NWZlNWEyYmI2YjFmYzAyRSU/X1pONGNvcmUzZm10OUZvcm1hdHRlcjE5cGFkX2Zvcm1hdHRlZF9wYXJ0czE3aGM1NDcxZTM3ODI5MDk4MjlFJidfWk4zc3RkNnRocmVhZDRwYXJrMTdoNzk1NzI5MmVlYTk1ZTk1OUUnS19aTjE4bWFyaW5lX3JzX3Nka19tYWluNmxvZ2dlcjE3V2FzbUxvZ2dlckJ1aWxkZXI1YnVpbGQxN2g4ODc3Njg5ZDg5NzE2ZTQzRShgX1pONjdfJExUJG1hcmluZV9yc19zZGtfbWFpbi4ubG9nZ2VyLi5XYXNtTG9nZ2VyJHUyMCRhcyR1MjAkbG9nLi5Mb2ckR1QkM2xvZzE3aDI0NTc5NzllNGRjZWIxMGZFKThfWk4zc3RkMmlvNVdyaXRlMTh3cml0ZV9hbGxfdmVjdG9yZWQxN2g5NDY1OGU4NWY3YjNmZjVhRSo3X1pONGNvcmU0aGFzaDExQnVpbGRIYXNoZXI4aGFzaF9vbmUxN2g2ZGMyMTI5MzA5ZDFkOTVmRSsIYWxsb2NhdGUsXF9aTjRjb3JlM2ZtdDNudW01MF8kTFQkaW1wbCR1MjAkY29yZS4uZm10Li5EZWJ1ZyR1MjAkZm9yJHUyMCR1NjQkR1QkM2ZtdDE3aDRkOTU4MjBmNWUxNzg2YzNFLVlfWk40Y29yZTNudW03Zmx0MmRlYzhzdHJhdGVneTVncmlzdTE2Zm9ybWF0X2V4YWN0X29wdDE0cG9zc2libHlfcm91bmQxN2gwODY5MWYwOTJjYjNjMmYyRS5GX1pONDFfJExUJGNoYXIkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2g3OGNjMWYxMjdjNmQ1YzU2RS9wX1pONzJfJExUJCRSRiRzdHIkdTIwJGFzJHUyMCRhbGxvYy4uZmZpLi5jX3N0ci4uQ1N0cmluZy4ubmV3Li5TcGVjTmV3SW1wbCRHVCQxM3NwZWNfbmV3X2ltcGwxN2g0MGE1ZjQ3ZDczY2E5MTI2RTARaW50ZXJuYWxfbWVtYWxpZ24xgAFfWk4zc3RkMmlvNWltcGxzNzRfJExUJGltcGwkdTIwJHN0ZC4uaW8uLldyaXRlJHUyMCRmb3IkdTIwJGFsbG9jLi52ZWMuLlZlYyRMVCR1OCRDJEEkR1QkJEdUJDE0d3JpdGVfdmVjdG9yZWQxN2g5ZGY3MmU1NjNiZTNjM2RiRTJGX1pONGNvcmUzbnVtNmJpZ251bThCaWczMng0MDEwbXVsX2RpZ2l0czltdWxfaW5uZXIxN2gzNTk4MWU3NDdmZjIwODFmRTM7X1pONGNvcmUzbnVtN2ZsdDJkZWMxN2RpZ2l0c190b19kZWNfc3RyMTdoODE4MmYzZWM0YTk0NDM2MUU0T19aTjNzdGQyaW84YnVmZmVyZWQ5YnVmd3JpdGVyMThCdWZXcml0ZXIkTFQkVyRHVCQ5Zmx1c2hfYnVmMTdoOTJiZTVhMGVkZDA5MGE0ZEU1O19aTjRjb3JlOXBhbmlja2luZzE5YXNzZXJ0X2ZhaWxlZF9pbm5lcjE3aDI0MmM1ZDY5NGI3ZDZmYjdFNgZtZW1zZXQ3NF9aTjRjb3JlN3VuaWNvZGU5cHJpbnRhYmxlNWNoZWNrMTdoNTk4MDM1ZmYxODliM2E3YUU4PF9aTjRjb3JlM2ZtdDhidWlsZGVyczExRGVidWdTdHJ1Y3Q1ZmllbGQxN2g2ZGQ1MmNlYjYzMWEwODEzRTlSX1pOM3N0ZDRzeW5jNG9uY2U0T25jZTljYWxsX29uY2UyOF8kdTdiJCR1N2IkY2xvc3VyZSR1N2QkJHU3ZCQxN2gzNGE2ODVlMzhjYzg5Y2NhRTpKX1pONGNvcmU3dW5pY29kZTEydW5pY29kZV9kYXRhMTVncmFwaGVtZV9leHRlbmQ2bG9va3VwMTdoZDU5NzU5MTdiNzY5OWYwZUU7V19aTjUwXyRMVCQkUkYkbXV0JHUyMCRXJHUyMCRhcyR1MjAkY29yZS4uZm10Li5Xcml0ZSRHVCQxMHdyaXRlX2NoYXIxN2hmNTc5MDg4ZDJhZWZmODhhRTxmX1pONzNfJExUJGNvcmUuLnBhbmljLi5wYW5pY19pbmZvLi5QYW5pY0luZm8kdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRpc3BsYXkkR1QkM2ZtdDE3aDVhNWY2NWFjZjgzNjczODFFPV9fWk41OF8kTFQkYWxsb2MuLnN0cmluZy4uU3RyaW5nJHUyMCRhcyR1MjAkY29yZS4uZm10Li5Xcml0ZSRHVCQxMHdyaXRlX2NoYXIxN2g1NzU1NjFlNjQyZjg1ODYzRT4IX19zdHBjcHk/X19aTjU4XyRMVCRhbGxvYy4uc3RyaW5nLi5TdHJpbmckdTIwJGFzJHUyMCRjb3JlLi5mbXQuLldyaXRlJEdUJDEwd3JpdGVfY2hhcjE3aDU3NTU2MWU2NDJmODU4NjNFQAtfX3N0cmNocm51bEE+X1pONGNvcmU1c2xpY2U2bWVtY2hyMTltZW1jaHJfZ2VuZXJhbF9jYXNlMTdoY2E1MDhkMGUxZWNmNmQ0Y0VCMF9aTjRjb3JlM2ZtdDNudW0zaW1wN2ZtdF91NjQxN2hiMGNhYmI1NTdjMDZjMWRiRUM7X1pOM3N0ZDVhbGxvYzI0ZGVmYXVsdF9hbGxvY19lcnJvcl9ob29rMTdoYjFmYmM1NTA2ZTkxMzMwZkVEN19aTjNzdGQzc3lzNHdhc2kxN2RlY29kZV9lcnJvcl9raW5kMTdoODUyZGE4ZjU5YWU5NzI3Y0VFXF9aTjRjb3JlM2ZtdDNudW01MF8kTFQkaW1wbCR1MjAkY29yZS4uZm10Li5EZWJ1ZyR1MjAkZm9yJHUyMCR1MzIkR1QkM2ZtdDE3aGEwYzIxYTYxZmY0MmNmMGFFRjtfWk40Y29yZTNmbXQ4YnVpbGRlcnMxMERlYnVnVHVwbGU1ZmllbGQxN2gxZTU2MTBiYWE3NDhjNDA5RUcyX1pONGNvcmUzZm10NVdyaXRlMTB3cml0ZV9jaGFyMTdoMzE2NjBhNDk3ZjE1ZDI3MUVILF9aTjNzdGQzZW52MTFjdXJyZW50X2RpcjE3aGM0MzU4ODc3M2Q2OGViZGNFSURfWk41YWxsb2MzZmZpNWNfc3RyN0NTdHJpbmcxOV9mcm9tX3ZlY191bmNoZWNrZWQxN2g4ZmMzNDk1NjlmZTYyNDQwRUo7X1pONGNvcmUzZm10OGJ1aWxkZXJzMTBEZWJ1Z0lubmVyNWVudHJ5MTdoNjA3MjA4OTI2MGI0ZjUxYUVLCXRlc3RfbG9nc0xMX1pOM3N0ZDEwc3lzX2NvbW1vbjEzdGhyZWFkX3BhcmtlcjdnZW5lcmljNlBhcmtlcjZ1bnBhcmsxN2hjZGE4MWYyNmYwNjFmYzQzRU14X1pOOTFfJExUJHN0ZC4uc3lzX2NvbW1vbi4uYmFja3RyYWNlLi5fcHJpbnQuLkRpc3BsYXlCYWNrdHJhY2UkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRpc3BsYXkkR1QkM2ZtdDE3aGVkMmNkODQ4MWRlOGFjYjFFTlBfWk4zc3RkNnRocmVhZDVsb2NhbDRsYXp5MjFMYXp5S2V5SW5uZXIkTFQkVCRHVCQxMGluaXRpYWxpemUxN2g1MmZmZmE1YWM0MzBlMzNlRU9zX1pOODBfJExUJHN0ZC4uaW8uLldyaXRlLi53cml0ZV9mbXQuLkFkYXB0ZXIkTFQkVCRHVCQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLldyaXRlJEdUJDl3cml0ZV9zdHIxN2hhMzc3ZjYxNmM2NDRkMTU3RVBJX1pOMThtYXJpbmVfcnNfc2RrX21haW42bG9nZ2VyMTdXYXNtTG9nZ2VyQnVpbGRlcjNuZXcxN2hhNWZmYmYwNWU1MDdiZjY4RVEzX1pOM3N0ZDJydDE5bGFuZ19zdGFydF9pbnRlcm5hbDE3aDcwODg1NmRiYTBkMGUzMjBFUnxfWk45MF8kTFQkc3RkLi5wYW5pY2tpbmcuLmJlZ2luX3BhbmljX2hhbmRsZXIuLlBhbmljUGF5bG9hZCR1MjAkYXMkdTIwJGNvcmUuLnBhbmljLi5Cb3hNZVVwJEdUJDh0YWtlX2JveDE3aDFjNGE5MWU2NjNlN2VkNWNFUy1fWk4zc3RkNnRocmVhZDZUaHJlYWQzbmV3MTdoZWMxNDVkNTM2YjE3NjZmNUVUV19aTjUwXyRMVCQkUkYkbXV0JHUyMCRXJHUyMCRhcyR1MjAkY29yZS4uZm10Li5Xcml0ZSRHVCQxMHdyaXRlX2NoYXIxN2hiOGRlMWU2YzcyMDVmMjNiRVUkX1pOM3N0ZDNlbnY0X3ZhcjE3aDNiM2Y0MDIzYzZhZTMxNGVFVldfWk41MF8kTFQkJFJGJG11dCR1MjAkVyR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uV3JpdGUkR1QkMTB3cml0ZV9jaGFyMTdoOTBjOTc3NzQ0ZjkzMmM0MEVXMl9aTjRjb3JlM2ZtdDVXcml0ZTEwd3JpdGVfY2hhcjE3aDk1NWYzNWY1NGY2ZGNhYzBFWDJfWk40Y29yZTNmbXQ1V3JpdGUxMHdyaXRlX2NoYXIxN2g3NDQ3MTNlN2I5ZDJiNDVkRVknX1pOM3N0ZDNlbnY3X3Zhcl9vczE3aGJjOGZlOTNiMTQwZGM4NGJFWi5fWk4zc3RkMmlvNVdyaXRlOXdyaXRlX2ZtdDE3aGYyNTgwZjg3OWYyMjI0NDhFWy5fWk4zc3RkMmlvNVdyaXRlOXdyaXRlX2ZtdDE3aDc3NjI5YWQ2YmY4NTQ5Y2FFXExfWk41YWxsb2M3cmF3X3ZlYzE5UmF3VmVjJExUJFQkQyRBJEdUJDE2cmVzZXJ2ZV9mb3JfcHVzaDE3aDI5ZjYyNmY4YjY5YWZlYWRFXUVfWk40Y29yZTNmbXQ5Rm9ybWF0dGVyMjVkZWJ1Z190dXBsZV9maWVsZDJfZmluaXNoMTdoMzM1OTVhZDAwNmFlYTZhNUVeRV9aTjRjb3JlM2ZtdDlGb3JtYXR0ZXIyNWRlYnVnX3R1cGxlX2ZpZWxkMV9maW5pc2gxN2hiZTYyNjY4NTNkM2JmNmZmRV82X1pOM3N0ZDVwYW5pYzE5Z2V0X2JhY2t0cmFjZV9zdHlsZTE3aDdlYmE3Y2FlYjZkNDIyZmNFYEBfWk4zc3RkNnRocmVhZDVsb2NhbDE3TG9jYWxLZXkkTFQkVCRHVCQ0d2l0aDE3aDY2ODAyNWNhYmJkMTliYjBFYS5fWk4zbG9nMTdfX3ByaXZhdGVfYXBpX2xvZzE3aGI4ODc0MjgwYTIyNzQ5ZTVFYi5fWk4zc3RkMmlvNVdyaXRlOXdyaXRlX2FsbDE3aGE3NTY5OWEwNGE1ZmU3YTZFYwZkaXZpZGVkTF9aTjVhbGxvYzdyYXdfdmVjMTlSYXdWZWMkTFQkVCRDJEEkR1QkMTZyZXNlcnZlX2Zvcl9wdXNoMTdoNDg2MDE1YWZkYjI2YTFmZkVlWV9aTjVhbGxvYzdyYXdfdmVjMTlSYXdWZWMkTFQkVCRDJEEkR1QkN3Jlc2VydmUyMWRvX3Jlc2VydmVfYW5kX2hhbmRsZTE3aGExM2QxYzE4YjYxOWRiZTJFZllfWk41YWxsb2M3cmF3X3ZlYzE5UmF3VmVjJExUJFQkQyRBJEdUJDdyZXNlcnZlMjFkb19yZXNlcnZlX2FuZF9oYW5kbGUxN2g2ZjI0NmE5NTRkZWU0YTZlRWdMX1pONWFsbG9jN3Jhd192ZWMxOVJhd1ZlYyRMVCRUJEMkQSRHVCQxNnJlc2VydmVfZm9yX3B1c2gxN2hkNmFiMWVkMDJhMTA1YTFkRWhMX1pONWFsbG9jN3Jhd192ZWMxOVJhd1ZlYyRMVCRUJEMkQSRHVCQxNnJlc2VydmVfZm9yX3B1c2gxN2gwZTdmMDE3OGU2MjU5MGJhRWkDYWRkaghzdWJ0cmFjdGsIbXVsdGlwbHlsBnN0cmxlbm04X1pOM3N0ZDEwc3lzX2NvbW1vbjExdGhyZWFkX2luZm8zc2V0MTdoZDVmMDUyMWE4ZDg3NzYyNUVuPF9aTjRjb3JlN3VuaWNvZGU5cHJpbnRhYmxlMTJpc19wcmludGFibGUxN2g4M2M4ZDAxMjkxZDViZmZjRW9dX1pONGNvcmUzcHRyNTlkcm9wX2luX3BsYWNlJExUJG1hcmluZV9yc19zZGtfbWFpbi4ubG9nZ2VyLi5XYXNtTG9nZ2VyJEdUJDE3aDkzMTIyNzY4ZjBlMDkxZTFFcE1fWk40Y29yZTNmbXQ4YnVpbGRlcnMxMURlYnVnU3RydWN0MjFmaW5pc2hfbm9uX2V4aGF1c3RpdmUxN2g4MzJkNjEwYTg0YzU2NzZhRXF3X1pOOTBfJExUJHN0ZC4ucGFuaWNraW5nLi5iZWdpbl9wYW5pY19oYW5kbGVyLi5QYW5pY1BheWxvYWQkdTIwJGFzJHUyMCRjb3JlLi5wYW5pYy4uQm94TWVVcCRHVCQzZ2V0MTdoYzhkNmQ2NGQ0Mzg2YTM3NkVyCnJ1c3RfcGFuaWNzMl9aTjVhbGxvYzdyYXdfdmVjMTFmaW5pc2hfZ3JvdzE3aDc2Y2JiMzFiM2VmYjFhZDlFdDJfWk41YWxsb2M3cmF3X3ZlYzExZmluaXNoX2dyb3cxN2g4MWRjYjY1NWI2YWY2YzYzRXVLX1pONWFsbG9jN3Jhd192ZWMxMWZpbmlzaF9ncm93MTdoMDliNzk0ODExZWZkMGRkNEUubGx2bS43MDQzNDUzNjExMTg5NzYzNzExdl9fWk40Y29yZTNmbXQzbnVtNTNfJExUJGltcGwkdTIwJGNvcmUuLmZtdC4uTG93ZXJIZXgkdTIwJGZvciR1MjAkaTE2JEdUJDNmbXQxN2hmZjVjYzMzMWExYmI0MzgzRXdeX1pONGNvcmUzZm10M251bTUyXyRMVCRpbXBsJHUyMCRjb3JlLi5mbXQuLkxvd2VySGV4JHUyMCRmb3IkdTIwJGk4JEdUJDNmbXQxN2hmZmI4NmQ0NWQxNzEwNDI4RXheX1pONGNvcmUzZm10M251bTUyXyRMVCRpbXBsJHUyMCRjb3JlLi5mbXQuLlVwcGVySGV4JHUyMCRmb3IkdTIwJGk4JEdUJDNmbXQxN2hkOGFjY2IxYmUxMjJkZTVkRXlfX1pONGNvcmUzZm10M251bTUzXyRMVCRpbXBsJHUyMCRjb3JlLi5mbXQuLlVwcGVySGV4JHUyMCRmb3IkdTIwJGkxNiRHVCQzZm10MTdoYjZiODQ4OWQ3NzUxOGM2N0V6X19aTjRjb3JlM2ZtdDNudW01M18kTFQkaW1wbCR1MjAkY29yZS4uZm10Li5Mb3dlckhleCR1MjAkZm9yJHUyMCRpMzIkR1QkM2ZtdDE3aGM5ZTIxNjEzNTIxNjlkOTBFe19fWk40Y29yZTNmbXQzbnVtNTNfJExUJGltcGwkdTIwJGNvcmUuLmZtdC4uVXBwZXJIZXgkdTIwJGZvciR1MjAkaTMyJEdUJDNmbXQxN2g2YjdkOWFiMDdlYWVjZmNhRXwdX193YXNpbGliY19pbml0aWFsaXplX2Vudmlyb259B3N0cm5jbXB+ZF9aTjY3XyRMVCRtYXJpbmVfcnNfc2RrX21haW4uLmxvZ2dlci4uV2FzbUxvZ2dlciR1MjAkYXMkdTIwJGxvZy4uTG9nJEdUJDdlbmFibGVkMTdoN2ExMjgwZTRhNzRkYTBlZkV/Y19aTjcwXyRMVCRjb3JlLi5wYW5pYy4ubG9jYXRpb24uLkxvY2F0aW9uJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EaXNwbGF5JEdUJDNmbXQxN2gxZjM3Mzc4YzAyYzI2OTA3RYABWF9aTjNzdGQ5cGFuaWNraW5nMTliZWdpbl9wYW5pY19oYW5kbGVyMjhfJHU3YiQkdTdiJGNsb3N1cmUkdTdkJCR1N2QkMTdoNTU0MWY3NGEwMzMxYTFkY0WBAQZnZXRlbnaCAVxfWk42M18kTFQkd2FzaS4ubGliX2dlbmVyYXRlZC4uRXJybm8kdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2g4ZTQwN2U5ZTIwYmNlMDQzRYMBMl9aTjRjb3JlNnJlc3VsdDEzdW53cmFwX2ZhaWxlZDE3aDg2OGEwMDYwMWEzZWI2ODdFhAFfX1pONjRfJExUJHN0ZC4uc3lzLi53YXNpLi5zdGRpby4uU3RkZXJyJHUyMCRhcyR1MjAkc3RkLi5pby4uV3JpdGUkR1QkNXdyaXRlMTdoOGRlNzk5NjUyNGZiM2FkZkWFAT1fWk40Y29yZTNmbXQ4YnVpbGRlcnMxMURlYnVnU3RydWN0NmZpbmlzaDE3aDE1ODY1OWZjZjc5YzU5ZjlFhgFkX1pONzFfJExUJGNvcmUuLm9wcy4ucmFuZ2UuLlJhbmdlJExUJElkeCRHVCQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2g2NzQzYWVkNmQyMzZhMzlhRYcBBmNhbGxvY4gBSV9aTjQ0XyRMVCQkUkYkVCR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uRGlzcGxheSRHVCQzZm10MTdoMjMwZDVhOTZjNzhkZDRlN0WJAUdfWk40Ml8kTFQkJFJGJFQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2gxZmM4NGJmMDZlOTFkZWUwRYoBOV9aTjNzdGQzc3lzNHdhc2kxOWhhc2htYXBfcmFuZG9tX2tleXMxN2gxYzBjMGM4ZGQ1ZDQ3YmE4RYsBSV9aTjVhbGxvYzN2ZWMxNlZlYyRMVCRUJEMkQSRHVCQ2cmVtb3ZlMTNhc3NlcnRfZmFpbGVkMTdoYWYyNmM2ODIzNjUyOGZkNkWMAUdfWk40Y29yZTVzbGljZTVpbmRleDI5c2xpY2Vfc3RhcnRfaW5kZXhfbGVuX2ZhaWxfcnQxN2hhNGE1MTA5MTg5YmU2MDBiRY0BRV9aTjRjb3JlNXNsaWNlNWluZGV4MjdzbGljZV9lbmRfaW5kZXhfbGVuX2ZhaWxfcnQxN2gxYjk4OWE3YjkyYmY2Y2Y1RY4BQ19aTjRjb3JlNXNsaWNlNWluZGV4MjVzbGljZV9pbmRleF9vcmRlcl9mYWlsX3J0MTdoNTlmZTk3Mzc0MzdiZTljMUWPATpfWk40Y29yZTlwYW5pY2tpbmcxOHBhbmljX2JvdW5kc19jaGVjazE3aDk4NDRlNDZjMzM5YjliZmZFkAFYX1pONTlfJExUJGNvcmUuLmZtdC4uQXJndW1lbnRzJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EaXNwbGF5JEdUJDNmbXQxN2hhNjM1MjMyMTQxNzYyYTVlRZEBNF9aTjRjb3JlM2ZtdDlGb3JtYXR0ZXI5d3JpdGVfZm10MTdoNTVhZGViODYxNTYzM2VkMUWSATVfWk40Y29yZTlwYW5pY2tpbmcxM2Fzc2VydF9mYWlsZWQxN2g4OTZkODFlMmU3ZDI3MjAwRZMBNV9aTjRjb3JlOXBhbmlja2luZzEzYXNzZXJ0X2ZhaWxlZDE3aDRhNzEyZTM2ZmQwN2U5ZDdFlAE1X1pONGNvcmU5cGFuaWNraW5nMTNhc3NlcnRfZmFpbGVkMTdoM2NmYmY5MWI2NGRiMzljMEWVAVVfWk41MF8kTFQkJFJGJG11dCR1MjAkVyR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uV3JpdGUkR1QkOXdyaXRlX2ZtdDE3aDBmMzMwMTcwODg4OGU2ZTNFlgFVX1pONTBfJExUJCRSRiRtdXQkdTIwJFckdTIwJGFzJHUyMCRjb3JlLi5mbXQuLldyaXRlJEdUJDl3cml0ZV9mbXQxN2gzYzY0ODYzMzk5NmZlMDc3RZcBVV9aTjUwXyRMVCQkUkYkbXV0JHUyMCRXJHUyMCRhcyR1MjAkY29yZS4uZm10Li5Xcml0ZSRHVCQ5d3JpdGVfZm10MTdoNjA5Zjc0NDg3MTYwNWU4YUWYAVVfWk41MF8kTFQkJFJGJG11dCR1MjAkVyR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uV3JpdGUkR1QkOXdyaXRlX2ZtdDE3aGU5ZThmNDI3ZGJhMWU1N2ZFmQFVX1pONTBfJExUJCRSRiRtdXQkdTIwJFckdTIwJGFzJHUyMCRjb3JlLi5mbXQuLldyaXRlJEdUJDl3cml0ZV9mbXQxN2gwZTQ3NWRiNzM1NDYxZTQ5RZoBMF9aTjRjb3JlM2ZtdDVXcml0ZTl3cml0ZV9mbXQxN2hkMmIzMGJjOGFhNTczYzQ3RZsBLV9aTjNsb2cxNnNldF9ib3hlZF9sb2dnZXIxN2g1YzA4OTg2YmQxZDc2MDNkRZwBMF9aTjRjb3JlM2ZtdDVXcml0ZTl3cml0ZV9mbXQxN2g0OGE0MmFkNzU4OGY0ZWU5RZ0BMF9aTjRjb3JlM2ZtdDVXcml0ZTl3cml0ZV9mbXQxN2g2ZWE0NzQ0ZmU2M2IyMTk1RZ4BaV9aTjY0XyRMVCRzdGQuLnN5cy4ud2FzaS4uc3RkaW8uLlN0ZGVyciR1MjAkYXMkdTIwJHN0ZC4uaW8uLldyaXRlJEdUJDE0d3JpdGVfdmVjdG9yZWQxN2g2OWRkZjM2YTk3OTdhOWFiRZ8BMF9aTjRjb3JlM2ZtdDVXcml0ZTl3cml0ZV9mbXQxN2hjZWU1ZjNmZTQ1M2ZiZmQxRaABBXN0YXRloQE6X1pONWFsbG9jNHN5bmMxMkFyYyRMVCRUJEdUJDlkcm9wX3Nsb3cxN2gxOTI4YzYyNTVmYTMzMDdkRaIBdl9aTjNzdGQyaW81aW1wbHM3NF8kTFQkaW1wbCR1MjAkc3RkLi5pby4uV3JpdGUkdTIwJGZvciR1MjAkYWxsb2MuLnZlYy4uVmVjJExUJHU4JEMkQSRHVCQkR1QkNXdyaXRlMTdoMzk5MTU1OWFhYzY0NzBmMkWjAQtjbGVhcl9zdGF0ZaQBY19aTjcwXyRMVCRjb3JlLi5yZXN1bHQuLlJlc3VsdCRMVCRUJEMkRSRHVCQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2hiZjI5ODBhYmFjYmMxZGU4RaUBfV9aTjkxXyRMVCRzdGQuLnBhbmlja2luZy4uYmVnaW5fcGFuaWMuLlBhbmljUGF5bG9hZCRMVCRBJEdUJCR1MjAkYXMkdTIwJGNvcmUuLnBhbmljLi5Cb3hNZVVwJEdUJDh0YWtlX2JveDE3aGUyYTNiMTY3ZGZhYjliNjBFpgFVX1pONTBfJExUJCRSRiRtdXQkdTIwJFckdTIwJGFzJHUyMCRjb3JlLi5mbXQuLldyaXRlJEdUJDl3cml0ZV9zdHIxN2g4YjdhNTE4MzA2ZWM2M2RiRacBVV9aTjUwXyRMVCQkUkYkbXV0JHUyMCRXJHUyMCRhcyR1MjAkY29yZS4uZm10Li5Xcml0ZSRHVCQ5d3JpdGVfc3RyMTdoMWI2MWEwMjJhZGMyNWRkYkWoAVVfWk41MF8kTFQkJFJGJG11dCR1MjAkVyR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uV3JpdGUkR1QkOXdyaXRlX3N0cjE3aDQ0ODczYjQ2ODNjZjk0M2FFqQF6X1pOM3N0ZDJpbzVpbXBsczc0XyRMVCRpbXBsJHUyMCRzdGQuLmlvLi5Xcml0ZSR1MjAkZm9yJHUyMCRhbGxvYy4udmVjLi5WZWMkTFQkdTgkQyRBJEdUJCRHVCQ5d3JpdGVfYWxsMTdoZThjYzI2MjMwNDQwNmUwYkWqAXNfWk44MF8kTFQkc3RkLi5pby4uV3JpdGUuLndyaXRlX2ZtdC4uQWRhcHRlciRMVCRUJEdUJCR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uV3JpdGUkR1QkOXdyaXRlX3N0cjE3aDkzNmQ4ZTkxYTE1NjhmNThFqwE0X1pONHdhc2kxM2xpYl9nZW5lcmF0ZWQ4ZmRfd3JpdGUxN2g1MDZlNmUxNGE4MGEwYmJiRawBXV9aTjU4XyRMVCRhbGxvYy4uc3RyaW5nLi5TdHJpbmckdTIwJGFzJHUyMCRjb3JlLi5mbXQuLldyaXRlJEdUJDl3cml0ZV9zdHIxN2g1MTY4MGQyM2NjMWU2ZWIxRa0BBHNicmuuAXNfWk40Y29yZTNwdHI4MWRyb3BfaW5fcGxhY2UkTFQkY29yZS4ucmVzdWx0Li5SZXN1bHQkTFQkJExQJCRSUCQkQyRzdGQuLmlvLi5lcnJvci4uRXJyb3IkR1QkJEdUJDE3aGQ4NGFkYWIyYThlNWVjYmFFrwF5X1pONGNvcmUzcHRyODdkcm9wX2luX3BsYWNlJExUJHN0ZC4uaW8uLldyaXRlLi53cml0ZV9mbXQuLkFkYXB0ZXIkTFQkJFJGJG11dCR1MjAkJHU1YiR1OCR1NWQkJEdUJCRHVCQxN2g0ZjQzY2EyMGEwY2JhNmM0RbABDV9fcmRsX3JlYWxsb2OxAQZtZW1jbXCyAUZfWk40Y29yZTNmbXQ5Rm9ybWF0dGVyMTJwYWRfaW50ZWdyYWwxMndyaXRlX3ByZWZpeDE3aDhmMmU0ZmMzZGFhMjYzNzVFswEGZ2V0Y3dktAE6X1pONWFsbG9jNHN5bmMxMkFyYyRMVCRUJEdUJDlkcm9wX3Nsb3cxN2g2YzFmZGI4NjZlMmFlZmQ3RbUBXV9aTjY0XyRMVCRhbGxvYy4uZmZpLi5jX3N0ci4uTnVsRXJyb3IkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2hlOGFiOTlhZDhmZDZiOTA4RbYBLF9aTjRjb3JlOXBhbmlja2luZzVwYW5pYzE3aGVkZjQzNzhlMjA0NjFiMjVFtwE1X1pONGNvcmU5cGFuaWNraW5nMTNwYW5pY19kaXNwbGF5MTdoNjE0YmNmYTcyMzZmOTFhYUW4AX9fWk45M18kTFQkc3RkLi5wYW5pY2tpbmcuLmJlZ2luX3BhbmljX2hhbmRsZXIuLlN0clBhbmljUGF5bG9hZCR1MjAkYXMkdTIwJGNvcmUuLnBhbmljLi5Cb3hNZVVwJEdUJDh0YWtlX2JveDE3aGNmODc3ZmRiMGZjY2Q1NjFFuQFgX1pONGNvcmUzZm10NWZsb2F0NTJfJExUJGltcGwkdTIwJGNvcmUuLmZtdC4uRGlzcGxheSR1MjAkZm9yJHUyMCRmNjQkR1QkM2ZtdDE3aDY1NDMyN2NkNmY5ZWM1YTJFugERcnVzdF9iZWdpbl91bndpbmS7AThfWk41YWxsb2M3cmF3X3ZlYzE3Y2FwYWNpdHlfb3ZlcmZsb3cxN2hjYTIzZTA2MDBhOTUzNGY2RbwBMF9aTjRjb3JlOXBhbmlja2luZzlwYW5pY19mbXQxN2g3YTY1MWM3MGE5NDkyMjhjRb0BKl9aTjEyY2FsY19zZXJ2aWNlNG1haW4xN2gwY2E3NWE5OTZkODFiYTczRb4BVV9aTjU2XyRMVCRsb2cuLlNldExvZ2dlckVycm9yJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EZWJ1ZyRHVCQzZm10MTdoNjUyYzYxNzYzODg0NTJhMkW/AUdfWk40Ml8kTFQkJFJGJFQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2gzZWJjMzNmYzA3ZjQwZmRmRcABYV9aTjY4XyRMVCRzdGQuLnRocmVhZC4ubG9jYWwuLkFjY2Vzc0Vycm9yJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EZWJ1ZyRHVCQzZm10MTdoNTE3ZjAxOTlmNzk2OWU0ZEXBAWlfWk43Nl8kTFQkc3RkLi5zeW5jLi5wb2lzb24uLlBvaXNvbkVycm9yJExUJFQkR1QkJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EZWJ1ZyRHVCQzZm10MTdoMTdhNDJkMjNlOGVjMWJjZEXCAUdfWk40Ml8kTFQkJFJGJFQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2g1Y2M3Njk4N2QxYWY4YzljRcMBR19aTjQyXyRMVCQkUkYkVCR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uRGVidWckR1QkM2ZtdDE3aGMxOGRkNjA0OTVjZWZlMDBFxAEPX19vcmlnaW5hbF9tYWluxQFhX1pOM3N0ZDJydDEwbGFuZ19zdGFydDI4XyR1N2IkJHU3YiRjbG9zdXJlJHU3ZCQkdTdkJDE3aDY5ZmNlMWZmZGI2ZjVhOThFLmxsdm0uNzEzOTI0MTQxMTY3NDgxMjc1M8YBc19aTjRjb3JlM29wczhmdW5jdGlvbjZGbk9uY2U0MGNhbGxfb25jZSR1N2IkJHU3YiR2dGFibGUuc2hpbSR1N2QkJHU3ZCQxN2gyMjFjZWNjMmEwOGQ2ZTM4RS5sbHZtLjcxMzkyNDE0MTE2NzQ4MTI3NTPHAYoBX1pONGNvcmUzcHRyMTAzZHJvcF9pbl9wbGFjZSRMVCRzdGQuLnN5bmMuLnBvaXNvbi4uUG9pc29uRXJyb3IkTFQkc3RkLi5zeW5jLi5tdXRleC4uTXV0ZXhHdWFyZCRMVCQkTFAkJFJQJCRHVCQkR1QkJEdUJDE3aGEzYjY1YzIyMDJlZDhjOWNFyAFQX1pOM3N0ZDlwYW5pY2tpbmcxMWJlZ2luX3BhbmljMjhfJHU3YiQkdTdiJGNsb3N1cmUkdTdkJCR1N2QkMTdoM2ZhOWYwYzVkM2JkNzBmZEXJATJfWk40Y29yZTNzdHIxNnNsaWNlX2Vycm9yX2ZhaWwxN2hkNGY4MTcyYTA1YjExYTk5RcoBLl9aTjRjb3JlM2ZtdDlGb3JtYXR0ZXIzbmV3MTdoNDkxOGE3OWU1NTQyN2Y4OEXLAThfWk40Y29yZTNmbXQ5Rm9ybWF0dGVyMTJkZWJ1Z19zdHJ1Y3QxN2g5N2UxYzNkYjQ0YzU5YmE3RcwBNl9aTjRjb3JlM2ZtdDlGb3JtYXR0ZXIxMGRlYnVnX2xpc3QxN2hjZmE0NmI2NDgxODczMjEyRc0BXF9aTjRjb3JlM2ZtdDNudW01MF8kTFQkaW1wbCR1MjAkY29yZS4uZm10Li5EZWJ1ZyR1MjAkZm9yJHUyMCR1MTYkR1QkM2ZtdDE3aGRjNTNlOTE1M2E4MGM4ZWFFzgFaX1pONGNvcmUzb3BzOGZ1bmN0aW9uNkZuT25jZTQwY2FsbF9vbmNlJHU3YiQkdTdiJHZ0YWJsZS5zaGltJHU3ZCQkdTdkJDE3aGIwYzFkNzhjYWUyM2M5ODFFzwE6X1pONGNvcmUzZm10OGJ1aWxkZXJzOURlYnVnTGlzdDZmaW5pc2gxN2hjNmJlNTZkZDZiZDQxYWVkRdABMl9aTjNzdGQ5cGFuaWNraW5nMTFiZWdpbl9wYW5pYzE3aGQ2N2I5NTY5NmM3ZjRmZjVF0QFoX1pONGNvcmUzcHRyNzBkcm9wX2luX3BsYWNlJExUJHN0ZC4ucGFuaWNraW5nLi5iZWdpbl9wYW5pY19oYW5kbGVyLi5QYW5pY1BheWxvYWQkR1QkMTdoNGI1ODNhYTM0NDIzYzUwMkXSATBfWk40Y29yZTlwYW5pY2tpbmc5cGFuaWNfc3RyMTdoZTE2NDQzMDcwMTk4OGU1YUXTAQtfX3JkbF9hbGxvY9QBNl9aTjR3YXNpMTNsaWJfZ2VuZXJhdGVkNUVycm5vNG5hbWUxN2hmZDJlOWQ1YjM5NGFhNzljRdUBOV9aTjR3YXNpMTNsaWJfZ2VuZXJhdGVkNUVycm5vN21lc3NhZ2UxN2hlNjQ0MWI5OTQ1ZjI4YjM0RdYBBnN0cmR1cNcBTF9aTjRjb3JlM3B0cjQyZHJvcF9pbl9wbGFjZSRMVCRhbGxvYy4uc3RyaW5nLi5TdHJpbmckR1QkMTdoYzI0MWFmNWJhYTA2M2RkM0XYAYUCX1pONGNvcmUzcHRyMjI2ZHJvcF9pbl9wbGFjZSRMVCRzdGQuLmVycm9yLi4kTFQkaW1wbCR1MjAkY29yZS4uY29udmVydC4uRnJvbSRMVCRhbGxvYy4uc3RyaW5nLi5TdHJpbmckR1QkJHUyMCRmb3IkdTIwJGFsbG9jLi5ib3hlZC4uQm94JExUJGR5biR1MjAkc3RkLi5lcnJvci4uRXJyb3IkdTJiJGNvcmUuLm1hcmtlci4uU3luYyR1MmIkY29yZS4ubWFya2VyLi5TZW5kJEdUJCRHVCQuLmZyb20uLlN0cmluZ0Vycm9yJEdUJDE3aGU0NzcyOTQ5NTNmOTJhZWNF2QFIX1pONDNfJExUJGJvb2wkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRpc3BsYXkkR1QkM2ZtdDE3aGExY2M5ZWEzZDEyZGRjNDJF2gF4X1pOOTFfJExUJHN0ZC4ucGFuaWNraW5nLi5iZWdpbl9wYW5pYy4uUGFuaWNQYXlsb2FkJExUJEEkR1QkJHUyMCRhcyR1MjAkY29yZS4ucGFuaWMuLkJveE1lVXAkR1QkM2dldDE3aDliMDdiZjIyZThiZTZkYjdF2wE/X1pONWFsbG9jNnN0cmluZzEzRnJvbVV0ZjhFcnJvcjEwaW50b19ieXRlczE3aGExN2RmMTk0OGI3Njc4NGVF3AEIcnVzdF9vb23dATdfWk40d2FzaTEzbGliX2dlbmVyYXRlZDEwcmFuZG9tX2dldDE3aDkxN2JjYWNhOWU5YWY4MGNF3gENYWxpZ25lZF9hbGxvY98BTl9aTjE4bWFyaW5lX3JzX3Nka19tYWluNnJlc3VsdDE4T0JKRUNUU19UT19SRUxFQVNFN19fZ2V0aXQxN2hjYjA2MGU1MmVlNWY5NTU4ReABO19aTjRjb3JlMTBpbnRyaW5zaWNzMTdjb25zdF9ldmFsX3NlbGVjdDE3aGQ1YWZmYTBjOWNlZTZlY2VF4QFcX1pONjNfJExUJGNvcmUuLmNlbGwuLkJvcnJvd011dEVycm9yJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EZWJ1ZyRHVCQzZm10MTdoMTI0MmQ5MTEyNjQ3MTI4MkXiAVJfWk41M18kTFQkY29yZS4uZm10Li5FcnJvciR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uRGVidWckR1QkM2ZtdDE3aGE2MGRhOGViOWMxMzQ5MThF4wE7X1pONGNvcmU2b3B0aW9uMTVPcHRpb24kTFQkVCRHVCQ2dW53cmFwMTdoNDRhNDBjZDU2YTcyNGUxY0XkATtfWk40Y29yZTZvcHRpb24xNU9wdGlvbiRMVCRUJEdUJDZ1bndyYXAxN2hiYzljMDJjZGNkZGNlMDE0ReUBBl9zdGFydOYBDl9fcnVzdF9yZWFsbG9j5wFNX1pOM3N0ZDEwc3lzX2NvbW1vbjliYWNrdHJhY2UyNl9fcnVzdF9lbmRfc2hvcnRfYmFja3RyYWNlMTdoODU1MzJmMzkwZGFlYWM0ZUXoAU1fWk4zc3RkMTBzeXNfY29tbW9uOWJhY2t0cmFjZTI2X19ydXN0X2VuZF9zaG9ydF9iYWNrdHJhY2UxN2g3M2E0M2YzOGI1ZTZlZTA5RekBSV9aTjQ0XyRMVCQkUkYkVCR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uRGlzcGxheSRHVCQzZm10MTdoMDY3YzhlZGUyYTNmYmQ3YkXqARlfX3dhc2lsaWJjX2Vuc3VyZV9lbnZpcm9u6wFHX1pONDJfJExUJCRSRiRUJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EZWJ1ZyRHVCQzZm10MTdoMjAwNWIzMWM4OTYxOTIxOUXsAQxfX3J1c3RfYWxsb2PtAUlfWk40NF8kTFQkJFJGJFQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRpc3BsYXkkR1QkM2ZtdDE3aGEwOGZhZjdmN2M3MTgyNzNF7gFXX1pONTBfJExUJCRSRiRtdXQkdTIwJFckdTIwJGFzJHUyMCRjb3JlLi5mbXQuLldyaXRlJEdUJDEwd3JpdGVfY2hhcjE3aDQyNTAzNDBiM2FjZTQyYzJF7wF6X1pOOTNfJExUJHN0ZC4ucGFuaWNraW5nLi5iZWdpbl9wYW5pY19oYW5kbGVyLi5TdHJQYW5pY1BheWxvYWQkdTIwJGFzJHUyMCRjb3JlLi5wYW5pYy4uQm94TWVVcCRHVCQzZ2V0MTdoN2VkNjU2ZThmZjhjNmIzZkXwAUdfWk40Ml8kTFQkJFJGJFQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2g0MWQzYTA2OTc1OTMzNTc1RfEBOl9aTjRjb3JlM29wczhmdW5jdGlvbjZGbk9uY2U5Y2FsbF9vbmNlMTdoYjdiZDgyYzY0MzM2OTI0Y0XyAUlfWk40NF8kTFQkJFJGJFQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRpc3BsYXkkR1QkM2ZtdDE3aGFjMGZkZjAzZWE5ODFmMmVF8wE7X1pONGNvcmUzZm10OUZvcm1hdHRlcjE1ZGVidWdfbG93ZXJfaGV4MTdoMzVkZWQxZDc5NGVhNWQ3MkX0ATtfWk40Y29yZTNmbXQ5Rm9ybWF0dGVyMTVkZWJ1Z191cHBlcl9oZXgxN2hmOWY5MmFjYTFlNTBkZDExRfUBDl9fcnVzdF9kZWFsbG9j9gFHX1pONDJfJExUJCRSRiRUJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EZWJ1ZyRHVCQzZm10MTdoNGNmYzczNWI4NDgyYmNjYUX3AVVfWk41MF8kTFQkJFJGJG11dCR1MjAkVyR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uV3JpdGUkR1QkOXdyaXRlX3N0cjE3aDRjMmI3MDQ4N2EzZmQxMzVF+AESX193YXNpX2Vudmlyb25fZ2V0+QEYX193YXNpX2Vudmlyb25fc2l6ZXNfZ2V0+gEEZXhpdPsBBnN0cmNwefwBOl9aTjRjb3JlM29wczhmdW5jdGlvbjZGbk9uY2U5Y2FsbF9vbmNlMTdoYzVhODdmYmI0MDFhN2VlZUX9AWJfWk40Y29yZTNmbXQzbnVtM2ltcDUyXyRMVCRpbXBsJHUyMCRjb3JlLi5mbXQuLkRpc3BsYXkkdTIwJGZvciR1MjAkdTMyJEdUJDNmbXQxN2hkNGI2ZmZjOGEwYzdlMzUyRf4BMl9aTjRjb3JlNm9wdGlvbjEzZXhwZWN0X2ZhaWxlZDE3aGI3ZWRkYzVhMTkzN2U2YmJF/wE4X1pONGNvcmUzZm10OGJ1aWxkZXJzOERlYnVnU2V0NWVudHJ5MTdoMDE0ZjlkNmYyZGMyZTQ2Y0WAAlVfWk41MF8kTFQkJFJGJG11dCR1MjAkVyR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uV3JpdGUkR1QkOXdyaXRlX3N0cjE3aDIxODAyY2EzZjM4MTRlZGZFgQJhX1pONGNvcmUzZm10M251bTNpbXA1MV8kTFQkaW1wbCR1MjAkY29yZS4uZm10Li5EaXNwbGF5JHUyMCRmb3IkdTIwJHU4JEdUJDNmbXQxN2g0MDBmMWYyNmZmMzI2Y2I2RYICYl9aTjRjb3JlM2ZtdDNudW0zaW1wNTJfJExUJGltcGwkdTIwJGNvcmUuLmZtdC4uRGlzcGxheSR1MjAkZm9yJHUyMCR1MTYkR1QkM2ZtdDE3aDI1NDk4MTU3MWU3OTU5NThFgwITbWFpbi5jb21tYW5kX2V4cG9ydIQCF2FsbG9jYXRlLmNvbW1hbmRfZXhwb3J0hQIaX19ydXN0X2FsbG9jX2Vycm9yX2hhbmRsZXKGAkdfWk40Ml8kTFQkJFJGJFQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2gzYTIzMzM0ODlkZDVlNjM4RYcCR19aTjQyXyRMVCQkUkYkVCR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uRGVidWckR1QkM2ZtdDE3aDBlOGZhNTFlM2UyYzJkZDBFiAJHX1pONDJfJExUJCRSRiRUJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EZWJ1ZyRHVCQzZm10MTdoZmNmMWQ4NDAxZWIxNzQwZkWJAklfWk40NF8kTFQkJFJGJFQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRpc3BsYXkkR1QkM2ZtdDE3aGI5ODMxNTk5NGYxODYwMmVFigJXX1pONTBfJExUJCRSRiRtdXQkdTIwJFckdTIwJGFzJHUyMCRjb3JlLi5mbXQuLldyaXRlJEdUJDEwd3JpdGVfY2hhcjE3aDZkOTY1Mjc3MmE3ZmE1YjhFiwI7X1pONGNvcmUxMGludHJpbnNpY3MxN2NvbnN0X2V2YWxfc2VsZWN0MTdoNzRlNzg5ZDUzNmFlMDYyYkWMAjpfWk40Y29yZTNvcHM4ZnVuY3Rpb242Rm5PbmNlOWNhbGxfb25jZTE3aGViYTk2ODMwZjRlYzc1YzdFjQJAX1pONWFsbG9jNWFsbG9jMThoYW5kbGVfYWxsb2NfZXJyb3I4cnRfZXJyb3IxN2hmMjhjYTFkNDc1YWU3OTQ4RY4CN19aTjVhbGxvYzVhbGxvYzE4aGFuZGxlX2FsbG9jX2Vycm9yMTdoMWVlMWNjZmRhZmU2YTQwYUWPAghfX3JnX29vbZACOl9aTjRjb3JlM29wczhmdW5jdGlvbjZGbk9uY2U5Y2FsbF9vbmNlMTdoMjQ4ZGJjYjIwNGNjMTRlNUWRAjpfWk40Y29yZTNvcHM4ZnVuY3Rpb242Rm5PbmNlOWNhbGxfb25jZTE3aDM4ZjFhYjY0YjJjZWM1MTRFkgI6X1pONGNvcmUzb3BzOGZ1bmN0aW9uNkZuT25jZTljYWxsX29uY2UxN2hkNWU1NThhODE1YzU0YWU3RZMCRF9aTjRjb3JlNXNsaWNlNWluZGV4MjZzbGljZV9zdGFydF9pbmRleF9sZW5fZmFpbDE3aDIzMWE0NDJlYWUyMDBkNmJFlAJCX1pONGNvcmU1c2xpY2U1aW5kZXgyNHNsaWNlX2VuZF9pbmRleF9sZW5fZmFpbDE3aGM5Mjg4ZWViMTkyN2M4ZDdFlQJAX1pONGNvcmU1c2xpY2U1aW5kZXgyMnNsaWNlX2luZGV4X29yZGVyX2ZhaWwxN2hmMTc0ZTA1NWFlNTMzNzNmRZYCO19aTjRjb3JlMTBpbnRyaW5zaWNzMTdjb25zdF9ldmFsX3NlbGVjdDE3aDA0MzllMDIyMmZhMjQ3MGFFlwI7X1pONGNvcmUxMGludHJpbnNpY3MxN2NvbnN0X2V2YWxfc2VsZWN0MTdoNDExYTg0ZjM2ODM4NWFmYUWYAjtfWk40Y29yZTEwaW50cmluc2ljczE3Y29uc3RfZXZhbF9zZWxlY3QxN2hlMDQxN2M3NjBiNGFhOTA3RZkCQF9aTjRjb3JlNXBhbmljMTBwYW5pY19pbmZvOVBhbmljSW5mbzdwYXlsb2FkMTdoNjk5YTNkYmZlZDIxMGQyNkWaAkdfWk40Ml8kTFQkc3RyJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EaXNwbGF5JEdUJDNmbXQxN2hiYTZmZTJhY2Q1NTE0YzJkRZsCR19aTjQyXyRMVCQkUkYkVCR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uRGVidWckR1QkM2ZtdDE3aDdiMWQzZDMzMGE3YTgxMzFFnAISYWRkLmNvbW1hbmRfZXhwb3J0nQIXc3VidHJhY3QuY29tbWFuZF9leHBvcnSeAhdtdWx0aXBseS5jb21tYW5kX2V4cG9ydJ8CFWRpdmlkZS5jb21tYW5kX2V4cG9ydKACHXNldF9yZXN1bHRfcHRyLmNvbW1hbmRfZXhwb3J0oQIec2V0X3Jlc3VsdF9zaXplLmNvbW1hbmRfZXhwb3J0ogJFX1pOM3N0ZDlwYW5pY2tpbmcxMXBhbmljX2NvdW50MTdpc196ZXJvX3Nsb3dfcGF0aDE3aGZmNzI3ZTc1ODE2MThkNTVFowJ2X1pOM3N0ZDJpbzVpbXBsczc0XyRMVCRpbXBsJHUyMCRzdGQuLmlvLi5Xcml0ZSR1MjAkZm9yJHUyMCRhbGxvYy4udmVjLi5WZWMkTFQkdTgkQyRBJEdUJCRHVCQ1Zmx1c2gxN2hiNDY5NDA3NmQwNWYyYjhiRaQCX19aTjY0XyRMVCRzdGQuLnN5cy4ud2FzaS4uc3RkaW8uLlN0ZGVyciR1MjAkYXMkdTIwJHN0ZC4uaW8uLldyaXRlJEdUJDVmbHVzaDE3aDgzMzY1ZTNiMTQ1ZDA4NzZFpQIQX193YXNpX3Byb2NfZXhpdKYCBV9FeGl0pwIOc2V0X3Jlc3VsdF9wdHKoAg9zZXRfcmVzdWx0X3NpemWpAhVfc3RhcnQuY29tbWFuZF9leHBvcnSqAhh0ZXN0X2xvZ3MuY29tbWFuZF9leHBvcnSrAhpjbGVhcl9zdGF0ZS5jb21tYW5kX2V4cG9ydKwCFHN0YXRlLmNvbW1hbmRfZXhwb3J0rQIdZ2V0X3Jlc3VsdF9wdHIuY29tbWFuZF9leHBvcnSuAh5nZXRfcmVzdWx0X3NpemUuY29tbWFuZF9leHBvcnSvAh5yZWxlYXNlX29iamVjdHMuY29tbWFuZF9leHBvcnSwAk9fWk4zc3RkMTBzeXNfY29tbW9uOWJhY2t0cmFjZTI4X19ydXN0X2JlZ2luX3Nob3J0X2JhY2t0cmFjZTE3aDNkMTVlZmZkMDg2MzYzOTJFsQI0X1pOM3N0ZDNzeXM0d2FzaTE0YWJvcnRfaW50ZXJuYWwxN2hlMjU0NWYwYjAyYmQzNjJkRbICKV9aTjNzdGQ3cHJvY2VzczVhYm9ydDE3aDRjYzRjY2QwZjViZGM4OTFFswINX19yZGxfZGVhbGxvY7QCPF9aTjNzdGQzc3lzNHdhc2k3cHJvY2VzczhFeGl0Q29kZTZhc19pMzIxN2g2OWY4NTg2MjEzYzJlNmQ3RbUCNV9aTjR3YXNpMTNsaWJfZ2VuZXJhdGVkNUVycm5vM3JhdzE3aDg4MzgzNDkzOTY4NGE4YTlFtgIGbWFsbG9jtwIEZnJlZbgCEV9fd2FzbV9jYWxsX2R0b3JzuQJAX1pONGNvcmU1cGFuaWMxMHBhbmljX2luZm85UGFuaWNJbmZvN21lc3NhZ2UxN2hhMDI2YTM3Zjc1MTM1NGFjRboCQV9aTjRjb3JlNXBhbmljMTBwYW5pY19pbmZvOVBhbmljSW5mbzhsb2NhdGlvbjE3aDU5NzNiODU1YTE4N2E5ZDZFuwJEX1pONGNvcmU1cGFuaWMxMHBhbmljX2luZm85UGFuaWNJbmZvMTBjYW5fdW53aW5kMTdoMjFiZGQ3NTAyZDZlMzVlZkW8Ag5nZXRfcmVzdWx0X3B0cr0CD2dldF9yZXN1bHRfc2l6Zb4CD3JlbGVhc2Vfb2JqZWN0c78CEV9fd2FzbV9jYWxsX2N0b3JzwAIEbWFpbsECTF9aTjQzXyRMVCRsb2cuLk5vcExvZ2dlciR1MjAkYXMkdTIwJGxvZy4uTG9nJEdUJDdlbmFibGVkMTdoNzAwNDJmODk4NmE2NWU5N0XCAkVfWk4zNl8kTFQkVCR1MjAkYXMkdTIwJGNvcmUuLmFueS4uQW55JEdUJDd0eXBlX2lkMTdoZDg0ZjVlZGUwYzY3ZTAxZUXDAkVfWk4zNl8kTFQkVCR1MjAkYXMkdTIwJGNvcmUuLmFueS4uQW55JEdUJDd0eXBlX2lkMTdoMzAyYzRiYTdiZTViNzY4NUXEAkVfWk4zNl8kTFQkVCR1MjAkYXMkdTIwJGNvcmUuLmFueS4uQW55JEdUJDd0eXBlX2lkMTdoM2RmZjNmOTA0ZTRlMmJiMkXFAkVfWk4zNl8kTFQkVCR1MjAkYXMkdTIwJGNvcmUuLmFueS4uQW55JEdUJDd0eXBlX2lkMTdoNjc4M2NkNzgyNGFlZDY4NEXGAoMBX1pOM3N0ZDJpbzVpbXBsczc0XyRMVCRpbXBsJHUyMCRzdGQuLmlvLi5Xcml0ZSR1MjAkZm9yJHUyMCRhbGxvYy4udmVjLi5WZWMkTFQkdTgkQyRBJEdUJCRHVCQxN2lzX3dyaXRlX3ZlY3RvcmVkMTdoNzIzMmUyNTQwZWU5MjVjOEXHAmxfWk42NF8kTFQkc3RkLi5zeXMuLndhc2kuLnN0ZGlvLi5TdGRlcnIkdTIwJGFzJHUyMCRzdGQuLmlvLi5Xcml0ZSRHVCQxN2lzX3dyaXRlX3ZlY3RvcmVkMTdoMDY5YjFmODgzMGU4MzZkZUXIAhJfX3J1c3Rfc3RhcnRfcGFuaWPJAiVfX3dhc2lsaWJjX2luaXRpYWxpemVfZW52aXJvbl9lYWdlcmx5ygIFYWJvcnTLAkVfWk4zNl8kTFQkVCR1MjAkYXMkdTIwJGNvcmUuLmFueS4uQW55JEdUJDd0eXBlX2lkMTdoYTc4MjMzN2Y2YzZlYWNmOUXMAkpfWk40Y29yZTNwdHI0MGRyb3BfaW5fcGxhY2UkTFQkbG9nLi5TZXRMb2dnZXJFcnJvciRHVCQxN2hhOWVlYTFjZGFhNmZkNGVmRc0CkAFfWk40Y29yZTNwdHI4NWRyb3BfaW5fcGxhY2UkTFQkc3RkLi5ydC4ubGFuZ19zdGFydCRMVCQkTFAkJFJQJCRHVCQuLiR1N2IkJHU3YiRjbG9zdXJlJHU3ZCQkdTdkJCRHVCQxN2gxNWUxZWJkMGFkYzg5ZWIyRS5sbHZtLjcxMzkyNDE0MTE2NzQ4MTI3NTPOAlhfWk40Y29yZTNwdHI1NGRyb3BfaW5fcGxhY2UkTFQkJFJGJG11dCR1MjAkYWxsb2MuLnN0cmluZy4uU3RyaW5nJEdUJDE3aDI2OWU0NDFiNTA0NmVjMjlFzwJHX1pONGNvcmUzcHRyMzdkcm9wX2luX3BsYWNlJExUJGNvcmUuLmZtdC4uRXJyb3IkR1QkMTdoZGM2NzQxY2U1YjMyZGVmM0XQAmJfWk42N18kTFQkbWFyaW5lX3JzX3Nka19tYWluLi5sb2dnZXIuLldhc21Mb2dnZXIkdTIwJGFzJHUyMCRsb2cuLkxvZyRHVCQ1Zmx1c2gxN2hjNTU5OWU5YWZhMDQ3YTg3RdECQl9aTjRjb3JlM3B0cjMyZHJvcF9pbl9wbGFjZSRMVCQkUkYkJFJGJHN0ciRHVCQxN2g5YzYyM2JkNTFiNzk1YTYxRdICSF9aTjQzXyRMVCRsb2cuLk5vcExvZ2dlciR1MjAkYXMkdTIwJGxvZy4uTG9nJEdUJDNsb2cxN2g4NzI1YjgwOTY1NWJjMjEyRdMCSl9aTjQzXyRMVCRsb2cuLk5vcExvZ2dlciR1MjAkYXMkdTIwJGxvZy4uTG9nJEdUJDVmbHVzaDE3aDQ4MmNhZTIzZWMzYWZiNTRF1AJvX1pONGNvcmUzcHRyNzdkcm9wX2luX3BsYWNlJExUJHN0ZC4ucGFuaWNraW5nLi5iZWdpbl9wYW5pYy4uUGFuaWNQYXlsb2FkJExUJCRSRiRzdHIkR1QkJEdUJDE3aGIyMTFiMWMzNmZlYzM2ZThF1QI+X1pONGNvcmUzcHRyMjhkcm9wX2luX3BsYWNlJExUJCRSRiRzdHIkR1QkMTdoNjJiZTY3ZWM0ODNiMGVhZUXWAocBX1pONGNvcmUzcHRyMTAwZHJvcF9pbl9wbGFjZSRMVCQkUkYkbXV0JHUyMCRzdGQuLmlvLi5Xcml0ZS4ud3JpdGVfZm10Li5BZGFwdGVyJExUJGFsbG9jLi52ZWMuLlZlYyRMVCR1OCRHVCQkR1QkJEdUJDE3aDU4Y2JlYzFiOGUyNGE4MDZF1wI5X1pONGNvcmUzcHRyMjNkcm9wX2luX3BsYWNlJExUJHU4JEdUJDE3aDExMjIyOTU3MGNhOWEwMTZF2AIFZHVtbXnZAj1fWk40Y29yZTNwdHIyN2Ryb3BfaW5fcGxhY2UkTFQkJFJGJHU4JEdUJDE3aGE0YmY1OGZjMWU2YmI5YzhF2gKJAV9aTjRjb3JlM3B0cjEwMmRyb3BfaW5fcGxhY2UkTFQkJFJGJGNvcmUuLml0ZXIuLmFkYXB0ZXJzLi5jb3BpZWQuLkNvcGllZCRMVCRjb3JlLi5zbGljZS4uaXRlci4uSXRlciRMVCR1OCRHVCQkR1QkJEdUJDE3aGRkZDAxNjVkMjVmNWVjNTRF2wJrX1pONGNvcmUzcHRyNDdkcm9wX2luX3BsYWNlJExUJGNvcmUuLmNlbGwuLkJvcnJvd011dEVycm9yJEdUJDE3aDdjNWJmNDRiNmE2ZDBiOTZFLmxsdm0uMTU3Nzc2NDg0NDA1MzUyNzMyMTQA8ICAgAAJcHJvZHVjZXJzAghsYW5ndWFnZQEEUnVzdAAMcHJvY2Vzc2VkLWJ5AwVjbGFuZwYxNC4wLjAFcnVzdGMlMS42NC4wLW5pZ2h0bHkgKDgzMDg4MDY0MCAyMDIyLTA2LTI4KQZ3YWxydXMGMC4xOS4wAKqBgIAAHV9fbV9nZW5lcmF0ZWRfc2VjdGlvbl9fZGl2aWRleyJhc3RfdHlwZSI6IkZ1bmN0aW9uIiwic2lnbmF0dXJlIjp7Im5hbWUiOiJkaXZpZGUiLCJhcmd1bWVudHMiOlt7Im5hbWUiOiJudW0iLCJ0eSI6eyJGNjQiOiJCeVZhbHVlIn19XSwib3V0cHV0X3R5cGVzIjpbeyJGNjQiOiJCeVZhbHVlIn1dfX0AroGAgAAfX19tX2dlbmVyYXRlZF9zZWN0aW9uX19tdWx0aXBseXsiYXN0X3R5cGUiOiJGdW5jdGlvbiIsInNpZ25hdHVyZSI6eyJuYW1lIjoibXVsdGlwbHkiLCJhcmd1bWVudHMiOlt7Im5hbWUiOiJudW0iLCJ0eSI6eyJGNjQiOiJCeVZhbHVlIn19XSwib3V0cHV0X3R5cGVzIjpbeyJGNjQiOiJCeVZhbHVlIn1dfX0Ag4GAgAAcX19tX2dlbmVyYXRlZF9zZWN0aW9uX19zdGF0ZXsiYXN0X3R5cGUiOiJGdW5jdGlvbiIsInNpZ25hdHVyZSI6eyJuYW1lIjoic3RhdGUiLCJhcmd1bWVudHMiOltdLCJvdXRwdXRfdHlwZXMiOlt7IkY2NCI6IkJ5VmFsdWUifV19fQD+gICAACJfX21fZ2VuZXJhdGVkX3NlY3Rpb25fX2NsZWFyX3N0YXRleyJhc3RfdHlwZSI6IkZ1bmN0aW9uIiwic2lnbmF0dXJlIjp7Im5hbWUiOiJjbGVhcl9zdGF0ZSIsImFyZ3VtZW50cyI6W10sIm91dHB1dF90eXBlcyI6W119fQCugYCAAB9fX21fZ2VuZXJhdGVkX3NlY3Rpb25fX3N1YnRyYWN0eyJhc3RfdHlwZSI6IkZ1bmN0aW9uIiwic2lnbmF0dXJlIjp7Im5hbWUiOiJzdWJ0cmFjdCIsImFyZ3VtZW50cyI6W3sibmFtZSI6Im51bSIsInR5Ijp7IkY2NCI6IkJ5VmFsdWUifX1dLCJvdXRwdXRfdHlwZXMiOlt7IkY2NCI6IkJ5VmFsdWUifV19fQCkgYCAABpfX21fZ2VuZXJhdGVkX3NlY3Rpb25fX2FkZHsiYXN0X3R5cGUiOiJGdW5jdGlvbiIsInNpZ25hdHVyZSI6eyJuYW1lIjoiYWRkIiwiYXJndW1lbnRzIjpbeyJuYW1lIjoibnVtIiwidHkiOnsiRjY0IjoiQnlWYWx1ZSJ9fV0sIm91dHB1dF90eXBlcyI6W3siRjY0IjoiQnlWYWx1ZSJ9XX19APqAgIAAIF9fbV9nZW5lcmF0ZWRfc2VjdGlvbl9fdGVzdF9sb2dzeyJhc3RfdHlwZSI6IkZ1bmN0aW9uIiwic2lnbmF0dXJlIjp7Im5hbWUiOiJ0ZXN0X2xvZ3MiLCJhcmd1bWVudHMiOltdLCJvdXRwdXRfdHlwZXMiOltdfX0A/4KAgAAPaW50ZXJmYWNlLXR5cGVzBQYwLjI0LjEAFAABBHNpemUMAQwAAAAAAAEMAAABDAABC3Jlc3VsdF9zaXplDAAAAQpyZXN1bHRfcHRyDAAAAQNudW0JAQkAAQNudW0JAQkAAQNudW0JAQkAAQNudW0JAQkAAAEJAAABCQAAAAAAAAABA251bQkBCQABA251bQkBCQABA251bQkBCQABA251bQkBCQAAAAAAAAIHBgIAAAEGCAIAAAEHCgEBCAwBAQkOAgAAAQoQAgAAAQsSAQEMAw0IYWxsb2NhdGUAD3JlbGVhc2Vfb2JqZWN0cwEPZ2V0X3Jlc3VsdF9zaXplAg5nZXRfcmVzdWx0X3B0cgMPc2V0X3Jlc3VsdF9zaXplBA5zZXRfcmVzdWx0X3B0cgUGZGl2aWRlBwhtdWx0aXBseQkFc3RhdGULC2NsZWFyX3N0YXRlDQhzdWJ0cmFjdA8DYWRkEQl0ZXN0X2xvZ3MTBAcHBgkICwoNDA8OERATEgCcgICAABVfX2ZsdWVuY2Vfc2RrX3ZlcnNpb24wLjYuMTU="; diff --git a/packages/@tests/smoke/node/src/index.ts b/packages/@tests/smoke/node/src/index.ts index 3040537d8..6b5cfc4e6 100644 --- a/packages/@tests/smoke/node/src/index.ts +++ b/packages/@tests/smoke/node/src/index.ts @@ -1,4 +1,22 @@ -import '@fluencelabs/js-client'; -import { runTest } from '@test/aqua_for_test'; +/** + * 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. + */ -runTest().then(() => console.log('Smoke tests succeed!')); +import "@fluencelabs/js-client"; +import { runTest } from "@test/aqua_for_test"; + +runTest().then(() => { + return console.log("Smoke tests succeed!"); +}); diff --git a/packages/@tests/smoke/web-cra-ts/package.json b/packages/@tests/smoke/web-cra-ts/package.json index 2cd242d0e..841fc45b6 100644 --- a/packages/@tests/smoke/web-cra-ts/package.json +++ b/packages/@tests/smoke/web-cra-ts/package.json @@ -15,7 +15,6 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-scripts": "5.0.1", - "typescript": "4.9.5", "web-vitals": "2.1.4" }, "devDependencies": { diff --git a/packages/@tests/smoke/web-cra-ts/src/App.css b/packages/@tests/smoke/web-cra-ts/src/App.css index 74b5e0534..78b8850cf 100644 --- a/packages/@tests/smoke/web-cra-ts/src/App.css +++ b/packages/@tests/smoke/web-cra-ts/src/App.css @@ -1,38 +1,38 @@ .App { - text-align: center; + text-align: center; } .App-logo { - height: 40vmin; - pointer-events: none; + height: 40vmin; + pointer-events: none; } @media (prefers-reduced-motion: no-preference) { - .App-logo { - animation: App-logo-spin infinite 20s linear; - } + .App-logo { + animation: App-logo-spin infinite 20s linear; + } } .App-header { - background-color: #282c34; - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; + background-color: #282c34; + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: calc(10px + 2vmin); + color: white; } .App-link { - color: #61dafb; + color: #61dafb; } @keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } } diff --git a/packages/@tests/smoke/web-cra-ts/src/App.tsx b/packages/@tests/smoke/web-cra-ts/src/App.tsx index ba9d1e000..e4fb0a3fb 100644 --- a/packages/@tests/smoke/web-cra-ts/src/App.tsx +++ b/packages/@tests/smoke/web-cra-ts/src/App.tsx @@ -1,7 +1,7 @@ -import { runTest, TestResult } from '@test/aqua_for_test'; -import React from 'react'; -import logo from './logo.svg'; -import './App.css'; +import { runTest, TestResult } from "@test/aqua_for_test"; +import React from "react"; +import logo from "./logo.svg"; +import "./App.css"; function App() { const [result, setResult] = React.useState(null); @@ -12,7 +12,7 @@ function App() { setResult(res); }) .catch((err) => { - setResult({ type: 'failure', error: err.toString() }); + setResult({ type: "failure", error: err.toString() }); }); }; @@ -27,9 +27,18 @@ function App() { Click to run test - {result && result.type === 'success' &&
{result.data}
} - {result && result.type === 'failure' &&
{result.error}
} - + {result && result.type === "success" && ( +
{result.data}
+ )} + {result && result.type === "failure" && ( +
{result.error}
+ )} +
Learn React diff --git a/packages/@tests/smoke/web-cra-ts/src/index.css b/packages/@tests/smoke/web-cra-ts/src/index.css index ec2585e8c..98556d760 100644 --- a/packages/@tests/smoke/web-cra-ts/src/index.css +++ b/packages/@tests/smoke/web-cra-ts/src/index.css @@ -1,13 +1,13 @@ body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", + "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", + "Helvetica Neue", sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; } code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; + font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", + monospace; } diff --git a/packages/@tests/smoke/web-cra-ts/src/index.tsx b/packages/@tests/smoke/web-cra-ts/src/index.tsx index bff925e58..4efb5c836 100644 --- a/packages/@tests/smoke/web-cra-ts/src/index.tsx +++ b/packages/@tests/smoke/web-cra-ts/src/index.tsx @@ -1,10 +1,12 @@ -import React from 'react'; -import ReactDOM from 'react-dom/client'; -import './index.css'; -import App from './App'; -import reportWebVitals from './reportWebVitals'; +import React from "react"; +import ReactDOM from "react-dom/client"; +import "./index.css"; +import App from "./App"; +import reportWebVitals from "./reportWebVitals"; -const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement); +const root = ReactDOM.createRoot( + document.getElementById("root") as HTMLElement, +); root.render( diff --git a/packages/@tests/smoke/web-cra-ts/src/reportWebVitals.ts b/packages/@tests/smoke/web-cra-ts/src/reportWebVitals.ts index 49a2a16e0..4d5a62920 100644 --- a/packages/@tests/smoke/web-cra-ts/src/reportWebVitals.ts +++ b/packages/@tests/smoke/web-cra-ts/src/reportWebVitals.ts @@ -1,15 +1,17 @@ -import { ReportHandler } from 'web-vitals'; +import { ReportHandler } from "web-vitals"; const reportWebVitals = (onPerfEntry?: ReportHandler) => { - if (onPerfEntry && onPerfEntry instanceof Function) { - import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { - getCLS(onPerfEntry); - getFID(onPerfEntry); - getFCP(onPerfEntry); - getLCP(onPerfEntry); - getTTFB(onPerfEntry); - }); - } + if (onPerfEntry && onPerfEntry instanceof Function) { + import("web-vitals").then( + ({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { + getCLS(onPerfEntry); + getFID(onPerfEntry); + getFCP(onPerfEntry); + getLCP(onPerfEntry); + getTTFB(onPerfEntry); + }, + ); + } }; export default reportWebVitals; diff --git a/packages/@tests/smoke/web-cra-ts/src/setupTests.ts b/packages/@tests/smoke/web-cra-ts/src/setupTests.ts index 8f2609b7b..1dd407a63 100644 --- a/packages/@tests/smoke/web-cra-ts/src/setupTests.ts +++ b/packages/@tests/smoke/web-cra-ts/src/setupTests.ts @@ -2,4 +2,4 @@ // allows you to do things like: // expect(element).toHaveTextContent(/react/i) // learn more: https://github.com/testing-library/jest-dom -import '@testing-library/jest-dom'; +import "@testing-library/jest-dom"; diff --git a/packages/@tests/smoke/web/src/index.ts b/packages/@tests/smoke/web/src/index.ts index bec899911..8e76ce5f9 100644 --- a/packages/@tests/smoke/web/src/index.ts +++ b/packages/@tests/smoke/web/src/index.ts @@ -1,49 +1,76 @@ -import puppeteer from 'puppeteer'; -import { dirname, join } from 'path'; -import { fileURLToPath } from 'url'; +/** + * 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 { CDN_PUBLIC_PATH, startCdn, startContentServer, stopServer } from '@test/test-utils'; -import { symlink, access } from 'fs/promises'; +import { symlink, access } from "fs/promises"; +import { dirname, join } from "path"; +import { fileURLToPath } from "url"; + +import { + CDN_PUBLIC_PATH, + startContentServer, + stopServer, +} from "@test/test-utils"; +import puppeteer from "puppeteer"; const port = 3000; const uri = `http://localhost:${port}/`; const __dirname = dirname(fileURLToPath(import.meta.url)); -const publicPath = join(__dirname, '../public/'); +const publicPath = join(__dirname, "../public/"); const test = async () => { const localServer = await startContentServer(port, publicPath); + try { - await access(join(publicPath, 'source')) + await access(join(publicPath, "source")); } catch { - await symlink(CDN_PUBLIC_PATH, join(publicPath, 'source')); + await symlink(CDN_PUBLIC_PATH, join(publicPath, "source")); } - console.log('starting puppeteer...'); + console.log("starting puppeteer..."); const browser = await puppeteer.launch(); const page = (await browser.pages())[0]; // uncomment to debug what's happening inside the browser // page.on('console', (msg) => console.log('// from console: ', msg.text())); - console.log('going to the page in browser...'); + console.log("going to the page in browser..."); await page.goto(uri); - console.log('clicking button...'); - await page.click('#btn'); + console.log("clicking button..."); + await page.click("#btn"); + + console.log("waiting for result to appear..."); + const elem = await page.waitForSelector("#res"); + + console.log("getting the content of result div..."); - console.log('waiting for result to appear...'); - const elem = await page.waitForSelector('#res'); + const content = await elem?.evaluate((x) => { + return x.textContent; + }); - console.log('getting the content of result div...'); - const content = await elem?.evaluate((x) => x.textContent); - console.log('raw result: ', content); + console.log("raw result: ", content); await browser.close(); await stopServer(localServer); if (!content) { - throw new Error('smoke test failed!'); + throw new Error("smoke test failed!"); } }; -test().then(() => console.log('smoke tests succeed!')); +test().then(() => { + return console.log("smoke tests succeed!"); +}); diff --git a/packages/@tests/smoke/web/tsconfig.json b/packages/@tests/smoke/web/tsconfig.json index 32d340ac6..82f29a61f 100644 --- a/packages/@tests/smoke/web/tsconfig.json +++ b/packages/@tests/smoke/web/tsconfig.json @@ -3,5 +3,5 @@ "compilerOptions": { "outDir": "./dist" }, - "exclude": ["node_modules", "dist"] + "exclude": ["node_modules", "dist", "public"] } diff --git a/packages/@tests/test-utils/src/index.ts b/packages/@tests/test-utils/src/index.ts index 5f8232c04..7775954cd 100644 --- a/packages/@tests/test-utils/src/index.ts +++ b/packages/@tests/test-utils/src/index.ts @@ -1,31 +1,65 @@ -import handler from 'serve-handler'; -import { createServer } from 'http'; -import type { Server } from 'http'; +/** + * 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 { dirname, join } from 'path'; -import { fileURLToPath } from 'url'; +import { createServer } from "http"; +import type { Server } from "http"; +import { dirname, join } from "path"; +import { fileURLToPath } from "url"; + +import handler from "serve-handler"; const __dirname = dirname(fileURLToPath(import.meta.url)); -export const CDN_PUBLIC_PATH = join(__dirname, '../../../core/js-client/dist/browser'); +export const CDN_PUBLIC_PATH = join( + __dirname, + "../../../core/js-client/dist/browser", +); -export const startCdn = (port: number) => startContentServer(port, CDN_PUBLIC_PATH); +export const startCdn = (port: number) => { + return startContentServer(port, CDN_PUBLIC_PATH); +}; -export const startContentServer = (port: number, publicDir: string): Promise => { +export const startContentServer = ( + port: number, + publicDir: string, +): Promise => { const server = createServer((request, response) => { return handler(request, response, { public: publicDir, - rewrites: [{ - source: '/js-client.min.js', - destination: '/source/index.umd.cjs' - }], - headers: [{ - source: '**/*', - headers: [ - { key: 'Cross-Origin-Opener-Policy', value: 'same-origin' }, - { key: 'Cross-Origin-Embedder-Policy', value: 'require-corp' } - ] - }] + rewrites: [ + { + source: "/js-client.min.js", + destination: "/source/index.umd.cjs", + }, + ], + headers: [ + { + source: "**/*", + headers: [ + { + key: "Cross-Origin-Opener-Policy", + value: "same-origin", + }, + { + key: "Cross-Origin-Embedder-Policy", + value: "require-corp", + }, + ], + }, + ], }); }); @@ -41,7 +75,7 @@ export const startContentServer = (port: number, publicDir: string): Promise => { return new Promise((resolve) => { app.close(() => { - console.log('server stopped'); + console.log("server stopped"); resolve(); }); }); diff --git a/packages/core/aqua-to-js/package.json b/packages/core/aqua-to-js/package.json index b3449c389..dc771ad44 100644 --- a/packages/core/aqua-to-js/package.json +++ b/packages/core/aqua-to-js/package.json @@ -25,7 +25,6 @@ "@fluencelabs/registry": "0.8.7", "@fluencelabs/spell": "0.5.20", "@fluencelabs/trust-graph": "0.4.7", - "typescript": "5.1.6", "vitest": "0.29.7" } } diff --git a/packages/core/aqua-to-js/src/common.ts b/packages/core/aqua-to-js/src/common.ts index c4d8aac04..04adfe77c 100644 --- a/packages/core/aqua-to-js/src/common.ts +++ b/packages/core/aqua-to-js/src/common.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,85 +14,147 @@ * limitations under the License. */ -import { ArrowType, ArrowWithoutCallbacks, NonArrowType, ProductType } from '@fluencelabs/interfaces'; -import { match, P } from 'ts-pattern'; -import { getFuncArgs } from './utils.js'; +import { + ArrowWithoutCallbacks, + NonArrowType, + ProductType, +} from "@fluencelabs/interfaces"; +import { match, P } from "ts-pattern"; -export function genTypeName(t: NonArrowType | ProductType | ArrowWithoutCallbacks, name: string): readonly [string | undefined, string] { +import { getFuncArgs } from "./utils.js"; + +export function genTypeName( + t: NonArrowType | ProductType | ArrowWithoutCallbacks, + name: string, +): readonly [string | undefined, string] { const genType = typeToTs(t); return match(t) + .with({ tag: "nil" }, () => { + return [undefined, "void"] as const; + }) + .with({ tag: "struct" }, () => { + return [`export type ${name} = ${genType}`, name] as const; + }) .with( - { tag: 'nil' }, - () => [undefined, 'void'] as const - ).with( - { tag: 'struct' }, - () => [`export type ${name} = ${genType}`, name] as const - ).with( - { tag: P.union('labeledProduct', 'unlabeledProduct') }, + { tag: P.union("labeledProduct", "unlabeledProduct") }, (item) => { - const args = item.tag === 'labeledProduct' - ? Object.values(item.fields) - : item.items; - + const args = + item.tag === "labeledProduct" + ? Object.values(item.fields) + : item.items; + if (args.length === 1) { return genTypeName(args[0], name); } return [`export type ${name} = ${genType}`, name] as const; }, - ).otherwise(() => [undefined, genType] as const); + ) + .otherwise(() => { + return [undefined, genType] as const; + }); } -export function typeToTs(t: NonArrowType | ArrowWithoutCallbacks | ProductType): string { +export function typeToTs( + t: NonArrowType | ArrowWithoutCallbacks | ProductType, +): string { return match(t) - .with( - { tag: 'nil' }, - () => 'null' - ).with( - { tag: 'option' }, - ({ type }) => typeToTs(type) + ' | null' - ).with( - { tag: 'scalar' }, - ({ name }) => match(name) - .with(P.union('u8', 'u16', 'u32', 'u64', 'i8', 'i16', 'i32', 'i64', 'f32', 'f64'), () => 'number') - .with('bool', () => 'boolean') - .with('string', () => 'string') - .with(P._, () => 'any').exhaustive() - ).with( - { tag: 'array' }, - ({ type }) => typeToTs(type) + '[]' - ).with( - { tag: 'struct' }, - ({ fields }) => `{ ${Object.entries(fields).map(([field, type]) => `${field}: ${typeToTs(type)};`).join(' ')} }` - ).with( - { tag: 'labeledProduct' }, - ({ fields }) => `{ ${Object.entries(fields).map(([field, type]) => `${field}: ${typeToTs(type)};`).join(' ')} }` - ).with( - { tag: 'unlabeledProduct' }, - ({ items }) => `[${items.map(item => typeToTs(item)).join(', ')}]` - ).with( - { tag: 'arrow' }, - ({ tag, domain, codomain }) => { - const retType = codomain.tag === 'nil' - ? 'void' - : codomain.items.length === 1 - ? typeToTs(codomain.items[0]) - : typeToTs(codomain); - - const args = getFuncArgs(domain).map(([name, type]) => ([name, typeToTs(type)])); + .with({ tag: "nil" }, () => { + return "null"; + }) + .with({ tag: "option" }, ({ type }) => { + return typeToTs(type) + " | null"; + }) + .with({ tag: "scalar" }, ({ name }) => { + return match(name) + .with( + P.union( + "u8", + "u16", + "u32", + "u64", + "i8", + "i16", + "i32", + "i64", + "f32", + "f64", + ), + () => { + return "number"; + }, + ) + .with("bool", () => { + return "boolean"; + }) + .with("string", () => { + return "string"; + }) + .with(P._, () => { + return "any"; + }) + .exhaustive(); + }) + .with({ tag: "array" }, ({ type }) => { + return typeToTs(type) + "[]"; + }) + .with({ tag: "struct" }, ({ fields }) => { + return `{ ${Object.entries(fields) + .map(([field, type]) => { + return `${field}: ${typeToTs(type)};`; + }) + .join(" ")} }`; + }) + .with({ tag: "labeledProduct" }, ({ fields }) => { + return `{ ${Object.entries(fields) + .map(([field, type]) => { + return `${field}: ${typeToTs(type)};`; + }) + .join(" ")} }`; + }) + .with({ tag: "unlabeledProduct" }, ({ items }) => { + return `[${items + .map((item) => { + return typeToTs(item); + }) + .join(", ")}]`; + }) + .with({ tag: "arrow" }, ({ tag, domain, codomain }) => { + const retType = + codomain.tag === "nil" + ? "void" + : codomain.items.length === 1 + ? typeToTs(codomain.items[0]) + : typeToTs(codomain); - const generic = args.length === 0 ? 'null' : args.map(([name]) => `'${name}'`).join(' | '); - args.push(['callParams', `CallParams$$<${generic}>`]); + const args = getFuncArgs(domain).map(([name, type]) => { + return [name, typeToTs(type)]; + }); - const funcArgs = args.map(([name, type]) => `${name}: ${type}`).join(', '); + const generic = + args.length === 0 + ? "null" + : args + .map(([name]) => { + return `'${name}'`; + }) + .join(" | "); - return `(${funcArgs}) => ${retType} | Promise<${retType}>`; - } - ).with( - { tag: 'topType' }, - () => 'unknown' - ).with( - { tag: 'bottomType' }, - () => 'never' - ).exhaustive(); -} \ No newline at end of file + args.push(["callParams", `CallParams$$<${generic}>`]); + + const funcArgs = args + .map(([name, type]) => { + return `${name}: ${type}`; + }) + .join(", "); + + return `(${funcArgs}) => ${retType} | Promise<${retType}>`; + }) + .with({ tag: "topType" }, () => { + return "unknown"; + }) + .with({ tag: "bottomType" }, () => { + return "never"; + }) + .exhaustive(); +} diff --git a/packages/core/aqua-to-js/src/constants.ts b/packages/core/aqua-to-js/src/constants.ts index f61265177..3a50511a5 100644 --- a/packages/core/aqua-to-js/src/constants.ts +++ b/packages/core/aqua-to-js/src/constants.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,4 +14,4 @@ * limitations under the License. */ -export const CLIENT = 'IFluenceClient$$'; \ No newline at end of file +export const CLIENT = "IFluenceClient$$"; diff --git a/packages/core/aqua-to-js/src/future.ts b/packages/core/aqua-to-js/src/future.ts index c894eda03..084c6dc18 100644 --- a/packages/core/aqua-to-js/src/future.ts +++ b/packages/core/aqua-to-js/src/future.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,46 +16,60 @@ import { ArrayType, - BottomType, LabeledProductType, + BottomType, + LabeledProductType, NilType, NonArrowType, OptionType, ScalarType, StructType, - TopType, UnlabeledProductType -} from '@fluencelabs/interfaces'; + TopType, + UnlabeledProductType, +} from "@fluencelabs/interfaces"; // Type definitions for inferring ts types from air json definition // In the future we may remove string type declaration and move to type inference. -type GetTsTypeFromScalar = T['name'] extends 'u8' | 'u16' | 'u32' | 'u64' | 'i8' | 'i16' | 'i32' | 'i64' | 'f32' | 'f64' +type GetTsTypeFromScalar = T["name"] extends + | "u8" + | "u16" + | "u32" + | "u64" + | "i8" + | "i16" + | "i32" + | "i64" + | "f32" + | "f64" ? number - : T['name'] extends 'bool' - ? boolean - : T['name'] extends 'string' - ? string - : never; + : T["name"] extends "bool" + ? boolean + : T["name"] extends "string" + ? string + : never; -type MapTuple = { [K in keyof T]: T[K] extends NonArrowType ? GetTsType : never } +type MapTuple = { + [K in keyof T]: T[K] extends NonArrowType ? GetTsType : never; +}; type GetTsType = T extends NilType ? null : T extends ArrayType - ? GetTsType[] - : T extends StructType - ? { [K in keyof T]: GetTsType } - : T extends OptionType - ? GetTsType | null - : T extends ScalarType - ? GetTsTypeFromScalar - : T extends TopType - ? unknown - : T extends BottomType - ? never - : T extends Exclude, NilType> - ? MapTuple - : T extends Exclude, NilType> - ? H extends NonArrowType - ? { [K in keyof T['fields']]: GetTsType } - : never - : never; \ No newline at end of file + ? GetTsType[] + : T extends StructType + ? { [K in keyof T]: GetTsType } + : T extends OptionType + ? GetTsType | null + : T extends ScalarType + ? GetTsTypeFromScalar + : T extends TopType + ? unknown + : T extends BottomType + ? never + : T extends Exclude, NilType> + ? MapTuple + : T extends Exclude, NilType> + ? H extends NonArrowType + ? { [K in keyof T["fields"]]: GetTsType } + : never + : never; diff --git a/packages/core/aqua-to-js/src/generate/__test__/generate.spec.ts b/packages/core/aqua-to-js/src/generate/__test__/generate.spec.ts index e2ba65f86..aa7172b72 100644 --- a/packages/core/aqua-to-js/src/generate/__test__/generate.spec.ts +++ b/packages/core/aqua-to-js/src/generate/__test__/generate.spec.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,36 +14,40 @@ * limitations under the License. */ -import { describe, expect, it } from 'vitest'; -import { generateTypes, generateSources } from '../index.js'; -import { compileFromPath } from '@fluencelabs/aqua-api'; -import url from 'url'; -import { getPackageJsonContent, PackageJson } from '../../utils.js'; +import url from "url"; -describe('Aqua to js/ts compiler', () => { - it('compiles smoke tests successfully', async () => { +import { compileFromPath } from "@fluencelabs/aqua-api"; +import { describe, expect, it } from "vitest"; + +import { getPackageJsonContent, PackageJson } from "../../utils.js"; +import { generateTypes, generateSources } from "../index.js"; + +describe("Aqua to js/ts compiler", () => { + it("compiles smoke tests successfully", async () => { const res = await compileFromPath({ - filePath: url.fileURLToPath(new URL('./sources/smoke_test.aqua', import.meta.url)), - imports: ['./node_modules'], - targetType: 'air' + filePath: url.fileURLToPath( + new URL("./sources/smoke_test.aqua", import.meta.url), + ), + imports: ["./node_modules"], + targetType: "air", }); - + const pkg: PackageJson = { ...(await getPackageJsonContent()), - version: '0.0.0', + version: "0.0.0", devDependencies: { - '@fluencelabs/aqua-api': '0.0.0' + "@fluencelabs/aqua-api": "0.0.0", }, }; - - const jsResult = await generateSources(res, 'js', pkg); + + const jsResult = await generateSources(res, "js", pkg); const jsTypes = await generateTypes(res, pkg); - + expect(jsResult).toMatchSnapshot(); expect(jsTypes).toMatchSnapshot(); - const tsResult = await generateSources(res, 'ts', pkg); + const tsResult = await generateSources(res, "ts", pkg); expect(tsResult).toMatchSnapshot(); }); -}); \ No newline at end of file +}); diff --git a/packages/core/aqua-to-js/src/generate/function.ts b/packages/core/aqua-to-js/src/generate/function.ts index d76ad2c48..18de7c86a 100644 --- a/packages/core/aqua-to-js/src/generate/function.ts +++ b/packages/core/aqua-to-js/src/generate/function.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,24 +14,35 @@ * limitations under the License. */ -import { recursiveRenameLaquaProps } from '../utils.js'; -import { AquaFunction, TypeGenerator } from './interfaces.js'; +import { recursiveRenameLaquaProps } from "../utils.js"; -export function generateFunctions(typeGenerator: TypeGenerator, functions: Record) { - return Object.values(functions).map(func => generateFunction(typeGenerator, func)).join('\n\n'); +import { AquaFunction, TypeGenerator } from "./interfaces.js"; + +export function generateFunctions( + typeGenerator: TypeGenerator, + functions: Record, +) { + return Object.values(functions) + .map((func) => { + return generateFunction(typeGenerator, func); + }) + .join("\n\n"); } function generateFunction(typeGenerator: TypeGenerator, func: AquaFunction) { - const scriptConstName = func.funcDef.functionName + '_script'; + const scriptConstName = func.funcDef.functionName + "_script"; return `export const ${scriptConstName} = \` ${func.script}\`; ${typeGenerator.funcType(func)} -export function ${func.funcDef.functionName}(${typeGenerator.type('...args', 'any[]')}) { +export function ${func.funcDef.functionName}(${typeGenerator.type( + "...args", + "any[]", + )}) { return callFunction$$( args, ${JSON.stringify(recursiveRenameLaquaProps(func.funcDef), null, 4)}, ${scriptConstName} ); -}` -} \ No newline at end of file +}`; +} diff --git a/packages/core/aqua-to-js/src/generate/header.ts b/packages/core/aqua-to-js/src/generate/header.ts index 335ea0cc5..5f3cfbb4a 100644 --- a/packages/core/aqua-to-js/src/generate/header.ts +++ b/packages/core/aqua-to-js/src/generate/header.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,25 +14,33 @@ * limitations under the License. */ -import { OutputType } from './interfaces.js'; -import { PackageJson } from '../utils.js'; +import { PackageJson } from "../utils.js"; + +import { OutputType } from "./interfaces.js"; -export default function generateHeader({ version, devDependencies }: PackageJson, outputType: OutputType) { +export default function generateHeader( + { version, devDependencies }: PackageJson, + outputType: OutputType, +) { return `/* eslint-disable */ // @ts-nocheck /** * * This file is generated using: - * @fluencelabs/aqua-api version: ${devDependencies['@fluencelabs/aqua-api']} + * @fluencelabs/aqua-api version: ${devDependencies["@fluencelabs/aqua-api"]} * @fluencelabs/aqua-to-js version: ${version} * 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 * */ -${outputType === 'ts' ? 'import type { IFluenceClient as IFluenceClient$$, CallParams as CallParams$$ } from \'@fluencelabs/js-client\';' : ''} +${ + outputType === "ts" + ? "import type { IFluenceClient as IFluenceClient$$, CallParams as CallParams$$ } from '@fluencelabs/js-client';" + : "" +} import { v5_callFunction as callFunction$$, v5_registerService as registerService$$, } from '@fluencelabs/js-client';`; -} \ No newline at end of file +} diff --git a/packages/core/aqua-to-js/src/generate/index.ts b/packages/core/aqua-to-js/src/generate/index.ts index cb1aa4ac7..04043016b 100644 --- a/packages/core/aqua-to-js/src/generate/index.ts +++ b/packages/core/aqua-to-js/src/generate/index.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,46 +14,80 @@ * limitations under the License. */ -import { CompilationResult, JSTypeGenerator, OutputType, TSTypeGenerator, TypeGenerator } from './interfaces.js'; -import { PackageJson } from '../utils.js'; -import { generateServices } from './service.js'; -import { generateFunctions } from './function.js'; -import header from './header.js'; +import { PackageJson } from "../utils.js"; -const typeGenerators: Record = { - 'js': new JSTypeGenerator(), - 'ts': new TSTypeGenerator() +import { generateFunctions } from "./function.js"; +import header from "./header.js"; +import { + CompilationResult, + JSTypeGenerator, + OutputType, + TSTypeGenerator, + TypeGenerator, +} from "./interfaces.js"; +import { generateServices } from "./service.js"; + +const typeGenerators: Record = { + js: new JSTypeGenerator(), + ts: new TSTypeGenerator(), }; -export async function generateSources({ services, functions }: CompilationResult, outputType: OutputType, packageJson: PackageJson) { +export async function generateSources( + { services, functions }: CompilationResult, + outputType: OutputType, + packageJson: PackageJson, +) { const typeGenerator = typeGenerators[outputType]; return `${header(packageJson, outputType)} -${Object.entries(services).length > 0 ? `// Services +${ + Object.entries(services).length > 0 + ? `// Services ${generateServices(typeGenerator, services)} -` : ''} -${Object.entries(functions).length > 0 ? `// Functions +` + : "" +} +${ + Object.entries(functions).length > 0 + ? `// Functions ${generateFunctions(typeGenerator, functions)} -`: ''}` +` + : "" +}`; } -export async function generateTypes({ services, functions }: CompilationResult, packageJson: PackageJson) { - const typeGenerator = typeGenerators['ts']; - +export async function generateTypes( + { services, functions }: CompilationResult, + packageJson: PackageJson, +) { + const typeGenerator = typeGenerators["ts"]; + const generatedServices = Object.entries(services) - .map(([srvName, srvDef]) => typeGenerator.serviceType(srvName, srvDef)) - .join('\n'); - + .map(([srvName, srvDef]) => { + return typeGenerator.serviceType(srvName, srvDef); + }) + .join("\n"); + const generatedFunctions = Object.entries(functions) - .map(([funcName, funcDef]) => typeGenerator.funcType(funcDef)) - .join('\n'); - - return `${header(packageJson, 'ts')} + .map(([funcName, funcDef]) => { + return typeGenerator.funcType(funcDef); + }) + .join("\n"); -${Object.entries(services).length > 0 ? `// Services + return `${header(packageJson, "ts")} + +${ + Object.entries(services).length > 0 + ? `// Services ${generatedServices} -` : ''} -${Object.entries(functions).length > 0 ? `// Functions +` + : "" +} +${ + Object.entries(functions).length > 0 + ? `// Functions ${generatedFunctions} -`: ''}` -} \ No newline at end of file +` + : "" +}`; +} diff --git a/packages/core/aqua-to-js/src/generate/interfaces.ts b/packages/core/aqua-to-js/src/generate/interfaces.ts index 0769a2a8b..d4edecfa8 100644 --- a/packages/core/aqua-to-js/src/generate/interfaces.ts +++ b/packages/core/aqua-to-js/src/generate/interfaces.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,10 +14,11 @@ * limitations under the License. */ -import { CLIENT } from '../constants.js'; -import { FunctionCallDef, ServiceDef } from '@fluencelabs/interfaces'; -import { genTypeName, typeToTs } from '../common.js'; -import { capitalize, getFuncArgs } from '../utils.js'; +import { FunctionCallDef, ServiceDef } from "@fluencelabs/interfaces"; + +import { genTypeName, typeToTs } from "../common.js"; +import { CLIENT } from "../constants.js"; +import { capitalize, getFuncArgs } from "../utils.js"; export interface TypeGenerator { type(field: string, type: string): string; @@ -42,58 +43,94 @@ export class TSTypeGenerator implements TypeGenerator { funcType({ funcDef }: AquaFunction): string { const args = getFuncArgs(funcDef.arrow.domain).map(([name, type]) => { - const [typeDesc, t] = genTypeName(type, capitalize(funcDef.functionName) + 'Arg' + capitalize(name)); + const [typeDesc, t] = genTypeName( + type, + capitalize(funcDef.functionName) + "Arg" + capitalize(name), + ); + return [typeDesc, `${name}: ${t}`] as const; }); + args.push([undefined, `config?: {ttl?: number}`]); - const argsDefs = args.map(([, def]) => " " + def); - const argsDesc = args.filter(([desc]) => desc !== undefined).map(([desc]) => desc); + const argsDefs = args.map(([, def]) => { + return " " + def; + }); + + const argsDesc = args + .filter(([desc]) => { + return desc !== undefined; + }) + .map(([desc]) => { + return desc; + }); const functionOverloads = [ - argsDefs.join(',\n'), - [` peer: ${CLIENT}`, ...argsDefs].join(',\n') + argsDefs.join(",\n"), + [` peer: ${CLIENT}`, ...argsDefs].join(",\n"), ]; - - const [resTypeDesc, resType] = genTypeName(funcDef.arrow.codomain, capitalize(funcDef.functionName) + "Result"); + + const [resTypeDesc, resType] = genTypeName( + funcDef.arrow.codomain, + capitalize(funcDef.functionName) + "Result", + ); return [ - argsDesc.join('\n'), + argsDesc.join("\n"), resTypeDesc || "", - functionOverloads.flatMap(fo => [ - `export function ${funcDef.functionName}(`, - fo, - `): Promise<${resType}>;`, - '' - ]).join('\n') - ].filter(s => s !== '').join('\n\n'); + functionOverloads + .flatMap((fo) => { + return [ + `export function ${funcDef.functionName}(`, + fo, + `): Promise<${resType}>;`, + "", + ]; + }) + .join("\n"), + ] + .filter((s) => { + return s !== ""; + }) + .join("\n\n"); } serviceType(srvName: string, srvDef: ServiceDef): string { - const members = srvDef.functions.tag === 'nil' ? [] : Object.entries(srvDef.functions.fields); + const members = + srvDef.functions.tag === "nil" + ? [] + : Object.entries(srvDef.functions.fields); const interfaceDefs = members .map(([name, arrow]) => { return ` ${name}: ${typeToTs(arrow)};`; }) - .join('\n'); + .join("\n"); + + const interfaces = [ + `export interface ${srvName}Def {`, + interfaceDefs, + "}", + ].join("\n"); - const interfaces = [`export interface ${srvName}Def {`, interfaceDefs, '}'].join('\n'); - const peerDecl = `peer: ${CLIENT}`; const serviceDecl = `service: ${srvName}Def`; const serviceIdDecl = `serviceId: string`; + const registerServiceArgs = [ [serviceDecl], [serviceIdDecl, serviceDecl], [peerDecl, serviceDecl], - [peerDecl, serviceIdDecl, serviceDecl] + [peerDecl, serviceIdDecl, serviceDecl], ]; - return [interfaces, ...registerServiceArgs.map(registerServiceArg => { - const args = registerServiceArg.join(', '); - return `export function register${srvName}(${args}): void;` - })].join('\n'); + return [ + interfaces, + ...registerServiceArgs.map((registerServiceArg) => { + const args = registerServiceArg.join(", "); + return `export function register${srvName}(${args}): void;`; + }), + ].join("\n"); } } @@ -111,11 +148,11 @@ export class JSTypeGenerator implements TypeGenerator { } funcType(): string { - return ''; + return ""; } serviceType(): string { - return ''; + return ""; } } @@ -133,4 +170,4 @@ export interface EntityGenerator { generate(compilationResult: CompilationResult): string; } -export type OutputType = 'js' | 'ts'; \ No newline at end of file +export type OutputType = "js" | "ts"; diff --git a/packages/core/aqua-to-js/src/generate/service.ts b/packages/core/aqua-to-js/src/generate/service.ts index dfea63f2d..5b5be2340 100644 --- a/packages/core/aqua-to-js/src/generate/service.ts +++ b/packages/core/aqua-to-js/src/generate/service.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,45 +14,71 @@ * limitations under the License. */ -import { ServiceDef } from '@fluencelabs/interfaces'; -import { recursiveRenameLaquaProps } from '../utils.js'; -import { TypeGenerator } from './interfaces.js'; +import { ServiceDef } from "@fluencelabs/interfaces"; + +import { recursiveRenameLaquaProps } from "../utils.js"; + +import { TypeGenerator } from "./interfaces.js"; interface DefaultServiceId { - s_Some__f_value?: string + s_Some__f_value?: string; } -export function generateServices(typeGenerator: TypeGenerator, services: Record) { - const generated = Object.entries(services).map(([srvName, srvDef]) => generateService(typeGenerator, srvName, srvDef)).join('\n\n'); +export function generateServices( + typeGenerator: TypeGenerator, + services: Record, +) { + const generated = Object.entries(services) + .map(([srvName, srvDef]) => { + return generateService(typeGenerator, srvName, srvDef); + }) + .join("\n\n"); - return generated + '\n'; + return generated + "\n"; } -function generateService(typeGenerator: TypeGenerator, srvName: string, srvDef: ServiceDef) { +function generateService( + typeGenerator: TypeGenerator, + srvName: string, + srvDef: ServiceDef, +) { return [ typeGenerator.serviceType(srvName, srvDef), - generateRegisterServiceOverload(typeGenerator, srvName, srvDef) - ].join('\n'); + generateRegisterServiceOverload(typeGenerator, srvName, srvDef), + ].join("\n"); } -function generateRegisterServiceOverload(typeGenerator: TypeGenerator, srvName: string, srvDef: ServiceDef) { +function generateRegisterServiceOverload( + typeGenerator: TypeGenerator, + srvName: string, + srvDef: ServiceDef, +) { return [ - `export function register${srvName}(${typeGenerator.type('...args', 'any[]')}) {`, - ' registerService$$(', - ' args,', + `export function register${srvName}(${typeGenerator.type( + "...args", + "any[]", + )}) {`, + " registerService$$(", + " args,", ` ${serviceToJson(srvDef)}`, - ' );', - '}' - ].join('\n'); + " );", + "}", + ].join("\n"); } function serviceToJson(service: ServiceDef): string { - return JSON.stringify({ - ...( - (service.defaultServiceId as DefaultServiceId)?.s_Some__f_value - ? { defaultServiceId: (service.defaultServiceId as DefaultServiceId).s_Some__f_value } - : {} - ), - functions: recursiveRenameLaquaProps(service.functions) - }, null, 4); -} \ No newline at end of file + return JSON.stringify( + { + ...((service.defaultServiceId as DefaultServiceId)?.s_Some__f_value + ? { + defaultServiceId: ( + service.defaultServiceId as DefaultServiceId + ).s_Some__f_value, + } + : {}), + functions: recursiveRenameLaquaProps(service.functions), + }, + null, + 4, + ); +} diff --git a/packages/core/aqua-to-js/src/index.ts b/packages/core/aqua-to-js/src/index.ts index 081713b7c..4df5b4bc5 100644 --- a/packages/core/aqua-to-js/src/index.ts +++ b/packages/core/aqua-to-js/src/index.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,12 +14,9 @@ * limitations under the License. */ -import { - generateSources, - generateTypes, -} from './generate/index.js'; -import { CompilationResult, OutputType } from './generate/interfaces.js'; -import { getPackageJsonContent } from './utils.js'; +import { generateSources, generateTypes } from "./generate/index.js"; +import { CompilationResult, OutputType } from "./generate/interfaces.js"; +import { getPackageJsonContent } from "./utils.js"; interface JsOutput { sources: string; @@ -31,17 +28,22 @@ interface TsOutput { } type LanguageOutput = { - "js": JsOutput, - "ts": TsOutput + js: JsOutput; + ts: TsOutput; }; -export default async function aquaToJs(res: CompilationResult, outputType: T): Promise { +export default async function aquaToJs( + res: CompilationResult, + outputType: T, +): Promise { const packageJson = await getPackageJsonContent(); - - return outputType === 'js' ? { - sources: await generateSources(res, 'js', packageJson), - types: await generateTypes(res, packageJson) - } : { - sources: await generateSources(res, 'ts', packageJson), - } as LanguageOutput[T]; -}; \ No newline at end of file + + return outputType === "js" + ? { + sources: await generateSources(res, "js", packageJson), + types: await generateTypes(res, packageJson), + } + : ({ + sources: await generateSources(res, "ts", packageJson), + } as LanguageOutput[T]); +} diff --git a/packages/core/aqua-to-js/src/utils.ts b/packages/core/aqua-to-js/src/utils.ts index a18657c3c..2e4a6173b 100644 --- a/packages/core/aqua-to-js/src/utils.ts +++ b/packages/core/aqua-to-js/src/utils.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,45 +14,66 @@ * limitations under the License. */ -import { ArrowWithoutCallbacks, NonArrowType, ProductType } from '@fluencelabs/interfaces'; -import { readFile } from 'fs/promises'; -import path from 'path'; +import { readFile } from "fs/promises"; +import path from "path"; + +import { + ArrowWithoutCallbacks, + NonArrowType, + ProductType, +} from "@fluencelabs/interfaces"; export interface PackageJson { name: string; version: string; devDependencies: { - ['@fluencelabs/aqua-api']: string - } + ["@fluencelabs/aqua-api"]: string; + }; } export async function getPackageJsonContent(): Promise { - const content = await readFile(new URL(path.join('..', 'package.json'), import.meta.url), 'utf-8'); + const content = await readFile( + new URL(path.join("..", "package.json"), import.meta.url), + "utf-8", + ); + return JSON.parse(content); } -export function getFuncArgs(domain: ProductType): [string, NonArrowType | ArrowWithoutCallbacks][] { - if (domain.tag === 'labeledProduct') { - return Object.entries(domain.fields).map(([label, type]) => [label, type]); - } else if (domain.tag === 'unlabeledProduct') { - return domain.items.map((type, index) => ['arg' + index, type]); +export function getFuncArgs( + domain: ProductType, +): [string, NonArrowType | ArrowWithoutCallbacks][] { + if (domain.tag === "labeledProduct") { + return Object.entries(domain.fields).map(([label, type]) => { + return [label, type]; + }); + } else if (domain.tag === "unlabeledProduct") { + return domain.items.map((type, index) => { + return ["arg" + index, type]; + }); } else { return []; } } export function recursiveRenameLaquaProps(obj: unknown): unknown { - if (typeof obj !== 'object' || obj === null) return obj; + if (typeof obj !== "object" || obj === null) { + return obj; + } if (Array.isArray(obj)) { - return obj.map(item => recursiveRenameLaquaProps(item)); + return obj.map((item) => { + return recursiveRenameLaquaProps(item); + }); } return Object.getOwnPropertyNames(obj).reduce((acc, prop) => { let accessProp = prop; - if (prop.includes('Laqua_js')) { - // Last part of the property separated by "_" is a correct name - const refinedProperty = prop.split('_').pop()!; + + if (prop.includes("Laqua_js")) { + // Last part of the property separated by "_" is a correct name + const refinedProperty = prop.split("_").pop()!; + if (refinedProperty in obj) { accessProp = refinedProperty; } @@ -60,11 +81,13 @@ export function recursiveRenameLaquaProps(obj: unknown): unknown { return { ...acc, - [accessProp]: recursiveRenameLaquaProps(obj[accessProp as keyof typeof obj]) + [accessProp]: recursiveRenameLaquaProps( + obj[accessProp as keyof typeof obj], + ), }; }, {}); } export function capitalize(str: string) { return str.slice(0, 1).toUpperCase() + str.slice(1); -} \ No newline at end of file +} diff --git a/packages/core/interfaces/src/commonTypes.ts b/packages/core/interfaces/src/commonTypes.ts index d7e64f5aa..3574c245d 100644 --- a/packages/core/interfaces/src/commonTypes.ts +++ b/packages/core/interfaces/src/commonTypes.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import type { SecurityTetraplet } from '@fluencelabs/avm'; + +import type { SecurityTetraplet } from "@fluencelabs/avm"; /** * Peer ID's id as a base58 string (multihash/CIDv0). @@ -61,5 +62,7 @@ export interface CallParams { /** * Security tetraplets */ - tetraplets: ArgName extends string ? Record : Record; + tetraplets: ArgName extends string + ? Record + : Record; } diff --git a/packages/core/interfaces/src/compilerSupport/aquaTypeDefinitions.ts b/packages/core/interfaces/src/compilerSupport/aquaTypeDefinitions.ts index e18d3c785..1eb6d2283 100644 --- a/packages/core/interfaces/src/compilerSupport/aquaTypeDefinitions.ts +++ b/packages/core/interfaces/src/compilerSupport/aquaTypeDefinitions.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,7 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -type SimpleTypes = ScalarType | OptionType | ArrayType | StructType | TopType | BottomType | NilType; + +type SimpleTypes = + | ScalarType + | OptionType + | ArrayType + | StructType + | TopType + | BottomType + | NilType; export type NonArrowType = SimpleTypes | ProductType; @@ -21,21 +29,21 @@ export type TopType = { /** * Type descriptor. Used for pattern-matching */ - tag: 'topType'; + tag: "topType"; }; export type BottomType = { /** * Type descriptor. Used for pattern-matching */ - tag: 'bottomType'; + tag: "bottomType"; }; export type OptionType = { /** * Type descriptor. Used for pattern-matching */ - tag: 'option'; + tag: "option"; /** * Underlying type of the option @@ -47,14 +55,14 @@ export type NilType = { /** * Type descriptor. Used for pattern-matching */ - tag: 'nil'; + tag: "nil"; }; export type ArrayType = { /** * Type descriptor. Used for pattern-matching */ - tag: 'array'; + tag: "array"; /** * Type of array elements @@ -66,24 +74,24 @@ export type ArrayType = { * All possible scalar type names */ export type ScalarNames = - | 'u8' - | 'u16' - | 'u32' - | 'u64' - | 'i8' - | 'i16' - | 'i32' - | 'i64' - | 'f32' - | 'f64' - | 'bool' - | 'string'; + | "u8" + | "u16" + | "u32" + | "u64" + | "i8" + | "i16" + | "i32" + | "i64" + | "f32" + | "f64" + | "bool" + | "string"; export type ScalarType = { /** * Type descriptor. Used for pattern-matching */ - tag: 'scalar'; + tag: "scalar"; /** * Name of the scalar type @@ -95,7 +103,7 @@ export type StructType = { /** * Type descriptor. Used for pattern-matching */ - tag: 'struct'; + tag: "struct"; /** * Struct name @@ -112,7 +120,7 @@ export type LabeledProductType = { /** * Type descriptor. Used for pattern-matching */ - tag: 'labeledProduct'; + tag: "labeledProduct"; /** * Labelled product fields @@ -124,7 +132,7 @@ export type UnlabeledProductType = { /** * Type descriptor. Used for pattern-matching */ - tag: 'unlabeledProduct'; + tag: "unlabeledProduct"; /** * Items in unlabelled product @@ -132,7 +140,10 @@ export type UnlabeledProductType = { items: Array; }; -export type ProductType = UnlabeledProductType | LabeledProductType | NilType; +export type ProductType = + | UnlabeledProductType + | LabeledProductType + | NilType; /** * ArrowType is a profunctor pointing its domain to codomain. @@ -142,7 +153,7 @@ export type ArrowType = { /** * Type descriptor. Used for pattern-matching */ - tag: 'arrow'; + tag: "arrow"; /** * Where this Arrow is defined @@ -163,7 +174,9 @@ export type ArrowWithoutCallbacks = ArrowType; /** * Arrow which domain does can contain both non-arrow types and arrows (which themselves cannot contain arrows) */ -export type ArrowWithCallbacks = ArrowType; +export type ArrowWithCallbacks = ArrowType< + NonArrowType | ArrowWithoutCallbacks +>; export interface FunctionCallConstants { /** @@ -253,15 +266,15 @@ export const getArgumentTypes = ( ): { [key: string]: NonArrowType | ArrowWithoutCallbacks; } => { - if (def.arrow.domain.tag !== 'labeledProduct') { - throw new Error('Should be impossible'); + 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') { + if (def.arrow.codomain.tag === "nil") { return true; } diff --git a/packages/core/interfaces/src/compilerSupport/compilerSupportInterface.ts b/packages/core/interfaces/src/compilerSupport/compilerSupportInterface.ts index 515ab90aa..dc4b2a04a 100644 --- a/packages/core/interfaces/src/compilerSupport/compilerSupportInterface.ts +++ b/packages/core/interfaces/src/compilerSupport/compilerSupportInterface.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,8 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { IFluenceInternalApi } from '../fluenceClient.js'; -import { FnConfig, FunctionCallDef, ServiceDef } from './aquaTypeDefinitions.js'; + +import { IFluenceInternalApi } from "../fluenceClient.js"; + +import { + FnConfig, + FunctionCallDef, + ServiceDef, +} from "./aquaTypeDefinitions.js"; /** * Arguments passed to Aqua function @@ -54,7 +60,9 @@ export interface CallAquaFunctionArgs { /** * Call a function from Aqua script */ -export type CallAquaFunctionType = (args: CallAquaFunctionArgs) => Promise; +export type CallAquaFunctionType = ( + args: CallAquaFunctionArgs, +) => Promise; /** * Arguments for registerService function diff --git a/packages/core/interfaces/src/fluenceClient.ts b/packages/core/interfaces/src/fluenceClient.ts index 77b8e2a42..e5751bce5 100644 --- a/packages/core/interfaces/src/fluenceClient.ts +++ b/packages/core/interfaces/src/fluenceClient.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import type { Node } from './commonTypes.js'; + +import type { Node } from "./commonTypes.js"; /** * A node in Fluence network a client can connect to. @@ -26,14 +27,14 @@ export type RelayOptions = string | Node; /** * Fluence Peer's key pair types */ -export type KeyTypes = 'RSA' | 'Ed25519' | 'secp256k1'; +export type KeyTypes = "RSA" | "Ed25519" | "secp256k1"; /** * Options to specify key pair used in Fluence Peer */ export type KeyPairOptions = { - type: 'Ed25519'; - source: 'random' | Uint8Array; + type: "Ed25519"; + source: "random" | Uint8Array; }; /** @@ -97,7 +98,12 @@ export interface ClientConfig { /** * Fluence JS Client connection states as string literals */ -export const ConnectionStates = ['disconnected', 'connecting', 'connected', 'disconnecting'] as const; +export const ConnectionStates = [ + "disconnected", + "connecting", + "connected", + "disconnecting", +] as const; /** * Fluence JS Client connection states @@ -128,7 +134,9 @@ export interface IFluenceClient extends IFluenceInternalApi { /** * Handle connection state changes. Immediately returns current connection state */ - onConnectionStateChange(handler: (state: ConnectionState) => void): ConnectionState; + onConnectionStateChange( + handler: (state: ConnectionState) => void, + ): ConnectionState; /** * Return peer's secret key as byte array. @@ -145,7 +153,3 @@ export interface IFluenceClient extends IFluenceInternalApi { */ getRelayPeerId(): string; } - - - - diff --git a/packages/core/interfaces/src/index.ts b/packages/core/interfaces/src/index.ts index f175fab7e..8dc7ce569 100644 --- a/packages/core/interfaces/src/index.ts +++ b/packages/core/interfaces/src/index.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export * from './compilerSupport/aquaTypeDefinitions.js'; -export * from './compilerSupport/compilerSupportInterface.js'; -export * from './commonTypes.js'; -export * from './fluenceClient.js'; + +export * from "./compilerSupport/aquaTypeDefinitions.js"; +export * from "./compilerSupport/compilerSupportInterface.js"; +export * from "./commonTypes.js"; +export * from "./fluenceClient.js"; diff --git a/packages/core/js-client/src/api.ts b/packages/core/js-client/src/api.ts index 38085de8c..b520f9454 100644 --- a/packages/core/js-client/src/api.ts +++ b/packages/core/js-client/src/api.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,13 +14,21 @@ * limitations under the License. */ -import type { FnConfig, FunctionCallDef, ServiceDef } from '@fluencelabs/interfaces'; -import type { IFluenceClient } from '@fluencelabs/interfaces'; -import { getArgumentTypes } from '@fluencelabs/interfaces'; -import { callAquaFunction, Fluence, registerService } from './index.js'; -import { FluencePeer } from './jsPeer/FluencePeer.js'; +import type { + FnConfig, + FunctionCallDef, + ServiceDef, + IFluenceClient, +} from "@fluencelabs/interfaces"; +import { getArgumentTypes } from "@fluencelabs/interfaces"; + +import { FluencePeer } from "./jsPeer/FluencePeer.js"; -export const isFluencePeer = (fluencePeerCandidate: unknown): fluencePeerCandidate is IFluenceClient => { +import { callAquaFunction, Fluence, registerService } from "./index.js"; + +export const isFluencePeer = ( + fluencePeerCandidate: unknown, +): fluencePeerCandidate is IFluenceClient => { return fluencePeerCandidate instanceof FluencePeer; }; @@ -37,8 +45,12 @@ export const v5_callFunction = async ( def: FunctionCallDef, script: string, ): Promise => { - const { args, client: peer, config } = await extractFunctionArgs(rawFnArgs, def); - + const { + args, + client: peer, + config, + } = await extractFunctionArgs(rawFnArgs, def); + return callAquaFunction({ args, def, @@ -54,9 +66,15 @@ export const v5_callFunction = async ( * @param args - raw arguments passed by user to the generated function * @param def - service definition generated by the Aqua compiler */ -export const v5_registerService = async (args: any[], def: ServiceDef): Promise => { - const { peer, service, serviceId } = await extractServiceArgs(args, def.defaultServiceId); - +export const v5_registerService = async ( + args: any[], + def: ServiceDef, +): Promise => { + const { peer, service, serviceId } = await extractServiceArgs( + args, + def.defaultServiceId, + ); + return registerService({ def, service, @@ -90,6 +108,7 @@ const extractFunctionArgs = async ( let peer: IFluenceClient; let structuredArgs: any[]; let config: FnConfig; + if (isFluencePeer(args[0])) { peer = args[0]; structuredArgs = args.slice(1, numberOfExpectedArgs + 1); @@ -97,19 +116,24 @@ const extractFunctionArgs = async ( } else { if (!Fluence.defaultClient) { throw new Error( - 'Could not register Aqua service because the client is not initialized. Did you forget to call Fluence.connect()?', + "Could not register Aqua service because the client is not initialized. Did you forget to call Fluence.connect()?", ); } + peer = Fluence.defaultClient; structuredArgs = args.slice(0, numberOfExpectedArgs); config = args[numberOfExpectedArgs]; } if (structuredArgs.length !== numberOfExpectedArgs) { - throw new Error(`Incorrect number of arguments. Expecting ${numberOfExpectedArgs}`); + throw new Error( + `Incorrect number of arguments. Expecting ${numberOfExpectedArgs}`, + ); } - const argsRes = argumentNames.reduce((acc, name, index) => ({ ...acc, [name]: structuredArgs[index] }), {}); + const argsRes = argumentNames.reduce((acc, name, index) => { + return { ...acc, [name]: structuredArgs[index] }; + }, {}); return { client: peer, @@ -137,20 +161,22 @@ const extractServiceArgs = async ( let peer: IFluenceClient; let serviceId: any; let service: any; + if (isFluencePeer(args[0])) { peer = args[0]; } else { if (!Fluence.defaultClient) { throw new Error( - 'Could not register Aqua service because the client is not initialized. Did you forget to call Fluence.connect()?', + "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') { + if (typeof args[0] === "string") { serviceId = args[0]; - } else if (typeof args[1] === 'string') { + } else if (typeof args[1] === "string") { serviceId = args[1]; } else { serviceId = defaultServiceId; @@ -161,9 +187,9 @@ const extractServiceArgs = async ( // If the first argument is peer, we are checking further. The second argument might either be // an object, that it must be the service object // or a string, which is the service id. In that case the service is the third argument - if (!isFluencePeer(args[0]) && typeof args[0] === 'object') { + if (!isFluencePeer(args[0]) && typeof args[0] === "object") { service = args[0]; - } else if (typeof args[1] === 'object') { + } else if (typeof args[1] === "object") { service = args[1]; } else { service = args[2]; diff --git a/packages/core/js-client/src/clientPeer/ClientPeer.ts b/packages/core/js-client/src/clientPeer/ClientPeer.ts index b93da9bf5..9feff149d 100644 --- a/packages/core/js-client/src/clientPeer/ClientPeer.ts +++ b/packages/core/js-client/src/clientPeer/ClientPeer.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,16 +13,26 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { ClientConfig, ConnectionState, IFluenceClient, PeerIdB58, RelayOptions } from '@fluencelabs/interfaces'; -import { RelayConnection, RelayConnectionConfig } from '../connection/RelayConnection.js'; -import { fromOpts, KeyPair } from '../keypair/index.js'; -import { FluencePeer, PeerConfig } from '../jsPeer/FluencePeer.js'; -import { relayOptionToMultiaddr } from '../util/libp2pUtils.js'; -import { IAvmRunner, IMarineHost } from '../marine/interfaces.js'; -import { JsServiceHost } from '../jsServiceHost/JsServiceHost.js'; -import { logger } from '../util/logger.js'; -const log = logger('client'); +import { + ClientConfig, + ConnectionState, + IFluenceClient, + RelayOptions, +} from "@fluencelabs/interfaces"; + +import { + RelayConnection, + RelayConnectionConfig, +} from "../connection/RelayConnection.js"; +import { FluencePeer, PeerConfig } from "../jsPeer/FluencePeer.js"; +import { JsServiceHost } from "../jsServiceHost/JsServiceHost.js"; +import { fromOpts, KeyPair } from "../keypair/index.js"; +import { IMarineHost } from "../marine/interfaces.js"; +import { relayOptionToMultiaddr } from "../util/libp2pUtils.js"; +import { logger } from "../util/logger.js"; + +const log = logger("client"); const DEFAULT_TTL_MS = 7000; const MAX_OUTBOUND_STREAMS = 1024; @@ -31,8 +41,12 @@ const MAX_INBOUND_STREAMS = 1024; export const makeClientPeerConfig = async ( relay: RelayOptions, config: ClientConfig, -): Promise<{ peerConfig: PeerConfig; relayConfig: RelayConnectionConfig; keyPair: KeyPair }> => { - const opts = config?.keyPair || { type: 'Ed25519', source: 'random' }; +): Promise<{ + peerConfig: PeerConfig; + relayConfig: RelayConnectionConfig; + keyPair: KeyPair; +}> => { + const opts = config?.keyPair || { type: "Ed25519", source: "random" }; const keyPair = await fromOpts(opts); const relayAddress = relayOptionToMultiaddr(relay); @@ -47,8 +61,12 @@ export const makeClientPeerConfig = async ( peerId: keyPair.getLibp2pPeerId(), relayAddress: relayAddress, dialTimeoutMs: config?.connectionOptions?.dialTimeoutMs, - maxInboundStreams: config?.connectionOptions?.maxInboundStreams || MAX_OUTBOUND_STREAMS, - maxOutboundStreams: config?.connectionOptions?.maxOutboundStreams || MAX_INBOUND_STREAMS, + maxInboundStreams: + config?.connectionOptions?.maxInboundStreams || + MAX_OUTBOUND_STREAMS, + maxOutboundStreams: + config?.connectionOptions?.maxOutboundStreams || + MAX_INBOUND_STREAMS, }, keyPair: keyPair, }; @@ -61,7 +79,13 @@ export class ClientPeer extends FluencePeer implements IFluenceClient { keyPair: KeyPair, marine: IMarineHost, ) { - super(peerConfig, keyPair, marine, new JsServiceHost(), new RelayConnection(relayConfig)); + super( + peerConfig, + keyPair, + marine, + new JsServiceHost(), + new RelayConnection(relayConfig), + ); } getPeerId(): string { @@ -72,14 +96,16 @@ export class ClientPeer extends FluencePeer implements IFluenceClient { return this.keyPair.toEd25519PrivateKey(); } - connectionState: ConnectionState = 'disconnected'; + connectionState: ConnectionState = "disconnected"; connectionStateChangeHandler: (state: ConnectionState) => void = () => {}; getRelayPeerId(): string { return this.internals.getRelayPeerId(); } - onConnectionStateChange(handler: (state: ConnectionState) => void): ConnectionState { + onConnectionStateChange( + handler: (state: ConnectionState) => void, + ): ConnectionState { this.connectionStateChangeHandler = handler; return this.connectionState; @@ -105,19 +131,19 @@ export class ClientPeer extends FluencePeer implements IFluenceClient { } async start(): Promise { - log.trace('connecting to Fluence network'); - this.changeConnectionState('connecting'); + log.trace("connecting to Fluence network"); + this.changeConnectionState("connecting"); await super.start(); // TODO: check connection (`checkConnection` function) here - this.changeConnectionState('connected'); - log.trace('connected'); + this.changeConnectionState("connected"); + log.trace("connected"); } async stop(): Promise { - log.trace('disconnecting from Fluence network'); - this.changeConnectionState('disconnecting'); + log.trace("disconnecting from Fluence network"); + this.changeConnectionState("disconnecting"); await super.stop(); - this.changeConnectionState('disconnected'); - log.trace('disconnected'); + this.changeConnectionState("disconnected"); + log.trace("disconnected"); } } diff --git a/packages/core/js-client/src/clientPeer/__test__/client.spec.ts b/packages/core/js-client/src/clientPeer/__test__/client.spec.ts index 06c521941..d556cb755 100644 --- a/packages/core/js-client/src/clientPeer/__test__/client.spec.ts +++ b/packages/core/js-client/src/clientPeer/__test__/client.spec.ts @@ -1,13 +1,31 @@ -import { it, describe, expect } from 'vitest'; -import { handleTimeout } from '../../particle/Particle.js'; -import { doNothing } from '../../jsServiceHost/serviceUtils.js'; -import { registerHandlersHelper, withClient } from '../../util/testUtils.js'; -import { checkConnection } from '../checkConnection.js'; -import { nodes, RELAY } from './connection.js'; -import { CallServiceData } from '../../jsServiceHost/interfaces.js'; - -describe('FluenceClient usage test suite', () => { - it('should make a call through network', async () => { +/** + * 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 { it, describe, expect } from "vitest"; + +import { CallServiceData } from "../../jsServiceHost/interfaces.js"; +import { doNothing } from "../../jsServiceHost/serviceUtils.js"; +import { handleTimeout } from "../../particle/Particle.js"; +import { registerHandlersHelper, withClient } from "../../util/testUtils.js"; +import { checkConnection } from "../checkConnection.js"; + +import { nodes, RELAY } from "./connection.js"; + +describe("FluenceClient usage test suite", () => { + it("should make a call through network", async () => { await withClient(RELAY, {}, async (peer) => { // arrange @@ -27,7 +45,7 @@ describe('FluenceClient usage test suite', () => { )`; const particle = await peer.internals.createNewParticle(script); - + const result = await new Promise((resolve, reject) => { if (particle instanceof Error) { return reject(particle.message); @@ -51,14 +69,17 @@ describe('FluenceClient usage test suite', () => { }, }); - peer.internals.initiateParticle(particle, handleTimeout(reject)); + peer.internals.initiateParticle( + particle, + handleTimeout(reject), + ); }); - expect(result).toBe('hello world!'); + expect(result).toBe("hello world!"); }); }); - it('check connection should work', async function () { + it("check connection should work", async function () { await withClient(RELAY, {}, async (peer) => { const isConnected = await checkConnection(peer); @@ -66,7 +87,7 @@ describe('FluenceClient usage test suite', () => { }); }); - it('check connection should work with ttl', async function () { + it("check connection should work with ttl", async function () { await withClient(RELAY, {}, async (peer) => { const isConnected = await checkConnection(peer, 10000); @@ -74,17 +95,21 @@ describe('FluenceClient usage test suite', () => { }); }); - it('two clients should work inside the same time javascript process', async () => { + it("two clients should work inside the same time javascript process", async () => { await withClient(RELAY, {}, async (peer1) => { await withClient(RELAY, {}, async (peer2) => { const res = new Promise((resolve) => { - peer2.internals.regHandler.common('test', 'test', (req: CallServiceData) => { - resolve(req.args[0]); - return { - result: {}, - retCode: 0, - }; - }); + peer2.internals.regHandler.common( + "test", + "test", + (req: CallServiceData) => { + resolve(req.args[0]); + return { + result: {}, + retCode: 0, + }; + }, + ); }); const script = ` @@ -93,7 +118,9 @@ describe('FluenceClient usage test suite', () => { (call "${peer2.getPeerId()}" ("test" "test") ["test"]) ) `; - const particle = await peer1.internals.createNewParticle(script); + + const particle = + await peer1.internals.createNewParticle(script); if (particle instanceof Error) { throw particle; @@ -101,13 +128,13 @@ describe('FluenceClient usage test suite', () => { peer1.internals.initiateParticle(particle, doNothing); - expect(await res).toEqual('test'); + expect(await res).toEqual("test"); }); }); }); - describe('should make connection to network', () => { - it('address as string', async () => { + describe("should make connection to network", () => { + it("address as string", async () => { await withClient(nodes[0].multiaddr, {}, async (peer) => { const isConnected = await checkConnection(peer); @@ -115,7 +142,7 @@ describe('FluenceClient usage test suite', () => { }); }); - it('address as node', async () => { + it("address as node", async () => { await withClient(nodes[0], {}, async (peer) => { const isConnected = await checkConnection(peer); @@ -123,23 +150,31 @@ describe('FluenceClient usage test suite', () => { }); }); - it('With connection options: dialTimeout', async () => { - await withClient(RELAY, { connectionOptions: { dialTimeoutMs: 100000 } }, async (peer) => { - const isConnected = await checkConnection(peer); + it("With connection options: dialTimeout", async () => { + await withClient( + RELAY, + { connectionOptions: { dialTimeoutMs: 100000 } }, + async (peer) => { + const isConnected = await checkConnection(peer); - expect(isConnected).toBeTruthy(); - }); + expect(isConnected).toBeTruthy(); + }, + ); }); - it('With connection options: skipCheckConnection', async () => { - await withClient(RELAY, { connectionOptions: { skipCheckConnection: true } }, async (peer) => { - const isConnected = await checkConnection(peer); + it("With connection options: skipCheckConnection", async () => { + await withClient( + RELAY, + { connectionOptions: { skipCheckConnection: true } }, + async (peer) => { + const isConnected = await checkConnection(peer); - expect(isConnected).toBeTruthy(); - }); + expect(isConnected).toBeTruthy(); + }, + ); }); - it('With connection options: defaultTTL', async () => { + it("With connection options: defaultTTL", async () => { await withClient(RELAY, { defaultTtlMs: 1 }, async (peer) => { const isConnected = await checkConnection(peer); @@ -148,14 +183,16 @@ describe('FluenceClient usage test suite', () => { }); }); - it.skip('Should throw correct error when the client tries to send a particle not to the relay', async () => { + it.skip("Should throw correct error when the client tries to send a particle not to the relay", async () => { await withClient(RELAY, {}, async (peer) => { const script = ` (xor (call "incorrect_peer_id" ("any" "service") []) (call %init_peer_id% ("callback" "error") [%last_error%]) )`; + const particle = await peer.internals.createNewParticle(script); + const promise = new Promise((resolve, reject) => { if (particle instanceof Error) { return reject(particle.message); @@ -171,7 +208,7 @@ describe('FluenceClient usage test suite', () => { }); peer.internals.initiateParticle(particle, (stage) => { - if (stage.stage === 'sendingError') { + if (stage.stage === "sendingError") { reject(stage.errorMessage); } }); @@ -180,7 +217,7 @@ describe('FluenceClient usage test suite', () => { await promise; await expect(promise).rejects.toMatch( - 'Particle is expected to be sent to only the single peer (relay which client is connected to)', + "Particle is expected to be sent to only the single peer (relay which client is connected to)", ); }); }); diff --git a/packages/core/js-client/src/clientPeer/__test__/connection.ts b/packages/core/js-client/src/clientPeer/__test__/connection.ts index 99d621b38..5988c5052 100644 --- a/packages/core/js-client/src/clientPeer/__test__/connection.ts +++ b/packages/core/js-client/src/clientPeer/__test__/connection.ts @@ -1,7 +1,24 @@ +/** + * 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. + */ + export const nodes = [ { - multiaddr: '/ip4/127.0.0.1/tcp/9991/ws/p2p/12D3KooWBM3SdXWqGaawQDGQ6JprtwswEg3FWGvGhmgmMez1vRbR', - peerId: '12D3KooWBM3SdXWqGaawQDGQ6JprtwswEg3FWGvGhmgmMez1vRbR', + multiaddr: + "/ip4/127.0.0.1/tcp/9991/ws/p2p/12D3KooWBM3SdXWqGaawQDGQ6JprtwswEg3FWGvGhmgmMez1vRbR", + peerId: "12D3KooWBM3SdXWqGaawQDGQ6JprtwswEg3FWGvGhmgmMez1vRbR", }, ]; diff --git a/packages/core/js-client/src/clientPeer/checkConnection.ts b/packages/core/js-client/src/clientPeer/checkConnection.ts index c969be161..1d42491ce 100644 --- a/packages/core/js-client/src/clientPeer/checkConnection.ts +++ b/packages/core/js-client/src/clientPeer/checkConnection.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,19 +13,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { ClientPeer } from './ClientPeer.js'; -import { logger } from '../util/logger.js'; -import { WrapFnIntoServiceCall } from '../jsServiceHost/serviceUtils.js'; -import { handleTimeout } from '../particle/Particle.js'; +import { WrapFnIntoServiceCall } from "../jsServiceHost/serviceUtils.js"; +import { handleTimeout } from "../particle/Particle.js"; +import { logger } from "../util/logger.js"; + +import { ClientPeer } from "./ClientPeer.js"; -const log = logger('connection'); +const log = logger("connection"); /** * Checks the network connection by sending a ping-like request to relay node * @param { ClientPeer } peer - The Fluence Client instance. */ -export const checkConnection = async (peer: ClientPeer, ttl?: number): Promise => { +export const checkConnection = async ( + peer: ClientPeer, + ttl?: number, +): Promise => { const msg = Math.random().toString(36).substring(7); const script = ` @@ -45,6 +49,7 @@ export const checkConnection = async (peer: ClientPeer, ttl?: number): Promise((resolve, reject) => { @@ -54,8 +59,8 @@ export const checkConnection = async (peer: ClientPeer, ttl?: number): Promise { return peer.getRelayPeerId(); }), @@ -63,8 +68,8 @@ export const checkConnection = async (peer: ClientPeer, ttl?: number): Promise { return msg; }), @@ -72,26 +77,30 @@ export const checkConnection = async (peer: ClientPeer, ttl?: number): Promise { const [val] = args; + setTimeout(() => { resolve(val); }, 0); + return {}; }), ); peer.internals.regHandler.forParticle( particle.id, - 'callback', - 'error', + "callback", + "error", WrapFnIntoServiceCall((args) => { const [error] = args; + setTimeout(() => { reject(error); }, 0); + return {}; }), ); @@ -99,19 +108,28 @@ export const checkConnection = async (peer: ClientPeer, ttl?: number): Promise { - reject('particle timed out'); + reject("particle timed out"); }), ); }); try { const result = await promise; + if (result != msg) { - log.error("unexpected behavior. 'identity' must return the passed arguments."); + log.error( + "unexpected behavior. 'identity' must return the passed arguments.", + ); } + return true; } catch (e) { - log.error('error on establishing connection. Relay: %s error: %j', peer.getRelayPeerId(), e); + log.error( + "error on establishing connection. Relay: %s error: %j", + peer.getRelayPeerId(), + e, + ); + return false; } }; diff --git a/packages/core/js-client/src/compilerSupport/__test__/v3.spec.ts b/packages/core/js-client/src/compilerSupport/__test__/v3.spec.ts index 651f5eb10..fa0412b9f 100644 --- a/packages/core/js-client/src/compilerSupport/__test__/v3.spec.ts +++ b/packages/core/js-client/src/compilerSupport/__test__/v3.spec.ts @@ -1,19 +1,36 @@ -import { it, describe, expect, test } from 'vitest'; -import { aqua2ts, ts2aqua } from '../conversions.js'; - -const i32 = { tag: 'scalar', name: 'i32' } as const; +/** + * 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 { it, describe, expect, test } from "vitest"; + +import { aqua2ts, ts2aqua } from "../conversions.js"; + +const i32 = { tag: "scalar", name: "i32" } as const; const opt_i32 = { - tag: 'option', + tag: "option", type: i32, } as const; -const array_i32 = { tag: 'array', type: i32 }; +const array_i32 = { tag: "array", type: i32 }; -const array_opt_i32 = { tag: 'array', type: opt_i32 }; +const array_opt_i32 = { tag: "array", type: opt_i32 }; const labeledProduct = { - tag: 'labeledProduct', + tag: "labeledProduct", fields: { a: i32, b: opt_i32, @@ -22,8 +39,8 @@ const labeledProduct = { }; const struct = { - tag: 'struct', - name: 'someStruct', + tag: "struct", + name: "someStruct", fields: { a: i32, b: opt_i32, @@ -61,7 +78,7 @@ const structs = [ ]; const labeledProduct2 = { - tag: 'labeledProduct', + tag: "labeledProduct", fields: { x: i32, y: i32, @@ -69,15 +86,15 @@ const labeledProduct2 = { }; const nestedLabeledProductType = { - tag: 'labeledProduct', + tag: "labeledProduct", fields: { a: labeledProduct2, b: { - tag: 'option', + tag: "option", type: labeledProduct2, }, c: { - tag: 'array', + tag: "array", type: labeledProduct2, }, }, @@ -151,7 +168,7 @@ const nestedStructs = [ }, ]; -describe('Conversion from aqua to typescript', () => { +describe("Conversion from aqua to typescript", () => { test.each` aqua | ts | type ${1} | ${1} | ${i32} @@ -171,7 +188,7 @@ describe('Conversion from aqua to typescript', () => { ${nestedStructs[1].aqua} | ${nestedStructs[1].ts} | ${nestedLabeledProductType} `( // - 'aqua: $aqua. ts: $ts. type: $type', + "aqua: $aqua. ts: $ts. type: $type", async ({ aqua, ts, type }) => { // arrange @@ -186,11 +203,11 @@ describe('Conversion from aqua to typescript', () => { ); }); -describe('Conversion corner cases', () => { - it('Should accept undefined in object entry', () => { +describe("Conversion corner cases", () => { + it("Should accept undefined in object entry", () => { // arrange const type = { - tag: 'labeledProduct', + tag: "labeledProduct", fields: { x: opt_i32, y: opt_i32, @@ -200,6 +217,7 @@ describe('Conversion corner cases', () => { const valueInTs = { x: 1, }; + const valueInAqua = { x: [1], y: [], diff --git a/packages/core/js-client/src/compilerSupport/callFunction.ts b/packages/core/js-client/src/compilerSupport/callFunction.ts index 9f562aa67..28bd386d6 100644 --- a/packages/core/js-client/src/compilerSupport/callFunction.ts +++ b/packages/core/js-client/src/compilerSupport/callFunction.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,7 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { CallAquaFunctionType, getArgumentTypes, isReturnTypeVoid } from '@fluencelabs/interfaces'; + +import { + CallAquaFunctionType, + getArgumentTypes, + isReturnTypeVoid, +} from "@fluencelabs/interfaces"; + +import { logger } from "../util/logger.js"; import { errorHandlingService, @@ -23,12 +30,9 @@ import { responseService, ServiceDescription, userHandlerService, -} from './services.js'; - -import { logger } from '../util/logger.js'; -import { IParticle } from '../particle/interfaces.js'; +} from "./services.js"; -const log = logger('aqua'); +const log = logger("aqua"); /** * Convenience function which does all the internal work of creating particles @@ -41,57 +45,94 @@ const log = logger('aqua'); * @param args - args in the form of JSON where each key corresponds to the name of the argument * @returns */ -export const callAquaFunction: CallAquaFunctionType = async ({ def, script, config, peer, args }) => { - log.trace('calling aqua function %j', { def, script, config, args }); +export const callAquaFunction: CallAquaFunctionType = async ({ + def, + script, + config, + peer, + args, +}) => { + log.trace("calling aqua function %j", { def, script, config, args }); const argumentTypes = getArgumentTypes(def); - const particle = await peer.internals.createNewParticle(script, config?.ttl); + const particle = await peer.internals.createNewParticle( + script, + config?.ttl, + ); return new Promise((resolve, reject) => { if (particle instanceof Error) { return reject(particle.message); } - for (let [name, argVal] of Object.entries(args)) { + for (const [name, argVal] of Object.entries(args)) { const type = argumentTypes[name]; let service: ServiceDescription; - if (type.tag === 'arrow') { - service = userHandlerService(def.names.callbackSrv, [name, type], argVal); + + if (type.tag === "arrow") { + service = userHandlerService( + def.names.callbackSrv, + [name, type], + argVal, + ); } else { - service = injectValueService(def.names.getDataSrv, name, type, argVal); + service = injectValueService( + def.names.getDataSrv, + name, + type, + argVal, + ); } + registerParticleScopeService(peer, particle, service); } - registerParticleScopeService(peer, particle, responseService(def, resolve)); + registerParticleScopeService( + peer, + particle, + responseService(def, resolve), + ); - registerParticleScopeService(peer, particle, injectRelayService(def, peer)); + registerParticleScopeService( + peer, + particle, + injectRelayService(def, peer), + ); - registerParticleScopeService(peer, particle, errorHandlingService(def, reject)); + registerParticleScopeService( + peer, + particle, + errorHandlingService(def, reject), + ); peer.internals.initiateParticle(particle, (stage: any) => { // If function is void, then it's completed when one of the two conditions is met: // 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') - if (isReturnTypeVoid(def) && (stage.stage === 'sent' || stage.stage === 'localWorkDone')) { + if ( + isReturnTypeVoid(def) && + (stage.stage === "sent" || stage.stage === "localWorkDone") + ) { resolve(undefined); } - if (stage.stage === 'sendingError') { - reject(`Could not send particle for ${def.functionName}: not connected (particle id: ${particle.id})`); + if (stage.stage === "sendingError") { + reject( + `Could not send particle for ${def.functionName}: not connected (particle id: ${particle.id})`, + ); } - if (stage.stage === 'expired') { + if (stage.stage === "expired") { reject( `Particle expired after ttl of ${particle.ttl}ms for function ${def.functionName} (particle id: ${particle.id})`, ); } - if (stage.stage === 'interpreterError') { + if (stage.stage === "interpreterError") { reject( `Script interpretation failed for ${def.functionName}: ${stage.errorMessage} (particle id: ${particle.id})`, ); } }); - }) + }); }; diff --git a/packages/core/js-client/src/compilerSupport/conversions.ts b/packages/core/js-client/src/compilerSupport/conversions.ts index 5840313f4..b2f31d974 100644 --- a/packages/core/js-client/src/compilerSupport/conversions.ts +++ b/packages/core/js-client/src/compilerSupport/conversions.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,10 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { jsonify } from '../util/utils.js'; -import { match } from 'ts-pattern'; -import type { ArrowType, ArrowWithoutCallbacks, NonArrowType } from '@fluencelabs/interfaces'; -import { CallServiceData } from '../jsServiceHost/interfaces.js'; + +import type { + ArrowType, + ArrowWithoutCallbacks, + NonArrowType, +} 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 @@ -26,10 +32,10 @@ import { CallServiceData } from '../jsServiceHost/interfaces.js'; */ export const aqua2ts = (value: any, type: NonArrowType): any => { const res = match(type) - .with({ tag: 'nil' }, () => { + .with({ tag: "nil" }, () => { return null; }) - .with({ tag: 'option' }, (opt) => { + .with({ tag: "option" }, (opt) => { if (value.length === 0) { return null; } else { @@ -37,25 +43,32 @@ export const aqua2ts = (value: any, type: NonArrowType): any => { } }) // @ts-ignore - .with({ tag: 'scalar' }, { tag: 'bottomType' }, { tag: 'topType' }, () => { - return value; - }) - .with({ tag: 'array' }, (arr) => { - return value.map((y: any) => aqua2ts(y, arr.type)); + .with( + { tag: "scalar" }, + { tag: "bottomType" }, + { tag: "topType" }, + () => { + return value; + }, + ) + .with({ tag: "array" }, (arr) => { + return value.map((y: any) => { + return aqua2ts(y, arr.type); + }); }) - .with({ tag: 'struct' }, (x) => { + .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) => { + .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) => { + .with({ tag: "unlabeledProduct" }, (x) => { return x.items.map((type, index) => { return aqua2ts(value[index], type); }); @@ -63,8 +76,9 @@ export const aqua2ts = (value: any, type: NonArrowType): any => { // uncomment to check that every pattern in matched // .exhaustive(); .otherwise(() => { - throw new Error('Unexpected tag: ' + jsonify(type)); + throw new Error("Unexpected tag: " + jsonify(type)); }); + return res; }; @@ -74,25 +88,30 @@ export const aqua2ts = (value: any, type: NonArrowType): any => { * @param arrow - aqua type definition * @returns arguments in typescript representation */ -export const aquaArgs2Ts = (req: CallServiceData, arrow: ArrowWithoutCallbacks) => { +export const aquaArgs2Ts = ( + req: CallServiceData, + arrow: ArrowWithoutCallbacks, +) => { const argTypes = match(arrow.domain) - .with({ tag: 'labeledProduct' }, (x) => { + .with({ tag: "labeledProduct" }, (x) => { return Object.values(x.fields); }) - .with({ tag: 'unlabeledProduct' }, (x) => { + .with({ tag: "unlabeledProduct" }, (x) => { return x.items; }) - .with({ tag: 'nil' }, (x) => { + .with({ tag: "nil" }, (x) => { return []; }) // uncomment to check that every pattern in matched // .exhaustive() .otherwise(() => { - throw new Error('Unexpected tag: ' + jsonify(arrow.domain)); + 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}`); + throw new Error( + `incorrect number of arguments, expected: ${argTypes.length}, got: ${req.args.length}`, + ); } return req.args.map((arg, index) => { @@ -108,10 +127,10 @@ export const aquaArgs2Ts = (req: CallServiceData, arrow: ArrowWithoutCallbacks) */ export const ts2aqua = (value: any, type: NonArrowType): any => { const res = match(type) - .with({ tag: 'nil' }, () => { + .with({ tag: "nil" }, () => { return null; }) - .with({ tag: 'option' }, (opt) => { + .with({ tag: "option" }, (opt) => { if (value === null || value === undefined) { return []; } else { @@ -119,25 +138,32 @@ export const ts2aqua = (value: any, type: NonArrowType): any => { } }) // @ts-ignore - .with({ tag: 'scalar' }, { tag: 'bottomType' }, { tag: 'topType' }, () => { - return value; - }) - .with({ tag: 'array' }, (arr) => { - return value.map((y: any) => ts2aqua(y, arr.type)); + .with( + { tag: "scalar" }, + { tag: "bottomType" }, + { tag: "topType" }, + () => { + return value; + }, + ) + .with({ tag: "array" }, (arr) => { + return value.map((y: any) => { + return ts2aqua(y, arr.type); + }); }) - .with({ tag: 'struct' }, (x) => { + .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) => { + .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) => { + .with({ tag: "unlabeledProduct" }, (x) => { return x.items.map((type, index) => { return ts2aqua(value[index], type); }); @@ -145,7 +171,7 @@ export const ts2aqua = (value: any, type: NonArrowType): any => { // uncomment to check that every pattern in matched // .exhaustive() .otherwise(() => { - throw new Error('Unexpected tag: ' + jsonify(type)); + throw new Error("Unexpected tag: " + jsonify(type)); }); return res; @@ -157,8 +183,11 @@ export const ts2aqua = (value: any, type: NonArrowType): any => { * @param arrowType - the arrow type which describes the service * @returns - value represented in aqua */ -export const returnType2Aqua = (returnValue: any, arrowType: ArrowType) => { - if (arrowType.codomain.tag === 'nil') { +export const returnType2Aqua = ( + returnValue: any, + arrowType: ArrowType, +) => { + if (arrowType.codomain.tag === "nil") { return {}; } @@ -181,12 +210,15 @@ export const returnType2Aqua = (returnValue: any, arrowType: ArrowType) => { +export const responseServiceValue2ts = ( + req: CallServiceData, + arrow: ArrowType, +) => { return match(arrow.codomain) - .with({ tag: 'nil' }, () => { + .with({ tag: "nil" }, () => { return undefined; }) - .with({ tag: 'unlabeledProduct' }, (x) => { + .with({ tag: "unlabeledProduct" }, (x) => { if (x.items.length === 0) { return undefined; } @@ -195,7 +227,9 @@ export const responseServiceValue2ts = (req: CallServiceData, arrow: ArrowType aqua2ts(y, x.items[index])); + return req.args.map((y, index) => { + return aqua2ts(y, x.items[index]); + }); }) .exhaustive(); }; diff --git a/packages/core/js-client/src/compilerSupport/registerService.ts b/packages/core/js-client/src/compilerSupport/registerService.ts index 3c687b8ce..5506520b4 100644 --- a/packages/core/js-client/src/compilerSupport/registerService.ts +++ b/packages/core/js-client/src/compilerSupport/registerService.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,23 +13,39 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import type { RegisterServiceType } from '@fluencelabs/interfaces'; -import { registerGlobalService, userHandlerService } from './services.js'; -import { logger } from '../util/logger.js'; +import type { RegisterServiceType } from "@fluencelabs/interfaces"; -const log = logger('aqua'); +import { logger } from "../util/logger.js"; -export const registerService: RegisterServiceType = ({ peer, def, serviceId, service }) => { - log.trace('registering aqua service %o', { def, serviceId, service }); +import { registerGlobalService, userHandlerService } from "./services.js"; + +const log = logger("aqua"); + +export const registerService: RegisterServiceType = ({ + peer, + def, + serviceId, + service, +}) => { + log.trace("registering aqua service %o", { def, serviceId, service }); // Checking for missing keys - const requiredKeys = def.functions.tag === 'nil' ? [] : Object.keys(def.functions.fields); - const incorrectServiceDefinitions = requiredKeys.filter((f) => !(f in service)); - if (!!incorrectServiceDefinitions.length) { + const requiredKeys = + def.functions.tag === "nil" ? [] : Object.keys(def.functions.fields); + + const incorrectServiceDefinitions = requiredKeys.filter((f) => { + return !(f in service); + }); + + if (incorrectServiceDefinitions.length > 0) { throw new Error( `Error registering service ${serviceId}: missing functions: ` + - incorrectServiceDefinitions.map((d) => "'" + d + "'").join(', '), + incorrectServiceDefinitions + .map((d) => { + return "'" + d + "'"; + }) + .join(", "), ); } @@ -38,18 +54,26 @@ export const registerService: RegisterServiceType = ({ peer, def, serviceId, ser } if (!serviceId) { - throw new Error('Service ID must be specified'); + throw new Error("Service ID must be specified"); } - const singleFunctions = def.functions.tag === 'nil' ? [] : Object.entries(def.functions.fields); - for (let singleFunction of singleFunctions) { - let [name, type] = singleFunction; + const singleFunctions = + def.functions.tag === "nil" ? [] : Object.entries(def.functions.fields); + + for (const singleFunction of singleFunctions) { + const [name, type] = singleFunction; // The function has type of (arg1, arg2, arg3, ... , callParams) => CallServiceResultType | void // Account for the fact that user service might be defined as a class - .bind(...) const userDefinedHandler = service[name].bind(service); - const serviceDescription = userHandlerService(serviceId, singleFunction, userDefinedHandler); + const serviceDescription = userHandlerService( + serviceId, + singleFunction, + userDefinedHandler, + ); + registerGlobalService(peer, serviceDescription); } - log.trace('aqua service registered %s', serviceId); + + log.trace("aqua service registered %s", serviceId); }; diff --git a/packages/core/js-client/src/compilerSupport/services.ts b/packages/core/js-client/src/compilerSupport/services.ts index 7da4c51eb..fb3b2a6a6 100644 --- a/packages/core/js-client/src/compilerSupport/services.ts +++ b/packages/core/js-client/src/compilerSupport/services.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,12 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { SecurityTetraplet } from '@fluencelabs/avm'; -import { match } from 'ts-pattern'; - -import { Particle } from '../particle/Particle.js'; -import { aquaArgs2Ts, responseServiceValue2ts, returnType2Aqua, ts2aqua } from './conversions.js'; +import { SecurityTetraplet } from "@fluencelabs/avm"; import { CallParams, ArrowWithoutCallbacks, @@ -26,9 +22,23 @@ import { FunctionCallDef, NonArrowType, IFluenceInternalApi, -} from '@fluencelabs/interfaces'; -import { CallServiceData, GenericCallServiceHandler, ResultCodes } from '../jsServiceHost/interfaces.js'; -import { fromUint8Array } from 'js-base64'; +} from "@fluencelabs/interfaces"; +import { fromUint8Array } from "js-base64"; +import { match } from "ts-pattern"; + +import { + CallServiceData, + GenericCallServiceHandler, + ResultCodes, +} from "../jsServiceHost/interfaces.js"; +import { Particle } from "../particle/Particle.js"; + +import { + aquaArgs2Ts, + responseServiceValue2ts, + returnType2Aqua, + ts2aqua, +} from "./conversions.js"; export interface ServiceDescription { serviceId: string; @@ -39,7 +49,10 @@ export interface ServiceDescription { /** * Creates a service which injects relay's peer id into aqua space */ -export const injectRelayService = (def: FunctionCallDef, peer: IFluenceInternalApi) => { +export const injectRelayService = ( + def: FunctionCallDef, + peer: IFluenceInternalApi, +) => { return { serviceId: def.names.getDataSrv, fnName: def.names.relay, @@ -55,7 +68,12 @@ export const injectRelayService = (def: FunctionCallDef, peer: IFluenceInternalA /** * Creates a service which injects plain value into aqua space */ -export const injectValueService = (serviceId: string, fnName: string, valueType: NonArrowType, value: any) => { +export const injectValueService = ( + serviceId: string, + fnName: string, + valueType: NonArrowType, + value: any, +) => { return { serviceId: serviceId, fnName: fnName, @@ -71,7 +89,10 @@ export const injectValueService = (serviceId: string, fnName: string, valueType: /** * Creates a service which is used to return value from aqua function into typescript space */ -export const responseService = (def: FunctionCallDef, resolveCallback: Function) => { +export const responseService = ( + def: FunctionCallDef, + resolveCallback: Function, +) => { return { serviceId: def.names.responseSrv, fnName: def.names.responseFnName, @@ -93,15 +114,20 @@ export const responseService = (def: FunctionCallDef, resolveCallback: Function) /** * Creates a service which is used to return errors from aqua function into typescript space */ -export const errorHandlingService = (def: FunctionCallDef, rejectCallback: Function) => { +export const errorHandlingService = ( + def: FunctionCallDef, + rejectCallback: Function, +) => { return { serviceId: def.names.errorHandlingSrv, fnName: def.names.errorFnName, handler: (req: CallServiceData) => { const [err, _] = req.args; + setTimeout(() => { rejectCallback(err); }, 0); + return { retCode: ResultCodes.success, result: {}, @@ -123,7 +149,11 @@ export const userHandlerService = ( serviceId, fnName, handler: async (req: CallServiceData) => { - const args = [...aquaArgs2Ts(req, type), extractCallParams(req, type)]; + const args = [ + ...aquaArgs2Ts(req, type), + extractCallParams(req, type), + ]; + const rawResult = await userHandler.apply(null, args); const result = returnType2Aqua(rawResult, type); @@ -146,7 +176,7 @@ export const argToServiceDef = ( argType: NonArrowType | ArrowWithoutCallbacks, names: FunctionCallConstants, ): ServiceDescription => { - if (argType.tag === 'arrow') { + if (argType.tag === "arrow") { return userHandlerService(names.callbackSrv, [argName, argType], arg); } else { return injectValueService(names.getDataSrv, argName, arg, argType); @@ -156,20 +186,26 @@ export const argToServiceDef = ( /** * Extracts call params from from call service data according to aqua type definition */ -const extractCallParams = (req: CallServiceData, arrow: ArrowWithoutCallbacks): CallParams => { +const extractCallParams = ( + req: CallServiceData, + arrow: ArrowWithoutCallbacks, +): CallParams => { const names = match(arrow.domain) - .with({ tag: 'nil' }, () => { + .with({ tag: "nil" }, () => { return [] as string[]; }) - .with({ tag: 'labeledProduct' }, (x) => { + .with({ tag: "labeledProduct" }, (x) => { return Object.keys(x.fields); }) - .with({ tag: 'unlabeledProduct' }, (x) => { - return x.items.map((_, index) => 'arg' + index); + .with({ tag: "unlabeledProduct" }, (x) => { + return x.items.map((_, index) => { + return "arg" + index; + }); }) .exhaustive(); const tetraplets: Record = {}; + for (let i = 0; i < req.args.length; i++) { if (names[i]) { tetraplets[names[i]] = req.tetraplets[i]; @@ -190,9 +226,21 @@ export const registerParticleScopeService = ( particle: Particle, service: ServiceDescription, ) => { - peer.internals.regHandler.forParticle(particle.id, service.serviceId, service.fnName, service.handler); + peer.internals.regHandler.forParticle( + particle.id, + service.serviceId, + service.fnName, + service.handler, + ); }; -export const registerGlobalService = (peer: IFluenceInternalApi, service: ServiceDescription) => { - peer.internals.regHandler.common(service.serviceId, service.fnName, service.handler); +export const registerGlobalService = ( + peer: IFluenceInternalApi, + service: ServiceDescription, +) => { + peer.internals.regHandler.common( + service.serviceId, + service.fnName, + service.handler, + ); }; diff --git a/packages/core/js-client/src/connection/RelayConnection.ts b/packages/core/js-client/src/connection/RelayConnection.ts index 774a1677f..393788f34 100644 --- a/packages/core/js-client/src/connection/RelayConnection.ts +++ b/packages/core/js-client/src/connection/RelayConnection.ts @@ -1,5 +1,5 @@ -/* - * Copyright 2020 Fluence Labs Limited +/** + * 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. @@ -13,38 +13,40 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { PeerIdB58 } from '@fluencelabs/interfaces'; -import { pipe } from 'it-pipe'; -import { decode, encode } from 'it-length-prefixed'; -import type { PeerId } from '@libp2p/interface/peer-id'; -import { createLibp2p, Libp2p } from 'libp2p'; - -import { noise } from '@chainsafe/libp2p-noise'; -import { yamux } from '@chainsafe/libp2p-yamux'; -import { webSockets } from '@libp2p/websockets'; -import { all } from '@libp2p/websockets/filters'; -import { multiaddr, type Multiaddr } from '@multiformats/multiaddr'; - -import map from 'it-map'; -import { fromString } from 'uint8arrays/from-string'; -import { toString } from 'uint8arrays/to-string'; - -import { logger } from '../util/logger.js'; -import { Subject } from 'rxjs'; -import { throwIfHasNoPeerId } from '../util/libp2pUtils.js'; -import { IConnection } from './interfaces.js'; -import { IParticle } from '../particle/interfaces.js'; -import { Particle, serializeToString, verifySignature } from '../particle/Particle.js'; -import { identifyService } from 'libp2p/identify'; -import { pingService } from 'libp2p/ping'; -import { unmarshalPublicKey } from '@libp2p/crypto/keys'; -import { peerIdFromString } from '@libp2p/peer-id'; -import { Stream } from '@libp2p/interface/connection'; -import { KeyPair } from '../keypair/index.js'; - -const log = logger('connection'); - -export const PROTOCOL_NAME = '/fluence/particle/2.0.0'; + +import { noise } from "@chainsafe/libp2p-noise"; +import { yamux } from "@chainsafe/libp2p-yamux"; +import { PeerIdB58 } from "@fluencelabs/interfaces"; +import { Stream } from "@libp2p/interface/connection"; +import type { PeerId } from "@libp2p/interface/peer-id"; +import { peerIdFromString } from "@libp2p/peer-id"; +import { webSockets } from "@libp2p/websockets"; +import { all } from "@libp2p/websockets/filters"; +import { multiaddr, type Multiaddr } from "@multiformats/multiaddr"; +import { decode, encode } from "it-length-prefixed"; +import map from "it-map"; +import { pipe } from "it-pipe"; +import { createLibp2p, Libp2p } from "libp2p"; +import { identifyService } from "libp2p/identify"; +import { pingService } from "libp2p/ping"; +import { Subject } from "rxjs"; +import { fromString } from "uint8arrays/from-string"; +import { toString } from "uint8arrays/to-string"; + +import { IParticle } from "../particle/interfaces.js"; +import { + Particle, + serializeToString, + verifySignature, +} from "../particle/Particle.js"; +import { throwIfHasNoPeerId } from "../util/libp2pUtils.js"; +import { logger } from "../util/logger.js"; + +import { IConnection } from "./interfaces.js"; + +const log = logger("connection"); + +export const PROTOCOL_NAME = "/fluence/particle/2.0.0"; /** * Options to configure fluence relay connection @@ -121,19 +123,24 @@ export class RelayConnection implements IConnection { }, connectionGater: { // By default, this function forbids connections to private peers. For example multiaddr with ip 127.0.0.1 isn't allowed - denyDialMultiaddr: () => Promise.resolve(false) + denyDialMultiaddr: () => { + return Promise.resolve(false); + }, }, services: { identify: identifyService(), - ping: pingService() - } + ping: pingService(), + }, }); - const supportedProtocols = (await this.lib2p2Peer.peerStore.get(this.lib2p2Peer.peerId)).protocols; + const supportedProtocols = ( + await this.lib2p2Peer.peerStore.get(this.lib2p2Peer.peerId) + ).protocols; + await this.lib2p2Peer.peerStore.patch(this.lib2p2Peer.peerId, { - protocols: [...supportedProtocols, PROTOCOL_NAME] + protocols: [...supportedProtocols, PROTOCOL_NAME], }); - + await this.connect(); } @@ -147,12 +154,18 @@ export class RelayConnection implements IConnection { await this.lib2p2Peer.stop(); } - async sendParticle(nextPeerIds: PeerIdB58[], particle: IParticle): Promise { + async sendParticle( + nextPeerIds: PeerIdB58[], + particle: IParticle, + ): Promise { if (this.lib2p2Peer === null) { - throw new Error('Relay connection is not started'); + throw new Error("Relay connection is not started"); } - if (nextPeerIds.length !== 1 && nextPeerIds[0] !== this.getRelayPeerId()) { + if ( + nextPeerIds.length !== 1 && + nextPeerIds[0] !== this.getRelayPeerId() + ) { throw new Error( `Relay connection only accepts peer id of the connected relay. Got: ${JSON.stringify( nextPeerIds, @@ -160,80 +173,120 @@ export class RelayConnection implements IConnection { ); } - log.trace('sending particle...'); + log.trace("sending particle..."); + // Reusing active connection here - const stream = await this.lib2p2Peer.dialProtocol(this.relayAddress, PROTOCOL_NAME); - log.trace('created stream with id ', stream.id); + const stream = await this.lib2p2Peer.dialProtocol( + this.relayAddress, + PROTOCOL_NAME, + ); + + log.trace("created stream with id ", stream.id); const sink = stream.sink; - await pipe( - [fromString(serializeToString(particle))], - encode(), - sink, - ); - log.trace('data written to sink'); + await pipe([fromString(serializeToString(particle))], encode(), sink); + log.trace("data written to sink"); } - + private async processIncomingMessage(msg: string, stream: Stream) { let particle: Particle | undefined; + try { particle = Particle.fromString(msg); - log.trace('got particle from stream with id %s and particle id %s', stream.id, particle.id); + + log.trace( + "got particle from stream with id %s and particle id %s", + stream.id, + particle.id, + ); + const initPeerId = peerIdFromString(particle.initPeerId); if (initPeerId.publicKey === undefined) { - log.error('cannot retrieve public key from init_peer_id. particle id: %s. init_peer_id: %s', particle.id, particle.initPeerId); + log.error( + "cannot retrieve public key from init_peer_id. particle id: %s. init_peer_id: %s", + particle.id, + particle.initPeerId, + ); + return; } - - const isVerified = await verifySignature(particle, initPeerId.publicKey); + + const isVerified = await verifySignature( + particle, + initPeerId.publicKey, + ); + if (isVerified) { this.particleSource.next(particle); } else { - log.trace('particle signature is incorrect. rejecting particle with id: %s', particle.id); + log.trace( + "particle signature is incorrect. rejecting particle with id: %s", + particle.id, + ); } } catch (e) { const particleId = particle?.id; - const particleIdMessage = typeof particleId === 'string' ? `. particle id: ${particleId}` : ''; - log.error(`error on handling an incoming message: %O%s`, e, particleIdMessage); + + const particleIdMessage = + typeof particleId === "string" + ? `. particle id: ${particleId}` + : ""; + + log.error( + `error on handling an incoming message: %O%s`, + e, + particleIdMessage, + ); } } private async connect() { if (this.lib2p2Peer === null) { - throw new Error('Relay connection is not started'); + throw new Error("Relay connection is not started"); } await this.lib2p2Peer.handle( [PROTOCOL_NAME], - async ({ connection, stream }) => pipe( - stream.source, - decode(), - (source) => map(source, (buf) => toString(buf.subarray())), - async (source) => { - try { - for await (const msg of source) { - await this.processIncomingMessage(msg, stream); + async ({ connection, stream }) => { + return pipe( + stream.source, + decode(), + (source) => { + return map(source, (buf) => { + return toString(buf.subarray()); + }); + }, + async (source) => { + try { + for await (const msg of source) { + await this.processIncomingMessage(msg, stream); + } + } catch (e) { + log.error("connection closed: %j", e); } - } catch (e) { - log.error('connection closed: %j', e); - } - }, - ), + }, + ); + }, { maxInboundStreams: this.config.maxInboundStreams, maxOutboundStreams: this.config.maxOutboundStreams, }, ); - log.debug("dialing to the node with client's address: %s", this.lib2p2Peer.peerId.toString()); + log.debug( + "dialing to the node with client's address: %s", + this.lib2p2Peer.peerId.toString(), + ); try { await this.lib2p2Peer.dial(this.relayAddress); } catch (e: any) { - if (e.name === 'AggregateError' && e._errors?.length === 1) { + if (e.name === "AggregateError" && e._errors?.length === 1) { const error = e._errors[0]; - throw new Error(`Error dialing node ${this.relayAddress}:\n${error.code}\n${error.message}`); + throw new Error( + `Error dialing node ${this.relayAddress}:\n${error.code}\n${error.message}`, + ); } else { throw e; } diff --git a/packages/core/js-client/src/connection/interfaces.ts b/packages/core/js-client/src/connection/interfaces.ts index b285cdfb9..bb5619a84 100644 --- a/packages/core/js-client/src/connection/interfaces.ts +++ b/packages/core/js-client/src/connection/interfaces.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,10 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import type { PeerIdB58 } from '@fluencelabs/interfaces'; -import type { Subscribable } from 'rxjs'; -import { IParticle } from '../particle/interfaces.js'; -import { IStartable } from '../util/commonTypes.js'; + +import type { PeerIdB58 } from "@fluencelabs/interfaces"; +import type { Subscribable } from "rxjs"; + +import { IParticle } from "../particle/interfaces.js"; +import { IStartable } from "../util/commonTypes.js"; /** * Interface for connection used in Fluence Peer. diff --git a/packages/core/js-client/src/ephemeral/__test__/ephemeral.spec.ts b/packages/core/js-client/src/ephemeral/__test__/ephemeral.spec.ts index c9aad47e9..9af02271c 100644 --- a/packages/core/js-client/src/ephemeral/__test__/ephemeral.spec.ts +++ b/packages/core/js-client/src/ephemeral/__test__/ephemeral.spec.ts @@ -1,17 +1,36 @@ -import { it, describe, expect, beforeEach, afterEach } from 'vitest'; -import { DEFAULT_CONFIG, FluencePeer } from '../../jsPeer/FluencePeer.js'; -import { CallServiceData, ResultCodes } from '../../jsServiceHost/interfaces.js'; -import { KeyPair } from '../../keypair/index.js'; -import { EphemeralNetworkClient } from '../client.js'; +/** + * 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 { EphemeralNetwork, defaultConfig } from '../network.js'; +import { it, describe, expect, beforeEach, afterEach } from "vitest"; + +import { DEFAULT_CONFIG, FluencePeer } from "../../jsPeer/FluencePeer.js"; +import { + CallServiceData, + ResultCodes, +} from "../../jsServiceHost/interfaces.js"; +import { KeyPair } from "../../keypair/index.js"; +import { EphemeralNetworkClient } from "../client.js"; +import { EphemeralNetwork, defaultConfig } from "../network.js"; let en: EphemeralNetwork; let client: FluencePeer; const relay = defaultConfig.peers[0].peerId; // TODO: race condition here. Needs to be fixed -describe.skip('Ephemeral networks tests', () => { +describe.skip("Ephemeral networks tests", () => { beforeEach(async () => { en = new EphemeralNetwork(defaultConfig); await en.up(); @@ -25,14 +44,17 @@ describe.skip('Ephemeral networks tests', () => { if (client) { await client.stop(); } + if (en) { await en.down(); } }); - it('smoke test', async function () { + it("smoke test", async function () { // arrange - const peers = defaultConfig.peers.map((x) => x.peerId); + const peers = defaultConfig.peers.map((x) => { + return x.peerId; + }); const script = ` (seq @@ -62,19 +84,24 @@ describe.skip('Ephemeral networks tests', () => { const particle = await client.internals.createNewParticle(script); const promise = new Promise((resolve) => { - client.internals.regHandler.forParticle(particle.id, 'test', 'test', (req: CallServiceData) => { - resolve('success'); - return { - result: 'test', - retCode: ResultCodes.success, - }; - }); + client.internals.regHandler.forParticle( + particle.id, + "test", + "test", + (req: CallServiceData) => { + resolve("success"); + return { + result: "test", + retCode: ResultCodes.success, + }; + }, + ); }); // act client.internals.initiateParticle(particle, () => {}); // assert - await expect(promise).resolves.toBe('success'); + await expect(promise).resolves.toBe("success"); }); }); diff --git a/packages/core/js-client/src/ephemeral/client.ts b/packages/core/js-client/src/ephemeral/client.ts index 78cb98095..117cbb28e 100644 --- a/packages/core/js-client/src/ephemeral/client.ts +++ b/packages/core/js-client/src/ephemeral/client.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,24 +13,46 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { PeerIdB58 } from '@fluencelabs/interfaces'; -import { FluencePeer, PeerConfig } from '../jsPeer/FluencePeer.js'; -import { KeyPair } from '../keypair/index.js'; -import { WasmLoaderFromNpm } from '../marine/deps-loader/node.js'; -import { WorkerLoader } from '../marine/worker-script/workerLoader.js'; -import { MarineBackgroundRunner } from '../marine/worker/index.js'; -import { EphemeralNetwork } from './network.js'; -import { JsServiceHost } from '../jsServiceHost/JsServiceHost.js'; + +import { PeerIdB58 } from "@fluencelabs/interfaces"; + +import { FluencePeer, PeerConfig } from "../jsPeer/FluencePeer.js"; +import { JsServiceHost } from "../jsServiceHost/JsServiceHost.js"; +import { KeyPair } from "../keypair/index.js"; +import { WasmLoaderFromNpm } from "../marine/deps-loader/node.js"; +import { MarineBackgroundRunner } from "../marine/worker/index.js"; +import { WorkerLoader } from "../marine/worker-script/workerLoader.js"; + +import { EphemeralNetwork } from "./network.js"; /** * Ephemeral network client is a FluencePeer that connects to a relay peer in an ephemeral network. */ export class EphemeralNetworkClient extends FluencePeer { - constructor(config: PeerConfig, keyPair: KeyPair, network: EphemeralNetwork, relay: PeerIdB58) { + constructor( + config: PeerConfig, + keyPair: KeyPair, + network: EphemeralNetwork, + relay: PeerIdB58, + ) { const workerLoader = new WorkerLoader(); - const controlModuleLoader = new WasmLoaderFromNpm('@fluencelabs/marine-js', 'marine-js.wasm'); - const avmModuleLoader = new WasmLoaderFromNpm('@fluencelabs/avm', 'avm.wasm'); - const marine = new MarineBackgroundRunner(workerLoader, controlModuleLoader, avmModuleLoader); + + const controlModuleLoader = new WasmLoaderFromNpm( + "@fluencelabs/marine-js", + "marine-js.wasm", + ); + + const avmModuleLoader = new WasmLoaderFromNpm( + "@fluencelabs/avm", + "avm.wasm", + ); + + const marine = new MarineBackgroundRunner( + workerLoader, + controlModuleLoader, + avmModuleLoader, + ); + const conn = network.getRelayConnection(keyPair.getPeerId(), relay); super(config, keyPair, marine, new JsServiceHost(), conn); } diff --git a/packages/core/js-client/src/ephemeral/network.ts b/packages/core/js-client/src/ephemeral/network.ts index b953adcb4..dc143fe93 100644 --- a/packages/core/js-client/src/ephemeral/network.ts +++ b/packages/core/js-client/src/ephemeral/network.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,23 +13,24 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { PeerIdB58 } from '@fluencelabs/interfaces'; -import { fromBase64Sk, KeyPair } from '../keypair/index.js'; -import { MarineBackgroundRunner } from '../marine/worker/index.js'; - -import { WorkerLoaderFromFs } from '../marine/deps-loader/node.js'; -import { logger } from '../util/logger.js'; -import { Subject } from 'rxjs'; -import { Particle } from '../particle/Particle.js'; +import { PeerIdB58 } from "@fluencelabs/interfaces"; +import { Subject } from "rxjs"; -import { WasmLoaderFromNpm } from '../marine/deps-loader/node.js'; -import { DEFAULT_CONFIG, FluencePeer } from '../jsPeer/FluencePeer.js'; -import { IConnection } from '../connection/interfaces.js'; -import { IAvmRunner, IMarineHost } from '../marine/interfaces.js'; -import { JsServiceHost } from '../jsServiceHost/JsServiceHost.js'; +import { IConnection } from "../connection/interfaces.js"; +import { DEFAULT_CONFIG, FluencePeer } from "../jsPeer/FluencePeer.js"; +import { JsServiceHost } from "../jsServiceHost/JsServiceHost.js"; +import { fromBase64Sk, KeyPair } from "../keypair/index.js"; +import { + WorkerLoaderFromFs, + WasmLoaderFromNpm, +} from "../marine/deps-loader/node.js"; +import { IMarineHost } from "../marine/interfaces.js"; +import { MarineBackgroundRunner } from "../marine/worker/index.js"; +import { Particle } from "../particle/Particle.js"; +import { logger } from "../util/logger.js"; -const log = logger('ephemeral'); +const log = logger("ephemeral"); interface EphemeralConfig { peers: Array<{ @@ -41,84 +42,84 @@ interface EphemeralConfig { export const defaultConfig = { peers: [ { - peerId: '12D3KooWJankP2PcEDYCZDdJ26JsU8BMRfdGWyGqbtFiWyoKVtmx', - sk: 'dWNAHhDVuFj9bEieILMu6TcCFRxBJdOPIvAWmf4sZQI=', + peerId: "12D3KooWJankP2PcEDYCZDdJ26JsU8BMRfdGWyGqbtFiWyoKVtmx", + sk: "dWNAHhDVuFj9bEieILMu6TcCFRxBJdOPIvAWmf4sZQI=", }, { - peerId: '12D3KooWSBTB5sYxdwayUyTnqopBwABsnGFY3p4dTx5hABYDtJjV', - sk: 'dOmaxAeu4Th+MJ22vRDLMFTNbiDgKNXar9fW9ofAMgQ=', + peerId: "12D3KooWSBTB5sYxdwayUyTnqopBwABsnGFY3p4dTx5hABYDtJjV", + sk: "dOmaxAeu4Th+MJ22vRDLMFTNbiDgKNXar9fW9ofAMgQ=", }, { - peerId: '12D3KooWQjwf781DJ41moW5RrZXypLdnTbo6aMsoA8QLctGGX8RB', - sk: 'TgzaLlxXuOMDNuuuTKEHUKsW0jM4AmX0gahFvkB1KgE=', + peerId: "12D3KooWQjwf781DJ41moW5RrZXypLdnTbo6aMsoA8QLctGGX8RB", + sk: "TgzaLlxXuOMDNuuuTKEHUKsW0jM4AmX0gahFvkB1KgE=", }, { - peerId: '12D3KooWCXWTLFyY1mqKnNAhLQTsjW1zqDzCMbUs8M4a8zdz28HK', - sk: 'hiO2Ta8g2ibMQ7iu5yj9CfN+qQCwE8oRShjr7ortKww=', + peerId: "12D3KooWCXWTLFyY1mqKnNAhLQTsjW1zqDzCMbUs8M4a8zdz28HK", + sk: "hiO2Ta8g2ibMQ7iu5yj9CfN+qQCwE8oRShjr7ortKww=", }, { - peerId: '12D3KooWPmZpf4ng6GMS39HLagxsXbjiTPLH5CFJpFAHyN6amw6V', - sk: 'LzJtOHTqxfrlHDW40BKiLfjai8JU4yW6/s2zrXLCcQE=', + peerId: "12D3KooWPmZpf4ng6GMS39HLagxsXbjiTPLH5CFJpFAHyN6amw6V", + sk: "LzJtOHTqxfrlHDW40BKiLfjai8JU4yW6/s2zrXLCcQE=", }, { - peerId: '12D3KooWKrx8PZxM1R9A8tp2jmrFf6c6q1ZQiWfD4QkNgh7fWSoF', - sk: 'XMhlk/xr1FPcp7sKQhS18doXlq1x16EMhBC2NGW2LQ4=', + peerId: "12D3KooWKrx8PZxM1R9A8tp2jmrFf6c6q1ZQiWfD4QkNgh7fWSoF", + sk: "XMhlk/xr1FPcp7sKQhS18doXlq1x16EMhBC2NGW2LQ4=", }, { - peerId: '12D3KooWCbJHvnzSZEXjR1UJmtSUozuJK13iRiCYHLN1gjvm4TZZ', - sk: 'KXPAIqxrSHr7v0ngv3qagcqivFvnQ0xd3s1/rKmi8QU=', + peerId: "12D3KooWCbJHvnzSZEXjR1UJmtSUozuJK13iRiCYHLN1gjvm4TZZ", + sk: "KXPAIqxrSHr7v0ngv3qagcqivFvnQ0xd3s1/rKmi8QU=", }, { - peerId: '12D3KooWEvKe7WQHp42W4xhHRgTAWQjtDWyH38uJbLHAsMuTtYvD', - sk: 'GCYMAshGnsrNtrHhuT7ayzh5uCzX99J03PmAXoOcCgw=', + peerId: "12D3KooWEvKe7WQHp42W4xhHRgTAWQjtDWyH38uJbLHAsMuTtYvD", + sk: "GCYMAshGnsrNtrHhuT7ayzh5uCzX99J03PmAXoOcCgw=", }, { - peerId: '12D3KooWSznSHN3BGrSykBXkLkFsqo9SYB73wVauVdqeuRt562cC', - sk: 'UP+SEuznS0h259VbFquzyOJAQ4W5iIwhP+hd1PmUQQ0=', + peerId: "12D3KooWSznSHN3BGrSykBXkLkFsqo9SYB73wVauVdqeuRt562cC", + sk: "UP+SEuznS0h259VbFquzyOJAQ4W5iIwhP+hd1PmUQQ0=", }, { - peerId: '12D3KooWF57jwbShfnT3c4dNfRDdGjr6SQ3B71m87UVpEpSWHFwi', - sk: '8dl+Crm5RSh0eh+LqLKwX8/Eo4QLpvIjfD8L0wzX4A4=', + peerId: "12D3KooWF57jwbShfnT3c4dNfRDdGjr6SQ3B71m87UVpEpSWHFwi", + sk: "8dl+Crm5RSh0eh+LqLKwX8/Eo4QLpvIjfD8L0wzX4A4=", }, { - peerId: '12D3KooWBWrzpSg9nwMLBCa2cJubUjTv63Mfy6PYg9rHGbetaV5C', - sk: 'qolc1FcpJ+vHDon0HeXdUYnstjV1wiVx2p0mjblrfAg=', + peerId: "12D3KooWBWrzpSg9nwMLBCa2cJubUjTv63Mfy6PYg9rHGbetaV5C", + sk: "qolc1FcpJ+vHDon0HeXdUYnstjV1wiVx2p0mjblrfAg=", }, { - peerId: '12D3KooWNkLVU6juM8oyN2SVq5nBd2kp7Rf4uzJH1hET6vj6G5j6', - sk: 'vN6QzWILTM7hSHp+iGkKxiXcqs8bzlnH3FPaRaDGSQY=', + peerId: "12D3KooWNkLVU6juM8oyN2SVq5nBd2kp7Rf4uzJH1hET6vj6G5j6", + sk: "vN6QzWILTM7hSHp+iGkKxiXcqs8bzlnH3FPaRaDGSQY=", }, { - peerId: '12D3KooWKo1YwGL5vivPiKJMJS7wjtB6B2nJNdSXPkSABT4NKBUU', - sk: 'YbDQ++bsor2kei7rYAsu2SbyoiOYPRzFRZWnNRUpBgQ=', + peerId: "12D3KooWKo1YwGL5vivPiKJMJS7wjtB6B2nJNdSXPkSABT4NKBUU", + sk: "YbDQ++bsor2kei7rYAsu2SbyoiOYPRzFRZWnNRUpBgQ=", }, { - peerId: '12D3KooWLUyBKmmNCyxaPkXoWcUFPcy5qrZsUo2E1tyM6CJmGJvC', - sk: 'ptB9eSFMKudAtHaFgDrRK/1oIMrhBujxbMw2Pzwx/wA=', + peerId: "12D3KooWLUyBKmmNCyxaPkXoWcUFPcy5qrZsUo2E1tyM6CJmGJvC", + sk: "ptB9eSFMKudAtHaFgDrRK/1oIMrhBujxbMw2Pzwx/wA=", }, { - peerId: '12D3KooWAEZXME4KMu9FvLezsJWDbYFe2zyujyMnDT1AgcAxgcCk', - sk: 'xtwTOKgAbDIgkuPf7RKiR7gYyZ1HY4mOgFMv3sOUcAQ=', + peerId: "12D3KooWAEZXME4KMu9FvLezsJWDbYFe2zyujyMnDT1AgcAxgcCk", + sk: "xtwTOKgAbDIgkuPf7RKiR7gYyZ1HY4mOgFMv3sOUcAQ=", }, { - peerId: '12D3KooWEhXetsFVAD9h2dRz9XgFpfidho1TCZVhFrczX8h8qgzY', - sk: '1I2MGuiKG1F4FDMiRihVOcOP2mxzOLWJ99MeexK27A4=', + peerId: "12D3KooWEhXetsFVAD9h2dRz9XgFpfidho1TCZVhFrczX8h8qgzY", + sk: "1I2MGuiKG1F4FDMiRihVOcOP2mxzOLWJ99MeexK27A4=", }, { - peerId: '12D3KooWDBfVNdMyV3hPEF4WLBmx9DwD2t2SYuqZ2mztYmDzZWM1', - sk: 'eqJ4Bp7iN4aBXgPH0ezwSg+nVsatkYtfrXv9obI0YQ0=', + peerId: "12D3KooWDBfVNdMyV3hPEF4WLBmx9DwD2t2SYuqZ2mztYmDzZWM1", + sk: "eqJ4Bp7iN4aBXgPH0ezwSg+nVsatkYtfrXv9obI0YQ0=", }, { - peerId: '12D3KooWSyY7wiSiR4vbXa1WtZawi3ackMTqcQhEPrvqtagoWPny', - sk: 'UVM3SBJhPYIY/gafpnd9/q/Fn9V4BE9zkgrvF1T7Pgc=', + peerId: "12D3KooWSyY7wiSiR4vbXa1WtZawi3ackMTqcQhEPrvqtagoWPny", + sk: "UVM3SBJhPYIY/gafpnd9/q/Fn9V4BE9zkgrvF1T7Pgc=", }, { - peerId: '12D3KooWFZmBMGG9PxTs9s6ASzkLGKJWMyPheA5ruaYc2FDkDTmv', - sk: '8RbZfEVpQhPVuhv64uqxENDuSoyJrslQoSQJznxsTQ0=', + peerId: "12D3KooWFZmBMGG9PxTs9s6ASzkLGKJWMyPheA5ruaYc2FDkDTmv", + sk: "8RbZfEVpQhPVuhv64uqxENDuSoyJrslQoSQJznxsTQ0=", }, { - peerId: '12D3KooWBbhUaqqur6KHPunnKxXjY1daCtqJdy4wRji89LmAkVB4', - sk: 'RbgKmG6soWW9uOi7yRedm+0Qck3f3rw6MSnDP7AcBQs=', + peerId: "12D3KooWBbhUaqqur6KHPunnKxXjY1daCtqJdy4wRji89LmAkVB4", + sk: "RbgKmG6soWW9uOi7yRedm+0Qck3f3rw6MSnDP7AcBQs=", }, ], }; @@ -136,7 +137,7 @@ export class EphemeralConnection implements IEphemeralConnection { constructor(selfPeerId: PeerIdB58) { this.selfPeerId = selfPeerId; } - + start(): Promise { return Promise.resolve(); } @@ -160,7 +161,7 @@ export class EphemeralConnection implements IEphemeralConnection { } disconnectFromAll() { - for (let other of this.connections.values()) { + for (const other of this.connections.values()) { this.disconnectFromOther(other); } } @@ -171,12 +172,17 @@ export class EphemeralConnection implements IEphemeralConnection { this.particleSource.next(Particle.fromString(particle.toString())); } - async sendParticle(nextPeerIds: string[], particle: Particle): Promise { + async sendParticle( + nextPeerIds: string[], + particle: Particle, + ): Promise { const from = this.selfPeerId; - for (let to of nextPeerIds) { + + for (const to of nextPeerIds) { const destConnection = this.connections.get(to); + if (destConnection === undefined) { - log.error('peer %s has no connection with %s', from, to); + log.error("peer %s has no connection with %s", from, to); continue; } @@ -190,7 +196,9 @@ export class EphemeralConnection implements IEphemeralConnection { return this.connections.keys().next().value; } - throw new Error('relay is not supported in this Ephemeral network peer'); + throw new Error( + "relay is not supported in this Ephemeral network peer", + ); } supportsRelay(): boolean { @@ -220,25 +228,44 @@ export class EphemeralNetwork { controlModuleLoader: WasmLoaderFromNpm; avmModuleLoader: WasmLoaderFromNpm; - constructor(public readonly config: EphemeralConfig) { + constructor(readonly config: EphemeralConfig) { // shared worker for all the peers - this.workerLoader = new WorkerLoaderFromFs('../../marine/worker-script'); - this.controlModuleLoader = new WasmLoaderFromNpm('@fluencelabs/marine-js', 'marine-js.wasm'); - this.avmModuleLoader = new WasmLoaderFromNpm('@fluencelabs/avm', 'avm.wasm'); + this.workerLoader = new WorkerLoaderFromFs( + "../../marine/worker-script", + ); + + this.controlModuleLoader = new WasmLoaderFromNpm( + "@fluencelabs/marine-js", + "marine-js.wasm", + ); + + this.avmModuleLoader = new WasmLoaderFromNpm( + "@fluencelabs/avm", + "avm.wasm", + ); } /** * Starts the Ephemeral network up */ async up(): Promise { - log.trace('starting ephemeral network up...'); + log.trace("starting ephemeral network up..."); const promises = this.config.peers.map(async (x) => { const kp = await fromBase64Sk(x.sk); - const marine = new MarineBackgroundRunner(this.workerLoader, this.controlModuleLoader, this.avmModuleLoader); + + const marine = new MarineBackgroundRunner( + this.workerLoader, + this.controlModuleLoader, + this.avmModuleLoader, + ); + const peerId = kp.getPeerId(); + if (peerId !== x.peerId) { - throw new Error(`Invalid config: peer id ${x.peerId} does not match the secret key ${x.sk}`); + throw new Error( + `Invalid config: peer id ${x.peerId} does not match the secret key ${x.sk}`, + ); } return new EphemeralPeer(kp, marine); @@ -252,14 +279,19 @@ export class EphemeralNetwork { continue; } - peers[i].ephemeralConnection.connectToOther(peers[j].ephemeralConnection); + peers[i].ephemeralConnection.connectToOther( + peers[j].ephemeralConnection, + ); } } - const startPromises = peers.map((x) => x.start()); + const startPromises = peers.map((x) => { + return x.start(); + }); + await Promise.all(startPromises); - for (let p of peers) { + for (const p of peers) { this.peers.set(p.keyPair.getPeerId(), p); } } @@ -268,8 +300,9 @@ export class EphemeralNetwork { * Shuts the ephemeral network down. Will disconnect all connected peers. */ async down(): Promise { - log.trace('shutting down ephemeral network...'); + log.trace("shutting down ephemeral network..."); const peers = Array.from(this.peers.entries()); + const promises = peers.map(async ([k, p]) => { await p.ephemeralConnection.disconnectFromAll(); await p.stop(); @@ -277,7 +310,7 @@ export class EphemeralNetwork { await Promise.all(promises); this.peers.clear(); - log.trace('ephemeral network shut down'); + log.trace("ephemeral network shut down"); } /** @@ -285,6 +318,7 @@ export class EphemeralNetwork { */ getRelayConnection(peerId: PeerIdB58, relayPeerId: PeerIdB58): IConnection { const relay = this.peers.get(relayPeerId); + if (relay === undefined) { throw new Error(`Peer ${relayPeerId} is not found`); } diff --git a/packages/core/js-client/src/fetchers/browser.ts b/packages/core/js-client/src/fetchers/browser.ts index ae710ca9f..c75277ac8 100644 --- a/packages/core/js-client/src/fetchers/browser.ts +++ b/packages/core/js-client/src/fetchers/browser.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,18 +23,38 @@ interface PackageJsonContent { const packageJsonContentString = `__PACKAGE_JSON_CONTENT__`; let parsedPackageJsonContent: PackageJsonContent; -const PRIMARY_CDN = "https://unpkg.com/"; +const PRIMARY_CDN = "https://unpkg.com/"; export async function fetchResource(pkg: string, assetPath: string) { - const packageJsonContent = parsedPackageJsonContent || (parsedPackageJsonContent = JSON.parse(packageJsonContentString)); - const version = packageJsonContent.dependencies[pkg] || packageJsonContent.devDependencies[pkg]; - + const packageJsonContent = + parsedPackageJsonContent || + (parsedPackageJsonContent = JSON.parse(packageJsonContentString)); + + const version = + packageJsonContent.dependencies[pkg] || + packageJsonContent.devDependencies[pkg]; + if (version === undefined) { - const availableDeps = [...Object.keys(packageJsonContent.dependencies), ...Object.keys(packageJsonContent.devDependencies)]; - throw new Error(`Cannot find version of ${pkg} in package.json. Available versions: ${availableDeps.join(',')}`); + const availableDeps = [ + ...Object.keys(packageJsonContent.dependencies), + ...Object.keys(packageJsonContent.devDependencies), + ]; + + throw new Error( + `Cannot find version of ${pkg} in package.json. Available versions: ${availableDeps.join( + ",", + )}`, + ); } - - const refinedAssetPath = assetPath.startsWith('/') ? assetPath.slice(1) : assetPath; - - return fetch(new globalThis.URL(`${pkg}@${version}/` + refinedAssetPath, PRIMARY_CDN)); + + const refinedAssetPath = assetPath.startsWith("/") + ? assetPath.slice(1) + : assetPath; + + return fetch( + new globalThis.URL( + `${pkg}@${version}/` + refinedAssetPath, + PRIMARY_CDN, + ), + ); } diff --git a/packages/core/js-client/src/fetchers/index.ts b/packages/core/js-client/src/fetchers/index.ts index 191ab9247..383d8fb7a 100644 --- a/packages/core/js-client/src/fetchers/index.ts +++ b/packages/core/js-client/src/fetchers/index.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,11 +14,13 @@ * limitations under the License. */ -import { fetchResource as fetchResourceBrowser } from './browser.js'; -import { fetchResource as fetchResourceNode } from './node.js'; -import process from 'process'; +import process from "process"; -const isNode = typeof process !== 'undefined' && process?.release?.name === 'node'; +import { fetchResource as fetchResourceBrowser } from "./browser.js"; +import { fetchResource as fetchResourceNode } from "./node.js"; + +const isNode = + typeof process !== "undefined" && process?.release?.name === "node"; export async function fetchResource(pkg: string, path: string) { switch (true) { diff --git a/packages/core/js-client/src/fetchers/node.ts b/packages/core/js-client/src/fetchers/node.ts index 759078e44..755bb682d 100644 --- a/packages/core/js-client/src/fetchers/node.ts +++ b/packages/core/js-client/src/fetchers/node.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,27 +14,27 @@ * limitations under the License. */ -import fs from 'fs'; -import path from 'path'; -import module from 'module'; +import fs from "fs"; +import module from "module"; +import path from "path"; export async function fetchResource(pkg: string, assetPath: string) { const require = module.createRequire(import.meta.url); const packagePathIndex = require.resolve(pkg); - - // Ensure that windows path is converted to posix path. So we can find a package + + // Ensure that windows path is converted to posix path. So we can find a package const posixPath = packagePathIndex.split(path.sep).join(path.posix.sep); - + const matches = new RegExp(`(.+${pkg})`).exec(posixPath); - + const packagePath = matches?.[0]; - + if (!packagePath) { throw new Error(`Cannot find dependency ${pkg} in path ${posixPath}`); } - + const pathToResource = path.join(packagePath, assetPath); - + const file = await new Promise((resolve, reject) => { // Cannot use 'fs/promises' with current vite config. This module is not polyfilled by default. fs.readFile(pathToResource, (err, data) => { @@ -42,18 +42,18 @@ export async function fetchResource(pkg: string, assetPath: string) { reject(err); return; } + resolve(data); }); }); - + return new Response(file, { headers: { - 'Content-type': - assetPath.endsWith('.wasm') - ? 'application/wasm' - : assetPath.endsWith('.js') - ? 'application/javascript' - : 'application/text' - } + "Content-type": assetPath.endsWith(".wasm") + ? "application/wasm" + : assetPath.endsWith(".js") + ? "application/javascript" + : "application/text", + }, }); } diff --git a/packages/core/js-client/src/index.ts b/packages/core/js-client/src/index.ts index 0003a021c..ccfaba480 100644 --- a/packages/core/js-client/src/index.ts +++ b/packages/core/js-client/src/index.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,71 +13,133 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import type { ClientConfig, IFluenceClient, RelayOptions, ConnectionState, CallAquaFunctionType, RegisterServiceType } from '@fluencelabs/interfaces'; -import { ClientPeer, makeClientPeerConfig } from './clientPeer/ClientPeer.js'; -import { callAquaFunction } from './compilerSupport/callFunction.js'; -import { registerService } from './compilerSupport/registerService.js'; -import { MarineBackgroundRunner } from './marine/worker/index.js'; + +import module from "module"; +import path from "path"; +import process from "process"; +import url from "url"; + +import type { + ClientConfig, + IFluenceClient, + RelayOptions, + ConnectionState, +} from "@fluencelabs/interfaces"; +import { BlobWorker, Worker } from "threads"; + +import { ClientPeer, makeClientPeerConfig } from "./clientPeer/ClientPeer.js"; +import { callAquaFunction } from "./compilerSupport/callFunction.js"; +import { registerService } from "./compilerSupport/registerService.js"; +import { fetchResource } from "./fetchers/index.js"; +import { MarineBackgroundRunner } from "./marine/worker/index.js"; // @ts-ignore -import { BlobWorker, Worker } from 'threads'; -import { doRegisterNodeUtils } from './services/NodeUtils.js'; -import { fetchResource } from './fetchers/index.js'; -import process from 'process'; -import path from 'path'; -import url from 'url'; -import module from 'module'; +import { doRegisterNodeUtils } from "./services/NodeUtils.js"; -const isNode = typeof process !== 'undefined' && process?.release?.name === 'node'; +const isNode = + typeof process !== "undefined" && process?.release?.name === "node"; -const fetchWorkerCode = () => fetchResource('@fluencelabs/marine-worker', '/dist/browser/marine-worker.umd.cjs').then(res => res.text()); -const fetchMarineJsWasm = () => fetchResource('@fluencelabs/marine-js', '/dist/marine-js.wasm').then(res => res.arrayBuffer()); -const fetchAvmWasm = () => fetchResource('@fluencelabs/avm', '/dist/avm.wasm').then(res => res.arrayBuffer()); +const fetchWorkerCode = () => { + return fetchResource( + "@fluencelabs/marine-worker", + "/dist/browser/marine-worker.umd.cjs", + ).then((res) => { + return res.text(); + }); +}; -const createClient = async (relay: RelayOptions, config: ClientConfig): Promise => { +const fetchMarineJsWasm = () => { + return fetchResource("@fluencelabs/marine-js", "/dist/marine-js.wasm").then( + (res) => { + return res.arrayBuffer(); + }, + ); +}; + +const fetchAvmWasm = () => { + return fetchResource("@fluencelabs/avm", "/dist/avm.wasm").then((res) => { + return res.arrayBuffer(); + }); +}; + +const createClient = async ( + relay: RelayOptions, + config: ClientConfig, +): Promise => { const marineJsWasm = await fetchMarineJsWasm(); const avmWasm = await fetchAvmWasm(); - - const marine = new MarineBackgroundRunner({ - async getValue() { - if (isNode) { - const require = module.createRequire(import.meta.url); - const pathToThisFile = path.dirname(url.fileURLToPath(import.meta.url)); - const pathToWorker = require.resolve('@fluencelabs/marine-worker'); - const relativePathToWorker = path.relative(pathToThisFile, pathToWorker); - return new Worker(relativePathToWorker); - } else { - const workerCode = await fetchWorkerCode(); - return BlobWorker.fromText(workerCode) - } + + const marine = new MarineBackgroundRunner( + { + async getValue() { + if (isNode) { + const require = module.createRequire(import.meta.url); + + const pathToThisFile = path.dirname( + url.fileURLToPath(import.meta.url), + ); + + const pathToWorker = require.resolve( + "@fluencelabs/marine-worker", + ); + + const relativePathToWorker = path.relative( + pathToThisFile, + pathToWorker, + ); + + return new Worker(relativePathToWorker); + } else { + const workerCode = await fetchWorkerCode(); + return BlobWorker.fromText(workerCode); + } + }, + start() { + return Promise.resolve(undefined); + }, + stop() { + return Promise.resolve(undefined); + }, }, - start() { - return Promise.resolve(undefined); + { + getValue() { + return marineJsWasm; + }, + start(): Promise { + return Promise.resolve(undefined); + }, + stop(): Promise { + return Promise.resolve(undefined); + }, }, - stop() { - return Promise.resolve(undefined); + { + getValue() { + return avmWasm; + }, + start(): Promise { + return Promise.resolve(undefined); + }, + stop(): Promise { + return Promise.resolve(undefined); + }, }, - }, { - getValue() { - return marineJsWasm; - }, start(): Promise { - return Promise.resolve(undefined); - }, stop(): Promise { - return Promise.resolve(undefined); - } - }, { - getValue() { - return avmWasm; - }, start(): Promise { - return Promise.resolve(undefined); - }, stop(): Promise { - return Promise.resolve(undefined); - } - }); - const { keyPair, peerConfig, relayConfig } = await makeClientPeerConfig(relay, config); - const client: IFluenceClient = new ClientPeer(peerConfig, relayConfig, keyPair, marine); + ); + + const { keyPair, peerConfig, relayConfig } = await makeClientPeerConfig( + relay, + config, + ); + + const client: IFluenceClient = new ClientPeer( + peerConfig, + relayConfig, + keyPair, + marine, + ); + if (isNode) { doRegisterNodeUtils(client); } + await client.connect(); return client; }; @@ -86,13 +148,16 @@ const createClient = async (relay: RelayOptions, config: ClientConfig): Promise< * Public interface to Fluence Network */ export const Fluence = { - defaultClient: undefined as (IFluenceClient | undefined), + defaultClient: undefined as IFluenceClient | undefined, /** * Connect to the Fluence network * @param relay - relay node to connect to * @param config - client configuration */ - connect: async function(relay: RelayOptions, config: ClientConfig): Promise { + connect: async function ( + relay: RelayOptions, + config: ClientConfig, + ): Promise { const client = await createClient(relay, config); this.defaultClient = client; }, @@ -100,7 +165,7 @@ export const Fluence = { /** * Disconnect from the Fluence network */ - disconnect: async function(): Promise { + disconnect: async function (): Promise { await this.defaultClient?.disconnect(); this.defaultClient = undefined; }, @@ -108,23 +173,35 @@ export const Fluence = { /** * Handle connection state changes. Immediately returns the current connection state */ - onConnectionStateChange(handler: (state: ConnectionState) => void): ConnectionState { - return this.defaultClient?.onConnectionStateChange(handler) || 'disconnected'; + onConnectionStateChange( + handler: (state: ConnectionState) => void, + ): ConnectionState { + return ( + this.defaultClient?.onConnectionStateChange(handler) || + "disconnected" + ); }, /** * Low level API. Get the underlying client instance which holds the connection to the network * @returns IFluenceClient instance */ - getClient: async function(): Promise { + getClient: async function (): Promise { if (!this.defaultClient) { - throw new Error('Fluence client is not initialized. Call Fluence.connect() first'); + throw new Error( + "Fluence client is not initialized. Call Fluence.connect() first", + ); } + return this.defaultClient; }, }; -export type { IFluenceClient, ClientConfig, CallParams } from '@fluencelabs/interfaces'; +export type { + IFluenceClient, + ClientConfig, + CallParams, +} from "@fluencelabs/interfaces"; export type { ArrayType, @@ -151,9 +228,9 @@ export type { FnConfig, RegisterServiceType, RegisterServiceArgs, -} from '@fluencelabs/interfaces'; +} from "@fluencelabs/interfaces"; -export { v5_callFunction, v5_registerService } from './api.js'; +export { v5_callFunction, v5_registerService } from "./api.js"; // @ts-ignore globalThis.new_fluence = Fluence; @@ -166,4 +243,7 @@ globalThis.fluence = { }; export { createClient, callAquaFunction, registerService }; -export { getFluenceInterface, getFluenceInterfaceFromGlobalThis } from './util/loadClient.js'; +export { + getFluenceInterface, + getFluenceInterfaceFromGlobalThis, +} from "./util/loadClient.js"; diff --git a/packages/core/js-client/src/jsPeer/FluencePeer.ts b/packages/core/js-client/src/jsPeer/FluencePeer.ts index 661bafe88..425ecd65d 100644 --- a/packages/core/js-client/src/jsPeer/FluencePeer.ts +++ b/packages/core/js-client/src/jsPeer/FluencePeer.ts @@ -1,5 +1,5 @@ -/* - * Copyright 2021 Fluence Labs Limited +/** + * 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. @@ -13,61 +13,64 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { KeyPair } from '../keypair/index.js'; -import type { PeerIdB58 } from '@fluencelabs/interfaces'; -import { deserializeAvmResult, InterpreterResult, KeyPairFormat, serializeAvmArgs } from '@fluencelabs/avm'; +import { Buffer } from "buffer"; + import { - cloneWithNewData, - getActualTTL, - hasExpired, - Particle, - ParticleExecutionStage, - ParticleQueueItem, -} from '../particle/Particle.js'; -import { defaultCallParameters } from '@fluencelabs/marine-js/dist/types' -import { jsonify, isString } from '../util/utils.js'; + deserializeAvmResult, + InterpreterResult, + KeyPairFormat, + serializeAvmArgs, +} from "@fluencelabs/avm"; +import { defaultCallParameters } from "@fluencelabs/marine-js/dist/types"; +import { fromUint8Array } from "js-base64"; import { - concatAll, concatMap, filter, - from, groupBy, lastValueFrom, - mergeAll, mergeMap, - Observable, pipe, Subject, tap, - Unsubscribable -} from 'rxjs'; -import { defaultSigGuard, Sig } from '../services/Sig.js'; -import { registerSig } from '../services/_aqua/services.js'; -import { registerSrv } from '../services/_aqua/single-module-srv.js'; -import { registerTracing } from '../services/_aqua/tracing.js'; -import { Buffer } from 'buffer'; - -import { Srv } from '../services/SingleModuleSrv.js'; -import { Tracing } from '../services/Tracing.js'; - -import { logger } from '../util/logger.js'; -import { getParticleContext, registerDefaultServices, ServiceError } from '../jsServiceHost/serviceUtils.js'; -import { IParticle } from '../particle/interfaces.js'; -import { IConnection } from '../connection/interfaces.js'; -import { IAvmRunner, IMarineHost } from '../marine/interfaces.js'; + Unsubscribable, +} from "rxjs"; + +import { IConnection } from "../connection/interfaces.js"; import { CallServiceData, CallServiceResult, - GenericCallServiceHandler, IJsServiceHost, ResultCodes, -} from '../jsServiceHost/interfaces.js'; -import { JSONValue } from '../util/commonTypes.js'; -import { fromUint8Array } from 'js-base64'; - -const log_particle = logger('particle'); -const log_peer = logger('peer'); +} from "../jsServiceHost/interfaces.js"; +import { + getParticleContext, + registerDefaultServices, + ServiceError, +} from "../jsServiceHost/serviceUtils.js"; +import { KeyPair } from "../keypair/index.js"; +import { IMarineHost } from "../marine/interfaces.js"; +import { IParticle } from "../particle/interfaces.js"; +import { + cloneWithNewData, + getActualTTL, + hasExpired, + Particle, + ParticleExecutionStage, + ParticleQueueItem, +} from "../particle/Particle.js"; +import { registerSig } from "../services/_aqua/services.js"; +import { registerSrv } from "../services/_aqua/single-module-srv.js"; +import { registerTracing } from "../services/_aqua/tracing.js"; +import { defaultSigGuard, Sig } from "../services/Sig.js"; +import { Srv } from "../services/SingleModuleSrv.js"; +import { Tracing } from "../services/Tracing.js"; +import { JSONValue } from "../util/commonTypes.js"; +import { logger } from "../util/logger.js"; +import { jsonify, isString } from "../util/utils.js"; + +const log_particle = logger("particle"); +const log_peer = logger("peer"); export type PeerConfig = { /** @@ -103,7 +106,7 @@ export const DEFAULT_CONFIG: PeerConfig = { export abstract class FluencePeer { constructor( protected readonly config: PeerConfig, - public readonly keyPair: KeyPair, + readonly keyPair: KeyPair, protected readonly marineHost: IMarineHost, protected readonly jsServiceHost: IJsServiceHost, protected readonly connection: IConnection, @@ -112,16 +115,18 @@ export abstract class FluencePeer { } async start(): Promise { - log_peer.trace('starting Fluence peer'); + log_peer.trace("starting Fluence peer"); + if (this.config?.debug?.printParticleId) { this.printParticleId = true; } + await this.marineHost.start(); this._startParticleProcessing(); this.isInitialized = true; await this.connection.start(); - log_peer.trace('started Fluence peer'); + log_peer.trace("started Fluence peer"); } /** @@ -129,20 +134,20 @@ export abstract class FluencePeer { * and disconnects from the Fluence network */ async stop() { - log_peer.trace('stopping Fluence peer'); - + log_peer.trace("stopping Fluence peer"); + this._particleSourceSubscription?.unsubscribe(); - log_peer.trace('Waiting for all particles to finish execution'); + log_peer.trace("Waiting for all particles to finish execution"); this._incomingParticles.complete(); await this._incomingParticlePromise; - log_peer.trace('All particles finished execution'); - + log_peer.trace("All particles finished execution"); + this._stopParticleProcessing(); await this.marineHost.stop(); await this.connection.stop(); this.isInitialized = false; - log_peer.trace('stopped Fluence peer'); + log_peer.trace("stopped Fluence peer"); } /** @@ -154,9 +159,14 @@ export abstract class FluencePeer { * @param wasm - buffer with the wasm file for service * @param serviceId - the service id by which the service can be accessed in aqua */ - async registerMarineService(wasm: SharedArrayBuffer | Buffer, serviceId: string): Promise { + async registerMarineService( + wasm: SharedArrayBuffer | Buffer, + serviceId: string, + ): Promise { if (!this.marineHost) { - throw new Error("Can't register marine service: peer is not initialized"); + throw new Error( + "Can't register marine service: peer is not initialized", + ); } if (this.jsServiceHost.hasService(serviceId)) { @@ -181,28 +191,42 @@ export abstract class FluencePeer { */ get internals() { return { - getServices: () => this._classServices, + getServices: () => { + return this._classServices; + }, getRelayPeerId: () => { if (this.connection.supportsRelay()) { return this.connection.getRelayPeerId(); } - throw new Error('Relay is not supported by the current connection'); + throw new Error( + "Relay is not supported by the current connection", + ); }, - parseAst: async (air: string): Promise<{ success: boolean; data: any }> => { + parseAst: async ( + air: string, + ): Promise<{ success: boolean; data: any }> => { if (!this.isInitialized) { new Error("Can't use avm: peer is not initialized"); } - const res = await this.marineHost.callService('avm', 'ast', [air], defaultCallParameters); + const res = await this.marineHost.callService( + "avm", + "ast", + [air], + defaultCallParameters, + ); + if (!isString(res)) { - throw new Error(`Call to avm:ast expected to return string. Actual return: ${res}`); + throw new Error( + `Call to avm:ast expected to return string. Actual return: ${res}`, + ); } try { - if (res.startsWith('error')) { + if (res.startsWith("error")) { return { success: false, data: res, @@ -214,12 +238,25 @@ export abstract class FluencePeer { }; } } catch (err) { - throw new Error('Failed to call avm. Result: ' + res + '. Error: ' + err); + throw new Error( + "Failed to call avm. Result: " + + res + + ". Error: " + + err, + ); } }, - createNewParticle: (script: string, ttl: number = this.config.defaultTtlMs): Promise => { - return Particle.createNew(script, this.keyPair.getPeerId(), ttl, this.keyPair); + createNewParticle: ( + script: string, + ttl: number = this.config.defaultTtlMs, + ): Promise => { + return Particle.createNew( + script, + this.keyPair.getPeerId(), + ttl, + this.keyPair, + ); }, /** @@ -227,13 +264,18 @@ export abstract class FluencePeer { * @param particle - particle to start execution of * @param onStageChange - callback for reacting on particle state changes */ - initiateParticle: (particle: IParticle, onStageChange: (stage: ParticleExecutionStage) => void): void => { + initiateParticle: ( + particle: IParticle, + onStageChange: (stage: ParticleExecutionStage) => void, + ): void => { if (!this.isInitialized) { - throw new Error('Cannot initiate new particle: peer is not initialized'); + throw new Error( + "Cannot initiate new particle: peer is not initialized", + ); } if (this.printParticleId) { - console.log('Particle id: ', particle.id); + console.log("Particle id: ", particle.id); } this._incomingParticles.next({ @@ -250,11 +292,16 @@ export abstract class FluencePeer { /** * Register handler for all particles */ - common: this.jsServiceHost.registerGlobalHandler.bind(this.jsServiceHost), + common: this.jsServiceHost.registerGlobalHandler.bind( + this.jsServiceHost, + ), /** * Register handler which will be called only for particle with the specific id */ - forParticle: this.jsServiceHost.registerParticleScopeHandler.bind(this.jsServiceHost), + forParticle: + this.jsServiceHost.registerParticleScopeHandler.bind( + this.jsServiceHost, + ), }, }; } @@ -290,39 +337,56 @@ export abstract class FluencePeer { registerDefaultServices(this); this._classServices.sig.securityGuard = defaultSigGuard(peerId); - registerSig(this, 'sig', this._classServices.sig); + registerSig(this, "sig", this._classServices.sig); registerSig(this, peerId, this._classServices.sig); - registerSrv(this, 'single_module_srv', this._classServices.srv); - registerTracing(this, 'tracingSrv', this._classServices.tracing); + registerSrv(this, "single_module_srv", this._classServices.srv); + registerTracing(this, "tracingSrv", this._classServices.tracing); } private _startParticleProcessing() { - this._particleSourceSubscription = this.connection.particleSource.subscribe({ - next: (p) => { - this._incomingParticles.next({ particle: p, callResults: [], onStageChange: () => {} }); - }, - }); + this._particleSourceSubscription = + this.connection.particleSource.subscribe({ + next: (p) => { + this._incomingParticles.next({ + particle: p, + callResults: [], + onStageChange: () => {}, + }); + }, + }); - this._incomingParticlePromise = lastValueFrom(this._incomingParticles - .pipe( + this._incomingParticlePromise = lastValueFrom( + this._incomingParticles.pipe( tap((item) => { - log_particle.debug('id %s. received:', item.particle.id); - log_particle.trace('id %s. data: %j', item.particle.id, { + log_particle.debug("id %s. received:", item.particle.id); + + log_particle.trace("id %s. data: %j", item.particle.id, { initPeerId: item.particle.initPeerId, timestamp: item.particle.timestamp, ttl: item.particle.ttl, signature: item.particle.signature, }); - log_particle.trace('id %s. script: %s', item.particle.id, item.particle.script); - log_particle.trace('id %s. call results: %j', item.particle.id, item.callResults); + log_particle.trace( + "id %s. script: %s", + item.particle.id, + item.particle.script, + ); + + log_particle.trace( + "id %s. call results: %j", + item.particle.id, + item.callResults, + ); }), filterExpiredParticles(this._expireParticle.bind(this)), - groupBy(item => fromUint8Array(item.particle.signature)), - mergeMap(group$ => { + groupBy((item) => { + return fromUint8Array(item.particle.signature); + }), + mergeMap((group$) => { let prevData: Uint8Array = Buffer.from([]); let firstRun = true; - + return group$.pipe( concatMap(async (item) => { if (firstRun) { @@ -333,8 +397,11 @@ export abstract class FluencePeer { this._timeouts.push(timeout); firstRun = false; } - - if (!this.isInitialized || this.marineHost === undefined) { + + if ( + !this.isInitialized || + this.marineHost === undefined + ) { // If `.stop()` was called return null to stop particle processing immediately return null; } @@ -344,8 +411,16 @@ export abstract class FluencePeer { // MUST happen sequentially (in a critical section). // Otherwise the race might occur corrupting the prevData - log_particle.debug('id %s. sending particle to interpreter', item.particle.id); - log_particle.trace('id %s. prevData: %s', item.particle.id, this.decodeAvmData(prevData).slice(0, 50)); + log_particle.debug( + "id %s. sending particle to interpreter", + item.particle.id, + ); + + log_particle.trace( + "id %s. prevData: %s", + item.particle.id, + this.decodeAvmData(prevData).slice(0, 50), + ); const args = serializeAvmArgs( { @@ -355,7 +430,8 @@ export abstract class FluencePeer { ttl: item.particle.ttl, keyFormat: KeyPairFormat.Ed25519, particleId: item.particle.id, - secretKeyBytes: this.keyPair.toEd25519PrivateKey(), + secretKeyBytes: + this.keyPair.toEd25519PrivateKey(), }, item.particle.script, prevData, @@ -364,14 +440,27 @@ export abstract class FluencePeer { ); let avmCallResult: InterpreterResult | Error; + try { - const res = await this.marineHost.callService('avm', 'invoke', args, defaultCallParameters); + const res = await this.marineHost.callService( + "avm", + "invoke", + args, + defaultCallParameters, + ); + avmCallResult = deserializeAvmResult(res); } catch (e) { - avmCallResult = e instanceof Error ? e : new Error(String(e)); + avmCallResult = + e instanceof Error + ? e + : new Error(String(e)); } - if (!(avmCallResult instanceof Error) && avmCallResult.retCode === 0) { + if ( + !(avmCallResult instanceof Error) && + avmCallResult.retCode === 0 + ) { const newData = Buffer.from(avmCallResult.data); prevData = newData; } @@ -381,8 +470,14 @@ export abstract class FluencePeer { result: avmCallResult, }; }), - filter((item): item is NonNullable => item !== null), - filterExpiredParticles(this._expireParticle.bind(this)), + filter((item): item is NonNullable => { + return item !== null; + }), + filterExpiredParticles< + ParticleQueueItem & { + result: Error | InterpreterResult; + } + >(this._expireParticle.bind(this)), mergeMap(async (item) => { // If peer was stopped, do not proceed further if (!this.isInitialized) { @@ -391,39 +486,62 @@ export abstract class FluencePeer { // Do not continue if there was an error in particle interpretation if (item.result instanceof Error) { - log_particle.error('id %s. interpreter failed: %s', item.particle.id, item.result.message); - item.onStageChange({ stage: 'interpreterError', errorMessage: item.result.message }); + log_particle.error( + "id %s. interpreter failed: %s", + item.particle.id, + item.result.message, + ); + + item.onStageChange({ + stage: "interpreterError", + errorMessage: item.result.message, + }); + return; } if (item.result.retCode !== 0) { log_particle.error( - 'id %s. interpreter failed: retCode: %d, message: %s', + "id %s. interpreter failed: retCode: %d, message: %s", item.particle.id, item.result.retCode, item.result.errorMessage, ); - log_particle.trace('id %s. avm data: %s', item.particle.id, this.decodeAvmData(item.result.data)); - item.onStageChange({ stage: 'interpreterError', errorMessage: item.result.errorMessage }); + + log_particle.trace( + "id %s. avm data: %s", + item.particle.id, + this.decodeAvmData(item.result.data), + ); + + item.onStageChange({ + stage: "interpreterError", + errorMessage: item.result.errorMessage, + }); + return; } log_particle.trace( - 'id %s. interpreter result: retCode: %d, avm data: %s', + "id %s. interpreter result: retCode: %d, avm data: %s", item.particle.id, item.result.retCode, - this.decodeAvmData(item.result.data) + this.decodeAvmData(item.result.data), ); setTimeout(() => { - item.onStageChange({ stage: 'interpreted' }); + item.onStageChange({ stage: "interpreted" }); }, 0); - - let connectionPromise: Promise = Promise.resolve(); + + let connectionPromise: Promise = + Promise.resolve(); // send particle further if requested if (item.result.nextPeerPks.length > 0) { - const newParticle = cloneWithNewData(item.particle, Buffer.from(item.result.data)); + const newParticle = cloneWithNewData( + item.particle, + Buffer.from(item.result.data), + ); // Do not send particle after the peer has been stopped if (!this.isInitialized) { @@ -431,35 +549,53 @@ export abstract class FluencePeer { } log_particle.debug( - 'id %s. sending particle into network. Next peer ids: %s', + "id %s. sending particle into network. Next peer ids: %s", newParticle.id, item.result.nextPeerPks.toString(), ); connectionPromise = this.connection - ?.sendParticle(item.result.nextPeerPks, newParticle) + ?.sendParticle( + item.result.nextPeerPks, + newParticle, + ) .then(() => { - log_particle.trace('id %s. send successful', newParticle.id); - item.onStageChange({ stage: 'sent' }); + log_particle.trace( + "id %s. send successful", + newParticle.id, + ); + + item.onStageChange({ stage: "sent" }); }) .catch((e: any) => { - log_particle.error('id %s. send failed %j', newParticle.id, e); - item.onStageChange({ stage: 'sendingError', errorMessage: e.toString() }); + log_particle.error( + "id %s. send failed %j", + newParticle.id, + e, + ); + + item.onStageChange({ + stage: "sendingError", + errorMessage: e.toString(), + }); }); } // execute call requests if needed // and put particle with the results back to queue if (item.result.callRequests.length > 0) { - for (const [key, cr] of item.result.callRequests) { + for (const [key, cr] of item.result + .callRequests) { const req = { fnName: cr.functionName, args: cr.arguments, serviceId: cr.serviceId, tetraplets: cr.tetraplets, - particleContext: getParticleContext(item.particle), + particleContext: getParticleContext( + item.particle, + ), }; - + this._execSingleCallRequest(req) .catch((err): CallServiceResult => { if (err instanceof ServiceError) { @@ -471,7 +607,9 @@ export abstract class FluencePeer { return { retCode: ResultCodes.error, - result: `Service call failed. fnName="${req.fnName}" serviceId="${ + result: `Service call failed. fnName="${ + req.fnName + }" serviceId="${ req.serviceId }" error: ${err.toString()}`, }; @@ -482,50 +620,74 @@ export abstract class FluencePeer { retCode: res.retCode, }; - const newParticle = cloneWithNewData(item.particle, Buffer.from([])); + const newParticle = + cloneWithNewData( + item.particle, + Buffer.from([]), + ); + this._incomingParticles.next({ ...item, particle: newParticle, - callResults: [[key, serviceResult]], + callResults: [ + [key, serviceResult], + ], }); }); } } else { - item.onStageChange({ stage: 'localWorkDone' }); + item.onStageChange({ stage: "localWorkDone" }); } - + return connectionPromise; }), - - ) - }) - ), { defaultValue: undefined }); + ); + }), + ), + { defaultValue: undefined }, + ); } private _expireParticle(item: ParticleQueueItem) { const particleId = item.particle.id; + log_particle.debug( - 'id %s. particle has expired after %d. Deleting particle-related queues and handlers', + "id %s. particle has expired after %d. Deleting particle-related queues and handlers", item.particle.id, item.particle.ttl, ); - + this.jsServiceHost.removeParticleScopeHandlers(particleId); - item.onStageChange({ stage: 'expired' }); + item.onStageChange({ stage: "expired" }); } private decodeAvmData(data: Uint8Array) { return new TextDecoder().decode(data.buffer); } - private async _execSingleCallRequest(req: CallServiceData): Promise { + private async _execSingleCallRequest( + req: CallServiceData, + ): Promise { const particleId = req.particleContext.particleId; - log_particle.trace('id %s. executing call service handler %j', particleId, req); - if (this.marineHost && await this.marineHost.hasService(req.serviceId)) { + log_particle.trace( + "id %s. executing call service handler %j", + particleId, + req, + ); + + if ( + this.marineHost && + (await this.marineHost.hasService(req.serviceId)) + ) { // TODO build correct CallParameters instead of default ones - const result = await this.marineHost.callService(req.serviceId, req.fnName, req.args, defaultCallParameters); + const result = await this.marineHost.callService( + req.serviceId, + req.fnName, + req.args, + defaultCallParameters, + ); return { retCode: ResultCodes.success, @@ -538,13 +700,19 @@ export abstract class FluencePeer { if (res === null) { res = { retCode: ResultCodes.error, - result: `No service found for service call: serviceId='${req.serviceId}', fnName='${ - req.fnName - }' args='${jsonify(req.args)}'`, + result: `No service found for service call: serviceId='${ + req.serviceId + }', fnName='${req.fnName}' args='${jsonify(req.args)}'`, }; } - log_particle.trace('id %s. executed call service handler, req: %j, res: %j ', particleId, req, res); + log_particle.trace( + "id %s. executed call service handler, req: %j, res: %j ", + particleId, + req, + res, + ); + return res; } @@ -556,13 +724,17 @@ export abstract class FluencePeer { } } -function filterExpiredParticles(onParticleExpiration: (item: T) => void) { +function filterExpiredParticles( + onParticleExpiration: (item: T) => void, +) { return pipe( tap((item: T) => { if (hasExpired(item.particle)) { onParticleExpiration(item); } }), - filter((x) => !hasExpired(x.particle)), + filter((x) => { + return !hasExpired(x.particle); + }), ); } diff --git a/packages/core/js-client/src/jsPeer/__test__/avm.spec.ts b/packages/core/js-client/src/jsPeer/__test__/avm.spec.ts index 548fe4c41..cd5022c2b 100644 --- a/packages/core/js-client/src/jsPeer/__test__/avm.spec.ts +++ b/packages/core/js-client/src/jsPeer/__test__/avm.spec.ts @@ -1,15 +1,33 @@ -import { it, describe, expect } from 'vitest'; -import { registerHandlersHelper, withPeer } from '../../util/testUtils.js'; -import { handleTimeout } from '../../particle/Particle.js'; - -describe('Basic AVM functionality in Fluence Peer tests', () => { - it('Simple call', async () => { +/** + * 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 { it, describe, expect } from "vitest"; + +import { handleTimeout } from "../../particle/Particle.js"; +import { registerHandlersHelper, withPeer } from "../../util/testUtils.js"; + +describe("Basic AVM functionality in Fluence Peer tests", () => { + it("Simple call", async () => { await withPeer(async (peer) => { const script = ` (call %init_peer_id% ("print" "print") ["1"]) `; + const particle = await peer.internals.createNewParticle(script); - + const res = await new Promise((resolve, reject) => { if (particle instanceof Error) { return reject(particle.message); @@ -24,14 +42,17 @@ describe('Basic AVM functionality in Fluence Peer tests', () => { }, }); - peer.internals.initiateParticle(particle, handleTimeout(reject)); + peer.internals.initiateParticle( + particle, + handleTimeout(reject), + ); }); - expect(res).toBe('1'); + expect(res).toBe("1"); }); }); - it('Par call', async () => { + it("Par call", async () => { await withPeer(async (peer) => { const script = ` (seq @@ -42,8 +63,9 @@ describe('Basic AVM functionality in Fluence Peer tests', () => { (call %init_peer_id% ("print" "print") ["2"]) ) `; + const particle = await peer.internals.createNewParticle(script); - + const res = await new Promise((resolve, reject) => { const res: any[] = []; @@ -55,6 +77,7 @@ describe('Basic AVM functionality in Fluence Peer tests', () => { print: { print: (args: any) => { res.push(args[0]); + if (res.length == 2) { resolve(res); } @@ -62,14 +85,17 @@ describe('Basic AVM functionality in Fluence Peer tests', () => { }, }); - peer.internals.initiateParticle(particle, handleTimeout(reject)); + peer.internals.initiateParticle( + particle, + handleTimeout(reject), + ); }); - expect(res).toStrictEqual(['1', '2']); + expect(res).toStrictEqual(["1", "2"]); }); }); - it('Timeout in par call: race', async () => { + it("Timeout in par call: race", async () => { await withPeer(async (peer) => { const script = ` (seq @@ -86,8 +112,9 @@ describe('Basic AVM functionality in Fluence Peer tests', () => { ) ) `; + const particle = await peer.internals.createNewParticle(script); - + const res = await new Promise((resolve, reject) => { if (particle instanceof Error) { return reject(particle.message); @@ -101,14 +128,17 @@ describe('Basic AVM functionality in Fluence Peer tests', () => { }, }); - peer.internals.initiateParticle(particle, handleTimeout(reject)); + peer.internals.initiateParticle( + particle, + handleTimeout(reject), + ); }); - expect(res).toBe('fast_result'); + expect(res).toBe("fast_result"); }); }); - it('Timeout in par call: wait', async () => { + it("Timeout in par call: wait", async () => { await withPeer(async (peer) => { const script = ` (seq @@ -136,8 +166,9 @@ describe('Basic AVM functionality in Fluence Peer tests', () => { ) ) `; + const particle = await peer.internals.createNewParticle(script); - + const res = await new Promise((resolve, reject) => { if (particle instanceof Error) { return reject(particle.message); @@ -151,10 +182,13 @@ describe('Basic AVM functionality in Fluence Peer tests', () => { }, }); - peer.internals.initiateParticle(particle, handleTimeout(reject)); + peer.internals.initiateParticle( + particle, + handleTimeout(reject), + ); }); - expect(res).toBe('failed_with_timeout'); + expect(res).toBe("failed_with_timeout"); }); }); }); diff --git a/packages/core/js-client/src/jsPeer/__test__/par.spec.ts b/packages/core/js-client/src/jsPeer/__test__/par.spec.ts index 88182c5ac..3bd4400ba 100644 --- a/packages/core/js-client/src/jsPeer/__test__/par.spec.ts +++ b/packages/core/js-client/src/jsPeer/__test__/par.spec.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,13 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { describe, expect, it } from 'vitest'; -import { registerHandlersHelper, withPeer } from '../../util/testUtils.js'; -import { handleTimeout } from '../../particle/Particle.js'; -import { CallServiceData, ResultCodes } from '../../jsServiceHost/interfaces.js'; -describe('FluencePeer flow tests', () => { - it('should execute par instruction in parallel', async function () { +import { describe, expect, it } from "vitest"; + +import { + CallServiceData, + ResultCodes, +} from "../../jsServiceHost/interfaces.js"; +import { handleTimeout } from "../../particle/Particle.js"; +import { registerHandlersHelper, withPeer } from "../../util/testUtils.js"; + +describe("FluencePeer flow tests", () => { + it("should execute par instruction in parallel", async function () { await withPeer(async (peer) => { const script = ` (par @@ -35,26 +40,32 @@ describe('FluencePeer flow tests', () => { `; const particle = await peer.internals.createNewParticle(script); - + const res = await new Promise((resolve, reject) => { - peer.internals.regHandler.forParticle(particle.id, 'flow', 'timeout', (req: CallServiceData) => { - const [timeout, message] = req.args; - - return new Promise((resolve) => { - setTimeout(() => { - const res = { - result: message, - retCode: ResultCodes.success, - }; - resolve(res); - }, timeout); - }); - }); + peer.internals.regHandler.forParticle( + particle.id, + "flow", + "timeout", + (req: CallServiceData) => { + const [timeout, message] = req.args; + + return new Promise((resolve) => { + setTimeout(() => { + const res = { + result: message, + retCode: ResultCodes.success, + }; + + resolve(res); + }, timeout); + }); + }, + ); if (particle instanceof Error) { return reject(particle.message); } - + const values: any[] = []; registerHandlersHelper(peer, particle, { @@ -62,6 +73,7 @@ describe('FluencePeer flow tests', () => { callback1: (args: any) => { const [val] = args; values.push(val); + if (values.length === 2) { resolve(values); } @@ -69,6 +81,7 @@ describe('FluencePeer flow tests', () => { callback2: (args: any) => { const [val] = args; values.push(val); + if (values.length === 2) { resolve(values); } @@ -76,10 +89,15 @@ describe('FluencePeer flow tests', () => { }, }); - peer.internals.initiateParticle(particle, handleTimeout(reject)); + peer.internals.initiateParticle( + particle, + handleTimeout(reject), + ); }); - await expect(res).toEqual(expect.arrayContaining(["test1", "test1"])); + await expect(res).toEqual( + expect.arrayContaining(["test1", "test1"]), + ); }); }, 1500); -}); \ No newline at end of file +}); diff --git a/packages/core/js-client/src/jsPeer/__test__/parseAst.spec.ts b/packages/core/js-client/src/jsPeer/__test__/parseAst.spec.ts index 7c66043ed..4b3ba69e9 100644 --- a/packages/core/js-client/src/jsPeer/__test__/parseAst.spec.ts +++ b/packages/core/js-client/src/jsPeer/__test__/parseAst.spec.ts @@ -1,9 +1,25 @@ -import { it, describe, expect } from 'vitest'; +/** + * 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 { withPeer } from '../../util/testUtils.js'; +import { it, describe, expect } from "vitest"; -describe('Parse ast tests', () => { - it('Correct ast should be parsed correctly', async () => { +import { withPeer } from "../../util/testUtils.js"; + +describe("Parse ast tests", () => { + it("Correct ast should be parsed correctly", async () => { withPeer(async (peer) => { const air = `(null)`; const res = await peer.internals.parseAst(air); @@ -15,14 +31,14 @@ describe('Parse ast tests', () => { }); }); - it('Incorrect ast should result in corresponding error', async () => { + it("Incorrect ast should result in corresponding error", async () => { withPeer(async (peer) => { const air = `(null`; const res = await peer.internals.parseAst(air); expect(res).toStrictEqual({ success: false, - data: expect.stringContaining('error'), + data: expect.stringContaining("error"), }); }); }); diff --git a/packages/core/js-client/src/jsPeer/__test__/peer.spec.ts b/packages/core/js-client/src/jsPeer/__test__/peer.spec.ts index 09b880676..6ffbe5811 100644 --- a/packages/core/js-client/src/jsPeer/__test__/peer.spec.ts +++ b/packages/core/js-client/src/jsPeer/__test__/peer.spec.ts @@ -1,16 +1,36 @@ -import { it, describe, expect } from 'vitest'; - -import { isFluencePeer } from '../../api.js'; -import { mkTestPeer, registerHandlersHelper, withPeer } from '../../util/testUtils.js'; -import { handleTimeout } from '../../particle/Particle.js'; -import { FluencePeer } from '../FluencePeer.js'; - -describe('FluencePeer usage test suite', () => { - it('should perform test for FluencePeer class correctly', async () => { +/** + * 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 { it, describe, expect } from "vitest"; + +import { isFluencePeer } from "../../api.js"; +import { handleTimeout } from "../../particle/Particle.js"; +import { + mkTestPeer, + registerHandlersHelper, + withPeer, +} from "../../util/testUtils.js"; +import { FluencePeer } from "../FluencePeer.js"; + +describe("FluencePeer usage test suite", () => { + it("should perform test for FluencePeer class correctly", async () => { // arrange const peer = await mkTestPeer(); const number = 1; - const object = { str: 'Hello!' }; + const object = { str: "Hello!" }; const undefinedVal = undefined; // act @@ -26,7 +46,7 @@ describe('FluencePeer usage test suite', () => { expect(isUndefinedPeer).toBe(false); }); - it('Should successfully call identity on local peer', async function () { + it("Should successfully call identity on local peer", async function () { await withPeer(async (peer) => { const script = ` (seq @@ -34,8 +54,9 @@ describe('FluencePeer usage test suite', () => { (call %init_peer_id% ("callback" "callback") [res]) ) `; + const particle = await peer.internals.createNewParticle(script); - + const res = await new Promise((resolve, reject) => { if (particle instanceof Error) { return reject(particle.message); @@ -50,14 +71,17 @@ describe('FluencePeer usage test suite', () => { }, }); - peer.internals.initiateParticle(particle, handleTimeout(reject)); + peer.internals.initiateParticle( + particle, + handleTimeout(reject), + ); }); - expect(res).toBe('test'); + expect(res).toBe("test"); }); }); - it('Should throw correct message when calling non existing local service', async function () { + it("Should throw correct message when calling non existing local service", async function () { await withPeer(async (peer) => { const res = callIncorrectService(peer); @@ -65,12 +89,13 @@ describe('FluencePeer usage test suite', () => { message: expect.stringContaining( `"No service found for service call: serviceId='incorrect', fnName='incorrect' args='[]'"`, ), - instruction: 'call %init_peer_id% ("incorrect" "incorrect") [] res', + instruction: + 'call %init_peer_id% ("incorrect" "incorrect") [] res', }); }); }); - it('Should not crash if undefined is passed as a variable', async () => { + it("Should not crash if undefined is passed as a variable", async () => { await withPeer(async (peer) => { const script = ` (seq @@ -80,8 +105,9 @@ describe('FluencePeer usage test suite', () => { (call %init_peer_id% ("callback" "callback") [res]) ) )`; + const particle = await peer.internals.createNewParticle(script); - + const res = await new Promise((resolve, reject) => { if (particle instanceof Error) { return reject(particle.message); @@ -89,7 +115,9 @@ describe('FluencePeer usage test suite', () => { registerHandlersHelper(peer, particle, { load: { - arg: () => undefined, + arg: () => { + return undefined; + }, }, callback: { callback: (args: any) => { @@ -103,22 +131,26 @@ describe('FluencePeer usage test suite', () => { }, }); - peer.internals.initiateParticle(particle, handleTimeout(reject)); + peer.internals.initiateParticle( + particle, + handleTimeout(reject), + ); }); expect(res).toBe(null); }); }); - it('Should not crash if an error ocurred in user-defined handler', async () => { + it("Should not crash if an error ocurred in user-defined handler", async () => { await withPeer(async (peer) => { const script = ` (xor (call %init_peer_id% ("load" "arg") [] arg) (call %init_peer_id% ("callback" "error") [%last_error%]) )`; + const particle = await peer.internals.createNewParticle(script); - + const promise = new Promise((_resolve, reject) => { if (particle instanceof Error) { return reject(particle.message); @@ -127,7 +159,7 @@ describe('FluencePeer usage test suite', () => { registerHandlersHelper(peer, particle, { load: { arg: () => { - throw new Error('my super custom error message'); + throw new Error("my super custom error message"); }, }, callback: { @@ -138,11 +170,16 @@ describe('FluencePeer usage test suite', () => { }, }); - peer.internals.initiateParticle(particle, handleTimeout(reject)); + peer.internals.initiateParticle( + particle, + handleTimeout(reject), + ); }); await expect(promise).rejects.toMatchObject({ - message: expect.stringContaining('my super custom error message'), + message: expect.stringContaining( + "my super custom error message", + ), }); }); }); @@ -154,8 +191,9 @@ async function callIncorrectService(peer: FluencePeer): Promise { (call %init_peer_id% ("incorrect" "incorrect") [] res) (call %init_peer_id% ("callback" "error") [%last_error%]) )`; + const particle = await peer.internals.createNewParticle(script); - + return new Promise((resolve, reject) => { if (particle instanceof Error) { return reject(particle.message); diff --git a/packages/core/js-client/src/jsServiceHost/JsServiceHost.ts b/packages/core/js-client/src/jsServiceHost/JsServiceHost.ts index fd41de189..369f0ebe2 100644 --- a/packages/core/js-client/src/jsServiceHost/JsServiceHost.ts +++ b/packages/core/js-client/src/jsServiceHost/JsServiceHost.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,17 +13,29 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { CallServiceData, CallServiceResult, GenericCallServiceHandler, IJsServiceHost } from './interfaces.js'; + +import { + CallServiceData, + CallServiceResult, + GenericCallServiceHandler, + IJsServiceHost, +} from "./interfaces.js"; export class JsServiceHost implements IJsServiceHost { - private particleScopeHandlers = new Map>(); + private particleScopeHandlers = new Map< + string, + Map + >(); private commonHandlers = new Map(); /** * Returns true if any handler for the specified serviceId is registered */ hasService(serviceId: string): boolean { - return this.commonHandlers.has(serviceId) || this.particleScopeHandlers.has(serviceId); + return ( + this.commonHandlers.has(serviceId) || + this.particleScopeHandlers.has(serviceId) + ); } /** @@ -40,7 +52,11 @@ export class JsServiceHost implements IJsServiceHost { * @param fnName Function name as specified in `call` air instruction * @param particleId Particle ID */ - getHandler(serviceId: string, fnName: string, particleId: string): GenericCallServiceHandler | null { + getHandler( + serviceId: string, + fnName: string, + particleId: string, + ): GenericCallServiceHandler | null { const key = serviceFnKey(serviceId, fnName); const psh = this.particleScopeHandlers.get(particleId); let handler: GenericCallServiceHandler | undefined = undefined; @@ -64,7 +80,11 @@ export class JsServiceHost implements IJsServiceHost { * Execute service call for specified call service data. Return null if no handler was found */ async callService(req: CallServiceData): Promise { - const handler = this.getHandler(req.serviceId, req.fnName, req.particleContext.particleId); + const handler = this.getHandler( + req.serviceId, + req.fnName, + req.particleContext.particleId, + ); if (handler === null) { return null; @@ -83,7 +103,11 @@ export class JsServiceHost implements IJsServiceHost { /** * Register handler for all particles */ - registerGlobalHandler(serviceId: string, fnName: string, handler: GenericCallServiceHandler): void { + registerGlobalHandler( + serviceId: string, + fnName: string, + handler: GenericCallServiceHandler, + ): void { this.commonHandlers.set(serviceFnKey(serviceId, fnName), handler); } @@ -97,6 +121,7 @@ export class JsServiceHost implements IJsServiceHost { handler: GenericCallServiceHandler, ): void { let psh = this.particleScopeHandlers.get(particleId); + if (psh === undefined) { psh = new Map(); this.particleScopeHandlers.set(particleId, psh); diff --git a/packages/core/js-client/src/jsServiceHost/interfaces.ts b/packages/core/js-client/src/jsServiceHost/interfaces.ts index 09a879e63..b29b16399 100644 --- a/packages/core/js-client/src/jsServiceHost/interfaces.ts +++ b/packages/core/js-client/src/jsServiceHost/interfaces.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,12 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import type { PeerIdB58 } from '@fluencelabs/interfaces'; -import type { SecurityTetraplet } from '@fluencelabs/avm'; -import { JSONValue } from '../util/commonTypes.js'; + +import type { SecurityTetraplet } from "@fluencelabs/avm"; +import type { PeerIdB58 } from "@fluencelabs/interfaces"; + +import { JSONValue } from "../util/commonTypes.js"; /** - * JS Service host a low level interface for managing pure javascript services. + * JS Service host a low level interface for managing pure javascript services. * It operates on a notion of Call Service Handlers - functions which are called when a `call` air instruction is executed on the local peer. */ export interface IJsServiceHost { @@ -33,7 +35,11 @@ export interface IJsServiceHost { * @param fnName Function name as specified in `call` air instruction * @param particleId Particle ID */ - getHandler(serviceId: string, fnName: string, particleId: string): GenericCallServiceHandler | null; + getHandler( + serviceId: string, + fnName: string, + particleId: string, + ): GenericCallServiceHandler | null; /** * Execute service call for specified call service data @@ -43,7 +49,11 @@ export interface IJsServiceHost { /** * Register handler for all particles */ - registerGlobalHandler(serviceId: string, fnName: string, handler: GenericCallServiceHandler): void; + registerGlobalHandler( + serviceId: string, + fnName: string, + handler: GenericCallServiceHandler, + ): void; /** * Register handler which will be called only for particle with the specific id @@ -135,7 +145,9 @@ export type CallServiceResultType = JSONValue; /** * Generic call service handler */ -export type GenericCallServiceHandler = (req: CallServiceData) => CallServiceResult | Promise; +export type GenericCallServiceHandler = ( + req: CallServiceData, +) => CallServiceResult | Promise; /** * Represents the result of the `call` air instruction to be returned into AVM diff --git a/packages/core/js-client/src/jsServiceHost/serviceUtils.ts b/packages/core/js-client/src/jsServiceHost/serviceUtils.ts index 234fbf094..b7887caf2 100644 --- a/packages/core/js-client/src/jsServiceHost/serviceUtils.ts +++ b/packages/core/js-client/src/jsServiceHost/serviceUtils.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,25 +13,33 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { FluencePeer } from '../jsPeer/FluencePeer.js'; -import { IParticle } from '../particle/interfaces.js'; -import { builtInServices } from '../services/builtins.js'; + +import { FluencePeer } from "../jsPeer/FluencePeer.js"; +import { IParticle } from "../particle/interfaces.js"; +import { builtInServices } from "../services/builtins.js"; + import { CallServiceData, CallServiceResult, CallServiceResultType, ParticleContext, ResultCodes, -} from './interfaces.js'; +} from "./interfaces.js"; -export const doNothing = (..._args: Array) => undefined; +export const doNothing = (..._args: Array) => { + return undefined; +}; -export const WrapFnIntoServiceCall = - (fn: (args: any[]) => CallServiceResultType) => - (req: CallServiceData): CallServiceResult => ({ - retCode: ResultCodes.success, - result: fn(req.args), - }); +export const WrapFnIntoServiceCall = ( + fn: (args: any[]) => CallServiceResultType, +) => { + return (req: CallServiceData): CallServiceResult => { + return { + retCode: ResultCodes.success, + result: fn(req.args), + }; + }; +}; export class ServiceError extends Error { constructor(message: string) { diff --git a/packages/core/js-client/src/keypair/__test__/KeyPair.spec.ts b/packages/core/js-client/src/keypair/__test__/KeyPair.spec.ts index 79961b026..0cdbe2064 100644 --- a/packages/core/js-client/src/keypair/__test__/KeyPair.spec.ts +++ b/packages/core/js-client/src/keypair/__test__/KeyPair.spec.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,29 +13,32 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { it, describe, expect } from 'vitest'; -import { toUint8Array } from 'js-base64'; -import * as bs58 from 'bs58'; -import { KeyPair } from '../index.js'; + +import * as bs58 from "bs58"; +import { toUint8Array } from "js-base64"; +import { it, describe, expect } from "vitest"; + +import { KeyPair } from "../index.js"; // @ts-ignore const { decode } = bs58.default; -const key = '+cmeYlZKj+MfSa9dpHV+BmLPm6wq4inGlsPlQ1GvtPk='; +const key = "+cmeYlZKj+MfSa9dpHV+BmLPm6wq4inGlsPlQ1GvtPk="; const keyBytes = toUint8Array(key); const testData = Uint8Array.from([1, 2, 3, 4, 5, 6, 7, 9, 10]); const testDataSig = Uint8Array.from([ - 224, 104, 245, 206, 140, 248, 27, 72, 68, 133, 111, 10, 164, 197, 242, 132, 107, 77, 224, 67, 99, 106, 76, 29, 144, - 121, 122, 169, 36, 173, 58, 80, 170, 102, 137, 253, 157, 247, 168, 87, 162, 223, 188, 214, 203, 220, 52, 246, 29, + 224, 104, 245, 206, 140, 248, 27, 72, 68, 133, 111, 10, 164, 197, 242, 132, + 107, 77, 224, 67, 99, 106, 76, 29, 144, 121, 122, 169, 36, 173, 58, 80, 170, + 102, 137, 253, 157, 247, 168, 87, 162, 223, 188, 214, 203, 220, 52, 246, 29, 86, 77, 71, 224, 248, 16, 213, 254, 75, 78, 239, 243, 222, 241, 15, ]); // signature produced by KeyPair created from some random KeyPair -describe('KeyPair tests', () => { - it('generate keypair from seed', async function () { +describe("KeyPair tests", () => { + it("generate keypair from seed", async function () { // arrange const random = await KeyPair.randomEd25519(); const privateKey = random.toEd25519PrivateKey(); @@ -48,20 +51,22 @@ describe('KeyPair tests', () => { expect(privateKey).toStrictEqual(privateKey2); }); - it('create keypair from ed25519 private key', async function () { + it("create keypair from ed25519 private key", async function () { // arrange - const rustSK = 'jDaxLJzYtzgwTMrELJCAqavtmx85ktQNfB2rLcK7MhH'; + const rustSK = "jDaxLJzYtzgwTMrELJCAqavtmx85ktQNfB2rLcK7MhH"; const sk = decode(rustSK); // act const keyPair = await KeyPair.fromEd25519SK(sk); // assert - const expectedPeerId = '12D3KooWH1W3VznVZ87JH4FwABK4mkntcspTVWJDta6c2xg9Pzbp'; + const expectedPeerId = + "12D3KooWH1W3VznVZ87JH4FwABK4mkntcspTVWJDta6c2xg9Pzbp"; + expect(keyPair.getPeerId()).toStrictEqual(expectedPeerId); }); - it('create keypair from a seed phrase', async function () { + it("create keypair from a seed phrase", async function () { // arrange const seedArray = new Uint8Array(32).fill(1); @@ -69,11 +74,13 @@ describe('KeyPair tests', () => { const keyPair = await KeyPair.fromEd25519SK(seedArray); // assert - const expectedPeerId = '12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5'; + const expectedPeerId = + "12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5"; + expect(keyPair.getPeerId()).toStrictEqual(expectedPeerId); }); - it('sign', async function () { + it("sign", async function () { // arrange const keyPair = await KeyPair.fromEd25519SK(keyBytes); @@ -83,7 +90,7 @@ describe('KeyPair tests', () => { expect(new Uint8Array(res)).toStrictEqual(testDataSig); }); - it('verify', async function () { + it("verify", async function () { // arrange const keyPair = await KeyPair.fromEd25519SK(keyBytes); @@ -94,7 +101,7 @@ describe('KeyPair tests', () => { expect(res).toBe(true); }); - it('sign-verify', async function () { + it("sign-verify", async function () { // arrange const keyPair = await KeyPair.fromEd25519SK(keyBytes); diff --git a/packages/core/js-client/src/keypair/index.ts b/packages/core/js-client/src/keypair/index.ts index a6ce6003a..2f6271010 100644 --- a/packages/core/js-client/src/keypair/index.ts +++ b/packages/core/js-client/src/keypair/index.ts @@ -1,5 +1,5 @@ -/* - * Copyright 2020 Fluence Labs Limited +/** + * 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. @@ -14,13 +14,13 @@ * limitations under the License. */ -import type { PeerId } from '@libp2p/interface/peer-id'; -import { generateKeyPairFromSeed, generateKeyPair, unmarshalPublicKey } from '@libp2p/crypto/keys'; -import { createFromPrivKey, createFromPubKey } from '@libp2p/peer-id-factory'; -import type { PrivateKey, PublicKey } from '@libp2p/interface/keys'; -import { toUint8Array } from 'js-base64'; -import * as bs58 from 'bs58'; -import { KeyPairOptions } from '@fluencelabs/interfaces'; +import { KeyPairOptions } from "@fluencelabs/interfaces"; +import { generateKeyPairFromSeed, generateKeyPair } from "@libp2p/crypto/keys"; +import type { PrivateKey, PublicKey } from "@libp2p/interface/keys"; +import type { PeerId } from "@libp2p/interface/peer-id"; +import { createFromPrivKey } from "@libp2p/peer-id-factory"; +import * as bs58 from "bs58"; +import { toUint8Array } from "js-base64"; // @ts-ignore const { decode } = bs58.default; @@ -36,7 +36,7 @@ export class KeyPair { constructor( private privateKey: PrivateKey | undefined, private publicKey: PublicKey, - private libp2pPeerId: PeerId + private libp2pPeerId: PeerId, ) {} /** @@ -45,7 +45,7 @@ export class KeyPair { * @returns - Promise with the created KeyPair */ static async fromEd25519SK(seed: Uint8Array): Promise { - const key = await generateKeyPairFromSeed('Ed25519', seed, 256); + const key = await generateKeyPairFromSeed("Ed25519", seed, 256); const lib2p2Pid = await createFromPrivKey(key); return new KeyPair(key, key.public, lib2p2Pid); } @@ -55,7 +55,7 @@ export class KeyPair { * @returns - Promise with the created KeyPair */ static async randomEd25519(): Promise { - const key = await generateKeyPair('Ed25519'); + const key = await generateKeyPair("Ed25519"); const lib2p2Pid = await createFromPrivKey(key); return new KeyPair(key, key.public, lib2p2Pid); } @@ -69,15 +69,17 @@ export class KeyPair { */ toEd25519PrivateKey(): Uint8Array { if (this.privateKey === undefined) { - throw new Error('Private key not supplied'); + throw new Error("Private key not supplied"); } + return this.privateKey.marshal().subarray(0, 32); } signBytes(data: Uint8Array): Promise { if (this.privateKey === undefined) { - throw new Error('Private key not supplied'); + throw new Error("Private key not supplied"); } + return this.privateKey.sign(data); } @@ -97,7 +99,7 @@ export const fromBase58Sk = (sk: string): Promise => { }; export const fromOpts = (opts: KeyPairOptions): Promise => { - if (opts.source === 'random') { + if (opts.source === "random") { return KeyPair.randomEd25519(); } diff --git a/packages/core/js-client/src/marine/__test__/marine-js.spec.ts b/packages/core/js-client/src/marine/__test__/marine-js.spec.ts index 22ecc6e03..979584dbb 100644 --- a/packages/core/js-client/src/marine/__test__/marine-js.spec.ts +++ b/packages/core/js-client/src/marine/__test__/marine-js.spec.ts @@ -1,31 +1,55 @@ -import { it, describe, expect, beforeAll } from 'vitest'; +/** + * 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 * as fs from 'fs'; -import * as url from 'url'; -import * as path from 'path'; -import { compileAqua, withPeer } from '../../util/testUtils.js'; +import * as fs from "fs"; +import * as path from "path"; +import * as url from "url"; + +import { it, describe, expect, beforeAll } from "vitest"; + +import { compileAqua, withPeer } from "../../util/testUtils.js"; let aqua: any; -const __dirname = url.fileURLToPath(new URL('.', import.meta.url)); +const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); -describe('Marine js tests', () => { +describe("Marine js tests", () => { beforeAll(async () => { - const pathToAquaFiles = path.join(__dirname, '../../../aqua_test/marine-js.aqua'); + const pathToAquaFiles = path.join( + __dirname, + "../../../aqua_test/marine-js.aqua", + ); + const { services, functions } = await compileAqua(pathToAquaFiles); aqua = functions; }); - it('should call marine service correctly', async () => { + it("should call marine service correctly", async () => { await withPeer(async (peer) => { // arrange - const wasm = await fs.promises.readFile(path.join(__dirname, '../../../data_for_test/greeting.wasm')); - await peer.registerMarineService(wasm, 'greeting'); + const wasm = await fs.promises.readFile( + path.join(__dirname, "../../../data_for_test/greeting.wasm"), + ); + + await peer.registerMarineService(wasm, "greeting"); // act - const res = await aqua.call(peer, { arg: 'test' }); + const res = await aqua.call(peer, { arg: "test" }); // assert - expect(res).toBe('Hi, Hi, Hi, test'); + expect(res).toBe("Hi, Hi, Hi, test"); }); }); }); diff --git a/packages/core/js-client/src/marine/deps-loader/common.ts b/packages/core/js-client/src/marine/deps-loader/common.ts index df7ba9862..198c1a5d5 100644 --- a/packages/core/js-client/src/marine/deps-loader/common.ts +++ b/packages/core/js-client/src/marine/deps-loader/common.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,13 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + // @ts-ignore -import { BlobWorker } from 'threads'; -import { fromBase64, toUint8Array } from 'js-base64'; +import { Buffer } from "buffer"; + +import { fromBase64, toUint8Array } from "js-base64"; +import { BlobWorker } from "threads"; // @ts-ignore -import type { WorkerImplementation } from 'threads/dist/types/master'; -import { Buffer } from 'buffer'; -import { LazyLoader } from '../interfaces.js'; +import type { WorkerImplementation } from "threads/dist/types/master"; + +import { LazyLoader } from "../interfaces.js"; export class InlinedWorkerLoader extends LazyLoader { constructor(b64script: string) { diff --git a/packages/core/js-client/src/marine/deps-loader/node.ts b/packages/core/js-client/src/marine/deps-loader/node.ts index 79f0a6472..2a118afd0 100644 --- a/packages/core/js-client/src/marine/deps-loader/node.ts +++ b/packages/core/js-client/src/marine/deps-loader/node.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,16 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { createRequire } from 'module'; // @ts-ignore -import type { WorkerImplementation } from 'threads/dist/types/master'; // @ts-ignore -import { Worker } from 'threads'; -import { Buffer } from 'buffer'; -import * as fs from 'fs'; -import * as path from 'path'; -import { LazyLoader } from '../interfaces.js'; +import { Buffer } from "buffer"; +import * as fs from "fs"; +import { createRequire } from "module"; +import * as path from "path"; + +import { Worker } from "threads"; +import type { WorkerImplementation } from "threads/dist/types/master"; + +import { LazyLoader } from "../interfaces.js"; const require = createRequire(import.meta.url); @@ -39,7 +41,10 @@ const bufferToSharedArrayBuffer = (buffer: Buffer): SharedArrayBuffer => { * @param source - object specifying the source of the file. Consist two fields: package name and file path. * @returns SharedArrayBuffer with the wasm file */ -export const loadWasmFromNpmPackage = async (source: { package: string; file: string }): Promise => { +export const loadWasmFromNpmPackage = async (source: { + package: string; + file: string; +}): Promise => { const packagePath = require.resolve(source.package); const filePath = path.join(path.dirname(packagePath), source.file); return loadWasmFromFileSystem(filePath); @@ -51,26 +56,34 @@ export const loadWasmFromNpmPackage = async (source: { package: string; file: st * @param filePath - path to the wasm file * @returns SharedArrayBuffer with the wasm fileWorker */ -export const loadWasmFromFileSystem = async (filePath: string): Promise => { +export const loadWasmFromFileSystem = async ( + filePath: string, +): Promise => { const buffer = await fs.promises.readFile(filePath); return bufferToSharedArrayBuffer(buffer); }; export class WasmLoaderFromFs extends LazyLoader { constructor(filePath: string) { - super(() => loadWasmFromFileSystem(filePath)); + super(() => { + return loadWasmFromFileSystem(filePath); + }); } } export class WasmLoaderFromNpm extends LazyLoader { constructor(pkg: string, file: string) { - super(() => loadWasmFromNpmPackage({ package: pkg, file: file })); + super(() => { + return loadWasmFromNpmPackage({ package: pkg, file: file }); + }); } } export class WorkerLoaderFromFs extends LazyLoader { constructor(scriptPath: string) { - super(() => new Worker(scriptPath)); + super(() => { + return new Worker(scriptPath); + }); } } diff --git a/packages/core/js-client/src/marine/deps-loader/web.ts b/packages/core/js-client/src/marine/deps-loader/web.ts index 3e4d91fa0..0784bd8a3 100644 --- a/packages/core/js-client/src/marine/deps-loader/web.ts +++ b/packages/core/js-client/src/marine/deps-loader/web.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,10 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { Buffer } from 'buffer'; -import { LazyLoader } from '../interfaces.js'; + +import { Buffer } from "buffer"; + +import type { WorkerImplementation } from "threads/dist/types/master"; + +import { LazyLoader } from "../interfaces.js"; // @ts-ignore -import type { WorkerImplementation } from 'threads/dist/types/master'; const bufferToSharedArrayBuffer = (buffer: Buffer): SharedArrayBuffer => { const sab = new SharedArrayBuffer(buffer.length); @@ -34,8 +37,10 @@ const bufferToSharedArrayBuffer = (buffer: Buffer): SharedArrayBuffer => { * @param filePath - path to the wasm file relative to current origin * @returns Either SharedArrayBuffer or Buffer with the wasm file */ -export const loadWasmFromUrl = async (filePath: string): Promise => { - const fullUrl = window.location.origin + '/' + filePath; +export const loadWasmFromUrl = async ( + filePath: string, +): Promise => { + const fullUrl = window.location.origin + "/" + filePath; const res = await fetch(fullUrl); const ab = await res.arrayBuffer(); new Uint8Array(ab); @@ -52,12 +57,16 @@ export const loadWasmFromUrl = async (filePath: string): Promise { constructor(filePath: string) { - super(() => loadWasmFromUrl(filePath)); + super(() => { + return loadWasmFromUrl(filePath); + }); } } export class WorkerLoaderFromUrl extends LazyLoader { constructor(scriptPath: string) { - super(() => new Worker(scriptPath)); + super(() => { + return new Worker(scriptPath); + }); } } diff --git a/packages/core/js-client/src/marine/interfaces.ts b/packages/core/js-client/src/marine/interfaces.ts index 10858ae86..ccbd7cf13 100644 --- a/packages/core/js-client/src/marine/interfaces.ts +++ b/packages/core/js-client/src/marine/interfaces.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,10 +13,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { CallResultsArray, InterpreterResult, RunParameters } from '@fluencelabs/avm'; -import { IStartable, JSONArray, JSONObject, CallParameters } from '../util/commonTypes.js'; + +import { + CallResultsArray, + InterpreterResult, + RunParameters, +} from "@fluencelabs/avm"; +import type { WorkerImplementation } from "threads/dist/types/master"; + +import { + IStartable, + JSONArray, + JSONObject, + CallParameters, +} from "../util/commonTypes.js"; // @ts-ignore -import type { WorkerImplementation } from 'threads/dist/types/master'; /** * Contract for marine host implementations. Marine host is responsible for creating calling and removing marine services @@ -25,7 +36,10 @@ export interface IMarineHost extends IStartable { /** * Creates marine service from the given module and service id */ - createService(serviceModule: ArrayBuffer | SharedArrayBuffer, serviceId: string): Promise; + createService( + serviceModule: ArrayBuffer | SharedArrayBuffer, + serviceId: string, + ): Promise; /** * Removes marine service with the given service id @@ -74,12 +88,16 @@ export interface IValueLoader { /** * Interface for something which can load wasm files */ -export interface IWasmLoader extends IValueLoader, IStartable {} +export interface IWasmLoader + extends IValueLoader, + IStartable {} /** * Interface for something which can thread.js based worker */ -export interface IWorkerLoader extends IValueLoader, IStartable {} +export interface IWorkerLoader + extends IValueLoader, + IStartable {} /** * Lazy loader for some value. Value is loaded only when `start` method is called @@ -91,7 +109,9 @@ export class LazyLoader implements IStartable, IValueLoader { getValue(): T { if (this.value == null) { - throw new Error('Value has not been loaded. Call `start` method to load the value.'); + throw new Error( + "Value has not been loaded. Call `start` method to load the value.", + ); } return this.value; diff --git a/packages/core/js-client/src/marine/worker-script/workerLoader.ts b/packages/core/js-client/src/marine/worker-script/workerLoader.ts index 813f9939c..af63adaab 100644 --- a/packages/core/js-client/src/marine/worker-script/workerLoader.ts +++ b/packages/core/js-client/src/marine/worker-script/workerLoader.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,14 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + // @ts-ignore -import type { WorkerImplementation } from 'threads/dist/types/master'; +import { Worker } from "threads"; +import type { WorkerImplementation } from "threads/dist/types/master"; + // @ts-ignore -import { Worker } from 'threads'; -import { LazyLoader } from '../interfaces.js'; +import { LazyLoader } from "../interfaces.js"; export class WorkerLoader extends LazyLoader { constructor() { - super(() => new Worker('../../../node_modules/@fluencelabs/marine-worker/dist/index.js')); + super(() => { + return new Worker( + "../../../node_modules/@fluencelabs/marine-worker/dist/index.js", + ); + }); } } diff --git a/packages/core/js-client/src/marine/worker/index.ts b/packages/core/js-client/src/marine/worker/index.ts index df6272597..e59aa4d7f 100644 --- a/packages/core/js-client/src/marine/worker/index.ts +++ b/packages/core/js-client/src/marine/worker/index.ts @@ -1,5 +1,5 @@ -/* - * Copyright 2022 Fluence Labs Limited +/** + * 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. @@ -14,73 +14,88 @@ * limitations under the License. */ -import type { JSONArray, JSONObject, CallParameters } from '@fluencelabs/marine-js/dist/types'; -import { LogFunction, logLevelToEnv } from '@fluencelabs/marine-js/dist/types'; -import type { MarineBackgroundInterface } from '@fluencelabs/marine-worker'; +import type { + JSONArray, + JSONObject, + CallParameters, +} from "@fluencelabs/marine-js/dist/types"; +import { LogFunction, logLevelToEnv } from "@fluencelabs/marine-js/dist/types"; +import type { MarineBackgroundInterface } from "@fluencelabs/marine-worker"; // @ts-ignore -import { ModuleThread, spawn, Thread } from 'threads'; +import { spawn, Thread } from "threads"; -import { MarineLogger, marineLogger } from '../../util/logger.js'; -import { IMarineHost, IWasmLoader, IWorkerLoader } from '../interfaces.js'; +import { MarineLogger, marineLogger } from "../../util/logger.js"; +import { IMarineHost, IWasmLoader, IWorkerLoader } from "../interfaces.js"; export class MarineBackgroundRunner implements IMarineHost { private workerThread?: MarineBackgroundInterface; private loggers = new Map(); - constructor(private workerLoader: IWorkerLoader, private controlModuleLoader: IWasmLoader, private avmWasmLoader: IWasmLoader) {} + constructor( + private workerLoader: IWorkerLoader, + private controlModuleLoader: IWasmLoader, + private avmWasmLoader: IWasmLoader, + ) {} async hasService(serviceId: string) { if (!this.workerThread) { - throw new Error('Worker is not initialized'); + throw new Error("Worker is not initialized"); } - + return this.workerThread.hasService(serviceId); } async removeService(serviceId: string) { if (!this.workerThread) { - throw new Error('Worker is not initialized'); + throw new Error("Worker is not initialized"); } - + await this.workerThread.removeService(serviceId); } async start(): Promise { if (this.workerThread) { - throw new Error('Worker thread already initialized'); + throw new Error("Worker thread already initialized"); } - + await this.controlModuleLoader.start(); const wasm = this.controlModuleLoader.getValue(); - + await this.avmWasmLoader.start(); await this.workerLoader.start(); const worker = await this.workerLoader.getValue(); - + const workerThread = await spawn(worker); + const logfn: LogFunction = (message) => { const serviceLogger = this.loggers.get(message.service); + if (!serviceLogger) { return; } + serviceLogger[message.level](message.message); }; + workerThread.onLogMessage().subscribe(logfn); await workerThread.init(wasm); this.workerThread = workerThread; - await this.createService(this.avmWasmLoader.getValue(), 'avm'); + await this.createService(this.avmWasmLoader.getValue(), "avm"); } - async createService(serviceModule: ArrayBuffer | SharedArrayBuffer, serviceId: string): Promise { + async createService( + serviceModule: ArrayBuffer | SharedArrayBuffer, + serviceId: string, + ): Promise { if (!this.workerThread) { - throw new Error('Worker is not initialized'); + throw new Error("Worker is not initialized"); } // The logging level is controlled by the environment variable passed to enable debug logs. // We enable all possible log levels passing the control for exact printouts to the logger - const env = logLevelToEnv('info'); + const env = logLevelToEnv("info"); this.loggers.set(serviceId, marineLogger(serviceId)); await this.workerThread.createService(serviceModule, serviceId, env); } @@ -92,17 +107,22 @@ export class MarineBackgroundRunner implements IMarineHost { callParams: CallParameters, ): Promise { if (!this.workerThread) { - throw 'Worker is not initialized'; + throw "Worker is not initialized"; } - return this.workerThread.callService(serviceId, functionName, args, callParams); + return this.workerThread.callService( + serviceId, + functionName, + args, + callParams, + ); } async stop(): Promise { if (!this.workerThread) { return; } - + await this.workerThread.terminate(); await Thread.terminate(this.workerThread); } diff --git a/packages/core/js-client/src/particle/Particle.ts b/packages/core/js-client/src/particle/Particle.ts index 5482ca180..d5271fabc 100644 --- a/packages/core/js-client/src/particle/Particle.ts +++ b/packages/core/js-client/src/particle/Particle.ts @@ -1,5 +1,5 @@ -/* - * Copyright 2020 Fluence Labs Limited +/** + * 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. @@ -14,37 +14,53 @@ * limitations under the License. */ -import { atob, fromUint8Array, toUint8Array } from 'js-base64'; -import { CallResultsArray } from '@fluencelabs/avm'; -import { v4 as uuidv4 } from 'uuid'; -import { Buffer } from 'buffer'; -import { IParticle } from './interfaces.js'; -import { concat } from 'uint8arrays/concat'; -import { numberToLittleEndianBytes } from '../util/bytes.js'; -import { KeyPair } from '../keypair/index.js'; -import { unmarshalPublicKey } from '@libp2p/crypto/keys'; +import { Buffer } from "buffer"; + +import { CallResultsArray } from "@fluencelabs/avm"; +import { fromUint8Array, toUint8Array } from "js-base64"; +import { concat } from "uint8arrays/concat"; +import { v4 as uuidv4 } from "uuid"; + +import { KeyPair } from "../keypair/index.js"; +import { numberToLittleEndianBytes } from "../util/bytes.js"; + +import { IParticle } from "./interfaces.js"; export class Particle implements IParticle { constructor( - public readonly id: string, - public readonly timestamp: number, - public readonly script: string, - public readonly data: Uint8Array, - public readonly ttl: number, - public readonly initPeerId: string, - public readonly signature: Uint8Array + readonly id: string, + readonly timestamp: number, + readonly script: string, + readonly data: Uint8Array, + readonly ttl: number, + readonly initPeerId: string, + readonly signature: Uint8Array, ) {} - static async createNew(script: string, initPeerId: string, ttl: number, keyPair: KeyPair): Promise { + static async createNew( + script: string, + initPeerId: string, + ttl: number, + keyPair: KeyPair, + ): Promise { const id = uuidv4(); const timestamp = Date.now(); const message = buildParticleMessage({ id, timestamp, ttl, script }); const signature = await keyPair.signBytes(message); - return new Particle(id, Date.now(), script, Buffer.from([]), ttl, initPeerId, signature); + return new Particle( + id, + Date.now(), + script, + Buffer.from([]), + ttl, + initPeerId, + signature, + ); } static fromString(str: string): Particle { const json = JSON.parse(str); + const res = new Particle( json.id, json.timestamp, @@ -52,7 +68,7 @@ export class Particle implements IParticle { toUint8Array(json.data), json.ttl, json.init_peer_id, - new Uint8Array(json.signature) + new Uint8Array(json.signature), ); return res; @@ -64,14 +80,19 @@ const en = new TextEncoder(); /** * Builds particle message for signing */ -export const buildParticleMessage = ({ id, timestamp, ttl, script }: Omit): Uint8Array => { +export const buildParticleMessage = ({ + id, + timestamp, + ttl, + script, +}: Omit): Uint8Array => { return concat([ en.encode(id), - numberToLittleEndianBytes(timestamp, 'u64'), - numberToLittleEndianBytes(ttl, 'u32'), + numberToLittleEndianBytes(timestamp, "u64"), + numberToLittleEndianBytes(ttl, "u32"), en.encode(script), ]); -} +}; /** * Returns actual ttl of a particle, i.e. ttl - time passed since particle creation @@ -90,18 +111,32 @@ export const hasExpired = (particle: IParticle): boolean => { /** * Validates that particle signature is correct */ -export const verifySignature = async (particle: IParticle, publicKey: Uint8Array): Promise => { +export const verifySignature = async ( + particle: IParticle, + publicKey: Uint8Array, +): Promise => { // TODO: Uncomment this when nox roll out particle signatures return true; // const message = buildParticleMessage(particle); // return unmarshalPublicKey(publicKey).verify(message, particle.signature); -} +}; /** * Creates a particle clone with new data */ -export const cloneWithNewData = (particle: IParticle, newData: Uint8Array): IParticle => { - return new Particle(particle.id, particle.timestamp, particle.script, newData, particle.ttl, particle.initPeerId, particle.signature); +export const cloneWithNewData = ( + particle: IParticle, + newData: Uint8Array, +): IParticle => { + return new Particle( + particle.id, + particle.timestamp, + particle.script, + newData, + particle.ttl, + particle.initPeerId, + particle.signature, + ); }; /** @@ -116,7 +151,7 @@ export const fullClone = (particle: IParticle): IParticle => { */ export const serializeToString = (particle: IParticle): string => { return JSON.stringify({ - action: 'Particle', + action: "Particle", id: particle.id, init_peer_id: particle.initPeerId, timestamp: particle.timestamp, @@ -131,13 +166,13 @@ export const serializeToString = (particle: IParticle): string => { * When particle is executed, it goes through different stages. The type describes all possible stages and their parameters */ export type ParticleExecutionStage = - | { stage: 'received' } - | { stage: 'interpreted' } - | { stage: 'interpreterError'; errorMessage: string } - | { stage: 'localWorkDone' } - | { stage: 'sent' } - | { stage: 'sendingError'; errorMessage: string } - | { stage: 'expired' }; + | { stage: "received" } + | { stage: "interpreted" } + | { stage: "interpreterError"; errorMessage: string } + | { stage: "localWorkDone" } + | { stage: "sent" } + | { stage: "sendingError"; errorMessage: string } + | { stage: "expired" }; /** * Particle queue item is a wrapper around particle, which contains additional information about particle execution @@ -151,8 +186,10 @@ export interface ParticleQueueItem { /** * Helper function to handle particle at expired stage */ -export const handleTimeout = (fn: () => void) => (stage: ParticleExecutionStage) => { - if (stage.stage === 'expired') { - fn(); - } +export const handleTimeout = (fn: () => void) => { + return (stage: ParticleExecutionStage) => { + if (stage.stage === "expired") { + fn(); + } + }; }; diff --git a/packages/core/js-client/src/particle/interfaces.ts b/packages/core/js-client/src/particle/interfaces.ts index 3f7a131ab..ca942ec38 100644 --- a/packages/core/js-client/src/particle/interfaces.ts +++ b/packages/core/js-client/src/particle/interfaces.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { PeerIdB58 } from '@fluencelabs/interfaces'; + +import { PeerIdB58 } from "@fluencelabs/interfaces"; /** * Immutable part of the particle. diff --git a/packages/core/js-client/src/services/NodeUtils.ts b/packages/core/js-client/src/services/NodeUtils.ts index d6b89be88..cd91be5bc 100644 --- a/packages/core/js-client/src/services/NodeUtils.ts +++ b/packages/core/js-client/src/services/NodeUtils.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,26 +14,29 @@ * limitations under the License. */ -import { CallParams, IFluenceInternalApi } from '@fluencelabs/interfaces'; -import { defaultGuard } from './SingleModuleSrv.js'; -import { NodeUtilsDef, registerNodeUtils } from './_aqua/node-utils.js'; -import { SecurityGuard } from './securityGuard.js'; -import * as fs from 'fs'; -import { FluencePeer } from '../jsPeer/FluencePeer.js'; -import { Buffer } from 'buffer'; +import { Buffer } from "buffer"; +import * as fs from "fs"; + +import { CallParams } from "@fluencelabs/interfaces"; + +import { FluencePeer } from "../jsPeer/FluencePeer.js"; + +import { NodeUtilsDef, registerNodeUtils } from "./_aqua/node-utils.js"; +import { SecurityGuard } from "./securityGuard.js"; +import { defaultGuard } from "./SingleModuleSrv.js"; export class NodeUtils implements NodeUtilsDef { constructor(private peer: FluencePeer) { this.securityGuard_readFile = defaultGuard(this.peer); } - securityGuard_readFile: SecurityGuard<'path'>; + securityGuard_readFile: SecurityGuard<"path">; - async read_file(path: string, callParams: CallParams<'path'>) { + async read_file(path: string, callParams: CallParams<"path">) { if (!this.securityGuard_readFile(callParams)) { return { success: false, - error: 'Security guard validation failed', + error: "Security guard validation failed", content: null, }; } @@ -46,9 +49,11 @@ export class NodeUtils implements NodeUtilsDef { reject(err); return; } + resolve(data); - }) + }); }); + return { success: true, content: data as unknown as string, @@ -66,5 +71,5 @@ export class NodeUtils implements NodeUtilsDef { // HACK:: security guard functions must be ported to user API export const doRegisterNodeUtils = (peer: any) => { - registerNodeUtils(peer, 'node_utils', new NodeUtils(peer)); + registerNodeUtils(peer, "node_utils", new NodeUtils(peer)); }; diff --git a/packages/core/js-client/src/services/Sig.ts b/packages/core/js-client/src/services/Sig.ts index 64703bfd8..ac6a588d6 100644 --- a/packages/core/js-client/src/services/Sig.ts +++ b/packages/core/js-client/src/services/Sig.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,22 +14,30 @@ * limitations under the License. */ -import { CallParams, PeerIdB58 } from '@fluencelabs/interfaces'; -import { KeyPair } from '../keypair/index.js'; -import { FluencePeer } from '../jsPeer/FluencePeer.js'; -import { SigDef } from './_aqua/services.js'; -import { allowOnlyParticleOriginatedAt, allowServiceFn, and, or, SecurityGuard } from './securityGuard.js'; +import { CallParams, PeerIdB58 } from "@fluencelabs/interfaces"; + +import { FluencePeer } from "../jsPeer/FluencePeer.js"; +import { KeyPair } from "../keypair/index.js"; + +import { SigDef } from "./_aqua/services.js"; +import { + allowOnlyParticleOriginatedAt, + allowServiceFn, + and, + or, + SecurityGuard, +} from "./securityGuard.js"; export const defaultSigGuard = (peerId: PeerIdB58) => { - return and<'data'>( + return and<"data">( allowOnlyParticleOriginatedAt(peerId), or( - allowServiceFn('trust-graph', 'get_trust_bytes'), - allowServiceFn('trust-graph', 'get_revocation_bytes'), - allowServiceFn('registry', 'get_key_bytes'), - allowServiceFn('registry', 'get_record_bytes'), - allowServiceFn('registry', 'get_record_metadata_bytes'), - allowServiceFn('registry', 'get_tombstone_bytes'), + allowServiceFn("trust-graph", "get_trust_bytes"), + allowServiceFn("trust-graph", "get_revocation_bytes"), + allowServiceFn("registry", "get_key_bytes"), + allowServiceFn("registry", "get_record_bytes"), + allowServiceFn("registry", "get_record_metadata_bytes"), + allowServiceFn("registry", "get_tombstone_bytes"), ), ); }; @@ -40,7 +48,7 @@ export class Sig implements SigDef { /** * Configurable security guard for sign method */ - securityGuard: SecurityGuard<'data'> = (params) => { + securityGuard: SecurityGuard<"data"> = (params) => { return true; }; @@ -56,12 +64,16 @@ export class Sig implements SigDef { */ async sign( data: number[], - callParams: CallParams<'data'>, - ): Promise<{ error: string | null; signature: number[] | null; success: boolean }> { + callParams: CallParams<"data">, + ): Promise<{ + error: string | null; + signature: number[] | null; + success: boolean; + }> { if (!this.securityGuard(callParams)) { return { success: false, - error: 'Security guard validation failed', + error: "Security guard validation failed", signature: null, }; } @@ -79,7 +91,10 @@ export class Sig implements SigDef { * Verifies the signature. Required by aqua */ verify(signature: number[], data: number[]): Promise { - return this.keyPair.verify(Uint8Array.from(data), Uint8Array.from(signature)) + return this.keyPair.verify( + Uint8Array.from(data), + Uint8Array.from(signature), + ); } } diff --git a/packages/core/js-client/src/services/SingleModuleSrv.ts b/packages/core/js-client/src/services/SingleModuleSrv.ts index 36fedf498..815d6fb65 100644 --- a/packages/core/js-client/src/services/SingleModuleSrv.ts +++ b/packages/core/js-client/src/services/SingleModuleSrv.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,12 +14,18 @@ * limitations under the License. */ -import { v4 as uuidv4 } from 'uuid'; -import { SrvDef } from './_aqua/single-module-srv.js'; -import { FluencePeer } from '../jsPeer/FluencePeer.js'; -import { CallParams } from '@fluencelabs/interfaces'; -import { Buffer } from 'buffer'; -import { allowOnlyParticleOriginatedAt, SecurityGuard } from './securityGuard.js'; +import { Buffer } from "buffer"; + +import { CallParams } from "@fluencelabs/interfaces"; +import { v4 as uuidv4 } from "uuid"; + +import { FluencePeer } from "../jsPeer/FluencePeer.js"; + +import { SrvDef } from "./_aqua/single-module-srv.js"; +import { + allowOnlyParticleOriginatedAt, + SecurityGuard, +} from "./securityGuard.js"; export const defaultGuard = (peer: FluencePeer) => { return allowOnlyParticleOriginatedAt(peer.keyPair.getPeerId()); @@ -33,20 +39,23 @@ export class Srv implements SrvDef { this.securityGuard_remove = defaultGuard(this.peer); } - securityGuard_create: SecurityGuard<'wasm_b64_content'>; + securityGuard_create: SecurityGuard<"wasm_b64_content">; - async create(wasm_b64_content: string, callParams: CallParams<'wasm_b64_content'>) { + async create( + wasm_b64_content: string, + callParams: CallParams<"wasm_b64_content">, + ) { if (!this.securityGuard_create(callParams)) { return { success: false, - error: 'Security guard validation failed', + error: "Security guard validation failed", service_id: null, }; } try { const newServiceId = uuidv4(); - const buffer = Buffer.from(wasm_b64_content, 'base64'); + const buffer = Buffer.from(wasm_b64_content, "base64"); // TODO:: figure out why SharedArrayBuffer is not working here // const sab = new SharedArrayBuffer(buffer.length); // const tmp = new Uint8Array(sab); @@ -68,13 +77,13 @@ export class Srv implements SrvDef { } } - securityGuard_remove: SecurityGuard<'service_id'>; + securityGuard_remove: SecurityGuard<"service_id">; - async remove(service_id: string, callParams: CallParams<'service_id'>) { + async remove(service_id: string, callParams: CallParams<"service_id">) { if (!this.securityGuard_remove(callParams)) { return { success: false, - error: 'Security guard validation failed', + error: "Security guard validation failed", service_id: null, }; } diff --git a/packages/core/js-client/src/services/Tracing.ts b/packages/core/js-client/src/services/Tracing.ts index 93bb61b54..989441a40 100644 --- a/packages/core/js-client/src/services/Tracing.ts +++ b/packages/core/js-client/src/services/Tracing.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,11 +14,16 @@ * limitations under the License. */ -import { CallParams } from '@fluencelabs/interfaces'; -import { TracingDef } from './_aqua/tracing.js'; +import { CallParams } from "@fluencelabs/interfaces"; + +import { TracingDef } from "./_aqua/tracing.js"; export class Tracing implements TracingDef { - tracingEvent(arrowName: string, event: string, callParams: CallParams<'arrowName' | 'event'>): void { - console.log('[%s] (%s) %s', callParams.particleId, arrowName, event); + tracingEvent( + arrowName: string, + event: string, + callParams: CallParams<"arrowName" | "event">, + ): void { + console.log("[%s] (%s) %s", callParams.particleId, arrowName, event); } } diff --git a/packages/core/js-client/src/services/__test__/builtInHandler.spec.ts b/packages/core/js-client/src/services/__test__/builtInHandler.spec.ts index 8601f2d20..aad5992de 100644 --- a/packages/core/js-client/src/services/__test__/builtInHandler.spec.ts +++ b/packages/core/js-client/src/services/__test__/builtInHandler.spec.ts @@ -1,12 +1,28 @@ -import { it, describe, expect, test } from 'vitest'; - -import { CallParams } from '@fluencelabs/interfaces'; -import { toUint8Array } from 'js-base64'; -import { KeyPair } from '../../keypair/index.js'; -import { Sig, defaultSigGuard } from '../Sig.js'; -import { allowServiceFn } from '../securityGuard.js'; -import { builtInServices } from '../builtins.js'; -import { CallServiceData } from '../../jsServiceHost/interfaces.js'; +/** + * 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 { CallParams } from "@fluencelabs/interfaces"; +import { toUint8Array } from "js-base64"; +import { it, describe, expect, test } from "vitest"; + +import { CallServiceData } from "../../jsServiceHost/interfaces.js"; +import { KeyPair } from "../../keypair/index.js"; +import { builtInServices } from "../builtins.js"; +import { allowServiceFn } from "../securityGuard.js"; +import { Sig, defaultSigGuard } from "../Sig.js"; const a10b20 = `{ "a": 10, @@ -20,96 +36,96 @@ const oneTwoThreeFour = `[ 4 ]`; -describe('Tests for default handler', () => { +describe("Tests for default handler", () => { test.each` 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'} | ${'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'} | ${'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'} | ${'string_to_b58'} | ${['test']} | ${0} | ${'3yZe7d'} - ${'op'} | ${'string_to_b58'} | ${['test', 1]} | ${1} | ${'string_to_b58 accepts only one string argument'} - ${'op'} | ${'string_from_b58'} | ${['3yZe7d']} | ${0} | ${'test'} - ${'op'} | ${'string_from_b58'} | ${['3yZe7d', 1]} | ${1} | ${'string_from_b58 accepts only one string argument'} - ${'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_from_b58'} | ${['3yZe7d']} | ${0} | ${[116, 101, 115, 116]} - ${'op'} | ${'bytes_from_b58'} | ${['3yZe7d', 1]} | ${1} | ${'bytes_from_b58 accepts only one string argument'} - ${'op'} | ${'sha256_string'} | ${['hello, world!']} | ${0} | ${'QmVQ8pg6L1tpoWYeq6dpoWqnzZoSLCh7E96fCFXKvfKD3u'} - ${'op'} | ${'sha256_string'} | ${['hello, world!', true]} | ${0} | ${'84V7ZxLW7qKsx1Qvbd63BdGaHxUc3TfT2MBPqAXM7Wyu'} - ${'op'} | ${'sha256_string'} | ${[]} | ${1} | ${'sha256_string accepts 1-3 arguments, found: 0'} - ${'op'} | ${'concat_strings'} | ${[]} | ${0} | ${''} - ${'op'} | ${'concat_strings'} | ${['a', 'b', 'c']} | ${0} | ${'abc'} - ${'peer'} | ${'timeout'} | ${[200, []]} | ${0} | ${[]} - ${'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'} - ${'debug'} | ${'stringify'} | ${[]} | ${0} | ${'""'} - ${'debug'} | ${'stringify'} | ${[{ a: 10, b: 20 }]} | ${0} | ${a10b20} - ${'debug'} | ${'stringify'} | ${[1, 2, 3, 4]} | ${0} | ${oneTwoThreeFour} - ${'math'} | ${'add'} | ${[2, 2]} | ${0} | ${4} - ${'math'} | ${'add'} | ${[2]} | ${1} | ${'Expected 2 argument(s). Got 1'} - ${'math'} | ${'sub'} | ${[2, 2]} | ${0} | ${0} - ${'math'} | ${'sub'} | ${[2, 3]} | ${0} | ${-1} - ${'math'} | ${'mul'} | ${[2, 2]} | ${0} | ${4} - ${'math'} | ${'mul'} | ${[2, 0]} | ${0} | ${0} - ${'math'} | ${'mul'} | ${[2, -1]} | ${0} | ${-2} - ${'math'} | ${'fmul'} | ${[10, 0.66]} | ${0} | ${6} - ${'math'} | ${'fmul'} | ${[0.5, 0.5]} | ${0} | ${0} - ${'math'} | ${'fmul'} | ${[100.5, 0.5]} | ${0} | ${50} - ${'math'} | ${'div'} | ${[2, 2]} | ${0} | ${1} - ${'math'} | ${'div'} | ${[2, 3]} | ${0} | ${0} - ${'math'} | ${'div'} | ${[10, 5]} | ${0} | ${2} - ${'math'} | ${'rem'} | ${[10, 3]} | ${0} | ${1} - ${'math'} | ${'pow'} | ${[2, 2]} | ${0} | ${4} - ${'math'} | ${'pow'} | ${[2, 0]} | ${0} | ${1} - ${'math'} | ${'log'} | ${[2, 2]} | ${0} | ${1} - ${'math'} | ${'log'} | ${[2, 4]} | ${0} | ${2} - ${'cmp'} | ${'gt'} | ${[2, 4]} | ${0} | ${false} - ${'cmp'} | ${'gte'} | ${[2, 4]} | ${0} | ${false} - ${'cmp'} | ${'gte'} | ${[4, 2]} | ${0} | ${true} - ${'cmp'} | ${'gte'} | ${[2, 2]} | ${0} | ${true} - ${'cmp'} | ${'lt'} | ${[2, 4]} | ${0} | ${true} - ${'cmp'} | ${'lte'} | ${[2, 4]} | ${0} | ${true} - ${'cmp'} | ${'lte'} | ${[4, 2]} | ${0} | ${false} - ${'cmp'} | ${'lte'} | ${[2, 2]} | ${0} | ${true} - ${'cmp'} | ${'cmp'} | ${[2, 4]} | ${0} | ${-1} - ${'cmp'} | ${'cmp'} | ${[2, -4]} | ${0} | ${1} - ${'cmp'} | ${'cmp'} | ${[2, 2]} | ${0} | ${0} - ${'array'} | ${'sum'} | ${[[1, 2, 3]]} | ${0} | ${6} - ${'array'} | ${'dedup'} | ${[['a', 'a', 'b', 'c', 'a', 'b', 'c']]} | ${0} | ${['a', 'b', 'c']} - ${'array'} | ${'intersect'} | ${[['a', 'b', 'c'], ['c', 'b', 'd']]} | ${0} | ${['b', 'c']} - ${'array'} | ${'diff'} | ${[['a', 'b', 'c'], ['c', 'b', 'd']]} | ${0} | ${['a']} - ${'array'} | ${'sdiff'} | ${[['a', 'b', 'c'], ['c', 'b', 'd']]} | ${0} | ${['a', 'd']} - ${'json'} | ${'obj'} | ${['a', 10, 'b', 'string', 'c', null]} | ${0} | ${{ a: 10, b: 'string', c: null }} - ${'json'} | ${'obj'} | ${['a', 10, 'b', 'string', 'c']} | ${1} | ${'Expected even number of argument(s). Got 5'} - ${'json'} | ${'obj'} | ${[]} | ${0} | ${{}} - ${'json'} | ${'put'} | ${[{}, 'a', 10]} | ${0} | ${{ a: 10 }} - ${'json'} | ${'put'} | ${[{ b: 11 }, 'a', 10]} | ${0} | ${{ a: 10, b: 11 }} - ${'json'} | ${'put'} | ${['a', 'a', 11]} | ${1} | ${'Argument 0 expected to be of type object, Got string'} - ${'json'} | ${'put'} | ${[{}, 'a', 10, 'b', 20]} | ${1} | ${'Expected 3 argument(s). Got 5'} - ${'json'} | ${'put'} | ${[{}]} | ${1} | ${'Expected 3 argument(s). Got 1'} - ${'json'} | ${'puts'} | ${[{}, 'a', 10]} | ${0} | ${{ a: 10 }} - ${'json'} | ${'puts'} | ${[{ b: 11 }, 'a', 10]} | ${0} | ${{ a: 10, b: 11 }} - ${'json'} | ${'puts'} | ${[{}, 'a', 10, 'b', 'string', 'c', null]} | ${0} | ${{ a: 10, b: 'string', c: null }} - ${'json'} | ${'puts'} | ${[{ x: 'text' }, 'a', 10, 'b', 'string']} | ${0} | ${{ a: 10, b: 'string', x: 'text' }} - ${'json'} | ${'puts'} | ${[{}]} | ${1} | ${'Expected more than 3 argument(s). Got 1'} - ${'json'} | ${'puts'} | ${['a', 'a', 11]} | ${1} | ${'Argument 0 expected to be of type object, Got string'} - ${'json'} | ${'stringify'} | ${[{ a: 10, b: 'string', c: null }]} | ${0} | ${'{"a":10,"b":"string","c":null}'} - ${'json'} | ${'stringify'} | ${[1]} | ${1} | ${'Argument 0 expected to be of type object, Got number'} - ${'json'} | ${'parse'} | ${['{"a":10,"b":"string","c":null}']} | ${0} | ${{ a: 10, b: 'string', c: null }} - ${'json'} | ${'parse'} | ${['incorrect']} | ${1} | ${'Unexpected token i in JSON at position 0'} - ${'json'} | ${'parse'} | ${[10]} | ${1} | ${'Argument 0 expected to be of type string, Got number'} + ${"op"} | ${"identity"} | ${[]} | ${0} | ${{}} + ${"op"} | ${"identity"} | ${[1]} | ${0} | ${1} + ${"op"} | ${"identity"} | ${[1, 2]} | ${1} | ${"identity accepts up to 1 arguments, received 2 arguments"} + ${"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"} | ${"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"} | ${"string_to_b58"} | ${["test"]} | ${0} | ${"3yZe7d"} + ${"op"} | ${"string_to_b58"} | ${["test", 1]} | ${1} | ${"string_to_b58 accepts only one string argument"} + ${"op"} | ${"string_from_b58"} | ${["3yZe7d"]} | ${0} | ${"test"} + ${"op"} | ${"string_from_b58"} | ${["3yZe7d", 1]} | ${1} | ${"string_from_b58 accepts only one string argument"} + ${"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_from_b58"} | ${["3yZe7d"]} | ${0} | ${[116, 101, 115, 116]} + ${"op"} | ${"bytes_from_b58"} | ${["3yZe7d", 1]} | ${1} | ${"bytes_from_b58 accepts only one string argument"} + ${"op"} | ${"sha256_string"} | ${["hello, world!"]} | ${0} | ${"QmVQ8pg6L1tpoWYeq6dpoWqnzZoSLCh7E96fCFXKvfKD3u"} + ${"op"} | ${"sha256_string"} | ${["hello, world!", true]} | ${0} | ${"84V7ZxLW7qKsx1Qvbd63BdGaHxUc3TfT2MBPqAXM7Wyu"} + ${"op"} | ${"sha256_string"} | ${[]} | ${1} | ${"sha256_string accepts 1-3 arguments, found: 0"} + ${"op"} | ${"concat_strings"} | ${[]} | ${0} | ${""} + ${"op"} | ${"concat_strings"} | ${["a", "b", "c"]} | ${0} | ${"abc"} + ${"peer"} | ${"timeout"} | ${[200, []]} | ${0} | ${[]} + ${"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"} + ${"debug"} | ${"stringify"} | ${[]} | ${0} | ${'""'} + ${"debug"} | ${"stringify"} | ${[{ a: 10, b: 20 }]} | ${0} | ${a10b20} + ${"debug"} | ${"stringify"} | ${[1, 2, 3, 4]} | ${0} | ${oneTwoThreeFour} + ${"math"} | ${"add"} | ${[2, 2]} | ${0} | ${4} + ${"math"} | ${"add"} | ${[2]} | ${1} | ${"Expected 2 argument(s). Got 1"} + ${"math"} | ${"sub"} | ${[2, 2]} | ${0} | ${0} + ${"math"} | ${"sub"} | ${[2, 3]} | ${0} | ${-1} + ${"math"} | ${"mul"} | ${[2, 2]} | ${0} | ${4} + ${"math"} | ${"mul"} | ${[2, 0]} | ${0} | ${0} + ${"math"} | ${"mul"} | ${[2, -1]} | ${0} | ${-2} + ${"math"} | ${"fmul"} | ${[10, 0.66]} | ${0} | ${6} + ${"math"} | ${"fmul"} | ${[0.5, 0.5]} | ${0} | ${0} + ${"math"} | ${"fmul"} | ${[100.5, 0.5]} | ${0} | ${50} + ${"math"} | ${"div"} | ${[2, 2]} | ${0} | ${1} + ${"math"} | ${"div"} | ${[2, 3]} | ${0} | ${0} + ${"math"} | ${"div"} | ${[10, 5]} | ${0} | ${2} + ${"math"} | ${"rem"} | ${[10, 3]} | ${0} | ${1} + ${"math"} | ${"pow"} | ${[2, 2]} | ${0} | ${4} + ${"math"} | ${"pow"} | ${[2, 0]} | ${0} | ${1} + ${"math"} | ${"log"} | ${[2, 2]} | ${0} | ${1} + ${"math"} | ${"log"} | ${[2, 4]} | ${0} | ${2} + ${"cmp"} | ${"gt"} | ${[2, 4]} | ${0} | ${false} + ${"cmp"} | ${"gte"} | ${[2, 4]} | ${0} | ${false} + ${"cmp"} | ${"gte"} | ${[4, 2]} | ${0} | ${true} + ${"cmp"} | ${"gte"} | ${[2, 2]} | ${0} | ${true} + ${"cmp"} | ${"lt"} | ${[2, 4]} | ${0} | ${true} + ${"cmp"} | ${"lte"} | ${[2, 4]} | ${0} | ${true} + ${"cmp"} | ${"lte"} | ${[4, 2]} | ${0} | ${false} + ${"cmp"} | ${"lte"} | ${[2, 2]} | ${0} | ${true} + ${"cmp"} | ${"cmp"} | ${[2, 4]} | ${0} | ${-1} + ${"cmp"} | ${"cmp"} | ${[2, -4]} | ${0} | ${1} + ${"cmp"} | ${"cmp"} | ${[2, 2]} | ${0} | ${0} + ${"array"} | ${"sum"} | ${[[1, 2, 3]]} | ${0} | ${6} + ${"array"} | ${"dedup"} | ${[["a", "a", "b", "c", "a", "b", "c"]]} | ${0} | ${["a", "b", "c"]} + ${"array"} | ${"intersect"} | ${[["a", "b", "c"], ["c", "b", "d"]]} | ${0} | ${["b", "c"]} + ${"array"} | ${"diff"} | ${[["a", "b", "c"], ["c", "b", "d"]]} | ${0} | ${["a"]} + ${"array"} | ${"sdiff"} | ${[["a", "b", "c"], ["c", "b", "d"]]} | ${0} | ${["a", "d"]} + ${"json"} | ${"obj"} | ${["a", 10, "b", "string", "c", null]} | ${0} | ${{ a: 10, b: "string", c: null }} + ${"json"} | ${"obj"} | ${["a", 10, "b", "string", "c"]} | ${1} | ${"Expected even number of argument(s). Got 5"} + ${"json"} | ${"obj"} | ${[]} | ${0} | ${{}} + ${"json"} | ${"put"} | ${[{}, "a", 10]} | ${0} | ${{ a: 10 }} + ${"json"} | ${"put"} | ${[{ b: 11 }, "a", 10]} | ${0} | ${{ a: 10, b: 11 }} + ${"json"} | ${"put"} | ${["a", "a", 11]} | ${1} | ${"Argument 0 expected to be of type object, Got string"} + ${"json"} | ${"put"} | ${[{}, "a", 10, "b", 20]} | ${1} | ${"Expected 3 argument(s). Got 5"} + ${"json"} | ${"put"} | ${[{}]} | ${1} | ${"Expected 3 argument(s). Got 1"} + ${"json"} | ${"puts"} | ${[{}, "a", 10]} | ${0} | ${{ a: 10 }} + ${"json"} | ${"puts"} | ${[{ b: 11 }, "a", 10]} | ${0} | ${{ a: 10, b: 11 }} + ${"json"} | ${"puts"} | ${[{}, "a", 10, "b", "string", "c", null]} | ${0} | ${{ a: 10, b: "string", c: null }} + ${"json"} | ${"puts"} | ${[{ x: "text" }, "a", 10, "b", "string"]} | ${0} | ${{ a: 10, b: "string", x: "text" }} + ${"json"} | ${"puts"} | ${[{}]} | ${1} | ${"Expected more than 3 argument(s). Got 1"} + ${"json"} | ${"puts"} | ${["a", "a", 11]} | ${1} | ${"Argument 0 expected to be of type object, Got string"} + ${"json"} | ${"stringify"} | ${[{ a: 10, b: "string", c: null }]} | ${0} | ${'{"a":10,"b":"string","c":null}'} + ${"json"} | ${"stringify"} | ${[1]} | ${1} | ${"Argument 0 expected to be of type object, Got number"} + ${"json"} | ${"parse"} | ${['{"a":10,"b":"string","c":null}']} | ${0} | ${{ a: 10, b: "string", c: null }} + ${"json"} | ${"parse"} | ${["incorrect"]} | ${1} | ${"Unexpected token i in JSON at position 0"} + ${"json"} | ${"parse"} | ${[10]} | ${1} | ${"Argument 0 expected to be of type string, Got number"} `( // - '$fnName with $args expected retcode: $retCode and result: $result', + "$fnName with $args expected retcode: $retCode and result: $result", async ({ serviceId, fnName, args, retCode, result }) => { // arrange const req: CallServiceData = { @@ -118,8 +134,8 @@ describe('Tests for default handler', () => { args: args, tetraplets: [], particleContext: { - particleId: 'some', - initPeerId: 'init peer id', + particleId: "some", + initPeerId: "init peer id", timestamp: 595951200, ttl: 595961200, signature: new Uint8Array([]), @@ -129,11 +145,14 @@ describe('Tests for default handler', () => { // act const fn = builtInServices[req.serviceId][req.fnName]; const res = await fn(req); - + // Our test cases above depend on node error message. In node 20 error message for JSON.parse has changed. // Simple and fast solution for this specific case is to unify both variations into node 18 version error format. - if (res.result === 'Unexpected token \'i\', "incorrect" is not valid JSON') { - res.result = 'Unexpected token i in JSON at position 0'; + if ( + res.result === + "Unexpected token 'i', \"incorrect\" is not valid JSON" + ) { + res.result = "Unexpected token i in JSON at position 0"; } // assert @@ -144,16 +163,16 @@ describe('Tests for default handler', () => { }, ); - it('should return correct error message for identiy service', async () => { + it("should return correct error message for identiy service", async () => { // arrange const req: CallServiceData = { - serviceId: 'peer', - fnName: 'identify', + serviceId: "peer", + fnName: "identify", args: [], tetraplets: [], particleContext: { - particleId: 'some', - initPeerId: 'init peer id', + particleId: "some", + initPeerId: "init peer id", timestamp: 595951200, ttl: 595961200, signature: new Uint8Array([]), @@ -169,22 +188,24 @@ describe('Tests for default handler', () => { retCode: 0, result: { external_addresses: [], - node_version: expect.stringContaining('js'), - air_version: expect.stringContaining('js'), + node_version: expect.stringContaining("js"), + air_version: expect.stringContaining("js"), }, }); }); }); -const key = '+cmeYlZKj+MfSa9dpHV+BmLPm6wq4inGlsPlQ1GvtPk='; +const key = "+cmeYlZKj+MfSa9dpHV+BmLPm6wq4inGlsPlQ1GvtPk="; const context = (async () => { const keyBytes = toUint8Array(key); const kp = await KeyPair.fromEd25519SK(keyBytes); + const res = { peerKeyPair: kp, peerId: kp.getPeerId(), }; + return res; })(); @@ -192,19 +213,26 @@ const testData = [1, 2, 3, 4, 5, 6, 7, 9, 10]; // signature produced by KeyPair created from key above (`key` variable) const testDataSig = [ - 224, 104, 245, 206, 140, 248, 27, 72, 68, 133, 111, 10, 164, 197, 242, 132, 107, 77, 224, 67, 99, 106, 76, 29, 144, - 121, 122, 169, 36, 173, 58, 80, 170, 102, 137, 253, 157, 247, 168, 87, 162, 223, 188, 214, 203, 220, 52, 246, 29, + 224, 104, 245, 206, 140, 248, 27, 72, 68, 133, 111, 10, 164, 197, 242, 132, + 107, 77, 224, 67, 99, 106, 76, 29, 144, 121, 122, 169, 36, 173, 58, 80, 170, + 102, 137, 253, 157, 247, 168, 87, 162, 223, 188, 214, 203, 220, 52, 246, 29, 86, 77, 71, 224, 248, 16, 213, 254, 75, 78, 239, 243, 222, 241, 15, ]; // signature produced by KeyPair created from some random KeyPair const testDataWrongSig = [ - 116, 247, 189, 118, 236, 53, 147, 123, 219, 75, 176, 105, 101, 108, 233, 137, 97, 14, 146, 132, 252, 70, 51, 153, - 237, 167, 156, 150, 36, 90, 229, 108, 166, 231, 255, 137, 8, 246, 125, 0, 213, 150, 83, 196, 237, 221, 131, 159, - 157, 159, 25, 109, 95, 160, 181, 65, 254, 238, 47, 156, 240, 151, 58, 14, + 116, 247, 189, 118, 236, 53, 147, 123, 219, 75, 176, 105, 101, 108, 233, + 137, 97, 14, 146, 132, 252, 70, 51, 153, 237, 167, 156, 150, 36, 90, 229, + 108, 166, 231, 255, 137, 8, 246, 125, 0, 213, 150, 83, 196, 237, 221, 131, + 159, 157, 159, 25, 109, 95, 160, 181, 65, 254, 238, 47, 156, 240, 151, 58, + 14, ]; -const makeTetraplet = (initPeerId: string, serviceId?: string, fnName?: string): CallParams<'data'> => { +const makeTetraplet = ( + initPeerId: string, + serviceId?: string, + fnName?: string, +): CallParams<"data"> => { return { initPeerId: initPeerId, tetraplets: { @@ -218,8 +246,8 @@ const makeTetraplet = (initPeerId: string, serviceId?: string, fnName?: string): } as any; }; -describe('Sig service tests', () => { - it('sig.sign should create the correct signature', async () => { +describe("Sig service tests", () => { + it("sig.sign should create the correct signature", async () => { const ctx = await context; const sig = new Sig(ctx.peerKeyPair); @@ -229,7 +257,7 @@ describe('Sig service tests', () => { expect(res.signature).toStrictEqual(testDataSig); }); - it('sig.verify should return true for the correct signature', async () => { + it("sig.verify should return true for the correct signature", async () => { const ctx = await context; const sig = new Sig(ctx.peerKeyPair); @@ -238,7 +266,7 @@ describe('Sig service tests', () => { expect(res).toBe(true); }); - it('sig.verify should return false for the incorrect signature', async () => { + it("sig.verify should return false for the incorrect signature", async () => { const ctx = await context; const sig = new Sig(ctx.peerKeyPair); @@ -247,7 +275,7 @@ describe('Sig service tests', () => { expect(res).toBe(false); }); - it('sign-verify call chain should work', async () => { + it("sign-verify call chain should work", async () => { const ctx = await context; const sig = new Sig(ctx.peerKeyPair); @@ -257,53 +285,77 @@ describe('Sig service tests', () => { expect(res).toBe(true); }); - it('sig.sign with defaultSigGuard should work for correct callParams', async () => { + it("sig.sign with defaultSigGuard should work for correct callParams", async () => { const ctx = await context; const sig = new Sig(ctx.peerKeyPair); sig.securityGuard = defaultSigGuard(ctx.peerId); - const signature = await sig.sign(testData, makeTetraplet(ctx.peerId, 'registry', 'get_route_bytes')); + const signature = await sig.sign( + testData, + makeTetraplet(ctx.peerId, "registry", "get_route_bytes"), + ); await expect(signature).toBeDefined(); }); - it('sig.sign with defaultSigGuard should not allow particles initiated from incorrect service', async () => { + it("sig.sign with defaultSigGuard should not allow particles initiated from incorrect service", async () => { const ctx = await context; const sig = new Sig(ctx.peerKeyPair); sig.securityGuard = defaultSigGuard(ctx.peerId); - const res = await sig.sign(testData, makeTetraplet(ctx.peerId, 'other_service', 'other_fn')); + const res = await sig.sign( + testData, + makeTetraplet(ctx.peerId, "other_service", "other_fn"), + ); await expect(res.success).toBe(false); - await expect(res.error).toBe('Security guard validation failed'); + await expect(res.error).toBe("Security guard validation failed"); }); - it('sig.sign with defaultSigGuard should not allow particles initiated from other peers', async () => { + it("sig.sign with defaultSigGuard should not allow particles initiated from other peers", async () => { const ctx = await context; const sig = new Sig(ctx.peerKeyPair); sig.securityGuard = defaultSigGuard(ctx.peerId); const res = await sig.sign( testData, - makeTetraplet((await KeyPair.randomEd25519()).getPeerId(), 'registry', 'get_key_bytes'), + makeTetraplet( + (await KeyPair.randomEd25519()).getPeerId(), + "registry", + "get_key_bytes", + ), ); await expect(res.success).toBe(false); - await expect(res.error).toBe('Security guard validation failed'); + await expect(res.error).toBe("Security guard validation failed"); }); - it('changing securityGuard should work', async () => { + it("changing securityGuard should work", async () => { const ctx = await context; const sig = new Sig(ctx.peerKeyPair); - sig.securityGuard = allowServiceFn('test', 'test'); + sig.securityGuard = allowServiceFn("test", "test"); - const successful1 = await sig.sign(testData, makeTetraplet(ctx.peerId, 'test', 'test')); - const unSuccessful1 = await sig.sign(testData, makeTetraplet(ctx.peerId, 'wrong', 'wrong')); + const successful1 = await sig.sign( + testData, + makeTetraplet(ctx.peerId, "test", "test"), + ); - sig.securityGuard = allowServiceFn('wrong', 'wrong'); + const unSuccessful1 = await sig.sign( + testData, + makeTetraplet(ctx.peerId, "wrong", "wrong"), + ); - const successful2 = await sig.sign(testData, makeTetraplet(ctx.peerId, 'wrong', 'wrong')); - const unSuccessful2 = await sig.sign(testData, makeTetraplet(ctx.peerId, 'test', 'test')); + sig.securityGuard = allowServiceFn("wrong", "wrong"); + + const successful2 = await sig.sign( + testData, + makeTetraplet(ctx.peerId, "wrong", "wrong"), + ); + + const unSuccessful2 = await sig.sign( + testData, + makeTetraplet(ctx.peerId, "test", "test"), + ); expect(successful1.success).toBe(true); expect(successful2.success).toBe(true); diff --git a/packages/core/js-client/src/services/__test__/jsonBuiltin.spec.ts b/packages/core/js-client/src/services/__test__/jsonBuiltin.spec.ts index 02cf46672..3a5367a66 100644 --- a/packages/core/js-client/src/services/__test__/jsonBuiltin.spec.ts +++ b/packages/core/js-client/src/services/__test__/jsonBuiltin.spec.ts @@ -1,13 +1,28 @@ -import { it, describe, expect, beforeEach, afterEach } from 'vitest'; +/** + * 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 { Particle } from '../../particle/Particle.js'; -import { FluencePeer } from '../../jsPeer/FluencePeer.js'; -import { mkTestPeer } from '../../util/testUtils.js'; -import { doNothing } from '../../jsServiceHost/serviceUtils.js'; +import { it, describe, expect, beforeEach, afterEach } from "vitest"; + +import { FluencePeer } from "../../jsPeer/FluencePeer.js"; +import { doNothing } from "../../jsServiceHost/serviceUtils.js"; +import { mkTestPeer } from "../../util/testUtils.js"; let peer: FluencePeer; -describe('Sig service test suite', () => { +describe("Sig service test suite", () => { afterEach(async () => { if (peer) { await peer.stop(); @@ -19,7 +34,7 @@ describe('Sig service test suite', () => { await peer.start(); }); - it('JSON builtin spec', async () => { + it("JSON builtin spec", async () => { const script = ` (seq (seq @@ -47,8 +62,9 @@ describe('Sig service test suite', () => { (call %init_peer_id% ("res" "res") [nested_first nested_second outer_first outer_second outer_first_string outer_first_parsed]) ) `; + const promise = new Promise((resolve) => { - peer.internals.regHandler.common('res', 'res', (req) => { + peer.internals.regHandler.common("res", "res", (req) => { resolve(req.args); return { result: {}, @@ -56,17 +72,25 @@ describe('Sig service test suite', () => { }; }); }); + const p = await peer.internals.createNewParticle(script); await peer.internals.initiateParticle(p, doNothing); - const [nestedFirst, nestedSecond, outerFirst, outerSecond, outerFirstString, outerFirstParsed] = await promise; + const [ + nestedFirst, + nestedSecond, + outerFirst, + outerSecond, + outerFirstString, + outerFirstParsed, + ] = await promise; - const nfExpected = { name: 'nested_first', num: 1 }; - const nsExpected = { name: 'nested_second', num: 2 }; + const nfExpected = { name: "nested_first", num: 1 }; + const nsExpected = { name: "nested_second", num: 2 }; - const ofExpected = { name: 'outer_first', nested: nfExpected, num: 0 }; + const ofExpected = { name: "outer_first", nested: nfExpected, num: 0 }; const ofString = JSON.stringify(ofExpected); - const osExpected = { name: 'outer_second', num: 3, nested: nsExpected }; + const osExpected = { name: "outer_second", num: 3, nested: nsExpected }; expect(nestedFirst).toMatchObject(nfExpected); expect(nestedSecond).toMatchObject(nsExpected); diff --git a/packages/core/js-client/src/services/__test__/sigService.spec.ts b/packages/core/js-client/src/services/__test__/sigService.spec.ts index c3a40b0f0..598492b72 100644 --- a/packages/core/js-client/src/services/__test__/sigService.spec.ts +++ b/packages/core/js-client/src/services/__test__/sigService.spec.ts @@ -1,22 +1,43 @@ -import { it, describe, expect, beforeAll } from 'vitest'; - -import * as path from 'path'; -import * as url from 'url'; -import { KeyPair } from '../../keypair/index.js'; -import { allowServiceFn } from '../securityGuard.js'; -import { Sig } from '../Sig.js'; -import { registerService } from '../../compilerSupport/registerService.js'; -import { compileAqua, withPeer } from '../../util/testUtils.js'; - -const __dirname = url.fileURLToPath(new URL('.', import.meta.url)); +/** + * 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 * as path from "path"; +import * as url from "url"; + +import { it, describe, expect, beforeAll } from "vitest"; + +import { registerService } from "../../compilerSupport/registerService.js"; +import { KeyPair } from "../../keypair/index.js"; +import { compileAqua, withPeer } from "../../util/testUtils.js"; +import { allowServiceFn } from "../securityGuard.js"; +import { Sig } from "../Sig.js"; + +const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); let aqua: any; let sigDef: any; let dataProviderDef: any; -describe('Sig service test suite', () => { +describe("Sig service test suite", () => { beforeAll(async () => { - const pathToAquaFiles = path.join(__dirname, '../../../aqua_test/sigService.aqua'); + const pathToAquaFiles = path.join( + __dirname, + "../../../aqua_test/sigService.aqua", + ); + const { services, functions } = await compileAqua(pathToAquaFiles); aqua = functions; @@ -24,18 +45,23 @@ describe('Sig service test suite', () => { dataProviderDef = services.DataProvider; }); - it('Use custom sig service, success path', async () => { + it("Use custom sig service, success path", async () => { await withPeer(async (peer) => { const customKeyPair = await KeyPair.randomEd25519(); const customSig = new Sig(customKeyPair); const data = [1, 2, 3, 4, 5]; - registerService({ peer, def: sigDef, serviceId: 'CustomSig', service: customSig }); + registerService({ + peer, + def: sigDef, + serviceId: "CustomSig", + service: customSig, + }); registerService({ peer, def: dataProviderDef, - serviceId: 'data', + serviceId: "data", service: { provide_data: () => { return data; @@ -43,28 +69,38 @@ describe('Sig service test suite', () => { }, }); - customSig.securityGuard = allowServiceFn('data', 'provide_data'); + customSig.securityGuard = allowServiceFn("data", "provide_data"); - const result = await aqua.callSig(peer, { sigId: 'CustomSig' }); + const result = await aqua.callSig(peer, { sigId: "CustomSig" }); expect(result.success).toBe(true); - const isSigCorrect = await customSig.verify(result.signature as number[], data); + + const isSigCorrect = await customSig.verify( + result.signature as number[], + data, + ); + expect(isSigCorrect).toBe(true); }); }); - it('Use custom sig service, fail path', async () => { + it("Use custom sig service, fail path", async () => { await withPeer(async (peer) => { const customKeyPair = await KeyPair.randomEd25519(); const customSig = new Sig(customKeyPair); const data = [1, 2, 3, 4, 5]; - registerService({ peer, def: sigDef, serviceId: 'CustomSig', service: customSig }); + registerService({ + peer, + def: sigDef, + serviceId: "CustomSig", + service: customSig, + }); registerService({ peer, def: dataProviderDef, - serviceId: 'data', + serviceId: "data", service: { provide_data: () => { return data; @@ -72,22 +108,23 @@ describe('Sig service test suite', () => { }, }); - customSig.securityGuard = allowServiceFn('wrong', 'wrong'); + customSig.securityGuard = allowServiceFn("wrong", "wrong"); - const result = await aqua.callSig(peer, { sigId: 'CustomSig' }); + const result = await aqua.callSig(peer, { sigId: "CustomSig" }); expect(result.success).toBe(false); }); }); - it('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) => { const sig = peer.internals.getServices().sig; const data = [1, 2, 3, 4, 5]; + registerService({ peer: peer, def: dataProviderDef, - serviceId: 'data', + serviceId: "data", service: { provide_data: () => { return data; @@ -95,15 +132,23 @@ describe('Sig service test suite', () => { }, }); - const callAsSigRes = await aqua.callSig(peer, { sigId: 'sig' }); - const callAsPeerIdRes = await aqua.callSig(peer, { sigId: peer.keyPair.getPeerId() }); + const callAsSigRes = await aqua.callSig(peer, { sigId: "sig" }); + + const callAsPeerIdRes = await aqua.callSig(peer, { + sigId: peer.keyPair.getPeerId(), + }); expect(callAsSigRes.success).toBe(false); expect(callAsPeerIdRes.success).toBe(false); - sig.securityGuard = () => true; + sig.securityGuard = () => { + return true; + }; + + const callAsSigResAfterGuardChange = await aqua.callSig(peer, { + sigId: "sig", + }); - const callAsSigResAfterGuardChange = await aqua.callSig(peer, { sigId: 'sig' }); const callAsPeerIdResAfterGuardChange = await aqua.callSig(peer, { sigId: peer.keyPair.getPeerId(), }); @@ -111,7 +156,10 @@ describe('Sig service test suite', () => { expect(callAsSigResAfterGuardChange.success).toBe(true); expect(callAsPeerIdResAfterGuardChange.success).toBe(true); - const isValid = await sig.verify(callAsSigResAfterGuardChange.signature as number[], data); + const isValid = await sig.verify( + callAsSigResAfterGuardChange.signature as number[], + data, + ); expect(isValid).toBe(true); }); diff --git a/packages/core/js-client/src/services/__test__/srv.spec.ts b/packages/core/js-client/src/services/__test__/srv.spec.ts index 48c649c1d..3f3a8605c 100644 --- a/packages/core/js-client/src/services/__test__/srv.spec.ts +++ b/packages/core/js-client/src/services/__test__/srv.spec.ts @@ -1,39 +1,69 @@ -import { it, describe, expect, beforeAll } from 'vitest'; -import * as path from 'path'; -import * as url from 'url'; -import { compileAqua, withPeer } from '../../util/testUtils.js'; -import { registerNodeUtils } from '../_aqua/node-utils.js'; -import { NodeUtils } from '../NodeUtils.js'; - -const __dirname = url.fileURLToPath(new URL('.', import.meta.url)); +/** + * 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 * as path from "path"; +import * as url from "url"; + +import { it, describe, expect, beforeAll } from "vitest"; + +import { compileAqua, withPeer } from "../../util/testUtils.js"; +import { registerNodeUtils } from "../_aqua/node-utils.js"; +import { NodeUtils } from "../NodeUtils.js"; + +const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); let aqua: any; -describe('Srv service test suite', () => { +describe("Srv service test suite", () => { beforeAll(async () => { - const pathToAquaFiles = path.join(__dirname, '../../../aqua_test/srv.aqua'); + const pathToAquaFiles = path.join( + __dirname, + "../../../aqua_test/srv.aqua", + ); + const { services, functions } = await compileAqua(pathToAquaFiles); aqua = functions; }); - it('Use custom srv service, success path', async () => { + it("Use custom srv service, success path", async () => { await withPeer(async (peer) => { // arrange - registerNodeUtils(peer, 'node_utils', new NodeUtils(peer)); - const wasm = path.join(__dirname, '../../../data_for_test/greeting.wasm'); + registerNodeUtils(peer, "node_utils", new NodeUtils(peer)); + + const wasm = path.join( + __dirname, + "../../../data_for_test/greeting.wasm", + ); // act const res = await aqua.happy_path(peer, { file_path: wasm }); // assert - expect(res).toBe('Hi, test'); + expect(res).toBe("Hi, test"); }); }); - it('List deployed services', async () => { + it("List deployed services", async () => { await withPeer(async (peer) => { // arrange - registerNodeUtils(peer, 'node_utils', new NodeUtils(peer)); - const wasm = path.join(__dirname, '../../../data_for_test/greeting.wasm'); + registerNodeUtils(peer, "node_utils", new NodeUtils(peer)); + + const wasm = path.join( + __dirname, + "../../../data_for_test/greeting.wasm", + ); // act const res = await aqua.list_services(peer, { file_path: wasm }); @@ -43,43 +73,49 @@ describe('Srv service test suite', () => { }); }); - it('Correct error for removed services', async () => { + it("Correct error for removed services", async () => { await withPeer(async (peer) => { // arrange - registerNodeUtils(peer, 'node_utils', new NodeUtils(peer)); - const wasm = path.join(__dirname, '../../../data_for_test/greeting.wasm'); + registerNodeUtils(peer, "node_utils", new NodeUtils(peer)); + + const wasm = path.join( + __dirname, + "../../../data_for_test/greeting.wasm", + ); // act const res = await aqua.service_removed(peer, { file_path: wasm }); // assert - expect(res).toMatch('No service found for service call'); + expect(res).toMatch("No service found for service call"); }); }); - it('Correct error for file not found', async () => { + it("Correct error for file not found", async () => { await withPeer(async (peer) => { // arrange - registerNodeUtils(peer, 'node_utils', new NodeUtils(peer)); + registerNodeUtils(peer, "node_utils", new NodeUtils(peer)); // act const res = await aqua.file_not_found(peer, {}); // assert - expect(res).toMatch("ENOENT: no such file or directory, open '/random/incorrect/file'"); + expect(res).toMatch( + "ENOENT: no such file or directory, open '/random/incorrect/file'", + ); }); }); - it('Correct error for removing non existing service', async () => { + it("Correct error for removing non existing service", async () => { await withPeer(async (peer) => { // arrange - registerNodeUtils(peer, 'node_utils', new NodeUtils(peer)); + registerNodeUtils(peer, "node_utils", new NodeUtils(peer)); // act const res = await aqua.removing_non_exiting(peer, {}); // assert - expect(res).toMatch('Service with id random_id not found'); + expect(res).toMatch("Service with id random_id not found"); }); }); }); diff --git a/packages/core/js-client/src/services/_aqua/node-utils.ts b/packages/core/js-client/src/services/_aqua/node-utils.ts index d95db446c..be9379546 100644 --- a/packages/core/js-client/src/services/_aqua/node-utils.ts +++ b/packages/core/js-client/src/services/_aqua/node-utils.ts @@ -1,65 +1,90 @@ +/** + * 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. + */ + /** * This compiled aqua file was modified to make it work in monorepo */ -import { CallParams, IFluenceInternalApi } from '@fluencelabs/interfaces'; -import { registerService } from '../../compilerSupport/registerService.js'; +import { CallParams, IFluenceInternalApi } from "@fluencelabs/interfaces"; + +import { registerService } from "../../compilerSupport/registerService.js"; // Services export interface NodeUtilsDef { read_file: ( path: string, - callParams: CallParams<'path'>, + callParams: CallParams<"path">, ) => | { content: string | null; error: string | null; success: boolean } - | Promise<{ content: string | null; error: string | null; success: boolean }>; + | Promise<{ + content: string | null; + error: string | null; + success: boolean; + }>; } -export function registerNodeUtils(peer: IFluenceInternalApi, serviceId: string, service: any) { +export function registerNodeUtils( + peer: IFluenceInternalApi, + serviceId: string, + service: any, +) { registerService({ peer, service, serviceId, def: { - defaultServiceId: 'node_utils', + defaultServiceId: "node_utils", functions: { - tag: 'labeledProduct', + tag: "labeledProduct", fields: { read_file: { - tag: 'arrow', + tag: "arrow", domain: { - tag: 'labeledProduct', + tag: "labeledProduct", fields: { path: { - tag: 'scalar', - name: 'string', + tag: "scalar", + name: "string", }, }, }, codomain: { - tag: 'unlabeledProduct', + tag: "unlabeledProduct", items: [ { - tag: 'struct', - name: 'ReadFileResult', + tag: "struct", + name: "ReadFileResult", fields: { content: { - tag: 'option', + tag: "option", type: { - tag: 'scalar', - name: 'string', + tag: "scalar", + name: "string", }, }, error: { - tag: 'option', + tag: "option", type: { - tag: 'scalar', - name: 'string', + tag: "scalar", + name: "string", }, }, success: { - tag: 'scalar', - name: 'bool', + tag: "scalar", + name: "bool", }, }, }, diff --git a/packages/core/js-client/src/services/_aqua/services.ts b/packages/core/js-client/src/services/_aqua/services.ts index c99b978a5..eb7d9dc2a 100644 --- a/packages/core/js-client/src/services/_aqua/services.ts +++ b/packages/core/js-client/src/services/_aqua/services.ts @@ -1,8 +1,25 @@ +/** + * 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. + */ + /** * This compiled aqua file was modified to make it work in monorepo */ -import { CallParams, IFluenceInternalApi } from '@fluencelabs/interfaces'; -import { registerService } from '../../compilerSupport/registerService.js'; +import { CallParams, IFluenceInternalApi } from "@fluencelabs/interfaces"; + +import { registerService } from "../../compilerSupport/registerService.js"; // Services @@ -10,83 +27,91 @@ export interface SigDef { get_peer_id: (callParams: CallParams) => string | Promise; sign: ( data: number[], - callParams: CallParams<'data'>, + callParams: CallParams<"data">, ) => | { error: string | null; signature: number[] | null; success: boolean } - | Promise<{ error: string | null; signature: number[] | null; success: boolean }>; + | Promise<{ + error: string | null; + signature: number[] | null; + success: boolean; + }>; verify: ( signature: number[], data: number[], - callParams: CallParams<'signature' | 'data'>, + callParams: CallParams<"signature" | "data">, ) => boolean | Promise; } -export function registerSig(peer: IFluenceInternalApi, serviceId: string, service: any) { +export function registerSig( + peer: IFluenceInternalApi, + serviceId: string, + service: any, +) { registerService({ peer, service, serviceId, def: { - defaultServiceId: 'sig', + defaultServiceId: "sig", functions: { - tag: 'labeledProduct', + tag: "labeledProduct", fields: { get_peer_id: { - tag: 'arrow', + tag: "arrow", domain: { - tag: 'nil', + tag: "nil", }, codomain: { - tag: 'unlabeledProduct', + tag: "unlabeledProduct", items: [ { - tag: 'scalar', - name: 'string', + tag: "scalar", + name: "string", }, ], }, }, sign: { - tag: 'arrow', + tag: "arrow", domain: { - tag: 'labeledProduct', + tag: "labeledProduct", fields: { data: { - tag: 'array', + tag: "array", type: { - tag: 'scalar', - name: 'u8', + tag: "scalar", + name: "u8", }, }, }, }, codomain: { - tag: 'unlabeledProduct', + tag: "unlabeledProduct", items: [ { - tag: 'struct', - name: 'SignResult', + tag: "struct", + name: "SignResult", fields: { error: { - tag: 'option', + tag: "option", type: { - tag: 'scalar', - name: 'string', + tag: "scalar", + name: "string", }, }, signature: { - tag: 'option', + tag: "option", type: { - tag: 'array', + tag: "array", type: { - tag: 'scalar', - name: 'u8', + tag: "scalar", + name: "u8", }, }, }, success: { - tag: 'scalar', - name: 'bool', + tag: "scalar", + name: "bool", }, }, }, @@ -94,32 +119,32 @@ export function registerSig(peer: IFluenceInternalApi, serviceId: string, servic }, }, verify: { - tag: 'arrow', + tag: "arrow", domain: { - tag: 'labeledProduct', + tag: "labeledProduct", fields: { signature: { - tag: 'array', + tag: "array", type: { - tag: 'scalar', - name: 'u8', + tag: "scalar", + name: "u8", }, }, data: { - tag: 'array', + tag: "array", type: { - tag: 'scalar', - name: 'u8', + tag: "scalar", + name: "u8", }, }, }, }, codomain: { - tag: 'unlabeledProduct', + tag: "unlabeledProduct", items: [ { - tag: 'scalar', - name: 'bool', + tag: "scalar", + name: "bool", }, ], }, diff --git a/packages/core/js-client/src/services/_aqua/single-module-srv.ts b/packages/core/js-client/src/services/_aqua/single-module-srv.ts index b97e6656e..027e46a41 100644 --- a/packages/core/js-client/src/services/_aqua/single-module-srv.ts +++ b/packages/core/js-client/src/services/_aqua/single-module-srv.ts @@ -1,70 +1,97 @@ +/** + * 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. + */ + /** * This compiled aqua file was modified to make it work in monorepo */ -import { CallParams, IFluenceInternalApi } from '@fluencelabs/interfaces'; -import { registerService } from '../../compilerSupport/registerService.js'; +import { CallParams, IFluenceInternalApi } from "@fluencelabs/interfaces"; + +import { registerService } from "../../compilerSupport/registerService.js"; // Services export interface SrvDef { create: ( wasm_b64_content: string, - callParams: CallParams<'wasm_b64_content'>, + callParams: CallParams<"wasm_b64_content">, ) => | { error: string | null; service_id: string | null; success: boolean } - | Promise<{ error: string | null; service_id: string | null; success: boolean }>; + | Promise<{ + error: string | null; + service_id: string | null; + success: boolean; + }>; list: (callParams: CallParams) => string[] | Promise; remove: ( service_id: string, - callParams: CallParams<'service_id'>, - ) => { error: string | null; success: boolean } | Promise<{ error: string | null; success: boolean }>; + callParams: CallParams<"service_id">, + ) => + | { error: string | null; success: boolean } + | Promise<{ error: string | null; success: boolean }>; } -export function registerSrv(peer: IFluenceInternalApi, serviceId: string, service: any) { +export function registerSrv( + peer: IFluenceInternalApi, + serviceId: string, + service: any, +) { registerService({ peer, serviceId, service, def: { - defaultServiceId: 'single_module_srv', + defaultServiceId: "single_module_srv", functions: { - tag: 'labeledProduct', + tag: "labeledProduct", fields: { create: { - tag: 'arrow', + tag: "arrow", domain: { - tag: 'labeledProduct', + tag: "labeledProduct", fields: { wasm_b64_content: { - tag: 'scalar', - name: 'string', + tag: "scalar", + name: "string", }, }, }, codomain: { - tag: 'unlabeledProduct', + tag: "unlabeledProduct", items: [ { - tag: 'struct', - name: 'ServiceCreationResult', + tag: "struct", + name: "ServiceCreationResult", fields: { error: { - tag: 'option', + tag: "option", type: { - tag: 'scalar', - name: 'string', + tag: "scalar", + name: "string", }, }, service_id: { - tag: 'option', + tag: "option", type: { - tag: 'scalar', - name: 'string', + tag: "scalar", + name: "string", }, }, success: { - tag: 'scalar', - name: 'bool', + tag: "scalar", + name: "bool", }, }, }, @@ -72,51 +99,51 @@ export function registerSrv(peer: IFluenceInternalApi, serviceId: string, servic }, }, list: { - tag: 'arrow', + tag: "arrow", domain: { - tag: 'nil', + tag: "nil", }, codomain: { - tag: 'unlabeledProduct', + tag: "unlabeledProduct", items: [ { - tag: 'array', + tag: "array", type: { - tag: 'scalar', - name: 'string', + tag: "scalar", + name: "string", }, }, ], }, }, remove: { - tag: 'arrow', + tag: "arrow", domain: { - tag: 'labeledProduct', + tag: "labeledProduct", fields: { service_id: { - tag: 'scalar', - name: 'string', + tag: "scalar", + name: "string", }, }, }, codomain: { - tag: 'unlabeledProduct', + tag: "unlabeledProduct", items: [ { - tag: 'struct', - name: 'RemoveResult', + tag: "struct", + name: "RemoveResult", fields: { error: { - tag: 'option', + tag: "option", type: { - tag: 'scalar', - name: 'string', + tag: "scalar", + name: "string", }, }, success: { - tag: 'scalar', - name: 'bool', + tag: "scalar", + name: "bool", }, }, }, diff --git a/packages/core/js-client/src/services/_aqua/tracing.ts b/packages/core/js-client/src/services/_aqua/tracing.ts index 405326b9b..81a9777da 100644 --- a/packages/core/js-client/src/services/_aqua/tracing.ts +++ b/packages/core/js-client/src/services/_aqua/tracing.ts @@ -1,8 +1,25 @@ +/** + * 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. + */ + /** * This compiled aqua file was modified to make it work in monorepo */ -import { CallParams, IFluenceInternalApi } from '@fluencelabs/interfaces'; -import { registerService } from '../../compilerSupport/registerService.js'; +import { CallParams, IFluenceInternalApi } from "@fluencelabs/interfaces"; + +import { registerService } from "../../compilerSupport/registerService.js"; // Services @@ -10,37 +27,41 @@ export interface TracingDef { tracingEvent: ( arrowName: string, event: string, - callParams: CallParams<'arrowName' | 'event'>, + callParams: CallParams<"arrowName" | "event">, ) => void | Promise; } -export function registerTracing(peer: IFluenceInternalApi, serviceId: string, service: any) { +export function registerTracing( + peer: IFluenceInternalApi, + serviceId: string, + service: any, +) { registerService({ peer, serviceId, service, def: { - defaultServiceId: 'tracingSrv', + defaultServiceId: "tracingSrv", functions: { - tag: 'labeledProduct', + tag: "labeledProduct", fields: { tracingEvent: { - tag: 'arrow', + tag: "arrow", domain: { - tag: 'labeledProduct', + tag: "labeledProduct", fields: { arrowName: { - tag: 'scalar', - name: 'string', + tag: "scalar", + name: "string", }, event: { - tag: 'scalar', - name: 'string', + tag: "scalar", + name: "string", }, }, }, codomain: { - tag: 'nil', + tag: "nil", }, }, }, diff --git a/packages/core/js-client/src/services/builtins.ts b/packages/core/js-client/src/services/builtins.ts index bdbf80c74..4608c7ccb 100644 --- a/packages/core/js-client/src/services/builtins.ts +++ b/packages/core/js-client/src/services/builtins.ts @@ -1,5 +1,5 @@ -/* - * Copyright 2021 Fluence Labs Limited +/** + * 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. @@ -14,14 +14,17 @@ * limitations under the License. */ -import * as bs58 from 'bs58'; +import { Buffer } from "buffer"; -import { sha256 } from 'multiformats/hashes/sha2'; -import { CallServiceResult } from '@fluencelabs/avm'; +import { CallServiceResult } from "@fluencelabs/avm"; +import * as bs58 from "bs58"; +import { sha256 } from "multiformats/hashes/sha2"; -import { isString, jsonify } from '../util/utils.js'; -import { Buffer } from 'buffer'; -import { GenericCallServiceHandler, ResultCodes } from '../jsServiceHost/interfaces.js'; +import { + GenericCallServiceHandler, + ResultCodes, +} from "../jsServiceHost/interfaces.js"; +import { isString, jsonify } from "../util/utils.js"; //@ts-ignore const { encode, decode } = bs58.default; @@ -41,18 +44,23 @@ const error = (error: string): CallServiceResult => { }; const errorNotImpl = (methodName: string) => { - return error(`The JS implementation of Peer does not support "${methodName}"`); + return error( + `The JS implementation of Peer does not support "${methodName}"`, + ); }; const makeJsonImpl = (args: Array) => { const [obj, ...kvs] = args; const toMerge: Record = {}; + for (let i = 0; i < kvs.length / 2; i++) { const k = kvs[i * 2]; + if (!isString(k)) { return error(`Argument ${k} is expected to be string`); } + const v = kvs[i * 2 + 1]; toMerge[k] = v; } @@ -61,14 +69,17 @@ const makeJsonImpl = (args: Array) => { return success(res); }; -export const builtInServices: Record> = { +export const builtInServices: Record< + string, + Record +> = { peer: { identify: () => { return success({ external_addresses: [], // TODO: remove hardcoded values - node_version: 'js-0.23.0', - air_version: 'js-0.24.2', + node_version: "js-0.23.0", + air_version: "js-0.24.2", }); }, @@ -81,21 +92,24 @@ export const builtInServices: Record { - return errorNotImpl('peer.is_connected'); + return errorNotImpl("peer.is_connected"); }, connect: () => { - return errorNotImpl('peer.connect'); + return errorNotImpl("peer.connect"); }, get_contact: () => { - return errorNotImpl('peer.get_contact'); + 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'); + 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]; @@ -110,97 +124,97 @@ export const builtInServices: Record { - return errorNotImpl('kad.neighborhood'); + return errorNotImpl("kad.neighborhood"); }, merge: () => { - return errorNotImpl('kad.merge'); + return errorNotImpl("kad.merge"); }, }, srv: { list: () => { - return errorNotImpl('srv.list'); + return errorNotImpl("srv.list"); }, create: () => { - return errorNotImpl('srv.create'); + return errorNotImpl("srv.create"); }, get_interface: () => { - return errorNotImpl('srv.get_interface'); + return errorNotImpl("srv.get_interface"); }, resolve_alias: () => { - return errorNotImpl('srv.resolve_alias'); + return errorNotImpl("srv.resolve_alias"); }, add_alias: () => { - return errorNotImpl('srv.add_alias'); + return errorNotImpl("srv.add_alias"); }, remove: () => { - return errorNotImpl('srv.remove'); + return errorNotImpl("srv.remove"); }, }, dist: { add_module_from_vault: () => { - return errorNotImpl('dist.add_module_from_vault'); + return errorNotImpl("dist.add_module_from_vault"); }, add_module: () => { - return errorNotImpl('dist.add_module'); + return errorNotImpl("dist.add_module"); }, add_blueprint: () => { - return errorNotImpl('dist.add_blueprint'); + return errorNotImpl("dist.add_blueprint"); }, make_module_config: () => { - return errorNotImpl('dist.make_module_config'); + return errorNotImpl("dist.make_module_config"); }, load_module_config: () => { - return errorNotImpl('dist.load_module_config'); + return errorNotImpl("dist.load_module_config"); }, default_module_config: () => { - return errorNotImpl('dist.default_module_config'); + return errorNotImpl("dist.default_module_config"); }, make_blueprint: () => { - return errorNotImpl('dist.make_blueprint'); + return errorNotImpl("dist.make_blueprint"); }, load_blueprint: () => { - return errorNotImpl('dist.load_blueprint'); + return errorNotImpl("dist.load_blueprint"); }, list_modules: () => { - return errorNotImpl('dist.list_modules'); + return errorNotImpl("dist.list_modules"); }, get_module_interface: () => { - return errorNotImpl('dist.get_module_interface'); + return errorNotImpl("dist.get_module_interface"); }, list_blueprints: () => { - return errorNotImpl('dist.list_blueprints'); + return errorNotImpl("dist.list_blueprints"); }, }, script: { add: () => { - return errorNotImpl('script.add'); + return errorNotImpl("script.add"); }, remove: () => { - return errorNotImpl('script.remove'); + return errorNotImpl("script.remove"); }, list: () => { - return errorNotImpl('script.list'); + return errorNotImpl("script.list"); }, }, @@ -215,7 +229,10 @@ export const builtInServices: Record { if (req.args.length !== 1) { - return error('array_length accepts exactly one argument, found: ' + req.args.length); + return error( + "array_length accepts exactly one argument, found: " + + req.args.length, + ); } else { return success(req.args[0].length); } @@ -223,7 +240,9 @@ export const builtInServices: Record { if (req.args.length > 1) { - return error(`identity accepts up to 1 arguments, received ${req.args.length} arguments`); + return error( + `identity accepts up to 1 arguments, received ${req.args.length} arguments`, + ); } else { return success(req.args.length === 0 ? {} : req.args[0]); } @@ -231,13 +250,21 @@ export const builtInServices: Record { const incorrectArgIndices = req.args // - .map((x, i) => [Array.isArray(x), i]) - .filter(([isArray, _]) => !isArray) - .map(([_, index]) => index); + .map((x, i) => { + 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`); + const str = incorrectArgIndices.join(", "); + return error( + `All arguments of 'concat' must be arrays: arguments ${str} are not`, + ); } else { return success([].concat.apply([], req.args)); } @@ -245,7 +272,7 @@ export const builtInServices: Record { if (req.args.length !== 1) { - return error('string_to_b58 accepts only one string argument'); + return error("string_to_b58 accepts only one string argument"); } else { return success(encode(new TextEncoder().encode(req.args[0]))); } @@ -253,7 +280,9 @@ export const builtInServices: Record { if (req.args.length !== 1) { - return error('string_from_b58 accepts only one string argument'); + return error( + "string_from_b58 accepts only one string argument", + ); } else { return success(new TextDecoder().decode(decode(req.args[0]))); } @@ -261,7 +290,9 @@ export const builtInServices: Record { if (req.args.length !== 1 || !Array.isArray(req.args[0])) { - return error('bytes_to_b58 accepts only single argument: array of numbers'); + return error( + "bytes_to_b58 accepts only single argument: array of numbers", + ); } else { const argumentArray = req.args[0] as number[]; return success(encode(new Uint8Array(argumentArray))); @@ -270,7 +301,7 @@ export const builtInServices: Record { if (req.args.length !== 1) { - return error('bytes_from_b58 accepts only one string argument'); + return error("bytes_from_b58 accepts only one string argument"); } else { return success(Array.from(decode(req.args[0]))); } @@ -278,13 +309,18 @@ export const builtInServices: Record { if (req.args.length < 1 || req.args.length > 3) { - return error(`sha256_string accepts 1-3 arguments, found: ${req.args.length}`); + return error( + `sha256_string accepts 1-3 arguments, found: ${req.args.length}`, + ); } else { const [input, digestOnly, asBytes] = req.args; const inBuffer = Buffer.from(input); const multihash = await sha256.digest(inBuffer); - const outBytes = digestOnly ? multihash.digest : multihash.bytes; + const outBytes = digestOnly + ? multihash.digest + : multihash.bytes; + const res = asBytes ? Array.from(outBytes) : encode(outBytes); return success(res); @@ -292,7 +328,7 @@ export const builtInServices: Record { - const res = ''.concat(...req.args); + const res = "".concat(...req.args); return success(res); }, }, @@ -302,7 +338,7 @@ export const builtInServices: Record { let err; + if ((err = checkForArgumentsCount(req, 2))) { return err; } + const [x, y] = req.args; return success(x + y); }, sub: (req) => { let err; + if ((err = checkForArgumentsCount(req, 2))) { return err; } + const [x, y] = req.args; return success(x - y); }, mul: (req) => { let err; + if ((err = checkForArgumentsCount(req, 2))) { return err; } + const [x, y] = req.args; return success(x * y); }, fmul: (req) => { let err; + if ((err = checkForArgumentsCount(req, 2))) { return err; } + const [x, y] = req.args; return success(Math.floor(x * y)); }, div: (req) => { let err; + if ((err = checkForArgumentsCount(req, 2))) { return err; } + const [x, y] = req.args; return success(Math.floor(x / y)); }, rem: (req) => { let err; + if ((err = checkForArgumentsCount(req, 2))) { return err; } + const [x, y] = req.args; return success(x % y); }, pow: (req) => { let err; + if ((err = checkForArgumentsCount(req, 2))) { return err; } + const [x, y] = req.args; return success(Math.pow(x, y)); }, log: (req) => { let err; + if ((err = checkForArgumentsCount(req, 2))) { return err; } + const [x, y] = req.args; return success(Math.log(y) / Math.log(x)); }, @@ -390,45 +442,55 @@ export const builtInServices: Record { let err; + if ((err = checkForArgumentsCount(req, 2))) { return err; } + const [x, y] = req.args; return success(x > y); }, gte: (req) => { let err; + if ((err = checkForArgumentsCount(req, 2))) { return err; } + const [x, y] = req.args; return success(x >= y); }, lt: (req) => { let err; + if ((err = checkForArgumentsCount(req, 2))) { return err; } + const [x, y] = req.args; return success(x < y); }, lte: (req) => { let err; + if ((err = checkForArgumentsCount(req, 2))) { return err; } + const [x, y] = req.args; return success(x <= y); }, cmp: (req) => { let err; + if ((err = checkForArgumentsCount(req, 2))) { return err; } + const [x, y] = req.args; return success(x === y ? 0 : x > y ? 1 : -1); }, @@ -437,18 +499,26 @@ export const builtInServices: Record { let err; + if ((err = checkForArgumentsCount(req, 1))) { return err; } + const [xs] = req.args; - return success(xs.reduce((agg: any, cur: any) => agg + cur, 0)); + return success( + xs.reduce((agg: any, cur: any) => { + return agg + cur; + }, 0), + ); }, dedup: (req) => { let err; + if ((err = checkForArgumentsCount(req, 1))) { return err; } + const [xs] = req.args; const set = new Set(xs); return success(Array.from(set)); @@ -456,35 +526,55 @@ export const builtInServices: Record { let err; + if ((err = checkForArgumentsCount(req, 2))) { return err; } + const [xs, ys] = req.args; - const intersection = xs.filter((x: any) => ys.includes(x)); + + const intersection = xs.filter((x: any) => { + return ys.includes(x); + }); + return success(intersection); }, diff: (req) => { let err; + if ((err = checkForArgumentsCount(req, 2))) { return err; } + const [xs, ys] = req.args; - const diff = xs.filter((x: unknown) => !ys.includes(x)); + + const diff = xs.filter((x: unknown) => { + return !ys.includes(x); + }); + return success(diff); }, sdiff: (req) => { let err; + if ((err = checkForArgumentsCount(req, 2))) { return err; } + const [xs, ys] = req.args; + const sdiff = [ // force new line - ...xs.filter((y: unknown) => !ys.includes(y)), - ...ys.filter((x: unknown) => !xs.includes(x)), + ...xs.filter((y: unknown) => { + return !ys.includes(y); + }), + ...ys.filter((x: unknown) => { + return !xs.includes(x); + }), ]; + return success(sdiff); }, }, @@ -492,6 +582,7 @@ export const builtInServices: Record { let err; + if ((err = checkForArgumentsCountEven(req, 1))) { return err; } @@ -501,11 +592,12 @@ export const builtInServices: Record { let err; + if ((err = checkForArgumentsCount(req, 3))) { return err; } - if ((err = checkForArgumentType(req, 0, 'object'))) { + if ((err = checkForArgumentType(req, 0, "object"))) { return err; } @@ -514,6 +606,7 @@ export const builtInServices: Record { let err; + if ((err = checkForArgumentsCountOdd(req, 1))) { return err; } @@ -522,7 +615,7 @@ export const builtInServices: Record { let err; + if ((err = checkForArgumentsCount(req, 1))) { return err; } - if ((err = checkForArgumentType(req, 0, 'object'))) { + if ((err = checkForArgumentType(req, 0, "object"))) { return err; } @@ -546,15 +640,17 @@ export const builtInServices: Record { let err; + if ((err = checkForArgumentsCount(req, 1))) { return err; } - if ((err = checkForArgumentType(req, 0, 'string'))) { + if ((err = checkForArgumentType(req, 0, "string"))) { return err; } const [raw] = req.args; + try { const json = JSON.parse(raw); return success(json); @@ -564,7 +660,7 @@ export const builtInServices: Record { console.log(...req.args); return success({}); @@ -572,33 +668,58 @@ export const builtInServices: Record }, count: number) => { +const checkForArgumentsCount = ( + req: { args: Array }, + count: number, +) => { if (req.args.length !== count) { return error(`Expected ${count} argument(s). Got ${req.args.length}`); } }; -const checkForArgumentsCountMoreThan = (req: { args: Array }, count: number) => { +const checkForArgumentsCountMoreThan = ( + req: { args: Array }, + count: number, +) => { if (req.args.length < count) { - return error(`Expected more than ${count} argument(s). Got ${req.args.length}`); + return error( + `Expected more than ${count} argument(s). Got ${req.args.length}`, + ); } }; -const checkForArgumentsCountEven = (req: { args: Array }, count: number) => { +const checkForArgumentsCountEven = ( + req: { args: Array }, + count: number, +) => { if (req.args.length % 2 === 1) { - return error(`Expected even number of argument(s). Got ${req.args.length}`); + return error( + `Expected even number of argument(s). Got ${req.args.length}`, + ); } }; -const checkForArgumentsCountOdd = (req: { args: Array }, count: number) => { +const checkForArgumentsCountOdd = ( + req: { args: Array }, + count: number, +) => { if (req.args.length % 2 === 0) { - return error(`Expected odd number of argument(s). Got ${req.args.length}`); + return error( + `Expected odd number of argument(s). Got ${req.args.length}`, + ); } }; -const checkForArgumentType = (req: { args: Array }, index: number, type: string) => { +const checkForArgumentType = ( + req: { args: Array }, + 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 error( + `Argument ${index} expected to be of type ${type}, Got ${actual}`, + ); } }; diff --git a/packages/core/js-client/src/services/securityGuard.ts b/packages/core/js-client/src/services/securityGuard.ts index 896505b88..adc01fc42 100644 --- a/packages/core/js-client/src/services/securityGuard.ts +++ b/packages/core/js-client/src/services/securityGuard.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,15 +14,17 @@ * limitations under the License. */ -import { SecurityTetraplet } from '@fluencelabs/avm'; -import { CallParams, PeerIdB58 } from '@fluencelabs/interfaces'; +import { SecurityTetraplet } from "@fluencelabs/avm"; +import { CallParams, PeerIdB58 } from "@fluencelabs/interfaces"; type ArgName = string | null; /** * A predicate of call params for sig service's sign method which determines whether signing operation is allowed or not */ -export type SecurityGuard = (params: CallParams) => boolean; +export type SecurityGuard = ( + params: CallParams, +) => boolean; /** * Only allow calls when tetraplet for 'data' argument satisfies the predicate @@ -39,7 +41,10 @@ export const allowTetraplet = ( /** * Only allow data which comes from the specified serviceId and fnName */ -export const allowServiceFn = (serviceId: string, fnName: string): SecurityGuard => { +export const allowServiceFn = ( + serviceId: string, + fnName: string, +): SecurityGuard => { return allowTetraplet((t) => { return t.service_id === serviceId && t.function_name === fnName; }); @@ -48,7 +53,9 @@ export const allowServiceFn = (serviceId: string, fnName: str /** * Only allow data originated from the specified json_path */ -export const allowExactJsonPath = (jsonPath: string): SecurityGuard => { +export const allowExactJsonPath = ( + jsonPath: string, +): SecurityGuard => { return allowTetraplet((t) => { return t.json_path === jsonPath; }); @@ -57,7 +64,9 @@ export const allowExactJsonPath = (jsonPath: string): Securit /** * Only allow signing when particle is initiated at the specified peer */ -export const allowOnlyParticleOriginatedAt = (peerId: PeerIdB58): SecurityGuard => { +export const allowOnlyParticleOriginatedAt = ( + peerId: PeerIdB58, +): SecurityGuard => { return (params) => { return params.initPeerId === peerId; }; @@ -67,14 +76,26 @@ export const allowOnlyParticleOriginatedAt = (peerId: PeerIdB * Only allow signing when all of the predicates are satisfied. * Useful for predicates reuse */ -export const and = (...predicates: SecurityGuard[]): SecurityGuard => { - return (params) => predicates.every((x) => x(params)); +export const and = ( + ...predicates: SecurityGuard[] +): SecurityGuard => { + return (params) => { + return predicates.every((x) => { + return x(params); + }); + }; }; /** * Only allow signing when any of the predicates are satisfied. * Useful for predicates reuse */ -export const or = (...predicates: SecurityGuard[]): SecurityGuard => { - return (params) => predicates.some((x) => x(params)); +export const or = ( + ...predicates: SecurityGuard[] +): SecurityGuard => { + return (params) => { + return predicates.some((x) => { + return x(params); + }); + }; }; diff --git a/packages/core/js-client/src/util/bytes.ts b/packages/core/js-client/src/util/bytes.ts index 5e19461a2..112e02a50 100644 --- a/packages/core/js-client/src/util/bytes.ts +++ b/packages/core/js-client/src/util/bytes.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,11 +14,11 @@ * limitations under the License. */ -type Size = 'u32' | 'u64'; +type Size = "u32" | "u64"; const sizeMap = { - 'u32': 4, - 'u64': 8 + u32: 4, + u64: 8, } as const; function numberToBytes(n: number, s: Size, littleEndian: boolean) { @@ -31,4 +31,4 @@ function numberToBytes(n: number, s: Size, littleEndian: boolean) { export function numberToLittleEndianBytes(n: number, s: Size) { return numberToBytes(n, s, true); -} \ No newline at end of file +} diff --git a/packages/core/js-client/src/util/commonTypes.ts b/packages/core/js-client/src/util/commonTypes.ts index bdbd50171..780d30536 100644 --- a/packages/core/js-client/src/util/commonTypes.ts +++ b/packages/core/js-client/src/util/commonTypes.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,13 +14,19 @@ * limitations under the License. */ -export { CallParameters} from "@fluencelabs/marine-js/dist/types"; +export { CallParameters } from "@fluencelabs/marine-js/dist/types"; export interface IStartable { start(): Promise; stop(): Promise; } -export type JSONValue = string | number | boolean | null | { [x: string]: JSONValue } | Array; +export type JSONValue = + | string + | number + | boolean + | null + | { [x: string]: JSONValue } + | Array; export type JSONArray = Array; export type JSONObject = { [x: string]: JSONValue }; diff --git a/packages/core/js-client/src/util/libp2pUtils.ts b/packages/core/js-client/src/util/libp2pUtils.ts index 0cf84e7af..6e58c19bd 100644 --- a/packages/core/js-client/src/util/libp2pUtils.ts +++ b/packages/core/js-client/src/util/libp2pUtils.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,9 +14,10 @@ * limitations under the License. */ -import { RelayOptions } from '@fluencelabs/interfaces'; -import { multiaddr, Multiaddr } from '@multiformats/multiaddr'; -import { isString } from './utils.js'; +import { RelayOptions } from "@fluencelabs/interfaces"; +import { multiaddr, Multiaddr } from "@multiformats/multiaddr"; + +import { isString } from "./utils.js"; export function relayOptionToMultiaddr(relay: RelayOptions): Multiaddr { const multiaddrString = isString(relay) ? relay : relay.multiaddr; @@ -29,7 +30,11 @@ export function relayOptionToMultiaddr(relay: RelayOptions): Multiaddr { export function throwIfHasNoPeerId(ma: Multiaddr): void { const peerId = ma.getPeerId(); + if (!peerId) { - throw new Error('Specified multiaddr is invalid or missing peer id: ' + ma.toString()); + throw new Error( + "Specified multiaddr is invalid or missing peer id: " + + ma.toString(), + ); } } diff --git a/packages/core/js-client/src/util/loadClient.ts b/packages/core/js-client/src/util/loadClient.ts index ff9fac9ff..a4b1b1939 100644 --- a/packages/core/js-client/src/util/loadClient.ts +++ b/packages/core/js-client/src/util/loadClient.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,16 +20,21 @@ import type { IFluenceClient, RegisterServiceType, RelayOptions, -} from '@fluencelabs/interfaces'; +} from "@fluencelabs/interfaces"; type PublicFluenceInterface = { defaultClient: IFluenceClient | undefined; - clientFactory: (relay: RelayOptions, config?: ClientConfig) => Promise; + clientFactory: ( + relay: RelayOptions, + config?: ClientConfig, + ) => Promise; callAquaFunction: CallAquaFunctionType; registerService: RegisterServiceType; }; -export const getFluenceInterfaceFromGlobalThis = (): PublicFluenceInterface | undefined => { +export const getFluenceInterfaceFromGlobalThis = (): + | PublicFluenceInterface + | undefined => { // @ts-ignore return globalThis.fluence; }; @@ -53,6 +58,7 @@ const POLL_PEER_INTERVAL = 100; export const getFluenceInterface = (): Promise => { // If the script is already loaded, then return the value immediately const optimisticResult = getFluenceInterfaceFromGlobalThis(); + if (optimisticResult) { return Promise.resolve(optimisticResult); } @@ -63,17 +69,20 @@ export const getFluenceInterface = (): Promise => { // to break out into the public API let interval: any; let hits = POLL_PEER_TIMEOUT / POLL_PEER_INTERVAL; + interval = setInterval(() => { if (hits === 0) { clearInterval(interval); reject(REJECT_MESSAGE); } - let res = getFluenceInterfaceFromGlobalThis(); + const res = getFluenceInterfaceFromGlobalThis(); + if (res) { clearInterval(interval); resolve(res); } + hits--; }, POLL_PEER_INTERVAL); }); diff --git a/packages/core/js-client/src/util/logger.ts b/packages/core/js-client/src/util/logger.ts index d359ebc13..237dcbac5 100644 --- a/packages/core/js-client/src/util/logger.ts +++ b/packages/core/js-client/src/util/logger.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,7 +14,7 @@ * limitations under the License. */ -import debug from 'debug'; +import debug from "debug"; type Logger = (formatter: any, ...args: any[]) => void; diff --git a/packages/core/js-client/src/util/testUtils.ts b/packages/core/js-client/src/util/testUtils.ts index 4b3a9c8ce..d8393a488 100644 --- a/packages/core/js-client/src/util/testUtils.ts +++ b/packages/core/js-client/src/util/testUtils.ts @@ -1,4 +1,4 @@ -/* +/** * Copyright 2023 Fluence Labs Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,23 +14,28 @@ * limitations under the License. */ -import * as api from '@fluencelabs/aqua-api/aqua-api.js'; - -import { promises as fs } from 'fs'; -import { DEFAULT_CONFIG, FluencePeer, PeerConfig } from '../jsPeer/FluencePeer.js'; -import { Particle } from '../particle/Particle.js'; -import { ClientConfig, IFluenceClient, RelayOptions, ServiceDef } from '@fluencelabs/interfaces'; -import { callAquaFunction } from '../compilerSupport/callFunction.js'; - -import { MarineBackgroundRunner } from '../marine/worker/index.js'; -import { WorkerLoader } from '../marine/worker-script/workerLoader.js'; -import { KeyPair } from '../keypair/index.js'; -import { Subject, Subscribable } from 'rxjs'; -import { WrapFnIntoServiceCall } from '../jsServiceHost/serviceUtils.js'; -import { JsServiceHost } from '../jsServiceHost/JsServiceHost.js'; -import { ClientPeer, makeClientPeerConfig } from '../clientPeer/ClientPeer.js'; -import { WasmLoaderFromNpm, WorkerLoaderFromNpm } from '../marine/deps-loader/node.js'; -import { IConnection } from '../connection/interfaces.js'; +import { promises as fs } from "fs"; + +import * as api from "@fluencelabs/aqua-api/aqua-api.js"; +import { + ClientConfig, + IFluenceClient, + RelayOptions, + ServiceDef, +} from "@fluencelabs/interfaces"; +import { Subject, Subscribable } from "rxjs"; + +import { ClientPeer, makeClientPeerConfig } from "../clientPeer/ClientPeer.js"; +import { callAquaFunction } from "../compilerSupport/callFunction.js"; +import { IConnection } from "../connection/interfaces.js"; +import { DEFAULT_CONFIG, FluencePeer } from "../jsPeer/FluencePeer.js"; +import { JsServiceHost } from "../jsServiceHost/JsServiceHost.js"; +import { WrapFnIntoServiceCall } from "../jsServiceHost/serviceUtils.js"; +import { KeyPair } from "../keypair/index.js"; +import { WasmLoaderFromNpm } from "../marine/deps-loader/node.js"; +import { MarineBackgroundRunner } from "../marine/worker/index.js"; +import { WorkerLoader } from "../marine/worker-script/workerLoader.js"; +import { Particle } from "../particle/Particle.js"; export const registerHandlersHelper = ( peer: FluencePeer, @@ -39,12 +44,20 @@ export const registerHandlersHelper = ( ) => { Object.entries(handlers).forEach(([serviceId, service]) => { Object.entries(service).forEach(([fnName, fn]) => { - peer.internals.regHandler.forParticle(particle.id, serviceId, fnName, WrapFnIntoServiceCall(fn)); + peer.internals.regHandler.forParticle( + particle.id, + serviceId, + fnName, + WrapFnIntoServiceCall(fn), + ); }); }); }; -export type CompiledFnCall = (peer: IFluenceClient, args: { [key: string]: any }) => Promise; +export type CompiledFnCall = ( + peer: IFluenceClient, + args: { [key: string]: any }, +) => Promise; export type CompiledFile = { functions: { [key: string]: CompiledFnCall }; services: { [key: string]: ServiceDef }; @@ -53,15 +66,25 @@ export type CompiledFile = { export const compileAqua = async (aquaFile: string): Promise => { await fs.access(aquaFile); - const compilationResult = await api.Aqua.compile(new api.Path(aquaFile), [], undefined); + const compilationResult = await api.Aqua.compile( + new api.Path(aquaFile), + [], + undefined, + ); if (compilationResult.errors.length > 0) { - throw new Error('Aqua compilation failed. Error: ' + compilationResult.errors.join('/n')); + throw new Error( + "Aqua compilation failed. Error: " + + compilationResult.errors.join("/n"), + ); } const functions = Object.entries(compilationResult.functions) .map(([name, fnInfo]) => { - const callFn = (peer: IFluenceClient, args: { [key: string]: any }) => { + const callFn = ( + peer: IFluenceClient, + args: { [key: string]: any }, + ) => { return callAquaFunction({ def: fnInfo.funcDef, script: fnInfo.script, @@ -70,6 +93,7 @@ export const compileAqua = async (aquaFile: string): Promise => { args, }); }; + return { [name]: callFn }; }) .reduce((agg, obj) => { @@ -87,9 +111,9 @@ class NoopConnection implements IConnection { stop(): Promise { return Promise.resolve(); } - + getRelayPeerId(): string { - return 'nothing_here'; + return "nothing_here"; } supportsRelay(): boolean { return true; @@ -104,9 +128,23 @@ class NoopConnection implements IConnection { export class TestPeer extends FluencePeer { constructor(keyPair: KeyPair, connection: IConnection) { const workerLoader = new WorkerLoader(); - const controlModuleLoader = new WasmLoaderFromNpm('@fluencelabs/marine-js', 'marine-js.wasm'); - const avmModuleLoader = new WasmLoaderFromNpm('@fluencelabs/avm', 'avm.wasm'); - const marine = new MarineBackgroundRunner(workerLoader, controlModuleLoader, avmModuleLoader); + + const controlModuleLoader = new WasmLoaderFromNpm( + "@fluencelabs/marine-js", + "marine-js.wasm", + ); + + const avmModuleLoader = new WasmLoaderFromNpm( + "@fluencelabs/avm", + "avm.wasm", + ); + + const marine = new MarineBackgroundRunner( + workerLoader, + controlModuleLoader, + avmModuleLoader, + ); + const jsHost = new JsServiceHost(); super(DEFAULT_CONFIG, keyPair, marine, jsHost, connection); } @@ -120,6 +158,7 @@ export const mkTestPeer = async () => { export const withPeer = async (action: (p: FluencePeer) => Promise) => { const p = await mkTestPeer(); + try { await p.start(); await action(p); @@ -134,11 +173,30 @@ export const withClient = async ( action: (client: ClientPeer) => Promise, ) => { const workerLoader = new WorkerLoader(); - const controlModuleLoader = new WasmLoaderFromNpm('@fluencelabs/marine-js', 'marine-js.wasm'); - const avmModuleLoader = new WasmLoaderFromNpm('@fluencelabs/avm', 'avm.wasm'); - const marine = new MarineBackgroundRunner(workerLoader, controlModuleLoader, avmModuleLoader); - const { keyPair, peerConfig, relayConfig } = await makeClientPeerConfig(relay, config); + + const controlModuleLoader = new WasmLoaderFromNpm( + "@fluencelabs/marine-js", + "marine-js.wasm", + ); + + const avmModuleLoader = new WasmLoaderFromNpm( + "@fluencelabs/avm", + "avm.wasm", + ); + + const marine = new MarineBackgroundRunner( + workerLoader, + controlModuleLoader, + avmModuleLoader, + ); + + const { keyPair, peerConfig, relayConfig } = await makeClientPeerConfig( + relay, + config, + ); + const client = new ClientPeer(peerConfig, relayConfig, keyPair, marine); + try { await client.connect(); await action(client); diff --git a/packages/core/js-client/src/util/utils.ts b/packages/core/js-client/src/util/utils.ts index 3633b3a6e..4840e6c5b 100644 --- a/packages/core/js-client/src/util/utils.ts +++ b/packages/core/js-client/src/util/utils.ts @@ -1,5 +1,5 @@ -/* - * Copyright 2021 Fluence Labs Limited +/** + * 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. @@ -19,9 +19,9 @@ export function jsonify(obj: unknown) { } export const isString = (unknown: unknown): unknown is string => { - return unknown !== null && typeof unknown === 'string'; + return unknown !== null && typeof unknown === "string"; }; export const isObject = (unknown: unknown): unknown is object => { - return unknown !== null && typeof unknown === 'object'; + return unknown !== null && typeof unknown === "object"; }; diff --git a/packages/core/marine-worker/src/index.ts b/packages/core/marine-worker/src/index.ts index 4afcd2510..72118d428 100644 --- a/packages/core/marine-worker/src/index.ts +++ b/packages/core/marine-worker/src/index.ts @@ -1,5 +1,5 @@ -/* - * Copyright 2022 Fluence Labs Limited +/** + * 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. @@ -14,40 +14,57 @@ * limitations under the License. */ -import { MarineService } from '@fluencelabs/marine-js/dist/MarineService'; -import type { Env, MarineModuleConfig, MarineServiceConfig, ModuleDescriptor } from '@fluencelabs/marine-js/dist/config' -import type { JSONArray, JSONObject, LogMessage, CallParameters } from '@fluencelabs/marine-js/dist/types'; -import { Observable, Subject } from 'observable-fns'; +import type { + Env, + MarineServiceConfig, + ModuleDescriptor, +} from "@fluencelabs/marine-js/dist/config"; +import { MarineService } from "@fluencelabs/marine-js/dist/MarineService"; +import type { + JSONArray, + JSONObject, + LogMessage, +} from "@fluencelabs/marine-js/dist/types"; +import { Observable, Subject } from "observable-fns"; // @ts-ignore no types provided for package -import { expose } from 'threads/worker'; +import { expose } from "threads/worker"; -const createSimpleModuleDescriptor = (name: string, envs?: Env): ModuleDescriptor => { +const createSimpleModuleDescriptor = ( + name: string, + envs?: Env, +): ModuleDescriptor => { return { import_name: name, config: { logger_enabled: true, logging_mask: 0, wasi: { - envs: {...envs}, + envs: { ...envs }, preopened_files: new Set(), - mapped_dirs: new Map, - } - } - } -} -const createSimpleMarineService = (name: string, env? : Env): MarineServiceConfig => { + mapped_dirs: new Map(), + }, + }, + }; +}; + +const createSimpleMarineService = ( + name: string, + env?: Env, +): MarineServiceConfig => { return { modules_config: [createSimpleModuleDescriptor(name, env)], - } -} + }; +}; -let marineServices = new Map(); +const marineServices = new Map(); let controlModule: WebAssembly.Module | undefined; const onLogMessage = new Subject(); const toExpose = { init: async (controlModuleWasm: ArrayBuffer | SharedArrayBuffer) => { - controlModule = new WebAssembly.Module(new Uint8Array(controlModuleWasm)); + controlModule = new WebAssembly.Module( + new Uint8Array(controlModuleWasm), + ); }, createService: async ( @@ -56,15 +73,20 @@ const toExpose = { envs?: Env, ): Promise => { if (!controlModule) { - throw new Error('MarineJS is not initialized. To initialize call `init` function'); + throw new Error( + "MarineJS is not initialized. To initialize call `init` function", + ); } if (marineServices.has(serviceId)) { - throw new Error(`Service with name ${serviceId} already registered`); + throw new Error( + `Service with name ${serviceId} already registered`, + ); } const marineConfig = createSimpleMarineService(serviceId, envs); - const modules = {[serviceId]: new Uint8Array(wasm)} + const modules = { [serviceId]: new Uint8Array(wasm) }; + const srv = new MarineService( controlModule, serviceId, @@ -73,6 +95,7 @@ const toExpose = { modules, envs, ); + await srv.init(); marineServices.set(serviceId, srv); }, @@ -82,10 +105,10 @@ const toExpose = { }, removeService: async (serviceId: string) => { - if (serviceId === 'avm') { - throw new Error('Cannot remove \'avm\' service'); + if (serviceId === "avm") { + throw new Error("Cannot remove 'avm' service"); } - + marineServices.get(serviceId)?.terminate(); return marineServices.delete(serviceId); }, @@ -94,12 +117,19 @@ const toExpose = { marineServices.forEach((val, key) => { val.terminate(); }); + marineServices.clear(); onLogMessage.complete(); }, - callService: async (serviceId: string, functionName: string, args: JSONArray | JSONObject, callParams: any) => { + callService: async ( + serviceId: string, + functionName: string, + args: JSONArray | JSONObject, + callParams: any, + ) => { const srv = marineServices.get(serviceId); + if (!srv) { throw new Error(`service with id=${serviceId} not found`); } @@ -112,12 +142,14 @@ const toExpose = { }, }; -type ExposedInterface unknown}> = { +type ExposedInterface< + T extends { [key: string]: (...args: any[]) => unknown }, +> = { [P in keyof T]: ReturnType extends Observable ? T[P] : ReturnType extends Promise - ? T[P] - : (...args: Parameters) => Promise> + ? T[P] + : (...args: Parameters) => Promise>; }; export type MarineBackgroundInterface = ExposedInterface; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c41027139..4d16418d2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,25 +10,55 @@ importers: devDependencies: '@fluencelabs/aqua': specifier: 0.9.1-374 - version: 0.9.1-374(jest@27.5.1)(node-fetch@3.3.2)(typescript@4.7.2) + version: 0.9.1-374(jest@27.5.1)(node-fetch@3.3.2)(typescript@5.1.6) '@fluencelabs/aqua-lib': specifier: 0.6.0 version: 0.6.0 + '@total-typescript/ts-reset': + specifier: 0.5.1 + version: 0.5.1 + '@tsconfig/strictest': + specifier: 2.0.2 + version: 2.0.2 '@types/node': specifier: 18.13.0 version: 18.13.0 + '@typescript-eslint/eslint-plugin': + specifier: 6.7.3 + version: 6.7.3(@typescript-eslint/parser@6.7.3)(eslint@8.50.0)(typescript@5.1.6) + '@typescript-eslint/parser': + specifier: 6.7.3 + version: 6.7.3(eslint@8.50.0)(typescript@5.1.6) + eslint: + specifier: 8.50.0 + version: 8.50.0 + eslint-config-prettier: + specifier: 9.0.0 + version: 9.0.0(eslint@8.50.0) + eslint-plugin-import: + specifier: 2.28.1 + version: 2.28.1(@typescript-eslint/parser@6.7.3)(eslint@8.50.0) + eslint-plugin-license-header: + specifier: 0.6.0 + version: 0.6.0 + eslint-plugin-unused-imports: + specifier: 3.0.0 + version: 3.0.0(@typescript-eslint/eslint-plugin@6.7.3)(eslint@8.50.0) http-server: specifier: 14.1.1 version: 14.1.1 + prettier: + specifier: 3.0.3 + version: 3.0.3 puppeteer: specifier: 19.7.2 - version: 19.7.2(typescript@4.7.2) + version: 19.7.2(typescript@5.1.6) ts-node: specifier: 10.9.1 - version: 10.9.1(@types/node@18.13.0)(typescript@4.7.2) + version: 10.9.1(@types/node@18.13.0)(typescript@5.1.6) typescript: - specifier: '4.7' - version: 4.7.2 + specifier: 5.1.6 + version: 5.1.6 packages/@tests/aqua: dependencies: @@ -44,7 +74,7 @@ importers: version: 0.6.0 '@fluencelabs/cli': specifier: 0.7.2 - version: 0.7.2(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@nomicfoundation/hardhat-chai-matchers@1.0.6)(@nomicfoundation/hardhat-network-helpers@1.0.8)(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(@typechain/ethers-v5@10.2.1)(@typechain/hardhat@6.1.6)(@types/chai@4.3.5)(@types/mocha@9.1.1)(@types/node@20.7.0)(chai@4.3.7)(hardhat-gas-reporter@1.0.9)(hardhat@2.15.0)(solidity-coverage@0.7.22)(ts-node@10.9.1)(typechain@8.2.0)(typescript@4.7.2) + version: 0.7.2(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@nomicfoundation/hardhat-chai-matchers@1.0.6)(@nomicfoundation/hardhat-network-helpers@1.0.8)(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(@typechain/ethers-v5@10.2.1)(@typechain/hardhat@6.1.6)(@types/chai@4.3.5)(@types/mocha@9.1.1)(@types/node@20.7.0)(chai@4.3.7)(hardhat-gas-reporter@1.0.9)(hardhat@2.15.0)(solidity-coverage@0.7.22)(ts-node@10.9.1)(typechain@8.2.0)(typescript@5.1.6) '@fluencelabs/registry': specifier: 0.8.2 version: 0.8.2 @@ -72,7 +102,7 @@ importers: devDependencies: puppeteer: specifier: 19.7.2 - version: 19.7.2(typescript@4.7.2) + version: 19.7.2(typescript@5.1.6) packages/@tests/smoke/web-cra-ts: dependencies: @@ -108,10 +138,7 @@ importers: version: 18.2.0(react@18.2.0) react-scripts: specifier: 5.0.1 - version: 5.0.1(@babel/plugin-syntax-flow@7.22.5)(@babel/plugin-transform-react-jsx@7.22.5)(eslint@8.43.0)(react@18.2.0)(ts-node@10.9.1)(typescript@4.9.5) - typescript: - specifier: 4.9.5 - version: 4.9.5 + version: 5.0.1(@babel/plugin-syntax-flow@7.22.5)(@babel/plugin-transform-react-jsx@7.22.5)(eslint@8.50.0)(react@18.2.0)(ts-node@10.9.1)(typescript@5.1.6) web-vitals: specifier: 2.1.4 version: 2.1.4 @@ -121,7 +148,7 @@ importers: version: link:../../test-utils puppeteer: specifier: 19.7.2 - version: 19.7.2(typescript@4.9.5) + version: 19.7.2(typescript@5.1.6) packages/@tests/test-utils: dependencies: @@ -160,9 +187,6 @@ importers: '@fluencelabs/trust-graph': specifier: 0.4.7 version: 0.4.7 - typescript: - specifier: 5.1.6 - version: 5.1.6 vitest: specifier: 0.29.7 version: 0.29.7 @@ -286,7 +310,7 @@ importers: version: 4.0.4(@types/node@20.7.0) vite-tsconfig-paths: specifier: 4.0.3 - version: 4.0.3(typescript@4.7.2)(vite@4.0.4) + version: 4.0.3(typescript@5.1.6)(vite@4.0.4) vitest: specifier: 0.29.7 version: 0.29.7 @@ -327,6 +351,10 @@ importers: packages: + /@aashutoshrathi/word-wrap@1.2.6: + resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} + engines: {node: '>=0.10.0'} + /@achingbrain/nat-port-mapper@1.0.9: resolution: {integrity: sha512-w1M7dh7IsO5fvX9VQpH0w8MMphzLUl52Kf+paXTScNmFH4Ua+R6XI+x5p7LI3vY36JkTllTqAxNo8g1y0CMCrA==} engines: {node: '>=16.0.0', npm: '>=7.0.0'} @@ -440,12 +468,12 @@ packages: debug: 4.3.4(supports-color@8.1.1) gensync: 1.0.0-beta.2 json5: 2.2.3 - semver: 6.3.0 + semver: 6.3.1 transitivePeerDependencies: - supports-color dev: false - /@babel/eslint-parser@7.22.5(@babel/core@7.22.5)(eslint@8.43.0): + /@babel/eslint-parser@7.22.5(@babel/core@7.22.5)(eslint@8.50.0): resolution: {integrity: sha512-C69RWYNYtrgIRE5CmTd77ZiLDXqgBipahJc/jHP3sLcAGj6AJzxNIuKNpVnICqbyK7X3pFUfEvL++rvtbQpZkQ==} engines: {node: ^10.13.0 || ^12.13.0 || >=14.0.0} peerDependencies: @@ -454,7 +482,7 @@ packages: dependencies: '@babel/core': 7.22.5 '@nicolo-ribaudo/eslint-scope-5-internals': 5.1.1-v1 - eslint: 8.43.0 + eslint: 8.50.0 eslint-visitor-keys: 2.1.0 semver: 6.3.1 dev: false @@ -3418,28 +3446,30 @@ packages: dev: true optional: true - /@eslint-community/eslint-utils@4.4.0(eslint@8.43.0): + /@eslint-community/eslint-utils@4.4.0(eslint@8.50.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 dependencies: - eslint: 8.43.0 - eslint-visitor-keys: 3.4.1 - dev: false + eslint: 8.50.0 + eslint-visitor-keys: 3.4.3 /@eslint-community/regexpp@4.5.1: resolution: {integrity: sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - dev: false - /@eslint/eslintrc@2.0.3: - resolution: {integrity: sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==} + /@eslint-community/regexpp@4.9.0: + resolution: {integrity: sha512-zJmuCWj2VLBt4c25CfBIbMZLGLyhkvs7LznyVX5HfpzeocThgIj5XQK4L+g3U36mMcx8bPMhGyPpwCATamC4jQ==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + /@eslint/eslintrc@2.1.2: + resolution: {integrity: sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: ajv: 6.12.6 debug: 4.3.4(supports-color@8.1.1) - espree: 9.5.2 + espree: 9.6.1 globals: 13.20.0 ignore: 5.2.4 import-fresh: 3.3.0 @@ -3448,12 +3478,10 @@ packages: strip-json-comments: 3.1.1 transitivePeerDependencies: - supports-color - dev: false - /@eslint/js@8.43.0: - resolution: {integrity: sha512-s2UHCoiXfxMvmfzqoN+vrQ84ahUSYde9qNO1MdxmoEhyHWsfmwOpFlwYV+ePJEVc7gFnATGUi376WowX1N7tFg==} + /@eslint/js@8.50.0: + resolution: {integrity: sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: false /@ethereumjs/common@2.5.0: resolution: {integrity: sha512-DEHjW6e38o+JmB/NO3GZBpW4lpaiBpkFgXF6jLcJ6gETBYpEyaA5nTimsWBUJR3Vmtm/didUEbNjajskugZORg==} @@ -3832,13 +3860,13 @@ packages: resolution: {integrity: sha512-+JVbWmHeGB+X/BSqmk6/B0gwWJ4bEAxkepVTN8l0mVrJ5zRRmYaCKVplWy6Z3W012m3VVK3A1o3rm/fgfVrQkw==} dev: true - /@fluencelabs/aqua@0.9.1-374(jest@27.5.1)(node-fetch@3.3.2)(typescript@4.7.2): + /@fluencelabs/aqua@0.9.1-374(jest@27.5.1)(node-fetch@3.3.2)(typescript@5.1.6): resolution: {integrity: sha512-jF6oVE4h7bP/dQArKEfsy4UxbQbzACfVIBY/TFUL5D3np4ssjxrh15Y3gl1PwSWjlaPcDeFvAuStmcqfYQmLqQ==} hasBin: true dependencies: '@fluencelabs/aqua-ipfs': 0.5.8 '@fluencelabs/aqua-lib': 0.6.0 - '@fluencelabs/fluence': 0.27.5(jest@27.5.1)(node-fetch@3.3.2)(typescript@4.7.2) + '@fluencelabs/fluence': 0.27.5(jest@27.5.1)(node-fetch@3.3.2)(typescript@5.1.6) '@fluencelabs/fluence-network-environment': 1.0.13 ipfs-http-client: 50.1.2(node-fetch@3.3.2) transitivePeerDependencies: @@ -3862,25 +3890,25 @@ packages: /@fluencelabs/avm@0.48.0: resolution: {integrity: sha512-9sXyKx2jp8JvmGUIddb7iILq9KN6d1PoCNSvrzIej4yP+pCxpiY9elgeaSoGY5yHcPClNnvHBKcenL23mdUckg==} - /@fluencelabs/cli@0.7.2(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@nomicfoundation/hardhat-chai-matchers@1.0.6)(@nomicfoundation/hardhat-network-helpers@1.0.8)(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(@typechain/ethers-v5@10.2.1)(@typechain/hardhat@6.1.6)(@types/chai@4.3.5)(@types/mocha@9.1.1)(@types/node@20.7.0)(chai@4.3.7)(hardhat-gas-reporter@1.0.9)(hardhat@2.15.0)(solidity-coverage@0.7.22)(ts-node@10.9.1)(typechain@8.2.0)(typescript@4.7.2): + /@fluencelabs/cli@0.7.2(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@nomicfoundation/hardhat-chai-matchers@1.0.6)(@nomicfoundation/hardhat-network-helpers@1.0.8)(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(@typechain/ethers-v5@10.2.1)(@typechain/hardhat@6.1.6)(@types/chai@4.3.5)(@types/mocha@9.1.1)(@types/node@20.7.0)(chai@4.3.7)(hardhat-gas-reporter@1.0.9)(hardhat@2.15.0)(solidity-coverage@0.7.22)(ts-node@10.9.1)(typechain@8.2.0)(typescript@5.1.6): resolution: {integrity: sha512-cXhlXBxNh1i66Twb3Nhpm1mXHpa+8zzoQ5wKJ6zJjOtrw6GWB6WrfIAb+aaLGWJMBnWHcZEkXs5vx9vwvVplcQ==} engines: {node: '=18'} hasBin: true dependencies: '@fluencelabs/air-beautify-wasm': 0.3.2 '@fluencelabs/aqua-api': 0.12.0 - '@fluencelabs/deal-aurora': 0.1.8(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@nomicfoundation/hardhat-chai-matchers@1.0.6)(@nomicfoundation/hardhat-network-helpers@1.0.8)(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(@typechain/ethers-v5@10.2.1)(@typechain/hardhat@6.1.6)(@types/chai@4.3.5)(@types/mocha@9.1.1)(@types/node@20.7.0)(chai@4.3.7)(ethers@5.7.2)(hardhat-gas-reporter@1.0.9)(hardhat@2.15.0)(solidity-coverage@0.7.22)(ts-node@10.9.1)(typechain@8.2.0)(typescript@4.7.2) + '@fluencelabs/deal-aurora': 0.1.8(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@nomicfoundation/hardhat-chai-matchers@1.0.6)(@nomicfoundation/hardhat-network-helpers@1.0.8)(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(@typechain/ethers-v5@10.2.1)(@typechain/hardhat@6.1.6)(@types/chai@4.3.5)(@types/mocha@9.1.1)(@types/node@20.7.0)(chai@4.3.7)(ethers@5.7.2)(hardhat-gas-reporter@1.0.9)(hardhat@2.15.0)(solidity-coverage@0.7.22)(ts-node@10.9.1)(typechain@8.2.0)(typescript@5.1.6) '@fluencelabs/fluence-network-environment': 1.1.2 '@fluencelabs/js-client': 0.0.10 '@iarna/toml': 2.2.5 '@mswjs/interceptors': 0.23.0 '@multiformats/multiaddr': 12.1.7 '@oclif/color': 1.0.11 - '@oclif/core': 2.13.0(@types/node@20.7.0)(typescript@4.7.2) - '@oclif/plugin-autocomplete': 2.3.6(@types/node@20.7.0)(typescript@4.7.2) - '@oclif/plugin-help': 5.2.18(@types/node@20.7.0)(typescript@4.7.2) - '@oclif/plugin-not-found': 2.4.0(@types/node@20.7.0)(typescript@4.7.2) - '@oclif/plugin-update': 3.2.0(@types/node@20.7.0)(typescript@4.7.2) + '@oclif/core': 2.13.0(@types/node@20.7.0)(typescript@5.1.6) + '@oclif/plugin-autocomplete': 2.3.6(@types/node@20.7.0)(typescript@5.1.6) + '@oclif/plugin-help': 5.2.18(@types/node@20.7.0)(typescript@5.1.6) + '@oclif/plugin-not-found': 2.4.0(@types/node@20.7.0)(typescript@5.1.6) + '@oclif/plugin-update': 3.2.0(@types/node@20.7.0)(typescript@5.1.6) '@walletconnect/universal-provider': 2.8.1(lokijs@1.5.12) ajv: 8.12.0 camelcase: 7.0.1 @@ -3956,10 +3984,10 @@ packages: - utf-8-validate dev: true - /@fluencelabs/deal-aurora@0.1.8(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@nomicfoundation/hardhat-chai-matchers@1.0.6)(@nomicfoundation/hardhat-network-helpers@1.0.8)(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(@typechain/ethers-v5@10.2.1)(@typechain/hardhat@6.1.6)(@types/chai@4.3.5)(@types/mocha@9.1.1)(@types/node@20.7.0)(chai@4.3.7)(ethers@5.7.2)(hardhat-gas-reporter@1.0.9)(hardhat@2.15.0)(solidity-coverage@0.7.22)(ts-node@10.9.1)(typechain@8.2.0)(typescript@4.7.2): + /@fluencelabs/deal-aurora@0.1.8(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@nomicfoundation/hardhat-chai-matchers@1.0.6)(@nomicfoundation/hardhat-network-helpers@1.0.8)(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(@typechain/ethers-v5@10.2.1)(@typechain/hardhat@6.1.6)(@types/chai@4.3.5)(@types/mocha@9.1.1)(@types/node@20.7.0)(chai@4.3.7)(ethers@5.7.2)(hardhat-gas-reporter@1.0.9)(hardhat@2.15.0)(solidity-coverage@0.7.22)(ts-node@10.9.1)(typechain@8.2.0)(typescript@5.1.6): resolution: {integrity: sha512-h2L3F67AsFxJy+mBAAUy8gMUGf85sgT3kuLhqEstdbQ20ASjxrSsXmyVZeVQLUx4nR1ygbGll9Y+FmRFgpNwMQ==} dependencies: - '@nomicfoundation/hardhat-toolbox': 1.0.2(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@nomicfoundation/hardhat-chai-matchers@1.0.6)(@nomicfoundation/hardhat-network-helpers@1.0.8)(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(@typechain/ethers-v5@10.2.1)(@typechain/hardhat@6.1.6)(@types/chai@4.3.5)(@types/mocha@9.1.1)(@types/node@20.7.0)(chai@4.3.7)(ethers@5.7.2)(hardhat-gas-reporter@1.0.9)(hardhat@2.15.0)(solidity-coverage@0.7.22)(ts-node@10.9.1)(typechain@8.2.0)(typescript@4.7.2) + '@nomicfoundation/hardhat-toolbox': 1.0.2(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@nomicfoundation/hardhat-chai-matchers@1.0.6)(@nomicfoundation/hardhat-network-helpers@1.0.8)(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(@typechain/ethers-v5@10.2.1)(@typechain/hardhat@6.1.6)(@types/chai@4.3.5)(@types/mocha@9.1.1)(@types/node@20.7.0)(chai@4.3.7)(ethers@5.7.2)(hardhat-gas-reporter@1.0.9)(hardhat@2.15.0)(solidity-coverage@0.7.22)(ts-node@10.9.1)(typechain@8.2.0)(typescript@5.1.6) '@openzeppelin/contracts': 4.9.2 '@openzeppelin/contracts-upgradeable': 4.9.2 dotenv: 16.3.1 @@ -3993,7 +4021,7 @@ packages: resolution: {integrity: sha512-1Bp2gBy3oMEILMynFpOIFK/q2Pj792xpnb3AJs5QcTQAaHz9V2nrEI8OOPwBAFTmjmLBirXBqQQX63O+ePH7yg==} dev: true - /@fluencelabs/fluence@0.27.5(jest@27.5.1)(node-fetch@3.3.2)(typescript@4.7.2): + /@fluencelabs/fluence@0.27.5(jest@27.5.1)(node-fetch@3.3.2)(typescript@5.1.6): resolution: {integrity: sha512-nMCzd/oHHk5/yWdg/+rPB+sc8X+fQ5YgwPhGVDoxFs8/CmIr1G5Na8Y6l8rrigasgQd+LV5GtAyh50Oq7/IXkg==} engines: {node: '>=10', pnpm: '>=3'} deprecated: fluencelabs/fluence is deprecated in favor of a thinner CDN-distributed .js bundle, please see the following link for installation instructions https://github.com/fluencelabs/js-client#installation @@ -4003,7 +4031,7 @@ packages: '@fluencelabs/connection': 0.2.0(node-fetch@3.3.2) '@fluencelabs/interfaces': 0.1.0 '@fluencelabs/keypair': 0.2.0 - '@fluencelabs/marine-js': 0.3.37(jest@27.5.1)(typescript@4.7.2) + '@fluencelabs/marine-js': 0.3.37(jest@27.5.1)(typescript@5.1.6) async: 3.2.4 base64-js: 1.5.1 browser-or-node: 2.0.0 @@ -4084,7 +4112,7 @@ packages: peer-id: 0.16.0 dev: true - /@fluencelabs/marine-js@0.3.37(jest@27.5.1)(typescript@4.7.2): + /@fluencelabs/marine-js@0.3.37(jest@27.5.1)(typescript@5.1.6): resolution: {integrity: sha512-/Kpu3S+aDOfrOpKBAK1VeWSHKCoD36/dxtHEWHbj3Lsro0GB9zkoaZPHlFFL7rorCB+hyjAJqLDuBGI8f3l/qg==} dependencies: '@wasmer/wasi': 0.12.0 @@ -4092,7 +4120,7 @@ packages: browser-or-node: 2.0.0 buffer: 6.0.3 threads: 1.7.0 - ts-jest: 27.1.5(jest@27.5.1)(typescript@4.7.2) + ts-jest: 27.1.5(jest@27.5.1)(typescript@5.1.6) transitivePeerDependencies: - '@babel/core' - '@types/jest' @@ -4152,8 +4180,8 @@ packages: '@fluencelabs/aqua-lib': 0.5.2 dev: true - /@humanwhocodes/config-array@0.11.10: - resolution: {integrity: sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==} + /@humanwhocodes/config-array@0.11.11: + resolution: {integrity: sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==} engines: {node: '>=10.10.0'} dependencies: '@humanwhocodes/object-schema': 1.2.1 @@ -4161,16 +4189,13 @@ packages: minimatch: 3.1.2 transitivePeerDependencies: - supports-color - dev: false /@humanwhocodes/module-importer@1.0.1: resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} engines: {node: '>=12.22'} - dev: false /@humanwhocodes/object-schema@1.2.1: resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} - dev: false /@iarna/toml@2.2.5: resolution: {integrity: sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==} @@ -5096,7 +5121,7 @@ packages: chai-as-promised: 7.1.1(chai@4.3.7) deep-eql: 4.1.3 ethers: 5.7.2 - hardhat: 2.15.0(ts-node@10.9.1)(typescript@4.7.2) + hardhat: 2.15.0(ts-node@10.9.1)(typescript@5.1.6) ordinal: 1.0.3 dev: true @@ -5106,10 +5131,10 @@ packages: hardhat: ^2.9.5 dependencies: ethereumjs-util: 7.1.5 - hardhat: 2.15.0(ts-node@10.9.1)(typescript@4.7.2) + hardhat: 2.15.0(ts-node@10.9.1)(typescript@5.1.6) dev: true - /@nomicfoundation/hardhat-toolbox@1.0.2(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@nomicfoundation/hardhat-chai-matchers@1.0.6)(@nomicfoundation/hardhat-network-helpers@1.0.8)(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(@typechain/ethers-v5@10.2.1)(@typechain/hardhat@6.1.6)(@types/chai@4.3.5)(@types/mocha@9.1.1)(@types/node@20.7.0)(chai@4.3.7)(ethers@5.7.2)(hardhat-gas-reporter@1.0.9)(hardhat@2.15.0)(solidity-coverage@0.7.22)(ts-node@10.9.1)(typechain@8.2.0)(typescript@4.7.2): + /@nomicfoundation/hardhat-toolbox@1.0.2(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@nomicfoundation/hardhat-chai-matchers@1.0.6)(@nomicfoundation/hardhat-network-helpers@1.0.8)(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(@typechain/ethers-v5@10.2.1)(@typechain/hardhat@6.1.6)(@types/chai@4.3.5)(@types/mocha@9.1.1)(@types/node@20.7.0)(chai@4.3.7)(ethers@5.7.2)(hardhat-gas-reporter@1.0.9)(hardhat@2.15.0)(solidity-coverage@0.7.22)(ts-node@10.9.1)(typechain@8.2.0)(typescript@5.1.6): resolution: {integrity: sha512-8CEgWSKUK2aMit+76Sez8n7UB0Ze1lwT+LcWxj4EFP30lQWOwOws048t6MTPfThH0BlSWjC6hJRr0LncIkc1Sw==} peerDependencies: '@ethersproject/abi': ^5.4.7 @@ -5138,19 +5163,19 @@ packages: '@nomicfoundation/hardhat-network-helpers': 1.0.8(hardhat@2.15.0) '@nomiclabs/hardhat-ethers': 2.2.3(ethers@5.7.2)(hardhat@2.15.0) '@nomiclabs/hardhat-etherscan': 3.1.7(hardhat@2.15.0) - '@typechain/ethers-v5': 10.2.1(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(ethers@5.7.2)(typechain@8.2.0)(typescript@4.7.2) + '@typechain/ethers-v5': 10.2.1(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(ethers@5.7.2)(typechain@8.2.0)(typescript@5.1.6) '@typechain/hardhat': 6.1.6(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@typechain/ethers-v5@10.2.1)(ethers@5.7.2)(hardhat@2.15.0)(typechain@8.2.0) '@types/chai': 4.3.5 '@types/mocha': 9.1.1 '@types/node': 20.7.0 chai: 4.3.7 ethers: 5.7.2 - hardhat: 2.15.0(ts-node@10.9.1)(typescript@4.7.2) + hardhat: 2.15.0(ts-node@10.9.1)(typescript@5.1.6) hardhat-gas-reporter: 1.0.9(hardhat@2.15.0) solidity-coverage: 0.7.22 - ts-node: 10.9.1(@types/node@20.7.0)(typescript@4.7.2) - typechain: 8.2.0(typescript@4.7.2) - typescript: 4.7.2 + ts-node: 10.9.1(@types/node@20.7.0)(typescript@5.1.6) + typechain: 8.2.0(typescript@5.1.6) + typescript: 5.1.6 dev: true /@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.1: @@ -5266,7 +5291,7 @@ packages: hardhat: ^2.0.0 dependencies: ethers: 5.7.2 - hardhat: 2.15.0(ts-node@10.9.1)(typescript@4.7.2) + hardhat: 2.15.0(ts-node@10.9.1)(typescript@5.1.6) dev: true /@nomiclabs/hardhat-etherscan@3.1.7(hardhat@2.15.0): @@ -5280,7 +5305,7 @@ packages: chalk: 2.4.2 debug: 4.3.4(supports-color@8.1.1) fs-extra: 7.0.1 - hardhat: 2.15.0(ts-node@10.9.1)(typescript@4.7.2) + hardhat: 2.15.0(ts-node@10.9.1)(typescript@5.1.6) lodash: 4.17.21 semver: 6.3.1 table: 6.8.1 @@ -5301,7 +5326,7 @@ packages: tslib: 2.5.3 dev: true - /@oclif/core@2.13.0(@types/node@20.7.0)(typescript@4.7.2): + /@oclif/core@2.13.0(@types/node@20.7.0)(typescript@5.1.6): resolution: {integrity: sha512-U/AgA/Jcqc04VwmsO/xSc3gJjVKkST8SB3wC3o3kzTAE4UWTOTMkHTtLujYZA5sUvBLhs66+A4dfrjz2sZQBdA==} engines: {node: '>=14.0.0'} dependencies: @@ -5330,7 +5355,7 @@ packages: strip-ansi: 6.0.1 supports-color: 8.1.1 supports-hyperlinks: 2.3.0 - ts-node: 10.9.1(@types/node@20.7.0)(typescript@4.7.2) + ts-node: 10.9.1(@types/node@20.7.0)(typescript@5.1.6) tslib: 2.5.3 widest-line: 3.1.0 wordwrap: 1.0.0 @@ -5342,11 +5367,11 @@ packages: - typescript dev: true - /@oclif/plugin-autocomplete@2.3.6(@types/node@20.7.0)(typescript@4.7.2): + /@oclif/plugin-autocomplete@2.3.6(@types/node@20.7.0)(typescript@5.1.6): resolution: {integrity: sha512-h969Vc9pzwJ87Z79PXjt67uUZm99zj8pD4zSX3pjc2xOf4ZNslLHNtvb3AjuU01mTM6FYJTsJcwjhPvXzxsqEg==} engines: {node: '>=12.0.0'} dependencies: - '@oclif/core': 2.13.0(@types/node@20.7.0)(typescript@4.7.2) + '@oclif/core': 2.13.0(@types/node@20.7.0)(typescript@5.1.6) chalk: 4.1.2 debug: 4.3.4(supports-color@8.1.1) fs-extra: 9.1.0 @@ -5358,11 +5383,11 @@ packages: - typescript dev: true - /@oclif/plugin-help@5.2.18(@types/node@20.7.0)(typescript@4.7.2): + /@oclif/plugin-help@5.2.18(@types/node@20.7.0)(typescript@5.1.6): resolution: {integrity: sha512-0JjupXUuDzlI0Ojj7/YL42btfUNuvSgZxdi8ZfeYt/uhC1/zvsSkO29KjffPxKEnbhr6jrkjOgy/Vly5JquYLg==} engines: {node: '>=12.0.0'} dependencies: - '@oclif/core': 2.13.0(@types/node@20.7.0)(typescript@4.7.2) + '@oclif/core': 2.13.0(@types/node@20.7.0)(typescript@5.1.6) transitivePeerDependencies: - '@swc/core' - '@swc/wasm' @@ -5370,11 +5395,11 @@ packages: - typescript dev: true - /@oclif/plugin-not-found@2.4.0(@types/node@20.7.0)(typescript@4.7.2): + /@oclif/plugin-not-found@2.4.0(@types/node@20.7.0)(typescript@5.1.6): resolution: {integrity: sha512-EOoesBEgyj4TMdHUpnCqN7qqH0f1NHh7buTdWfhwlSjbfrL9rAuodiART5/zgtsj5b8uao3aXdcx1gPxWOogEw==} engines: {node: '>=12.0.0'} dependencies: - '@oclif/core': 2.13.0(@types/node@20.7.0)(typescript@4.7.2) + '@oclif/core': 2.13.0(@types/node@20.7.0)(typescript@5.1.6) chalk: 4.1.2 fast-levenshtein: 3.0.0 transitivePeerDependencies: @@ -5384,11 +5409,11 @@ packages: - typescript dev: true - /@oclif/plugin-update@3.2.0(@types/node@20.7.0)(typescript@4.7.2): + /@oclif/plugin-update@3.2.0(@types/node@20.7.0)(typescript@5.1.6): resolution: {integrity: sha512-naQIw/sjbNBNdYnoQOudYMJc1Im2fpyQAh87ZN8tR/6Wuf4fyxfLUENm8Gy8jqBM3GN4rw/yg0uW7tDH5wY0qg==} engines: {node: '>=12.0.0'} dependencies: - '@oclif/core': 2.13.0(@types/node@20.7.0)(typescript@4.7.2) + '@oclif/core': 2.13.0(@types/node@20.7.0)(typescript@5.1.6) chalk: 4.1.2 cross-spawn: 7.0.3 debug: 4.3.4(supports-color@8.1.1) @@ -6044,6 +6069,10 @@ packages: resolution: {integrity: sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==} engines: {node: '>= 6'} + /@total-typescript/ts-reset@0.5.1: + resolution: {integrity: sha512-AqlrT8YA1o7Ff5wPfMOL0pvL+1X+sw60NN6CcOCqs658emD6RfiXhF7Gu9QcfKBH7ELY2nInLhKSCWVoNL70MQ==} + dev: true + /@truffle/error@0.1.1: resolution: {integrity: sha512-sE7c9IHIGdbK4YayH4BC8i8qMjoAOeg6nUXUDZZp8wlU21/EMpaG+CLx+KqcIPyR+GSWIW3Dm0PXkr2nlggFDA==} dev: true @@ -6092,7 +6121,11 @@ packages: /@tsconfig/node16@1.0.4: resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} - /@typechain/ethers-v5@10.2.1(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(ethers@5.7.2)(typechain@8.2.0)(typescript@4.7.2): + /@tsconfig/strictest@2.0.2: + resolution: {integrity: sha512-jt4jIsWKvUvuY6adJnQJlb/UR7DdjC8CjHI/OaSQruj2yX9/K6+KOvDt/vD6udqos/FUk5Op66CvYT7TBLYO5Q==} + dev: true + + /@typechain/ethers-v5@10.2.1(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(ethers@5.7.2)(typechain@8.2.0)(typescript@5.1.6): resolution: {integrity: sha512-n3tQmCZjRE6IU4h6lqUGiQ1j866n5MTCBJreNEHHVWXa2u9GJTaeYyU1/k+1qLutkyw+sS6VAN+AbeiTqsxd/A==} peerDependencies: '@ethersproject/abi': ^5.0.0 @@ -6105,9 +6138,9 @@ packages: '@ethersproject/providers': 5.7.2 ethers: 5.7.2 lodash: 4.17.21 - ts-essentials: 7.0.3(typescript@4.7.2) - typechain: 8.2.0(typescript@4.7.2) - typescript: 4.7.2 + ts-essentials: 7.0.3(typescript@5.1.6) + typechain: 8.2.0(typescript@5.1.6) + typescript: 5.1.6 dev: true /@typechain/hardhat@6.1.6(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@typechain/ethers-v5@10.2.1)(ethers@5.7.2)(hardhat@2.15.0)(typechain@8.2.0): @@ -6122,11 +6155,11 @@ packages: dependencies: '@ethersproject/abi': 5.7.0 '@ethersproject/providers': 5.7.2 - '@typechain/ethers-v5': 10.2.1(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(ethers@5.7.2)(typechain@8.2.0)(typescript@4.7.2) + '@typechain/ethers-v5': 10.2.1(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(ethers@5.7.2)(typechain@8.2.0)(typescript@5.1.6) ethers: 5.7.2 fs-extra: 9.1.0 - hardhat: 2.15.0(ts-node@10.9.1)(typescript@4.7.2) - typechain: 8.2.0(typescript@4.7.2) + hardhat: 2.15.0(ts-node@10.9.1)(typescript@5.1.6) + typechain: 8.2.0(typescript@5.1.6) dev: true /@types/aria-query@5.0.1: @@ -6345,11 +6378,9 @@ packages: /@types/json-schema@7.0.12: resolution: {integrity: sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==} - dev: false /@types/json5@0.0.29: resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} - dev: false /@types/keyv@3.1.4: resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} @@ -6494,7 +6525,6 @@ packages: /@types/semver@7.5.0: resolution: {integrity: sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==} - dev: false /@types/send@0.17.1: resolution: {integrity: sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==} @@ -6572,7 +6602,7 @@ packages: dev: true optional: true - /@typescript-eslint/eslint-plugin@5.60.0(@typescript-eslint/parser@5.60.0)(eslint@8.43.0)(typescript@4.9.5): + /@typescript-eslint/eslint-plugin@5.60.0(@typescript-eslint/parser@5.60.0)(eslint@8.50.0)(typescript@5.1.6): resolution: {integrity: sha512-78B+anHLF1TI8Jn/cD0Q00TBYdMgjdOn980JfAVa9yw5sop8nyTfVOQAv6LWywkOGLclDBtv5z3oxN4w7jxyNg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -6584,36 +6614,65 @@ packages: optional: true dependencies: '@eslint-community/regexpp': 4.5.1 - '@typescript-eslint/parser': 5.60.0(eslint@8.43.0)(typescript@4.9.5) + '@typescript-eslint/parser': 5.60.0(eslint@8.50.0)(typescript@5.1.6) '@typescript-eslint/scope-manager': 5.60.0 - '@typescript-eslint/type-utils': 5.60.0(eslint@8.43.0)(typescript@4.9.5) - '@typescript-eslint/utils': 5.60.0(eslint@8.43.0)(typescript@4.9.5) + '@typescript-eslint/type-utils': 5.60.0(eslint@8.50.0)(typescript@5.1.6) + '@typescript-eslint/utils': 5.60.0(eslint@8.50.0)(typescript@5.1.6) debug: 4.3.4(supports-color@8.1.1) - eslint: 8.43.0 + eslint: 8.50.0 grapheme-splitter: 1.0.4 ignore: 5.2.4 natural-compare-lite: 1.4.0 semver: 7.5.4 - tsutils: 3.21.0(typescript@4.9.5) - typescript: 4.9.5 + tsutils: 3.21.0(typescript@5.1.6) + typescript: 5.1.6 transitivePeerDependencies: - supports-color dev: false - /@typescript-eslint/experimental-utils@5.60.0(eslint@8.43.0)(typescript@4.9.5): + /@typescript-eslint/eslint-plugin@6.7.3(@typescript-eslint/parser@6.7.3)(eslint@8.50.0)(typescript@5.1.6): + resolution: {integrity: sha512-vntq452UHNltxsaaN+L9WyuMch8bMd9CqJ3zhzTPXXidwbf5mqqKCVXEuvRZUqLJSTLeWE65lQwyXsRGnXkCTA==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@eslint-community/regexpp': 4.5.1 + '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.1.6) + '@typescript-eslint/scope-manager': 6.7.3 + '@typescript-eslint/type-utils': 6.7.3(eslint@8.50.0)(typescript@5.1.6) + '@typescript-eslint/utils': 6.7.3(eslint@8.50.0)(typescript@5.1.6) + '@typescript-eslint/visitor-keys': 6.7.3 + debug: 4.3.4(supports-color@8.1.1) + eslint: 8.50.0 + graphemer: 1.4.0 + ignore: 5.2.4 + natural-compare: 1.4.0 + semver: 7.5.4 + ts-api-utils: 1.0.3(typescript@5.1.6) + typescript: 5.1.6 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/experimental-utils@5.60.0(eslint@8.50.0)(typescript@5.1.6): resolution: {integrity: sha512-ovid3u7CNBrr0Ct35LUPkNYH4e+z4Kc6dPfSG99oMmH9SfoEoefq09uSnJI4mUb/UM7a/peVM03G+MzLxrD16g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - '@typescript-eslint/utils': 5.60.0(eslint@8.43.0)(typescript@4.9.5) - eslint: 8.43.0 + '@typescript-eslint/utils': 5.60.0(eslint@8.50.0)(typescript@5.1.6) + eslint: 8.50.0 transitivePeerDependencies: - supports-color - typescript dev: false - /@typescript-eslint/parser@5.60.0(eslint@8.43.0)(typescript@4.9.5): + /@typescript-eslint/parser@5.60.0(eslint@8.50.0)(typescript@5.1.6): resolution: {integrity: sha512-jBONcBsDJ9UoTWrARkRRCgDz6wUggmH5RpQVlt7BimSwaTkTjwypGzKORXbR4/2Hqjk9hgwlon2rVQAjWNpkyQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -6625,14 +6684,35 @@ packages: dependencies: '@typescript-eslint/scope-manager': 5.60.0 '@typescript-eslint/types': 5.60.0 - '@typescript-eslint/typescript-estree': 5.60.0(typescript@4.9.5) + '@typescript-eslint/typescript-estree': 5.60.0(typescript@5.1.6) debug: 4.3.4(supports-color@8.1.1) - eslint: 8.43.0 - typescript: 4.9.5 + eslint: 8.50.0 + typescript: 5.1.6 transitivePeerDependencies: - supports-color dev: false + /@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.1.6): + resolution: {integrity: sha512-TlutE+iep2o7R8Lf+yoer3zU6/0EAUc8QIBB3GYBc1KGz4c4TRm83xwXUZVPlZ6YCLss4r77jbu6j3sendJoiQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/scope-manager': 6.7.3 + '@typescript-eslint/types': 6.7.3 + '@typescript-eslint/typescript-estree': 6.7.3(typescript@5.1.6) + '@typescript-eslint/visitor-keys': 6.7.3 + debug: 4.3.4(supports-color@8.1.1) + eslint: 8.50.0 + typescript: 5.1.6 + transitivePeerDependencies: + - supports-color + dev: true + /@typescript-eslint/scope-manager@5.60.0: resolution: {integrity: sha512-hakuzcxPwXi2ihf9WQu1BbRj1e/Pd8ZZwVTG9kfbxAMZstKz8/9OoexIwnmLzShtsdap5U/CoQGRCWlSuPbYxQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -6641,7 +6721,15 @@ packages: '@typescript-eslint/visitor-keys': 5.60.0 dev: false - /@typescript-eslint/type-utils@5.60.0(eslint@8.43.0)(typescript@4.9.5): + /@typescript-eslint/scope-manager@6.7.3: + resolution: {integrity: sha512-wOlo0QnEou9cHO2TdkJmzF7DFGvAKEnB82PuPNHpT8ZKKaZu6Bm63ugOTn9fXNJtvuDPanBc78lGUGGytJoVzQ==} + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@typescript-eslint/types': 6.7.3 + '@typescript-eslint/visitor-keys': 6.7.3 + dev: true + + /@typescript-eslint/type-utils@5.60.0(eslint@8.50.0)(typescript@5.1.6): resolution: {integrity: sha512-X7NsRQddORMYRFH7FWo6sA9Y/zbJ8s1x1RIAtnlj6YprbToTiQnM6vxcMu7iYhdunmoC0rUWlca13D5DVHkK2g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -6651,22 +6739,47 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 5.60.0(typescript@4.9.5) - '@typescript-eslint/utils': 5.60.0(eslint@8.43.0)(typescript@4.9.5) + '@typescript-eslint/typescript-estree': 5.60.0(typescript@5.1.6) + '@typescript-eslint/utils': 5.60.0(eslint@8.50.0)(typescript@5.1.6) debug: 4.3.4(supports-color@8.1.1) - eslint: 8.43.0 - tsutils: 3.21.0(typescript@4.9.5) - typescript: 4.9.5 + eslint: 8.50.0 + tsutils: 3.21.0(typescript@5.1.6) + typescript: 5.1.6 transitivePeerDependencies: - supports-color dev: false + /@typescript-eslint/type-utils@6.7.3(eslint@8.50.0)(typescript@5.1.6): + resolution: {integrity: sha512-Fc68K0aTDrKIBvLnKTZ5Pf3MXK495YErrbHb1R6aTpfK5OdSFj0rVN7ib6Tx6ePrZ2gsjLqr0s98NG7l96KSQw==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/typescript-estree': 6.7.3(typescript@5.1.6) + '@typescript-eslint/utils': 6.7.3(eslint@8.50.0)(typescript@5.1.6) + debug: 4.3.4(supports-color@8.1.1) + eslint: 8.50.0 + ts-api-utils: 1.0.3(typescript@5.1.6) + typescript: 5.1.6 + transitivePeerDependencies: + - supports-color + dev: true + /@typescript-eslint/types@5.60.0: resolution: {integrity: sha512-ascOuoCpNZBccFVNJRSC6rPq4EmJ2NkuoKnd6LDNyAQmdDnziAtxbCGWCbefG1CNzmDvd05zO36AmB7H8RzKPA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: false - /@typescript-eslint/typescript-estree@5.60.0(typescript@4.9.5): + /@typescript-eslint/types@6.7.3: + resolution: {integrity: sha512-4g+de6roB2NFcfkZb439tigpAMnvEIg3rIjWQ+EM7IBaYt/CdJt6em9BJ4h4UpdgaBWdmx2iWsafHTrqmgIPNw==} + engines: {node: ^16.0.0 || >=18.0.0} + dev: true + + /@typescript-eslint/typescript-estree@5.60.0(typescript@5.1.6): resolution: {integrity: sha512-R43thAuwarC99SnvrBmh26tc7F6sPa2B3evkXp/8q954kYL6Ro56AwASYWtEEi+4j09GbiNAHqYwNNZuNlARGQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -6681,25 +6794,46 @@ packages: globby: 11.1.0 is-glob: 4.0.3 semver: 7.5.4 - tsutils: 3.21.0(typescript@4.9.5) - typescript: 4.9.5 + tsutils: 3.21.0(typescript@5.1.6) + typescript: 5.1.6 transitivePeerDependencies: - supports-color dev: false - /@typescript-eslint/utils@5.60.0(eslint@8.43.0)(typescript@4.9.5): + /@typescript-eslint/typescript-estree@6.7.3(typescript@5.1.6): + resolution: {integrity: sha512-YLQ3tJoS4VxLFYHTw21oe1/vIZPRqAO91z6Uv0Ss2BKm/Ag7/RVQBcXTGcXhgJMdA4U+HrKuY5gWlJlvoaKZ5g==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 6.7.3 + '@typescript-eslint/visitor-keys': 6.7.3 + debug: 4.3.4(supports-color@8.1.1) + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.5.4 + ts-api-utils: 1.0.3(typescript@5.1.6) + typescript: 5.1.6 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/utils@5.60.0(eslint@8.50.0)(typescript@5.1.6): resolution: {integrity: sha512-ba51uMqDtfLQ5+xHtwlO84vkdjrqNzOnqrnwbMHMRY8Tqeme8C2Q8Fc7LajfGR+e3/4LoYiWXUM6BpIIbHJ4hQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.43.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.50.0) '@types/json-schema': 7.0.12 '@types/semver': 7.5.0 '@typescript-eslint/scope-manager': 5.60.0 '@typescript-eslint/types': 5.60.0 - '@typescript-eslint/typescript-estree': 5.60.0(typescript@4.9.5) - eslint: 8.43.0 + '@typescript-eslint/typescript-estree': 5.60.0(typescript@5.1.6) + eslint: 8.50.0 eslint-scope: 5.1.1 semver: 7.5.4 transitivePeerDependencies: @@ -6707,6 +6841,25 @@ packages: - typescript dev: false + /@typescript-eslint/utils@6.7.3(eslint@8.50.0)(typescript@5.1.6): + resolution: {integrity: sha512-vzLkVder21GpWRrmSR9JxGZ5+ibIUSudXlW52qeKpzUEQhRSmyZiVDDj3crAth7+5tmN1ulvgKaCU2f/bPRCzg==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.50.0) + '@types/json-schema': 7.0.12 + '@types/semver': 7.5.0 + '@typescript-eslint/scope-manager': 6.7.3 + '@typescript-eslint/types': 6.7.3 + '@typescript-eslint/typescript-estree': 6.7.3(typescript@5.1.6) + eslint: 8.50.0 + semver: 7.5.4 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + /@typescript-eslint/visitor-keys@5.60.0: resolution: {integrity: sha512-wm9Uz71SbCyhUKgcaPRauBdTegUyY/ZWl8gLwD/i/ybJqscrrdVSFImpvUz16BLPChIeKBK5Fa9s6KDQjsjyWw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -6715,6 +6868,14 @@ packages: eslint-visitor-keys: 3.4.1 dev: false + /@typescript-eslint/visitor-keys@6.7.3: + resolution: {integrity: sha512-HEVXkU9IB+nk9o63CeICMHxFWbHWr3E1mpilIQBe9+7L/lH97rleFLVtYsfnWB+JVMaiFnEaxvknvmIzX+CqVg==} + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@typescript-eslint/types': 6.7.3 + eslint-visitor-keys: 3.4.1 + dev: true + /@vascosantos/moving-average@1.1.0: resolution: {integrity: sha512-MVEJ4vWAPNbrGLjz7ITnHYg+YXZ6ijAqtH5/cHwSoCpbvuJ98aLXwFfPKAUfZpJMQR5uXB58UJajbY130IRF/w==} dev: true @@ -7187,7 +7348,6 @@ packages: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: acorn: 8.10.0 - dev: false /acorn-walk@7.2.0: resolution: {integrity: sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==} @@ -7464,7 +7624,6 @@ packages: es-abstract: 1.21.2 get-intrinsic: 1.2.1 is-string: 1.0.7 - dev: false /array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} @@ -7475,6 +7634,17 @@ packages: engines: {node: '>=0.10.0'} dev: true + /array.prototype.findlastindex@1.2.3: + resolution: {integrity: sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.22.2 + es-shim-unscopables: 1.0.0 + get-intrinsic: 1.2.1 + dev: true + /array.prototype.flat@1.3.1: resolution: {integrity: sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==} engines: {node: '>= 0.4'} @@ -7483,7 +7653,6 @@ packages: define-properties: 1.2.0 es-abstract: 1.21.2 es-shim-unscopables: 1.0.0 - dev: false /array.prototype.flatmap@1.3.1: resolution: {integrity: sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==} @@ -7493,7 +7662,6 @@ packages: define-properties: 1.2.0 es-abstract: 1.21.2 es-shim-unscopables: 1.0.0 - dev: false /array.prototype.reduce@1.0.5: resolution: {integrity: sha512-kDdugMl7id9COE8R7MHF5jWk7Dqt/fs4Pv+JXoICnYwqpjjjbUurz6w5fT5IG6brLdJhv6/VoHB0H7oyIBXd+Q==} @@ -7515,6 +7683,19 @@ packages: get-intrinsic: 1.2.1 dev: false + /arraybuffer.prototype.slice@1.0.2: + resolution: {integrity: sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.0 + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.22.2 + get-intrinsic: 1.2.1 + is-array-buffer: 3.0.2 + is-shared-array-buffer: 1.0.2 + dev: true + /asap@2.0.6: resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} @@ -9153,7 +9334,7 @@ packages: postcss-modules-scope: 3.0.0(postcss@8.4.24) postcss-modules-values: 4.0.0(postcss@8.4.24) postcss-value-parser: 4.2.0 - semver: 7.5.2 + semver: 7.5.4 webpack: 5.87.0 dev: false @@ -9621,6 +9802,15 @@ packages: engines: {node: '>=10'} dev: true + /define-data-property@1.1.0: + resolution: {integrity: sha512-UzGwzcjyv3OtAvolTj1GoyNYzfFR+iqbGjcnBEENZVCpM4/Ng1yhGNvS3lR/xDS74Tb2wGG9WzNSNIOS9UVb2g==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.1 + gopd: 1.0.1 + has-property-descriptors: 1.0.0 + dev: true + /define-lazy-prop@2.0.0: resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} engines: {node: '>=8'} @@ -9786,14 +9976,12 @@ packages: engines: {node: '>=0.10.0'} dependencies: esutils: 2.0.3 - dev: false /doctrine@3.0.0: resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} engines: {node: '>=6.0.0'} dependencies: esutils: 2.0.3 - dev: false /dom-accessibility-api@0.5.16: resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} @@ -10077,6 +10265,51 @@ packages: unbox-primitive: 1.0.2 which-typed-array: 1.1.9 + /es-abstract@1.22.2: + resolution: {integrity: sha512-YoxfFcDmhjOgWPWsV13+2RNjq1F6UQnfs+8TftwNqtzlmFzEXvlUwdrNrYeaizfjQzRMxkZ6ElWMOJIFKdVqwA==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.0 + arraybuffer.prototype.slice: 1.0.2 + available-typed-arrays: 1.0.5 + call-bind: 1.0.2 + es-set-tostringtag: 2.0.1 + es-to-primitive: 1.2.1 + function.prototype.name: 1.1.6 + get-intrinsic: 1.2.1 + get-symbol-description: 1.0.0 + globalthis: 1.0.3 + gopd: 1.0.1 + has: 1.0.3 + has-property-descriptors: 1.0.0 + has-proto: 1.0.1 + has-symbols: 1.0.3 + internal-slot: 1.0.5 + is-array-buffer: 3.0.2 + is-callable: 1.2.7 + is-negative-zero: 2.0.2 + is-regex: 1.1.4 + is-shared-array-buffer: 1.0.2 + is-string: 1.0.7 + is-typed-array: 1.1.12 + is-weakref: 1.0.2 + object-inspect: 1.12.3 + object-keys: 1.1.1 + object.assign: 4.1.4 + regexp.prototype.flags: 1.5.1 + safe-array-concat: 1.0.1 + safe-regex-test: 1.0.0 + string.prototype.trim: 1.2.8 + string.prototype.trimend: 1.0.7 + string.prototype.trimstart: 1.0.7 + typed-array-buffer: 1.0.0 + typed-array-byte-length: 1.0.0 + typed-array-byte-offset: 1.0.0 + typed-array-length: 1.0.4 + unbox-primitive: 1.0.2 + which-typed-array: 1.1.11 + dev: true + /es-array-method-boxes-properly@1.0.0: resolution: {integrity: sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==} @@ -10110,7 +10343,6 @@ packages: resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==} dependencies: has: 1.0.3 - dev: false /es-to-primitive@1.2.1: resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} @@ -10236,7 +10468,16 @@ packages: optionalDependencies: source-map: 0.6.1 - /eslint-config-react-app@7.0.1(@babel/plugin-syntax-flow@7.22.5)(@babel/plugin-transform-react-jsx@7.22.5)(eslint@8.43.0)(jest@27.5.1)(typescript@4.9.5): + /eslint-config-prettier@9.0.0(eslint@8.50.0): + resolution: {integrity: sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + dependencies: + eslint: 8.50.0 + dev: true + + /eslint-config-react-app@7.0.1(@babel/plugin-syntax-flow@7.22.5)(@babel/plugin-transform-react-jsx@7.22.5)(eslint@8.50.0)(jest@27.5.1)(typescript@5.1.6): resolution: {integrity: sha512-K6rNzvkIeHaTd8m/QEh1Zko0KI7BACWkkneSs6s9cKZC/J27X3eZR6Upt1jkmZ/4FK+XUOPPxMEN7+lbUXfSlA==} engines: {node: '>=14.0.0'} peerDependencies: @@ -10247,21 +10488,21 @@ packages: optional: true dependencies: '@babel/core': 7.22.5 - '@babel/eslint-parser': 7.22.5(@babel/core@7.22.5)(eslint@8.43.0) + '@babel/eslint-parser': 7.22.5(@babel/core@7.22.5)(eslint@8.50.0) '@rushstack/eslint-patch': 1.3.2 - '@typescript-eslint/eslint-plugin': 5.60.0(@typescript-eslint/parser@5.60.0)(eslint@8.43.0)(typescript@4.9.5) - '@typescript-eslint/parser': 5.60.0(eslint@8.43.0)(typescript@4.9.5) + '@typescript-eslint/eslint-plugin': 5.60.0(@typescript-eslint/parser@5.60.0)(eslint@8.50.0)(typescript@5.1.6) + '@typescript-eslint/parser': 5.60.0(eslint@8.50.0)(typescript@5.1.6) babel-preset-react-app: 10.0.1 confusing-browser-globals: 1.0.11 - eslint: 8.43.0 - eslint-plugin-flowtype: 8.0.3(@babel/plugin-syntax-flow@7.22.5)(@babel/plugin-transform-react-jsx@7.22.5)(eslint@8.43.0) - eslint-plugin-import: 2.27.5(@typescript-eslint/parser@5.60.0)(eslint@8.43.0) - eslint-plugin-jest: 25.7.0(@typescript-eslint/eslint-plugin@5.60.0)(eslint@8.43.0)(jest@27.5.1)(typescript@4.9.5) - eslint-plugin-jsx-a11y: 6.7.1(eslint@8.43.0) - eslint-plugin-react: 7.32.2(eslint@8.43.0) - eslint-plugin-react-hooks: 4.6.0(eslint@8.43.0) - eslint-plugin-testing-library: 5.11.0(eslint@8.43.0)(typescript@4.9.5) - typescript: 4.9.5 + eslint: 8.50.0 + eslint-plugin-flowtype: 8.0.3(@babel/plugin-syntax-flow@7.22.5)(@babel/plugin-transform-react-jsx@7.22.5)(eslint@8.50.0) + eslint-plugin-import: 2.27.5(@typescript-eslint/parser@5.60.0)(eslint@8.50.0) + eslint-plugin-jest: 25.7.0(@typescript-eslint/eslint-plugin@5.60.0)(eslint@8.50.0)(jest@27.5.1)(typescript@5.1.6) + eslint-plugin-jsx-a11y: 6.7.1(eslint@8.50.0) + eslint-plugin-react: 7.32.2(eslint@8.50.0) + eslint-plugin-react-hooks: 4.6.0(eslint@8.50.0) + eslint-plugin-testing-library: 5.11.0(eslint@8.50.0)(typescript@5.1.6) + typescript: 5.1.6 transitivePeerDependencies: - '@babel/plugin-syntax-flow' - '@babel/plugin-transform-react-jsx' @@ -10279,9 +10520,8 @@ packages: resolve: 1.22.4 transitivePeerDependencies: - supports-color - dev: false - /eslint-module-utils@2.8.0(@typescript-eslint/parser@5.60.0)(eslint-import-resolver-node@0.3.7)(eslint@8.43.0): + /eslint-module-utils@2.8.0(@typescript-eslint/parser@5.60.0)(eslint-import-resolver-node@0.3.7)(eslint@8.50.0): resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} engines: {node: '>=4'} peerDependencies: @@ -10302,15 +10542,44 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 5.60.0(eslint@8.43.0)(typescript@4.9.5) + '@typescript-eslint/parser': 5.60.0(eslint@8.50.0)(typescript@5.1.6) debug: 3.2.7 - eslint: 8.43.0 + eslint: 8.50.0 eslint-import-resolver-node: 0.3.7 transitivePeerDependencies: - supports-color dev: false - /eslint-plugin-flowtype@8.0.3(@babel/plugin-syntax-flow@7.22.5)(@babel/plugin-transform-react-jsx@7.22.5)(eslint@8.43.0): + /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.7.3)(eslint-import-resolver-node@0.3.7)(eslint@8.50.0): + resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + dependencies: + '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.1.6) + debug: 3.2.7 + eslint: 8.50.0 + eslint-import-resolver-node: 0.3.7 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-plugin-flowtype@8.0.3(@babel/plugin-syntax-flow@7.22.5)(@babel/plugin-transform-react-jsx@7.22.5)(eslint@8.50.0): resolution: {integrity: sha512-dX8l6qUL6O+fYPtpNRideCFSpmWOUVx5QcaGLVqe/vlDiBSe4vYljDWDETwnyFzpl7By/WVIu6rcrniCgH9BqQ==} engines: {node: '>=12.0.0'} peerDependencies: @@ -10320,12 +10589,12 @@ packages: dependencies: '@babel/plugin-syntax-flow': 7.22.5(@babel/core@7.22.10) '@babel/plugin-transform-react-jsx': 7.22.5(@babel/core@7.22.10) - eslint: 8.43.0 + eslint: 8.50.0 lodash: 4.17.21 string-natural-compare: 3.0.1 dev: false - /eslint-plugin-import@2.27.5(@typescript-eslint/parser@5.60.0)(eslint@8.43.0): + /eslint-plugin-import@2.27.5(@typescript-eslint/parser@5.60.0)(eslint@8.50.0): resolution: {integrity: sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==} engines: {node: '>=4'} peerDependencies: @@ -10335,17 +10604,17 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 5.60.0(eslint@8.43.0)(typescript@4.9.5) + '@typescript-eslint/parser': 5.60.0(eslint@8.50.0)(typescript@5.1.6) array-includes: 3.1.6 array.prototype.flat: 1.3.1 array.prototype.flatmap: 1.3.1 debug: 3.2.7 doctrine: 2.1.0 - eslint: 8.43.0 + eslint: 8.50.0 eslint-import-resolver-node: 0.3.7 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.60.0)(eslint-import-resolver-node@0.3.7)(eslint@8.43.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.60.0)(eslint-import-resolver-node@0.3.7)(eslint@8.50.0) has: 1.0.3 - is-core-module: 2.12.1 + is-core-module: 2.13.0 is-glob: 4.0.3 minimatch: 3.1.2 object.values: 1.1.6 @@ -10358,7 +10627,42 @@ packages: - supports-color dev: false - /eslint-plugin-jest@25.7.0(@typescript-eslint/eslint-plugin@5.60.0)(eslint@8.43.0)(jest@27.5.1)(typescript@4.9.5): + /eslint-plugin-import@2.28.1(@typescript-eslint/parser@6.7.3)(eslint@8.50.0): + resolution: {integrity: sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + dependencies: + '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.1.6) + array-includes: 3.1.6 + array.prototype.findlastindex: 1.2.3 + array.prototype.flat: 1.3.1 + array.prototype.flatmap: 1.3.1 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 8.50.0 + eslint-import-resolver-node: 0.3.7 + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.7.3)(eslint-import-resolver-node@0.3.7)(eslint@8.50.0) + has: 1.0.3 + is-core-module: 2.13.0 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.fromentries: 2.0.6 + object.groupby: 1.0.1 + object.values: 1.1.6 + semver: 6.3.1 + tsconfig-paths: 3.14.2 + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + dev: true + + /eslint-plugin-jest@25.7.0(@typescript-eslint/eslint-plugin@5.60.0)(eslint@8.50.0)(jest@27.5.1)(typescript@5.1.6): resolution: {integrity: sha512-PWLUEXeeF7C9QGKqvdSbzLOiLTx+bno7/HC9eefePfEb257QFHg7ye3dh80AZVkaa/RQsBB1Q/ORQvg2X7F0NQ==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} peerDependencies: @@ -10371,16 +10675,16 @@ packages: jest: optional: true dependencies: - '@typescript-eslint/eslint-plugin': 5.60.0(@typescript-eslint/parser@5.60.0)(eslint@8.43.0)(typescript@4.9.5) - '@typescript-eslint/experimental-utils': 5.60.0(eslint@8.43.0)(typescript@4.9.5) - eslint: 8.43.0 + '@typescript-eslint/eslint-plugin': 5.60.0(@typescript-eslint/parser@5.60.0)(eslint@8.50.0)(typescript@5.1.6) + '@typescript-eslint/experimental-utils': 5.60.0(eslint@8.50.0)(typescript@5.1.6) + eslint: 8.50.0 jest: 27.5.1(ts-node@10.9.1) transitivePeerDependencies: - supports-color - typescript dev: false - /eslint-plugin-jsx-a11y@6.7.1(eslint@8.43.0): + /eslint-plugin-jsx-a11y@6.7.1(eslint@8.50.0): resolution: {integrity: sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==} engines: {node: '>=4.0'} peerDependencies: @@ -10395,7 +10699,7 @@ packages: axobject-query: 3.2.1 damerau-levenshtein: 1.0.8 emoji-regex: 9.2.2 - eslint: 8.43.0 + eslint: 8.50.0 has: 1.0.3 jsx-ast-utils: 3.3.3 language-tags: 1.0.5 @@ -10405,16 +10709,22 @@ packages: semver: 6.3.1 dev: false - /eslint-plugin-react-hooks@4.6.0(eslint@8.43.0): + /eslint-plugin-license-header@0.6.0: + resolution: {integrity: sha512-IEywStBWaDBDMkogYoKUAdaOuomZ+YaQmdoSD2vHmXobekM+XuP6SWLlvwUUhIbdocn3MTlb5CUJ8E4VHz1c/w==} + dependencies: + requireindex: 1.2.0 + dev: true + + /eslint-plugin-react-hooks@4.6.0(eslint@8.50.0): resolution: {integrity: sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==} engines: {node: '>=10'} peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 dependencies: - eslint: 8.43.0 + eslint: 8.50.0 dev: false - /eslint-plugin-react@7.32.2(eslint@8.43.0): + /eslint-plugin-react@7.32.2(eslint@8.50.0): resolution: {integrity: sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==} engines: {node: '>=4'} peerDependencies: @@ -10424,7 +10734,7 @@ packages: array.prototype.flatmap: 1.3.1 array.prototype.tosorted: 1.1.1 doctrine: 2.1.0 - eslint: 8.43.0 + eslint: 8.50.0 estraverse: 5.3.0 jsx-ast-utils: 3.3.3 minimatch: 3.1.2 @@ -10438,19 +10748,39 @@ packages: string.prototype.matchall: 4.0.8 dev: false - /eslint-plugin-testing-library@5.11.0(eslint@8.43.0)(typescript@4.9.5): + /eslint-plugin-testing-library@5.11.0(eslint@8.50.0)(typescript@5.1.6): resolution: {integrity: sha512-ELY7Gefo+61OfXKlQeXNIDVVLPcvKTeiQOoMZG9TeuWa7Ln4dUNRv8JdRWBQI9Mbb427XGlVB1aa1QPZxBJM8Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0, npm: '>=6'} peerDependencies: eslint: ^7.5.0 || ^8.0.0 dependencies: - '@typescript-eslint/utils': 5.60.0(eslint@8.43.0)(typescript@4.9.5) - eslint: 8.43.0 + '@typescript-eslint/utils': 5.60.0(eslint@8.50.0)(typescript@5.1.6) + eslint: 8.50.0 transitivePeerDependencies: - supports-color - typescript dev: false + /eslint-plugin-unused-imports@3.0.0(@typescript-eslint/eslint-plugin@6.7.3)(eslint@8.50.0): + resolution: {integrity: sha512-sduiswLJfZHeeBJ+MQaG+xYzSWdRXoSw61DpU13mzWumCkR0ufD0HmO4kdNokjrkluMHpj/7PJeN35pgbhW3kw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + '@typescript-eslint/eslint-plugin': ^6.0.0 + eslint: ^8.0.0 + peerDependenciesMeta: + '@typescript-eslint/eslint-plugin': + optional: true + dependencies: + '@typescript-eslint/eslint-plugin': 6.7.3(@typescript-eslint/parser@6.7.3)(eslint@8.50.0)(typescript@5.1.6) + eslint: 8.50.0 + eslint-rule-composer: 0.3.0 + dev: true + + /eslint-rule-composer@0.3.0: + resolution: {integrity: sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==} + engines: {node: '>=4.0.0'} + dev: true + /eslint-scope@5.1.1: resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} engines: {node: '>=8.0.0'} @@ -10459,13 +10789,12 @@ packages: estraverse: 4.3.0 dev: false - /eslint-scope@7.2.0: - resolution: {integrity: sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==} + /eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: esrecurse: 4.3.0 estraverse: 5.3.0 - dev: false /eslint-visitor-keys@2.1.0: resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} @@ -10475,9 +10804,12 @@ packages: /eslint-visitor-keys@3.4.1: resolution: {integrity: sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: false - /eslint-webpack-plugin@3.2.0(eslint@8.43.0)(webpack@5.87.0): + /eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + /eslint-webpack-plugin@3.2.0(eslint@8.50.0)(webpack@5.87.0): resolution: {integrity: sha512-avrKcGncpPbPSUHX6B3stNGzkKFto3eL+DKM4+VyMrVnhPc3vRczVlCq3uhuFOdRvDHTVXuzwk1ZKUrqDQHQ9w==} engines: {node: '>= 12.13.0'} peerDependencies: @@ -10485,7 +10817,7 @@ packages: webpack: ^5.0.0 dependencies: '@types/eslint': 8.40.2 - eslint: 8.43.0 + eslint: 8.50.0 jest-worker: 28.1.3 micromatch: 4.0.5 normalize-path: 3.0.0 @@ -10493,16 +10825,16 @@ packages: webpack: 5.87.0 dev: false - /eslint@8.43.0: - resolution: {integrity: sha512-aaCpf2JqqKesMFGgmRPessmVKjcGXqdlAYLLC3THM8t5nBRZRQ+st5WM/hoJXkdioEXLLbXgclUpM0TXo5HX5Q==} + /eslint@8.50.0: + resolution: {integrity: sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} hasBin: true dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.43.0) - '@eslint-community/regexpp': 4.5.1 - '@eslint/eslintrc': 2.0.3 - '@eslint/js': 8.43.0 - '@humanwhocodes/config-array': 0.11.10 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.50.0) + '@eslint-community/regexpp': 4.9.0 + '@eslint/eslintrc': 2.1.2 + '@eslint/js': 8.50.0 + '@humanwhocodes/config-array': 0.11.11 '@humanwhocodes/module-importer': 1.0.1 '@nodelib/fs.walk': 1.2.8 ajv: 6.12.6 @@ -10511,9 +10843,9 @@ packages: debug: 4.3.4(supports-color@8.1.1) doctrine: 3.0.0 escape-string-regexp: 4.0.0 - eslint-scope: 7.2.0 - eslint-visitor-keys: 3.4.1 - espree: 9.5.2 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 esquery: 1.5.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 @@ -10523,7 +10855,6 @@ packages: globals: 13.20.0 graphemer: 1.4.0 ignore: 5.2.4 - import-fresh: 3.3.0 imurmurhash: 0.1.4 is-glob: 4.0.3 is-path-inside: 3.0.3 @@ -10533,13 +10864,11 @@ packages: lodash.merge: 4.6.2 minimatch: 3.1.2 natural-compare: 1.4.0 - optionator: 0.9.1 + optionator: 0.9.3 strip-ansi: 6.0.1 - strip-json-comments: 3.1.1 text-table: 0.2.0 transitivePeerDependencies: - supports-color - dev: false /esm@3.2.25: resolution: {integrity: sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==} @@ -10547,14 +10876,13 @@ packages: requiresBuild: true optional: true - /espree@9.5.2: - resolution: {integrity: sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==} + /espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: acorn: 8.10.0 acorn-jsx: 5.3.2(acorn@8.10.0) - eslint-visitor-keys: 3.4.1 - dev: false + eslint-visitor-keys: 3.4.3 /esprima@2.7.3: resolution: {integrity: sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A==} @@ -10572,14 +10900,12 @@ packages: engines: {node: '>=0.10'} dependencies: estraverse: 5.3.0 - dev: false /esrecurse@4.3.0: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} engines: {node: '>=4.0'} dependencies: estraverse: 5.3.0 - dev: false /estraverse@1.9.3: resolution: {integrity: sha512-25w1fMXQrGdoquWnScXZGckOv+Wes+JDnuN/+7ex3SauFRS72r2lFDec0EKPt2YD1wUJ/IrfEex+9yp4hfSOJA==} @@ -11031,7 +11357,6 @@ packages: engines: {node: ^10.12.0 || >=12.0.0} dependencies: flat-cache: 3.0.4 - dev: false /file-loader@6.2.0(webpack@5.87.0): resolution: {integrity: sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==} @@ -11164,7 +11489,6 @@ packages: dependencies: flatted: 3.2.7 rimraf: 3.0.2 - dev: false /flat@4.1.1: resolution: {integrity: sha512-FmTtBsHskrU6FJ2VxCnsDb84wu9zhmO3cUX2kGFb5tuwhfXxGciiT0oRY+cck35QmG+NmGh5eLz6lLCpWTqwpA==} @@ -11180,7 +11504,6 @@ packages: /flatted@3.2.7: resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} - dev: false /follow-redirects@1.15.2(debug@4.3.4): resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==} @@ -11202,7 +11525,7 @@ packages: resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==} dev: true - /fork-ts-checker-webpack-plugin@6.5.3(eslint@8.43.0)(typescript@4.9.5)(webpack@5.87.0): + /fork-ts-checker-webpack-plugin@6.5.3(eslint@8.50.0)(typescript@5.1.6)(webpack@5.87.0): resolution: {integrity: sha512-SbH/l9ikmMWycd5puHJKTkZJKddF4iRLyW3DeZ08HTI7NGyLS38MXd/KGgeWumQO7YNQbW2u/NtPT2YowbPaGQ==} engines: {node: '>=10', yarn: '>=1.0.0'} peerDependencies: @@ -11222,7 +11545,7 @@ packages: chokidar: 3.5.3 cosmiconfig: 6.0.0 deepmerge: 4.3.1 - eslint: 8.43.0 + eslint: 8.50.0 fs-extra: 9.1.0 glob: 7.2.3 memfs: 3.5.3 @@ -11230,7 +11553,7 @@ packages: schema-utils: 2.7.0 semver: 7.5.4 tapable: 1.1.3 - typescript: 4.9.5 + typescript: 5.1.6 webpack: 5.87.0 dev: false @@ -11405,6 +11728,16 @@ packages: es-abstract: 1.21.2 functions-have-names: 1.2.3 + /function.prototype.name@1.1.6: + resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.22.2 + functions-have-names: 1.2.3 + dev: true + /functional-red-black-tree@1.0.1: resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} dev: true @@ -11517,7 +11850,6 @@ packages: engines: {node: '>=10.13.0'} dependencies: is-glob: 4.0.3 - dev: false /glob-to-regexp@0.4.1: resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} @@ -11617,7 +11949,6 @@ packages: engines: {node: '>=8'} dependencies: type-fest: 0.20.2 - dev: false /globalthis@1.0.3: resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} @@ -11723,7 +12054,6 @@ packages: /graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - dev: false /growl@1.10.5: resolution: {integrity: sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==} @@ -11775,13 +12105,13 @@ packages: dependencies: array-uniq: 1.0.3 eth-gas-reporter: 0.2.25 - hardhat: 2.15.0(ts-node@10.9.1)(typescript@4.7.2) + hardhat: 2.15.0(ts-node@10.9.1)(typescript@5.1.6) sha1: 1.1.1 transitivePeerDependencies: - '@codechecks/client' dev: true - /hardhat@2.15.0(ts-node@10.9.1)(typescript@4.7.2): + /hardhat@2.15.0(ts-node@10.9.1)(typescript@5.1.6): resolution: {integrity: sha512-cC9tM/N10YaES04zPOp7yR13iX3YibqaNmi0//Ep40Nt9ELIJx3kFpQmucur0PAIfXYpGnw5RuXHNLkxpnVHEw==} engines: {node: '>=14.0.0'} hasBin: true @@ -11840,9 +12170,9 @@ packages: solc: 0.7.3(debug@4.3.4) source-map-support: 0.5.21 stacktrace-parser: 0.1.10 - ts-node: 10.9.1(@types/node@20.7.0)(typescript@4.7.2) + ts-node: 10.9.1(@types/node@20.7.0)(typescript@5.1.6) tsort: 0.0.1 - typescript: 4.7.2 + typescript: 5.1.6 undici: 5.22.1 uuid: 8.3.2 ws: 7.5.9 @@ -12739,12 +13069,6 @@ packages: resolution: {integrity: sha512-YttjnrswnUYRVJvxCvu8z+PGMUSzC2JttP0OEXezlAEdp3EXzhf7IZ3j0gRAybJBQupedIZFhY61Tga6E0qASA==} dev: true - /is-core-module@2.12.1: - resolution: {integrity: sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==} - dependencies: - has: 1.0.3 - dev: false - /is-core-module@2.13.0: resolution: {integrity: sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==} dependencies: @@ -12877,7 +13201,6 @@ packages: /is-path-inside@3.0.3: resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} engines: {node: '>=8'} - dev: false /is-plain-obj@2.1.0: resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} @@ -12953,6 +13276,13 @@ packages: gopd: 1.0.1 has-tostringtag: 1.0.0 + /is-typed-array@1.1.12: + resolution: {integrity: sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==} + engines: {node: '>= 0.4'} + dependencies: + which-typed-array: 1.1.11 + dev: true + /is-typedarray@1.0.0: resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} @@ -13543,7 +13873,7 @@ packages: pretty-format: 27.5.1 slash: 3.0.0 strip-json-comments: 3.1.1 - ts-node: 10.9.1(@types/node@18.13.0)(typescript@4.7.2) + ts-node: 10.9.1(@types/node@18.13.0)(typescript@5.1.6) transitivePeerDependencies: - bufferutil - canvas @@ -14094,7 +14424,6 @@ packages: /json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - dev: false /json-stringify-safe@5.0.1: resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} @@ -14112,7 +14441,6 @@ packages: hasBin: true dependencies: minimist: 1.2.8 - dev: false /json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} @@ -14274,7 +14602,6 @@ packages: dependencies: prelude-ls: 1.2.1 type-check: 0.4.0 - dev: false /libp2p-crypto@0.19.7: resolution: {integrity: sha512-Qb5o/3WFKF2j6mYSt4UBPyi2kbKl3jYV0podBJoJCw70DlpM5Xc+oh3fFY9ToSunu8aSQQ5GY8nutjXgX/uGRA==} @@ -14592,7 +14919,6 @@ packages: /lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - dev: false /lodash.sortby@4.7.0: resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} @@ -15765,7 +16091,6 @@ packages: call-bind: 1.0.2 define-properties: 1.2.0 es-abstract: 1.21.2 - dev: false /object.getownpropertydescriptors@2.1.6: resolution: {integrity: sha512-lq+61g26E/BgHv0ZTFgRvi7NMEPuAxLkFU7rukXjc/AlwH4Am5xXVnIXy3un1bg/JPbXHrixRkK1itUzzPiIjQ==} @@ -15777,6 +16102,15 @@ packages: es-abstract: 1.21.2 safe-array-concat: 1.0.0 + /object.groupby@1.0.1: + resolution: {integrity: sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==} + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.22.2 + get-intrinsic: 1.2.1 + dev: true + /object.hasown@1.1.2: resolution: {integrity: sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==} dependencies: @@ -15791,7 +16125,6 @@ packages: call-bind: 1.0.2 define-properties: 1.2.0 es-abstract: 1.21.2 - dev: false /obliterator@2.0.4: resolution: {integrity: sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==} @@ -15877,17 +16210,16 @@ packages: word-wrap: 1.2.3 dev: true - /optionator@0.9.1: - resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==} + /optionator@0.9.3: + resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} engines: {node: '>= 0.8.0'} dependencies: + '@aashutoshrathi/word-wrap': 1.2.6 deep-is: 0.1.4 fast-levenshtein: 2.0.6 levn: 0.4.1 prelude-ls: 1.2.1 type-check: 0.4.0 - word-wrap: 1.2.3 - dev: false /ora@5.4.1: resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} @@ -16692,7 +17024,7 @@ packages: dependencies: lilconfig: 2.1.0 postcss: 8.4.24 - ts-node: 10.9.1(@types/node@18.13.0)(typescript@4.7.2) + ts-node: 10.9.1(@types/node@18.13.0)(typescript@5.1.6) yaml: 2.3.1 dev: false @@ -16706,7 +17038,7 @@ packages: cosmiconfig: 7.1.0 klona: 2.0.6 postcss: 8.4.24 - semver: 7.5.2 + semver: 7.5.4 webpack: 5.87.0 dev: false @@ -17175,7 +17507,6 @@ packages: /prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - dev: false /prepend-http@2.0.0: resolution: {integrity: sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==} @@ -17188,6 +17519,12 @@ packages: hasBin: true dev: true + /prettier@3.0.3: + resolution: {integrity: sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==} + engines: {node: '>=14'} + hasBin: true + dev: true + /pretty-bytes@5.6.0: resolution: {integrity: sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==} engines: {node: '>=6'} @@ -17394,35 +17731,7 @@ packages: resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} engines: {node: '>=6'} - /puppeteer-core@19.7.2(typescript@4.7.2): - resolution: {integrity: sha512-PvI+fXqgP0uGJxkyZcX51bnzjFA73MODZOAv0fSD35yR7tvbqwtMV3/Y+hxQ0AMMwzxkEebP6c7po/muqxJvmQ==} - engines: {node: '>=14.1.0'} - peerDependencies: - typescript: '>= 4.7.4' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - chromium-bidi: 0.4.4(devtools-protocol@0.0.1094867) - cross-fetch: 3.1.5 - debug: 4.3.4(supports-color@8.1.1) - devtools-protocol: 0.0.1094867 - extract-zip: 2.0.1 - https-proxy-agent: 5.0.1 - proxy-from-env: 1.1.0 - rimraf: 3.0.2 - tar-fs: 2.1.1 - typescript: 4.7.2 - unbzip2-stream: 1.4.3 - ws: 8.11.0 - transitivePeerDependencies: - - bufferutil - - encoding - - supports-color - - utf-8-validate - dev: true - - /puppeteer-core@19.7.2(typescript@4.9.5): + /puppeteer-core@19.7.2(typescript@5.1.6): resolution: {integrity: sha512-PvI+fXqgP0uGJxkyZcX51bnzjFA73MODZOAv0fSD35yR7tvbqwtMV3/Y+hxQ0AMMwzxkEebP6c7po/muqxJvmQ==} engines: {node: '>=14.1.0'} peerDependencies: @@ -17440,7 +17749,7 @@ packages: proxy-from-env: 1.1.0 rimraf: 3.0.2 tar-fs: 2.1.1 - typescript: 4.9.5 + typescript: 5.1.6 unbzip2-stream: 1.4.3 ws: 8.11.0 transitivePeerDependencies: @@ -17450,25 +17759,7 @@ packages: - utf-8-validate dev: true - /puppeteer@19.7.2(typescript@4.7.2): - resolution: {integrity: sha512-4Lm7Qpe/LU95Svirei/jDLDvR5oMrl9BPGd7HMY5+Q28n+BhvKuW97gKkR+1LlI86bO8J3g8rG/Ll5kv9J1nlQ==} - engines: {node: '>=14.1.0'} - requiresBuild: true - dependencies: - cosmiconfig: 8.0.0 - https-proxy-agent: 5.0.1 - progress: 2.0.3 - proxy-from-env: 1.1.0 - puppeteer-core: 19.7.2(typescript@4.7.2) - transitivePeerDependencies: - - bufferutil - - encoding - - supports-color - - typescript - - utf-8-validate - dev: true - - /puppeteer@19.7.2(typescript@4.9.5): + /puppeteer@19.7.2(typescript@5.1.6): resolution: {integrity: sha512-4Lm7Qpe/LU95Svirei/jDLDvR5oMrl9BPGd7HMY5+Q28n+BhvKuW97gKkR+1LlI86bO8J3g8rG/Ll5kv9J1nlQ==} engines: {node: '>=14.1.0'} requiresBuild: true @@ -17477,7 +17768,7 @@ packages: https-proxy-agent: 5.0.1 progress: 2.0.3 proxy-from-env: 1.1.0 - puppeteer-core: 19.7.2(typescript@4.9.5) + puppeteer-core: 19.7.2(typescript@5.1.6) transitivePeerDependencies: - bufferutil - encoding @@ -17612,7 +17903,7 @@ packages: whatwg-fetch: 3.6.2 dev: false - /react-dev-utils@12.0.1(eslint@8.43.0)(typescript@4.9.5)(webpack@5.87.0): + /react-dev-utils@12.0.1(eslint@8.50.0)(typescript@5.1.6)(webpack@5.87.0): resolution: {integrity: sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==} engines: {node: '>=14'} peerDependencies: @@ -17631,7 +17922,7 @@ packages: escape-string-regexp: 4.0.0 filesize: 8.0.7 find-up: 5.0.0 - fork-ts-checker-webpack-plugin: 6.5.3(eslint@8.43.0)(typescript@4.9.5)(webpack@5.87.0) + fork-ts-checker-webpack-plugin: 6.5.3(eslint@8.50.0)(typescript@5.1.6)(webpack@5.87.0) global-modules: 2.0.0 globby: 11.1.0 gzip-size: 6.0.0 @@ -17646,7 +17937,7 @@ packages: shell-quote: 1.8.1 strip-ansi: 6.0.1 text-table: 0.2.0 - typescript: 4.9.5 + typescript: 5.1.6 webpack: 5.87.0 transitivePeerDependencies: - eslint @@ -17696,7 +17987,7 @@ packages: engines: {node: '>=0.10.0'} dev: false - /react-scripts@5.0.1(@babel/plugin-syntax-flow@7.22.5)(@babel/plugin-transform-react-jsx@7.22.5)(eslint@8.43.0)(react@18.2.0)(ts-node@10.9.1)(typescript@4.9.5): + /react-scripts@5.0.1(@babel/plugin-syntax-flow@7.22.5)(@babel/plugin-transform-react-jsx@7.22.5)(eslint@8.50.0)(react@18.2.0)(ts-node@10.9.1)(typescript@5.1.6): resolution: {integrity: sha512-8VAmEm/ZAwQzJ+GOMLbBsTdDKOpuZh7RPs0UymvBR2vRk4iZWCskjbFnxqjrzoIvlNNRZ3QJFx6/qDSi6zSnaQ==} engines: {node: '>=14.0.0'} hasBin: true @@ -17723,9 +18014,9 @@ packages: css-minimizer-webpack-plugin: 3.4.1(webpack@5.87.0) dotenv: 10.0.0 dotenv-expand: 5.1.0 - eslint: 8.43.0 - eslint-config-react-app: 7.0.1(@babel/plugin-syntax-flow@7.22.5)(@babel/plugin-transform-react-jsx@7.22.5)(eslint@8.43.0)(jest@27.5.1)(typescript@4.9.5) - eslint-webpack-plugin: 3.2.0(eslint@8.43.0)(webpack@5.87.0) + eslint: 8.50.0 + eslint-config-react-app: 7.0.1(@babel/plugin-syntax-flow@7.22.5)(@babel/plugin-transform-react-jsx@7.22.5)(eslint@8.50.0)(jest@27.5.1)(typescript@5.1.6) + eslint-webpack-plugin: 3.2.0(eslint@8.50.0)(webpack@5.87.0) file-loader: 6.2.0(webpack@5.87.0) fs-extra: 10.1.0 html-webpack-plugin: 5.5.3(webpack@5.87.0) @@ -17742,7 +18033,7 @@ packages: prompts: 2.4.2 react: 18.2.0 react-app-polyfill: 3.0.0 - react-dev-utils: 12.0.1(eslint@8.43.0)(typescript@4.9.5)(webpack@5.87.0) + react-dev-utils: 12.0.1(eslint@8.50.0)(typescript@5.1.6)(webpack@5.87.0) react-refresh: 0.11.0 resolve: 1.22.2 resolve-url-loader: 4.0.0 @@ -17752,7 +18043,7 @@ packages: style-loader: 3.3.3(webpack@5.87.0) tailwindcss: 3.3.2(ts-node@10.9.1) terser-webpack-plugin: 5.3.9(webpack@5.87.0) - typescript: 4.9.5 + typescript: 5.1.6 webpack: 5.87.0 webpack-dev-server: 4.15.1(webpack@5.87.0) webpack-manifest-plugin: 4.1.1(webpack@5.87.0) @@ -17913,6 +18204,15 @@ packages: define-properties: 1.2.0 functions-have-names: 1.2.3 + /regexp.prototype.flags@1.5.1: + resolution: {integrity: sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + set-function-name: 2.0.1 + dev: true + /regexpu-core@5.3.2: resolution: {integrity: sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==} engines: {node: '>=4'} @@ -18028,6 +18328,11 @@ packages: resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} dev: true + /requireindex@1.2.0: + resolution: {integrity: sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==} + engines: {node: '>=0.10.5'} + dev: true + /requires-port@1.0.0: resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} @@ -18091,7 +18396,7 @@ packages: resolution: {integrity: sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==} hasBin: true dependencies: - is-core-module: 2.12.1 + is-core-module: 2.13.0 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 dev: false @@ -18250,6 +18555,16 @@ packages: has-symbols: 1.0.3 isarray: 2.0.5 + /safe-array-concat@1.0.1: + resolution: {integrity: sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==} + engines: {node: '>=0.4'} + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.2.1 + has-symbols: 1.0.3 + isarray: 2.0.5 + dev: true + /safe-buffer@5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} @@ -18425,11 +18740,6 @@ packages: hasBin: true dev: true - /semver@6.3.0: - resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} - hasBin: true - dev: false - /semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true @@ -18547,6 +18857,15 @@ packages: resolution: {integrity: sha512-29fhAwuZlLcuBnW/EwxvLcg2D3ELX+VBDNhnavs3YYkab72qmrcSeQNVdzl8EcPPahGQXhBM6MKdPLCQGMDakw==} dev: true + /set-function-name@2.0.1: + resolution: {integrity: sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.0 + dev: true + /setimmediate@1.0.4: resolution: {integrity: sha512-/TjEmXQVEzdod/FFskf3o7oOAsGhHf2j1dZqRFbDzq4F3mvvxflIIi4Hd3bLQE9y/CpwqfSQam5JakI/mi3Pog==} dev: true @@ -19020,6 +19339,15 @@ packages: define-properties: 1.2.0 es-abstract: 1.21.2 + /string.prototype.trim@1.2.8: + resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.22.2 + dev: true + /string.prototype.trimend@1.0.6: resolution: {integrity: sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==} dependencies: @@ -19027,6 +19355,14 @@ packages: define-properties: 1.2.0 es-abstract: 1.21.2 + /string.prototype.trimend@1.0.7: + resolution: {integrity: sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==} + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.22.2 + dev: true + /string.prototype.trimstart@1.0.6: resolution: {integrity: sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==} dependencies: @@ -19034,6 +19370,14 @@ packages: define-properties: 1.2.0 es-abstract: 1.21.2 + /string.prototype.trimstart@1.0.7: + resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==} + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.22.2 + dev: true + /string_decoder@1.1.1: resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} dependencies: @@ -19082,7 +19426,6 @@ packages: /strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} - dev: false /strip-bom@4.0.0: resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} @@ -19461,7 +19804,6 @@ packages: /text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - dev: false /then-request@6.0.2: resolution: {integrity: sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==} @@ -19643,6 +19985,15 @@ packages: resolution: {integrity: sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==} dev: false + /ts-api-utils@1.0.3(typescript@5.1.6): + resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==} + engines: {node: '>=16.13.0'} + peerDependencies: + typescript: '>=4.2.0' + dependencies: + typescript: 5.1.6 + dev: true + /ts-command-line-args@2.5.1: resolution: {integrity: sha512-H69ZwTw3rFHb5WYpQya40YAX2/w7Ut75uUECbgBIsLmM+BNuYnxsltfyyLMxy6sEeKxgijLTnQtLd0nKd6+IYw==} hasBin: true @@ -19653,19 +20004,19 @@ packages: string-format: 2.0.0 dev: true - /ts-essentials@7.0.3(typescript@4.7.2): + /ts-essentials@7.0.3(typescript@5.1.6): resolution: {integrity: sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ==} peerDependencies: typescript: '>=3.7.0' dependencies: - typescript: 4.7.2 + typescript: 5.1.6 dev: true /ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} dev: false - /ts-jest@27.1.5(jest@27.5.1)(typescript@4.7.2): + /ts-jest@27.1.5(jest@27.5.1)(typescript@5.1.6): resolution: {integrity: sha512-Xv6jBQPoBEvBq/5i2TeSG9tt/nqkbpcurrEG1b+2yfBrcJelOZF9Ml6dmyMh7bcW9JyFbRYpR5rxROSlBLTZHA==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} hasBin: true @@ -19694,11 +20045,11 @@ packages: lodash.memoize: 4.1.2 make-error: 1.3.6 semver: 7.5.4 - typescript: 4.7.2 + typescript: 5.1.6 yargs-parser: 20.2.9 dev: true - /ts-node@10.9.1(@types/node@18.13.0)(typescript@4.7.2): + /ts-node@10.9.1(@types/node@18.13.0)(typescript@5.1.6): resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} hasBin: true peerDependencies: @@ -19724,11 +20075,11 @@ packages: create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 4.7.2 + typescript: 5.1.6 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 - /ts-node@10.9.1(@types/node@20.7.0)(typescript@4.7.2): + /ts-node@10.9.1(@types/node@20.7.0)(typescript@5.1.6): resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} hasBin: true peerDependencies: @@ -19748,13 +20099,13 @@ packages: '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 '@types/node': 20.7.0 - acorn: 8.9.0 + acorn: 8.10.0 acorn-walk: 8.2.0 arg: 4.1.3 create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 4.7.2 + typescript: 5.1.6 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 dev: true @@ -19766,7 +20117,7 @@ packages: resolution: {integrity: sha512-tL0w8U/pgaacOmkb9fRlYzWEUDCfVjjv9dD4wHTgZ61MjhuMt46VNWTG747NqW6vRzoWIKABVhFSOJ82FvXrfA==} dev: false - /tsconfck@2.1.1(typescript@4.7.2): + /tsconfck@2.1.1(typescript@5.1.6): resolution: {integrity: sha512-ZPCkJBKASZBmBUNqGHmRhdhM8pJYDdOXp4nRgj/O0JwUwsMq50lCDRQP/M5GBNAA0elPrq4gAeu4dkaVCuKWww==} engines: {node: ^14.13.1 || ^16 || >=18} hasBin: true @@ -19776,7 +20127,7 @@ packages: typescript: optional: true dependencies: - typescript: 4.7.2 + typescript: 5.1.6 dev: true /tsconfig-paths@3.14.2: @@ -19786,7 +20137,6 @@ packages: json5: 1.0.2 minimist: 1.2.8 strip-bom: 3.0.0 - dev: false /tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} @@ -19798,14 +20148,14 @@ packages: resolution: {integrity: sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==} dev: true - /tsutils@3.21.0(typescript@4.9.5): + /tsutils@3.21.0(typescript@5.1.6): resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} peerDependencies: typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' dependencies: tslib: 1.14.1 - typescript: 4.9.5 + typescript: 5.1.6 dev: false /tty-browserify@0.0.1: @@ -19842,7 +20192,6 @@ packages: engines: {node: '>= 0.8.0'} dependencies: prelude-ls: 1.2.1 - dev: false /type-detect@4.0.8: resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} @@ -19856,7 +20205,6 @@ packages: /type-fest@0.20.2: resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} engines: {node: '>=10'} - dev: false /type-fest@0.21.3: resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} @@ -19882,7 +20230,7 @@ packages: resolution: {integrity: sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==} dev: true - /typechain@8.2.0(typescript@4.7.2): + /typechain@8.2.0(typescript@5.1.6): resolution: {integrity: sha512-tZqhqjxJ9xAS/Lh32jccTjMkpx7sTdUVVHAy5Bf0TIer5QFNYXotiX74oCvoVYjyxUKDK3MXHtMFzMyD3kE+jg==} hasBin: true peerDependencies: @@ -19897,12 +20245,42 @@ packages: mkdirp: 1.0.4 prettier: 2.8.8 ts-command-line-args: 2.5.1 - ts-essentials: 7.0.3(typescript@4.7.2) - typescript: 4.7.2 + ts-essentials: 7.0.3(typescript@5.1.6) + typescript: 5.1.6 transitivePeerDependencies: - supports-color dev: true + /typed-array-buffer@1.0.0: + resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.2.1 + is-typed-array: 1.1.12 + dev: true + + /typed-array-byte-length@1.0.0: + resolution: {integrity: sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + for-each: 0.3.3 + has-proto: 1.0.1 + is-typed-array: 1.1.12 + dev: true + + /typed-array-byte-offset@1.0.0: + resolution: {integrity: sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.5 + call-bind: 1.0.2 + for-each: 0.3.3 + has-proto: 1.0.1 + is-typed-array: 1.1.12 + dev: true + /typed-array-length@1.0.4: resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} dependencies: @@ -19919,21 +20297,10 @@ packages: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} dev: true - /typescript@4.7.2: - resolution: {integrity: sha512-Mamb1iX2FDUpcTRzltPxgWMKy3fhg0TN378ylbktPGPK/99KbDtMQ4W1hwgsbPAsG3a0xKa1vmw4VKZQbkvz5A==} - engines: {node: '>=4.2.0'} - hasBin: true - - /typescript@4.9.5: - resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} - engines: {node: '>=4.2.0'} - hasBin: true - /typescript@5.1.6: resolution: {integrity: sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==} engines: {node: '>=14.17'} hasBin: true - dev: true /typical@4.0.0: resolution: {integrity: sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==} @@ -20279,14 +20646,14 @@ packages: - terser dev: true - /vite-tsconfig-paths@4.0.3(typescript@4.7.2)(vite@4.0.4): + /vite-tsconfig-paths@4.0.3(typescript@5.1.6)(vite@4.0.4): resolution: {integrity: sha512-gRO2Q/tOkV+9kMht5tz90+IaEKvW2zCnvwJV3tp2ruPNZOTM5rF+yXorJT4ggmAMYEaJ3nyXjx5P5jY5FwiZ+A==} peerDependencies: vite: '>2.0.0-0' dependencies: debug: 4.3.4(supports-color@8.1.1) globrex: 0.1.2 - tsconfck: 2.1.1(typescript@4.7.2) + tsconfck: 2.1.1(typescript@5.1.6) vite: 4.0.4(@types/node@20.7.0) transitivePeerDependencies: - supports-color @@ -21260,6 +21627,17 @@ packages: resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} dev: true + /which-typed-array@1.1.11: + resolution: {integrity: sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.5 + call-bind: 1.0.2 + for-each: 0.3.3 + gopd: 1.0.1 + has-tostringtag: 1.0.0 + dev: true + /which-typed-array@1.1.9: resolution: {integrity: sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==} engines: {node: '>= 0.4'} @@ -21309,6 +21687,7 @@ packages: /word-wrap@1.2.3: resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==} engines: {node: '>=0.10.0'} + dev: true /wordwrap@1.0.0: resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} diff --git a/reset.d.ts b/reset.d.ts new file mode 100644 index 000000000..e186b1ff0 --- /dev/null +++ b/reset.d.ts @@ -0,0 +1 @@ +import "@total-typescript/ts-reset"; \ No newline at end of file diff --git a/resources/license-header.js b/resources/license-header.js new file mode 100644 index 000000000..7dae4dad4 --- /dev/null +++ b/resources/license-header.js @@ -0,0 +1,15 @@ +/** + * 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. + */ diff --git a/tsconfig.json b/tsconfig.json index 016ecc546..ab0634aca 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,13 +1,10 @@ { + "extends": "@tsconfig/strictest/tsconfig.json", "compilerOptions": { - "lib": ["es2015", "dom"], + "lib": ["es2023", "dom"], "outDir": "./dist/", "target": "ESNext", "module": "ESNext", - "skipLibCheck": true, - "strict": true, - "forceConsistentCasingInFileNames": true, - "allowJs": true, "esModuleInterop": true, "declaration": true, "moduleResolution": "nodenext" From c6abda168abb6f5fece8d21f1feab4f0b3037cf6 Mon Sep 17 00:00:00 2001 From: Akim Mamedov Date: Fri, 6 Oct 2023 17:21:19 +0700 Subject: [PATCH 02/45] Fix all eslint errors --- .eslintrc.json | 23 +- .gitignore | 1 + package.json | 2 +- packages/@tests/.eslintrc.json | 8 + packages/@tests/aqua/_aqua/smoke_test.aqua | 3 + packages/@tests/aqua/src/_aqua/smoke_test.ts | 117 +++++++++ packages/@tests/aqua/src/index.ts | 2 +- packages/@tests/smoke/node/src/index.ts | 2 +- packages/@tests/smoke/web/src/index.ts | 4 +- packages/@tests/test-utils/src/index.ts | 2 +- packages/core/aqua-to-js/.eslintrc.json | 5 + packages/core/aqua-to-js/src/common.ts | 14 +- packages/core/aqua-to-js/src/future.ts | 75 ------ .../src/generate/__test__/generate.spec.ts | 6 +- .../core/aqua-to-js/src/generate/index.ts | 6 +- .../aqua-to-js/src/generate/interfaces.ts | 6 +- .../core/aqua-to-js/src/generate/service.ts | 13 +- packages/core/aqua-to-js/src/index.ts | 10 +- packages/core/aqua-to-js/src/utils.ts | 28 +- packages/core/interfaces/package.json | 3 +- packages/core/interfaces/src/commonTypes.ts | 25 +- .../compilerSupport/aquaTypeDefinitions.ts | 69 ++--- .../compilerSupportInterface.ts | 12 +- packages/core/interfaces/src/fluenceClient.ts | 2 +- packages/core/interfaces/src/future.ts | 90 +++++++ packages/core/interfaces/src/index.ts | 1 + packages/core/interfaces/src/utils.ts | 21 ++ packages/core/interfaces/tsconfig.json | 3 +- packages/core/js-client/package.json | 4 +- packages/core/js-client/src/api.ts | 116 ++++----- .../js-client/src/clientPeer/ClientPeer.ts | 20 +- .../src/clientPeer/__test__/client.spec.ts | 11 +- .../src/clientPeer/checkConnection.ts | 6 +- .../src/compilerSupport/__test__/v3.spec.ts | 9 +- .../src/compilerSupport/callFunction.ts | 28 +- .../src/compilerSupport/conversions.ts | 28 +- .../src/compilerSupport/registerService.ts | 21 +- .../js-client/src/compilerSupport/services.ts | 62 ++--- .../src/connection/RelayConnection.ts | 31 +-- .../src/ephemeral/__test__/ephemeral.spec.ts | 16 +- .../core/js-client/src/ephemeral/network.ts | 26 +- .../core/js-client/src/fetchers/browser.ts | 10 +- packages/core/js-client/src/fetchers/node.ts | 4 +- packages/core/js-client/src/index.ts | 56 ++-- .../core/js-client/src/jsPeer/FluencePeer.ts | 38 ++- .../js-client/src/jsPeer/__test__/avm.spec.ts | 17 +- .../js-client/src/jsPeer/__test__/par.spec.ts | 16 +- .../src/jsPeer/__test__/parseAst.spec.ts | 5 +- .../src/jsPeer/__test__/peer.spec.ts | 34 +-- .../src/jsServiceHost/JsServiceHost.ts | 2 +- .../js-client/src/jsServiceHost/interfaces.ts | 5 +- .../src/jsServiceHost/serviceUtils.ts | 8 +- .../src/keypair/__test__/KeyPair.spec.ts | 5 +- packages/core/js-client/src/keypair/index.ts | 5 +- .../src/marine/__test__/marine-js.spec.ts | 8 +- .../src/marine/deps-loader/common.ts | 43 ---- .../js-client/src/marine/deps-loader/node.ts | 11 +- .../js-client/src/marine/deps-loader/web.ts | 72 ------ .../core/js-client/src/marine/interfaces.ts | 15 +- .../src/marine/worker-script/workerLoader.ts | 7 +- .../core/js-client/src/marine/worker/index.ts | 31 ++- .../core/js-client/src/particle/Particle.ts | 56 ++-- .../core/js-client/src/services/NodeUtils.ts | 13 +- packages/core/js-client/src/services/Sig.ts | 27 +- .../js-client/src/services/SingleModuleSrv.ts | 7 +- .../core/js-client/src/services/Tracing.ts | 2 + .../services/__test__/builtInHandler.spec.ts | 75 ++++-- .../src/services/__test__/jsonBuiltin.spec.ts | 6 +- .../src/services/__test__/sigService.spec.ts | 68 +++-- .../src/services/__test__/srv.spec.ts | 18 +- .../src/services/_aqua/node-utils.ts | 12 +- .../js-client/src/services/_aqua/services.ts | 12 +- .../src/services/_aqua/single-module-srv.ts | 12 +- .../js-client/src/services/_aqua/tracing.ts | 12 +- .../core/js-client/src/services/builtins.ts | 242 ++++++++++++------ .../js-client/src/services/securityGuard.ts | 2 +- .../core/js-client/src/util/commonTypes.ts | 12 +- .../core/js-client/src/util/libp2pUtils.ts | 2 +- .../core/js-client/src/util/loadClient.ts | 89 ------- packages/core/js-client/src/util/logger.ts | 2 +- packages/core/js-client/src/util/testUtils.ts | 32 ++- packages/core/js-client/src/util/utils.ts | 8 + packages/core/marine-worker/package.json | 4 +- packages/core/marine-worker/src/index.ts | 43 ++-- pnpm-lock.yaml | 32 ++- reset.d.ts | 16 ++ tsconfig.eslint.json | 4 + tsconfig.json | 6 +- 88 files changed, 1190 insertions(+), 947 deletions(-) create mode 100644 packages/@tests/.eslintrc.json create mode 100644 packages/core/aqua-to-js/.eslintrc.json delete mode 100644 packages/core/aqua-to-js/src/future.ts create mode 100644 packages/core/interfaces/src/future.ts create mode 100644 packages/core/interfaces/src/utils.ts delete mode 100644 packages/core/js-client/src/marine/deps-loader/common.ts delete mode 100644 packages/core/js-client/src/marine/deps-loader/web.ts delete mode 100644 packages/core/js-client/src/util/loadClient.ts create mode 100644 tsconfig.eslint.json diff --git a/.eslintrc.json b/.eslintrc.json index 5aaa57f71..c13d62fbf 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -3,10 +3,9 @@ "parserOptions": { "ecmaVersion": 2022, "project": [ - "./tsconfig.json", - "./tsconfig.eslint.json", - "./test/tsconfig.json" - ] + "./tsconfig.eslint.json" + ], + "sourceType": "module" }, "extends": [ "eslint:recommended", @@ -22,10 +21,17 @@ "license-header", "unused-imports" ], + "ignorePatterns": [ + "**/node_modules/**/*", + "**/dist/**/*" + ], "rules": { "eqeqeq": [ "error", - "always" + "always", + { + "null": "ignore" + } ], "no-console": [ "error" @@ -40,11 +46,6 @@ "allowEmptyCatch": true } ], - "no-plusplus": "error", - "operator-assignment": [ - "error", - "never" - ], "curly": [ "error", "all" @@ -109,7 +110,7 @@ ], "import/extensions": [ "error", - "always" + "ignorePackages" ], "import/no-unresolved": "off", "import/no-cycle": [ diff --git a/.gitignore b/.gitignore index 4ab831252..9ce219d1d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ *.log .idea +.eslintcache # Dependency directories node_modules/ diff --git a/package.json b/package.json index 57e671d97..e54ece19c 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "lint-check": "pnpm run prettier --check && pnpm run eslint", "lint-fix": "pnpm run prettier --write && pnpm run eslint --fix", "prettier": "prettier \"**/src/**/*.{js,ts}\"", - "eslint": "eslint --ext .js,.ts --cache \"**/src/**\"" + "eslint": "eslint --cache \"**/src/**/*.{js,ts}\"" }, "author": "Fluence Labs", "license": "Apache-2.0", diff --git a/packages/@tests/.eslintrc.json b/packages/@tests/.eslintrc.json new file mode 100644 index 000000000..d8f2bc08d --- /dev/null +++ b/packages/@tests/.eslintrc.json @@ -0,0 +1,8 @@ +{ + "ignorePatterns": [ + "**/*.css" + ], + "rules": { + "no-console": "off" + } +} \ No newline at end of file diff --git a/packages/@tests/aqua/_aqua/smoke_test.aqua b/packages/@tests/aqua/_aqua/smoke_test.aqua index adfd9843c..e6520538b 100644 --- a/packages/@tests/aqua/_aqua/smoke_test.aqua +++ b/packages/@tests/aqua/_aqua/smoke_test.aqua @@ -53,3 +53,6 @@ func marineTest(wasm64: string) -> f64: <- res +func callHappy(a: string, b: f64, c: f64, d: string -> f64) -> f64: + res <- d("abc") + <- res diff --git a/packages/@tests/aqua/src/_aqua/smoke_test.ts b/packages/@tests/aqua/src/_aqua/smoke_test.ts index c098703eb..484c58867 100644 --- a/packages/@tests/aqua/src/_aqua/smoke_test.ts +++ b/packages/@tests/aqua/src/_aqua/smoke_test.ts @@ -700,6 +700,123 @@ export function helloTest(...args: any) { ); } +export const callHappy_script = ` + (seq + (seq + (seq + (seq + (seq + (call %init_peer_id% ("getDataSrv" "-relay-") [] -relay-) + (call %init_peer_id% ("getDataSrv" "a") [] a) + ) + (call %init_peer_id% ("getDataSrv" "b") [] b) + ) + (call %init_peer_id% ("getDataSrv" "c") [] c) + ) + (xor + (xor + (call %init_peer_id% ("callbackSrv" "d") ["abc"] init_call_res0) + (fail %last_error%) + ) + (call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 0]) + ) + ) + (call %init_peer_id% ("callbackSrv" "response") [init_call_res0]) + ) + `; + +export function callHappy( + a: string, + b: number, + c: number, + d: ( + arg0: string, + callParams: CallParams$$<"arg0">, + ) => number | Promise, + config?: { ttl?: number }, +): Promise; + +export function callHappy( + peer: IFluenceClient$$, + a: string, + b: number, + c: number, + d: ( + arg0: string, + callParams: CallParams$$<"arg0">, + ) => number | Promise, + config?: { ttl?: number }, +): Promise; + +export function callHappy(...args: any) { + return callFunction$$( + args, + { + functionName: "callHappy", + arrow: { + tag: "arrow", + domain: { + tag: "labeledProduct", + fields: { + a: { + tag: "scalar", + name: "string", + }, + b: { + tag: "scalar", + name: "f64", + }, + c: { + tag: "scalar", + name: "f64", + }, + d: { + tag: "arrow", + domain: { + tag: "unlabeledProduct", + items: [ + { + tag: "scalar", + name: "string", + }, + ], + }, + codomain: { + tag: "unlabeledProduct", + items: [ + { + tag: "scalar", + name: "f64", + }, + ], + }, + }, + }, + }, + codomain: { + tag: "unlabeledProduct", + items: [ + { + tag: "scalar", + name: "f64", + }, + ], + }, + }, + names: { + relay: "-relay-", + getDataSrv: "getDataSrv", + callbackSrv: "callbackSrv", + responseSrv: "callbackSrv", + responseFnName: "response", + errorHandlingSrv: "errorHandlingSrv", + errorFnName: "error", + }, + }, + callHappy_script, + ); +} + export const demo_calculation_script = ` (seq (seq diff --git a/packages/@tests/aqua/src/index.ts b/packages/@tests/aqua/src/index.ts index 81491472c..8a534aa8b 100644 --- a/packages/@tests/aqua/src/index.ts +++ b/packages/@tests/aqua/src/index.ts @@ -70,7 +70,7 @@ export const runTest = async (): Promise => { const relayPeerId = (await Fluence.getClient()).getRelayPeerId(); console.log("relay:", relayPeerId); - await registerHelloWorld({ + registerHelloWorld({ hello(str) { return "Hello, " + str + "!"; }, diff --git a/packages/@tests/smoke/node/src/index.ts b/packages/@tests/smoke/node/src/index.ts index 6b5cfc4e6..72a1924d5 100644 --- a/packages/@tests/smoke/node/src/index.ts +++ b/packages/@tests/smoke/node/src/index.ts @@ -17,6 +17,6 @@ import "@fluencelabs/js-client"; import { runTest } from "@test/aqua_for_test"; -runTest().then(() => { +void runTest().then(() => { return console.log("Smoke tests succeed!"); }); diff --git a/packages/@tests/smoke/web/src/index.ts b/packages/@tests/smoke/web/src/index.ts index 8e76ce5f9..08946ded1 100644 --- a/packages/@tests/smoke/web/src/index.ts +++ b/packages/@tests/smoke/web/src/index.ts @@ -66,11 +66,11 @@ const test = async () => { await browser.close(); await stopServer(localServer); - if (!content) { + if (content == null) { throw new Error("smoke test failed!"); } }; -test().then(() => { +void test().then(() => { return console.log("smoke tests succeed!"); }); diff --git a/packages/@tests/test-utils/src/index.ts b/packages/@tests/test-utils/src/index.ts index 7775954cd..9a8b4f7de 100644 --- a/packages/@tests/test-utils/src/index.ts +++ b/packages/@tests/test-utils/src/index.ts @@ -37,7 +37,7 @@ export const startContentServer = ( publicDir: string, ): Promise => { const server = createServer((request, response) => { - return handler(request, response, { + void handler(request, response, { public: publicDir, rewrites: [ { diff --git a/packages/core/aqua-to-js/.eslintrc.json b/packages/core/aqua-to-js/.eslintrc.json new file mode 100644 index 000000000..ec3836832 --- /dev/null +++ b/packages/core/aqua-to-js/.eslintrc.json @@ -0,0 +1,5 @@ +{ + "ignorePatterns": [ + "src/**/__snapshots__/**/*" + ] +} \ No newline at end of file diff --git a/packages/core/aqua-to-js/src/common.ts b/packages/core/aqua-to-js/src/common.ts index 04adfe77c..ba69fba76 100644 --- a/packages/core/aqua-to-js/src/common.ts +++ b/packages/core/aqua-to-js/src/common.ts @@ -14,17 +14,13 @@ * limitations under the License. */ -import { - ArrowWithoutCallbacks, - NonArrowType, - ProductType, -} from "@fluencelabs/interfaces"; +import { ArrowWithoutCallbacks, NonArrowType } from "@fluencelabs/interfaces"; import { match, P } from "ts-pattern"; import { getFuncArgs } from "./utils.js"; export function genTypeName( - t: NonArrowType | ProductType | ArrowWithoutCallbacks, + t: NonArrowType | ArrowWithoutCallbacks, name: string, ): readonly [string | undefined, string] { const genType = typeToTs(t); @@ -55,9 +51,7 @@ export function genTypeName( }); } -export function typeToTs( - t: NonArrowType | ArrowWithoutCallbacks | ProductType, -): string { +export function typeToTs(t: NonArrowType | ArrowWithoutCallbacks): string { return match(t) .with({ tag: "nil" }, () => { return "null"; @@ -119,7 +113,7 @@ export function typeToTs( }) .join(", ")}]`; }) - .with({ tag: "arrow" }, ({ tag, domain, codomain }) => { + .with({ tag: "arrow" }, ({ domain, codomain }) => { const retType = codomain.tag === "nil" ? "void" diff --git a/packages/core/aqua-to-js/src/future.ts b/packages/core/aqua-to-js/src/future.ts deleted file mode 100644 index 084c6dc18..000000000 --- a/packages/core/aqua-to-js/src/future.ts +++ /dev/null @@ -1,75 +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 { - ArrayType, - BottomType, - LabeledProductType, - NilType, - NonArrowType, - OptionType, - ScalarType, - StructType, - TopType, - UnlabeledProductType, -} from "@fluencelabs/interfaces"; - -// Type definitions for inferring ts types from air json definition -// In the future we may remove string type declaration and move to type inference. - -type GetTsTypeFromScalar = T["name"] extends - | "u8" - | "u16" - | "u32" - | "u64" - | "i8" - | "i16" - | "i32" - | "i64" - | "f32" - | "f64" - ? number - : T["name"] extends "bool" - ? boolean - : T["name"] extends "string" - ? string - : never; - -type MapTuple = { - [K in keyof T]: T[K] extends NonArrowType ? GetTsType : never; -}; - -type GetTsType = T extends NilType - ? null - : T extends ArrayType - ? GetTsType[] - : T extends StructType - ? { [K in keyof T]: GetTsType } - : T extends OptionType - ? GetTsType | null - : T extends ScalarType - ? GetTsTypeFromScalar - : T extends TopType - ? unknown - : T extends BottomType - ? never - : T extends Exclude, NilType> - ? MapTuple - : T extends Exclude, NilType> - ? H extends NonArrowType - ? { [K in keyof T["fields"]]: GetTsType } - : never - : never; diff --git a/packages/core/aqua-to-js/src/generate/__test__/generate.spec.ts b/packages/core/aqua-to-js/src/generate/__test__/generate.spec.ts index aa7172b72..d80ed7788 100644 --- a/packages/core/aqua-to-js/src/generate/__test__/generate.spec.ts +++ b/packages/core/aqua-to-js/src/generate/__test__/generate.spec.ts @@ -40,13 +40,13 @@ describe("Aqua to js/ts compiler", () => { }, }; - const jsResult = await generateSources(res, "js", pkg); - const jsTypes = await generateTypes(res, pkg); + const jsResult = generateSources(res, "js", pkg); + const jsTypes = generateTypes(res, pkg); expect(jsResult).toMatchSnapshot(); expect(jsTypes).toMatchSnapshot(); - const tsResult = await generateSources(res, "ts", pkg); + const tsResult = generateSources(res, "ts", pkg); expect(tsResult).toMatchSnapshot(); }); diff --git a/packages/core/aqua-to-js/src/generate/index.ts b/packages/core/aqua-to-js/src/generate/index.ts index 04043016b..9b1225dc6 100644 --- a/packages/core/aqua-to-js/src/generate/index.ts +++ b/packages/core/aqua-to-js/src/generate/index.ts @@ -32,7 +32,7 @@ const typeGenerators: Record = { ts: new TSTypeGenerator(), }; -export async function generateSources( +export function generateSources( { services, functions }: CompilationResult, outputType: OutputType, packageJson: PackageJson, @@ -56,7 +56,7 @@ ${generateFunctions(typeGenerator, functions)} }`; } -export async function generateTypes( +export function generateTypes( { services, functions }: CompilationResult, packageJson: PackageJson, ) { @@ -69,7 +69,7 @@ export async function generateTypes( .join("\n"); const generatedFunctions = Object.entries(functions) - .map(([funcName, funcDef]) => { + .map(([, funcDef]) => { return typeGenerator.funcType(funcDef); }) .join("\n"); diff --git a/packages/core/aqua-to-js/src/generate/interfaces.ts b/packages/core/aqua-to-js/src/generate/interfaces.ts index d4edecfa8..0ad409fd6 100644 --- a/packages/core/aqua-to-js/src/generate/interfaces.ts +++ b/packages/core/aqua-to-js/src/generate/interfaces.ts @@ -77,7 +77,7 @@ export class TSTypeGenerator implements TypeGenerator { return [ argsDesc.join("\n"), - resTypeDesc || "", + resTypeDesc ?? "", functionOverloads .flatMap((fo) => { return [ @@ -139,11 +139,11 @@ export class JSTypeGenerator implements TypeGenerator { return field; } - generic(field: string, type: string): string { + generic(field: string): string { return field; } - type(field: string, type: string): string { + type(field: string): string { return field; } diff --git a/packages/core/aqua-to-js/src/generate/service.ts b/packages/core/aqua-to-js/src/generate/service.ts index 5b5be2340..b81768d48 100644 --- a/packages/core/aqua-to-js/src/generate/service.ts +++ b/packages/core/aqua-to-js/src/generate/service.ts @@ -69,11 +69,16 @@ function generateRegisterServiceOverload( function serviceToJson(service: ServiceDef): string { return JSON.stringify( { - ...((service.defaultServiceId as DefaultServiceId)?.s_Some__f_value + // This assertion is required because aqua-api gives bad types + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + ...((service.defaultServiceId as DefaultServiceId) + ?.s_Some__f_value != null ? { - defaultServiceId: ( - service.defaultServiceId as DefaultServiceId - ).s_Some__f_value, + defaultServiceId: + // This assertion is required because aqua-api gives bad types + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + (service.defaultServiceId as DefaultServiceId) + .s_Some__f_value, } : {}), functions: recursiveRenameLaquaProps(service.functions), diff --git a/packages/core/aqua-to-js/src/index.ts b/packages/core/aqua-to-js/src/index.ts index 4df5b4bc5..33b23ca28 100644 --- a/packages/core/aqua-to-js/src/index.ts +++ b/packages/core/aqua-to-js/src/index.ts @@ -40,10 +40,12 @@ export default async function aquaToJs( return outputType === "js" ? { - sources: await generateSources(res, "js", packageJson), - types: await generateTypes(res, packageJson), + sources: generateSources(res, "js", packageJson), + types: generateTypes(res, packageJson), } - : ({ - sources: await generateSources(res, "ts", 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]); } diff --git a/packages/core/aqua-to-js/src/utils.ts b/packages/core/aqua-to-js/src/utils.ts index 2e4a6173b..f79314214 100644 --- a/packages/core/aqua-to-js/src/utils.ts +++ b/packages/core/aqua-to-js/src/utils.ts @@ -14,13 +14,18 @@ * limitations under the License. */ +import assert from "assert"; import { readFile } from "fs/promises"; import path from "path"; import { + ArrowType, ArrowWithoutCallbacks, - NonArrowType, - ProductType, + JSONValue, + LabeledProductType, + NilType, + SimpleTypes, + UnlabeledProductType, } from "@fluencelabs/interfaces"; export interface PackageJson { @@ -37,12 +42,17 @@ export async function getPackageJsonContent(): Promise { "utf-8", ); - return JSON.parse(content); + // TODO: Add validation here + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + return JSON.parse(content) as PackageJson; } export function getFuncArgs( - domain: ProductType, -): [string, NonArrowType | ArrowWithoutCallbacks][] { + domain: + | LabeledProductType> + | UnlabeledProductType + | NilType, +): [string, SimpleTypes | ArrowWithoutCallbacks][] { if (domain.tag === "labeledProduct") { return Object.entries(domain.fields).map(([label, type]) => { return [label, type]; @@ -56,7 +66,7 @@ export function getFuncArgs( } } -export function recursiveRenameLaquaProps(obj: unknown): unknown { +export function recursiveRenameLaquaProps(obj: JSONValue): unknown { if (typeof obj !== "object" || obj === null) { return obj; } @@ -79,11 +89,11 @@ export function recursiveRenameLaquaProps(obj: unknown): unknown { } } + assert(accessProp in obj); + return { ...acc, - [accessProp]: recursiveRenameLaquaProps( - obj[accessProp as keyof typeof obj], - ), + [accessProp]: recursiveRenameLaquaProps(obj[accessProp]), }; }, {}); } diff --git a/packages/core/interfaces/package.json b/packages/core/interfaces/package.json index 2c116ea4b..9333379dd 100644 --- a/packages/core/interfaces/package.json +++ b/packages/core/interfaces/package.json @@ -51,6 +51,7 @@ "devDependencies": { "@multiformats/multiaddr": "11.3.0", "@fluencelabs/avm": "0.48.0", - "@fluencelabs/marine-js": "0.7.2" + "@fluencelabs/marine-js": "0.7.2", + "hotscript": "1.0.13" } } diff --git a/packages/core/interfaces/src/commonTypes.ts b/packages/core/interfaces/src/commonTypes.ts index 3574c245d..4e650e8f5 100644 --- a/packages/core/interfaces/src/commonTypes.ts +++ b/packages/core/interfaces/src/commonTypes.ts @@ -16,6 +16,8 @@ import type { SecurityTetraplet } from "@fluencelabs/avm"; +import { InterfaceToType, MaybePromise } from "./utils.js"; + /** * Peer ID's id as a base58 string (multihash/CIDv0). */ @@ -33,7 +35,7 @@ export type Node = { * Additional information about a service call * @typeparam ArgName */ -export interface CallParams { +export type CallParams = { /** * The identifier of particle which triggered the call */ @@ -63,6 +65,23 @@ export interface CallParams { * Security tetraplets */ tetraplets: ArgName extends string - ? Record + ? Record[]> : Record; -} +}; + +export type ServiceImpl = Record< + string, + ( + ...args: [...JSONArray, CallParams] + ) => MaybePromise +>; + +export type JSONValue = + | string + | number + | boolean + | null + | { [x: string]: JSONValue } + | Array; +export type JSONArray = Array; +export type JSONObject = { [x: string]: JSONValue }; diff --git a/packages/core/interfaces/src/compilerSupport/aquaTypeDefinitions.ts b/packages/core/interfaces/src/compilerSupport/aquaTypeDefinitions.ts index 1eb6d2283..447c72d5e 100644 --- a/packages/core/interfaces/src/compilerSupport/aquaTypeDefinitions.ts +++ b/packages/core/interfaces/src/compilerSupport/aquaTypeDefinitions.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -type SimpleTypes = +export type SimpleTypes = | ScalarType | OptionType | ArrayType @@ -23,7 +23,7 @@ type SimpleTypes = | BottomType | NilType; -export type NonArrowType = SimpleTypes | ProductType; +export type NonArrowType = SimpleTypes | ProductType; export type TopType = { /** @@ -48,7 +48,7 @@ export type OptionType = { /** * Underlying type of the option */ - type: NonArrowType; + type: SimpleTypes; }; export type NilType = { @@ -67,7 +67,7 @@ export type ArrayType = { /** * Type of array elements */ - type: NonArrowType; + type: SimpleTypes; }; /** @@ -113,10 +113,17 @@ export type StructType = { /** * Struct fields */ - fields: { [key: string]: NonArrowType }; + fields: { [key: string]: SimpleTypes }; }; -export type LabeledProductType = { +export type LabeledProductType< + T extends + | SimpleTypes + | ArrowType | UnlabeledProductType> = + | SimpleTypes + | ArrowType | UnlabeledProductType>, + K = { [key: string]: T }, +> = { /** * Type descriptor. Used for pattern-matching */ @@ -125,31 +132,29 @@ export type LabeledProductType = { /** * Labelled product fields */ - fields: { [key: string]: T }; + fields: K; }; -export type UnlabeledProductType = { - /** - * Type descriptor. Used for pattern-matching - */ - tag: "unlabeledProduct"; +export type UnlabeledProductType = SimpleTypes[]> = + { + /** + * Type descriptor. Used for pattern-matching + */ + tag: "unlabeledProduct"; - /** - * Items in unlabelled product - */ - items: Array; -}; + /** + * Items in unlabelled product + */ + items: T; + }; -export type ProductType = - | UnlabeledProductType - | LabeledProductType - | NilType; +export type ProductType = UnlabeledProductType | LabeledProductType; /** * ArrowType is a profunctor pointing its domain to codomain. * Profunctor means variance: Arrow is contravariant on domain, and variant on codomain. */ -export type ArrowType = { +export type ArrowType = { /** * Type descriptor. Used for pattern-matching */ @@ -158,25 +163,23 @@ export type ArrowType = { /** * Where this Arrow is defined */ - domain: ProductType; + domain: T | NilType; /** * Where this Arrow points to */ - codomain: UnlabeledProductType | NilType; + codomain: UnlabeledProductType | NilType; }; /** * Arrow which domain contains only non-arrow types */ -export type ArrowWithoutCallbacks = ArrowType; +export type ArrowWithoutCallbacks = ArrowType>; /** * Arrow which domain does can contain both non-arrow types and arrows (which themselves cannot contain arrows) */ -export type ArrowWithCallbacks = ArrowType< - NonArrowType | ArrowWithoutCallbacks ->; +export type ArrowWithCallbacks = ArrowType; export interface FunctionCallConstants { /** @@ -227,7 +230,9 @@ export interface FunctionCallDef { /** * Underlying arrow which represents function in aqua */ - arrow: ArrowWithCallbacks; + arrow: ArrowType< + LabeledProductType> + >; /** * Names of the different entities used in generated air script @@ -247,7 +252,9 @@ export interface ServiceDef { /** * List of functions which the service consists of */ - functions: LabeledProductType | NilType; + functions: + | LabeledProductType>> + | NilType; } /** @@ -278,5 +285,5 @@ export const isReturnTypeVoid = (def: FunctionCallDef): boolean => { return true; } - return def.arrow.codomain.items.length == 0; + return def.arrow.codomain.items.length === 0; }; diff --git a/packages/core/interfaces/src/compilerSupport/compilerSupportInterface.ts b/packages/core/interfaces/src/compilerSupport/compilerSupportInterface.ts index dc4b2a04a..b28bcb9e7 100644 --- a/packages/core/interfaces/src/compilerSupport/compilerSupportInterface.ts +++ b/packages/core/interfaces/src/compilerSupport/compilerSupportInterface.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +import { JSONValue } from "../commonTypes.js"; import { IFluenceInternalApi } from "../fluenceClient.js"; import { @@ -22,10 +23,17 @@ import { ServiceDef, } from "./aquaTypeDefinitions.js"; +/** + * Type for callback passed as aqua function argument + */ +export type ArgCallbackFunction = ( + ...args: JSONValue[] +) => JSONValue | Promise; + /** * Arguments passed to Aqua function */ -export type PassedArgs = { [key: string]: any }; +export type PassedArgs = { [key: string]: JSONValue | ArgCallbackFunction }; /** * Arguments for callAquaFunction function @@ -86,7 +94,7 @@ export interface RegisterServiceArgs { /** * Service implementation */ - service: any; + service: unknown; } /** diff --git a/packages/core/interfaces/src/fluenceClient.ts b/packages/core/interfaces/src/fluenceClient.ts index e5751bce5..f887769cb 100644 --- a/packages/core/interfaces/src/fluenceClient.ts +++ b/packages/core/interfaces/src/fluenceClient.ts @@ -114,7 +114,7 @@ export interface IFluenceInternalApi { /** * Internal API */ - internals: any; + internals: unknown; } /** diff --git a/packages/core/interfaces/src/future.ts b/packages/core/interfaces/src/future.ts new file mode 100644 index 000000000..d174cf44a --- /dev/null +++ b/packages/core/interfaces/src/future.ts @@ -0,0 +1,90 @@ +/** + * 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 { + ArrayType, + ArrowType, + LabeledProductType, + NilType, + OptionType, + ScalarType, + SimpleTypes, + StructType, + TopType, + UnlabeledProductType, +} from "@fluencelabs/interfaces"; +import { Call, Pipe, Objects, Tuples, Unions, Fn } from "hotscript"; + +// Type definitions for inferring ts types from air json definition +// In the future we may remove string type declaration and move to type inference. + +type GetTsTypeFromScalar = [T["name"]] extends [ + "u8" | "u16" | "u32" | "u64" | "i8" | "i16" | "i32" | "i64" | "f32" | "f64", +] + ? number + : [T["name"]] extends ["bool"] + ? boolean + : [T["name"]] extends ["string"] + ? string + : never; + +type MapTuple = { + [K in keyof T]: [T[K]] extends [SimpleTypes] ? GetSimpleType : never; +}; + +type UnpackIfSingle = [T] extends [[infer R]] ? R : T; + +type GetSimpleType = [T] extends [NilType] + ? null + : [T] extends [ArrayType] + ? GetSimpleType[] + : [T] extends [StructType] + ? { [K in keyof T["fields"]]: GetSimpleType } + : [T] extends [OptionType] + ? GetSimpleType | null + : [T] extends [ScalarType] + ? GetTsTypeFromScalar + : [T] extends [TopType] + ? unknown + : never; + +interface Access extends Fn { + return: __GetTsType, T>>; +} + +type __GetTsType = [T] extends [SimpleTypes] + ? GetSimpleType + : [T] extends [UnlabeledProductType] + ? MapTuple + : [T] extends [LabeledProductType] + ? { [K in keyof T["fields"]]: __GetTsType } + : [T] extends [ArrowType] + ? ( + ...t: [H] extends [UnlabeledProductType] + ? MapTuple + : [H] extends [LabeledProductType] + ? Pipe>]> + : [] + ) => [T["codomain"]] extends [UnlabeledProductType] + ? UnpackIfSingle> + : void + : never; + +type DeepMutable = { + -readonly [K in keyof T]: DeepMutable; +}; + +export type GetTsType = __GetTsType>; diff --git a/packages/core/interfaces/src/index.ts b/packages/core/interfaces/src/index.ts index 8dc7ce569..c984197c0 100644 --- a/packages/core/interfaces/src/index.ts +++ b/packages/core/interfaces/src/index.ts @@ -18,3 +18,4 @@ export * from "./compilerSupport/aquaTypeDefinitions.js"; export * from "./compilerSupport/compilerSupportInterface.js"; export * from "./commonTypes.js"; export * from "./fluenceClient.js"; +export * from "./future.js"; diff --git a/packages/core/interfaces/src/utils.ts b/packages/core/interfaces/src/utils.ts new file mode 100644 index 000000000..5f30c6f11 --- /dev/null +++ b/packages/core/interfaces/src/utils.ts @@ -0,0 +1,21 @@ +/** + * 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. + */ + +export type InterfaceToType = { + [K in keyof T]: T[K]; +}; + +export type MaybePromise = T | Promise; diff --git a/packages/core/interfaces/tsconfig.json b/packages/core/interfaces/tsconfig.json index aa5bb8304..68ec53d78 100644 --- a/packages/core/interfaces/tsconfig.json +++ b/packages/core/interfaces/tsconfig.json @@ -1,7 +1,8 @@ { "extends": "../../../tsconfig.json", "compilerOptions": { - "outDir": "./dist" + "outDir": "./dist", + "rootDir": "src" }, "include": ["src/**/*"], "exclude": ["node_modules", "dist"] diff --git a/packages/core/js-client/package.json b/packages/core/js-client/package.json index d381c136b..c07cdde73 100644 --- a/packages/core/js-client/package.json +++ b/packages/core/js-client/package.json @@ -50,7 +50,8 @@ "threads": "1.7.0", "ts-pattern": "3.3.3", "uint8arrays": "4.0.3", - "uuid": "8.3.2" + "uuid": "8.3.2", + "zod": "3.22.4" }, "devDependencies": { "@fluencelabs/aqua-api": "0.9.3", @@ -61,6 +62,7 @@ "@types/debug": "4.1.7", "@types/node": "20.7.0", "@types/uuid": "8.3.2", + "hotscript": "1.0.13", "vite": "4.0.4", "vite-tsconfig-paths": "4.0.3", "vitest": "0.29.7" diff --git a/packages/core/js-client/src/api.ts b/packages/core/js-client/src/api.ts index b520f9454..98d3ab148 100644 --- a/packages/core/js-client/src/api.ts +++ b/packages/core/js-client/src/api.ts @@ -18,18 +18,19 @@ import type { FnConfig, FunctionCallDef, ServiceDef, - IFluenceClient, -} from "@fluencelabs/interfaces"; + PassedArgs, ServiceImpl, +} from '@fluencelabs/interfaces'; import { getArgumentTypes } from "@fluencelabs/interfaces"; +import { ClientPeer } from "./clientPeer/ClientPeer.js"; import { FluencePeer } from "./jsPeer/FluencePeer.js"; import { callAquaFunction, Fluence, registerService } from "./index.js"; -export const isFluencePeer = ( +export const isClientPeer = ( fluencePeerCandidate: unknown, -): fluencePeerCandidate is IFluenceClient => { - return fluencePeerCandidate instanceof FluencePeer; +): fluencePeerCandidate is ClientPeer => { + return fluencePeerCandidate instanceof ClientPeer; }; /** @@ -41,21 +42,17 @@ export const isFluencePeer = ( * @param script - air script with function execution logic generated by the Aqua compiler */ export const v5_callFunction = async ( - rawFnArgs: Array, + rawFnArgs: unknown[], def: FunctionCallDef, script: string, ): Promise => { - const { - args, - client: peer, - config, - } = await extractFunctionArgs(rawFnArgs, def); + const { args, client: peer, config } = extractFunctionArgs(rawFnArgs, def); return callAquaFunction({ args, def, script, - config: config || {}, + config: config, peer: peer, }); }; @@ -64,18 +61,20 @@ export const v5_callFunction = async ( * 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 * @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 = async ( - args: any[], - def: ServiceDef, -): Promise => { - const { peer, service, serviceId } = await extractServiceArgs( +export const v5_registerService = (args: unknown[], def: ServiceDef): void => { + // TODO: Support this in aqua-to-js package + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + const service: ServiceImpl = args.pop() as ServiceImpl; + + const { peer, serviceId } = extractServiceArgs( args, def.defaultServiceId, ); - return registerService({ + registerService({ def, service, serviceId, @@ -83,6 +82,10 @@ export const v5_registerService = async ( }); }; +function isConfig(arg: unknown): arg is FnConfig { + return typeof arg === "object" && arg !== null; +} + /** * Arguments could be passed in one these configurations: * [...actualArgs] @@ -93,38 +96,44 @@ export const v5_registerService = async ( * This function select the appropriate configuration and returns * arguments in a structured way of: { peer, config, args } */ -const extractFunctionArgs = async ( - args: any[], +function extractFunctionArgs( + args: unknown[], def: FunctionCallDef, -): Promise<{ - client: IFluenceClient; - config?: FnConfig; - args: { [key: string]: any }; -}> => { +): { + client: FluencePeer; + config: FnConfig; + args: PassedArgs; +} { const argumentTypes = getArgumentTypes(def); const argumentNames = Object.keys(argumentTypes); const numberOfExpectedArgs = argumentNames.length; - let peer: IFluenceClient; - let structuredArgs: any[]; + let peer: ClientPeer; let config: FnConfig; - if (isFluencePeer(args[0])) { + if (isClientPeer(args[0])) { peer = args[0]; - structuredArgs = args.slice(1, numberOfExpectedArgs + 1); - config = args[numberOfExpectedArgs + 1]; + args = args.slice(1); } else { - if (!Fluence.defaultClient) { + 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; - structuredArgs = args.slice(0, numberOfExpectedArgs); - config = args[numberOfExpectedArgs]; } + 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}`, @@ -137,10 +146,10 @@ const extractFunctionArgs = async ( return { client: peer, - config: config, args: argsRes, + config: config, }; -}; +} /** * Arguments could be passed in one these configurations: @@ -154,18 +163,21 @@ const extractFunctionArgs = async ( * This function select the appropriate configuration and returns * arguments in a structured way of: { peer, serviceId, service } */ -const extractServiceArgs = async ( - args: any[], +const extractServiceArgs = ( + args: unknown[], defaultServiceId?: string, -): Promise<{ peer: IFluenceClient; serviceId: string; service: any }> => { - let peer: IFluenceClient; - let serviceId: any; - let service: any; - - if (isFluencePeer(args[0])) { +): { + peer: FluencePeer; + serviceId: string | undefined; +} => { + let peer: FluencePeer; + let serviceId: string | undefined; + + if (isClientPeer(args[0])) { peer = args[0]; + args = args.slice(1); } else { - if (!Fluence.defaultClient) { + 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()?", ); @@ -176,28 +188,12 @@ const extractServiceArgs = async ( if (typeof args[0] === "string") { serviceId = args[0]; - } else if (typeof args[1] === "string") { - serviceId = args[1]; } else { serviceId = defaultServiceId; } - // Figuring out which overload is the service. - // If the first argument is not Fluence Peer and it is an object, then it can only be the service def - // If the first argument is peer, we are checking further. The second argument might either be - // an object, that it must be the service object - // or a string, which is the service id. In that case the service is the third argument - if (!isFluencePeer(args[0]) && typeof args[0] === "object") { - service = args[0]; - } else if (typeof args[1] === "object") { - service = args[1]; - } else { - service = args[2]; - } - return { peer: peer, serviceId: serviceId, - service: service, }; }; diff --git a/packages/core/js-client/src/clientPeer/ClientPeer.ts b/packages/core/js-client/src/clientPeer/ClientPeer.ts index 9feff149d..f7d7cbba6 100644 --- a/packages/core/js-client/src/clientPeer/ClientPeer.ts +++ b/packages/core/js-client/src/clientPeer/ClientPeer.ts @@ -46,26 +46,30 @@ export const makeClientPeerConfig = async ( relayConfig: RelayConnectionConfig; keyPair: KeyPair; }> => { - const opts = config?.keyPair || { type: "Ed25519", source: "random" }; + const opts = config?.keyPair ?? { type: "Ed25519", source: "random" }; const keyPair = await fromOpts(opts); const relayAddress = relayOptionToMultiaddr(relay); return { peerConfig: { debug: { - printParticleId: config?.debug?.printParticleId || false, + printParticleId: config?.debug?.printParticleId ?? false, }, - defaultTtlMs: config?.defaultTtlMs || DEFAULT_TTL_MS, + defaultTtlMs: config?.defaultTtlMs ?? DEFAULT_TTL_MS, }, relayConfig: { peerId: keyPair.getLibp2pPeerId(), relayAddress: relayAddress, - dialTimeoutMs: config?.connectionOptions?.dialTimeoutMs, + ...(config.connectionOptions?.dialTimeoutMs != null + ? { + dialTimeout: config.connectionOptions?.dialTimeoutMs, + } + : {}), maxInboundStreams: - config?.connectionOptions?.maxInboundStreams || + config?.connectionOptions?.maxInboundStreams ?? MAX_OUTBOUND_STREAMS, maxOutboundStreams: - config?.connectionOptions?.maxOutboundStreams || + config?.connectionOptions?.maxOutboundStreams ?? MAX_INBOUND_STREAMS, }, keyPair: keyPair, @@ -130,7 +134,7 @@ export class ClientPeer extends FluencePeer implements IFluenceClient { return this.stop(); } - async start(): Promise { + override async start(): Promise { log.trace("connecting to Fluence network"); this.changeConnectionState("connecting"); await super.start(); @@ -139,7 +143,7 @@ export class ClientPeer extends FluencePeer implements IFluenceClient { log.trace("connected"); } - async stop(): Promise { + override async stop(): Promise { log.trace("disconnecting from Fluence network"); this.changeConnectionState("disconnecting"); await super.stop(); diff --git a/packages/core/js-client/src/clientPeer/__test__/client.spec.ts b/packages/core/js-client/src/clientPeer/__test__/client.spec.ts index d556cb755..04afd1a8e 100644 --- a/packages/core/js-client/src/clientPeer/__test__/client.spec.ts +++ b/packages/core/js-client/src/clientPeer/__test__/client.spec.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +import { JSONValue } from "@fluencelabs/interfaces"; import { it, describe, expect } from "vitest"; import { CallServiceData } from "../../jsServiceHost/interfaces.js"; @@ -46,7 +47,7 @@ describe("FluenceClient usage test suite", () => { const particle = await peer.internals.createNewParticle(script); - const result = await new Promise((resolve, reject) => { + const result = await new Promise((resolve, reject) => { if (particle instanceof Error) { return reject(particle.message); } @@ -58,11 +59,11 @@ describe("FluenceClient usage test suite", () => { }, }, callback: { - callback: (args: any) => { + callback: (args) => { const [val] = args; resolve(val); }, - error: (args: any) => { + error: (args) => { const [error] = args; reject(error); }, @@ -193,14 +194,14 @@ describe("FluenceClient usage test suite", () => { const particle = await peer.internals.createNewParticle(script); - const promise = new Promise((resolve, reject) => { + const promise = new Promise((_resolve, reject) => { if (particle instanceof Error) { return reject(particle.message); } registerHandlersHelper(peer, particle, { callback: { - error: (args: any) => { + error: (args) => { const [error] = args; reject(error); }, diff --git a/packages/core/js-client/src/clientPeer/checkConnection.ts b/packages/core/js-client/src/clientPeer/checkConnection.ts index 1d42491ce..0c8d626c7 100644 --- a/packages/core/js-client/src/clientPeer/checkConnection.ts +++ b/packages/core/js-client/src/clientPeer/checkConnection.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { JSONValue } from "@fluencelabs/interfaces"; + import { WrapFnIntoServiceCall } from "../jsServiceHost/serviceUtils.js"; import { handleTimeout } from "../particle/Particle.js"; import { logger } from "../util/logger.js"; @@ -52,7 +54,7 @@ export const checkConnection = async ( const particle = await peer.internals.createNewParticle(script, ttl); - const promise = new Promise((resolve, reject) => { + const promise = new Promise((resolve, reject) => { if (particle instanceof Error) { return reject(particle.message); } @@ -116,7 +118,7 @@ export const checkConnection = async ( try { const result = await promise; - if (result != msg) { + if (result !== msg) { log.error( "unexpected behavior. 'identity' must return the passed arguments.", ); diff --git a/packages/core/js-client/src/compilerSupport/__test__/v3.spec.ts b/packages/core/js-client/src/compilerSupport/__test__/v3.spec.ts index fa0412b9f..acfd24329 100644 --- a/packages/core/js-client/src/compilerSupport/__test__/v3.spec.ts +++ b/packages/core/js-client/src/compilerSupport/__test__/v3.spec.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +import { JSONValue, NonArrowType } from "@fluencelabs/interfaces"; import { it, describe, expect, test } from "vitest"; import { aqua2ts, ts2aqua } from "../conversions.js"; @@ -168,6 +169,12 @@ const nestedStructs = [ }, ]; +interface ConversionTestArgs { + aqua: JSONValue; + ts: JSONValue; + type: NonArrowType; +} + describe("Conversion from aqua to typescript", () => { test.each` aqua | ts | type @@ -189,7 +196,7 @@ describe("Conversion from aqua to typescript", () => { `( // "aqua: $aqua. ts: $ts. type: $type", - async ({ aqua, ts, type }) => { + ({ aqua, ts, type }: ConversionTestArgs) => { // arrange // act diff --git a/packages/core/js-client/src/compilerSupport/callFunction.ts b/packages/core/js-client/src/compilerSupport/callFunction.ts index 28bd386d6..2e417eec2 100644 --- a/packages/core/js-client/src/compilerSupport/callFunction.ts +++ b/packages/core/js-client/src/compilerSupport/callFunction.ts @@ -14,12 +14,17 @@ * limitations under the License. */ +import assert from "assert"; + import { - CallAquaFunctionType, + FnConfig, + FunctionCallDef, getArgumentTypes, isReturnTypeVoid, + PassedArgs, } from "@fluencelabs/interfaces"; +import { FluencePeer } from "../jsPeer/FluencePeer.js"; import { logger } from "../util/logger.js"; import { @@ -45,13 +50,22 @@ const log = logger("aqua"); * @param args - args in the form of JSON where each key corresponds to the name of the argument * @returns */ -export const callAquaFunction: CallAquaFunctionType = async ({ + +type CallAquaFunctionArgs = { + def: FunctionCallDef; + script: string; + config: FnConfig; + peer: FluencePeer; + args: PassedArgs; +}; + +export const callAquaFunction = async ({ def, script, config, peer, args, -}) => { +}: CallAquaFunctionArgs) => { log.trace("calling aqua function %j", { def, script, config, args }); const argumentTypes = getArgumentTypes(def); @@ -70,12 +84,18 @@ export const callAquaFunction: CallAquaFunctionType = async ({ let service: ServiceDescription; if (type.tag === "arrow") { + // TODO: Add validation here + assert(typeof argVal === "function"); + service = userHandlerService( def.names.callbackSrv, [name, type], argVal, ); } else { + // TODO: Add validation here + assert(typeof argVal !== "function"); + service = injectValueService( def.names.getDataSrv, name, @@ -105,7 +125,7 @@ export const callAquaFunction: CallAquaFunctionType = async ({ errorHandlingService(def, reject), ); - peer.internals.initiateParticle(particle, (stage: any) => { + peer.internals.initiateParticle(particle, (stage) => { // If function is void, then it's completed when one of the two conditions is met: // 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') diff --git a/packages/core/js-client/src/compilerSupport/conversions.ts b/packages/core/js-client/src/compilerSupport/conversions.ts index b2f31d974..bc339e7a2 100644 --- a/packages/core/js-client/src/compilerSupport/conversions.ts +++ b/packages/core/js-client/src/compilerSupport/conversions.ts @@ -14,9 +14,17 @@ * 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, NonArrowType, } from "@fluencelabs/interfaces"; import { match } from "ts-pattern"; @@ -30,19 +38,20 @@ import { jsonify } from "../util/utils.js"; * @param type - definition of the aqua type * @returns value represented in typescript */ -export const aqua2ts = (value: any, type: NonArrowType): any => { +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)); + if (value.length === 0) { return null; } else { return aqua2ts(value[0], opt.type); } }) - // @ts-ignore .with( { tag: "scalar" }, { tag: "bottomType" }, @@ -52,7 +61,8 @@ export const aqua2ts = (value: any, type: NonArrowType): any => { }, ) .with({ tag: "array" }, (arr) => { - return value.map((y: any) => { + assert(Array.isArray(value)); + return value.map((y) => { return aqua2ts(y, arr.type); }); }) @@ -91,7 +101,7 @@ export const aqua2ts = (value: any, type: NonArrowType): any => { export const aquaArgs2Ts = ( req: CallServiceData, arrow: ArrowWithoutCallbacks, -) => { +): JSONArray => { const argTypes = match(arrow.domain) .with({ tag: "labeledProduct" }, (x) => { return Object.values(x.fields); @@ -125,7 +135,7 @@ export const aquaArgs2Ts = ( * @param type - definition of the aqua type * @returns value represented in aqua */ -export const ts2aqua = (value: any, type: NonArrowType): any => { +export const ts2aqua = (value: JSONValue, type: NonArrowType): JSONValue => { const res = match(type) .with({ tag: "nil" }, () => { return null; @@ -137,7 +147,6 @@ export const ts2aqua = (value: any, type: NonArrowType): any => { return [ts2aqua(value, opt.type)]; } }) - // @ts-ignore .with( { tag: "scalar" }, { tag: "bottomType" }, @@ -147,7 +156,8 @@ export const ts2aqua = (value: any, type: NonArrowType): any => { }, ) .with({ tag: "array" }, (arr) => { - return value.map((y: any) => { + assert(Array.isArray(value)); + return value.map((y) => { return ts2aqua(y, arr.type); }); }) @@ -216,11 +226,11 @@ export const responseServiceValue2ts = ( ) => { return match(arrow.codomain) .with({ tag: "nil" }, () => { - return undefined; + return null; }) .with({ tag: "unlabeledProduct" }, (x) => { if (x.items.length === 0) { - return undefined; + return null; } if (x.items.length === 1) { diff --git a/packages/core/js-client/src/compilerSupport/registerService.ts b/packages/core/js-client/src/compilerSupport/registerService.ts index 5506520b4..a2a27f38f 100644 --- a/packages/core/js-client/src/compilerSupport/registerService.ts +++ b/packages/core/js-client/src/compilerSupport/registerService.ts @@ -14,20 +14,29 @@ * limitations under the License. */ -import type { RegisterServiceType } from "@fluencelabs/interfaces"; +import type { ServiceDef, ServiceImpl } from "@fluencelabs/interfaces"; +import { FluencePeer } from "../jsPeer/FluencePeer.js"; import { logger } from "../util/logger.js"; import { registerGlobalService, userHandlerService } from "./services.js"; const log = logger("aqua"); -export const registerService: RegisterServiceType = ({ +interface RegisterServiceArgs { + peer: FluencePeer; + def: ServiceDef; + serviceId: string | undefined; + service: ServiceImpl; +} + +export const registerService = ({ peer, def, serviceId, service, -}) => { +}: 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", { def, serviceId, service }); // Checking for missing keys @@ -49,11 +58,11 @@ export const registerService: RegisterServiceType = ({ ); } - if (!serviceId) { + if (serviceId == null) { serviceId = def.defaultServiceId; } - if (!serviceId) { + if (serviceId == null) { throw new Error("Service ID must be specified"); } @@ -61,7 +70,7 @@ export const registerService: RegisterServiceType = ({ def.functions.tag === "nil" ? [] : Object.entries(def.functions.fields); for (const singleFunction of singleFunctions) { - const [name, type] = singleFunction; + const [name] = singleFunction; // The function has type of (arg1, arg2, arg3, ... , callParams) => CallServiceResultType | void // Account for the fact that user service might be defined as a class - .bind(...) const userDefinedHandler = service[name].bind(service); diff --git a/packages/core/js-client/src/compilerSupport/services.ts b/packages/core/js-client/src/compilerSupport/services.ts index fb3b2a6a6..98d3ad996 100644 --- a/packages/core/js-client/src/compilerSupport/services.ts +++ b/packages/core/js-client/src/compilerSupport/services.ts @@ -18,14 +18,15 @@ import { SecurityTetraplet } from "@fluencelabs/avm"; import { CallParams, ArrowWithoutCallbacks, - FunctionCallConstants, FunctionCallDef, NonArrowType, - IFluenceInternalApi, -} from "@fluencelabs/interfaces"; + ServiceImpl, + JSONValue +} from '@fluencelabs/interfaces'; import { fromUint8Array } from "js-base64"; import { match } from "ts-pattern"; +import { FluencePeer } from "../jsPeer/FluencePeer.js"; import { CallServiceData, GenericCallServiceHandler, @@ -49,10 +50,7 @@ export interface ServiceDescription { /** * Creates a service which injects relay's peer id into aqua space */ -export const injectRelayService = ( - def: FunctionCallDef, - peer: IFluenceInternalApi, -) => { +export const injectRelayService = (def: FunctionCallDef, peer: FluencePeer) => { return { serviceId: def.names.getDataSrv, fnName: def.names.relay, @@ -72,7 +70,7 @@ export const injectValueService = ( serviceId: string, fnName: string, valueType: NonArrowType, - value: any, + value: JSONValue, ) => { return { serviceId: serviceId, @@ -91,7 +89,7 @@ export const injectValueService = ( */ export const responseService = ( def: FunctionCallDef, - resolveCallback: Function, + resolveCallback: (val: JSONValue) => void, ) => { return { serviceId: def.names.responseSrv, @@ -116,13 +114,13 @@ export const responseService = ( */ export const errorHandlingService = ( def: FunctionCallDef, - rejectCallback: Function, + rejectCallback: (err: JSONValue) => void, ) => { return { serviceId: def.names.errorHandlingSrv, fnName: def.names.errorFnName, handler: (req: CallServiceData) => { - const [err, _] = req.args; + const [err] = req.args; setTimeout(() => { rejectCallback(err); @@ -142,19 +140,19 @@ export const errorHandlingService = ( export const userHandlerService = ( serviceId: string, arrowType: [string, ArrowWithoutCallbacks], - userHandler: (...args: Array) => Promise, + userHandler: ServiceImpl[string], ) => { const [fnName, type] = arrowType; return { serviceId, fnName, handler: async (req: CallServiceData) => { - const args = [ + const args: [...JSONValue[], CallParams] = [ ...aquaArgs2Ts(req, type), extractCallParams(req, type), ]; - const rawResult = await userHandler.apply(null, args); + const rawResult = await userHandler.bind(null)(...args); const result = returnType2Aqua(rawResult, type); return { @@ -165,49 +163,33 @@ export const userHandlerService = ( }; }; -/** - * Converts argument of aqua function to a corresponding service. - * For arguments of non-arrow types the resulting service injects the argument into aqua space. - * For arguments of arrow types the resulting service calls the corresponding function. - */ -export const argToServiceDef = ( - arg: any, - argName: string, - argType: NonArrowType | ArrowWithoutCallbacks, - names: FunctionCallConstants, -): ServiceDescription => { - if (argType.tag === "arrow") { - return userHandlerService(names.callbackSrv, [argName, argType], arg); - } else { - return injectValueService(names.getDataSrv, argName, arg, argType); - } -}; - /** * Extracts call params from from call service data according to aqua type definition */ const extractCallParams = ( req: CallServiceData, arrow: ArrowWithoutCallbacks, -): CallParams => { +): CallParams => { const names = match(arrow.domain) .with({ tag: "nil" }, () => { - return [] as string[]; - }) - .with({ tag: "labeledProduct" }, (x) => { - return Object.keys(x.fields); + return []; }) .with({ tag: "unlabeledProduct" }, (x) => { return x.items.map((_, index) => { return "arg" + index; }); }) + .with({ tag: "labeledProduct" }, (x) => { + return Object.keys(x.fields).map((label) => { + return label; + }) + }) .exhaustive(); const tetraplets: Record = {}; for (let i = 0; i < req.args.length; i++) { - if (names[i]) { + if (names[i] != null) { tetraplets[names[i]] = req.tetraplets[i]; } } @@ -222,7 +204,7 @@ const extractCallParams = ( }; export const registerParticleScopeService = ( - peer: IFluenceInternalApi, + peer: FluencePeer, particle: Particle, service: ServiceDescription, ) => { @@ -235,7 +217,7 @@ export const registerParticleScopeService = ( }; export const registerGlobalService = ( - peer: IFluenceInternalApi, + peer: FluencePeer, service: ServiceDescription, ) => { peer.internals.regHandler.common( diff --git a/packages/core/js-client/src/connection/RelayConnection.ts b/packages/core/js-client/src/connection/RelayConnection.ts index 393788f34..c13f3cc05 100644 --- a/packages/core/js-client/src/connection/RelayConnection.ts +++ b/packages/core/js-client/src/connection/RelayConnection.ts @@ -119,7 +119,11 @@ export class RelayConnection implements IConnection { streamMuxers: [yamux()], connectionEncryption: [noise()], connectionManager: { - dialTimeout: this.config.dialTimeoutMs, + ...(this.config.dialTimeoutMs != null + ? { + dialTimeout: this.config.dialTimeoutMs, + } + : {}), }, connectionGater: { // By default, this function forbids connections to private peers. For example multiaddr with ip 127.0.0.1 isn't allowed @@ -212,10 +216,10 @@ export class RelayConnection implements IConnection { return; } - const isVerified = await verifySignature( - particle, - initPeerId.publicKey, - ); + const isVerified = await verifySignature(); + // TODO: Uncomment this when nox rolls out particle signatures + // particle, + // initPeerId.publicKey, if (isVerified) { this.particleSource.next(particle); @@ -248,8 +252,8 @@ export class RelayConnection implements IConnection { await this.lib2p2Peer.handle( [PROTOCOL_NAME], - async ({ connection, stream }) => { - return pipe( + ({ stream }) => { + void pipe( stream.source, decode(), (source) => { @@ -279,17 +283,6 @@ export class RelayConnection implements IConnection { this.lib2p2Peer.peerId.toString(), ); - try { - await this.lib2p2Peer.dial(this.relayAddress); - } catch (e: any) { - if (e.name === "AggregateError" && e._errors?.length === 1) { - const error = e._errors[0]; - throw new Error( - `Error dialing node ${this.relayAddress}:\n${error.code}\n${error.message}`, - ); - } else { - throw e; - } - } + await this.lib2p2Peer.dial(this.relayAddress); } } diff --git a/packages/core/js-client/src/ephemeral/__test__/ephemeral.spec.ts b/packages/core/js-client/src/ephemeral/__test__/ephemeral.spec.ts index 9af02271c..8c892d38c 100644 --- a/packages/core/js-client/src/ephemeral/__test__/ephemeral.spec.ts +++ b/packages/core/js-client/src/ephemeral/__test__/ephemeral.spec.ts @@ -17,10 +17,7 @@ import { it, describe, expect, beforeEach, afterEach } from "vitest"; import { DEFAULT_CONFIG, FluencePeer } from "../../jsPeer/FluencePeer.js"; -import { - CallServiceData, - ResultCodes, -} from "../../jsServiceHost/interfaces.js"; +import { ResultCodes } from "../../jsServiceHost/interfaces.js"; import { KeyPair } from "../../keypair/index.js"; import { EphemeralNetworkClient } from "../client.js"; import { EphemeralNetwork, defaultConfig } from "../network.js"; @@ -41,13 +38,8 @@ describe.skip("Ephemeral networks tests", () => { }); afterEach(async () => { - if (client) { - await client.stop(); - } - - if (en) { - await en.down(); - } + await client.stop(); + await en.down(); }); it("smoke test", async function () { @@ -88,7 +80,7 @@ describe.skip("Ephemeral networks tests", () => { particle.id, "test", "test", - (req: CallServiceData) => { + () => { resolve("success"); return { result: "test", diff --git a/packages/core/js-client/src/ephemeral/network.ts b/packages/core/js-client/src/ephemeral/network.ts index dc143fe93..78e871dfa 100644 --- a/packages/core/js-client/src/ephemeral/network.ts +++ b/packages/core/js-client/src/ephemeral/network.ts @@ -169,13 +169,10 @@ export class EphemeralConnection implements IEphemeralConnection { particleSource = new Subject(); receiveParticle(particle: Particle): void { - this.particleSource.next(Particle.fromString(particle.toString())); + this.particleSource.next(particle); } - async sendParticle( - nextPeerIds: string[], - particle: Particle, - ): Promise { + sendParticle(nextPeerIds: string[], particle: Particle): Promise { const from = this.selfPeerId; for (const to of nextPeerIds) { @@ -189,16 +186,21 @@ export class EphemeralConnection implements IEphemeralConnection { // log.trace(`Sending particle from %s, to %j, particleId %s`, from, to, particle.id); destConnection.receiveParticle(particle); } + + return Promise.resolve(); } getRelayPeerId(): string { - if (this.connections.size === 1) { - return this.connections.keys().next().value; + const firstMapKey = this.connections.keys().next(); + + // Empty map + if (firstMapKey.done === true) { + throw new Error( + "relay is not supported in this Ephemeral network peer", + ); } - throw new Error( - "relay is not supported in this Ephemeral network peer", - ); + return firstMapKey.value; } supportsRelay(): boolean { @@ -303,8 +305,8 @@ export class EphemeralNetwork { log.trace("shutting down ephemeral network..."); const peers = Array.from(this.peers.entries()); - const promises = peers.map(async ([k, p]) => { - await p.ephemeralConnection.disconnectFromAll(); + const promises = peers.map(async ([, p]) => { + p.ephemeralConnection.disconnectFromAll(); await p.stop(); }); diff --git a/packages/core/js-client/src/fetchers/browser.ts b/packages/core/js-client/src/fetchers/browser.ts index c75277ac8..ff38849d0 100644 --- a/packages/core/js-client/src/fetchers/browser.ts +++ b/packages/core/js-client/src/fetchers/browser.ts @@ -27,11 +27,15 @@ const PRIMARY_CDN = "https://unpkg.com/"; export async function fetchResource(pkg: string, assetPath: string) { const packageJsonContent = - parsedPackageJsonContent || - (parsedPackageJsonContent = JSON.parse(packageJsonContentString)); + parsedPackageJsonContent ?? + // TODO: Should be validated + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + (parsedPackageJsonContent = JSON.parse( + packageJsonContentString, + ) as PackageJsonContent); const version = - packageJsonContent.dependencies[pkg] || + packageJsonContent.dependencies[pkg] ?? packageJsonContent.devDependencies[pkg]; if (version === undefined) { diff --git a/packages/core/js-client/src/fetchers/node.ts b/packages/core/js-client/src/fetchers/node.ts index 755bb682d..9b15dd447 100644 --- a/packages/core/js-client/src/fetchers/node.ts +++ b/packages/core/js-client/src/fetchers/node.ts @@ -29,7 +29,7 @@ export async function fetchResource(pkg: string, assetPath: string) { const packagePath = matches?.[0]; - if (!packagePath) { + if (packagePath == null) { throw new Error(`Cannot find dependency ${pkg} in path ${posixPath}`); } @@ -38,7 +38,7 @@ export async function fetchResource(pkg: string, assetPath: string) { const file = await new Promise((resolve, reject) => { // Cannot use 'fs/promises' with current vite config. This module is not polyfilled by default. fs.readFile(pathToResource, (err, data) => { - if (err) { + if (err != null) { reject(err); return; } diff --git a/packages/core/js-client/src/index.ts b/packages/core/js-client/src/index.ts index ccfaba480..0d87e9bbe 100644 --- a/packages/core/js-client/src/index.ts +++ b/packages/core/js-client/src/index.ts @@ -21,18 +21,19 @@ import url from "url"; import type { ClientConfig, + ConnectionState, IFluenceClient, RelayOptions, - ConnectionState, } from "@fluencelabs/interfaces"; -import { BlobWorker, Worker } from "threads"; + +// "threads" package has broken type definitions in package.json. This is the workaround. +import { BlobWorker, Worker } from "../node_modules/threads/dist/index.js"; import { ClientPeer, makeClientPeerConfig } from "./clientPeer/ClientPeer.js"; import { callAquaFunction } from "./compilerSupport/callFunction.js"; import { registerService } from "./compilerSupport/registerService.js"; import { fetchResource } from "./fetchers/index.js"; import { MarineBackgroundRunner } from "./marine/worker/index.js"; -// @ts-ignore import { doRegisterNodeUtils } from "./services/NodeUtils.js"; const isNode = @@ -64,7 +65,7 @@ const fetchAvmWasm = () => { const createClient = async ( relay: RelayOptions, config: ClientConfig, -): Promise => { +): Promise => { const marineJsWasm = await fetchMarineJsWasm(); const avmWasm = await fetchAvmWasm(); @@ -129,12 +130,7 @@ const createClient = async ( config, ); - const client: IFluenceClient = new ClientPeer( - peerConfig, - relayConfig, - keyPair, - marine, - ); + const client = new ClientPeer(peerConfig, relayConfig, keyPair, marine); if (isNode) { doRegisterNodeUtils(client); @@ -147,19 +143,25 @@ const createClient = async ( /** * Public interface to Fluence Network */ -export const Fluence = { - defaultClient: undefined as IFluenceClient | undefined, +interface FluencePublicApi { + defaultClient: ClientPeer | undefined; + connect: (relay: RelayOptions, config: ClientConfig) => Promise; + disconnect: () => Promise; + onConnectionStateChange: ( + handler: (state: ConnectionState) => void, + ) => ConnectionState; + getClient: () => IFluenceClient; +} + +export const Fluence: FluencePublicApi = { + defaultClient: undefined, /** * Connect to the Fluence network * @param relay - relay node to connect to * @param config - client configuration */ - connect: async function ( - relay: RelayOptions, - config: ClientConfig, - ): Promise { - const client = await createClient(relay, config); - this.defaultClient = client; + connect: async function (relay, config) { + this.defaultClient = await createClient(relay, config); }, /** @@ -173,11 +175,9 @@ export const Fluence = { /** * Handle connection state changes. Immediately returns the current connection state */ - onConnectionStateChange( - handler: (state: ConnectionState) => void, - ): ConnectionState { + onConnectionStateChange(handler) { return ( - this.defaultClient?.onConnectionStateChange(handler) || + this.defaultClient?.onConnectionStateChange(handler) ?? "disconnected" ); }, @@ -186,8 +186,8 @@ export const Fluence = { * Low level API. Get the underlying client instance which holds the connection to the network * @returns IFluenceClient instance */ - getClient: async function (): Promise { - if (!this.defaultClient) { + getClient: function () { + if (this.defaultClient == null) { throw new Error( "Fluence client is not initialized. Call Fluence.connect() first", ); @@ -232,10 +232,10 @@ export type { export { v5_callFunction, v5_registerService } from "./api.js"; -// @ts-ignore +// @ts-expect-error Writing to global object like this prohibited by ts globalThis.new_fluence = Fluence; -// @ts-ignore +// @ts-expect-error Writing to global object like this prohibited by ts globalThis.fluence = { clientFactory: createClient, callAquaFunction, @@ -243,7 +243,3 @@ globalThis.fluence = { }; export { createClient, callAquaFunction, registerService }; -export { - getFluenceInterface, - getFluenceInterfaceFromGlobalThis, -} from "./util/loadClient.js"; diff --git a/packages/core/js-client/src/jsPeer/FluencePeer.ts b/packages/core/js-client/src/jsPeer/FluencePeer.ts index 425ecd65d..cdc622291 100644 --- a/packages/core/js-client/src/jsPeer/FluencePeer.ts +++ b/packages/core/js-client/src/jsPeer/FluencePeer.ts @@ -65,9 +65,8 @@ import { registerTracing } from "../services/_aqua/tracing.js"; import { defaultSigGuard, Sig } from "../services/Sig.js"; import { Srv } from "../services/SingleModuleSrv.js"; import { Tracing } from "../services/Tracing.js"; -import { JSONValue } from "../util/commonTypes.js"; import { logger } from "../util/logger.js"; -import { jsonify, isString } from "../util/utils.js"; +import { jsonify, isString, getErrorMessage } from "../util/utils.js"; const log_particle = logger("particle"); const log_peer = logger("peer"); @@ -163,12 +162,6 @@ export abstract class FluencePeer { wasm: SharedArrayBuffer | Buffer, serviceId: string, ): Promise { - if (!this.marineHost) { - throw new Error( - "Can't register marine service: peer is not initialized", - ); - } - if (this.jsServiceHost.hasService(serviceId)) { throw new Error(`Service with '${serviceId}' id already exists`); } @@ -184,8 +177,6 @@ export abstract class FluencePeer { await this.marineHost.removeService(serviceId); } - // internal api - /** * @private Is not intended to be used manually. Subject to change */ @@ -207,7 +198,7 @@ export abstract class FluencePeer { parseAst: async ( air: string, - ): Promise<{ success: boolean; data: any }> => { + ): Promise<{ success: boolean; data: unknown }> => { if (!this.isInitialized) { new Error("Can't use avm: peer is not initialized"); } @@ -221,7 +212,9 @@ export abstract class FluencePeer { if (!isString(res)) { throw new Error( - `Call to avm:ast expected to return string. Actual return: ${res}`, + `Call to avm:ast expected to return string. Actual return: ${JSON.stringify( + res, + )}`, ); } @@ -242,7 +235,7 @@ export abstract class FluencePeer { "Failed to call avm. Result: " + res + ". Error: " + - err, + getErrorMessage(err), ); } }, @@ -275,6 +268,8 @@ export abstract class FluencePeer { } if (this.printParticleId) { + // This is intended console-log + // eslint-disable-next-line no-console console.log("Particle id: ", particle.id); } @@ -567,7 +562,7 @@ export abstract class FluencePeer { item.onStageChange({ stage: "sent" }); }) - .catch((e: any) => { + .catch((e: unknown) => { log_particle.error( "id %s. send failed %j", newParticle.id, @@ -576,7 +571,7 @@ export abstract class FluencePeer { item.onStageChange({ stage: "sendingError", - errorMessage: e.toString(), + errorMessage: getErrorMessage(e), }); }); } @@ -596,7 +591,7 @@ export abstract class FluencePeer { ), }; - this._execSingleCallRequest(req) + void this._execSingleCallRequest(req) .catch((err): CallServiceResult => { if (err instanceof ServiceError) { return { @@ -611,7 +606,9 @@ export abstract class FluencePeer { req.fnName }" serviceId="${ req.serviceId - }" error: ${err.toString()}`, + }" error: ${getErrorMessage( + err, + )}`, }; }) .then((res) => { @@ -677,10 +674,7 @@ export abstract class FluencePeer { req, ); - if ( - this.marineHost && - (await this.marineHost.hasService(req.serviceId)) - ) { + if (await this.marineHost.hasService(req.serviceId)) { // TODO build correct CallParameters instead of default ones const result = await this.marineHost.callService( req.serviceId, @@ -691,7 +685,7 @@ export abstract class FluencePeer { return { retCode: ResultCodes.success, - result: result as JSONValue, + result: result, }; } diff --git a/packages/core/js-client/src/jsPeer/__test__/avm.spec.ts b/packages/core/js-client/src/jsPeer/__test__/avm.spec.ts index cd5022c2b..643850ef2 100644 --- a/packages/core/js-client/src/jsPeer/__test__/avm.spec.ts +++ b/packages/core/js-client/src/jsPeer/__test__/avm.spec.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +import { JSONValue } from "@fluencelabs/interfaces"; import { it, describe, expect } from "vitest"; import { handleTimeout } from "../../particle/Particle.js"; @@ -28,14 +29,14 @@ describe("Basic AVM functionality in Fluence Peer tests", () => { const particle = await peer.internals.createNewParticle(script); - const res = await new Promise((resolve, reject) => { + const res = await new Promise((resolve, reject) => { if (particle instanceof Error) { return reject(particle.message); } registerHandlersHelper(peer, particle, { print: { - print: (args: Array) => { + print: (args) => { const [res] = args; resolve(res); }, @@ -66,8 +67,8 @@ describe("Basic AVM functionality in Fluence Peer tests", () => { const particle = await peer.internals.createNewParticle(script); - const res = await new Promise((resolve, reject) => { - const res: any[] = []; + const res = await new Promise((resolve, reject) => { + const res: JSONValue[] = []; if (particle instanceof Error) { return reject(particle.message); @@ -75,10 +76,10 @@ describe("Basic AVM functionality in Fluence Peer tests", () => { registerHandlersHelper(peer, particle, { print: { - print: (args: any) => { + print: (args) => { res.push(args[0]); - if (res.length == 2) { + if (res.length === 2) { resolve(res); } }, @@ -122,7 +123,7 @@ describe("Basic AVM functionality in Fluence Peer tests", () => { registerHandlersHelper(peer, particle, { return: { - return: (args: any) => { + return: (args) => { resolve(args[0]); }, }, @@ -176,7 +177,7 @@ describe("Basic AVM functionality in Fluence Peer tests", () => { registerHandlersHelper(peer, particle, { return: { - return: (args: any) => { + return: (args) => { resolve(args[0]); }, }, diff --git a/packages/core/js-client/src/jsPeer/__test__/par.spec.ts b/packages/core/js-client/src/jsPeer/__test__/par.spec.ts index 3bd4400ba..3f76a6776 100644 --- a/packages/core/js-client/src/jsPeer/__test__/par.spec.ts +++ b/packages/core/js-client/src/jsPeer/__test__/par.spec.ts @@ -14,6 +14,9 @@ * limitations under the License. */ +import assert from "assert"; + +import { JSONValue } from "@fluencelabs/interfaces"; import { describe, expect, it } from "vitest"; import { @@ -41,13 +44,14 @@ describe("FluencePeer flow tests", () => { const particle = await peer.internals.createNewParticle(script); - const res = await new Promise((resolve, reject) => { + const res = await new Promise((resolve, reject) => { peer.internals.regHandler.forParticle( particle.id, "flow", "timeout", (req: CallServiceData) => { const [timeout, message] = req.args; + assert(typeof timeout === "number"); return new Promise((resolve) => { setTimeout(() => { @@ -66,11 +70,11 @@ describe("FluencePeer flow tests", () => { return reject(particle.message); } - const values: any[] = []; + const values: JSONValue[] = []; registerHandlersHelper(peer, particle, { callback: { - callback1: (args: any) => { + callback1: (args) => { const [val] = args; values.push(val); @@ -78,7 +82,7 @@ describe("FluencePeer flow tests", () => { resolve(values); } }, - callback2: (args: any) => { + callback2: (args) => { const [val] = args; values.push(val); @@ -95,9 +99,7 @@ describe("FluencePeer flow tests", () => { ); }); - await expect(res).toEqual( - expect.arrayContaining(["test1", "test1"]), - ); + expect(res).toEqual(expect.arrayContaining(["test1", "test1"])); }); }, 1500); }); diff --git a/packages/core/js-client/src/jsPeer/__test__/parseAst.spec.ts b/packages/core/js-client/src/jsPeer/__test__/parseAst.spec.ts index 4b3ba69e9..ac0c67a4d 100644 --- a/packages/core/js-client/src/jsPeer/__test__/parseAst.spec.ts +++ b/packages/core/js-client/src/jsPeer/__test__/parseAst.spec.ts @@ -20,7 +20,7 @@ import { withPeer } from "../../util/testUtils.js"; describe("Parse ast tests", () => { it("Correct ast should be parsed correctly", async () => { - withPeer(async (peer) => { + await withPeer(async (peer) => { const air = `(null)`; const res = await peer.internals.parseAst(air); @@ -32,12 +32,13 @@ describe("Parse ast tests", () => { }); it("Incorrect ast should result in corresponding error", async () => { - withPeer(async (peer) => { + await withPeer(async (peer) => { const air = `(null`; const res = await peer.internals.parseAst(air); expect(res).toStrictEqual({ success: false, + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment data: expect.stringContaining("error"), }); }); diff --git a/packages/core/js-client/src/jsPeer/__test__/peer.spec.ts b/packages/core/js-client/src/jsPeer/__test__/peer.spec.ts index 6ffbe5811..0c04fb179 100644 --- a/packages/core/js-client/src/jsPeer/__test__/peer.spec.ts +++ b/packages/core/js-client/src/jsPeer/__test__/peer.spec.ts @@ -16,7 +16,7 @@ import { it, describe, expect } from "vitest"; -import { isFluencePeer } from "../../api.js"; +import { isClientPeer } from "../../api.js"; import { handleTimeout } from "../../particle/Particle.js"; import { mkTestPeer, @@ -34,10 +34,10 @@ describe("FluencePeer usage test suite", () => { const undefinedVal = undefined; // act - const isPeerPeer = isFluencePeer(peer); - const isNumberPeer = isFluencePeer(number); - const isObjectPeer = isFluencePeer(object); - const isUndefinedPeer = isFluencePeer(undefinedVal); + const isPeerPeer = isClientPeer(peer); + const isNumberPeer = isClientPeer(number); + const isObjectPeer = isClientPeer(object); + const isUndefinedPeer = isClientPeer(undefinedVal); // act expect(isPeerPeer).toBe(true); @@ -57,14 +57,14 @@ describe("FluencePeer usage test suite", () => { const particle = await peer.internals.createNewParticle(script); - const res = await new Promise((resolve, reject) => { + const res = await new Promise((resolve, reject) => { if (particle instanceof Error) { return reject(particle.message); } registerHandlersHelper(peer, particle, { callback: { - callback: async (args: any) => { + callback: (args) => { const [res] = args; resolve(res); }, @@ -86,6 +86,7 @@ describe("FluencePeer usage test suite", () => { const res = callIncorrectService(peer); await expect(res).rejects.toMatchObject({ + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment message: expect.stringContaining( `"No service found for service call: serviceId='incorrect', fnName='incorrect' args='[]'"`, ), @@ -108,7 +109,7 @@ describe("FluencePeer usage test suite", () => { const particle = await peer.internals.createNewParticle(script); - const res = await new Promise((resolve, reject) => { + const res = await new Promise((resolve, reject) => { if (particle instanceof Error) { return reject(particle.message); } @@ -120,11 +121,11 @@ describe("FluencePeer usage test suite", () => { }, }, callback: { - callback: (args: any) => { + callback: (args) => { const [val] = args; resolve(val); }, - error: (args: any) => { + error: (args) => { const [error] = args; reject(error); }, @@ -151,7 +152,7 @@ describe("FluencePeer usage test suite", () => { const particle = await peer.internals.createNewParticle(script); - const promise = new Promise((_resolve, reject) => { + const promise = new Promise((_resolve, reject) => { if (particle instanceof Error) { return reject(particle.message); } @@ -163,7 +164,7 @@ describe("FluencePeer usage test suite", () => { }, }, callback: { - error: (args: any) => { + error: (args) => { const [error] = args; reject(error); }, @@ -177,6 +178,7 @@ describe("FluencePeer usage test suite", () => { }); await expect(promise).rejects.toMatchObject({ + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment message: expect.stringContaining( "my super custom error message", ), @@ -185,7 +187,7 @@ describe("FluencePeer usage test suite", () => { }); }); -async function callIncorrectService(peer: FluencePeer): Promise { +async function callIncorrectService(peer: FluencePeer) { const script = ` (xor (call %init_peer_id% ("incorrect" "incorrect") [] res) @@ -194,17 +196,17 @@ async function callIncorrectService(peer: FluencePeer): Promise { const particle = await peer.internals.createNewParticle(script); - return new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { if (particle instanceof Error) { return reject(particle.message); } registerHandlersHelper(peer, particle, { callback: { - callback: (args: any) => { + callback: (args) => { resolve(args); }, - error: (args: any) => { + error: (args) => { const [error] = args; reject(error); }, diff --git a/packages/core/js-client/src/jsServiceHost/JsServiceHost.ts b/packages/core/js-client/src/jsServiceHost/JsServiceHost.ts index 369f0ebe2..36ed2ff10 100644 --- a/packages/core/js-client/src/jsServiceHost/JsServiceHost.ts +++ b/packages/core/js-client/src/jsServiceHost/JsServiceHost.ts @@ -73,7 +73,7 @@ export class JsServiceHost implements IJsServiceHost { handler = this.commonHandlers.get(key); } - return handler || null; + return handler ?? null; } /** diff --git a/packages/core/js-client/src/jsServiceHost/interfaces.ts b/packages/core/js-client/src/jsServiceHost/interfaces.ts index b29b16399..2369f067f 100644 --- a/packages/core/js-client/src/jsServiceHost/interfaces.ts +++ b/packages/core/js-client/src/jsServiceHost/interfaces.ts @@ -16,8 +16,7 @@ import type { SecurityTetraplet } from "@fluencelabs/avm"; import type { PeerIdB58 } from "@fluencelabs/interfaces"; - -import { JSONValue } from "../util/commonTypes.js"; +import { JSONArray, JSONValue } from "@fluencelabs/interfaces"; /** * JS Service host a low level interface for managing pure javascript services. @@ -124,7 +123,7 @@ export interface CallServiceData { /** * Arguments as specified in `call` air instruction */ - args: any[]; + args: JSONArray; /** * Security Tetraplets received from AVM diff --git a/packages/core/js-client/src/jsServiceHost/serviceUtils.ts b/packages/core/js-client/src/jsServiceHost/serviceUtils.ts index b7887caf2..6cc9ffe74 100644 --- a/packages/core/js-client/src/jsServiceHost/serviceUtils.ts +++ b/packages/core/js-client/src/jsServiceHost/serviceUtils.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { JSONArray } from "@fluencelabs/interfaces"; + import { FluencePeer } from "../jsPeer/FluencePeer.js"; import { IParticle } from "../particle/interfaces.js"; import { builtInServices } from "../services/builtins.js"; @@ -26,17 +28,17 @@ import { ResultCodes, } from "./interfaces.js"; -export const doNothing = (..._args: Array) => { +export const doNothing = () => { return undefined; }; export const WrapFnIntoServiceCall = ( - fn: (args: any[]) => CallServiceResultType, + fn: (args: JSONArray) => CallServiceResultType | void, ) => { return (req: CallServiceData): CallServiceResult => { return { retCode: ResultCodes.success, - result: fn(req.args), + result: fn(req.args) ?? null, }; }; }; diff --git a/packages/core/js-client/src/keypair/__test__/KeyPair.spec.ts b/packages/core/js-client/src/keypair/__test__/KeyPair.spec.ts index 0cdbe2064..b1e09f5e4 100644 --- a/packages/core/js-client/src/keypair/__test__/KeyPair.spec.ts +++ b/packages/core/js-client/src/keypair/__test__/KeyPair.spec.ts @@ -14,15 +14,12 @@ * limitations under the License. */ -import * as bs58 from "bs58"; +import { decode } from "bs58"; import { toUint8Array } from "js-base64"; import { it, describe, expect } from "vitest"; import { KeyPair } from "../index.js"; -// @ts-ignore -const { decode } = bs58.default; - const key = "+cmeYlZKj+MfSa9dpHV+BmLPm6wq4inGlsPlQ1GvtPk="; const keyBytes = toUint8Array(key); diff --git a/packages/core/js-client/src/keypair/index.ts b/packages/core/js-client/src/keypair/index.ts index 2f6271010..853f4eed5 100644 --- a/packages/core/js-client/src/keypair/index.ts +++ b/packages/core/js-client/src/keypair/index.ts @@ -19,12 +19,9 @@ import { generateKeyPairFromSeed, generateKeyPair } from "@libp2p/crypto/keys"; import type { PrivateKey, PublicKey } from "@libp2p/interface/keys"; import type { PeerId } from "@libp2p/interface/peer-id"; import { createFromPrivKey } from "@libp2p/peer-id-factory"; -import * as bs58 from "bs58"; +import { decode } from "bs58"; import { toUint8Array } from "js-base64"; -// @ts-ignore -const { decode } = bs58.default; - export class KeyPair { /** * Key pair in libp2p format. Used for backward compatibility with the current FluencePeer implementation diff --git a/packages/core/js-client/src/marine/__test__/marine-js.spec.ts b/packages/core/js-client/src/marine/__test__/marine-js.spec.ts index 979584dbb..d970c58e7 100644 --- a/packages/core/js-client/src/marine/__test__/marine-js.spec.ts +++ b/packages/core/js-client/src/marine/__test__/marine-js.spec.ts @@ -20,9 +20,9 @@ import * as url from "url"; import { it, describe, expect, beforeAll } from "vitest"; -import { compileAqua, withPeer } from "../../util/testUtils.js"; +import { compileAqua, CompiledFnCall, withPeer } from "../../util/testUtils.js"; -let aqua: any; +let aqua: Record; const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); describe("Marine js tests", () => { @@ -32,7 +32,7 @@ describe("Marine js tests", () => { "../../../aqua_test/marine-js.aqua", ); - const { services, functions } = await compileAqua(pathToAquaFiles); + const { functions } = await compileAqua(pathToAquaFiles); aqua = functions; }); @@ -46,7 +46,7 @@ describe("Marine js tests", () => { await peer.registerMarineService(wasm, "greeting"); // act - const res = await aqua.call(peer, { arg: "test" }); + const res = await aqua["call"](peer, { arg: "test" }); // assert expect(res).toBe("Hi, Hi, Hi, test"); diff --git a/packages/core/js-client/src/marine/deps-loader/common.ts b/packages/core/js-client/src/marine/deps-loader/common.ts deleted file mode 100644 index 198c1a5d5..000000000 --- a/packages/core/js-client/src/marine/deps-loader/common.ts +++ /dev/null @@ -1,43 +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. - */ - -// @ts-ignore -import { Buffer } from "buffer"; - -import { fromBase64, toUint8Array } from "js-base64"; -import { BlobWorker } from "threads"; -// @ts-ignore -import type { WorkerImplementation } from "threads/dist/types/master"; - -import { LazyLoader } from "../interfaces.js"; - -export class InlinedWorkerLoader extends LazyLoader { - constructor(b64script: string) { - super(() => { - const script = fromBase64(b64script); - return BlobWorker.fromText(script); - }); - } -} - -export class InlinedWasmLoader extends LazyLoader { - constructor(b64wasm: string) { - super(() => { - const wasm = toUint8Array(b64wasm); - return Buffer.from(wasm); - }); - } -} diff --git a/packages/core/js-client/src/marine/deps-loader/node.ts b/packages/core/js-client/src/marine/deps-loader/node.ts index 2a118afd0..bd7fee514 100644 --- a/packages/core/js-client/src/marine/deps-loader/node.ts +++ b/packages/core/js-client/src/marine/deps-loader/node.ts @@ -14,16 +14,13 @@ * limitations under the License. */ -// @ts-ignore -// @ts-ignore import { Buffer } from "buffer"; -import * as fs from "fs"; +import fs from "fs"; import { createRequire } from "module"; -import * as path from "path"; - -import { Worker } from "threads"; -import type { WorkerImplementation } from "threads/dist/types/master"; +import path from "path"; +import { Worker } from "../../../node_modules/threads/dist/index.js"; +import type { WorkerImplementation } from "../../../node_modules/threads/dist/types/master.js"; import { LazyLoader } from "../interfaces.js"; const require = createRequire(import.meta.url); diff --git a/packages/core/js-client/src/marine/deps-loader/web.ts b/packages/core/js-client/src/marine/deps-loader/web.ts deleted file mode 100644 index 0784bd8a3..000000000 --- a/packages/core/js-client/src/marine/deps-loader/web.ts +++ /dev/null @@ -1,72 +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 { Buffer } from "buffer"; - -import type { WorkerImplementation } from "threads/dist/types/master"; - -import { LazyLoader } from "../interfaces.js"; -// @ts-ignore - -const bufferToSharedArrayBuffer = (buffer: Buffer): SharedArrayBuffer => { - const sab = new SharedArrayBuffer(buffer.length); - const tmp = new Uint8Array(sab); - tmp.set(buffer, 0); - return sab; -}; - -/** - * Load wasm file from the server. Only works in browsers. - * The function will try load file into SharedArrayBuffer if the site is cross-origin isolated. - * Otherwise the return value fallbacks to Buffer which is less performant but is still compatible with FluenceAppService methods. - * We strongly recommend to set-up cross-origin headers. For more details see: See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements - * Filename is relative to current origin. - * @param filePath - path to the wasm file relative to current origin - * @returns Either SharedArrayBuffer or Buffer with the wasm file - */ -export const loadWasmFromUrl = async ( - filePath: string, -): Promise => { - const fullUrl = window.location.origin + "/" + filePath; - const res = await fetch(fullUrl); - const ab = await res.arrayBuffer(); - new Uint8Array(ab); - const buffer = Buffer.from(ab); - - // only convert to shared buffers if necessary CORS headers have been set: - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements - if (crossOriginIsolated) { - return bufferToSharedArrayBuffer(buffer); - } - - return buffer; -}; - -export class WasmLoaderFromUrl extends LazyLoader { - constructor(filePath: string) { - super(() => { - return loadWasmFromUrl(filePath); - }); - } -} - -export class WorkerLoaderFromUrl extends LazyLoader { - constructor(scriptPath: string) { - super(() => { - return new Worker(scriptPath); - }); - } -} diff --git a/packages/core/js-client/src/marine/interfaces.ts b/packages/core/js-client/src/marine/interfaces.ts index ccbd7cf13..afc875231 100644 --- a/packages/core/js-client/src/marine/interfaces.ts +++ b/packages/core/js-client/src/marine/interfaces.ts @@ -19,15 +19,10 @@ import { InterpreterResult, RunParameters, } from "@fluencelabs/avm"; -import type { WorkerImplementation } from "threads/dist/types/master"; +import { JSONObject, JSONValue, JSONArray } from "@fluencelabs/interfaces"; -import { - IStartable, - JSONArray, - JSONObject, - CallParameters, -} from "../util/commonTypes.js"; -// @ts-ignore +import type { WorkerImplementation } from "../../node_modules/threads/dist/types/master.js"; +import { IStartable, CallParameters } from "../util/commonTypes.js"; /** * Contract for marine host implementations. Marine host is responsible for creating calling and removing marine services @@ -59,7 +54,7 @@ export interface IMarineHost extends IStartable { functionName: string, args: JSONArray | JSONObject, callParams: CallParameters, - ): Promise; + ): Promise; } /** @@ -96,7 +91,7 @@ export interface IWasmLoader * Interface for something which can thread.js based worker */ export interface IWorkerLoader - extends IValueLoader, + extends IValueLoader>, IStartable {} /** diff --git a/packages/core/js-client/src/marine/worker-script/workerLoader.ts b/packages/core/js-client/src/marine/worker-script/workerLoader.ts index af63adaab..d895c0c25 100644 --- a/packages/core/js-client/src/marine/worker-script/workerLoader.ts +++ b/packages/core/js-client/src/marine/worker-script/workerLoader.ts @@ -14,11 +14,10 @@ * limitations under the License. */ -// @ts-ignore -import { Worker } from "threads"; -import type { WorkerImplementation } from "threads/dist/types/master"; +import { Worker } from "../../../node_modules/threads/dist/index.js"; +// eslint-disable-next-line import/order +import type { WorkerImplementation } from "../../../node_modules/threads/dist/types/master.js"; -// @ts-ignore import { LazyLoader } from "../interfaces.js"; export class WorkerLoader extends LazyLoader { diff --git a/packages/core/js-client/src/marine/worker/index.ts b/packages/core/js-client/src/marine/worker/index.ts index e59aa4d7f..8ad908165 100644 --- a/packages/core/js-client/src/marine/worker/index.ts +++ b/packages/core/js-client/src/marine/worker/index.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +import { JSONValue } from "@fluencelabs/interfaces"; import type { JSONArray, JSONObject, @@ -21,14 +22,17 @@ import type { } from "@fluencelabs/marine-js/dist/types"; import { LogFunction, logLevelToEnv } from "@fluencelabs/marine-js/dist/types"; import type { MarineBackgroundInterface } from "@fluencelabs/marine-worker"; -// @ts-ignore -import { spawn, Thread } from "threads"; +import { + ModuleThread, + Thread, + spawn, +} from "../../../node_modules/threads/dist/master/index.js"; import { MarineLogger, marineLogger } from "../../util/logger.js"; import { IMarineHost, IWasmLoader, IWorkerLoader } from "../interfaces.js"; export class MarineBackgroundRunner implements IMarineHost { - private workerThread?: MarineBackgroundInterface; + private workerThread?: ModuleThread; private loggers = new Map(); @@ -39,7 +43,7 @@ export class MarineBackgroundRunner implements IMarineHost { ) {} async hasService(serviceId: string) { - if (!this.workerThread) { + if (this.workerThread == null) { throw new Error("Worker is not initialized"); } @@ -47,7 +51,7 @@ export class MarineBackgroundRunner implements IMarineHost { } async removeService(serviceId: string) { - if (!this.workerThread) { + if (this.workerThread == null) { throw new Error("Worker is not initialized"); } @@ -55,7 +59,7 @@ export class MarineBackgroundRunner implements IMarineHost { } async start(): Promise { - if (this.workerThread) { + if (this.workerThread != null) { throw new Error("Worker thread already initialized"); } @@ -67,18 +71,21 @@ export class MarineBackgroundRunner implements IMarineHost { await this.workerLoader.start(); const worker = await this.workerLoader.getValue(); - const workerThread = await spawn(worker); + const workerThread: ModuleThread = + await spawn(worker); const logfn: LogFunction = (message) => { const serviceLogger = this.loggers.get(message.service); - if (!serviceLogger) { + if (serviceLogger == null) { return; } serviceLogger[message.level](message.message); }; + // @ts-expect-error This type is bugged + // eslint-disable-next-line @typescript-eslint/no-unsafe-call workerThread.onLogMessage().subscribe(logfn); await workerThread.init(wasm); this.workerThread = workerThread; @@ -89,7 +96,7 @@ export class MarineBackgroundRunner implements IMarineHost { serviceModule: ArrayBuffer | SharedArrayBuffer, serviceId: string, ): Promise { - if (!this.workerThread) { + if (this.workerThread == null) { throw new Error("Worker is not initialized"); } @@ -105,8 +112,8 @@ export class MarineBackgroundRunner implements IMarineHost { functionName: string, args: JSONArray | JSONObject, callParams: CallParameters, - ): Promise { - if (!this.workerThread) { + ): Promise { + if (this.workerThread == null) { throw "Worker is not initialized"; } @@ -119,7 +126,7 @@ export class MarineBackgroundRunner implements IMarineHost { } async stop(): Promise { - if (!this.workerThread) { + if (this.workerThread == null) { return; } diff --git a/packages/core/js-client/src/particle/Particle.ts b/packages/core/js-client/src/particle/Particle.ts index d5271fabc..8ac57a70d 100644 --- a/packages/core/js-client/src/particle/Particle.ts +++ b/packages/core/js-client/src/particle/Particle.ts @@ -20,12 +20,23 @@ import { CallResultsArray } from "@fluencelabs/avm"; import { fromUint8Array, toUint8Array } from "js-base64"; import { concat } from "uint8arrays/concat"; import { v4 as uuidv4 } from "uuid"; +import { z } from "zod"; import { KeyPair } from "../keypair/index.js"; import { numberToLittleEndianBytes } from "../util/bytes.js"; import { IParticle } from "./interfaces.js"; +const particleSchema = z.object({ + id: z.string(), + timestamp: z.number().positive(), + script: z.string(), + data: z.string(), + ttl: z.number().positive(), + init_peer_id: z.string(), + signature: z.array(z.number()), +}); + export class Particle implements IParticle { constructor( readonly id: string, @@ -61,17 +72,23 @@ export class Particle implements IParticle { static fromString(str: string): Particle { const json = JSON.parse(str); - const res = new Particle( - json.id, - json.timestamp, - json.script, - toUint8Array(json.data), - json.ttl, - json.init_peer_id, - new Uint8Array(json.signature), - ); + const res = particleSchema.safeParse(json); + + if (!res.success) { + throw new Error(`Particle format invalid. Given: ${str}`); + } + + const data = res.data; - return res; + return new Particle( + data.id, + data.timestamp, + data.script, + toUint8Array(data.data), + data.ttl, + data.init_peer_id, + new Uint8Array(data.signature), + ); } } @@ -111,11 +128,11 @@ export const hasExpired = (particle: IParticle): boolean => { /** * Validates that particle signature is correct */ -export const verifySignature = async ( - particle: IParticle, - publicKey: Uint8Array, -): Promise => { - // TODO: Uncomment this when nox roll out particle signatures +export const verifySignature = async () // particle: IParticle, +// publicKey: Uint8Array, +// eslint-disable-next-line @typescript-eslint/require-await +: Promise => { + // TODO: Uncomment this when nox rolls out particle signatures return true; // const message = buildParticleMessage(particle); // return unmarshalPublicKey(publicKey).verify(message, particle.signature); @@ -139,13 +156,6 @@ export const cloneWithNewData = ( ); }; -/** - * Creates a deep copy of a particle - */ -export const fullClone = (particle: IParticle): IParticle => { - return JSON.parse(JSON.stringify(particle)); -}; - /** * Serializes particle into string suitable for sending through network */ @@ -158,7 +168,7 @@ export const serializeToString = (particle: IParticle): string => { ttl: particle.ttl, script: particle.script, signature: Array.from(particle.signature), - data: particle.data && fromUint8Array(particle.data), + data: fromUint8Array(particle.data), }); }; diff --git a/packages/core/js-client/src/services/NodeUtils.ts b/packages/core/js-client/src/services/NodeUtils.ts index cd91be5bc..4cada01b2 100644 --- a/packages/core/js-client/src/services/NodeUtils.ts +++ b/packages/core/js-client/src/services/NodeUtils.ts @@ -17,9 +17,10 @@ import { Buffer } from "buffer"; import * as fs from "fs"; -import { CallParams } from "@fluencelabs/interfaces"; +import { CallParams } from '@fluencelabs/interfaces'; import { FluencePeer } from "../jsPeer/FluencePeer.js"; +import { getErrorMessage } from "../util/utils.js"; import { NodeUtilsDef, registerNodeUtils } from "./_aqua/node-utils.js"; import { SecurityGuard } from "./securityGuard.js"; @@ -45,7 +46,7 @@ export class NodeUtils implements NodeUtilsDef { // Strange enough, but Buffer type works here, while reading with encoding 'utf-8' doesn't const data = await new Promise((resolve, reject) => { fs.readFile(path, (err, data) => { - if (err) { + if (err != null) { reject(err); return; } @@ -56,13 +57,15 @@ export class NodeUtils implements NodeUtilsDef { return { success: true, + // TODO: this is strange bug. + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions content: data as unknown as string, error: null, }; - } catch (err: any) { + } catch (err: unknown) { return { success: false, - error: err.message, + error: getErrorMessage(err), content: null, }; } @@ -70,6 +73,6 @@ export class NodeUtils implements NodeUtilsDef { } // HACK:: security guard functions must be ported to user API -export const doRegisterNodeUtils = (peer: any) => { +export const doRegisterNodeUtils = (peer: FluencePeer) => { registerNodeUtils(peer, "node_utils", new NodeUtils(peer)); }; diff --git a/packages/core/js-client/src/services/Sig.ts b/packages/core/js-client/src/services/Sig.ts index ac6a588d6..bc99ebb52 100644 --- a/packages/core/js-client/src/services/Sig.ts +++ b/packages/core/js-client/src/services/Sig.ts @@ -14,9 +14,8 @@ * limitations under the License. */ -import { CallParams, PeerIdB58 } from "@fluencelabs/interfaces"; +import { CallParams, PeerIdB58 } from '@fluencelabs/interfaces'; -import { FluencePeer } from "../jsPeer/FluencePeer.js"; import { KeyPair } from "../keypair/index.js"; import { SigDef } from "./_aqua/services.js"; @@ -42,13 +41,25 @@ export const defaultSigGuard = (peerId: PeerIdB58) => { ); }; +type SignReturnType = + | { + error: null; + signature: number[]; + success: true; + } + | { + error: string; + signature: null; + success: false; + }; + export class Sig implements SigDef { constructor(private keyPair: KeyPair) {} /** * Configurable security guard for sign method */ - securityGuard: SecurityGuard<"data"> = (params) => { + securityGuard: SecurityGuard<"data"> = () => { return true; }; @@ -65,11 +76,7 @@ export class Sig implements SigDef { async sign( data: number[], callParams: CallParams<"data">, - ): Promise<{ - error: string | null; - signature: number[] | null; - success: boolean; - }> { + ): Promise { if (!this.securityGuard(callParams)) { return { success: false, @@ -97,7 +104,3 @@ export class Sig implements SigDef { ); } } - -export const getDefaultSig = (peer: FluencePeer) => { - peer.registerMarineService; -}; diff --git a/packages/core/js-client/src/services/SingleModuleSrv.ts b/packages/core/js-client/src/services/SingleModuleSrv.ts index 815d6fb65..dcf4241cf 100644 --- a/packages/core/js-client/src/services/SingleModuleSrv.ts +++ b/packages/core/js-client/src/services/SingleModuleSrv.ts @@ -20,6 +20,7 @@ import { CallParams } from "@fluencelabs/interfaces"; import { v4 as uuidv4 } from "uuid"; import { FluencePeer } from "../jsPeer/FluencePeer.js"; +import { getErrorMessage } from "../util/utils.js"; import { SrvDef } from "./_aqua/single-module-srv.js"; import { @@ -28,7 +29,7 @@ import { } from "./securityGuard.js"; export const defaultGuard = (peer: FluencePeer) => { - return allowOnlyParticleOriginatedAt(peer.keyPair.getPeerId()); + return allowOnlyParticleOriginatedAt(peer.keyPair.getPeerId()); }; export class Srv implements SrvDef { @@ -68,11 +69,11 @@ export class Srv implements SrvDef { service_id: newServiceId, error: null, }; - } catch (err: any) { + } catch (err: unknown) { return { success: true, service_id: null, - error: err.message, + error: getErrorMessage(err), }; } } diff --git a/packages/core/js-client/src/services/Tracing.ts b/packages/core/js-client/src/services/Tracing.ts index 989441a40..e304396fe 100644 --- a/packages/core/js-client/src/services/Tracing.ts +++ b/packages/core/js-client/src/services/Tracing.ts @@ -24,6 +24,8 @@ export class Tracing implements TracingDef { event: string, callParams: CallParams<"arrowName" | "event">, ): void { + // This console log is intentional + // eslint-disable-next-line no-console console.log("[%s] (%s) %s", callParams.particleId, arrowName, event); } } diff --git a/packages/core/js-client/src/services/__test__/builtInHandler.spec.ts b/packages/core/js-client/src/services/__test__/builtInHandler.spec.ts index aad5992de..cf826daab 100644 --- a/packages/core/js-client/src/services/__test__/builtInHandler.spec.ts +++ b/packages/core/js-client/src/services/__test__/builtInHandler.spec.ts @@ -14,7 +14,9 @@ * limitations under the License. */ -import { CallParams } from "@fluencelabs/interfaces"; +import assert from "assert"; + +import { CallParams, JSONArray } from "@fluencelabs/interfaces"; import { toUint8Array } from "js-base64"; import { it, describe, expect, test } from "vitest"; @@ -36,6 +38,14 @@ const oneTwoThreeFour = `[ 4 ]`; +interface ServiceCallType { + serviceId: string; + fnName: string; + args: JSONArray; + retCode: 0 | 1; + result: unknown; +} + describe("Tests for default handler", () => { test.each` serviceId | fnName | args | retCode | result @@ -126,7 +136,13 @@ describe("Tests for default handler", () => { `( // "$fnName with $args expected retcode: $retCode and result: $result", - async ({ serviceId, fnName, args, retCode, result }) => { + async ({ + serviceId, + fnName, + args, + retCode, + result, + }: ServiceCallType) => { // arrange const req: CallServiceData = { serviceId: serviceId, @@ -188,7 +204,10 @@ describe("Tests for default handler", () => { retCode: 0, result: { external_addresses: [], + // stringContaining method returns any for some reason + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment node_version: expect.stringContaining("js"), + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment air_version: expect.stringContaining("js"), }, }); @@ -228,22 +247,27 @@ const testDataWrongSig = [ 14, ]; -const makeTetraplet = ( +const makeTestTetraplet = ( initPeerId: string, - serviceId?: string, - fnName?: string, + serviceId: string, + fnName: string, ): CallParams<"data"> => { return { + particleId: "", + timestamp: 0, + ttl: 0, initPeerId: initPeerId, tetraplets: { data: [ { + peer_pk: initPeerId, function_name: fnName, service_id: serviceId, + json_path: "", }, ], }, - } as any; + }; }; describe("Sig service tests", () => { @@ -251,7 +275,10 @@ describe("Sig service tests", () => { const ctx = await context; const sig = new Sig(ctx.peerKeyPair); - const res = await sig.sign(testData, makeTetraplet(ctx.peerId)); + const res = await sig.sign( + testData, + makeTestTetraplet(ctx.peerId, "any_service", "any_func"), + ); expect(res.success).toBe(true); expect(res.signature).toStrictEqual(testDataSig); @@ -279,8 +306,14 @@ describe("Sig service tests", () => { const ctx = await context; const sig = new Sig(ctx.peerKeyPair); - const signature = await sig.sign(testData, makeTetraplet(ctx.peerId)); - const res = await sig.verify(signature.signature as number[], testData); + const signature = await sig.sign( + testData, + makeTestTetraplet(ctx.peerId, "any_service", "any_func"), + ); + + expect(signature.success).toBe(true); + assert(signature.success); + const res = await sig.verify(signature.signature, testData); expect(res).toBe(true); }); @@ -292,10 +325,10 @@ describe("Sig service tests", () => { const signature = await sig.sign( testData, - makeTetraplet(ctx.peerId, "registry", "get_route_bytes"), + makeTestTetraplet(ctx.peerId, "registry", "get_route_bytes"), ); - await expect(signature).toBeDefined(); + expect(signature).toBeDefined(); }); it("sig.sign with defaultSigGuard should not allow particles initiated from incorrect service", async () => { @@ -305,11 +338,11 @@ describe("Sig service tests", () => { const res = await sig.sign( testData, - makeTetraplet(ctx.peerId, "other_service", "other_fn"), + makeTestTetraplet(ctx.peerId, "other_service", "other_fn"), ); - await expect(res.success).toBe(false); - await expect(res.error).toBe("Security guard validation failed"); + expect(res.success).toBe(false); + expect(res.error).toBe("Security guard validation failed"); }); it("sig.sign with defaultSigGuard should not allow particles initiated from other peers", async () => { @@ -319,15 +352,15 @@ describe("Sig service tests", () => { const res = await sig.sign( testData, - makeTetraplet( + makeTestTetraplet( (await KeyPair.randomEd25519()).getPeerId(), "registry", "get_key_bytes", ), ); - await expect(res.success).toBe(false); - await expect(res.error).toBe("Security guard validation failed"); + expect(res.success).toBe(false); + expect(res.error).toBe("Security guard validation failed"); }); it("changing securityGuard should work", async () => { @@ -337,24 +370,24 @@ describe("Sig service tests", () => { const successful1 = await sig.sign( testData, - makeTetraplet(ctx.peerId, "test", "test"), + makeTestTetraplet(ctx.peerId, "test", "test"), ); const unSuccessful1 = await sig.sign( testData, - makeTetraplet(ctx.peerId, "wrong", "wrong"), + makeTestTetraplet(ctx.peerId, "wrong", "wrong"), ); sig.securityGuard = allowServiceFn("wrong", "wrong"); const successful2 = await sig.sign( testData, - makeTetraplet(ctx.peerId, "wrong", "wrong"), + makeTestTetraplet(ctx.peerId, "wrong", "wrong"), ); const unSuccessful2 = await sig.sign( testData, - makeTetraplet(ctx.peerId, "test", "test"), + makeTestTetraplet(ctx.peerId, "test", "test"), ); expect(successful1.success).toBe(true); diff --git a/packages/core/js-client/src/services/__test__/jsonBuiltin.spec.ts b/packages/core/js-client/src/services/__test__/jsonBuiltin.spec.ts index 3a5367a66..7eb918fa5 100644 --- a/packages/core/js-client/src/services/__test__/jsonBuiltin.spec.ts +++ b/packages/core/js-client/src/services/__test__/jsonBuiltin.spec.ts @@ -24,7 +24,7 @@ let peer: FluencePeer; describe("Sig service test suite", () => { afterEach(async () => { - if (peer) { + if (peer != null) { await peer.stop(); } }); @@ -63,7 +63,7 @@ describe("Sig service test suite", () => { ) `; - const promise = new Promise((resolve) => { + const promise = new Promise((resolve) => { peer.internals.regHandler.common("res", "res", (req) => { resolve(req.args); return { @@ -74,7 +74,7 @@ describe("Sig service test suite", () => { }); const p = await peer.internals.createNewParticle(script); - await peer.internals.initiateParticle(p, doNothing); + peer.internals.initiateParticle(p, doNothing); const [ nestedFirst, diff --git a/packages/core/js-client/src/services/__test__/sigService.spec.ts b/packages/core/js-client/src/services/__test__/sigService.spec.ts index 598492b72..1d1406064 100644 --- a/packages/core/js-client/src/services/__test__/sigService.spec.ts +++ b/packages/core/js-client/src/services/__test__/sigService.spec.ts @@ -17,19 +17,20 @@ import * as path from "path"; import * as url from "url"; +import { ServiceDef, ServiceImpl } from '@fluencelabs/interfaces'; import { it, describe, expect, beforeAll } from "vitest"; import { registerService } from "../../compilerSupport/registerService.js"; import { KeyPair } from "../../keypair/index.js"; -import { compileAqua, withPeer } from "../../util/testUtils.js"; +import { compileAqua, CompiledFnCall, withPeer } from "../../util/testUtils.js"; import { allowServiceFn } from "../securityGuard.js"; import { Sig } from "../Sig.js"; const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); -let aqua: any; -let sigDef: any; -let dataProviderDef: any; +let aqua: Record; +let sigDef: ServiceDef; +let dataProviderDef: ServiceDef; describe("Sig service test suite", () => { beforeAll(async () => { @@ -41,8 +42,8 @@ describe("Sig service test suite", () => { const { services, functions } = await compileAqua(pathToAquaFiles); aqua = functions; - sigDef = services.Sig; - dataProviderDef = services.DataProvider; + sigDef = services["Sig"]; + dataProviderDef = services["DataProvider"]; }); it("Use custom sig service, success path", async () => { @@ -55,7 +56,9 @@ describe("Sig service test suite", () => { peer, def: sigDef, serviceId: "CustomSig", - service: customSig, + // TODO: fix this after changing registerService signature + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + service: customSig as unknown as ServiceImpl, }); registerService({ @@ -71,12 +74,14 @@ describe("Sig service test suite", () => { customSig.securityGuard = allowServiceFn("data", "provide_data"); - const result = await aqua.callSig(peer, { sigId: "CustomSig" }); + const result = await aqua["callSig"](peer, { sigId: "CustomSig" }); - expect(result.success).toBe(true); + expect(result).toHaveProperty("success", true); const isSigCorrect = await customSig.verify( - result.signature as number[], + // TODO: Use compiled ts wrappers + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + (result as { signature: number[] }).signature, data, ); @@ -94,7 +99,9 @@ describe("Sig service test suite", () => { peer, def: sigDef, serviceId: "CustomSig", - service: customSig, + // TODO: fix this after changing registerService signature + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + service: customSig as unknown as ServiceImpl, }); registerService({ @@ -110,8 +117,8 @@ describe("Sig service test suite", () => { customSig.securityGuard = allowServiceFn("wrong", "wrong"); - const result = await aqua.callSig(peer, { sigId: "CustomSig" }); - expect(result.success).toBe(false); + const result = await aqua["callSig"](peer, { sigId: "CustomSig" }); + expect(result).toHaveProperty("success", false); }); }); @@ -132,32 +139,45 @@ describe("Sig service test suite", () => { }, }); - const callAsSigRes = await aqua.callSig(peer, { sigId: "sig" }); + const callAsSigRes = await aqua["callSig"](peer, { sigId: "sig" }); - const callAsPeerIdRes = await aqua.callSig(peer, { + const callAsPeerIdRes = await aqua["callSig"](peer, { sigId: peer.keyPair.getPeerId(), }); - expect(callAsSigRes.success).toBe(false); - expect(callAsPeerIdRes.success).toBe(false); + expect(callAsSigRes).toHaveProperty("success", false); + expect(callAsPeerIdRes).toHaveProperty("success", false); sig.securityGuard = () => { return true; }; - const callAsSigResAfterGuardChange = await aqua.callSig(peer, { + const callAsSigResAfterGuardChange = await aqua["callSig"](peer, { sigId: "sig", }); - const callAsPeerIdResAfterGuardChange = await aqua.callSig(peer, { - sigId: peer.keyPair.getPeerId(), - }); + const callAsPeerIdResAfterGuardChange = await aqua["callSig"]( + peer, + { + sigId: peer.keyPair.getPeerId(), + }, + ); + + expect(callAsSigResAfterGuardChange).toHaveProperty( + "success", + true, + ); - expect(callAsSigResAfterGuardChange.success).toBe(true); - expect(callAsPeerIdResAfterGuardChange.success).toBe(true); + expect(callAsPeerIdResAfterGuardChange).toHaveProperty( + "success", + true, + ); const isValid = await sig.verify( - callAsSigResAfterGuardChange.signature as number[], + // TODO: Use compiled ts wrappers + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + (callAsSigResAfterGuardChange as { signature: number[] }) + .signature, data, ); diff --git a/packages/core/js-client/src/services/__test__/srv.spec.ts b/packages/core/js-client/src/services/__test__/srv.spec.ts index 3f3a8605c..d76997988 100644 --- a/packages/core/js-client/src/services/__test__/srv.spec.ts +++ b/packages/core/js-client/src/services/__test__/srv.spec.ts @@ -19,12 +19,12 @@ import * as url from "url"; import { it, describe, expect, beforeAll } from "vitest"; -import { compileAqua, withPeer } from "../../util/testUtils.js"; +import { compileAqua, CompiledFnCall, withPeer } from "../../util/testUtils.js"; import { registerNodeUtils } from "../_aqua/node-utils.js"; import { NodeUtils } from "../NodeUtils.js"; const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); -let aqua: any; +let aqua: Record; describe("Srv service test suite", () => { beforeAll(async () => { @@ -33,7 +33,7 @@ describe("Srv service test suite", () => { "../../../aqua_test/srv.aqua", ); - const { services, functions } = await compileAqua(pathToAquaFiles); + const { functions } = await compileAqua(pathToAquaFiles); aqua = functions; }); @@ -48,7 +48,7 @@ describe("Srv service test suite", () => { ); // act - const res = await aqua.happy_path(peer, { file_path: wasm }); + const res = await aqua["happy_path"](peer, { file_path: wasm }); // assert expect(res).toBe("Hi, test"); @@ -66,7 +66,7 @@ describe("Srv service test suite", () => { ); // act - const res = await aqua.list_services(peer, { file_path: wasm }); + const res = await aqua["list_services"](peer, { file_path: wasm }); // assert expect(res).toHaveLength(3); @@ -84,7 +84,9 @@ describe("Srv service test suite", () => { ); // act - const res = await aqua.service_removed(peer, { file_path: wasm }); + const res = await aqua["service_removed"](peer, { + file_path: wasm, + }); // assert expect(res).toMatch("No service found for service call"); @@ -97,7 +99,7 @@ describe("Srv service test suite", () => { registerNodeUtils(peer, "node_utils", new NodeUtils(peer)); // act - const res = await aqua.file_not_found(peer, {}); + const res = await aqua["file_not_found"](peer, {}); // assert expect(res).toMatch( @@ -112,7 +114,7 @@ describe("Srv service test suite", () => { registerNodeUtils(peer, "node_utils", new NodeUtils(peer)); // act - const res = await aqua.removing_non_exiting(peer, {}); + const res = await aqua["removing_non_exiting"](peer, {}); // assert expect(res).toMatch("Service with id random_id not found"); diff --git a/packages/core/js-client/src/services/_aqua/node-utils.ts b/packages/core/js-client/src/services/_aqua/node-utils.ts index be9379546..7a855b107 100644 --- a/packages/core/js-client/src/services/_aqua/node-utils.ts +++ b/packages/core/js-client/src/services/_aqua/node-utils.ts @@ -17,9 +17,11 @@ /** * This compiled aqua file was modified to make it work in monorepo */ -import { CallParams, IFluenceInternalApi } from "@fluencelabs/interfaces"; +import { CallParams, ServiceImpl } from "@fluencelabs/interfaces"; import { registerService } from "../../compilerSupport/registerService.js"; +import { FluencePeer } from "../../jsPeer/FluencePeer.js"; +import { NodeUtils } from '../NodeUtils.js'; // Services @@ -37,13 +39,15 @@ export interface NodeUtilsDef { } export function registerNodeUtils( - peer: IFluenceInternalApi, + peer: FluencePeer, serviceId: string, - service: any, + service: NodeUtils, ) { registerService({ peer, - service, + // TODO: fix this after changing registerService signature + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + service: { ...service } as unknown as ServiceImpl, serviceId, def: { defaultServiceId: "node_utils", diff --git a/packages/core/js-client/src/services/_aqua/services.ts b/packages/core/js-client/src/services/_aqua/services.ts index eb7d9dc2a..14f113bb2 100644 --- a/packages/core/js-client/src/services/_aqua/services.ts +++ b/packages/core/js-client/src/services/_aqua/services.ts @@ -17,9 +17,11 @@ /** * This compiled aqua file was modified to make it work in monorepo */ -import { CallParams, IFluenceInternalApi } from "@fluencelabs/interfaces"; +import { CallParams, ServiceImpl } from "@fluencelabs/interfaces"; import { registerService } from "../../compilerSupport/registerService.js"; +import { FluencePeer } from "../../jsPeer/FluencePeer.js"; +import { Sig } from '../Sig.js'; // Services @@ -43,13 +45,15 @@ export interface SigDef { } export function registerSig( - peer: IFluenceInternalApi, + peer: FluencePeer, serviceId: string, - service: any, + service: Sig, ) { registerService({ peer, - service, + // TODO: fix this after changing registerService signature + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + service: service as unknown as ServiceImpl, serviceId, def: { defaultServiceId: "sig", diff --git a/packages/core/js-client/src/services/_aqua/single-module-srv.ts b/packages/core/js-client/src/services/_aqua/single-module-srv.ts index 027e46a41..b5504cf0e 100644 --- a/packages/core/js-client/src/services/_aqua/single-module-srv.ts +++ b/packages/core/js-client/src/services/_aqua/single-module-srv.ts @@ -17,9 +17,11 @@ /** * This compiled aqua file was modified to make it work in monorepo */ -import { CallParams, IFluenceInternalApi } from "@fluencelabs/interfaces"; +import { CallParams, ServiceImpl } from '@fluencelabs/interfaces'; import { registerService } from "../../compilerSupport/registerService.js"; +import { FluencePeer } from "../../jsPeer/FluencePeer.js"; +import { Srv } from '../SingleModuleSrv.js'; // Services @@ -44,14 +46,16 @@ export interface SrvDef { } export function registerSrv( - peer: IFluenceInternalApi, + peer: FluencePeer, serviceId: string, - service: any, + service: Srv, ) { registerService({ peer, serviceId, - service, + // TODO: fix this after changing registerService signature + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + service: service as unknown as ServiceImpl, def: { defaultServiceId: "single_module_srv", functions: { diff --git a/packages/core/js-client/src/services/_aqua/tracing.ts b/packages/core/js-client/src/services/_aqua/tracing.ts index 81a9777da..909b920ba 100644 --- a/packages/core/js-client/src/services/_aqua/tracing.ts +++ b/packages/core/js-client/src/services/_aqua/tracing.ts @@ -17,9 +17,11 @@ /** * This compiled aqua file was modified to make it work in monorepo */ -import { CallParams, IFluenceInternalApi } from "@fluencelabs/interfaces"; +import { CallParams, ServiceImpl } from '@fluencelabs/interfaces'; import { registerService } from "../../compilerSupport/registerService.js"; +import { FluencePeer } from "../../jsPeer/FluencePeer.js"; +import { Tracing } from '../Tracing.js'; // Services @@ -32,14 +34,16 @@ export interface TracingDef { } export function registerTracing( - peer: IFluenceInternalApi, + peer: FluencePeer, serviceId: string, - service: any, + service: Tracing, ) { registerService({ peer, serviceId, - service, + // TODO: fix this after changing registerService signature + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + service: service as unknown as ServiceImpl, def: { defaultServiceId: "tracingSrv", functions: { diff --git a/packages/core/js-client/src/services/builtins.ts b/packages/core/js-client/src/services/builtins.ts index 4608c7ccb..0963fabaf 100644 --- a/packages/core/js-client/src/services/builtins.ts +++ b/packages/core/js-client/src/services/builtins.ts @@ -14,31 +14,43 @@ * limitations under the License. */ +import assert from "assert"; import { Buffer } from "buffer"; -import { CallServiceResult } from "@fluencelabs/avm"; -import * as bs58 from "bs58"; +import { JSONValue } from "@fluencelabs/interfaces"; +import { encode, decode } from "bs58"; import { sha256 } from "multiformats/hashes/sha2"; import { + CallServiceResult, + CallServiceResultType, GenericCallServiceHandler, ResultCodes, } from "../jsServiceHost/interfaces.js"; -import { isString, jsonify } from "../util/utils.js"; +import { getErrorMessage, isString, jsonify } from "../util/utils.js"; -//@ts-ignore -const { encode, decode } = bs58.default; - -const success = (result: any): CallServiceResult => { +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 => { return { - result: result, + // TODO: Remove type assertion after adding validation to builtin inputs + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + result: result as CallServiceResultType, retCode: ResultCodes.success, }; }; -const error = (error: string): CallServiceResult => { +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 => { return { - result: error, + // TODO: Remove type assertion after adding validation to builtin inputs + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + result: error as CallServiceResultType, retCode: ResultCodes.error, }; }; @@ -49,16 +61,16 @@ const errorNotImpl = (methodName: string) => { ); }; -const makeJsonImpl = (args: Array) => { +const makeJsonImpl = (args: [Record, ...JSONValue[]]) => { const [obj, ...kvs] = args; - const toMerge: Record = {}; + const toMerge: Record = {}; for (let i = 0; i < kvs.length / 2; i++) { const k = kvs[i * 2]; if (!isString(k)) { - return error(`Argument ${k} is expected to be string`); + return error(`Argument ${i * 2 + 1} is expected to be string`); } const v = kvs[i * 2 + 1]; @@ -69,6 +81,7 @@ const makeJsonImpl = (args: Array) => { return success(res); }; +// TODO: These assert made for silencing more stricter ts rules. Will be fixed in DXJ-493 export const builtInServices: Record< string, Record @@ -113,6 +126,10 @@ export const builtInServices: Record< const durationMs = req.args[0]; const message = req.args[1]; + assert( + typeof durationMs === "number" && typeof message === "string", + ); + return new Promise((resolve) => { setTimeout(() => { const res = success(message); @@ -234,6 +251,7 @@ export const builtInServices: Record< req.args.length, ); } else { + assert(Array.isArray(req.args[0])); return success(req.args[0].length); } }, @@ -250,13 +268,13 @@ export const builtInServices: Record< concat: (req) => { const incorrectArgIndices = req.args // - .map((x, i) => { + .map((x, i): [boolean, number] => { return [Array.isArray(x), i]; }) - .filter(([isArray, _]) => { + .filter(([isArray]) => { return !isArray; }) - .map(([_, index]) => { + .map(([index]) => { return index; }); @@ -266,7 +284,9 @@ export const builtInServices: Record< `All arguments of 'concat' must be arrays: arguments ${str} are not`, ); } else { - return success([].concat.apply([], req.args)); + // TODO: remove after adding validation + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + return success([].concat(...(req.args as never[][]))); } }, @@ -274,7 +294,10 @@ export const builtInServices: Record< if (req.args.length !== 1) { return error("string_to_b58 accepts only one string argument"); } else { - return success(encode(new TextEncoder().encode(req.args[0]))); + const [input] = req.args; + // TODO: remove after adding validation + assert(typeof input === "string"); + return success(encode(new TextEncoder().encode(input))); } }, @@ -284,7 +307,10 @@ export const builtInServices: Record< "string_from_b58 accepts only one string argument", ); } else { - return success(new TextDecoder().decode(decode(req.args[0]))); + const [input] = req.args; + // TODO: remove after adding validation + assert(typeof input === "string"); + return success(new TextDecoder().decode(decode(input))); } }, @@ -294,6 +320,8 @@ export const builtInServices: Record< "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(encode(new Uint8Array(argumentArray))); } @@ -303,32 +331,33 @@ export const builtInServices: Record< if (req.args.length !== 1) { return error("bytes_from_b58 accepts only one string argument"); } else { - return success(Array.from(decode(req.args[0]))); + const [input] = req.args; + // TODO: remove after adding validation + assert(typeof input === "string"); + return success(Array.from(decode(input))); } }, sha256_string: async (req) => { - if (req.args.length < 1 || req.args.length > 3) { + if (req.args.length !== 1) { return error( - `sha256_string accepts 1-3 arguments, found: ${req.args.length}`, + `sha256_string accepts 1 argument, found: ${req.args.length}`, ); } else { - const [input, digestOnly, asBytes] = req.args; + const [input] = req.args; + // TODO: remove after adding validation + assert(typeof input === "string"); const inBuffer = Buffer.from(input); const multihash = await sha256.digest(inBuffer); - const outBytes = digestOnly - ? multihash.digest - : multihash.bytes; - - const res = asBytes ? Array.from(outBytes) : encode(outBytes); - - return success(res); + return success(encode(multihash.bytes)); } }, concat_strings: (req) => { - const res = "".concat(...req.args); + // TODO: remove after adding validation + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + const res = "".concat(...(req.args as string[])); return success(res); }, }, @@ -353,88 +382,104 @@ export const builtInServices: Record< add: (req) => { let err; - if ((err = checkForArgumentsCount(req, 2))) { + 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"); return success(x + y); }, sub: (req) => { let err; - if ((err = checkForArgumentsCount(req, 2))) { + 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"); return success(x - y); }, mul: (req) => { let err; - if ((err = checkForArgumentsCount(req, 2))) { + 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"); return success(x * y); }, fmul: (req) => { let err; - if ((err = checkForArgumentsCount(req, 2))) { + 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"); return success(Math.floor(x * y)); }, div: (req) => { let err; - if ((err = checkForArgumentsCount(req, 2))) { + 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"); return success(Math.floor(x / y)); }, rem: (req) => { let err; - if ((err = checkForArgumentsCount(req, 2))) { + 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"); return success(x % y); }, pow: (req) => { let err; - if ((err = checkForArgumentsCount(req, 2))) { + 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"); return success(Math.pow(x, y)); }, log: (req) => { let err; - if ((err = checkForArgumentsCount(req, 2))) { + 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"); return success(Math.log(y) / Math.log(x)); }, }, @@ -443,55 +488,65 @@ export const builtInServices: Record< gt: (req) => { let err; - if ((err = checkForArgumentsCount(req, 2))) { + 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"); return success(x > y); }, gte: (req) => { let err; - if ((err = checkForArgumentsCount(req, 2))) { + 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"); return success(x >= y); }, lt: (req) => { let err; - if ((err = checkForArgumentsCount(req, 2))) { + 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"); return success(x < y); }, lte: (req) => { let err; - if ((err = checkForArgumentsCount(req, 2))) { + 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"); return success(x <= y); }, cmp: (req) => { let err; - if ((err = checkForArgumentsCount(req, 2))) { + 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"); return success(x === y ? 0 : x > y ? 1 : -1); }, }, @@ -500,13 +555,15 @@ export const builtInServices: Record< sum: (req) => { let err; - if ((err = checkForArgumentsCount(req, 1))) { + if ((err = checkForArgumentsCount(req, 1)) != null) { return err; } - const [xs] = req.args; + // TODO: Remove after adding validation + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + const [xs] = req.args as [number[]]; return success( - xs.reduce((agg: any, cur: any) => { + xs.reduce((agg, cur) => { return agg + cur; }, 0), ); @@ -515,11 +572,13 @@ export const builtInServices: Record< dedup: (req) => { let err; - if ((err = checkForArgumentsCount(req, 1))) { + if ((err = checkForArgumentsCount(req, 1)) != null) { return err; } const [xs] = req.args; + // TODO: Remove after adding validation + assert(Array.isArray(xs)); const set = new Set(xs); return success(Array.from(set)); }, @@ -527,13 +586,15 @@ export const builtInServices: Record< intersect: (req) => { let err; - if ((err = checkForArgumentsCount(req, 2))) { + 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 intersection = xs.filter((x: any) => { + const intersection = xs.filter((x) => { return ys.includes(x); }); @@ -543,13 +604,15 @@ export const builtInServices: Record< diff: (req) => { let err; - if ((err = checkForArgumentsCount(req, 2))) { + 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: unknown) => { + const diff = xs.filter((x) => { return !ys.includes(x); }); @@ -559,18 +622,20 @@ export const builtInServices: Record< sdiff: (req) => { let err; - if ((err = checkForArgumentsCount(req, 2))) { + 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: unknown) => { + ...xs.filter((y) => { return !ys.includes(y); }), - ...ys.filter((x: unknown) => { + ...ys.filter((x) => { return !xs.includes(x); }), ]; @@ -583,53 +648,66 @@ export const builtInServices: Record< obj: (req) => { let err; - if ((err = checkForArgumentsCountEven(req, 1))) { + if ((err = checkForArgumentsCountEven(req)) != null) { return err; } - return makeJsonImpl([{}, ...req.args]); + // TODO: remove after adding validation + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + return makeJsonImpl([{}, ...req.args] as [ + Record, + ...JSONValue[], + ]); }, put: (req) => { let err; - if ((err = checkForArgumentsCount(req, 3))) { + if ((err = checkForArgumentsCount(req, 3)) != null) { return err; } - if ((err = checkForArgumentType(req, 0, "object"))) { + if ((err = checkForArgumentType(req, 0, "object")) != null) { return err; } - return makeJsonImpl(req.args); + return makeJsonImpl( + // TODO: remove after adding validation + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + req.args as [Record, ...JSONValue[]], + ); }, puts: (req) => { let err; - if ((err = checkForArgumentsCountOdd(req, 1))) { + if ((err = checkForArgumentsCountOdd(req)) != null) { return err; } - if ((err = checkForArgumentsCountMoreThan(req, 3))) { + if ((err = checkForArgumentsCountMoreThan(req, 3)) != null) { return err; } - if ((err = checkForArgumentType(req, 0, "object"))) { + if ((err = checkForArgumentType(req, 0, "object")) != null) { return err; } - return makeJsonImpl(req.args); + return makeJsonImpl( + // TODO: remove after adding validation + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + req.args as [Record, ...JSONValue[]], + ); }, stringify: (req) => { let err; - if ((err = checkForArgumentsCount(req, 1))) { + if ((err = checkForArgumentsCount(req, 1)) != null) { return err; } - if ((err = checkForArgumentType(req, 0, "object"))) { + if ((err = checkForArgumentType(req, 0, "object")) != null) { return err; } @@ -641,27 +719,31 @@ export const builtInServices: Record< parse: (req) => { let err; - if ((err = checkForArgumentsCount(req, 1))) { + if ((err = checkForArgumentsCount(req, 1)) != null) { return err; } - if ((err = checkForArgumentType(req, 0, "string"))) { + if ((err = checkForArgumentType(req, 0, "string")) != null) { return err; } const [raw] = req.args; try { + // TODO: Remove after adding validation + assert(typeof raw === "string"); const json = JSON.parse(raw); return success(json); - } catch (err: any) { - return error(err.message); + } catch (err: unknown) { + return error(getErrorMessage(err)); } }, }, "run-console": { print: (req) => { + // This log is intentional + // eslint-disable-next-line no-console console.log(...req.args); return success({}); }, @@ -675,6 +757,8 @@ const checkForArgumentsCount = ( if (req.args.length !== count) { return error(`Expected ${count} argument(s). Got ${req.args.length}`); } + + return null; }; const checkForArgumentsCountMoreThan = ( @@ -686,28 +770,28 @@ const checkForArgumentsCountMoreThan = ( `Expected more than ${count} argument(s). Got ${req.args.length}`, ); } + + return null; }; -const checkForArgumentsCountEven = ( - req: { args: Array }, - count: number, -) => { +const checkForArgumentsCountEven = (req: { args: Array }) => { 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 }, - count: number, -) => { +const checkForArgumentsCountOdd = (req: { args: Array }) => { if (req.args.length % 2 === 0) { return error( `Expected odd number of argument(s). Got ${req.args.length}`, ); } + + return null; }; const checkForArgumentType = ( @@ -722,4 +806,6 @@ const checkForArgumentType = ( `Argument ${index} expected to be of type ${type}, Got ${actual}`, ); } + + return null; }; diff --git a/packages/core/js-client/src/services/securityGuard.ts b/packages/core/js-client/src/services/securityGuard.ts index adc01fc42..de15180f0 100644 --- a/packages/core/js-client/src/services/securityGuard.ts +++ b/packages/core/js-client/src/services/securityGuard.ts @@ -33,7 +33,7 @@ export const allowTetraplet = ( pred: (tetraplet: SecurityTetraplet) => boolean, ): SecurityGuard => { return (params) => { - const t = params.tetraplets.data[0]; + const t = params.tetraplets["data"][0]; return pred(t); }; }; diff --git a/packages/core/js-client/src/util/commonTypes.ts b/packages/core/js-client/src/util/commonTypes.ts index 780d30536..bb2697a8b 100644 --- a/packages/core/js-client/src/util/commonTypes.ts +++ b/packages/core/js-client/src/util/commonTypes.ts @@ -14,19 +14,9 @@ * limitations under the License. */ -export { CallParameters } from "@fluencelabs/marine-js/dist/types"; +export type { CallParameters } from "@fluencelabs/marine-js/dist/types"; export interface IStartable { start(): Promise; stop(): Promise; } - -export type JSONValue = - | string - | number - | boolean - | null - | { [x: string]: JSONValue } - | Array; -export type JSONArray = Array; -export type JSONObject = { [x: string]: JSONValue }; diff --git a/packages/core/js-client/src/util/libp2pUtils.ts b/packages/core/js-client/src/util/libp2pUtils.ts index 6e58c19bd..31777faa2 100644 --- a/packages/core/js-client/src/util/libp2pUtils.ts +++ b/packages/core/js-client/src/util/libp2pUtils.ts @@ -31,7 +31,7 @@ export function relayOptionToMultiaddr(relay: RelayOptions): Multiaddr { export function throwIfHasNoPeerId(ma: Multiaddr): void { const peerId = ma.getPeerId(); - if (!peerId) { + if (peerId == null) { throw new Error( "Specified multiaddr is invalid or missing peer id: " + ma.toString(), diff --git a/packages/core/js-client/src/util/loadClient.ts b/packages/core/js-client/src/util/loadClient.ts deleted file mode 100644 index a4b1b1939..000000000 --- a/packages/core/js-client/src/util/loadClient.ts +++ /dev/null @@ -1,89 +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 type { - CallAquaFunctionType, - ClientConfig, - IFluenceClient, - RegisterServiceType, - RelayOptions, -} from "@fluencelabs/interfaces"; - -type PublicFluenceInterface = { - defaultClient: IFluenceClient | undefined; - clientFactory: ( - relay: RelayOptions, - config?: ClientConfig, - ) => Promise; - callAquaFunction: CallAquaFunctionType; - registerService: RegisterServiceType; -}; - -export const getFluenceInterfaceFromGlobalThis = (): - | PublicFluenceInterface - | undefined => { - // @ts-ignore - return globalThis.fluence; -}; - -// TODO: fix link DXJ-271 -const REJECT_MESSAGE = `Could not load Fluence JS Client library. -If you are using Node.js that probably means that you forgot in install or import the @fluencelabs/js-client.node package. -If you are using a browser, then you probably forgot to add the - - ``` + ```html + + Cool App + + + ``` - If you cannot or don't want to use a CDN, feel free to get the script directly from the [npm package](https://www.npmjs.com/package/@fluencelabs/js-client.web.standalone) and host it yourself. You can find the script in the `/dist` directory of the package. (Note: this option means that developers understand what they are doing and know how to serve this file from their own web server.) + If you cannot or don't want to use a CDN, feel free to get the script directly from the [npm package](https://www.npmjs.com/package/@fluencelabs/js-client.web.standalone) and host it yourself. You can find the script in the `/dist` directory of the package. (Note: this option means that developers understand what they are doing and know how to serve this file from their own web server.) 2. Install the following packages: - ``` - npm i @fluencelabs/js-client.api @fluencelabs/fluence-network-environment - ``` + ``` + npm i @fluencelabs/js-client.api @fluencelabs/fluence-network-environment + ``` 3. Add the following lines at the beginning of your code: - ``` - import { Fluence } from "@fluencelabs/js-client.api"; - import { randomKras } from '@fluencelabs/fluence-network-environment'; + ``` + import { Fluence } from "@fluencelabs/js-client.api"; + import { randomKras } from '@fluencelabs/fluence-network-environment'; - Fluence.connect(randomKras()); - ``` + Fluence.connect(randomKras()); + ``` ### Node.js Apps @@ -48,37 +48,37 @@ Adding the Fluence JS client for your web application is very easy. The Fluence JS Client only supports the ESM format. This implies that a few preliminary steps are required if your project is not already using ESM: -- Add `"type": "module"` to your package.json. -- Replace `"main": "index.js"` with `"exports": "./index.js"` in your package.json. -- Remove `'use strict';` from all JavaScript files. -- Replace all `require()`/`module.export` with `import`/`export`. -- Use only full relative file paths for imports: `import x from '.';` → `import x from './index.js';`. +- Add `"type": "module"` to your package.json. +- Replace `"main": "index.js"` with `"exports": "./index.js"` in your package.json. +- Remove `'use strict';` from all JavaScript files. +- Replace all `require()`/`module.export` with `import`/`export`. +- Use only full relative file paths for imports: `import x from '.';` → `import x from './index.js';`. If you are using TypeScript: -- Make sure you are using TypeScript 4.7 or later. -- Add [`"module": "ESNext", "target": "ESNext", "moduleResolution": "nodenext"`](https://www.typescriptlang.org/tsconfig#module) to your tsconfig.json. -- Use only full relative file paths for imports: `import x from '.';` → `import x from './index.js';`. -- Remove `namespace` usage and use `export` instead. -- You must use a `.js` extension in relative imports even though you're importing `.ts` files. +- Make sure you are using TypeScript 4.7 or later. +- Add [`"module": "ESNext", "target": "ESNext", "moduleResolution": "nodenext"`](https://www.typescriptlang.org/tsconfig#module) to your tsconfig.json. +- Use only full relative file paths for imports: `import x from '.';` → `import x from './index.js';`. +- Remove `namespace` usage and use `export` instead. +- You must use a `.js` extension in relative imports even though you're importing `.ts` files. **Installation:** 1. Install the following packages: - ``` - npm i @fluencelabs/js-client.api"@fluencelabs/js-client.node @fluencelabs/fluence-network-environment - ``` + ``` + npm i @fluencelabs/js-client.api"@fluencelabs/js-client.node @fluencelabs/fluence-network-environment + ``` 2. Add the following lines at the beginning of your code: - ``` - import '@fluencelabs/js-client.node'; - import { Fluence } from "@fluencelabs/js-client.api"; - import { randomKras } from '@fluencelabs/fluence-network-environment'; + ``` + import '@fluencelabs/js-client.node'; + import { Fluence } from "@fluencelabs/js-client.api"; + import { randomKras } from '@fluencelabs/fluence-network-environment'; - Fluence.connect(randomKras()); - ``` + Fluence.connect(randomKras()); + ``` ## Usage in an Application @@ -86,9 +86,9 @@ Once you've added the client, you can compile [Aqua](https://github.com/fluencel 1. Install the package: - ``` - npm i -D @fluencelabs/cli - ``` + ``` + npm i -D @fluencelabs/cli + ``` 2. Add a directory in your project for Aqua code, e.g., `_aqua`. @@ -98,46 +98,46 @@ Once you've added the client, you can compile [Aqua](https://github.com/fluencel 5. To compile Aqua code once, run `npx fluence aqua -i ./_aqua -o ./src/_aqua/`. To watch the changes and to recompile on the fly, add the `-w` flag: `npx fluence aqua -w -i ./_aqua -o ./src/_aqua/`. - **Hint**: it might be a good idea to add these scripts to your `package.json` file. - For example, you project structure could look like this: - - ``` - ┣ _aqua - ┃ ┗ demo.aqua - ┣ src - ┃ ┣ _aqua - ┃ ┃ ┗ demo.ts - ┃ ┗ index.ts - ┣ package-lock.json - ┣ package.json - ┗ tsconfig.json - ``` - - Then, your `package.json` file should include the following lines: - - ``` - { - ... - "scripts": { - ... - "aqua:compile": "fluence aqua -i ./aqua/ -o ./src/_aqua", - "aqua:watch": "fluence aqua -w -i ./aqua/ -o ./src/_aqua" - }, - ... - } - ``` + **Hint**: it might be a good idea to add these scripts to your `package.json` file. + For example, you project structure could look like this: + + ``` + ┣ _aqua + ┃ ┗ demo.aqua + ┣ src + ┃ ┣ _aqua + ┃ ┃ ┗ demo.ts + ┃ ┗ index.ts + ┣ package-lock.json + ┣ package.json + ┗ tsconfig.json + ``` + + Then, your `package.json` file should include the following lines: + + ``` + { + ... + "scripts": { + ... + "aqua:compile": "fluence aqua -i ./aqua/ -o ./src/_aqua", + "aqua:watch": "fluence aqua -w -i ./aqua/ -o ./src/_aqua" + }, + ... + } + ``` 6. Now you can import and call Aqua code from your application like this: - ``` - import { getRelayTime } from "./_aqua/demo"; + ``` + import { getRelayTime } from "./_aqua/demo"; - async function buttonClick() { - const time = await getRelayTime(); - alert("relay time: " + time); - } - ``` + async function buttonClick() { + const time = await getRelayTime(); + alert("relay time: " + time); + } + ``` ## Debug @@ -165,10 +165,10 @@ Star (`*`) character can be used as a wildcard to enable logs for multiple compo ### Index of components: -- `particle`: everything related to particle processing queue -- `aqua`: infrastructure of aqua compiler support -- `connection`: connection layer -- `marine`: Marine JS logs +- `particle`: everything related to particle processing queue +- `aqua`: infrastructure of aqua compiler support +- `connection`: connection layer +- `marine`: Marine JS logs ### Enabling logs in Node.js diff --git a/ci.cjs b/ci.cjs index 4de78e2d8..b0b5758a3 100644 --- a/ci.cjs +++ b/ci.cjs @@ -4,165 +4,163 @@ const fs = require("fs").promises; const path = require("path"); function printUsage() { - console.log( - `Usage: "ci check-consistency" or "ci bump-version %postfix%" or "ci get-version"`, - ); + console.log( + `Usage: "ci check-consistency" or "ci bump-version %postfix%" or "ci get-version"`, + ); } let postfix; const mode = process.argv[2]; function validateArgs() { - switch (mode) { - case "get-version": - return true; - - case "bump-version": - postfix = process.argv[3]; - if (!postfix) { - printUsage(); - process.exit(); - } - return true; - - case "": - case undefined: - case "check-consistency": - return true; - - default: - return false; - } + switch (mode) { + case "get-version": + return true; + + case "bump-version": + postfix = process.argv[3]; + if (!postfix) { + printUsage(); + process.exit(); + } + return true; + + case "": + case undefined: + case "check-consistency": + return true; + + default: + return false; + } } const PATH_TO_PACKAGES = "./packages/"; async function getPackageJsonsRecursive(currentPath) { - return ( - await Promise.all( - (await fs.readdir(currentPath, { withFileTypes: true })) - .filter( - (file) => - file.name !== "node_modules" && - file.name !== "@tests" && - (file.isDirectory() || file.name === "package.json"), - ) - .map((file) => - file.isDirectory() - ? getPackageJsonsRecursive( - path.join(currentPath, file.name), - ) - : Promise.resolve([ - path.join(process.cwd(), currentPath, file.name), - ]), - ), + return ( + await Promise.all( + (await fs.readdir(currentPath, { withFileTypes: true })) + .filter( + (file) => + file.name !== "node_modules" && + file.name !== "@tests" && + (file.isDirectory() || file.name === "package.json"), ) - ).flat(); + .map((file) => + file.isDirectory() + ? getPackageJsonsRecursive(path.join(currentPath, file.name)) + : Promise.resolve([ + path.join(process.cwd(), currentPath, file.name), + ]), + ), + ) + ).flat(); } async function getVersion(file) { - const content = await fs.readFile(file); - const json = JSON.parse(content); - return [json.name, json.version]; + const content = await fs.readFile(file); + const json = JSON.parse(content); + return [json.name, json.version]; } function processDep(obj, name, fn) { - if (!obj) { - return; - } + if (!obj) { + return; + } - if (!obj[name]) { - return; - } + if (!obj[name]) { + return; + } - fn(obj, obj[name]); + fn(obj, obj[name]); } async function getVersionsMap(allPackageJsons) { - return new Map(await Promise.all(allPackageJsons.map(getVersion))); + return new Map(await Promise.all(allPackageJsons.map(getVersion))); } function getVersionForPackageOrThrow(versionsMap, packageName) { - const version = versionsMap.get(packageName); - if (!version) { - console.log("Failed to get version for package: ", packageName); - process.exit(1); - } - return version; + const version = versionsMap.get(packageName); + if (!version) { + console.log("Failed to get version for package: ", packageName); + process.exit(1); + } + return version; } async function checkConsistency(file, versionsMap) { - console.log("Checking: ", file); - const content = await fs.readFile(file); - const json = JSON.parse(content); - - for (const [name, versionInDep] of versionsMap) { - const check = (x, version) => { - if (version.includes("*")) { - return; - } - - if (versionInDep !== version) { - console.log( - `Error, versions don't match: ${name}:${version} !== ${versionInDep}`, - file, - ); - process.exit(1); - } - }; - processDep(json.dependencies, name, check); - processDep(json.devDependencies, name, check); - } + console.log("Checking: ", file); + const content = await fs.readFile(file); + const json = JSON.parse(content); + + for (const [name, versionInDep] of versionsMap) { + const check = (x, version) => { + if (version.includes("*")) { + return; + } + + if (versionInDep !== version) { + console.log( + `Error, versions don't match: ${name}:${version} !== ${versionInDep}`, + file, + ); + process.exit(1); + } + }; + processDep(json.dependencies, name, check); + processDep(json.devDependencies, name, check); + } } async function bumpVersions(file, versionsMap) { - console.log("Updating: ", file); - const content = await fs.readFile(file); - const json = JSON.parse(content); - - // bump dependencies - for (const [name, version] of versionsMap) { - const update = (x) => (x[name] = `${version}-${postfix}`); - processDep(json.dependencies, name, update); - processDep(json.devDependencies, name, update); - } - - // also bump version in package itself - const version = getVersionForPackageOrThrow(versionsMap, json.name); - json.version = `${version}-${postfix}`; - - const newContent = JSON.stringify(json, undefined, 4) + "\n"; - await fs.writeFile(file, newContent); + console.log("Updating: ", file); + const content = await fs.readFile(file); + const json = JSON.parse(content); + + // bump dependencies + for (const [name, version] of versionsMap) { + const update = (x) => (x[name] = `${version}-${postfix}`); + processDep(json.dependencies, name, update); + processDep(json.devDependencies, name, update); + } + + // also bump version in package itself + const version = getVersionForPackageOrThrow(versionsMap, json.name); + json.version = `${version}-${postfix}`; + + const newContent = JSON.stringify(json, undefined, 4) + "\n"; + await fs.writeFile(file, newContent); } async function processPackageJsons(allPackageJsons, versionsMap, fn) { - await Promise.all(allPackageJsons.map((x) => fn(x, versionsMap))); + await Promise.all(allPackageJsons.map((x) => fn(x, versionsMap))); } async function run() { - if (!validateArgs()) { - printUsage(); - process.exit(0); - } - - const packageJsons = await getPackageJsonsRecursive(PATH_TO_PACKAGES); - const versionsMap = await getVersionsMap(packageJsons); - - if (mode === "get-version") { - const fjs = versionsMap.get("@fluencelabs/fluence"); - console.log(fjs); - return; - } - - // always check consistency - console.log("Checking versions consistency..."); - await processPackageJsons(packageJsons, versionsMap, checkConsistency); - console.log("Versions are consistent"); - - if (mode === "bump-version") { - console.log("Adding postfix: ", postfix); - await processPackageJsons(packageJsons, versionsMap, bumpVersions); - console.log("Done"); - } + if (!validateArgs()) { + printUsage(); + process.exit(0); + } + + const packageJsons = await getPackageJsonsRecursive(PATH_TO_PACKAGES); + const versionsMap = await getVersionsMap(packageJsons); + + if (mode === "get-version") { + const fjs = versionsMap.get("@fluencelabs/fluence"); + console.log(fjs); + return; + } + + // always check consistency + console.log("Checking versions consistency..."); + await processPackageJsons(packageJsons, versionsMap, checkConsistency); + console.log("Versions are consistent"); + + if (mode === "bump-version") { + console.log("Adding postfix: ", postfix); + await processPackageJsons(packageJsons, versionsMap, bumpVersions); + console.log("Done"); + } } run(); diff --git a/package.json b/package.json index 5a7b0b47c..a68f9dbdd 100644 --- a/package.json +++ b/package.json @@ -1,38 +1,38 @@ { - "name": "common-dev-deps", - "version": "0.1.0", - "main": "./dist/index.js", - "typings": "./dist/index.d.ts", - "type": "module", - "engines": { - "node": ">=10", - "pnpm": ">=3" - }, - "scripts": { - "lint-check": "pnpm run prettier --check && pnpm run eslint", - "lint-fix": "pnpm run prettier --write && pnpm run eslint --fix", - "prettier": "prettier .", - "eslint": "eslint --cache \"**/src/**/*.{js,ts}\"" - }, - "author": "Fluence Labs", - "license": "Apache-2.0", - "devDependencies": { - "@fluencelabs/aqua": "0.9.1-374", - "@fluencelabs/aqua-lib": "0.6.0", - "@total-typescript/ts-reset": "0.5.1", - "@tsconfig/strictest": "2.0.2", - "@types/node": "18.13.0", - "@typescript-eslint/eslint-plugin": "6.7.3", - "@typescript-eslint/parser": "6.7.3", - "eslint": "8.50.0", - "eslint-config-prettier": "9.0.0", - "eslint-plugin-import": "2.28.1", - "eslint-plugin-license-header": "0.6.0", - "eslint-plugin-unused-imports": "3.0.0", - "http-server": "14.1.1", - "prettier": "3.0.3", - "puppeteer": "19.7.2", - "ts-node": "10.9.1", - "typescript": "5.1.6" - } + "name": "common-dev-deps", + "version": "0.1.0", + "main": "./dist/index.js", + "typings": "./dist/index.d.ts", + "type": "module", + "engines": { + "node": ">=10", + "pnpm": ">=3" + }, + "scripts": { + "lint-check": "pnpm run prettier --check && pnpm run eslint", + "lint-fix": "pnpm run prettier --write && pnpm run eslint --fix", + "prettier": "prettier .", + "eslint": "eslint --cache \"**/src/**/*.{js,ts}\"" + }, + "author": "Fluence Labs", + "license": "Apache-2.0", + "devDependencies": { + "@fluencelabs/aqua": "0.9.1-374", + "@fluencelabs/aqua-lib": "0.6.0", + "@total-typescript/ts-reset": "0.5.1", + "@tsconfig/strictest": "2.0.2", + "@types/node": "18.13.0", + "@typescript-eslint/eslint-plugin": "6.7.3", + "@typescript-eslint/parser": "6.7.3", + "eslint": "8.50.0", + "eslint-config-prettier": "9.0.0", + "eslint-plugin-import": "2.28.1", + "eslint-plugin-license-header": "0.6.0", + "eslint-plugin-unused-imports": "3.0.0", + "http-server": "14.1.1", + "prettier": "3.0.3", + "puppeteer": "19.7.2", + "ts-node": "10.9.1", + "typescript": "5.1.6" + } } diff --git a/packages/@tests/.eslintrc.json b/packages/@tests/.eslintrc.json index 5666faa3f..9d3374e3c 100644 --- a/packages/@tests/.eslintrc.json +++ b/packages/@tests/.eslintrc.json @@ -1,6 +1,6 @@ { - "ignorePatterns": ["**/*.css"], - "rules": { - "no-console": "off" - } + "ignorePatterns": ["**/*.css"], + "rules": { + "no-console": "off" + } } diff --git a/packages/@tests/aqua/package.json b/packages/@tests/aqua/package.json index 26cd59955..91bebb3a5 100644 --- a/packages/@tests/aqua/package.json +++ b/packages/@tests/aqua/package.json @@ -1,29 +1,29 @@ { - "name": "@test/aqua_for_test", - "version": "0.1.0", - "description": "Shared aqua code for tests", - "main": "./dist/index.js", - "typings": "./dist/index.d.ts", - "engines": { - "node": ">=10", - "pnpm": ">=3" - }, - "type": "module", - "scripts": { - "build": "tsc", - "compile-aqua": "fluence aqua -i ./_aqua -o ./src/_aqua" - }, - "repository": "https://github.com/fluencelabs/fluence-js", - "author": "Fluence Labs", - "license": "Apache-2.0", - "dependencies": { - "base64-js": "1.5.1" - }, - "devDependencies": { - "@fluencelabs/aqua-lib": "0.6.0", - "@fluencelabs/cli": "0.7.2", - "@fluencelabs/js-client": "workspace:^", - "@fluencelabs/registry": "0.8.2", - "@fluencelabs/trust-graph": "3.1.2" - } + "name": "@test/aqua_for_test", + "version": "0.1.0", + "description": "Shared aqua code for tests", + "main": "./dist/index.js", + "typings": "./dist/index.d.ts", + "engines": { + "node": ">=10", + "pnpm": ">=3" + }, + "type": "module", + "scripts": { + "build": "tsc", + "compile-aqua": "fluence aqua -i ./_aqua -o ./src/_aqua" + }, + "repository": "https://github.com/fluencelabs/fluence-js", + "author": "Fluence Labs", + "license": "Apache-2.0", + "dependencies": { + "base64-js": "1.5.1" + }, + "devDependencies": { + "@fluencelabs/aqua-lib": "0.6.0", + "@fluencelabs/cli": "0.7.2", + "@fluencelabs/js-client": "workspace:^", + "@fluencelabs/registry": "0.8.2", + "@fluencelabs/trust-graph": "3.1.2" + } } diff --git a/packages/@tests/aqua/src/_aqua/finalize_particle.ts b/packages/@tests/aqua/src/_aqua/finalize_particle.ts index f6d29bb7f..99f035f0d 100644 --- a/packages/@tests/aqua/src/_aqua/finalize_particle.ts +++ b/packages/@tests/aqua/src/_aqua/finalize_particle.ts @@ -9,12 +9,12 @@ * */ import type { - IFluenceClient as IFluenceClient$$, - CallParams as CallParams$$, + IFluenceClient as IFluenceClient$$, + CallParams as CallParams$$, } from "@fluencelabs/js-client"; import { - v5_callFunction as callFunction$$, - v5_registerService as registerService$$, + v5_callFunction as callFunction$$, + v5_registerService as registerService$$, } from "@fluencelabs/js-client"; // Services @@ -36,37 +36,37 @@ export const test_script = ` export function test(config?: { ttl?: number }): Promise; export function test( - peer: IFluenceClient$$, - config?: { ttl?: number }, + peer: IFluenceClient$$, + config?: { ttl?: number }, ): Promise; export function test(...args: any) { - return callFunction$$( - args, - { - 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", - }, + return callFunction$$( + args, + { + functionName: "test", + arrow: { + tag: "arrow", + domain: { + tag: "labeledProduct", + fields: {}, }, - test_script, - ); + codomain: { + tag: "nil", + }, + }, + names: { + relay: "-relay-", + getDataSrv: "getDataSrv", + callbackSrv: "callbackSrv", + responseSrv: "callbackSrv", + responseFnName: "response", + errorHandlingSrv: "errorHandlingSrv", + errorFnName: "error", + }, + }, + test_script, + ); } /* eslint-enable */ diff --git a/packages/@tests/aqua/src/_aqua/smoke_test.ts b/packages/@tests/aqua/src/_aqua/smoke_test.ts index 484c58867..9ca2479c6 100644 --- a/packages/@tests/aqua/src/_aqua/smoke_test.ts +++ b/packages/@tests/aqua/src/_aqua/smoke_test.ts @@ -9,357 +9,357 @@ * */ import type { - IFluenceClient as IFluenceClient$$, - CallParams as CallParams$$, + IFluenceClient as IFluenceClient$$, + CallParams as CallParams$$, } from "@fluencelabs/js-client"; import { - v5_callFunction as callFunction$$, - v5_registerService as registerService$$, + v5_callFunction as callFunction$$, + v5_registerService as registerService$$, } from "@fluencelabs/js-client"; // Services export interface SrvDef { - create: ( - wasm_b64_content: string, - callParams: CallParams$$<"wasm_b64_content">, - ) => - | { error: string | null; service_id: string | null; success: boolean } - | Promise<{ - error: string | null; - service_id: string | null; - success: boolean; - }>; - list: (callParams: CallParams$$) => string[] | Promise; - remove: ( - service_id: string, - callParams: CallParams$$<"service_id">, - ) => - | { error: string | null; success: boolean } - | Promise<{ error: string | null; success: boolean }>; + create: ( + wasm_b64_content: string, + callParams: CallParams$$<"wasm_b64_content">, + ) => + | { error: string | null; service_id: string | null; success: boolean } + | Promise<{ + error: string | null; + service_id: string | null; + success: boolean; + }>; + list: (callParams: CallParams$$) => string[] | Promise; + remove: ( + service_id: string, + callParams: CallParams$$<"service_id">, + ) => + | { 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, + peer: IFluenceClient$$, + serviceId: string, + service: SrvDef, ): void; export function registerSrv(...args: any) { - registerService$$(args, { - defaultServiceId: "single_module_srv", - functions: { + registerService$$(args, { + defaultServiceId: "single_module_srv", + functions: { + tag: "labeledProduct", + fields: { + create: { + tag: "arrow", + domain: { tag: "labeledProduct", fields: { - create: { - tag: "arrow", - domain: { - tag: "labeledProduct", - fields: { - wasm_b64_content: { - tag: "scalar", - name: "string", - }, - }, + wasm_b64_content: { + tag: "scalar", + name: "string", + }, + }, + }, + codomain: { + tag: "unlabeledProduct", + items: [ + { + tag: "struct", + name: "ServiceCreationResult", + fields: { + error: { + tag: "option", + type: { + tag: "scalar", + name: "string", }, - codomain: { - tag: "unlabeledProduct", - items: [ - { - tag: "struct", - name: "ServiceCreationResult", - fields: { - error: { - tag: "option", - type: { - tag: "scalar", - name: "string", - }, - }, - service_id: { - tag: "option", - type: { - tag: "scalar", - name: "string", - }, - }, - success: { - tag: "scalar", - name: "bool", - }, - }, - }, - ], + }, + service_id: { + tag: "option", + type: { + tag: "scalar", + name: "string", }, + }, + success: { + tag: "scalar", + name: "bool", + }, }, - list: { - tag: "arrow", - domain: { - tag: "nil", - }, - codomain: { - tag: "unlabeledProduct", - items: [ - { - tag: "array", - type: { - tag: "scalar", - name: "string", - }, - }, - ], - }, + }, + ], + }, + }, + list: { + tag: "arrow", + domain: { + tag: "nil", + }, + codomain: { + tag: "unlabeledProduct", + items: [ + { + tag: "array", + type: { + tag: "scalar", + name: "string", }, - remove: { - tag: "arrow", - domain: { - tag: "labeledProduct", - fields: { - service_id: { - tag: "scalar", - name: "string", - }, - }, - }, - codomain: { - tag: "unlabeledProduct", - items: [ - { - tag: "struct", - name: "RemoveResult", - fields: { - error: { - tag: "option", - type: { - tag: "scalar", - name: "string", - }, - }, - success: { - tag: "scalar", - name: "bool", - }, - }, - }, - ], + }, + ], + }, + }, + remove: { + tag: "arrow", + domain: { + tag: "labeledProduct", + fields: { + service_id: { + tag: "scalar", + name: "string", + }, + }, + }, + codomain: { + tag: "unlabeledProduct", + items: [ + { + tag: "struct", + name: "RemoveResult", + fields: { + error: { + tag: "option", + type: { + tag: "scalar", + name: "string", }, + }, + success: { + tag: "scalar", + name: "bool", + }, }, - }, + }, + ], + }, }, - }); + }, + }, + }); } export interface CalcServiceDef { - add: ( - num: number, - callParams: CallParams$$<"num">, - ) => number | Promise; - clear_state: (callParams: CallParams$$) => void | Promise; - divide: ( - num: number, - callParams: CallParams$$<"num">, - ) => number | Promise; - multiply: ( - num: number, - callParams: CallParams$$<"num">, - ) => number | Promise; - state: (callParams: CallParams$$) => number | Promise; - subtract: ( - num: number, - callParams: CallParams$$<"num">, - ) => number | Promise; - test_logs: (callParams: CallParams$$) => void | Promise; + add: ( + num: number, + callParams: CallParams$$<"num">, + ) => number | Promise; + clear_state: (callParams: CallParams$$) => void | Promise; + divide: ( + num: number, + callParams: CallParams$$<"num">, + ) => number | Promise; + multiply: ( + num: number, + callParams: CallParams$$<"num">, + ) => number | Promise; + state: (callParams: CallParams$$) => number | Promise; + subtract: ( + num: number, + callParams: CallParams$$<"num">, + ) => number | Promise; + test_logs: (callParams: CallParams$$) => void | Promise; } export function registerCalcService( - serviceId: string, - service: CalcServiceDef, + serviceId: string, + service: CalcServiceDef, ): void; export function registerCalcService( - peer: IFluenceClient$$, - serviceId: string, - service: CalcServiceDef, + peer: IFluenceClient$$, + serviceId: string, + service: CalcServiceDef, ): void; export function registerCalcService(...args: any) { - registerService$$(args, { - functions: { + registerService$$(args, { + functions: { + tag: "labeledProduct", + fields: { + add: { + tag: "arrow", + domain: { tag: "labeledProduct", fields: { - add: { - tag: "arrow", - domain: { - tag: "labeledProduct", - fields: { - num: { - tag: "scalar", - name: "f64", - }, - }, - }, - codomain: { - tag: "unlabeledProduct", - items: [ - { - tag: "scalar", - name: "f64", - }, - ], - }, - }, - clear_state: { - tag: "arrow", - domain: { - tag: "nil", - }, - codomain: { - tag: "nil", - }, - }, - divide: { - tag: "arrow", - domain: { - tag: "labeledProduct", - fields: { - num: { - tag: "scalar", - name: "f64", - }, - }, - }, - codomain: { - tag: "unlabeledProduct", - items: [ - { - tag: "scalar", - name: "f64", - }, - ], - }, - }, - multiply: { - tag: "arrow", - domain: { - tag: "labeledProduct", - fields: { - num: { - tag: "scalar", - name: "f64", - }, - }, - }, - codomain: { - tag: "unlabeledProduct", - items: [ - { - tag: "scalar", - name: "f64", - }, - ], - }, - }, - state: { - tag: "arrow", - domain: { - tag: "nil", - }, - codomain: { - tag: "unlabeledProduct", - items: [ - { - tag: "scalar", - name: "f64", - }, - ], - }, - }, - subtract: { - tag: "arrow", - domain: { - tag: "labeledProduct", - fields: { - num: { - tag: "scalar", - name: "f64", - }, - }, - }, - codomain: { - tag: "unlabeledProduct", - items: [ - { - tag: "scalar", - name: "f64", - }, - ], - }, - }, - test_logs: { - tag: "arrow", - domain: { - tag: "nil", - }, - codomain: { - tag: "nil", - }, - }, + num: { + tag: "scalar", + name: "f64", + }, + }, + }, + codomain: { + tag: "unlabeledProduct", + items: [ + { + tag: "scalar", + name: "f64", + }, + ], + }, + }, + clear_state: { + tag: "arrow", + domain: { + tag: "nil", + }, + codomain: { + tag: "nil", + }, + }, + divide: { + tag: "arrow", + domain: { + tag: "labeledProduct", + fields: { + num: { + tag: "scalar", + name: "f64", + }, + }, + }, + codomain: { + tag: "unlabeledProduct", + items: [ + { + tag: "scalar", + name: "f64", + }, + ], + }, + }, + multiply: { + tag: "arrow", + domain: { + tag: "labeledProduct", + fields: { + num: { + tag: "scalar", + name: "f64", + }, + }, + }, + codomain: { + tag: "unlabeledProduct", + items: [ + { + tag: "scalar", + name: "f64", + }, + ], + }, + }, + state: { + tag: "arrow", + domain: { + tag: "nil", + }, + codomain: { + tag: "unlabeledProduct", + items: [ + { + tag: "scalar", + name: "f64", + }, + ], + }, + }, + subtract: { + tag: "arrow", + domain: { + tag: "labeledProduct", + fields: { + num: { + tag: "scalar", + name: "f64", + }, }, + }, + codomain: { + tag: "unlabeledProduct", + items: [ + { + tag: "scalar", + name: "f64", + }, + ], + }, }, - }); + test_logs: { + tag: "arrow", + domain: { + tag: "nil", + }, + codomain: { + tag: "nil", + }, + }, + }, + }, + }); } export interface HelloWorldDef { - hello: ( - str: string, - callParams: CallParams$$<"str">, - ) => string | Promise; + hello: ( + str: string, + callParams: CallParams$$<"str">, + ) => string | Promise; } export function registerHelloWorld(service: HelloWorldDef): void; export function registerHelloWorld( - serviceId: string, - service: HelloWorldDef, + serviceId: string, + service: HelloWorldDef, ): void; export function registerHelloWorld( - peer: IFluenceClient$$, - service: HelloWorldDef, + peer: IFluenceClient$$, + service: HelloWorldDef, ): void; export function registerHelloWorld( - peer: IFluenceClient$$, - serviceId: string, - service: HelloWorldDef, + peer: IFluenceClient$$, + serviceId: string, + service: HelloWorldDef, ): void; export function registerHelloWorld(...args: any) { - registerService$$(args, { - defaultServiceId: "hello-world", - functions: { + registerService$$(args, { + defaultServiceId: "hello-world", + functions: { + tag: "labeledProduct", + fields: { + hello: { + tag: "arrow", + domain: { tag: "labeledProduct", fields: { - hello: { - tag: "arrow", - domain: { - tag: "labeledProduct", - fields: { - str: { - tag: "scalar", - name: "string", - }, - }, - }, - codomain: { - tag: "unlabeledProduct", - items: [ - { - tag: "scalar", - name: "string", - }, - ], - }, - }, + str: { + tag: "scalar", + name: "string", + }, }, + }, + codomain: { + tag: "unlabeledProduct", + items: [ + { + tag: "scalar", + name: "string", + }, + ], + }, }, - }); + }, + }, + }); } // Functions @@ -585,64 +585,64 @@ export const resourceTest_script = ` export type ResourceTestResult = [string | null, string[]]; export function resourceTest( - label: string, - config?: { ttl?: number }, + label: string, + config?: { ttl?: number }, ): Promise; export function resourceTest( - peer: IFluenceClient$$, - label: string, - config?: { ttl?: number }, + peer: IFluenceClient$$, + label: string, + config?: { ttl?: number }, ): Promise; export function resourceTest(...args: any) { - return callFunction$$( - args, - { - functionName: "resourceTest", - arrow: { - tag: "arrow", - domain: { - tag: "labeledProduct", - fields: { - label: { - tag: "scalar", - name: "string", - }, - }, - }, - codomain: { - tag: "unlabeledProduct", - items: [ - { - tag: "option", - type: { - tag: "scalar", - name: "string", - }, - }, - { - tag: "array", - type: { - tag: "scalar", - name: "string", - }, - }, - ], - }, + return callFunction$$( + args, + { + functionName: "resourceTest", + arrow: { + tag: "arrow", + domain: { + tag: "labeledProduct", + fields: { + label: { + tag: "scalar", + name: "string", }, - names: { - relay: "-relay-", - getDataSrv: "getDataSrv", - callbackSrv: "callbackSrv", - responseSrv: "callbackSrv", - responseFnName: "response", - errorHandlingSrv: "errorHandlingSrv", - errorFnName: "error", + }, + }, + codomain: { + tag: "unlabeledProduct", + items: [ + { + tag: "option", + type: { + tag: "scalar", + name: "string", + }, + }, + { + tag: "array", + type: { + tag: "scalar", + name: "string", + }, }, + ], }, - resourceTest_script, - ); + }, + names: { + relay: "-relay-", + getDataSrv: "getDataSrv", + callbackSrv: "callbackSrv", + responseSrv: "callbackSrv", + responseFnName: "response", + errorHandlingSrv: "errorHandlingSrv", + errorFnName: "error", + }, + }, + resourceTest_script, + ); } export const helloTest_script = ` @@ -661,43 +661,43 @@ export const helloTest_script = ` export function helloTest(config?: { ttl?: number }): Promise; export function helloTest( - peer: IFluenceClient$$, - config?: { ttl?: number }, + peer: IFluenceClient$$, + config?: { ttl?: number }, ): Promise; export function helloTest(...args: any) { - return callFunction$$( - args, - { - functionName: "helloTest", - arrow: { - tag: "arrow", - domain: { - tag: "labeledProduct", - fields: {}, - }, - codomain: { - tag: "unlabeledProduct", - items: [ - { - tag: "scalar", - name: "string", - }, - ], - }, - }, - names: { - relay: "-relay-", - getDataSrv: "getDataSrv", - callbackSrv: "callbackSrv", - responseSrv: "callbackSrv", - responseFnName: "response", - errorHandlingSrv: "errorHandlingSrv", - errorFnName: "error", + return callFunction$$( + args, + { + functionName: "helloTest", + arrow: { + tag: "arrow", + domain: { + tag: "labeledProduct", + fields: {}, + }, + codomain: { + tag: "unlabeledProduct", + items: [ + { + tag: "scalar", + name: "string", }, + ], }, - helloTest_script, - ); + }, + names: { + relay: "-relay-", + getDataSrv: "getDataSrv", + callbackSrv: "callbackSrv", + responseSrv: "callbackSrv", + responseFnName: "response", + errorHandlingSrv: "errorHandlingSrv", + errorFnName: "error", + }, + }, + helloTest_script, + ); } export const callHappy_script = ` @@ -726,95 +726,95 @@ export const callHappy_script = ` `; export function callHappy( - a: string, - b: number, - c: number, - d: ( - arg0: string, - callParams: CallParams$$<"arg0">, - ) => number | Promise, - config?: { ttl?: number }, + a: string, + b: number, + c: number, + d: ( + arg0: string, + callParams: CallParams$$<"arg0">, + ) => number | Promise, + config?: { ttl?: number }, ): Promise; export function callHappy( - peer: IFluenceClient$$, - a: string, - b: number, - c: number, - d: ( - arg0: string, - callParams: CallParams$$<"arg0">, - ) => number | Promise, - config?: { ttl?: number }, + peer: IFluenceClient$$, + a: string, + b: number, + c: number, + d: ( + arg0: string, + callParams: CallParams$$<"arg0">, + ) => number | Promise, + config?: { ttl?: number }, ): Promise; export function callHappy(...args: any) { - return callFunction$$( - args, - { - functionName: "callHappy", - arrow: { - tag: "arrow", - domain: { - tag: "labeledProduct", - fields: { - a: { - tag: "scalar", - name: "string", - }, - b: { - tag: "scalar", - name: "f64", - }, - c: { - tag: "scalar", - name: "f64", - }, - d: { - tag: "arrow", - domain: { - tag: "unlabeledProduct", - items: [ - { - tag: "scalar", - name: "string", - }, - ], - }, - codomain: { - tag: "unlabeledProduct", - items: [ - { - tag: "scalar", - name: "f64", - }, - ], - }, - }, - }, - }, - codomain: { - tag: "unlabeledProduct", - items: [ - { - tag: "scalar", - name: "f64", - }, - ], - }, + return callFunction$$( + args, + { + functionName: "callHappy", + arrow: { + tag: "arrow", + domain: { + tag: "labeledProduct", + fields: { + a: { + tag: "scalar", + name: "string", }, - names: { - relay: "-relay-", - getDataSrv: "getDataSrv", - callbackSrv: "callbackSrv", - responseSrv: "callbackSrv", - responseFnName: "response", - errorHandlingSrv: "errorHandlingSrv", - errorFnName: "error", + b: { + tag: "scalar", + name: "f64", }, + c: { + tag: "scalar", + name: "f64", + }, + d: { + tag: "arrow", + domain: { + tag: "unlabeledProduct", + items: [ + { + tag: "scalar", + name: "string", + }, + ], + }, + codomain: { + tag: "unlabeledProduct", + items: [ + { + tag: "scalar", + name: "f64", + }, + ], + }, + }, + }, }, - callHappy_script, - ); + codomain: { + tag: "unlabeledProduct", + items: [ + { + tag: "scalar", + name: "f64", + }, + ], + }, + }, + names: { + relay: "-relay-", + getDataSrv: "getDataSrv", + callbackSrv: "callbackSrv", + responseSrv: "callbackSrv", + responseFnName: "response", + errorHandlingSrv: "errorHandlingSrv", + errorFnName: "error", + }, + }, + callHappy_script, + ); } export const demo_calculation_script = ` @@ -849,54 +849,54 @@ export const demo_calculation_script = ` `; export function demo_calculation( - service_id: string, - config?: { ttl?: number }, + service_id: string, + config?: { ttl?: number }, ): Promise; export function demo_calculation( - peer: IFluenceClient$$, - service_id: string, - config?: { ttl?: number }, + peer: IFluenceClient$$, + service_id: string, + config?: { ttl?: number }, ): Promise; export function demo_calculation(...args: any) { - return callFunction$$( - args, - { - functionName: "demo_calculation", - arrow: { - tag: "arrow", - domain: { - tag: "labeledProduct", - fields: { - service_id: { - tag: "scalar", - name: "string", - }, - }, - }, - codomain: { - tag: "unlabeledProduct", - items: [ - { - tag: "scalar", - name: "f64", - }, - ], - }, + return callFunction$$( + args, + { + functionName: "demo_calculation", + arrow: { + tag: "arrow", + domain: { + tag: "labeledProduct", + fields: { + service_id: { + tag: "scalar", + name: "string", }, - names: { - relay: "-relay-", - getDataSrv: "getDataSrv", - callbackSrv: "callbackSrv", - responseSrv: "callbackSrv", - responseFnName: "response", - errorHandlingSrv: "errorHandlingSrv", - errorFnName: "error", + }, + }, + codomain: { + tag: "unlabeledProduct", + items: [ + { + tag: "scalar", + name: "f64", }, + ], }, - demo_calculation_script, - ); + }, + names: { + relay: "-relay-", + getDataSrv: "getDataSrv", + callbackSrv: "callbackSrv", + responseSrv: "callbackSrv", + responseFnName: "response", + errorHandlingSrv: "errorHandlingSrv", + errorFnName: "error", + }, + }, + demo_calculation_script, + ); } export const marineTest_script = ` @@ -934,54 +934,54 @@ export const marineTest_script = ` `; export function marineTest( - wasm64: string, - config?: { ttl?: number }, + wasm64: string, + config?: { ttl?: number }, ): Promise; export function marineTest( - peer: IFluenceClient$$, - wasm64: string, - config?: { ttl?: number }, + peer: IFluenceClient$$, + wasm64: string, + config?: { ttl?: number }, ): Promise; export function marineTest(...args: any) { - return callFunction$$( - args, - { - functionName: "marineTest", - arrow: { - tag: "arrow", - domain: { - tag: "labeledProduct", - fields: { - wasm64: { - tag: "scalar", - name: "string", - }, - }, - }, - codomain: { - tag: "unlabeledProduct", - items: [ - { - tag: "scalar", - name: "f64", - }, - ], - }, + return callFunction$$( + args, + { + functionName: "marineTest", + arrow: { + tag: "arrow", + domain: { + tag: "labeledProduct", + fields: { + wasm64: { + tag: "scalar", + name: "string", }, - names: { - relay: "-relay-", - getDataSrv: "getDataSrv", - callbackSrv: "callbackSrv", - responseSrv: "callbackSrv", - responseFnName: "response", - errorHandlingSrv: "errorHandlingSrv", - errorFnName: "error", + }, + }, + codomain: { + tag: "unlabeledProduct", + items: [ + { + tag: "scalar", + name: "f64", }, + ], }, - marineTest_script, - ); + }, + names: { + relay: "-relay-", + getDataSrv: "getDataSrv", + callbackSrv: "callbackSrv", + responseSrv: "callbackSrv", + responseFnName: "response", + errorHandlingSrv: "errorHandlingSrv", + errorFnName: "error", + }, + }, + marineTest_script, + ); } /* eslint-enable */ diff --git a/packages/@tests/aqua/src/index.ts b/packages/@tests/aqua/src/index.ts index aa43be300..2855a42cd 100644 --- a/packages/@tests/aqua/src/index.ts +++ b/packages/@tests/aqua/src/index.ts @@ -20,98 +20,98 @@ import { fromByteArray } from "base64-js"; import { test as particleTest } from "./_aqua/finalize_particle.js"; import { - registerHelloWorld, - helloTest, - marineTest, + registerHelloWorld, + helloTest, + marineTest, } from "./_aqua/smoke_test.js"; import { wasm } from "./wasmb64.js"; const relay = { - multiaddr: - "/ip4/127.0.0.1/tcp/9991/ws/p2p/12D3KooWBM3SdXWqGaawQDGQ6JprtwswEg3FWGvGhmgmMez1vRbR", - peerId: "12D3KooWBM3SdXWqGaawQDGQ6JprtwswEg3FWGvGhmgmMez1vRbR", + multiaddr: + "/ip4/127.0.0.1/tcp/9991/ws/p2p/12D3KooWBM3SdXWqGaawQDGQ6JprtwswEg3FWGvGhmgmMez1vRbR", + peerId: "12D3KooWBM3SdXWqGaawQDGQ6JprtwswEg3FWGvGhmgmMez1vRbR", }; function generateRandomUint8Array() { - const uint8Array = new Uint8Array(32); + const uint8Array = new Uint8Array(32); - for (let i = 0; i < uint8Array.length; i++) { - uint8Array[i] = Math.floor(Math.random() * 256); - } + for (let i = 0; i < uint8Array.length; i++) { + uint8Array[i] = Math.floor(Math.random() * 256); + } - return uint8Array; + return uint8Array; } const optsWithRandomKeyPair = (): ClientConfig => { - return { - keyPair: { - type: "Ed25519", - source: generateRandomUint8Array(), - }, - } as const; + return { + keyPair: { + type: "Ed25519", + source: generateRandomUint8Array(), + }, + } as const; }; export type TestResult = - | { type: "success"; data: string } - | { type: "failure"; error: string }; + | { type: "success"; data: string } + | { type: "failure"; error: string }; export const runTest = async (): Promise => { - try { - Fluence.onConnectionStateChange((state) => { - console.info("connection state changed: ", state); - }); + try { + Fluence.onConnectionStateChange((state) => { + console.info("connection state changed: ", state); + }); - console.log("connecting to Fluence Network..."); - console.log("multiaddr: ", relay.multiaddr); - await Fluence.connect(relay, optsWithRandomKeyPair()); + console.log("connecting to Fluence Network..."); + console.log("multiaddr: ", relay.multiaddr); + await Fluence.connect(relay, optsWithRandomKeyPair()); - console.log("connected"); + console.log("connected"); - const relayPeerId = Fluence.getClient().getRelayPeerId(); - console.log("relay:", relayPeerId); + const relayPeerId = Fluence.getClient().getRelayPeerId(); + console.log("relay:", relayPeerId); - registerHelloWorld({ - hello(str) { - return "Hello, " + str + "!"; - }, - }); + registerHelloWorld({ + hello(str) { + return "Hello, " + str + "!"; + }, + }); - const client = Fluence.getClient(); + const client = Fluence.getClient(); - console.log("my peer id: ", client.getPeerId()); - console.log("my sk id: ", fromByteArray(client.getPeerSecretKey())); + console.log("my peer id: ", client.getPeerId()); + console.log("my sk id: ", fromByteArray(client.getPeerSecretKey())); - console.log("running hello test..."); - const hello = await helloTest(); - console.log("hello test finished, result: ", hello); + console.log("running hello test..."); + const hello = await helloTest(); + console.log("hello test finished, result: ", hello); - console.log("running marine test..."); - const marine = await marineTest(wasm); + console.log("running marine test..."); + const marine = await marineTest(wasm); - console.log("running particle test..."); - await particleTest(); + console.log("running particle test..."); + await particleTest(); - console.log("marine test finished, result: ", marine); + console.log("marine test finished, result: ", marine); - const returnVal = { - hello, - marine, - }; + const returnVal = { + hello, + marine, + }; - return { type: "success", data: JSON.stringify(returnVal) }; - } finally { - console.log("disconnecting from Fluence Network..."); - await Fluence.disconnect(); - console.log("disconnected"); - } + return { type: "success", data: JSON.stringify(returnVal) }; + } finally { + console.log("disconnecting from Fluence Network..."); + await Fluence.disconnect(); + console.log("disconnected"); + } }; export const runMain = () => { - runTest() - .then(() => { - console.log("done!"); - }) - .catch((err) => { - console.error("error: ", err); - }); + runTest() + .then(() => { + console.log("done!"); + }) + .catch((err) => { + console.error("error: ", err); + }); }; diff --git a/packages/@tests/aqua/src/wasmb64.ts b/packages/@tests/aqua/src/wasmb64.ts index e1e88fa3c..e39e805e8 100644 --- a/packages/@tests/aqua/src/wasmb64.ts +++ b/packages/@tests/aqua/src/wasmb64.ts @@ -15,4 +15,4 @@ */ export const wasm = - "AGFzbQEAAAABmIGAgAAWYAAAYAABf2AAAXxgAX8AYAF/AX9gAX8BfmACf38AYAJ/fwF/YAN/f38AYAN/f38Bf2ADf39/AX5gBH9/f38AYAR/f39/AX9gBX9/f39/AGAFf39/f38Bf2AGf39/f39/AX9gB39/f39/f38AYAd/f39/f39/AX9gCX9/f39/f35+fgBgBH98f38Bf2ADfn9/AX9gAXwBfALRgYCAAAYEaG9zdA9sb2dfdXRmOF9zdHJpbmcACxZ3YXNpX3NuYXBzaG90X3ByZXZpZXcxCGZkX3dyaXRlAAwWd2FzaV9zbmFwc2hvdF9wcmV2aWV3MQpyYW5kb21fZ2V0AAcWd2FzaV9zbmFwc2hvdF9wcmV2aWV3MQtlbnZpcm9uX2dldAAHFndhc2lfc25hcHNob3RfcHJldmlldzERZW52aXJvbl9zaXplc19nZXQABxZ3YXNpX3NuYXBzaG90X3ByZXZpZXcxCXByb2NfZXhpdAADA9iCgIAA1gILBA0HCwgDBgkJBwsHDQcHCRMPCQ0DCwgJEwgIBw0JBwAEBgsKBwcSBwgHCw4QBhAJEQ4GBAcHBwcHBwsUBgQHCQcDBggAAwcHCQMMBgcHCAcHBwgICAYRDgEDDQsVBggIBgYVFRUEAwQDBAYGCwsLBwcHBwcHAAkHBwgEBw0LBAcHBwcDCAYGBggHBwYICAcHBwcHBwcHBwsHAgMLAAcGCQkJCwkLCQQDAwwJDAcDBwgGBgcDAAYABwcHBwcHAQQEAwgNCAsGBwYECAMIBwYGBAMDBwYGBggHBAMHBwcEAAwDAwcABwcHBwYHCwcEBAgHCQcHAwcHBwgJCQcHBwcGBwcHBwcGBgYGBgYGBggICAYGBgYJBxUVFRUDAwEGBgMDAwMAAAACAQEAAwAACAQEBAMABAQEAQEAAAcHBQUFBQQEBAAABQMDAwMDAwYDAwMDAwADAwMEhYCAgAABcAF0dAWDgICAAAEAEQaZgICAAAN/AUGAgMAAC38AQaCBwQALfwBBmIHBAAsH7oGAgAASBm1lbW9yeQIAC19faGVhcF9iYXNlAwEKX19kYXRhX2VuZAMCBl9zdGFydACpAgRtYWluAIMCCXRlc3RfbG9ncwCqAgNhZGQAnAIIc3VidHJhY3QAnQIIbXVsdGlwbHkAngIGZGl2aWRlAJ8CC2Ns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AAAgA0EGaiABQQZqLQAAOgAAIANBB2ogAUEHai0AADoAACADQQhqIQMgAUEIaiEBIARBeGoiBA0ACwsgAAuvCQEHfwJAAkAgAUH/CUsNACABQQV2IQICQAJAAkACQCAAKAIAIgNFDQAgACADQQJ0aiEEIAAgAyACakECdGohBSADQX9qIgNBJ0shBgNAIAYNBCACIANqIgdBKE8NAiAFIAQoAgA2AgAgBUF8aiEFIARBfGohBCADQX9qIgNBf0cNAAsLIAFBIEkNBCAAQQA2AgQgAUHAAE8NAQwECyAHQShB3PHAABCPAQALIABBCGpBADYCACACQQEgAkEBSxsiA0ECRg0CIABBDGpBADYCACADQQNGDQIgAEEQakEANgIAIANBBEYNAiAAQRRqQQA2AgAgA0EFRg0CIABBGGpBADYCACADQQZGDQIgAEEcakEANgIAIANBB0YNAiAAQSBqQQA2AgAgA0EIRg0CIABBJGpBADYCACADQQlGDQIgAEEoakEANgIAIANBCkYNAiAAQSxqQQA2AgAgA0ELRg0CIABBMGpBADYCACADQQxGDQIgAEE0akEANgIAIANBDUYNAiAAQThqQQA2AgAgA0EORg0CIABBPGpBADYCACADQQ9GDQIgAEHAAGpBADYCACADQRBGDQIgAEHEAGpBADYCACADQRFGDQIgAEHIAGpBADYCACADQRJGDQIgAEHMAGpBADYCACADQRNGDQIgAEHQAGpBADYCACADQRRGDQIgAEHUAGpBADYCACADQRVGDQIgAEHYAGpBADYCACADQRZGDQIgAEHcAGpBADYCACADQRdGDQIgAEHgAGpBADYCACADQRhGDQIgAEHkAGpBADYCACADQRlGDQIgAEHoAGpBADYCACADQRpGDQIgAEHsAGpBADYCACADQRtGDQIgAEHwAGpBADYCACADQRxGDQIgAEH0AGpBADYCACADQR1GDQIgAEH4AGpBADYCACADQR5GDQIgAEH8AGpBADYCACADQR9GDQIgAEGAAWpBADYCACADQSBGDQIgAEGEAWpBADYCACADQSFGDQIgAEGIAWpBADYCACADQSJGDQIgAEGMAWpBADYCACADQSNGDQIgAEGQAWpBADYCACADQSRGDQIgAEGUAWpBADYCACADQSVGDQIgAEGYAWpBADYCACADQSZGDQIgAEGc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NgIAIAFBIGpBFGpBAzYCACABQgM3AiQgAUH8g8AANgIgIAFBBDYCPCABIAFBOGo2AjAgASABQRhqNgJIIAEgAUEIajYCQCABIAFBEGo2AjggAUEgakEDQZSEwABBACABEGEgASsDGCECCyABQdAAaiQAIAILvwEBA38jAEEgayICJAACQCABQQFqIgMgAUkNACAAQQRqKAIAIgRBAXQiASADIAEgA0sbIgFBCCABQQhLGyEBAkACQCAEDQBBACEDDAELIAIgBDYCFCACIAAoAgA2AhBBASEDCyACIAM2AhggAiABQQEgAkEQahB1AkAgAigCAEUNACACQQhqKAIAIgBFDQEgAigCBCAAEI4CAAsgAigCBCEDIABBBGogATYCACAAIAM2AgAgAkEgaiQADwsQuwEAC78BAQJ/IwBBIGsiAyQAAkAgASACaiICIAFJDQAgAEEEaigCACIEQQF0IgEgAiABIAJLGyIBQQggAUEISxshAQJAAkAgBA0AQQAhAgwBCyADIAQ2AhQgAyAAKAIANgIQQQEhAgsgAyACNgIYIAMgAUEBIANBEGoQdQJAIAMoAgBFDQAgA0EIaigCACIARQ0BIAMoAgQgABCOAgALIAMoAgQhAiAAQQRqIAE2AgAgACACNgIAIANBIGokAA8LELsBAAu/AQECfyMAQSBrIgMkAAJAIAEgAmoiAiABSQ0AIABBBGooAgAiBEEBdCIBIAIgASACSxsiAUEIIAFBCEsbIQECQAJAIAQNAEEAIQIMAQsgAyAENgIUIAMgACgCADYCEEEBIQILIAMgAjYCGCADIAFBASADQRBqEHMCQCADKAIARQ0AIANBCGooAgAiAEUNASADKAIEIAAQjgIACyADKAIEIQIgAEEEaiABNgIAIAAgAjYCACADQSBqJAAPCxC7AQALvwEBA38jAEEgayICJAACQCABQQFqIgMgAUkNACAAQQRqKAIAIgRBAXQiASADIAEgA0sbIgFBCCABQQhLGyEBAkACQCAEDQBBACEDDAELIAIgBDYCFCACIAAoAgA2AhBBASEDCyACIAM2AhggAiABQQEgAkEQahBzAkAgAigCAEUNACACQQhqKAIAIgBFDQEgAigCBCAAEI4CAAsgAigCBCEDIABBBGogATYCACAAIAM2AgAgAkEgaiQADwsQuwEAC78BAQN/IwBBIGsi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IgBBCGooAgAhAyAAKAIAIQAgAiABEMwBAkAgA0UNAANAIAIgADYCDCACIAJBDGpBnMDAABD/ARogAEEBaiEAIANBf2oiAw0ACwsgAhDPASEAIAJBEGokACAAC3QBAX8jAEEgayIBJAAgAUEQakIANwMAIAFCADcDCCABIAFBCGpBEBDdAQJAIAEvAQBFDQAgASABLwECOwEeQaiiwABBEiABQR5qQdSMwABB3KLAABCDAQALIAAgASkDEDcDCCAAIAEpAwg3AwAgAUEgaiQAC20BAX8jAEEwayIDJAAgAyABNgIEIAMgADYCACADQRxqQQI2AgAgA0EsakEiNgIAIANCAzcCDCADQfjBwAA2AgggA0EiNgIkIAMgA0EgajYCGCADIANBBGo2AiggAyADNgIgIANBCGogAhC8AQALcAEBfyMAQTBrIgIkACACIAE2AgQgAiAANgIAIAJBHGpBAjYCACACQSxqQSI2AgAgAkICNwIMIAJB0N/AADYCCCACQSI2AiQgAiACQSBqNgIYIAIgAkEEajYCKCACIAI2AiAgAkEIakGA4MAAELwBAAtwAQF/IwBBMGsiAiQAIAIgATYCBCACIAA2AgAgAkEcakECNgIAIAJBLGpBIjYCACACQgI3AgwgAkGg4MAANgIIIAJBIjYCJCACIAJBIGo2AhggAiACQQRqNgIoIAIgAjYCICACQQhqQbDgwAAQvAEAC3ABAX8jAEEwayICJAAgAiABNgIEIAIgADYCACACQRxqQQI2AgAgAkEsakEiNgIAIAJCAjcCDCACQeTgwAA2AgggAkEiNgIkIAIgAkEgajYCGCACIAJBBGo2AiggAiACNgIgIAJBCGpB9ODAABC8AQALbQEBfyMAQTBrIgMkACADIAE2AgQgAyAANgIAIANBHGpBAjYCACADQSxqQSI2AgAgA0ICNwIMIANB8NnAADYCCCADQSI2AiQgAyADQSBqNgIYIAMgAzYCKCADIANBBGo2AiAgA0EIaiACELwBAAtkAQJ/IwBBIGsiAiQAIAFBHGooAgAhAyABKAIYIQEgAkEIakEQaiAAQRBqKQIANwMAIAJBCGpBCGogAEEIaikCADcDACACIAApAgA3AwggASADIAJBCGoQJCEAIAJBIGokACAAC2QBAn8jAEEgayICJAAgAEEcaigCACEDIAAoAhghACACQQhqQRBqIAFBEGopAgA3AwAgAkEIakEIaiABQQhqKQIANwMAIAIgASkCADcDCCAAIAMgAkEIahAkIQEgAkEgaiQAIAELbgEBfyMAQSBrIgIkACACQYCSwAA2AgQgAiAANgIAIAJBCGpBEGogAUEQaikCADcDACACQQhqQQhqIAFBCGopAgA3AwAgAiABKQIANwMIQQAgAkGwjcAAIAJBBGpBsI3AACACQQhqQdChwAAQNQALawEBfyMAQSBrIgMkACADQeCWwAA2AgQgAyAANgIAIANBCGpBEGogAUEQaikCADcDACADQQhqQQhqIAFBCGopAgA3AwAgAyABKQIANwMIQQAgA0GgjcAAIANBBGpBoI3AACADQQhqIAIQNQALawEBfyMAQSBrIgMkACADIAE2AgQgAyAANgIAIANBCGpBEGogAkEQaikCADcDACADQQhqQQhqIAJBCGopAgA3AwAgAyACKQIANwMIQQAgA0H82sAAIANBBGpB/NrAACADQQhqQYjDwAAQNQALYwEBfyMAQSBrIgIkACACIAAoAgA2AgQgAkEIakEQaiABQRBqKQIANwMAIAJBCGpBCGogAUEIaikCADcDACACIAEpAgA3AwggAkEEakGEh8AAIAJBCGoQJCEBIAJBIGokACABC2MBAX8jAEEgayICJAAgAiAAKAIANgIEIAJBCGpBEGogAUEQaikCADcDACACQQhqQQhqIAFBCGopAgA3AwAgAiABKQIANwMIIAJBBGpBsIvAACACQQhqECQhASACQSBqJAAgAQtjAQF/IwBBIGsiAiQAIAIgACgCADYCBCACQQhqQRBqIAFBEGopAgA3AwAgAkEIakEIaiABQQhqKQIANwMAIAIgASkCADcDCCACQQRqQeCLwAAgAkEIahAkIQEgAkEgaiQAIAELYwEBfyMAQSBrIgIkACACIAAoAgA2AgQgAkEIakEQaiABQRBqKQIANwMAIAJBCGpBCGogAUEIaikCADcDACACIAEpAgA3AwggAkEEakHIi8AAIAJBCGoQJCEBIAJBIGokACABC2MBAX8jAEEgayICJAAgAiAAKAIANgIEIAJBCGpBEGogAUEQaikCADcDACACQQhqQQhqIAFBCGopAgA3AwAgAiABKQIANwMIIAJBBGpBuN7AACACQQhqECQhASACQSBqJAAgAQtgAQF/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ACEDAkAgASgCEEEBRw0AIAEgAyACIAFBFGooAgAQFw8LIAEgAyACQQAQHwtBAQN/IwBBEGsiASQAIAAQugJB5JzAABDjASECIAAQuQIQ5AEhAyABIAI2AgggASAANgIEIAEgAzYCACABEOgBAAtAAQF/IwBBIGsiACQAIABBHGpBADYCACAAQazAwAA2AhggAEIBNwIMIABBhMHAADYCCCAAQQhqQYzBwAAQvAEACz8BAX8jAEEgayICJAAgAkEBOgAYIAIgATYCFCACIAA2AhAgAkHE2sAANgIMIAJBuMLAADYCCCACQQhqELoBAAs5AQF/IwBBMGsiACQAIAAQUAJAIAAQJ0UNAEGAgMAAQSsgAEGsgMAAQciAwAAQgwEACyAAQTBqJAALNAEBfyMAQRBrIgIkACACIAA2AgwgAUHoisAAQQ4gAkEMakH4isAAEF4hASACQRBqJAAgAQsyACAAKAIAIQACQCABEPMBDQACQCABEPQBDQAgACABEP0BDwsgACABEHsPCyAAIAEQegsxAQF/IwBBEGsiAiQAIAJBCGogAUHwj8AAQQsQywEgAkEIahCFASEBIAJBEGokACABCzABAX8jAEEQayICJAAgAkEIaiABQYSXwABBCxDLASACQQhqEHAhASACQRBqJAAgAQsyACAAKAIAIQACQCABEPMBDQACQCABEPQBDQAgACABEP0BDwsgACABEHsPCyAAIAEQegsyACAAKAIAIQACQCABEPMBDQACQCABEPQBDQAgACABEIECDwsgACABEHgPCyAAIAEQdwsvAQJ/IwBBEGsiACQAIABBATYCDCAAQQxqQaSFwABBAEEAEFEhASAAQRBqJAAgAQsvAQF/IwBBEGsiASQAIAAoAgAQsAIgAUEAOgAPIAFBD2oQtAIhACABQRBqJAAgAAsvAQF/IwBBEGsiASQAIAAoAgAQsAIgAUEAOgAPIAFBD2oQtAIhACABQRBqJAAgAAs5AQF/IAAoAgAhAQJAIAAtAAQNAEEAKALI/EBB/////wdxRQ0AEKICDQAgAUEBOgABCyABQQA6AAALLgEBfyMAQRBrIgMkACADIAE2AgwgAyAANgIIIANBCGpBiIvAAEEAIAJBARAaAAsvAQF/IwBBEGsiBSQAIAUgAzYCDCAFIAI2AgggBSABNgIEIAUgADYCACAFEOABAAs0ACAAQQM6ACAgAEKAgICAgAQ3AgAgACABNgIYIABBADYCECAAQQA2AgggAEEcaiACNgIACzAAIAEoAhggAiADIAFBHGooAgAoAgwRCQAhAiAAQQA6AAUgACACOgAEIAAgATYCAAs1AQF/IAEoAhhB6tzAAEEBIAFBHGooAgAoAgwRCQAhAiAAQQA6AAUgACACOgAEIAAgATYCAAsrAAJAAkAgARDzAQ0AIAEQ9AENASAAIAEQggIPCyAAIAEQdg8LIAAgARB5CycBAX8jAEEQayICJAAgAiAAKAIANgIMIAJBDGogARA5IAJBEGokAAsyAQF/QQEhAQJAIAAtAAQNACAAKAIAIgAoAhhB69zAAEEBIAAoAhwoAgwRCQAhAQsgAQsoAQF/IwBBEGsiAyQAIAMgAjYCCCADIAE2AgQgAyAANgIAIAMQ5wEACycBAX8CQCAAKAIEIgFFDQAgAEEIaigCACIARQ0AIAEgAEEBEPUBCwsmAQF/IwBBEGsiAyQAIAMgATYCDCADIAA2AgggA0EIaiACELcBAAsjAAJAAkAgAUEISw0AIAEgAE0NAQsgASAAEN4BDwsgABC2AgsqACAAIAEuAQBBAnQiAUHItsAAaigCADYCBCAAIAFB/LjAAGooAgA2AgALKgAgACABLgEAQQJ0IgFBsLvAAGooAgA2AgQgACABQeS9wABqKAIANgIACyMBAn8CQCAAEGxBAWoiARC2AiICRQ0AIAIgACABEA4aCyACCyABAX8CQCAAQQRqKAIAIgFFDQAgACgCACABQQEQ9QELCyABAX8CQCAAQQRqKAIAIgFFDQAgACgCACABQQEQ9QELCyMAAkAgAC0AAA0AIAFBlN/AAEEFEBYPCyABQZDfwABBBBAWCyEAAkAgASgCAA0AELICAAsgAEGci8AANgIEIAAgATYCAAscACAAIAEpAgA3AgAgAEEIaiABQQhqKAIANgIACx0BAX8gACABQQAoArj8QCICQSMgAhsRBgAQsgIACxkAIAAgASACEAIiATsBAiAAIAFBAEc7AQALFwACQCAAQRBLDQAgARAHDwsgACABEDALJAEBf0GIgcEAIQECQEEAKAKEgUENAEGEgcEAIAAQTiEBCyABCxoAIAAoAgAgACgCBCAAKAIIIAAoAgwQ8QEACxwAIAEoAhhBsNnAAEEOIAFBHGooAgAoAgwRCQALHAAgASgCGEG+8sAAQQUgAUEcaigCACgCDBEJAAsYAAJAIAANAEGYjMAAQSsgARC2AQALIAALGwACQCAADQBBmIzAAEErQfScwAAQtgEACyAACxUBAX8CQBDEASIARQ0AIAAQ+gEACwsUAQF/IAAgASACIAMQsAEhBCAEDwsVACAAKAIAIAAoAgQgACgCCBDIAQALFQAgACgCACAAKAIEIAAoAggQgAEACxUAIAEgACgCACIAKAIAIAAoAgQQFgsTAAJAQQAoAvSAQUF/Rw0AEHwLCxQAIAAoAgAgASAAKAIEKAIMEQcACxABAX8gACABENMBIQIgAg8LEQAgACgCACAAKAIEIAEQmgILDgAgACgCACABED8aQQALEwAgAEGUncAANgIEIAAgATYCAAsQACAAKAIAIAAoAgQgARAZCw0AIAAgASACIAMQEQALEAAgASAAKAIAIAAoAgQQFgsNACAALQAAQRBxQQR2Cw0AIAAtAABBIHFBBXYLDAAgACABIAIQswIPCw8AIAAoAgAoAgAgARC1AQsNACAAKAIAIAEgAhBPCw0AIAAgARADQf//A3ELDQAgACABEARB//8DcQsOABDYAhDYAiAAEKYCAAsLACAAIAEQPhogAAsNACAAKAIAGgN/DAALCw0AIAA1AgBBASABEEILDAAgACABIAIQ0gEACwwAIAAgASACEEogAAsNACAAKAIAIAEgAhAeCw0AIAAxAABBASABEEILDQAgADMBAEEBIAEQQgsPABC/AiAAIAEQwAIQuAILDgAQvwIgACABECsQuAILCgAgACABEI8CDwsNACABQayLwABBAhAWCw0AIAFBrovAAEECEBYLDAAgACgCACABENkBCwsAIAAoAgAgARB/CwsAIAAoAgAgARBHCwoAIAAgARCMAgALCgAgACABEI0CAAsKACAAIAEQhQIACwoAIAAgARCLAgALCgAgACABENwBAAsKACAAIAEQjAEACwoAIAAgARCNAQALCgAgACABEI4BAAsKACAAIAEQlwIACwoAIAAgARCYAgALCgAgACABEJYCAAsKACAAIAEQkgIACwoAIAAgARCQAgALCgAgACABEJECAAsMACAAIAEpAgA3AwALCgAgAiAAIAEQFgsLACAAKAIAIAEQLAsMABC/AiAAEGkQuAILDAAQvwIgABBqELgC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IGdlbmVyYXRlIHVuaXF1ZSB0aHJlYWQgSUQ6IGJpdHNwYWNlIGV4aGF1c3RlZACICBAANwAAAFkIEAAdAAAAEwQAABEAAABZCBAAHQAAABkEAAAqAAAAUlVTVF9CQUNLVFJBQ0UAAPgFEAAAAAAAAGZhaWxlZCB0byB3cml0ZSB0aGUgYnVmZmVyZWQgZGF0YQAAAQkQACEAAAAXAAAAbGlicmFyeS9zdGQvc3JjL2lvL2J1ZmZlcmVkL2J1ZndyaXRlci5yczAJEAAoAAAAjQAAABIAAABmYWlsZWQgdG8gd3JpdGUgd2hvbGUgYnVmZmVyaAkQABwAAAAXAAAAbGlicmFyeS9zdGQvc3JjL2lvL3N0ZGlvLnJzAJAJEAAbAAAAbgIAABMAAABsaWJyYXJ5L3N0ZC9zcmMvaW8vbW9kLnJzAAAAvAkQABkAAAAaBQAAFgAAAGFkdmFuY2luZyBpbyBzbGljZXMgYmV5b25kIHRoZWlyIGxlbmd0aADoCRAAJwAAALwJEAAZAAAAHAUAAA0AAAC8CRAAGQAAAAMGAAAhAAAAZm9ybWF0dGVyIGVycm9yADgKEAAPAAAAKAAAADsAAAAMAAAABAAAADwAAAA9AAAAPgAAADsAAAAMAAAABAAAAD8AAABAAAAAQQAAAGxpYnJhcnkvc3RkL3NyYy9wYW5pYy5yc4QKEAAYAAAA8AAAABIAAAAoAAAABAAAAAQAAABCAAAAQwAAAGxpYnJhcnkvc3RkL3NyYy9zeW5jL29uY2UucnPAChAAHAAAABQBAAAyAAAAYXNzZXJ0aW9uIGZhaWxlZDogc3RhdGVfYW5kX3F1ZXVlLmFkZHIoKSAmIFNUQVRFX01BU0sgPT0gUlVOTklOR09uY2UgaW5zdGFuY2UgaGFzIHByZXZpb3VzbHkgYmVlbiBwb2lzb25lZAAALAsQACoAAAACAAAAwAoQABwAAAD/AQAACQAAAMAKEAAcAAAADAIAADUAAABQb2lzb25FcnJvcnN0YWNrIGJhY2t0cmFjZToKjwsQABEAAABub3RlOiBTb21lIGRldGFpbHMgYXJlIG9taXR0ZWQsIHJ1biB3aXRoIGBSVVNUX0JBQ0tUUkFDRT1mdWxsYCBmb3IgYSB2ZXJib3NlIGJhY2t0cmFjZS4KqAsQAFgAAABsb2NrIGNvdW50IG92ZXJmbG93IGluIHJlZW50cmFudCBtdXRleGxpYnJhcnkvc3RkL3NyYy9zeXNfY29tbW9uL3JlbXV0ZXgucnMALgwQACUAAACnAAAADgAAAGxpYnJhcnkvc3RkL3NyYy9zeXNfY29tbW9uL3RocmVhZF9pbmZvLnJzAAAAZAwQACkAAAAWAAAAMwAAAGQMEAApAAAAKwAAACsAAABhc3NlcnRpb24gZmFpbGVkOiB0aHJlYWRfaW5mby5pc19ub25lKCkAsAwQACcAAABtZW1vcnkgYWxsb2NhdGlvbiBvZiAgYnl0ZXMgZmFpbGVkCgDgDBAAFQAAAPUMEAAOAAAAbGlicmFyeS9zdGQvc3JjL2FsbG9jLnJzFA0QABgAAABSAQAACQAAAGxpYnJhcnkvc3RkL3NyYy9wYW5pY2tpbmcucnM8DRAAHAAAABEBAAAkAAAAQm94PGR5biBBbnk+PHVubmFtZWQ+AAAAKAAAAAAAAAABAAAARAAAAEUAAABGAAAARwAAAEgAAABJAAAASgAAAEsAAAAMAAAABAAAAEwAAABNAAAATgAAAE8AAABQAAAAUQAAAFIAAAB0aHJlYWQgJycgcGFuaWNrZWQgYXQgJycsIAAA0A0QAAgAAADYDRAADwAAAOcNEAADAAAAhQcQAAEAAABub3RlOiBydW4gd2l0aCBgUlVTVF9CQUNLVFJBQ0U9MWAgZW52aXJvbm1lbnQgdmFyaWFibGUgdG8gZGlzcGxheSBhIGJhY2t0cmFjZQoAAAwOEABOAAAAPA0QABwAAABGAgAAHwAAADwNEAAcAAAARwIAAB4AAABLAAAADAAAAAQAAABTAAAAKAAAAAgAAAAEAAAAVAAAAFUAAAAQAAAABAAAAFYAAABXAAAAKAAAAAgAAAAEAAAAWAAAAFkAAAB0aHJlYWQgcGFuaWNrZWQgd2hpbGUgcHJvY2Vzc2luZyBwYW5pYy4gYWJvcnRpbmcuCgAAzA4QADIAAAAKcGFuaWNrZWQgYWZ0ZXIgcGFuaWM6OmFsd2F5c19hYm9ydCgpLCBhYm9ydGluZy4KAAAA+AUQAAAAAAAIDxAAMQAAAHRocmVhZCBwYW5pY2tlZCB3aGlsZSBwYW5pY2tpbmcuIGFib3J0aW5nLgoATA8QACsAAABmYWlsZWQgdG8gaW5pdGlhdGUgcGFuaWMsIGVycm9yIIAPEAAgAAAAYWR2YW5jaW5nIElvU2xpY2UgYmV5b25kIGl0cyBsZW5ndGgAqA8QACMAAABsaWJyYXJ5L3N0ZC9zcmMvc3lzL3dhc2kvaW8ucnMAANQPEAAeAAAAFgAAAA0AAABjb25kdmFyIHdhaXQgbm90IHN1cHBvcnRlZAAABBAQABoAAABsaWJyYXJ5L3N0ZC9zcmMvc3lzL3dhc2kvLi4vdW5zdXBwb3J0ZWQvbG9ja3MvY29uZHZhci5ycygQEAA4AAAAFQAAAAkAAABjYW5ub3QgcmVjdXJzaXZlbHkgYWNxdWlyZSBtdXRleHAQEAAgAAAAbGlicmFyeS9zdGQvc3JjL3N5cy93YXNpLy4uL3Vuc3VwcG9ydGVkL2xvY2tzL211dGV4LnJzAACYEBAANgAAABgAAAAJAAAAcndsb2NrIGxvY2tlZCBmb3Igd3JpdGluZwAAAOAQEAAZAAAACAAOAA8APwACAEAANQANAAQAAwAsABsAHABJABQABgA0ADAAcmFuZG9tX2dldCBmYWlsdXJlbGlicmFyeS9zdGQvc3JjL3N5cy93YXNpL21vZC5ycwAAADoREAAfAAAAXQAAACUAAABsaWJyYXJ5L3N0ZC9zcmMvc3lzX2NvbW1vbi90aHJlYWRfcGFya2VyL2dlbmVyaWMucnMAbBEQADMAAAAnAAAAJgAAAGluY29uc2lzdGVudCBwYXJrIHN0YXRlALAREAAXAAAAbBEQADMAAAA1AAAAFwAAAHBhcmsgc3RhdGUgY2hhbmdlZCB1bmV4cGVjdGVkbHkA4BEQAB8AAABsERAAMwAAADIAAAARAAAAaW5jb25zaXN0ZW50IHN0YXRlIGluIHVucGFyaxgSEAAcAAAAbBEQADMAAABsAAAAEgAAAGwREAAzAAAAegAAAB8AAABjb2RlbmFtZVoAAAAIAAAABAAAAFsAAABtZXNzYWdlTk9UQ0FQQUJMRVhERVZUWFRCU1lUSU1FRE9VVFNUQUxFU1JDSFNQSVBFUk9GU1JBTkdFUFJPVE9UWVBFUFJPVE9OT1NVUFBPUlRQUk9UT1BJUEVQRVJNT1dORVJERUFET1ZFUkZMT1dOWElPTk9UVFlOT1RTVVBOT1RTT0NLTk9UUkVDT1ZFUkFCTEVOT1RFTVBUWU5PVERJUk5PVENPTk5OT1NZU05PU1BDTk9QUk9UT09QVE5PTVNHTk9NRU1OT0xJTktOT0xDS05PRVhFQ05PRU5UTk9ERVZOT0JVRlNORklMRU5FVFVOUkVBQ0hORVRSRVNFVE5FVERPV05OQU1FVE9PTE9OR01VTFRJSE9QTVNHU0laRU1MSU5LTUZJTEVMT09QSVNESVJJU0NPTk5JT0lOVkFMSU5UUklOUFJPR1JFU1NJTFNFUUlEUk1IT1NUVU5SRUFDSEZCSUdGQVVMVEVYSVNURFFVT1RET01ERVNUQUREUlJFUURFQURMS0NPTk5SRVNFVENPTk5SRUZVU0VEQ09OTkFCT1JURURDSElMRENBTkNFTEVEQlVTWUJBRE1TR0JBREZBTFJFQURZQUdBSU5BRk5PU1VQUE9SVEFERFJOT1RBVkFJTEFERFJJTlVTRUFDQ0VTMkJJR1NVQ0NFU1NFeHRlbnNpb246IENhcGFiaWxpdGllcyBpbnN1ZmZpY2llbnQuQ3Jvc3MtZGV2aWNlIGxpbmsuVGV4dCBmaWxlIGJ1c3kuQ29ubmVjdGlvbiB0aW1lZCBvdXQuUmVzZXJ2ZWQuTm8gc3VjaCBwcm9jZXNzLkludmFsaWQgc2Vlay5SZWFkLW9ubHkgZmlsZSBzeXN0ZW0uUmVzdWx0IHRvbyBsYXJnZS5Qcm90b2NvbCB3cm9uZyB0eXBlIGZvciBzb2NrZXQuUHJvdG9jb2wgbm90IHN1cHBvcnRlZC5Qcm90b2NvbCBlcnJvci5Ccm9rZW4gcGlwZS5PcGVyYXRpb24gbm90IHBlcm1pdHRlZC5QcmV2aW91cyBvd25lciBkaWVkLlZhbHVlIHRvbyBsYXJnZSB0byBiZSBzdG9yZWQgaW4gZGF0YSB0eXBlLk5vIHN1Y2ggZGV2aWNlIG9yIGFkZHJlc3MuSW5hcHByb3ByaWF0ZSBJL08gY29udHJvbCBvcGVyYXRpb24uTm90IHN1cHBvcnRlZCwgb3Igb3BlcmF0aW9uIG5vdCBzdXBwb3J0ZWQgb24gc29ja2V0Lk5vdCBhIHNvY2tldC5TdGF0ZSBub3QgcmVjb3ZlcmFibGUuRGlyZWN0b3J5IG5vdCBlbXB0eS5Ob3QgYSBkaXJlY3Rvcnkgb3IgYSBzeW1ib2xpYyBsaW5rIHRvIGEgZGlyZWN0b3J5LlRoZSBzb2NrZXQgaXMgbm90IGNvbm5lY3RlZC5GdW5jdGlvbiBub3Qgc3VwcG9ydGVkLk5vIHNwYWNlIGxlZnQgb24gZGV2aWNlLlByb3RvY29sIG5vdCBhdmFpbGFibGUuTm8gbWVzc2FnZSBvZiB0aGUgZGVzaXJlZCB0eXBlLk5vdCBlbm91Z2ggc3BhY2UuTm8gbG9ja3MgYXZhaWxhYmxlLkV4ZWN1dGFibGUgZmlsZSBmb3JtYXQgZXJyb3IuTm8gc3VjaCBmaWxlIG9yIGRpcmVjdG9yeS5ObyBzdWNoIGRldmljZS5ObyBidWZmZXIgc3BhY2UgYXZhaWxhYmxlLlRvbyBtYW55IGZpbGVzIG9wZW4gaW4gc3lzdGVtLk5ldHdvcmsgdW5yZWFjaGFibGUuQ29ubmVjdGlvbiBhYm9ydGVkIGJ5IG5ldHdvcmsuTmV0d29yayBpcyBkb3duLkZpbGVuYW1lIHRvbyBsb25nLk1lc3NhZ2UgdG9vIGxhcmdlLlRvbyBtYW55IGxpbmtzLkZpbGUgZGVzY3JpcHRvciB2YWx1ZSB0b28gbGFyZ2UuVG9vIG1hbnkgbGV2ZWxzIG9mIHN5bWJvbGljIGxpbmtzLklzIGEgZGlyZWN0b3J5LlNvY2tldCBpcyBjb25uZWN0ZWQuSS9PIGVycm9yLkludmFsaWQgYXJndW1lbnQuSW50ZXJydXB0ZWQgZnVuY3Rpb24uT3BlcmF0aW9uIGluIHByb2dyZXNzLklsbGVnYWwgYnl0ZSBzZXF1ZW5jZS5JZGVudGlmaWVyIHJlbW92ZWQuSG9zdCBpcyB1bnJlYWNoYWJsZS5GaWxlIHRvbyBsYXJnZS5CYWQgYWRkcmVzcy5GaWxlIGV4aXN0cy5NYXRoZW1hdGljcyBhcmd1bWVudCBvdXQgb2YgZG9tYWluIG9mIGZ1bmN0aW9uLkRlc3RpbmF0aW9uIGFkZHJlc3MgcmVxdWlyZWQuUmVzb3VyY2UgZGVhZGxvY2sgd291bGQgb2NjdXIuQ29ubmVjdGlvbiByZXNldC5Db25uZWN0aW9uIHJlZnVzZWQuQ29ubmVjdGlvbiBhYm9ydGVkLk5vIGNoaWxkIHByb2Nlc3Nlcy5PcGVyYXRpb24gY2FuY2VsZWQuRGV2aWNlIG9yIHJlc291cmNlIGJ1c3kuQmFk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AAAAAAAAAAEAAAByAAAAL2hvbWUvcGF2ZWwvLmNhcmdvL3JlZ2lzdHJ5L3NyYy9naXRodWIuY29tLTFlY2M2Mjk5ZGI5ZWM4MjMvbWFyaW5lLXJzLXNkay1tYWluLTAuNi4xNS9zcmMvcmVzdWx0LnJzAFw9EABjAAAAQwAAACMAAABzAAAAAEHY+8AACxiIBBAAlAQQAAEAAAAAAAAAAQAAABggEAAA362BgAAEbmFtZQHUrYGAANwCAEhfWk4xOG1hcmluZV9yc19zZGtfbWFpbjZsb2dnZXIyMGxvZ191dGY4X3N0cmluZ19pbXBsMTdoZGQ5NGY0NzFjMzYyZjE3ZUUBTF9aTjR3YXNpMTNsaWJfZ2VuZXJhdGVkMjJ3YXNpX3NuYXBzaG90X3ByZXZpZXcxOGZkX3dyaXRlMTdoODFlNzQwZmI4NjZkMmMxOUUCT19aTjR3YXNpMTNsaWJfZ2VuZXJhdGVkMjJ3YXNpX3NuYXBzaG90X3ByZXZpZXcxMTByYW5kb21fZ2V0MTdoNjE2NGI5NmNjZGRmYzcxYUUDLV9faW1wb3J0ZWRfd2FzaV9zbmFwc2hvdF9wcmV2aWV3MV9lbnZpcm9uX2dldAQzX19pbXBvcnRlZF93YXNpX3NuYXBzaG90X3ByZXZpZXcxX2Vudmlyb25fc2l6ZXNfZ2V0BStfX2ltcG9ydGVkX3dhc2lfc25hcHNob3RfcHJldmlldzFfcHJvY19leGl0BklfWk40Y29yZTNudW03Zmx0MmRlYzhzdHJhdGVneTZkcmFnb24xNWZvcm1hdF9zaG9ydGVzdDE3aGVkN2VhYzBiMWFiNzg2ODBFBwhkbG1hbGxvYwhGX1pONGNvcmUzbnVtN2ZsdDJkZWM4c3RyYXRlZ3k2ZHJhZ29uMTJmb3JtYXRfZXhhY3QxN2hhNzZkNGM5NjlmN2U5MDkyRQlCX1pONGNvcmUzbnVtN2ZsdDJkZWM4c3RyYXRlZ3k2ZHJhZ29uOW11bF9wb3cxMDE3aDI1NGI5MDc2OWE4M2ZlMGVFCkxfWk40Y29yZTNudW03Zmx0MmRlYzhzdHJhdGVneTVncmlzdTE5Zm9ybWF0X3Nob3J0ZXN0X29wdDE3aGU4ZjFlYjFjNGExYmUyZDNFCy9fWk41YWxsb2M1c2xpY2UxMG1lcmdlX3NvcnQxN2gwMzAzNWY0MDk4M2RhODRhRQwGZGxmcmVlDQ1kaXNwb3NlX2NodW5rDgZtZW1jcHkPB21lbW1vdmUQOV9aTjRjb3JlM251bTZiaWdudW04QmlnMzJ4NDA4bXVsX3BvdzIxN2gzMWFiZGI4ZTA4NTdmMTE2RRE1X1pONGNvcmUzc3RyMTlzbGljZV9lcnJvcl9mYWlsX3J0MTdoNjcwNDcyNjc5ZTFlNDgxMUUSNl9aTjRjb3JlM3N0cjVjb3VudDE0ZG9fY291bnRfY2hhcnMxN2g4MDZiZDU1NTI1NDc0ZDk2RRNJX1pONGNvcmUzbnVtN2ZsdDJkZWM4c3RyYXRlZ3k1Z3Jpc3UxNmZvcm1hdF9leGFjdF9vcHQxN2gyOGRhYzg4MDU0M2FhMTFmRRQHcmVhbGxvYxVhX1pONjNfJExUJGxvZy4uTGV2ZWxGaWx0ZXIkdTIwJGFzJHUyMCRjb3JlLi5zdHIuLnRyYWl0cy4uRnJvbVN0ciRHVCQ4ZnJvbV9zdHIxN2gzYmEwMzMwYmM5NGM4ZWU5RRYuX1pONGNvcmUzZm10OUZvcm1hdHRlcjNwYWQxN2hiOWZkYzQzNGNiYjBjM2E4RRdFX1pONGNvcmUzZm10NWZsb2F0MjlmbG9hdF90b19kZWNpbWFsX2NvbW1vbl9leGFjdDE3aDA4NDZiYzU2YmM0NDU0ZThFGDhfWk40Y29yZTNmbXQ5Rm9ybWF0dGVyMTJwYWRfaW50ZWdyYWwxN2hiYTUzODI4NTNlOTliOGYzRRlFX1pONDBfJExUJHN0ciR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uRGVidWckR1QkM2ZtdDE3aDYzYjYyZWI4NDZiMzg1YzVFGjtfWk4zc3RkOXBhbmlja2luZzIwcnVzdF9wYW5pY193aXRoX2hvb2sxN2hjY2IwNGUwZDg2ODExNmIwRRszX1pOM3N0ZDlwYW5pY2tpbmcxMmRlZmF1bHRfaG9vazE3aGZjNjA2MWQxZDM0NWIzOGVFHDhfWk4zc3RkMmlvNVdyaXRlMTh3cml0ZV9hbGxfdmVjdG9yZWQxN2hjOTA2MDUxYzRiMjgwZDFkRR1RX1pOM3N0ZDlwYW5pY2tpbmcxMmRlZmF1bHRfaG9vazI4XyR1N2IkJHU3YiRjbG9zdXJlJHU3ZCQkdTdkJDE3aDFjOWRhZWViOGU5MDQ0NDVFHmdfWk42OF8kTFQkY29yZS4uZm10Li5idWlsZGVycy4uUGFkQWRhcHRlciR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uV3JpdGUkR1QkOXdyaXRlX3N0cjE3aDViZTYzNjcyNmFkMTEzZmVFH0hfWk40Y29yZTNmbXQ1ZmxvYXQzMmZsb2F0X3RvX2RlY2ltYWxfY29tbW9uX3Nob3J0ZXN0MTdoOGRjNDI5NzIzZDBhNmRlNEUgM19aTjRjb3JlM3N0cjhjb252ZXJ0czlmcm9tX3V0ZjgxN2g5MDZkMmZiMGNiYTdiOTA5RSFmX1pONzFfJExUJGNvcmUuLmhhc2guLnNpcC4uSGFzaGVyJExUJFMkR1QkJHUyMCRhcyR1MjAkY29yZS4uaGFzaC4uSGFzaGVyJEdUJDV3cml0ZTE3aGIxMTk4ZDI3YjkxYjk5OTNFIkFfWk40Y29yZTNmbXQ5Rm9ybWF0dGVyMjF3cml0ZV9mb3JtYXR0ZWRfcGFydHMxN2g2ZjA3NzNkYzljZGQyYWZiRSM2X1pOM3N0ZDRzeW5jNG9uY2U0T25jZTEwY2FsbF9pbm5lcjE3aDE4ZDE4YzAzMTI0NTg5ZTZFJCZfWk40Y29yZTNmbXQ1d3JpdGUxN2g3NWZlNWEyYmI2YjFmYzAyRSU/X1pONGNvcmUzZm10OUZvcm1hdHRlcjE5cGFkX2Zvcm1hdHRlZF9wYXJ0czE3aGM1NDcxZTM3ODI5MDk4MjlFJidfWk4zc3RkNnRocmVhZDRwYXJrMTdoNzk1NzI5MmVlYTk1ZTk1OUUnS19aTjE4bWFyaW5lX3JzX3Nka19tYWluNmxvZ2dlcjE3V2FzbUxvZ2dlckJ1aWxkZXI1YnVpbGQxN2g4ODc3Njg5ZDg5NzE2ZTQzRShgX1pONjdfJExUJG1hcmluZV9yc19zZGtfbWFpbi4ubG9nZ2VyLi5XYXNtTG9nZ2VyJHUyMCRhcyR1MjAkbG9nLi5Mb2ckR1QkM2xvZzE3aDI0NTc5NzllNGRjZWIxMGZFKThfWk4zc3RkMmlvNVdyaXRlMTh3cml0ZV9hbGxfdmVjdG9yZWQxN2g5NDY1OGU4NWY3YjNmZjVhRSo3X1pONGNvcmU0aGFzaDExQnVpbGRIYXNoZXI4aGFzaF9vbmUxN2g2ZGMyMTI5MzA5ZDFkOTVmRSsIYWxsb2NhdGUsXF9aTjRjb3JlM2ZtdDNudW01MF8kTFQkaW1wbCR1MjAkY29yZS4uZm10Li5EZWJ1ZyR1MjAkZm9yJHUyMCR1NjQkR1QkM2ZtdDE3aDRkOTU4MjBmNWUxNzg2YzNFLVlfWk40Y29yZTNudW03Zmx0MmRlYzhzdHJhdGVneTVncmlzdTE2Zm9ybWF0X2V4YWN0X29wdDE0cG9zc2libHlfcm91bmQxN2gwODY5MWYwOTJjYjNjMmYyRS5GX1pONDFfJExUJGNoYXIkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2g3OGNjMWYxMjdjNmQ1YzU2RS9wX1pONzJfJExUJCRSRiRzdHIkdTIwJGFzJHUyMCRhbGxvYy4uZmZpLi5jX3N0ci4uQ1N0cmluZy4ubmV3Li5TcGVjTmV3SW1wbCRHVCQxM3NwZWNfbmV3X2ltcGwxN2g0MGE1ZjQ3ZDczY2E5MTI2RTARaW50ZXJuYWxfbWVtYWxpZ24xgAFfWk4zc3RkMmlvNWltcGxzNzRfJExUJGltcGwkdTIwJHN0ZC4uaW8uLldyaXRlJHUyMCRmb3IkdTIwJGFsbG9jLi52ZWMuLlZlYyRMVCR1OCRDJEEkR1QkJEdUJDE0d3JpdGVfdmVjdG9yZWQxN2g5ZGY3MmU1NjNiZTNjM2RiRTJGX1pONGNvcmUzbnVtNmJpZ251bThCaWczMng0MDEwbXVsX2RpZ2l0czltdWxfaW5uZXIxN2gzNTk4MWU3NDdmZjIwODFmRTM7X1pONGNvcmUzbnVtN2ZsdDJkZWMxN2RpZ2l0c190b19kZWNfc3RyMTdoODE4MmYzZWM0YTk0NDM2MUU0T19aTjNzdGQyaW84YnVmZmVyZWQ5YnVmd3JpdGVyMThCdWZXcml0ZXIkTFQkVyRHVCQ5Zmx1c2hfYnVmMTdoOTJiZTVhMGVkZDA5MGE0ZEU1O19aTjRjb3JlOXBhbmlja2luZzE5YXNzZXJ0X2ZhaWxlZF9pbm5lcjE3aDI0MmM1ZDY5NGI3ZDZmYjdFNgZtZW1zZXQ3NF9aTjRjb3JlN3VuaWNvZGU5cHJpbnRhYmxlNWNoZWNrMTdoNTk4MDM1ZmYxODliM2E3YUU4PF9aTjRjb3JlM2ZtdDhidWlsZGVyczExRGVidWdTdHJ1Y3Q1ZmllbGQxN2g2ZGQ1MmNlYjYzMWEwODEzRTlSX1pOM3N0ZDRzeW5jNG9uY2U0T25jZTljYWxsX29uY2UyOF8kdTdiJCR1N2IkY2xvc3VyZSR1N2QkJHU3ZCQxN2gzNGE2ODVlMzhjYzg5Y2NhRTpKX1pONGNvcmU3dW5pY29kZTEydW5pY29kZV9kYXRhMTVncmFwaGVtZV9leHRlbmQ2bG9va3VwMTdoZDU5NzU5MTdiNzY5OWYwZUU7V19aTjUwXyRMVCQkUkYkbXV0JHUyMCRXJHUyMCRhcyR1MjAkY29yZS4uZm10Li5Xcml0ZSRHVCQxMHdyaXRlX2NoYXIxN2hmNTc5MDg4ZDJhZWZmODhhRTxmX1pONzNfJExUJGNvcmUuLnBhbmljLi5wYW5pY19pbmZvLi5QYW5pY0luZm8kdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRpc3BsYXkkR1QkM2ZtdDE3aDVhNWY2NWFjZjgzNjczODFFPV9fWk41OF8kTFQkYWxsb2MuLnN0cmluZy4uU3RyaW5nJHUyMCRhcyR1MjAkY29yZS4uZm10Li5Xcml0ZSRHVCQxMHdyaXRlX2NoYXIxN2g1NzU1NjFlNjQyZjg1ODYzRT4IX19zdHBjcHk/X19aTjU4XyRMVCRhbGxvYy4uc3RyaW5nLi5TdHJpbmckdTIwJGFzJHUyMCRjb3JlLi5mbXQuLldyaXRlJEdUJDEwd3JpdGVfY2hhcjE3aDU3NTU2MWU2NDJmODU4NjNFQAtfX3N0cmNocm51bEE+X1pONGNvcmU1c2xpY2U2bWVtY2hyMTltZW1jaHJfZ2VuZXJhbF9jYXNlMTdoY2E1MDhkMGUxZWNmNmQ0Y0VCMF9aTjRjb3JlM2ZtdDNudW0zaW1wN2ZtdF91NjQxN2hiMGNhYmI1NTdjMDZjMWRiRUM7X1pOM3N0ZDVhbGxvYzI0ZGVmYXVsdF9hbGxvY19lcnJvcl9ob29rMTdoYjFmYmM1NTA2ZTkxMzMwZkVEN19aTjNzdGQzc3lzNHdhc2kxN2RlY29kZV9lcnJvcl9raW5kMTdoODUyZGE4ZjU5YWU5NzI3Y0VFXF9aTjRjb3JlM2ZtdDNudW01MF8kTFQkaW1wbCR1MjAkY29yZS4uZm10Li5EZWJ1ZyR1MjAkZm9yJHUyMCR1MzIkR1QkM2ZtdDE3aGEwYzIxYTYxZmY0MmNmMGFFRjtfWk40Y29yZTNmbXQ4YnVpbGRlcnMxMERlYnVnVHVwbGU1ZmllbGQxN2gxZTU2MTBiYWE3NDhjNDA5RUcyX1pONGNvcmUzZm10NVdyaXRlMTB3cml0ZV9jaGFyMTdoMzE2NjBhNDk3ZjE1ZDI3MUVILF9aTjNzdGQzZW52MTFjdXJyZW50X2RpcjE3aGM0MzU4ODc3M2Q2OGViZGNFSURfWk41YWxsb2MzZmZpNWNfc3RyN0NTdHJpbmcxOV9mcm9tX3ZlY191bmNoZWNrZWQxN2g4ZmMzNDk1NjlmZTYyNDQwRUo7X1pONGNvcmUzZm10OGJ1aWxkZXJzMTBEZWJ1Z0lubmVyNWVudHJ5MTdoNjA3MjA4OTI2MGI0ZjUxYUVLCXRlc3RfbG9nc0xMX1pOM3N0ZDEwc3lzX2NvbW1vbjEzdGhyZWFkX3BhcmtlcjdnZW5lcmljNlBhcmtlcjZ1bnBhcmsxN2hjZGE4MWYyNmYwNjFmYzQzRU14X1pOOTFfJExUJHN0ZC4uc3lzX2NvbW1vbi4uYmFja3RyYWNlLi5fcHJpbnQuLkRpc3BsYXlCYWNrdHJhY2UkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRpc3BsYXkkR1QkM2ZtdDE3aGVkMmNkODQ4MWRlOGFjYjFFTlBfWk4zc3RkNnRocmVhZDVsb2NhbDRsYXp5MjFMYXp5S2V5SW5uZXIkTFQkVCRHVCQxMGluaXRpYWxpemUxN2g1MmZmZmE1YWM0MzBlMzNlRU9zX1pOODBfJExUJHN0ZC4uaW8uLldyaXRlLi53cml0ZV9mbXQuLkFkYXB0ZXIkTFQkVCRHVCQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLldyaXRlJEdUJDl3cml0ZV9zdHIxN2hhMzc3ZjYxNmM2NDRkMTU3RVBJX1pOMThtYXJpbmVfcnNfc2RrX21haW42bG9nZ2VyMTdXYXNtTG9nZ2VyQnVpbGRlcjNuZXcxN2hhNWZmYmYwNWU1MDdiZjY4RVEzX1pOM3N0ZDJydDE5bGFuZ19zdGFydF9pbnRlcm5hbDE3aDcwODg1NmRiYTBkMGUzMjBFUnxfWk45MF8kTFQkc3RkLi5wYW5pY2tpbmcuLmJlZ2luX3BhbmljX2hhbmRsZXIuLlBhbmljUGF5bG9hZCR1MjAkYXMkdTIwJGNvcmUuLnBhbmljLi5Cb3hNZVVwJEdUJDh0YWtlX2JveDE3aDFjNGE5MWU2NjNlN2VkNWNFUy1fWk4zc3RkNnRocmVhZDZUaHJlYWQzbmV3MTdoZWMxNDVkNTM2YjE3NjZmNUVUV19aTjUwXyRMVCQkUkYkbXV0JHUyMCRXJHUyMCRhcyR1MjAkY29yZS4uZm10Li5Xcml0ZSRHVCQxMHdyaXRlX2NoYXIxN2hiOGRlMWU2YzcyMDVmMjNiRVUkX1pOM3N0ZDNlbnY0X3ZhcjE3aDNiM2Y0MDIzYzZhZTMxNGVFVldfWk41MF8kTFQkJFJGJG11dCR1MjAkVyR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uV3JpdGUkR1QkMTB3cml0ZV9jaGFyMTdoOTBjOTc3NzQ0ZjkzMmM0MEVXMl9aTjRjb3JlM2ZtdDVXcml0ZTEwd3JpdGVfY2hhcjE3aDk1NWYzNWY1NGY2ZGNhYzBFWDJfWk40Y29yZTNmbXQ1V3JpdGUxMHdyaXRlX2NoYXIxN2g3NDQ3MTNlN2I5ZDJiNDVkRVknX1pOM3N0ZDNlbnY3X3Zhcl9vczE3aGJjOGZlOTNiMTQwZGM4NGJFWi5fWk4zc3RkMmlvNVdyaXRlOXdyaXRlX2ZtdDE3aGYyNTgwZjg3OWYyMjI0NDhFWy5fWk4zc3RkMmlvNVdyaXRlOXdyaXRlX2ZtdDE3aDc3NjI5YWQ2YmY4NTQ5Y2FFXExfWk41YWxsb2M3cmF3X3ZlYzE5UmF3VmVjJExUJFQkQyRBJEdUJDE2cmVzZXJ2ZV9mb3JfcHVzaDE3aDI5ZjYyNmY4YjY5YWZlYWRFXUVfWk40Y29yZTNmbXQ5Rm9ybWF0dGVyMjVkZWJ1Z190dXBsZV9maWVsZDJfZmluaXNoMTdoMzM1OTVhZDAwNmFlYTZhNUVeRV9aTjRjb3JlM2ZtdDlGb3JtYXR0ZXIyNWRlYnVnX3R1cGxlX2ZpZWxkMV9maW5pc2gxN2hiZTYyNjY4NTNkM2JmNmZmRV82X1pOM3N0ZDVwYW5pYzE5Z2V0X2JhY2t0cmFjZV9zdHlsZTE3aDdlYmE3Y2FlYjZkNDIyZmNFYEBfWk4zc3RkNnRocmVhZDVsb2NhbDE3TG9jYWxLZXkkTFQkVCRHVCQ0d2l0aDE3aDY2ODAyNWNhYmJkMTliYjBFYS5fWk4zbG9nMTdfX3ByaXZhdGVfYXBpX2xvZzE3aGI4ODc0MjgwYTIyNzQ5ZTVFYi5fWk4zc3RkMmlvNVdyaXRlOXdyaXRlX2FsbDE3aGE3NTY5OWEwNGE1ZmU3YTZFYwZkaXZpZGVkTF9aTjVhbGxvYzdyYXdfdmVjMTlSYXdWZWMkTFQkVCRDJEEkR1QkMTZyZXNlcnZlX2Zvcl9wdXNoMTdoNDg2MDE1YWZkYjI2YTFmZkVlWV9aTjVhbGxvYzdyYXdfdmVjMTlSYXdWZWMkTFQkVCRDJEEkR1QkN3Jlc2VydmUyMWRvX3Jlc2VydmVfYW5kX2hhbmRsZTE3aGExM2QxYzE4YjYxOWRiZTJFZllfWk41YWxsb2M3cmF3X3ZlYzE5UmF3VmVjJExUJFQkQyRBJEdUJDdyZXNlcnZlMjFkb19yZXNlcnZlX2FuZF9oYW5kbGUxN2g2ZjI0NmE5NTRkZWU0YTZlRWdMX1pONWFsbG9jN3Jhd192ZWMxOVJhd1ZlYyRMVCRUJEMkQSRHVCQxNnJlc2VydmVfZm9yX3B1c2gxN2hkNmFiMWVkMDJhMTA1YTFkRWhMX1pONWFsbG9jN3Jhd192ZWMxOVJhd1ZlYyRMVCRUJEMkQSRHVCQxNnJlc2VydmVfZm9yX3B1c2gxN2gwZTdmMDE3OGU2MjU5MGJhRWkDYWRkaghzdWJ0cmFjdGsIbXVsdGlwbHlsBnN0cmxlbm04X1pOM3N0ZDEwc3lzX2NvbW1vbjExdGhyZWFkX2luZm8zc2V0MTdoZDVmMDUyMWE4ZDg3NzYyNUVuPF9aTjRjb3JlN3VuaWNvZGU5cHJpbnRhYmxlMTJpc19wcmludGFibGUxN2g4M2M4ZDAxMjkxZDViZmZjRW9dX1pONGNvcmUzcHRyNTlkcm9wX2luX3BsYWNlJExUJG1hcmluZV9yc19zZGtfbWFpbi4ubG9nZ2VyLi5XYXNtTG9nZ2VyJEdUJDE3aDkzMTIyNzY4ZjBlMDkxZTFFcE1fWk40Y29yZTNmbXQ4YnVpbGRlcnMxMURlYnVnU3RydWN0MjFmaW5pc2hfbm9uX2V4aGF1c3RpdmUxN2g4MzJkNjEwYTg0YzU2NzZhRXF3X1pOOTBfJExUJHN0ZC4ucGFuaWNraW5nLi5iZWdpbl9wYW5pY19oYW5kbGVyLi5QYW5pY1BheWxvYWQkdTIwJGFzJHUyMCRjb3JlLi5wYW5pYy4uQm94TWVVcCRHVCQzZ2V0MTdoYzhkNmQ2NGQ0Mzg2YTM3NkVyCnJ1c3RfcGFuaWNzMl9aTjVhbGxvYzdyYXdfdmVjMTFmaW5pc2hfZ3JvdzE3aDc2Y2JiMzFiM2VmYjFhZDlFdDJfWk41YWxsb2M3cmF3X3ZlYzExZmluaXNoX2dyb3cxN2g4MWRjYjY1NWI2YWY2YzYzRXVLX1pONWFsbG9jN3Jhd192ZWMxMWZpbmlzaF9ncm93MTdoMDliNzk0ODExZWZkMGRkNEUubGx2bS43MDQzNDUzNjExMTg5NzYzNzExdl9fWk40Y29yZTNmbXQzbnVtNTNfJExUJGltcGwkdTIwJGNvcmUuLmZtdC4uTG93ZXJIZXgkdTIwJGZvciR1MjAkaTE2JEdUJDNmbXQxN2hmZjVjYzMzMWExYmI0MzgzRXdeX1pONGNvcmUzZm10M251bTUyXyRMVCRpbXBsJHUyMCRjb3JlLi5mbXQuLkxvd2VySGV4JHUyMCRmb3IkdTIwJGk4JEdUJDNmbXQxN2hmZmI4NmQ0NWQxNzEwNDI4RXheX1pONGNvcmUzZm10M251bTUyXyRMVCRpbXBsJHUyMCRjb3JlLi5mbXQuLlVwcGVySGV4JHUyMCRmb3IkdTIwJGk4JEdUJDNmbXQxN2hkOGFjY2IxYmUxMjJkZTVkRXlfX1pONGNvcmUzZm10M251bTUzXyRMVCRpbXBsJHUyMCRjb3JlLi5mbXQuLlVwcGVySGV4JHUyMCRmb3IkdTIwJGkxNiRHVCQzZm10MTdoYjZiODQ4OWQ3NzUxOGM2N0V6X19aTjRjb3JlM2ZtdDNudW01M18kTFQkaW1wbCR1MjAkY29yZS4uZm10Li5Mb3dlckhleCR1MjAkZm9yJHUyMCRpMzIkR1QkM2ZtdDE3aGM5ZTIxNjEzNTIxNjlkOTBFe19fWk40Y29yZTNmbXQzbnVtNTNfJExUJGltcGwkdTIwJGNvcmUuLmZtdC4uVXBwZXJIZXgkdTIwJGZvciR1MjAkaTMyJEdUJDNmbXQxN2g2YjdkOWFiMDdlYWVjZmNhRXwdX193YXNpbGliY19pbml0aWFsaXplX2Vudmlyb259B3N0cm5jbXB+ZF9aTjY3XyRMVCRtYXJpbmVfcnNfc2RrX21haW4uLmxvZ2dlci4uV2FzbUxvZ2dlciR1MjAkYXMkdTIwJGxvZy4uTG9nJEdUJDdlbmFibGVkMTdoN2ExMjgwZTRhNzRkYTBlZkV/Y19aTjcwXyRMVCRjb3JlLi5wYW5pYy4ubG9jYXRpb24uLkxvY2F0aW9uJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EaXNwbGF5JEdUJDNmbXQxN2gxZjM3Mzc4YzAyYzI2OTA3RYABWF9aTjNzdGQ5cGFuaWNraW5nMTliZWdpbl9wYW5pY19oYW5kbGVyMjhfJHU3YiQkdTdiJGNsb3N1cmUkdTdkJCR1N2QkMTdoNTU0MWY3NGEwMzMxYTFkY0WBAQZnZXRlbnaCAVxfWk42M18kTFQkd2FzaS4ubGliX2dlbmVyYXRlZC4uRXJybm8kdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2g4ZTQwN2U5ZTIwYmNlMDQzRYMBMl9aTjRjb3JlNnJlc3VsdDEzdW53cmFwX2ZhaWxlZDE3aDg2OGEwMDYwMWEzZWI2ODdFhAFfX1pONjRfJExUJHN0ZC4uc3lzLi53YXNpLi5zdGRpby4uU3RkZXJyJHUyMCRhcyR1MjAkc3RkLi5pby4uV3JpdGUkR1QkNXdyaXRlMTdoOGRlNzk5NjUyNGZiM2FkZkWFAT1fWk40Y29yZTNmbXQ4YnVpbGRlcnMxMURlYnVnU3RydWN0NmZpbmlzaDE3aDE1ODY1OWZjZjc5YzU5ZjlFhgFkX1pONzFfJExUJGNvcmUuLm9wcy4ucmFuZ2UuLlJhbmdlJExUJElkeCRHVCQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2g2NzQzYWVkNmQyMzZhMzlhRYcBBmNhbGxvY4gBSV9aTjQ0XyRMVCQkUkYkVCR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uRGlzcGxheSRHVCQzZm10MTdoMjMwZDVhOTZjNzhkZDRlN0WJAUdfWk40Ml8kTFQkJFJGJFQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2gxZmM4NGJmMDZlOTFkZWUwRYoBOV9aTjNzdGQzc3lzNHdhc2kxOWhhc2htYXBfcmFuZG9tX2tleXMxN2gxYzBjMGM4ZGQ1ZDQ3YmE4RYsBSV9aTjVhbGxvYzN2ZWMxNlZlYyRMVCRUJEMkQSRHVCQ2cmVtb3ZlMTNhc3NlcnRfZmFpbGVkMTdoYWYyNmM2ODIzNjUyOGZkNkWMAUdfWk40Y29yZTVzbGljZTVpbmRleDI5c2xpY2Vfc3RhcnRfaW5kZXhfbGVuX2ZhaWxfcnQxN2hhNGE1MTA5MTg5YmU2MDBiRY0BRV9aTjRjb3JlNXNsaWNlNWluZGV4MjdzbGljZV9lbmRfaW5kZXhfbGVuX2ZhaWxfcnQxN2gxYjk4OWE3YjkyYmY2Y2Y1RY4BQ19aTjRjb3JlNXNsaWNlNWluZGV4MjVzbGljZV9pbmRleF9vcmRlcl9mYWlsX3J0MTdoNTlmZTk3Mzc0MzdiZTljMUWPATpfWk40Y29yZTlwYW5pY2tpbmcxOHBhbmljX2JvdW5kc19jaGVjazE3aDk4NDRlNDZjMzM5YjliZmZFkAFYX1pONTlfJExUJGNvcmUuLmZtdC4uQXJndW1lbnRzJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EaXNwbGF5JEdUJDNmbXQxN2hhNjM1MjMyMTQxNzYyYTVlRZEBNF9aTjRjb3JlM2ZtdDlGb3JtYXR0ZXI5d3JpdGVfZm10MTdoNTVhZGViODYxNTYzM2VkMUWSATVfWk40Y29yZTlwYW5pY2tpbmcxM2Fzc2VydF9mYWlsZWQxN2g4OTZkODFlMmU3ZDI3MjAwRZMBNV9aTjRjb3JlOXBhbmlja2luZzEzYXNzZXJ0X2ZhaWxlZDE3aDRhNzEyZTM2ZmQwN2U5ZDdFlAE1X1pONGNvcmU5cGFuaWNraW5nMTNhc3NlcnRfZmFpbGVkMTdoM2NmYmY5MWI2NGRiMzljMEWVAVVfWk41MF8kTFQkJFJGJG11dCR1MjAkVyR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uV3JpdGUkR1QkOXdyaXRlX2ZtdDE3aDBmMzMwMTcwODg4OGU2ZTNFlgFVX1pONTBfJExUJCRSRiRtdXQkdTIwJFckdTIwJGFzJHUyMCRjb3JlLi5mbXQuLldyaXRlJEdUJDl3cml0ZV9mbXQxN2gzYzY0ODYzMzk5NmZlMDc3RZcBVV9aTjUwXyRMVCQkUkYkbXV0JHUyMCRXJHUyMCRhcyR1MjAkY29yZS4uZm10Li5Xcml0ZSRHVCQ5d3JpdGVfZm10MTdoNjA5Zjc0NDg3MTYwNWU4YUWYAVVfWk41MF8kTFQkJFJGJG11dCR1MjAkVyR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uV3JpdGUkR1QkOXdyaXRlX2ZtdDE3aGU5ZThmNDI3ZGJhMWU1N2ZFmQFVX1pONTBfJExUJCRSRiRtdXQkdTIwJFckdTIwJGFzJHUyMCRjb3JlLi5mbXQuLldyaXRlJEdUJDl3cml0ZV9mbXQxN2gwZTQ3NWRiNzM1NDYxZTQ5RZoBMF9aTjRjb3JlM2ZtdDVXcml0ZTl3cml0ZV9mbXQxN2hkMmIzMGJjOGFhNTczYzQ3RZsBLV9aTjNsb2cxNnNldF9ib3hlZF9sb2dnZXIxN2g1YzA4OTg2YmQxZDc2MDNkRZwBMF9aTjRjb3JlM2ZtdDVXcml0ZTl3cml0ZV9mbXQxN2g0OGE0MmFkNzU4OGY0ZWU5RZ0BMF9aTjRjb3JlM2ZtdDVXcml0ZTl3cml0ZV9mbXQxN2g2ZWE0NzQ0ZmU2M2IyMTk1RZ4BaV9aTjY0XyRMVCRzdGQuLnN5cy4ud2FzaS4uc3RkaW8uLlN0ZGVyciR1MjAkYXMkdTIwJHN0ZC4uaW8uLldyaXRlJEdUJDE0d3JpdGVfdmVjdG9yZWQxN2g2OWRkZjM2YTk3OTdhOWFiRZ8BMF9aTjRjb3JlM2ZtdDVXcml0ZTl3cml0ZV9mbXQxN2hjZWU1ZjNmZTQ1M2ZiZmQxRaABBXN0YXRloQE6X1pONWFsbG9jNHN5bmMxMkFyYyRMVCRUJEdUJDlkcm9wX3Nsb3cxN2gxOTI4YzYyNTVmYTMzMDdkRaIBdl9aTjNzdGQyaW81aW1wbHM3NF8kTFQkaW1wbCR1MjAkc3RkLi5pby4uV3JpdGUkdTIwJGZvciR1MjAkYWxsb2MuLnZlYy4uVmVjJExUJHU4JEMkQSRHVCQkR1QkNXdyaXRlMTdoMzk5MTU1OWFhYzY0NzBmMkWjAQtjbGVhcl9zdGF0ZaQBY19aTjcwXyRMVCRjb3JlLi5yZXN1bHQuLlJlc3VsdCRMVCRUJEMkRSRHVCQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2hiZjI5ODBhYmFjYmMxZGU4RaUBfV9aTjkxXyRMVCRzdGQuLnBhbmlja2luZy4uYmVnaW5fcGFuaWMuLlBhbmljUGF5bG9hZCRMVCRBJEdUJCR1MjAkYXMkdTIwJGNvcmUuLnBhbmljLi5Cb3hNZVVwJEdUJDh0YWtlX2JveDE3aGUyYTNiMTY3ZGZhYjliNjBFpgFVX1pONTBfJExUJCRSRiRtdXQkdTIwJFckdTIwJGFzJHUyMCRjb3JlLi5mbXQuLldyaXRlJEdUJDl3cml0ZV9zdHIxN2g4YjdhNTE4MzA2ZWM2M2RiRacBVV9aTjUwXyRMVCQkUkYkbXV0JHUyMCRXJHUyMCRhcyR1MjAkY29yZS4uZm10Li5Xcml0ZSRHVCQ5d3JpdGVfc3RyMTdoMWI2MWEwMjJhZGMyNWRkYkWoAVVfWk41MF8kTFQkJFJGJG11dCR1MjAkVyR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uV3JpdGUkR1QkOXdyaXRlX3N0cjE3aDQ0ODczYjQ2ODNjZjk0M2FFqQF6X1pOM3N0ZDJpbzVpbXBsczc0XyRMVCRpbXBsJHUyMCRzdGQuLmlvLi5Xcml0ZSR1MjAkZm9yJHUyMCRhbGxvYy4udmVjLi5WZWMkTFQkdTgkQyRBJEdUJCRHVCQ5d3JpdGVfYWxsMTdoZThjYzI2MjMwNDQwNmUwYkWqAXNfWk44MF8kTFQkc3RkLi5pby4uV3JpdGUuLndyaXRlX2ZtdC4uQWRhcHRlciRMVCRUJEdUJCR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uV3JpdGUkR1QkOXdyaXRlX3N0cjE3aDkzNmQ4ZTkxYTE1NjhmNThFqwE0X1pONHdhc2kxM2xpYl9nZW5lcmF0ZWQ4ZmRfd3JpdGUxN2g1MDZlNmUxNGE4MGEwYmJiRawBXV9aTjU4XyRMVCRhbGxvYy4uc3RyaW5nLi5TdHJpbmckdTIwJGFzJHUyMCRjb3JlLi5mbXQuLldyaXRlJEdUJDl3cml0ZV9zdHIxN2g1MTY4MGQyM2NjMWU2ZWIxRa0BBHNicmuuAXNfWk40Y29yZTNwdHI4MWRyb3BfaW5fcGxhY2UkTFQkY29yZS4ucmVzdWx0Li5SZXN1bHQkTFQkJExQJCRSUCQkQyRzdGQuLmlvLi5lcnJvci4uRXJyb3IkR1QkJEdUJDE3aGQ4NGFkYWIyYThlNWVjYmFFrwF5X1pONGNvcmUzcHRyODdkcm9wX2luX3BsYWNlJExUJHN0ZC4uaW8uLldyaXRlLi53cml0ZV9mbXQuLkFkYXB0ZXIkTFQkJFJGJG11dCR1MjAkJHU1YiR1OCR1NWQkJEdUJCRHVCQxN2g0ZjQzY2EyMGEwY2JhNmM0RbABDV9fcmRsX3JlYWxsb2OxAQZtZW1jbXCyAUZfWk40Y29yZTNmbXQ5Rm9ybWF0dGVyMTJwYWRfaW50ZWdyYWwxMndyaXRlX3ByZWZpeDE3aDhmMmU0ZmMzZGFhMjYzNzVFswEGZ2V0Y3dktAE6X1pONWFsbG9jNHN5bmMxMkFyYyRMVCRUJEdUJDlkcm9wX3Nsb3cxN2g2YzFmZGI4NjZlMmFlZmQ3RbUBXV9aTjY0XyRMVCRhbGxvYy4uZmZpLi5jX3N0ci4uTnVsRXJyb3IkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2hlOGFiOTlhZDhmZDZiOTA4RbYBLF9aTjRjb3JlOXBhbmlja2luZzVwYW5pYzE3aGVkZjQzNzhlMjA0NjFiMjVFtwE1X1pONGNvcmU5cGFuaWNraW5nMTNwYW5pY19kaXNwbGF5MTdoNjE0YmNmYTcyMzZmOTFhYUW4AX9fWk45M18kTFQkc3RkLi5wYW5pY2tpbmcuLmJlZ2luX3BhbmljX2hhbmRsZXIuLlN0clBhbmljUGF5bG9hZCR1MjAkYXMkdTIwJGNvcmUuLnBhbmljLi5Cb3hNZVVwJEdUJDh0YWtlX2JveDE3aGNmODc3ZmRiMGZjY2Q1NjFFuQFgX1pONGNvcmUzZm10NWZsb2F0NTJfJExUJGltcGwkdTIwJGNvcmUuLmZtdC4uRGlzcGxheSR1MjAkZm9yJHUyMCRmNjQkR1QkM2ZtdDE3aDY1NDMyN2NkNmY5ZWM1YTJFugERcnVzdF9iZWdpbl91bndpbmS7AThfWk41YWxsb2M3cmF3X3ZlYzE3Y2FwYWNpdHlfb3ZlcmZsb3cxN2hjYTIzZTA2MDBhOTUzNGY2RbwBMF9aTjRjb3JlOXBhbmlja2luZzlwYW5pY19mbXQxN2g3YTY1MWM3MGE5NDkyMjhjRb0BKl9aTjEyY2FsY19zZXJ2aWNlNG1haW4xN2gwY2E3NWE5OTZkODFiYTczRb4BVV9aTjU2XyRMVCRsb2cuLlNldExvZ2dlckVycm9yJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EZWJ1ZyRHVCQzZm10MTdoNjUyYzYxNzYzODg0NTJhMkW/AUdfWk40Ml8kTFQkJFJGJFQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2gzZWJjMzNmYzA3ZjQwZmRmRcABYV9aTjY4XyRMVCRzdGQuLnRocmVhZC4ubG9jYWwuLkFjY2Vzc0Vycm9yJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EZWJ1ZyRHVCQzZm10MTdoNTE3ZjAxOTlmNzk2OWU0ZEXBAWlfWk43Nl8kTFQkc3RkLi5zeW5jLi5wb2lzb24uLlBvaXNvbkVycm9yJExUJFQkR1QkJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EZWJ1ZyRHVCQzZm10MTdoMTdhNDJkMjNlOGVjMWJjZEXCAUdfWk40Ml8kTFQkJFJGJFQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2g1Y2M3Njk4N2QxYWY4YzljRcMBR19aTjQyXyRMVCQkUkYkVCR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uRGVidWckR1QkM2ZtdDE3aGMxOGRkNjA0OTVjZWZlMDBFxAEPX19vcmlnaW5hbF9tYWluxQFhX1pOM3N0ZDJydDEwbGFuZ19zdGFydDI4XyR1N2IkJHU3YiRjbG9zdXJlJHU3ZCQkdTdkJDE3aDY5ZmNlMWZmZGI2ZjVhOThFLmxsdm0uNzEzOTI0MTQxMTY3NDgxMjc1M8YBc19aTjRjb3JlM29wczhmdW5jdGlvbjZGbk9uY2U0MGNhbGxfb25jZSR1N2IkJHU3YiR2dGFibGUuc2hpbSR1N2QkJHU3ZCQxN2gyMjFjZWNjMmEwOGQ2ZTM4RS5sbHZtLjcxMzkyNDE0MTE2NzQ4MTI3NTPHAYoBX1pONGNvcmUzcHRyMTAzZHJvcF9pbl9wbGFjZSRMVCRzdGQuLnN5bmMuLnBvaXNvbi4uUG9pc29uRXJyb3IkTFQkc3RkLi5zeW5jLi5tdXRleC4uTXV0ZXhHdWFyZCRMVCQkTFAkJFJQJCRHVCQkR1QkJEdUJDE3aGEzYjY1YzIyMDJlZDhjOWNFyAFQX1pOM3N0ZDlwYW5pY2tpbmcxMWJlZ2luX3BhbmljMjhfJHU3YiQkdTdiJGNsb3N1cmUkdTdkJCR1N2QkMTdoM2ZhOWYwYzVkM2JkNzBmZEXJATJfWk40Y29yZTNzdHIxNnNsaWNlX2Vycm9yX2ZhaWwxN2hkNGY4MTcyYTA1YjExYTk5RcoBLl9aTjRjb3JlM2ZtdDlGb3JtYXR0ZXIzbmV3MTdoNDkxOGE3OWU1NTQyN2Y4OEXLAThfWk40Y29yZTNmbXQ5Rm9ybWF0dGVyMTJkZWJ1Z19zdHJ1Y3QxN2g5N2UxYzNkYjQ0YzU5YmE3RcwBNl9aTjRjb3JlM2ZtdDlGb3JtYXR0ZXIxMGRlYnVnX2xpc3QxN2hjZmE0NmI2NDgxODczMjEyRc0BXF9aTjRjb3JlM2ZtdDNudW01MF8kTFQkaW1wbCR1MjAkY29yZS4uZm10Li5EZWJ1ZyR1MjAkZm9yJHUyMCR1MTYkR1QkM2ZtdDE3aGRjNTNlOTE1M2E4MGM4ZWFFzgFaX1pONGNvcmUzb3BzOGZ1bmN0aW9uNkZuT25jZTQwY2FsbF9vbmNlJHU3YiQkdTdiJHZ0YWJsZS5zaGltJHU3ZCQkdTdkJDE3aGIwYzFkNzhjYWUyM2M5ODFFzwE6X1pONGNvcmUzZm10OGJ1aWxkZXJzOURlYnVnTGlzdDZmaW5pc2gxN2hjNmJlNTZkZDZiZDQxYWVkRdABMl9aTjNzdGQ5cGFuaWNraW5nMTFiZWdpbl9wYW5pYzE3aGQ2N2I5NTY5NmM3ZjRmZjVF0QFoX1pONGNvcmUzcHRyNzBkcm9wX2luX3BsYWNlJExUJHN0ZC4ucGFuaWNraW5nLi5iZWdpbl9wYW5pY19oYW5kbGVyLi5QYW5pY1BheWxvYWQkR1QkMTdoNGI1ODNhYTM0NDIzYzUwMkXSATBfWk40Y29yZTlwYW5pY2tpbmc5cGFuaWNfc3RyMTdoZTE2NDQzMDcwMTk4OGU1YUXTAQtfX3JkbF9hbGxvY9QBNl9aTjR3YXNpMTNsaWJfZ2VuZXJhdGVkNUVycm5vNG5hbWUxN2hmZDJlOWQ1YjM5NGFhNzljRdUBOV9aTjR3YXNpMTNsaWJfZ2VuZXJhdGVkNUVycm5vN21lc3NhZ2UxN2hlNjQ0MWI5OTQ1ZjI4YjM0RdYBBnN0cmR1cNcBTF9aTjRjb3JlM3B0cjQyZHJvcF9pbl9wbGFjZSRMVCRhbGxvYy4uc3RyaW5nLi5TdHJpbmckR1QkMTdoYzI0MWFmNWJhYTA2M2RkM0XYAYUCX1pONGNvcmUzcHRyMjI2ZHJvcF9pbl9wbGFjZSRMVCRzdGQuLmVycm9yLi4kTFQkaW1wbCR1MjAkY29yZS4uY29udmVydC4uRnJvbSRMVCRhbGxvYy4uc3RyaW5nLi5TdHJpbmckR1QkJHUyMCRmb3IkdTIwJGFsbG9jLi5ib3hlZC4uQm94JExUJGR5biR1MjAkc3RkLi5lcnJvci4uRXJyb3IkdTJiJGNvcmUuLm1hcmtlci4uU3luYyR1MmIkY29yZS4ubWFya2VyLi5TZW5kJEdUJCRHVCQuLmZyb20uLlN0cmluZ0Vycm9yJEdUJDE3aGU0NzcyOTQ5NTNmOTJhZWNF2QFIX1pONDNfJExUJGJvb2wkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRpc3BsYXkkR1QkM2ZtdDE3aGExY2M5ZWEzZDEyZGRjNDJF2gF4X1pOOTFfJExUJHN0ZC4ucGFuaWNraW5nLi5iZWdpbl9wYW5pYy4uUGFuaWNQYXlsb2FkJExUJEEkR1QkJHUyMCRhcyR1MjAkY29yZS4ucGFuaWMuLkJveE1lVXAkR1QkM2dldDE3aDliMDdiZjIyZThiZTZkYjdF2wE/X1pONWFsbG9jNnN0cmluZzEzRnJvbVV0ZjhFcnJvcjEwaW50b19ieXRlczE3aGExN2RmMTk0OGI3Njc4NGVF3AEIcnVzdF9vb23dATdfWk40d2FzaTEzbGliX2dlbmVyYXRlZDEwcmFuZG9tX2dldDE3aDkxN2JjYWNhOWU5YWY4MGNF3gENYWxpZ25lZF9hbGxvY98BTl9aTjE4bWFyaW5lX3JzX3Nka19tYWluNnJlc3VsdDE4T0JKRUNUU19UT19SRUxFQVNFN19fZ2V0aXQxN2hjYjA2MGU1MmVlNWY5NTU4ReABO19aTjRjb3JlMTBpbnRyaW5zaWNzMTdjb25zdF9ldmFsX3NlbGVjdDE3aGQ1YWZmYTBjOWNlZTZlY2VF4QFcX1pONjNfJExUJGNvcmUuLmNlbGwuLkJvcnJvd011dEVycm9yJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EZWJ1ZyRHVCQzZm10MTdoMTI0MmQ5MTEyNjQ3MTI4MkXiAVJfWk41M18kTFQkY29yZS4uZm10Li5FcnJvciR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uRGVidWckR1QkM2ZtdDE3aGE2MGRhOGViOWMxMzQ5MThF4wE7X1pONGNvcmU2b3B0aW9uMTVPcHRpb24kTFQkVCRHVCQ2dW53cmFwMTdoNDRhNDBjZDU2YTcyNGUxY0XkATtfWk40Y29yZTZvcHRpb24xNU9wdGlvbiRMVCRUJEdUJDZ1bndyYXAxN2hiYzljMDJjZGNkZGNlMDE0ReUBBl9zdGFydOYBDl9fcnVzdF9yZWFsbG9j5wFNX1pOM3N0ZDEwc3lzX2NvbW1vbjliYWNrdHJhY2UyNl9fcnVzdF9lbmRfc2hvcnRfYmFja3RyYWNlMTdoODU1MzJmMzkwZGFlYWM0ZUXoAU1fWk4zc3RkMTBzeXNfY29tbW9uOWJhY2t0cmFjZTI2X19ydXN0X2VuZF9zaG9ydF9iYWNrdHJhY2UxN2g3M2E0M2YzOGI1ZTZlZTA5RekBSV9aTjQ0XyRMVCQkUkYkVCR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uRGlzcGxheSRHVCQzZm10MTdoMDY3YzhlZGUyYTNmYmQ3YkXqARlfX3dhc2lsaWJjX2Vuc3VyZV9lbnZpcm9u6wFHX1pONDJfJExUJCRSRiRUJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EZWJ1ZyRHVCQzZm10MTdoMjAwNWIzMWM4OTYxOTIxOUXsAQxfX3J1c3RfYWxsb2PtAUlfWk40NF8kTFQkJFJGJFQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRpc3BsYXkkR1QkM2ZtdDE3aGEwOGZhZjdmN2M3MTgyNzNF7gFXX1pONTBfJExUJCRSRiRtdXQkdTIwJFckdTIwJGFzJHUyMCRjb3JlLi5mbXQuLldyaXRlJEdUJDEwd3JpdGVfY2hhcjE3aDQyNTAzNDBiM2FjZTQyYzJF7wF6X1pOOTNfJExUJHN0ZC4ucGFuaWNraW5nLi5iZWdpbl9wYW5pY19oYW5kbGVyLi5TdHJQYW5pY1BheWxvYWQkdTIwJGFzJHUyMCRjb3JlLi5wYW5pYy4uQm94TWVVcCRHVCQzZ2V0MTdoN2VkNjU2ZThmZjhjNmIzZkXwAUdfWk40Ml8kTFQkJFJGJFQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2g0MWQzYTA2OTc1OTMzNTc1RfEBOl9aTjRjb3JlM29wczhmdW5jdGlvbjZGbk9uY2U5Y2FsbF9vbmNlMTdoYjdiZDgyYzY0MzM2OTI0Y0XyAUlfWk40NF8kTFQkJFJGJFQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRpc3BsYXkkR1QkM2ZtdDE3aGFjMGZkZjAzZWE5ODFmMmVF8wE7X1pONGNvcmUzZm10OUZvcm1hdHRlcjE1ZGVidWdfbG93ZXJfaGV4MTdoMzVkZWQxZDc5NGVhNWQ3MkX0ATtfWk40Y29yZTNmbXQ5Rm9ybWF0dGVyMTVkZWJ1Z191cHBlcl9oZXgxN2hmOWY5MmFjYTFlNTBkZDExRfUBDl9fcnVzdF9kZWFsbG9j9gFHX1pONDJfJExUJCRSRiRUJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EZWJ1ZyRHVCQzZm10MTdoNGNmYzczNWI4NDgyYmNjYUX3AVVfWk41MF8kTFQkJFJGJG11dCR1MjAkVyR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uV3JpdGUkR1QkOXdyaXRlX3N0cjE3aDRjMmI3MDQ4N2EzZmQxMzVF+AESX193YXNpX2Vudmlyb25fZ2V0+QEYX193YXNpX2Vudmlyb25fc2l6ZXNfZ2V0+gEEZXhpdPsBBnN0cmNwefwBOl9aTjRjb3JlM29wczhmdW5jdGlvbjZGbk9uY2U5Y2FsbF9vbmNlMTdoYzVhODdmYmI0MDFhN2VlZUX9AWJfWk40Y29yZTNmbXQzbnVtM2ltcDUyXyRMVCRpbXBsJHUyMCRjb3JlLi5mbXQuLkRpc3BsYXkkdTIwJGZvciR1MjAkdTMyJEdUJDNmbXQxN2hkNGI2ZmZjOGEwYzdlMzUyRf4BMl9aTjRjb3JlNm9wdGlvbjEzZXhwZWN0X2ZhaWxlZDE3aGI3ZWRkYzVhMTkzN2U2YmJF/wE4X1pONGNvcmUzZm10OGJ1aWxkZXJzOERlYnVnU2V0NWVudHJ5MTdoMDE0ZjlkNmYyZGMyZTQ2Y0WAAlVfWk41MF8kTFQkJFJGJG11dCR1MjAkVyR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uV3JpdGUkR1QkOXdyaXRlX3N0cjE3aDIxODAyY2EzZjM4MTRlZGZFgQJhX1pONGNvcmUzZm10M251bTNpbXA1MV8kTFQkaW1wbCR1MjAkY29yZS4uZm10Li5EaXNwbGF5JHUyMCRmb3IkdTIwJHU4JEdUJDNmbXQxN2g0MDBmMWYyNmZmMzI2Y2I2RYICYl9aTjRjb3JlM2ZtdDNudW0zaW1wNTJfJExUJGltcGwkdTIwJGNvcmUuLmZtdC4uRGlzcGxheSR1MjAkZm9yJHUyMCR1MTYkR1QkM2ZtdDE3aDI1NDk4MTU3MWU3OTU5NThFgwITbWFpbi5jb21tYW5kX2V4cG9ydIQCF2FsbG9jYXRlLmNvbW1hbmRfZXhwb3J0hQIaX19ydXN0X2FsbG9jX2Vycm9yX2hhbmRsZXKGAkdfWk40Ml8kTFQkJFJGJFQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2gzYTIzMzM0ODlkZDVlNjM4RYcCR19aTjQyXyRMVCQkUkYkVCR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uRGVidWckR1QkM2ZtdDE3aDBlOGZhNTFlM2UyYzJkZDBFiAJHX1pONDJfJExUJCRSRiRUJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EZWJ1ZyRHVCQzZm10MTdoZmNmMWQ4NDAxZWIxNzQwZkWJAklfWk40NF8kTFQkJFJGJFQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRpc3BsYXkkR1QkM2ZtdDE3aGI5ODMxNTk5NGYxODYwMmVFigJXX1pONTBfJExUJCRSRiRtdXQkdTIwJFckdTIwJGFzJHUyMCRjb3JlLi5mbXQuLldyaXRlJEdUJDEwd3JpdGVfY2hhcjE3aDZkOTY1Mjc3MmE3ZmE1YjhFiwI7X1pONGNvcmUxMGludHJpbnNpY3MxN2NvbnN0X2V2YWxfc2VsZWN0MTdoNzRlNzg5ZDUzNmFlMDYyYkWMAjpfWk40Y29yZTNvcHM4ZnVuY3Rpb242Rm5PbmNlOWNhbGxfb25jZTE3aGViYTk2ODMwZjRlYzc1YzdFjQJAX1pONWFsbG9jNWFsbG9jMThoYW5kbGVfYWxsb2NfZXJyb3I4cnRfZXJyb3IxN2hmMjhjYTFkNDc1YWU3OTQ4RY4CN19aTjVhbGxvYzVhbGxvYzE4aGFuZGxlX2FsbG9jX2Vycm9yMTdoMWVlMWNjZmRhZmU2YTQwYUWPAghfX3JnX29vbZACOl9aTjRjb3JlM29wczhmdW5jdGlvbjZGbk9uY2U5Y2FsbF9vbmNlMTdoMjQ4ZGJjYjIwNGNjMTRlNUWRAjpfWk40Y29yZTNvcHM4ZnVuY3Rpb242Rm5PbmNlOWNhbGxfb25jZTE3aDM4ZjFhYjY0YjJjZWM1MTRFkgI6X1pONGNvcmUzb3BzOGZ1bmN0aW9uNkZuT25jZTljYWxsX29uY2UxN2hkNWU1NThhODE1YzU0YWU3RZMCRF9aTjRjb3JlNXNsaWNlNWluZGV4MjZzbGljZV9zdGFydF9pbmRleF9sZW5fZmFpbDE3aDIzMWE0NDJlYWUyMDBkNmJFlAJCX1pONGNvcmU1c2xpY2U1aW5kZXgyNHNsaWNlX2VuZF9pbmRleF9sZW5fZmFpbDE3aGM5Mjg4ZWViMTkyN2M4ZDdFlQJAX1pONGNvcmU1c2xpY2U1aW5kZXgyMnNsaWNlX2luZGV4X29yZGVyX2ZhaWwxN2hmMTc0ZTA1NWFlNTMzNzNmRZYCO19aTjRjb3JlMTBpbnRyaW5zaWNzMTdjb25zdF9ldmFsX3NlbGVjdDE3aDA0MzllMDIyMmZhMjQ3MGFFlwI7X1pONGNvcmUxMGludHJpbnNpY3MxN2NvbnN0X2V2YWxfc2VsZWN0MTdoNDExYTg0ZjM2ODM4NWFmYUWYAjtfWk40Y29yZTEwaW50cmluc2ljczE3Y29uc3RfZXZhbF9zZWxlY3QxN2hlMDQxN2M3NjBiNGFhOTA3RZkCQF9aTjRjb3JlNXBhbmljMTBwYW5pY19pbmZvOVBhbmljSW5mbzdwYXlsb2FkMTdoNjk5YTNkYmZlZDIxMGQyNkWaAkdfWk40Ml8kTFQkc3RyJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EaXNwbGF5JEdUJDNmbXQxN2hiYTZmZTJhY2Q1NTE0YzJkRZsCR19aTjQyXyRMVCQkUkYkVCR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uRGVidWckR1QkM2ZtdDE3aDdiMWQzZDMzMGE3YTgxMzFFnAISYWRkLmNvbW1hbmRfZXhwb3J0nQIXc3VidHJhY3QuY29tbWFuZF9leHBvcnSeAhdtdWx0aXBseS5jb21tYW5kX2V4cG9ydJ8CFWRpdmlkZS5jb21tYW5kX2V4cG9ydKACHXNldF9yZXN1bHRfcHRyLmNvbW1hbmRfZXhwb3J0oQIec2V0X3Jlc3VsdF9zaXplLmNvbW1hbmRfZXhwb3J0ogJFX1pOM3N0ZDlwYW5pY2tpbmcxMXBhbmljX2NvdW50MTdpc196ZXJvX3Nsb3dfcGF0aDE3aGZmNzI3ZTc1ODE2MThkNTVFowJ2X1pOM3N0ZDJpbzVpbXBsczc0XyRMVCRpbXBsJHUyMCRzdGQuLmlvLi5Xcml0ZSR1MjAkZm9yJHUyMCRhbGxvYy4udmVjLi5WZWMkTFQkdTgkQyRBJEdUJCRHVCQ1Zmx1c2gxN2hiNDY5NDA3NmQwNWYyYjhiRaQCX19aTjY0XyRMVCRzdGQuLnN5cy4ud2FzaS4uc3RkaW8uLlN0ZGVyciR1MjAkYXMkdTIwJHN0ZC4uaW8uLldyaXRlJEdUJDVmbHVzaDE3aDgzMzY1ZTNiMTQ1ZDA4NzZFpQIQX193YXNpX3Byb2NfZXhpdKYCBV9FeGl0pwIOc2V0X3Jlc3VsdF9wdHKoAg9zZXRfcmVzdWx0X3NpemWpAhVfc3RhcnQuY29tbWFuZF9leHBvcnSqAhh0ZXN0X2xvZ3MuY29tbWFuZF9leHBvcnSrAhpjbGVhcl9zdGF0ZS5jb21tYW5kX2V4cG9ydKwCFHN0YXRlLmNvbW1hbmRfZXhwb3J0rQIdZ2V0X3Jlc3VsdF9wdHIuY29tbWFuZF9leHBvcnSuAh5nZXRfcmVzdWx0X3NpemUuY29tbWFuZF9leHBvcnSvAh5yZWxlYXNlX29iamVjdHMuY29tbWFuZF9leHBvcnSwAk9fWk4zc3RkMTBzeXNfY29tbW9uOWJhY2t0cmFjZTI4X19ydXN0X2JlZ2luX3Nob3J0X2JhY2t0cmFjZTE3aDNkMTVlZmZkMDg2MzYzOTJFsQI0X1pOM3N0ZDNzeXM0d2FzaTE0YWJvcnRfaW50ZXJuYWwxN2hlMjU0NWYwYjAyYmQzNjJkRbICKV9aTjNzdGQ3cHJvY2VzczVhYm9ydDE3aDRjYzRjY2QwZjViZGM4OTFFswINX19yZGxfZGVhbGxvY7QCPF9aTjNzdGQzc3lzNHdhc2k3cHJvY2VzczhFeGl0Q29kZTZhc19pMzIxN2g2OWY4NTg2MjEzYzJlNmQ3RbUCNV9aTjR3YXNpMTNsaWJfZ2VuZXJhdGVkNUVycm5vM3JhdzE3aDg4MzgzNDkzOTY4NGE4YTlFtgIGbWFsbG9jtwIEZnJlZbgCEV9fd2FzbV9jYWxsX2R0b3JzuQJAX1pONGNvcmU1cGFuaWMxMHBhbmljX2luZm85UGFuaWNJbmZvN21lc3NhZ2UxN2hhMDI2YTM3Zjc1MTM1NGFjRboCQV9aTjRjb3JlNXBhbmljMTBwYW5pY19pbmZvOVBhbmljSW5mbzhsb2NhdGlvbjE3aDU5NzNiODU1YTE4N2E5ZDZFuwJEX1pONGNvcmU1cGFuaWMxMHBhbmljX2luZm85UGFuaWNJbmZvMTBjYW5fdW53aW5kMTdoMjFiZGQ3NTAyZDZlMzVlZkW8Ag5nZXRfcmVzdWx0X3B0cr0CD2dldF9yZXN1bHRfc2l6Zb4CD3JlbGVhc2Vfb2JqZWN0c78CEV9fd2FzbV9jYWxsX2N0b3JzwAIEbWFpbsECTF9aTjQzXyRMVCRsb2cuLk5vcExvZ2dlciR1MjAkYXMkdTIwJGxvZy4uTG9nJEdUJDdlbmFibGVkMTdoNzAwNDJmODk4NmE2NWU5N0XCAkVfWk4zNl8kTFQkVCR1MjAkYXMkdTIwJGNvcmUuLmFueS4uQW55JEdUJDd0eXBlX2lkMTdoZDg0ZjVlZGUwYzY3ZTAxZUXDAkVfWk4zNl8kTFQkVCR1MjAkYXMkdTIwJGNvcmUuLmFueS4uQW55JEdUJDd0eXBlX2lkMTdoMzAyYzRiYTdiZTViNzY4NUXEAkVfWk4zNl8kTFQkVCR1MjAkYXMkdTIwJGNvcmUuLmFueS4uQW55JEdUJDd0eXBlX2lkMTdoM2RmZjNmOTA0ZTRlMmJiMkXFAkVfWk4zNl8kTFQkVCR1MjAkYXMkdTIwJGNvcmUuLmFueS4uQW55JEdUJDd0eXBlX2lkMTdoNjc4M2NkNzgyNGFlZDY4NEXGAoMBX1pOM3N0ZDJpbzVpbXBsczc0XyRMVCRpbXBsJHUyMCRzdGQuLmlvLi5Xcml0ZSR1MjAkZm9yJHUyMCRhbGxvYy4udmVjLi5WZWMkTFQkdTgkQyRBJEdUJCRHVCQxN2lzX3dyaXRlX3ZlY3RvcmVkMTdoNzIzMmUyNTQwZWU5MjVjOEXHAmxfWk42NF8kTFQkc3RkLi5zeXMuLndhc2kuLnN0ZGlvLi5TdGRlcnIkdTIwJGFzJHUyMCRzdGQuLmlvLi5Xcml0ZSRHVCQxN2lzX3dyaXRlX3ZlY3RvcmVkMTdoMDY5YjFmODgzMGU4MzZkZUXIAhJfX3J1c3Rfc3RhcnRfcGFuaWPJAiVfX3dhc2lsaWJjX2luaXRpYWxpemVfZW52aXJvbl9lYWdlcmx5ygIFYWJvcnTLAkVfWk4zNl8kTFQkVCR1MjAkYXMkdTIwJGNvcmUuLmFueS4uQW55JEdUJDd0eXBlX2lkMTdoYTc4MjMzN2Y2YzZlYWNmOUXMAkpfWk40Y29yZTNwdHI0MGRyb3BfaW5fcGxhY2UkTFQkbG9nLi5TZXRMb2dnZXJFcnJvciRHVCQxN2hhOWVlYTFjZGFhNmZkNGVmRc0CkAFfWk40Y29yZTNwdHI4NWRyb3BfaW5fcGxhY2UkTFQkc3RkLi5ydC4ubGFuZ19zdGFydCRMVCQkTFAkJFJQJCRHVCQuLiR1N2IkJHU3YiRjbG9zdXJlJHU3ZCQkdTdkJCRHVCQxN2gxNWUxZWJkMGFkYzg5ZWIyRS5sbHZtLjcxMzkyNDE0MTE2NzQ4MTI3NTPOAlhfWk40Y29yZTNwdHI1NGRyb3BfaW5fcGxhY2UkTFQkJFJGJG11dCR1MjAkYWxsb2MuLnN0cmluZy4uU3RyaW5nJEdUJDE3aDI2OWU0NDFiNTA0NmVjMjlFzwJHX1pONGNvcmUzcHRyMzdkcm9wX2luX3BsYWNlJExUJGNvcmUuLmZtdC4uRXJyb3IkR1QkMTdoZGM2NzQxY2U1YjMyZGVmM0XQAmJfWk42N18kTFQkbWFyaW5lX3JzX3Nka19tYWluLi5sb2dnZXIuLldhc21Mb2dnZXIkdTIwJGFzJHUyMCRsb2cuLkxvZyRHVCQ1Zmx1c2gxN2hjNTU5OWU5YWZhMDQ3YTg3RdECQl9aTjRjb3JlM3B0cjMyZHJvcF9pbl9wbGFjZSRMVCQkUkYkJFJGJHN0ciRHVCQxN2g5YzYyM2JkNTFiNzk1YTYxRdICSF9aTjQzXyRMVCRsb2cuLk5vcExvZ2dlciR1MjAkYXMkdTIwJGxvZy4uTG9nJEdUJDNsb2cxN2g4NzI1YjgwOTY1NWJjMjEyRdMCSl9aTjQzXyRMVCRsb2cuLk5vcExvZ2dlciR1MjAkYXMkdTIwJGxvZy4uTG9nJEdUJDVmbHVzaDE3aDQ4MmNhZTIzZWMzYWZiNTRF1AJvX1pONGNvcmUzcHRyNzdkcm9wX2luX3BsYWNlJExUJHN0ZC4ucGFuaWNraW5nLi5iZWdpbl9wYW5pYy4uUGFuaWNQYXlsb2FkJExUJCRSRiRzdHIkR1QkJEdUJDE3aGIyMTFiMWMzNmZlYzM2ZThF1QI+X1pONGNvcmUzcHRyMjhkcm9wX2luX3BsYWNlJExUJCRSRiRzdHIkR1QkMTdoNjJiZTY3ZWM0ODNiMGVhZUXWAocBX1pONGNvcmUzcHRyMTAwZHJvcF9pbl9wbGFjZSRMVCQkUkYkbXV0JHUyMCRzdGQuLmlvLi5Xcml0ZS4ud3JpdGVfZm10Li5BZGFwdGVyJExUJGFsbG9jLi52ZWMuLlZlYyRMVCR1OCRHVCQkR1QkJEdUJDE3aDU4Y2JlYzFiOGUyNGE4MDZF1wI5X1pONGNvcmUzcHRyMjNkcm9wX2luX3BsYWNlJExUJHU4JEdUJDE3aDExMjIyOTU3MGNhOWEwMTZF2AIFZHVtbXnZAj1fWk40Y29yZTNwdHIyN2Ryb3BfaW5fcGxhY2UkTFQkJFJGJHU4JEdUJDE3aGE0YmY1OGZjMWU2YmI5YzhF2gKJAV9aTjRjb3JlM3B0cjEwMmRyb3BfaW5fcGxhY2UkTFQkJFJGJGNvcmUuLml0ZXIuLmFkYXB0ZXJzLi5jb3BpZWQuLkNvcGllZCRMVCRjb3JlLi5zbGljZS4uaXRlci4uSXRlciRMVCR1OCRHVCQkR1QkJEdUJDE3aGRkZDAxNjVkMjVmNWVjNTRF2wJrX1pONGNvcmUzcHRyNDdkcm9wX2luX3BsYWNlJExUJGNvcmUuLmNlbGwuLkJvcnJvd011dEVycm9yJEdUJDE3aDdjNWJmNDRiNmE2ZDBiOTZFLmxsdm0uMTU3Nzc2NDg0NDA1MzUyNzMyMTQA8ICAgAAJcHJvZHVjZXJzAghsYW5ndWFnZQEEUnVzdAAMcHJvY2Vzc2VkLWJ5AwVjbGFuZwYxNC4wLjAFcnVzdGMlMS42NC4wLW5pZ2h0bHkgKDgzMDg4MDY0MCAyMDIyLTA2LTI4KQZ3YWxydXMGMC4xOS4wAKqBgIAAHV9fbV9nZW5lcmF0ZWRfc2VjdGlvbl9fZGl2aWRleyJhc3RfdHlwZSI6IkZ1bmN0aW9uIiwic2lnbmF0dXJlIjp7Im5hbWUiOiJkaXZpZGUiLCJhcmd1bWVudHMiOlt7Im5hbWUiOiJudW0iLCJ0eSI6eyJGNjQiOiJCeVZhbHVlIn19XSwib3V0cHV0X3R5cGVzIjpbeyJGNjQiOiJCeVZhbHVlIn1dfX0AroGAgAAfX19tX2dlbmVyYXRlZF9zZWN0aW9uX19tdWx0aXBseXsiYXN0X3R5cGUiOiJGdW5jdGlvbiIsInNpZ25hdHVyZSI6eyJuYW1lIjoibXVsdGlwbHkiLCJhcmd1bWVudHMiOlt7Im5hbWUiOiJudW0iLCJ0eSI6eyJGNjQiOiJCeVZhbHVlIn19XSwib3V0cHV0X3R5cGVzIjpbeyJGNjQiOiJCeVZhbHVlIn1dfX0Ag4GAgAAcX19tX2dlbmVyYXRlZF9zZWN0aW9uX19zdGF0ZXsiYXN0X3R5cGUiOiJGdW5jdGlvbiIsInNpZ25hdHVyZSI6eyJuYW1lIjoic3RhdGUiLCJhcmd1bWVudHMiOltdLCJvdXRwdXRfdHlwZXMiOlt7IkY2NCI6IkJ5VmFsdWUifV19fQD+gICAACJfX21fZ2VuZXJhdGVkX3NlY3Rpb25fX2NsZWFyX3N0YXRleyJhc3RfdHlwZSI6IkZ1bmN0aW9uIiwic2lnbmF0dXJlIjp7Im5hbWUiOiJjbGVhcl9zdGF0ZSIsImFyZ3VtZW50cyI6W10sIm91dHB1dF90eXBlcyI6W119fQCugYCAAB9fX21fZ2VuZXJhdGVkX3NlY3Rpb25fX3N1YnRyYWN0eyJhc3RfdHlwZSI6IkZ1bmN0aW9uIiwic2lnbmF0dXJlIjp7Im5hbWUiOiJzdWJ0cmFjdCIsImFyZ3VtZW50cyI6W3sibmFtZSI6Im51bSIsInR5Ijp7IkY2NCI6IkJ5VmFsdWUifX1dLCJvdXRwdXRfdHlwZXMiOlt7IkY2NCI6IkJ5VmFsdWUifV19fQCkgYCAABpfX21fZ2VuZXJhdGVkX3NlY3Rpb25fX2FkZHsiYXN0X3R5cGUiOiJGdW5jdGlvbiIsInNpZ25hdHVyZSI6eyJuYW1lIjoiYWRkIiwiYXJndW1lbnRzIjpbeyJuYW1lIjoibnVtIiwidHkiOnsiRjY0IjoiQnlWYWx1ZSJ9fV0sIm91dHB1dF90eXBlcyI6W3siRjY0IjoiQnlWYWx1ZSJ9XX19APqAgIAAIF9fbV9nZW5lcmF0ZWRfc2VjdGlvbl9fdGVzdF9sb2dzeyJhc3RfdHlwZSI6IkZ1bmN0aW9uIiwic2lnbmF0dXJlIjp7Im5hbWUiOiJ0ZXN0X2xvZ3MiLCJhcmd1bWVudHMiOltdLCJvdXRwdXRfdHlwZXMiOltdfX0A/4KAgAAPaW50ZXJmYWNlLXR5cGVzBQYwLjI0LjEAFAABBHNpemUMAQwAAAAAAAEMAAABDAABC3Jlc3VsdF9zaXplDAAAAQpyZXN1bHRfcHRyDAAAAQNudW0JAQkAAQNudW0JAQkAAQNudW0JAQkAAQNudW0JAQkAAAEJAAABCQAAAAAAAAABA251bQkBCQABA251bQkBCQABA251bQkBCQABA251bQkBCQAAAAAAAAIHBgIAAAEGCAIAAAEHCgEBCAwBAQkOAgAAAQoQAgAAAQsSAQEMAw0IYWxsb2NhdGUAD3JlbGVhc2Vfb2JqZWN0cwEPZ2V0X3Jlc3VsdF9zaXplAg5nZXRfcmVzdWx0X3B0cgMPc2V0X3Jlc3VsdF9zaXplBA5zZXRfcmVzdWx0X3B0cgUGZGl2aWRlBwhtdWx0aXBseQkFc3RhdGULC2NsZWFyX3N0YXRlDQhzdWJ0cmFjdA8DYWRkEQl0ZXN0X2xvZ3MTBAcHBgkICwoNDA8OERATEgCcgICAABVfX2ZsdWVuY2Vfc2RrX3ZlcnNpb24wLjYuMTU="; + "AGFzbQEAAAABmIGAgAAWYAAAYAABf2AAAXxgAX8AYAF/AX9gAX8BfmACf38AYAJ/fwF/YAN/f38AYAN/f38Bf2ADf39/AX5gBH9/f38AYAR/f39/AX9gBX9/f39/AGAFf39/f38Bf2AGf39/f39/AX9gB39/f39/f38AYAd/f39/f39/AX9gCX9/f39/f35+fgBgBH98f38Bf2ADfn9/AX9gAXwBfALRgYCAAAYEaG9zdA9sb2dfdXRmOF9zdHJpbmcACxZ3YXNpX3NuYXBzaG90X3ByZXZpZXcxCGZkX3dyaXRlAAwWd2FzaV9zbmFwc2hvdF9wcmV2aWV3MQpyYW5kb21fZ2V0AAcWd2FzaV9zbmFwc2hvdF9wcmV2aWV3MQtlbnZpcm9uX2dldAAHFndhc2lfc25hcHNob3RfcHJldmlldzERZW52aXJvbl9zaXplc19nZXQABxZ3YXNpX3NuYXBzaG90X3ByZXZpZXcxCXByb2NfZXhpdAADA9iCgIAA1gILBA0HCwgDBgkJBwsHDQcHCRMPCQ0DCwgJEwgIBw0JBwAEBgsKBwcSBwgHCw4QBhAJEQ4GBAcHBwcHBwsUBgQHCQcDBggAAwcHCQMMBgcHCAcHBwgICAYRDgEDDQsVBggIBgYVFRUEAwQDBAYGCwsLBwcHBwcHAAkHBwgEBw0LBAcHBwcDCAYGBggHBwYICAcHBwcHBwcHBwsHAgMLAAcGCQkJCwkLCQQDAwwJDAcDBwgGBgcDAAYABwcHBwcHAQQEAwgNCAsGBwYECAMIBwYGBAMDBwYGBggHBAMHBwcEAAwDAwcABwcHBwYHCwcEBAgHCQcHAwcHBwgJCQcHBwcGBwcHBwcGBgYGBgYGBggICAYGBgYJBxUVFRUDAwEGBgMDAwMAAAACAQEAAwAACAQEBAMABAQEAQEAAAcHBQUFBQQEBAAABQMDAwMDAwYDAwMDAwADAwMEhYCAgAABcAF0dAWDgICAAAEAEQaZgICAAAN/AUGAgMAAC38AQaCBwQALfwBBmIHBAAsH7oGAgAASBm1lbW9yeQIAC19faGVhcF9iYXNlAwEKX19kYXRhX2VuZAMCBl9zdGFydACpAgRtYWluAIMCCXRlc3RfbG9ncwCqAgNhZGQAnAIIc3VidHJhY3QAnQIIbXVsdGlwbHkAngIGZGl2aWRlAJ8CC2Ns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AAAgA0EGaiABQQZqLQAAOgAAIANBB2ogAUEHai0AADoAACADQQhqIQMgAUEIaiEBIARBeGoiBA0ACwsgAAuvCQEHfwJAAkAgAUH/CUsNACABQQV2IQICQAJAAkACQCAAKAIAIgNFDQAgACADQQJ0aiEEIAAgAyACakECdGohBSADQX9qIgNBJ0shBgNAIAYNBCACIANqIgdBKE8NAiAFIAQoAgA2AgAgBUF8aiEFIARBfGohBCADQX9qIgNBf0cNAAsLIAFBIEkNBCAAQQA2AgQgAUHAAE8NAQwECyAHQShB3PHAABCPAQALIABBCGpBADYCACACQQEgAkEBSxsiA0ECRg0CIABBDGpBADYCACADQQNGDQIgAEEQakEANgIAIANBBEYNAiAAQRRqQQA2AgAgA0EFRg0CIABBGGpBADYCACADQQZGDQIgAEEcakEANgIAIANBB0YNAiAAQSBqQQA2AgAgA0EIRg0CIABBJGpBADYCACADQQlGDQIgAEEoakEANgIAIANBCkYNAiAAQSxqQQA2AgAgA0ELRg0CIABBMGpBADYCACADQQxGDQIgAEE0akEANgIAIANBDUYNAiAAQThqQQA2AgAgA0EORg0CIABBPGpBADYCACADQQ9GDQIgAEHAAGpBADYCACADQRBGDQIgAEHEAGpBADYCACADQRFGDQIgAEHIAGpBADYCACADQRJGDQIgAEHMAGpBADYCACADQRNGDQIgAEHQAGpBADYCACADQRRGDQIgAEHUAGpBADYCACADQRVGDQIgAEHYAGpBADYCACADQRZGDQIgAEHcAGpBADYCACADQRdGDQIgAEHgAGpBADYCACADQRhGDQIgAEHkAGpBADYCACADQRlGDQIgAEHoAGpBADYCACADQRpGDQIgAEHsAGpBADYCACADQRtGDQIgAEHwAGpBADYCACADQRxGDQIgAEH0AGpBADYCACADQR1GDQIgAEH4AGpBADYCACADQR5GDQIgAEH8AGpBADYCACADQR9GDQIgAEGAAWpBADYCACADQSBGDQIgAEGEAWpBADYCACADQSFGDQIgAEGIAWpBADYCACADQSJGDQIgAEGMAWpBADYCACADQSNGDQIgAEGQAWpBADYCACADQSRGDQIgAEGUAWpBADYCACADQSVGDQIgAEGYAWpBADYCACADQSZGDQIgAEGc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NgIAIAFBIGpBFGpBAzYCACABQgM3AiQgAUH8g8AANgIgIAFBBDYCPCABIAFBOGo2AjAgASABQRhqNgJIIAEgAUEIajYCQCABIAFBEGo2AjggAUEgakEDQZSEwABBACABEGEgASsDGCECCyABQdAAaiQAIAILvwEBA38jAEEgayICJAACQCABQQFqIgMgAUkNACAAQQRqKAIAIgRBAXQiASADIAEgA0sbIgFBCCABQQhLGyEBAkACQCAEDQBBACEDDAELIAIgBDYCFCACIAAoAgA2AhBBASEDCyACIAM2AhggAiABQQEgAkEQahB1AkAgAigCAEUNACACQQhqKAIAIgBFDQEgAigCBCAAEI4CAAsgAigCBCEDIABBBGogATYCACAAIAM2AgAgAkEgaiQADwsQuwEAC78BAQJ/IwBBIGsiAyQAAkAgASACaiICIAFJDQAgAEEEaigCACIEQQF0IgEgAiABIAJLGyIBQQggAUEISxshAQJAAkAgBA0AQQAhAgwBCyADIAQ2AhQgAyAAKAIANgIQQQEhAgsgAyACNgIYIAMgAUEBIANBEGoQdQJAIAMoAgBFDQAgA0EIaigCACIARQ0BIAMoAgQgABCOAgALIAMoAgQhAiAAQQRqIAE2AgAgACACNgIAIANBIGokAA8LELsBAAu/AQECfyMAQSBrIgMkAAJAIAEgAmoiAiABSQ0AIABBBGooAgAiBEEBdCIBIAIgASACSxsiAUEIIAFBCEsbIQECQAJAIAQNAEEAIQIMAQsgAyAENgIUIAMgACgCADYCEEEBIQILIAMgAjYCGCADIAFBASADQRBqEHMCQCADKAIARQ0AIANBCGooAgAiAEUNASADKAIEIAAQjgIACyADKAIEIQIgAEEEaiABNgIAIAAgAjYCACADQSBqJAAPCxC7AQALvwEBA38jAEEgayICJAACQCABQQFqIgMgAUkNACAAQQRqKAIAIgRBAXQiASADIAEgA0sbIgFBCCABQQhLGyEBAkACQCAEDQBBACEDDAELIAIgBDYCFCACIAAoAgA2AhBBASEDCyACIAM2AhggAiABQQEgAkEQahBzAkAgAigCAEUNACACQQhqKAIAIgBFDQEgAigCBCAAEI4CAAsgAigCBCEDIABBBGogATYCACAAIAM2AgAgAkEgaiQADwsQuwEAC78BAQN/IwBBIGsi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IgBBCGooAgAhAyAAKAIAIQAgAiABEMwBAkAgA0UNAANAIAIgADYCDCACIAJBDGpBnMDAABD/ARogAEEBaiEAIANBf2oiAw0ACwsgAhDPASEAIAJBEGokACAAC3QBAX8jAEEgayIBJAAgAUEQakIANwMAIAFCADcDCCABIAFBCGpBEBDdAQJAIAEvAQBFDQAgASABLwECOwEeQaiiwABBEiABQR5qQdSMwABB3KLAABCDAQALIAAgASkDEDcDCCAAIAEpAwg3AwAgAUEgaiQAC20BAX8jAEEwayIDJAAgAyABNgIEIAMgADYCACADQRxqQQI2AgAgA0EsakEiNgIAIANCAzcCDCADQfjBwAA2AgggA0EiNgIkIAMgA0EgajYCGCADIANBBGo2AiggAyADNgIgIANBCGogAhC8AQALcAEBfyMAQTBrIgIkACACIAE2AgQgAiAANgIAIAJBHGpBAjYCACACQSxqQSI2AgAgAkICNwIMIAJB0N/AADYCCCACQSI2AiQgAiACQSBqNgIYIAIgAkEEajYCKCACIAI2AiAgAkEIakGA4MAAELwBAAtwAQF/IwBBMGsiAiQAIAIgATYCBCACIAA2AgAgAkEcakECNgIAIAJBLGpBIjYCACACQgI3AgwgAkGg4MAANgIIIAJBIjYCJCACIAJBIGo2AhggAiACQQRqNgIoIAIgAjYCICACQQhqQbDgwAAQvAEAC3ABAX8jAEEwayICJAAgAiABNgIEIAIgADYCACACQRxqQQI2AgAgAkEsakEiNgIAIAJCAjcCDCACQeTgwAA2AgggAkEiNgIkIAIgAkEgajYCGCACIAJBBGo2AiggAiACNgIgIAJBCGpB9ODAABC8AQALbQEBfyMAQTBrIgMkACADIAE2AgQgAyAANgIAIANBHGpBAjYCACADQSxqQSI2AgAgA0ICNwIMIANB8NnAADYCCCADQSI2AiQgAyADQSBqNgIYIAMgAzYCKCADIANBBGo2AiAgA0EIaiACELwBAAtkAQJ/IwBBIGsiAiQAIAFBHGooAgAhAyABKAIYIQEgAkEIakEQaiAAQRBqKQIANwMAIAJBCGpBCGogAEEIaikCADcDACACIAApAgA3AwggASADIAJBCGoQJCEAIAJBIGokACAAC2QBAn8jAEEgayICJAAgAEEcaigCACEDIAAoAhghACACQQhqQRBqIAFBEGopAgA3AwAgAkEIakEIaiABQQhqKQIANwMAIAIgASkCADcDCCAAIAMgAkEIahAkIQEgAkEgaiQAIAELbgEBfyMAQSBrIgIkACACQYCSwAA2AgQgAiAANgIAIAJBCGpBEGogAUEQaikCADcDACACQQhqQQhqIAFBCGopAgA3AwAgAiABKQIANwMIQQAgAkGwjcAAIAJBBGpBsI3AACACQQhqQdChwAAQNQALawEBfyMAQSBrIgMkACADQeCWwAA2AgQgAyAANgIAIANBCGpBEGogAUEQaikCADcDACADQQhqQQhqIAFBCGopAgA3AwAgAyABKQIANwMIQQAgA0GgjcAAIANBBGpBoI3AACADQQhqIAIQNQALawEBfyMAQSBrIgMkACADIAE2AgQgAyAANgIAIANBCGpBEGogAkEQaikCADcDACADQQhqQQhqIAJBCGopAgA3AwAgAyACKQIANwMIQQAgA0H82sAAIANBBGpB/NrAACADQQhqQYjDwAAQNQALYwEBfyMAQSBrIgIkACACIAAoAgA2AgQgAkEIakEQaiABQRBqKQIANwMAIAJBCGpBCGogAUEIaikCADcDACACIAEpAgA3AwggAkEEakGEh8AAIAJBCGoQJCEBIAJBIGokACABC2MBAX8jAEEgayICJAAgAiAAKAIANgIEIAJBCGpBEGogAUEQaikCADcDACACQQhqQQhqIAFBCGopAgA3AwAgAiABKQIANwMIIAJBBGpBsIvAACACQQhqECQhASACQSBqJAAgAQtjAQF/IwBBIGsiAiQAIAIgACgCADYCBCACQQhqQRBqIAFBEGopAgA3AwAgAkEIakEIaiABQQhqKQIANwMAIAIgASkCADcDCCACQQRqQeCLwAAgAkEIahAkIQEgAkEgaiQAIAELYwEBfyMAQSBrIgIkACACIAAoAgA2AgQgAkEIakEQaiABQRBqKQIANwMAIAJBCGpBCGogAUEIaikCADcDACACIAEpAgA3AwggAkEEakHIi8AAIAJBCGoQJCEBIAJBIGokACABC2MBAX8jAEEgayICJAAgAiAAKAIANgIEIAJBCGpBEGogAUEQaikCADcDACACQQhqQQhqIAFBCGopAgA3AwAgAiABKQIANwMIIAJBBGpBuN7AACACQQhqECQhASACQSBqJAAgAQtgAQF/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ACEDAkAgASgCEEEBRw0AIAEgAyACIAFBFGooAgAQFw8LIAEgAyACQQAQHwtBAQN/IwBBEGsiASQAIAAQugJB5JzAABDjASECIAAQuQIQ5AEhAyABIAI2AgggASAANgIEIAEgAzYCACABEOgBAAtAAQF/IwBBIGsiACQAIABBHGpBADYCACAAQazAwAA2AhggAEIBNwIMIABBhMHAADYCCCAAQQhqQYzBwAAQvAEACz8BAX8jAEEgayICJAAgAkEBOgAYIAIgATYCFCACIAA2AhAgAkHE2sAANgIMIAJBuMLAADYCCCACQQhqELoBAAs5AQF/IwBBMGsiACQAIAAQUAJAIAAQJ0UNAEGAgMAAQSsgAEGsgMAAQciAwAAQgwEACyAAQTBqJAALNAEBfyMAQRBrIgIkACACIAA2AgwgAUHoisAAQQ4gAkEMakH4isAAEF4hASACQRBqJAAgAQsyACAAKAIAIQACQCABEPMBDQACQCABEPQBDQAgACABEP0BDwsgACABEHsPCyAAIAEQegsxAQF/IwBBEGsiAiQAIAJBCGogAUHwj8AAQQsQywEgAkEIahCFASEBIAJBEGokACABCzABAX8jAEEQayICJAAgAkEIaiABQYSXwABBCxDLASACQQhqEHAhASACQRBqJAAgAQsyACAAKAIAIQACQCABEPMBDQACQCABEPQBDQAgACABEP0BDwsgACABEHsPCyAAIAEQegsyACAAKAIAIQACQCABEPMBDQACQCABEPQBDQAgACABEIECDwsgACABEHgPCyAAIAEQdwsvAQJ/IwBBEGsiACQAIABBATYCDCAAQQxqQaSFwABBAEEAEFEhASAAQRBqJAAgAQsvAQF/IwBBEGsiASQAIAAoAgAQsAIgAUEAOgAPIAFBD2oQtAIhACABQRBqJAAgAAsvAQF/IwBBEGsiASQAIAAoAgAQsAIgAUEAOgAPIAFBD2oQtAIhACABQRBqJAAgAAs5AQF/IAAoAgAhAQJAIAAtAAQNAEEAKALI/EBB/////wdxRQ0AEKICDQAgAUEBOgABCyABQQA6AAALLgEBfyMAQRBrIgMkACADIAE2AgwgAyAANgIIIANBCGpBiIvAAEEAIAJBARAaAAsvAQF/IwBBEGsiBSQAIAUgAzYCDCAFIAI2AgggBSABNgIEIAUgADYCACAFEOABAAs0ACAAQQM6ACAgAEKAgICAgAQ3AgAgACABNgIYIABBADYCECAAQQA2AgggAEEcaiACNgIACzAAIAEoAhggAiADIAFBHGooAgAoAgwRCQAhAiAAQQA6AAUgACACOgAEIAAgATYCAAs1AQF/IAEoAhhB6tzAAEEBIAFBHGooAgAoAgwRCQAhAiAAQQA6AAUgACACOgAEIAAgATYCAAsrAAJAAkAgARDzAQ0AIAEQ9AENASAAIAEQggIPCyAAIAEQdg8LIAAgARB5CycBAX8jAEEQayICJAAgAiAAKAIANgIMIAJBDGogARA5IAJBEGokAAsyAQF/QQEhAQJAIAAtAAQNACAAKAIAIgAoAhhB69zAAEEBIAAoAhwoAgwRCQAhAQsgAQsoAQF/IwBBEGsiAyQAIAMgAjYCCCADIAE2AgQgAyAANgIAIAMQ5wEACycBAX8CQCAAKAIEIgFFDQAgAEEIaigCACIARQ0AIAEgAEEBEPUBCwsmAQF/IwBBEGsiAyQAIAMgATYCDCADIAA2AgggA0EIaiACELcBAAsjAAJAAkAgAUEISw0AIAEgAE0NAQsgASAAEN4BDwsgABC2AgsqACAAIAEuAQBBAnQiAUHItsAAaigCADYCBCAAIAFB/LjAAGooAgA2AgALKgAgACABLgEAQQJ0IgFBsLvAAGooAgA2AgQgACABQeS9wABqKAIANgIACyMBAn8CQCAAEGxBAWoiARC2AiICRQ0AIAIgACABEA4aCyACCyABAX8CQCAAQQRqKAIAIgFFDQAgACgCACABQQEQ9QELCyABAX8CQCAAQQRqKAIAIgFFDQAgACgCACABQQEQ9QELCyMAAkAgAC0AAA0AIAFBlN/AAEEFEBYPCyABQZDfwABBBBAWCyEAAkAgASgCAA0AELICAAsgAEGci8AANgIEIAAgATYCAAscACAAIAEpAgA3AgAgAEEIaiABQQhqKAIANgIACx0BAX8gACABQQAoArj8QCICQSMgAhsRBgAQsgIACxkAIAAgASACEAIiATsBAiAAIAFBAEc7AQALFwACQCAAQRBLDQAgARAHDwsgACABEDALJAEBf0GIgcEAIQECQEEAKAKEgUENAEGEgcEAIAAQTiEBCyABCxoAIAAoAgAgACgCBCAAKAIIIAAoAgwQ8QEACxwAIAEoAhhBsNnAAEEOIAFBHGooAgAoAgwRCQALHAAgASgCGEG+8sAAQQUgAUEcaigCACgCDBEJAAsYAAJAIAANAEGYjMAAQSsgARC2AQALIAALGwACQCAADQBBmIzAAEErQfScwAAQtgEACyAACxUBAX8CQBDEASIARQ0AIAAQ+gEACwsUAQF/IAAgASACIAMQsAEhBCAEDwsVACAAKAIAIAAoAgQgACgCCBDIAQALFQAgACgCACAAKAIEIAAoAggQgAEACxUAIAEgACgCACIAKAIAIAAoAgQQFgsTAAJAQQAoAvSAQUF/Rw0AEHwLCxQAIAAoAgAgASAAKAIEKAIMEQcACxABAX8gACABENMBIQIgAg8LEQAgACgCACAAKAIEIAEQmgILDgAgACgCACABED8aQQALEwAgAEGUncAANgIEIAAgATYCAAsQACAAKAIAIAAoAgQgARAZCw0AIAAgASACIAMQEQALEAAgASAAKAIAIAAoAgQQFgsNACAALQAAQRBxQQR2Cw0AIAAtAABBIHFBBXYLDAAgACABIAIQswIPCw8AIAAoAgAoAgAgARC1AQsNACAAKAIAIAEgAhBPCw0AIAAgARADQf//A3ELDQAgACABEARB//8DcQsOABDYAhDYAiAAEKYCAAsLACAAIAEQPhogAAsNACAAKAIAGgN/DAALCw0AIAA1AgBBASABEEILDAAgACABIAIQ0gEACwwAIAAgASACEEogAAsNACAAKAIAIAEgAhAeCw0AIAAxAABBASABEEILDQAgADMBAEEBIAEQQgsPABC/AiAAIAEQwAIQuAILDgAQvwIgACABECsQuAILCgAgACABEI8CDwsNACABQayLwABBAhAWCw0AIAFBrovAAEECEBYLDAAgACgCACABENkBCwsAIAAoAgAgARB/CwsAIAAoAgAgARBHCwoAIAAgARCMAgALCgAgACABEI0CAAsKACAAIAEQhQIACwoAIAAgARCLAgALCgAgACABENwBAAsKACAAIAEQjAEACwoAIAAgARCNAQALCgAgACABEI4BAAsKACAAIAEQlwIACwoAIAAgARCYAgALCgAgACABEJYCAAsKACAAIAEQkgIACwoAIAAgARCQAgALCgAgACABEJECAAsMACAAIAEpAgA3AwALCgAgAiAAIAEQFgsLACAAKAIAIAEQLAsMABC/AiAAEGkQuAILDAAQvwIgABBqELgC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IGdlbmVyYXRlIHVuaXF1ZSB0aHJlYWQgSUQ6IGJpdHNwYWNlIGV4aGF1c3RlZACICBAANwAAAFkIEAAdAAAAEwQAABEAAABZCBAAHQAAABkEAAAqAAAAUlVTVF9CQUNLVFJBQ0UAAPgFEAAAAAAAAGZhaWxlZCB0byB3cml0ZSB0aGUgYnVmZmVyZWQgZGF0YQAAAQkQACEAAAAXAAAAbGlicmFyeS9zdGQvc3JjL2lvL2J1ZmZlcmVkL2J1ZndyaXRlci5yczAJEAAoAAAAjQAAABIAAABmYWlsZWQgdG8gd3JpdGUgd2hvbGUgYnVmZmVyaAkQABwAAAAXAAAAbGlicmFyeS9zdGQvc3JjL2lvL3N0ZGlvLnJzAJAJEAAbAAAAbgIAABMAAABsaWJyYXJ5L3N0ZC9zcmMvaW8vbW9kLnJzAAAAvAkQABkAAAAaBQAAFgAAAGFkdmFuY2luZyBpbyBzbGljZXMgYmV5b25kIHRoZWlyIGxlbmd0aADoCRAAJwAAALwJEAAZAAAAHAUAAA0AAAC8CRAAGQAAAAMGAAAhAAAAZm9ybWF0dGVyIGVycm9yADgKEAAPAAAAKAAAADsAAAAMAAAABAAAADwAAAA9AAAAPgAAADsAAAAMAAAABAAAAD8AAABAAAAAQQAAAGxpYnJhcnkvc3RkL3NyYy9wYW5pYy5yc4QKEAAYAAAA8AAAABIAAAAoAAAABAAAAAQAAABCAAAAQwAAAGxpYnJhcnkvc3RkL3NyYy9zeW5jL29uY2UucnPAChAAHAAAABQBAAAyAAAAYXNzZXJ0aW9uIGZhaWxlZDogc3RhdGVfYW5kX3F1ZXVlLmFkZHIoKSAmIFNUQVRFX01BU0sgPT0gUlVOTklOR09uY2UgaW5zdGFuY2UgaGFzIHByZXZpb3VzbHkgYmVlbiBwb2lzb25lZAAALAsQACoAAAACAAAAwAoQABwAAAD/AQAACQAAAMAKEAAcAAAADAIAADUAAABQb2lzb25FcnJvcnN0YWNrIGJhY2t0cmFjZToKjwsQABEAAABub3RlOiBTb21lIGRldGFpbHMgYXJlIG9taXR0ZWQsIHJ1biB3aXRoIGBSVVNUX0JBQ0tUUkFDRT1mdWxsYCBmb3IgYSB2ZXJib3NlIGJhY2t0cmFjZS4KqAsQAFgAAABsb2NrIGNvdW50IG92ZXJmbG93IGluIHJlZW50cmFudCBtdXRleGxpYnJhcnkvc3RkL3NyYy9zeXNfY29tbW9uL3JlbXV0ZXgucnMALgwQACUAAACnAAAADgAAAGxpYnJhcnkvc3RkL3NyYy9zeXNfY29tbW9uL3RocmVhZF9pbmZvLnJzAAAAZAwQACkAAAAWAAAAMwAAAGQMEAApAAAAKwAAACsAAABhc3NlcnRpb24gZmFpbGVkOiB0aHJlYWRfaW5mby5pc19ub25lKCkAsAwQACcAAABtZW1vcnkgYWxsb2NhdGlvbiBvZiAgYnl0ZXMgZmFpbGVkCgDgDBAAFQAAAPUMEAAOAAAAbGlicmFyeS9zdGQvc3JjL2FsbG9jLnJzFA0QABgAAABSAQAACQAAAGxpYnJhcnkvc3RkL3NyYy9wYW5pY2tpbmcucnM8DRAAHAAAABEBAAAkAAAAQm94PGR5biBBbnk+PHVubmFtZWQ+AAAAKAAAAAAAAAABAAAARAAAAEUAAABGAAAARwAAAEgAAABJAAAASgAAAEsAAAAMAAAABAAAAEwAAABNAAAATgAAAE8AAABQAAAAUQAAAFIAAAB0aHJlYWQgJycgcGFuaWNrZWQgYXQgJycsIAAA0A0QAAgAAADYDRAADwAAAOcNEAADAAAAhQcQAAEAAABub3RlOiBydW4gd2l0aCBgUlVTVF9CQUNLVFJBQ0U9MWAgZW52aXJvbm1lbnQgdmFyaWFibGUgdG8gZGlzcGxheSBhIGJhY2t0cmFjZQoAAAwOEABOAAAAPA0QABwAAABGAgAAHwAAADwNEAAcAAAARwIAAB4AAABLAAAADAAAAAQAAABTAAAAKAAAAAgAAAAEAAAAVAAAAFUAAAAQAAAABAAAAFYAAABXAAAAKAAAAAgAAAAEAAAAWAAAAFkAAAB0aHJlYWQgcGFuaWNrZWQgd2hpbGUgcHJvY2Vzc2luZyBwYW5pYy4gYWJvcnRpbmcuCgAAzA4QADIAAAAKcGFuaWNrZWQgYWZ0ZXIgcGFuaWM6OmFsd2F5c19hYm9ydCgpLCBhYm9ydGluZy4KAAAA+AUQAAAAAAAIDxAAMQAAAHRocmVhZCBwYW5pY2tlZCB3aGlsZSBwYW5pY2tpbmcuIGFib3J0aW5nLgoATA8QACsAAABmYWlsZWQgdG8gaW5pdGlhdGUgcGFuaWMsIGVycm9yIIAPEAAgAAAAYWR2YW5jaW5nIElvU2xpY2UgYmV5b25kIGl0cyBsZW5ndGgAqA8QACMAAABsaWJyYXJ5L3N0ZC9zcmMvc3lzL3dhc2kvaW8ucnMAANQPEAAeAAAAFgAAAA0AAABjb25kdmFyIHdhaXQgbm90IHN1cHBvcnRlZAAABBAQABoAAABsaWJyYXJ5L3N0ZC9zcmMvc3lzL3dhc2kvLi4vdW5zdXBwb3J0ZWQvbG9ja3MvY29uZHZhci5ycygQEAA4AAAAFQAAAAkAAABjYW5ub3QgcmVjdXJzaXZlbHkgYWNxdWlyZSBtdXRleHAQEAAgAAAAbGlicmFyeS9zdGQvc3JjL3N5cy93YXNpLy4uL3Vuc3VwcG9ydGVkL2xvY2tzL211dGV4LnJzAACYEBAANgAAABgAAAAJAAAAcndsb2NrIGxvY2tlZCBmb3Igd3JpdGluZwAAAOAQEAAZAAAACAAOAA8APwACAEAANQANAAQAAwAsABsAHABJABQABgA0ADAAcmFuZG9tX2dldCBmYWlsdXJlbGlicmFyeS9zdGQvc3JjL3N5cy93YXNpL21vZC5ycwAAADoREAAfAAAAXQAAACUAAABsaWJyYXJ5L3N0ZC9zcmMvc3lzX2NvbW1vbi90aHJlYWRfcGFya2VyL2dlbmVyaWMucnMAbBEQADMAAAAnAAAAJgAAAGluY29uc2lzdGVudCBwYXJrIHN0YXRlALAREAAXAAAAbBEQADMAAAA1AAAAFwAAAHBhcmsgc3RhdGUgY2hhbmdlZCB1bmV4cGVjdGVkbHkA4BEQAB8AAABsERAAMwAAADIAAAARAAAAaW5jb25zaXN0ZW50IHN0YXRlIGluIHVucGFyaxgSEAAcAAAAbBEQADMAAABsAAAAEgAAAGwREAAzAAAAegAAAB8AAABjb2RlbmFtZVoAAAAIAAAABAAAAFsAAABtZXNzYWdlTk9UQ0FQQUJMRVhERVZUWFRCU1lUSU1FRE9VVFNUQUxFU1JDSFNQSVBFUk9GU1JBTkdFUFJPVE9UWVBFUFJPVE9OT1NVUFBPUlRQUk9UT1BJUEVQRVJNT1dORVJERUFET1ZFUkZMT1dOWElPTk9UVFlOT1RTVVBOT1RTT0NLTk9UUkVDT1ZFUkFCTEVOT1RFTVBUWU5PVERJUk5PVENPTk5OT1NZU05PU1BDTk9QUk9UT09QVE5PTVNHTk9NRU1OT0xJTktOT0xDS05PRVhFQ05PRU5UTk9ERVZOT0JVRlNORklMRU5FVFVOUkVBQ0hORVRSRVNFVE5FVERPV05OQU1FVE9PTE9OR01VTFRJSE9QTVNHU0laRU1MSU5LTUZJTEVMT09QSVNESVJJU0NPTk5JT0lOVkFMSU5UUklOUFJPR1JFU1NJTFNFUUlEUk1IT1NUVU5SRUFDSEZCSUdGQVVMVEVYSVNURFFVT1RET01ERVNUQUREUlJFUURFQURMS0NPTk5SRVNFVENPTk5SRUZVU0VEQ09OTkFCT1JURURDSElMRENBTkNFTEVEQlVTWUJBRE1TR0JBREZBTFJFQURZQUdBSU5BRk5PU1VQUE9SVEFERFJOT1RBVkFJTEFERFJJTlVTRUFDQ0VTMkJJR1NVQ0NFU1NFeHRlbnNpb246IENhcGFiaWxpdGllcyBpbnN1ZmZpY2llbnQuQ3Jvc3MtZGV2aWNlIGxpbmsuVGV4dCBmaWxlIGJ1c3kuQ29ubmVjdGlvbiB0aW1lZCBvdXQuUmVzZXJ2ZWQuTm8gc3VjaCBwcm9jZXNzLkludmFsaWQgc2Vlay5SZWFkLW9ubHkgZmlsZSBzeXN0ZW0uUmVzdWx0IHRvbyBsYXJnZS5Qcm90b2NvbCB3cm9uZyB0eXBlIGZvciBzb2NrZXQuUHJvdG9jb2wgbm90IHN1cHBvcnRlZC5Qcm90b2NvbCBlcnJvci5Ccm9rZW4gcGlwZS5PcGVyYXRpb24gbm90IHBlcm1pdHRlZC5QcmV2aW91cyBvd25lciBkaWVkLlZhbHVlIHRvbyBsYXJnZSB0byBiZSBzdG9yZWQgaW4gZGF0YSB0eXBlLk5vIHN1Y2ggZGV2aWNlIG9yIGFkZHJlc3MuSW5hcHByb3ByaWF0ZSBJL08gY29udHJvbCBvcGVyYXRpb24uTm90IHN1cHBvcnRlZCwgb3Igb3BlcmF0aW9uIG5vdCBzdXBwb3J0ZWQgb24gc29ja2V0Lk5vdCBhIHNvY2tldC5TdGF0ZSBub3QgcmVjb3ZlcmFibGUuRGlyZWN0b3J5IG5vdCBlbXB0eS5Ob3QgYSBkaXJlY3Rvcnkgb3IgYSBzeW1ib2xpYyBsaW5rIHRvIGEgZGlyZWN0b3J5LlRoZSBzb2NrZXQgaXMgbm90IGNvbm5lY3RlZC5GdW5jdGlvbiBub3Qgc3VwcG9ydGVkLk5vIHNwYWNlIGxlZnQgb24gZGV2aWNlLlByb3RvY29sIG5vdCBhdmFpbGFibGUuTm8gbWVzc2FnZSBvZiB0aGUgZGVzaXJlZCB0eXBlLk5vdCBlbm91Z2ggc3BhY2UuTm8gbG9ja3MgYXZhaWxhYmxlLkV4ZWN1dGFibGUgZmlsZSBmb3JtYXQgZXJyb3IuTm8gc3VjaCBmaWxlIG9yIGRpcmVjdG9yeS5ObyBzdWNoIGRldmljZS5ObyBidWZmZXIgc3BhY2UgYXZhaWxhYmxlLlRvbyBtYW55IGZpbGVzIG9wZW4gaW4gc3lzdGVtLk5ldHdvcmsgdW5yZWFjaGFibGUuQ29ubmVjdGlvbiBhYm9ydGVkIGJ5IG5ldHdvcmsuTmV0d29yayBpcyBkb3duLkZpbGVuYW1lIHRvbyBsb25nLk1lc3NhZ2UgdG9vIGxhcmdlLlRvbyBtYW55IGxpbmtzLkZpbGUgZGVzY3JpcHRvciB2YWx1ZSB0b28gbGFyZ2UuVG9vIG1hbnkgbGV2ZWxzIG9mIHN5bWJvbGljIGxpbmtzLklzIGEgZGlyZWN0b3J5LlNvY2tldCBpcyBjb25uZWN0ZWQuSS9PIGVycm9yLkludmFsaWQgYXJndW1lbnQuSW50ZXJydXB0ZWQgZnVuY3Rpb24uT3BlcmF0aW9uIGluIHByb2dyZXNzLklsbGVnYWwgYnl0ZSBzZXF1ZW5jZS5JZGVudGlmaWVyIHJlbW92ZWQuSG9zdCBpcyB1bnJlYWNoYWJsZS5GaWxlIHRvbyBsYXJnZS5CYWQgYWRkcmVzcy5GaWxlIGV4aXN0cy5NYXRoZW1hdGljcyBhcmd1bWVudCBvdXQgb2YgZG9tYWluIG9mIGZ1bmN0aW9uLkRlc3RpbmF0aW9uIGFkZHJlc3MgcmVxdWlyZWQuUmVzb3VyY2UgZGVhZGxvY2sgd291bGQgb2NjdXIuQ29ubmVjdGlvbiByZXNldC5Db25uZWN0aW9uIHJlZnVzZWQuQ29ubmVjdGlvbiBhYm9ydGVkLk5vIGNoaWxkIHByb2Nlc3Nlcy5PcGVyYXRpb24gY2FuY2VsZWQuRGV2aWNlIG9yIHJlc291cmNlIGJ1c3kuQmFk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AAAAAAAAAAEAAAByAAAAL2hvbWUvcGF2ZWwvLmNhcmdvL3JlZ2lzdHJ5L3NyYy9naXRodWIuY29tLTFlY2M2Mjk5ZGI5ZWM4MjMvbWFyaW5lLXJzLXNkay1tYWluLTAuNi4xNS9zcmMvcmVzdWx0LnJzAFw9EABjAAAAQwAAACMAAABzAAAAAEHY+8AACxiIBBAAlAQQAAEAAAAAAAAAAQAAABggEAAA362BgAAEbmFtZQHUrYGAANwCAEhfWk4xOG1hcmluZV9yc19zZGtfbWFpbjZsb2dnZXIyMGxvZ191dGY4X3N0cmluZ19pbXBsMTdoZGQ5NGY0NzFjMzYyZjE3ZUUBTF9aTjR3YXNpMTNsaWJfZ2VuZXJhdGVkMjJ3YXNpX3NuYXBzaG90X3ByZXZpZXcxOGZkX3dyaXRlMTdoODFlNzQwZmI4NjZkMmMxOUUCT19aTjR3YXNpMTNsaWJfZ2VuZXJhdGVkMjJ3YXNpX3NuYXBzaG90X3ByZXZpZXcxMTByYW5kb21fZ2V0MTdoNjE2NGI5NmNjZGRmYzcxYUUDLV9faW1wb3J0ZWRfd2FzaV9zbmFwc2hvdF9wcmV2aWV3MV9lbnZpcm9uX2dldAQzX19pbXBvcnRlZF93YXNpX3NuYXBzaG90X3ByZXZpZXcxX2Vudmlyb25fc2l6ZXNfZ2V0BStfX2ltcG9ydGVkX3dhc2lfc25hcHNob3RfcHJldmlldzFfcHJvY19leGl0BklfWk40Y29yZTNudW03Zmx0MmRlYzhzdHJhdGVneTZkcmFnb24xNWZvcm1hdF9zaG9ydGVzdDE3aGVkN2VhYzBiMWFiNzg2ODBFBwhkbG1hbGxvYwhGX1pONGNvcmUzbnVtN2ZsdDJkZWM4c3RyYXRlZ3k2ZHJhZ29uMTJmb3JtYXRfZXhhY3QxN2hhNzZkNGM5NjlmN2U5MDkyRQlCX1pONGNvcmUzbnVtN2ZsdDJkZWM4c3RyYXRlZ3k2ZHJhZ29uOW11bF9wb3cxMDE3aDI1NGI5MDc2OWE4M2ZlMGVFCkxfWk40Y29yZTNudW03Zmx0MmRlYzhzdHJhdGVneTVncmlzdTE5Zm9ybWF0X3Nob3J0ZXN0X29wdDE3aGU4ZjFlYjFjNGExYmUyZDNFCy9fWk41YWxsb2M1c2xpY2UxMG1lcmdlX3NvcnQxN2gwMzAzNWY0MDk4M2RhODRhRQwGZGxmcmVlDQ1kaXNwb3NlX2NodW5rDgZtZW1jcHkPB21lbW1vdmUQOV9aTjRjb3JlM251bTZiaWdudW04QmlnMzJ4NDA4bXVsX3BvdzIxN2gzMWFiZGI4ZTA4NTdmMTE2RRE1X1pONGNvcmUzc3RyMTlzbGljZV9lcnJvcl9mYWlsX3J0MTdoNjcwNDcyNjc5ZTFlNDgxMUUSNl9aTjRjb3JlM3N0cjVjb3VudDE0ZG9fY291bnRfY2hhcnMxN2g4MDZiZDU1NTI1NDc0ZDk2RRNJX1pONGNvcmUzbnVtN2ZsdDJkZWM4c3RyYXRlZ3k1Z3Jpc3UxNmZvcm1hdF9leGFjdF9vcHQxN2gyOGRhYzg4MDU0M2FhMTFmRRQHcmVhbGxvYxVhX1pONjNfJExUJGxvZy4uTGV2ZWxGaWx0ZXIkdTIwJGFzJHUyMCRjb3JlLi5zdHIuLnRyYWl0cy4uRnJvbVN0ciRHVCQ4ZnJvbV9zdHIxN2gzYmEwMzMwYmM5NGM4ZWU5RRYuX1pONGNvcmUzZm10OUZvcm1hdHRlcjNwYWQxN2hiOWZkYzQzNGNiYjBjM2E4RRdFX1pONGNvcmUzZm10NWZsb2F0MjlmbG9hdF90b19kZWNpbWFsX2NvbW1vbl9leGFjdDE3aDA4NDZiYzU2YmM0NDU0ZThFGDhfWk40Y29yZTNmbXQ5Rm9ybWF0dGVyMTJwYWRfaW50ZWdyYWwxN2hiYTUzODI4NTNlOTliOGYzRRlFX1pONDBfJExUJHN0ciR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uRGVidWckR1QkM2ZtdDE3aDYzYjYyZWI4NDZiMzg1YzVFGjtfWk4zc3RkOXBhbmlja2luZzIwcnVzdF9wYW5pY193aXRoX2hvb2sxN2hjY2IwNGUwZDg2ODExNmIwRRszX1pOM3N0ZDlwYW5pY2tpbmcxMmRlZmF1bHRfaG9vazE3aGZjNjA2MWQxZDM0NWIzOGVFHDhfWk4zc3RkMmlvNVdyaXRlMTh3cml0ZV9hbGxfdmVjdG9yZWQxN2hjOTA2MDUxYzRiMjgwZDFkRR1RX1pOM3N0ZDlwYW5pY2tpbmcxMmRlZmF1bHRfaG9vazI4XyR1N2IkJHU3YiRjbG9zdXJlJHU3ZCQkdTdkJDE3aDFjOWRhZWViOGU5MDQ0NDVFHmdfWk42OF8kTFQkY29yZS4uZm10Li5idWlsZGVycy4uUGFkQWRhcHRlciR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uV3JpdGUkR1QkOXdyaXRlX3N0cjE3aDViZTYzNjcyNmFkMTEzZmVFH0hfWk40Y29yZTNmbXQ1ZmxvYXQzMmZsb2F0X3RvX2RlY2ltYWxfY29tbW9uX3Nob3J0ZXN0MTdoOGRjNDI5NzIzZDBhNmRlNEUgM19aTjRjb3JlM3N0cjhjb252ZXJ0czlmcm9tX3V0ZjgxN2g5MDZkMmZiMGNiYTdiOTA5RSFmX1pONzFfJExUJGNvcmUuLmhhc2guLnNpcC4uSGFzaGVyJExUJFMkR1QkJHUyMCRhcyR1MjAkY29yZS4uaGFzaC4uSGFzaGVyJEdUJDV3cml0ZTE3aGIxMTk4ZDI3YjkxYjk5OTNFIkFfWk40Y29yZTNmbXQ5Rm9ybWF0dGVyMjF3cml0ZV9mb3JtYXR0ZWRfcGFydHMxN2g2ZjA3NzNkYzljZGQyYWZiRSM2X1pOM3N0ZDRzeW5jNG9uY2U0T25jZTEwY2FsbF9pbm5lcjE3aDE4ZDE4YzAzMTI0NTg5ZTZFJCZfWk40Y29yZTNmbXQ1d3JpdGUxN2g3NWZlNWEyYmI2YjFmYzAyRSU/X1pONGNvcmUzZm10OUZvcm1hdHRlcjE5cGFkX2Zvcm1hdHRlZF9wYXJ0czE3aGM1NDcxZTM3ODI5MDk4MjlFJidfWk4zc3RkNnRocmVhZDRwYXJrMTdoNzk1NzI5MmVlYTk1ZTk1OUUnS19aTjE4bWFyaW5lX3JzX3Nka19tYWluNmxvZ2dlcjE3V2FzbUxvZ2dlckJ1aWxkZXI1YnVpbGQxN2g4ODc3Njg5ZDg5NzE2ZTQzRShgX1pONjdfJExUJG1hcmluZV9yc19zZGtfbWFpbi4ubG9nZ2VyLi5XYXNtTG9nZ2VyJHUyMCRhcyR1MjAkbG9nLi5Mb2ckR1QkM2xvZzE3aDI0NTc5NzllNGRjZWIxMGZFKThfWk4zc3RkMmlvNVdyaXRlMTh3cml0ZV9hbGxfdmVjdG9yZWQxN2g5NDY1OGU4NWY3YjNmZjVhRSo3X1pONGNvcmU0aGFzaDExQnVpbGRIYXNoZXI4aGFzaF9vbmUxN2g2ZGMyMTI5MzA5ZDFkOTVmRSsIYWxsb2NhdGUsXF9aTjRjb3JlM2ZtdDNudW01MF8kTFQkaW1wbCR1MjAkY29yZS4uZm10Li5EZWJ1ZyR1MjAkZm9yJHUyMCR1NjQkR1QkM2ZtdDE3aDRkOTU4MjBmNWUxNzg2YzNFLVlfWk40Y29yZTNudW03Zmx0MmRlYzhzdHJhdGVneTVncmlzdTE2Zm9ybWF0X2V4YWN0X29wdDE0cG9zc2libHlfcm91bmQxN2gwODY5MWYwOTJjYjNjMmYyRS5GX1pONDFfJExUJGNoYXIkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2g3OGNjMWYxMjdjNmQ1YzU2RS9wX1pONzJfJExUJCRSRiRzdHIkdTIwJGFzJHUyMCRhbGxvYy4uZmZpLi5jX3N0ci4uQ1N0cmluZy4ubmV3Li5TcGVjTmV3SW1wbCRHVCQxM3NwZWNfbmV3X2ltcGwxN2g0MGE1ZjQ3ZDczY2E5MTI2RTARaW50ZXJuYWxfbWVtYWxpZ24xgAFfWk4zc3RkMmlvNWltcGxzNzRfJExUJGltcGwkdTIwJHN0ZC4uaW8uLldyaXRlJHUyMCRmb3IkdTIwJGFsbG9jLi52ZWMuLlZlYyRMVCR1OCRDJEEkR1QkJEdUJDE0d3JpdGVfdmVjdG9yZWQxN2g5ZGY3MmU1NjNiZTNjM2RiRTJGX1pONGNvcmUzbnVtNmJpZ251bThCaWczMng0MDEwbXVsX2RpZ2l0czltdWxfaW5uZXIxN2gzNTk4MWU3NDdmZjIwODFmRTM7X1pONGNvcmUzbnVtN2ZsdDJkZWMxN2RpZ2l0c190b19kZWNfc3RyMTdoODE4MmYzZWM0YTk0NDM2MUU0T19aTjNzdGQyaW84YnVmZmVyZWQ5YnVmd3JpdGVyMThCdWZXcml0ZXIkTFQkVyRHVCQ5Zmx1c2hfYnVmMTdoOTJiZTVhMGVkZDA5MGE0ZEU1O19aTjRjb3JlOXBhbmlja2luZzE5YXNzZXJ0X2ZhaWxlZF9pbm5lcjE3aDI0MmM1ZDY5NGI3ZDZmYjdFNgZtZW1zZXQ3NF9aTjRjb3JlN3VuaWNvZGU5cHJpbnRhYmxlNWNoZWNrMTdoNTk4MDM1ZmYxODliM2E3YUU4PF9aTjRjb3JlM2ZtdDhidWlsZGVyczExRGVidWdTdHJ1Y3Q1ZmllbGQxN2g2ZGQ1MmNlYjYzMWEwODEzRTlSX1pOM3N0ZDRzeW5jNG9uY2U0T25jZTljYWxsX29uY2UyOF8kdTdiJCR1N2IkY2xvc3VyZSR1N2QkJHU3ZCQxN2gzNGE2ODVlMzhjYzg5Y2NhRTpKX1pONGNvcmU3dW5pY29kZTEydW5pY29kZV9kYXRhMTVncmFwaGVtZV9leHRlbmQ2bG9va3VwMTdoZDU5NzU5MTdiNzY5OWYwZUU7V19aTjUwXyRMVCQkUkYkbXV0JHUyMCRXJHUyMCRhcyR1MjAkY29yZS4uZm10Li5Xcml0ZSRHVCQxMHdyaXRlX2NoYXIxN2hmNTc5MDg4ZDJhZWZmODhhRTxmX1pONzNfJExUJGNvcmUuLnBhbmljLi5wYW5pY19pbmZvLi5QYW5pY0luZm8kdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRpc3BsYXkkR1QkM2ZtdDE3aDVhNWY2NWFjZjgzNjczODFFPV9fWk41OF8kTFQkYWxsb2MuLnN0cmluZy4uU3RyaW5nJHUyMCRhcyR1MjAkY29yZS4uZm10Li5Xcml0ZSRHVCQxMHdyaXRlX2NoYXIxN2g1NzU1NjFlNjQyZjg1ODYzRT4IX19zdHBjcHk/X19aTjU4XyRMVCRhbGxvYy4uc3RyaW5nLi5TdHJpbmckdTIwJGFzJHUyMCRjb3JlLi5mbXQuLldyaXRlJEdUJDEwd3JpdGVfY2hhcjE3aDU3NTU2MWU2NDJmODU4NjNFQAtfX3N0cmNocm51bEE+X1pONGNvcmU1c2xpY2U2bWVtY2hyMTltZW1jaHJfZ2VuZXJhbF9jYXNlMTdoY2E1MDhkMGUxZWNmNmQ0Y0VCMF9aTjRjb3JlM2ZtdDNudW0zaW1wN2ZtdF91NjQxN2hiMGNhYmI1NTdjMDZjMWRiRUM7X1pOM3N0ZDVhbGxvYzI0ZGVmYXVsdF9hbGxvY19lcnJvcl9ob29rMTdoYjFmYmM1NTA2ZTkxMzMwZkVEN19aTjNzdGQzc3lzNHdhc2kxN2RlY29kZV9lcnJvcl9raW5kMTdoODUyZGE4ZjU5YWU5NzI3Y0VFXF9aTjRjb3JlM2ZtdDNudW01MF8kTFQkaW1wbCR1MjAkY29yZS4uZm10Li5EZWJ1ZyR1MjAkZm9yJHUyMCR1MzIkR1QkM2ZtdDE3aGEwYzIxYTYxZmY0MmNmMGFFRjtfWk40Y29yZTNmbXQ4YnVpbGRlcnMxMERlYnVnVHVwbGU1ZmllbGQxN2gxZTU2MTBiYWE3NDhjNDA5RUcyX1pONGNvcmUzZm10NVdyaXRlMTB3cml0ZV9jaGFyMTdoMzE2NjBhNDk3ZjE1ZDI3MUVILF9aTjNzdGQzZW52MTFjdXJyZW50X2RpcjE3aGM0MzU4ODc3M2Q2OGViZGNFSURfWk41YWxsb2MzZmZpNWNfc3RyN0NTdHJpbmcxOV9mcm9tX3ZlY191bmNoZWNrZWQxN2g4ZmMzNDk1NjlmZTYyNDQwRUo7X1pONGNvcmUzZm10OGJ1aWxkZXJzMTBEZWJ1Z0lubmVyNWVudHJ5MTdoNjA3MjA4OTI2MGI0ZjUxYUVLCXRlc3RfbG9nc0xMX1pOM3N0ZDEwc3lzX2NvbW1vbjEzdGhyZWFkX3BhcmtlcjdnZW5lcmljNlBhcmtlcjZ1bnBhcmsxN2hjZGE4MWYyNmYwNjFmYzQzRU14X1pOOTFfJExUJHN0ZC4uc3lzX2NvbW1vbi4uYmFja3RyYWNlLi5fcHJpbnQuLkRpc3BsYXlCYWNrdHJhY2UkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRpc3BsYXkkR1QkM2ZtdDE3aGVkMmNkODQ4MWRlOGFjYjFFTlBfWk4zc3RkNnRocmVhZDVsb2NhbDRsYXp5MjFMYXp5S2V5SW5uZXIkTFQkVCRHVCQxMGluaXRpYWxpemUxN2g1MmZmZmE1YWM0MzBlMzNlRU9zX1pOODBfJExUJHN0ZC4uaW8uLldyaXRlLi53cml0ZV9mbXQuLkFkYXB0ZXIkTFQkVCRHVCQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLldyaXRlJEdUJDl3cml0ZV9zdHIxN2hhMzc3ZjYxNmM2NDRkMTU3RVBJX1pOMThtYXJpbmVfcnNfc2RrX21haW42bG9nZ2VyMTdXYXNtTG9nZ2VyQnVpbGRlcjNuZXcxN2hhNWZmYmYwNWU1MDdiZjY4RVEzX1pOM3N0ZDJydDE5bGFuZ19zdGFydF9pbnRlcm5hbDE3aDcwODg1NmRiYTBkMGUzMjBFUnxfWk45MF8kTFQkc3RkLi5wYW5pY2tpbmcuLmJlZ2luX3BhbmljX2hhbmRsZXIuLlBhbmljUGF5bG9hZCR1MjAkYXMkdTIwJGNvcmUuLnBhbmljLi5Cb3hNZVVwJEdUJDh0YWtlX2JveDE3aDFjNGE5MWU2NjNlN2VkNWNFUy1fWk4zc3RkNnRocmVhZDZUaHJlYWQzbmV3MTdoZWMxNDVkNTM2YjE3NjZmNUVUV19aTjUwXyRMVCQkUkYkbXV0JHUyMCRXJHUyMCRhcyR1MjAkY29yZS4uZm10Li5Xcml0ZSRHVCQxMHdyaXRlX2NoYXIxN2hiOGRlMWU2YzcyMDVmMjNiRVUkX1pOM3N0ZDNlbnY0X3ZhcjE3aDNiM2Y0MDIzYzZhZTMxNGVFVldfWk41MF8kTFQkJFJGJG11dCR1MjAkVyR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uV3JpdGUkR1QkMTB3cml0ZV9jaGFyMTdoOTBjOTc3NzQ0ZjkzMmM0MEVXMl9aTjRjb3JlM2ZtdDVXcml0ZTEwd3JpdGVfY2hhcjE3aDk1NWYzNWY1NGY2ZGNhYzBFWDJfWk40Y29yZTNmbXQ1V3JpdGUxMHdyaXRlX2NoYXIxN2g3NDQ3MTNlN2I5ZDJiNDVkRVknX1pOM3N0ZDNlbnY3X3Zhcl9vczE3aGJjOGZlOTNiMTQwZGM4NGJFWi5fWk4zc3RkMmlvNVdyaXRlOXdyaXRlX2ZtdDE3aGYyNTgwZjg3OWYyMjI0NDhFWy5fWk4zc3RkMmlvNVdyaXRlOXdyaXRlX2ZtdDE3aDc3NjI5YWQ2YmY4NTQ5Y2FFXExfWk41YWxsb2M3cmF3X3ZlYzE5UmF3VmVjJExUJFQkQyRBJEdUJDE2cmVzZXJ2ZV9mb3JfcHVzaDE3aDI5ZjYyNmY4YjY5YWZlYWRFXUVfWk40Y29yZTNmbXQ5Rm9ybWF0dGVyMjVkZWJ1Z190dXBsZV9maWVsZDJfZmluaXNoMTdoMzM1OTVhZDAwNmFlYTZhNUVeRV9aTjRjb3JlM2ZtdDlGb3JtYXR0ZXIyNWRlYnVnX3R1cGxlX2ZpZWxkMV9maW5pc2gxN2hiZTYyNjY4NTNkM2JmNmZmRV82X1pOM3N0ZDVwYW5pYzE5Z2V0X2JhY2t0cmFjZV9zdHlsZTE3aDdlYmE3Y2FlYjZkNDIyZmNFYEBfWk4zc3RkNnRocmVhZDVsb2NhbDE3TG9jYWxLZXkkTFQkVCRHVCQ0d2l0aDE3aDY2ODAyNWNhYmJkMTliYjBFYS5fWk4zbG9nMTdfX3ByaXZhdGVfYXBpX2xvZzE3aGI4ODc0MjgwYTIyNzQ5ZTVFYi5fWk4zc3RkMmlvNVdyaXRlOXdyaXRlX2FsbDE3aGE3NTY5OWEwNGE1ZmU3YTZFYwZkaXZpZGVkTF9aTjVhbGxvYzdyYXdfdmVjMTlSYXdWZWMkTFQkVCRDJEEkR1QkMTZyZXNlcnZlX2Zvcl9wdXNoMTdoNDg2MDE1YWZkYjI2YTFmZkVlWV9aTjVhbGxvYzdyYXdfdmVjMTlSYXdWZWMkTFQkVCRDJEEkR1QkN3Jlc2VydmUyMWRvX3Jlc2VydmVfYW5kX2hhbmRsZTE3aGExM2QxYzE4YjYxOWRiZTJFZllfWk41YWxsb2M3cmF3X3ZlYzE5UmF3VmVjJExUJFQkQyRBJEdUJDdyZXNlcnZlMjFkb19yZXNlcnZlX2FuZF9oYW5kbGUxN2g2ZjI0NmE5NTRkZWU0YTZlRWdMX1pONWFsbG9jN3Jhd192ZWMxOVJhd1ZlYyRMVCRUJEMkQSRHVCQxNnJlc2VydmVfZm9yX3B1c2gxN2hkNmFiMWVkMDJhMTA1YTFkRWhMX1pONWFsbG9jN3Jhd192ZWMxOVJhd1ZlYyRMVCRUJEMkQSRHVCQxNnJlc2VydmVfZm9yX3B1c2gxN2gwZTdmMDE3OGU2MjU5MGJhRWkDYWRkaghzdWJ0cmFjdGsIbXVsdGlwbHlsBnN0cmxlbm04X1pOM3N0ZDEwc3lzX2NvbW1vbjExdGhyZWFkX2luZm8zc2V0MTdoZDVmMDUyMWE4ZDg3NzYyNUVuPF9aTjRjb3JlN3VuaWNvZGU5cHJpbnRhYmxlMTJpc19wcmludGFibGUxN2g4M2M4ZDAxMjkxZDViZmZjRW9dX1pONGNvcmUzcHRyNTlkcm9wX2luX3BsYWNlJExUJG1hcmluZV9yc19zZGtfbWFpbi4ubG9nZ2VyLi5XYXNtTG9nZ2VyJEdUJDE3aDkzMTIyNzY4ZjBlMDkxZTFFcE1fWk40Y29yZTNmbXQ4YnVpbGRlcnMxMURlYnVnU3RydWN0MjFmaW5pc2hfbm9uX2V4aGF1c3RpdmUxN2g4MzJkNjEwYTg0YzU2NzZhRXF3X1pOOTBfJExUJHN0ZC4ucGFuaWNraW5nLi5iZWdpbl9wYW5pY19oYW5kbGVyLi5QYW5pY1BheWxvYWQkdTIwJGFzJHUyMCRjb3JlLi5wYW5pYy4uQm94TWVVcCRHVCQzZ2V0MTdoYzhkNmQ2NGQ0Mzg2YTM3NkVyCnJ1c3RfcGFuaWNzMl9aTjVhbGxvYzdyYXdfdmVjMTFmaW5pc2hfZ3JvdzE3aDc2Y2JiMzFiM2VmYjFhZDlFdDJfWk41YWxsb2M3cmF3X3ZlYzExZmluaXNoX2dyb3cxN2g4MWRjYjY1NWI2YWY2YzYzRXVLX1pONWFsbG9jN3Jhd192ZWMxMWZpbmlzaF9ncm93MTdoMDliNzk0ODExZWZkMGRkNEUubGx2bS43MDQzNDUzNjExMTg5NzYzNzExdl9fWk40Y29yZTNmbXQzbnVtNTNfJExUJGltcGwkdTIwJGNvcmUuLmZtdC4uTG93ZXJIZXgkdTIwJGZvciR1MjAkaTE2JEdUJDNmbXQxN2hmZjVjYzMzMWExYmI0MzgzRXdeX1pONGNvcmUzZm10M251bTUyXyRMVCRpbXBsJHUyMCRjb3JlLi5mbXQuLkxvd2VySGV4JHUyMCRmb3IkdTIwJGk4JEdUJDNmbXQxN2hmZmI4NmQ0NWQxNzEwNDI4RXheX1pONGNvcmUzZm10M251bTUyXyRMVCRpbXBsJHUyMCRjb3JlLi5mbXQuLlVwcGVySGV4JHUyMCRmb3IkdTIwJGk4JEdUJDNmbXQxN2hkOGFjY2IxYmUxMjJkZTVkRXlfX1pONGNvcmUzZm10M251bTUzXyRMVCRpbXBsJHUyMCRjb3JlLi5mbXQuLlVwcGVySGV4JHUyMCRmb3IkdTIwJGkxNiRHVCQzZm10MTdoYjZiODQ4OWQ3NzUxOGM2N0V6X19aTjRjb3JlM2ZtdDNudW01M18kTFQkaW1wbCR1MjAkY29yZS4uZm10Li5Mb3dlckhleCR1MjAkZm9yJHUyMCRpMzIkR1QkM2ZtdDE3aGM5ZTIxNjEzNTIxNjlkOTBFe19fWk40Y29yZTNmbXQzbnVtNTNfJExUJGltcGwkdTIwJGNvcmUuLmZtdC4uVXBwZXJIZXgkdTIwJGZvciR1MjAkaTMyJEdUJDNmbXQxN2g2YjdkOWFiMDdlYWVjZmNhRXwdX193YXNpbGliY19pbml0aWFsaXplX2Vudmlyb259B3N0cm5jbXB+ZF9aTjY3XyRMVCRtYXJpbmVfcnNfc2RrX21haW4uLmxvZ2dlci4uV2FzbUxvZ2dlciR1MjAkYXMkdTIwJGxvZy4uTG9nJEdUJDdlbmFibGVkMTdoN2ExMjgwZTRhNzRkYTBlZkV/Y19aTjcwXyRMVCRjb3JlLi5wYW5pYy4ubG9jYXRpb24uLkxvY2F0aW9uJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EaXNwbGF5JEdUJDNmbXQxN2gxZjM3Mzc4YzAyYzI2OTA3RYABWF9aTjNzdGQ5cGFuaWNraW5nMTliZWdpbl9wYW5pY19oYW5kbGVyMjhfJHU3YiQkdTdiJGNsb3N1cmUkdTdkJCR1N2QkMTdoNTU0MWY3NGEwMzMxYTFkY0WBAQZnZXRlbnaCAVxfWk42M18kTFQkd2FzaS4ubGliX2dlbmVyYXRlZC4uRXJybm8kdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2g4ZTQwN2U5ZTIwYmNlMDQzRYMBMl9aTjRjb3JlNnJlc3VsdDEzdW53cmFwX2ZhaWxlZDE3aDg2OGEwMDYwMWEzZWI2ODdFhAFfX1pONjRfJExUJHN0ZC4uc3lzLi53YXNpLi5zdGRpby4uU3RkZXJyJHUyMCRhcyR1MjAkc3RkLi5pby4uV3JpdGUkR1QkNXdyaXRlMTdoOGRlNzk5NjUyNGZiM2FkZkWFAT1fWk40Y29yZTNmbXQ4YnVpbGRlcnMxMURlYnVnU3RydWN0NmZpbmlzaDE3aDE1ODY1OWZjZjc5YzU5ZjlFhgFkX1pONzFfJExUJGNvcmUuLm9wcy4ucmFuZ2UuLlJhbmdlJExUJElkeCRHVCQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2g2NzQzYWVkNmQyMzZhMzlhRYcBBmNhbGxvY4gBSV9aTjQ0XyRMVCQkUkYkVCR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uRGlzcGxheSRHVCQzZm10MTdoMjMwZDVhOTZjNzhkZDRlN0WJAUdfWk40Ml8kTFQkJFJGJFQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2gxZmM4NGJmMDZlOTFkZWUwRYoBOV9aTjNzdGQzc3lzNHdhc2kxOWhhc2htYXBfcmFuZG9tX2tleXMxN2gxYzBjMGM4ZGQ1ZDQ3YmE4RYsBSV9aTjVhbGxvYzN2ZWMxNlZlYyRMVCRUJEMkQSRHVCQ2cmVtb3ZlMTNhc3NlcnRfZmFpbGVkMTdoYWYyNmM2ODIzNjUyOGZkNkWMAUdfWk40Y29yZTVzbGljZTVpbmRleDI5c2xpY2Vfc3RhcnRfaW5kZXhfbGVuX2ZhaWxfcnQxN2hhNGE1MTA5MTg5YmU2MDBiRY0BRV9aTjRjb3JlNXNsaWNlNWluZGV4MjdzbGljZV9lbmRfaW5kZXhfbGVuX2ZhaWxfcnQxN2gxYjk4OWE3YjkyYmY2Y2Y1RY4BQ19aTjRjb3JlNXNsaWNlNWluZGV4MjVzbGljZV9pbmRleF9vcmRlcl9mYWlsX3J0MTdoNTlmZTk3Mzc0MzdiZTljMUWPATpfWk40Y29yZTlwYW5pY2tpbmcxOHBhbmljX2JvdW5kc19jaGVjazE3aDk4NDRlNDZjMzM5YjliZmZFkAFYX1pONTlfJExUJGNvcmUuLmZtdC4uQXJndW1lbnRzJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EaXNwbGF5JEdUJDNmbXQxN2hhNjM1MjMyMTQxNzYyYTVlRZEBNF9aTjRjb3JlM2ZtdDlGb3JtYXR0ZXI5d3JpdGVfZm10MTdoNTVhZGViODYxNTYzM2VkMUWSATVfWk40Y29yZTlwYW5pY2tpbmcxM2Fzc2VydF9mYWlsZWQxN2g4OTZkODFlMmU3ZDI3MjAwRZMBNV9aTjRjb3JlOXBhbmlja2luZzEzYXNzZXJ0X2ZhaWxlZDE3aDRhNzEyZTM2ZmQwN2U5ZDdFlAE1X1pONGNvcmU5cGFuaWNraW5nMTNhc3NlcnRfZmFpbGVkMTdoM2NmYmY5MWI2NGRiMzljMEWVAVVfWk41MF8kTFQkJFJGJG11dCR1MjAkVyR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uV3JpdGUkR1QkOXdyaXRlX2ZtdDE3aDBmMzMwMTcwODg4OGU2ZTNFlgFVX1pONTBfJExUJCRSRiRtdXQkdTIwJFckdTIwJGFzJHUyMCRjb3JlLi5mbXQuLldyaXRlJEdUJDl3cml0ZV9mbXQxN2gzYzY0ODYzMzk5NmZlMDc3RZcBVV9aTjUwXyRMVCQkUkYkbXV0JHUyMCRXJHUyMCRhcyR1MjAkY29yZS4uZm10Li5Xcml0ZSRHVCQ5d3JpdGVfZm10MTdoNjA5Zjc0NDg3MTYwNWU4YUWYAVVfWk41MF8kTFQkJFJGJG11dCR1MjAkVyR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uV3JpdGUkR1QkOXdyaXRlX2ZtdDE3aGU5ZThmNDI3ZGJhMWU1N2ZFmQFVX1pONTBfJExUJCRSRiRtdXQkdTIwJFckdTIwJGFzJHUyMCRjb3JlLi5mbXQuLldyaXRlJEdUJDl3cml0ZV9mbXQxN2gwZTQ3NWRiNzM1NDYxZTQ5RZoBMF9aTjRjb3JlM2ZtdDVXcml0ZTl3cml0ZV9mbXQxN2hkMmIzMGJjOGFhNTczYzQ3RZsBLV9aTjNsb2cxNnNldF9ib3hlZF9sb2dnZXIxN2g1YzA4OTg2YmQxZDc2MDNkRZwBMF9aTjRjb3JlM2ZtdDVXcml0ZTl3cml0ZV9mbXQxN2g0OGE0MmFkNzU4OGY0ZWU5RZ0BMF9aTjRjb3JlM2ZtdDVXcml0ZTl3cml0ZV9mbXQxN2g2ZWE0NzQ0ZmU2M2IyMTk1RZ4BaV9aTjY0XyRMVCRzdGQuLnN5cy4ud2FzaS4uc3RkaW8uLlN0ZGVyciR1MjAkYXMkdTIwJHN0ZC4uaW8uLldyaXRlJEdUJDE0d3JpdGVfdmVjdG9yZWQxN2g2OWRkZjM2YTk3OTdhOWFiRZ8BMF9aTjRjb3JlM2ZtdDVXcml0ZTl3cml0ZV9mbXQxN2hjZWU1ZjNmZTQ1M2ZiZmQxRaABBXN0YXRloQE6X1pONWFsbG9jNHN5bmMxMkFyYyRMVCRUJEdUJDlkcm9wX3Nsb3cxN2gxOTI4YzYyNTVmYTMzMDdkRaIBdl9aTjNzdGQyaW81aW1wbHM3NF8kTFQkaW1wbCR1MjAkc3RkLi5pby4uV3JpdGUkdTIwJGZvciR1MjAkYWxsb2MuLnZlYy4uVmVjJExUJHU4JEMkQSRHVCQkR1QkNXdyaXRlMTdoMzk5MTU1OWFhYzY0NzBmMkWjAQtjbGVhcl9zdGF0ZaQBY19aTjcwXyRMVCRjb3JlLi5yZXN1bHQuLlJlc3VsdCRMVCRUJEMkRSRHVCQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2hiZjI5ODBhYmFjYmMxZGU4RaUBfV9aTjkxXyRMVCRzdGQuLnBhbmlja2luZy4uYmVnaW5fcGFuaWMuLlBhbmljUGF5bG9hZCRMVCRBJEdUJCR1MjAkYXMkdTIwJGNvcmUuLnBhbmljLi5Cb3hNZVVwJEdUJDh0YWtlX2JveDE3aGUyYTNiMTY3ZGZhYjliNjBFpgFVX1pONTBfJExUJCRSRiRtdXQkdTIwJFckdTIwJGFzJHUyMCRjb3JlLi5mbXQuLldyaXRlJEdUJDl3cml0ZV9zdHIxN2g4YjdhNTE4MzA2ZWM2M2RiRacBVV9aTjUwXyRMVCQkUkYkbXV0JHUyMCRXJHUyMCRhcyR1MjAkY29yZS4uZm10Li5Xcml0ZSRHVCQ5d3JpdGVfc3RyMTdoMWI2MWEwMjJhZGMyNWRkYkWoAVVfWk41MF8kTFQkJFJGJG11dCR1MjAkVyR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uV3JpdGUkR1QkOXdyaXRlX3N0cjE3aDQ0ODczYjQ2ODNjZjk0M2FFqQF6X1pOM3N0ZDJpbzVpbXBsczc0XyRMVCRpbXBsJHUyMCRzdGQuLmlvLi5Xcml0ZSR1MjAkZm9yJHUyMCRhbGxvYy4udmVjLi5WZWMkTFQkdTgkQyRBJEdUJCRHVCQ5d3JpdGVfYWxsMTdoZThjYzI2MjMwNDQwNmUwYkWqAXNfWk44MF8kTFQkc3RkLi5pby4uV3JpdGUuLndyaXRlX2ZtdC4uQWRhcHRlciRMVCRUJEdUJCR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uV3JpdGUkR1QkOXdyaXRlX3N0cjE3aDkzNmQ4ZTkxYTE1NjhmNThFqwE0X1pONHdhc2kxM2xpYl9nZW5lcmF0ZWQ4ZmRfd3JpdGUxN2g1MDZlNmUxNGE4MGEwYmJiRawBXV9aTjU4XyRMVCRhbGxvYy4uc3RyaW5nLi5TdHJpbmckdTIwJGFzJHUyMCRjb3JlLi5mbXQuLldyaXRlJEdUJDl3cml0ZV9zdHIxN2g1MTY4MGQyM2NjMWU2ZWIxRa0BBHNicmuuAXNfWk40Y29yZTNwdHI4MWRyb3BfaW5fcGxhY2UkTFQkY29yZS4ucmVzdWx0Li5SZXN1bHQkTFQkJExQJCRSUCQkQyRzdGQuLmlvLi5lcnJvci4uRXJyb3IkR1QkJEdUJDE3aGQ4NGFkYWIyYThlNWVjYmFFrwF5X1pONGNvcmUzcHRyODdkcm9wX2luX3BsYWNlJExUJHN0ZC4uaW8uLldyaXRlLi53cml0ZV9mbXQuLkFkYXB0ZXIkTFQkJFJGJG11dCR1MjAkJHU1YiR1OCR1NWQkJEdUJCRHVCQxN2g0ZjQzY2EyMGEwY2JhNmM0RbABDV9fcmRsX3JlYWxsb2OxAQZtZW1jbXCyAUZfWk40Y29yZTNmbXQ5Rm9ybWF0dGVyMTJwYWRfaW50ZWdyYWwxMndyaXRlX3ByZWZpeDE3aDhmMmU0ZmMzZGFhMjYzNzVFswEGZ2V0Y3dktAE6X1pONWFsbG9jNHN5bmMxMkFyYyRMVCRUJEdUJDlkcm9wX3Nsb3cxN2g2YzFmZGI4NjZlMmFlZmQ3RbUBXV9aTjY0XyRMVCRhbGxvYy4uZmZpLi5jX3N0ci4uTnVsRXJyb3IkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2hlOGFiOTlhZDhmZDZiOTA4RbYBLF9aTjRjb3JlOXBhbmlja2luZzVwYW5pYzE3aGVkZjQzNzhlMjA0NjFiMjVFtwE1X1pONGNvcmU5cGFuaWNraW5nMTNwYW5pY19kaXNwbGF5MTdoNjE0YmNmYTcyMzZmOTFhYUW4AX9fWk45M18kTFQkc3RkLi5wYW5pY2tpbmcuLmJlZ2luX3BhbmljX2hhbmRsZXIuLlN0clBhbmljUGF5bG9hZCR1MjAkYXMkdTIwJGNvcmUuLnBhbmljLi5Cb3hNZVVwJEdUJDh0YWtlX2JveDE3aGNmODc3ZmRiMGZjY2Q1NjFFuQFgX1pONGNvcmUzZm10NWZsb2F0NTJfJExUJGltcGwkdTIwJGNvcmUuLmZtdC4uRGlzcGxheSR1MjAkZm9yJHUyMCRmNjQkR1QkM2ZtdDE3aDY1NDMyN2NkNmY5ZWM1YTJFugERcnVzdF9iZWdpbl91bndpbmS7AThfWk41YWxsb2M3cmF3X3ZlYzE3Y2FwYWNpdHlfb3ZlcmZsb3cxN2hjYTIzZTA2MDBhOTUzNGY2RbwBMF9aTjRjb3JlOXBhbmlja2luZzlwYW5pY19mbXQxN2g3YTY1MWM3MGE5NDkyMjhjRb0BKl9aTjEyY2FsY19zZXJ2aWNlNG1haW4xN2gwY2E3NWE5OTZkODFiYTczRb4BVV9aTjU2XyRMVCRsb2cuLlNldExvZ2dlckVycm9yJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EZWJ1ZyRHVCQzZm10MTdoNjUyYzYxNzYzODg0NTJhMkW/AUdfWk40Ml8kTFQkJFJGJFQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2gzZWJjMzNmYzA3ZjQwZmRmRcABYV9aTjY4XyRMVCRzdGQuLnRocmVhZC4ubG9jYWwuLkFjY2Vzc0Vycm9yJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EZWJ1ZyRHVCQzZm10MTdoNTE3ZjAxOTlmNzk2OWU0ZEXBAWlfWk43Nl8kTFQkc3RkLi5zeW5jLi5wb2lzb24uLlBvaXNvbkVycm9yJExUJFQkR1QkJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EZWJ1ZyRHVCQzZm10MTdoMTdhNDJkMjNlOGVjMWJjZEXCAUdfWk40Ml8kTFQkJFJGJFQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2g1Y2M3Njk4N2QxYWY4YzljRcMBR19aTjQyXyRMVCQkUkYkVCR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uRGVidWckR1QkM2ZtdDE3aGMxOGRkNjA0OTVjZWZlMDBFxAEPX19vcmlnaW5hbF9tYWluxQFhX1pOM3N0ZDJydDEwbGFuZ19zdGFydDI4XyR1N2IkJHU3YiRjbG9zdXJlJHU3ZCQkdTdkJDE3aDY5ZmNlMWZmZGI2ZjVhOThFLmxsdm0uNzEzOTI0MTQxMTY3NDgxMjc1M8YBc19aTjRjb3JlM29wczhmdW5jdGlvbjZGbk9uY2U0MGNhbGxfb25jZSR1N2IkJHU3YiR2dGFibGUuc2hpbSR1N2QkJHU3ZCQxN2gyMjFjZWNjMmEwOGQ2ZTM4RS5sbHZtLjcxMzkyNDE0MTE2NzQ4MTI3NTPHAYoBX1pONGNvcmUzcHRyMTAzZHJvcF9pbl9wbGFjZSRMVCRzdGQuLnN5bmMuLnBvaXNvbi4uUG9pc29uRXJyb3IkTFQkc3RkLi5zeW5jLi5tdXRleC4uTXV0ZXhHdWFyZCRMVCQkTFAkJFJQJCRHVCQkR1QkJEdUJDE3aGEzYjY1YzIyMDJlZDhjOWNFyAFQX1pOM3N0ZDlwYW5pY2tpbmcxMWJlZ2luX3BhbmljMjhfJHU3YiQkdTdiJGNsb3N1cmUkdTdkJCR1N2QkMTdoM2ZhOWYwYzVkM2JkNzBmZEXJATJfWk40Y29yZTNzdHIxNnNsaWNlX2Vycm9yX2ZhaWwxN2hkNGY4MTcyYTA1YjExYTk5RcoBLl9aTjRjb3JlM2ZtdDlGb3JtYXR0ZXIzbmV3MTdoNDkxOGE3OWU1NTQyN2Y4OEXLAThfWk40Y29yZTNmbXQ5Rm9ybWF0dGVyMTJkZWJ1Z19zdHJ1Y3QxN2g5N2UxYzNkYjQ0YzU5YmE3RcwBNl9aTjRjb3JlM2ZtdDlGb3JtYXR0ZXIxMGRlYnVnX2xpc3QxN2hjZmE0NmI2NDgxODczMjEyRc0BXF9aTjRjb3JlM2ZtdDNudW01MF8kTFQkaW1wbCR1MjAkY29yZS4uZm10Li5EZWJ1ZyR1MjAkZm9yJHUyMCR1MTYkR1QkM2ZtdDE3aGRjNTNlOTE1M2E4MGM4ZWFFzgFaX1pONGNvcmUzb3BzOGZ1bmN0aW9uNkZuT25jZTQwY2FsbF9vbmNlJHU3YiQkdTdiJHZ0YWJsZS5zaGltJHU3ZCQkdTdkJDE3aGIwYzFkNzhjYWUyM2M5ODFFzwE6X1pONGNvcmUzZm10OGJ1aWxkZXJzOURlYnVnTGlzdDZmaW5pc2gxN2hjNmJlNTZkZDZiZDQxYWVkRdABMl9aTjNzdGQ5cGFuaWNraW5nMTFiZWdpbl9wYW5pYzE3aGQ2N2I5NTY5NmM3ZjRmZjVF0QFoX1pONGNvcmUzcHRyNzBkcm9wX2luX3BsYWNlJExUJHN0ZC4ucGFuaWNraW5nLi5iZWdpbl9wYW5pY19oYW5kbGVyLi5QYW5pY1BheWxvYWQkR1QkMTdoNGI1ODNhYTM0NDIzYzUwMkXSATBfWk40Y29yZTlwYW5pY2tpbmc5cGFuaWNfc3RyMTdoZTE2NDQzMDcwMTk4OGU1YUXTAQtfX3JkbF9hbGxvY9QBNl9aTjR3YXNpMTNsaWJfZ2VuZXJhdGVkNUVycm5vNG5hbWUxN2hmZDJlOWQ1YjM5NGFhNzljRdUBOV9aTjR3YXNpMTNsaWJfZ2VuZXJhdGVkNUVycm5vN21lc3NhZ2UxN2hlNjQ0MWI5OTQ1ZjI4YjM0RdYBBnN0cmR1cNcBTF9aTjRjb3JlM3B0cjQyZHJvcF9pbl9wbGFjZSRMVCRhbGxvYy4uc3RyaW5nLi5TdHJpbmckR1QkMTdoYzI0MWFmNWJhYTA2M2RkM0XYAYUCX1pONGNvcmUzcHRyMjI2ZHJvcF9pbl9wbGFjZSRMVCRzdGQuLmVycm9yLi4kTFQkaW1wbCR1MjAkY29yZS4uY29udmVydC4uRnJvbSRMVCRhbGxvYy4uc3RyaW5nLi5TdHJpbmckR1QkJHUyMCRmb3IkdTIwJGFsbG9jLi5ib3hlZC4uQm94JExUJGR5biR1MjAkc3RkLi5lcnJvci4uRXJyb3IkdTJiJGNvcmUuLm1hcmtlci4uU3luYyR1MmIkY29yZS4ubWFya2VyLi5TZW5kJEdUJCRHVCQuLmZyb20uLlN0cmluZ0Vycm9yJEdUJDE3aGU0NzcyOTQ5NTNmOTJhZWNF2QFIX1pONDNfJExUJGJvb2wkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRpc3BsYXkkR1QkM2ZtdDE3aGExY2M5ZWEzZDEyZGRjNDJF2gF4X1pOOTFfJExUJHN0ZC4ucGFuaWNraW5nLi5iZWdpbl9wYW5pYy4uUGFuaWNQYXlsb2FkJExUJEEkR1QkJHUyMCRhcyR1MjAkY29yZS4ucGFuaWMuLkJveE1lVXAkR1QkM2dldDE3aDliMDdiZjIyZThiZTZkYjdF2wE/X1pONWFsbG9jNnN0cmluZzEzRnJvbVV0ZjhFcnJvcjEwaW50b19ieXRlczE3aGExN2RmMTk0OGI3Njc4NGVF3AEIcnVzdF9vb23dATdfWk40d2FzaTEzbGliX2dlbmVyYXRlZDEwcmFuZG9tX2dldDE3aDkxN2JjYWNhOWU5YWY4MGNF3gENYWxpZ25lZF9hbGxvY98BTl9aTjE4bWFyaW5lX3JzX3Nka19tYWluNnJlc3VsdDE4T0JKRUNUU19UT19SRUxFQVNFN19fZ2V0aXQxN2hjYjA2MGU1MmVlNWY5NTU4ReABO19aTjRjb3JlMTBpbnRyaW5zaWNzMTdjb25zdF9ldmFsX3NlbGVjdDE3aGQ1YWZmYTBjOWNlZTZlY2VF4QFcX1pONjNfJExUJGNvcmUuLmNlbGwuLkJvcnJvd011dEVycm9yJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EZWJ1ZyRHVCQzZm10MTdoMTI0MmQ5MTEyNjQ3MTI4MkXiAVJfWk41M18kTFQkY29yZS4uZm10Li5FcnJvciR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uRGVidWckR1QkM2ZtdDE3aGE2MGRhOGViOWMxMzQ5MThF4wE7X1pONGNvcmU2b3B0aW9uMTVPcHRpb24kTFQkVCRHVCQ2dW53cmFwMTdoNDRhNDBjZDU2YTcyNGUxY0XkATtfWk40Y29yZTZvcHRpb24xNU9wdGlvbiRMVCRUJEdUJDZ1bndyYXAxN2hiYzljMDJjZGNkZGNlMDE0ReUBBl9zdGFydOYBDl9fcnVzdF9yZWFsbG9j5wFNX1pOM3N0ZDEwc3lzX2NvbW1vbjliYWNrdHJhY2UyNl9fcnVzdF9lbmRfc2hvcnRfYmFja3RyYWNlMTdoODU1MzJmMzkwZGFlYWM0ZUXoAU1fWk4zc3RkMTBzeXNfY29tbW9uOWJhY2t0cmFjZTI2X19ydXN0X2VuZF9zaG9ydF9iYWNrdHJhY2UxN2g3M2E0M2YzOGI1ZTZlZTA5RekBSV9aTjQ0XyRMVCQkUkYkVCR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uRGlzcGxheSRHVCQzZm10MTdoMDY3YzhlZGUyYTNmYmQ3YkXqARlfX3dhc2lsaWJjX2Vuc3VyZV9lbnZpcm9u6wFHX1pONDJfJExUJCRSRiRUJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EZWJ1ZyRHVCQzZm10MTdoMjAwNWIzMWM4OTYxOTIxOUXsAQxfX3J1c3RfYWxsb2PtAUlfWk40NF8kTFQkJFJGJFQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRpc3BsYXkkR1QkM2ZtdDE3aGEwOGZhZjdmN2M3MTgyNzNF7gFXX1pONTBfJExUJCRSRiRtdXQkdTIwJFckdTIwJGFzJHUyMCRjb3JlLi5mbXQuLldyaXRlJEdUJDEwd3JpdGVfY2hhcjE3aDQyNTAzNDBiM2FjZTQyYzJF7wF6X1pOOTNfJExUJHN0ZC4ucGFuaWNraW5nLi5iZWdpbl9wYW5pY19oYW5kbGVyLi5TdHJQYW5pY1BheWxvYWQkdTIwJGFzJHUyMCRjb3JlLi5wYW5pYy4uQm94TWVVcCRHVCQzZ2V0MTdoN2VkNjU2ZThmZjhjNmIzZkXwAUdfWk40Ml8kTFQkJFJGJFQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2g0MWQzYTA2OTc1OTMzNTc1RfEBOl9aTjRjb3JlM29wczhmdW5jdGlvbjZGbk9uY2U5Y2FsbF9vbmNlMTdoYjdiZDgyYzY0MzM2OTI0Y0XyAUlfWk40NF8kTFQkJFJGJFQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRpc3BsYXkkR1QkM2ZtdDE3aGFjMGZkZjAzZWE5ODFmMmVF8wE7X1pONGNvcmUzZm10OUZvcm1hdHRlcjE1ZGVidWdfbG93ZXJfaGV4MTdoMzVkZWQxZDc5NGVhNWQ3MkX0ATtfWk40Y29yZTNmbXQ5Rm9ybWF0dGVyMTVkZWJ1Z191cHBlcl9oZXgxN2hmOWY5MmFjYTFlNTBkZDExRfUBDl9fcnVzdF9kZWFsbG9j9gFHX1pONDJfJExUJCRSRiRUJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EZWJ1ZyRHVCQzZm10MTdoNGNmYzczNWI4NDgyYmNjYUX3AVVfWk41MF8kTFQkJFJGJG11dCR1MjAkVyR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uV3JpdGUkR1QkOXdyaXRlX3N0cjE3aDRjMmI3MDQ4N2EzZmQxMzVF+AESX193YXNpX2Vudmlyb25fZ2V0+QEYX193YXNpX2Vudmlyb25fc2l6ZXNfZ2V0+gEEZXhpdPsBBnN0cmNwefwBOl9aTjRjb3JlM29wczhmdW5jdGlvbjZGbk9uY2U5Y2FsbF9vbmNlMTdoYzVhODdmYmI0MDFhN2VlZUX9AWJfWk40Y29yZTNmbXQzbnVtM2ltcDUyXyRMVCRpbXBsJHUyMCRjb3JlLi5mbXQuLkRpc3BsYXkkdTIwJGZvciR1MjAkdTMyJEdUJDNmbXQxN2hkNGI2ZmZjOGEwYzdlMzUyRf4BMl9aTjRjb3JlNm9wdGlvbjEzZXhwZWN0X2ZhaWxlZDE3aGI3ZWRkYzVhMTkzN2U2YmJF/wE4X1pONGNvcmUzZm10OGJ1aWxkZXJzOERlYnVnU2V0NWVudHJ5MTdoMDE0ZjlkNmYyZGMyZTQ2Y0WAAlVfWk41MF8kTFQkJFJGJG11dCR1MjAkVyR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uV3JpdGUkR1QkOXdyaXRlX3N0cjE3aDIxODAyY2EzZjM4MTRlZGZFgQJhX1pONGNvcmUzZm10M251bTNpbXA1MV8kTFQkaW1wbCR1MjAkY29yZS4uZm10Li5EaXNwbGF5JHUyMCRmb3IkdTIwJHU4JEdUJDNmbXQxN2g0MDBmMWYyNmZmMzI2Y2I2RYICYl9aTjRjb3JlM2ZtdDNudW0zaW1wNTJfJExUJGltcGwkdTIwJGNvcmUuLmZtdC4uRGlzcGxheSR1MjAkZm9yJHUyMCR1MTYkR1QkM2ZtdDE3aDI1NDk4MTU3MWU3OTU5NThFgwITbWFpbi5jb21tYW5kX2V4cG9ydIQCF2FsbG9jYXRlLmNvbW1hbmRfZXhwb3J0hQIaX19ydXN0X2FsbG9jX2Vycm9yX2hhbmRsZXKGAkdfWk40Ml8kTFQkJFJGJFQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRlYnVnJEdUJDNmbXQxN2gzYTIzMzM0ODlkZDVlNjM4RYcCR19aTjQyXyRMVCQkUkYkVCR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uRGVidWckR1QkM2ZtdDE3aDBlOGZhNTFlM2UyYzJkZDBFiAJHX1pONDJfJExUJCRSRiRUJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EZWJ1ZyRHVCQzZm10MTdoZmNmMWQ4NDAxZWIxNzQwZkWJAklfWk40NF8kTFQkJFJGJFQkdTIwJGFzJHUyMCRjb3JlLi5mbXQuLkRpc3BsYXkkR1QkM2ZtdDE3aGI5ODMxNTk5NGYxODYwMmVFigJXX1pONTBfJExUJCRSRiRtdXQkdTIwJFckdTIwJGFzJHUyMCRjb3JlLi5mbXQuLldyaXRlJEdUJDEwd3JpdGVfY2hhcjE3aDZkOTY1Mjc3MmE3ZmE1YjhFiwI7X1pONGNvcmUxMGludHJpbnNpY3MxN2NvbnN0X2V2YWxfc2VsZWN0MTdoNzRlNzg5ZDUzNmFlMDYyYkWMAjpfWk40Y29yZTNvcHM4ZnVuY3Rpb242Rm5PbmNlOWNhbGxfb25jZTE3aGViYTk2ODMwZjRlYzc1YzdFjQJAX1pONWFsbG9jNWFsbG9jMThoYW5kbGVfYWxsb2NfZXJyb3I4cnRfZXJyb3IxN2hmMjhjYTFkNDc1YWU3OTQ4RY4CN19aTjVhbGxvYzVhbGxvYzE4aGFuZGxlX2FsbG9jX2Vycm9yMTdoMWVlMWNjZmRhZmU2YTQwYUWPAghfX3JnX29vbZACOl9aTjRjb3JlM29wczhmdW5jdGlvbjZGbk9uY2U5Y2FsbF9vbmNlMTdoMjQ4ZGJjYjIwNGNjMTRlNUWRAjpfWk40Y29yZTNvcHM4ZnVuY3Rpb242Rm5PbmNlOWNhbGxfb25jZTE3aDM4ZjFhYjY0YjJjZWM1MTRFkgI6X1pONGNvcmUzb3BzOGZ1bmN0aW9uNkZuT25jZTljYWxsX29uY2UxN2hkNWU1NThhODE1YzU0YWU3RZMCRF9aTjRjb3JlNXNsaWNlNWluZGV4MjZzbGljZV9zdGFydF9pbmRleF9sZW5fZmFpbDE3aDIzMWE0NDJlYWUyMDBkNmJFlAJCX1pONGNvcmU1c2xpY2U1aW5kZXgyNHNsaWNlX2VuZF9pbmRleF9sZW5fZmFpbDE3aGM5Mjg4ZWViMTkyN2M4ZDdFlQJAX1pONGNvcmU1c2xpY2U1aW5kZXgyMnNsaWNlX2luZGV4X29yZGVyX2ZhaWwxN2hmMTc0ZTA1NWFlNTMzNzNmRZYCO19aTjRjb3JlMTBpbnRyaW5zaWNzMTdjb25zdF9ldmFsX3NlbGVjdDE3aDA0MzllMDIyMmZhMjQ3MGFFlwI7X1pONGNvcmUxMGludHJpbnNpY3MxN2NvbnN0X2V2YWxfc2VsZWN0MTdoNDExYTg0ZjM2ODM4NWFmYUWYAjtfWk40Y29yZTEwaW50cmluc2ljczE3Y29uc3RfZXZhbF9zZWxlY3QxN2hlMDQxN2M3NjBiNGFhOTA3RZkCQF9aTjRjb3JlNXBhbmljMTBwYW5pY19pbmZvOVBhbmljSW5mbzdwYXlsb2FkMTdoNjk5YTNkYmZlZDIxMGQyNkWaAkdfWk40Ml8kTFQkc3RyJHUyMCRhcyR1MjAkY29yZS4uZm10Li5EaXNwbGF5JEdUJDNmbXQxN2hiYTZmZTJhY2Q1NTE0YzJkRZsCR19aTjQyXyRMVCQkUkYkVCR1MjAkYXMkdTIwJGNvcmUuLmZtdC4uRGVidWckR1QkM2ZtdDE3aDdiMWQzZDMzMGE3YTgxMzFFnAISYWRkLmNvbW1hbmRfZXhwb3J0nQIXc3VidHJhY3QuY29tbWFuZF9leHBvcnSeAhdtdWx0aXBseS5jb21tYW5kX2V4cG9ydJ8CFWRpdmlkZS5jb21tYW5kX2V4cG9ydKACHXNldF9yZXN1bHRfcHRyLmNvbW1hbmRfZXhwb3J0oQIec2V0X3Jlc3VsdF9zaXplLmNvbW1hbmRfZXhwb3J0ogJFX1pOM3N0ZDlwYW5pY2tpbmcxMXBhbmljX2NvdW50MTdpc196ZXJvX3Nsb3dfcGF0aDE3aGZmNzI3ZTc1ODE2MThkNTVFowJ2X1pOM3N0ZDJpbzVpbXBsczc0XyRMVCRpbXBsJHUyMCRzdGQuLmlvLi5Xcml0ZSR1MjAkZm9yJHUyMCRhbGxvYy4udmVjLi5WZWMkTFQkdTgkQyRBJEdUJCRHVCQ1Zmx1c2gxN2hiNDY5NDA3NmQwNWYyYjhiRaQCX19aTjY0XyRMVCRzdGQuLnN5cy4ud2FzaS4uc3RkaW8uLlN0ZGVyciR1MjAkYXMkdTIwJHN0ZC4uaW8uLldyaXRlJEdUJDVmbHVzaDE3aDgzMzY1ZTNiMTQ1ZDA4NzZFpQIQX193YXNpX3Byb2NfZXhpdKYCBV9FeGl0pwIOc2V0X3Jlc3VsdF9wdHKoAg9zZXRfcmVzdWx0X3NpemWpAhVfc3RhcnQuY29tbWFuZF9leHBvcnSqAhh0ZXN0X2xvZ3MuY29tbWFuZF9leHBvcnSrAhpjbGVhcl9zdGF0ZS5jb21tYW5kX2V4cG9ydKwCFHN0YXRlLmNvbW1hbmRfZXhwb3J0rQIdZ2V0X3Jlc3VsdF9wdHIuY29tbWFuZF9leHBvcnSuAh5nZXRfcmVzdWx0X3NpemUuY29tbWFuZF9leHBvcnSvAh5yZWxlYXNlX29iamVjdHMuY29tbWFuZF9leHBvcnSwAk9fWk4zc3RkMTBzeXNfY29tbW9uOWJhY2t0cmFjZTI4X19ydXN0X2JlZ2luX3Nob3J0X2JhY2t0cmFjZTE3aDNkMTVlZmZkMDg2MzYzOTJFsQI0X1pOM3N0ZDNzeXM0d2FzaTE0YWJvcnRfaW50ZXJuYWwxN2hlMjU0NWYwYjAyYmQzNjJkRbICKV9aTjNzdGQ3cHJvY2VzczVhYm9ydDE3aDRjYzRjY2QwZjViZGM4OTFFswINX19yZGxfZGVhbGxvY7QCPF9aTjNzdGQzc3lzNHdhc2k3cHJvY2VzczhFeGl0Q29kZTZhc19pMzIxN2g2OWY4NTg2MjEzYzJlNmQ3RbUCNV9aTjR3YXNpMTNsaWJfZ2VuZXJhdGVkNUVycm5vM3JhdzE3aDg4MzgzNDkzOTY4NGE4YTlFtgIGbWFsbG9jtwIEZnJlZbgCEV9fd2FzbV9jYWxsX2R0b3JzuQJAX1pONGNvcmU1cGFuaWMxMHBhbmljX2luZm85UGFuaWNJbmZvN21lc3NhZ2UxN2hhMDI2YTM3Zjc1MTM1NGFjRboCQV9aTjRjb3JlNXBhbmljMTBwYW5pY19pbmZvOVBhbmljSW5mbzhsb2NhdGlvbjE3aDU5NzNiODU1YTE4N2E5ZDZFuwJEX1pONGNvcmU1cGFuaWMxMHBhbmljX2luZm85UGFuaWNJbmZvMTBjYW5fdW53aW5kMTdoMjFiZGQ3NTAyZDZlMzVlZkW8Ag5nZXRfcmVzdWx0X3B0cr0CD2dldF9yZXN1bHRfc2l6Zb4CD3JlbGVhc2Vfb2JqZWN0c78CEV9fd2FzbV9jYWxsX2N0b3JzwAIEbWFpbsECTF9aTjQzXyRMVCRsb2cuLk5vcExvZ2dlciR1MjAkYXMkdTIwJGxvZy4uTG9nJEdUJDdlbmFibGVkMTdoNzAwNDJmODk4NmE2NWU5N0XCAkVfWk4zNl8kTFQkVCR1MjAkYXMkdTIwJGNvcmUuLmFueS4uQW55JEdUJDd0eXBlX2lkMTdoZDg0ZjVlZGUwYzY3ZTAxZUXDAkVfWk4zNl8kTFQkVCR1MjAkYXMkdTIwJGNvcmUuLmFueS4uQW55JEdUJDd0eXBlX2lkMTdoMzAyYzRiYTdiZTViNzY4NUXEAkVfWk4zNl8kTFQkVCR1MjAkYXMkdTIwJGNvcmUuLmFueS4uQW55JEdUJDd0eXBlX2lkMTdoM2RmZjNmOTA0ZTRlMmJiMkXFAkVfWk4zNl8kTFQkVCR1MjAkYXMkdTIwJGNvcmUuLmFueS4uQW55JEdUJDd0eXBlX2lkMTdoNjc4M2NkNzgyNGFlZDY4NEXGAoMBX1pOM3N0ZDJpbzVpbXBsczc0XyRMVCRpbXBsJHUyMCRzdGQuLmlvLi5Xcml0ZSR1MjAkZm9yJHUyMCRhbGxvYy4udmVjLi5WZWMkTFQkdTgkQyRBJEdUJCRHVCQxN2lzX3dyaXRlX3ZlY3RvcmVkMTdoNzIzMmUyNTQwZWU5MjVjOEXHAmxfWk42NF8kTFQkc3RkLi5zeXMuLndhc2kuLnN0ZGlvLi5TdGRlcnIkdTIwJGFzJHUyMCRzdGQuLmlvLi5Xcml0ZSRHVCQxN2lzX3dyaXRlX3ZlY3RvcmVkMTdoMDY5YjFmODgzMGU4MzZkZUXIAhJfX3J1c3Rfc3RhcnRfcGFuaWPJAiVfX3dhc2lsaWJjX2luaXRpYWxpemVfZW52aXJvbl9lYWdlcmx5ygIFYWJvcnTLAkVfWk4zNl8kTFQkVCR1MjAkYXMkdTIwJGNvcmUuLmFueS4uQW55JEdUJDd0eXBlX2lkMTdoYTc4MjMzN2Y2YzZlYWNmOUXMAkpfWk40Y29yZTNwdHI0MGRyb3BfaW5fcGxhY2UkTFQkbG9nLi5TZXRMb2dnZXJFcnJvciRHVCQxN2hhOWVlYTFjZGFhNmZkNGVmRc0CkAFfWk40Y29yZTNwdHI4NWRyb3BfaW5fcGxhY2UkTFQkc3RkLi5ydC4ubGFuZ19zdGFydCRMVCQkTFAkJFJQJCRHVCQuLiR1N2IkJHU3YiRjbG9zdXJlJHU3ZCQkdTdkJCRHVCQxN2gxNWUxZWJkMGFkYzg5ZWIyRS5sbHZtLjcxMzkyNDE0MTE2NzQ4MTI3NTPOAlhfWk40Y29yZTNwdHI1NGRyb3BfaW5fcGxhY2UkTFQkJFJGJG11dCR1MjAkYWxsb2MuLnN0cmluZy4uU3RyaW5nJEdUJDE3aDI2OWU0NDFiNTA0NmVjMjlFzwJHX1pONGNvcmUzcHRyMzdkcm9wX2luX3BsYWNlJExUJGNvcmUuLmZtdC4uRXJyb3IkR1QkMTdoZGM2NzQxY2U1YjMyZGVmM0XQAmJfWk42N18kTFQkbWFyaW5lX3JzX3Nka19tYWluLi5sb2dnZXIuLldhc21Mb2dnZXIkdTIwJGFzJHUyMCRsb2cuLkxvZyRHVCQ1Zmx1c2gxN2hjNTU5OWU5YWZhMDQ3YTg3RdECQl9aTjRjb3JlM3B0cjMyZHJvcF9pbl9wbGFjZSRMVCQkUkYkJFJGJHN0ciRHVCQxN2g5YzYyM2JkNTFiNzk1YTYxRdICSF9aTjQzXyRMVCRsb2cuLk5vcExvZ2dlciR1MjAkYXMkdTIwJGxvZy4uTG9nJEdUJDNsb2cxN2g4NzI1YjgwOTY1NWJjMjEyRdMCSl9aTjQzXyRMVCRsb2cuLk5vcExvZ2dlciR1MjAkYXMkdTIwJGxvZy4uTG9nJEdUJDVmbHVzaDE3aDQ4MmNhZTIzZWMzYWZiNTRF1AJvX1pONGNvcmUzcHRyNzdkcm9wX2luX3BsYWNlJExUJHN0ZC4ucGFuaWNraW5nLi5iZWdpbl9wYW5pYy4uUGFuaWNQYXlsb2FkJExUJCRSRiRzdHIkR1QkJEdUJDE3aGIyMTFiMWMzNmZlYzM2ZThF1QI+X1pONGNvcmUzcHRyMjhkcm9wX2luX3BsYWNlJExUJCRSRiRzdHIkR1QkMTdoNjJiZTY3ZWM0ODNiMGVhZUXWAocBX1pONGNvcmUzcHRyMTAwZHJvcF9pbl9wbGFjZSRMVCQkUkYkbXV0JHUyMCRzdGQuLmlvLi5Xcml0ZS4ud3JpdGVfZm10Li5BZGFwdGVyJExUJGFsbG9jLi52ZWMuLlZlYyRMVCR1OCRHVCQkR1QkJEdUJDE3aDU4Y2JlYzFiOGUyNGE4MDZF1wI5X1pONGNvcmUzcHRyMjNkcm9wX2luX3BsYWNlJExUJHU4JEdUJDE3aDExMjIyOTU3MGNhOWEwMTZF2AIFZHVtbXnZAj1fWk40Y29yZTNwdHIyN2Ryb3BfaW5fcGxhY2UkTFQkJFJGJHU4JEdUJDE3aGE0YmY1OGZjMWU2YmI5YzhF2gKJAV9aTjRjb3JlM3B0cjEwMmRyb3BfaW5fcGxhY2UkTFQkJFJGJGNvcmUuLml0ZXIuLmFkYXB0ZXJzLi5jb3BpZWQuLkNvcGllZCRMVCRjb3JlLi5zbGljZS4uaXRlci4uSXRlciRMVCR1OCRHVCQkR1QkJEdUJDE3aGRkZDAxNjVkMjVmNWVjNTRF2wJrX1pONGNvcmUzcHRyNDdkcm9wX2luX3BsYWNlJExUJGNvcmUuLmNlbGwuLkJvcnJvd011dEVycm9yJEdUJDE3aDdjNWJmNDRiNmE2ZDBiOTZFLmxsdm0uMTU3Nzc2NDg0NDA1MzUyNzMyMTQA8ICAgAAJcHJvZHVjZXJzAghsYW5ndWFnZQEEUnVzdAAMcHJvY2Vzc2VkLWJ5AwVjbGFuZwYxNC4wLjAFcnVzdGMlMS42NC4wLW5pZ2h0bHkgKDgzMDg4MDY0MCAyMDIyLTA2LTI4KQZ3YWxydXMGMC4xOS4wAKqBgIAAHV9fbV9nZW5lcmF0ZWRfc2VjdGlvbl9fZGl2aWRleyJhc3RfdHlwZSI6IkZ1bmN0aW9uIiwic2lnbmF0dXJlIjp7Im5hbWUiOiJkaXZpZGUiLCJhcmd1bWVudHMiOlt7Im5hbWUiOiJudW0iLCJ0eSI6eyJGNjQiOiJCeVZhbHVlIn19XSwib3V0cHV0X3R5cGVzIjpbeyJGNjQiOiJCeVZhbHVlIn1dfX0AroGAgAAfX19tX2dlbmVyYXRlZF9zZWN0aW9uX19tdWx0aXBseXsiYXN0X3R5cGUiOiJGdW5jdGlvbiIsInNpZ25hdHVyZSI6eyJuYW1lIjoibXVsdGlwbHkiLCJhcmd1bWVudHMiOlt7Im5hbWUiOiJudW0iLCJ0eSI6eyJGNjQiOiJCeVZhbHVlIn19XSwib3V0cHV0X3R5cGVzIjpbeyJGNjQiOiJCeVZhbHVlIn1dfX0Ag4GAgAAcX19tX2dlbmVyYXRlZF9zZWN0aW9uX19zdGF0ZXsiYXN0X3R5cGUiOiJGdW5jdGlvbiIsInNpZ25hdHVyZSI6eyJuYW1lIjoic3RhdGUiLCJhcmd1bWVudHMiOltdLCJvdXRwdXRfdHlwZXMiOlt7IkY2NCI6IkJ5VmFsdWUifV19fQD+gICAACJfX21fZ2VuZXJhdGVkX3NlY3Rpb25fX2NsZWFyX3N0YXRleyJhc3RfdHlwZSI6IkZ1bmN0aW9uIiwic2lnbmF0dXJlIjp7Im5hbWUiOiJjbGVhcl9zdGF0ZSIsImFyZ3VtZW50cyI6W10sIm91dHB1dF90eXBlcyI6W119fQCugYCAAB9fX21fZ2VuZXJhdGVkX3NlY3Rpb25fX3N1YnRyYWN0eyJhc3RfdHlwZSI6IkZ1bmN0aW9uIiwic2lnbmF0dXJlIjp7Im5hbWUiOiJzdWJ0cmFjdCIsImFyZ3VtZW50cyI6W3sibmFtZSI6Im51bSIsInR5Ijp7IkY2NCI6IkJ5VmFsdWUifX1dLCJvdXRwdXRfdHlwZXMiOlt7IkY2NCI6IkJ5VmFsdWUifV19fQCkgYCAABpfX21fZ2VuZXJhdGVkX3NlY3Rpb25fX2FkZHsiYXN0X3R5cGUiOiJGdW5jdGlvbiIsInNpZ25hdHVyZSI6eyJuYW1lIjoiYWRkIiwiYXJndW1lbnRzIjpbeyJuYW1lIjoibnVtIiwidHkiOnsiRjY0IjoiQnlWYWx1ZSJ9fV0sIm91dHB1dF90eXBlcyI6W3siRjY0IjoiQnlWYWx1ZSJ9XX19APqAgIAAIF9fbV9nZW5lcmF0ZWRfc2VjdGlvbl9fdGVzdF9sb2dzeyJhc3RfdHlwZSI6IkZ1bmN0aW9uIiwic2lnbmF0dXJlIjp7Im5hbWUiOiJ0ZXN0X2xvZ3MiLCJhcmd1bWVudHMiOltdLCJvdXRwdXRfdHlwZXMiOltdfX0A/4KAgAAPaW50ZXJmYWNlLXR5cGVzBQYwLjI0LjEAFAABBHNpemUMAQwAAAAAAAEMAAABDAABC3Jlc3VsdF9zaXplDAAAAQpyZXN1bHRfcHRyDAAAAQNudW0JAQkAAQNudW0JAQkAAQNudW0JAQkAAQNudW0JAQkAAAEJAAABCQAAAAAAAAABA251bQkBCQABA251bQkBCQABA251bQkBCQABA251bQkBCQAAAAAAAAIHBgIAAAEGCAIAAAEHCgEBCAwBAQkOAgAAAQoQAgAAAQsSAQEMAw0IYWxsb2NhdGUAD3JlbGVhc2Vfb2JqZWN0cwEPZ2V0X3Jlc3VsdF9zaXplAg5nZXRfcmVzdWx0X3B0cgMPc2V0X3Jlc3VsdF9zaXplBA5zZXRfcmVzdWx0X3B0cgUGZGl2aWRlBwhtdWx0aXBseQkFc3RhdGULC2NsZWFyX3N0YXRlDQhzdWJ0cmFjdA8DYWRkEQl0ZXN0X2xvZ3MTBAcHBgkICwoNDA8OERATEgCcgICAABVfX2ZsdWVuY2Vfc2RrX3ZlcnNpb24wLjYuMTU="; diff --git a/packages/@tests/aqua/tsconfig.json b/packages/@tests/aqua/tsconfig.json index 9c0bfac2c..44db9b100 100644 --- a/packages/@tests/aqua/tsconfig.json +++ b/packages/@tests/aqua/tsconfig.json @@ -1,9 +1,9 @@ { - "extends": "../../../tsconfig.json", - "compilerOptions": { - "outDir": "./dist", - "module": "NodeNext" - }, - "include": ["src/**/*"], - "exclude": ["node_modules", "dist"] + "extends": "../../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist", + "module": "NodeNext" + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] } diff --git a/packages/@tests/smoke/node/package.json b/packages/@tests/smoke/node/package.json index 24a790bd1..7c6be3a6f 100644 --- a/packages/@tests/smoke/node/package.json +++ b/packages/@tests/smoke/node/package.json @@ -1,23 +1,23 @@ { - "name": "@test/smoke", - "version": "0.1.0", - "description": "Smoke test", - "main": "./dist/index.js", - "typings": "./dist/index.d.ts", - "engines": { - "node": ">=10", - "pnpm": ">=3" - }, - "type": "module", - "scripts": { - "build": "tsc", - "test": "node --loader ts-node/esm ./src/index.ts" - }, - "repository": "https://github.com/fluencelabs/fluence-js", - "author": "Fluence Labs", - "license": "Apache-2.0", - "dependencies": { - "@fluencelabs/js-client": "workspace:*", - "@test/aqua_for_test": "workspace:*" - } + "name": "@test/smoke", + "version": "0.1.0", + "description": "Smoke test", + "main": "./dist/index.js", + "typings": "./dist/index.d.ts", + "engines": { + "node": ">=10", + "pnpm": ">=3" + }, + "type": "module", + "scripts": { + "build": "tsc", + "test": "node --loader ts-node/esm ./src/index.ts" + }, + "repository": "https://github.com/fluencelabs/fluence-js", + "author": "Fluence Labs", + "license": "Apache-2.0", + "dependencies": { + "@fluencelabs/js-client": "workspace:*", + "@test/aqua_for_test": "workspace:*" + } } diff --git a/packages/@tests/smoke/node/src/index.ts b/packages/@tests/smoke/node/src/index.ts index 6332ecd01..0d97b44f6 100644 --- a/packages/@tests/smoke/node/src/index.ts +++ b/packages/@tests/smoke/node/src/index.ts @@ -18,5 +18,5 @@ import "@fluencelabs/js-client"; import { runTest } from "@test/aqua_for_test"; await runTest().then(() => { - console.log("Smoke tests succeed!"); + console.log("Smoke tests succeed!"); }); diff --git a/packages/@tests/smoke/node/tsconfig.json b/packages/@tests/smoke/node/tsconfig.json index 32d340ac6..4398ffdaa 100644 --- a/packages/@tests/smoke/node/tsconfig.json +++ b/packages/@tests/smoke/node/tsconfig.json @@ -1,7 +1,7 @@ { - "extends": "../../../../tsconfig.json", - "compilerOptions": { - "outDir": "./dist" - }, - "exclude": ["node_modules", "dist"] + "extends": "../../../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist" + }, + "exclude": ["node_modules", "dist"] } diff --git a/packages/@tests/smoke/web-cra-ts/package.json b/packages/@tests/smoke/web-cra-ts/package.json index ed0bf420d..bfeea5c8f 100644 --- a/packages/@tests/smoke/web-cra-ts/package.json +++ b/packages/@tests/smoke/web-cra-ts/package.json @@ -1,50 +1,50 @@ { - "name": "cra-ts", - "version": "0.1.0", - "private": true, - "type": "module", - "dependencies": { - "@test/aqua_for_test": "workspace:*", - "@testing-library/jest-dom": "5.16.5", - "@testing-library/react": "13.4.0", - "@testing-library/user-event": "13.5.0", - "@types/jest": "27.5.2", - "@types/node": "16.18.12", - "@types/react": "18.0.27", - "@types/react-dom": "18.0.10", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "react-scripts": "5.0.1", - "web-vitals": "2.1.4" - }, - "devDependencies": { - "@test/test-utils": "workspace:*", - "puppeteer": "19.7.2" - }, - "scripts": { - "test": "node --loader ts-node/esm ./test/index.ts", - "simulate-cdn": "http-server -p 8766 ../../../client/js-client.web.standalone/dist", - "start": "react-scripts start", - "build": "react-scripts build", - "_test": "react-scripts test", - "eject": "react-scripts eject" - }, - "eslintConfig": { - "extends": [ - "react-app", - "react-app/jest" - ] - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] - } + "name": "cra-ts", + "version": "0.1.0", + "private": true, + "type": "module", + "dependencies": { + "@test/aqua_for_test": "workspace:*", + "@testing-library/jest-dom": "5.16.5", + "@testing-library/react": "13.4.0", + "@testing-library/user-event": "13.5.0", + "@types/jest": "27.5.2", + "@types/node": "16.18.12", + "@types/react": "18.0.27", + "@types/react-dom": "18.0.10", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-scripts": "5.0.1", + "web-vitals": "2.1.4" + }, + "devDependencies": { + "@test/test-utils": "workspace:*", + "puppeteer": "19.7.2" + }, + "scripts": { + "test": "node --loader ts-node/esm ./test/index.ts", + "simulate-cdn": "http-server -p 8766 ../../../client/js-client.web.standalone/dist", + "start": "react-scripts start", + "build": "react-scripts build", + "_test": "react-scripts test", + "eject": "react-scripts eject" + }, + "eslintConfig": { + "extends": [ + "react-app", + "react-app/jest" + ] + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } } diff --git a/packages/@tests/smoke/web-cra-ts/src/App.css b/packages/@tests/smoke/web-cra-ts/src/App.css index 78b8850cf..74b5e0534 100644 --- a/packages/@tests/smoke/web-cra-ts/src/App.css +++ b/packages/@tests/smoke/web-cra-ts/src/App.css @@ -1,38 +1,38 @@ .App { - text-align: center; + text-align: center; } .App-logo { - height: 40vmin; - pointer-events: none; + height: 40vmin; + pointer-events: none; } @media (prefers-reduced-motion: no-preference) { - .App-logo { - animation: App-logo-spin infinite 20s linear; - } + .App-logo { + animation: App-logo-spin infinite 20s linear; + } } .App-header { - background-color: #282c34; - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; + background-color: #282c34; + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: calc(10px + 2vmin); + color: white; } .App-link { - color: #61dafb; + color: #61dafb; } @keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } } diff --git a/packages/@tests/smoke/web-cra-ts/src/App.tsx b/packages/@tests/smoke/web-cra-ts/src/App.tsx index e4fb0a3fb..d5ca86f36 100644 --- a/packages/@tests/smoke/web-cra-ts/src/App.tsx +++ b/packages/@tests/smoke/web-cra-ts/src/App.tsx @@ -4,46 +4,46 @@ import logo from "./logo.svg"; import "./App.css"; function App() { - const [result, setResult] = React.useState(null); + const [result, setResult] = React.useState(null); - const onButtonClick = () => { - runTest() - .then((res) => { - setResult(res); - }) - .catch((err) => { - setResult({ type: "failure", error: err.toString() }); - }); - }; + const onButtonClick = () => { + runTest() + .then((res) => { + setResult(res); + }) + .catch((err) => { + setResult({ type: "failure", error: err.toString() }); + }); + }; - return ( - + ); } export default App; diff --git a/packages/@tests/smoke/web-cra-ts/src/index.css b/packages/@tests/smoke/web-cra-ts/src/index.css index 98556d760..4a1df4db7 100644 --- a/packages/@tests/smoke/web-cra-ts/src/index.css +++ b/packages/@tests/smoke/web-cra-ts/src/index.css @@ -1,13 +1,13 @@ body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", - "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", - "Helvetica Neue", sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", + "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", + sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; } code { - font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", - monospace; + font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", + monospace; } diff --git a/packages/@tests/smoke/web-cra-ts/src/index.tsx b/packages/@tests/smoke/web-cra-ts/src/index.tsx index 4efb5c836..4fa2a47f5 100644 --- a/packages/@tests/smoke/web-cra-ts/src/index.tsx +++ b/packages/@tests/smoke/web-cra-ts/src/index.tsx @@ -5,12 +5,12 @@ import App from "./App"; import reportWebVitals from "./reportWebVitals"; const root = ReactDOM.createRoot( - document.getElementById("root") as HTMLElement, + document.getElementById("root") as HTMLElement, ); root.render( - - - , + + + , ); // If you want to start measuring performance in your app, pass a function diff --git a/packages/@tests/smoke/web-cra-ts/src/reportWebVitals.ts b/packages/@tests/smoke/web-cra-ts/src/reportWebVitals.ts index 4d5a62920..5fa3583b7 100644 --- a/packages/@tests/smoke/web-cra-ts/src/reportWebVitals.ts +++ b/packages/@tests/smoke/web-cra-ts/src/reportWebVitals.ts @@ -1,17 +1,15 @@ import { ReportHandler } from "web-vitals"; const reportWebVitals = (onPerfEntry?: ReportHandler) => { - if (onPerfEntry && onPerfEntry instanceof Function) { - import("web-vitals").then( - ({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { - getCLS(onPerfEntry); - getFID(onPerfEntry); - getFCP(onPerfEntry); - getLCP(onPerfEntry); - getTTFB(onPerfEntry); - }, - ); - } + if (onPerfEntry && onPerfEntry instanceof Function) { + import("web-vitals").then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { + getCLS(onPerfEntry); + getFID(onPerfEntry); + getFCP(onPerfEntry); + getLCP(onPerfEntry); + getTTFB(onPerfEntry); + }); + } }; export default reportWebVitals; diff --git a/packages/@tests/smoke/web-cra-ts/test/index.ts b/packages/@tests/smoke/web-cra-ts/test/index.ts index d43887525..456f99801 100644 --- a/packages/@tests/smoke/web-cra-ts/test/index.ts +++ b/packages/@tests/smoke/web-cra-ts/test/index.ts @@ -3,9 +3,9 @@ import { dirname, join } from "path"; import { fileURLToPath } from "url"; import { - CDN_PUBLIC_PATH, - startContentServer, - stopServer, + CDN_PUBLIC_PATH, + startContentServer, + stopServer, } from "@test/test-utils"; import { access, symlink } from "fs/promises"; @@ -15,39 +15,39 @@ const __dirname = dirname(fileURLToPath(import.meta.url)); const publicPath = join(__dirname, "../build/"); const test = async () => { - const localServer = await startContentServer(port, publicPath); - try { - await access(join(publicPath, "source")); - } catch { - await symlink(CDN_PUBLIC_PATH, join(publicPath, "source")); - } + const localServer = await startContentServer(port, publicPath); + try { + await access(join(publicPath, "source")); + } catch { + await symlink(CDN_PUBLIC_PATH, join(publicPath, "source")); + } - console.log("starting puppeteer..."); - const browser = await puppeteer.launch(); - const page = (await browser.pages())[0]; + console.log("starting puppeteer..."); + const browser = await puppeteer.launch(); + const page = (await browser.pages())[0]; - // uncomment to debug what's happening inside the browser - // page.on('console', (msg) => console.log('// from console: ', msg.text())); + // uncomment to debug what's happening inside the browser + // page.on('console', (msg) => console.log('// from console: ', msg.text())); - console.log("going to the page in browser..."); - await page.goto(uri); + console.log("going to the page in browser..."); + await page.goto(uri); - console.log("clicking button..."); - await page.click("#btn"); + console.log("clicking button..."); + await page.click("#btn"); - console.log("waiting for result to appear..."); - const elem = await page.waitForSelector("#res"); + console.log("waiting for result to appear..."); + const elem = await page.waitForSelector("#res"); - console.log("getting the content of result div..."); - const content = await elem?.evaluate((x) => x.textContent); - console.log("raw result: ", content); + console.log("getting the content of result div..."); + const content = await elem?.evaluate((x) => x.textContent); + console.log("raw result: ", content); - await browser.close(); - await stopServer(localServer); + await browser.close(); + await stopServer(localServer); - if (!content) { - throw new Error("smoke test failed!"); - } + if (!content) { + throw new Error("smoke test failed!"); + } }; test().then(() => console.log("smoke tests succeed!")); diff --git a/packages/@tests/smoke/web-cra-ts/tsconfig.json b/packages/@tests/smoke/web-cra-ts/tsconfig.json index 65063b6f3..7d0ccc550 100644 --- a/packages/@tests/smoke/web-cra-ts/tsconfig.json +++ b/packages/@tests/smoke/web-cra-ts/tsconfig.json @@ -1,20 +1,20 @@ { - "compilerOptions": { - "target": "es5", - "lib": ["dom", "dom.iterable", "esnext"], - "allowJs": true, - "skipLibCheck": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "strict": true, - "forceConsistentCasingInFileNames": true, - "noFallthroughCasesInSwitch": true, - "module": "esnext", - "moduleResolution": "node", - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - "jsx": "react-jsx" - }, - "include": ["src", "test"] + "compilerOptions": { + "target": "es5", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx" + }, + "include": ["src", "test"] } diff --git a/packages/@tests/smoke/web/package.json b/packages/@tests/smoke/web/package.json index 320c0b7fc..6344982d3 100644 --- a/packages/@tests/smoke/web/package.json +++ b/packages/@tests/smoke/web/package.json @@ -1,28 +1,28 @@ { - "name": "@tests/smoke_web", - "version": "0.1.0", - "description": "Smoke test web", - "main": "./dist/index.js", - "typings": "./dist/index.d.ts", - "engines": { - "node": ">=10", - "pnpm": ">=3" - }, - "type": "module", - "scripts": { - "build": "tsc", - "simulate-cdn": "http-server -p 8765 ../../../client/js-client.web.standalone/dist", - "test": "node --loader ts-node/esm ./src/index.ts", - "serve": "http-server public" - }, - "repository": "https://github.com/fluencelabs/fluence-js", - "author": "Fluence Labs", - "license": "Apache-2.0", - "dependencies": { - "@fluencelabs/js-client": "workspace:^", - "@test/test-utils": "workspace:../../test-utils" - }, - "devDependencies": { - "puppeteer": "19.7.2" - } + "name": "@tests/smoke_web", + "version": "0.1.0", + "description": "Smoke test web", + "main": "./dist/index.js", + "typings": "./dist/index.d.ts", + "engines": { + "node": ">=10", + "pnpm": ">=3" + }, + "type": "module", + "scripts": { + "build": "tsc", + "simulate-cdn": "http-server -p 8765 ../../../client/js-client.web.standalone/dist", + "test": "node --loader ts-node/esm ./src/index.ts", + "serve": "http-server public" + }, + "repository": "https://github.com/fluencelabs/fluence-js", + "author": "Fluence Labs", + "license": "Apache-2.0", + "dependencies": { + "@fluencelabs/js-client": "workspace:^", + "@test/test-utils": "workspace:../../test-utils" + }, + "devDependencies": { + "puppeteer": "19.7.2" + } } diff --git a/packages/@tests/smoke/web/src/index.ts b/packages/@tests/smoke/web/src/index.ts index 27ecf5cfb..8e718a094 100644 --- a/packages/@tests/smoke/web/src/index.ts +++ b/packages/@tests/smoke/web/src/index.ts @@ -19,9 +19,9 @@ import { dirname, join } from "path"; import { fileURLToPath } from "url"; import { - CDN_PUBLIC_PATH, - startContentServer, - stopServer, + CDN_PUBLIC_PATH, + startContentServer, + stopServer, } from "@test/test-utils"; import puppeteer from "puppeteer"; @@ -31,46 +31,46 @@ const __dirname = dirname(fileURLToPath(import.meta.url)); const publicPath = join(__dirname, "../public/"); const test = async () => { - const localServer = await startContentServer(port, publicPath); + const localServer = await startContentServer(port, publicPath); - try { - await access(join(publicPath, "source")); - } catch { - await symlink(CDN_PUBLIC_PATH, join(publicPath, "source")); - } + try { + await access(join(publicPath, "source")); + } catch { + await symlink(CDN_PUBLIC_PATH, join(publicPath, "source")); + } - console.log("starting puppeteer..."); - const browser = await puppeteer.launch(); - const page = (await browser.pages())[0]; + console.log("starting puppeteer..."); + const browser = await puppeteer.launch(); + const page = (await browser.pages())[0]; - // uncomment to debug what's happening inside the browser - // page.on('console', (msg) => console.log('// from console: ', msg.text())); + // uncomment to debug what's happening inside the browser + // page.on('console', (msg) => console.log('// from console: ', msg.text())); - console.log("going to the page in browser..."); - await page.goto(uri); + console.log("going to the page in browser..."); + await page.goto(uri); - console.log("clicking button..."); - await page.click("#btn"); + console.log("clicking button..."); + await page.click("#btn"); - console.log("waiting for result to appear..."); - const elem = await page.waitForSelector("#res"); + console.log("waiting for result to appear..."); + const elem = await page.waitForSelector("#res"); - console.log("getting the content of result div..."); + console.log("getting the content of result div..."); - const content = await elem?.evaluate((x) => { - return x.textContent; - }); + const content = await elem?.evaluate((x) => { + return x.textContent; + }); - console.log("raw result: ", content); + console.log("raw result: ", content); - await browser.close(); - await stopServer(localServer); + await browser.close(); + await stopServer(localServer); - if (content == null) { - throw new Error("smoke test failed!"); - } + if (content == null) { + throw new Error("smoke test failed!"); + } }; void test().then(() => { - console.log("smoke tests succeed!"); + console.log("smoke tests succeed!"); }); diff --git a/packages/@tests/smoke/web/tsconfig.json b/packages/@tests/smoke/web/tsconfig.json index 82f29a61f..aec347962 100644 --- a/packages/@tests/smoke/web/tsconfig.json +++ b/packages/@tests/smoke/web/tsconfig.json @@ -1,7 +1,7 @@ { - "extends": "../../../../tsconfig.json", - "compilerOptions": { - "outDir": "./dist" - }, - "exclude": ["node_modules", "dist", "public"] + "extends": "../../../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist" + }, + "exclude": ["node_modules", "dist", "public"] } diff --git a/packages/@tests/test-utils/package.json b/packages/@tests/test-utils/package.json index 0c6ca2bc4..10b157dfe 100644 --- a/packages/@tests/test-utils/package.json +++ b/packages/@tests/test-utils/package.json @@ -1,24 +1,24 @@ { - "name": "@test/test-utils", - "version": "0.1.0", - "description": "Test utils", - "main": "./dist/index.js", - "typings": "./dist/index.d.ts", - "engines": { - "node": ">=10", - "pnpm": ">=3" - }, - "type": "module", - "scripts": { - "build": "tsc" - }, - "repository": "https://github.com/fluencelabs/fluence-js", - "author": "Fluence Labs", - "license": "Apache-2.0", - "dependencies": { - "serve-handler": "6.1.5" - }, - "devDependencies": { - "@types/serve-handler": "6.1.1" - } + "name": "@test/test-utils", + "version": "0.1.0", + "description": "Test utils", + "main": "./dist/index.js", + "typings": "./dist/index.d.ts", + "engines": { + "node": ">=10", + "pnpm": ">=3" + }, + "type": "module", + "scripts": { + "build": "tsc" + }, + "repository": "https://github.com/fluencelabs/fluence-js", + "author": "Fluence Labs", + "license": "Apache-2.0", + "dependencies": { + "serve-handler": "6.1.5" + }, + "devDependencies": { + "@types/serve-handler": "6.1.1" + } } diff --git a/packages/@tests/test-utils/src/index.ts b/packages/@tests/test-utils/src/index.ts index 9a8b4f7de..9dcd10970 100644 --- a/packages/@tests/test-utils/src/index.ts +++ b/packages/@tests/test-utils/src/index.ts @@ -24,59 +24,59 @@ import handler from "serve-handler"; const __dirname = dirname(fileURLToPath(import.meta.url)); export const CDN_PUBLIC_PATH = join( - __dirname, - "../../../core/js-client/dist/browser", + __dirname, + "../../../core/js-client/dist/browser", ); export const startCdn = (port: number) => { - return startContentServer(port, CDN_PUBLIC_PATH); + return startContentServer(port, CDN_PUBLIC_PATH); }; export const startContentServer = ( - port: number, - publicDir: string, + port: number, + publicDir: string, ): Promise => { - const server = createServer((request, response) => { - void handler(request, response, { - public: publicDir, - rewrites: [ - { - source: "/js-client.min.js", - destination: "/source/index.umd.cjs", - }, - ], - headers: [ - { - source: "**/*", - headers: [ - { - key: "Cross-Origin-Opener-Policy", - value: "same-origin", - }, - { - key: "Cross-Origin-Embedder-Policy", - value: "require-corp", - }, - ], - }, - ], - }); + const server = createServer((request, response) => { + void handler(request, response, { + public: publicDir, + rewrites: [ + { + source: "/js-client.min.js", + destination: "/source/index.umd.cjs", + }, + ], + headers: [ + { + source: "**/*", + headers: [ + { + key: "Cross-Origin-Opener-Policy", + value: "same-origin", + }, + { + key: "Cross-Origin-Embedder-Policy", + value: "require-corp", + }, + ], + }, + ], }); + }); - return new Promise((resolve) => { - const result = server.listen(port, () => { - console.log(`server started on port ${port}`); - console.log(`public dir ${publicDir}`); - resolve(result); - }); + return new Promise((resolve) => { + const result = server.listen(port, () => { + console.log(`server started on port ${port}`); + console.log(`public dir ${publicDir}`); + resolve(result); }); + }); }; export const stopServer = (app: Server): Promise => { - return new Promise((resolve) => { - app.close(() => { - console.log("server stopped"); - resolve(); - }); + return new Promise((resolve) => { + app.close(() => { + console.log("server stopped"); + resolve(); }); + }); }; diff --git a/packages/@tests/test-utils/tsconfig.json b/packages/@tests/test-utils/tsconfig.json index 8c892f213..995a8f672 100644 --- a/packages/@tests/test-utils/tsconfig.json +++ b/packages/@tests/test-utils/tsconfig.json @@ -1,7 +1,7 @@ { - "extends": "../../../tsconfig.json", - "compilerOptions": { - "outDir": "./dist" - }, - "exclude": ["node_modules", "dist"] + "extends": "../../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist" + }, + "exclude": ["node_modules", "dist"] } diff --git a/packages/core/aqua-to-js/.eslintrc.json b/packages/core/aqua-to-js/.eslintrc.json index 36a1cee74..0e1b20d4c 100644 --- a/packages/core/aqua-to-js/.eslintrc.json +++ b/packages/core/aqua-to-js/.eslintrc.json @@ -1,3 +1,3 @@ { - "ignorePatterns": ["src/**/__snapshots__/**/*"] + "ignorePatterns": ["src/**/__snapshots__/**/*"] } diff --git a/packages/core/aqua-to-js/CHANGELOG.md b/packages/core/aqua-to-js/CHANGELOG.md index 1db8be10d..ef8f07705 100644 --- a/packages/core/aqua-to-js/CHANGELOG.md +++ b/packages/core/aqua-to-js/CHANGELOG.md @@ -2,12 +2,12 @@ ### Dependencies -- The following workspace dependencies were updated - - devDependencies - - @fluencelabs/js-client bumped to 0.1.7 +- The following workspace dependencies were updated + - devDependencies + - @fluencelabs/js-client bumped to 0.1.7 ## 0.0.1 (2023-09-22) ### Features -- **aqua-compiler:** JS-client aqua wrapper [fixes DXJ-461] ([#347](https://github.com/fluencelabs/js-client/issues/347)) ([7fff3b1](https://github.com/fluencelabs/js-client/commit/7fff3b1c0374eef76ab4e665b13cf97b5c50ff70)) +- **aqua-compiler:** JS-client aqua wrapper [fixes DXJ-461] ([#347](https://github.com/fluencelabs/js-client/issues/347)) ([7fff3b1](https://github.com/fluencelabs/js-client/commit/7fff3b1c0374eef76ab4e665b13cf97b5c50ff70)) diff --git a/packages/core/aqua-to-js/package.json b/packages/core/aqua-to-js/package.json index dc771ad44..17d483961 100644 --- a/packages/core/aqua-to-js/package.json +++ b/packages/core/aqua-to-js/package.json @@ -1,30 +1,30 @@ { - "name": "@fluencelabs/aqua-to-js", - "type": "module", - "version": "0.0.2", - "description": "Tool for generating aqua wrapper", - "main": "dist/index.js", - "files": [ - "dist" - ], - "scripts": { - "test": "vitest run", - "build": "tsc" - }, - "keywords": [], - "author": "Fluence Labs", - "license": "Apache-2.0", - "dependencies": { - "ts-pattern": "5.0.5" - }, - "devDependencies": { - "@fluencelabs/aqua-api": "0.12.0", - "@fluencelabs/aqua-lib": "0.7.3", - "@fluencelabs/interfaces": "workspace:*", - "@fluencelabs/js-client": "workspace:*", - "@fluencelabs/registry": "0.8.7", - "@fluencelabs/spell": "0.5.20", - "@fluencelabs/trust-graph": "0.4.7", - "vitest": "0.29.7" - } + "name": "@fluencelabs/aqua-to-js", + "type": "module", + "version": "0.0.2", + "description": "Tool for generating aqua wrapper", + "main": "dist/index.js", + "files": [ + "dist" + ], + "scripts": { + "test": "vitest run", + "build": "tsc" + }, + "keywords": [], + "author": "Fluence Labs", + "license": "Apache-2.0", + "dependencies": { + "ts-pattern": "5.0.5" + }, + "devDependencies": { + "@fluencelabs/aqua-api": "0.12.0", + "@fluencelabs/aqua-lib": "0.7.3", + "@fluencelabs/interfaces": "workspace:*", + "@fluencelabs/js-client": "workspace:*", + "@fluencelabs/registry": "0.8.7", + "@fluencelabs/spell": "0.5.20", + "@fluencelabs/trust-graph": "0.4.7", + "vitest": "0.29.7" + } } diff --git a/packages/core/aqua-to-js/src/common.ts b/packages/core/aqua-to-js/src/common.ts index ba69fba76..27d989749 100644 --- a/packages/core/aqua-to-js/src/common.ts +++ b/packages/core/aqua-to-js/src/common.ts @@ -20,135 +20,130 @@ import { match, P } from "ts-pattern"; import { getFuncArgs } from "./utils.js"; export function genTypeName( - t: NonArrowType | ArrowWithoutCallbacks, - name: string, + t: NonArrowType | ArrowWithoutCallbacks, + name: string, ): readonly [string | undefined, string] { - const genType = typeToTs(t); - return match(t) - .with({ tag: "nil" }, () => { - return [undefined, "void"] as const; - }) - .with({ tag: "struct" }, () => { - return [`export type ${name} = ${genType}`, name] as const; - }) - .with( - { tag: P.union("labeledProduct", "unlabeledProduct") }, - (item) => { - const args = - item.tag === "labeledProduct" - ? Object.values(item.fields) - : item.items; + const genType = typeToTs(t); + return match(t) + .with({ tag: "nil" }, () => { + return [undefined, "void"] as const; + }) + .with({ tag: "struct" }, () => { + return [`export type ${name} = ${genType}`, name] as const; + }) + .with({ tag: P.union("labeledProduct", "unlabeledProduct") }, (item) => { + const args = + item.tag === "labeledProduct" ? Object.values(item.fields) : item.items; - if (args.length === 1) { - return genTypeName(args[0], name); - } + if (args.length === 1) { + return genTypeName(args[0], name); + } - return [`export type ${name} = ${genType}`, name] as const; - }, - ) - .otherwise(() => { - return [undefined, genType] as const; - }); + return [`export type ${name} = ${genType}`, name] as const; + }) + .otherwise(() => { + return [undefined, genType] as const; + }); } export function typeToTs(t: NonArrowType | ArrowWithoutCallbacks): string { - return match(t) - .with({ tag: "nil" }, () => { - return "null"; - }) - .with({ tag: "option" }, ({ type }) => { - return typeToTs(type) + " | null"; + return match(t) + .with({ tag: "nil" }, () => { + return "null"; + }) + .with({ tag: "option" }, ({ type }) => { + return typeToTs(type) + " | null"; + }) + .with({ tag: "scalar" }, ({ name }) => { + return match(name) + .with( + P.union( + "u8", + "u16", + "u32", + "u64", + "i8", + "i16", + "i32", + "i64", + "f32", + "f64", + ), + () => { + return "number"; + }, + ) + .with("bool", () => { + return "boolean"; }) - .with({ tag: "scalar" }, ({ name }) => { - return match(name) - .with( - P.union( - "u8", - "u16", - "u32", - "u64", - "i8", - "i16", - "i32", - "i64", - "f32", - "f64", - ), - () => { - return "number"; - }, - ) - .with("bool", () => { - return "boolean"; - }) - .with("string", () => { - return "string"; - }) - .with(P._, () => { - return "any"; - }) - .exhaustive(); + .with("string", () => { + return "string"; }) - .with({ tag: "array" }, ({ type }) => { - return typeToTs(type) + "[]"; + .with(P._, () => { + return "any"; }) - .with({ tag: "struct" }, ({ fields }) => { - return `{ ${Object.entries(fields) - .map(([field, type]) => { - return `${field}: ${typeToTs(type)};`; - }) - .join(" ")} }`; + .exhaustive(); + }) + .with({ tag: "array" }, ({ type }) => { + return typeToTs(type) + "[]"; + }) + .with({ tag: "struct" }, ({ fields }) => { + return `{ ${Object.entries(fields) + .map(([field, type]) => { + return `${field}: ${typeToTs(type)};`; }) - .with({ tag: "labeledProduct" }, ({ fields }) => { - return `{ ${Object.entries(fields) - .map(([field, type]) => { - return `${field}: ${typeToTs(type)};`; - }) - .join(" ")} }`; + .join(" ")} }`; + }) + .with({ tag: "labeledProduct" }, ({ fields }) => { + return `{ ${Object.entries(fields) + .map(([field, type]) => { + return `${field}: ${typeToTs(type)};`; }) - .with({ tag: "unlabeledProduct" }, ({ items }) => { - return `[${items - .map((item) => { - return typeToTs(item); - }) - .join(", ")}]`; + .join(" ")} }`; + }) + .with({ tag: "unlabeledProduct" }, ({ items }) => { + return `[${items + .map((item) => { + return typeToTs(item); }) - .with({ tag: "arrow" }, ({ domain, codomain }) => { - const retType = - codomain.tag === "nil" - ? "void" - : codomain.items.length === 1 - ? typeToTs(codomain.items[0]) - : typeToTs(codomain); - - const args = getFuncArgs(domain).map(([name, type]) => { - return [name, typeToTs(type)]; - }); + .join(", ")}]`; + }) + .with({ tag: "arrow" }, ({ domain, codomain }) => { + const retType = + codomain.tag === "nil" + ? "void" + : codomain.items.length === 1 + ? typeToTs(codomain.items[0]) + : typeToTs(codomain); - const generic = - args.length === 0 - ? "null" - : args - .map(([name]) => { - return `'${name}'`; - }) - .join(" | "); + const args = getFuncArgs(domain).map(([name, type]) => { + return [name, typeToTs(type)]; + }); - args.push(["callParams", `CallParams$$<${generic}>`]); + const generic = + args.length === 0 + ? "null" + : args + .map(([name]) => { + return `'${name}'`; + }) + .join(" | "); - const funcArgs = args - .map(([name, type]) => { - return `${name}: ${type}`; - }) - .join(", "); + args.push(["callParams", `CallParams$$<${generic}>`]); - return `(${funcArgs}) => ${retType} | Promise<${retType}>`; - }) - .with({ tag: "topType" }, () => { - return "unknown"; + const funcArgs = args + .map(([name, type]) => { + return `${name}: ${type}`; }) - .with({ tag: "bottomType" }, () => { - return "never"; - }) - .exhaustive(); + .join(", "); + + return `(${funcArgs}) => ${retType} | Promise<${retType}>`; + }) + .with({ tag: "topType" }, () => { + return "unknown"; + }) + .with({ tag: "bottomType" }, () => { + return "never"; + }) + .exhaustive(); } diff --git a/packages/core/aqua-to-js/src/generate/__test__/generate.spec.ts b/packages/core/aqua-to-js/src/generate/__test__/generate.spec.ts index d80ed7788..34effb2be 100644 --- a/packages/core/aqua-to-js/src/generate/__test__/generate.spec.ts +++ b/packages/core/aqua-to-js/src/generate/__test__/generate.spec.ts @@ -23,31 +23,31 @@ import { getPackageJsonContent, PackageJson } from "../../utils.js"; import { generateTypes, generateSources } from "../index.js"; describe("Aqua to js/ts compiler", () => { - it("compiles smoke tests successfully", async () => { - const res = await compileFromPath({ - filePath: url.fileURLToPath( - new URL("./sources/smoke_test.aqua", import.meta.url), - ), - imports: ["./node_modules"], - targetType: "air", - }); - - const pkg: PackageJson = { - ...(await getPackageJsonContent()), - version: "0.0.0", - devDependencies: { - "@fluencelabs/aqua-api": "0.0.0", - }, - }; - - const jsResult = generateSources(res, "js", pkg); - const jsTypes = generateTypes(res, pkg); - - expect(jsResult).toMatchSnapshot(); - expect(jsTypes).toMatchSnapshot(); - - const tsResult = generateSources(res, "ts", pkg); - - expect(tsResult).toMatchSnapshot(); + it("compiles smoke tests successfully", async () => { + const res = await compileFromPath({ + filePath: url.fileURLToPath( + new URL("./sources/smoke_test.aqua", import.meta.url), + ), + imports: ["./node_modules"], + targetType: "air", }); + + const pkg: PackageJson = { + ...(await getPackageJsonContent()), + version: "0.0.0", + devDependencies: { + "@fluencelabs/aqua-api": "0.0.0", + }, + }; + + const jsResult = generateSources(res, "js", pkg); + const jsTypes = generateTypes(res, pkg); + + expect(jsResult).toMatchSnapshot(); + expect(jsTypes).toMatchSnapshot(); + + const tsResult = generateSources(res, "ts", pkg); + + expect(tsResult).toMatchSnapshot(); + }); }); diff --git a/packages/core/aqua-to-js/src/generate/function.ts b/packages/core/aqua-to-js/src/generate/function.ts index 9059ce9d2..0eca8ab66 100644 --- a/packages/core/aqua-to-js/src/generate/function.ts +++ b/packages/core/aqua-to-js/src/generate/function.ts @@ -19,29 +19,29 @@ import { recursiveRenameLaquaProps } from "../utils.js"; import { AquaFunction, TypeGenerator } from "./interfaces.js"; export function generateFunctions( - typeGenerator: TypeGenerator, - functions: Record, + typeGenerator: TypeGenerator, + functions: Record, ) { - return Object.values(functions) - .map((func) => { - return generateFunction(typeGenerator, func); - }) - .join("\n\n"); + return Object.values(functions) + .map((func) => { + return generateFunction(typeGenerator, func); + }) + .join("\n\n"); } type DeepToType = { [K in keyof T]: DeepToType }; function generateFunction(typeGenerator: TypeGenerator, func: AquaFunction) { - const funcDef: DeepToType = func.funcDef; - const scriptConstName = func.funcDef.functionName + "_script"; - return `export const ${scriptConstName} = \` + const funcDef: DeepToType = func.funcDef; + const scriptConstName = func.funcDef.functionName + "_script"; + return `export const ${scriptConstName} = \` ${func.script}\`; ${typeGenerator.funcType(func)} export function ${func.funcDef.functionName}(${typeGenerator.type( - "...args", - "any[]", - )}) { + "...args", + "any[]", + )}) { return callFunction$$( args, ${JSON.stringify(recursiveRenameLaquaProps(funcDef), null, 4)}, diff --git a/packages/core/aqua-to-js/src/generate/header.ts b/packages/core/aqua-to-js/src/generate/header.ts index 5f3cfbb4a..8a6d0794b 100644 --- a/packages/core/aqua-to-js/src/generate/header.ts +++ b/packages/core/aqua-to-js/src/generate/header.ts @@ -19,10 +19,10 @@ import { PackageJson } from "../utils.js"; import { OutputType } from "./interfaces.js"; export default function generateHeader( - { version, devDependencies }: PackageJson, - outputType: OutputType, + { version, devDependencies }: PackageJson, + outputType: OutputType, ) { - return `/* eslint-disable */ + return `/* eslint-disable */ // @ts-nocheck /** * @@ -34,9 +34,9 @@ export default function generateHeader( * */ ${ - outputType === "ts" - ? "import type { IFluenceClient as IFluenceClient$$, CallParams as CallParams$$ } from '@fluencelabs/js-client';" - : "" + outputType === "ts" + ? "import type { IFluenceClient as IFluenceClient$$, CallParams as CallParams$$ } from '@fluencelabs/js-client';" + : "" } import { diff --git a/packages/core/aqua-to-js/src/generate/index.ts b/packages/core/aqua-to-js/src/generate/index.ts index 9b1225dc6..c7077c174 100644 --- a/packages/core/aqua-to-js/src/generate/index.ts +++ b/packages/core/aqua-to-js/src/generate/index.ts @@ -19,75 +19,75 @@ import { PackageJson } from "../utils.js"; import { generateFunctions } from "./function.js"; import header from "./header.js"; import { - CompilationResult, - JSTypeGenerator, - OutputType, - TSTypeGenerator, - TypeGenerator, + CompilationResult, + JSTypeGenerator, + OutputType, + TSTypeGenerator, + TypeGenerator, } from "./interfaces.js"; import { generateServices } from "./service.js"; const typeGenerators: Record = { - js: new JSTypeGenerator(), - ts: new TSTypeGenerator(), + js: new JSTypeGenerator(), + ts: new TSTypeGenerator(), }; export function generateSources( - { services, functions }: CompilationResult, - outputType: OutputType, - packageJson: PackageJson, + { services, functions }: CompilationResult, + outputType: OutputType, + packageJson: PackageJson, ) { - const typeGenerator = typeGenerators[outputType]; - return `${header(packageJson, outputType)} + const typeGenerator = typeGenerators[outputType]; + return `${header(packageJson, outputType)} ${ - Object.entries(services).length > 0 - ? `// Services + Object.entries(services).length > 0 + ? `// Services ${generateServices(typeGenerator, services)} ` - : "" + : "" } ${ - Object.entries(functions).length > 0 - ? `// Functions + Object.entries(functions).length > 0 + ? `// Functions ${generateFunctions(typeGenerator, functions)} ` - : "" + : "" }`; } export function generateTypes( - { services, functions }: CompilationResult, - packageJson: PackageJson, + { services, functions }: CompilationResult, + packageJson: PackageJson, ) { - const typeGenerator = typeGenerators["ts"]; + const typeGenerator = typeGenerators["ts"]; - const generatedServices = Object.entries(services) - .map(([srvName, srvDef]) => { - return typeGenerator.serviceType(srvName, srvDef); - }) - .join("\n"); + const generatedServices = Object.entries(services) + .map(([srvName, srvDef]) => { + return typeGenerator.serviceType(srvName, srvDef); + }) + .join("\n"); - const generatedFunctions = Object.entries(functions) - .map(([, funcDef]) => { - return typeGenerator.funcType(funcDef); - }) - .join("\n"); + const generatedFunctions = Object.entries(functions) + .map(([, funcDef]) => { + return typeGenerator.funcType(funcDef); + }) + .join("\n"); - return `${header(packageJson, "ts")} + return `${header(packageJson, "ts")} ${ - Object.entries(services).length > 0 - ? `// Services + Object.entries(services).length > 0 + ? `// Services ${generatedServices} ` - : "" + : "" } ${ - Object.entries(functions).length > 0 - ? `// Functions + Object.entries(functions).length > 0 + ? `// Functions ${generatedFunctions} ` - : "" + : "" }`; } diff --git a/packages/core/aqua-to-js/src/generate/interfaces.ts b/packages/core/aqua-to-js/src/generate/interfaces.ts index 0ad409fd6..97693fad1 100644 --- a/packages/core/aqua-to-js/src/generate/interfaces.ts +++ b/packages/core/aqua-to-js/src/generate/interfaces.ts @@ -21,153 +21,153 @@ import { CLIENT } from "../constants.js"; import { capitalize, getFuncArgs } from "../utils.js"; export interface TypeGenerator { - type(field: string, type: string): string; - generic(field: string, type: string): string; - bang(field: string): string; - funcType(funcDef: AquaFunction): string; - serviceType(srvName: string, srvDef: ServiceDef): string; + type(field: string, type: string): string; + generic(field: string, type: string): string; + bang(field: string): string; + funcType(funcDef: AquaFunction): string; + serviceType(srvName: string, srvDef: ServiceDef): string; } export class TSTypeGenerator implements TypeGenerator { - bang(field: string): string { - return `${field}!`; - } - - generic(field: string, type: string): string { - return `${field}<${type}>`; - } - - type(field: string, type: string): string { - return `${field}: ${type}`; - } - - funcType({ funcDef }: AquaFunction): string { - const args = getFuncArgs(funcDef.arrow.domain).map(([name, type]) => { - const [typeDesc, t] = genTypeName( - type, - capitalize(funcDef.functionName) + "Arg" + capitalize(name), - ); - - return [typeDesc, `${name}: ${t}`] as const; - }); - - args.push([undefined, `config?: {ttl?: number}`]); - - const argsDefs = args.map(([, def]) => { - return " " + def; - }); - - const argsDesc = args - .filter(([desc]) => { - return desc !== undefined; - }) - .map(([desc]) => { - return desc; - }); - - const functionOverloads = [ - argsDefs.join(",\n"), - [` peer: ${CLIENT}`, ...argsDefs].join(",\n"), - ]; - - const [resTypeDesc, resType] = genTypeName( - funcDef.arrow.codomain, - capitalize(funcDef.functionName) + "Result", - ); - - return [ - argsDesc.join("\n"), - resTypeDesc ?? "", - functionOverloads - .flatMap((fo) => { - return [ - `export function ${funcDef.functionName}(`, - fo, - `): Promise<${resType}>;`, - "", - ]; - }) - .join("\n"), - ] - .filter((s) => { - return s !== ""; - }) - .join("\n\n"); - } - - serviceType(srvName: string, srvDef: ServiceDef): string { - const members = - srvDef.functions.tag === "nil" - ? [] - : Object.entries(srvDef.functions.fields); - - const interfaceDefs = members - .map(([name, arrow]) => { - return ` ${name}: ${typeToTs(arrow)};`; - }) - .join("\n"); - - const interfaces = [ - `export interface ${srvName}Def {`, - interfaceDefs, - "}", - ].join("\n"); - - const peerDecl = `peer: ${CLIENT}`; - const serviceDecl = `service: ${srvName}Def`; - const serviceIdDecl = `serviceId: string`; - - const registerServiceArgs = [ - [serviceDecl], - [serviceIdDecl, serviceDecl], - [peerDecl, serviceDecl], - [peerDecl, serviceIdDecl, serviceDecl], - ]; - - return [ - interfaces, - ...registerServiceArgs.map((registerServiceArg) => { - const args = registerServiceArg.join(", "); - return `export function register${srvName}(${args}): void;`; - }), - ].join("\n"); - } + bang(field: string): string { + return `${field}!`; + } + + generic(field: string, type: string): string { + return `${field}<${type}>`; + } + + type(field: string, type: string): string { + return `${field}: ${type}`; + } + + funcType({ funcDef }: AquaFunction): string { + const args = getFuncArgs(funcDef.arrow.domain).map(([name, type]) => { + const [typeDesc, t] = genTypeName( + type, + capitalize(funcDef.functionName) + "Arg" + capitalize(name), + ); + + return [typeDesc, `${name}: ${t}`] as const; + }); + + args.push([undefined, `config?: {ttl?: number}`]); + + const argsDefs = args.map(([, def]) => { + return " " + def; + }); + + const argsDesc = args + .filter(([desc]) => { + return desc !== undefined; + }) + .map(([desc]) => { + return desc; + }); + + const functionOverloads = [ + argsDefs.join(",\n"), + [` peer: ${CLIENT}`, ...argsDefs].join(",\n"), + ]; + + const [resTypeDesc, resType] = genTypeName( + funcDef.arrow.codomain, + capitalize(funcDef.functionName) + "Result", + ); + + return [ + argsDesc.join("\n"), + resTypeDesc ?? "", + functionOverloads + .flatMap((fo) => { + return [ + `export function ${funcDef.functionName}(`, + fo, + `): Promise<${resType}>;`, + "", + ]; + }) + .join("\n"), + ] + .filter((s) => { + return s !== ""; + }) + .join("\n\n"); + } + + serviceType(srvName: string, srvDef: ServiceDef): string { + const members = + srvDef.functions.tag === "nil" + ? [] + : Object.entries(srvDef.functions.fields); + + const interfaceDefs = members + .map(([name, arrow]) => { + return ` ${name}: ${typeToTs(arrow)};`; + }) + .join("\n"); + + const interfaces = [ + `export interface ${srvName}Def {`, + interfaceDefs, + "}", + ].join("\n"); + + const peerDecl = `peer: ${CLIENT}`; + const serviceDecl = `service: ${srvName}Def`; + const serviceIdDecl = `serviceId: string`; + + const registerServiceArgs = [ + [serviceDecl], + [serviceIdDecl, serviceDecl], + [peerDecl, serviceDecl], + [peerDecl, serviceIdDecl, serviceDecl], + ]; + + return [ + interfaces, + ...registerServiceArgs.map((registerServiceArg) => { + const args = registerServiceArg.join(", "); + return `export function register${srvName}(${args}): void;`; + }), + ].join("\n"); + } } export class JSTypeGenerator implements TypeGenerator { - bang(field: string): string { - return field; - } + bang(field: string): string { + return field; + } - generic(field: string): string { - return field; - } + generic(field: string): string { + return field; + } - type(field: string): string { - return field; - } + type(field: string): string { + return field; + } - funcType(): string { - return ""; - } + funcType(): string { + return ""; + } - serviceType(): string { - return ""; - } + serviceType(): string { + return ""; + } } export interface AquaFunction { - funcDef: FunctionCallDef; - script: string; + funcDef: FunctionCallDef; + script: string; } export interface CompilationResult { - services: Record; - functions: Record; + services: Record; + functions: Record; } export interface EntityGenerator { - generate(compilationResult: CompilationResult): string; + generate(compilationResult: CompilationResult): string; } export type OutputType = "js" | "ts"; diff --git a/packages/core/aqua-to-js/src/generate/service.ts b/packages/core/aqua-to-js/src/generate/service.ts index d5c04ecb3..4c643bd69 100644 --- a/packages/core/aqua-to-js/src/generate/service.ts +++ b/packages/core/aqua-to-js/src/generate/service.ts @@ -21,69 +21,67 @@ import { recursiveRenameLaquaProps } from "../utils.js"; import { TypeGenerator } from "./interfaces.js"; interface DefaultServiceId { - s_Some__f_value?: string; + s_Some__f_value?: string; } export function generateServices( - typeGenerator: TypeGenerator, - services: Record, + typeGenerator: TypeGenerator, + services: Record, ) { - const generated = Object.entries(services) - .map(([srvName, srvDef]) => { - return generateService(typeGenerator, srvName, srvDef); - }) - .join("\n\n"); + const generated = Object.entries(services) + .map(([srvName, srvDef]) => { + return generateService(typeGenerator, srvName, srvDef); + }) + .join("\n\n"); - return generated + "\n"; + return generated + "\n"; } function generateService( - typeGenerator: TypeGenerator, - srvName: string, - srvDef: ServiceDef, + typeGenerator: TypeGenerator, + srvName: string, + srvDef: ServiceDef, ) { - return [ - typeGenerator.serviceType(srvName, srvDef), - generateRegisterServiceOverload(typeGenerator, srvName, srvDef), - ].join("\n"); + return [ + typeGenerator.serviceType(srvName, srvDef), + generateRegisterServiceOverload(typeGenerator, srvName, srvDef), + ].join("\n"); } function generateRegisterServiceOverload( - typeGenerator: TypeGenerator, - srvName: string, - srvDef: ServiceDef, + typeGenerator: TypeGenerator, + srvName: string, + srvDef: ServiceDef, ) { - return [ - `export function register${srvName}(${typeGenerator.type( - "...args", - "any[]", - )}) {`, - " registerService$$(", - " args,", - ` ${serviceToJson(srvDef)}`, - " );", - "}", - ].join("\n"); + return [ + `export function register${srvName}(${typeGenerator.type( + "...args", + "any[]", + )}) {`, + " registerService$$(", + " args,", + ` ${serviceToJson(srvDef)}`, + " );", + "}", + ].join("\n"); } function serviceToJson(service: ServiceDef): string { - return JSON.stringify( - { - // This assertion is required because aqua-api gives bad types - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - ...((service.defaultServiceId as DefaultServiceId) - .s_Some__f_value != null - ? { - defaultServiceId: - // This assertion is required because aqua-api gives bad types - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - (service.defaultServiceId as DefaultServiceId) - .s_Some__f_value, - } - : {}), - functions: recursiveRenameLaquaProps(service.functions), - }, - null, - 4, - ); + return JSON.stringify( + { + // This assertion is required because aqua-api gives bad types + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + ...((service.defaultServiceId as DefaultServiceId).s_Some__f_value != null + ? { + defaultServiceId: + // This assertion is required because aqua-api gives bad types + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + (service.defaultServiceId as DefaultServiceId).s_Some__f_value, + } + : {}), + functions: recursiveRenameLaquaProps(service.functions), + }, + null, + 4, + ); } diff --git a/packages/core/aqua-to-js/src/index.ts b/packages/core/aqua-to-js/src/index.ts index 693c44305..44c21160e 100644 --- a/packages/core/aqua-to-js/src/index.ts +++ b/packages/core/aqua-to-js/src/index.ts @@ -19,42 +19,42 @@ import { CompilationResult, OutputType } from "./generate/interfaces.js"; import { getPackageJsonContent } from "./utils.js"; interface JsOutput { - sources: string; - types: string; + sources: string; + types: string; } interface TsOutput { - sources: string; + sources: string; } type LanguageOutput = { - js: JsOutput; - ts: TsOutput; + js: JsOutput; + ts: TsOutput; }; type NothingToGenerate = null; export default async function aquaToJs( - res: CompilationResult, - outputType: T, + res: CompilationResult, + outputType: T, ): Promise { - if ( - Object.keys(res.services).length === 0 && - Object.keys(res.functions).length === 0 - ) { - return null; - } - - const packageJson = await getPackageJsonContent(); - - return outputType === "js" - ? { - sources: generateSources(res, "js", 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]); + if ( + Object.keys(res.services).length === 0 && + Object.keys(res.functions).length === 0 + ) { + return null; + } + + const packageJson = await getPackageJsonContent(); + + return outputType === "js" + ? { + sources: generateSources(res, "js", 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]); } diff --git a/packages/core/aqua-to-js/src/utils.ts b/packages/core/aqua-to-js/src/utils.ts index b66ffc8da..cd2a5d1d4 100644 --- a/packages/core/aqua-to-js/src/utils.ts +++ b/packages/core/aqua-to-js/src/utils.ts @@ -19,89 +19,89 @@ import { readFile } from "fs/promises"; import path from "path"; import { - ArrowType, - ArrowWithoutCallbacks, - JSONValue, - LabeledProductType, - NilType, - SimpleTypes, - UnlabeledProductType, + ArrowType, + ArrowWithoutCallbacks, + JSONValue, + LabeledProductType, + NilType, + SimpleTypes, + UnlabeledProductType, } from "@fluencelabs/interfaces"; export interface PackageJson { - name: string; - version: string; - devDependencies: { - ["@fluencelabs/aqua-api"]: string; - }; + name: string; + version: string; + devDependencies: { + ["@fluencelabs/aqua-api"]: string; + }; } export async function getPackageJsonContent(): Promise { - const content = await readFile( - new URL(path.join("..", "package.json"), import.meta.url), - "utf-8", - ); + const content = await readFile( + new URL(path.join("..", "package.json"), import.meta.url), + "utf-8", + ); - // TODO: Add validation here - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - return JSON.parse(content) as PackageJson; + // TODO: Add validation here + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + return JSON.parse(content) as PackageJson; } export function getFuncArgs( - domain: - | LabeledProductType> - | UnlabeledProductType - | NilType, + domain: + | LabeledProductType> + | UnlabeledProductType + | NilType, ): [string, SimpleTypes | ArrowWithoutCallbacks][] { - if (domain.tag === "labeledProduct") { - return Object.entries(domain.fields).map(([label, type]) => { - return [label, type]; - }); - } else if (domain.tag === "unlabeledProduct") { - return domain.items.map((type, index) => { - return ["arg" + index, type]; - }); - } else { - return []; - } + if (domain.tag === "labeledProduct") { + return Object.entries(domain.fields).map(([label, type]) => { + return [label, type]; + }); + } else if (domain.tag === "unlabeledProduct") { + return domain.items.map((type, index) => { + return ["arg" + index, type]; + }); + } else { + return []; + } } export function recursiveRenameLaquaProps(obj: JSONValue): unknown { - if (typeof obj !== "object" || obj === null) { - return obj; - } + if (typeof obj !== "object" || obj === null) { + return obj; + } - if (Array.isArray(obj)) { - return obj.map((item) => { - return recursiveRenameLaquaProps(item); - }); - } + if (Array.isArray(obj)) { + return obj.map((item) => { + return recursiveRenameLaquaProps(item); + }); + } - return Object.getOwnPropertyNames(obj).reduce((acc, prop) => { - let accessProp = prop; + return Object.getOwnPropertyNames(obj).reduce((acc, prop) => { + let accessProp = prop; - if (prop.includes("Laqua_js")) { - // Last part of the property separated by "_" is a correct name - const refinedProperty = prop.split("_").pop(); + if (prop.includes("Laqua_js")) { + // Last part of the property separated by "_" is a correct name + const refinedProperty = prop.split("_").pop(); - if (refinedProperty == null) { - throw new Error(`Bad property name: ${prop}.`); - } + if (refinedProperty == null) { + throw new Error(`Bad property name: ${prop}.`); + } - if (refinedProperty in obj) { - accessProp = refinedProperty; - } - } + if (refinedProperty in obj) { + accessProp = refinedProperty; + } + } - assert(accessProp in obj); + assert(accessProp in obj); - return { - ...acc, - [accessProp]: recursiveRenameLaquaProps(obj[accessProp]), - }; - }, {}); + return { + ...acc, + [accessProp]: recursiveRenameLaquaProps(obj[accessProp]), + }; + }, {}); } export function capitalize(str: string) { - return str.slice(0, 1).toUpperCase() + str.slice(1); + return str.slice(0, 1).toUpperCase() + str.slice(1); } diff --git a/packages/core/aqua-to-js/tsconfig.json b/packages/core/aqua-to-js/tsconfig.json index 705dfb8b6..db12131a9 100644 --- a/packages/core/aqua-to-js/tsconfig.json +++ b/packages/core/aqua-to-js/tsconfig.json @@ -1,10 +1,10 @@ { - "extends": "../../../tsconfig.json", - "compilerOptions": { - "esModuleInterop": true, - "resolveJsonModule": true, - "outDir": "./dist" - }, - "include": ["src/**/*"], - "exclude": ["node_modules", "dist", "src/**/__test__"] + "extends": "../../../tsconfig.json", + "compilerOptions": { + "esModuleInterop": true, + "resolveJsonModule": true, + "outDir": "./dist" + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "src/**/__test__"] } diff --git a/packages/core/interfaces/CHANGELOG.md b/packages/core/interfaces/CHANGELOG.md index 0170c5b28..65eaaefab 100644 --- a/packages/core/interfaces/CHANGELOG.md +++ b/packages/core/interfaces/CHANGELOG.md @@ -4,72 +4,72 @@ ### Features -- use marine-js 0.7.2 ([#321](https://github.com/fluencelabs/js-client/issues/321)) ([c99a509](https://github.com/fluencelabs/js-client/commit/c99a509c8743471856b0beb25696ffe7357d5399)) +- use marine-js 0.7.2 ([#321](https://github.com/fluencelabs/js-client/issues/321)) ([c99a509](https://github.com/fluencelabs/js-client/commit/c99a509c8743471856b0beb25696ffe7357d5399)) ## [0.8.1](https://github.com/fluencelabs/js-client/compare/interfaces-v0.8.0...interfaces-v0.8.1) (2023-08-08) ### Bug Fixes -- **deps:** update dependency @fluencelabs/avm to v0.43.1 ([#322](https://github.com/fluencelabs/js-client/issues/322)) ([c1d1fa6](https://github.com/fluencelabs/js-client/commit/c1d1fa6659b6dc2c6707786748b3410fab7f1bcd)) +- **deps:** update dependency @fluencelabs/avm to v0.43.1 ([#322](https://github.com/fluencelabs/js-client/issues/322)) ([c1d1fa6](https://github.com/fluencelabs/js-client/commit/c1d1fa6659b6dc2c6707786748b3410fab7f1bcd)) ## [0.8.0](https://github.com/fluencelabs/js-client/compare/interfaces-v0.7.6...interfaces-v0.8.0) (2023-06-29) ### ⚠ BREAKING CHANGES -- **avm:** avm 0.40.0 (https://github.com/fluencelabs/js-client/pull/315) +- **avm:** avm 0.40.0 (https://github.com/fluencelabs/js-client/pull/315) ### Features -- **avm:** avm 0.40.0 (https://github.com/fluencelabs/js-client/pull/315) ([8bae6e2](https://github.com/fluencelabs/js-client/commit/8bae6e24e62153b567f320ccecc7bce76bc826d1)) +- **avm:** avm 0.40.0 (https://github.com/fluencelabs/js-client/pull/315) ([8bae6e2](https://github.com/fluencelabs/js-client/commit/8bae6e24e62153b567f320ccecc7bce76bc826d1)) ## [0.7.6](https://github.com/fluencelabs/js-client/compare/interfaces-v0.7.5...interfaces-v0.7.6) (2023-06-20) ### Features -- support signatures [fixes DXJ-389] ([#310](https://github.com/fluencelabs/js-client/issues/310)) ([a60dfe0](https://github.com/fluencelabs/js-client/commit/a60dfe0d680b4d9ac5092dec64e2ebf478bf80eb)) +- support signatures [fixes DXJ-389] ([#310](https://github.com/fluencelabs/js-client/issues/310)) ([a60dfe0](https://github.com/fluencelabs/js-client/commit/a60dfe0d680b4d9ac5092dec64e2ebf478bf80eb)) ## [0.7.5](https://github.com/fluencelabs/js-client/compare/interfaces-v0.7.4...interfaces-v0.7.5) (2023-04-04) ### Features -- Cleaning up technical debts ([#295](https://github.com/fluencelabs/js-client/issues/295)) ([0b2f12d](https://github.com/fluencelabs/js-client/commit/0b2f12d8ac223db341d6c30ff403166b3eae2e56)) +- Cleaning up technical debts ([#295](https://github.com/fluencelabs/js-client/issues/295)) ([0b2f12d](https://github.com/fluencelabs/js-client/commit/0b2f12d8ac223db341d6c30ff403166b3eae2e56)) ## [0.7.4](https://github.com/fluencelabs/js-client/compare/interfaces-v0.7.3...interfaces-v0.7.4) (2023-03-31) ### Features -- **logs:** Use `debug.js` library for logging [DXJ-327] ([#285](https://github.com/fluencelabs/js-client/issues/285)) ([e95c34a](https://github.com/fluencelabs/js-client/commit/e95c34a79220bd8ecdcee806802ac3d69a2af0cb)) +- **logs:** Use `debug.js` library for logging [DXJ-327] ([#285](https://github.com/fluencelabs/js-client/issues/285)) ([e95c34a](https://github.com/fluencelabs/js-client/commit/e95c34a79220bd8ecdcee806802ac3d69a2af0cb)) ## [0.7.3](https://github.com/fluencelabs/js-client/compare/interfaces-v0.7.2...interfaces-v0.7.3) (2023-02-16) ### Bug Fixes -- Trigger release to publish packages that were built ([#262](https://github.com/fluencelabs/js-client/issues/262)) ([47abf38](https://github.com/fluencelabs/js-client/commit/47abf3882956ffbdc52df372db26ba6252e8306b)) +- Trigger release to publish packages that were built ([#262](https://github.com/fluencelabs/js-client/issues/262)) ([47abf38](https://github.com/fluencelabs/js-client/commit/47abf3882956ffbdc52df372db26ba6252e8306b)) ## [0.7.2](https://github.com/fluencelabs/js-client/compare/interfaces-v0.7.1...interfaces-v0.7.2) (2023-02-16) ### Features -- Add `getRelayPeerId` method for `IFluenceClient` ([#260](https://github.com/fluencelabs/js-client/issues/260)) ([a10278a](https://github.com/fluencelabs/js-client/commit/a10278afaa782a307feb10c4eac060094c101230)) +- Add `getRelayPeerId` method for `IFluenceClient` ([#260](https://github.com/fluencelabs/js-client/issues/260)) ([a10278a](https://github.com/fluencelabs/js-client/commit/a10278afaa782a307feb10c4eac060094c101230)) ## [0.7.1](https://github.com/fluencelabs/js-client/compare/interfaces-v0.7.0...interfaces-v0.7.1) (2023-02-16) ### Features -- Simplify JS Client public API ([#257](https://github.com/fluencelabs/js-client/issues/257)) ([9daaf41](https://github.com/fluencelabs/js-client/commit/9daaf410964d43228192c829c7ff785db6e88081)) +- Simplify JS Client public API ([#257](https://github.com/fluencelabs/js-client/issues/257)) ([9daaf41](https://github.com/fluencelabs/js-client/commit/9daaf410964d43228192c829c7ff785db6e88081)) ## [0.7.0](https://github.com/fluencelabs/fluence-js/compare/interfaces-v0.6.0...interfaces-v0.7.0) (2023-02-15) ### ⚠ BREAKING CHANGES -- Expose updated JS Client API via `js-client.api` package ([#246](https://github.com/fluencelabs/fluence-js/issues/246)) -- Standalone web JS Client ([#243](https://github.com/fluencelabs/fluence-js/issues/243)) +- Expose updated JS Client API via `js-client.api` package ([#246](https://github.com/fluencelabs/fluence-js/issues/246)) +- Standalone web JS Client ([#243](https://github.com/fluencelabs/fluence-js/issues/243)) ### Features -- Expose updated JS Client API via `js-client.api` package ([#246](https://github.com/fluencelabs/fluence-js/issues/246)) ([d4bb8fb](https://github.com/fluencelabs/fluence-js/commit/d4bb8fb42964b3ba25154232980b9ae82c21e627)) -- Standalone web JS Client ([#243](https://github.com/fluencelabs/fluence-js/issues/243)) ([9667c4f](https://github.com/fluencelabs/fluence-js/commit/9667c4fec6868f984bba13249f3c47d293396406)) +- Expose updated JS Client API via `js-client.api` package ([#246](https://github.com/fluencelabs/fluence-js/issues/246)) ([d4bb8fb](https://github.com/fluencelabs/fluence-js/commit/d4bb8fb42964b3ba25154232980b9ae82c21e627)) +- Standalone web JS Client ([#243](https://github.com/fluencelabs/fluence-js/issues/243)) ([9667c4f](https://github.com/fluencelabs/fluence-js/commit/9667c4fec6868f984bba13249f3c47d293396406)) ### Bug Fixes -- NodeJS package building ([#248](https://github.com/fluencelabs/fluence-js/issues/248)) ([0d05e51](https://github.com/fluencelabs/fluence-js/commit/0d05e517d89529af513fcb96cfa6c722ccc357a7)) +- NodeJS package building ([#248](https://github.com/fluencelabs/fluence-js/issues/248)) ([0d05e51](https://github.com/fluencelabs/fluence-js/commit/0d05e517d89529af513fcb96cfa6c722ccc357a7)) diff --git a/packages/core/interfaces/package.json b/packages/core/interfaces/package.json index 9333379dd..d668d103d 100644 --- a/packages/core/interfaces/package.json +++ b/packages/core/interfaces/package.json @@ -1,57 +1,57 @@ { - "name": "@fluencelabs/interfaces", - "type": "module", - "version": "0.8.2", - "description": "Interfaces", - "main": "./dist/index.js", - "typings": "./dist/index.d.ts", - "exports": { - ".": { - "import": "./dist/index.js", - "types": "./dist/index.d.ts" - }, - "./fluenceClient": { - "import": "./dist/fluenceClient.js", - "types": "./dist/fluenceClient.d.ts" - }, - "./compilerSupport": { - "import": "./dist/compilerSupport.js", - "types": "./dist/compilerSupport.d.ts" - }, - "./dist/fluenceClient": { - "import": "./dist/fluenceClient.js", - "types": "./dist/fluenceClient.d.ts" - }, - "./dist/compilerSupport": { - "import": "./dist/compilerSupport.js", - "types": "./dist/compilerSupport.d.ts" - } + "name": "@fluencelabs/interfaces", + "type": "module", + "version": "0.8.2", + "description": "Interfaces", + "main": "./dist/index.js", + "typings": "./dist/index.d.ts", + "exports": { + ".": { + "import": "./dist/index.js", + "types": "./dist/index.d.ts" }, - "typesVersions": { - "*": { - "fluenceClient.d.ts": [ - "./dist/fluenceClient.d.ts" - ], - "compilerSupport.d.ts": [ - "./dist/compilerSupport.d.ts" - ] - } + "./fluenceClient": { + "import": "./dist/fluenceClient.js", + "types": "./dist/fluenceClient.d.ts" }, - "engines": { - "node": ">=10", - "pnpm": ">=3" + "./compilerSupport": { + "import": "./dist/compilerSupport.js", + "types": "./dist/compilerSupport.d.ts" }, - "scripts": { - "build": "tsc" + "./dist/fluenceClient": { + "import": "./dist/fluenceClient.js", + "types": "./dist/fluenceClient.d.ts" }, - "repository": "https://github.com/fluencelabs/fluence-js", - "author": "Fluence Labs", - "license": "Apache-2.0", - "dependencies": {}, - "devDependencies": { - "@multiformats/multiaddr": "11.3.0", - "@fluencelabs/avm": "0.48.0", - "@fluencelabs/marine-js": "0.7.2", - "hotscript": "1.0.13" + "./dist/compilerSupport": { + "import": "./dist/compilerSupport.js", + "types": "./dist/compilerSupport.d.ts" } + }, + "typesVersions": { + "*": { + "fluenceClient.d.ts": [ + "./dist/fluenceClient.d.ts" + ], + "compilerSupport.d.ts": [ + "./dist/compilerSupport.d.ts" + ] + } + }, + "engines": { + "node": ">=10", + "pnpm": ">=3" + }, + "scripts": { + "build": "tsc" + }, + "repository": "https://github.com/fluencelabs/fluence-js", + "author": "Fluence Labs", + "license": "Apache-2.0", + "dependencies": {}, + "devDependencies": { + "@multiformats/multiaddr": "11.3.0", + "@fluencelabs/avm": "0.48.0", + "@fluencelabs/marine-js": "0.7.2", + "hotscript": "1.0.13" + } } diff --git a/packages/core/interfaces/src/commonTypes.ts b/packages/core/interfaces/src/commonTypes.ts index 6deaad28e..6cff6f5fa 100644 --- a/packages/core/interfaces/src/commonTypes.ts +++ b/packages/core/interfaces/src/commonTypes.ts @@ -27,8 +27,8 @@ export type PeerIdB58 = string; * Node of the Fluence network specified as a pair of node's multiaddr and it's peer id */ export type Node = { - peerId: PeerIdB58; - multiaddr: string; + peerId: PeerIdB58; + multiaddr: string; }; /** @@ -36,52 +36,52 @@ export type Node = { * @typeparam ArgName */ export type CallParams = { - /** - * The identifier of particle which triggered the call - */ - particleId: string; + /** + * The identifier of particle which triggered the call + */ + particleId: string; - /** - * The peer id which created the particle - */ - initPeerId: PeerIdB58; + /** + * The peer id which created the particle + */ + initPeerId: PeerIdB58; - /** - * Particle's timestamp when it was created - */ - timestamp: number; + /** + * Particle's timestamp when it was created + */ + timestamp: number; - /** - * Time to live in milliseconds. The time after the particle should be expired - */ - ttl: number; + /** + * Time to live in milliseconds. The time after the particle should be expired + */ + ttl: number; - /** - * Particle's signature - */ - signature?: string; + /** + * Particle's signature + */ + signature?: string; - /** - * Security tetraplets - */ - tetraplets: ArgName extends string - ? Record[]> - : Record; + /** + * Security tetraplets + */ + tetraplets: ArgName extends string + ? Record[]> + : Record; }; export type ServiceImpl = Record< - string, - ( - ...args: [...JSONArray, CallParams] - ) => MaybePromise + string, + ( + ...args: [...JSONArray, CallParams] + ) => MaybePromise >; export type JSONValue = - | string - | number - | boolean - | null - | { [x: string]: JSONValue } - | Array; + | string + | number + | boolean + | null + | { [x: string]: JSONValue } + | Array; export type JSONArray = Array; export type JSONObject = { [x: string]: JSONValue }; diff --git a/packages/core/interfaces/src/compilerSupport/aquaTypeDefinitions.ts b/packages/core/interfaces/src/compilerSupport/aquaTypeDefinitions.ts index b00ffd9a9..4d34cc826 100644 --- a/packages/core/interfaces/src/compilerSupport/aquaTypeDefinitions.ts +++ b/packages/core/interfaces/src/compilerSupport/aquaTypeDefinitions.ts @@ -15,138 +15,138 @@ */ export type SimpleTypes = - | ScalarType - | OptionType - | ArrayType - | StructType - | TopType - | BottomType - | NilType; + | ScalarType + | OptionType + | ArrayType + | StructType + | TopType + | BottomType + | NilType; export type NonArrowType = SimpleTypes | ProductType; export type TopType = { - /** - * Type descriptor. Used for pattern-matching - */ - tag: "topType"; + /** + * Type descriptor. Used for pattern-matching + */ + tag: "topType"; }; export type BottomType = { - /** - * Type descriptor. Used for pattern-matching - */ - tag: "bottomType"; + /** + * Type descriptor. Used for pattern-matching + */ + tag: "bottomType"; }; export type OptionType = { - /** - * Type descriptor. Used for pattern-matching - */ - tag: "option"; - - /** - * Underlying type of the option - */ - type: SimpleTypes; + /** + * Type descriptor. Used for pattern-matching + */ + tag: "option"; + + /** + * Underlying type of the option + */ + type: SimpleTypes; }; export type NilType = { - /** - * Type descriptor. Used for pattern-matching - */ - tag: "nil"; + /** + * Type descriptor. Used for pattern-matching + */ + tag: "nil"; }; export type ArrayType = { - /** - * Type descriptor. Used for pattern-matching - */ - tag: "array"; - - /** - * Type of array elements - */ - type: SimpleTypes; + /** + * Type descriptor. Used for pattern-matching + */ + tag: "array"; + + /** + * Type of array elements + */ + type: SimpleTypes; }; /** * All possible scalar type names */ export type ScalarNames = - | "u8" - | "u16" - | "u32" - | "u64" - | "i8" - | "i16" - | "i32" - | "i64" - | "f32" - | "f64" - | "bool" - | "string"; + | "u8" + | "u16" + | "u32" + | "u64" + | "i8" + | "i16" + | "i32" + | "i64" + | "f32" + | "f64" + | "bool" + | "string"; export type ScalarType = { - /** - * Type descriptor. Used for pattern-matching - */ - tag: "scalar"; - - /** - * Name of the scalar type - */ - name: ScalarNames; + /** + * Type descriptor. Used for pattern-matching + */ + tag: "scalar"; + + /** + * Name of the scalar type + */ + name: ScalarNames; }; export type StructType = { - /** - * Type descriptor. Used for pattern-matching - */ - tag: "struct"; - - /** - * Struct name - */ - name: string; - - /** - * Struct fields - */ - fields: { [key: string]: SimpleTypes }; + /** + * Type descriptor. Used for pattern-matching + */ + tag: "struct"; + + /** + * Struct name + */ + name: string; + + /** + * Struct fields + */ + fields: { [key: string]: SimpleTypes }; }; export type LabeledProductType< - T extends - | SimpleTypes - | ArrowType | UnlabeledProductType> = - | SimpleTypes - | ArrowType | UnlabeledProductType>, - K extends { [key: string]: T } = { [key: string]: T }, + T extends + | SimpleTypes + | ArrowType | UnlabeledProductType> = + | SimpleTypes + | ArrowType | UnlabeledProductType>, + K extends { [key: string]: T } = { [key: string]: T }, > = { + /** + * Type descriptor. Used for pattern-matching + */ + tag: "labeledProduct"; + + /** + * Labelled product fields + */ + fields: K; +}; + +export type UnlabeledProductType = SimpleTypes[]> = + { /** * Type descriptor. Used for pattern-matching */ - tag: "labeledProduct"; + tag: "unlabeledProduct"; /** - * Labelled product fields + * Items in unlabelled product */ - fields: K; -}; - -export type UnlabeledProductType = SimpleTypes[]> = - { - /** - * Type descriptor. Used for pattern-matching - */ - tag: "unlabeledProduct"; - - /** - * Items in unlabelled product - */ - items: T; - }; + items: T; + }; export type ProductType = UnlabeledProductType | LabeledProductType; @@ -155,27 +155,27 @@ export type ProductType = UnlabeledProductType | LabeledProductType; * Profunctor means variance: Arrow is contravariant on domain, and variant on codomain. */ export type ArrowType = { - /** - * Type descriptor. Used for pattern-matching - */ - tag: "arrow"; - - /** - * Where this Arrow is defined - */ - domain: T | NilType; - - /** - * Where this Arrow points to - */ - codomain: UnlabeledProductType | NilType; + /** + * Type descriptor. Used for pattern-matching + */ + tag: "arrow"; + + /** + * Where this Arrow is defined + */ + domain: T | NilType; + + /** + * Where this Arrow points to + */ + codomain: UnlabeledProductType | NilType; }; /** * Arrow which domain contains only non-arrow types */ export type ArrowWithoutCallbacks = ArrowType< - UnlabeledProductType | LabeledProductType + UnlabeledProductType | LabeledProductType >; /** @@ -184,108 +184,108 @@ export type ArrowWithoutCallbacks = ArrowType< export type ArrowWithCallbacks = ArrowType; export interface FunctionCallConstants { - /** - * The name of the relay variable - */ - relay: string; - - /** - * The name of the serviceId used load variables at the beginning of the script - */ - getDataSrv: string; - - /** - * The name of serviceId is used to execute callbacks for the current particle - */ - callbackSrv: string; - - /** - * The name of the serviceId which is called to propagate return value to the generated function caller - */ - responseSrv: string; - - /** - * The name of the functionName which is called to propagate return value to the generated function caller - */ - responseFnName: string; - - /** - * The name of the serviceId which is called to report errors to the generated function caller - */ - errorHandlingSrv: string; - - /** - * The name of the functionName which is called to report errors to the generated function caller - */ - errorFnName: string; + /** + * The name of the relay variable + */ + relay: string; + + /** + * The name of the serviceId used load variables at the beginning of the script + */ + getDataSrv: string; + + /** + * The name of serviceId is used to execute callbacks for the current particle + */ + callbackSrv: string; + + /** + * The name of the serviceId which is called to propagate return value to the generated function caller + */ + responseSrv: string; + + /** + * The name of the functionName which is called to propagate return value to the generated function caller + */ + responseFnName: string; + + /** + * The name of the serviceId which is called to report errors to the generated function caller + */ + errorHandlingSrv: string; + + /** + * The name of the functionName which is called to report errors to the generated function caller + */ + errorFnName: string; } /** * Definition of function (`func` instruction) generated by the Aqua compiler */ export interface FunctionCallDef { - /** - * The name of the function in Aqua language - */ - functionName: string; - - /** - * Underlying arrow which represents function in aqua - */ - arrow: ArrowType< - LabeledProductType> - >; - - /** - * Names of the different entities used in generated air script - */ - names: FunctionCallConstants; + /** + * The name of the function in Aqua language + */ + functionName: string; + + /** + * Underlying arrow which represents function in aqua + */ + arrow: ArrowType< + LabeledProductType> + >; + + /** + * Names of the different entities used in generated air script + */ + names: FunctionCallConstants; } /** * Definition of service registration function (`service` instruction) generated by the Aqua compiler */ export interface ServiceDef { - /** - * Default service id. If the service has no default id the value should be undefined - */ - defaultServiceId?: string; - - /** - * List of functions which the service consists of - */ - functions: - | LabeledProductType>> - | NilType; + /** + * Default service id. If the service has no default id the value should be undefined + */ + defaultServiceId?: string; + + /** + * List of functions which the service consists of + */ + functions: + | LabeledProductType>> + | 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; + /** + * 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, + def: FunctionCallDef, ): { - [key: string]: NonArrowType | ArrowWithoutCallbacks; + [key: string]: NonArrowType | ArrowWithoutCallbacks; } => { - if (def.arrow.domain.tag !== "labeledProduct") { - throw new Error("Should be impossible"); - } + if (def.arrow.domain.tag !== "labeledProduct") { + throw new Error("Should be impossible"); + } - return def.arrow.domain.fields; + return def.arrow.domain.fields; }; export const isReturnTypeVoid = (def: FunctionCallDef): boolean => { - if (def.arrow.codomain.tag === "nil") { - return true; - } + if (def.arrow.codomain.tag === "nil") { + return true; + } - return def.arrow.codomain.items.length === 0; + return def.arrow.codomain.items.length === 0; }; diff --git a/packages/core/interfaces/src/compilerSupport/compilerSupportInterface.ts b/packages/core/interfaces/src/compilerSupport/compilerSupportInterface.ts index b28bcb9e7..1d21ffd67 100644 --- a/packages/core/interfaces/src/compilerSupport/compilerSupportInterface.ts +++ b/packages/core/interfaces/src/compilerSupport/compilerSupportInterface.ts @@ -18,16 +18,16 @@ import { JSONValue } from "../commonTypes.js"; import { IFluenceInternalApi } from "../fluenceClient.js"; import { - FnConfig, - FunctionCallDef, - ServiceDef, + FnConfig, + FunctionCallDef, + ServiceDef, } from "./aquaTypeDefinitions.js"; /** * Type for callback passed as aqua function argument */ export type ArgCallbackFunction = ( - ...args: JSONValue[] + ...args: JSONValue[] ) => JSONValue | Promise; /** @@ -39,62 +39,62 @@ export type PassedArgs = { [key: string]: JSONValue | ArgCallbackFunction }; * Arguments for callAquaFunction function */ export interface CallAquaFunctionArgs { - /** - * Peer to call the function on - */ - peer: IFluenceInternalApi; + /** + * Peer to call the function on + */ + peer: IFluenceInternalApi; - /** - * Function definition - */ - def: FunctionCallDef; + /** + * Function definition + */ + def: FunctionCallDef; - /** - * Air script used by the aqua function - */ - script: string; + /** + * Air script used by the aqua function + */ + script: string; - /** - * Function configuration - */ - config: FnConfig; + /** + * Function configuration + */ + config: FnConfig; - /** - * Arguments to pass to the function - */ - args: PassedArgs; + /** + * Arguments to pass to the function + */ + args: PassedArgs; } /** * Call a function from Aqua script */ export type CallAquaFunctionType = ( - args: CallAquaFunctionArgs, + args: CallAquaFunctionArgs, ) => Promise; /** * Arguments for registerService function */ export interface RegisterServiceArgs { - /** - * Peer to register the service on - */ - peer: IFluenceInternalApi; + /** + * Peer to register the service on + */ + peer: IFluenceInternalApi; - /** - * Service definition - */ - def: ServiceDef; + /** + * Service definition + */ + def: ServiceDef; - /** - * Service id - */ - serviceId: string | undefined; + /** + * Service id + */ + serviceId: string | undefined; - /** - * Service implementation - */ - service: unknown; + /** + * Service implementation + */ + service: unknown; } /** diff --git a/packages/core/interfaces/src/fluenceClient.ts b/packages/core/interfaces/src/fluenceClient.ts index f887769cb..743b987cb 100644 --- a/packages/core/interfaces/src/fluenceClient.ts +++ b/packages/core/interfaces/src/fluenceClient.ts @@ -33,76 +33,76 @@ export type KeyTypes = "RSA" | "Ed25519" | "secp256k1"; * Options to specify key pair used in Fluence Peer */ export type KeyPairOptions = { - type: "Ed25519"; - source: "random" | Uint8Array; + type: "Ed25519"; + source: "random" | Uint8Array; }; /** * 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?: { /** - * Specify the KeyPair to be used to identify the Fluence Peer. - * Will be generated randomly if not specified + * 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 */ - keyPair?: KeyPairOptions; + skipCheckConnection?: boolean; /** - * Options to configure the connection to the Fluence network + * The dialing timeout in milliseconds */ - 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; - }; + dialTimeoutMs?: 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 + * The maximum number of inbound streams for the libp2p node. + * Default: 1024 */ - defaultTtlMs?: number; + maxInboundStreams?: number; /** - * Enables\disabled various debugging features + * The maximum number of outbound streams for the libp2p node. + * Default: 1024 */ - 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; - }; + 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; + + /** + * 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; + }; } /** * Fluence JS Client connection states as string literals */ export const ConnectionStates = [ - "disconnected", - "connecting", - "connected", - "disconnecting", + "disconnected", + "connecting", + "connected", + "disconnecting", ] as const; /** @@ -111,45 +111,45 @@ export const ConnectionStates = [ export type ConnectionState = (typeof ConnectionStates)[number]; export interface IFluenceInternalApi { - /** - * Internal API - */ - internals: unknown; + /** + * Internal API + */ + internals: unknown; } /** * Public API of Fluence JS Client */ export interface IFluenceClient extends IFluenceInternalApi { - /** - * Connect to the Fluence network - */ - connect: () => Promise; - - /** - * Disconnect from the Fluence network - */ - disconnect(): Promise; - - /** - * Handle connection state changes. Immediately returns current connection state - */ - onConnectionStateChange( - handler: (state: ConnectionState) => void, - ): ConnectionState; - - /** - * Return peer's secret key as byte array. - */ - getPeerSecretKey(): Uint8Array; - - /** - * Return peer's public key as a base58 string (multihash/CIDv0). - */ - getPeerId(): string; - - /** - * Return relay's public key as a base58 string (multihash/CIDv0). - */ - getRelayPeerId(): string; + /** + * Connect to the Fluence network + */ + connect: () => Promise; + + /** + * Disconnect from the Fluence network + */ + disconnect(): Promise; + + /** + * Handle connection state changes. Immediately returns current connection state + */ + onConnectionStateChange( + handler: (state: ConnectionState) => void, + ): ConnectionState; + + /** + * Return peer's secret key as byte array. + */ + getPeerSecretKey(): Uint8Array; + + /** + * Return peer's public key as a base58 string (multihash/CIDv0). + */ + getPeerId(): string; + + /** + * Return relay's public key as a base58 string (multihash/CIDv0). + */ + getRelayPeerId(): string; } diff --git a/packages/core/interfaces/src/future.ts b/packages/core/interfaces/src/future.ts index 3648967b3..0cb12aab6 100644 --- a/packages/core/interfaces/src/future.ts +++ b/packages/core/interfaces/src/future.ts @@ -15,16 +15,16 @@ */ import { - ArrayType, - ArrowType, - LabeledProductType, - NilType, - OptionType, - ScalarType, - SimpleTypes, - StructType, - TopType, - UnlabeledProductType, + ArrayType, + ArrowType, + LabeledProductType, + NilType, + OptionType, + ScalarType, + SimpleTypes, + StructType, + TopType, + UnlabeledProductType, } from "@fluencelabs/interfaces"; import { Call, Pipe, Objects, Tuples, Unions, Fn } from "hotscript"; @@ -32,59 +32,59 @@ import { Call, Pipe, Objects, Tuples, Unions, Fn } from "hotscript"; // In the future we may remove string type declaration and move to type inference. type GetTsTypeFromScalar = [T["name"]] extends [ - "u8" | "u16" | "u32" | "u64" | "i8" | "i16" | "i32" | "i64" | "f32" | "f64", + "u8" | "u16" | "u32" | "u64" | "i8" | "i16" | "i32" | "i64" | "f32" | "f64", ] - ? number - : [T["name"]] extends ["bool"] - ? boolean - : [T["name"]] extends ["string"] - ? string - : never; + ? number + : [T["name"]] extends ["bool"] + ? boolean + : [T["name"]] extends ["string"] + ? string + : never; type MapTuple = { - [K in keyof T]: [T[K]] extends [SimpleTypes] ? GetSimpleType : never; + [K in keyof T]: [T[K]] extends [SimpleTypes] ? GetSimpleType : never; }; type UnpackIfSingle = [T] extends [[infer R]] ? R : T; type GetSimpleType = [T] extends [NilType] - ? null - : [T] extends [ArrayType] - ? GetSimpleType[] - : [T] extends [StructType] - ? { [K in keyof T["fields"]]: GetSimpleType } - : [T] extends [OptionType] - ? GetSimpleType | null - : [T] extends [ScalarType] - ? GetTsTypeFromScalar - : [T] extends [TopType] - ? unknown - : never; + ? null + : [T] extends [ArrayType] + ? GetSimpleType[] + : [T] extends [StructType] + ? { [K in keyof T["fields"]]: GetSimpleType } + : [T] extends [OptionType] + ? GetSimpleType | null + : [T] extends [ScalarType] + ? GetTsTypeFromScalar + : [T] extends [TopType] + ? unknown + : never; interface Access extends Fn { - return: __GetTsType, T>>; + return: __GetTsType, T>>; } type __GetTsType = [T] extends [SimpleTypes] - ? GetSimpleType - : [T] extends [UnlabeledProductType] - ? MapTuple - : [T] extends [LabeledProductType] - ? { [K in keyof T["fields"]]: __GetTsType } - : [T] extends [ArrowType] - ? ( - ...t: [H] extends [UnlabeledProductType] - ? MapTuple - : [H] extends [LabeledProductType] - ? Pipe>]> - : [] - ) => [T["codomain"]] extends [UnlabeledProductType] - ? UnpackIfSingle> - : undefined - : never; + ? GetSimpleType + : [T] extends [UnlabeledProductType] + ? MapTuple + : [T] extends [LabeledProductType] + ? { [K in keyof T["fields"]]: __GetTsType } + : [T] extends [ArrowType] + ? ( + ...t: [H] extends [UnlabeledProductType] + ? MapTuple + : [H] extends [LabeledProductType] + ? Pipe>]> + : [] + ) => [T["codomain"]] extends [UnlabeledProductType] + ? UnpackIfSingle> + : undefined + : never; type DeepMutable = { - -readonly [K in keyof T]: DeepMutable; + -readonly [K in keyof T]: DeepMutable; }; export type GetTsType = __GetTsType>; diff --git a/packages/core/interfaces/src/utils.ts b/packages/core/interfaces/src/utils.ts index 5f30c6f11..06015c7f4 100644 --- a/packages/core/interfaces/src/utils.ts +++ b/packages/core/interfaces/src/utils.ts @@ -15,7 +15,7 @@ */ export type InterfaceToType = { - [K in keyof T]: T[K]; + [K in keyof T]: T[K]; }; export type MaybePromise = T | Promise; diff --git a/packages/core/interfaces/tsconfig.json b/packages/core/interfaces/tsconfig.json index 68ec53d78..258e367dd 100644 --- a/packages/core/interfaces/tsconfig.json +++ b/packages/core/interfaces/tsconfig.json @@ -1,9 +1,9 @@ { - "extends": "../../../tsconfig.json", - "compilerOptions": { - "outDir": "./dist", - "rootDir": "src" - }, - "include": ["src/**/*"], - "exclude": ["node_modules", "dist"] + "extends": "../../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "src" + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] } diff --git a/packages/core/js-client/CHANGELOG.md b/packages/core/js-client/CHANGELOG.md index 3d7fa111e..86fa524e3 100644 --- a/packages/core/js-client/CHANGELOG.md +++ b/packages/core/js-client/CHANGELOG.md @@ -4,232 +4,232 @@ ### Bug Fixes -- **deps:** update dependency @fluencelabs/avm to v0.48.0 ([#350](https://github.com/fluencelabs/js-client/issues/350)) ([945908a](https://github.com/fluencelabs/js-client/commit/945908a992976f2ad953bcaa3918741f890ffeeb)) +- **deps:** update dependency @fluencelabs/avm to v0.48.0 ([#350](https://github.com/fluencelabs/js-client/issues/350)) ([945908a](https://github.com/fluencelabs/js-client/commit/945908a992976f2ad953bcaa3918741f890ffeeb)) ### Dependencies -- The following workspace dependencies were updated - - devDependencies - - @fluencelabs/marine-worker bumped to 0.3.3 +- The following workspace dependencies were updated + - devDependencies + - @fluencelabs/marine-worker bumped to 0.3.3 ## [0.1.6](https://github.com/fluencelabs/js-client/compare/js-client-v0.1.5...js-client-v0.1.6) (2023-09-15) ### Bug Fixes -- **deps:** update dependency @fluencelabs/avm to v0.47.0 ([#341](https://github.com/fluencelabs/js-client/issues/341)) ([f186f20](https://github.com/fluencelabs/js-client/commit/f186f209366c29f12e6677e03564ee2fa14b51ae)) +- **deps:** update dependency @fluencelabs/avm to v0.47.0 ([#341](https://github.com/fluencelabs/js-client/issues/341)) ([f186f20](https://github.com/fluencelabs/js-client/commit/f186f209366c29f12e6677e03564ee2fa14b51ae)) ### Dependencies -- The following workspace dependencies were updated - - devDependencies - - @fluencelabs/marine-worker bumped to 0.3.2 +- The following workspace dependencies were updated + - devDependencies + - @fluencelabs/marine-worker bumped to 0.3.2 ## [0.1.5](https://github.com/fluencelabs/js-client/compare/js-client-v0.1.4...js-client-v0.1.5) (2023-09-14) ### Bug Fixes -- **libp2p:** Add fluence protocol to local peer store protocols [fixes DXJ-471] ([#343](https://github.com/fluencelabs/js-client/issues/343)) ([88fcf02](https://github.com/fluencelabs/js-client/commit/88fcf02d5fd3d28db619427c31b38154646f7ad2)) +- **libp2p:** Add fluence protocol to local peer store protocols [fixes DXJ-471] ([#343](https://github.com/fluencelabs/js-client/issues/343)) ([88fcf02](https://github.com/fluencelabs/js-client/commit/88fcf02d5fd3d28db619427c31b38154646f7ad2)) ## [0.1.4](https://github.com/fluencelabs/js-client/compare/js-client-v0.1.3...js-client-v0.1.4) (2023-09-14) ### Bug Fixes -- Fire and forget [fixes DXJ-446] ([#336](https://github.com/fluencelabs/js-client/issues/336)) ([e0a970d](https://github.com/fluencelabs/js-client/commit/e0a970d86a13f1617778a461c1c4d558d7dbafcb)) +- Fire and forget [fixes DXJ-446] ([#336](https://github.com/fluencelabs/js-client/issues/336)) ([e0a970d](https://github.com/fluencelabs/js-client/commit/e0a970d86a13f1617778a461c1c4d558d7dbafcb)) ## [0.1.3](https://github.com/fluencelabs/js-client/compare/js-client-v0.1.2...js-client-v0.1.3) (2023-09-07) ### Bug Fixes -- **deps:** update dependency @fluencelabs/avm to v0.46.0 ([#338](https://github.com/fluencelabs/js-client/issues/338)) ([8e6918c](https://github.com/fluencelabs/js-client/commit/8e6918c4da5bc4cdfe1c840312f477d782d9ca20)) +- **deps:** update dependency @fluencelabs/avm to v0.46.0 ([#338](https://github.com/fluencelabs/js-client/issues/338)) ([8e6918c](https://github.com/fluencelabs/js-client/commit/8e6918c4da5bc4cdfe1c840312f477d782d9ca20)) ### Dependencies -- The following workspace dependencies were updated - - devDependencies - - @fluencelabs/marine-worker bumped to 0.3.1 +- The following workspace dependencies were updated + - devDependencies + - @fluencelabs/marine-worker bumped to 0.3.1 ## [0.1.2](https://github.com/fluencelabs/js-client/compare/js-client-v0.1.1...js-client-v0.1.2) (2023-09-05) ### Features -- remove obsolete packages [fixes DXJ-462] ([#337](https://github.com/fluencelabs/js-client/issues/337)) ([e7e6176](https://github.com/fluencelabs/js-client/commit/e7e617661f39e1df36a703d5dad93ba52a338919)) +- remove obsolete packages [fixes DXJ-462] ([#337](https://github.com/fluencelabs/js-client/issues/337)) ([e7e6176](https://github.com/fluencelabs/js-client/commit/e7e617661f39e1df36a703d5dad93ba52a338919)) ### Bug Fixes -- **logger:** Change formatter that collides with new libp2p version [fixes DXJ-459] ([#334](https://github.com/fluencelabs/js-client/issues/334)) ([18a972b](https://github.com/fluencelabs/js-client/commit/18a972b573559d0717ec93a95b8c63dd1cbcd93b)) +- **logger:** Change formatter that collides with new libp2p version [fixes DXJ-459] ([#334](https://github.com/fluencelabs/js-client/issues/334)) ([18a972b](https://github.com/fluencelabs/js-client/commit/18a972b573559d0717ec93a95b8c63dd1cbcd93b)) ## [0.1.1](https://github.com/fluencelabs/js-client/compare/js-client-v0.1.0...js-client-v0.1.1) (2023-08-25) ### Bug Fixes -- Use info log level instead trace [Fixes DXJ-457] ([#328](https://github.com/fluencelabs/js-client/issues/328)) ([477c6f0](https://github.com/fluencelabs/js-client/commit/477c6f0c151ef6759aaa2802c5e9907065d58e17)) +- Use info log level instead trace [Fixes DXJ-457] ([#328](https://github.com/fluencelabs/js-client/issues/328)) ([477c6f0](https://github.com/fluencelabs/js-client/commit/477c6f0c151ef6759aaa2802c5e9907065d58e17)) ## [0.1.0](https://github.com/fluencelabs/js-client/compare/js-client-v0.0.10...js-client-v0.1.0) (2023-08-24) ### âš  BREAKING CHANGES -- Unify all packages ([#327](https://github.com/fluencelabs/js-client/issues/327)) +- Unify all packages ([#327](https://github.com/fluencelabs/js-client/issues/327)) ### Features -- Unify all packages ([#327](https://github.com/fluencelabs/js-client/issues/327)) ([97c2491](https://github.com/fluencelabs/js-client/commit/97c24918d84b34e7ac58337838dc8343cbd44b19)) +- Unify all packages ([#327](https://github.com/fluencelabs/js-client/issues/327)) ([97c2491](https://github.com/fluencelabs/js-client/commit/97c24918d84b34e7ac58337838dc8343cbd44b19)) ### Dependencies -- The following workspace dependencies were updated - - dependencies - - @fluencelabs/interfaces bumped from 0.8.1 to 0.8.2 - - devDependencies - - @fluencelabs/marine-worker bumped to 0.3.0 +- The following workspace dependencies were updated + - dependencies + - @fluencelabs/interfaces bumped from 0.8.1 to 0.8.2 + - devDependencies + - @fluencelabs/marine-worker bumped to 0.3.0 ## [0.9.1](https://github.com/fluencelabs/js-client/compare/js-peer-v0.9.0...js-peer-v0.9.1) (2023-08-08) ### Bug Fixes -- **deps:** update dependency @fluencelabs/avm to v0.43.1 ([#322](https://github.com/fluencelabs/js-client/issues/322)) ([c1d1fa6](https://github.com/fluencelabs/js-client/commit/c1d1fa6659b6dc2c6707786748b3410fab7f1bcd)) +- **deps:** update dependency @fluencelabs/avm to v0.43.1 ([#322](https://github.com/fluencelabs/js-client/issues/322)) ([c1d1fa6](https://github.com/fluencelabs/js-client/commit/c1d1fa6659b6dc2c6707786748b3410fab7f1bcd)) ### Dependencies -- The following workspace dependencies were updated - - dependencies - - @fluencelabs/interfaces bumped from 0.8.0 to 0.8.1 +- The following workspace dependencies were updated + - dependencies + - @fluencelabs/interfaces bumped from 0.8.0 to 0.8.1 ## [0.9.0](https://github.com/fluencelabs/js-client/compare/js-peer-v0.8.10...js-peer-v0.9.0) (2023-06-29) ### âš  BREAKING CHANGES -- **avm:** avm 0.40.0 (https://github.com/fluencelabs/js-client/pull/315) +- **avm:** avm 0.40.0 (https://github.com/fluencelabs/js-client/pull/315) ### Features -- **avm:** avm 0.40.0 (https://github.com/fluencelabs/js-client/pull/315) ([8bae6e2](https://github.com/fluencelabs/js-client/commit/8bae6e24e62153b567f320ccecc7bce76bc826d1)) +- **avm:** avm 0.40.0 (https://github.com/fluencelabs/js-client/pull/315) ([8bae6e2](https://github.com/fluencelabs/js-client/commit/8bae6e24e62153b567f320ccecc7bce76bc826d1)) ### Dependencies -- The following workspace dependencies were updated - - dependencies - - @fluencelabs/interfaces bumped from 0.7.6 to 0.8.0 +- The following workspace dependencies were updated + - dependencies + - @fluencelabs/interfaces bumped from 0.7.6 to 0.8.0 ## [0.8.10](https://github.com/fluencelabs/js-client/compare/js-peer-v0.8.9...js-peer-v0.8.10) (2023-06-20) ### Features -- support signatures [fixes DXJ-389] ([#310](https://github.com/fluencelabs/js-client/issues/310)) ([a60dfe0](https://github.com/fluencelabs/js-client/commit/a60dfe0d680b4d9ac5092dec64e2ebf478bf80eb)) +- support signatures [fixes DXJ-389] ([#310](https://github.com/fluencelabs/js-client/issues/310)) ([a60dfe0](https://github.com/fluencelabs/js-client/commit/a60dfe0d680b4d9ac5092dec64e2ebf478bf80eb)) ### Dependencies -- The following workspace dependencies were updated - - dependencies - - @fluencelabs/interfaces bumped from 0.7.5 to 0.7.6 +- The following workspace dependencies were updated + - dependencies + - @fluencelabs/interfaces bumped from 0.7.5 to 0.7.6 ## [0.8.9](https://github.com/fluencelabs/js-client/compare/js-peer-v0.8.8...js-peer-v0.8.9) (2023-06-14) ### Features -- Add tracing service [fixes DXJ-388] ([#307](https://github.com/fluencelabs/js-client/issues/307)) ([771086f](https://github.com/fluencelabs/js-client/commit/771086fddf52b7a5a1280894c7238e409cdf6a64)) -- improve ttl error message ([#300](https://github.com/fluencelabs/js-client/issues/300)) ([9821183](https://github.com/fluencelabs/js-client/commit/9821183d53870240cb5700be67cb8d57533b954b)) +- Add tracing service [fixes DXJ-388] ([#307](https://github.com/fluencelabs/js-client/issues/307)) ([771086f](https://github.com/fluencelabs/js-client/commit/771086fddf52b7a5a1280894c7238e409cdf6a64)) +- improve ttl error message ([#300](https://github.com/fluencelabs/js-client/issues/300)) ([9821183](https://github.com/fluencelabs/js-client/commit/9821183d53870240cb5700be67cb8d57533b954b)) ## [0.8.8](https://github.com/fluencelabs/js-client/compare/js-peer-v0.8.7...js-peer-v0.8.8) (2023-05-30) ### Features -- add run-console ([#305](https://github.com/fluencelabs/js-client/issues/305)) ([cf1f029](https://github.com/fluencelabs/js-client/commit/cf1f02963c1d7e1a17866f5798901a0f61b8bc31)) +- add run-console ([#305](https://github.com/fluencelabs/js-client/issues/305)) ([cf1f029](https://github.com/fluencelabs/js-client/commit/cf1f02963c1d7e1a17866f5798901a0f61b8bc31)) ## [0.8.7](https://github.com/fluencelabs/js-client/compare/js-peer-v0.8.6...js-peer-v0.8.7) (2023-04-04) ### Features -- Cleaning up technical debts ([#295](https://github.com/fluencelabs/js-client/issues/295)) ([0b2f12d](https://github.com/fluencelabs/js-client/commit/0b2f12d8ac223db341d6c30ff403166b3eae2e56)) +- Cleaning up technical debts ([#295](https://github.com/fluencelabs/js-client/issues/295)) ([0b2f12d](https://github.com/fluencelabs/js-client/commit/0b2f12d8ac223db341d6c30ff403166b3eae2e56)) ### Dependencies -- The following workspace dependencies were updated - - dependencies - - @fluencelabs/interfaces bumped from 0.7.4 to 0.7.5 +- The following workspace dependencies were updated + - dependencies + - @fluencelabs/interfaces bumped from 0.7.4 to 0.7.5 ## [0.8.6](https://github.com/fluencelabs/js-client/compare/js-peer-v0.8.5...js-peer-v0.8.6) (2023-03-31) ### Features -- **logs:** Use `debug.js` library for logging [DXJ-327] ([#285](https://github.com/fluencelabs/js-client/issues/285)) ([e95c34a](https://github.com/fluencelabs/js-client/commit/e95c34a79220bd8ecdcee806802ac3d69a2af0cb)) -- **test:** Automate smoke tests for JS Client [DXJ-293] ([#282](https://github.com/fluencelabs/js-client/issues/282)) ([10d7eae](https://github.com/fluencelabs/js-client/commit/10d7eaed809dde721b582d4b3228a48bbec50884)) +- **logs:** Use `debug.js` library for logging [DXJ-327] ([#285](https://github.com/fluencelabs/js-client/issues/285)) ([e95c34a](https://github.com/fluencelabs/js-client/commit/e95c34a79220bd8ecdcee806802ac3d69a2af0cb)) +- **test:** Automate smoke tests for JS Client [DXJ-293] ([#282](https://github.com/fluencelabs/js-client/issues/282)) ([10d7eae](https://github.com/fluencelabs/js-client/commit/10d7eaed809dde721b582d4b3228a48bbec50884)) ### Bug Fixes -- **test:** All tests are working with vitest [DXJ-306] ([#291](https://github.com/fluencelabs/js-client/issues/291)) ([58ad3ca](https://github.com/fluencelabs/js-client/commit/58ad3ca6f666e8580997bb47609947645903436d)) +- **test:** All tests are working with vitest [DXJ-306] ([#291](https://github.com/fluencelabs/js-client/issues/291)) ([58ad3ca](https://github.com/fluencelabs/js-client/commit/58ad3ca6f666e8580997bb47609947645903436d)) ### Dependencies -- The following workspace dependencies were updated - - dependencies - - @fluencelabs/interfaces bumped from 0.7.3 to 0.7.4 +- The following workspace dependencies were updated + - dependencies + - @fluencelabs/interfaces bumped from 0.7.3 to 0.7.4 ## [0.8.5](https://github.com/fluencelabs/js-client/compare/js-peer-v0.8.4...js-peer-v0.8.5) (2023-03-03) ### Bug Fixes -- Increase number of inbound and outbound streams to 1024 ([#280](https://github.com/fluencelabs/js-client/issues/280)) ([1ccc483](https://github.com/fluencelabs/js-client/commit/1ccc4835328426b546f31e1646d3a49ed042fdf9)) +- Increase number of inbound and outbound streams to 1024 ([#280](https://github.com/fluencelabs/js-client/issues/280)) ([1ccc483](https://github.com/fluencelabs/js-client/commit/1ccc4835328426b546f31e1646d3a49ed042fdf9)) ## [0.8.4](https://github.com/fluencelabs/js-client/compare/js-peer-v0.8.3...js-peer-v0.8.4) (2023-02-22) ### Bug Fixes -- `nodenext` moduleResolution for js peer ([#271](https://github.com/fluencelabs/js-client/issues/271)) ([78d98f1](https://github.com/fluencelabs/js-client/commit/78d98f15c12431dee9fdd7b9869d57760503f8c7)) +- `nodenext` moduleResolution for js peer ([#271](https://github.com/fluencelabs/js-client/issues/271)) ([78d98f1](https://github.com/fluencelabs/js-client/commit/78d98f15c12431dee9fdd7b9869d57760503f8c7)) ## [0.8.3](https://github.com/fluencelabs/js-client/compare/js-peer-v0.8.2...js-peer-v0.8.3) (2023-02-16) ### Bug Fixes -- Trigger release to publish packages that were built ([#262](https://github.com/fluencelabs/js-client/issues/262)) ([47abf38](https://github.com/fluencelabs/js-client/commit/47abf3882956ffbdc52df372db26ba6252e8306b)) +- Trigger release to publish packages that were built ([#262](https://github.com/fluencelabs/js-client/issues/262)) ([47abf38](https://github.com/fluencelabs/js-client/commit/47abf3882956ffbdc52df372db26ba6252e8306b)) ### Dependencies -- The following workspace dependencies were updated - - dependencies - - @fluencelabs/interfaces bumped from 0.7.2 to 0.7.3 +- The following workspace dependencies were updated + - dependencies + - @fluencelabs/interfaces bumped from 0.7.2 to 0.7.3 ## [0.8.2](https://github.com/fluencelabs/js-client/compare/js-peer-v0.8.1...js-peer-v0.8.2) (2023-02-16) ### Features -- Add `getRelayPeerId` method for `IFluenceClient` ([#260](https://github.com/fluencelabs/js-client/issues/260)) ([a10278a](https://github.com/fluencelabs/js-client/commit/a10278afaa782a307feb10c4eac060094c101230)) +- Add `getRelayPeerId` method for `IFluenceClient` ([#260](https://github.com/fluencelabs/js-client/issues/260)) ([a10278a](https://github.com/fluencelabs/js-client/commit/a10278afaa782a307feb10c4eac060094c101230)) ### Dependencies -- The following workspace dependencies were updated - - dependencies - - @fluencelabs/interfaces bumped from 0.7.1 to 0.7.2 +- The following workspace dependencies were updated + - dependencies + - @fluencelabs/interfaces bumped from 0.7.1 to 0.7.2 ## [0.8.1](https://github.com/fluencelabs/js-client/compare/js-peer-v0.8.0...js-peer-v0.8.1) (2023-02-16) ### Features -- Simplify JS Client public API ([#257](https://github.com/fluencelabs/js-client/issues/257)) ([9daaf41](https://github.com/fluencelabs/js-client/commit/9daaf410964d43228192c829c7ff785db6e88081)) +- Simplify JS Client public API ([#257](https://github.com/fluencelabs/js-client/issues/257)) ([9daaf41](https://github.com/fluencelabs/js-client/commit/9daaf410964d43228192c829c7ff785db6e88081)) ### Dependencies -- The following workspace dependencies were updated - - dependencies - - @fluencelabs/interfaces bumped from 0.7.0 to 0.7.1 +- The following workspace dependencies were updated + - dependencies + - @fluencelabs/interfaces bumped from 0.7.0 to 0.7.1 ## [0.8.0](https://github.com/fluencelabs/fluence-js/compare/js-peer-v0.7.0...js-peer-v0.8.0) (2023-02-15) ### âš  BREAKING CHANGES -- Expose updated JS Client API via `js-client.api` package ([#246](https://github.com/fluencelabs/fluence-js/issues/246)) -- Standalone web JS Client ([#243](https://github.com/fluencelabs/fluence-js/issues/243)) +- Expose updated JS Client API via `js-client.api` package ([#246](https://github.com/fluencelabs/fluence-js/issues/246)) +- Standalone web JS Client ([#243](https://github.com/fluencelabs/fluence-js/issues/243)) ### Features -- Expose updated JS Client API via `js-client.api` package ([#246](https://github.com/fluencelabs/fluence-js/issues/246)) ([d4bb8fb](https://github.com/fluencelabs/fluence-js/commit/d4bb8fb42964b3ba25154232980b9ae82c21e627)) -- Standalone web JS Client ([#243](https://github.com/fluencelabs/fluence-js/issues/243)) ([9667c4f](https://github.com/fluencelabs/fluence-js/commit/9667c4fec6868f984bba13249f3c47d293396406)) +- Expose updated JS Client API via `js-client.api` package ([#246](https://github.com/fluencelabs/fluence-js/issues/246)) ([d4bb8fb](https://github.com/fluencelabs/fluence-js/commit/d4bb8fb42964b3ba25154232980b9ae82c21e627)) +- Standalone web JS Client ([#243](https://github.com/fluencelabs/fluence-js/issues/243)) ([9667c4f](https://github.com/fluencelabs/fluence-js/commit/9667c4fec6868f984bba13249f3c47d293396406)) ### Bug Fixes -- NodeJS package building ([#248](https://github.com/fluencelabs/fluence-js/issues/248)) ([0d05e51](https://github.com/fluencelabs/fluence-js/commit/0d05e517d89529af513fcb96cfa6c722ccc357a7)) +- NodeJS package building ([#248](https://github.com/fluencelabs/fluence-js/issues/248)) ([0d05e51](https://github.com/fluencelabs/fluence-js/commit/0d05e517d89529af513fcb96cfa6c722ccc357a7)) ### Dependencies -- The following workspace dependencies were updated - - dependencies - - @fluencelabs/interfaces bumped from 0.6.0 to 0.7.0 +- The following workspace dependencies were updated + - dependencies + - @fluencelabs/interfaces bumped from 0.6.0 to 0.7.0 diff --git a/packages/core/js-client/package.json b/packages/core/js-client/package.json index c07cdde73..cc1522c50 100644 --- a/packages/core/js-client/package.json +++ b/packages/core/js-client/package.json @@ -1,70 +1,70 @@ { - "name": "@fluencelabs/js-client", - "version": "0.1.7", - "description": "Client for interacting with Fluence network", - "engines": { - "node": ">=10", - "pnpm": ">=8" - }, - "files": [ - "dist" - ], - "main": "./dist/index.js", - "unpkg": "./dist/browser/index.umd.js", + "name": "@fluencelabs/js-client", + "version": "0.1.7", + "description": "Client for interacting with Fluence network", + "engines": { + "node": ">=10", + "pnpm": ">=8" + }, + "files": [ + "dist" + ], + "main": "./dist/index.js", + "unpkg": "./dist/browser/index.umd.js", + "types": "./dist/index.d.ts", + "exports": { "types": "./dist/index.d.ts", - "exports": { - "types": "./dist/index.d.ts", - "node": "./dist/index.js", - "default": "./dist/browser/index.js" - }, - "type": "module", - "scripts": { - "build": "tsc && vite build", - "test": "vitest --threads false run" - }, - "repository": "https://github.com/fluencelabs/fluence-js", - "author": "Fluence Labs", - "license": "Apache-2.0", - "dependencies": { - "@chainsafe/libp2p-noise": "13.0.0", - "@chainsafe/libp2p-yamux": "5.0.0", - "@fluencelabs/interfaces": "workspace:*", - "@fluencelabs/marine-worker": "0.3.3", - "@libp2p/crypto": "2.0.3", - "@libp2p/interface": "0.1.2", - "@libp2p/peer-id": "3.0.2", - "@libp2p/peer-id-factory": "3.0.3", - "@libp2p/websockets": "7.0.4", - "@multiformats/multiaddr": "11.3.0", - "async": "3.2.4", - "bs58": "5.0.0", - "buffer": "6.0.3", - "debug": "4.3.4", - "it-length-prefixed": "8.0.4", - "it-map": "2.0.0", - "it-pipe": "2.0.5", - "js-base64": "3.7.5", - "libp2p": "0.46.6", - "multiformats": "11.0.1", - "rxjs": "7.5.5", - "threads": "1.7.0", - "ts-pattern": "3.3.3", - "uint8arrays": "4.0.3", - "uuid": "8.3.2", - "zod": "3.22.4" - }, - "devDependencies": { - "@fluencelabs/aqua-api": "0.9.3", - "@fluencelabs/avm": "0.48.0", - "@fluencelabs/marine-js": "0.7.2", - "@rollup/plugin-inject": "5.0.3", - "@types/bs58": "4.0.1", - "@types/debug": "4.1.7", - "@types/node": "20.7.0", - "@types/uuid": "8.3.2", - "hotscript": "1.0.13", - "vite": "4.0.4", - "vite-tsconfig-paths": "4.0.3", - "vitest": "0.29.7" - } + "node": "./dist/index.js", + "default": "./dist/browser/index.js" + }, + "type": "module", + "scripts": { + "build": "tsc && vite build", + "test": "vitest --threads false run" + }, + "repository": "https://github.com/fluencelabs/fluence-js", + "author": "Fluence Labs", + "license": "Apache-2.0", + "dependencies": { + "@chainsafe/libp2p-noise": "13.0.0", + "@chainsafe/libp2p-yamux": "5.0.0", + "@fluencelabs/interfaces": "workspace:*", + "@fluencelabs/marine-worker": "0.3.3", + "@libp2p/crypto": "2.0.3", + "@libp2p/interface": "0.1.2", + "@libp2p/peer-id": "3.0.2", + "@libp2p/peer-id-factory": "3.0.3", + "@libp2p/websockets": "7.0.4", + "@multiformats/multiaddr": "11.3.0", + "async": "3.2.4", + "bs58": "5.0.0", + "buffer": "6.0.3", + "debug": "4.3.4", + "it-length-prefixed": "8.0.4", + "it-map": "2.0.0", + "it-pipe": "2.0.5", + "js-base64": "3.7.5", + "libp2p": "0.46.6", + "multiformats": "11.0.1", + "rxjs": "7.5.5", + "threads": "1.7.0", + "ts-pattern": "3.3.3", + "uint8arrays": "4.0.3", + "uuid": "8.3.2", + "zod": "3.22.4" + }, + "devDependencies": { + "@fluencelabs/aqua-api": "0.9.3", + "@fluencelabs/avm": "0.48.0", + "@fluencelabs/marine-js": "0.7.2", + "@rollup/plugin-inject": "5.0.3", + "@types/bs58": "4.0.1", + "@types/debug": "4.1.7", + "@types/node": "20.7.0", + "@types/uuid": "8.3.2", + "hotscript": "1.0.13", + "vite": "4.0.4", + "vite-tsconfig-paths": "4.0.3", + "vitest": "0.29.7" + } } diff --git a/packages/core/js-client/src/api.ts b/packages/core/js-client/src/api.ts index 519011c88..fe3e33166 100644 --- a/packages/core/js-client/src/api.ts +++ b/packages/core/js-client/src/api.ts @@ -15,11 +15,11 @@ */ import type { - FnConfig, - FunctionCallDef, - ServiceDef, - PassedArgs, - ServiceImpl, + FnConfig, + FunctionCallDef, + ServiceDef, + PassedArgs, + ServiceImpl, } from "@fluencelabs/interfaces"; import { getArgumentTypes } from "@fluencelabs/interfaces"; @@ -28,9 +28,9 @@ import { FluencePeer } from "./jsPeer/FluencePeer.js"; import { callAquaFunction, Fluence, registerService } from "./index.js"; export const isFluencePeer = ( - fluencePeerCandidate: unknown, + fluencePeerCandidate: unknown, ): fluencePeerCandidate is FluencePeer => { - return fluencePeerCandidate instanceof FluencePeer; + return fluencePeerCandidate instanceof FluencePeer; }; /** @@ -42,19 +42,19 @@ export const isFluencePeer = ( * @param script - air script with function execution logic generated by the Aqua compiler */ export const v5_callFunction = async ( - rawFnArgs: unknown[], - def: FunctionCallDef, - script: string, + rawFnArgs: unknown[], + def: FunctionCallDef, + script: string, ): Promise => { - const { args, client: peer, config } = extractFunctionArgs(rawFnArgs, def); - - return callAquaFunction({ - args, - def, - script, - config: config, - peer: peer, - }); + const { args, client: peer, config } = extractFunctionArgs(rawFnArgs, def); + + return callAquaFunction({ + args, + def, + script, + config: config, + peer: peer, + }); }; /** @@ -65,22 +65,22 @@ export const v5_callFunction = async ( * @param def - service definition generated by the Aqua compiler */ export const v5_registerService = (args: unknown[], def: ServiceDef): void => { - // TODO: Support this in aqua-to-js package - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - const service: ServiceImpl = args.pop() as ServiceImpl; - - const { peer, serviceId } = extractServiceArgs(args, def.defaultServiceId); - - registerService({ - def, - service, - serviceId, - peer, - }); + // TODO: Support this in aqua-to-js package + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + const service: ServiceImpl = args.pop() as ServiceImpl; + + const { peer, serviceId } = extractServiceArgs(args, def.defaultServiceId); + + registerService({ + def, + service, + serviceId, + peer, + }); }; function isConfig(arg: unknown): arg is FnConfig { - return typeof arg === "object" && arg !== null; + return typeof arg === "object" && arg !== null; } /** @@ -94,58 +94,58 @@ function isConfig(arg: unknown): arg is FnConfig { * arguments in a structured way of: { peer, config, args } */ function extractFunctionArgs( - args: unknown[], - def: FunctionCallDef, + args: unknown[], + def: FunctionCallDef, ): { - client: FluencePeer; - config: FnConfig; - args: PassedArgs; + 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 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()?", + ); } - const maybeConfig = args[numberOfExpectedArgs]; + peer = Fluence.defaultClient; + } - if (isConfig(maybeConfig)) { - config = maybeConfig; - } else { - config = {}; - } + const maybeConfig = args[numberOfExpectedArgs]; - const structuredArgs = args.slice(0, numberOfExpectedArgs); + if (isConfig(maybeConfig)) { + config = maybeConfig; + } else { + config = {}; + } - if (structuredArgs.length !== numberOfExpectedArgs) { - throw new Error( - `Incorrect number of arguments. Expecting ${numberOfExpectedArgs}`, - ); - } + 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] }; - }, {}); + const argsRes = argumentNames.reduce((acc, name, index) => { + return { ...acc, [name]: structuredArgs[index] }; + }, {}); - return { - client: peer, - args: argsRes, - config: config, - }; + return { + client: peer, + args: argsRes, + config: config, + }; } /** @@ -161,36 +161,36 @@ function extractFunctionArgs( * arguments in a structured way of: { peer, serviceId, service } */ const extractServiceArgs = ( - args: unknown[], - defaultServiceId?: string, + args: unknown[], + defaultServiceId?: string, ): { - peer: FluencePeer; - serviceId: string | undefined; + 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; + 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()?", + ); } - if (typeof args[0] === "string") { - serviceId = args[0]; - } else { - serviceId = defaultServiceId; - } + peer = Fluence.defaultClient; + } + + if (typeof args[0] === "string") { + serviceId = args[0]; + } else { + serviceId = defaultServiceId; + } - return { - peer: peer, - serviceId: serviceId, - }; + return { + peer: peer, + serviceId: serviceId, + }; }; diff --git a/packages/core/js-client/src/clientPeer/ClientPeer.ts b/packages/core/js-client/src/clientPeer/ClientPeer.ts index e02473406..215748db0 100644 --- a/packages/core/js-client/src/clientPeer/ClientPeer.ts +++ b/packages/core/js-client/src/clientPeer/ClientPeer.ts @@ -15,15 +15,15 @@ */ import { - ClientConfig, - ConnectionState, - IFluenceClient, - RelayOptions, + ClientConfig, + ConnectionState, + IFluenceClient, + RelayOptions, } from "@fluencelabs/interfaces"; import { - RelayConnection, - RelayConnectionConfig, + RelayConnection, + RelayConnectionConfig, } from "../connection/RelayConnection.js"; import { FluencePeer, PeerConfig } from "../jsPeer/FluencePeer.js"; import { JsServiceHost } from "../jsServiceHost/JsServiceHost.js"; @@ -39,115 +39,113 @@ const MAX_OUTBOUND_STREAMS = 1024; const MAX_INBOUND_STREAMS = 1024; export const makeClientPeerConfig = async ( - relay: RelayOptions, - config: ClientConfig, + relay: RelayOptions, + config: ClientConfig, ): Promise<{ - peerConfig: PeerConfig; - relayConfig: RelayConnectionConfig; - keyPair: KeyPair; + peerConfig: PeerConfig; + relayConfig: RelayConnectionConfig; + keyPair: KeyPair; }> => { - const opts = config.keyPair ?? { type: "Ed25519", source: "random" }; - const keyPair = await fromOpts(opts); - const relayAddress = relayOptionToMultiaddr(relay); - - return { - peerConfig: { - debug: { - printParticleId: config.debug?.printParticleId ?? false, - }, - defaultTtlMs: config.defaultTtlMs ?? DEFAULT_TTL_MS, - }, - relayConfig: { - peerId: keyPair.getLibp2pPeerId(), - relayAddress: relayAddress, - ...(config.connectionOptions?.dialTimeoutMs != null - ? { - dialTimeout: config.connectionOptions.dialTimeoutMs, - } - : {}), - maxInboundStreams: - config.connectionOptions?.maxInboundStreams ?? - MAX_OUTBOUND_STREAMS, - maxOutboundStreams: - config.connectionOptions?.maxOutboundStreams ?? - MAX_INBOUND_STREAMS, - }, - keyPair: keyPair, - }; + const opts = config.keyPair ?? { type: "Ed25519", source: "random" }; + const keyPair = await fromOpts(opts); + const relayAddress = relayOptionToMultiaddr(relay); + + return { + peerConfig: { + debug: { + printParticleId: config.debug?.printParticleId ?? false, + }, + defaultTtlMs: config.defaultTtlMs ?? DEFAULT_TTL_MS, + }, + relayConfig: { + peerId: keyPair.getLibp2pPeerId(), + relayAddress: relayAddress, + ...(config.connectionOptions?.dialTimeoutMs != null + ? { + dialTimeout: config.connectionOptions.dialTimeoutMs, + } + : {}), + maxInboundStreams: + config.connectionOptions?.maxInboundStreams ?? MAX_OUTBOUND_STREAMS, + maxOutboundStreams: + config.connectionOptions?.maxOutboundStreams ?? MAX_INBOUND_STREAMS, + }, + keyPair: keyPair, + }; }; export class ClientPeer extends FluencePeer implements IFluenceClient { - constructor( - peerConfig: PeerConfig, - relayConfig: RelayConnectionConfig, - keyPair: KeyPair, - marine: IMarineHost, - ) { - super( - peerConfig, - keyPair, - marine, - new JsServiceHost(), - new RelayConnection(relayConfig), - ); - } - - getPeerId(): string { - return this.keyPair.getPeerId(); - } - - getPeerSecretKey(): Uint8Array { - return this.keyPair.toEd25519PrivateKey(); - } - - connectionState: ConnectionState = "disconnected"; - connectionStateChangeHandler: (state: ConnectionState) => void = () => {}; - - getRelayPeerId(): string { - return this.internals.getRelayPeerId(); - } - - onConnectionStateChange( - handler: (state: ConnectionState) => void, - ): ConnectionState { - this.connectionStateChangeHandler = handler; - - return this.connectionState; - } - - private changeConnectionState(state: ConnectionState) { - this.connectionState = state; - this.connectionStateChangeHandler(state); - } - - /** - * Connect to the Fluence network - */ - async connect(): Promise { - return this.start(); - } - - // /** - // * Disconnect from the Fluence network - // */ - async disconnect(): Promise { - return this.stop(); - } - - override async start(): Promise { - log.trace("connecting to Fluence network"); - this.changeConnectionState("connecting"); - await super.start(); - // TODO: check connection (`checkConnection` function) here - this.changeConnectionState("connected"); - log.trace("connected"); - } - - override async stop(): Promise { - log.trace("disconnecting from Fluence network"); - this.changeConnectionState("disconnecting"); - await super.stop(); - this.changeConnectionState("disconnected"); - log.trace("disconnected"); - } + constructor( + peerConfig: PeerConfig, + relayConfig: RelayConnectionConfig, + keyPair: KeyPair, + marine: IMarineHost, + ) { + super( + peerConfig, + keyPair, + marine, + new JsServiceHost(), + new RelayConnection(relayConfig), + ); + } + + getPeerId(): string { + return this.keyPair.getPeerId(); + } + + getPeerSecretKey(): Uint8Array { + return this.keyPair.toEd25519PrivateKey(); + } + + connectionState: ConnectionState = "disconnected"; + connectionStateChangeHandler: (state: ConnectionState) => void = () => {}; + + getRelayPeerId(): string { + return this.internals.getRelayPeerId(); + } + + onConnectionStateChange( + handler: (state: ConnectionState) => void, + ): ConnectionState { + this.connectionStateChangeHandler = handler; + + return this.connectionState; + } + + private changeConnectionState(state: ConnectionState) { + this.connectionState = state; + this.connectionStateChangeHandler(state); + } + + /** + * Connect to the Fluence network + */ + async connect(): Promise { + return this.start(); + } + + // /** + // * Disconnect from the Fluence network + // */ + async disconnect(): Promise { + return this.stop(); + } + + override async start(): Promise { + log.trace("connecting to Fluence network"); + this.changeConnectionState("connecting"); + await super.start(); + // TODO: check connection (`checkConnection` function) here + this.changeConnectionState("connected"); + log.trace("connected"); + } + + override async stop(): Promise { + log.trace("disconnecting from Fluence network"); + this.changeConnectionState("disconnecting"); + await super.stop(); + this.changeConnectionState("disconnected"); + log.trace("disconnected"); + } } diff --git a/packages/core/js-client/src/clientPeer/__test__/client.spec.ts b/packages/core/js-client/src/clientPeer/__test__/client.spec.ts index 1831f4348..371c40044 100644 --- a/packages/core/js-client/src/clientPeer/__test__/client.spec.ts +++ b/packages/core/js-client/src/clientPeer/__test__/client.spec.ts @@ -26,11 +26,11 @@ import { checkConnection } from "../checkConnection.js"; import { nodes, RELAY } from "./connection.js"; describe("FluenceClient usage test suite", () => { - it("should make a call through network", async () => { - await withClient(RELAY, {}, async (peer) => { - // arrange + it("should make a call through network", async () => { + await withClient(RELAY, {}, async (peer) => { + // arrange - const script = ` + const script = ` (xor (seq (call %init_peer_id% ("load" "relay") [] init_relay) @@ -45,183 +45,179 @@ describe("FluenceClient usage test suite", () => { ) )`; - const particle = await peer.internals.createNewParticle(script); - - const result = await new Promise((resolve, reject) => { - if (particle instanceof Error) { - reject(particle.message); - return; - } - - registerHandlersHelper(peer, particle, { - load: { - relay: () => { - return peer.getRelayPeerId(); - }, - }, - callback: { - callback: (args) => { - const [val] = args; - resolve(val); - }, - error: (args) => { - const [error] = args; - reject(error); - }, - }, - }); - - peer.internals.initiateParticle( - particle, - handleTimeout(reject), - ); - }); - - expect(result).toBe("hello world!"); + const particle = await peer.internals.createNewParticle(script); + + const result = await new Promise((resolve, reject) => { + if (particle instanceof Error) { + reject(particle.message); + return; + } + + registerHandlersHelper(peer, particle, { + load: { + relay: () => { + return peer.getRelayPeerId(); + }, + }, + callback: { + callback: (args) => { + const [val] = args; + resolve(val); + }, + error: (args) => { + const [error] = args; + reject(error); + }, + }, }); + + peer.internals.initiateParticle(particle, handleTimeout(reject)); + }); + + expect(result).toBe("hello world!"); }); + }); - it("check connection should work", async function () { - await withClient(RELAY, {}, async (peer) => { - const isConnected = await checkConnection(peer); + it("check connection should work", async function () { + await withClient(RELAY, {}, async (peer) => { + const isConnected = await checkConnection(peer); - expect(isConnected).toEqual(true); - }); + expect(isConnected).toEqual(true); }); + }); - it("check connection should work with ttl", async function () { - await withClient(RELAY, {}, async (peer) => { - const isConnected = await checkConnection(peer, 10000); + it("check connection should work with ttl", async function () { + await withClient(RELAY, {}, async (peer) => { + const isConnected = await checkConnection(peer, 10000); - expect(isConnected).toEqual(true); - }); + expect(isConnected).toEqual(true); }); + }); + + it("two clients should work inside the same time javascript process", async () => { + await withClient(RELAY, {}, async (peer1) => { + await withClient(RELAY, {}, async (peer2) => { + const res = new Promise((resolve) => { + peer2.internals.regHandler.common( + "test", + "test", + (req: CallServiceData) => { + resolve(req.args[0]); + return { + result: {}, + retCode: 0, + }; + }, + ); + }); - it("two clients should work inside the same time javascript process", async () => { - await withClient(RELAY, {}, async (peer1) => { - await withClient(RELAY, {}, async (peer2) => { - const res = new Promise((resolve) => { - peer2.internals.regHandler.common( - "test", - "test", - (req: CallServiceData) => { - resolve(req.args[0]); - return { - result: {}, - retCode: 0, - }; - }, - ); - }); - - const script = ` + const script = ` (seq (call "${peer1.getRelayPeerId()}" ("op" "identity") []) (call "${peer2.getPeerId()}" ("test" "test") ["test"]) ) `; - const particle = - await peer1.internals.createNewParticle(script); + const particle = await peer1.internals.createNewParticle(script); - if (particle instanceof Error) { - throw particle; - } + if (particle instanceof Error) { + throw particle; + } - peer1.internals.initiateParticle(particle, doNothing); + peer1.internals.initiateParticle(particle, doNothing); - expect(await res).toEqual("test"); - }); - }); + expect(await res).toEqual("test"); + }); }); + }); - describe("should make connection to network", () => { - it("address as string", async () => { - await withClient(nodes[0].multiaddr, {}, async (peer) => { - const isConnected = await checkConnection(peer); + describe("should make connection to network", () => { + it("address as string", async () => { + await withClient(nodes[0].multiaddr, {}, async (peer) => { + const isConnected = await checkConnection(peer); - expect(isConnected).toBeTruthy(); - }); - }); + expect(isConnected).toBeTruthy(); + }); + }); - it("address as node", async () => { - await withClient(nodes[0], {}, async (peer) => { - const isConnected = await checkConnection(peer); + it("address as node", async () => { + await withClient(nodes[0], {}, async (peer) => { + const isConnected = await checkConnection(peer); - expect(isConnected).toBeTruthy(); - }); - }); + expect(isConnected).toBeTruthy(); + }); + }); - it("With connection options: dialTimeout", async () => { - await withClient( - RELAY, - { connectionOptions: { dialTimeoutMs: 100000 } }, - async (peer) => { - const isConnected = await checkConnection(peer); + it("With connection options: dialTimeout", async () => { + await withClient( + RELAY, + { connectionOptions: { dialTimeoutMs: 100000 } }, + async (peer) => { + const isConnected = await checkConnection(peer); - expect(isConnected).toBeTruthy(); - }, - ); - }); + expect(isConnected).toBeTruthy(); + }, + ); + }); - it("With connection options: skipCheckConnection", async () => { - await withClient( - RELAY, - { connectionOptions: { skipCheckConnection: true } }, - async (peer) => { - const isConnected = await checkConnection(peer); + it("With connection options: skipCheckConnection", async () => { + await withClient( + RELAY, + { connectionOptions: { skipCheckConnection: true } }, + async (peer) => { + const isConnected = await checkConnection(peer); - expect(isConnected).toBeTruthy(); - }, - ); - }); + expect(isConnected).toBeTruthy(); + }, + ); + }); - it("With connection options: defaultTTL", async () => { - await withClient(RELAY, { defaultTtlMs: 1 }, async (peer) => { - const isConnected = await checkConnection(peer); + it("With connection options: defaultTTL", async () => { + await withClient(RELAY, { defaultTtlMs: 1 }, async (peer) => { + const isConnected = await checkConnection(peer); - expect(isConnected).toBeFalsy(); - }); - }); + expect(isConnected).toBeFalsy(); + }); }); + }); - it.skip("Should throw correct error when the client tries to send a particle not to the relay", async () => { - await withClient(RELAY, {}, async (peer) => { - const script = ` + it.skip("Should throw correct error when the client tries to send a particle not to the relay", async () => { + await withClient(RELAY, {}, async (peer) => { + const script = ` (xor (call "incorrect_peer_id" ("any" "service") []) (call %init_peer_id% ("callback" "error") [%last_error%]) )`; - const particle = await peer.internals.createNewParticle(script); - - const promise = new Promise((_resolve, reject) => { - if (particle instanceof Error) { - reject(particle.message); - return; - } - - registerHandlersHelper(peer, particle, { - callback: { - error: (args) => { - const [error] = args; - reject(error); - }, - }, - }); - - peer.internals.initiateParticle(particle, (stage) => { - if (stage.stage === "sendingError") { - reject(stage.errorMessage); - } - }); - }); - - await promise; - - await expect(promise).rejects.toMatch( - "Particle is expected to be sent to only the single peer (relay which client is connected to)", - ); + const particle = await peer.internals.createNewParticle(script); + + const promise = new Promise((_resolve, reject) => { + if (particle instanceof Error) { + reject(particle.message); + return; + } + + registerHandlersHelper(peer, particle, { + callback: { + error: (args) => { + const [error] = args; + reject(error); + }, + }, }); + + peer.internals.initiateParticle(particle, (stage) => { + if (stage.stage === "sendingError") { + reject(stage.errorMessage); + } + }); + }); + + await promise; + + await expect(promise).rejects.toMatch( + "Particle is expected to be sent to only the single peer (relay which client is connected to)", + ); }); + }); }); diff --git a/packages/core/js-client/src/clientPeer/__test__/connection.ts b/packages/core/js-client/src/clientPeer/__test__/connection.ts index 5988c5052..8554564ba 100644 --- a/packages/core/js-client/src/clientPeer/__test__/connection.ts +++ b/packages/core/js-client/src/clientPeer/__test__/connection.ts @@ -15,11 +15,11 @@ */ export const nodes = [ - { - multiaddr: - "/ip4/127.0.0.1/tcp/9991/ws/p2p/12D3KooWBM3SdXWqGaawQDGQ6JprtwswEg3FWGvGhmgmMez1vRbR", - peerId: "12D3KooWBM3SdXWqGaawQDGQ6JprtwswEg3FWGvGhmgmMez1vRbR", - }, + { + multiaddr: + "/ip4/127.0.0.1/tcp/9991/ws/p2p/12D3KooWBM3SdXWqGaawQDGQ6JprtwswEg3FWGvGhmgmMez1vRbR", + peerId: "12D3KooWBM3SdXWqGaawQDGQ6JprtwswEg3FWGvGhmgmMez1vRbR", + }, ]; export const RELAY = nodes[0].multiaddr; diff --git a/packages/core/js-client/src/clientPeer/checkConnection.ts b/packages/core/js-client/src/clientPeer/checkConnection.ts index 355209064..e2f398244 100644 --- a/packages/core/js-client/src/clientPeer/checkConnection.ts +++ b/packages/core/js-client/src/clientPeer/checkConnection.ts @@ -29,12 +29,12 @@ const log = logger("connection"); * @param { ClientPeer } peer - The Fluence Client instance. */ export const checkConnection = async ( - peer: ClientPeer, - ttl?: number, + peer: ClientPeer, + ttl?: number, ): Promise => { - const msg = Math.random().toString(36).substring(7); + const msg = Math.random().toString(36).substring(7); - const script = ` + const script = ` (xor (seq (call %init_peer_id% ("load" "relay") [] init_relay) @@ -52,87 +52,87 @@ export const checkConnection = async ( ) )`; - const particle = await peer.internals.createNewParticle(script, ttl); - - const promise = new Promise((resolve, reject) => { - if (particle instanceof Error) { - reject(particle.message); - return; - } - - peer.internals.regHandler.forParticle( - particle.id, - "load", - "relay", - WrapFnIntoServiceCall(() => { - return peer.getRelayPeerId(); - }), - ); - - peer.internals.regHandler.forParticle( - particle.id, - "load", - "msg", - WrapFnIntoServiceCall(() => { - return msg; - }), - ); - - peer.internals.regHandler.forParticle( - particle.id, - "callback", - "callback", - WrapFnIntoServiceCall((args) => { - const [val] = args; - - setTimeout(() => { - resolve(val); - }, 0); - - return {}; - }), - ); - - peer.internals.regHandler.forParticle( - particle.id, - "callback", - "error", - WrapFnIntoServiceCall((args) => { - const [error] = args; - - setTimeout(() => { - reject(error); - }, 0); - - return {}; - }), - ); - - peer.internals.initiateParticle( - particle, - handleTimeout(() => { - reject("particle timed out"); - }), - ); - }); - - try { - const result = await promise; - - if (result !== msg) { - log.error( - "unexpected behavior. 'identity' must return the passed arguments.", - ); - } - - return true; - } catch (e) { - log.error( - "error on establishing connection. Relay: %s error: %j", - peer.getRelayPeerId(), - e, - ); - - return false; + const particle = await peer.internals.createNewParticle(script, ttl); + + const promise = new Promise((resolve, reject) => { + if (particle instanceof Error) { + reject(particle.message); + return; + } + + peer.internals.regHandler.forParticle( + particle.id, + "load", + "relay", + WrapFnIntoServiceCall(() => { + return peer.getRelayPeerId(); + }), + ); + + peer.internals.regHandler.forParticle( + particle.id, + "load", + "msg", + WrapFnIntoServiceCall(() => { + return msg; + }), + ); + + peer.internals.regHandler.forParticle( + particle.id, + "callback", + "callback", + WrapFnIntoServiceCall((args) => { + const [val] = args; + + setTimeout(() => { + resolve(val); + }, 0); + + return {}; + }), + ); + + peer.internals.regHandler.forParticle( + particle.id, + "callback", + "error", + WrapFnIntoServiceCall((args) => { + const [error] = args; + + setTimeout(() => { + reject(error); + }, 0); + + return {}; + }), + ); + + peer.internals.initiateParticle( + particle, + handleTimeout(() => { + reject("particle timed out"); + }), + ); + }); + + try { + const result = await promise; + + if (result !== msg) { + log.error( + "unexpected behavior. 'identity' must return the passed arguments.", + ); } + + return true; + } catch (e) { + log.error( + "error on establishing connection. Relay: %s error: %j", + peer.getRelayPeerId(), + e, + ); + + return false; + } }; diff --git a/packages/core/js-client/src/compilerSupport/__test__/v3.spec.ts b/packages/core/js-client/src/compilerSupport/__test__/v3.spec.ts index acfd24329..89207e8e6 100644 --- a/packages/core/js-client/src/compilerSupport/__test__/v3.spec.ts +++ b/packages/core/js-client/src/compilerSupport/__test__/v3.spec.ts @@ -22,8 +22,8 @@ import { aqua2ts, ts2aqua } from "../conversions.js"; const i32 = { tag: "scalar", name: "i32" } as const; const opt_i32 = { - tag: "option", - type: i32, + tag: "option", + type: i32, } as const; const array_i32 = { tag: "array", type: i32 }; @@ -31,218 +31,218 @@ const array_i32 = { tag: "array", type: i32 }; const array_opt_i32 = { tag: "array", type: opt_i32 }; const labeledProduct = { - tag: "labeledProduct", - fields: { - a: i32, - b: opt_i32, - c: array_opt_i32, - }, + tag: "labeledProduct", + fields: { + a: i32, + b: opt_i32, + c: array_opt_i32, + }, }; const struct = { - tag: "struct", - name: "someStruct", - fields: { - a: i32, - b: opt_i32, - c: array_opt_i32, - }, + tag: "struct", + name: "someStruct", + fields: { + a: i32, + b: opt_i32, + c: array_opt_i32, + }, }; const structs = [ - { - aqua: { - a: 1, - b: [2], - c: [[1], [2]], - }, + { + aqua: { + a: 1, + b: [2], + c: [[1], [2]], + }, - ts: { - a: 1, - b: 2, - c: [1, 2], - }, + ts: { + a: 1, + b: 2, + c: [1, 2], + }, + }, + { + aqua: { + a: 1, + b: [], + c: [[], [2]], }, - { - aqua: { - a: 1, - b: [], - c: [[], [2]], - }, - ts: { - a: 1, - b: null, - c: [null, 2], - }, + ts: { + a: 1, + b: null, + c: [null, 2], }, + }, ]; const labeledProduct2 = { - tag: "labeledProduct", - fields: { - x: i32, - y: i32, - }, + tag: "labeledProduct", + fields: { + x: i32, + y: i32, + }, }; const nestedLabeledProductType = { - tag: "labeledProduct", - fields: { - a: labeledProduct2, - b: { - tag: "option", - type: labeledProduct2, - }, - c: { - tag: "array", - type: labeledProduct2, - }, + tag: "labeledProduct", + fields: { + a: labeledProduct2, + b: { + tag: "option", + type: labeledProduct2, + }, + c: { + tag: "array", + type: labeledProduct2, }, + }, }; const nestedStructs = [ - { - aqua: { - a: { - x: 1, - y: 2, - }, - b: [ - { - x: 1, - y: 2, - }, - ], - c: [ - { - x: 1, - y: 2, - }, - { - x: 3, - y: 4, - }, - ], + { + aqua: { + a: { + x: 1, + y: 2, + }, + b: [ + { + x: 1, + y: 2, }, - - ts: { - a: { - x: 1, - y: 2, - }, - b: { - x: 1, - y: 2, - }, - - c: [ - { - x: 1, - y: 2, - }, - { - x: 3, - y: 4, - }, - ], + ], + c: [ + { + x: 1, + y: 2, }, - }, - { - aqua: { - a: { - x: 1, - y: 2, - }, - b: [], - c: [], + { + x: 3, + y: 4, }, + ], + }, - ts: { - a: { - x: 1, - y: 2, - }, - b: null, - c: [], + ts: { + a: { + x: 1, + y: 2, + }, + b: { + x: 1, + y: 2, + }, + + c: [ + { + x: 1, + y: 2, }, + { + x: 3, + y: 4, + }, + ], + }, + }, + { + aqua: { + a: { + x: 1, + y: 2, + }, + b: [], + c: [], }, + + ts: { + a: { + x: 1, + y: 2, + }, + b: null, + c: [], + }, + }, ]; interface ConversionTestArgs { - aqua: JSONValue; - ts: JSONValue; - type: NonArrowType; + aqua: JSONValue; + ts: JSONValue; + type: NonArrowType; } describe("Conversion from aqua to typescript", () => { - test.each` - aqua | ts | type - ${1} | ${1} | ${i32} - ${[]} | ${null} | ${opt_i32} - ${[1]} | ${1} | ${opt_i32} - ${[1, 2, 3]} | ${[1, 2, 3]} | ${array_i32} - ${[]} | ${[]} | ${array_i32} - ${[[1]]} | ${[1]} | ${array_opt_i32} - ${[[]]} | ${[null]} | ${array_opt_i32} - ${[[1], [2]]} | ${[1, 2]} | ${array_opt_i32} - ${[[], [2]]} | ${[null, 2]} | ${array_opt_i32} - ${structs[0].aqua} | ${structs[0].ts} | ${labeledProduct} - ${structs[1].aqua} | ${structs[1].ts} | ${labeledProduct} - ${structs[0].aqua} | ${structs[0].ts} | ${struct} - ${structs[1].aqua} | ${structs[1].ts} | ${struct} - ${nestedStructs[0].aqua} | ${nestedStructs[0].ts} | ${nestedLabeledProductType} - ${nestedStructs[1].aqua} | ${nestedStructs[1].ts} | ${nestedLabeledProductType} - `( - // - "aqua: $aqua. ts: $ts. type: $type", - ({ aqua, ts, type }: ConversionTestArgs) => { - // arrange - - // act - const tsFromAqua = aqua2ts(aqua, type); - const aquaFromTs = ts2aqua(ts, type); - - // assert - expect(tsFromAqua).toStrictEqual(ts); - expect(aquaFromTs).toStrictEqual(aqua); - }, - ); + test.each` + aqua | ts | type + ${1} | ${1} | ${i32} + ${[]} | ${null} | ${opt_i32} + ${[1]} | ${1} | ${opt_i32} + ${[1, 2, 3]} | ${[1, 2, 3]} | ${array_i32} + ${[]} | ${[]} | ${array_i32} + ${[[1]]} | ${[1]} | ${array_opt_i32} + ${[[]]} | ${[null]} | ${array_opt_i32} + ${[[1], [2]]} | ${[1, 2]} | ${array_opt_i32} + ${[[], [2]]} | ${[null, 2]} | ${array_opt_i32} + ${structs[0].aqua} | ${structs[0].ts} | ${labeledProduct} + ${structs[1].aqua} | ${structs[1].ts} | ${labeledProduct} + ${structs[0].aqua} | ${structs[0].ts} | ${struct} + ${structs[1].aqua} | ${structs[1].ts} | ${struct} + ${nestedStructs[0].aqua} | ${nestedStructs[0].ts} | ${nestedLabeledProductType} + ${nestedStructs[1].aqua} | ${nestedStructs[1].ts} | ${nestedLabeledProductType} + `( + // + "aqua: $aqua. ts: $ts. type: $type", + ({ aqua, ts, type }: ConversionTestArgs) => { + // arrange + + // act + const tsFromAqua = aqua2ts(aqua, type); + const aquaFromTs = ts2aqua(ts, type); + + // assert + expect(tsFromAqua).toStrictEqual(ts); + expect(aquaFromTs).toStrictEqual(aqua); + }, + ); }); describe("Conversion corner cases", () => { - it("Should accept undefined in object entry", () => { - // arrange - const type = { - tag: "labeledProduct", - fields: { - x: opt_i32, - y: opt_i32, - }, - } as const; - - const valueInTs = { - x: 1, - }; - - const valueInAqua = { - x: [1], - y: [], - }; - - // act - const aqua = ts2aqua(valueInTs, type); - const ts = aqua2ts(valueInAqua, type); - - // assert - expect(aqua).toStrictEqual({ - x: [1], - y: [], - }); - - expect(ts).toStrictEqual({ - x: 1, - y: null, - }); + it("Should accept undefined in object entry", () => { + // arrange + const type = { + tag: "labeledProduct", + fields: { + x: opt_i32, + y: opt_i32, + }, + } as const; + + const valueInTs = { + x: 1, + }; + + const valueInAqua = { + x: [1], + y: [], + }; + + // act + const aqua = ts2aqua(valueInTs, type); + const ts = aqua2ts(valueInAqua, type); + + // assert + expect(aqua).toStrictEqual({ + x: [1], + y: [], + }); + + expect(ts).toStrictEqual({ + x: 1, + y: null, }); + }); }); diff --git a/packages/core/js-client/src/compilerSupport/callFunction.ts b/packages/core/js-client/src/compilerSupport/callFunction.ts index 718dadb2d..3736ecff4 100644 --- a/packages/core/js-client/src/compilerSupport/callFunction.ts +++ b/packages/core/js-client/src/compilerSupport/callFunction.ts @@ -17,24 +17,24 @@ import assert from "assert"; import { - FnConfig, - FunctionCallDef, - getArgumentTypes, - isReturnTypeVoid, - PassedArgs, + FnConfig, + FunctionCallDef, + getArgumentTypes, + isReturnTypeVoid, + PassedArgs, } from "@fluencelabs/interfaces"; import { FluencePeer } from "../jsPeer/FluencePeer.js"; import { logger } from "../util/logger.js"; import { - errorHandlingService, - injectRelayService, - injectValueService, - registerParticleScopeService, - responseService, - ServiceDescription, - userHandlerService, + errorHandlingService, + injectRelayService, + injectValueService, + registerParticleScopeService, + responseService, + ServiceDescription, + userHandlerService, } from "./services.js"; const log = logger("aqua"); @@ -52,100 +52,87 @@ const log = logger("aqua"); */ type CallAquaFunctionArgs = { - def: FunctionCallDef; - script: string; - config: FnConfig; - peer: FluencePeer; - args: PassedArgs; + def: FunctionCallDef; + script: string; + config: FnConfig; + peer: FluencePeer; + args: PassedArgs; }; export const callAquaFunction = async ({ - def, - script, - config, - peer, - args, + def, + script, + config, + peer, + args, }: CallAquaFunctionArgs) => { - log.trace("calling aqua function %j", { def, script, config, args }); - const argumentTypes = getArgumentTypes(def); - - const particle = await peer.internals.createNewParticle(script, config.ttl); - - return new Promise((resolve, reject) => { - for (const [name, argVal] of Object.entries(args)) { - const type = argumentTypes[name]; - let service: ServiceDescription; - - if (type.tag === "arrow") { - // TODO: Add validation here - assert(typeof argVal === "function"); - - service = userHandlerService( - def.names.callbackSrv, - [name, type], - argVal, - ); - } else { - // TODO: Add validation here - assert(typeof argVal !== "function"); - - service = injectValueService( - def.names.getDataSrv, - name, - type, - argVal, - ); - } - - registerParticleScopeService(peer, particle, service); - } - - registerParticleScopeService( - peer, - particle, - responseService(def, resolve), - ); + log.trace("calling aqua function %j", { def, script, config, args }); + const argumentTypes = getArgumentTypes(def); + + const particle = await peer.internals.createNewParticle(script, config.ttl); + + return new Promise((resolve, reject) => { + for (const [name, argVal] of Object.entries(args)) { + const type = argumentTypes[name]; + let service: ServiceDescription; - registerParticleScopeService( - peer, - particle, - injectRelayService(def, peer), + if (type.tag === "arrow") { + // TODO: Add validation here + assert(typeof argVal === "function"); + + service = userHandlerService( + def.names.callbackSrv, + [name, type], + argVal, + ); + } else { + // TODO: Add validation here + assert(typeof argVal !== "function"); + + service = injectValueService(def.names.getDataSrv, name, type, argVal); + } + + registerParticleScopeService(peer, particle, service); + } + + registerParticleScopeService(peer, particle, responseService(def, resolve)); + + registerParticleScopeService(peer, particle, injectRelayService(def, peer)); + + registerParticleScopeService( + peer, + particle, + errorHandlingService(def, reject), + ); + + peer.internals.initiateParticle(particle, (stage) => { + // If function is void, then it's completed when one of the two conditions is met: + // 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') + if ( + isReturnTypeVoid(def) && + (stage.stage === "sent" || stage.stage === "localWorkDone") + ) { + resolve(undefined); + } + + if (stage.stage === "sendingError") { + reject( + `Could not send particle for ${def.functionName}: not connected (particle id: ${particle.id})`, ); + } - registerParticleScopeService( - peer, - particle, - errorHandlingService(def, reject), + if (stage.stage === "expired") { + reject( + `Particle expired after ttl of ${particle.ttl}ms for function ${def.functionName} (particle id: ${particle.id})`, ); + } - peer.internals.initiateParticle(particle, (stage) => { - // If function is void, then it's completed when one of the two conditions is met: - // 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') - if ( - isReturnTypeVoid(def) && - (stage.stage === "sent" || stage.stage === "localWorkDone") - ) { - resolve(undefined); - } - - if (stage.stage === "sendingError") { - reject( - `Could not send particle for ${def.functionName}: not connected (particle id: ${particle.id})`, - ); - } - - if (stage.stage === "expired") { - reject( - `Particle expired after ttl of ${particle.ttl}ms for function ${def.functionName} (particle id: ${particle.id})`, - ); - } - - if (stage.stage === "interpreterError") { - reject( - `Script interpretation failed for ${def.functionName}: ${stage.errorMessage} (particle id: ${particle.id})`, - ); - } - }); + if (stage.stage === "interpreterError") { + reject( + `Script interpretation failed for ${def.functionName}: ${stage.errorMessage} (particle id: ${particle.id})`, + ); + } }); + }); }; diff --git a/packages/core/js-client/src/compilerSupport/conversions.ts b/packages/core/js-client/src/compilerSupport/conversions.ts index bc339e7a2..eeeaa53a6 100644 --- a/packages/core/js-client/src/compilerSupport/conversions.ts +++ b/packages/core/js-client/src/compilerSupport/conversions.ts @@ -21,11 +21,11 @@ import assert from "assert"; import type { - ArrowType, - ArrowWithoutCallbacks, - JSONArray, - JSONValue, - NonArrowType, + ArrowType, + ArrowWithoutCallbacks, + JSONArray, + JSONValue, + NonArrowType, } from "@fluencelabs/interfaces"; import { match } from "ts-pattern"; @@ -39,57 +39,52 @@ import { jsonify } from "../util/utils.js"; * @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)); - - 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)); - 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; + const res = match(type) + .with({ tag: "nil" }, () => { + return null; + }) + .with({ tag: "option" }, (opt) => { + assert(Array.isArray(value)); + + 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)); + 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; }; /** @@ -99,34 +94,34 @@ export const aqua2ts = (value: JSONValue, type: NonArrowType): JSONValue => { * @returns arguments in typescript representation */ export const aquaArgs2Ts = ( - req: CallServiceData, - arrow: ArrowWithoutCallbacks, + req: CallServiceData, + arrow: ArrowWithoutCallbacks, ): 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]); + 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]); + }); }; /** @@ -136,55 +131,50 @@ export const aquaArgs2Ts = ( * @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)); - 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; + 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)); + 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; }; /** @@ -194,24 +184,24 @@ export const ts2aqua = (value: JSONValue, type: NonArrowType): JSONValue => { * @returns - value represented in aqua */ export const returnType2Aqua = ( - returnValue: any, - arrowType: ArrowType, + returnValue: any, + arrowType: ArrowType, ) => { - if (arrowType.codomain.tag === "nil") { - return {}; - } + if (arrowType.codomain.tag === "nil") { + return {}; + } - if (arrowType.codomain.items.length === 0) { - return {}; - } + if (arrowType.codomain.items.length === 0) { + return {}; + } - if (arrowType.codomain.items.length === 1) { - return ts2aqua(returnValue, arrowType.codomain.items[0]); - } + 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); - }); + return arrowType.codomain.items.map((type, index) => { + return ts2aqua(returnValue[index], type); + }); }; /** @@ -221,25 +211,25 @@ export const returnType2Aqua = ( * @returns response value in typescript representation */ export const responseServiceValue2ts = ( - req: CallServiceData, - arrow: ArrowType, + req: CallServiceData, + arrow: ArrowType, ) => { - 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(); + 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(); }; diff --git a/packages/core/js-client/src/compilerSupport/registerService.ts b/packages/core/js-client/src/compilerSupport/registerService.ts index a2a27f38f..686f9f169 100644 --- a/packages/core/js-client/src/compilerSupport/registerService.ts +++ b/packages/core/js-client/src/compilerSupport/registerService.ts @@ -24,65 +24,65 @@ import { registerGlobalService, userHandlerService } from "./services.js"; const log = logger("aqua"); interface RegisterServiceArgs { - peer: FluencePeer; - def: ServiceDef; - serviceId: string | undefined; - service: ServiceImpl; + peer: FluencePeer; + def: ServiceDef; + serviceId: string | undefined; + service: ServiceImpl; } export const registerService = ({ - peer, - def, - serviceId, - service, + peer, + def, + serviceId, + service, }: 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", { def, serviceId, service }); - - // Checking for missing keys - const requiredKeys = - def.functions.tag === "nil" ? [] : Object.keys(def.functions.fields); - - const incorrectServiceDefinitions = requiredKeys.filter((f) => { - return !(f in service); - }); - - if (incorrectServiceDefinitions.length > 0) { - throw new Error( - `Error registering service ${serviceId}: missing functions: ` + - incorrectServiceDefinitions - .map((d) => { - return "'" + d + "'"; - }) - .join(", "), - ); - } - - if (serviceId == null) { - serviceId = def.defaultServiceId; - } - - if (serviceId == null) { - throw new Error("Service ID must be specified"); - } - - const singleFunctions = - def.functions.tag === "nil" ? [] : Object.entries(def.functions.fields); - - for (const singleFunction of singleFunctions) { - const [name] = singleFunction; - // The function has type of (arg1, arg2, arg3, ... , callParams) => CallServiceResultType | void - // Account for the fact that user service might be defined as a class - .bind(...) - const userDefinedHandler = service[name].bind(service); - - const serviceDescription = userHandlerService( - serviceId, - singleFunction, - userDefinedHandler, - ); - - registerGlobalService(peer, serviceDescription); - } - - log.trace("aqua service registered %s", serviceId); + // TODO: Need to refactor this. We can compute function types from service implementation, making func more type safe + log.trace("registering aqua service %o", { def, serviceId, service }); + + // Checking for missing keys + const requiredKeys = + def.functions.tag === "nil" ? [] : Object.keys(def.functions.fields); + + const incorrectServiceDefinitions = requiredKeys.filter((f) => { + return !(f in service); + }); + + if (incorrectServiceDefinitions.length > 0) { + throw new Error( + `Error registering service ${serviceId}: missing functions: ` + + incorrectServiceDefinitions + .map((d) => { + return "'" + d + "'"; + }) + .join(", "), + ); + } + + if (serviceId == null) { + serviceId = def.defaultServiceId; + } + + if (serviceId == null) { + throw new Error("Service ID must be specified"); + } + + const singleFunctions = + def.functions.tag === "nil" ? [] : Object.entries(def.functions.fields); + + for (const singleFunction of singleFunctions) { + const [name] = singleFunction; + // The function has type of (arg1, arg2, arg3, ... , callParams) => CallServiceResultType | void + // Account for the fact that user service might be defined as a class - .bind(...) + const userDefinedHandler = service[name].bind(service); + + const serviceDescription = userHandlerService( + serviceId, + singleFunction, + userDefinedHandler, + ); + + registerGlobalService(peer, serviceDescription); + } + + log.trace("aqua service registered %s", serviceId); }; diff --git a/packages/core/js-client/src/compilerSupport/services.ts b/packages/core/js-client/src/compilerSupport/services.ts index d1a1aedb7..7b59c55e9 100644 --- a/packages/core/js-client/src/compilerSupport/services.ts +++ b/packages/core/js-client/src/compilerSupport/services.ts @@ -16,215 +16,215 @@ import { SecurityTetraplet } from "@fluencelabs/avm"; import { - CallParams, - ArrowWithoutCallbacks, - FunctionCallDef, - NonArrowType, - ServiceImpl, - JSONValue, + CallParams, + ArrowWithoutCallbacks, + FunctionCallDef, + NonArrowType, + ServiceImpl, + JSONValue, } from "@fluencelabs/interfaces"; import { fromUint8Array } from "js-base64"; import { match } from "ts-pattern"; import { FluencePeer } from "../jsPeer/FluencePeer.js"; import { - CallServiceData, - GenericCallServiceHandler, - ResultCodes, + CallServiceData, + GenericCallServiceHandler, + ResultCodes, } from "../jsServiceHost/interfaces.js"; import { Particle } from "../particle/Particle.js"; import { - aquaArgs2Ts, - responseServiceValue2ts, - returnType2Aqua, - ts2aqua, + aquaArgs2Ts, + responseServiceValue2ts, + returnType2Aqua, + ts2aqua, } from "./conversions.js"; export interface ServiceDescription { - serviceId: string; - fnName: string; - handler: GenericCallServiceHandler; + serviceId: string; + fnName: string; + handler: GenericCallServiceHandler; } /** * Creates a service which injects relay's peer id into aqua space */ export const injectRelayService = (def: FunctionCallDef, peer: FluencePeer) => { - return { - serviceId: def.names.getDataSrv, - fnName: def.names.relay, - handler: () => { - return { - retCode: ResultCodes.success, - result: peer.internals.getRelayPeerId(), - }; - }, - }; + return { + serviceId: def.names.getDataSrv, + fnName: def.names.relay, + handler: () => { + return { + retCode: ResultCodes.success, + result: peer.internals.getRelayPeerId(), + }; + }, + }; }; /** * Creates a service which injects plain value into aqua space */ export const injectValueService = ( - serviceId: string, - fnName: string, - valueType: NonArrowType, - value: JSONValue, + serviceId: string, + fnName: string, + valueType: NonArrowType, + value: JSONValue, ) => { - return { - serviceId: serviceId, - fnName: fnName, - handler: () => { - return { - retCode: ResultCodes.success, - result: ts2aqua(value, valueType), - }; - }, - }; + return { + serviceId: serviceId, + fnName: fnName, + handler: () => { + return { + retCode: ResultCodes.success, + result: ts2aqua(value, valueType), + }; + }, + }; }; /** * Creates a service which is used to return value from aqua function into typescript space */ export const responseService = ( - def: FunctionCallDef, - resolveCallback: (val: JSONValue) => void, + def: FunctionCallDef, + resolveCallback: (val: JSONValue) => void, ) => { - return { - serviceId: def.names.responseSrv, - fnName: def.names.responseFnName, - handler: (req: CallServiceData) => { - const userFunctionReturn = responseServiceValue2ts(req, def.arrow); - - setTimeout(() => { - resolveCallback(userFunctionReturn); - }, 0); - - return { - retCode: ResultCodes.success, - result: {}, - }; - }, - }; + return { + serviceId: def.names.responseSrv, + fnName: def.names.responseFnName, + handler: (req: CallServiceData) => { + const userFunctionReturn = responseServiceValue2ts(req, def.arrow); + + setTimeout(() => { + resolveCallback(userFunctionReturn); + }, 0); + + return { + retCode: ResultCodes.success, + result: {}, + }; + }, + }; }; /** * Creates a service which is used to return errors from aqua function into typescript space */ export const errorHandlingService = ( - def: FunctionCallDef, - rejectCallback: (err: JSONValue) => void, + def: FunctionCallDef, + rejectCallback: (err: JSONValue) => void, ) => { - return { - serviceId: def.names.errorHandlingSrv, - fnName: def.names.errorFnName, - handler: (req: CallServiceData) => { - const [err] = req.args; - - setTimeout(() => { - rejectCallback(err); - }, 0); - - return { - retCode: ResultCodes.success, - result: {}, - }; - }, - }; + return { + serviceId: def.names.errorHandlingSrv, + fnName: def.names.errorFnName, + handler: (req: CallServiceData) => { + const [err] = req.args; + + setTimeout(() => { + rejectCallback(err); + }, 0); + + return { + retCode: ResultCodes.success, + result: {}, + }; + }, + }; }; /** * Creates a service for user-defined service function handler */ export const userHandlerService = ( - serviceId: string, - arrowType: [string, ArrowWithoutCallbacks], - userHandler: ServiceImpl[string], + serviceId: string, + arrowType: [string, ArrowWithoutCallbacks], + userHandler: ServiceImpl[string], ) => { - const [fnName, type] = arrowType; - return { - serviceId, - fnName, - handler: async (req: CallServiceData) => { - const args: [...JSONValue[], CallParams] = [ - ...aquaArgs2Ts(req, type), - extractCallParams(req, type), - ]; - - const rawResult = await userHandler.bind(null)(...args); - const result = returnType2Aqua(rawResult, type); - - return { - retCode: ResultCodes.success, - result: result, - }; - }, - }; + const [fnName, type] = arrowType; + return { + serviceId, + fnName, + handler: async (req: CallServiceData) => { + const args: [...JSONValue[], CallParams] = [ + ...aquaArgs2Ts(req, type), + extractCallParams(req, type), + ]; + + const rawResult = await userHandler.bind(null)(...args); + const result = returnType2Aqua(rawResult, type); + + return { + retCode: ResultCodes.success, + result: result, + }; + }, + }; }; /** * Extracts call params from from call service data according to aqua type definition */ const extractCallParams = ( - req: CallServiceData, - arrow: ArrowWithoutCallbacks, + req: CallServiceData, + arrow: ArrowWithoutCallbacks, ): CallParams => { - const names: (string | undefined)[] = match(arrow.domain) - .with({ tag: "nil" }, () => { - return []; - }) - .with({ tag: "unlabeledProduct" }, (x) => { - return x.items.map((_, index) => { - return "arg" + index; - }); - }) - .with({ tag: "labeledProduct" }, (x) => { - return Object.keys(x.fields).map((label) => { - return label; - }); - }) - .exhaustive(); - - const tetraplets: Record = {}; - - for (let i = 0; i < req.args.length; i++) { - const name = names[i]; - - if (name != null) { - tetraplets[name] = req.tetraplets[i]; - } + const names: (string | undefined)[] = match(arrow.domain) + .with({ tag: "nil" }, () => { + return []; + }) + .with({ tag: "unlabeledProduct" }, (x) => { + return x.items.map((_, index) => { + return "arg" + index; + }); + }) + .with({ tag: "labeledProduct" }, (x) => { + return Object.keys(x.fields).map((label) => { + return label; + }); + }) + .exhaustive(); + + const tetraplets: Record = {}; + + for (let i = 0; i < req.args.length; i++) { + const name = names[i]; + + if (name != null) { + tetraplets[name] = req.tetraplets[i]; } + } - const callParams = { - ...req.particleContext, - signature: fromUint8Array(req.particleContext.signature), - tetraplets, - }; + const callParams = { + ...req.particleContext, + signature: fromUint8Array(req.particleContext.signature), + tetraplets, + }; - return callParams; + return callParams; }; export const registerParticleScopeService = ( - peer: FluencePeer, - particle: Particle, - service: ServiceDescription, + peer: FluencePeer, + particle: Particle, + service: ServiceDescription, ) => { - peer.internals.regHandler.forParticle( - particle.id, - service.serviceId, - service.fnName, - service.handler, - ); + peer.internals.regHandler.forParticle( + particle.id, + service.serviceId, + service.fnName, + service.handler, + ); }; export const registerGlobalService = ( - peer: FluencePeer, - service: ServiceDescription, + peer: FluencePeer, + service: ServiceDescription, ) => { - peer.internals.regHandler.common( - service.serviceId, - service.fnName, - service.handler, - ); + peer.internals.regHandler.common( + service.serviceId, + service.fnName, + service.handler, + ); }; diff --git a/packages/core/js-client/src/connection/RelayConnection.ts b/packages/core/js-client/src/connection/RelayConnection.ts index 6acad6260..131045b81 100644 --- a/packages/core/js-client/src/connection/RelayConnection.ts +++ b/packages/core/js-client/src/connection/RelayConnection.ts @@ -48,246 +48,241 @@ export const PROTOCOL_NAME = "/fluence/particle/2.0.0"; * Options to configure fluence relay connection */ export interface RelayConnectionConfig { - /** - * Peer id of the Fluence Peer - */ - peerId: PeerId; - - /** - * Multiaddress of the relay to make connection to - */ - relayAddress: Multiaddr; - - /** - * 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; + /** + * Peer id of the Fluence Peer + */ + peerId: PeerId; + + /** + * Multiaddress of the relay to make connection to + */ + relayAddress: Multiaddr; + + /** + * 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; } /** * Implementation for JS peers which connects to Fluence through relay node */ export class RelayConnection implements IConnection { - private relayAddress: Multiaddr; - private lib2p2Peer: Libp2p | null = null; - private relayPeerId: string; + private relayAddress: Multiaddr; + private lib2p2Peer: Libp2p | null = null; + private relayPeerId: string; - constructor(private config: RelayConnectionConfig) { - this.relayAddress = multiaddr(this.config.relayAddress); - const peerId = this.relayAddress.getPeerId(); + constructor(private config: RelayConnectionConfig) { + this.relayAddress = multiaddr(this.config.relayAddress); + const peerId = this.relayAddress.getPeerId(); - if (peerId == null) { - throwHasNoPeerId(this.relayAddress); - } - - this.relayPeerId = peerId; + if (peerId == null) { + throwHasNoPeerId(this.relayAddress); } - getRelayPeerId(): string { - return this.relayPeerId; - } + this.relayPeerId = peerId; + } - supportsRelay(): boolean { - return true; - } + getRelayPeerId(): string { + return this.relayPeerId; + } - particleSource = new Subject(); - - async start(): Promise { - // check if already started - if (this.lib2p2Peer !== null) { - return; - } - - this.lib2p2Peer = await createLibp2p({ - peerId: this.config.peerId, - transports: [ - webSockets({ - filter: all, - }), - ], - streamMuxers: [yamux()], - connectionEncryption: [noise()], - connectionManager: { - ...(this.config.dialTimeoutMs != null - ? { - dialTimeout: this.config.dialTimeoutMs, - } - : {}), - }, - connectionGater: { - // By default, this function forbids connections to private peers. For example multiaddr with ip 127.0.0.1 isn't allowed - denyDialMultiaddr: () => { - return Promise.resolve(false); - }, - }, - services: { - identify: identifyService(), - ping: pingService(), - }, - }); - - const supportedProtocols = ( - await this.lib2p2Peer.peerStore.get(this.lib2p2Peer.peerId) - ).protocols; - - await this.lib2p2Peer.peerStore.patch(this.lib2p2Peer.peerId, { - protocols: [...supportedProtocols, PROTOCOL_NAME], - }); - - await this.connect(); - } + supportsRelay(): boolean { + return true; + } - async stop(): Promise { - // check if already stopped - if (this.lib2p2Peer === null) { - return; - } + particleSource = new Subject(); - await this.lib2p2Peer.unhandle(PROTOCOL_NAME); - await this.lib2p2Peer.stop(); + async start(): Promise { + // check if already started + if (this.lib2p2Peer !== null) { + return; } - async sendParticle( - nextPeerIds: PeerIdB58[], - particle: IParticle, - ): Promise { - if (this.lib2p2Peer === null) { - throw new Error("Relay connection is not started"); - } - - if ( - nextPeerIds.length !== 1 && - nextPeerIds[0] !== this.getRelayPeerId() - ) { - throw new Error( - `Relay connection only accepts peer id of the connected relay. Got: ${JSON.stringify( - nextPeerIds, - )} instead.`, - ); - } - - log.trace("sending particle..."); - - // Reusing active connection here - const stream = await this.lib2p2Peer.dialProtocol( - this.relayAddress, - PROTOCOL_NAME, - ); + this.lib2p2Peer = await createLibp2p({ + peerId: this.config.peerId, + transports: [ + webSockets({ + filter: all, + }), + ], + streamMuxers: [yamux()], + connectionEncryption: [noise()], + connectionManager: { + ...(this.config.dialTimeoutMs != null + ? { + dialTimeout: this.config.dialTimeoutMs, + } + : {}), + }, + connectionGater: { + // By default, this function forbids connections to private peers. For example multiaddr with ip 127.0.0.1 isn't allowed + denyDialMultiaddr: () => { + return Promise.resolve(false); + }, + }, + services: { + identify: identifyService(), + ping: pingService(), + }, + }); + + const supportedProtocols = ( + await this.lib2p2Peer.peerStore.get(this.lib2p2Peer.peerId) + ).protocols; + + await this.lib2p2Peer.peerStore.patch(this.lib2p2Peer.peerId, { + protocols: [...supportedProtocols, PROTOCOL_NAME], + }); + + await this.connect(); + } + + async stop(): Promise { + // check if already stopped + if (this.lib2p2Peer === null) { + return; + } - log.trace("created stream with id ", stream.id); - const sink = stream.sink; + await this.lib2p2Peer.unhandle(PROTOCOL_NAME); + await this.lib2p2Peer.stop(); + } - await pipe([fromString(serializeToString(particle))], encode(), sink); - log.trace("data written to sink"); + async sendParticle( + nextPeerIds: PeerIdB58[], + particle: IParticle, + ): Promise { + if (this.lib2p2Peer === null) { + throw new Error("Relay connection is not started"); } - // Await will appear after uncommenting lines in func body - // eslint-disable-next-line @typescript-eslint/require-await - private async processIncomingMessage(msg: string, stream: Stream) { - let particle: Particle | undefined; + if (nextPeerIds.length !== 1 && nextPeerIds[0] !== this.getRelayPeerId()) { + throw new Error( + `Relay connection only accepts peer id of the connected relay. Got: ${JSON.stringify( + nextPeerIds, + )} instead.`, + ); + } - try { - particle = Particle.fromString(msg); + log.trace("sending particle..."); - log.trace( - "got particle from stream with id %s and particle id %s", - stream.id, - particle.id, - ); + // Reusing active connection here + const stream = await this.lib2p2Peer.dialProtocol( + this.relayAddress, + PROTOCOL_NAME, + ); - const initPeerId = peerIdFromString(particle.initPeerId); + log.trace("created stream with id ", stream.id); + const sink = stream.sink; - if (initPeerId.publicKey === undefined) { - log.error( - "cannot retrieve public key from init_peer_id. particle id: %s. init_peer_id: %s", - particle.id, - particle.initPeerId, - ); + await pipe([fromString(serializeToString(particle))], encode(), sink); + log.trace("data written to sink"); + } - return; - } + // Await will appear after uncommenting lines in func body + // eslint-disable-next-line @typescript-eslint/require-await + private async processIncomingMessage(msg: string, stream: Stream) { + let particle: Particle | undefined; - // TODO: Uncomment this when nox rolls out particle signatures - // const message = buildParticleMessage(particle); - // const isVerified = await KeyPair.verifyWithPublicKey(initPeerId.publicKey, message, particle.signature); - const isVerified = true; - - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - if (isVerified) { - this.particleSource.next(particle); - } else { - log.trace( - "particle signature is incorrect. rejecting particle with id: %s", - particle.id, - ); - } - } catch (e) { - const particleId = particle?.id; - - const particleIdMessage = - typeof particleId === "string" - ? `. particle id: ${particleId}` - : ""; - - log.error( - `error on handling an incoming message: %O%s`, - e, - particleIdMessage, - ); - } - } + try { + particle = Particle.fromString(msg); + + log.trace( + "got particle from stream with id %s and particle id %s", + stream.id, + particle.id, + ); + + const initPeerId = peerIdFromString(particle.initPeerId); - private async connect() { - if (this.lib2p2Peer === null) { - throw new Error("Relay connection is not started"); - } - - await this.lib2p2Peer.handle( - [PROTOCOL_NAME], - ({ stream }) => { - void pipe( - stream.source, - decode(), - (source) => { - return map(source, (buf) => { - return toString(buf.subarray()); - }); - }, - async (source) => { - try { - for await (const msg of source) { - await this.processIncomingMessage(msg, stream); - } - } catch (e) { - log.error("connection closed: %j", e); - } - }, - ); - }, - { - maxInboundStreams: this.config.maxInboundStreams, - maxOutboundStreams: this.config.maxOutboundStreams, - }, + if (initPeerId.publicKey === undefined) { + log.error( + "cannot retrieve public key from init_peer_id. particle id: %s. init_peer_id: %s", + particle.id, + particle.initPeerId, ); - log.debug( - "dialing to the node with client's address: %s", - this.lib2p2Peer.peerId.toString(), + return; + } + + // TODO: Uncomment this when nox rolls out particle signatures + // const message = buildParticleMessage(particle); + // const isVerified = await KeyPair.verifyWithPublicKey(initPeerId.publicKey, message, particle.signature); + const isVerified = true; + + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (isVerified) { + this.particleSource.next(particle); + } else { + log.trace( + "particle signature is incorrect. rejecting particle with id: %s", + particle.id, ); + } + } catch (e) { + const particleId = particle?.id; + + const particleIdMessage = + typeof particleId === "string" ? `. particle id: ${particleId}` : ""; + + log.error( + `error on handling an incoming message: %O%s`, + e, + particleIdMessage, + ); + } + } - await this.lib2p2Peer.dial(this.relayAddress); + private async connect() { + if (this.lib2p2Peer === null) { + throw new Error("Relay connection is not started"); } + + await this.lib2p2Peer.handle( + [PROTOCOL_NAME], + ({ stream }) => { + void pipe( + stream.source, + decode(), + (source) => { + return map(source, (buf) => { + return toString(buf.subarray()); + }); + }, + async (source) => { + try { + for await (const msg of source) { + await this.processIncomingMessage(msg, stream); + } + } catch (e) { + log.error("connection closed: %j", e); + } + }, + ); + }, + { + maxInboundStreams: this.config.maxInboundStreams, + maxOutboundStreams: this.config.maxOutboundStreams, + }, + ); + + log.debug( + "dialing to the node with client's address: %s", + this.lib2p2Peer.peerId.toString(), + ); + + await this.lib2p2Peer.dial(this.relayAddress); + } } diff --git a/packages/core/js-client/src/connection/interfaces.ts b/packages/core/js-client/src/connection/interfaces.ts index bb5619a84..bb0345c4f 100644 --- a/packages/core/js-client/src/connection/interfaces.ts +++ b/packages/core/js-client/src/connection/interfaces.ts @@ -24,25 +24,25 @@ import { IStartable } from "../util/commonTypes.js"; * Interface for connection used in Fluence Peer. */ export interface IConnection extends IStartable { - /** - * Observable that emits particles received from the connection. - */ - particleSource: Subscribable; + /** + * Observable that emits particles received from the connection. + */ + particleSource: Subscribable; - /** - * Send particle to the network using the connection. - * @param nextPeerIds - list of peer ids to send the particle to - * @param particle - particle to send - */ - sendParticle(nextPeerIds: PeerIdB58[], particle: IParticle): Promise; + /** + * Send particle to the network using the connection. + * @param nextPeerIds - list of peer ids to send the particle to + * @param particle - particle to send + */ + sendParticle(nextPeerIds: PeerIdB58[], particle: IParticle): Promise; - /** - * Get peer id of the relay peer. Throws an error if the connection doesn't support relay. - */ - getRelayPeerId(): PeerIdB58; + /** + * Get peer id of the relay peer. Throws an error if the connection doesn't support relay. + */ + getRelayPeerId(): PeerIdB58; - /** - * Check if the connection supports relay. - */ - supportsRelay(): boolean; + /** + * Check if the connection supports relay. + */ + supportsRelay(): boolean; } diff --git a/packages/core/js-client/src/ephemeral/__test__/ephemeral.spec.ts b/packages/core/js-client/src/ephemeral/__test__/ephemeral.spec.ts index 8c892d38c..267861e0b 100644 --- a/packages/core/js-client/src/ephemeral/__test__/ephemeral.spec.ts +++ b/packages/core/js-client/src/ephemeral/__test__/ephemeral.spec.ts @@ -28,27 +28,27 @@ const relay = defaultConfig.peers[0].peerId; // TODO: race condition here. Needs to be fixed describe.skip("Ephemeral networks tests", () => { - beforeEach(async () => { - en = new EphemeralNetwork(defaultConfig); - await en.up(); + beforeEach(async () => { + en = new EphemeralNetwork(defaultConfig); + await en.up(); - const kp = await KeyPair.randomEd25519(); - client = new EphemeralNetworkClient(DEFAULT_CONFIG, kp, en, relay); - await client.start(); - }); + const kp = await KeyPair.randomEd25519(); + client = new EphemeralNetworkClient(DEFAULT_CONFIG, kp, en, relay); + await client.start(); + }); - afterEach(async () => { - await client.stop(); - await en.down(); - }); + afterEach(async () => { + await client.stop(); + await en.down(); + }); - it("smoke test", async function () { - // arrange - const peers = defaultConfig.peers.map((x) => { - return x.peerId; - }); + it("smoke test", async function () { + // arrange + const peers = defaultConfig.peers.map((x) => { + return x.peerId; + }); - const script = ` + const script = ` (seq (call "${relay}" ("op" "noop") []) (seq @@ -73,27 +73,27 @@ describe.skip("Ephemeral networks tests", () => { ) `; - const particle = await client.internals.createNewParticle(script); + const particle = await client.internals.createNewParticle(script); - const promise = new Promise((resolve) => { - client.internals.regHandler.forParticle( - particle.id, - "test", - "test", - () => { - resolve("success"); - return { - result: "test", - retCode: ResultCodes.success, - }; - }, - ); - }); + const promise = new Promise((resolve) => { + client.internals.regHandler.forParticle( + particle.id, + "test", + "test", + () => { + resolve("success"); + return { + result: "test", + retCode: ResultCodes.success, + }; + }, + ); + }); - // act - client.internals.initiateParticle(particle, () => {}); + // act + client.internals.initiateParticle(particle, () => {}); - // assert - await expect(promise).resolves.toBe("success"); - }); + // assert + await expect(promise).resolves.toBe("success"); + }); }); diff --git a/packages/core/js-client/src/ephemeral/client.ts b/packages/core/js-client/src/ephemeral/client.ts index 117cbb28e..c4d45773a 100644 --- a/packages/core/js-client/src/ephemeral/client.ts +++ b/packages/core/js-client/src/ephemeral/client.ts @@ -29,31 +29,31 @@ import { EphemeralNetwork } from "./network.js"; * Ephemeral network client is a FluencePeer that connects to a relay peer in an ephemeral network. */ export class EphemeralNetworkClient extends FluencePeer { - constructor( - config: PeerConfig, - keyPair: KeyPair, - network: EphemeralNetwork, - relay: PeerIdB58, - ) { - const workerLoader = new WorkerLoader(); - - const controlModuleLoader = new WasmLoaderFromNpm( - "@fluencelabs/marine-js", - "marine-js.wasm", - ); - - const avmModuleLoader = new WasmLoaderFromNpm( - "@fluencelabs/avm", - "avm.wasm", - ); - - const marine = new MarineBackgroundRunner( - workerLoader, - controlModuleLoader, - avmModuleLoader, - ); - - const conn = network.getRelayConnection(keyPair.getPeerId(), relay); - super(config, keyPair, marine, new JsServiceHost(), conn); - } + constructor( + config: PeerConfig, + keyPair: KeyPair, + network: EphemeralNetwork, + relay: PeerIdB58, + ) { + const workerLoader = new WorkerLoader(); + + const controlModuleLoader = new WasmLoaderFromNpm( + "@fluencelabs/marine-js", + "marine-js.wasm", + ); + + const avmModuleLoader = new WasmLoaderFromNpm( + "@fluencelabs/avm", + "avm.wasm", + ); + + const marine = new MarineBackgroundRunner( + workerLoader, + controlModuleLoader, + avmModuleLoader, + ); + + const conn = network.getRelayConnection(keyPair.getPeerId(), relay); + super(config, keyPair, marine, new JsServiceHost(), conn); + } } diff --git a/packages/core/js-client/src/ephemeral/network.ts b/packages/core/js-client/src/ephemeral/network.ts index 78e871dfa..ba8cf7108 100644 --- a/packages/core/js-client/src/ephemeral/network.ts +++ b/packages/core/js-client/src/ephemeral/network.ts @@ -22,8 +22,8 @@ import { DEFAULT_CONFIG, FluencePeer } from "../jsPeer/FluencePeer.js"; import { JsServiceHost } from "../jsServiceHost/JsServiceHost.js"; import { fromBase64Sk, KeyPair } from "../keypair/index.js"; import { - WorkerLoaderFromFs, - WasmLoaderFromNpm, + WorkerLoaderFromFs, + WasmLoaderFromNpm, } from "../marine/deps-loader/node.js"; import { IMarineHost } from "../marine/interfaces.js"; import { MarineBackgroundRunner } from "../marine/worker/index.js"; @@ -33,190 +33,188 @@ import { logger } from "../util/logger.js"; const log = logger("ephemeral"); interface EphemeralConfig { - peers: Array<{ - peerId: PeerIdB58; - sk: string; - }>; + peers: Array<{ + peerId: PeerIdB58; + sk: string; + }>; } export const defaultConfig = { - peers: [ - { - peerId: "12D3KooWJankP2PcEDYCZDdJ26JsU8BMRfdGWyGqbtFiWyoKVtmx", - sk: "dWNAHhDVuFj9bEieILMu6TcCFRxBJdOPIvAWmf4sZQI=", - }, - { - peerId: "12D3KooWSBTB5sYxdwayUyTnqopBwABsnGFY3p4dTx5hABYDtJjV", - sk: "dOmaxAeu4Th+MJ22vRDLMFTNbiDgKNXar9fW9ofAMgQ=", - }, - { - peerId: "12D3KooWQjwf781DJ41moW5RrZXypLdnTbo6aMsoA8QLctGGX8RB", - sk: "TgzaLlxXuOMDNuuuTKEHUKsW0jM4AmX0gahFvkB1KgE=", - }, - { - peerId: "12D3KooWCXWTLFyY1mqKnNAhLQTsjW1zqDzCMbUs8M4a8zdz28HK", - sk: "hiO2Ta8g2ibMQ7iu5yj9CfN+qQCwE8oRShjr7ortKww=", - }, - { - peerId: "12D3KooWPmZpf4ng6GMS39HLagxsXbjiTPLH5CFJpFAHyN6amw6V", - sk: "LzJtOHTqxfrlHDW40BKiLfjai8JU4yW6/s2zrXLCcQE=", - }, - { - peerId: "12D3KooWKrx8PZxM1R9A8tp2jmrFf6c6q1ZQiWfD4QkNgh7fWSoF", - sk: "XMhlk/xr1FPcp7sKQhS18doXlq1x16EMhBC2NGW2LQ4=", - }, - { - peerId: "12D3KooWCbJHvnzSZEXjR1UJmtSUozuJK13iRiCYHLN1gjvm4TZZ", - sk: "KXPAIqxrSHr7v0ngv3qagcqivFvnQ0xd3s1/rKmi8QU=", - }, - { - peerId: "12D3KooWEvKe7WQHp42W4xhHRgTAWQjtDWyH38uJbLHAsMuTtYvD", - sk: "GCYMAshGnsrNtrHhuT7ayzh5uCzX99J03PmAXoOcCgw=", - }, - { - peerId: "12D3KooWSznSHN3BGrSykBXkLkFsqo9SYB73wVauVdqeuRt562cC", - sk: "UP+SEuznS0h259VbFquzyOJAQ4W5iIwhP+hd1PmUQQ0=", - }, - { - peerId: "12D3KooWF57jwbShfnT3c4dNfRDdGjr6SQ3B71m87UVpEpSWHFwi", - sk: "8dl+Crm5RSh0eh+LqLKwX8/Eo4QLpvIjfD8L0wzX4A4=", - }, - { - peerId: "12D3KooWBWrzpSg9nwMLBCa2cJubUjTv63Mfy6PYg9rHGbetaV5C", - sk: "qolc1FcpJ+vHDon0HeXdUYnstjV1wiVx2p0mjblrfAg=", - }, - { - peerId: "12D3KooWNkLVU6juM8oyN2SVq5nBd2kp7Rf4uzJH1hET6vj6G5j6", - sk: "vN6QzWILTM7hSHp+iGkKxiXcqs8bzlnH3FPaRaDGSQY=", - }, - { - peerId: "12D3KooWKo1YwGL5vivPiKJMJS7wjtB6B2nJNdSXPkSABT4NKBUU", - sk: "YbDQ++bsor2kei7rYAsu2SbyoiOYPRzFRZWnNRUpBgQ=", - }, - { - peerId: "12D3KooWLUyBKmmNCyxaPkXoWcUFPcy5qrZsUo2E1tyM6CJmGJvC", - sk: "ptB9eSFMKudAtHaFgDrRK/1oIMrhBujxbMw2Pzwx/wA=", - }, - { - peerId: "12D3KooWAEZXME4KMu9FvLezsJWDbYFe2zyujyMnDT1AgcAxgcCk", - sk: "xtwTOKgAbDIgkuPf7RKiR7gYyZ1HY4mOgFMv3sOUcAQ=", - }, - { - peerId: "12D3KooWEhXetsFVAD9h2dRz9XgFpfidho1TCZVhFrczX8h8qgzY", - sk: "1I2MGuiKG1F4FDMiRihVOcOP2mxzOLWJ99MeexK27A4=", - }, - { - peerId: "12D3KooWDBfVNdMyV3hPEF4WLBmx9DwD2t2SYuqZ2mztYmDzZWM1", - sk: "eqJ4Bp7iN4aBXgPH0ezwSg+nVsatkYtfrXv9obI0YQ0=", - }, - { - peerId: "12D3KooWSyY7wiSiR4vbXa1WtZawi3ackMTqcQhEPrvqtagoWPny", - sk: "UVM3SBJhPYIY/gafpnd9/q/Fn9V4BE9zkgrvF1T7Pgc=", - }, - { - peerId: "12D3KooWFZmBMGG9PxTs9s6ASzkLGKJWMyPheA5ruaYc2FDkDTmv", - sk: "8RbZfEVpQhPVuhv64uqxENDuSoyJrslQoSQJznxsTQ0=", - }, - { - peerId: "12D3KooWBbhUaqqur6KHPunnKxXjY1daCtqJdy4wRji89LmAkVB4", - sk: "RbgKmG6soWW9uOi7yRedm+0Qck3f3rw6MSnDP7AcBQs=", - }, - ], + peers: [ + { + peerId: "12D3KooWJankP2PcEDYCZDdJ26JsU8BMRfdGWyGqbtFiWyoKVtmx", + sk: "dWNAHhDVuFj9bEieILMu6TcCFRxBJdOPIvAWmf4sZQI=", + }, + { + peerId: "12D3KooWSBTB5sYxdwayUyTnqopBwABsnGFY3p4dTx5hABYDtJjV", + sk: "dOmaxAeu4Th+MJ22vRDLMFTNbiDgKNXar9fW9ofAMgQ=", + }, + { + peerId: "12D3KooWQjwf781DJ41moW5RrZXypLdnTbo6aMsoA8QLctGGX8RB", + sk: "TgzaLlxXuOMDNuuuTKEHUKsW0jM4AmX0gahFvkB1KgE=", + }, + { + peerId: "12D3KooWCXWTLFyY1mqKnNAhLQTsjW1zqDzCMbUs8M4a8zdz28HK", + sk: "hiO2Ta8g2ibMQ7iu5yj9CfN+qQCwE8oRShjr7ortKww=", + }, + { + peerId: "12D3KooWPmZpf4ng6GMS39HLagxsXbjiTPLH5CFJpFAHyN6amw6V", + sk: "LzJtOHTqxfrlHDW40BKiLfjai8JU4yW6/s2zrXLCcQE=", + }, + { + peerId: "12D3KooWKrx8PZxM1R9A8tp2jmrFf6c6q1ZQiWfD4QkNgh7fWSoF", + sk: "XMhlk/xr1FPcp7sKQhS18doXlq1x16EMhBC2NGW2LQ4=", + }, + { + peerId: "12D3KooWCbJHvnzSZEXjR1UJmtSUozuJK13iRiCYHLN1gjvm4TZZ", + sk: "KXPAIqxrSHr7v0ngv3qagcqivFvnQ0xd3s1/rKmi8QU=", + }, + { + peerId: "12D3KooWEvKe7WQHp42W4xhHRgTAWQjtDWyH38uJbLHAsMuTtYvD", + sk: "GCYMAshGnsrNtrHhuT7ayzh5uCzX99J03PmAXoOcCgw=", + }, + { + peerId: "12D3KooWSznSHN3BGrSykBXkLkFsqo9SYB73wVauVdqeuRt562cC", + sk: "UP+SEuznS0h259VbFquzyOJAQ4W5iIwhP+hd1PmUQQ0=", + }, + { + peerId: "12D3KooWF57jwbShfnT3c4dNfRDdGjr6SQ3B71m87UVpEpSWHFwi", + sk: "8dl+Crm5RSh0eh+LqLKwX8/Eo4QLpvIjfD8L0wzX4A4=", + }, + { + peerId: "12D3KooWBWrzpSg9nwMLBCa2cJubUjTv63Mfy6PYg9rHGbetaV5C", + sk: "qolc1FcpJ+vHDon0HeXdUYnstjV1wiVx2p0mjblrfAg=", + }, + { + peerId: "12D3KooWNkLVU6juM8oyN2SVq5nBd2kp7Rf4uzJH1hET6vj6G5j6", + sk: "vN6QzWILTM7hSHp+iGkKxiXcqs8bzlnH3FPaRaDGSQY=", + }, + { + peerId: "12D3KooWKo1YwGL5vivPiKJMJS7wjtB6B2nJNdSXPkSABT4NKBUU", + sk: "YbDQ++bsor2kei7rYAsu2SbyoiOYPRzFRZWnNRUpBgQ=", + }, + { + peerId: "12D3KooWLUyBKmmNCyxaPkXoWcUFPcy5qrZsUo2E1tyM6CJmGJvC", + sk: "ptB9eSFMKudAtHaFgDrRK/1oIMrhBujxbMw2Pzwx/wA=", + }, + { + peerId: "12D3KooWAEZXME4KMu9FvLezsJWDbYFe2zyujyMnDT1AgcAxgcCk", + sk: "xtwTOKgAbDIgkuPf7RKiR7gYyZ1HY4mOgFMv3sOUcAQ=", + }, + { + peerId: "12D3KooWEhXetsFVAD9h2dRz9XgFpfidho1TCZVhFrczX8h8qgzY", + sk: "1I2MGuiKG1F4FDMiRihVOcOP2mxzOLWJ99MeexK27A4=", + }, + { + peerId: "12D3KooWDBfVNdMyV3hPEF4WLBmx9DwD2t2SYuqZ2mztYmDzZWM1", + sk: "eqJ4Bp7iN4aBXgPH0ezwSg+nVsatkYtfrXv9obI0YQ0=", + }, + { + peerId: "12D3KooWSyY7wiSiR4vbXa1WtZawi3ackMTqcQhEPrvqtagoWPny", + sk: "UVM3SBJhPYIY/gafpnd9/q/Fn9V4BE9zkgrvF1T7Pgc=", + }, + { + peerId: "12D3KooWFZmBMGG9PxTs9s6ASzkLGKJWMyPheA5ruaYc2FDkDTmv", + sk: "8RbZfEVpQhPVuhv64uqxENDuSoyJrslQoSQJznxsTQ0=", + }, + { + peerId: "12D3KooWBbhUaqqur6KHPunnKxXjY1daCtqJdy4wRji89LmAkVB4", + sk: "RbgKmG6soWW9uOi7yRedm+0Qck3f3rw6MSnDP7AcBQs=", + }, + ], }; export interface IEphemeralConnection extends IConnection { - readonly selfPeerId: PeerIdB58; - readonly connections: Map; - receiveParticle(particle: Particle): void; + readonly selfPeerId: PeerIdB58; + readonly connections: Map; + receiveParticle(particle: Particle): void; } export class EphemeralConnection implements IEphemeralConnection { - readonly selfPeerId: PeerIdB58; - readonly connections: Map = new Map(); + readonly selfPeerId: PeerIdB58; + readonly connections: Map = new Map(); - constructor(selfPeerId: PeerIdB58) { - this.selfPeerId = selfPeerId; - } + constructor(selfPeerId: PeerIdB58) { + this.selfPeerId = selfPeerId; + } - start(): Promise { - return Promise.resolve(); - } + start(): Promise { + return Promise.resolve(); + } - stop(): Promise { - return Promise.resolve(); - } - - connectToOther(other: IEphemeralConnection) { - if (other.selfPeerId === this.selfPeerId) { - return; - } + stop(): Promise { + return Promise.resolve(); + } - this.connections.set(other.selfPeerId, other); - other.connections.set(this.selfPeerId, this); + connectToOther(other: IEphemeralConnection) { + if (other.selfPeerId === this.selfPeerId) { + return; } - disconnectFromOther(other: IEphemeralConnection) { - this.connections.delete(other.selfPeerId); - other.connections.delete(this.selfPeerId); - } - - disconnectFromAll() { - for (const other of this.connections.values()) { - this.disconnectFromOther(other); - } - } + this.connections.set(other.selfPeerId, other); + other.connections.set(this.selfPeerId, this); + } - particleSource = new Subject(); + disconnectFromOther(other: IEphemeralConnection) { + this.connections.delete(other.selfPeerId); + other.connections.delete(this.selfPeerId); + } - receiveParticle(particle: Particle): void { - this.particleSource.next(particle); + disconnectFromAll() { + for (const other of this.connections.values()) { + this.disconnectFromOther(other); } + } - sendParticle(nextPeerIds: string[], particle: Particle): Promise { - const from = this.selfPeerId; + particleSource = new Subject(); - for (const to of nextPeerIds) { - const destConnection = this.connections.get(to); + receiveParticle(particle: Particle): void { + this.particleSource.next(particle); + } - if (destConnection === undefined) { - log.error("peer %s has no connection with %s", from, to); - continue; - } + sendParticle(nextPeerIds: string[], particle: Particle): Promise { + const from = this.selfPeerId; - // log.trace(`Sending particle from %s, to %j, particleId %s`, from, to, particle.id); - destConnection.receiveParticle(particle); - } + for (const to of nextPeerIds) { + const destConnection = this.connections.get(to); + + if (destConnection === undefined) { + log.error("peer %s has no connection with %s", from, to); + continue; + } - return Promise.resolve(); + // log.trace(`Sending particle from %s, to %j, particleId %s`, from, to, particle.id); + destConnection.receiveParticle(particle); } - getRelayPeerId(): string { - const firstMapKey = this.connections.keys().next(); + return Promise.resolve(); + } - // Empty map - if (firstMapKey.done === true) { - throw new Error( - "relay is not supported in this Ephemeral network peer", - ); - } + getRelayPeerId(): string { + const firstMapKey = this.connections.keys().next(); - return firstMapKey.value; + // Empty map + if (firstMapKey.done === true) { + throw new Error("relay is not supported in this Ephemeral network peer"); } - supportsRelay(): boolean { - return this.connections.size === 1; - } + return firstMapKey.value; + } + + supportsRelay(): boolean { + return this.connections.size === 1; + } } class EphemeralPeer extends FluencePeer { - ephemeralConnection: EphemeralConnection; + ephemeralConnection: EphemeralConnection; - constructor(keyPair: KeyPair, marine: IMarineHost) { - const conn = new EphemeralConnection(keyPair.getPeerId()); - super(DEFAULT_CONFIG, keyPair, marine, new JsServiceHost(), conn); + constructor(keyPair: KeyPair, marine: IMarineHost) { + const conn = new EphemeralConnection(keyPair.getPeerId()); + super(DEFAULT_CONFIG, keyPair, marine, new JsServiceHost(), conn); - this.ephemeralConnection = conn; - } + this.ephemeralConnection = conn; + } } /** @@ -224,109 +222,107 @@ class EphemeralPeer extends FluencePeer { * Ephemeral network is a virtual network which runs locally and focuses on p2p interaction by removing connectivity layer out of the equation. */ export class EphemeralNetwork { - private peers: Map = new Map(); + private peers: Map = new Map(); + + workerLoader: WorkerLoaderFromFs; + controlModuleLoader: WasmLoaderFromNpm; + avmModuleLoader: WasmLoaderFromNpm; + + constructor(readonly config: EphemeralConfig) { + // shared worker for all the peers + this.workerLoader = new WorkerLoaderFromFs("../../marine/worker-script"); + + this.controlModuleLoader = new WasmLoaderFromNpm( + "@fluencelabs/marine-js", + "marine-js.wasm", + ); + + this.avmModuleLoader = new WasmLoaderFromNpm( + "@fluencelabs/avm", + "avm.wasm", + ); + } + + /** + * Starts the Ephemeral network up + */ + async up(): Promise { + log.trace("starting ephemeral network up..."); + + const promises = this.config.peers.map(async (x) => { + const kp = await fromBase64Sk(x.sk); + + const marine = new MarineBackgroundRunner( + this.workerLoader, + this.controlModuleLoader, + this.avmModuleLoader, + ); + + const peerId = kp.getPeerId(); + + if (peerId !== x.peerId) { + throw new Error( + `Invalid config: peer id ${x.peerId} does not match the secret key ${x.sk}`, + ); + } - workerLoader: WorkerLoaderFromFs; - controlModuleLoader: WasmLoaderFromNpm; - avmModuleLoader: WasmLoaderFromNpm; + return new EphemeralPeer(kp, marine); + }); - constructor(readonly config: EphemeralConfig) { - // shared worker for all the peers - this.workerLoader = new WorkerLoaderFromFs( - "../../marine/worker-script", - ); + const peers = await Promise.all(promises); - this.controlModuleLoader = new WasmLoaderFromNpm( - "@fluencelabs/marine-js", - "marine-js.wasm", - ); + for (let i = 0; i < peers.length; i++) { + for (let j = 0; j < i; j++) { + if (i === j) { + continue; + } - this.avmModuleLoader = new WasmLoaderFromNpm( - "@fluencelabs/avm", - "avm.wasm", + peers[i].ephemeralConnection.connectToOther( + peers[j].ephemeralConnection, ); + } } - /** - * Starts the Ephemeral network up - */ - async up(): Promise { - log.trace("starting ephemeral network up..."); - - const promises = this.config.peers.map(async (x) => { - const kp = await fromBase64Sk(x.sk); - - const marine = new MarineBackgroundRunner( - this.workerLoader, - this.controlModuleLoader, - this.avmModuleLoader, - ); - - const peerId = kp.getPeerId(); - - if (peerId !== x.peerId) { - throw new Error( - `Invalid config: peer id ${x.peerId} does not match the secret key ${x.sk}`, - ); - } + const startPromises = peers.map((x) => { + return x.start(); + }); - return new EphemeralPeer(kp, marine); - }); - - const peers = await Promise.all(promises); - - for (let i = 0; i < peers.length; i++) { - for (let j = 0; j < i; j++) { - if (i === j) { - continue; - } - - peers[i].ephemeralConnection.connectToOther( - peers[j].ephemeralConnection, - ); - } - } + await Promise.all(startPromises); - const startPromises = peers.map((x) => { - return x.start(); - }); - - await Promise.all(startPromises); - - for (const p of peers) { - this.peers.set(p.keyPair.getPeerId(), p); - } + for (const p of peers) { + this.peers.set(p.keyPair.getPeerId(), p); } - - /** - * Shuts the ephemeral network down. Will disconnect all connected peers. - */ - async down(): Promise { - log.trace("shutting down ephemeral network..."); - const peers = Array.from(this.peers.entries()); - - const promises = peers.map(async ([, p]) => { - p.ephemeralConnection.disconnectFromAll(); - await p.stop(); - }); - - await Promise.all(promises); - this.peers.clear(); - log.trace("ephemeral network shut down"); + } + + /** + * Shuts the ephemeral network down. Will disconnect all connected peers. + */ + async down(): Promise { + log.trace("shutting down ephemeral network..."); + const peers = Array.from(this.peers.entries()); + + const promises = peers.map(async ([, p]) => { + p.ephemeralConnection.disconnectFromAll(); + await p.stop(); + }); + + await Promise.all(promises); + this.peers.clear(); + log.trace("ephemeral network shut down"); + } + + /** + * Gets a relay connection to the specified peer. + */ + getRelayConnection(peerId: PeerIdB58, relayPeerId: PeerIdB58): IConnection { + const relay = this.peers.get(relayPeerId); + + if (relay === undefined) { + throw new Error(`Peer ${relayPeerId} is not found`); } - /** - * Gets a relay connection to the specified peer. - */ - getRelayConnection(peerId: PeerIdB58, relayPeerId: PeerIdB58): IConnection { - const relay = this.peers.get(relayPeerId); - - if (relay === undefined) { - throw new Error(`Peer ${relayPeerId} is not found`); - } - - const res = new EphemeralConnection(peerId); - res.connectToOther(relay.ephemeralConnection); - return res; - } + const res = new EphemeralConnection(peerId); + res.connectToOther(relay.ephemeralConnection); + return res; + } } diff --git a/packages/core/js-client/src/fetchers/browser.ts b/packages/core/js-client/src/fetchers/browser.ts index bf00057f4..b01d5958a 100644 --- a/packages/core/js-client/src/fetchers/browser.ts +++ b/packages/core/js-client/src/fetchers/browser.ts @@ -15,8 +15,8 @@ */ interface PackageJsonContent { - dependencies: Record; - devDependencies: Record; + dependencies: Record; + devDependencies: Record; } // This will be substituted in build phase @@ -26,39 +26,36 @@ let parsedPackageJsonContent: PackageJsonContent | undefined; const PRIMARY_CDN = "https://unpkg.com/"; export async function fetchResource(pkg: string, assetPath: string) { - const packageJsonContent = - parsedPackageJsonContent ?? - // TODO: Should be validated - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - (parsedPackageJsonContent = JSON.parse( - packageJsonContentString, - ) as PackageJsonContent); - - const version = - packageJsonContent.dependencies[pkg] ?? - packageJsonContent.devDependencies[pkg]; - - if (version === undefined) { - const availableDeps = [ - ...Object.keys(packageJsonContent.dependencies), - ...Object.keys(packageJsonContent.devDependencies), - ]; - - throw new Error( - `Cannot find version of ${pkg} in package.json. Available versions: ${availableDeps.join( - ",", - )}`, - ); - } + const packageJsonContent = + parsedPackageJsonContent ?? + // TODO: Should be validated + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + (parsedPackageJsonContent = JSON.parse( + packageJsonContentString, + ) as PackageJsonContent); + + const version = + packageJsonContent.dependencies[pkg] ?? + packageJsonContent.devDependencies[pkg]; + + if (version === undefined) { + const availableDeps = [ + ...Object.keys(packageJsonContent.dependencies), + ...Object.keys(packageJsonContent.devDependencies), + ]; + + throw new Error( + `Cannot find version of ${pkg} in package.json. Available versions: ${availableDeps.join( + ",", + )}`, + ); + } - const refinedAssetPath = assetPath.startsWith("/") - ? assetPath.slice(1) - : assetPath; + const refinedAssetPath = assetPath.startsWith("/") + ? assetPath.slice(1) + : assetPath; - return fetch( - new globalThis.URL( - `${pkg}@${version}/` + refinedAssetPath, - PRIMARY_CDN, - ), - ); + return fetch( + new globalThis.URL(`${pkg}@${version}/` + refinedAssetPath, PRIMARY_CDN), + ); } diff --git a/packages/core/js-client/src/fetchers/index.ts b/packages/core/js-client/src/fetchers/index.ts index c7f8ed2a5..b0c45fb72 100644 --- a/packages/core/js-client/src/fetchers/index.ts +++ b/packages/core/js-client/src/fetchers/index.ts @@ -20,13 +20,13 @@ import { fetchResource as fetchResourceBrowser } from "./browser.js"; import { fetchResource as fetchResourceNode } from "./node.js"; const isNode = - typeof process !== "undefined" && process.release.name === "node"; + typeof process !== "undefined" && process.release.name === "node"; export async function fetchResource(pkg: string, path: string) { - switch (true) { - case isNode: - return fetchResourceNode(pkg, path); - default: - return fetchResourceBrowser(pkg, path); - } + switch (true) { + case isNode: + return fetchResourceNode(pkg, path); + default: + return fetchResourceBrowser(pkg, path); + } } diff --git a/packages/core/js-client/src/fetchers/node.ts b/packages/core/js-client/src/fetchers/node.ts index 9b15dd447..a2b3dbc86 100644 --- a/packages/core/js-client/src/fetchers/node.ts +++ b/packages/core/js-client/src/fetchers/node.ts @@ -19,41 +19,41 @@ import module from "module"; import path from "path"; export async function fetchResource(pkg: string, assetPath: string) { - const require = module.createRequire(import.meta.url); - const packagePathIndex = require.resolve(pkg); + const require = module.createRequire(import.meta.url); + const packagePathIndex = require.resolve(pkg); - // Ensure that windows path is converted to posix path. So we can find a package - const posixPath = packagePathIndex.split(path.sep).join(path.posix.sep); + // Ensure that windows path is converted to posix path. So we can find a package + const posixPath = packagePathIndex.split(path.sep).join(path.posix.sep); - const matches = new RegExp(`(.+${pkg})`).exec(posixPath); + const matches = new RegExp(`(.+${pkg})`).exec(posixPath); - const packagePath = matches?.[0]; + const packagePath = matches?.[0]; - if (packagePath == null) { - throw new Error(`Cannot find dependency ${pkg} in path ${posixPath}`); - } + if (packagePath == null) { + throw new Error(`Cannot find dependency ${pkg} in path ${posixPath}`); + } - const pathToResource = path.join(packagePath, assetPath); + const pathToResource = path.join(packagePath, assetPath); - const file = await new Promise((resolve, reject) => { - // Cannot use 'fs/promises' with current vite config. This module is not polyfilled by default. - fs.readFile(pathToResource, (err, data) => { - if (err != null) { - reject(err); - return; - } + const file = await new Promise((resolve, reject) => { + // Cannot use 'fs/promises' with current vite config. This module is not polyfilled by default. + fs.readFile(pathToResource, (err, data) => { + if (err != null) { + reject(err); + return; + } - resolve(data); - }); - }); - - return new Response(file, { - headers: { - "Content-type": assetPath.endsWith(".wasm") - ? "application/wasm" - : assetPath.endsWith(".js") - ? "application/javascript" - : "application/text", - }, + resolve(data); }); + }); + + return new Response(file, { + headers: { + "Content-type": assetPath.endsWith(".wasm") + ? "application/wasm" + : assetPath.endsWith(".js") + ? "application/javascript" + : "application/text", + }, + }); } diff --git a/packages/core/js-client/src/index.ts b/packages/core/js-client/src/index.ts index 48951997c..a2a0ba85f 100644 --- a/packages/core/js-client/src/index.ts +++ b/packages/core/js-client/src/index.ts @@ -20,10 +20,10 @@ import process from "process"; import url from "url"; import type { - ClientConfig, - ConnectionState, - IFluenceClient, - RelayOptions, + ClientConfig, + ConnectionState, + IFluenceClient, + RelayOptions, } from "@fluencelabs/interfaces"; // "threads" package has broken type definitions in package.json. This is the workaround. @@ -37,197 +37,194 @@ import { MarineBackgroundRunner } from "./marine/worker/index.js"; import { doRegisterNodeUtils } from "./services/NodeUtils.js"; const isNode = - typeof process !== "undefined" && process.release.name === "node"; + typeof process !== "undefined" && process.release.name === "node"; const fetchWorkerCode = () => { - return fetchResource( - "@fluencelabs/marine-worker", - "/dist/browser/marine-worker.umd.cjs", - ).then((res) => { - return res.text(); - }); + return fetchResource( + "@fluencelabs/marine-worker", + "/dist/browser/marine-worker.umd.cjs", + ).then((res) => { + return res.text(); + }); }; const fetchMarineJsWasm = () => { - return fetchResource("@fluencelabs/marine-js", "/dist/marine-js.wasm").then( - (res) => { - return res.arrayBuffer(); - }, - ); + return fetchResource("@fluencelabs/marine-js", "/dist/marine-js.wasm").then( + (res) => { + return res.arrayBuffer(); + }, + ); }; const fetchAvmWasm = () => { - return fetchResource("@fluencelabs/avm", "/dist/avm.wasm").then((res) => { - return res.arrayBuffer(); - }); + return fetchResource("@fluencelabs/avm", "/dist/avm.wasm").then((res) => { + return res.arrayBuffer(); + }); }; const createClient = async ( - relay: RelayOptions, - config: ClientConfig, + relay: RelayOptions, + config: ClientConfig, ): Promise => { - const marineJsWasm = await fetchMarineJsWasm(); - const avmWasm = await fetchAvmWasm(); - - const marine = new MarineBackgroundRunner( - { - async getValue() { - if (isNode) { - const require = module.createRequire(import.meta.url); - - const pathToThisFile = path.dirname( - url.fileURLToPath(import.meta.url), - ); - - const pathToWorker = require.resolve( - "@fluencelabs/marine-worker", - ); - - const relativePathToWorker = path.relative( - pathToThisFile, - pathToWorker, - ); - - return new Worker(relativePathToWorker); - } else { - const workerCode = await fetchWorkerCode(); - return BlobWorker.fromText(workerCode); - } - }, - start() { - return Promise.resolve(undefined); - }, - stop() { - return Promise.resolve(undefined); - }, - }, - { - getValue() { - return marineJsWasm; - }, - start(): Promise { - return Promise.resolve(undefined); - }, - stop(): Promise { - return Promise.resolve(undefined); - }, - }, - { - getValue() { - return avmWasm; - }, - start(): Promise { - return Promise.resolve(undefined); - }, - stop(): Promise { - return Promise.resolve(undefined); - }, - }, - ); + const marineJsWasm = await fetchMarineJsWasm(); + const avmWasm = await fetchAvmWasm(); + + const marine = new MarineBackgroundRunner( + { + async getValue() { + if (isNode) { + const require = module.createRequire(import.meta.url); + + const pathToThisFile = path.dirname( + url.fileURLToPath(import.meta.url), + ); + + const pathToWorker = require.resolve("@fluencelabs/marine-worker"); + + const relativePathToWorker = path.relative( + pathToThisFile, + pathToWorker, + ); + + return new Worker(relativePathToWorker); + } else { + const workerCode = await fetchWorkerCode(); + return BlobWorker.fromText(workerCode); + } + }, + start() { + return Promise.resolve(undefined); + }, + stop() { + return Promise.resolve(undefined); + }, + }, + { + getValue() { + return marineJsWasm; + }, + start(): Promise { + return Promise.resolve(undefined); + }, + stop(): Promise { + return Promise.resolve(undefined); + }, + }, + { + getValue() { + return avmWasm; + }, + start(): Promise { + return Promise.resolve(undefined); + }, + stop(): Promise { + return Promise.resolve(undefined); + }, + }, + ); - const { keyPair, peerConfig, relayConfig } = await makeClientPeerConfig( - relay, - config, - ); + const { keyPair, peerConfig, relayConfig } = await makeClientPeerConfig( + relay, + config, + ); - const client = new ClientPeer(peerConfig, relayConfig, keyPair, marine); + const client = new ClientPeer(peerConfig, relayConfig, keyPair, marine); - if (isNode) { - doRegisterNodeUtils(client); - } + if (isNode) { + doRegisterNodeUtils(client); + } - await client.connect(); - return client; + await client.connect(); + return client; }; /** * Public interface to Fluence Network */ interface FluencePublicApi { - defaultClient: ClientPeer | undefined; - connect: (relay: RelayOptions, config: ClientConfig) => Promise; - disconnect: () => Promise; - onConnectionStateChange: ( - handler: (state: ConnectionState) => void, - ) => ConnectionState; - getClient: () => IFluenceClient; + defaultClient: ClientPeer | undefined; + connect: (relay: RelayOptions, config: ClientConfig) => Promise; + disconnect: () => Promise; + onConnectionStateChange: ( + handler: (state: ConnectionState) => void, + ) => ConnectionState; + getClient: () => IFluenceClient; } export const Fluence: FluencePublicApi = { - defaultClient: undefined, - /** - * Connect to the Fluence network - * @param relay - relay node to connect to - * @param config - client configuration - */ - connect: async function (relay, config) { - this.defaultClient = await createClient(relay, config); - }, - - /** - * Disconnect from the Fluence network - */ - disconnect: async function (): Promise { - await this.defaultClient?.disconnect(); - this.defaultClient = undefined; - }, - - /** - * Handle connection state changes. Immediately returns the current connection state - */ - onConnectionStateChange(handler) { - return ( - this.defaultClient?.onConnectionStateChange(handler) ?? - "disconnected" - ); - }, - - /** - * Low level API. Get the underlying client instance which holds the connection to the network - * @returns IFluenceClient instance - */ - getClient: function () { - if (this.defaultClient == null) { - throw new Error( - "Fluence client is not initialized. Call Fluence.connect() first", - ); - } + defaultClient: undefined, + /** + * Connect to the Fluence network + * @param relay - relay node to connect to + * @param config - client configuration + */ + connect: async function (relay, config) { + this.defaultClient = await createClient(relay, config); + }, + + /** + * Disconnect from the Fluence network + */ + disconnect: async function (): Promise { + await this.defaultClient?.disconnect(); + this.defaultClient = undefined; + }, + + /** + * Handle connection state changes. Immediately returns the current connection state + */ + onConnectionStateChange(handler) { + return ( + this.defaultClient?.onConnectionStateChange(handler) ?? "disconnected" + ); + }, + + /** + * Low level API. Get the underlying client instance which holds the connection to the network + * @returns IFluenceClient instance + */ + getClient: function () { + if (this.defaultClient == null) { + throw new Error( + "Fluence client is not initialized. Call Fluence.connect() first", + ); + } - return this.defaultClient; - }, + return this.defaultClient; + }, }; export type { - IFluenceClient, - ClientConfig, - CallParams, + IFluenceClient, + ClientConfig, + CallParams, } from "@fluencelabs/interfaces"; export type { - ArrayType, - ArrowType, - ArrowWithCallbacks, - ArrowWithoutCallbacks, - BottomType, - FunctionCallConstants, - FunctionCallDef, - LabeledProductType, - NilType, - NonArrowType, - OptionType, - ProductType, - ScalarNames, - ScalarType, - ServiceDef, - StructType, - TopType, - UnlabeledProductType, - CallAquaFunctionType, - CallAquaFunctionArgs, - PassedArgs, - FnConfig, - RegisterServiceType, - RegisterServiceArgs, + ArrayType, + ArrowType, + ArrowWithCallbacks, + ArrowWithoutCallbacks, + BottomType, + FunctionCallConstants, + FunctionCallDef, + LabeledProductType, + NilType, + NonArrowType, + OptionType, + ProductType, + ScalarNames, + ScalarType, + ServiceDef, + StructType, + TopType, + UnlabeledProductType, + CallAquaFunctionType, + CallAquaFunctionArgs, + PassedArgs, + FnConfig, + RegisterServiceType, + RegisterServiceArgs, } from "@fluencelabs/interfaces"; export { v5_callFunction, v5_registerService } from "./api.js"; @@ -237,15 +234,15 @@ globalThis.new_fluence = Fluence; // @ts-expect-error Writing to global object like this prohibited by ts globalThis.fluence = { - clientFactory: createClient, - callAquaFunction, - registerService, + clientFactory: createClient, + callAquaFunction, + registerService, }; export { createClient, callAquaFunction, registerService }; export { - KeyPair, - fromBase64Sk, - fromBase58Sk, - fromOpts, + KeyPair, + fromBase64Sk, + fromBase58Sk, + fromOpts, } from "./keypair/index.js"; diff --git a/packages/core/js-client/src/jsPeer/FluencePeer.ts b/packages/core/js-client/src/jsPeer/FluencePeer.ts index 289584cf2..487bc875f 100644 --- a/packages/core/js-client/src/jsPeer/FluencePeer.ts +++ b/packages/core/js-client/src/jsPeer/FluencePeer.ts @@ -17,47 +17,47 @@ import { Buffer } from "buffer"; import { - deserializeAvmResult, - InterpreterResult, - KeyPairFormat, - serializeAvmArgs, + deserializeAvmResult, + InterpreterResult, + KeyPairFormat, + serializeAvmArgs, } from "@fluencelabs/avm"; import { defaultCallParameters } from "@fluencelabs/marine-js/dist/types"; import { fromUint8Array } from "js-base64"; import { - concatMap, - filter, - groupBy, - lastValueFrom, - mergeMap, - pipe, - Subject, - tap, - Unsubscribable, + concatMap, + filter, + groupBy, + lastValueFrom, + mergeMap, + pipe, + Subject, + tap, + Unsubscribable, } from "rxjs"; import { IConnection } from "../connection/interfaces.js"; import { - CallServiceData, - CallServiceResult, - IJsServiceHost, - ResultCodes, + CallServiceData, + CallServiceResult, + IJsServiceHost, + ResultCodes, } from "../jsServiceHost/interfaces.js"; import { - getParticleContext, - registerDefaultServices, - ServiceError, + getParticleContext, + registerDefaultServices, + ServiceError, } from "../jsServiceHost/serviceUtils.js"; import { KeyPair } from "../keypair/index.js"; import { IMarineHost } from "../marine/interfaces.js"; import { IParticle } from "../particle/interfaces.js"; import { - cloneWithNewData, - getActualTTL, - hasExpired, - Particle, - ParticleExecutionStage, - ParticleQueueItem, + cloneWithNewData, + getActualTTL, + hasExpired, + Particle, + ParticleExecutionStage, + ParticleQueueItem, } from "../particle/Particle.js"; import { registerSig } from "../services/_aqua/services.js"; import { registerSrv } from "../services/_aqua/single-module-srv.js"; @@ -72,30 +72,30 @@ const log_particle = logger("particle"); const log_peer = logger("peer"); export type PeerConfig = { + /** + * 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; + + /** + * Enables\disabled various debugging features + */ + debug: { /** - * 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 + * If set to true, newly initiated particle ids will be printed to console. + * Useful to see what particle id is responsible for aqua function */ - defaultTtlMs: number; - - /** - * 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; - }; + printParticleId: boolean; + }; }; export const DEFAULT_CONFIG: PeerConfig = { - debug: { - printParticleId: false, - }, - defaultTtlMs: 7000, + debug: { + printParticleId: false, + }, + defaultTtlMs: 7000, }; /** @@ -103,624 +103,606 @@ export const DEFAULT_CONFIG: PeerConfig = { * It provides all the necessary features to communicate with Fluence network */ export abstract class FluencePeer { - constructor( - protected readonly config: PeerConfig, - readonly keyPair: KeyPair, - protected readonly marineHost: IMarineHost, - protected readonly jsServiceHost: IJsServiceHost, - protected readonly connection: IConnection, - ) { - this._initServices(); + constructor( + protected readonly config: PeerConfig, + readonly keyPair: KeyPair, + protected readonly marineHost: IMarineHost, + protected readonly jsServiceHost: IJsServiceHost, + protected readonly connection: IConnection, + ) { + this._initServices(); + } + + async start(): Promise { + log_peer.trace("starting Fluence peer"); + + if (this.config.debug.printParticleId) { + this.printParticleId = true; } - async start(): Promise { - log_peer.trace("starting Fluence peer"); + await this.marineHost.start(); + + this._startParticleProcessing(); + this.isInitialized = true; + await this.connection.start(); + log_peer.trace("started Fluence peer"); + } + + /** + * Un-initializes the peer: stops all the underlying workflows, stops the Aqua VM + * and disconnects from the Fluence network + */ + async stop() { + log_peer.trace("stopping Fluence peer"); + + this._particleSourceSubscription?.unsubscribe(); + + log_peer.trace("Waiting for all particles to finish execution"); + this._incomingParticles.complete(); + await this._incomingParticlePromise; + log_peer.trace("All particles finished execution"); + + this._stopParticleProcessing(); + await this.marineHost.stop(); + await this.connection.stop(); + this.isInitialized = false; + log_peer.trace("stopped Fluence peer"); + } + + /** + * Registers marine service within the Fluence peer from wasm file. + * Following helper functions can be used to load wasm files: + * * loadWasmFromFileSystem + * * loadWasmFromNpmPackage + * * loadWasmFromServer + * @param wasm - buffer with the wasm file for service + * @param serviceId - the service id by which the service can be accessed in aqua + */ + async registerMarineService( + wasm: SharedArrayBuffer | Buffer, + serviceId: string, + ): Promise { + if (this.jsServiceHost.hasService(serviceId)) { + throw new Error(`Service with '${serviceId}' id already exists`); + } - if (this.config.debug.printParticleId) { - this.printParticleId = true; + await this.marineHost.createService(wasm, serviceId); + } + + /** + * Removes the specified marine service from the Fluence peer + * @param serviceId - the service id to remove + */ + async removeMarineService(serviceId: string): Promise { + await this.marineHost.removeService(serviceId); + } + + /** + * @private Is not intended to be used manually. Subject to change + */ + get internals() { + return { + getServices: () => { + return this._classServices; + }, + + getRelayPeerId: () => { + if (this.connection.supportsRelay()) { + return this.connection.getRelayPeerId(); } - await this.marineHost.start(); + throw new Error("Relay is not supported by the current connection"); + }, - this._startParticleProcessing(); - this.isInitialized = true; - await this.connection.start(); - log_peer.trace("started Fluence peer"); - } - - /** - * Un-initializes the peer: stops all the underlying workflows, stops the Aqua VM - * and disconnects from the Fluence network - */ - async stop() { - log_peer.trace("stopping Fluence peer"); + parseAst: async ( + air: string, + ): Promise<{ success: boolean; data: unknown }> => { + if (!this.isInitialized) { + new Error("Can't use avm: peer is not initialized"); + } - this._particleSourceSubscription?.unsubscribe(); + const res = await this.marineHost.callService( + "avm", + "ast", + [air], + defaultCallParameters, + ); - log_peer.trace("Waiting for all particles to finish execution"); - this._incomingParticles.complete(); - await this._incomingParticlePromise; - log_peer.trace("All particles finished execution"); + if (!isString(res)) { + throw new Error( + `Call to avm:ast expected to return string. Actual return: ${JSON.stringify( + res, + )}`, + ); + } - this._stopParticleProcessing(); - await this.marineHost.stop(); - await this.connection.stop(); - this.isInitialized = false; - log_peer.trace("stopped Fluence peer"); - } + try { + if (res.startsWith("error")) { + return { + success: false, + data: res, + }; + } else { + return { + success: true, + data: JSON.parse(res), + }; + } + } catch (err) { + throw new Error( + "Failed to call avm. Result: " + + res + + ". Error: " + + getErrorMessage(err), + ); + } + }, + + createNewParticle: ( + script: string, + ttl: number = this.config.defaultTtlMs, + ): Promise => { + return Particle.createNew( + script, + this.keyPair.getPeerId(), + ttl, + this.keyPair, + ); + }, + + /** + * Initiates a new particle execution starting from local peer + * @param particle - particle to start execution of + * @param onStageChange - callback for reacting on particle state changes + */ + initiateParticle: ( + particle: IParticle, + onStageChange: (stage: ParticleExecutionStage) => void, + ): void => { + if (!this.isInitialized) { + throw new Error( + "Cannot initiate new particle: peer is not initialized", + ); + } - /** - * Registers marine service within the Fluence peer from wasm file. - * Following helper functions can be used to load wasm files: - * * loadWasmFromFileSystem - * * loadWasmFromNpmPackage - * * loadWasmFromServer - * @param wasm - buffer with the wasm file for service - * @param serviceId - the service id by which the service can be accessed in aqua - */ - async registerMarineService( - wasm: SharedArrayBuffer | Buffer, - serviceId: string, - ): Promise { - if (this.jsServiceHost.hasService(serviceId)) { - throw new Error(`Service with '${serviceId}' id already exists`); + if (this.printParticleId) { + // This is intended console-log + // eslint-disable-next-line no-console + console.log("Particle id: ", particle.id); } - await this.marineHost.createService(wasm, serviceId); - } + this._incomingParticles.next({ + particle: particle, + callResults: [], + onStageChange: onStageChange, + }); + }, - /** - * Removes the specified marine service from the Fluence peer - * @param serviceId - the service id to remove - */ - async removeMarineService(serviceId: string): Promise { - await this.marineHost.removeService(serviceId); - } + /** + * Register Call Service handler functions + */ + regHandler: { + /** + * Register handler for all particles + */ + common: this.jsServiceHost.registerGlobalHandler.bind( + this.jsServiceHost, + ), + /** + * Register handler which will be called only for particle with the specific id + */ + forParticle: this.jsServiceHost.registerParticleScopeHandler.bind( + this.jsServiceHost, + ), + }, + }; + } - /** - * @private Is not intended to be used manually. Subject to change - */ - get internals() { - return { - getServices: () => { - return this._classServices; - }, - - getRelayPeerId: () => { - if (this.connection.supportsRelay()) { - return this.connection.getRelayPeerId(); - } + // Queues for incoming and outgoing particles - throw new Error( - "Relay is not supported by the current connection", - ); - }, + private _incomingParticles = new Subject(); + private _timeouts: Array = []; + private _particleSourceSubscription?: Unsubscribable; + private _incomingParticlePromise?: Promise; - parseAst: async ( - air: string, - ): Promise<{ success: boolean; data: unknown }> => { - if (!this.isInitialized) { - new Error("Can't use avm: peer is not initialized"); - } + // Internal peer state - const res = await this.marineHost.callService( - "avm", - "ast", - [air], - defaultCallParameters, - ); + // @ts-expect-error - initialized in constructor through `_initServices` call + private _classServices: { + sig: Sig; + srv: Srv; + tracing: Tracing; + }; - if (!isString(res)) { - throw new Error( - `Call to avm:ast expected to return string. Actual return: ${JSON.stringify( - res, - )}`, - ); - } + private isInitialized = false; + private printParticleId = false; - try { - if (res.startsWith("error")) { - return { - success: false, - data: res, - }; - } else { - return { - success: true, - data: JSON.parse(res), - }; - } - } catch (err) { - throw new Error( - "Failed to call avm. Result: " + - res + - ". Error: " + - getErrorMessage(err), - ); - } - }, - - createNewParticle: ( - script: string, - ttl: number = this.config.defaultTtlMs, - ): Promise => { - return Particle.createNew( - script, - this.keyPair.getPeerId(), - ttl, - this.keyPair, + private _initServices() { + this._classServices = { + sig: new Sig(this.keyPair), + srv: new Srv(this), + tracing: new Tracing(), + }; + + const peerId = this.keyPair.getPeerId(); + + registerDefaultServices(this); + + this._classServices.sig.securityGuard = defaultSigGuard(peerId); + registerSig(this, "sig", this._classServices.sig); + registerSig(this, peerId, this._classServices.sig); + registerSrv(this, "single_module_srv", this._classServices.srv); + registerTracing(this, "tracingSrv", this._classServices.tracing); + } + + private _startParticleProcessing() { + this._particleSourceSubscription = this.connection.particleSource.subscribe( + { + next: (p) => { + this._incomingParticles.next({ + particle: p, + callResults: [], + onStageChange: () => {}, + }); + }, + }, + ); + + this._incomingParticlePromise = lastValueFrom( + this._incomingParticles.pipe( + tap((item) => { + log_particle.debug("id %s. received:", item.particle.id); + + log_particle.trace("id %s. data: %j", item.particle.id, { + initPeerId: item.particle.initPeerId, + timestamp: item.particle.timestamp, + ttl: item.particle.ttl, + signature: item.particle.signature, + }); + + log_particle.trace( + "id %s. script: %s", + item.particle.id, + item.particle.script, + ); + + log_particle.trace( + "id %s. call results: %j", + item.particle.id, + item.callResults, + ); + }), + filterExpiredParticles(this._expireParticle.bind(this)), + groupBy((item) => { + return fromUint8Array(item.particle.signature); + }), + mergeMap((group$) => { + let prevData: Uint8Array = Buffer.from([]); + let firstRun = true; + + return group$.pipe( + concatMap(async (item) => { + if (firstRun) { + const timeout = setTimeout(() => { + this._expireParticle(item); + }, getActualTTL(item.particle)); + + this._timeouts.push(timeout); + firstRun = false; + } + + if (!this.isInitialized) { + // If `.stop()` was called return null to stop particle processing immediately + return null; + } + + // IMPORTANT! + // AVM runner execution and prevData <-> newData swapping + // MUST happen sequentially (in a critical section). + // Otherwise the race might occur corrupting the prevData + + log_particle.debug( + "id %s. sending particle to interpreter", + item.particle.id, + ); + + log_particle.trace( + "id %s. prevData: %s", + item.particle.id, + this.decodeAvmData(prevData).slice(0, 50), + ); + + const args = serializeAvmArgs( + { + initPeerId: item.particle.initPeerId, + currentPeerId: this.keyPair.getPeerId(), + timestamp: item.particle.timestamp, + ttl: item.particle.ttl, + keyFormat: KeyPairFormat.Ed25519, + particleId: item.particle.id, + secretKeyBytes: this.keyPair.toEd25519PrivateKey(), + }, + item.particle.script, + prevData, + item.particle.data, + item.callResults, + ); + + let avmCallResult: InterpreterResult | Error; + + try { + const res = await this.marineHost.callService( + "avm", + "invoke", + args, + defaultCallParameters, ); - }, - - /** - * Initiates a new particle execution starting from local peer - * @param particle - particle to start execution of - * @param onStageChange - callback for reacting on particle state changes - */ - initiateParticle: ( - particle: IParticle, - onStageChange: (stage: ParticleExecutionStage) => void, - ): void => { - if (!this.isInitialized) { - throw new Error( - "Cannot initiate new particle: peer is not initialized", - ); - } - if (this.printParticleId) { - // This is intended console-log - // eslint-disable-next-line no-console - console.log("Particle id: ", particle.id); - } + avmCallResult = deserializeAvmResult(res); + } catch (e) { + avmCallResult = e instanceof Error ? e : new Error(String(e)); + } + + if ( + !(avmCallResult instanceof Error) && + avmCallResult.retCode === 0 + ) { + const newData = Buffer.from(avmCallResult.data); + prevData = newData; + } + + return { + ...item, + result: avmCallResult, + }; + }), + filter((item): item is NonNullable => { + return item !== null; + }), + filterExpiredParticles< + ParticleQueueItem & { + result: Error | InterpreterResult; + } + >(this._expireParticle.bind(this)), + mergeMap(async (item) => { + // If peer was stopped, do not proceed further + if (!this.isInitialized) { + return; + } + + // Do not continue if there was an error in particle interpretation + if (item.result instanceof Error) { + log_particle.error( + "id %s. interpreter failed: %s", + item.particle.id, + item.result.message, + ); - this._incomingParticles.next({ - particle: particle, - callResults: [], - onStageChange: onStageChange, + item.onStageChange({ + stage: "interpreterError", + errorMessage: item.result.message, }); - }, - - /** - * Register Call Service handler functions - */ - regHandler: { - /** - * Register handler for all particles - */ - common: this.jsServiceHost.registerGlobalHandler.bind( - this.jsServiceHost, - ), - /** - * Register handler which will be called only for particle with the specific id - */ - forParticle: - this.jsServiceHost.registerParticleScopeHandler.bind( - this.jsServiceHost, - ), - }, - }; - } - // Queues for incoming and outgoing particles + return; + } - private _incomingParticles = new Subject(); - private _timeouts: Array = []; - private _particleSourceSubscription?: Unsubscribable; - private _incomingParticlePromise?: Promise; + if (item.result.retCode !== 0) { + log_particle.error( + "id %s. interpreter failed: retCode: %d, message: %s", + item.particle.id, + item.result.retCode, + item.result.errorMessage, + ); - // Internal peer state + log_particle.trace( + "id %s. avm data: %s", + item.particle.id, + this.decodeAvmData(item.result.data), + ); - // @ts-expect-error - initialized in constructor through `_initServices` call - private _classServices: { - sig: Sig; - srv: Srv; - tracing: Tracing; - }; + item.onStageChange({ + stage: "interpreterError", + errorMessage: item.result.errorMessage, + }); - private isInitialized = false; - private printParticleId = false; + return; + } - private _initServices() { - this._classServices = { - sig: new Sig(this.keyPair), - srv: new Srv(this), - tracing: new Tracing(), - }; + log_particle.trace( + "id %s. interpreter result: retCode: %d, avm data: %s", + item.particle.id, + item.result.retCode, + this.decodeAvmData(item.result.data), + ); - const peerId = this.keyPair.getPeerId(); + setTimeout(() => { + item.onStageChange({ stage: "interpreted" }); + }, 0); - registerDefaultServices(this); + let connectionPromise: Promise = Promise.resolve(); - this._classServices.sig.securityGuard = defaultSigGuard(peerId); - registerSig(this, "sig", this._classServices.sig); - registerSig(this, peerId, this._classServices.sig); - registerSrv(this, "single_module_srv", this._classServices.srv); - registerTracing(this, "tracingSrv", this._classServices.tracing); - } + // send particle further if requested + if (item.result.nextPeerPks.length > 0) { + const newParticle = cloneWithNewData( + item.particle, + Buffer.from(item.result.data), + ); - private _startParticleProcessing() { - this._particleSourceSubscription = - this.connection.particleSource.subscribe({ - next: (p) => { - this._incomingParticles.next({ - particle: p, - callResults: [], - onStageChange: () => {}, - }); - }, - }); - - this._incomingParticlePromise = lastValueFrom( - this._incomingParticles.pipe( - tap((item) => { - log_particle.debug("id %s. received:", item.particle.id); - - log_particle.trace("id %s. data: %j", item.particle.id, { - initPeerId: item.particle.initPeerId, - timestamp: item.particle.timestamp, - ttl: item.particle.ttl, - signature: item.particle.signature, - }); + log_particle.debug( + "id %s. sending particle into network. Next peer ids: %s", + newParticle.id, + item.result.nextPeerPks.toString(), + ); + connectionPromise = this.connection + .sendParticle(item.result.nextPeerPks, newParticle) + .then(() => { log_particle.trace( - "id %s. script: %s", - item.particle.id, - item.particle.script, + "id %s. send successful", + newParticle.id, ); - log_particle.trace( - "id %s. call results: %j", - item.particle.id, - item.callResults, + item.onStageChange({ stage: "sent" }); + }) + .catch((e: unknown) => { + log_particle.error( + "id %s. send failed %j", + newParticle.id, + e, ); - }), - filterExpiredParticles(this._expireParticle.bind(this)), - groupBy((item) => { - return fromUint8Array(item.particle.signature); - }), - mergeMap((group$) => { - let prevData: Uint8Array = Buffer.from([]); - let firstRun = true; - - return group$.pipe( - concatMap(async (item) => { - if (firstRun) { - const timeout = setTimeout(() => { - this._expireParticle(item); - }, getActualTTL(item.particle)); - - this._timeouts.push(timeout); - firstRun = false; - } - - if (!this.isInitialized) { - // If `.stop()` was called return null to stop particle processing immediately - return null; - } - - // IMPORTANT! - // AVM runner execution and prevData <-> newData swapping - // MUST happen sequentially (in a critical section). - // Otherwise the race might occur corrupting the prevData - - log_particle.debug( - "id %s. sending particle to interpreter", - item.particle.id, - ); - - log_particle.trace( - "id %s. prevData: %s", - item.particle.id, - this.decodeAvmData(prevData).slice(0, 50), - ); - - const args = serializeAvmArgs( - { - initPeerId: item.particle.initPeerId, - currentPeerId: this.keyPair.getPeerId(), - timestamp: item.particle.timestamp, - ttl: item.particle.ttl, - keyFormat: KeyPairFormat.Ed25519, - particleId: item.particle.id, - secretKeyBytes: - this.keyPair.toEd25519PrivateKey(), - }, - item.particle.script, - prevData, - item.particle.data, - item.callResults, - ); - - let avmCallResult: InterpreterResult | Error; - - try { - const res = await this.marineHost.callService( - "avm", - "invoke", - args, - defaultCallParameters, - ); - - avmCallResult = deserializeAvmResult(res); - } catch (e) { - avmCallResult = - e instanceof Error - ? e - : new Error(String(e)); - } - - if ( - !(avmCallResult instanceof Error) && - avmCallResult.retCode === 0 - ) { - const newData = Buffer.from(avmCallResult.data); - prevData = newData; - } - - return { - ...item, - result: avmCallResult, - }; - }), - filter((item): item is NonNullable => { - return item !== null; - }), - filterExpiredParticles< - ParticleQueueItem & { - result: Error | InterpreterResult; - } - >(this._expireParticle.bind(this)), - mergeMap(async (item) => { - // If peer was stopped, do not proceed further - if (!this.isInitialized) { - return; - } - - // Do not continue if there was an error in particle interpretation - if (item.result instanceof Error) { - log_particle.error( - "id %s. interpreter failed: %s", - item.particle.id, - item.result.message, - ); - - item.onStageChange({ - stage: "interpreterError", - errorMessage: item.result.message, - }); - - return; - } - - if (item.result.retCode !== 0) { - log_particle.error( - "id %s. interpreter failed: retCode: %d, message: %s", - item.particle.id, - item.result.retCode, - item.result.errorMessage, - ); - - log_particle.trace( - "id %s. avm data: %s", - item.particle.id, - this.decodeAvmData(item.result.data), - ); - - item.onStageChange({ - stage: "interpreterError", - errorMessage: item.result.errorMessage, - }); - - return; - } - - log_particle.trace( - "id %s. interpreter result: retCode: %d, avm data: %s", - item.particle.id, - item.result.retCode, - this.decodeAvmData(item.result.data), - ); - - setTimeout(() => { - item.onStageChange({ stage: "interpreted" }); - }, 0); - - let connectionPromise: Promise = - Promise.resolve(); - - // send particle further if requested - if (item.result.nextPeerPks.length > 0) { - const newParticle = cloneWithNewData( - item.particle, - Buffer.from(item.result.data), - ); - - log_particle.debug( - "id %s. sending particle into network. Next peer ids: %s", - newParticle.id, - item.result.nextPeerPks.toString(), - ); - - connectionPromise = this.connection - .sendParticle( - item.result.nextPeerPks, - newParticle, - ) - .then(() => { - log_particle.trace( - "id %s. send successful", - newParticle.id, - ); - - item.onStageChange({ stage: "sent" }); - }) - .catch((e: unknown) => { - log_particle.error( - "id %s. send failed %j", - newParticle.id, - e, - ); - - item.onStageChange({ - stage: "sendingError", - errorMessage: getErrorMessage(e), - }); - }); - } - - // execute call requests if needed - // and put particle with the results back to queue - if (item.result.callRequests.length > 0) { - for (const [key, cr] of item.result - .callRequests) { - const req = { - fnName: cr.functionName, - args: cr.arguments, - serviceId: cr.serviceId, - tetraplets: cr.tetraplets, - particleContext: getParticleContext( - item.particle, - ), - }; - - void this._execSingleCallRequest(req) - .catch((err): CallServiceResult => { - if (err instanceof ServiceError) { - return { - retCode: ResultCodes.error, - result: err.message, - }; - } - - return { - retCode: ResultCodes.error, - result: `Service call failed. fnName="${ - req.fnName - }" serviceId="${ - req.serviceId - }" error: ${getErrorMessage( - err, - )}`, - }; - }) - .then((res) => { - const serviceResult = { - result: jsonify(res.result), - retCode: res.retCode, - }; - - const newParticle = - cloneWithNewData( - item.particle, - Buffer.from([]), - ); - - this._incomingParticles.next({ - ...item, - particle: newParticle, - callResults: [ - [key, serviceResult], - ], - }); - }); - } - } else { - item.onStageChange({ stage: "localWorkDone" }); - } - - return connectionPromise; - }), - ); - }), - ), - { defaultValue: undefined }, - ); - } - - private _expireParticle(item: ParticleQueueItem) { - const particleId = item.particle.id; - log_particle.debug( - "id %s. particle has expired after %d. Deleting particle-related queues and handlers", - item.particle.id, - item.particle.ttl, - ); + item.onStageChange({ + stage: "sendingError", + errorMessage: getErrorMessage(e), + }); + }); + } + + // execute call requests if needed + // and put particle with the results back to queue + if (item.result.callRequests.length > 0) { + for (const [key, cr] of item.result.callRequests) { + const req = { + fnName: cr.functionName, + args: cr.arguments, + serviceId: cr.serviceId, + tetraplets: cr.tetraplets, + particleContext: getParticleContext(item.particle), + }; + + void this._execSingleCallRequest(req) + .catch((err): CallServiceResult => { + if (err instanceof ServiceError) { + return { + retCode: ResultCodes.error, + result: err.message, + }; + } + + return { + retCode: ResultCodes.error, + result: `Service call failed. fnName="${ + req.fnName + }" serviceId="${ + req.serviceId + }" error: ${getErrorMessage(err)}`, + }; + }) + .then((res) => { + const serviceResult = { + result: jsonify(res.result), + retCode: res.retCode, + }; + + const newParticle = cloneWithNewData( + item.particle, + Buffer.from([]), + ); + + this._incomingParticles.next({ + ...item, + particle: newParticle, + callResults: [[key, serviceResult]], + }); + }); + } + } else { + item.onStageChange({ stage: "localWorkDone" }); + } - this.jsServiceHost.removeParticleScopeHandlers(particleId); + return connectionPromise; + }), + ); + }), + ), + { defaultValue: undefined }, + ); + } - item.onStageChange({ stage: "expired" }); - } + private _expireParticle(item: ParticleQueueItem) { + const particleId = item.particle.id; - private decodeAvmData(data: Uint8Array) { - return new TextDecoder().decode(data.buffer); - } + log_particle.debug( + "id %s. particle has expired after %d. Deleting particle-related queues and handlers", + item.particle.id, + item.particle.ttl, + ); - private async _execSingleCallRequest( - req: CallServiceData, - ): Promise { - const particleId = req.particleContext.particleId; + this.jsServiceHost.removeParticleScopeHandlers(particleId); - log_particle.trace( - "id %s. executing call service handler %j", - particleId, - req, - ); + item.onStageChange({ stage: "expired" }); + } - if (await this.marineHost.hasService(req.serviceId)) { - // TODO build correct CallParameters instead of default ones - const result = await this.marineHost.callService( - req.serviceId, - req.fnName, - req.args, - defaultCallParameters, - ); + private decodeAvmData(data: Uint8Array) { + return new TextDecoder().decode(data.buffer); + } - return { - retCode: ResultCodes.success, - result: result, - }; - } + private async _execSingleCallRequest( + req: CallServiceData, + ): Promise { + const particleId = req.particleContext.particleId; - let res = await this.jsServiceHost.callService(req); + log_particle.trace( + "id %s. executing call service handler %j", + particleId, + req, + ); - if (res === null) { - res = { - retCode: ResultCodes.error, - result: `No service found for service call: serviceId='${ - req.serviceId - }', fnName='${req.fnName}' args='${jsonify(req.args)}'`, - }; - } + if (await this.marineHost.hasService(req.serviceId)) { + // TODO build correct CallParameters instead of default ones + const result = await this.marineHost.callService( + req.serviceId, + req.fnName, + req.args, + defaultCallParameters, + ); + + return { + retCode: ResultCodes.success, + result: result, + }; + } - log_particle.trace( - "id %s. executed call service handler, req: %j, res: %j ", - particleId, - req, - res, - ); + let res = await this.jsServiceHost.callService(req); - return res; + if (res === null) { + res = { + retCode: ResultCodes.error, + result: `No service found for service call: serviceId='${ + req.serviceId + }', fnName='${req.fnName}' args='${jsonify(req.args)}'`, + }; } - private _stopParticleProcessing() { - // do not hang if the peer has been stopped while some of the timeouts are still being executed - this._timeouts.forEach((timeout) => { - clearTimeout(timeout); - }); - } + log_particle.trace( + "id %s. executed call service handler, req: %j, res: %j ", + particleId, + req, + res, + ); + + return res; + } + + private _stopParticleProcessing() { + // do not hang if the peer has been stopped while some of the timeouts are still being executed + this._timeouts.forEach((timeout) => { + clearTimeout(timeout); + }); + } } function filterExpiredParticles( - onParticleExpiration: (item: T) => void, + onParticleExpiration: (item: T) => void, ) { - return pipe( - tap((item: T) => { - if (hasExpired(item.particle)) { - onParticleExpiration(item); - } - }), - filter((x) => { - return !hasExpired(x.particle); - }), - ); + return pipe( + tap((item: T) => { + if (hasExpired(item.particle)) { + onParticleExpiration(item); + } + }), + filter((x) => { + return !hasExpired(x.particle); + }), + ); } diff --git a/packages/core/js-client/src/jsPeer/__test__/avm.spec.ts b/packages/core/js-client/src/jsPeer/__test__/avm.spec.ts index c063b725f..8743328ab 100644 --- a/packages/core/js-client/src/jsPeer/__test__/avm.spec.ts +++ b/packages/core/js-client/src/jsPeer/__test__/avm.spec.ts @@ -21,42 +21,39 @@ import { handleTimeout } from "../../particle/Particle.js"; import { registerHandlersHelper, withPeer } from "../../util/testUtils.js"; describe("Basic AVM functionality in Fluence Peer tests", () => { - it("Simple call", async () => { - await withPeer(async (peer) => { - const script = ` + it("Simple call", async () => { + await withPeer(async (peer) => { + const script = ` (call %init_peer_id% ("print" "print") ["1"]) `; - const particle = await peer.internals.createNewParticle(script); - - const res = await new Promise((resolve, reject) => { - if (particle instanceof Error) { - reject(particle.message); - return; - } - - registerHandlersHelper(peer, particle, { - print: { - print: (args) => { - const [res] = args; - resolve(res); - }, - }, - }); - - peer.internals.initiateParticle( - particle, - handleTimeout(reject), - ); - }); - - expect(res).toBe("1"); + const particle = await peer.internals.createNewParticle(script); + + const res = await new Promise((resolve, reject) => { + if (particle instanceof Error) { + reject(particle.message); + return; + } + + registerHandlersHelper(peer, particle, { + print: { + print: (args) => { + const [res] = args; + resolve(res); + }, + }, }); + + peer.internals.initiateParticle(particle, handleTimeout(reject)); + }); + + expect(res).toBe("1"); }); + }); - it("Par call", async () => { - await withPeer(async (peer) => { - const script = ` + it("Par call", async () => { + await withPeer(async (peer) => { + const script = ` (seq (par (call %init_peer_id% ("print" "print") ["1"]) @@ -66,41 +63,38 @@ describe("Basic AVM functionality in Fluence Peer tests", () => { ) `; - const particle = await peer.internals.createNewParticle(script); + const particle = await peer.internals.createNewParticle(script); - const res = await new Promise((resolve, reject) => { - const res: JSONValue[] = []; + const res = await new Promise((resolve, reject) => { + const res: JSONValue[] = []; - if (particle instanceof Error) { - reject(particle.message); - return; - } + if (particle instanceof Error) { + reject(particle.message); + return; + } - registerHandlersHelper(peer, particle, { - print: { - print: (args) => { - res.push(args[0]); + registerHandlersHelper(peer, particle, { + print: { + print: (args) => { + res.push(args[0]); - if (res.length === 2) { - resolve(res); - } - }, - }, - }); + if (res.length === 2) { + resolve(res); + } + }, + }, + }); - peer.internals.initiateParticle( - particle, - handleTimeout(reject), - ); - }); + peer.internals.initiateParticle(particle, handleTimeout(reject)); + }); - expect(res).toStrictEqual(["1", "2"]); - }); + expect(res).toStrictEqual(["1", "2"]); }); + }); - it("Timeout in par call: race", async () => { - await withPeer(async (peer) => { - const script = ` + it("Timeout in par call: race", async () => { + await withPeer(async (peer) => { + const script = ` (seq (call %init_peer_id% ("op" "identity") ["slow_result"] arg) (seq @@ -116,35 +110,32 @@ describe("Basic AVM functionality in Fluence Peer tests", () => { ) `; - const particle = await peer.internals.createNewParticle(script); - - const res = await new Promise((resolve, reject) => { - if (particle instanceof Error) { - reject(particle.message); - return; - } - - registerHandlersHelper(peer, particle, { - return: { - return: (args) => { - resolve(args[0]); - }, - }, - }); - - peer.internals.initiateParticle( - particle, - handleTimeout(reject), - ); - }); - - expect(res).toBe("fast_result"); + const particle = await peer.internals.createNewParticle(script); + + const res = await new Promise((resolve, reject) => { + if (particle instanceof Error) { + reject(particle.message); + return; + } + + registerHandlersHelper(peer, particle, { + return: { + return: (args) => { + resolve(args[0]); + }, + }, }); + + peer.internals.initiateParticle(particle, handleTimeout(reject)); + }); + + expect(res).toBe("fast_result"); }); + }); - it("Timeout in par call: wait", async () => { - await withPeer(async (peer) => { - const script = ` + it("Timeout in par call: wait", async () => { + await withPeer(async (peer) => { + const script = ` (seq (call %init_peer_id% ("op" "identity") ["timeout_msg"] arg) (seq @@ -171,29 +162,26 @@ describe("Basic AVM functionality in Fluence Peer tests", () => { ) `; - const particle = await peer.internals.createNewParticle(script); - - const res = await new Promise((resolve, reject) => { - if (particle instanceof Error) { - reject(particle.message); - return; - } - - registerHandlersHelper(peer, particle, { - return: { - return: (args) => { - resolve(args[0]); - }, - }, - }); - - peer.internals.initiateParticle( - particle, - handleTimeout(reject), - ); - }); - - expect(res).toBe("failed_with_timeout"); + const particle = await peer.internals.createNewParticle(script); + + const res = await new Promise((resolve, reject) => { + if (particle instanceof Error) { + reject(particle.message); + return; + } + + registerHandlersHelper(peer, particle, { + return: { + return: (args) => { + resolve(args[0]); + }, + }, }); + + peer.internals.initiateParticle(particle, handleTimeout(reject)); + }); + + expect(res).toBe("failed_with_timeout"); }); + }); }); diff --git a/packages/core/js-client/src/jsPeer/__test__/par.spec.ts b/packages/core/js-client/src/jsPeer/__test__/par.spec.ts index e772730e7..66ee5d1d3 100644 --- a/packages/core/js-client/src/jsPeer/__test__/par.spec.ts +++ b/packages/core/js-client/src/jsPeer/__test__/par.spec.ts @@ -20,16 +20,16 @@ import { JSONValue } from "@fluencelabs/interfaces"; import { describe, expect, it } from "vitest"; import { - CallServiceData, - ResultCodes, + CallServiceData, + ResultCodes, } from "../../jsServiceHost/interfaces.js"; import { handleTimeout } from "../../particle/Particle.js"; import { registerHandlersHelper, withPeer } from "../../util/testUtils.js"; describe("FluencePeer flow tests", () => { - it("should execute par instruction in parallel", async function () { - await withPeer(async (peer) => { - const script = ` + it("should execute par instruction in parallel", async function () { + await withPeer(async (peer) => { + const script = ` (par (seq (call %init_peer_id% ("flow" "timeout") [1000 "test1"] res1) @@ -42,65 +42,62 @@ describe("FluencePeer flow tests", () => { ) `; - const particle = await peer.internals.createNewParticle(script); + const particle = await peer.internals.createNewParticle(script); - const res = await new Promise((resolve, reject) => { - peer.internals.regHandler.forParticle( - particle.id, - "flow", - "timeout", - (req: CallServiceData) => { - const [timeout, message] = req.args; - assert(typeof timeout === "number"); + const res = await new Promise((resolve, reject) => { + peer.internals.regHandler.forParticle( + particle.id, + "flow", + "timeout", + (req: CallServiceData) => { + const [timeout, message] = req.args; + assert(typeof timeout === "number"); - return new Promise((resolve) => { - setTimeout(() => { - const res = { - result: message, - retCode: ResultCodes.success, - }; + return new Promise((resolve) => { + setTimeout(() => { + const res = { + result: message, + retCode: ResultCodes.success, + }; - resolve(res); - }, timeout); - }); - }, - ); + resolve(res); + }, timeout); + }); + }, + ); - if (particle instanceof Error) { - reject(particle.message); - return; - } + if (particle instanceof Error) { + reject(particle.message); + return; + } - const values: JSONValue[] = []; + const values: JSONValue[] = []; - registerHandlersHelper(peer, particle, { - callback: { - callback1: (args) => { - const [val] = args; - values.push(val); + registerHandlersHelper(peer, particle, { + callback: { + callback1: (args) => { + const [val] = args; + values.push(val); - if (values.length === 2) { - resolve(values); - } - }, - callback2: (args) => { - const [val] = args; - values.push(val); + if (values.length === 2) { + resolve(values); + } + }, + callback2: (args) => { + const [val] = args; + values.push(val); - if (values.length === 2) { - resolve(values); - } - }, - }, - }); + if (values.length === 2) { + resolve(values); + } + }, + }, + }); - peer.internals.initiateParticle( - particle, - handleTimeout(reject), - ); - }); + peer.internals.initiateParticle(particle, handleTimeout(reject)); + }); - expect(res).toEqual(expect.arrayContaining(["test1", "test1"])); - }); - }, 1500); + expect(res).toEqual(expect.arrayContaining(["test1", "test1"])); + }); + }, 1500); }); diff --git a/packages/core/js-client/src/jsPeer/__test__/parseAst.spec.ts b/packages/core/js-client/src/jsPeer/__test__/parseAst.spec.ts index ac0c67a4d..2249bb117 100644 --- a/packages/core/js-client/src/jsPeer/__test__/parseAst.spec.ts +++ b/packages/core/js-client/src/jsPeer/__test__/parseAst.spec.ts @@ -19,28 +19,28 @@ import { it, describe, expect } from "vitest"; import { withPeer } from "../../util/testUtils.js"; describe("Parse ast tests", () => { - it("Correct ast should be parsed correctly", async () => { - await withPeer(async (peer) => { - const air = `(null)`; - const res = await peer.internals.parseAst(air); + it("Correct ast should be parsed correctly", async () => { + await withPeer(async (peer) => { + const air = `(null)`; + const res = await peer.internals.parseAst(air); - expect(res).toStrictEqual({ - success: true, - data: { Null: null }, - }); - }); + expect(res).toStrictEqual({ + success: true, + data: { Null: null }, + }); }); + }); - it("Incorrect ast should result in corresponding error", async () => { - await withPeer(async (peer) => { - const air = `(null`; - const res = await peer.internals.parseAst(air); + it("Incorrect ast should result in corresponding error", async () => { + await withPeer(async (peer) => { + const air = `(null`; + const res = await peer.internals.parseAst(air); - expect(res).toStrictEqual({ - success: false, - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - data: expect.stringContaining("error"), - }); - }); + expect(res).toStrictEqual({ + success: false, + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + data: expect.stringContaining("error"), + }); }); + }); }); diff --git a/packages/core/js-client/src/jsPeer/__test__/peer.spec.ts b/packages/core/js-client/src/jsPeer/__test__/peer.spec.ts index 27760f7dc..2d7b9cf0f 100644 --- a/packages/core/js-client/src/jsPeer/__test__/peer.spec.ts +++ b/packages/core/js-client/src/jsPeer/__test__/peer.spec.ts @@ -19,87 +19,83 @@ import { it, describe, expect } from "vitest"; import { isFluencePeer } from "../../api.js"; import { handleTimeout } from "../../particle/Particle.js"; import { - mkTestPeer, - registerHandlersHelper, - withPeer, + mkTestPeer, + registerHandlersHelper, + withPeer, } from "../../util/testUtils.js"; import { FluencePeer } from "../FluencePeer.js"; describe("FluencePeer usage test suite", () => { - it("should perform test for FluencePeer class correctly", async () => { - // arrange - const peer = await mkTestPeer(); - const number = 1; - const object = { str: "Hello!" }; - const undefinedVal = undefined; - - // act - const isPeerPeer = isFluencePeer(peer); - const isNumberPeer = isFluencePeer(number); - const isObjectPeer = isFluencePeer(object); - const isUndefinedPeer = isFluencePeer(undefinedVal); - - // act - expect(isPeerPeer).toBe(true); - expect(isNumberPeer).toBe(false); - expect(isObjectPeer).toBe(false); - expect(isUndefinedPeer).toBe(false); - }); - - it("Should successfully call identity on local peer", async function () { - await withPeer(async (peer) => { - const script = ` + it("should perform test for FluencePeer class correctly", async () => { + // arrange + const peer = await mkTestPeer(); + const number = 1; + const object = { str: "Hello!" }; + const undefinedVal = undefined; + + // act + const isPeerPeer = isFluencePeer(peer); + const isNumberPeer = isFluencePeer(number); + const isObjectPeer = isFluencePeer(object); + const isUndefinedPeer = isFluencePeer(undefinedVal); + + // act + expect(isPeerPeer).toBe(true); + expect(isNumberPeer).toBe(false); + expect(isObjectPeer).toBe(false); + expect(isUndefinedPeer).toBe(false); + }); + + it("Should successfully call identity on local peer", async function () { + await withPeer(async (peer) => { + const script = ` (seq (call %init_peer_id% ("op" "identity") ["test"] res) (call %init_peer_id% ("callback" "callback") [res]) ) `; - const particle = await peer.internals.createNewParticle(script); - - const res = await new Promise((resolve, reject) => { - if (particle instanceof Error) { - reject(particle.message); - return; - } - - registerHandlersHelper(peer, particle, { - callback: { - callback: (args) => { - const [res] = args; - resolve(res); - }, - }, - }); - - peer.internals.initiateParticle( - particle, - handleTimeout(reject), - ); - }); - - expect(res).toBe("test"); - }); - }); + const particle = await peer.internals.createNewParticle(script); - it("Should throw correct message when calling non existing local service", async function () { - await withPeer(async (peer) => { - const res = callIncorrectService(peer); - - await expect(res).rejects.toMatchObject({ - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - message: expect.stringContaining( - `"No service found for service call: serviceId='incorrect', fnName='incorrect' args='[]'"`, - ), - instruction: - 'call %init_peer_id% ("incorrect" "incorrect") [] res', - }); + const res = await new Promise((resolve, reject) => { + if (particle instanceof Error) { + reject(particle.message); + return; + } + + registerHandlersHelper(peer, particle, { + callback: { + callback: (args) => { + const [res] = args; + resolve(res); + }, + }, }); + + peer.internals.initiateParticle(particle, handleTimeout(reject)); + }); + + expect(res).toBe("test"); + }); + }); + + it("Should throw correct message when calling non existing local service", async function () { + await withPeer(async (peer) => { + const res = callIncorrectService(peer); + + await expect(res).rejects.toMatchObject({ + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + message: expect.stringContaining( + `"No service found for service call: serviceId='incorrect', fnName='incorrect' args='[]'"`, + ), + instruction: 'call %init_peer_id% ("incorrect" "incorrect") [] res', + }); }); + }); - it("Should not crash if undefined is passed as a variable", async () => { - await withPeer(async (peer) => { - const script = ` + it("Should not crash if undefined is passed as a variable", async () => { + await withPeer(async (peer) => { + const script = ` (seq (call %init_peer_id% ("load" "arg") [] arg) (seq @@ -108,115 +104,107 @@ describe("FluencePeer usage test suite", () => { ) )`; - const particle = await peer.internals.createNewParticle(script); - - const res = await new Promise((resolve, reject) => { - if (particle instanceof Error) { - reject(particle.message); - return; - } - - registerHandlersHelper(peer, particle, { - load: { - arg: () => { - return undefined; - }, - }, - callback: { - callback: (args) => { - const [val] = args; - resolve(val); - }, - error: (args) => { - const [error] = args; - reject(error); - }, - }, - }); - - peer.internals.initiateParticle( - particle, - handleTimeout(reject), - ); - }); - - expect(res).toBe(null); + const particle = await peer.internals.createNewParticle(script); + + const res = await new Promise((resolve, reject) => { + if (particle instanceof Error) { + reject(particle.message); + return; + } + + registerHandlersHelper(peer, particle, { + load: { + arg: () => { + return undefined; + }, + }, + callback: { + callback: (args) => { + const [val] = args; + resolve(val); + }, + error: (args) => { + const [error] = args; + reject(error); + }, + }, }); + + peer.internals.initiateParticle(particle, handleTimeout(reject)); + }); + + expect(res).toBe(null); }); + }); - it("Should not crash if an error ocurred in user-defined handler", async () => { - await withPeer(async (peer) => { - const script = ` + it("Should not crash if an error ocurred in user-defined handler", async () => { + await withPeer(async (peer) => { + const script = ` (xor (call %init_peer_id% ("load" "arg") [] arg) (call %init_peer_id% ("callback" "error") [%last_error%]) )`; - const particle = await peer.internals.createNewParticle(script); - - const promise = new Promise((_resolve, reject) => { - if (particle instanceof Error) { - reject(particle.message); - return; - } - - registerHandlersHelper(peer, particle, { - load: { - arg: () => { - throw new Error("my super custom error message"); - }, - }, - callback: { - error: (args) => { - const [error] = args; - reject(error); - }, - }, - }); - - peer.internals.initiateParticle( - particle, - handleTimeout(reject), - ); - }); - - await expect(promise).rejects.toMatchObject({ - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - message: expect.stringContaining( - "my super custom error message", - ), - }); + const particle = await peer.internals.createNewParticle(script); + + const promise = new Promise((_resolve, reject) => { + if (particle instanceof Error) { + reject(particle.message); + return; + } + + registerHandlersHelper(peer, particle, { + load: { + arg: () => { + throw new Error("my super custom error message"); + }, + }, + callback: { + error: (args) => { + const [error] = args; + reject(error); + }, + }, }); + + peer.internals.initiateParticle(particle, handleTimeout(reject)); + }); + + await expect(promise).rejects.toMatchObject({ + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + message: expect.stringContaining("my super custom error message"), + }); }); + }); }); async function callIncorrectService(peer: FluencePeer) { - const script = ` + const script = ` (xor (call %init_peer_id% ("incorrect" "incorrect") [] res) (call %init_peer_id% ("callback" "error") [%last_error%]) )`; - const particle = await peer.internals.createNewParticle(script); - - return new Promise((resolve, reject) => { - if (particle instanceof Error) { - reject(particle.message); - return; - } - - registerHandlersHelper(peer, particle, { - callback: { - callback: (args) => { - resolve(args); - }, - error: (args) => { - const [error] = args; - reject(error); - }, - }, - }); - - peer.internals.initiateParticle(particle, handleTimeout(reject)); + const particle = await peer.internals.createNewParticle(script); + + return new Promise((resolve, reject) => { + if (particle instanceof Error) { + reject(particle.message); + return; + } + + registerHandlersHelper(peer, particle, { + callback: { + callback: (args) => { + resolve(args); + }, + error: (args) => { + const [error] = args; + reject(error); + }, + }, }); + + peer.internals.initiateParticle(particle, handleTimeout(reject)); + }); } diff --git a/packages/core/js-client/src/jsServiceHost/JsServiceHost.ts b/packages/core/js-client/src/jsServiceHost/JsServiceHost.ts index 749bc8f83..7dac7ef49 100644 --- a/packages/core/js-client/src/jsServiceHost/JsServiceHost.ts +++ b/packages/core/js-client/src/jsServiceHost/JsServiceHost.ts @@ -15,123 +15,123 @@ */ import { - CallServiceData, - CallServiceResult, - GenericCallServiceHandler, - IJsServiceHost, + CallServiceData, + CallServiceResult, + GenericCallServiceHandler, + IJsServiceHost, } from "./interfaces.js"; export class JsServiceHost implements IJsServiceHost { - private particleScopeHandlers = new Map< - string, - Map - >(); - private commonHandlers = new Map(); - - /** - * Returns true if any handler for the specified serviceId is registered - */ - hasService(serviceId: string): boolean { - return ( - this.commonHandlers.has(serviceId) || - this.particleScopeHandlers.has(serviceId) - ); + private particleScopeHandlers = new Map< + string, + Map + >(); + private commonHandlers = new Map(); + + /** + * Returns true if any handler for the specified serviceId is registered + */ + hasService(serviceId: string): boolean { + return ( + this.commonHandlers.has(serviceId) || + this.particleScopeHandlers.has(serviceId) + ); + } + + /** + * Removes all handlers associated with the specified particle scope + * @param particleId Particle ID to remove handlers for + */ + removeParticleScopeHandlers(particleId: string): void { + this.particleScopeHandlers.delete(particleId); + } + + /** + * Find call service handler for specified particle + * @param serviceId Service ID as specified in `call` air instruction + * @param fnName Function name as specified in `call` air instruction + * @param particleId Particle ID + */ + getHandler( + serviceId: string, + fnName: string, + particleId: string, + ): GenericCallServiceHandler | null { + const key = serviceFnKey(serviceId, fnName); + const psh = this.particleScopeHandlers.get(particleId); + let handler: GenericCallServiceHandler | undefined = undefined; + + // we should prioritize handler for this particle if there is one + // if particle-scoped handler exist for this particle try getting handler there + if (psh !== undefined) { + handler = psh.get(key); } - /** - * Removes all handlers associated with the specified particle scope - * @param particleId Particle ID to remove handlers for - */ - removeParticleScopeHandlers(particleId: string): void { - this.particleScopeHandlers.delete(particleId); + // then try to find a common handler for all particles with this service-fn key + // if there is no particle-specific handler, get one from common map + if (handler === undefined) { + handler = this.commonHandlers.get(key); } - /** - * Find call service handler for specified particle - * @param serviceId Service ID as specified in `call` air instruction - * @param fnName Function name as specified in `call` air instruction - * @param particleId Particle ID - */ - getHandler( - serviceId: string, - fnName: string, - particleId: string, - ): GenericCallServiceHandler | null { - const key = serviceFnKey(serviceId, fnName); - const psh = this.particleScopeHandlers.get(particleId); - let handler: GenericCallServiceHandler | undefined = undefined; - - // we should prioritize handler for this particle if there is one - // if particle-scoped handler exist for this particle try getting handler there - if (psh !== undefined) { - handler = psh.get(key); - } - - // then try to find a common handler for all particles with this service-fn key - // if there is no particle-specific handler, get one from common map - if (handler === undefined) { - handler = this.commonHandlers.get(key); - } - - return handler ?? null; + return handler ?? null; + } + + /** + * Execute service call for specified call service data. Return null if no handler was found + */ + async callService(req: CallServiceData): Promise { + const handler = this.getHandler( + req.serviceId, + req.fnName, + req.particleContext.particleId, + ); + + if (handler === null) { + return null; } - /** - * Execute service call for specified call service data. Return null if no handler was found - */ - async callService(req: CallServiceData): Promise { - const handler = this.getHandler( - req.serviceId, - req.fnName, - req.particleContext.particleId, - ); - - if (handler === null) { - return null; - } - - const result = await handler(req); - - // Otherwise AVM might break - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - if (result.result === undefined) { - result.result = null; - } - - return result; - } + const result = await handler(req); - /** - * Register handler for all particles - */ - registerGlobalHandler( - serviceId: string, - fnName: string, - handler: GenericCallServiceHandler, - ): void { - this.commonHandlers.set(serviceFnKey(serviceId, fnName), handler); + // Otherwise AVM might break + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (result.result === undefined) { + result.result = null; } - /** - * Register handler which will be called only for particle with the specific id - */ - registerParticleScopeHandler( - particleId: string, - serviceId: string, - fnName: string, - handler: GenericCallServiceHandler, - ): void { - let psh = this.particleScopeHandlers.get(particleId); - - if (psh === undefined) { - psh = new Map(); - this.particleScopeHandlers.set(particleId, psh); - } - - psh.set(serviceFnKey(serviceId, fnName), handler); + return result; + } + + /** + * Register handler for all particles + */ + registerGlobalHandler( + serviceId: string, + fnName: string, + handler: GenericCallServiceHandler, + ): void { + this.commonHandlers.set(serviceFnKey(serviceId, fnName), handler); + } + + /** + * Register handler which will be called only for particle with the specific id + */ + registerParticleScopeHandler( + particleId: string, + serviceId: string, + fnName: string, + handler: GenericCallServiceHandler, + ): void { + let psh = this.particleScopeHandlers.get(particleId); + + if (psh === undefined) { + psh = new Map(); + this.particleScopeHandlers.set(particleId, psh); } + + psh.set(serviceFnKey(serviceId, fnName), handler); + } } function serviceFnKey(serviceId: string, fnName: string) { - return `${serviceId}/${fnName}`; + return `${serviceId}/${fnName}`; } diff --git a/packages/core/js-client/src/jsServiceHost/interfaces.ts b/packages/core/js-client/src/jsServiceHost/interfaces.ts index 2369f067f..be6c3818f 100644 --- a/packages/core/js-client/src/jsServiceHost/interfaces.ts +++ b/packages/core/js-client/src/jsServiceHost/interfaces.ts @@ -23,117 +23,117 @@ import { JSONArray, JSONValue } from "@fluencelabs/interfaces"; * It operates on a notion of Call Service Handlers - functions which are called when a `call` air instruction is executed on the local peer. */ export interface IJsServiceHost { - /** - * Returns true if any handler for the specified serviceId is registered - */ - hasService(serviceId: string): boolean; - - /** - * Find call service handler for specified particle - * @param serviceId Service ID as specified in `call` air instruction - * @param fnName Function name as specified in `call` air instruction - * @param particleId Particle ID - */ - getHandler( - serviceId: string, - fnName: string, - particleId: string, - ): GenericCallServiceHandler | null; - - /** - * Execute service call for specified call service data - */ - callService(req: CallServiceData): Promise; - - /** - * Register handler for all particles - */ - registerGlobalHandler( - serviceId: string, - fnName: string, - handler: GenericCallServiceHandler, - ): void; - - /** - * Register handler which will be called only for particle with the specific id - */ - registerParticleScopeHandler( - particleId: string, - serviceId: string, - fnName: string, - handler: GenericCallServiceHandler, - ): void; - - /** - * Removes all handlers associated with the specified particle scope - * @param particleId Particle ID to remove handlers for - */ - removeParticleScopeHandlers(particleId: string): void; + /** + * Returns true if any handler for the specified serviceId is registered + */ + hasService(serviceId: string): boolean; + + /** + * Find call service handler for specified particle + * @param serviceId Service ID as specified in `call` air instruction + * @param fnName Function name as specified in `call` air instruction + * @param particleId Particle ID + */ + getHandler( + serviceId: string, + fnName: string, + particleId: string, + ): GenericCallServiceHandler | null; + + /** + * Execute service call for specified call service data + */ + callService(req: CallServiceData): Promise; + + /** + * Register handler for all particles + */ + registerGlobalHandler( + serviceId: string, + fnName: string, + handler: GenericCallServiceHandler, + ): void; + + /** + * Register handler which will be called only for particle with the specific id + */ + registerParticleScopeHandler( + particleId: string, + serviceId: string, + fnName: string, + handler: GenericCallServiceHandler, + ): void; + + /** + * Removes all handlers associated with the specified particle scope + * @param particleId Particle ID to remove handlers for + */ + removeParticleScopeHandlers(particleId: string): void; } export enum ResultCodes { - success = 0, - error = 1, + success = 0, + error = 1, } /** * Particle context. Contains additional information about particle which triggered `call` air instruction from AVM */ export interface ParticleContext { - /** - * The identifier of particle which triggered the call - */ - particleId: string; - - /** - * The peer id which created the particle - */ - initPeerId: PeerIdB58; - - /** - * Particle's timestamp when it was created - */ - timestamp: number; - - /** - * Time to live in milliseconds. The time after the particle should be expired - */ - ttl: number; - - /** - * Particle's signature - */ - signature: Uint8Array; + /** + * The identifier of particle which triggered the call + */ + particleId: string; + + /** + * The peer id which created the particle + */ + initPeerId: PeerIdB58; + + /** + * Particle's timestamp when it was created + */ + timestamp: number; + + /** + * Time to live in milliseconds. The time after the particle should be expired + */ + ttl: number; + + /** + * Particle's signature + */ + signature: Uint8Array; } /** * Represents the information passed from AVM when a `call` air instruction is executed on the local peer */ export interface CallServiceData { - /** - * Service ID as specified in `call` air instruction - */ - serviceId: string; - - /** - * Function name as specified in `call` air instruction - */ - fnName: string; - - /** - * Arguments as specified in `call` air instruction - */ - args: JSONArray; - - /** - * Security Tetraplets received from AVM - */ - tetraplets: SecurityTetraplet[][]; - - /** - * Particle context, @see {@link ParticleContext} - */ - particleContext: ParticleContext; + /** + * Service ID as specified in `call` air instruction + */ + serviceId: string; + + /** + * Function name as specified in `call` air instruction + */ + fnName: string; + + /** + * Arguments as specified in `call` air instruction + */ + args: JSONArray; + + /** + * Security Tetraplets received from AVM + */ + tetraplets: SecurityTetraplet[][]; + + /** + * Particle context, @see {@link ParticleContext} + */ + particleContext: ParticleContext; } /** @@ -145,20 +145,20 @@ export type CallServiceResultType = JSONValue; * Generic call service handler */ export type GenericCallServiceHandler = ( - req: CallServiceData, + req: CallServiceData, ) => CallServiceResult | Promise; /** * Represents the result of the `call` air instruction to be returned into AVM */ export interface CallServiceResult { - /** - * Return code to be returned to AVM - */ - retCode: ResultCodes; - - /** - * Result object to be returned to AVM - */ - result: CallServiceResultType; + /** + * Return code to be returned to AVM + */ + retCode: ResultCodes; + + /** + * Result object to be returned to AVM + */ + result: CallServiceResultType; } diff --git a/packages/core/js-client/src/jsServiceHost/serviceUtils.ts b/packages/core/js-client/src/jsServiceHost/serviceUtils.ts index 5d3d0a6fb..ac9090c3b 100644 --- a/packages/core/js-client/src/jsServiceHost/serviceUtils.ts +++ b/packages/core/js-client/src/jsServiceHost/serviceUtils.ts @@ -21,50 +21,50 @@ import { IParticle } from "../particle/interfaces.js"; import { builtInServices } from "../services/builtins.js"; import { - CallServiceData, - CallServiceResult, - CallServiceResultType, - ParticleContext, - ResultCodes, + CallServiceData, + CallServiceResult, + CallServiceResultType, + ParticleContext, + ResultCodes, } from "./interfaces.js"; export const doNothing = () => { - return undefined; + return undefined; }; export const WrapFnIntoServiceCall = ( - fn: (args: JSONArray) => CallServiceResultType | undefined, + fn: (args: JSONArray) => CallServiceResultType | undefined, ) => { - return (req: CallServiceData): CallServiceResult => { - return { - retCode: ResultCodes.success, - result: fn(req.args) ?? null, - }; + return (req: CallServiceData): CallServiceResult => { + return { + retCode: ResultCodes.success, + result: fn(req.args) ?? null, }; + }; }; export class ServiceError extends Error { - constructor(message: string) { - super(message); + constructor(message: string) { + super(message); - Object.setPrototypeOf(this, ServiceError.prototype); - } + Object.setPrototypeOf(this, ServiceError.prototype); + } } export const getParticleContext = (particle: IParticle): ParticleContext => { - return { - particleId: particle.id, - initPeerId: particle.initPeerId, - timestamp: particle.timestamp, - ttl: particle.ttl, - signature: particle.signature, - }; + return { + particleId: particle.id, + initPeerId: particle.initPeerId, + timestamp: particle.timestamp, + ttl: particle.ttl, + signature: particle.signature, + }; }; export function registerDefaultServices(peer: FluencePeer) { - Object.entries(builtInServices).forEach(([serviceId, service]) => { - Object.entries(service).forEach(([fnName, fn]) => { - peer.internals.regHandler.common(serviceId, fnName, fn); - }); + Object.entries(builtInServices).forEach(([serviceId, service]) => { + Object.entries(service).forEach(([fnName, fn]) => { + peer.internals.regHandler.common(serviceId, fnName, fn); }); + }); } diff --git a/packages/core/js-client/src/keypair/__test__/KeyPair.spec.ts b/packages/core/js-client/src/keypair/__test__/KeyPair.spec.ts index b1e09f5e4..58ca9cf49 100644 --- a/packages/core/js-client/src/keypair/__test__/KeyPair.spec.ts +++ b/packages/core/js-client/src/keypair/__test__/KeyPair.spec.ts @@ -26,88 +26,88 @@ const keyBytes = toUint8Array(key); const testData = Uint8Array.from([1, 2, 3, 4, 5, 6, 7, 9, 10]); const testDataSig = Uint8Array.from([ - 224, 104, 245, 206, 140, 248, 27, 72, 68, 133, 111, 10, 164, 197, 242, 132, - 107, 77, 224, 67, 99, 106, 76, 29, 144, 121, 122, 169, 36, 173, 58, 80, 170, - 102, 137, 253, 157, 247, 168, 87, 162, 223, 188, 214, 203, 220, 52, 246, 29, - 86, 77, 71, 224, 248, 16, 213, 254, 75, 78, 239, 243, 222, 241, 15, + 224, 104, 245, 206, 140, 248, 27, 72, 68, 133, 111, 10, 164, 197, 242, 132, + 107, 77, 224, 67, 99, 106, 76, 29, 144, 121, 122, 169, 36, 173, 58, 80, 170, + 102, 137, 253, 157, 247, 168, 87, 162, 223, 188, 214, 203, 220, 52, 246, 29, + 86, 77, 71, 224, 248, 16, 213, 254, 75, 78, 239, 243, 222, 241, 15, ]); // signature produced by KeyPair created from some random KeyPair describe("KeyPair tests", () => { - it("generate keypair from seed", async function () { - // arrange - const random = await KeyPair.randomEd25519(); - const privateKey = random.toEd25519PrivateKey(); + it("generate keypair from seed", async function () { + // arrange + const random = await KeyPair.randomEd25519(); + const privateKey = random.toEd25519PrivateKey(); - // act - const keyPair = await KeyPair.fromEd25519SK(privateKey); - const privateKey2 = keyPair.toEd25519PrivateKey(); + // act + const keyPair = await KeyPair.fromEd25519SK(privateKey); + const privateKey2 = keyPair.toEd25519PrivateKey(); - // assert - expect(privateKey).toStrictEqual(privateKey2); - }); + // assert + expect(privateKey).toStrictEqual(privateKey2); + }); - it("create keypair from ed25519 private key", async function () { - // arrange - const rustSK = "jDaxLJzYtzgwTMrELJCAqavtmx85ktQNfB2rLcK7MhH"; - const sk = decode(rustSK); + it("create keypair from ed25519 private key", async function () { + // arrange + const rustSK = "jDaxLJzYtzgwTMrELJCAqavtmx85ktQNfB2rLcK7MhH"; + const sk = decode(rustSK); - // act - const keyPair = await KeyPair.fromEd25519SK(sk); + // act + const keyPair = await KeyPair.fromEd25519SK(sk); - // assert - const expectedPeerId = - "12D3KooWH1W3VznVZ87JH4FwABK4mkntcspTVWJDta6c2xg9Pzbp"; + // assert + const expectedPeerId = + "12D3KooWH1W3VznVZ87JH4FwABK4mkntcspTVWJDta6c2xg9Pzbp"; - expect(keyPair.getPeerId()).toStrictEqual(expectedPeerId); - }); + expect(keyPair.getPeerId()).toStrictEqual(expectedPeerId); + }); - it("create keypair from a seed phrase", async function () { - // arrange - const seedArray = new Uint8Array(32).fill(1); + it("create keypair from a seed phrase", async function () { + // arrange + const seedArray = new Uint8Array(32).fill(1); - // act - const keyPair = await KeyPair.fromEd25519SK(seedArray); + // act + const keyPair = await KeyPair.fromEd25519SK(seedArray); - // assert - const expectedPeerId = - "12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5"; + // assert + const expectedPeerId = + "12D3KooWK99VoVxNE7XzyBwXEzW7xhK7Gpv85r9F3V3fyKSUKPH5"; - expect(keyPair.getPeerId()).toStrictEqual(expectedPeerId); - }); + expect(keyPair.getPeerId()).toStrictEqual(expectedPeerId); + }); - it("sign", async function () { - // arrange - const keyPair = await KeyPair.fromEd25519SK(keyBytes); + it("sign", async function () { + // arrange + const keyPair = await KeyPair.fromEd25519SK(keyBytes); - // act - const res = await keyPair.signBytes(testData); - // assert - expect(new Uint8Array(res)).toStrictEqual(testDataSig); - }); + // act + const res = await keyPair.signBytes(testData); + // assert + expect(new Uint8Array(res)).toStrictEqual(testDataSig); + }); - it("verify", async function () { - // arrange - const keyPair = await KeyPair.fromEd25519SK(keyBytes); + it("verify", async function () { + // arrange + const keyPair = await KeyPair.fromEd25519SK(keyBytes); - // act - const res = await keyPair.verify(testData, testDataSig); + // act + const res = await keyPair.verify(testData, testDataSig); - // assert - expect(res).toBe(true); - }); + // assert + expect(res).toBe(true); + }); - it("sign-verify", async function () { - // arrange - const keyPair = await KeyPair.fromEd25519SK(keyBytes); + it("sign-verify", async function () { + // arrange + const keyPair = await KeyPair.fromEd25519SK(keyBytes); - // act - const data = new Uint8Array(32).fill(1); - const sig = await keyPair.signBytes(data); - const res = await keyPair.verify(data, sig); + // act + const data = new Uint8Array(32).fill(1); + const sig = await keyPair.signBytes(data); + const res = await keyPair.verify(data, sig); - // assert - expect(res).toBe(true); - }); + // assert + expect(res).toBe(true); + }); }); diff --git a/packages/core/js-client/src/keypair/index.ts b/packages/core/js-client/src/keypair/index.ts index d6e7ff482..c19185fc9 100644 --- a/packages/core/js-client/src/keypair/index.ts +++ b/packages/core/js-client/src/keypair/index.ts @@ -16,9 +16,9 @@ import { KeyPairOptions } from "@fluencelabs/interfaces"; import { - generateKeyPairFromSeed, - generateKeyPair, - unmarshalPublicKey, + generateKeyPairFromSeed, + generateKeyPair, + unmarshalPublicKey, } from "@libp2p/crypto/keys"; import type { PrivateKey, PublicKey } from "@libp2p/interface/keys"; import type { PeerId } from "@libp2p/interface/peer-id"; @@ -27,85 +27,85 @@ import { decode } from "bs58"; import { toUint8Array } from "js-base64"; export class KeyPair { - private publicKey: PublicKey; + private publicKey: PublicKey; - private constructor( - private privateKey: PrivateKey, - private libp2pPeerId: PeerId, - ) { - this.publicKey = privateKey.public; - } + private constructor( + private privateKey: PrivateKey, + private libp2pPeerId: PeerId, + ) { + this.publicKey = privateKey.public; + } - /** - * Key pair in libp2p format. Used for backward compatibility with the current FluencePeer implementation - */ - getLibp2pPeerId() { - return this.libp2pPeerId; - } + /** + * Key pair in libp2p format. Used for backward compatibility with the current FluencePeer implementation + */ + getLibp2pPeerId() { + return this.libp2pPeerId; + } - /** - * Generates new KeyPair from ed25519 private key represented as a 32 byte array - * @param seed - Any sequence of 32 bytes - * @returns - Promise with the created KeyPair - */ - static async fromEd25519SK(seed: Uint8Array): Promise { - const key = await generateKeyPairFromSeed("Ed25519", seed, 256); - const lib2p2Pid = await createFromPrivKey(key); - return new KeyPair(key, lib2p2Pid); - } + /** + * Generates new KeyPair from ed25519 private key represented as a 32 byte array + * @param seed - Any sequence of 32 bytes + * @returns - Promise with the created KeyPair + */ + static async fromEd25519SK(seed: Uint8Array): Promise { + const key = await generateKeyPairFromSeed("Ed25519", seed, 256); + const lib2p2Pid = await createFromPrivKey(key); + return new KeyPair(key, lib2p2Pid); + } - /** - * Generates new KeyPair with a random secret key - * @returns - Promise with the created KeyPair - */ - static async randomEd25519(): Promise { - const key = await generateKeyPair("Ed25519"); - const lib2p2Pid = await createFromPrivKey(key); - return new KeyPair(key, lib2p2Pid); - } + /** + * Generates new KeyPair with a random secret key + * @returns - Promise with the created KeyPair + */ + static async randomEd25519(): Promise { + const key = await generateKeyPair("Ed25519"); + const lib2p2Pid = await createFromPrivKey(key); + return new KeyPair(key, lib2p2Pid); + } - static verifyWithPublicKey( - publicKey: Uint8Array, - message: Uint8Array, - signature: Uint8Array, - ) { - return unmarshalPublicKey(publicKey).verify(message, signature); - } + static verifyWithPublicKey( + publicKey: Uint8Array, + message: Uint8Array, + signature: Uint8Array, + ) { + return unmarshalPublicKey(publicKey).verify(message, signature); + } - getPeerId(): string { - return this.libp2pPeerId.toString(); - } + getPeerId(): string { + return this.libp2pPeerId.toString(); + } - /** - * @returns 32 byte private key - */ - toEd25519PrivateKey(): Uint8Array { - return this.privateKey.marshal().subarray(0, 32); - } + /** + * @returns 32 byte private key + */ + toEd25519PrivateKey(): Uint8Array { + return this.privateKey.marshal().subarray(0, 32); + } - signBytes(data: Uint8Array): Promise { - return this.privateKey.sign(data); - } + signBytes(data: Uint8Array): Promise { + return this.privateKey.sign(data); + } - verify(data: Uint8Array, signature: Uint8Array): Promise { - return this.publicKey.verify(data, signature); - } + verify(data: Uint8Array, signature: Uint8Array): Promise { + return this.publicKey.verify(data, signature); + } } export const fromBase64Sk = (sk: string): Promise => { - const skArr = toUint8Array(sk); - return KeyPair.fromEd25519SK(skArr); + const skArr = toUint8Array(sk); + return KeyPair.fromEd25519SK(skArr); }; export const fromBase58Sk = (sk: string): Promise => { - const skArr = decode(sk); - return KeyPair.fromEd25519SK(skArr); + const skArr = decode(sk); + return KeyPair.fromEd25519SK(skArr); }; export const fromOpts = (opts: KeyPairOptions): Promise => { - if (opts.source === "random") { - return KeyPair.randomEd25519(); - } + if (opts.source === "random") { + return KeyPair.randomEd25519(); + } - return KeyPair.fromEd25519SK(opts.source); + return KeyPair.fromEd25519SK(opts.source); }; diff --git a/packages/core/js-client/src/marine/__test__/marine-js.spec.ts b/packages/core/js-client/src/marine/__test__/marine-js.spec.ts index d970c58e7..f5e3c3c8f 100644 --- a/packages/core/js-client/src/marine/__test__/marine-js.spec.ts +++ b/packages/core/js-client/src/marine/__test__/marine-js.spec.ts @@ -26,30 +26,30 @@ let aqua: Record; const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); describe("Marine js tests", () => { - beforeAll(async () => { - const pathToAquaFiles = path.join( - __dirname, - "../../../aqua_test/marine-js.aqua", - ); - - const { functions } = await compileAqua(pathToAquaFiles); - aqua = functions; - }); - - it("should call marine service correctly", async () => { - await withPeer(async (peer) => { - // arrange - const wasm = await fs.promises.readFile( - path.join(__dirname, "../../../data_for_test/greeting.wasm"), - ); - - await peer.registerMarineService(wasm, "greeting"); - - // act - const res = await aqua["call"](peer, { arg: "test" }); - - // assert - expect(res).toBe("Hi, Hi, Hi, test"); - }); + beforeAll(async () => { + const pathToAquaFiles = path.join( + __dirname, + "../../../aqua_test/marine-js.aqua", + ); + + const { functions } = await compileAqua(pathToAquaFiles); + aqua = functions; + }); + + it("should call marine service correctly", async () => { + await withPeer(async (peer) => { + // arrange + const wasm = await fs.promises.readFile( + path.join(__dirname, "../../../data_for_test/greeting.wasm"), + ); + + await peer.registerMarineService(wasm, "greeting"); + + // act + const res = await aqua["call"](peer, { arg: "test" }); + + // assert + expect(res).toBe("Hi, Hi, Hi, test"); }); + }); }); diff --git a/packages/core/js-client/src/marine/deps-loader/node.ts b/packages/core/js-client/src/marine/deps-loader/node.ts index bd7fee514..dd4b3ffed 100644 --- a/packages/core/js-client/src/marine/deps-loader/node.ts +++ b/packages/core/js-client/src/marine/deps-loader/node.ts @@ -26,10 +26,10 @@ import { LazyLoader } from "../interfaces.js"; const require = createRequire(import.meta.url); const bufferToSharedArrayBuffer = (buffer: Buffer): SharedArrayBuffer => { - const sab = new SharedArrayBuffer(buffer.length); - const tmp = new Uint8Array(sab); - tmp.set(buffer, 0); - return sab; + const sab = new SharedArrayBuffer(buffer.length); + const tmp = new Uint8Array(sab); + tmp.set(buffer, 0); + return sab; }; /** @@ -39,12 +39,12 @@ const bufferToSharedArrayBuffer = (buffer: Buffer): SharedArrayBuffer => { * @returns SharedArrayBuffer with the wasm file */ export const loadWasmFromNpmPackage = async (source: { - package: string; - file: string; + package: string; + file: string; }): Promise => { - const packagePath = require.resolve(source.package); - const filePath = path.join(path.dirname(packagePath), source.file); - return loadWasmFromFileSystem(filePath); + const packagePath = require.resolve(source.package); + const filePath = path.join(path.dirname(packagePath), source.file); + return loadWasmFromFileSystem(filePath); }; /** @@ -54,42 +54,42 @@ export const loadWasmFromNpmPackage = async (source: { * @returns SharedArrayBuffer with the wasm fileWorker */ export const loadWasmFromFileSystem = async ( - filePath: string, + filePath: string, ): Promise => { - const buffer = await fs.promises.readFile(filePath); - return bufferToSharedArrayBuffer(buffer); + const buffer = await fs.promises.readFile(filePath); + return bufferToSharedArrayBuffer(buffer); }; export class WasmLoaderFromFs extends LazyLoader { - constructor(filePath: string) { - super(() => { - return loadWasmFromFileSystem(filePath); - }); - } + constructor(filePath: string) { + super(() => { + return loadWasmFromFileSystem(filePath); + }); + } } export class WasmLoaderFromNpm extends LazyLoader { - constructor(pkg: string, file: string) { - super(() => { - return loadWasmFromNpmPackage({ package: pkg, file: file }); - }); - } + constructor(pkg: string, file: string) { + super(() => { + return loadWasmFromNpmPackage({ package: pkg, file: file }); + }); + } } export class WorkerLoaderFromFs extends LazyLoader { - constructor(scriptPath: string) { - super(() => { - return new Worker(scriptPath); - }); - } + constructor(scriptPath: string) { + super(() => { + return new Worker(scriptPath); + }); + } } export class WorkerLoaderFromNpm extends LazyLoader { - constructor(pkg: string, file: string) { - super(() => { - const packagePath = require.resolve(pkg); - const scriptPath = path.join(path.dirname(packagePath), file); - return new Worker(scriptPath); - }); - } + constructor(pkg: string, file: string) { + super(() => { + const packagePath = require.resolve(pkg); + const scriptPath = path.join(path.dirname(packagePath), file); + return new Worker(scriptPath); + }); + } } diff --git a/packages/core/js-client/src/marine/interfaces.ts b/packages/core/js-client/src/marine/interfaces.ts index afc875231..be7607b80 100644 --- a/packages/core/js-client/src/marine/interfaces.ts +++ b/packages/core/js-client/src/marine/interfaces.ts @@ -15,9 +15,9 @@ */ import { - CallResultsArray, - InterpreterResult, - RunParameters, + CallResultsArray, + InterpreterResult, + RunParameters, } from "@fluencelabs/avm"; import { JSONObject, JSONValue, JSONArray } from "@fluencelabs/interfaces"; @@ -28,97 +28,97 @@ import { IStartable, CallParameters } from "../util/commonTypes.js"; * Contract for marine host implementations. Marine host is responsible for creating calling and removing marine services */ export interface IMarineHost extends IStartable { - /** - * Creates marine service from the given module and service id - */ - createService( - serviceModule: ArrayBuffer | SharedArrayBuffer, - serviceId: string, - ): Promise; - - /** - * Removes marine service with the given service id - */ - removeService(serviceId: string): Promise; - - /** - * Returns true if any service with the specified service id is registered - */ - hasService(serviceId: string): Promise; - - /** - * Calls the specified function of the specified service with the given arguments - */ - callService( - serviceId: string, - functionName: string, - args: JSONArray | JSONObject, - callParams: CallParameters, - ): Promise; + /** + * Creates marine service from the given module and service id + */ + createService( + serviceModule: ArrayBuffer | SharedArrayBuffer, + serviceId: string, + ): Promise; + + /** + * Removes marine service with the given service id + */ + removeService(serviceId: string): Promise; + + /** + * Returns true if any service with the specified service id is registered + */ + hasService(serviceId: string): Promise; + + /** + * Calls the specified function of the specified service with the given arguments + */ + callService( + serviceId: string, + functionName: string, + args: JSONArray | JSONObject, + callParams: CallParameters, + ): Promise; } /** * Interface for different implementations of AVM runner */ export interface IAvmRunner extends IStartable { - /** - * Run AVM interpreter with the specified parameters - */ - run( - runParams: RunParameters, - air: string, - prevData: Uint8Array, - data: Uint8Array, - callResults: CallResultsArray, - ): Promise; + /** + * Run AVM interpreter with the specified parameters + */ + run( + runParams: RunParameters, + air: string, + prevData: Uint8Array, + data: Uint8Array, + callResults: CallResultsArray, + ): Promise; } /** * Interface for something which can hold a value */ export interface IValueLoader { - getValue(): T; + getValue(): T; } /** * Interface for something which can load wasm files */ export interface IWasmLoader - extends IValueLoader, - IStartable {} + extends IValueLoader, + IStartable {} /** * Interface for something which can thread.js based worker */ export interface IWorkerLoader - extends IValueLoader>, - IStartable {} + extends IValueLoader>, + IStartable {} /** * Lazy loader for some value. Value is loaded only when `start` method is called */ export class LazyLoader implements IStartable, IValueLoader { - private value: T | null = null; + private value: T | null = null; - constructor(private loadValue: () => Promise | T) {} + constructor(private loadValue: () => Promise | T) {} - getValue(): T { - if (this.value == null) { - throw new Error( - "Value has not been loaded. Call `start` method to load the value.", - ); - } - - return this.value; + getValue(): T { + if (this.value == null) { + throw new Error( + "Value has not been loaded. Call `start` method to load the value.", + ); } - async start() { - if (this.value !== null) { - return; - } + return this.value; + } - this.value = await this.loadValue(); + async start() { + if (this.value !== null) { + return; } - async stop() {} + this.value = await this.loadValue(); + } + + async stop() {} } diff --git a/packages/core/js-client/src/marine/worker-script/workerLoader.ts b/packages/core/js-client/src/marine/worker-script/workerLoader.ts index d895c0c25..d707aea0a 100644 --- a/packages/core/js-client/src/marine/worker-script/workerLoader.ts +++ b/packages/core/js-client/src/marine/worker-script/workerLoader.ts @@ -21,11 +21,11 @@ import type { WorkerImplementation } from "../../../node_modules/threads/dist/ty import { LazyLoader } from "../interfaces.js"; export class WorkerLoader extends LazyLoader { - constructor() { - super(() => { - return new Worker( - "../../../node_modules/@fluencelabs/marine-worker/dist/index.js", - ); - }); - } + constructor() { + super(() => { + return new Worker( + "../../../node_modules/@fluencelabs/marine-worker/dist/index.js", + ); + }); + } } diff --git a/packages/core/js-client/src/marine/worker/index.ts b/packages/core/js-client/src/marine/worker/index.ts index 8601c352c..ecf162f01 100644 --- a/packages/core/js-client/src/marine/worker/index.ts +++ b/packages/core/js-client/src/marine/worker/index.ts @@ -16,121 +16,121 @@ import { JSONValue } from "@fluencelabs/interfaces"; import type { - JSONArray, - JSONObject, - CallParameters, + JSONArray, + JSONObject, + CallParameters, } from "@fluencelabs/marine-js/dist/types"; import { LogFunction, logLevelToEnv } from "@fluencelabs/marine-js/dist/types"; import type { MarineBackgroundInterface } from "@fluencelabs/marine-worker"; import { - ModuleThread, - Thread, - spawn, + ModuleThread, + Thread, + spawn, } from "../../../node_modules/threads/dist/master/index.js"; import { MarineLogger, marineLogger } from "../../util/logger.js"; import { IMarineHost, IWasmLoader, IWorkerLoader } from "../interfaces.js"; export class MarineBackgroundRunner implements IMarineHost { - private workerThread?: ModuleThread; + private workerThread?: ModuleThread; - private loggers = new Map(); + private loggers = new Map(); - constructor( - private workerLoader: IWorkerLoader, - private controlModuleLoader: IWasmLoader, - private avmWasmLoader: IWasmLoader, - ) {} + constructor( + private workerLoader: IWorkerLoader, + private controlModuleLoader: IWasmLoader, + private avmWasmLoader: IWasmLoader, + ) {} - async hasService(serviceId: string) { - if (this.workerThread == null) { - throw new Error("Worker is not initialized"); - } + async hasService(serviceId: string) { + if (this.workerThread == null) { + throw new Error("Worker is not initialized"); + } + + return this.workerThread.hasService(serviceId); + } - return this.workerThread.hasService(serviceId); + async removeService(serviceId: string) { + if (this.workerThread == null) { + throw new Error("Worker is not initialized"); } - async removeService(serviceId: string) { - if (this.workerThread == null) { - throw new Error("Worker is not initialized"); - } + await this.workerThread.removeService(serviceId); + } - await this.workerThread.removeService(serviceId); + async start(): Promise { + if (this.workerThread != null) { + throw new Error("Worker thread already initialized"); } - async start(): Promise { - if (this.workerThread != null) { - throw new Error("Worker thread already initialized"); - } + await this.controlModuleLoader.start(); + const wasm = this.controlModuleLoader.getValue(); - await this.controlModuleLoader.start(); - const wasm = this.controlModuleLoader.getValue(); + await this.avmWasmLoader.start(); - await this.avmWasmLoader.start(); + await this.workerLoader.start(); + const worker = await this.workerLoader.getValue(); - await this.workerLoader.start(); - const worker = await this.workerLoader.getValue(); + const workerThread: ModuleThread = + await spawn(worker); - const workerThread: ModuleThread = - await spawn(worker); + const logfn: LogFunction = (message) => { + const serviceLogger = this.loggers.get(message.service); - const logfn: LogFunction = (message) => { - const serviceLogger = this.loggers.get(message.service); + if (serviceLogger == null) { + return; + } - if (serviceLogger == null) { - return; - } + serviceLogger[message.level](message.message); + }; - serviceLogger[message.level](message.message); - }; + // @ts-expect-error This type is bugged + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + workerThread.onLogMessage().subscribe(logfn); + await workerThread.init(wasm); + this.workerThread = workerThread; + await this.createService(this.avmWasmLoader.getValue(), "avm"); + } - // @ts-expect-error This type is bugged - // eslint-disable-next-line @typescript-eslint/no-unsafe-call - workerThread.onLogMessage().subscribe(logfn); - await workerThread.init(wasm); - this.workerThread = workerThread; - await this.createService(this.avmWasmLoader.getValue(), "avm"); + async createService( + serviceModule: ArrayBuffer | SharedArrayBuffer, + serviceId: string, + ): Promise { + if (this.workerThread == null) { + throw new Error("Worker is not initialized"); } - async createService( - serviceModule: ArrayBuffer | SharedArrayBuffer, - serviceId: string, - ): Promise { - if (this.workerThread == null) { - throw new Error("Worker is not initialized"); - } - - // The logging level is controlled by the environment variable passed to enable debug logs. - // We enable all possible log levels passing the control for exact printouts to the logger - const env = logLevelToEnv("info"); - this.loggers.set(serviceId, marineLogger(serviceId)); - await this.workerThread.createService(serviceModule, serviceId, env); + // The logging level is controlled by the environment variable passed to enable debug logs. + // We enable all possible log levels passing the control for exact printouts to the logger + const env = logLevelToEnv("info"); + this.loggers.set(serviceId, marineLogger(serviceId)); + await this.workerThread.createService(serviceModule, serviceId, env); + } + + async callService( + serviceId: string, + functionName: string, + args: JSONArray | JSONObject, + callParams: CallParameters, + ): Promise { + if (this.workerThread == null) { + throw new Error("Worker is not initialized"); } - async callService( - serviceId: string, - functionName: string, - args: JSONArray | JSONObject, - callParams: CallParameters, - ): Promise { - if (this.workerThread == null) { - throw new Error("Worker is not initialized"); - } - - return this.workerThread.callService( - serviceId, - functionName, - args, - callParams, - ); + return this.workerThread.callService( + serviceId, + functionName, + args, + callParams, + ); + } + + async stop(): Promise { + if (this.workerThread == null) { + return; } - async stop(): Promise { - if (this.workerThread == null) { - return; - } - - await this.workerThread.terminate(); - await Thread.terminate(this.workerThread); - } + await this.workerThread.terminate(); + await Thread.terminate(this.workerThread); + } } diff --git a/packages/core/js-client/src/particle/Particle.ts b/packages/core/js-client/src/particle/Particle.ts index 08b2fad67..63566ae5f 100644 --- a/packages/core/js-client/src/particle/Particle.ts +++ b/packages/core/js-client/src/particle/Particle.ts @@ -28,68 +28,68 @@ import { numberToLittleEndianBytes } from "../util/bytes.js"; import { IParticle } from "./interfaces.js"; const particleSchema = z.object({ - id: z.string(), - timestamp: z.number().positive(), - script: z.string(), - data: z.string(), - ttl: z.number().positive(), - init_peer_id: z.string(), - signature: z.array(z.number()), + id: z.string(), + timestamp: z.number().positive(), + script: z.string(), + data: z.string(), + ttl: z.number().positive(), + init_peer_id: z.string(), + signature: z.array(z.number()), }); export class Particle implements IParticle { - constructor( - readonly id: string, - readonly timestamp: number, - readonly script: string, - readonly data: Uint8Array, - readonly ttl: number, - readonly initPeerId: string, - readonly signature: Uint8Array, - ) {} - - static async createNew( - script: string, - initPeerId: string, - ttl: number, - keyPair: KeyPair, - ): Promise { - const id = uuidv4(); - const timestamp = Date.now(); - const message = buildParticleMessage({ id, timestamp, ttl, script }); - const signature = await keyPair.signBytes(message); - return new Particle( - id, - Date.now(), - script, - Buffer.from([]), - ttl, - initPeerId, - signature, - ); - } + constructor( + readonly id: string, + readonly timestamp: number, + readonly script: string, + readonly data: Uint8Array, + readonly ttl: number, + readonly initPeerId: string, + readonly signature: Uint8Array, + ) {} + + static async createNew( + script: string, + initPeerId: string, + ttl: number, + keyPair: KeyPair, + ): Promise { + const id = uuidv4(); + const timestamp = Date.now(); + const message = buildParticleMessage({ id, timestamp, ttl, script }); + const signature = await keyPair.signBytes(message); + return new Particle( + id, + Date.now(), + script, + Buffer.from([]), + ttl, + initPeerId, + signature, + ); + } - static fromString(str: string): Particle { - const json = JSON.parse(str); + static fromString(str: string): Particle { + const json = JSON.parse(str); - const res = particleSchema.safeParse(json); + const res = particleSchema.safeParse(json); - if (!res.success) { - throw new Error(`Particle format invalid. Given: ${str}`); - } + if (!res.success) { + throw new Error(`Particle format invalid. Given: ${str}`); + } - const data = res.data; + const data = res.data; - return new Particle( - data.id, - data.timestamp, - data.script, - toUint8Array(data.data), - data.ttl, - data.init_peer_id, - new Uint8Array(data.signature), - ); - } + return new Particle( + data.id, + data.timestamp, + data.script, + toUint8Array(data.data), + data.ttl, + data.init_peer_id, + new Uint8Array(data.signature), + ); + } } const en = new TextEncoder(); @@ -98,95 +98,95 @@ const en = new TextEncoder(); * Builds particle message for signing */ export const buildParticleMessage = ({ - id, - timestamp, - ttl, - script, + id, + timestamp, + ttl, + script, }: Omit): Uint8Array => { - return concat([ - en.encode(id), - numberToLittleEndianBytes(timestamp, "u64"), - numberToLittleEndianBytes(ttl, "u32"), - en.encode(script), - ]); + return concat([ + en.encode(id), + numberToLittleEndianBytes(timestamp, "u64"), + numberToLittleEndianBytes(ttl, "u32"), + en.encode(script), + ]); }; /** * Returns actual ttl of a particle, i.e. ttl - time passed since particle creation */ export const getActualTTL = (particle: IParticle): number => { - return particle.timestamp + particle.ttl - Date.now(); + return particle.timestamp + particle.ttl - Date.now(); }; /** * Returns true if particle has expired */ export const hasExpired = (particle: IParticle): boolean => { - return getActualTTL(particle) <= 0; + return getActualTTL(particle) <= 0; }; /** * Creates a particle clone with new data */ export const cloneWithNewData = ( - particle: IParticle, - newData: Uint8Array, + particle: IParticle, + newData: Uint8Array, ): IParticle => { - return new Particle( - particle.id, - particle.timestamp, - particle.script, - newData, - particle.ttl, - particle.initPeerId, - particle.signature, - ); + return new Particle( + particle.id, + particle.timestamp, + particle.script, + newData, + particle.ttl, + particle.initPeerId, + particle.signature, + ); }; /** * Serializes particle into string suitable for sending through network */ export const serializeToString = (particle: IParticle): string => { - return JSON.stringify({ - action: "Particle", - id: particle.id, - init_peer_id: particle.initPeerId, - timestamp: particle.timestamp, - ttl: particle.ttl, - script: particle.script, - signature: Array.from(particle.signature), - data: fromUint8Array(particle.data), - }); + return JSON.stringify({ + action: "Particle", + id: particle.id, + init_peer_id: particle.initPeerId, + timestamp: particle.timestamp, + ttl: particle.ttl, + script: particle.script, + signature: Array.from(particle.signature), + data: fromUint8Array(particle.data), + }); }; /** * When particle is executed, it goes through different stages. The type describes all possible stages and their parameters */ export type ParticleExecutionStage = - | { stage: "received" } - | { stage: "interpreted" } - | { stage: "interpreterError"; errorMessage: string } - | { stage: "localWorkDone" } - | { stage: "sent" } - | { stage: "sendingError"; errorMessage: string } - | { stage: "expired" }; + | { stage: "received" } + | { stage: "interpreted" } + | { stage: "interpreterError"; errorMessage: string } + | { stage: "localWorkDone" } + | { stage: "sent" } + | { stage: "sendingError"; errorMessage: string } + | { stage: "expired" }; /** * Particle queue item is a wrapper around particle, which contains additional information about particle execution */ export interface ParticleQueueItem { - particle: IParticle; - callResults: CallResultsArray; - onStageChange: (state: ParticleExecutionStage) => void; + particle: IParticle; + callResults: CallResultsArray; + onStageChange: (state: ParticleExecutionStage) => void; } /** * Helper function to handle particle at expired stage */ export const handleTimeout = (fn: () => void) => { - return (stage: ParticleExecutionStage) => { - if (stage.stage === "expired") { - fn(); - } - }; + return (stage: ParticleExecutionStage) => { + if (stage.stage === "expired") { + fn(); + } + }; }; diff --git a/packages/core/js-client/src/particle/interfaces.ts b/packages/core/js-client/src/particle/interfaces.ts index ca942ec38..cbe5c8cb5 100644 --- a/packages/core/js-client/src/particle/interfaces.ts +++ b/packages/core/js-client/src/particle/interfaces.ts @@ -20,43 +20,43 @@ import { PeerIdB58 } from "@fluencelabs/interfaces"; * Immutable part of the particle. */ export interface IImmutableParticlePart { - /** - * Particle id - */ - readonly id: string; - - /** - * Particle timestamp. Specifies when the particle was created. - */ - readonly timestamp: number; - - /** - * Particle's air script - */ - readonly script: string; - - /** - * Particle's ttl. Specifies how long the particle is valid in milliseconds. - */ - readonly ttl: number; - - /** - * Peer id where the particle was initiated. - */ - readonly initPeerId: PeerIdB58; - - /** - * Particle's signature of concatenation of bytes of all immutable particle fields. - */ - readonly signature: Uint8Array; + /** + * Particle id + */ + readonly id: string; + + /** + * Particle timestamp. Specifies when the particle was created. + */ + readonly timestamp: number; + + /** + * Particle's air script + */ + readonly script: string; + + /** + * Particle's ttl. Specifies how long the particle is valid in milliseconds. + */ + readonly ttl: number; + + /** + * Peer id where the particle was initiated. + */ + readonly initPeerId: PeerIdB58; + + /** + * Particle's signature of concatenation of bytes of all immutable particle fields. + */ + readonly signature: Uint8Array; } /** * Particle is a data structure that is used to transfer data between peers in Fluence network. */ export interface IParticle extends IImmutableParticlePart { - /** - * Mutable particle data - */ - data: Uint8Array; + /** + * Mutable particle data + */ + data: Uint8Array; } diff --git a/packages/core/js-client/src/services/NodeUtils.ts b/packages/core/js-client/src/services/NodeUtils.ts index a9c85de57..4ebba7b4b 100644 --- a/packages/core/js-client/src/services/NodeUtils.ts +++ b/packages/core/js-client/src/services/NodeUtils.ts @@ -27,52 +27,52 @@ import { SecurityGuard } from "./securityGuard.js"; import { defaultGuard } from "./SingleModuleSrv.js"; export class NodeUtils implements NodeUtilsDef { - constructor(private peer: FluencePeer) { - this.securityGuard_readFile = defaultGuard(this.peer); - } + constructor(private peer: FluencePeer) { + this.securityGuard_readFile = defaultGuard(this.peer); + } - securityGuard_readFile: SecurityGuard<"path">; + securityGuard_readFile: SecurityGuard<"path">; - async read_file(path: string, callParams: CallParams<"path">) { - if (!this.securityGuard_readFile(callParams)) { - return { - success: false, - error: "Security guard validation failed", - content: null, - }; - } + async read_file(path: string, callParams: CallParams<"path">) { + if (!this.securityGuard_readFile(callParams)) { + return { + success: false, + error: "Security guard validation failed", + content: null, + }; + } - try { - // Strange enough, but Buffer type works here, while reading with encoding 'utf-8' doesn't - const data = await new Promise((resolve, reject) => { - fs.readFile(path, (err, data) => { - if (err != null) { - reject(err); - return; - } + try { + // Strange enough, but Buffer type works here, while reading with encoding 'utf-8' doesn't + const data = await new Promise((resolve, reject) => { + fs.readFile(path, (err, data) => { + if (err != null) { + reject(err); + return; + } - resolve(data); - }); - }); + resolve(data); + }); + }); - return { - success: true, - // TODO: this is strange bug. - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - content: data as unknown as string, - error: null, - }; - } catch (err: unknown) { - return { - success: false, - error: getErrorMessage(err), - content: null, - }; - } + return { + success: true, + // TODO: this is strange bug. + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + content: data as unknown as string, + error: null, + }; + } catch (err: unknown) { + return { + success: false, + error: getErrorMessage(err), + content: null, + }; } + } } // HACK:: security guard functions must be ported to user API export const doRegisterNodeUtils = (peer: FluencePeer) => { - registerNodeUtils(peer, "node_utils", new NodeUtils(peer)); + registerNodeUtils(peer, "node_utils", new NodeUtils(peer)); }; diff --git a/packages/core/js-client/src/services/Sig.ts b/packages/core/js-client/src/services/Sig.ts index b80f8eda0..5663e5720 100644 --- a/packages/core/js-client/src/services/Sig.ts +++ b/packages/core/js-client/src/services/Sig.ts @@ -20,87 +20,87 @@ import { KeyPair } from "../keypair/index.js"; import { SigDef } from "./_aqua/services.js"; import { - allowOnlyParticleOriginatedAt, - allowServiceFn, - and, - or, - SecurityGuard, + allowOnlyParticleOriginatedAt, + allowServiceFn, + and, + or, + SecurityGuard, } from "./securityGuard.js"; export const defaultSigGuard = (peerId: PeerIdB58) => { - return and<"data">( - allowOnlyParticleOriginatedAt(peerId), - or( - allowServiceFn("trust-graph", "get_trust_bytes"), - allowServiceFn("trust-graph", "get_revocation_bytes"), - allowServiceFn("registry", "get_key_bytes"), - allowServiceFn("registry", "get_record_bytes"), - allowServiceFn("registry", "get_record_metadata_bytes"), - allowServiceFn("registry", "get_tombstone_bytes"), - ), - ); + return and<"data">( + allowOnlyParticleOriginatedAt(peerId), + or( + allowServiceFn("trust-graph", "get_trust_bytes"), + allowServiceFn("trust-graph", "get_revocation_bytes"), + allowServiceFn("registry", "get_key_bytes"), + allowServiceFn("registry", "get_record_bytes"), + allowServiceFn("registry", "get_record_metadata_bytes"), + allowServiceFn("registry", "get_tombstone_bytes"), + ), + ); }; type SignReturnType = - | { - error: null; - signature: number[]; - success: true; - } - | { - error: string; - signature: null; - success: false; - }; + | { + error: null; + signature: number[]; + success: true; + } + | { + error: string; + signature: null; + success: false; + }; export class Sig implements SigDef { - constructor(private keyPair: KeyPair) {} + constructor(private keyPair: KeyPair) {} - /** - * Configurable security guard for sign method - */ - securityGuard: SecurityGuard<"data"> = () => { - return true; - }; + /** + * Configurable security guard for sign method + */ + securityGuard: SecurityGuard<"data"> = () => { + return true; + }; - /** - * Gets the public key of KeyPair. Required by aqua - */ - get_peer_id() { - return this.keyPair.getPeerId(); - } + /** + * Gets the public key of KeyPair. Required by aqua + */ + get_peer_id() { + return this.keyPair.getPeerId(); + } - /** - * Signs the data using key pair's private key. Required by aqua - */ - async sign( - data: number[], - callParams: CallParams<"data">, - ): Promise { - if (!this.securityGuard(callParams)) { - return { - success: false, - error: "Security guard validation failed", - signature: null, - }; - } + /** + * Signs the data using key pair's private key. Required by aqua + */ + async sign( + data: number[], + callParams: CallParams<"data">, + ): Promise { + if (!this.securityGuard(callParams)) { + return { + success: false, + error: "Security guard validation failed", + signature: null, + }; + } - const signedData = await this.keyPair.signBytes(Uint8Array.from(data)); + const signedData = await this.keyPair.signBytes(Uint8Array.from(data)); - return { - success: true, - error: null, - signature: Array.from(signedData), - }; - } + return { + success: true, + error: null, + signature: Array.from(signedData), + }; + } - /** - * Verifies the signature. Required by aqua - */ - verify(signature: number[], data: number[]): Promise { - return this.keyPair.verify( - Uint8Array.from(data), - Uint8Array.from(signature), - ); - } + /** + * Verifies the signature. Required by aqua + */ + verify(signature: number[], data: number[]): Promise { + return this.keyPair.verify( + Uint8Array.from(data), + Uint8Array.from(signature), + ); + } } diff --git a/packages/core/js-client/src/services/SingleModuleSrv.ts b/packages/core/js-client/src/services/SingleModuleSrv.ts index dcf4241cf..4c29e8752 100644 --- a/packages/core/js-client/src/services/SingleModuleSrv.ts +++ b/packages/core/js-client/src/services/SingleModuleSrv.ts @@ -24,88 +24,88 @@ import { getErrorMessage } from "../util/utils.js"; import { SrvDef } from "./_aqua/single-module-srv.js"; import { - allowOnlyParticleOriginatedAt, - SecurityGuard, + allowOnlyParticleOriginatedAt, + SecurityGuard, } from "./securityGuard.js"; export const defaultGuard = (peer: FluencePeer) => { - return allowOnlyParticleOriginatedAt(peer.keyPair.getPeerId()); + return allowOnlyParticleOriginatedAt(peer.keyPair.getPeerId()); }; export class Srv implements SrvDef { - private services: Set = new Set(); - - constructor(private peer: FluencePeer) { - this.securityGuard_create = defaultGuard(this.peer); - this.securityGuard_remove = defaultGuard(this.peer); + private services: Set = new Set(); + + constructor(private peer: FluencePeer) { + this.securityGuard_create = defaultGuard(this.peer); + this.securityGuard_remove = defaultGuard(this.peer); + } + + securityGuard_create: SecurityGuard<"wasm_b64_content">; + + async create( + wasm_b64_content: string, + callParams: CallParams<"wasm_b64_content">, + ) { + if (!this.securityGuard_create(callParams)) { + return { + success: false, + error: "Security guard validation failed", + service_id: null, + }; } - securityGuard_create: SecurityGuard<"wasm_b64_content">; - - async create( - wasm_b64_content: string, - callParams: CallParams<"wasm_b64_content">, - ) { - if (!this.securityGuard_create(callParams)) { - return { - success: false, - error: "Security guard validation failed", - service_id: null, - }; - } - - try { - const newServiceId = uuidv4(); - const buffer = Buffer.from(wasm_b64_content, "base64"); - // TODO:: figure out why SharedArrayBuffer is not working here - // const sab = new SharedArrayBuffer(buffer.length); - // const tmp = new Uint8Array(sab); - // tmp.set(buffer, 0); - await this.peer.registerMarineService(buffer, newServiceId); - this.services.add(newServiceId); - - return { - success: true, - service_id: newServiceId, - error: null, - }; - } catch (err: unknown) { - return { - success: true, - service_id: null, - error: getErrorMessage(err), - }; - } + try { + const newServiceId = uuidv4(); + const buffer = Buffer.from(wasm_b64_content, "base64"); + // TODO:: figure out why SharedArrayBuffer is not working here + // const sab = new SharedArrayBuffer(buffer.length); + // const tmp = new Uint8Array(sab); + // tmp.set(buffer, 0); + await this.peer.registerMarineService(buffer, newServiceId); + this.services.add(newServiceId); + + return { + success: true, + service_id: newServiceId, + error: null, + }; + } catch (err: unknown) { + return { + success: true, + service_id: null, + error: getErrorMessage(err), + }; } + } + + securityGuard_remove: SecurityGuard<"service_id">; - securityGuard_remove: SecurityGuard<"service_id">; - - async remove(service_id: string, callParams: CallParams<"service_id">) { - if (!this.securityGuard_remove(callParams)) { - return { - success: false, - error: "Security guard validation failed", - service_id: null, - }; - } - - if (!this.services.has(service_id)) { - return { - success: false, - error: `Service with id ${service_id} not found`, - }; - } - - await this.peer.removeMarineService(service_id); - this.services.delete(service_id); - - return { - success: true, - error: null, - }; + async remove(service_id: string, callParams: CallParams<"service_id">) { + if (!this.securityGuard_remove(callParams)) { + return { + success: false, + error: "Security guard validation failed", + service_id: null, + }; } - list() { - return Array.from(this.services.values()); + if (!this.services.has(service_id)) { + return { + success: false, + error: `Service with id ${service_id} not found`, + }; } + + await this.peer.removeMarineService(service_id); + this.services.delete(service_id); + + return { + success: true, + error: null, + }; + } + + list() { + return Array.from(this.services.values()); + } } diff --git a/packages/core/js-client/src/services/Tracing.ts b/packages/core/js-client/src/services/Tracing.ts index e304396fe..3764aa8b4 100644 --- a/packages/core/js-client/src/services/Tracing.ts +++ b/packages/core/js-client/src/services/Tracing.ts @@ -19,13 +19,13 @@ import { CallParams } from "@fluencelabs/interfaces"; import { TracingDef } from "./_aqua/tracing.js"; export class Tracing implements TracingDef { - tracingEvent( - arrowName: string, - event: string, - callParams: CallParams<"arrowName" | "event">, - ): void { - // This console log is intentional - // eslint-disable-next-line no-console - console.log("[%s] (%s) %s", callParams.particleId, arrowName, event); - } + tracingEvent( + arrowName: string, + event: string, + callParams: CallParams<"arrowName" | "event">, + ): void { + // This console log is intentional + // eslint-disable-next-line no-console + console.log("[%s] (%s) %s", callParams.particleId, arrowName, event); + } } diff --git a/packages/core/js-client/src/services/__test__/builtInHandler.spec.ts b/packages/core/js-client/src/services/__test__/builtInHandler.spec.ts index 9bba67f1b..3d538096d 100644 --- a/packages/core/js-client/src/services/__test__/builtInHandler.spec.ts +++ b/packages/core/js-client/src/services/__test__/builtInHandler.spec.ts @@ -39,360 +39,352 @@ const oneTwoThreeFour = `[ ]`; interface ServiceCallType { - serviceId: string; - fnName: string; - args: JSONArray; - retCode: 0 | 1; - result: unknown; + serviceId: string; + fnName: string; + args: JSONArray; + retCode: 0 | 1; + result: unknown; } describe("Tests for default handler", () => { - test.each` - 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"} | ${"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"} | ${"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"} | ${"string_to_b58"} | ${["test"]} | ${0} | ${"3yZe7d"} - ${"op"} | ${"string_to_b58"} | ${["test", 1]} | ${1} | ${"string_to_b58 accepts only one string argument"} - ${"op"} | ${"string_from_b58"} | ${["3yZe7d"]} | ${0} | ${"test"} - ${"op"} | ${"string_from_b58"} | ${["3yZe7d", 1]} | ${1} | ${"string_from_b58 accepts only one string argument"} - ${"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_from_b58"} | ${["3yZe7d"]} | ${0} | ${[116, 101, 115, 116]} - ${"op"} | ${"bytes_from_b58"} | ${["3yZe7d", 1]} | ${1} | ${"bytes_from_b58 accepts only one string argument"} - ${"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"} | ${"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, "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"} - ${"debug"} | ${"stringify"} | ${[]} | ${0} | ${'""'} - ${"debug"} | ${"stringify"} | ${[{ a: 10, b: 20 }]} | ${0} | ${a10b20} - ${"debug"} | ${"stringify"} | ${[1, 2, 3, 4]} | ${0} | ${oneTwoThreeFour} - ${"math"} | ${"add"} | ${[2, 2]} | ${0} | ${4} - ${"math"} | ${"add"} | ${[2]} | ${1} | ${"Expected 2 argument(s). Got 1"} - ${"math"} | ${"sub"} | ${[2, 2]} | ${0} | ${0} - ${"math"} | ${"sub"} | ${[2, 3]} | ${0} | ${-1} - ${"math"} | ${"mul"} | ${[2, 2]} | ${0} | ${4} - ${"math"} | ${"mul"} | ${[2, 0]} | ${0} | ${0} - ${"math"} | ${"mul"} | ${[2, -1]} | ${0} | ${-2} - ${"math"} | ${"fmul"} | ${[10, 0.66]} | ${0} | ${6} - ${"math"} | ${"fmul"} | ${[0.5, 0.5]} | ${0} | ${0} - ${"math"} | ${"fmul"} | ${[100.5, 0.5]} | ${0} | ${50} - ${"math"} | ${"div"} | ${[2, 2]} | ${0} | ${1} - ${"math"} | ${"div"} | ${[2, 3]} | ${0} | ${0} - ${"math"} | ${"div"} | ${[10, 5]} | ${0} | ${2} - ${"math"} | ${"rem"} | ${[10, 3]} | ${0} | ${1} - ${"math"} | ${"pow"} | ${[2, 2]} | ${0} | ${4} - ${"math"} | ${"pow"} | ${[2, 0]} | ${0} | ${1} - ${"math"} | ${"log"} | ${[2, 2]} | ${0} | ${1} - ${"math"} | ${"log"} | ${[2, 4]} | ${0} | ${2} - ${"cmp"} | ${"gt"} | ${[2, 4]} | ${0} | ${false} - ${"cmp"} | ${"gte"} | ${[2, 4]} | ${0} | ${false} - ${"cmp"} | ${"gte"} | ${[4, 2]} | ${0} | ${true} - ${"cmp"} | ${"gte"} | ${[2, 2]} | ${0} | ${true} - ${"cmp"} | ${"lt"} | ${[2, 4]} | ${0} | ${true} - ${"cmp"} | ${"lte"} | ${[2, 4]} | ${0} | ${true} - ${"cmp"} | ${"lte"} | ${[4, 2]} | ${0} | ${false} - ${"cmp"} | ${"lte"} | ${[2, 2]} | ${0} | ${true} - ${"cmp"} | ${"cmp"} | ${[2, 4]} | ${0} | ${-1} - ${"cmp"} | ${"cmp"} | ${[2, -4]} | ${0} | ${1} - ${"cmp"} | ${"cmp"} | ${[2, 2]} | ${0} | ${0} - ${"array"} | ${"sum"} | ${[[1, 2, 3]]} | ${0} | ${6} - ${"array"} | ${"dedup"} | ${[["a", "a", "b", "c", "a", "b", "c"]]} | ${0} | ${["a", "b", "c"]} - ${"array"} | ${"intersect"} | ${[["a", "b", "c"], ["c", "b", "d"]]} | ${0} | ${["b", "c"]} - ${"array"} | ${"diff"} | ${[["a", "b", "c"], ["c", "b", "d"]]} | ${0} | ${["a"]} - ${"array"} | ${"sdiff"} | ${[["a", "b", "c"], ["c", "b", "d"]]} | ${0} | ${["a", "d"]} - ${"json"} | ${"obj"} | ${["a", 10, "b", "string", "c", null]} | ${0} | ${{ a: 10, b: "string", c: null }} - ${"json"} | ${"obj"} | ${["a", 10, "b", "string", "c"]} | ${1} | ${"Expected even number of argument(s). Got 5"} - ${"json"} | ${"obj"} | ${[]} | ${0} | ${{}} - ${"json"} | ${"put"} | ${[{}, "a", 10]} | ${0} | ${{ a: 10 }} - ${"json"} | ${"put"} | ${[{ b: 11 }, "a", 10]} | ${0} | ${{ a: 10, b: 11 }} - ${"json"} | ${"put"} | ${["a", "a", 11]} | ${1} | ${"Argument 0 expected to be of type object, Got string"} - ${"json"} | ${"put"} | ${[{}, "a", 10, "b", 20]} | ${1} | ${"Expected 3 argument(s). Got 5"} - ${"json"} | ${"put"} | ${[{}]} | ${1} | ${"Expected 3 argument(s). Got 1"} - ${"json"} | ${"puts"} | ${[{}, "a", 10]} | ${0} | ${{ a: 10 }} - ${"json"} | ${"puts"} | ${[{ b: 11 }, "a", 10]} | ${0} | ${{ a: 10, b: 11 }} - ${"json"} | ${"puts"} | ${[{}, "a", 10, "b", "string", "c", null]} | ${0} | ${{ a: 10, b: "string", c: null }} - ${"json"} | ${"puts"} | ${[{ x: "text" }, "a", 10, "b", "string"]} | ${0} | ${{ a: 10, b: "string", x: "text" }} - ${"json"} | ${"puts"} | ${[{}]} | ${1} | ${"Expected more than 3 argument(s). Got 1"} - ${"json"} | ${"puts"} | ${["a", "a", 11]} | ${1} | ${"Argument 0 expected to be of type object, Got string"} - ${"json"} | ${"stringify"} | ${[{ a: 10, b: "string", c: null }]} | ${0} | ${'{"a":10,"b":"string","c":null}'} - ${"json"} | ${"stringify"} | ${[1]} | ${1} | ${"Argument 0 expected to be of type object, Got number"} - ${"json"} | ${"parse"} | ${['{"a":10,"b":"string","c":null}']} | ${0} | ${{ a: 10, b: "string", c: null }} - ${"json"} | ${"parse"} | ${["incorrect"]} | ${1} | ${"Unexpected token i in JSON at position 0"} - ${"json"} | ${"parse"} | ${[10]} | ${1} | ${"Argument 0 expected to be of type string, Got number"} - `( - // - "$fnName with $args expected retcode: $retCode and result: $result", - async ({ - serviceId, - fnName, - args, - retCode, - result, - }: ServiceCallType) => { - // arrange - const req: CallServiceData = { - serviceId: serviceId, - fnName: fnName, - args: args, - tetraplets: [], - particleContext: { - particleId: "some", - initPeerId: "init peer id", - timestamp: 595951200, - ttl: 595961200, - signature: new Uint8Array([]), - }, - }; - - // act - const fn = builtInServices[req.serviceId][req.fnName]; - const res = await fn(req); - - // Our test cases above depend on node error message. In node 20 error message for JSON.parse has changed. - // Simple and fast solution for this specific case is to unify both variations into node 18 version error format. - if ( - res.result === - "Unexpected token 'i', \"incorrect\" is not valid JSON" - ) { - res.result = "Unexpected token i in JSON at position 0"; - } - - // assert - expect(res).toMatchObject({ - retCode: retCode, - result: result, - }); + test.each` + 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"} | ${"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"} | ${"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"} | ${"string_to_b58"} | ${["test"]} | ${0} | ${"3yZe7d"} + ${"op"} | ${"string_to_b58"} | ${["test", 1]} | ${1} | ${"string_to_b58 accepts only one string argument"} + ${"op"} | ${"string_from_b58"} | ${["3yZe7d"]} | ${0} | ${"test"} + ${"op"} | ${"string_from_b58"} | ${["3yZe7d", 1]} | ${1} | ${"string_from_b58 accepts only one string argument"} + ${"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_from_b58"} | ${["3yZe7d"]} | ${0} | ${[116, 101, 115, 116]} + ${"op"} | ${"bytes_from_b58"} | ${["3yZe7d", 1]} | ${1} | ${"bytes_from_b58 accepts only one string argument"} + ${"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"} | ${"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, "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"} + ${"debug"} | ${"stringify"} | ${[]} | ${0} | ${'""'} + ${"debug"} | ${"stringify"} | ${[{ a: 10, b: 20 }]} | ${0} | ${a10b20} + ${"debug"} | ${"stringify"} | ${[1, 2, 3, 4]} | ${0} | ${oneTwoThreeFour} + ${"math"} | ${"add"} | ${[2, 2]} | ${0} | ${4} + ${"math"} | ${"add"} | ${[2]} | ${1} | ${"Expected 2 argument(s). Got 1"} + ${"math"} | ${"sub"} | ${[2, 2]} | ${0} | ${0} + ${"math"} | ${"sub"} | ${[2, 3]} | ${0} | ${-1} + ${"math"} | ${"mul"} | ${[2, 2]} | ${0} | ${4} + ${"math"} | ${"mul"} | ${[2, 0]} | ${0} | ${0} + ${"math"} | ${"mul"} | ${[2, -1]} | ${0} | ${-2} + ${"math"} | ${"fmul"} | ${[10, 0.66]} | ${0} | ${6} + ${"math"} | ${"fmul"} | ${[0.5, 0.5]} | ${0} | ${0} + ${"math"} | ${"fmul"} | ${[100.5, 0.5]} | ${0} | ${50} + ${"math"} | ${"div"} | ${[2, 2]} | ${0} | ${1} + ${"math"} | ${"div"} | ${[2, 3]} | ${0} | ${0} + ${"math"} | ${"div"} | ${[10, 5]} | ${0} | ${2} + ${"math"} | ${"rem"} | ${[10, 3]} | ${0} | ${1} + ${"math"} | ${"pow"} | ${[2, 2]} | ${0} | ${4} + ${"math"} | ${"pow"} | ${[2, 0]} | ${0} | ${1} + ${"math"} | ${"log"} | ${[2, 2]} | ${0} | ${1} + ${"math"} | ${"log"} | ${[2, 4]} | ${0} | ${2} + ${"cmp"} | ${"gt"} | ${[2, 4]} | ${0} | ${false} + ${"cmp"} | ${"gte"} | ${[2, 4]} | ${0} | ${false} + ${"cmp"} | ${"gte"} | ${[4, 2]} | ${0} | ${true} + ${"cmp"} | ${"gte"} | ${[2, 2]} | ${0} | ${true} + ${"cmp"} | ${"lt"} | ${[2, 4]} | ${0} | ${true} + ${"cmp"} | ${"lte"} | ${[2, 4]} | ${0} | ${true} + ${"cmp"} | ${"lte"} | ${[4, 2]} | ${0} | ${false} + ${"cmp"} | ${"lte"} | ${[2, 2]} | ${0} | ${true} + ${"cmp"} | ${"cmp"} | ${[2, 4]} | ${0} | ${-1} + ${"cmp"} | ${"cmp"} | ${[2, -4]} | ${0} | ${1} + ${"cmp"} | ${"cmp"} | ${[2, 2]} | ${0} | ${0} + ${"array"} | ${"sum"} | ${[[1, 2, 3]]} | ${0} | ${6} + ${"array"} | ${"dedup"} | ${[["a", "a", "b", "c", "a", "b", "c"]]} | ${0} | ${["a", "b", "c"]} + ${"array"} | ${"intersect"} | ${[["a", "b", "c"], ["c", "b", "d"]]} | ${0} | ${["b", "c"]} + ${"array"} | ${"diff"} | ${[["a", "b", "c"], ["c", "b", "d"]]} | ${0} | ${["a"]} + ${"array"} | ${"sdiff"} | ${[["a", "b", "c"], ["c", "b", "d"]]} | ${0} | ${["a", "d"]} + ${"json"} | ${"obj"} | ${["a", 10, "b", "string", "c", null]} | ${0} | ${{ a: 10, b: "string", c: null }} + ${"json"} | ${"obj"} | ${["a", 10, "b", "string", "c"]} | ${1} | ${"Expected even number of argument(s). Got 5"} + ${"json"} | ${"obj"} | ${[]} | ${0} | ${{}} + ${"json"} | ${"put"} | ${[{}, "a", 10]} | ${0} | ${{ a: 10 }} + ${"json"} | ${"put"} | ${[{ b: 11 }, "a", 10]} | ${0} | ${{ a: 10, b: 11 }} + ${"json"} | ${"put"} | ${["a", "a", 11]} | ${1} | ${"Argument 0 expected to be of type object, Got string"} + ${"json"} | ${"put"} | ${[{}, "a", 10, "b", 20]} | ${1} | ${"Expected 3 argument(s). Got 5"} + ${"json"} | ${"put"} | ${[{}]} | ${1} | ${"Expected 3 argument(s). Got 1"} + ${"json"} | ${"puts"} | ${[{}, "a", 10]} | ${0} | ${{ a: 10 }} + ${"json"} | ${"puts"} | ${[{ b: 11 }, "a", 10]} | ${0} | ${{ a: 10, b: 11 }} + ${"json"} | ${"puts"} | ${[{}, "a", 10, "b", "string", "c", null]} | ${0} | ${{ a: 10, b: "string", c: null }} + ${"json"} | ${"puts"} | ${[{ x: "text" }, "a", 10, "b", "string"]} | ${0} | ${{ a: 10, b: "string", x: "text" }} + ${"json"} | ${"puts"} | ${[{}]} | ${1} | ${"Expected more than 3 argument(s). Got 1"} + ${"json"} | ${"puts"} | ${["a", "a", 11]} | ${1} | ${"Argument 0 expected to be of type object, Got string"} + ${"json"} | ${"stringify"} | ${[{ a: 10, b: "string", c: null }]} | ${0} | ${'{"a":10,"b":"string","c":null}'} + ${"json"} | ${"stringify"} | ${[1]} | ${1} | ${"Argument 0 expected to be of type object, Got number"} + ${"json"} | ${"parse"} | ${['{"a":10,"b":"string","c":null}']} | ${0} | ${{ a: 10, b: "string", c: null }} + ${"json"} | ${"parse"} | ${["incorrect"]} | ${1} | ${"Unexpected token i in JSON at position 0"} + ${"json"} | ${"parse"} | ${[10]} | ${1} | ${"Argument 0 expected to be of type string, Got number"} + `( + // + "$fnName with $args expected retcode: $retCode and result: $result", + async ({ serviceId, fnName, args, retCode, result }: ServiceCallType) => { + // arrange + const req: CallServiceData = { + serviceId: serviceId, + fnName: fnName, + args: args, + tetraplets: [], + particleContext: { + particleId: "some", + initPeerId: "init peer id", + timestamp: 595951200, + ttl: 595961200, + signature: new Uint8Array([]), }, - ); + }; + + // act + const fn = builtInServices[req.serviceId][req.fnName]; + const res = await fn(req); + + // Our test cases above depend on node error message. In node 20 error message for JSON.parse has changed. + // Simple and fast solution for this specific case is to unify both variations into node 18 version error format. + if ( + res.result === "Unexpected token 'i', \"incorrect\" is not valid JSON" + ) { + res.result = "Unexpected token i in JSON at position 0"; + } + + // assert + expect(res).toMatchObject({ + retCode: retCode, + result: result, + }); + }, + ); + + it("should return correct error message for identiy service", async () => { + // arrange + const req: CallServiceData = { + serviceId: "peer", + fnName: "identify", + args: [], + tetraplets: [], + particleContext: { + particleId: "some", + initPeerId: "init peer id", + timestamp: 595951200, + ttl: 595961200, + signature: new Uint8Array([]), + }, + }; - it("should return correct error message for identiy service", async () => { - // arrange - const req: CallServiceData = { - serviceId: "peer", - fnName: "identify", - args: [], - tetraplets: [], - particleContext: { - particleId: "some", - initPeerId: "init peer id", - timestamp: 595951200, - ttl: 595961200, - signature: new Uint8Array([]), - }, - }; - - // act - const fn = builtInServices[req.serviceId][req.fnName]; - const res = await fn(req); - - // assert - expect(res).toMatchObject({ - retCode: 0, - result: { - external_addresses: [], - // stringContaining method returns any for some reason - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - node_version: expect.stringContaining("js"), - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - air_version: expect.stringContaining("js"), - }, - }); + // act + const fn = builtInServices[req.serviceId][req.fnName]; + const res = await fn(req); + + // assert + expect(res).toMatchObject({ + retCode: 0, + result: { + external_addresses: [], + // stringContaining method returns any for some reason + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + node_version: expect.stringContaining("js"), + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + air_version: expect.stringContaining("js"), + }, }); + }); }); const key = "+cmeYlZKj+MfSa9dpHV+BmLPm6wq4inGlsPlQ1GvtPk="; const context = (async () => { - const keyBytes = toUint8Array(key); - const kp = await KeyPair.fromEd25519SK(keyBytes); + const keyBytes = toUint8Array(key); + const kp = await KeyPair.fromEd25519SK(keyBytes); - const res = { - peerKeyPair: kp, - peerId: kp.getPeerId(), - }; + const res = { + peerKeyPair: kp, + peerId: kp.getPeerId(), + }; - return res; + return res; })(); const testData = [1, 2, 3, 4, 5, 6, 7, 9, 10]; // signature produced by KeyPair created from key above (`key` variable) const testDataSig = [ - 224, 104, 245, 206, 140, 248, 27, 72, 68, 133, 111, 10, 164, 197, 242, 132, - 107, 77, 224, 67, 99, 106, 76, 29, 144, 121, 122, 169, 36, 173, 58, 80, 170, - 102, 137, 253, 157, 247, 168, 87, 162, 223, 188, 214, 203, 220, 52, 246, 29, - 86, 77, 71, 224, 248, 16, 213, 254, 75, 78, 239, 243, 222, 241, 15, + 224, 104, 245, 206, 140, 248, 27, 72, 68, 133, 111, 10, 164, 197, 242, 132, + 107, 77, 224, 67, 99, 106, 76, 29, 144, 121, 122, 169, 36, 173, 58, 80, 170, + 102, 137, 253, 157, 247, 168, 87, 162, 223, 188, 214, 203, 220, 52, 246, 29, + 86, 77, 71, 224, 248, 16, 213, 254, 75, 78, 239, 243, 222, 241, 15, ]; // signature produced by KeyPair created from some random KeyPair const testDataWrongSig = [ - 116, 247, 189, 118, 236, 53, 147, 123, 219, 75, 176, 105, 101, 108, 233, - 137, 97, 14, 146, 132, 252, 70, 51, 153, 237, 167, 156, 150, 36, 90, 229, - 108, 166, 231, 255, 137, 8, 246, 125, 0, 213, 150, 83, 196, 237, 221, 131, - 159, 157, 159, 25, 109, 95, 160, 181, 65, 254, 238, 47, 156, 240, 151, 58, - 14, + 116, 247, 189, 118, 236, 53, 147, 123, 219, 75, 176, 105, 101, 108, 233, 137, + 97, 14, 146, 132, 252, 70, 51, 153, 237, 167, 156, 150, 36, 90, 229, 108, 166, + 231, 255, 137, 8, 246, 125, 0, 213, 150, 83, 196, 237, 221, 131, 159, 157, + 159, 25, 109, 95, 160, 181, 65, 254, 238, 47, 156, 240, 151, 58, 14, ]; const makeTestTetraplet = ( - initPeerId: string, - serviceId: string, - fnName: string, + initPeerId: string, + serviceId: string, + fnName: string, ): CallParams<"data"> => { - return { - particleId: "", - timestamp: 0, - ttl: 0, - initPeerId: initPeerId, - tetraplets: { - data: [ - { - peer_pk: initPeerId, - function_name: fnName, - service_id: serviceId, - json_path: "", - }, - ], + return { + particleId: "", + timestamp: 0, + ttl: 0, + initPeerId: initPeerId, + tetraplets: { + data: [ + { + peer_pk: initPeerId, + function_name: fnName, + service_id: serviceId, + json_path: "", }, - }; + ], + }, + }; }; describe("Sig service tests", () => { - it("sig.sign should create the correct signature", async () => { - const ctx = await context; - const sig = new Sig(ctx.peerKeyPair); + it("sig.sign should create the correct signature", async () => { + const ctx = await context; + const sig = new Sig(ctx.peerKeyPair); - const res = await sig.sign( - testData, - makeTestTetraplet(ctx.peerId, "any_service", "any_func"), - ); + const res = await sig.sign( + testData, + makeTestTetraplet(ctx.peerId, "any_service", "any_func"), + ); - expect(res.success).toBe(true); - expect(res.signature).toStrictEqual(testDataSig); - }); + expect(res.success).toBe(true); + expect(res.signature).toStrictEqual(testDataSig); + }); - it("sig.verify should return true for the correct signature", async () => { - const ctx = await context; - const sig = new Sig(ctx.peerKeyPair); + it("sig.verify should return true for the correct signature", async () => { + const ctx = await context; + const sig = new Sig(ctx.peerKeyPair); - const res = await sig.verify(testDataSig, testData); + const res = await sig.verify(testDataSig, testData); - expect(res).toBe(true); - }); + expect(res).toBe(true); + }); - it("sig.verify should return false for the incorrect signature", async () => { - const ctx = await context; - const sig = new Sig(ctx.peerKeyPair); + it("sig.verify should return false for the incorrect signature", async () => { + const ctx = await context; + const sig = new Sig(ctx.peerKeyPair); - const res = await sig.verify(testDataWrongSig, testData); + const res = await sig.verify(testDataWrongSig, testData); - expect(res).toBe(false); - }); + expect(res).toBe(false); + }); - it("sign-verify call chain should work", async () => { - const ctx = await context; - const sig = new Sig(ctx.peerKeyPair); + it("sign-verify call chain should work", async () => { + const ctx = await context; + const sig = new Sig(ctx.peerKeyPair); - const signature = await sig.sign( - testData, - makeTestTetraplet(ctx.peerId, "any_service", "any_func"), - ); + const signature = await sig.sign( + testData, + makeTestTetraplet(ctx.peerId, "any_service", "any_func"), + ); - expect(signature.success).toBe(true); - assert(signature.success); - const res = await sig.verify(signature.signature, testData); + expect(signature.success).toBe(true); + assert(signature.success); + const res = await sig.verify(signature.signature, testData); - expect(res).toBe(true); - }); + expect(res).toBe(true); + }); - it("sig.sign with defaultSigGuard should work for correct callParams", async () => { - const ctx = await context; - const sig = new Sig(ctx.peerKeyPair); - sig.securityGuard = defaultSigGuard(ctx.peerId); + it("sig.sign with defaultSigGuard should work for correct callParams", async () => { + const ctx = await context; + const sig = new Sig(ctx.peerKeyPair); + sig.securityGuard = defaultSigGuard(ctx.peerId); - const signature = await sig.sign( - testData, - makeTestTetraplet(ctx.peerId, "registry", "get_route_bytes"), - ); + const signature = await sig.sign( + testData, + makeTestTetraplet(ctx.peerId, "registry", "get_route_bytes"), + ); - expect(signature).toBeDefined(); - }); + expect(signature).toBeDefined(); + }); - it("sig.sign with defaultSigGuard should not allow particles initiated from incorrect service", async () => { - const ctx = await context; - const sig = new Sig(ctx.peerKeyPair); - sig.securityGuard = defaultSigGuard(ctx.peerId); + it("sig.sign with defaultSigGuard should not allow particles initiated from incorrect service", async () => { + const ctx = await context; + const sig = new Sig(ctx.peerKeyPair); + sig.securityGuard = defaultSigGuard(ctx.peerId); - const res = await sig.sign( - testData, - makeTestTetraplet(ctx.peerId, "other_service", "other_fn"), - ); + const res = await sig.sign( + testData, + makeTestTetraplet(ctx.peerId, "other_service", "other_fn"), + ); - expect(res.success).toBe(false); - expect(res.error).toBe("Security guard validation failed"); - }); + expect(res.success).toBe(false); + expect(res.error).toBe("Security guard validation failed"); + }); + + it("sig.sign with defaultSigGuard should not allow particles initiated from other peers", async () => { + const ctx = await context; + const sig = new Sig(ctx.peerKeyPair); + sig.securityGuard = defaultSigGuard(ctx.peerId); + + const res = await sig.sign( + testData, + makeTestTetraplet( + (await KeyPair.randomEd25519()).getPeerId(), + "registry", + "get_key_bytes", + ), + ); - it("sig.sign with defaultSigGuard should not allow particles initiated from other peers", async () => { - const ctx = await context; - const sig = new Sig(ctx.peerKeyPair); - sig.securityGuard = defaultSigGuard(ctx.peerId); - - const res = await sig.sign( - testData, - makeTestTetraplet( - (await KeyPair.randomEd25519()).getPeerId(), - "registry", - "get_key_bytes", - ), - ); - - expect(res.success).toBe(false); - expect(res.error).toBe("Security guard validation failed"); - }); + expect(res.success).toBe(false); + expect(res.error).toBe("Security guard validation failed"); + }); - it("changing securityGuard should work", async () => { - const ctx = await context; - const sig = new Sig(ctx.peerKeyPair); - sig.securityGuard = allowServiceFn("test", "test"); - - const successful1 = await sig.sign( - testData, - makeTestTetraplet(ctx.peerId, "test", "test"), - ); - - const unSuccessful1 = await sig.sign( - testData, - makeTestTetraplet(ctx.peerId, "wrong", "wrong"), - ); - - sig.securityGuard = allowServiceFn("wrong", "wrong"); - - const successful2 = await sig.sign( - testData, - makeTestTetraplet(ctx.peerId, "wrong", "wrong"), - ); - - const unSuccessful2 = await sig.sign( - testData, - makeTestTetraplet(ctx.peerId, "test", "test"), - ); - - expect(successful1.success).toBe(true); - expect(successful2.success).toBe(true); - expect(unSuccessful1.success).toBe(false); - expect(unSuccessful2.success).toBe(false); - }); + it("changing securityGuard should work", async () => { + const ctx = await context; + const sig = new Sig(ctx.peerKeyPair); + sig.securityGuard = allowServiceFn("test", "test"); + + const successful1 = await sig.sign( + testData, + makeTestTetraplet(ctx.peerId, "test", "test"), + ); + + const unSuccessful1 = await sig.sign( + testData, + makeTestTetraplet(ctx.peerId, "wrong", "wrong"), + ); + + sig.securityGuard = allowServiceFn("wrong", "wrong"); + + const successful2 = await sig.sign( + testData, + makeTestTetraplet(ctx.peerId, "wrong", "wrong"), + ); + + const unSuccessful2 = await sig.sign( + testData, + makeTestTetraplet(ctx.peerId, "test", "test"), + ); + + expect(successful1.success).toBe(true); + expect(successful2.success).toBe(true); + expect(unSuccessful1.success).toBe(false); + expect(unSuccessful2.success).toBe(false); + }); }); diff --git a/packages/core/js-client/src/services/__test__/jsonBuiltin.spec.ts b/packages/core/js-client/src/services/__test__/jsonBuiltin.spec.ts index 61795b39e..430ee6098 100644 --- a/packages/core/js-client/src/services/__test__/jsonBuiltin.spec.ts +++ b/packages/core/js-client/src/services/__test__/jsonBuiltin.spec.ts @@ -23,17 +23,17 @@ import { mkTestPeer } from "../../util/testUtils.js"; let peer: FluencePeer; describe("Sig service test suite", () => { - afterEach(async () => { - await peer.stop(); - }); + afterEach(async () => { + await peer.stop(); + }); - beforeEach(async () => { - peer = await mkTestPeer(); - await peer.start(); - }); + beforeEach(async () => { + peer = await mkTestPeer(); + await peer.start(); + }); - it("JSON builtin spec", async () => { - const script = ` + it("JSON builtin spec", async () => { + const script = ` (seq (seq (seq @@ -61,40 +61,40 @@ describe("Sig service test suite", () => { ) `; - const promise = new Promise((resolve) => { - peer.internals.regHandler.common("res", "res", (req) => { - resolve(req.args); - return { - result: {}, - retCode: 0, - }; - }); - }); + const promise = new Promise((resolve) => { + peer.internals.regHandler.common("res", "res", (req) => { + resolve(req.args); + return { + result: {}, + retCode: 0, + }; + }); + }); - const p = await peer.internals.createNewParticle(script); - peer.internals.initiateParticle(p, doNothing); + const p = await peer.internals.createNewParticle(script); + peer.internals.initiateParticle(p, doNothing); - const [ - nestedFirst, - nestedSecond, - outerFirst, - outerSecond, - outerFirstString, - outerFirstParsed, - ] = await promise; + const [ + nestedFirst, + nestedSecond, + outerFirst, + outerSecond, + outerFirstString, + outerFirstParsed, + ] = await promise; - const nfExpected = { name: "nested_first", num: 1 }; - const nsExpected = { name: "nested_second", num: 2 }; + const nfExpected = { name: "nested_first", num: 1 }; + const nsExpected = { name: "nested_second", num: 2 }; - const ofExpected = { name: "outer_first", nested: nfExpected, num: 0 }; - const ofString = JSON.stringify(ofExpected); - const osExpected = { name: "outer_second", num: 3, nested: nsExpected }; + const ofExpected = { name: "outer_first", nested: nfExpected, num: 0 }; + const ofString = JSON.stringify(ofExpected); + const osExpected = { name: "outer_second", num: 3, nested: nsExpected }; - expect(nestedFirst).toMatchObject(nfExpected); - expect(nestedSecond).toMatchObject(nsExpected); - expect(outerFirst).toMatchObject(ofExpected); - expect(outerSecond).toMatchObject(osExpected); - expect(outerFirstParsed).toMatchObject(ofExpected); - expect(outerFirstString).toBe(ofString); - }); + expect(nestedFirst).toMatchObject(nfExpected); + expect(nestedSecond).toMatchObject(nsExpected); + expect(outerFirst).toMatchObject(ofExpected); + expect(outerSecond).toMatchObject(osExpected); + expect(outerFirstParsed).toMatchObject(ofExpected); + expect(outerFirstString).toBe(ofString); + }); }); diff --git a/packages/core/js-client/src/services/__test__/sigService.spec.ts b/packages/core/js-client/src/services/__test__/sigService.spec.ts index b51695034..c46ffffaf 100644 --- a/packages/core/js-client/src/services/__test__/sigService.spec.ts +++ b/packages/core/js-client/src/services/__test__/sigService.spec.ts @@ -33,155 +33,145 @@ let sigDef: ServiceDef; let dataProviderDef: ServiceDef; describe("Sig service test suite", () => { - beforeAll(async () => { - const pathToAquaFiles = path.join( - __dirname, - "../../../aqua_test/sigService.aqua", - ); + beforeAll(async () => { + const pathToAquaFiles = path.join( + __dirname, + "../../../aqua_test/sigService.aqua", + ); + + const { services, functions } = await compileAqua(pathToAquaFiles); + + aqua = functions; + sigDef = services["Sig"]; + dataProviderDef = services["DataProvider"]; + }); + + it("Use custom sig service, success path", async () => { + await withPeer(async (peer) => { + const customKeyPair = await KeyPair.randomEd25519(); + const customSig = new Sig(customKeyPair); + const data = [1, 2, 3, 4, 5]; + + registerService({ + peer, + def: sigDef, + serviceId: "CustomSig", + // TODO: fix this after changing registerService signature + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + service: customSig as unknown as ServiceImpl, + }); + + registerService({ + peer, + def: dataProviderDef, + serviceId: "data", + service: { + provide_data: () => { + return data; + }, + }, + }); + + customSig.securityGuard = allowServiceFn("data", "provide_data"); + + const result = await aqua["callSig"](peer, { sigId: "CustomSig" }); + + expect(result).toHaveProperty("success", true); + + const isSigCorrect = await customSig.verify( + // TODO: Use compiled ts wrappers + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + (result as { signature: number[] }).signature, + data, + ); + + expect(isSigCorrect).toBe(true); + }); + }); + + it("Use custom sig service, fail path", async () => { + await withPeer(async (peer) => { + const customKeyPair = await KeyPair.randomEd25519(); + const customSig = new Sig(customKeyPair); + const data = [1, 2, 3, 4, 5]; + + registerService({ + peer, + def: sigDef, + serviceId: "CustomSig", + // TODO: fix this after changing registerService signature + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + service: customSig as unknown as ServiceImpl, + }); + + registerService({ + peer, + def: dataProviderDef, + serviceId: "data", + service: { + provide_data: () => { + return data; + }, + }, + }); + + customSig.securityGuard = allowServiceFn("wrong", "wrong"); + + const result = await aqua["callSig"](peer, { sigId: "CustomSig" }); + expect(result).toHaveProperty("success", false); + }); + }); - const { services, functions } = await compileAqua(pathToAquaFiles); + it("Default sig service should be resolvable by peer id", async () => { + await withPeer(async (peer) => { + const sig = peer.internals.getServices().sig; - aqua = functions; - sigDef = services["Sig"]; - dataProviderDef = services["DataProvider"]; - }); + const data = [1, 2, 3, 4, 5]; - it("Use custom sig service, success path", async () => { - await withPeer(async (peer) => { - const customKeyPair = await KeyPair.randomEd25519(); - const customSig = new Sig(customKeyPair); - const data = [1, 2, 3, 4, 5]; - - registerService({ - peer, - def: sigDef, - serviceId: "CustomSig", - // TODO: fix this after changing registerService signature - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - service: customSig as unknown as ServiceImpl, - }); - - registerService({ - peer, - def: dataProviderDef, - serviceId: "data", - service: { - provide_data: () => { - return data; - }, - }, - }); - - customSig.securityGuard = allowServiceFn("data", "provide_data"); - - const result = await aqua["callSig"](peer, { sigId: "CustomSig" }); - - expect(result).toHaveProperty("success", true); - - const isSigCorrect = await customSig.verify( - // TODO: Use compiled ts wrappers - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - (result as { signature: number[] }).signature, - data, - ); - - expect(isSigCorrect).toBe(true); - }); - }); + registerService({ + peer: peer, + def: dataProviderDef, + serviceId: "data", + service: { + provide_data: () => { + return data; + }, + }, + }); - it("Use custom sig service, fail path", async () => { - await withPeer(async (peer) => { - const customKeyPair = await KeyPair.randomEd25519(); - const customSig = new Sig(customKeyPair); - const data = [1, 2, 3, 4, 5]; - - registerService({ - peer, - def: sigDef, - serviceId: "CustomSig", - // TODO: fix this after changing registerService signature - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - service: customSig as unknown as ServiceImpl, - }); - - registerService({ - peer, - def: dataProviderDef, - serviceId: "data", - service: { - provide_data: () => { - return data; - }, - }, - }); - - customSig.securityGuard = allowServiceFn("wrong", "wrong"); - - const result = await aqua["callSig"](peer, { sigId: "CustomSig" }); - expect(result).toHaveProperty("success", false); - }); - }); + const callAsSigRes = await aqua["callSig"](peer, { sigId: "sig" }); + + const callAsPeerIdRes = await aqua["callSig"](peer, { + sigId: peer.keyPair.getPeerId(), + }); + + expect(callAsSigRes).toHaveProperty("success", false); + expect(callAsPeerIdRes).toHaveProperty("success", false); + + sig.securityGuard = () => { + return true; + }; + + const callAsSigResAfterGuardChange = await aqua["callSig"](peer, { + sigId: "sig", + }); + + const callAsPeerIdResAfterGuardChange = await aqua["callSig"](peer, { + sigId: peer.keyPair.getPeerId(), + }); + + expect(callAsSigResAfterGuardChange).toHaveProperty("success", true); + + expect(callAsPeerIdResAfterGuardChange).toHaveProperty("success", true); + + const isValid = await sig.verify( + // TODO: Use compiled ts wrappers + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + (callAsSigResAfterGuardChange as { signature: number[] }).signature, + data, + ); - it("Default sig service should be resolvable by peer id", async () => { - await withPeer(async (peer) => { - const sig = peer.internals.getServices().sig; - - const data = [1, 2, 3, 4, 5]; - - registerService({ - peer: peer, - def: dataProviderDef, - serviceId: "data", - service: { - provide_data: () => { - return data; - }, - }, - }); - - const callAsSigRes = await aqua["callSig"](peer, { sigId: "sig" }); - - const callAsPeerIdRes = await aqua["callSig"](peer, { - sigId: peer.keyPair.getPeerId(), - }); - - expect(callAsSigRes).toHaveProperty("success", false); - expect(callAsPeerIdRes).toHaveProperty("success", false); - - sig.securityGuard = () => { - return true; - }; - - const callAsSigResAfterGuardChange = await aqua["callSig"](peer, { - sigId: "sig", - }); - - const callAsPeerIdResAfterGuardChange = await aqua["callSig"]( - peer, - { - sigId: peer.keyPair.getPeerId(), - }, - ); - - expect(callAsSigResAfterGuardChange).toHaveProperty( - "success", - true, - ); - - expect(callAsPeerIdResAfterGuardChange).toHaveProperty( - "success", - true, - ); - - const isValid = await sig.verify( - // TODO: Use compiled ts wrappers - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - (callAsSigResAfterGuardChange as { signature: number[] }) - .signature, - data, - ); - - expect(isValid).toBe(true); - }); + expect(isValid).toBe(true); }); + }); }); diff --git a/packages/core/js-client/src/services/__test__/srv.spec.ts b/packages/core/js-client/src/services/__test__/srv.spec.ts index d76997988..caaa3054f 100644 --- a/packages/core/js-client/src/services/__test__/srv.spec.ts +++ b/packages/core/js-client/src/services/__test__/srv.spec.ts @@ -27,97 +27,85 @@ const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); let aqua: Record; describe("Srv service test suite", () => { - beforeAll(async () => { - const pathToAquaFiles = path.join( - __dirname, - "../../../aqua_test/srv.aqua", - ); - - const { functions } = await compileAqua(pathToAquaFiles); - aqua = functions; - }); + beforeAll(async () => { + const pathToAquaFiles = path.join(__dirname, "../../../aqua_test/srv.aqua"); + + const { functions } = await compileAqua(pathToAquaFiles); + aqua = functions; + }); - it("Use custom srv service, success path", async () => { - await withPeer(async (peer) => { - // arrange - registerNodeUtils(peer, "node_utils", new NodeUtils(peer)); + it("Use custom srv service, success path", async () => { + await withPeer(async (peer) => { + // arrange + registerNodeUtils(peer, "node_utils", new NodeUtils(peer)); - const wasm = path.join( - __dirname, - "../../../data_for_test/greeting.wasm", - ); + const wasm = path.join(__dirname, "../../../data_for_test/greeting.wasm"); - // act - const res = await aqua["happy_path"](peer, { file_path: wasm }); + // act + const res = await aqua["happy_path"](peer, { file_path: wasm }); - // assert - expect(res).toBe("Hi, test"); - }); + // assert + expect(res).toBe("Hi, test"); }); + }); - it("List deployed services", async () => { - await withPeer(async (peer) => { - // arrange - registerNodeUtils(peer, "node_utils", new NodeUtils(peer)); + it("List deployed services", async () => { + await withPeer(async (peer) => { + // arrange + registerNodeUtils(peer, "node_utils", new NodeUtils(peer)); - const wasm = path.join( - __dirname, - "../../../data_for_test/greeting.wasm", - ); + const wasm = path.join(__dirname, "../../../data_for_test/greeting.wasm"); - // act - const res = await aqua["list_services"](peer, { file_path: wasm }); + // act + const res = await aqua["list_services"](peer, { file_path: wasm }); - // assert - expect(res).toHaveLength(3); - }); + // assert + expect(res).toHaveLength(3); }); + }); - it("Correct error for removed services", async () => { - await withPeer(async (peer) => { - // arrange - registerNodeUtils(peer, "node_utils", new NodeUtils(peer)); + it("Correct error for removed services", async () => { + await withPeer(async (peer) => { + // arrange + registerNodeUtils(peer, "node_utils", new NodeUtils(peer)); - const wasm = path.join( - __dirname, - "../../../data_for_test/greeting.wasm", - ); + const wasm = path.join(__dirname, "../../../data_for_test/greeting.wasm"); - // act - const res = await aqua["service_removed"](peer, { - file_path: wasm, - }); + // act + const res = await aqua["service_removed"](peer, { + file_path: wasm, + }); - // assert - expect(res).toMatch("No service found for service call"); - }); + // assert + expect(res).toMatch("No service found for service call"); }); + }); - it("Correct error for file not found", async () => { - await withPeer(async (peer) => { - // arrange - registerNodeUtils(peer, "node_utils", new NodeUtils(peer)); + it("Correct error for file not found", async () => { + await withPeer(async (peer) => { + // arrange + registerNodeUtils(peer, "node_utils", new NodeUtils(peer)); - // act - const res = await aqua["file_not_found"](peer, {}); + // act + const res = await aqua["file_not_found"](peer, {}); - // assert - expect(res).toMatch( - "ENOENT: no such file or directory, open '/random/incorrect/file'", - ); - }); + // assert + expect(res).toMatch( + "ENOENT: no such file or directory, open '/random/incorrect/file'", + ); }); + }); - it("Correct error for removing non existing service", async () => { - await withPeer(async (peer) => { - // arrange - registerNodeUtils(peer, "node_utils", new NodeUtils(peer)); + it("Correct error for removing non existing service", async () => { + await withPeer(async (peer) => { + // arrange + registerNodeUtils(peer, "node_utils", new NodeUtils(peer)); - // act - const res = await aqua["removing_non_exiting"](peer, {}); + // act + const res = await aqua["removing_non_exiting"](peer, {}); - // assert - expect(res).toMatch("Service with id random_id not found"); - }); + // assert + expect(res).toMatch("Service with id random_id not found"); }); + }); }); diff --git a/packages/core/js-client/src/services/_aqua/node-utils.ts b/packages/core/js-client/src/services/_aqua/node-utils.ts index 94fc988fd..c9debf71d 100644 --- a/packages/core/js-client/src/services/_aqua/node-utils.ts +++ b/packages/core/js-client/src/services/_aqua/node-utils.ts @@ -26,79 +26,79 @@ import { NodeUtils } from "../NodeUtils.js"; // Services export interface NodeUtilsDef { - read_file: ( - path: string, - callParams: CallParams<"path">, - ) => - | { content: string | null; error: string | null; success: boolean } - | Promise<{ - content: string | null; - error: string | null; - success: boolean; - }>; + read_file: ( + path: string, + callParams: CallParams<"path">, + ) => + | { content: string | null; error: string | null; success: boolean } + | Promise<{ + content: string | null; + error: string | null; + success: boolean; + }>; } export function registerNodeUtils( - peer: FluencePeer, - serviceId: string, - service: NodeUtils, + peer: FluencePeer, + serviceId: string, + service: NodeUtils, ) { - registerService({ - peer, - // TODO: fix this after changing registerService signature - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - service: service as unknown as ServiceImpl, - serviceId, - def: { - defaultServiceId: "node_utils", - functions: { - tag: "labeledProduct", - fields: { - read_file: { - tag: "arrow", - domain: { - tag: "labeledProduct", - fields: { - path: { - tag: "scalar", - name: "string", - }, - }, - }, - codomain: { - tag: "unlabeledProduct", - items: [ - { - tag: "struct", - name: "ReadFileResult", - fields: { - content: { - tag: "option", - type: { - tag: "scalar", - name: "string", - }, - }, - error: { - tag: "option", - type: { - tag: "scalar", - name: "string", - }, - }, - success: { - tag: "scalar", - name: "bool", - }, - }, - }, - ], - }, + registerService({ + peer, + // TODO: fix this after changing registerService signature + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + service: service as unknown as ServiceImpl, + serviceId, + def: { + defaultServiceId: "node_utils", + functions: { + tag: "labeledProduct", + fields: { + read_file: { + tag: "arrow", + domain: { + tag: "labeledProduct", + fields: { + path: { + tag: "scalar", + name: "string", + }, + }, + }, + codomain: { + tag: "unlabeledProduct", + items: [ + { + tag: "struct", + name: "ReadFileResult", + fields: { + content: { + tag: "option", + type: { + tag: "scalar", + name: "string", + }, + }, + error: { + tag: "option", + type: { + tag: "scalar", + name: "string", + }, + }, + success: { + tag: "scalar", + name: "bool", }, + }, }, + ], }, + }, }, - }); + }, + }, + }); } // Functions diff --git a/packages/core/js-client/src/services/_aqua/services.ts b/packages/core/js-client/src/services/_aqua/services.ts index 0d2bdb0e6..896ad0a86 100644 --- a/packages/core/js-client/src/services/_aqua/services.ts +++ b/packages/core/js-client/src/services/_aqua/services.ts @@ -26,137 +26,137 @@ import { Sig } from "../Sig.js"; // Services export interface SigDef { - get_peer_id: (callParams: CallParams) => string | Promise; - sign: ( - data: number[], - callParams: CallParams<"data">, - ) => - | { error: string | null; signature: number[] | null; success: boolean } - | Promise<{ - error: string | null; - signature: number[] | null; - success: boolean; - }>; - verify: ( - signature: number[], - data: number[], - callParams: CallParams<"signature" | "data">, - ) => boolean | Promise; + get_peer_id: (callParams: CallParams) => string | Promise; + sign: ( + data: number[], + callParams: CallParams<"data">, + ) => + | { error: string | null; signature: number[] | null; success: boolean } + | Promise<{ + error: string | null; + signature: number[] | null; + success: boolean; + }>; + verify: ( + signature: number[], + data: number[], + callParams: CallParams<"signature" | "data">, + ) => boolean | Promise; } export function registerSig( - peer: FluencePeer, - serviceId: string, - service: Sig, + peer: FluencePeer, + serviceId: string, + service: Sig, ) { - registerService({ - peer, - // TODO: fix this after changing registerService signature - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - service: service as unknown as ServiceImpl, - serviceId, - def: { - defaultServiceId: "sig", - functions: { - tag: "labeledProduct", - fields: { - get_peer_id: { - tag: "arrow", - domain: { - tag: "nil", - }, - codomain: { - tag: "unlabeledProduct", - items: [ - { - tag: "scalar", - name: "string", - }, - ], - }, + registerService({ + peer, + // TODO: fix this after changing registerService signature + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + service: service as unknown as ServiceImpl, + serviceId, + def: { + defaultServiceId: "sig", + functions: { + tag: "labeledProduct", + fields: { + get_peer_id: { + tag: "arrow", + domain: { + tag: "nil", + }, + codomain: { + tag: "unlabeledProduct", + items: [ + { + tag: "scalar", + name: "string", + }, + ], + }, + }, + sign: { + tag: "arrow", + domain: { + tag: "labeledProduct", + fields: { + data: { + tag: "array", + type: { + tag: "scalar", + name: "u8", + }, + }, + }, + }, + codomain: { + tag: "unlabeledProduct", + items: [ + { + tag: "struct", + name: "SignResult", + fields: { + error: { + tag: "option", + type: { + tag: "scalar", + name: "string", + }, }, - sign: { - tag: "arrow", - domain: { - tag: "labeledProduct", - fields: { - data: { - tag: "array", - type: { - tag: "scalar", - name: "u8", - }, - }, - }, - }, - codomain: { - tag: "unlabeledProduct", - items: [ - { - tag: "struct", - name: "SignResult", - fields: { - error: { - tag: "option", - type: { - tag: "scalar", - name: "string", - }, - }, - signature: { - tag: "option", - type: { - tag: "array", - type: { - tag: "scalar", - name: "u8", - }, - }, - }, - success: { - tag: "scalar", - name: "bool", - }, - }, - }, - ], + signature: { + tag: "option", + type: { + tag: "array", + type: { + tag: "scalar", + name: "u8", }, + }, }, - verify: { - tag: "arrow", - domain: { - tag: "labeledProduct", - fields: { - signature: { - tag: "array", - type: { - tag: "scalar", - name: "u8", - }, - }, - data: { - tag: "array", - type: { - tag: "scalar", - name: "u8", - }, - }, - }, - }, - codomain: { - tag: "unlabeledProduct", - items: [ - { - tag: "scalar", - name: "bool", - }, - ], - }, + success: { + tag: "scalar", + name: "bool", }, + }, + }, + ], + }, + }, + verify: { + tag: "arrow", + domain: { + tag: "labeledProduct", + fields: { + signature: { + tag: "array", + type: { + tag: "scalar", + name: "u8", + }, + }, + data: { + tag: "array", + type: { + tag: "scalar", + name: "u8", + }, + }, + }, + }, + codomain: { + tag: "unlabeledProduct", + items: [ + { + tag: "scalar", + name: "bool", }, + ], }, + }, }, - }); + }, + }, + }); } // Functions diff --git a/packages/core/js-client/src/services/_aqua/single-module-srv.ts b/packages/core/js-client/src/services/_aqua/single-module-srv.ts index b7d18806b..b82665ba3 100644 --- a/packages/core/js-client/src/services/_aqua/single-module-srv.ts +++ b/packages/core/js-client/src/services/_aqua/single-module-srv.ts @@ -26,138 +26,138 @@ import { Srv } from "../SingleModuleSrv.js"; // Services export interface SrvDef { - create: ( - wasm_b64_content: string, - callParams: CallParams<"wasm_b64_content">, - ) => - | { error: string | null; service_id: string | null; success: boolean } - | Promise<{ - error: string | null; - service_id: string | null; - success: boolean; - }>; - list: (callParams: CallParams) => string[] | Promise; - remove: ( - service_id: string, - callParams: CallParams<"service_id">, - ) => - | { error: string | null; success: boolean } - | Promise<{ error: string | null; success: boolean }>; + create: ( + wasm_b64_content: string, + callParams: CallParams<"wasm_b64_content">, + ) => + | { error: string | null; service_id: string | null; success: boolean } + | Promise<{ + error: string | null; + service_id: string | null; + success: boolean; + }>; + list: (callParams: CallParams) => string[] | Promise; + remove: ( + service_id: string, + callParams: CallParams<"service_id">, + ) => + | { error: string | null; success: boolean } + | Promise<{ error: string | null; success: boolean }>; } export function registerSrv( - peer: FluencePeer, - serviceId: string, - service: Srv, + peer: FluencePeer, + serviceId: string, + service: Srv, ) { - 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, - def: { - defaultServiceId: "single_module_srv", - functions: { - tag: "labeledProduct", - fields: { - create: { - tag: "arrow", - domain: { - tag: "labeledProduct", - fields: { - wasm_b64_content: { - tag: "scalar", - name: "string", - }, - }, - }, - codomain: { - tag: "unlabeledProduct", - items: [ - { - tag: "struct", - name: "ServiceCreationResult", - fields: { - error: { - tag: "option", - type: { - tag: "scalar", - name: "string", - }, - }, - service_id: { - tag: "option", - type: { - tag: "scalar", - name: "string", - }, - }, - success: { - tag: "scalar", - name: "bool", - }, - }, - }, - ], - }, + 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, + def: { + defaultServiceId: "single_module_srv", + functions: { + tag: "labeledProduct", + fields: { + create: { + tag: "arrow", + domain: { + tag: "labeledProduct", + fields: { + wasm_b64_content: { + tag: "scalar", + name: "string", + }, + }, + }, + codomain: { + tag: "unlabeledProduct", + items: [ + { + tag: "struct", + name: "ServiceCreationResult", + fields: { + error: { + tag: "option", + type: { + tag: "scalar", + name: "string", + }, + }, + service_id: { + tag: "option", + type: { + tag: "scalar", + name: "string", + }, }, - list: { - tag: "arrow", - domain: { - tag: "nil", - }, - codomain: { - tag: "unlabeledProduct", - items: [ - { - tag: "array", - type: { - tag: "scalar", - name: "string", - }, - }, - ], - }, + success: { + tag: "scalar", + name: "bool", + }, + }, + }, + ], + }, + }, + list: { + tag: "arrow", + domain: { + tag: "nil", + }, + codomain: { + tag: "unlabeledProduct", + items: [ + { + tag: "array", + type: { + tag: "scalar", + name: "string", + }, + }, + ], + }, + }, + remove: { + tag: "arrow", + domain: { + tag: "labeledProduct", + fields: { + service_id: { + tag: "scalar", + name: "string", + }, + }, + }, + codomain: { + tag: "unlabeledProduct", + items: [ + { + tag: "struct", + name: "RemoveResult", + fields: { + error: { + tag: "option", + type: { + tag: "scalar", + name: "string", + }, }, - remove: { - tag: "arrow", - domain: { - tag: "labeledProduct", - fields: { - service_id: { - tag: "scalar", - name: "string", - }, - }, - }, - codomain: { - tag: "unlabeledProduct", - items: [ - { - tag: "struct", - name: "RemoveResult", - fields: { - error: { - tag: "option", - type: { - tag: "scalar", - name: "string", - }, - }, - success: { - tag: "scalar", - name: "bool", - }, - }, - }, - ], - }, + success: { + tag: "scalar", + name: "bool", }, + }, }, + ], }, + }, }, - }); + }, + }, + }); } // Functions diff --git a/packages/core/js-client/src/services/_aqua/tracing.ts b/packages/core/js-client/src/services/_aqua/tracing.ts index 542a935db..b87c88359 100644 --- a/packages/core/js-client/src/services/_aqua/tracing.ts +++ b/packages/core/js-client/src/services/_aqua/tracing.ts @@ -26,52 +26,52 @@ import { Tracing } from "../Tracing.js"; // Services export interface TracingDef { - tracingEvent: ( - arrowName: string, - event: string, - callParams: CallParams<"arrowName" | "event">, - ) => void | Promise; + tracingEvent: ( + arrowName: string, + event: string, + callParams: CallParams<"arrowName" | "event">, + ) => void | Promise; } export function registerTracing( - peer: FluencePeer, - serviceId: string, - service: Tracing, + peer: FluencePeer, + serviceId: string, + service: Tracing, ) { - 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, - 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", - }, - }, + 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, + 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", }, + }, }, - }); + }, + }, + }); } // Functions diff --git a/packages/core/js-client/src/services/builtins.ts b/packages/core/js-client/src/services/builtins.ts index 62c26e496..99804ff43 100644 --- a/packages/core/js-client/src/services/builtins.ts +++ b/packages/core/js-client/src/services/builtins.ts @@ -22,792 +22,786 @@ import { encode, decode } from "bs58"; import { sha256 } from "multiformats/hashes/sha2"; import { - CallServiceResult, - CallServiceResultType, - GenericCallServiceHandler, - ResultCodes, + CallServiceResult, + CallServiceResultType, + GenericCallServiceHandler, + ResultCodes, } from "../jsServiceHost/interfaces.js"; import { getErrorMessage, isString, 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, + // TODO: Remove unknown after adding validation to builtin inputs + // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents + result: CallServiceResultType | unknown, ): 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, - retCode: ResultCodes.success, - }; + return { + // TODO: Remove type assertion after adding validation to builtin inputs + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + result: result as CallServiceResultType, + 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, + // TODO: Remove unknown after adding validation to builtin inputs + // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents + error: CallServiceResultType | unknown, ): 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, - retCode: ResultCodes.error, - }; + return { + // TODO: Remove type assertion after adding validation to builtin inputs + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + result: error as CallServiceResultType, + retCode: ResultCodes.error, + }; }; const errorNotImpl = (methodName: string) => { - return error( - `The JS implementation of Peer does not support "${methodName}"`, - ); + return error( + `The JS implementation of Peer does not support "${methodName}"`, + ); }; const makeJsonImpl = (args: [Record, ...JSONValue[]]) => { - const [obj, ...kvs] = args; + const [obj, ...kvs] = args; - const toMerge: Record = {}; + const toMerge: Record = {}; - for (let i = 0; i < kvs.length / 2; i++) { - const k = kvs[i * 2]; + for (let i = 0; i < kvs.length / 2; i++) { + const k = kvs[i * 2]; - if (!isString(k)) { - return error(`Argument ${i * 2 + 1} is expected to be string`); - } - - const v = kvs[i * 2 + 1]; - toMerge[k] = v; + if (!isString(k)) { + return error(`Argument ${i * 2 + 1} is expected to be string`); } - const res = { ...obj, ...toMerge }; - return success(res); + const v = kvs[i * 2 + 1]; + toMerge[k] = v; + } + + const res = { ...obj, ...toMerge }; + return success(res); }; // TODO: These assert made for silencing more stricter ts rules. Will be fixed in DXJ-493 export const builtInServices: Record< - string, - Record + string, + Record > = { - peer: { - identify: () => { - return success({ - external_addresses: [], - // TODO: remove hardcoded values - node_version: "js-0.23.0", - air_version: "js-0.24.2", - }); - }, - - timestamp_ms: () => { - return success(Date.now()); - }, - - timestamp_sec: () => { - return success(Math.floor(Date.now() / 1000)); - }, - - is_connected: () => { - return errorNotImpl("peer.is_connected"); - }, - - connect: () => { - return errorNotImpl("peer.connect"); - }, - - get_contact: () => { - 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); - }); - }, - }, - - kad: { - neighborhood: () => { - return errorNotImpl("kad.neighborhood"); - }, - - merge: () => { - return errorNotImpl("kad.merge"); - }, - }, - - srv: { - list: () => { - return errorNotImpl("srv.list"); - }, - - create: () => { - return errorNotImpl("srv.create"); - }, - - get_interface: () => { - return errorNotImpl("srv.get_interface"); - }, - - resolve_alias: () => { - return errorNotImpl("srv.resolve_alias"); - }, - - add_alias: () => { - return errorNotImpl("srv.add_alias"); - }, - - remove: () => { - return errorNotImpl("srv.remove"); - }, - }, - - dist: { - add_module_from_vault: () => { - return errorNotImpl("dist.add_module_from_vault"); - }, - - add_module: () => { - return errorNotImpl("dist.add_module"); - }, - - add_blueprint: () => { - return errorNotImpl("dist.add_blueprint"); - }, - - make_module_config: () => { - return errorNotImpl("dist.make_module_config"); - }, - - load_module_config: () => { - return errorNotImpl("dist.load_module_config"); - }, - - default_module_config: () => { - return errorNotImpl("dist.default_module_config"); - }, - - make_blueprint: () => { - return errorNotImpl("dist.make_blueprint"); - }, - - load_blueprint: () => { - return errorNotImpl("dist.load_blueprint"); - }, - - list_modules: () => { - return errorNotImpl("dist.list_modules"); - }, - - get_module_interface: () => { - return errorNotImpl("dist.get_module_interface"); - }, - - list_blueprints: () => { - return errorNotImpl("dist.list_blueprints"); - }, - }, - - script: { - add: () => { - return errorNotImpl("script.add"); - }, - - remove: () => { - return errorNotImpl("script.remove"); - }, - - list: () => { - return errorNotImpl("script.list"); - }, - }, - - op: { - noop: () => { - return success({}); - }, - - array: (req) => { - 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); - } - }, - - 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]); - } - }, - - 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(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(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(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(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(encode(multihash.bytes)); - } - }, - - concat_strings: (req) => { - // TODO: remove after adding validation - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - const res = "".concat(...(req.args as string[])); - return success(res); - }, - }, - - debug: { - stringify: (req) => { - let out; - - if (req.args.length === 0) { - out = ""; - } else if (req.args.length === 1) { - out = req.args[0]; - } else { - out = req.args; - } - - return success(jsonify(out)); - }, - }, - - 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"); - 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"); - 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"); - 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"); - 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"); - 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"); - 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"); - 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"); - 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"); - 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"); - 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"); - 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"); - 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"); - 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[]]; - 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)); - const set = new Set(xs); - return success(Array.from(set)); - }, - - intersect: (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 intersection = xs.filter((x) => { - return ys.includes(x); - }); - - return success(intersection); - }, - - 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); - }, - }, - - json: { - obj: (req) => { - let err; - - if ((err = checkForArgumentsCountEven(req)) != null) { - return err; - } - - // TODO: remove after adding validation - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - return makeJsonImpl([{}, ...req.args] as [ - Record, - ...JSONValue[], - ]); - }, - - 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, ...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, ...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; - - try { - // TODO: Remove after adding validation - assert(typeof raw === "string"); - const json = JSON.parse(raw); - return success(json); - } catch (err: unknown) { - return error(getErrorMessage(err)); - } - }, - }, - - "run-console": { - print: (req) => { - // This log is intentional - // eslint-disable-next-line no-console - console.log(...req.args); - return success({}); - }, + peer: { + identify: () => { + return success({ + external_addresses: [], + // TODO: remove hardcoded values + node_version: "js-0.23.0", + air_version: "js-0.24.2", + }); + }, + + timestamp_ms: () => { + return success(Date.now()); + }, + + timestamp_sec: () => { + return success(Math.floor(Date.now() / 1000)); + }, + + is_connected: () => { + return errorNotImpl("peer.is_connected"); + }, + + connect: () => { + return errorNotImpl("peer.connect"); + }, + + get_contact: () => { + 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); + }); + }, + }, + + kad: { + neighborhood: () => { + return errorNotImpl("kad.neighborhood"); + }, + + merge: () => { + return errorNotImpl("kad.merge"); + }, + }, + + srv: { + list: () => { + return errorNotImpl("srv.list"); + }, + + create: () => { + return errorNotImpl("srv.create"); + }, + + get_interface: () => { + return errorNotImpl("srv.get_interface"); + }, + + resolve_alias: () => { + return errorNotImpl("srv.resolve_alias"); + }, + + add_alias: () => { + return errorNotImpl("srv.add_alias"); + }, + + remove: () => { + return errorNotImpl("srv.remove"); + }, + }, + + dist: { + add_module_from_vault: () => { + return errorNotImpl("dist.add_module_from_vault"); + }, + + add_module: () => { + return errorNotImpl("dist.add_module"); + }, + + add_blueprint: () => { + return errorNotImpl("dist.add_blueprint"); + }, + + make_module_config: () => { + return errorNotImpl("dist.make_module_config"); + }, + + load_module_config: () => { + return errorNotImpl("dist.load_module_config"); + }, + + default_module_config: () => { + return errorNotImpl("dist.default_module_config"); + }, + + make_blueprint: () => { + return errorNotImpl("dist.make_blueprint"); + }, + + load_blueprint: () => { + return errorNotImpl("dist.load_blueprint"); + }, + + list_modules: () => { + return errorNotImpl("dist.list_modules"); + }, + + get_module_interface: () => { + return errorNotImpl("dist.get_module_interface"); + }, + + list_blueprints: () => { + return errorNotImpl("dist.list_blueprints"); + }, + }, + + script: { + add: () => { + return errorNotImpl("script.add"); + }, + + remove: () => { + return errorNotImpl("script.remove"); + }, + + list: () => { + return errorNotImpl("script.list"); + }, + }, + + op: { + noop: () => { + return success({}); + }, + + array: (req) => { + 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); + } + }, + + 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]); + } + }, + + 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(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(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(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(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(encode(multihash.bytes)); + } + }, + + concat_strings: (req) => { + // TODO: remove after adding validation + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + const res = "".concat(...(req.args as string[])); + return success(res); + }, + }, + + debug: { + stringify: (req) => { + let out; + + if (req.args.length === 0) { + out = ""; + } else if (req.args.length === 1) { + out = req.args[0]; + } else { + out = req.args; + } + + return success(jsonify(out)); + }, + }, + + 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"); + 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"); + 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"); + 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"); + 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"); + 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"); + 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"); + 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"); + 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"); + 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"); + 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"); + 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"); + 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"); + 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[]]; + 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)); + const set = new Set(xs); + return success(Array.from(set)); + }, + + intersect: (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 intersection = xs.filter((x) => { + return ys.includes(x); + }); + + return success(intersection); + }, + + 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); + }, + }, + + json: { + obj: (req) => { + let err; + + if ((err = checkForArgumentsCountEven(req)) != null) { + return err; + } + + // TODO: remove after adding validation + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + return makeJsonImpl([{}, ...req.args] as [ + Record, + ...JSONValue[], + ]); + }, + + 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, ...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, ...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; + + try { + // TODO: Remove after adding validation + assert(typeof raw === "string"); + const json = JSON.parse(raw); + return success(json); + } catch (err: unknown) { + return error(getErrorMessage(err)); + } + }, + }, + + "run-console": { + print: (req) => { + // This log is intentional + // eslint-disable-next-line no-console + console.log(...req.args); + return success({}); }, + }, } as const; const checkForArgumentsCount = ( - req: { args: Array }, - count: number, + req: { args: Array }, + count: number, ) => { - if (req.args.length !== count) { - return error(`Expected ${count} argument(s). Got ${req.args.length}`); - } + if (req.args.length !== count) { + return error(`Expected ${count} argument(s). Got ${req.args.length}`); + } - return null; + return null; }; const checkForArgumentsCountMoreThan = ( - req: { args: Array }, - count: number, + req: { args: Array }, + count: number, ) => { - if (req.args.length < count) { - return error( - `Expected more than ${count} argument(s). Got ${req.args.length}`, - ); - } + if (req.args.length < count) { + return error( + `Expected more than ${count} argument(s). Got ${req.args.length}`, + ); + } - return null; + return null; }; const checkForArgumentsCountEven = (req: { args: Array }) => { - if (req.args.length % 2 === 1) { - return error( - `Expected even number of argument(s). Got ${req.args.length}`, - ); - } + if (req.args.length % 2 === 1) { + return error(`Expected even number of argument(s). Got ${req.args.length}`); + } - return null; + return null; }; const checkForArgumentsCountOdd = (req: { args: Array }) => { - if (req.args.length % 2 === 0) { - return error( - `Expected odd number of argument(s). Got ${req.args.length}`, - ); - } + if (req.args.length % 2 === 0) { + return error(`Expected odd number of argument(s). Got ${req.args.length}`); + } - return null; + return null; }; const checkForArgumentType = ( - req: { args: Array }, - index: number, - type: string, + req: { args: Array }, + index: number, + type: string, ) => { - const actual = typeof req.args[index]; + const actual = typeof req.args[index]; - if (actual !== type) { - return error( - `Argument ${index} expected to be of type ${type}, Got ${actual}`, - ); - } + if (actual !== type) { + return error( + `Argument ${index} expected to be of type ${type}, Got ${actual}`, + ); + } - return null; + return null; }; diff --git a/packages/core/js-client/src/services/securityGuard.ts b/packages/core/js-client/src/services/securityGuard.ts index de15180f0..02462cde9 100644 --- a/packages/core/js-client/src/services/securityGuard.ts +++ b/packages/core/js-client/src/services/securityGuard.ts @@ -23,53 +23,53 @@ type ArgName = string | null; * A predicate of call params for sig service's sign method which determines whether signing operation is allowed or not */ export type SecurityGuard = ( - params: CallParams, + params: CallParams, ) => boolean; /** * Only allow calls when tetraplet for 'data' argument satisfies the predicate */ export const allowTetraplet = ( - pred: (tetraplet: SecurityTetraplet) => boolean, + pred: (tetraplet: SecurityTetraplet) => boolean, ): SecurityGuard => { - return (params) => { - const t = params.tetraplets["data"][0]; - return pred(t); - }; + return (params) => { + const t = params.tetraplets["data"][0]; + return pred(t); + }; }; /** * Only allow data which comes from the specified serviceId and fnName */ export const allowServiceFn = ( - serviceId: string, - fnName: string, + serviceId: string, + fnName: string, ): SecurityGuard => { - return allowTetraplet((t) => { - return t.service_id === serviceId && t.function_name === fnName; - }); + return allowTetraplet((t) => { + return t.service_id === serviceId && t.function_name === fnName; + }); }; /** * Only allow data originated from the specified json_path */ export const allowExactJsonPath = ( - jsonPath: string, + jsonPath: string, ): SecurityGuard => { - return allowTetraplet((t) => { - return t.json_path === jsonPath; - }); + return allowTetraplet((t) => { + return t.json_path === jsonPath; + }); }; /** * Only allow signing when particle is initiated at the specified peer */ export const allowOnlyParticleOriginatedAt = ( - peerId: PeerIdB58, + peerId: PeerIdB58, ): SecurityGuard => { - return (params) => { - return params.initPeerId === peerId; - }; + return (params) => { + return params.initPeerId === peerId; + }; }; /** @@ -77,13 +77,13 @@ export const allowOnlyParticleOriginatedAt = ( * Useful for predicates reuse */ export const and = ( - ...predicates: SecurityGuard[] + ...predicates: SecurityGuard[] ): SecurityGuard => { - return (params) => { - return predicates.every((x) => { - return x(params); - }); - }; + return (params) => { + return predicates.every((x) => { + return x(params); + }); + }; }; /** @@ -91,11 +91,11 @@ export const and = ( * Useful for predicates reuse */ export const or = ( - ...predicates: SecurityGuard[] + ...predicates: SecurityGuard[] ): SecurityGuard => { - return (params) => { - return predicates.some((x) => { - return x(params); - }); - }; + return (params) => { + return predicates.some((x) => { + return x(params); + }); + }; }; diff --git a/packages/core/js-client/src/util/bytes.ts b/packages/core/js-client/src/util/bytes.ts index 112e02a50..ad2706818 100644 --- a/packages/core/js-client/src/util/bytes.ts +++ b/packages/core/js-client/src/util/bytes.ts @@ -17,18 +17,18 @@ type Size = "u32" | "u64"; const sizeMap = { - u32: 4, - u64: 8, + u32: 4, + u64: 8, } as const; function numberToBytes(n: number, s: Size, littleEndian: boolean) { - const size = sizeMap[s]; - const buffer = new ArrayBuffer(size); - const dv = new DataView(buffer); - dv.setUint32(0, n, littleEndian); - return new Uint8Array(buffer); + const size = sizeMap[s]; + const buffer = new ArrayBuffer(size); + const dv = new DataView(buffer); + dv.setUint32(0, n, littleEndian); + return new Uint8Array(buffer); } export function numberToLittleEndianBytes(n: number, s: Size) { - return numberToBytes(n, s, true); + return numberToBytes(n, s, true); } diff --git a/packages/core/js-client/src/util/commonTypes.ts b/packages/core/js-client/src/util/commonTypes.ts index bb2697a8b..43469a2f4 100644 --- a/packages/core/js-client/src/util/commonTypes.ts +++ b/packages/core/js-client/src/util/commonTypes.ts @@ -17,6 +17,6 @@ export type { CallParameters } from "@fluencelabs/marine-js/dist/types"; export interface IStartable { - start(): Promise; - stop(): Promise; + start(): Promise; + stop(): Promise; } diff --git a/packages/core/js-client/src/util/libp2pUtils.ts b/packages/core/js-client/src/util/libp2pUtils.ts index 16dbbb9ee..fd579d814 100644 --- a/packages/core/js-client/src/util/libp2pUtils.ts +++ b/packages/core/js-client/src/util/libp2pUtils.ts @@ -20,20 +20,20 @@ import { multiaddr, Multiaddr } from "@multiformats/multiaddr"; import { isString } from "./utils.js"; export function relayOptionToMultiaddr(relay: RelayOptions): Multiaddr { - const multiaddrString = isString(relay) ? relay : relay.multiaddr; - const ma = multiaddr(multiaddrString); + const multiaddrString = isString(relay) ? relay : relay.multiaddr; + const ma = multiaddr(multiaddrString); - const peerId = ma.getPeerId(); + const peerId = ma.getPeerId(); - if (peerId == null) { - throwHasNoPeerId(ma); - } + if (peerId == null) { + throwHasNoPeerId(ma); + } - return ma; + return ma; } export function throwHasNoPeerId(ma: Multiaddr): never { - throw new Error( - "Specified multiaddr is invalid or missing peer id: " + ma.toString(), - ); + throw new Error( + "Specified multiaddr is invalid or missing peer id: " + ma.toString(), + ); } diff --git a/packages/core/js-client/src/util/logger.ts b/packages/core/js-client/src/util/logger.ts index bc9d8985d..7d8615cd2 100644 --- a/packages/core/js-client/src/util/logger.ts +++ b/packages/core/js-client/src/util/logger.ts @@ -19,46 +19,46 @@ import debug from "debug"; type Logger = (formatter: unknown, ...args: unknown[]) => void; export interface CommonLogger { - error: Logger; - trace: Logger; - debug: Logger; + error: Logger; + trace: Logger; + debug: Logger; } export interface MarineLogger { - warn: Logger; - error: Logger; - debug: Logger; - trace: Logger; - info: Logger; + warn: Logger; + error: Logger; + debug: Logger; + trace: Logger; + info: Logger; } export function logger(name: string): CommonLogger { - return { - error: debug(`fluence:${name}:error`), - trace: debug(`fluence:${name}:trace`), - debug: debug(`fluence:${name}:debug`), - }; + return { + error: debug(`fluence:${name}:error`), + trace: debug(`fluence:${name}:trace`), + debug: debug(`fluence:${name}:debug`), + }; } export function marineLogger(serviceId: string): MarineLogger { - const name = `fluence:marine:${serviceId}`; - return { - warn: debug(`${name}:warn`), - error: debug(`${name}:error`), - debug: debug(`${name}:debug`), - trace: debug(`${name}:trace`), - info: debug(`${name}:info`), - }; + const name = `fluence:marine:${serviceId}`; + return { + warn: debug(`${name}:warn`), + error: debug(`${name}:error`), + debug: debug(`${name}:debug`), + trace: debug(`${name}:trace`), + info: debug(`${name}:info`), + }; } export function disable() { - debug.disable(); + debug.disable(); } export function enable(namespaces: string) { - debug.enable(namespaces); + debug.enable(namespaces); } export function enabled(namespaces: string) { - return debug.enabled(namespaces); + return debug.enabled(namespaces); } diff --git a/packages/core/js-client/src/util/testUtils.ts b/packages/core/js-client/src/util/testUtils.ts index 2d6d4c1f8..4f23dad7b 100644 --- a/packages/core/js-client/src/util/testUtils.ts +++ b/packages/core/js-client/src/util/testUtils.ts @@ -18,12 +18,12 @@ import { promises as fs } from "fs"; import * as api from "@fluencelabs/aqua-api/aqua-api.js"; import { - ClientConfig, - FunctionCallDef, - JSONArray, - PassedArgs, - RelayOptions, - ServiceDef, + ClientConfig, + FunctionCallDef, + JSONArray, + PassedArgs, + RelayOptions, + ServiceDef, } from "@fluencelabs/interfaces"; import { Subject, Subscribable } from "rxjs"; @@ -41,176 +41,172 @@ import { WorkerLoader } from "../marine/worker-script/workerLoader.js"; import { Particle } from "../particle/Particle.js"; export const registerHandlersHelper = ( - peer: FluencePeer, - particle: Particle, - handlers: Record< - string, - Record CallServiceResultType | undefined> - >, + peer: FluencePeer, + particle: Particle, + handlers: Record< + string, + Record CallServiceResultType | undefined> + >, ) => { - Object.entries(handlers).forEach(([serviceId, service]) => { - Object.entries(service).forEach(([fnName, fn]) => { - peer.internals.regHandler.forParticle( - particle.id, - serviceId, - fnName, - WrapFnIntoServiceCall(fn), - ); - }); + Object.entries(handlers).forEach(([serviceId, service]) => { + Object.entries(service).forEach(([fnName, fn]) => { + peer.internals.regHandler.forParticle( + particle.id, + serviceId, + fnName, + WrapFnIntoServiceCall(fn), + ); }); + }); }; export type CompiledFnCall = ( - peer: FluencePeer, - args: PassedArgs, + peer: FluencePeer, + args: PassedArgs, ) => Promise; export type CompiledFile = { - functions: { [key: string]: CompiledFnCall }; - services: { [key: string]: ServiceDef }; + functions: { [key: string]: CompiledFnCall }; + services: { [key: string]: ServiceDef }; }; export const compileAqua = async (aquaFile: string): Promise => { - await fs.access(aquaFile); + await fs.access(aquaFile); - const compilationResult = await api.Aqua.compile( - new api.Path(aquaFile), - [], - undefined, - ); + const compilationResult = await api.Aqua.compile( + new api.Path(aquaFile), + [], + undefined, + ); - if (compilationResult.errors.length > 0) { - throw new Error( - "Aqua compilation failed. Error: " + - compilationResult.errors.join("/n"), - ); - } - - const functions = Object.entries(compilationResult.functions) - .map(([name, fnInfo]) => { - const callFn = (peer: FluencePeer, args: PassedArgs) => { - return callAquaFunction({ - // TODO: Set our compiler here and fix this - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - def: fnInfo.funcDef as FunctionCallDef, - script: fnInfo.script, - config: {}, - peer: peer, - args, - }); - }; - - return { [name]: callFn }; - }) - .reduce((agg, obj) => { - return { ...agg, ...obj }; - }, {}); - - return { - functions, - // TODO: set our compiler here and fix this - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - services: compilationResult.services as Record, - }; + if (compilationResult.errors.length > 0) { + throw new Error( + "Aqua compilation failed. Error: " + compilationResult.errors.join("/n"), + ); + } + + const functions = Object.entries(compilationResult.functions) + .map(([name, fnInfo]) => { + const callFn = (peer: FluencePeer, args: PassedArgs) => { + return callAquaFunction({ + // TODO: Set our compiler here and fix this + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + def: fnInfo.funcDef as FunctionCallDef, + script: fnInfo.script, + config: {}, + peer: peer, + args, + }); + }; + + return { [name]: callFn }; + }) + .reduce((agg, obj) => { + return { ...agg, ...obj }; + }, {}); + + return { + functions, + // TODO: set our compiler here and fix this + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + services: compilationResult.services as Record, + }; }; class NoopConnection implements IConnection { - start(): Promise { - return Promise.resolve(); - } - - stop(): Promise { - return Promise.resolve(); - } - - getRelayPeerId(): string { - return "nothing_here"; - } - supportsRelay(): boolean { - return true; - } - particleSource: Subscribable = new Subject(); - - sendParticle(): Promise { - return Promise.resolve(); - } + start(): Promise { + return Promise.resolve(); + } + + stop(): Promise { + return Promise.resolve(); + } + + getRelayPeerId(): string { + return "nothing_here"; + } + supportsRelay(): boolean { + return true; + } + particleSource: Subscribable = new Subject(); + + sendParticle(): Promise { + return Promise.resolve(); + } } export class TestPeer extends FluencePeer { - constructor(keyPair: KeyPair, connection: IConnection) { - const workerLoader = new WorkerLoader(); - - const controlModuleLoader = new WasmLoaderFromNpm( - "@fluencelabs/marine-js", - "marine-js.wasm", - ); - - const avmModuleLoader = new WasmLoaderFromNpm( - "@fluencelabs/avm", - "avm.wasm", - ); - - const marine = new MarineBackgroundRunner( - workerLoader, - controlModuleLoader, - avmModuleLoader, - ); - - const jsHost = new JsServiceHost(); - super(DEFAULT_CONFIG, keyPair, marine, jsHost, connection); - } -} - -export const mkTestPeer = async () => { - const kp = await KeyPair.randomEd25519(); - const conn = new NoopConnection(); - return new TestPeer(kp, conn); -}; - -export const withPeer = async (action: (p: FluencePeer) => Promise) => { - const p = await mkTestPeer(); - - try { - await p.start(); - await action(p); - } finally { - await p.stop(); - } -}; - -export const withClient = async ( - relay: RelayOptions, - config: ClientConfig, - action: (client: ClientPeer) => Promise, -) => { + constructor(keyPair: KeyPair, connection: IConnection) { const workerLoader = new WorkerLoader(); const controlModuleLoader = new WasmLoaderFromNpm( - "@fluencelabs/marine-js", - "marine-js.wasm", + "@fluencelabs/marine-js", + "marine-js.wasm", ); const avmModuleLoader = new WasmLoaderFromNpm( - "@fluencelabs/avm", - "avm.wasm", + "@fluencelabs/avm", + "avm.wasm", ); const marine = new MarineBackgroundRunner( - workerLoader, - controlModuleLoader, - avmModuleLoader, + workerLoader, + controlModuleLoader, + avmModuleLoader, ); - const { keyPair, peerConfig, relayConfig } = await makeClientPeerConfig( - relay, - config, - ); + const jsHost = new JsServiceHost(); + super(DEFAULT_CONFIG, keyPair, marine, jsHost, connection); + } +} - const client = new ClientPeer(peerConfig, relayConfig, keyPair, marine); +export const mkTestPeer = async () => { + const kp = await KeyPair.randomEd25519(); + const conn = new NoopConnection(); + return new TestPeer(kp, conn); +}; - try { - await client.connect(); - await action(client); - } finally { - await client.disconnect(); - } +export const withPeer = async (action: (p: FluencePeer) => Promise) => { + const p = await mkTestPeer(); + + try { + await p.start(); + await action(p); + } finally { + await p.stop(); + } +}; + +export const withClient = async ( + relay: RelayOptions, + config: ClientConfig, + action: (client: ClientPeer) => Promise, +) => { + const workerLoader = new WorkerLoader(); + + const controlModuleLoader = new WasmLoaderFromNpm( + "@fluencelabs/marine-js", + "marine-js.wasm", + ); + + const avmModuleLoader = new WasmLoaderFromNpm("@fluencelabs/avm", "avm.wasm"); + + const marine = new MarineBackgroundRunner( + workerLoader, + controlModuleLoader, + avmModuleLoader, + ); + + const { keyPair, peerConfig, relayConfig } = await makeClientPeerConfig( + relay, + config, + ); + + const client = new ClientPeer(peerConfig, relayConfig, keyPair, marine); + + try { + await client.connect(); + await action(client); + } finally { + await client.disconnect(); + } }; diff --git a/packages/core/js-client/src/util/utils.ts b/packages/core/js-client/src/util/utils.ts index c41be9124..44ea44a5c 100644 --- a/packages/core/js-client/src/util/utils.ts +++ b/packages/core/js-client/src/util/utils.ts @@ -15,21 +15,21 @@ */ export function jsonify(obj: unknown) { - return JSON.stringify(obj, null, 4); + return JSON.stringify(obj, null, 4); } export const isString = (unknown: unknown): unknown is string => { - return unknown !== null && typeof unknown === "string"; + return unknown !== null && typeof unknown === "string"; }; export const isObject = (unknown: unknown): unknown is object => { - return unknown !== null && typeof unknown === "object"; + return unknown !== null && typeof unknown === "object"; }; export const getErrorMessage = (error: unknown) => { - if (error instanceof Error) { - return error.message; - } + if (error instanceof Error) { + return error.message; + } - return String(error); + return String(error); }; diff --git a/packages/core/js-client/tsconfig.json b/packages/core/js-client/tsconfig.json index 869d72d61..d2b4fef30 100644 --- a/packages/core/js-client/tsconfig.json +++ b/packages/core/js-client/tsconfig.json @@ -1,11 +1,11 @@ { - "extends": "../../../tsconfig.json", - "compilerOptions": { - "types": ["vite/client", "node"], - "outDir": "./dist", - "esModuleInterop": true, - "resolveJsonModule": true - }, - "include": ["src/**/*"], - "exclude": ["node_modules", "dist"] + "extends": "../../../tsconfig.json", + "compilerOptions": { + "types": ["vite/client", "node"], + "outDir": "./dist", + "esModuleInterop": true, + "resolveJsonModule": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] } diff --git a/packages/core/js-client/vite.config.ts b/packages/core/js-client/vite.config.ts index 2641d7845..db763faaa 100644 --- a/packages/core/js-client/vite.config.ts +++ b/packages/core/js-client/vite.config.ts @@ -23,38 +23,38 @@ const require = createRequire(import.meta.url); const esbuildShim = require.resolve("node-stdlib-browser/helpers/esbuild/shim"); export default { - build: { - target: "modules", - minify: "esbuild", - lib: { - entry: "./src/index.ts", - name: "js-client", - fileName: "index", - }, - outDir: "./dist/browser", - rollupOptions: { - plugins: [ - { - // @ts-ignore - ...inject({ - global: [esbuildShim, "global"], - process: [esbuildShim, "process"], - Buffer: [esbuildShim, "Buffer"], - }), - enforce: "post", - }, - ], - }, + build: { + target: "modules", + minify: "esbuild", + lib: { + entry: "./src/index.ts", + name: "js-client", + fileName: "index", }, - plugins: [tsconfigPaths()], - optimizeDeps: { - esbuildOptions: { - define: { - global: "globalThis", - }, + outDir: "./dist/browser", + rollupOptions: { + plugins: [ + { + // @ts-ignore + ...inject({ + global: [esbuildShim, "global"], + process: [esbuildShim, "process"], + Buffer: [esbuildShim, "Buffer"], + }), + enforce: "post", }, + ], }, - define: { - __PACKAGE_JSON_CONTENT__: readFileSync("./package.json", "utf-8"), + }, + plugins: [tsconfigPaths()], + optimizeDeps: { + esbuildOptions: { + define: { + global: "globalThis", + }, }, + }, + define: { + __PACKAGE_JSON_CONTENT__: readFileSync("./package.json", "utf-8"), + }, }; diff --git a/packages/core/marine-worker/CHANGELOG.md b/packages/core/marine-worker/CHANGELOG.md index 7f9169618..d37261450 100644 --- a/packages/core/marine-worker/CHANGELOG.md +++ b/packages/core/marine-worker/CHANGELOG.md @@ -4,26 +4,26 @@ ### Bug Fixes -- **deps:** update dependency @fluencelabs/avm to v0.48.0 ([#350](https://github.com/fluencelabs/js-client/issues/350)) ([945908a](https://github.com/fluencelabs/js-client/commit/945908a992976f2ad953bcaa3918741f890ffeeb)) +- **deps:** update dependency @fluencelabs/avm to v0.48.0 ([#350](https://github.com/fluencelabs/js-client/issues/350)) ([945908a](https://github.com/fluencelabs/js-client/commit/945908a992976f2ad953bcaa3918741f890ffeeb)) ## [0.3.2](https://github.com/fluencelabs/js-client/compare/marine-worker-v0.3.1...marine-worker-v0.3.2) (2023-09-15) ### Bug Fixes -- **deps:** update dependency @fluencelabs/avm to v0.47.0 ([#341](https://github.com/fluencelabs/js-client/issues/341)) ([f186f20](https://github.com/fluencelabs/js-client/commit/f186f209366c29f12e6677e03564ee2fa14b51ae)) +- **deps:** update dependency @fluencelabs/avm to v0.47.0 ([#341](https://github.com/fluencelabs/js-client/issues/341)) ([f186f20](https://github.com/fluencelabs/js-client/commit/f186f209366c29f12e6677e03564ee2fa14b51ae)) ## [0.3.1](https://github.com/fluencelabs/js-client/compare/marine-worker-v0.3.0...marine-worker-v0.3.1) (2023-09-07) ### Bug Fixes -- **deps:** update dependency @fluencelabs/avm to v0.46.0 ([#338](https://github.com/fluencelabs/js-client/issues/338)) ([8e6918c](https://github.com/fluencelabs/js-client/commit/8e6918c4da5bc4cdfe1c840312f477d782d9ca20)) +- **deps:** update dependency @fluencelabs/avm to v0.46.0 ([#338](https://github.com/fluencelabs/js-client/issues/338)) ([8e6918c](https://github.com/fluencelabs/js-client/commit/8e6918c4da5bc4cdfe1c840312f477d782d9ca20)) ## [0.3.0](https://github.com/fluencelabs/js-client/compare/marine-worker-v0.2.10...marine-worker-v0.3.0) (2023-08-24) ### âš  BREAKING CHANGES -- Unify all packages ([#327](https://github.com/fluencelabs/js-client/issues/327)) +- Unify all packages ([#327](https://github.com/fluencelabs/js-client/issues/327)) ### Features -- Unify all packages ([#327](https://github.com/fluencelabs/js-client/issues/327)) ([97c2491](https://github.com/fluencelabs/js-client/commit/97c24918d84b34e7ac58337838dc8343cbd44b19)) +- Unify all packages ([#327](https://github.com/fluencelabs/js-client/issues/327)) ([97c2491](https://github.com/fluencelabs/js-client/commit/97c24918d84b34e7ac58337838dc8343cbd44b19)) diff --git a/packages/core/marine-worker/package.json b/packages/core/marine-worker/package.json index 98eeb5c3f..8379585c7 100644 --- a/packages/core/marine-worker/package.json +++ b/packages/core/marine-worker/package.json @@ -1,33 +1,33 @@ { - "type": "module", - "name": "@fluencelabs/marine-worker", - "version": "0.3.3", - "description": "Marine worker", - "files": [ - "dist" - ], - "main": "./dist/index.js", - "unpkg": "./dist/browser/marine-worker.umd.cjs", - "types": "./dist/index.d.ts", - "scripts": { - "build": "tsc && vite build" - }, - "repository": "https://github.com/fluencelabs/fluence-js", - "author": "Fluence Labs", - "license": "Apache-2.0", - "keywords": [], - "devDependencies": { - "@rollup/plugin-inject": "5.0.3", - "@types/node": "20.4.5", - "node-stdlib-browser": "1.2.0", - "vite": "4.0.4", - "vitest": "0.29.7" - }, - "dependencies": { - "@fluencelabs/avm": "0.48.0", - "@fluencelabs/marine-js": "0.7.2", - "observable-fns": "0.6.1", - "threads": "1.7.0", - "web-worker": "1.2.0" - } + "type": "module", + "name": "@fluencelabs/marine-worker", + "version": "0.3.3", + "description": "Marine worker", + "files": [ + "dist" + ], + "main": "./dist/index.js", + "unpkg": "./dist/browser/marine-worker.umd.cjs", + "types": "./dist/index.d.ts", + "scripts": { + "build": "tsc && vite build" + }, + "repository": "https://github.com/fluencelabs/fluence-js", + "author": "Fluence Labs", + "license": "Apache-2.0", + "keywords": [], + "devDependencies": { + "@rollup/plugin-inject": "5.0.3", + "@types/node": "20.4.5", + "node-stdlib-browser": "1.2.0", + "vite": "4.0.4", + "vitest": "0.29.7" + }, + "dependencies": { + "@fluencelabs/avm": "0.48.0", + "@fluencelabs/marine-js": "0.7.2", + "observable-fns": "0.6.1", + "threads": "1.7.0", + "web-worker": "1.2.0" + } } diff --git a/packages/core/marine-worker/src/index.ts b/packages/core/marine-worker/src/index.ts index 0f6686338..5f604de40 100644 --- a/packages/core/marine-worker/src/index.ts +++ b/packages/core/marine-worker/src/index.ts @@ -15,16 +15,16 @@ */ import type { - Env, - MarineServiceConfig, - ModuleDescriptor, + Env, + MarineServiceConfig, + ModuleDescriptor, } from "@fluencelabs/marine-js/dist/config"; import { MarineService } from "@fluencelabs/marine-js/dist/MarineService"; import type { - CallParameters, - JSONArray, - JSONObject, - LogMessage, + CallParameters, + JSONArray, + JSONObject, + LogMessage, } from "@fluencelabs/marine-js/dist/types"; import { JSONValue } from "@fluencelabs/marine-js/dist/types"; import { Observable, Subject } from "observable-fns"; @@ -33,30 +33,30 @@ import { Observable, Subject } from "observable-fns"; import { expose } from "../node_modules/threads/worker.js"; const createSimpleModuleDescriptor = ( - name: string, - envs?: Env, + name: string, + envs?: Env, ): ModuleDescriptor => { - return { - import_name: name, - config: { - logger_enabled: true, - logging_mask: 0, - wasi: { - envs: { ...envs }, - preopened_files: new Set(), - mapped_dirs: new Map(), - }, - }, - }; + return { + import_name: name, + config: { + logger_enabled: true, + logging_mask: 0, + wasi: { + envs: { ...envs }, + preopened_files: new Set(), + mapped_dirs: new Map(), + }, + }, + }; }; const createSimpleMarineService = ( - name: string, - env?: Env, + name: string, + env?: Env, ): MarineServiceConfig => { - return { - modules_config: [createSimpleModuleDescriptor(name, env)], - }; + return { + modules_config: [createSimpleModuleDescriptor(name, env)], + }; }; const marineServices = new Map(); @@ -64,87 +64,83 @@ let controlModule: WebAssembly.Module | undefined; const onLogMessage = new Subject(); const toExpose = { - init: (controlModuleWasm: ArrayBuffer | SharedArrayBuffer) => { - controlModule = new WebAssembly.Module( - new Uint8Array(controlModuleWasm), - ); - }, - - createService: async ( - wasm: ArrayBuffer | SharedArrayBuffer, - serviceId: string, - envs?: Env, - ): Promise => { - if (controlModule == null) { - throw new Error( - "MarineJS is not initialized. To initialize call `init` function", - ); - } - - if (marineServices.has(serviceId)) { - throw new Error( - `Service with name ${serviceId} already registered`, - ); - } - - const marineConfig = createSimpleMarineService(serviceId, envs); - const modules = { [serviceId]: new Uint8Array(wasm) }; - - const srv = new MarineService( - controlModule, - serviceId, - onLogMessage.next.bind(onLogMessage), - marineConfig, - modules, - envs, - ); - - await srv.init(); - marineServices.set(serviceId, srv); - }, + init: (controlModuleWasm: ArrayBuffer | SharedArrayBuffer) => { + controlModule = new WebAssembly.Module(new Uint8Array(controlModuleWasm)); + }, - hasService: (serviceId: string) => { - return marineServices.has(serviceId); - }, - - removeService: (serviceId: string) => { - if (serviceId === "avm") { - throw new Error("Cannot remove 'avm' service"); - } - - marineServices.get(serviceId)?.terminate(); - return marineServices.delete(serviceId); - }, - - terminate: () => { - marineServices.forEach((val) => { - val.terminate(); - }); - - marineServices.clear(); - onLogMessage.complete(); - }, - - callService: ( - serviceId: string, - functionName: string, - args: JSONArray | JSONObject, - callParams: CallParameters, - ) => { - const srv = marineServices.get(serviceId); - - if (srv == null) { - 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; - }, - - onLogMessage() { - return Observable.from(onLogMessage); - }, + createService: async ( + wasm: ArrayBuffer | SharedArrayBuffer, + serviceId: string, + envs?: Env, + ): Promise => { + if (controlModule == null) { + throw new Error( + "MarineJS is not initialized. To initialize call `init` function", + ); + } + + if (marineServices.has(serviceId)) { + throw new Error(`Service with name ${serviceId} already registered`); + } + + const marineConfig = createSimpleMarineService(serviceId, envs); + const modules = { [serviceId]: new Uint8Array(wasm) }; + + const srv = new MarineService( + controlModule, + serviceId, + onLogMessage.next.bind(onLogMessage), + marineConfig, + modules, + envs, + ); + + await srv.init(); + marineServices.set(serviceId, srv); + }, + + hasService: (serviceId: string) => { + return marineServices.has(serviceId); + }, + + removeService: (serviceId: string) => { + if (serviceId === "avm") { + throw new Error("Cannot remove 'avm' service"); + } + + marineServices.get(serviceId)?.terminate(); + return marineServices.delete(serviceId); + }, + + terminate: () => { + marineServices.forEach((val) => { + val.terminate(); + }); + + marineServices.clear(); + onLogMessage.complete(); + }, + + callService: ( + serviceId: string, + functionName: string, + args: JSONArray | JSONObject, + callParams: CallParameters, + ) => { + const srv = marineServices.get(serviceId); + + if (srv == null) { + 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; + }, + + onLogMessage() { + return Observable.from(onLogMessage); + }, }; export type MarineBackgroundInterface = typeof toExpose; diff --git a/packages/core/marine-worker/tsconfig.json b/packages/core/marine-worker/tsconfig.json index aa5bb8304..a04ef1f84 100644 --- a/packages/core/marine-worker/tsconfig.json +++ b/packages/core/marine-worker/tsconfig.json @@ -1,8 +1,8 @@ { - "extends": "../../../tsconfig.json", - "compilerOptions": { - "outDir": "./dist" - }, - "include": ["src/**/*"], - "exclude": ["node_modules", "dist"] + "extends": "../../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist" + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] } diff --git a/packages/core/marine-worker/vite.config.ts b/packages/core/marine-worker/vite.config.ts index 5cd9ed2ce..b41d8dc72 100644 --- a/packages/core/marine-worker/vite.config.ts +++ b/packages/core/marine-worker/vite.config.ts @@ -24,25 +24,22 @@ const require = createRequire(import.meta.url); const esbuildShim = require.resolve("node-stdlib-browser/helpers/esbuild/shim"); export default { - build: { - lib: { - entry: resolve( - dirname(fileURLToPath(import.meta.url)), - "src/index.ts", - ), - name: "MarineWorker", - }, - outDir: "dist/browser", + build: { + lib: { + entry: resolve(dirname(fileURLToPath(import.meta.url)), "src/index.ts"), + name: "MarineWorker", }, - plugins: [ - { - // @ts-ignore - ...inject({ - global: [esbuildShim, "global"], - process: [esbuildShim, "process"], - Buffer: [esbuildShim, "Buffer"], - }), - enforce: "post", - } as PluginOption, - ], + outDir: "dist/browser", + }, + plugins: [ + { + // @ts-ignore + ...inject({ + global: [esbuildShim, "global"], + process: [esbuildShim, "process"], + Buffer: [esbuildShim, "Buffer"], + }), + enforce: "post", + } as PluginOption, + ], }; diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 2d2768f71..a4e134d3e 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,2 +1,2 @@ packages: - - "packages/**/*" + - "packages/**/*" diff --git a/tsconfig.eslint.json b/tsconfig.eslint.json index f64ce053b..a6e80f824 100644 --- a/tsconfig.eslint.json +++ b/tsconfig.eslint.json @@ -1,4 +1,4 @@ { - "extends": "./tsconfig.json", - "include": ["**/src/**/*"] + "extends": "./tsconfig.json", + "include": ["**/src/**/*"] } diff --git a/tsconfig.json b/tsconfig.json index ae879e35c..31786ed42 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,14 +1,14 @@ { - "extends": "@tsconfig/strictest/tsconfig.json", - "compilerOptions": { - "lib": ["es2023", "dom"], - "outDir": "./dist/", - "target": "ESNext", - "module": "ESNext", - "esModuleInterop": true, - "declaration": true, - "moduleResolution": "nodenext", - "noUncheckedIndexedAccess": false - }, - "files": ["reset.d.ts"] + "extends": "@tsconfig/strictest/tsconfig.json", + "compilerOptions": { + "lib": ["es2023", "dom"], + "outDir": "./dist/", + "target": "ESNext", + "module": "ESNext", + "esModuleInterop": true, + "declaration": true, + "moduleResolution": "nodenext", + "noUncheckedIndexedAccess": false + }, + "files": ["reset.d.ts"] } From ebd9970eaa3d8dfd2d85bcc319d8df2c6f0ece30 Mon Sep 17 00:00:00 2001 From: Akim Mamedov Date: Mon, 9 Oct 2023 22:21:16 +0700 Subject: [PATCH 15/45] Fix build errors --- .../js-client/src/clientPeer/__test__/client.spec.ts | 6 +++--- .../core/js-client/src/jsPeer/__test__/avm.spec.ts | 8 ++++---- .../core/js-client/src/jsPeer/__test__/par.spec.ts | 4 ++-- .../core/js-client/src/jsPeer/__test__/peer.spec.ts | 12 ++++++------ 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/packages/core/js-client/src/clientPeer/__test__/client.spec.ts b/packages/core/js-client/src/clientPeer/__test__/client.spec.ts index 371c40044..41806e9a8 100644 --- a/packages/core/js-client/src/clientPeer/__test__/client.spec.ts +++ b/packages/core/js-client/src/clientPeer/__test__/client.spec.ts @@ -60,11 +60,11 @@ describe("FluenceClient usage test suite", () => { }, }, callback: { - callback: (args) => { + callback: (args): undefined => { const [val] = args; resolve(val); }, - error: (args) => { + error: (args): undefined => { const [error] = args; reject(error); }, @@ -199,7 +199,7 @@ describe("FluenceClient usage test suite", () => { registerHandlersHelper(peer, particle, { callback: { - error: (args) => { + error: (args): undefined => { const [error] = args; reject(error); }, diff --git a/packages/core/js-client/src/jsPeer/__test__/avm.spec.ts b/packages/core/js-client/src/jsPeer/__test__/avm.spec.ts index 8743328ab..565749d8c 100644 --- a/packages/core/js-client/src/jsPeer/__test__/avm.spec.ts +++ b/packages/core/js-client/src/jsPeer/__test__/avm.spec.ts @@ -37,7 +37,7 @@ describe("Basic AVM functionality in Fluence Peer tests", () => { registerHandlersHelper(peer, particle, { print: { - print: (args) => { + print: (args): undefined => { const [res] = args; resolve(res); }, @@ -75,7 +75,7 @@ describe("Basic AVM functionality in Fluence Peer tests", () => { registerHandlersHelper(peer, particle, { print: { - print: (args) => { + print: (args): undefined => { res.push(args[0]); if (res.length === 2) { @@ -120,7 +120,7 @@ describe("Basic AVM functionality in Fluence Peer tests", () => { registerHandlersHelper(peer, particle, { return: { - return: (args) => { + return: (args): undefined => { resolve(args[0]); }, }, @@ -172,7 +172,7 @@ describe("Basic AVM functionality in Fluence Peer tests", () => { registerHandlersHelper(peer, particle, { return: { - return: (args) => { + return: (args): undefined => { resolve(args[0]); }, }, diff --git a/packages/core/js-client/src/jsPeer/__test__/par.spec.ts b/packages/core/js-client/src/jsPeer/__test__/par.spec.ts index 66ee5d1d3..0a4da727d 100644 --- a/packages/core/js-client/src/jsPeer/__test__/par.spec.ts +++ b/packages/core/js-client/src/jsPeer/__test__/par.spec.ts @@ -75,7 +75,7 @@ describe("FluencePeer flow tests", () => { registerHandlersHelper(peer, particle, { callback: { - callback1: (args) => { + callback1: (args): undefined => { const [val] = args; values.push(val); @@ -83,7 +83,7 @@ describe("FluencePeer flow tests", () => { resolve(values); } }, - callback2: (args) => { + callback2: (args): undefined => { const [val] = args; values.push(val); diff --git a/packages/core/js-client/src/jsPeer/__test__/peer.spec.ts b/packages/core/js-client/src/jsPeer/__test__/peer.spec.ts index 2d7b9cf0f..f71db1be6 100644 --- a/packages/core/js-client/src/jsPeer/__test__/peer.spec.ts +++ b/packages/core/js-client/src/jsPeer/__test__/peer.spec.ts @@ -65,7 +65,7 @@ describe("FluencePeer usage test suite", () => { registerHandlersHelper(peer, particle, { callback: { - callback: (args) => { + callback: (args): undefined => { const [res] = args; resolve(res); }, @@ -119,11 +119,11 @@ describe("FluencePeer usage test suite", () => { }, }, callback: { - callback: (args) => { + callback: (args): undefined => { const [val] = args; resolve(val); }, - error: (args) => { + error: (args): undefined => { const [error] = args; reject(error); }, @@ -160,7 +160,7 @@ describe("FluencePeer usage test suite", () => { }, }, callback: { - error: (args) => { + error: (args): undefined => { const [error] = args; reject(error); }, @@ -195,10 +195,10 @@ async function callIncorrectService(peer: FluencePeer) { registerHandlersHelper(peer, particle, { callback: { - callback: (args) => { + callback: (args): undefined => { resolve(args); }, - error: (args) => { + error: (args): undefined => { const [error] = args; reject(error); }, From 5026ea593009e0dbb1a61f35fa3007d8b1cb7c10 Mon Sep 17 00:00:00 2001 From: Akim Mamedov Date: Tue, 10 Oct 2023 07:22:23 +0700 Subject: [PATCH 16/45] Remove unused deps --- package.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/package.json b/package.json index a68f9dbdd..258c3dbe1 100644 --- a/package.json +++ b/package.json @@ -17,8 +17,6 @@ "author": "Fluence Labs", "license": "Apache-2.0", "devDependencies": { - "@fluencelabs/aqua": "0.9.1-374", - "@fluencelabs/aqua-lib": "0.6.0", "@total-typescript/ts-reset": "0.5.1", "@tsconfig/strictest": "2.0.2", "@types/node": "18.13.0", From c94cf87349a69eeea29f4610cad597c1fa9cb481 Mon Sep 17 00:00:00 2001 From: Akim Mamedov Date: Tue, 10 Oct 2023 07:26:30 +0700 Subject: [PATCH 17/45] remove changelog from formatting --- .prettierignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.prettierignore b/.prettierignore index 605607ad6..ce2074832 100644 --- a/.prettierignore +++ b/.prettierignore @@ -6,3 +6,5 @@ pnpm-lock.yaml **/dist **/build **/public + +**/CHANGELOG.md \ No newline at end of file From dd4ef4e6fa43e1280babf7a643640463c73ab55c Mon Sep 17 00:00:00 2001 From: Akim Mamedov Date: Tue, 10 Oct 2023 07:30:54 +0700 Subject: [PATCH 18/45] deps cleanup --- packages/@tests/smoke/web/package.json | 4 +- packages/core/interfaces/package.json | 1 - packages/core/marine-worker/package.json | 4 +- pnpm-lock.yaml | 1555 +++------------------- 4 files changed, 206 insertions(+), 1358 deletions(-) diff --git a/packages/@tests/smoke/web/package.json b/packages/@tests/smoke/web/package.json index 6344982d3..3bacec7a2 100644 --- a/packages/@tests/smoke/web/package.json +++ b/packages/@tests/smoke/web/package.json @@ -19,8 +19,8 @@ "author": "Fluence Labs", "license": "Apache-2.0", "dependencies": { - "@fluencelabs/js-client": "workspace:^", - "@test/test-utils": "workspace:../../test-utils" + "@fluencelabs/js-client": "workspace:*", + "@test/test-utils": "workspace:*" }, "devDependencies": { "puppeteer": "19.7.2" diff --git a/packages/core/interfaces/package.json b/packages/core/interfaces/package.json index d668d103d..7fc887a06 100644 --- a/packages/core/interfaces/package.json +++ b/packages/core/interfaces/package.json @@ -51,7 +51,6 @@ "devDependencies": { "@multiformats/multiaddr": "11.3.0", "@fluencelabs/avm": "0.48.0", - "@fluencelabs/marine-js": "0.7.2", "hotscript": "1.0.13" } } diff --git a/packages/core/marine-worker/package.json b/packages/core/marine-worker/package.json index 8379585c7..3fb19fea5 100644 --- a/packages/core/marine-worker/package.json +++ b/packages/core/marine-worker/package.json @@ -24,10 +24,8 @@ "vitest": "0.29.7" }, "dependencies": { - "@fluencelabs/avm": "0.48.0", "@fluencelabs/marine-js": "0.7.2", "observable-fns": "0.6.1", - "threads": "1.7.0", - "web-worker": "1.2.0" + "threads": "1.7.0" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b4faa5ff6..3c20baeec 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,12 +8,6 @@ importers: .: devDependencies: - '@fluencelabs/aqua': - specifier: 0.9.1-374 - version: 0.9.1-374(jest@27.5.1)(node-fetch@3.3.2)(typescript@5.1.6) - '@fluencelabs/aqua-lib': - specifier: 0.6.0 - version: 0.6.0 '@total-typescript/ts-reset': specifier: 0.5.1 version: 0.5.1 @@ -94,10 +88,10 @@ importers: packages/@tests/smoke/web: dependencies: '@fluencelabs/js-client': - specifier: workspace:^ + specifier: workspace:* version: link:../../../core/js-client '@test/test-utils': - specifier: workspace:../../test-utils + specifier: workspace:* version: link:../../test-utils devDependencies: puppeteer: @@ -196,9 +190,6 @@ importers: '@fluencelabs/avm': specifier: 0.48.0 version: 0.48.0 - '@fluencelabs/marine-js': - specifier: 0.7.2 - version: 0.7.2 '@multiformats/multiaddr': specifier: 11.3.0 version: 11.3.0 @@ -326,9 +317,6 @@ importers: packages/core/marine-worker: dependencies: - '@fluencelabs/avm': - specifier: 0.48.0 - version: 0.48.0 '@fluencelabs/marine-js': specifier: 0.7.2 version: 0.7.2 @@ -338,9 +326,6 @@ importers: threads: specifier: 1.7.0 version: 1.7.0 - web-worker: - specifier: 1.2.0 - version: 1.2.0 devDependencies: '@rollup/plugin-inject': specifier: 5.0.3 @@ -379,11 +364,6 @@ packages: transitivePeerDependencies: - supports-color - /@achingbrain/node-fetch@2.6.7: - resolution: {integrity: sha512-iTASGs+HTFK5E4ZqcMsHmeJ4zodyq8L38lZV33jwqcBJYoUt3HjN4+ot+O9/0b+ke8ddE7UgOtVuZN/OkV19/g==} - engines: {node: 4.x || >=6.0.0} - dev: true - /@achingbrain/ssdp@4.0.4: resolution: {integrity: sha512-fY/ShiYJmhLdr45Vn2+f88xTqZjBSH3X3F+EJu/89cjB1JIkMCVtD5CQaaS38YknIL8cEcNhjMZM4cdE3ckSSQ==} engines: {node: '>=16.0.0', npm: '>=7.0.0'} @@ -408,6 +388,7 @@ packages: dependencies: '@jridgewell/gen-mapping': 0.3.3 '@jridgewell/trace-mapping': 0.3.19 + dev: false /@apideck/better-ajv-errors@0.3.6(ajv@8.12.0): resolution: {integrity: sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA==} @@ -436,6 +417,7 @@ packages: /@babel/compat-data@7.22.9: resolution: {integrity: sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==} engines: {node: '>=6.9.0'} + dev: false /@babel/core@7.22.10: resolution: {integrity: sha512-fTmqbbUBAwCcre6zPzNngvsI0aNrPZe77AeqvDxWM9Nm+04RrJ3CAmGHA9f7lJQY6ZMhRztNemy4uslDxTX4Qw==} @@ -458,6 +440,7 @@ packages: semver: 6.3.1 transitivePeerDependencies: - supports-color + dev: false /@babel/core@7.22.5: resolution: {integrity: sha512-SBuTAjg91A3eKOvD+bPEz3LlhHZRNu1nFOVts9lzDJTXshHTjII0BAtDS3Y2DAkdZdDKWVZGVwkDfc4Clxn1dg==} @@ -504,6 +487,7 @@ packages: '@jridgewell/gen-mapping': 0.3.3 '@jridgewell/trace-mapping': 0.3.19 jsesc: 2.5.2 + dev: false /@babel/generator@7.22.5: resolution: {integrity: sha512-+lcUbnTRhd0jOewtFSedLyiPsD5tswKkbgcezOqqWFUVNEwoUTlpPOBmvhG7OXWLR4jMdv0czPGH5XbflnD1EA==} @@ -538,6 +522,7 @@ packages: browserslist: 4.21.10 lru-cache: 5.1.1 semver: 6.3.1 + dev: false /@babel/helper-compilation-targets@7.22.5(@babel/core@7.22.10): resolution: {integrity: sha512-Ji+ywpHeuqxB8WDxraCiqR0xfhYjiDE/e6k7FuIaANnoOFxAHskHChz4vA1mJC9Lbm01s1PVAGhQY4FUKSkGZw==} @@ -666,6 +651,7 @@ packages: /@babel/helper-environment-visitor@7.22.5: resolution: {integrity: sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==} engines: {node: '>=6.9.0'} + dev: false /@babel/helper-function-name@7.22.5: resolution: {integrity: sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==} @@ -673,12 +659,14 @@ packages: dependencies: '@babel/template': 7.22.5 '@babel/types': 7.22.10 + dev: false /@babel/helper-hoist-variables@7.22.5: resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.22.10 + dev: false /@babel/helper-member-expression-to-functions@7.22.5: resolution: {integrity: sha512-aBiH1NKMG0H2cGZqspNvsaBe6wNGjbJjuLy29aU+eDZjSbbN53BaxlpB02xm9v34pLTZ1nIQPFYn2qMZoa5BQQ==} @@ -692,6 +680,7 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.22.10 + dev: false /@babel/helper-module-transforms@7.22.5: resolution: {integrity: sha512-+hGKDt/Ze8GFExiVHno/2dvG5IdstpzCq0y4Qc9OJ25D4q3pKfiIP/4Vp3/JvhDkLKsDK2api3q3fpIgiIF5bw==} @@ -721,6 +710,7 @@ packages: '@babel/helper-simple-access': 7.22.5 '@babel/helper-split-export-declaration': 7.22.6 '@babel/helper-validator-identifier': 7.22.5 + dev: false /@babel/helper-optimise-call-expression@7.22.5: resolution: {integrity: sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==} @@ -732,6 +722,7 @@ packages: /@babel/helper-plugin-utils@7.22.5: resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==} engines: {node: '>=6.9.0'} + dev: false /@babel/helper-remap-async-to-generator@7.22.5(@babel/core@7.22.10): resolution: {integrity: sha512-cU0Sq1Rf4Z55fgz7haOakIyM7+x/uCFwXpLPaeRzfoUtAEAuUZjZvFPjL/rk5rW693dIgn2hng1W7xbT7lWT4g==} @@ -782,6 +773,7 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.22.10 + dev: false /@babel/helper-skip-transparent-expression-wrappers@7.22.5: resolution: {integrity: sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==} @@ -802,10 +794,12 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.22.10 + dev: false /@babel/helper-string-parser@7.22.5: resolution: {integrity: sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==} engines: {node: '>=6.9.0'} + dev: false /@babel/helper-validator-identifier@7.22.5: resolution: {integrity: sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==} @@ -814,6 +808,7 @@ packages: /@babel/helper-validator-option@7.22.5: resolution: {integrity: sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==} engines: {node: '>=6.9.0'} + dev: false /@babel/helper-wrap-function@7.22.5: resolution: {integrity: sha512-bYqLIBSEshYcYQyfks8ewYA8S30yaGSeRslcvKMvoUk6HHPySbxHq9YRi6ghhzEU+yhQv9bP/jXnygkStOcqZw==} @@ -836,6 +831,7 @@ packages: '@babel/types': 7.22.10 transitivePeerDependencies: - supports-color + dev: false /@babel/helpers@7.22.5: resolution: {integrity: sha512-pSXRmfE1vzcUIDFQcSGA5Mr+GxBV9oiRKDuDxXvWQQBCh8HoIjs/2DlDB7H8smac1IVrB9/xdXj2N3Wol9Cr+Q==} @@ -862,6 +858,7 @@ packages: hasBin: true dependencies: '@babel/types': 7.22.10 + dev: false /@babel/parser@7.22.5: resolution: {integrity: sha512-DFZMC9LJUG9PLOclRC32G63UXwzqS2koQC8dkx+PLdmt1xSePYpbT/NbsrJy8Q/muXz7o/h/d4A7Fuyixm559Q==} @@ -1053,6 +1050,7 @@ packages: dependencies: '@babel/core': 7.22.10 '@babel/helper-plugin-utils': 7.22.5 + dev: false /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.22.5): resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} @@ -1070,6 +1068,7 @@ packages: dependencies: '@babel/core': 7.22.10 '@babel/helper-plugin-utils': 7.22.5 + dev: false /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.22.5): resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} @@ -1087,6 +1086,7 @@ packages: dependencies: '@babel/core': 7.22.10 '@babel/helper-plugin-utils': 7.22.5 + dev: false /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.22.5): resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} @@ -1230,6 +1230,7 @@ packages: dependencies: '@babel/core': 7.22.10 '@babel/helper-plugin-utils': 7.22.5 + dev: false /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.22.5): resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} @@ -1247,6 +1248,7 @@ packages: dependencies: '@babel/core': 7.22.10 '@babel/helper-plugin-utils': 7.22.5 + dev: false /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.22.5): resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} @@ -1284,6 +1286,7 @@ packages: dependencies: '@babel/core': 7.22.10 '@babel/helper-plugin-utils': 7.22.5 + dev: false /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.22.5): resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} @@ -1301,6 +1304,7 @@ packages: dependencies: '@babel/core': 7.22.10 '@babel/helper-plugin-utils': 7.22.5 + dev: false /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.22.5): resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} @@ -1318,6 +1322,7 @@ packages: dependencies: '@babel/core': 7.22.10 '@babel/helper-plugin-utils': 7.22.5 + dev: false /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.22.5): resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} @@ -1335,6 +1340,7 @@ packages: dependencies: '@babel/core': 7.22.10 '@babel/helper-plugin-utils': 7.22.5 + dev: false /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.22.5): resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} @@ -1352,6 +1358,7 @@ packages: dependencies: '@babel/core': 7.22.10 '@babel/helper-plugin-utils': 7.22.5 + dev: false /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.22.5): resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} @@ -1369,6 +1376,7 @@ packages: dependencies: '@babel/core': 7.22.10 '@babel/helper-plugin-utils': 7.22.5 + dev: false /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.22.5): resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} @@ -1407,6 +1415,7 @@ packages: dependencies: '@babel/core': 7.22.10 '@babel/helper-plugin-utils': 7.22.5 + dev: false /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.22.5): resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} @@ -1426,6 +1435,7 @@ packages: dependencies: '@babel/core': 7.22.10 '@babel/helper-plugin-utils': 7.22.5 + dev: false /@babel/plugin-syntax-typescript@7.22.5(@babel/core@7.22.5): resolution: {integrity: sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==} @@ -2940,6 +2950,7 @@ packages: '@babel/code-frame': 7.22.10 '@babel/parser': 7.22.10 '@babel/types': 7.22.10 + dev: false /@babel/traverse@7.22.10: resolution: {integrity: sha512-Q/urqV4pRByiNNpb/f5OSv28ZlGJiFiiTh+GAHktbIrkPhPbl90+uW6SmpoLyZqutrg9AEaEf3Q/ZBRHBXgxig==} @@ -2957,6 +2968,7 @@ packages: globals: 11.12.0 transitivePeerDependencies: - supports-color + dev: false /@babel/traverse@7.22.5: resolution: {integrity: sha512-7DuIjPgERaNo6r+PZwItpjCZEa5vyw4eJGufeLxrPdBXBoLcCJCIasvK6pK/9DVNrLZTLFhUGqaC6X/PA007TQ==} @@ -2983,6 +2995,7 @@ packages: '@babel/helper-string-parser': 7.22.5 '@babel/helper-validator-identifier': 7.22.5 to-fast-properties: 2.0.0 + dev: false /@babel/types@7.22.5: resolution: {integrity: sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==} @@ -2995,6 +3008,7 @@ packages: /@bcoe/v8-coverage@0.2.3: resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + dev: false /@chainsafe/as-sha256@0.3.1: resolution: {integrity: sha512-hldFFYuf49ed7DAakWVXSJODuq3pzJEguD8tQ7h+sGkM18vja+OFoJI9krnGmgzyuZC2ETX0NOIcCTy31v2Mtg==} @@ -3026,27 +3040,6 @@ packages: transitivePeerDependencies: - supports-color - /@chainsafe/libp2p-noise@4.1.2: - resolution: {integrity: sha512-UvZLWvIS7bAz6M8XfsnC/NhT1c/lg8NNsME1hTvo21kRwyxNFpB8gEhId03Cb5B23oIaHhMySAHBcpuMiSxQ2w==} - dependencies: - '@stablelib/chacha20poly1305': 1.0.1 - '@stablelib/hkdf': 1.0.1 - '@stablelib/sha256': 1.0.1 - '@stablelib/x25519': 1.0.3 - debug: 4.3.4(supports-color@8.1.1) - it-buffer: 0.1.3 - it-length-prefixed: 5.0.3 - it-pair: 1.0.0 - it-pb-rpc: 0.1.13 - it-pipe: 1.1.0 - libp2p-crypto: 0.19.7 - peer-id: 0.15.4 - protobufjs: 6.11.3 - uint8arrays: 3.1.1 - transitivePeerDependencies: - - supports-color - dev: true - /@chainsafe/libp2p-yamux@5.0.0: resolution: {integrity: sha512-aWTnBPR2hJt0A2y579sMtZVB6IqgSSHlZ6Eg+WDxNZQ0zcexafuruZQDj+z3FUTNPz+E8IeuyCi7tjI4IEehjw==} engines: {node: '>=16.0.0', npm: '>=7.0.0'} @@ -3847,12 +3840,6 @@ packages: resolution: {integrity: sha512-ieM2e7qMXgm9BPSSd2fxVbqLlYkR/a/aVTAQXO8gdx2rKKFqnTgFX4gpSOTxrrCMshi8OnXfd2OZi1hsJHTnKA==} dev: true - /@fluencelabs/aqua-ipfs@0.5.8: - resolution: {integrity: sha512-jKlyGBm8oJAIQ3Ags58oJ8QVTlCYSvZQVTnX2SnugGXWVwt4+9qtqtvNT5MvWKK3M9lCFDbJJy/qVTjzPJlaiw==} - dependencies: - '@fluencelabs/aqua-lib': 0.5.2 - dev: true - /@fluencelabs/aqua-lib@0.5.2: resolution: {integrity: sha512-fmoFFE8myhLH9d+YR0+0ZPL2YIQyR6M1woAGu5d1xXI02Sjzn4id6dE4PpxHb8cSBPRie8AwsKobHCNqGxI8oA==} dev: true @@ -3869,35 +3856,9 @@ packages: resolution: {integrity: sha512-+JVbWmHeGB+X/BSqmk6/B0gwWJ4bEAxkepVTN8l0mVrJ5zRRmYaCKVplWy6Z3W012m3VVK3A1o3rm/fgfVrQkw==} dev: true - /@fluencelabs/aqua@0.9.1-374(jest@27.5.1)(node-fetch@3.3.2)(typescript@5.1.6): - resolution: {integrity: sha512-jF6oVE4h7bP/dQArKEfsy4UxbQbzACfVIBY/TFUL5D3np4ssjxrh15Y3gl1PwSWjlaPcDeFvAuStmcqfYQmLqQ==} - hasBin: true - dependencies: - '@fluencelabs/aqua-ipfs': 0.5.8 - '@fluencelabs/aqua-lib': 0.6.0 - '@fluencelabs/fluence': 0.27.5(jest@27.5.1)(node-fetch@3.3.2)(typescript@5.1.6) - '@fluencelabs/fluence-network-environment': 1.0.13 - ipfs-http-client: 50.1.2(node-fetch@3.3.2) - transitivePeerDependencies: - - '@babel/core' - - '@types/jest' - - babel-jest - - bufferutil - - encoding - - esbuild - - jest - - node-fetch - - supports-color - - typescript - - utf-8-validate - dev: true - - /@fluencelabs/avm@0.31.10: - resolution: {integrity: sha512-tkpjdHyRmsTwAEZCJt15//jXEgC2Nw2qFiD1NenvK127SlgKeuzQU9IMReUYY3dowb2IGeC578/uGMu96jHYKw==} - dev: true - /@fluencelabs/avm@0.48.0: resolution: {integrity: sha512-9sXyKx2jp8JvmGUIddb7iILq9KN6d1PoCNSvrzIej4yP+pCxpiY9elgeaSoGY5yHcPClNnvHBKcenL23mdUckg==} + dev: true /@fluencelabs/cli@0.7.2(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@nomicfoundation/hardhat-chai-matchers@1.0.6)(@nomicfoundation/hardhat-network-helpers@1.0.8)(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(@typechain/ethers-v5@10.2.1)(@typechain/hardhat@6.1.6)(@types/chai@4.3.5)(@types/mocha@9.1.1)(@types/node@20.7.0)(chai@4.3.7)(hardhat-gas-reporter@1.0.9)(hardhat@2.15.0)(solidity-coverage@0.7.22)(ts-node@10.9.1)(typechain@8.2.0)(typescript@5.1.6): resolution: {integrity: sha512-cXhlXBxNh1i66Twb3Nhpm1mXHpa+8zzoQ5wKJ6zJjOtrw6GWB6WrfIAb+aaLGWJMBnWHcZEkXs5vx9vwvVplcQ==} @@ -3968,31 +3929,6 @@ packages: - utf-8-validate dev: true - /@fluencelabs/connection@0.2.0(node-fetch@3.3.2): - resolution: {integrity: sha512-0jTRI1h/j/fR2VaLIlcIm6VoP3j2jL2lI6/OaYaOnwGXmI6CbZWHNeq9eaKWycT9B1vpN9wHu0Vi7vH3pFplhg==} - engines: {node: '>=10', pnpm: '>=3'} - dependencies: - '@chainsafe/libp2p-noise': 4.1.2 - '@fluencelabs/interfaces': 0.1.0 - browser-or-node: 2.0.0 - buffer: 6.0.3 - it-length-prefixed: 5.0.3 - it-pipe: 1.1.0 - libp2p: 0.36.2(node-fetch@3.3.2) - libp2p-interfaces: 4.0.6(node-fetch@3.3.2) - libp2p-mplex: 0.10.7 - libp2p-websockets: 0.16.2(node-fetch@3.3.2) - loglevel: 1.8.0 - multiaddr: 10.0.1(node-fetch@3.3.2) - peer-id: 0.16.0 - transitivePeerDependencies: - - bufferutil - - encoding - - node-fetch - - supports-color - - utf-8-validate - dev: true - /@fluencelabs/deal-aurora@0.1.8(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@nomicfoundation/hardhat-chai-matchers@1.0.6)(@nomicfoundation/hardhat-network-helpers@1.0.8)(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(@typechain/ethers-v5@10.2.1)(@typechain/hardhat@6.1.6)(@types/chai@4.3.5)(@types/mocha@9.1.1)(@types/node@20.7.0)(chai@4.3.7)(ethers@5.7.2)(hardhat-gas-reporter@1.0.9)(hardhat@2.15.0)(solidity-coverage@0.7.22)(ts-node@10.9.1)(typechain@8.2.0)(typescript@5.1.6): resolution: {integrity: sha512-h2L3F67AsFxJy+mBAAUy8gMUGf85sgT3kuLhqEstdbQ20ASjxrSsXmyVZeVQLUx4nR1ygbGll9Y+FmRFgpNwMQ==} dependencies: @@ -4022,57 +3958,10 @@ packages: - typescript dev: true - /@fluencelabs/fluence-network-environment@1.0.13: - resolution: {integrity: sha512-2pci3T0sUHE08jwEs1r/vHKVT4XUh/A3j/QJ0eIhddsxyIjEksjdn05X7DF6STD14CF8GgBVOJEPgav8qaUMpA==} - dev: true - /@fluencelabs/fluence-network-environment@1.1.2: resolution: {integrity: sha512-1Bp2gBy3oMEILMynFpOIFK/q2Pj792xpnb3AJs5QcTQAaHz9V2nrEI8OOPwBAFTmjmLBirXBqQQX63O+ePH7yg==} dev: true - /@fluencelabs/fluence@0.27.5(jest@27.5.1)(node-fetch@3.3.2)(typescript@5.1.6): - resolution: {integrity: sha512-nMCzd/oHHk5/yWdg/+rPB+sc8X+fQ5YgwPhGVDoxFs8/CmIr1G5Na8Y6l8rrigasgQd+LV5GtAyh50Oq7/IXkg==} - engines: {node: '>=10', pnpm: '>=3'} - deprecated: fluencelabs/fluence is deprecated in favor of a thinner CDN-distributed .js bundle, please see the following link for installation instructions https://github.com/fluencelabs/js-client#installation - hasBin: true - dependencies: - '@fluencelabs/avm': 0.31.10 - '@fluencelabs/connection': 0.2.0(node-fetch@3.3.2) - '@fluencelabs/interfaces': 0.1.0 - '@fluencelabs/keypair': 0.2.0 - '@fluencelabs/marine-js': 0.3.37(jest@27.5.1)(typescript@5.1.6) - async: 3.2.4 - base64-js: 1.5.1 - browser-or-node: 2.0.0 - bs58: 5.0.0 - buffer: 6.0.3 - cids: 1.1.9 - loglevel: 1.8.1 - multiformats: 9.9.0 - peer-id: 0.16.0 - platform: 1.3.6 - rxjs: 7.5.5 - ts-pattern: 3.3.3 - uuid: 8.3.2 - transitivePeerDependencies: - - '@babel/core' - - '@types/jest' - - babel-jest - - bufferutil - - encoding - - esbuild - - jest - - node-fetch - - supports-color - - typescript - - utf-8-validate - dev: true - - /@fluencelabs/interfaces@0.1.0: - resolution: {integrity: sha512-1nBgrTXa0vwloMMw3iJgbkqK23O6y1hM9YAEOwkUcmvvHQG/OPSYtzAenW7djGhNlA4Lk8QIV4bKNn54WIzjdA==} - engines: {node: '>=10', pnpm: '>=3'} - dev: true - /@fluencelabs/interfaces@0.8.1: resolution: {integrity: sha512-RVdaBX8HbMLbgLPMwYvPaQ+XPvelNOGgOpsQGoy4Chw2njuj142LwxeQsa4LBWqE24Z7ebUqcjhlCrfrf9Efqg==} engines: {node: '>=10', pnpm: '>=3'} @@ -4112,34 +4001,6 @@ packages: - utf-8-validate dev: true - /@fluencelabs/keypair@0.2.0: - resolution: {integrity: sha512-sNFvoeefSa0Xa/xzzLwWBXPMB4y/vHEFh3BaA6FCGNPwbtN0pje9rd8AOgSP9fjlTPpxy3TuBI+eAIzBk5b+SQ==} - engines: {node: '>=10', pnpm: '>=3'} - dependencies: - js-base64: 3.7.5 - libp2p-crypto: 0.21.2 - peer-id: 0.16.0 - dev: true - - /@fluencelabs/marine-js@0.3.37(jest@27.5.1)(typescript@5.1.6): - resolution: {integrity: sha512-/Kpu3S+aDOfrOpKBAK1VeWSHKCoD36/dxtHEWHbj3Lsro0GB9zkoaZPHlFFL7rorCB+hyjAJqLDuBGI8f3l/qg==} - dependencies: - '@wasmer/wasi': 0.12.0 - '@wasmer/wasmfs': 0.12.0 - browser-or-node: 2.0.0 - buffer: 6.0.3 - threads: 1.7.0 - ts-jest: 27.1.5(jest@27.5.1)(typescript@5.1.6) - transitivePeerDependencies: - - '@babel/core' - - '@types/jest' - - babel-jest - - esbuild - - jest - - supports-color - - typescript - dev: true - /@fluencelabs/marine-js@0.7.2: resolution: {integrity: sha512-etjbXDgzyZkK82UZvtuIU3bfy5f52siDUy1m+T5Y5r70k82xYdZZ8vgWVgB6ivi2f3aDyQjgNTfzWQjKFpAReQ==} dependencies: @@ -4242,10 +4103,12 @@ packages: get-package-type: 0.1.0 js-yaml: 3.14.1 resolve-from: 5.0.0 + dev: false /@istanbuljs/schema@0.1.3: resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} engines: {node: '>=8'} + dev: false /@jest/console@27.5.1: resolution: {integrity: sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==} @@ -4257,6 +4120,7 @@ packages: jest-message-util: 27.5.1 jest-util: 27.5.1 slash: 3.0.0 + dev: false /@jest/console@28.1.3: resolution: {integrity: sha512-QPAkP5EwKdK/bxIr6C1I4Vs0rm2nHiANzj/Z5X2JQkrZo6IqvC4ldZ9K95tF0HdidhA8Bo6egxSzUFPYKcEXLw==} @@ -4313,6 +4177,7 @@ packages: - supports-color - ts-node - utf-8-validate + dev: false /@jest/environment@27.5.1: resolution: {integrity: sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==} @@ -4322,6 +4187,7 @@ packages: '@jest/types': 27.5.1 '@types/node': 20.7.0 jest-mock: 27.5.1 + dev: false /@jest/fake-timers@27.5.1: resolution: {integrity: sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==} @@ -4333,6 +4199,7 @@ packages: jest-message-util: 27.5.1 jest-mock: 27.5.1 jest-util: 27.5.1 + dev: false /@jest/globals@27.5.1: resolution: {integrity: sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==} @@ -4341,6 +4208,7 @@ packages: '@jest/environment': 27.5.1 '@jest/types': 27.5.1 expect: 27.5.1 + dev: false /@jest/reporters@27.5.1: resolution: {integrity: sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==} @@ -4378,6 +4246,7 @@ packages: v8-to-istanbul: 8.1.1 transitivePeerDependencies: - supports-color + dev: false /@jest/schemas@28.1.3: resolution: {integrity: sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==} @@ -4393,6 +4262,7 @@ packages: callsites: 3.1.0 graceful-fs: 4.2.11 source-map: 0.6.1 + dev: false /@jest/test-result@27.5.1: resolution: {integrity: sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==} @@ -4402,6 +4272,7 @@ packages: '@jest/types': 27.5.1 '@types/istanbul-lib-coverage': 2.0.4 collect-v8-coverage: 1.0.2 + dev: false /@jest/test-result@28.1.3: resolution: {integrity: sha512-kZAkxnSE+FqE8YjW8gNuoVkkC9I7S1qmenl8sGcDOLropASP+BkcGKwhXoyqQuGOGeYY0y/ixjrd/iERpEXHNg==} @@ -4423,6 +4294,7 @@ packages: jest-runtime: 27.5.1 transitivePeerDependencies: - supports-color + dev: false /@jest/transform@27.5.1: resolution: {integrity: sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==} @@ -4445,6 +4317,7 @@ packages: write-file-atomic: 3.0.3 transitivePeerDependencies: - supports-color + dev: false /@jest/types@27.5.1: resolution: {integrity: sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==} @@ -4455,6 +4328,7 @@ packages: '@types/node': 20.7.0 '@types/yargs': 16.0.5 chalk: 4.1.2 + dev: false /@jest/types@28.1.3: resolution: {integrity: sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==} @@ -4475,6 +4349,7 @@ packages: '@jridgewell/set-array': 1.1.2 '@jridgewell/sourcemap-codec': 1.4.15 '@jridgewell/trace-mapping': 0.3.19 + dev: false /@jridgewell/resolve-uri@3.1.0: resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} @@ -4488,6 +4363,7 @@ packages: /@jridgewell/set-array@1.1.2: resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} engines: {node: '>=6.0.0'} + dev: false /@jridgewell/source-map@0.3.3: resolution: {integrity: sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==} @@ -4515,6 +4391,7 @@ packages: dependencies: '@jridgewell/resolve-uri': 3.1.1 '@jridgewell/sourcemap-codec': 1.4.15 + dev: false /@jridgewell/trace-mapping@0.3.9: resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} @@ -4854,10 +4731,6 @@ packages: strict-event-emitter: 0.5.0 dev: true - /@multiformats/base-x@4.0.1: - resolution: {integrity: sha512-eMk0b9ReBbV23xXU693TAIrLyeO5iTgBZGSJfpqriG8UkYvr/hC9u9pyMlAakDNHWmbhMZCDs6KQO0jzKD8OTw==} - dev: true - /@multiformats/mafmt@12.1.6: resolution: {integrity: sha512-tlJRfL21X+AKn9b5i5VnaTD6bNttpSpcqwKVmDmSHLwxoz97fAHaepqFOk/l1fIu94nImIXneNbhsJx/RQNIww==} dependencies: @@ -4923,10 +4796,6 @@ packages: dependencies: '@noble/hashes': 1.3.1 - /@noble/ed25519@1.7.3: - resolution: {integrity: sha512-iR8GBkDt0Q3GyaVcIu7mSsVIqnFbkbRzGLWlvhwunacoLwt4J3swfKhfaM6rN6WY+TBGoYT1GtT1mIh2/jGbRQ==} - dev: true - /@noble/hashes@1.2.0: resolution: {integrity: sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==} dev: true @@ -5735,11 +5604,13 @@ packages: resolution: {integrity: sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==} dependencies: type-detect: 4.0.8 + dev: false /@sinonjs/fake-timers@8.1.0: resolution: {integrity: sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==} dependencies: '@sinonjs/commons': 1.8.6 + dev: false /@solidity-parser/parser@0.14.5: resolution: {integrity: sha512-6dKnHZn7fg/iQATVEzqyUOyEidbn05q7YA2mQ9hC0MMXhhV3/JrsxmFSYZAcr7j1yUP700LLhTruvJ3MiQmjJg==} @@ -5747,11 +5618,6 @@ packages: antlr4ts: 0.5.0-alpha.4 dev: true - /@sovpro/delimited-stream@1.1.0: - resolution: {integrity: sha512-kQpk267uxB19X3X2T1mvNMjyvIEonpNSHrMlK5ZaBU6aZxw7wPbpgKJOjHN3+/GPVpXgAV9soVT2oyHpLkLtyw==} - engines: {node: '>= 8'} - dev: true - /@stablelib/aead@1.0.1: resolution: {integrity: sha512-q39ik6sxGHewqtO0nP4BuSe3db5G1fEJE8ukvngS2gLkBXyy6E7pLubhbYgnkDFv6V8cWaxcE4Xn0t6LWcJkyg==} dev: true @@ -6077,6 +5943,7 @@ packages: /@tootallnate/once@1.1.2: resolution: {integrity: sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==} engines: {node: '>= 6'} + dev: false /@total-typescript/ts-reset@0.5.1: resolution: {integrity: sha512-AqlrT8YA1o7Ff5wPfMOL0pvL+1X+sw60NN6CcOCqs658emD6RfiXhF7Gu9QcfKBH7ELY2nInLhKSCWVoNL70MQ==} @@ -6183,22 +6050,26 @@ packages: '@types/babel__generator': 7.6.4 '@types/babel__template': 7.4.1 '@types/babel__traverse': 7.20.1 + dev: false /@types/babel__generator@7.6.4: resolution: {integrity: sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==} dependencies: '@babel/types': 7.22.10 + dev: false /@types/babel__template@7.4.1: resolution: {integrity: sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==} dependencies: '@babel/parser': 7.22.10 '@babel/types': 7.22.10 + dev: false /@types/babel__traverse@7.20.1: resolution: {integrity: sha512-MitHFXnhtgwsGZWtT68URpOvLN4EREih1u3QtQiN4VdAxWKRVvGCSvw/Qth0M0Qq3pJpnGOu5JaM/ydK7OGbqg==} dependencies: '@babel/types': 7.22.10 + dev: false /@types/bn.js@4.11.6: resolution: {integrity: sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==} @@ -6343,6 +6214,7 @@ packages: resolution: {integrity: sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==} dependencies: '@types/node': 20.7.0 + dev: false /@types/html-minifier-terser@6.1.0: resolution: {integrity: sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==} @@ -6360,16 +6232,19 @@ packages: /@types/istanbul-lib-coverage@2.0.4: resolution: {integrity: sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==} + dev: false /@types/istanbul-lib-report@3.0.0: resolution: {integrity: sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==} dependencies: '@types/istanbul-lib-coverage': 2.0.4 + dev: false /@types/istanbul-reports@3.0.1: resolution: {integrity: sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==} dependencies: '@types/istanbul-lib-report': 3.0.0 + dev: false /@types/jest@27.5.2: resolution: {integrity: sha512-mpT8LJJ4CMeeahobofYWIjFo0xonRS/HfxnVEPMPFSQdGUt1uHCnoPT7Zhb+sjDU2wz0oKV0OLUR0WzrHNgfeA==} @@ -6397,10 +6272,6 @@ packages: '@types/node': 20.7.0 dev: true - /@types/long@4.0.2: - resolution: {integrity: sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==} - dev: true - /@types/lru-cache@5.1.1: resolution: {integrity: sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==} dev: true @@ -6518,6 +6389,7 @@ packages: /@types/retry@0.12.0: resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==} + dev: false /@types/retry@0.12.1: resolution: {integrity: sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==} @@ -6569,6 +6441,7 @@ packages: /@types/stack-utils@2.0.1: resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==} + dev: false /@types/testing-library__jest-dom@5.14.6: resolution: {integrity: sha512-FkHXCb+ikSoUP4Y4rOslzTdX5sqYwMxfefKh1GmZ8ce1GOkEHntSp6b5cGadmNfp5e4BMEWOMx+WSKd5/MqlDA==} @@ -6591,11 +6464,13 @@ packages: /@types/yargs-parser@21.0.0: resolution: {integrity: sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==} + dev: false /@types/yargs@16.0.5: resolution: {integrity: sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==} dependencies: '@types/yargs-parser': 21.0.0 + dev: false /@types/yargs@17.0.24: resolution: {integrity: sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==} @@ -6885,10 +6760,6 @@ packages: eslint-visitor-keys: 3.4.1 dev: true - /@vascosantos/moving-average@1.1.0: - resolution: {integrity: sha512-MVEJ4vWAPNbrGLjz7ITnHYg+YXZ6ijAqtH5/cHwSoCpbvuJ98aLXwFfPKAUfZpJMQR5uXB58UJajbY130IRF/w==} - dev: true - /@vitest/expect@0.29.7: resolution: {integrity: sha512-UtG0tW0DP6b3N8aw7PHmweKDsvPv4wjGvrVZW7OSxaFg76ShtVdMiMcUkZJgCE8QWUmhwaM0aQhbbVLo4F4pkA==} dependencies: @@ -7288,6 +7159,7 @@ packages: /abab@2.0.6: resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} + dev: false /abbrev@1.0.9: resolution: {integrity: sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q==} @@ -7300,12 +7172,6 @@ packages: event-target-shim: 5.0.1 dev: true - /abortable-iterator@3.0.2: - resolution: {integrity: sha512-qVP8HFfTpUQI2F+f1tpTriKDIZ4XrmwCrBCrQeRKO7DKWF3kgoT6NXiNDv2krrGcHxPwmI63eGQiec81sEaWIw==} - dependencies: - get-iterator: 1.0.2 - dev: true - /abortable-iterator@5.0.1: resolution: {integrity: sha512-hlZ5Z8UwqrKsJcelVPEqDduZowJPBQJ9ZhBC2FXpja3lXy8X6MoI5uMzIgmrA8+3jcVnp8TF/tx+IBBqYJNUrg==} engines: {node: '>=16.0.0', npm: '>=7.0.0'} @@ -7342,6 +7208,7 @@ packages: dependencies: acorn: 7.4.1 acorn-walk: 7.2.0 + dev: false /acorn-import-assertions@1.9.0(acorn@8.10.0): resolution: {integrity: sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==} @@ -7361,6 +7228,7 @@ packages: /acorn-walk@7.2.0: resolution: {integrity: sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==} engines: {node: '>=0.4.0'} + dev: false /acorn-walk@8.2.0: resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==} @@ -7370,6 +7238,7 @@ packages: resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==} engines: {node: '>=0.4.0'} hasBin: true + dev: false /acorn@8.10.0: resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==} @@ -7552,13 +7421,6 @@ packages: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} dev: false - /any-signal@2.1.2: - resolution: {integrity: sha512-B+rDnWasMi/eWcajPcCWSlYc7muXOrcYrqgyzcdKisl2H/WTlQ0gip1KyQfr0ZlxJdsuWCj/LWwQm7fhyhRfIQ==} - dependencies: - abort-controller: 3.0.0 - native-abort-controller: 1.0.4(abort-controller@3.0.0) - dev: true - /any-signal@3.0.1: resolution: {integrity: sha512-xgZgJtKEa9YmDqXodIgl7Fl1C8yNXr8w6gXjqK3LW4GcEiYT+6AQfJSE/8SPsEpLLmcvbv8YU+qet94UewHxqg==} dev: true @@ -7843,6 +7705,7 @@ packages: slash: 3.0.0 transitivePeerDependencies: - supports-color + dev: false /babel-jest@27.5.1(@babel/core@7.22.5): resolution: {integrity: sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==} @@ -7889,6 +7752,7 @@ packages: test-exclude: 6.0.0 transitivePeerDependencies: - supports-color + dev: false /babel-plugin-jest-hoist@27.5.1: resolution: {integrity: sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==} @@ -7898,6 +7762,7 @@ packages: '@babel/types': 7.22.10 '@types/babel__core': 7.20.1 '@types/babel__traverse': 7.20.1 + dev: false /babel-plugin-macros@3.1.0: resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} @@ -8010,6 +7875,7 @@ packages: '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.22.10) '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.22.10) '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.22.10) + dev: false /babel-preset-current-node-syntax@1.0.1(@babel/core@7.22.5): resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} @@ -8040,6 +7906,7 @@ packages: '@babel/core': 7.22.10 babel-plugin-jest-hoist: 27.5.1 babel-preset-current-node-syntax: 1.0.1(@babel/core@7.22.10) + dev: false /babel-preset-jest@27.5.1(@babel/core@7.22.5): resolution: {integrity: sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==} @@ -8146,12 +8013,6 @@ packages: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} - /bindings@1.5.0: - resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} - dependencies: - file-uri-to-path: 1.0.0 - dev: true - /bl@1.2.3: resolution: {integrity: sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==} dependencies: @@ -8166,24 +8027,10 @@ packages: inherits: 2.0.4 readable-stream: 3.6.2 - /bl@5.1.0: - resolution: {integrity: sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==} - dependencies: - buffer: 6.0.3 - inherits: 2.0.4 - readable-stream: 3.6.2 - dev: true - /blakejs@1.2.1: resolution: {integrity: sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==} dev: true - /blob-to-it@1.0.4: - resolution: {integrity: sha512-iCmk0W4NdbrWgRRuxOriU8aM5ijeVLI61Zulsmg/lUHNr7pYjoj+U77opLefNagevtrrbMt3JQ5Qip7ar178kA==} - dependencies: - browser-readablestream-to-it: 1.0.3 - dev: true - /blob-to-it@2.0.3: resolution: {integrity: sha512-Z3CAVpJMwB9B/lp+hOGEyD+6Rx690v1EBj37Wf/eF7ltXZEu2ppd2H9w/FFNGlx36PW5tsoynTNt2HwkgNV9hw==} engines: {node: '>=16.0.0', npm: '>=7.0.0'} @@ -8258,20 +8105,6 @@ packages: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} dev: false - /borc@3.0.0: - resolution: {integrity: sha512-ec4JmVC46kE0+layfnwM3l15O70MlFiEbmQHY/vpqIKiUtPVntv4BY4NVnz3N4vb21edV3mY97XVckFvYHWF9g==} - engines: {node: '>=4'} - hasBin: true - dependencies: - bignumber.js: 9.1.1 - buffer: 6.0.3 - commander: 2.20.3 - ieee754: 1.2.1 - iso-url: 1.2.1 - json-text-sequence: 0.3.0 - readable-stream: 3.6.2 - dev: true - /brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} dependencies: @@ -8302,10 +8135,6 @@ packages: run-parallel-limit: 1.1.0 dev: true - /browser-or-node@2.0.0: - resolution: {integrity: sha512-3Lrks/Okgof+/cRguUNG+qRXSeq79SO3hY4QrXJayJofwJwHiGC0qi99uDjsfTwULUFSr1OGVsBkdIkygKjTUA==} - dev: true - /browser-process-hrtime@1.0.0: resolution: {integrity: sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==} @@ -8392,6 +8221,7 @@ packages: electron-to-chromium: 1.4.498 node-releases: 2.0.13 update-browserslist-db: 1.0.11(browserslist@4.21.10) + dev: false /browserslist@4.21.9: resolution: {integrity: sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==} @@ -8404,13 +8234,6 @@ packages: update-browserslist-db: 1.0.11(browserslist@4.21.9) dev: false - /bs-logger@0.2.6: - resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} - engines: {node: '>= 6'} - dependencies: - fast-json-stable-stringify: 2.1.0 - dev: true - /bs58@4.0.1: resolution: {integrity: sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==} dependencies: @@ -8434,6 +8257,7 @@ packages: resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} dependencies: node-int64: 0.4.0 + dev: false /buffer-alloc-unsafe@1.1.0: resolution: {integrity: sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==} @@ -8614,6 +8438,7 @@ packages: /caniuse-lite@1.0.30001522: resolution: {integrity: sha512-TKiyTVZxJGhsTszLuzb+6vUZSjVOAhClszBr2Ta2k9IwtNBT/4dzmL6aywt0HCgEZlmwJzXJd8yNiob6HgwTRg==} + dev: false /cardinal@2.1.1: resolution: {integrity: sha512-JSr5eOgoEymtYHBjNWyjrMqet9Am2miJhlfKNdqLp6zoeAh0KN5dRAcxlecj5mAJrmQomgiOBj35xHLrFjqBpw==} @@ -8707,6 +8532,7 @@ packages: /char-regex@1.0.2: resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} engines: {node: '>=10'} + dev: false /char-regex@2.0.1: resolution: {integrity: sha512-oSvEeo6ZUD7NepqAat3RqoucZ5SeqLJgOvVIwkafu6IP3V0pO38s/ypdVUmDDK6qIIHNlYHJAKX9E7R7HoKElw==} @@ -8783,6 +8609,7 @@ packages: /ci-info@3.8.0: resolution: {integrity: sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==} engines: {node: '>=8'} + dev: false /cids@0.7.5: resolution: {integrity: sha512-zT7mPeghoWAu+ppn8+BS1tQ5qGmbMfB4AregnQjA/qHY3GC1m1ptI9GkWNlgeu38r7CuRdXB47uY2XgAYt6QVA==} @@ -8796,17 +8623,6 @@ packages: multihashes: 0.4.21 dev: true - /cids@1.1.9: - resolution: {integrity: sha512-l11hWRfugIcbGuTZwAM5PwpjPPjyb6UZOGwlHSnOBV5o07XhQ4gNpBN67FbODvpjyHtd+0Xs6KNvUcGBiDRsdg==} - engines: {node: '>=4.0.0', npm: '>=3.0.0'} - deprecated: This module has been superseded by the multiformats module - dependencies: - multibase: 4.0.6 - multicodec: 3.2.1 - multihashes: 4.0.3 - uint8arrays: 3.1.1 - dev: true - /cipher-base@1.0.4: resolution: {integrity: sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==} dependencies: @@ -8816,6 +8632,7 @@ packages: /cjs-module-lexer@1.2.3: resolution: {integrity: sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==} + dev: false /class-is@1.1.0: resolution: {integrity: sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw==} @@ -8928,6 +8745,7 @@ packages: /co@4.6.0: resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + dev: false /coa@2.0.2: resolution: {integrity: sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==} @@ -8940,6 +8758,7 @@ packages: /collect-v8-coverage@1.0.2: resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} + dev: false /color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} @@ -9113,6 +8932,7 @@ packages: /convert-source-map@1.9.0: resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} + dev: false /cookie-signature@1.0.6: resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} @@ -9516,15 +9336,18 @@ packages: /cssom@0.3.8: resolution: {integrity: sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==} + dev: false /cssom@0.4.4: resolution: {integrity: sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==} + dev: false /cssstyle@2.3.0: resolution: {integrity: sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==} engines: {node: '>=8'} dependencies: cssom: 0.3.8 + dev: false /csstype@3.1.2: resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} @@ -9555,11 +9378,6 @@ packages: assert-plus: 1.0.0 dev: true - /data-uri-to-buffer@4.0.1: - resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} - engines: {node: '>= 12'} - dev: true - /data-urls@2.0.0: resolution: {integrity: sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==} engines: {node: '>=10'} @@ -9567,31 +9385,13 @@ packages: abab: 2.0.6 whatwg-mimetype: 2.3.0 whatwg-url: 8.7.0 + dev: false - /datastore-core@7.0.3: - resolution: {integrity: sha512-DmPsUux63daOfCszxLkcp6LjdJ0k/BQNhIMtoAi5mbraYQnEQkFtKORmTu6XmDX6ujbtaBkeuJAiCBNI7MZklw==} + /datastore-core@9.2.2: + resolution: {integrity: sha512-WFB1wVlD3Tr2yBZpJutPedBc18A4t0HvLOSksokYr/2nHBapplgnwkg2esI6xxctma+76FghhXx7G26khx2Uxg==} engines: {node: '>=16.0.0', npm: '>=7.0.0'} dependencies: - debug: 4.3.4(supports-color@8.1.1) - err-code: 3.0.1 - interface-datastore: 6.1.1 - it-drain: 1.0.5 - it-filter: 1.0.3 - it-map: 1.0.6 - it-merge: 1.0.4 - it-pipe: 1.1.0 - it-pushable: 1.4.2 - it-take: 1.0.2 - uint8arrays: 3.1.1 - transitivePeerDependencies: - - supports-color - dev: true - - /datastore-core@9.2.2: - resolution: {integrity: sha512-WFB1wVlD3Tr2yBZpJutPedBc18A4t0HvLOSksokYr/2nHBapplgnwkg2esI6xxctma+76FghhXx7G26khx2Uxg==} - engines: {node: '>=16.0.0', npm: '>=7.0.0'} - dependencies: - '@libp2p/logger': 3.0.2 + '@libp2p/logger': 3.0.2 err-code: 3.0.1 interface-store: 5.1.2 it-all: 3.0.3 @@ -9668,6 +9468,7 @@ packages: /decimal.js@10.4.3: resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==} + dev: false /decode-uri-component@0.2.2: resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==} @@ -9743,6 +9544,7 @@ packages: /dedent@0.7.0: resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==} + dev: false /deep-eql@4.1.3: resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} @@ -9785,6 +9587,7 @@ packages: /deepmerge@4.3.1: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} + dev: false /default-gateway@6.0.3: resolution: {integrity: sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==} @@ -9872,6 +9675,7 @@ packages: /detect-newline@3.1.0: resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} engines: {node: '>=8'} + dev: false /detect-node@2.1.0: resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==} @@ -9909,6 +9713,7 @@ packages: /diff-sequences@27.5.1: resolution: {integrity: sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dev: false /diff@3.5.0: resolution: {integrity: sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==} @@ -9951,17 +9756,6 @@ packages: resolution: {integrity: sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==} dev: false - /dns-over-http-resolver@1.2.3(node-fetch@3.3.2): - resolution: {integrity: sha512-miDiVSI6KSNbi4SVifzO/reD8rMnxgrlnkrlkugOLQpWQTe2qMdHsZp5DmfKjxNE+/T3VAAYLQUZMv9SMr6+AA==} - dependencies: - debug: 4.3.4(supports-color@8.1.1) - native-fetch: 3.0.0(node-fetch@3.3.2) - receptacle: 1.3.2 - transitivePeerDependencies: - - node-fetch - - supports-color - dev: true - /dns-over-http-resolver@2.1.1: resolution: {integrity: sha512-Lm/eXB7yAQLJ5WxlBGwYfBY7utduXPZykcSmcG6K7ozM0wrZFvxZavhT6PqI0kd/5CUTfev/RrEFQqyU4CGPew==} engines: {node: '>=16.0.0', npm: '>=7.0.0'} @@ -10039,6 +9833,7 @@ packages: engines: {node: '>=8'} dependencies: webidl-conversions: 5.0.0 + dev: false /domhandler@4.3.1: resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==} @@ -10145,6 +9940,7 @@ packages: /electron-to-chromium@1.4.498: resolution: {integrity: sha512-4LODxAzKGVy7CJyhhN5mebwe7U2L29P+0G+HUriHnabm0d7LSff8Yn7t+Wq+2/9ze2Fu1dhX7mww090xfv7qXQ==} + dev: false /elliptic@6.5.4: resolution: {integrity: sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==} @@ -10166,6 +9962,7 @@ packages: /emittery@0.8.1: resolution: {integrity: sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==} engines: {node: '>=10'} + dev: false /emoji-regex@7.0.3: resolution: {integrity: sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==} @@ -10387,11 +10184,6 @@ packages: resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} dev: true - /es6-promisify@7.0.0: - resolution: {integrity: sha512-ginqzK3J90Rd4/Yz7qRrqUeIpe3TwSXTPPZtPne7tGBPeAaQiU8qt4fpKApnxHcq1AwtUdHVg5P77x/yrggG8Q==} - engines: {node: '>=6'} - dev: true - /es6-symbol@3.1.3: resolution: {integrity: sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==} dependencies: @@ -10443,6 +10235,7 @@ packages: /escape-string-regexp@2.0.0: resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} engines: {node: '>=8'} + dev: false /escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} @@ -10476,6 +10269,7 @@ packages: esutils: 2.0.3 optionalDependencies: source-map: 0.6.1 + dev: false /eslint-config-prettier@9.0.0(eslint@8.50.0): resolution: {integrity: sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==} @@ -11178,6 +10972,7 @@ packages: /exit@0.1.2: resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} engines: {node: '>= 0.8.0'} + dev: false /expect@27.5.1: resolution: {integrity: sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==} @@ -11187,6 +10982,7 @@ packages: jest-get-type: 27.5.1 jest-matcher-utils: 27.5.1 jest-message-util: 27.5.1 + dev: false /express@4.18.2: resolution: {integrity: sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==} @@ -11332,6 +11128,7 @@ packages: resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} dependencies: bser: 2.1.1 + dev: false /fd-slicer@1.1.0: resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} @@ -11339,14 +11136,6 @@ packages: pend: 1.2.0 dev: true - /fetch-blob@3.2.0: - resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} - engines: {node: ^12.20 || >= 14.13} - dependencies: - node-domexception: 1.0.0 - web-streams-polyfill: 3.2.1 - dev: true - /figures@3.2.0: resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} engines: {node: '>=8'} @@ -11394,10 +11183,6 @@ packages: engines: {node: '>=4'} dev: true - /file-uri-to-path@1.0.0: - resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} - dev: true - /filelist@1.0.4: resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} dependencies: @@ -11485,6 +11270,7 @@ packages: dependencies: locate-path: 5.0.0 path-exists: 4.0.0 + dev: false /find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} @@ -11596,22 +11382,7 @@ packages: asynckit: 0.4.0 combined-stream: 1.0.8 mime-types: 2.1.35 - - /form-data@4.0.0: - resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} - engines: {node: '>= 6'} - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - mime-types: 2.1.35 - dev: true - - /formdata-polyfill@4.0.10: - resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} - engines: {node: '>=12.20.0'} - dependencies: - fetch-blob: 3.2.0 - dev: true + dev: false /forwarded@0.2.0: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} @@ -11758,6 +11529,7 @@ packages: /gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} + dev: false /get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} @@ -11953,6 +11725,7 @@ packages: /globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} + dev: false /globals@13.20.0: resolution: {integrity: sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==} @@ -12260,10 +12033,6 @@ packages: minimalistic-assert: 1.0.1 dev: true - /hashlru@2.3.0: - resolution: {integrity: sha512-0cMsjjIC8I+D3M44pOQdsy0OHXGLVz6Z0beRuufhKa0KfaD2wGwAev6jILzXsd3/vpnNQJmWyZtIILqM1N+n5A==} - dev: true - /he@1.2.0: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true @@ -12303,6 +12072,7 @@ packages: engines: {node: '>=10'} dependencies: whatwg-encoding: 1.0.5 + dev: false /html-encoding-sniffer@3.0.0: resolution: {integrity: sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==} @@ -12317,6 +12087,7 @@ packages: /html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + dev: false /html-minifier-terser@6.1.0: resolution: {integrity: sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==} @@ -12424,6 +12195,7 @@ packages: debug: 4.3.4(supports-color@8.1.1) transitivePeerDependencies: - supports-color + dev: false /http-proxy-middleware@2.0.6(@types/express@4.17.17): resolution: {integrity: sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==} @@ -12598,6 +12370,7 @@ packages: dependencies: pkg-dir: 4.2.0 resolve-cwd: 3.0.0 + dev: false /imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} @@ -12665,29 +12438,6 @@ packages: wrap-ansi: 6.2.0 dev: true - /interface-datastore@4.0.2: - resolution: {integrity: sha512-/XRmD7oagZMTaK25rV3WFrejLoUwxZcpgE+eNyZNYvb2jlB5P3MwJCIbetJSlVYK7yvaFmJi8s3f9VLcxJjdog==} - dependencies: - err-code: 3.0.1 - interface-store: 0.0.2 - ipfs-utils: 8.1.6 - iso-random-stream: 2.0.2 - it-all: 1.0.6 - it-drain: 1.0.5 - it-filter: 1.0.3 - it-take: 1.0.2 - nanoid: 3.3.6 - uint8arrays: 2.1.10 - dev: true - - /interface-datastore@6.1.1: - resolution: {integrity: sha512-AmCS+9CT34pp2u0QQVXjKztkuq3y5T+BIciuiHDDtDZucZD8VudosnSdUyXJV6IsRkN5jc4RFDhCk1O6Q3Gxjg==} - dependencies: - interface-store: 2.0.2 - nanoid: 3.3.6 - uint8arrays: 3.1.1 - dev: true - /interface-datastore@7.0.4: resolution: {integrity: sha512-Q8LZS/jfFFHz6XyZazLTAc078SSCoa27ZPBOfobWdpDiFO7FqPA2yskitUJIhaCgxNK8C+/lMBUTBNfVIDvLiw==} engines: {node: '>=16.0.0', npm: '>=7.0.0'} @@ -12705,23 +12455,6 @@ packages: nanoid: 4.0.2 uint8arrays: 4.0.3 - /interface-ipld-format@1.0.1: - resolution: {integrity: sha512-WV/ar+KQJVoQpqRDYdo7YPGYIUHJxCuOEhdvsRpzLqoOIVCqPKdMMYmsLL1nCRsF3yYNio+PAJbCKiv6drrEAg==} - deprecated: This module has been superseded by the multiformats module - dependencies: - cids: 1.1.9 - multicodec: 3.2.1 - multihashes: 4.0.3 - dev: true - - /interface-store@0.0.2: - resolution: {integrity: sha512-t4c9GKXH1Vi/WxmppGyIi6iedbGo92YmLneopHmbIEIp27ep7VnrYGA6lM/rLsFo5Tj6TJgIqr3FOk8mvPgIWQ==} - dev: true - - /interface-store@2.0.2: - resolution: {integrity: sha512-rScRlhDcz6k199EkHqT8NpM87ebN89ICOzILoBHgaG36/WX50N32BnU/kpZgCGPLhARRAWUUX5/cyaIjt7Kipg==} - dev: true - /interface-store@3.0.4: resolution: {integrity: sha512-OjHUuGXbH4eXSBx1TF1tTySvjLldPLzRSYYXJwrEQI+XfH5JWYZofr0gVMV4F8XTwC+4V7jomDYkvGRmDSRKqQ==} engines: {node: '>=16.0.0', npm: '>=7.0.0'} @@ -12750,19 +12483,6 @@ packages: fp-ts: 1.19.3 dev: true - /ip-address@8.1.0: - resolution: {integrity: sha512-Wz91gZKpNKoXtqvY8ScarKYwhXoK4r/b5QuT+uywe/azv0/nUCo7Bh0IRRI7F9DHR06kJNWtzMGLIbXavngbKA==} - engines: {node: '>= 12'} - dependencies: - jsbn: 1.1.0 - sprintf-js: 1.1.2 - dev: true - - /ip-regex@4.3.0: - resolution: {integrity: sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==} - engines: {node: '>=8'} - dev: true - /ip-regex@5.0.0: resolution: {integrity: sha512-fOCG6lhoKKakwv+C6KdsOnGvgXnmgfmp0myi3bcNwj3qfwPAxRKWEuFhvEFF7ceYIz6+1jRZ+yguLFAmUNPEfw==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -12794,20 +12514,6 @@ packages: - supports-color dev: true - /ipfs-core-types@0.5.2(node-fetch@3.3.2): - resolution: {integrity: sha512-DOQeL+GFGYMTlnbdtMeBzvfVnyAalSgCfPr8XUCI+FVBZZWwzkt5jZZzGDmF87HVRrMR3FuVyBKZj772mcXKyQ==} - deprecated: js-IPFS has been deprecated in favour of Helia - please see https://github.com/ipfs/js-ipfs/issues/4336 for details - dependencies: - cids: 1.1.9 - interface-datastore: 4.0.2 - ipld-block: 0.11.1 - multiaddr: 9.0.2(node-fetch@3.3.2) - multibase: 4.0.6 - transitivePeerDependencies: - - node-fetch - - supports-color - dev: true - /ipfs-core-utils@0.18.1: resolution: {integrity: sha512-P7jTpdfvlyBG3JR4o+Th3QJADlmXmwMxbkjszXry6VAjfSfLIIqXsdeYPoVRkV69GFEeQozuz2k/jR+U8cUH/Q==} engines: {node: '>=16.0.0', npm: '>=7.0.0'} @@ -12838,68 +12544,6 @@ packages: - supports-color dev: true - /ipfs-core-utils@0.8.3(node-fetch@3.3.2): - resolution: {integrity: sha512-PY7PkCgCtVYtNOe1C3ew1+5D9NqXqizb886R/lyGWe+KsmWtBQkQIk0ZIDwKyHGvG2KA2QQeIDzdOmzBQBJtHQ==} - deprecated: js-IPFS has been deprecated in favour of Helia - please see https://github.com/ipfs/js-ipfs/issues/4336 for details - dependencies: - any-signal: 2.1.2 - blob-to-it: 1.0.4 - browser-readablestream-to-it: 1.0.3 - cids: 1.1.9 - err-code: 3.0.1 - ipfs-core-types: 0.5.2(node-fetch@3.3.2) - ipfs-unixfs: 4.0.3 - ipfs-utils: 8.1.6 - it-all: 1.0.6 - it-map: 1.0.6 - it-peekable: 1.0.3 - multiaddr: 9.0.2(node-fetch@3.3.2) - multiaddr-to-uri: 7.0.0(node-fetch@3.3.2) - parse-duration: 1.1.0 - timeout-abort-controller: 1.1.1 - uint8arrays: 2.1.10 - transitivePeerDependencies: - - node-fetch - - supports-color - dev: true - - /ipfs-http-client@50.1.2(node-fetch@3.3.2): - resolution: {integrity: sha512-ZbJlED4wqwFXQFVB9FQDs20ygdq7O/zSq4AvO9KRAmkqUj2TsCWCteUz2fBMnGWLh2tExxeSl/rQbHbJptb8JQ==} - engines: {node: '>=14.0.0', npm: '>=3.0.0'} - deprecated: js-IPFS has been deprecated in favour of Helia - please see https://github.com/ipfs/js-ipfs/issues/4336 for details - dependencies: - abort-controller: 3.0.0 - any-signal: 2.1.2 - cids: 1.1.9 - debug: 4.3.4(supports-color@8.1.1) - form-data: 4.0.0 - ipfs-core-types: 0.5.2(node-fetch@3.3.2) - ipfs-core-utils: 0.8.3(node-fetch@3.3.2) - ipfs-unixfs: 4.0.3 - ipfs-utils: 8.1.6 - ipld-block: 0.11.1 - ipld-dag-cbor: 1.0.1 - ipld-dag-pb: 0.22.3 - ipld-raw: 7.0.1 - it-last: 1.0.6 - it-map: 1.0.6 - it-tar: 3.0.0 - it-to-stream: 1.0.0 - merge-options: 3.0.4 - multiaddr: 9.0.2(node-fetch@3.3.2) - multibase: 4.0.6 - multicodec: 3.2.1 - multihashes: 4.0.3 - nanoid: 3.3.6 - native-abort-controller: 1.0.4(abort-controller@3.0.0) - parse-duration: 1.1.0 - stream-to-it: 0.2.4 - uint8arrays: 2.1.10 - transitivePeerDependencies: - - node-fetch - - supports-color - dev: true - /ipfs-http-client@60.0.1: resolution: {integrity: sha512-amwM5TNuf077J+/q27jPHfatC05vJuIbX6ZnlYLjc2QsjOCKsORNBqV3brNw7l+fPrijV1yrwEDLG3JEnKsfMw==} engines: {node: '>=16.0.0', npm: '>=7.0.0'} @@ -12929,14 +12573,6 @@ packages: - supports-color dev: true - /ipfs-unixfs@4.0.3: - resolution: {integrity: sha512-hzJ3X4vlKT8FQ3Xc4M1szaFVjsc1ZydN+E4VQ91aXxfpjFn9G2wsMo1EFdAXNq/BUnN5dgqIOMP5zRYr3DTsAw==} - engines: {node: '>=14.0.0', npm: '>=7.0.0'} - dependencies: - err-code: 3.0.1 - protobufjs: 6.11.3 - dev: true - /ipfs-unixfs@9.0.1: resolution: {integrity: sha512-jh2CbXyxID+v3jLml9CqMwjdSS9ZRnsGfQGGPOfem0/hT/L48xUeTPvh7qLFWkZcIMhZtG+fnS1teei8x5uGBg==} engines: {node: '>=16.0.0', npm: '>=7.0.0'} @@ -12945,27 +12581,6 @@ packages: protobufjs: 7.2.4 dev: true - /ipfs-utils@8.1.6: - resolution: {integrity: sha512-V/cwb6113DrDhrjDTWImA6+zmJbpdbUkxdxmEQO7it8ykV76bBmzU1ZXSM0QR0qxGy9VW8dkUlPAC2K10VgSmw==} - dependencies: - abort-controller: 3.0.0 - any-signal: 2.1.2 - buffer: 6.0.3 - electron-fetch: 1.9.1 - err-code: 3.0.1 - is-electron: 2.2.2 - iso-url: 1.2.1 - it-glob: 0.0.14 - it-to-stream: 1.0.0 - merge-options: 3.0.4 - nanoid: 3.3.6 - native-abort-controller: 1.0.4(abort-controller@3.0.0) - native-fetch: 3.0.0(@achingbrain/node-fetch@2.6.7) - node-fetch: /@achingbrain/node-fetch@2.6.7 - react-native-fetch-api: 2.0.0 - stream-to-it: 0.2.4 - dev: true - /ipfs-utils@9.0.14: resolution: {integrity: sha512-zIaiEGX18QATxgaS0/EOQNoo33W0islREABAcxXE8n7y2MGAlB+hdsxXn4J0hGZge8IqVQhW8sWIb+oJz2yEvg==} engines: {node: '>=16.0.0', npm: '>=7.0.0'} @@ -12990,51 +12605,6 @@ packages: - encoding dev: true - /ipld-block@0.11.1: - resolution: {integrity: sha512-sDqqLqD5qh4QzGq6ssxLHUCnH4emCf/8F8IwjQM2cjEEIEHMUj57XhNYgmGbemdYPznUhffxFGEHsruh5+HQRw==} - engines: {node: '>=6.0.0', npm: '>=3.0.0'} - dependencies: - cids: 1.1.9 - dev: true - - /ipld-dag-cbor@1.0.1: - resolution: {integrity: sha512-PZh8rHnRETX5bj60i73W2oq6BXoZnIvYCBDwIffYVJgxMr7BEVd5PycAARBiT6daORJ/4zbqEFR5CcrjeCtm/A==} - engines: {node: '>=6.0.0', npm: '>=3.0.0'} - deprecated: This module has been superseded by @ipld/dag-cbor and multiformats - dependencies: - borc: 3.0.0 - cids: 1.1.9 - interface-ipld-format: 1.0.1 - is-circular: 1.0.2 - multicodec: 3.2.1 - multihashing-async: 2.1.4 - uint8arrays: 2.1.10 - dev: true - - /ipld-dag-pb@0.22.3: - resolution: {integrity: sha512-dfG5C5OVAR4FEP7Al2CrHWvAyIM7UhAQrjnOYOIxXGQz5NlEj6wGX0XQf6Ru6or1na6upvV3NQfstapQG8X2rg==} - engines: {node: '>=6.0.0', npm: '>=3.0.0'} - deprecated: This module has been superseded by @ipld/dag-pb and multiformats - dependencies: - cids: 1.1.9 - interface-ipld-format: 1.0.1 - multicodec: 3.2.1 - multihashing-async: 2.1.4 - protobufjs: 6.11.3 - stable: 0.1.8 - uint8arrays: 2.1.10 - dev: true - - /ipld-raw@7.0.1: - resolution: {integrity: sha512-oaiy0Ot23NCnoBA7sLvPL9qFRC6JDB0IsdZL6rUeZJxzxabQuBLNGYXcqjQ8jlF0UPLEUSO+h8OJh2DZPzL2aQ==} - deprecated: This module has been superseded by the multiformats module - dependencies: - cids: 1.1.9 - interface-ipld-format: 1.0.1 - multicodec: 3.2.1 - multihashing-async: 2.1.4 - dev: true - /is-arguments@1.1.1: resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} engines: {node: '>= 0.4'} @@ -13079,10 +12649,6 @@ packages: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} - /is-circular@1.0.2: - resolution: {integrity: sha512-YttjnrswnUYRVJvxCvu8z+PGMUSzC2JttP0OEXezlAEdp3EXzhf7IZ3j0gRAybJBQupedIZFhY61Tga6E0qASA==} - dev: true - /is-core-module@2.13.0: resolution: {integrity: sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==} dependencies: @@ -13127,6 +12693,7 @@ packages: /is-generator-fn@2.1.0: resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} engines: {node: '>=6'} + dev: false /is-generator-function@1.0.10: resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} @@ -13151,17 +12718,6 @@ packages: engines: {node: '>=8'} dev: true - /is-ip@3.1.0: - resolution: {integrity: sha512-35vd5necO7IitFPjd/YBeqwWnyDWbuLH9ZXQdMfDA8TEo7pv5X8yfrvVO3xbJbLUlERCMvf6X0hTUamQxCYJ9Q==} - engines: {node: '>=8'} - dependencies: - ip-regex: 4.3.0 - dev: true - - /is-loopback-addr@1.0.1: - resolution: {integrity: sha512-DhWU/kqY7X2F6KrrVTu7mHlbd2Pbo4D1YkAzasBMjQs6lJAoefxaA6m6CpSX0K6pjt9D0b9PNFI5zduy/vzOYw==} - dev: true - /is-loopback-addr@2.0.1: resolution: {integrity: sha512-SEsepLbdWFb13B6U0tt6dYcUM0iK/U7XOC43N70Z4Qb88WpNtp+ospyNI9ddpqncs7Z7brAEsVBTQpaqSNntIw==} @@ -13227,6 +12783,7 @@ packages: /is-potential-custom-element-name@1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + dev: false /is-regex@1.1.4: resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} @@ -13341,20 +12898,6 @@ packages: /isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - /iso-constants@0.1.2: - resolution: {integrity: sha512-OTCM5ZCQsHBCI4Wdu4tSxvDIkmDHd5EwJDps5mKqnQnWJSKlnwMs3EDZ4n3Fh1tmkWkDlyd2vCDbEYuPbyrUNQ==} - engines: {node: '>=10'} - requiresBuild: true - dev: true - - /iso-random-stream@2.0.2: - resolution: {integrity: sha512-yJvs+Nnelic1L2vH2JzWvvPQFA4r7kSTnpST/+LkAQjSz0hos2oqLD+qIVi9Qk38Hoe7mNDt3j0S27R58MVjLQ==} - engines: {node: '>=10'} - dependencies: - events: 3.3.0 - readable-stream: 3.6.2 - dev: true - /iso-url@1.2.1: resolution: {integrity: sha512-9JPDgCN4B7QPkLtYAAOrEuAWvP9rWvR5offAr0/SeF046wIkglqH3VXgYYP6NcsKslH80UIVgmPqNe3j7tG2ng==} engines: {node: '>=12'} @@ -13371,6 +12914,7 @@ packages: /istanbul-lib-coverage@3.2.0: resolution: {integrity: sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==} engines: {node: '>=8'} + dev: false /istanbul-lib-instrument@5.2.1: resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} @@ -13383,6 +12927,7 @@ packages: semver: 6.3.1 transitivePeerDependencies: - supports-color + dev: false /istanbul-lib-report@3.0.1: resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} @@ -13391,6 +12936,7 @@ packages: istanbul-lib-coverage: 3.2.0 make-dir: 4.0.0 supports-color: 7.2.0 + dev: false /istanbul-lib-source-maps@4.0.1: resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} @@ -13401,6 +12947,7 @@ packages: source-map: 0.6.1 transitivePeerDependencies: - supports-color + dev: false /istanbul-reports@3.1.6: resolution: {integrity: sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==} @@ -13408,6 +12955,7 @@ packages: dependencies: html-escaper: 2.0.2 istanbul-lib-report: 3.0.1 + dev: false /it-all@1.0.6: resolution: {integrity: sha512-3cmCc6Heqe3uWi3CVM/k51fa/XbMFpQVzFoDsV0IZNHSQDyAXl3c4MjHkFX5kF3922OGj7Myv1nSEUgRtcuM1A==} @@ -13428,13 +12976,6 @@ packages: uint8arraylist: 2.4.3 dev: true - /it-buffer@0.1.3: - resolution: {integrity: sha512-9a2/9SYVwG7bcn3tpRDR4bXbtuMLXnDK48KVC+GXiQg97ZOOdWz2nIITBsOQ19b+gj01Rw8RNwtiLDLI8P8oiQ==} - dependencies: - bl: 5.1.0 - buffer: 6.0.3 - dev: true - /it-byte-stream@1.0.1: resolution: {integrity: sha512-Nu1/y8ObmrEmpHfWBHrWKtla9xwTdnMceB7v1z7tM+H84VP5Ou59wyFiJHsyvuIETLfKFY+TfhEbOJy24FRGjQ==} dependencies: @@ -13442,32 +12983,14 @@ packages: it-stream-types: 2.0.1 uint8arraylist: 2.4.3 - /it-concat@2.0.0: - resolution: {integrity: sha512-jchrEB3fHlUENWkVJRmbFJ1A7gcjJDmwiolQsHhVC14DpUIbX8fgr3SOC7XNE5OoUUQNL6/RaMCPChkPemyQUw==} - dependencies: - bl: 5.1.0 - dev: true - - /it-drain@1.0.5: - resolution: {integrity: sha512-r/GjkiW1bZswC04TNmUnLxa6uovme7KKwPhc+cb1hHU65E3AByypHH6Pm91WHuvqfFsm+9ws0kPtDBV3/8vmIg==} - dev: true - /it-drain@3.0.3: resolution: {integrity: sha512-l4s+izxUpFAR2axprpFiCaq0EtxK1QMd0LWbEtau5b+OegiZ5xdRtz35iJyh6KZY9QtuwEiQxydiOfYJc7stoA==} - /it-filter@1.0.3: - resolution: {integrity: sha512-EI3HpzUrKjTH01miLHWmhNWy3Xpbx4OXMXltgrNprL5lDpF3giVpHIouFpr5l+evXw6aOfxhnt01BIB+4VQA+w==} - dev: true - /it-filter@3.0.3: resolution: {integrity: sha512-2zXUrJuuV6QHM21ahc8NqVUUxkLMVDWXBoUBcj9GCQLQez2OXmddTHN0r0F5B+TkNTpeL618yIgXi1HNPJOxow==} dependencies: it-peekable: 3.0.2 - /it-first@1.0.7: - resolution: {integrity: sha512-nvJKZoBpZD/6Rtde6FXqwDqDZGF1sCADmr2Zoc0hZsIvnE449gRFnGctxDf09Bzc/FWnHXAdaHVIetY6lrE0/g==} - dev: true - /it-first@2.0.1: resolution: {integrity: sha512-noC1oEQcWZZMUwq7VWxHNLML43dM+5bviZpfmkxkXlvBe60z7AFRqpZSga9uQBo792jKv9otnn1IjA4zwgNARw==} engines: {node: '>=16.0.0', npm: '>=7.0.0'} @@ -13477,23 +13000,12 @@ packages: resolution: {integrity: sha512-QPLAM2BOkait/o6W25HvP0XTEv+Os3Ce4wET//ADNaPv+WYAHWfQwJuMu5FB8X066hA1F7LEMnULvTpE7/4yQw==} engines: {node: '>=16.0.0', npm: '>=7.0.0'} - /it-foreach@0.1.1: - resolution: {integrity: sha512-ZLxL651N5w5SL/EIIcrXELgYrrkuEKj/TErG93C4lr6lNZziKsf338ljSG85PjQfu7Frg/1wESl5pLrPSFXI9g==} - dev: true - /it-foreach@2.0.4: resolution: {integrity: sha512-txxcoc09g+KdLyOapxAuB12H9zUb2FuZC/TqSXRT+YR0T5fHnvcDIhspgvx/e/HiPKlKjOR8onA0qtuiAtcXqg==} dependencies: it-peekable: 3.0.2 dev: false - /it-glob@0.0.14: - resolution: {integrity: sha512-TKKzs9CglbsihSpcwJPXN5DBUssu4akRzPlp8QJRCoLrKoaOpyY2V1qDlxx+UMivn0i114YyTd4AawWl7eqIdw==} - dependencies: - '@types/minimatch': 3.0.5 - minimatch: 3.1.2 - dev: true - /it-glob@1.0.2: resolution: {integrity: sha512-Ch2Dzhw4URfB9L/0ZHyY+uqOnKvBNeS/SMcRiPmJfpHiM0TsUZn+GkpcZxAoF3dJVdPm/PuIk3A4wlV7SUo23Q==} dependencies: @@ -13501,14 +13013,6 @@ packages: minimatch: 3.1.2 dev: true - /it-handshake@2.0.0: - resolution: {integrity: sha512-K4q+mz8aLlCK3vTjtgNdHC9c/JbuOATsfogarjMsLcBZC5vYfKbX3Gq3AWcCdjIsIrPqzTlhPKSxl64LJkrt2w==} - dependencies: - it-pushable: 1.4.2 - it-reader: 3.0.0 - p-defer: 3.0.0 - dev: true - /it-handshake@4.1.3: resolution: {integrity: sha512-V6Lt9A9usox9iduOX+edU1Vo94E6v9Lt9dOvg3ubFaw1qf5NCxXLi93Ao4fyCHWDYd8Y+DUhadwNtWVyn7qqLg==} engines: {node: '>=16.0.0', npm: '>=7.0.0'} @@ -13519,10 +13023,6 @@ packages: p-defer: 4.0.0 uint8arraylist: 2.4.3 - /it-last@1.0.6: - resolution: {integrity: sha512-aFGeibeiX/lM4bX3JY0OkVCFkAw8+n9lkukkLNivbJRvNz8lI3YXv5xcqhFUV2lDJiraEK3OXRDbGuevnnR67Q==} - dev: true - /it-last@2.0.1: resolution: {integrity: sha512-uVMedYW0wa2Cx0TAmcOCLbfuLLII7+vyURmhKa8Zovpd+aBTMsmINtsta2n364wJ5qsEDBH+akY1sUtAkaYBlg==} engines: {node: '>=16.0.0', npm: '>=7.0.0'} @@ -13537,14 +13037,6 @@ packages: uint8-varint: 2.0.1 uint8arraylist: 2.4.3 - /it-length-prefixed@5.0.3: - resolution: {integrity: sha512-b+jDHLcnOnPDQN79ronmzF5jeBjdJsy0ce2O6i6X4J5tnaO8Fd146ZA/tMbzaLlKnTpXa0eKtofpYhumXGENeg==} - dependencies: - bl: 5.1.0 - buffer: 6.0.3 - varint: 6.0.0 - dev: true - /it-length-prefixed@8.0.4: resolution: {integrity: sha512-5OJ1lxH+IaqJB7lxe8IAIwt9UfSfsmjKJoAI/RO9djYoBDt1Jfy9PeVHUmOfqhqyu/4kJvWBFAJUaG1HhLQ12A==} engines: {node: '>=16.0.0', npm: '>=7.0.0'} @@ -13576,10 +13068,6 @@ packages: uint8arraylist: 2.4.3 uint8arrays: 4.0.3 - /it-map@1.0.6: - resolution: {integrity: sha512-XT4/RM6UHIFG9IobGlQPFQUrlEKkU4eBUFG3qhWhfAdh1JfF2x11ShCrKCdmZ0OiZppPfoLuzcfA4cey6q3UAQ==} - dev: true - /it-map@2.0.0: resolution: {integrity: sha512-mLgtk/NZaN7NZ06iLrMXCA6jjhtZO0vZT5Ocsp31H+nsGI18RSPVmUbFyA1sWx7q+g92J22Sixya7T2QSSAwfA==} engines: {node: '>=16.0.0', npm: '>=7.0.0'} @@ -13589,12 +13077,6 @@ packages: dependencies: it-peekable: 3.0.2 - /it-merge@1.0.4: - resolution: {integrity: sha512-DcL6GksTD2HQ7+5/q3JznXaLNfwjyG3/bObaF98da+oHfUiPmdo64oJlT9J8R8G5sJRU7thwaY5zxoAKCn7FJw==} - dependencies: - it-pushable: 1.4.2 - dev: true - /it-merge@2.0.1: resolution: {integrity: sha512-ItoBy3dPlNKnhjHR8e7nfabfZzH4Jy2OMPvayYH3XHy4YNqSVKmWTIxhz7KX4UMBsLChlIJZ+5j6csJgrYGQtw==} engines: {node: '>=16.0.0', npm: '>=7.0.0'} @@ -13612,12 +13094,6 @@ packages: dependencies: it-pushable: 3.2.1 - /it-pair@1.0.0: - resolution: {integrity: sha512-9raOiDu5OAuDOahtMtapKQDrQTxBfzlzrNcB6o7JARHkt+7Bb1dMkW/TpYdAjBJE77KH3e2zGzwpGUP9tXbLww==} - dependencies: - get-iterator: 1.0.2 - dev: true - /it-pair@2.0.6: resolution: {integrity: sha512-5M0t5RAcYEQYNG5BV7d7cqbdwbCAp5yLdzvkxsZmkuZsLbTdZzah6MQySYfaAQjNDCq6PUnDt0hqBZ4NwMfW6g==} engines: {node: '>=16.0.0', npm: '>=7.0.0'} @@ -13630,18 +13106,6 @@ packages: dependencies: p-defer: 4.0.0 - /it-pb-rpc@0.1.13: - resolution: {integrity: sha512-aZ4FNJsDgNepVVTmYXgXbQabIiOQyqYWUhdfovaHDcPSM5KjegwJihJEWMJjMyj+oLSKcZl0vmHgHxXWJ9/ufw==} - dependencies: - is-buffer: 2.0.5 - it-handshake: 2.0.0 - it-length-prefixed: 5.0.3 - dev: true - - /it-peekable@1.0.3: - resolution: {integrity: sha512-5+8zemFS+wSfIkSZyf0Zh5kNN+iGyccN02914BY4w/Dj+uoFEoPSvj5vaWn8pNZJNSxzjW0zHRxC3LUb2KWJTQ==} - dev: true - /it-peekable@2.0.1: resolution: {integrity: sha512-fJ/YTU9rHRhGJOM2hhQKKEfRM6uKB9r4yGGFLBHqp72ACC8Yi6+7/FhuBAMG8cpN6mLoj9auVX7ZJ3ul6qFpTA==} engines: {node: '>=16.0.0', npm: '>=7.0.0'} @@ -13650,10 +13114,6 @@ packages: /it-peekable@3.0.2: resolution: {integrity: sha512-nWwUdhNQ1CfAuoJmsaUotNMYUrfNIlY9gBA1jwWfWSu1I0mLY2brwreKHGOUptXLJUiG5pR04He0xYZMWBRiGA==} - /it-pipe@1.1.0: - resolution: {integrity: sha512-lF0/3qTVeth13TOnHVs0BTFaziwQF7m5Gg+E6JV0BXcLKutC92YjSi7bASgkPOXaLEb+YvNZrPorGMBIJvZfxg==} - dev: true - /it-pipe@2.0.5: resolution: {integrity: sha512-y85nW1N6zoiTnkidr2EAyC+ZVzc7Mwt2p+xt2a2ooG1ThFakSpNw1Kxm+7F13Aivru96brJhjQVRQNU+w0yozw==} engines: {node: '>=16.0.0', npm: '>=7.0.0'} @@ -13678,12 +13138,6 @@ packages: protons-runtime: 5.0.0(uint8arraylist@2.4.3) uint8arraylist: 2.4.3 - /it-pushable@1.4.2: - resolution: {integrity: sha512-vVPu0CGRsTI8eCfhMknA7KIBqqGFolbRx+1mbQ6XuZ7YCz995Qj7L4XUviwClFunisDq96FdxzF5FnAbw15afg==} - dependencies: - fast-fifo: 1.2.0 - dev: true - /it-pushable@3.1.3: resolution: {integrity: sha512-f50iQ85HISS6DaWCyrqf9QJ6G/kQtKIMf9xZkgZgyOvxEQDfn8OfYcLXXquCqgoLboxQtAW1ZFZyFIAsLHDtJw==} engines: {node: '>=16.0.0', npm: '>=7.0.0'} @@ -13694,12 +13148,6 @@ packages: dependencies: p-defer: 4.0.0 - /it-reader@3.0.0: - resolution: {integrity: sha512-NxR40odATeaBmSefn6Xn43DplYvn2KtEKQzn4jrTRuPYXMky5M4e+KQ7aTJh0k0vkytLyeenGO1I1GXlGm4laQ==} - dependencies: - bl: 5.1.0 - dev: true - /it-reader@6.0.4: resolution: {integrity: sha512-XCWifEcNFFjjBHtor4Sfaj8rcpt+FkY0L6WdhD578SCDhV4VUm7fCkF3dv5a+fTcfQqvN9BsxBTvWbYO6iCjTg==} engines: {node: '>=16.0.0', npm: '>=7.0.0'} @@ -13707,12 +13155,6 @@ packages: it-stream-types: 2.0.1 uint8arraylist: 2.4.3 - /it-sort@1.0.1: - resolution: {integrity: sha512-c+C48cP7XMMebB9irLrJs2EmpLILId8NYSojqAqN8etE8ienx0azBgaKvZHYH1DkerqIul0Fl2FqISu2BZgTEQ==} - dependencies: - it-all: 1.0.6 - dev: true - /it-sort@3.0.3: resolution: {integrity: sha512-9BuQc5Y2fmBUNhevQBUDHfItrQmzWoZcnzydJl91V6na6M+RkbNj71UtCPPNIpOt/SQG+va0pe1wMQJ9lP2Oew==} dependencies: @@ -13726,24 +13168,9 @@ packages: resolution: {integrity: sha512-6DmOs5r7ERDbvS4q8yLKENcj6Yecr7QQTqWApbZdfAUTEC947d+PEha7PCqhm//9oxaLYL7TWRekwhoXl2s6fg==} engines: {node: '>=16.0.0', npm: '>=7.0.0'} - /it-take@1.0.2: - resolution: {integrity: sha512-u7I6qhhxH7pSevcYNaMECtkvZW365ARqAIt9K+xjdK1B2WUDEjQSfETkOCT8bxFq/59LqrN3cMLUtTgmDBaygw==} - dev: true - /it-take@3.0.3: resolution: {integrity: sha512-Ay5SXEyrBKD0tO8PQif2QjrStImIsLIg0F50Uu4EeXOw8C9DfVIGfsGL3X9s65F2I9skDp9mLgBzl71IToMxNw==} - /it-tar@3.0.0: - resolution: {integrity: sha512-VhD1Hnx4IXDcQgYJnJgltkn+w5F8kiJaB46lqovh+YWfty2JGW7i40QQjWbSvcg1QfaU8is8AVX8xwx/Db9oOg==} - dependencies: - bl: 5.1.0 - buffer: 6.0.3 - iso-constants: 0.1.2 - it-concat: 2.0.0 - it-reader: 3.0.0 - p-defer: 3.0.0 - dev: true - /it-to-stream@1.0.0: resolution: {integrity: sha512-pLULMZMAB/+vbdvbZtebC0nWBTbG581lk6w8P7DfIIIKUfa8FbY7Oi0FxZcFPbxvISs7A9E+cMpLDBc1XhpAOA==} dependencies: @@ -13755,18 +13182,6 @@ packages: readable-stream: 3.6.2 dev: true - /it-ws@4.0.0: - resolution: {integrity: sha512-XmTzpMkevc6rUboy73r0CCNhciMmL/Yxir9O6FujRwdrjysztqLBQ1Xkr4CpY2m7BVSCObKotaCWJeZ29lOXRA==} - dependencies: - buffer: 6.0.3 - event-iterator: 2.0.0 - iso-url: 1.2.1 - ws: 7.5.9 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - dev: true - /it-ws@6.0.5: resolution: {integrity: sha512-xp7tF4fHgx8+vN3Qy/8wGiWUKbC9E1U1g9PwtlbdxD7pY4zld71ZyWZVFHLxnxxg14T9mVNK5uO7U9HK11VQ5g==} engines: {node: '>=16.0.0', npm: '>=7.0.0'} @@ -13798,6 +13213,7 @@ packages: '@jest/types': 27.5.1 execa: 5.1.1 throat: 6.0.2 + dev: false /jest-circus@27.5.1: resolution: {integrity: sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==} @@ -13824,6 +13240,7 @@ packages: throat: 6.0.2 transitivePeerDependencies: - supports-color + dev: false /jest-cli@27.5.1(ts-node@10.9.1): resolution: {integrity: sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==} @@ -13853,6 +13270,7 @@ packages: - supports-color - ts-node - utf-8-validate + dev: false /jest-config@27.5.1(ts-node@10.9.1): resolution: {integrity: sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==} @@ -13893,6 +13311,7 @@ packages: - canvas - supports-color - utf-8-validate + dev: false /jest-diff@27.5.1: resolution: {integrity: sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==} @@ -13902,12 +13321,14 @@ packages: diff-sequences: 27.5.1 jest-get-type: 27.5.1 pretty-format: 27.5.1 + dev: false /jest-docblock@27.5.1: resolution: {integrity: sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: detect-newline: 3.1.0 + dev: false /jest-each@27.5.1: resolution: {integrity: sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==} @@ -13918,6 +13339,7 @@ packages: jest-get-type: 27.5.1 jest-util: 27.5.1 pretty-format: 27.5.1 + dev: false /jest-environment-jsdom@27.5.1: resolution: {integrity: sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==} @@ -13935,6 +13357,7 @@ packages: - canvas - supports-color - utf-8-validate + dev: false /jest-environment-node@27.5.1: resolution: {integrity: sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==} @@ -13946,10 +13369,12 @@ packages: '@types/node': 20.7.0 jest-mock: 27.5.1 jest-util: 27.5.1 + dev: false /jest-get-type@27.5.1: resolution: {integrity: sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dev: false /jest-haste-map@27.5.1: resolution: {integrity: sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==} @@ -13969,6 +13394,7 @@ packages: walker: 1.0.8 optionalDependencies: fsevents: 2.3.3 + dev: false /jest-jasmine2@27.5.1: resolution: {integrity: sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==} @@ -13993,6 +13419,7 @@ packages: throat: 6.0.2 transitivePeerDependencies: - supports-color + dev: false /jest-leak-detector@27.5.1: resolution: {integrity: sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==} @@ -14000,6 +13427,7 @@ packages: dependencies: jest-get-type: 27.5.1 pretty-format: 27.5.1 + dev: false /jest-matcher-utils@27.5.1: resolution: {integrity: sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==} @@ -14009,6 +13437,7 @@ packages: jest-diff: 27.5.1 jest-get-type: 27.5.1 pretty-format: 27.5.1 + dev: false /jest-message-util@27.5.1: resolution: {integrity: sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==} @@ -14023,6 +13452,7 @@ packages: pretty-format: 27.5.1 slash: 3.0.0 stack-utils: 2.0.6 + dev: false /jest-message-util@28.1.3: resolution: {integrity: sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==} @@ -14045,6 +13475,7 @@ packages: dependencies: '@jest/types': 27.5.1 '@types/node': 20.7.0 + dev: false /jest-pnp-resolver@1.2.3(jest-resolve@27.5.1): resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} @@ -14056,10 +13487,12 @@ packages: optional: true dependencies: jest-resolve: 27.5.1 + dev: false /jest-regex-util@27.5.1: resolution: {integrity: sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dev: false /jest-regex-util@28.0.2: resolution: {integrity: sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==} @@ -14075,6 +13508,7 @@ packages: jest-snapshot: 27.5.1 transitivePeerDependencies: - supports-color + dev: false /jest-resolve@27.5.1: resolution: {integrity: sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==} @@ -14090,6 +13524,7 @@ packages: resolve: 1.22.4 resolve.exports: 1.1.1 slash: 3.0.0 + dev: false /jest-runner@27.5.1: resolution: {integrity: sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==} @@ -14121,6 +13556,7 @@ packages: - canvas - supports-color - utf-8-validate + dev: false /jest-runtime@27.5.1: resolution: {integrity: sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==} @@ -14150,6 +13586,7 @@ packages: strip-bom: 4.0.0 transitivePeerDependencies: - supports-color + dev: false /jest-serializer@27.5.1: resolution: {integrity: sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==} @@ -14157,6 +13594,7 @@ packages: dependencies: '@types/node': 20.7.0 graceful-fs: 4.2.11 + dev: false /jest-snapshot@27.5.1: resolution: {integrity: sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==} @@ -14186,6 +13624,7 @@ packages: semver: 7.5.4 transitivePeerDependencies: - supports-color + dev: false /jest-util@27.5.1: resolution: {integrity: sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==} @@ -14197,6 +13636,7 @@ packages: ci-info: 3.8.0 graceful-fs: 4.2.11 picomatch: 2.3.1 + dev: false /jest-util@28.1.3: resolution: {integrity: sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==} @@ -14220,6 +13660,7 @@ packages: jest-get-type: 27.5.1 leven: 3.1.0 pretty-format: 27.5.1 + dev: false /jest-watch-typeahead@1.1.0(jest@27.5.1): resolution: {integrity: sha512-Va5nLSJTN7YFtC2jd+7wsoe1pNe5K4ShLux/E5iHEwlB9AxaxmggY7to9KUqKojhaJw3aXqt5WAb4jGPOolpEw==} @@ -14248,6 +13689,7 @@ packages: chalk: 4.1.2 jest-util: 27.5.1 string-length: 4.0.2 + dev: false /jest-watcher@28.1.3: resolution: {integrity: sha512-t4qcqj9hze+jviFPUN3YAtAEeFnr/azITXQEMARf5cMwKY2SMBRnCQTXLixTl20OR6mLh9KLMrgVJgJISym+1g==} @@ -14279,6 +13721,7 @@ packages: '@types/node': 20.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 + dev: false /jest-worker@28.1.3: resolution: {integrity: sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==} @@ -14308,6 +13751,7 @@ packages: - supports-color - ts-node - utf-8-validate + dev: false /jiti@1.18.2: resolution: {integrity: sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==} @@ -14357,10 +13801,6 @@ packages: resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==} dev: true - /jsbn@1.1.0: - resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==} - dev: true - /jsdom@16.7.0: resolution: {integrity: sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==} engines: {node: '>=10'} @@ -14401,6 +13841,7 @@ packages: - bufferutil - supports-color - utf-8-validate + dev: false /jsesc@0.5.0: resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==} @@ -14411,6 +13852,7 @@ packages: resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} engines: {node: '>=4'} hasBin: true + dev: false /json-buffer@3.0.0: resolution: {integrity: sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==} @@ -14443,13 +13885,6 @@ packages: resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} dev: true - /json-text-sequence@0.3.0: - resolution: {integrity: sha512-7khKIYPKwXQem4lWXfpIN/FEnhztCeRPSxH4qm3fVlqulwujrRDD54xAwDDn/qVKpFtV550+QAkcWJcufzqQuA==} - engines: {node: '>=10.18.0'} - dependencies: - '@sovpro/delimited-stream': 1.1.0 - dev: true - /json5@1.0.2: resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} hasBin: true @@ -14460,6 +13895,7 @@ packages: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} hasBin: true + dev: false /jsonc-parser@3.2.0: resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} @@ -14521,10 +13957,6 @@ packages: readable-stream: 3.6.2 dev: true - /keypair@1.0.4: - resolution: {integrity: sha512-zwhgOhhniaL7oxMgUMKKw5219PWWABMO+dgMnzJOQ2/5L3XJtTJGhW2PEXlxXj9zaccdReZJZ83+4NPhVfNVDg==} - dev: true - /keyv@3.1.0: resolution: {integrity: sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==} dependencies: @@ -14554,6 +13986,7 @@ packages: /kleur@3.0.3: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} + dev: false /klona@2.0.6: resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} @@ -14601,6 +14034,7 @@ packages: /leven@3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} engines: {node: '>=6'} + dev: false /levn@0.3.0: resolution: {integrity: sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==} @@ -14617,190 +14051,6 @@ packages: prelude-ls: 1.2.1 type-check: 0.4.0 - /libp2p-crypto@0.19.7: - resolution: {integrity: sha512-Qb5o/3WFKF2j6mYSt4UBPyi2kbKl3jYV0podBJoJCw70DlpM5Xc+oh3fFY9ToSunu8aSQQ5GY8nutjXgX/uGRA==} - engines: {node: '>=12.0.0'} - dependencies: - err-code: 3.0.1 - is-typedarray: 1.0.0 - iso-random-stream: 2.0.2 - keypair: 1.0.4 - multiformats: 9.9.0 - node-forge: 0.10.0 - pem-jwk: 2.0.0 - protobufjs: 6.11.3 - secp256k1: 4.0.3 - uint8arrays: 3.1.1 - ursa-optional: 0.10.2 - dev: true - - /libp2p-crypto@0.20.0: - resolution: {integrity: sha512-WgIW9rYcWaO/5j2T6NW3R6Q46yvp2ZfFErqRMbi4/pOTL3T7+OROYpL/1iWVksWkXyurU/t2qFsIijWMxR5C4Q==} - engines: {node: '>=12.0.0'} - dependencies: - err-code: 3.0.1 - iso-random-stream: 2.0.2 - keypair: 1.0.4 - multiformats: 9.9.0 - noble-ed25519: 1.2.6 - noble-secp256k1: 1.2.14 - node-forge: 0.10.0 - pem-jwk: 2.0.0 - protobufjs: 6.11.3 - uint8arrays: 3.1.1 - ursa-optional: 0.10.2 - dev: true - - /libp2p-crypto@0.21.2: - resolution: {integrity: sha512-EXFrhSpiHtJ+/L8xXDvQNK5VjUMG51u878jzZcaT5XhuN/zFg6PWJFnl/qB2Y2j7eMWnvCRP7Kp+ua2H36cG4g==} - engines: {node: '>=12.0.0'} - dependencies: - '@noble/ed25519': 1.7.3 - '@noble/secp256k1': 1.7.1 - err-code: 3.0.1 - iso-random-stream: 2.0.2 - multiformats: 9.9.0 - node-forge: 1.3.1 - protobufjs: 6.11.3 - uint8arrays: 3.1.1 - dev: true - - /libp2p-interfaces@4.0.6(node-fetch@3.3.2): - resolution: {integrity: sha512-3KjzNEIWhi+VoOamLvgKKUE/xqwxSw/JYqsBnfMhAWVRvRtosROtVT03wci2XbuuowCYw+/hEX1xKJIR1w5n0A==} - dependencies: - abortable-iterator: 3.0.2 - debug: 4.3.4(supports-color@8.1.1) - err-code: 3.0.1 - it-length-prefixed: 5.0.3 - it-pipe: 1.1.0 - it-pushable: 1.4.2 - libp2p-crypto: 0.21.2 - multiaddr: 10.0.1(node-fetch@3.3.2) - multiformats: 9.9.0 - p-queue: 6.6.2 - peer-id: 0.16.0 - protobufjs: 6.11.3 - uint8arrays: 3.1.1 - transitivePeerDependencies: - - node-fetch - - supports-color - dev: true - - /libp2p-mplex@0.10.7: - resolution: {integrity: sha512-21VV0DZWuOsHgitWy1GZD1M/kki3a/hVoAJ5QC48p01JNSK5W8gxRiZtq7cCGJ/xNpbQxvMlMtS5eq8CFRlysg==} - dependencies: - abortable-iterator: 3.0.2 - bl: 5.1.0 - debug: 4.3.4(supports-color@8.1.1) - err-code: 3.0.1 - it-pipe: 1.1.0 - it-pushable: 1.4.2 - varint: 6.0.0 - transitivePeerDependencies: - - supports-color - dev: true - - /libp2p-utils@0.4.1(node-fetch@3.3.2): - resolution: {integrity: sha512-kq/US2unamiyY+YwP47dO1uqpAdcbdYI2Fzi9JIEhjfPBaD1MR/uyQ/YP7ABthl3EaxAjIQYd1TVp85d6QKAtQ==} - dependencies: - abortable-iterator: 3.0.2 - debug: 4.3.4(supports-color@8.1.1) - err-code: 3.0.1 - ip-address: 8.1.0 - is-loopback-addr: 1.0.1 - multiaddr: 10.0.1(node-fetch@3.3.2) - private-ip: 2.3.4 - transitivePeerDependencies: - - node-fetch - - supports-color - dev: true - - /libp2p-websockets@0.16.2(node-fetch@3.3.2): - resolution: {integrity: sha512-QGfo8jX1Ks16yi8C67CCyMW7k9cfCYiQ0lzKVJBud0fV3ymbMO2L8gzU6iXUUZTHILo8ka26zKhwQ4lmUMI+nA==} - dependencies: - abortable-iterator: 3.0.2 - class-is: 1.1.0 - debug: 4.3.4(supports-color@8.1.1) - err-code: 3.0.1 - ipfs-utils: 9.0.14 - it-ws: 4.0.0 - libp2p-utils: 0.4.1(node-fetch@3.3.2) - mafmt: 10.0.0(node-fetch@3.3.2) - multiaddr: 10.0.1(node-fetch@3.3.2) - multiaddr-to-uri: 8.0.0(node-fetch@3.3.2) - p-defer: 3.0.0 - p-timeout: 4.1.0 - transitivePeerDependencies: - - bufferutil - - encoding - - node-fetch - - supports-color - - utf-8-validate - dev: true - - /libp2p@0.36.2(node-fetch@3.3.2): - resolution: {integrity: sha512-UpNYBMQVivMu56zoibdGitopv39uBBAybIBOEGWmFy/I2NnTVGUutLPrxo47AuN2kntYgo/TNJfW+PpswUgSaw==} - engines: {node: '>=15.0.0'} - dependencies: - '@vascosantos/moving-average': 1.1.0 - abortable-iterator: 3.0.2 - aggregate-error: 3.1.0 - any-signal: 3.0.1 - bignumber.js: 9.1.1 - class-is: 1.1.0 - datastore-core: 7.0.3 - debug: 4.3.4(supports-color@8.1.1) - err-code: 3.0.1 - es6-promisify: 7.0.0 - events: 3.3.0 - hashlru: 2.3.0 - interface-datastore: 6.1.1 - it-all: 1.0.6 - it-buffer: 0.1.3 - it-drain: 1.0.5 - it-filter: 1.0.3 - it-first: 1.0.7 - it-foreach: 0.1.1 - it-handshake: 2.0.0 - it-length-prefixed: 5.0.3 - it-map: 1.0.6 - it-merge: 1.0.4 - it-pipe: 1.1.0 - it-sort: 1.0.1 - it-take: 1.0.2 - libp2p-crypto: 0.21.2 - libp2p-interfaces: 4.0.6(node-fetch@3.3.2) - libp2p-utils: 0.4.1(node-fetch@3.3.2) - mafmt: 10.0.0(node-fetch@3.3.2) - merge-options: 3.0.4 - mortice: 2.0.1 - multiaddr: 10.0.1(node-fetch@3.3.2) - multiformats: 9.9.0 - multistream-select: 3.0.2 - mutable-proxy: 1.0.0 - nat-api: 0.3.1 - node-forge: 1.3.1 - p-any: 3.0.0 - p-fifo: 1.0.0 - p-retry: 4.6.2 - p-settle: 4.1.1 - peer-id: 0.16.0 - private-ip: 2.3.4 - protobufjs: 6.11.3 - retimer: 3.0.0 - sanitize-filename: 1.6.3 - set-delayed-interval: 1.0.0 - streaming-iterables: 6.2.0 - timeout-abort-controller: 3.0.0 - uint8arrays: 3.1.1 - varint: 6.0.0 - wherearewe: 1.0.2 - xsalsa20: 1.2.0 - transitivePeerDependencies: - - node-fetch - - supports-color - dev: true - /libp2p@0.46.6: resolution: {integrity: sha512-5zDUpi4Foj30s+I/f6UC+wrO2u1CMLVFXby+AnCl1cEt4r+z92rLlN1Td0gUQjiAw1I3EL9yI+ASt3/Pts5IPw==} dependencies: @@ -14905,6 +14155,7 @@ packages: engines: {node: '>=8'} dependencies: p-locate: 4.1.0 + dev: false /locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} @@ -14930,6 +14181,7 @@ packages: /lodash.memoize@4.1.2: resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + dev: false /lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} @@ -14975,24 +14227,10 @@ packages: is-unicode-supported: 0.1.0 dev: true - /loglevel@1.8.0: - resolution: {integrity: sha512-G6A/nJLRgWOuuwdNuA6koovfEV1YpqqAG4pRUlFaz3jj2QNZ8M4vBqnVA+HBTmU/AMNUtlOsMmSpF6NyOjztbA==} - engines: {node: '>= 0.6.0'} - dev: true - - /loglevel@1.8.1: - resolution: {integrity: sha512-tCRIJM51SHjAayKwC+QAg8hT8vg6z7GSgLJKGvzuPb1Wc+hLzqtuVLxp6/HzSPOozuK+8ErAhy7U/sVzw8Dgfg==} - engines: {node: '>= 0.6.0'} - dev: true - /lokijs@1.5.12: resolution: {integrity: sha512-Q5ALD6JiS6xAUWCwX3taQmgwxyveCtIIuL08+ml0nHwT3k0S/GIFJN+Hd38b1qYIMaE5X++iqsqWVksz7SYW+Q==} dev: true - /long@4.0.0: - resolution: {integrity: sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==} - dev: true - /long@5.2.3: resolution: {integrity: sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==} @@ -15057,15 +14295,6 @@ packages: hasBin: true dev: false - /mafmt@10.0.0(node-fetch@3.3.2): - resolution: {integrity: sha512-K1bziJOXcnepfztu+2Xy9FLKVLaFMDuspmiyJIYRxnO0WOxFSV7XKSdMxMrVZxcvg1+YjlTIvSGTImUHU2k4Aw==} - dependencies: - multiaddr: 10.0.1(node-fetch@3.3.2) - transitivePeerDependencies: - - node-fetch - - supports-color - dev: true - /magic-string@0.25.9: resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} dependencies: @@ -15098,6 +14327,7 @@ packages: engines: {node: '>=10'} dependencies: semver: 7.5.4 + dev: false /make-error@1.3.6: resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} @@ -15106,6 +14336,7 @@ packages: resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} dependencies: tmpl: 1.0.5 + dev: false /markdown-table@1.1.3: resolution: {integrity: sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q==} @@ -15431,15 +14662,6 @@ packages: engines: {node: '>=10'} dev: true - /mortice@2.0.1: - resolution: {integrity: sha512-9gsXmjq+5LZmXDIoyC/crf2i/7CUwDGSBEwSEsr1i/WfKmJ6DVt38B5kg6BE/WF/1/yfGJYiB1Wyiu423iI3nQ==} - dependencies: - nanoid: 3.3.6 - observable-webworkers: 1.0.0 - p-queue: 6.6.2 - promise-timeout: 1.3.0 - dev: true - /mortice@3.0.1: resolution: {integrity: sha512-eyDUsl1nCR9+JtNksKnaESLP9MgAXCA4w1LTtsmOSQNsThnv++f36rrBu5fC/fdGIwTJZmbiaR/QewptH93pYA==} engines: {node: '>=16.0.0', npm: '>=7.0.0'} @@ -15462,57 +14684,6 @@ packages: /ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - /multiaddr-to-uri@7.0.0(node-fetch@3.3.2): - resolution: {integrity: sha512-VbscDpLcbV0m25tJqfnZSfbjVUuNlPa4BbD5l/7me1t0lc3SWI0XAoO5E/PNJF0e1qUlbdq7yjVFEQjUT+9r0g==} - deprecated: This module is deprecated, please upgrade to @multiformats/multiaddr-to-uri - dependencies: - multiaddr: 9.0.2(node-fetch@3.3.2) - transitivePeerDependencies: - - node-fetch - - supports-color - dev: true - - /multiaddr-to-uri@8.0.0(node-fetch@3.3.2): - resolution: {integrity: sha512-dq4p/vsOOUdVEd1J1gl+R2GFrXJQH8yjLtz4hodqdVbieg39LvBOdMQRdQnfbg5LSM/q1BYNVf5CBbwZFFqBgA==} - deprecated: This module is deprecated, please upgrade to @multiformats/multiaddr-to-uri - dependencies: - multiaddr: 10.0.1(node-fetch@3.3.2) - transitivePeerDependencies: - - node-fetch - - supports-color - dev: true - - /multiaddr@10.0.1(node-fetch@3.3.2): - resolution: {integrity: sha512-G5upNcGzEGuTHkzxezPrrD6CaIHR9uo+7MwqhNVcXTs33IInon4y7nMiGxl2CY5hG7chvYQUQhz5V52/Qe3cbg==} - deprecated: This module is deprecated, please upgrade to @multiformats/multiaddr - dependencies: - dns-over-http-resolver: 1.2.3(node-fetch@3.3.2) - err-code: 3.0.1 - is-ip: 3.1.0 - multiformats: 9.9.0 - uint8arrays: 3.1.1 - varint: 6.0.0 - transitivePeerDependencies: - - node-fetch - - supports-color - dev: true - - /multiaddr@9.0.2(node-fetch@3.3.2): - resolution: {integrity: sha512-YFaEb9t4yXSbaGksSEdg+Kn2U02s7w4wXUgyEMQmPxFJj7CfVHY10WOsScAX/rK6Soa15S1zXYadqH9TtlVreQ==} - deprecated: This module is deprecated, please upgrade to @multiformats/multiaddr - dependencies: - cids: 1.1.9 - dns-over-http-resolver: 1.2.3(node-fetch@3.3.2) - err-code: 3.0.1 - is-ip: 3.1.0 - multibase: 4.0.6 - uint8arrays: 2.1.10 - varint: 6.0.0 - transitivePeerDependencies: - - node-fetch - - supports-color - dev: true - /multibase@0.6.1: resolution: {integrity: sha512-pFfAwyTjbbQgNc3G7D48JkJxWtoJoBMaR4xQUOuB8RnCgRqaYmWNFeJTTvrJ2w51bjLq2zTby6Rqj9TQ9elSUw==} deprecated: This module has been superseded by the multiformats module @@ -15529,14 +14700,6 @@ packages: buffer: 5.7.1 dev: true - /multibase@4.0.6: - resolution: {integrity: sha512-x23pDe5+svdLz/k5JPGCVdfn7Q5mZVMBETiC+ORfO+sor9Sgs0smJzAjfTbM5tckeCqnaUuMYoz+k3RXMmJClQ==} - engines: {node: '>=12.0.0', npm: '>=6.0.0'} - deprecated: This module has been superseded by the multiformats module - dependencies: - '@multiformats/base-x': 4.0.1 - dev: true - /multicast-dns@7.2.5: resolution: {integrity: sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==} hasBin: true @@ -15557,15 +14720,7 @@ packages: deprecated: This module has been superseded by the multiformats module dependencies: buffer: 5.7.1 - varint: 5.0.2 - dev: true - - /multicodec@3.2.1: - resolution: {integrity: sha512-+expTPftro8VAW8kfvcuNNNBgb9gPeNYV9dn+z1kJRWF2vih+/S79f2RVeIwmrJBUJ6NT9IUPWnZDQvegEh5pw==} - deprecated: This module has been superseded by the multiformats module - dependencies: - uint8arrays: 3.1.1 - varint: 6.0.0 + varint: 5.0.2 dev: true /multiformats@11.0.1: @@ -15592,55 +14747,6 @@ packages: varint: 5.0.2 dev: true - /multihashes@4.0.3: - resolution: {integrity: sha512-0AhMH7Iu95XjDLxIeuCOOE4t9+vQZsACyKZ9Fxw2pcsRmlX4iCn1mby0hS0bb+nQOVpdQYWPpnyusw4da5RPhA==} - engines: {node: '>=12.0.0', npm: '>=6.0.0'} - dependencies: - multibase: 4.0.6 - uint8arrays: 3.1.1 - varint: 5.0.2 - dev: true - - /multihashing-async@2.1.4: - resolution: {integrity: sha512-sB1MiQXPSBTNRVSJc2zM157PXgDtud2nMFUEIvBrsq5Wv96sUclMRK/ecjoP1T/W61UJBqt4tCTwMkUpt2Gbzg==} - engines: {node: '>=12.0.0', npm: '>=6.0.0'} - dependencies: - blakejs: 1.2.1 - err-code: 3.0.1 - js-sha3: 0.8.0 - multihashes: 4.0.3 - murmurhash3js-revisited: 3.0.0 - uint8arrays: 3.1.1 - dev: true - - /multistream-select@3.0.2: - resolution: {integrity: sha512-ICGA8DAviZj6Xo1NkaRV3J38M+tFDoWiGtO1ksluyMnskAsdGjAzocg806OzpQPivNGWWboX3CrFT2Tk4UdYXA==} - dependencies: - abortable-iterator: 3.0.2 - bl: 5.1.0 - debug: 4.3.4(supports-color@8.1.1) - err-code: 3.0.1 - it-first: 1.0.7 - it-handshake: 2.0.0 - it-length-prefixed: 5.0.3 - it-pipe: 1.1.0 - it-reader: 3.0.0 - p-defer: 3.0.0 - uint8arrays: 3.1.1 - transitivePeerDependencies: - - supports-color - dev: true - - /murmurhash3js-revisited@3.0.0: - resolution: {integrity: sha512-/sF3ee6zvScXMb1XFJ8gDsSnY+X8PbOyjIuBhtgis10W2Jx4ZjIhikUCIF9c4gpJxVnQIsPAFrSwTCuAjicP6g==} - engines: {node: '>=8.0.0'} - dev: true - - /mutable-proxy@1.0.0: - resolution: {integrity: sha512-4OvNRr1DJpy2QuDUV74m+BWZ//n4gG4bmd21MzDSPqHEidIDWqwyOjcadU1LBMO3vXYGurVKjfBrxrSQIHFu9A==} - engines: {node: '>=6.X.X', npm: '>=3.X.X'} - dev: true - /mute-stream@0.0.8: resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} dev: true @@ -15658,10 +14764,6 @@ packages: thenify-all: 1.6.0 dev: false - /nan@2.17.0: - resolution: {integrity: sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==} - dev: true - /nano-json-stream-parser@0.1.2: resolution: {integrity: sha512-9MqxMH/BSJC7dnLsEMPyfN5Dvoo49IsPFYMcHw3Bcfc2kN0lpHRBSzlMSVx4HGyJ7s9B31CyBTVehWJoQ8Ctew==} dev: true @@ -15686,36 +14788,6 @@ packages: resolution: {integrity: sha512-hmEVtAGYzVQpCKdbQea4skABsdXW4RUh5t5mJ2zzqowJS2OyXZTU1KhDVFhx+NlWZ4ap9mqR9TcDO3LTTttd+g==} dev: true - /nat-api@0.3.1: - resolution: {integrity: sha512-5cyLugEkXnKSKSvVjKjxxPMLDnkwY3boZLbATWwiGJ4T/3UvIpiQmzb2RqtxxEFcVo/7PwsHPGN0MosopONO8Q==} - engines: {node: '>=10.0.0'} - dependencies: - async: 3.2.4 - debug: 4.3.4(supports-color@8.1.1) - default-gateway: 6.0.3 - request: 2.88.2 - unordered-array-remove: 1.0.2 - xml2js: 0.1.14 - transitivePeerDependencies: - - supports-color - dev: true - - /native-abort-controller@1.0.4(abort-controller@3.0.0): - resolution: {integrity: sha512-zp8yev7nxczDJMoP6pDxyD20IU0T22eX8VwN2ztDccKvSZhRaV33yP1BGwKSZfXuqWUzsXopVFjBdau9OOAwMQ==} - peerDependencies: - abort-controller: '*' - dependencies: - abort-controller: 3.0.0 - dev: true - - /native-fetch@3.0.0(@achingbrain/node-fetch@2.6.7): - resolution: {integrity: sha512-G3Z7vx0IFb/FQ4JxvtqGABsOTIqRWvgQz6e+erkB+JJD6LrszQtMozEHI4EkmgZQvnGHrpLVzUWk7t4sJCIkVw==} - peerDependencies: - node-fetch: '*' - dependencies: - node-fetch: /@achingbrain/node-fetch@2.6.7 - dev: true - /native-fetch@3.0.0(node-fetch@2.6.13): resolution: {integrity: sha512-G3Z7vx0IFb/FQ4JxvtqGABsOTIqRWvgQz6e+erkB+JJD6LrszQtMozEHI4EkmgZQvnGHrpLVzUWk7t4sJCIkVw==} peerDependencies: @@ -15724,14 +14796,6 @@ packages: node-fetch: 2.6.13 dev: true - /native-fetch@3.0.0(node-fetch@3.3.2): - resolution: {integrity: sha512-G3Z7vx0IFb/FQ4JxvtqGABsOTIqRWvgQz6e+erkB+JJD6LrszQtMozEHI4EkmgZQvnGHrpLVzUWk7t4sJCIkVw==} - peerDependencies: - node-fetch: '*' - dependencies: - node-fetch: 3.3.2 - dev: true - /native-fetch@4.0.2(undici@5.22.1): resolution: {integrity: sha512-4QcVlKFtv2EYVS5MBgsGX5+NWKtbDbIECdUXDBGDMAZXq3Jkv9zf+y8iS7Ub8fEdga3GpYeazp9gauNqXHJOCg==} peerDependencies: @@ -15776,25 +14840,10 @@ packages: tslib: 2.5.3 dev: false - /noble-ed25519@1.2.6: - resolution: {integrity: sha512-zfnWqg9FVMp8CnzUpAjbt1nDXpDjCvxYiCXdnW1mY8zQHw/6twUlkFm14VPdojVzc0kcd+i9zT79+26GcNbsuQ==} - deprecated: Switch to namespaced @noble/ed25519 for security and feature updates - dev: true - - /noble-secp256k1@1.2.14: - resolution: {integrity: sha512-GSCXyoZBUaaPwVWdYncMEmzlSUjF9J/YeEHpklYJCyg8wPuJP3NzDx0BkiwArzINkdX2HJHvUJhL6vVWPOQQcg==} - deprecated: Switch to namespaced @noble/secp256k1 for security and feature updates - dev: true - /node-addon-api@2.0.2: resolution: {integrity: sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==} dev: true - /node-domexception@1.0.0: - resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} - engines: {node: '>=10.5.0'} - dev: true - /node-emoji@1.11.0: resolution: {integrity: sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==} dependencies: @@ -15832,20 +14881,6 @@ packages: whatwg-url: 5.0.0 dev: true - /node-fetch@3.3.2: - resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dependencies: - data-uri-to-buffer: 4.0.1 - fetch-blob: 3.2.0 - formdata-polyfill: 4.0.10 - dev: true - - /node-forge@0.10.0: - resolution: {integrity: sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==} - engines: {node: '>= 6.0.0'} - dev: true - /node-forge@1.3.1: resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} engines: {node: '>= 6.13.0'} @@ -15857,6 +14892,7 @@ packages: /node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} + dev: false /node-releases@2.0.12: resolution: {integrity: sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==} @@ -15864,6 +14900,7 @@ packages: /node-releases@2.0.13: resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==} + dev: false /node-stdlib-browser@1.2.0: resolution: {integrity: sha512-VSjFxUhRhkyed8AtLwSCkMrJRfQ3e2lGtG3sP6FEgaLKBBbxM/dLfjRe1+iLhjvyLFW3tBQ8+c0pcOtXGbAZJg==} @@ -16037,6 +15074,7 @@ packages: /nwsapi@2.2.7: resolution: {integrity: sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==} + dev: false /oauth-sign@0.9.0: resolution: {integrity: sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==} @@ -16153,10 +15191,6 @@ packages: /observable-fns@0.6.1: resolution: {integrity: sha512-9gRK4+sRWzeN6AOewNBTLXir7Zl/i3GB6Yl26gK4flxz8BXVpD3kt8amREmWNb0mxYOGDotvE5a4N+PtGGKdkg==} - /observable-webworkers@1.0.0: - resolution: {integrity: sha512-+cECwCR8IEh8UY5nefQVLO9Cydqpk1izO+o7BABmKjXfJZyEOzBWY3ss5jbOPM6KmEa9aQExvAtTW6tVTOsNAQ==} - dev: true - /observable-webworkers@2.0.1: resolution: {integrity: sha512-JI1vB0u3pZjoQKOK1ROWzp0ygxSi7Yb0iR+7UNsw4/Zn4cQ0P3R7XL38zac/Dy2tEA7Lg88/wIJTjF8vYXZ0uw==} engines: {node: '>=16.0.0', npm: '>=7.0.0'} @@ -16267,14 +15301,6 @@ packages: resolution: {integrity: sha512-AlWY719RF02ujitly7Kk/0QlV+pXGFDHrHf9O2OKqyqgBieaPOIeuSkL8sRK6j2WK+/ZAURq2kZsY0d8JapUiw==} dev: true - /p-any@3.0.0: - resolution: {integrity: sha512-5rqbqfsRWNb0sukt0awwgJMlaep+8jV45S15SKKB34z4UuzjcofIfnriCBhWjZP2jbVtjt9yRl7buB6RlKsu9w==} - engines: {node: '>=10'} - dependencies: - p-cancelable: 2.1.1 - p-some: 5.0.0 - dev: true - /p-cancelable@1.1.0: resolution: {integrity: sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==} engines: {node: '>=6'} @@ -16306,11 +15332,6 @@ packages: p-defer: 3.0.0 dev: true - /p-finally@1.0.0: - resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} - engines: {node: '>=4'} - dev: true - /p-limit@1.3.0: resolution: {integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==} engines: {node: '>=4'} @@ -16355,6 +15376,7 @@ packages: engines: {node: '>=8'} dependencies: p-limit: 2.3.0 + dev: false /p-locate@5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} @@ -16369,14 +15391,6 @@ packages: aggregate-error: 3.1.0 dev: true - /p-queue@6.6.2: - resolution: {integrity: sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==} - engines: {node: '>=8'} - dependencies: - eventemitter3: 4.0.7 - p-timeout: 3.2.0 - dev: true - /p-queue@7.3.4: resolution: {integrity: sha512-esox8CWt0j9EZECFvkFl2WNPat8LN4t7WWeXq73D9ha0V96qPRufApZi4ZhPwXAln1uVVal429HVVKPa2X0yQg==} engines: {node: '>=12'} @@ -16384,17 +15398,13 @@ packages: eventemitter3: 4.0.7 p-timeout: 5.1.0 - /p-reflect@2.1.0: - resolution: {integrity: sha512-paHV8NUz8zDHu5lhr/ngGWQiW067DK/+IbJ+RfZ4k+s8y4EKyYCz8pGYWjxCg35eHztpJAt+NUgvN4L+GCbPlg==} - engines: {node: '>=8'} - dev: true - /p-retry@4.6.2: resolution: {integrity: sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==} engines: {node: '>=8'} dependencies: '@types/retry': 0.12.0 retry: 0.13.1 + dev: false /p-retry@5.1.2: resolution: {integrity: sha512-couX95waDu98NfNZV+i/iLt+fdVxmI7CbrrdC2uDWfPdUAApyxT4wmDlyOtR5KtTDmkDO0zDScDjDou9YHhd9g==} @@ -16403,34 +15413,6 @@ packages: '@types/retry': 0.12.1 retry: 0.13.1 - /p-settle@4.1.1: - resolution: {integrity: sha512-6THGh13mt3gypcNMm0ADqVNCcYa3BK6DWsuJWFCuEKP1rpY+OKGp7gaZwVmLspmic01+fsg/fN57MfvDzZ/PuQ==} - engines: {node: '>=10'} - dependencies: - p-limit: 2.3.0 - p-reflect: 2.1.0 - dev: true - - /p-some@5.0.0: - resolution: {integrity: sha512-Js5XZxo6vHjB9NOYAzWDYAIyyiPvva0DWESAIWIK7uhSpGsyg5FwUPxipU/SOQx5x9EqhOh545d1jo6cVkitig==} - engines: {node: '>=10'} - dependencies: - aggregate-error: 3.1.0 - p-cancelable: 2.1.1 - dev: true - - /p-timeout@3.2.0: - resolution: {integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==} - engines: {node: '>=8'} - dependencies: - p-finally: 1.0.0 - dev: true - - /p-timeout@4.1.0: - resolution: {integrity: sha512-+/wmHtzJuWii1sXn3HCuH/FTwGhrp4tmJTxSKJbfS+vkipci6osxXM5mY0jUiRzWKMTgUT8l7HFbeSwZAynqHw==} - engines: {node: '>=10'} - dev: true - /p-timeout@5.1.0: resolution: {integrity: sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew==} engines: {node: '>=12'} @@ -16505,6 +15487,7 @@ packages: /parse5@6.0.1: resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} + dev: false /parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} @@ -16585,38 +15568,6 @@ packages: sha.js: 2.4.11 dev: true - /peer-id@0.15.4: - resolution: {integrity: sha512-MDoBIMZYwQIAHaZQUwsIcvoFgdbIl5GtZMwSkXpIYvc5v0TSDv+u8WsTKrKt2Vv28tHFFDJQdVzu3T4qTPzK+w==} - engines: {node: '>=14.0.0'} - hasBin: true - dependencies: - class-is: 1.1.0 - libp2p-crypto: 0.20.0 - minimist: 1.2.8 - multiformats: 9.9.0 - protobufjs: 6.11.3 - uint8arrays: 3.1.1 - dev: true - - /peer-id@0.16.0: - resolution: {integrity: sha512-EmL7FurFUduU9m1PS9cfJ5TAuCvxKQ7DKpfx3Yj6IKWyBRtosriFuOag/l3ni/dtPgPLwiA4R9IvpL7hsDLJuQ==} - engines: {node: '>=15.0.0'} - dependencies: - class-is: 1.1.0 - libp2p-crypto: 0.21.2 - multiformats: 9.9.0 - protobufjs: 6.11.3 - uint8arrays: 3.1.1 - dev: true - - /pem-jwk@2.0.0: - resolution: {integrity: sha512-rFxu7rVoHgQ5H9YsP50dDWf0rHjreVA2z0yPiWr5WdH/UHb29hKtF7h6l8vNd1cbYR1t0QL+JKhW55a2ZV4KtA==} - engines: {node: '>=5.10.0'} - hasBin: true - dependencies: - asn1.js: 5.4.1 - dev: true - /pend@1.2.0: resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} dev: true @@ -16692,12 +15643,14 @@ packages: /pirates@4.0.6: resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} engines: {node: '>= 6'} + dev: false /pkg-dir@4.2.0: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} dependencies: find-up: 4.1.0 + dev: false /pkg-dir@5.0.0: resolution: {integrity: sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==} @@ -17569,15 +16522,6 @@ packages: react-is: 18.2.0 dev: false - /private-ip@2.3.4: - resolution: {integrity: sha512-ts/YFVwfBeLq61f9+KsOhXW6RH0wvY0gU50R6QZYzgFhggyyLK6WDFeYdjfi/HMnBm2hecLvsR3PB3JcRxDk+A==} - dependencies: - ip-regex: 4.3.0 - ipaddr.js: 2.1.0 - is-ip: 3.1.0 - netmask: 2.0.2 - dev: true - /private-ip@3.0.0: resolution: {integrity: sha512-HkMBs4nMtrP+cvcw0bDi2BAZIGgiKI4Zq8Oc+dMqNBpHS8iGL4+WO/pRtc8Bwnv9rjnV0QwMDwEBymFtqv7Kww==} engines: {node: '>=14.16'} @@ -17604,10 +16548,6 @@ packages: engines: {node: '>=0.4.0'} dev: true - /promise-timeout@1.3.0: - resolution: {integrity: sha512-5yANTE0tmi5++POym6OgtFmwfDvOXABD9oj/jLQr5GPEyuNEb7jH4wbbANJceJid49jwhi1RddxnhnEAb/doqg==} - dev: true - /promise@8.3.0: resolution: {integrity: sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==} dependencies: @@ -17619,6 +16559,7 @@ packages: dependencies: kleur: 3.0.3 sisteransi: 1.0.5 + dev: false /prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} @@ -17628,26 +16569,6 @@ packages: react-is: 16.13.1 dev: false - /protobufjs@6.11.3: - resolution: {integrity: sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==} - hasBin: true - requiresBuild: true - dependencies: - '@protobufjs/aspromise': 1.1.2 - '@protobufjs/base64': 1.1.2 - '@protobufjs/codegen': 2.0.4 - '@protobufjs/eventemitter': 1.1.0 - '@protobufjs/fetch': 1.1.0 - '@protobufjs/float': 1.0.2 - '@protobufjs/inquire': 1.1.0 - '@protobufjs/path': 1.1.2 - '@protobufjs/pool': 1.1.0 - '@protobufjs/utf8': 1.1.0 - '@types/long': 4.0.2 - '@types/node': 20.7.0 - long: 4.0.0 - dev: true - /protobufjs@7.2.3: resolution: {integrity: sha512-TtpvOqwB5Gdz/PQmOjgsrGH1nHjAQVCN7JG4A6r1sXRWESL5rNMAiRcBQlCAdKxZcAbstExQePYG8xof/JVRgg==} engines: {node: '>=12.0.0'} @@ -17840,6 +16761,7 @@ packages: /querystringify@2.2.0: resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} + dev: false /queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -17984,12 +16906,6 @@ packages: resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} dev: false - /react-native-fetch-api@2.0.0: - resolution: {integrity: sha512-GOA8tc1EVYLnHvma/TU9VTgLOyralO7eATRuCDchQveXW9Fr9vXygyq9iwqmM7YRZ8qRJfEt9xOS7OYMdJvRFw==} - dependencies: - p-defer: 3.0.0 - dev: true - /react-native-fetch-api@3.0.0: resolution: {integrity: sha512-g2rtqPjdroaboDKTsJCTlcmtw54E25OjyaunUP0anOZn4Fuo2IKs8BVfe02zVggA/UysbmfSnRJIqtNkAgggNA==} dependencies: @@ -18359,6 +17275,7 @@ packages: engines: {node: '>=8'} dependencies: resolve-from: 5.0.0 + dev: false /resolve-from@3.0.0: resolution: {integrity: sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==} @@ -18372,6 +17289,7 @@ packages: /resolve-from@5.0.0: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} + dev: false /resolve-url-loader@4.0.0: resolution: {integrity: sha512-05VEMczVREcbtT7Bz+C+96eUO5HDNvdthIiMB34t7FcF8ehcu4wC0sSgPUubs3XW2Q3CNLJk/BJrCU9wVRymiA==} @@ -18395,6 +17313,7 @@ packages: /resolve.exports@1.1.1: resolution: {integrity: sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ==} engines: {node: '>=10'} + dev: false /resolve@1.1.7: resolution: {integrity: sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==} @@ -18452,10 +17371,6 @@ packages: signal-exit: 3.0.7 dev: true - /retimer@2.0.0: - resolution: {integrity: sha512-KLXY85WkEq2V2bKex/LOO1ViXVn2KGYe4PYysAdYdjmraYIUsVkXu8O4am+8+5UbaaGl1qho4aqAAPHNQ4GSbg==} - dev: true - /retimer@3.0.0: resolution: {integrity: sha512-WKE0j11Pa0ZJI5YIk0nflGI7SQsfl2ljihVy7ogh7DeQSeYAUi0ubZ/yEueGtDfUPk6GH5LRw1hBdLq4IwUBWA==} dev: true @@ -18645,6 +17560,7 @@ packages: engines: {node: '>=10'} dependencies: xmlchars: 2.2.0 + dev: false /sc-istanbul@0.4.6: resolution: {integrity: sha512-qJFF/8tW/zJsbyfh/iT/ZM5QNHE3CXxtLJbZsL+CzdJLBsPD7SedJZoUA4d8iAcN2IoMp/Dx80shOOd2x96X/g==} @@ -18867,10 +17783,6 @@ packages: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} dev: true - /set-delayed-interval@1.0.0: - resolution: {integrity: sha512-29fhAwuZlLcuBnW/EwxvLcg2D3ELX+VBDNhnavs3YYkab72qmrcSeQNVdzl8EcPPahGQXhBM6MKdPLCQGMDakw==} - dev: true - /set-function-name@2.0.1: resolution: {integrity: sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==} engines: {node: '>= 0.4'} @@ -18974,6 +17886,7 @@ packages: /sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + dev: false /slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} @@ -19104,6 +18017,7 @@ packages: /source-map@0.7.4: resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} engines: {node: '>= 8'} + dev: false /source-map@0.8.0-beta.0: resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} @@ -19156,10 +18070,6 @@ packages: /sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - /sprintf-js@1.1.2: - resolution: {integrity: sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==} - dev: true - /sshpk@1.17.0: resolution: {integrity: sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==} engines: {node: '>=0.10.0'} @@ -19179,12 +18089,14 @@ packages: /stable@0.1.8: resolution: {integrity: sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==} deprecated: 'Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility' + dev: false /stack-utils@2.0.6: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} dependencies: escape-string-regexp: 2.0.0 + dev: false /stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} @@ -19252,11 +18164,6 @@ packages: get-iterator: 1.0.2 dev: true - /streaming-iterables@6.2.0: - resolution: {integrity: sha512-3AYC8oB60WyD1ic7uHmN/vm2oRGzRnQ3XFBl/bFMDi1q1+nc5/vjMmiE4vroIya3jG59t87VpyAj/iXYxyw9AA==} - engines: {node: '>=10'} - dev: true - /streamsearch@1.1.0: resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} engines: {node: '>=10.0.0'} @@ -19285,6 +18192,7 @@ packages: dependencies: char-regex: 1.0.2 strip-ansi: 6.0.1 + dev: false /string-length@5.0.1: resolution: {integrity: sha512-9Ep08KAMUn0OadnVaBuRdE2l615CQ508kr0XMadjClfYpdCyvrbFp6Taebo8yyxokQ4viUd/xPPUA4FGgUa0ow==} @@ -19444,6 +18352,7 @@ packages: /strip-bom@4.0.0: resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} engines: {node: '>=8'} + dev: false /strip-comments@2.0.1: resolution: {integrity: sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==} @@ -19627,6 +18536,7 @@ packages: /symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + dev: false /sync-request@6.1.0: resolution: {integrity: sha512-8fjNkrNlNCrVc/av+Jn+xxqfCjYaBoHqCsDz6mt030UMxJGr+GSfCV1dQt2gRtlL63+VPidwDVLr7V2OcTSdRw==} @@ -19772,6 +18682,7 @@ packages: dependencies: ansi-escapes: 4.3.2 supports-hyperlinks: 2.3.0 + dev: false /terser-webpack-plugin@5.3.9(webpack@5.87.0): resolution: {integrity: sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==} @@ -19815,6 +18726,7 @@ packages: '@istanbuljs/schema': 0.1.3 glob: 7.2.3 minimatch: 3.1.2 + dev: false /text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} @@ -19869,6 +18781,7 @@ packages: /throat@6.0.2: resolution: {integrity: sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ==} + dev: false /through@2.3.8: resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} @@ -19883,13 +18796,6 @@ packages: engines: {node: '>=0.10.0'} dev: true - /timeout-abort-controller@1.1.1: - resolution: {integrity: sha512-BsF9i3NAJag6T0ZEjki9j654zoafI2X6ayuNd6Tp8+Ul6Tr5s4jo973qFeiWrRSweqvskC+AHDKUmIW4b7pdhQ==} - dependencies: - abort-controller: 3.0.0 - retimer: 2.0.0 - dev: true - /timeout-abort-controller@3.0.0: resolution: {integrity: sha512-O3e+2B8BKrQxU2YRyEjC/2yFdb33slI22WRdUaDx6rvysfi9anloNZyR2q0l6LnePo5qH7gSM7uZtvvwZbc2yA==} dependencies: @@ -19933,6 +18839,7 @@ packages: /tmpl@1.0.5: resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} + dev: false /to-buffer@1.1.1: resolution: {integrity: sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==} @@ -19941,6 +18848,7 @@ packages: /to-fast-properties@2.0.0: resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} engines: {node: '>=4'} + dev: false /to-readable-stream@1.0.0: resolution: {integrity: sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==} @@ -19973,6 +18881,7 @@ packages: punycode: 2.3.0 universalify: 0.2.0 url-parse: 1.5.10 + dev: false /tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} @@ -19989,6 +18898,7 @@ packages: engines: {node: '>=8'} dependencies: punycode: 2.3.0 + dev: false /truncate-utf8-bytes@1.0.2: resolution: {integrity: sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==} @@ -20030,39 +18940,6 @@ packages: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} dev: false - /ts-jest@27.1.5(jest@27.5.1)(typescript@5.1.6): - resolution: {integrity: sha512-Xv6jBQPoBEvBq/5i2TeSG9tt/nqkbpcurrEG1b+2yfBrcJelOZF9Ml6dmyMh7bcW9JyFbRYpR5rxROSlBLTZHA==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - hasBin: true - peerDependencies: - '@babel/core': '>=7.0.0-beta.0 <8' - '@types/jest': ^27.0.0 - babel-jest: '>=27.0.0 <28' - esbuild: '*' - jest: ^27.0.0 - typescript: '>=3.8 <5.0' - peerDependenciesMeta: - '@babel/core': - optional: true - '@types/jest': - optional: true - babel-jest: - optional: true - esbuild: - optional: true - dependencies: - bs-logger: 0.2.6 - fast-json-stable-stringify: 2.1.0 - jest: 27.5.1(ts-node@10.9.1) - jest-util: 27.5.1 - json5: 2.2.3 - lodash.memoize: 4.1.2 - make-error: 1.3.6 - semver: 7.5.4 - typescript: 5.1.6 - yargs-parser: 20.2.9 - dev: true - /ts-node@10.9.1(@types/node@18.13.0)(typescript@5.1.6): resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} hasBin: true @@ -20359,12 +19236,6 @@ packages: dependencies: uint8arrays: 4.0.3 - /uint8arrays@2.1.10: - resolution: {integrity: sha512-Q9/hhJa2836nQfEJSZTmr+pg9+cDJS9XEAp7N2Vg5MzL3bK/mkMVfjscRGYruP9jNda6MAdf4QD/y78gSzkp6A==} - dependencies: - multiformats: 9.9.0 - dev: true - /uint8arrays@3.1.1: resolution: {integrity: sha512-+QJa8QRnbdXVpHYjLoTpJIdCTiw9Ir62nocClWuXIq2JIh4Uta0cQsTSpFL678p2CN8B+XSApwcU+pQEqVpKWg==} dependencies: @@ -20452,15 +19323,12 @@ packages: /universalify@0.2.0: resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} engines: {node: '>= 4.0.0'} + dev: false /universalify@2.0.0: resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==} engines: {node: '>= 10.0.0'} - /unordered-array-remove@1.0.2: - resolution: {integrity: sha512-45YsfD6svkgaCBNyvD+dFHm4qFX9g3wRSIVgWVPtm2OCnphvPxzJoe20ATsiNpNJrmzHifnxm+BN5F7gFT/4gw==} - dev: true - /unpipe@1.0.0: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} @@ -20483,6 +19351,7 @@ packages: browserslist: 4.21.10 escalade: 3.1.1 picocolors: 1.0.0 + dev: false /update-browserslist-db@1.0.11(browserslist@4.21.9): resolution: {integrity: sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==} @@ -20516,6 +19385,7 @@ packages: dependencies: querystringify: 2.2.0 requires-port: 1.0.0 + dev: false /url-set-query@1.0.0: resolution: {integrity: sha512-3AChu4NiXquPfeckE5R5cGdiHCMWJx1dwCWOmWIL4KHAziJNOFIYJlpGFeKDvwLPHovZRCxK3cYlwzqI9Vp+Gg==} @@ -20528,15 +19398,6 @@ packages: qs: 6.11.2 dev: true - /ursa-optional@0.10.2: - resolution: {integrity: sha512-TKdwuLboBn7M34RcvVTuQyhvrA8gYKapuVdm0nBP0mnBc7oECOfUQZrY91cefL3/nm64ZyrejSRrhTVdX7NG/A==} - engines: {node: '>=4'} - requiresBuild: true - dependencies: - bindings: 1.5.0 - nan: 2.17.0 - dev: true - /utf-8-validate@5.0.10: resolution: {integrity: sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==} engines: {node: '>=6.14.2'} @@ -20618,6 +19479,7 @@ packages: '@types/istanbul-lib-coverage': 2.0.4 convert-source-map: 1.9.0 source-map: 0.7.4 + dev: false /varint@5.0.2: resolution: {integrity: sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow==} @@ -20812,17 +19674,20 @@ packages: deprecated: Use your platform's native performance.now() and performance.timeOrigin. dependencies: browser-process-hrtime: 1.0.0 + dev: false /w3c-xmlserializer@2.0.0: resolution: {integrity: sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==} engines: {node: '>=10'} dependencies: xml-name-validator: 3.0.0 + dev: false /walker@1.0.8: resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} dependencies: makeerror: 1.0.12 + dev: false /watchpack@2.4.0: resolution: {integrity: sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==} @@ -20844,19 +19709,10 @@ packages: defaults: 1.0.4 dev: true - /web-streams-polyfill@3.2.1: - resolution: {integrity: sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==} - engines: {node: '>= 8'} - dev: true - /web-vitals@2.1.4: resolution: {integrity: sha512-sVWcwhU5mX6crfI5Vd2dC4qchyTqxV8URinzt25XqVh+bHEPGH4C3NPrNionCP7Obx59wrYEbNlw4Z8sjALzZg==} dev: false - /web-worker@1.2.0: - resolution: {integrity: sha512-PgF341avzqyx60neE9DD+XS26MMNMoUQRz9NOZwW32nPQrF6p77f1htcnjBSEV8BGMKZ16choqUG4hyI0Hx7mA==} - dev: false - /web3-bzz@1.10.0: resolution: {integrity: sha512-o9IR59io3pDUsXTsps5pO5hW1D5zBmg46iNc2t4j2DkaYHNdDLwk2IP9ukoM2wg47QILfPEJYzhTfkS/CcX0KA==} engines: {node: '>=8.0.0'} @@ -21399,10 +20255,12 @@ packages: /webidl-conversions@5.0.0: resolution: {integrity: sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==} engines: {node: '>=8'} + dev: false /webidl-conversions@6.1.0: resolution: {integrity: sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==} engines: {node: '>=10.4'} + dev: false /webpack-dev-middleware@5.3.3(webpack@5.87.0): resolution: {integrity: sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==} @@ -21572,6 +20430,7 @@ packages: resolution: {integrity: sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==} dependencies: iconv-lite: 0.4.24 + dev: false /whatwg-encoding@2.0.0: resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==} @@ -21586,6 +20445,7 @@ packages: /whatwg-mimetype@2.3.0: resolution: {integrity: sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==} + dev: false /whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} @@ -21609,13 +20469,7 @@ packages: lodash: 4.17.21 tr46: 2.1.0 webidl-conversions: 6.1.0 - - /wherearewe@1.0.2: - resolution: {integrity: sha512-HyLZ7n1Yox+w1qWaFEgP/sMs5D7ka2UXmoVNaY0XzbEHLGljo4ScBchYm6cWRYNO33tmFX3Mgg4BiZkDOjihyw==} - engines: {node: '>=16.0.0', npm: '>=7.0.0'} - dependencies: - is-electron: 2.2.2 - dev: true + dev: false /wherearewe@2.0.1: resolution: {integrity: sha512-XUguZbDxCA2wBn2LoFtcEhXL6AXo+hVjGonwhSTTTU9SzbWG8Xu3onNIpzf9j/mYUcJQ0f+m37SzG77G851uFw==} @@ -21923,6 +20777,7 @@ packages: is-typedarray: 1.0.0 signal-exit: 3.0.7 typedarray-to-buffer: 3.1.5 + dev: false /ws@3.3.3: resolution: {integrity: sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==} @@ -22025,12 +20880,7 @@ packages: /xml-name-validator@3.0.0: resolution: {integrity: sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==} - - /xml2js@0.1.14: - resolution: {integrity: sha512-pbdws4PPPNc1HPluSUKamY4GWMk592K7qwcj6BExbVOhhubub8+pMda/ql68b6L3luZs/OGjGSB5goV7SnmgnA==} - dependencies: - sax: 1.2.4 - dev: true + dev: false /xml2js@0.5.0: resolution: {integrity: sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==} @@ -22052,6 +20902,7 @@ packages: /xmlchars@2.2.0: resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + dev: false /xmlhttprequest@1.8.0: resolution: {integrity: sha512-58Im/U0mlVBLM38NdZjHyhuMtCqa61469k2YP/AaPbvCoV9aQGUpbJBj1QRm2ytRiVQBD/fsw7L2bJGDVQswBA==} From fc33ce3b6dbeac7e5884a491c5c5afe8d9bfb0ef Mon Sep 17 00:00:00 2001 From: Akim Mamedov Date: Tue, 10 Oct 2023 07:34:35 +0700 Subject: [PATCH 19/45] make resource importers async --- packages/core/js-client/src/index.ts | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/core/js-client/src/index.ts b/packages/core/js-client/src/index.ts index a2a0ba85f..830583cca 100644 --- a/packages/core/js-client/src/index.ts +++ b/packages/core/js-client/src/index.ts @@ -39,27 +39,27 @@ import { doRegisterNodeUtils } from "./services/NodeUtils.js"; const isNode = typeof process !== "undefined" && process.release.name === "node"; -const fetchWorkerCode = () => { - return fetchResource( +const fetchWorkerCode = async () => { + const resource = await fetchResource( "@fluencelabs/marine-worker", "/dist/browser/marine-worker.umd.cjs", - ).then((res) => { - return res.text(); - }); + ); + + return resource.text(); }; -const fetchMarineJsWasm = () => { - return fetchResource("@fluencelabs/marine-js", "/dist/marine-js.wasm").then( - (res) => { - return res.arrayBuffer(); - }, +const fetchMarineJsWasm = async () => { + const resource = await fetchResource( + "@fluencelabs/marine-js", + "/dist/marine-js.wasm", ); + + return resource.arrayBuffer(); }; -const fetchAvmWasm = () => { - return fetchResource("@fluencelabs/avm", "/dist/avm.wasm").then((res) => { - return res.arrayBuffer(); - }); +const fetchAvmWasm = async () => { + const resource = await fetchResource("@fluencelabs/avm", "/dist/avm.wasm"); + return resource.arrayBuffer(); }; const createClient = async ( From 2abed24986507a985ba8478ad5ba36f83394fc47 Mon Sep 17 00:00:00 2001 From: Akim Mamedov Date: Tue, 10 Oct 2023 18:11:38 +0700 Subject: [PATCH 20/45] Refactor --- packages/core/js-client/src/api.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/core/js-client/src/api.ts b/packages/core/js-client/src/api.ts index fe3e33166..84213ed3f 100644 --- a/packages/core/js-client/src/api.ts +++ b/packages/core/js-client/src/api.ts @@ -52,8 +52,8 @@ export const v5_callFunction = async ( args, def, script, - config: config, - peer: peer, + config, + peer, }); }; @@ -190,7 +190,7 @@ const extractServiceArgs = ( } return { - peer: peer, - serviceId: serviceId, + peer, + serviceId, }; }; From 4ae649f951d912019def83ddd24ec17987945357 Mon Sep 17 00:00:00 2001 From: Akim Mamedov Date: Tue, 10 Oct 2023 18:30:40 +0700 Subject: [PATCH 21/45] Fix error message --- packages/core/js-client/src/particle/Particle.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/js-client/src/particle/Particle.ts b/packages/core/js-client/src/particle/Particle.ts index 63566ae5f..9614540ac 100644 --- a/packages/core/js-client/src/particle/Particle.ts +++ b/packages/core/js-client/src/particle/Particle.ts @@ -75,7 +75,7 @@ export class Particle implements IParticle { const res = particleSchema.safeParse(json); if (!res.success) { - throw new Error(`Particle format invalid. Given: ${str}`); + throw new Error(`Particle format invalid. Errors: ${JSON.stringify(res.error.flatten())}`); } const data = res.data; From 8d51ab18b3a1c9e0ce5f39ca2ae724d2da09e6cd Mon Sep 17 00:00:00 2001 From: Akim Mamedov Date: Tue, 10 Oct 2023 18:31:36 +0700 Subject: [PATCH 22/45] remove comment --- packages/core/js-client/src/marine/worker-script/workerLoader.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/core/js-client/src/marine/worker-script/workerLoader.ts b/packages/core/js-client/src/marine/worker-script/workerLoader.ts index d707aea0a..48d9db7d4 100644 --- a/packages/core/js-client/src/marine/worker-script/workerLoader.ts +++ b/packages/core/js-client/src/marine/worker-script/workerLoader.ts @@ -15,7 +15,6 @@ */ import { Worker } from "../../../node_modules/threads/dist/index.js"; -// eslint-disable-next-line import/order import type { WorkerImplementation } from "../../../node_modules/threads/dist/types/master.js"; import { LazyLoader } from "../interfaces.js"; From 7ff71990dcf0cf4412180be9f8cdb7a80cd4134d Mon Sep 17 00:00:00 2001 From: Akim Mamedov Date: Tue, 10 Oct 2023 18:50:06 +0700 Subject: [PATCH 23/45] more refactoring --- .../src/jsServiceHost/JsServiceHost.ts | 17 +---------------- packages/core/js-client/vite.config.ts | 5 ++++- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/packages/core/js-client/src/jsServiceHost/JsServiceHost.ts b/packages/core/js-client/src/jsServiceHost/JsServiceHost.ts index 7dac7ef49..5c3560e72 100644 --- a/packages/core/js-client/src/jsServiceHost/JsServiceHost.ts +++ b/packages/core/js-client/src/jsServiceHost/JsServiceHost.ts @@ -58,22 +58,7 @@ export class JsServiceHost implements IJsServiceHost { particleId: string, ): GenericCallServiceHandler | null { const key = serviceFnKey(serviceId, fnName); - const psh = this.particleScopeHandlers.get(particleId); - let handler: GenericCallServiceHandler | undefined = undefined; - - // we should prioritize handler for this particle if there is one - // if particle-scoped handler exist for this particle try getting handler there - if (psh !== undefined) { - handler = psh.get(key); - } - - // then try to find a common handler for all particles with this service-fn key - // if there is no particle-specific handler, get one from common map - if (handler === undefined) { - handler = this.commonHandlers.get(key); - } - - return handler ?? null; + return this.particleScopeHandlers.get(particleId)?.get(key) ?? this.commonHandlers.get(key) ?? null; } /** diff --git a/packages/core/js-client/vite.config.ts b/packages/core/js-client/vite.config.ts index db763faaa..6cfe3847a 100644 --- a/packages/core/js-client/vite.config.ts +++ b/packages/core/js-client/vite.config.ts @@ -18,11 +18,12 @@ import inject from "@rollup/plugin-inject"; import tsconfigPaths from "vite-tsconfig-paths"; import { createRequire } from "module"; import { readFileSync } from "fs"; +import { UserConfig } from "vite"; const require = createRequire(import.meta.url); const esbuildShim = require.resolve("node-stdlib-browser/helpers/esbuild/shim"); -export default { +const config: UserConfig = { build: { target: "modules", minify: "esbuild", @@ -58,3 +59,5 @@ export default { __PACKAGE_JSON_CONTENT__: readFileSync("./package.json", "utf-8"), }, }; + +export default config; From ad52a1d7f4f8dcd5970904d81ca54cd2b610f6f9 Mon Sep 17 00:00:00 2001 From: Akim <59872966+akim-bow@users.noreply.github.com> Date: Tue, 10 Oct 2023 19:50:45 +0700 Subject: [PATCH 24/45] Update packages/core/js-client/src/compilerSupport/registerService.ts Co-authored-by: shamsartem --- .../src/compilerSupport/registerService.ts | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/packages/core/js-client/src/compilerSupport/registerService.ts b/packages/core/js-client/src/compilerSupport/registerService.ts index 686f9f169..8f651e665 100644 --- a/packages/core/js-client/src/compilerSupport/registerService.ts +++ b/packages/core/js-client/src/compilerSupport/registerService.ts @@ -33,7 +33,7 @@ interface RegisterServiceArgs { export const registerService = ({ peer, def, - serviceId, + serviceId = def.defaultServiceId, service, }: RegisterServiceArgs) => { // TODO: Need to refactor this. We can compute function types from service implementation, making func more type safe @@ -47,6 +47,10 @@ export const registerService = ({ return !(f in service); }); + if (serviceId == null) { + throw new Error("Service ID must be specified"); + } + if (incorrectServiceDefinitions.length > 0) { throw new Error( `Error registering service ${serviceId}: missing functions: ` + @@ -58,14 +62,6 @@ export const registerService = ({ ); } - if (serviceId == null) { - serviceId = def.defaultServiceId; - } - - if (serviceId == null) { - throw new Error("Service ID must be specified"); - } - const singleFunctions = def.functions.tag === "nil" ? [] : Object.entries(def.functions.fields); From 20c9597235468daa3033adc6401d02319e393b58 Mon Sep 17 00:00:00 2001 From: Akim Mamedov Date: Tue, 10 Oct 2023 19:58:17 +0700 Subject: [PATCH 25/45] refactoring --- .../js-client/src/compilerSupport/callFunction.ts | 5 +++-- .../js-client/src/compilerSupport/conversions.ts | 6 +++--- .../src/compilerSupport/registerService.ts | 14 +++++--------- .../core/js-client/src/compilerSupport/services.ts | 4 +--- 4 files changed, 12 insertions(+), 17 deletions(-) diff --git a/packages/core/js-client/src/compilerSupport/callFunction.ts b/packages/core/js-client/src/compilerSupport/callFunction.ts index 3736ecff4..b46ceebe2 100644 --- a/packages/core/js-client/src/compilerSupport/callFunction.ts +++ b/packages/core/js-client/src/compilerSupport/callFunction.ts @@ -66,6 +66,7 @@ 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", { def, script, config, args }); const argumentTypes = getArgumentTypes(def); @@ -78,7 +79,7 @@ export const callAquaFunction = async ({ if (type.tag === "arrow") { // TODO: Add validation here - assert(typeof argVal === "function"); + assert(typeof argVal !== "function", "Should not be possible, bad types"); service = userHandlerService( def.names.callbackSrv, @@ -87,7 +88,7 @@ export const callAquaFunction = async ({ ); } else { // TODO: Add validation here - assert(typeof argVal !== "function"); + assert(typeof argVal !== "function", "Should not be possible, bad types"); service = injectValueService(def.names.getDataSrv, name, type, argVal); } diff --git a/packages/core/js-client/src/compilerSupport/conversions.ts b/packages/core/js-client/src/compilerSupport/conversions.ts index eeeaa53a6..9e93a2527 100644 --- a/packages/core/js-client/src/compilerSupport/conversions.ts +++ b/packages/core/js-client/src/compilerSupport/conversions.ts @@ -44,7 +44,7 @@ export const aqua2ts = (value: JSONValue, type: NonArrowType): JSONValue => { return null; }) .with({ tag: "option" }, (opt) => { - assert(Array.isArray(value)); + assert(Array.isArray(value), "Should not be possible, bad types"); if (value.length === 0) { return null; @@ -56,7 +56,7 @@ export const aqua2ts = (value: JSONValue, type: NonArrowType): JSONValue => { return value; }) .with({ tag: "array" }, (arr) => { - assert(Array.isArray(value)); + assert(Array.isArray(value), "Should not be possible, bad types"); return value.map((y) => { return aqua2ts(y, arr.type); }); @@ -146,7 +146,7 @@ export const ts2aqua = (value: JSONValue, type: NonArrowType): JSONValue => { return value; }) .with({ tag: "array" }, (arr) => { - assert(Array.isArray(value)); + assert(Array.isArray(value), "Should not be possible, bad types"); return value.map((y) => { return ts2aqua(y, arr.type); }); diff --git a/packages/core/js-client/src/compilerSupport/registerService.ts b/packages/core/js-client/src/compilerSupport/registerService.ts index 686f9f169..8f651e665 100644 --- a/packages/core/js-client/src/compilerSupport/registerService.ts +++ b/packages/core/js-client/src/compilerSupport/registerService.ts @@ -33,7 +33,7 @@ interface RegisterServiceArgs { export const registerService = ({ peer, def, - serviceId, + serviceId = def.defaultServiceId, service, }: RegisterServiceArgs) => { // TODO: Need to refactor this. We can compute function types from service implementation, making func more type safe @@ -47,6 +47,10 @@ export const registerService = ({ return !(f in service); }); + if (serviceId == null) { + throw new Error("Service ID must be specified"); + } + if (incorrectServiceDefinitions.length > 0) { throw new Error( `Error registering service ${serviceId}: missing functions: ` + @@ -58,14 +62,6 @@ export const registerService = ({ ); } - if (serviceId == null) { - serviceId = def.defaultServiceId; - } - - if (serviceId == null) { - throw new Error("Service ID must be specified"); - } - const singleFunctions = def.functions.tag === "nil" ? [] : Object.entries(def.functions.fields); diff --git a/packages/core/js-client/src/compilerSupport/services.ts b/packages/core/js-client/src/compilerSupport/services.ts index 7b59c55e9..dd1b16e4e 100644 --- a/packages/core/js-client/src/compilerSupport/services.ts +++ b/packages/core/js-client/src/compilerSupport/services.ts @@ -180,9 +180,7 @@ const extractCallParams = ( }); }) .with({ tag: "labeledProduct" }, (x) => { - return Object.keys(x.fields).map((label) => { - return label; - }); + return Object.keys(x.fields); }) .exhaustive(); From 2fd23f0700ce43a2991127c8b2d873cab08e7c85 Mon Sep 17 00:00:00 2001 From: Akim Mamedov Date: Tue, 10 Oct 2023 20:00:14 +0700 Subject: [PATCH 26/45] refactoring fix --- packages/core/js-client/src/compilerSupport/callFunction.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/js-client/src/compilerSupport/callFunction.ts b/packages/core/js-client/src/compilerSupport/callFunction.ts index b46ceebe2..830be9dec 100644 --- a/packages/core/js-client/src/compilerSupport/callFunction.ts +++ b/packages/core/js-client/src/compilerSupport/callFunction.ts @@ -79,7 +79,7 @@ export const callAquaFunction = async ({ if (type.tag === "arrow") { // TODO: Add validation here - assert(typeof argVal !== "function", "Should not be possible, bad types"); + assert(typeof argVal === "function", "Should not be possible, bad types"); service = userHandlerService( def.names.callbackSrv, From 12c790eff4d80a2c67abbd3f2bc7b413637bd427 Mon Sep 17 00:00:00 2001 From: Akim Mamedov Date: Wed, 11 Oct 2023 18:16:03 +0700 Subject: [PATCH 27/45] optimize import --- packages/core/js-client/package.json | 12 +- .../core/js-client/src/fetchers/browser.ts | 37 +--- packages/core/js-client/src/fetchers/index.ts | 5 +- .../src/keypair/__test__/KeyPair.spec.ts | 4 +- packages/core/js-client/src/keypair/index.ts | 4 +- .../core/js-client/src/services/builtins.ts | 12 +- pnpm-lock.yaml | 181 ++++++++++++++---- 7 files changed, 163 insertions(+), 92 deletions(-) diff --git a/packages/core/js-client/package.json b/packages/core/js-client/package.json index cc1522c50..09b33170b 100644 --- a/packages/core/js-client/package.json +++ b/packages/core/js-client/package.json @@ -9,13 +9,13 @@ "files": [ "dist" ], - "main": "./dist/index.js", - "unpkg": "./dist/browser/index.umd.js", - "types": "./dist/index.d.ts", + "main": "./dist/src/index.js", + "unpkg": "./dist/src/browser/index.umd.js", + "types": "./dist/src/index.d.ts", "exports": { - "types": "./dist/index.d.ts", - "node": "./dist/index.js", - "default": "./dist/browser/index.js" + "types": "./dist/src/index.d.ts", + "node": "./dist/src/index.js", + "default": "./dist/src/browser/index.js" }, "type": "module", "scripts": { diff --git a/packages/core/js-client/src/fetchers/browser.ts b/packages/core/js-client/src/fetchers/browser.ts index b01d5958a..62f987b89 100644 --- a/packages/core/js-client/src/fetchers/browser.ts +++ b/packages/core/js-client/src/fetchers/browser.ts @@ -14,42 +14,13 @@ * limitations under the License. */ -interface PackageJsonContent { - dependencies: Record; - devDependencies: Record; -} - -// This will be substituted in build phase -const packageJsonContentString = `__PACKAGE_JSON_CONTENT__`; -let parsedPackageJsonContent: PackageJsonContent | undefined; +import packageJSON from "../../package.json"; +import type { AvailableDependencies } from './index.js'; const PRIMARY_CDN = "https://unpkg.com/"; -export async function fetchResource(pkg: string, assetPath: string) { - const packageJsonContent = - parsedPackageJsonContent ?? - // TODO: Should be validated - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - (parsedPackageJsonContent = JSON.parse( - packageJsonContentString, - ) as PackageJsonContent); - - const version = - packageJsonContent.dependencies[pkg] ?? - packageJsonContent.devDependencies[pkg]; - - if (version === undefined) { - const availableDeps = [ - ...Object.keys(packageJsonContent.dependencies), - ...Object.keys(packageJsonContent.devDependencies), - ]; - - throw new Error( - `Cannot find version of ${pkg} in package.json. Available versions: ${availableDeps.join( - ",", - )}`, - ); - } +export async function fetchResource(pkg: T, assetPath: string) { + const version = { ...packageJSON.dependencies, ...packageJSON.devDependencies }[pkg]; const refinedAssetPath = assetPath.startsWith("/") ? assetPath.slice(1) diff --git a/packages/core/js-client/src/fetchers/index.ts b/packages/core/js-client/src/fetchers/index.ts index b0c45fb72..fb8f31f9a 100644 --- a/packages/core/js-client/src/fetchers/index.ts +++ b/packages/core/js-client/src/fetchers/index.ts @@ -18,11 +18,14 @@ import process from "process"; import { fetchResource as fetchResourceBrowser } from "./browser.js"; import { fetchResource as fetchResourceNode } from "./node.js"; +import packageJSON from '../../package.json'; const isNode = typeof process !== "undefined" && process.release.name === "node"; -export async function fetchResource(pkg: string, path: string) { +export type AvailableDependencies = (keyof typeof packageJSON['dependencies']) | (keyof typeof packageJSON['devDependencies']); + +export async function fetchResource(pkg: AvailableDependencies, path: string) { switch (true) { case isNode: return fetchResourceNode(pkg, path); diff --git a/packages/core/js-client/src/keypair/__test__/KeyPair.spec.ts b/packages/core/js-client/src/keypair/__test__/KeyPair.spec.ts index 58ca9cf49..12ef31a6f 100644 --- a/packages/core/js-client/src/keypair/__test__/KeyPair.spec.ts +++ b/packages/core/js-client/src/keypair/__test__/KeyPair.spec.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { decode } from "bs58"; +import bs58 from "bs58"; import { toUint8Array } from "js-base64"; import { it, describe, expect } from "vitest"; @@ -51,7 +51,7 @@ describe("KeyPair tests", () => { it("create keypair from ed25519 private key", async function () { // arrange const rustSK = "jDaxLJzYtzgwTMrELJCAqavtmx85ktQNfB2rLcK7MhH"; - const sk = decode(rustSK); + const sk = bs58.decode(rustSK); // act const keyPair = await KeyPair.fromEd25519SK(sk); diff --git a/packages/core/js-client/src/keypair/index.ts b/packages/core/js-client/src/keypair/index.ts index c19185fc9..1730633b6 100644 --- a/packages/core/js-client/src/keypair/index.ts +++ b/packages/core/js-client/src/keypair/index.ts @@ -23,7 +23,7 @@ import { import type { PrivateKey, PublicKey } from "@libp2p/interface/keys"; import type { PeerId } from "@libp2p/interface/peer-id"; import { createFromPrivKey } from "@libp2p/peer-id-factory"; -import { decode } from "bs58"; +import bs58 from "bs58"; import { toUint8Array } from "js-base64"; export class KeyPair { @@ -98,7 +98,7 @@ export const fromBase64Sk = (sk: string): Promise => { }; export const fromBase58Sk = (sk: string): Promise => { - const skArr = decode(sk); + const skArr = bs58.decode(sk); return KeyPair.fromEd25519SK(skArr); }; diff --git a/packages/core/js-client/src/services/builtins.ts b/packages/core/js-client/src/services/builtins.ts index 99804ff43..7ee3f68d3 100644 --- a/packages/core/js-client/src/services/builtins.ts +++ b/packages/core/js-client/src/services/builtins.ts @@ -18,7 +18,7 @@ import assert from "assert"; import { Buffer } from "buffer"; import { JSONValue } from "@fluencelabs/interfaces"; -import { encode, decode } from "bs58"; +import bs58 from "bs58"; import { sha256 } from "multiformats/hashes/sha2"; import { @@ -299,7 +299,7 @@ export const builtInServices: Record< const [input] = req.args; // TODO: remove after adding validation assert(typeof input === "string"); - return success(encode(new TextEncoder().encode(input))); + return success(bs58.encode(new TextEncoder().encode(input))); } }, @@ -310,7 +310,7 @@ export const builtInServices: Record< const [input] = req.args; // TODO: remove after adding validation assert(typeof input === "string"); - return success(new TextDecoder().decode(decode(input))); + return success(new TextDecoder().decode(bs58.decode(input))); } }, @@ -323,7 +323,7 @@ export const builtInServices: Record< // TODO: remove after adding validation // eslint-disable-next-line @typescript-eslint/consistent-type-assertions const argumentArray = req.args[0] as number[]; - return success(encode(new Uint8Array(argumentArray))); + return success(bs58.encode(new Uint8Array(argumentArray))); } }, @@ -334,7 +334,7 @@ export const builtInServices: Record< const [input] = req.args; // TODO: remove after adding validation assert(typeof input === "string"); - return success(Array.from(decode(input))); + return success(Array.from(bs58.decode(input))); } }, @@ -350,7 +350,7 @@ export const builtInServices: Record< const inBuffer = Buffer.from(input); const multihash = await sha256.digest(inBuffer); - return success(encode(multihash.bytes)); + return success(bs58.encode(multihash.bytes)); } }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3c20baeec..5a0a3b95a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -68,7 +68,7 @@ importers: version: 0.7.2(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@nomicfoundation/hardhat-chai-matchers@1.0.6)(@nomicfoundation/hardhat-network-helpers@1.0.8)(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(@typechain/ethers-v5@10.2.1)(@typechain/hardhat@6.1.6)(@types/chai@4.3.5)(@types/mocha@9.1.1)(@types/node@20.7.0)(chai@4.3.7)(hardhat-gas-reporter@1.0.9)(hardhat@2.15.0)(solidity-coverage@0.7.22)(ts-node@10.9.1)(typechain@8.2.0)(typescript@5.1.6) '@fluencelabs/js-client': specifier: workspace:^ - version: link:../../core/js-client + version: link:../../core/js-client/dist '@fluencelabs/registry': specifier: 0.8.2 version: 0.8.2 @@ -80,7 +80,7 @@ importers: dependencies: '@fluencelabs/js-client': specifier: workspace:* - version: link:../../../core/js-client + version: link:../../../core/js-client/dist '@test/aqua_for_test': specifier: workspace:* version: link:../../aqua @@ -89,7 +89,7 @@ importers: dependencies: '@fluencelabs/js-client': specifier: workspace:* - version: link:../../../core/js-client + version: link:../../../core/js-client/dist '@test/test-utils': specifier: workspace:* version: link:../../test-utils @@ -171,7 +171,7 @@ importers: version: link:../interfaces '@fluencelabs/js-client': specifier: workspace:* - version: link:../js-client + version: link:../js-client/dist '@fluencelabs/registry': specifier: 0.8.7 version: 0.8.7 @@ -315,6 +315,124 @@ importers: specifier: 0.29.7 version: 0.29.7 + packages/core/js-client/dist: + dependencies: + '@chainsafe/libp2p-noise': + specifier: 13.0.0 + version: 13.0.0 + '@chainsafe/libp2p-yamux': + specifier: 5.0.0 + version: 5.0.0 + '@fluencelabs/interfaces': + specifier: workspace:* + version: link:../../interfaces + '@fluencelabs/marine-worker': + specifier: 0.3.3 + version: link:../../marine-worker + '@libp2p/crypto': + specifier: 2.0.3 + version: 2.0.3 + '@libp2p/interface': + specifier: 0.1.2 + version: 0.1.2 + '@libp2p/peer-id': + specifier: 3.0.2 + version: 3.0.2 + '@libp2p/peer-id-factory': + specifier: 3.0.3 + version: 3.0.3 + '@libp2p/websockets': + specifier: 7.0.4 + version: 7.0.4 + '@multiformats/multiaddr': + specifier: 11.3.0 + version: 11.3.0 + async: + specifier: 3.2.4 + version: 3.2.4 + bs58: + specifier: 5.0.0 + version: 5.0.0 + buffer: + specifier: 6.0.3 + version: 6.0.3 + debug: + specifier: 4.3.4 + version: 4.3.4(supports-color@8.1.1) + it-length-prefixed: + specifier: 8.0.4 + version: 8.0.4 + it-map: + specifier: 2.0.0 + version: 2.0.0 + it-pipe: + specifier: 2.0.5 + version: 2.0.5 + js-base64: + specifier: 3.7.5 + version: 3.7.5 + libp2p: + specifier: 0.46.6 + version: 0.46.6 + multiformats: + specifier: 11.0.1 + version: 11.0.1 + rxjs: + specifier: 7.5.5 + version: 7.5.5 + threads: + specifier: 1.7.0 + version: 1.7.0 + ts-pattern: + specifier: 3.3.3 + version: 3.3.3 + uint8arrays: + specifier: 4.0.3 + version: 4.0.3 + uuid: + specifier: 8.3.2 + version: 8.3.2 + zod: + specifier: 3.22.4 + version: 3.22.4 + devDependencies: + '@fluencelabs/aqua-api': + specifier: 0.9.3 + version: 0.9.3 + '@fluencelabs/avm': + specifier: 0.48.0 + version: 0.48.0 + '@fluencelabs/marine-js': + specifier: 0.7.2 + version: 0.7.2 + '@rollup/plugin-inject': + specifier: 5.0.3 + version: 5.0.3 + '@types/bs58': + specifier: 4.0.1 + version: 4.0.1 + '@types/debug': + specifier: 4.1.7 + version: 4.1.7 + '@types/node': + specifier: 20.7.0 + version: 20.7.0 + '@types/uuid': + specifier: 8.3.2 + version: 8.3.2 + hotscript: + specifier: 1.0.13 + version: 1.0.13 + vite: + specifier: 4.0.4 + version: 4.0.4(@types/node@20.7.0) + vite-tsconfig-paths: + specifier: 4.0.3 + version: 4.0.3(typescript@5.1.6)(vite@4.0.4) + vitest: + specifier: 0.29.7 + version: 0.29.7 + packages/core/marine-worker: dependencies: '@fluencelabs/marine-js': @@ -4587,8 +4705,8 @@ packages: abortable-iterator: 5.0.1 it-first: 3.0.2 it-handshake: 4.1.3 - it-length-prefixed: 9.0.1 - it-merge: 3.0.1 + it-length-prefixed: 9.0.3 + it-merge: 3.0.2 it-pipe: 3.0.1 it-pushable: 3.2.1 it-reader: 6.0.4 @@ -4642,7 +4760,7 @@ packages: '@libp2p/peer-id': 3.0.2 '@libp2p/utils': 4.0.2 '@multiformats/multiaddr': 12.1.7 - protons-runtime: 5.0.0(uint8arraylist@2.4.3) + protons-runtime: 5.0.2(uint8arraylist@2.4.3) uint8-varint: 1.0.6 uint8arraylist: 2.4.3 uint8arrays: 4.0.6 @@ -4663,7 +4781,7 @@ packages: it-all: 3.0.3 mortice: 3.0.1 multiformats: 12.0.1 - protons-runtime: 5.0.0(uint8arraylist@2.4.3) + protons-runtime: 5.0.2(uint8arraylist@2.4.3) uint8arraylist: 2.4.3 uint8arrays: 4.0.6 transitivePeerDependencies: @@ -9398,9 +9516,9 @@ packages: it-drain: 3.0.3 it-filter: 3.0.3 it-map: 3.0.4 - it-merge: 3.0.1 + it-merge: 3.0.2 it-pipe: 3.0.1 - it-pushable: 3.1.3 + it-pushable: 3.2.1 it-sort: 3.0.3 it-take: 3.0.3 uint8arrays: 4.0.3 @@ -10803,7 +10921,6 @@ packages: /ethereum-cryptography@0.1.3: resolution: {integrity: sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==} - deprecated: Upgrade to ethereum-cryptography@2.0 for security and reduced package size dependencies: '@types/pbkdf2': 3.1.0 '@types/secp256k1': 4.0.3 @@ -13032,7 +13149,7 @@ packages: resolution: {integrity: sha512-gWevodoctgwWUaRJN9t+xEs1H1GQNYAjLCR7FO50fon9Ph4OJGgrxPKTc26QXKrC/cIQZLkHYClphUw0wl1k2A==} dependencies: it-byte-stream: 1.0.1 - it-length-prefixed: 9.0.1 + it-length-prefixed: 9.0.3 it-stream-types: 2.0.1 uint8-varint: 2.0.1 uint8arraylist: 2.4.3 @@ -13047,16 +13164,6 @@ packages: uint8arraylist: 2.4.3 uint8arrays: 4.0.3 - /it-length-prefixed@9.0.1: - resolution: {integrity: sha512-ZBD8ZFLERj8d1q9CeBtk0eJ4EpeI3qwnkmWtemBSm3ZI2dM8PUweNVk5haZ2vw3EIq2uYQiabV9YwNm6EASM4A==} - engines: {node: '>=16.0.0', npm: '>=7.0.0'} - dependencies: - err-code: 3.0.1 - it-stream-types: 2.0.1 - uint8-varint: 1.0.6 - uint8arraylist: 2.4.3 - uint8arrays: 4.0.3 - /it-length-prefixed@9.0.3: resolution: {integrity: sha512-YAu424ceYpXctxtjcLOqn7vJq082CaoP8J646ZusYISfQc3bpzQErgTUqMFj81V262KG2W9/YMBHsy6A/4yvmg==} engines: {node: '>=16.0.0', npm: '>=7.0.0'} @@ -13083,12 +13190,6 @@ packages: dependencies: it-pushable: 3.1.3 - /it-merge@3.0.1: - resolution: {integrity: sha512-I6hjU1ABO+k3xY1H6JtCSDXvUME88pxIXSgKeT4WI5rPYbQzpr98ldacVuG95WbjaJxKl6Qot6lUdxduLBQPHA==} - engines: {node: '>=16.0.0', npm: '>=7.0.0'} - dependencies: - it-pushable: 3.1.3 - /it-merge@3.0.2: resolution: {integrity: sha512-bMk2km8lTz+Rwv30hzDUdGIcqQkOemFJqmGT2wqQZ6/zHKCsYqdRunPrteCqHLV/nIVhUK8nZZkDA2eJ4MJZiA==} dependencies: @@ -13119,7 +13220,7 @@ packages: engines: {node: '>=16.0.0', npm: '>=7.0.0'} dependencies: it-merge: 2.0.1 - it-pushable: 3.1.3 + it-pushable: 3.2.1 it-stream-types: 1.0.5 /it-pipe@3.0.1: @@ -14080,9 +14181,9 @@ packages: it-filter: 3.0.3 it-first: 3.0.2 it-handshake: 4.1.3 - it-length-prefixed: 9.0.1 + it-length-prefixed: 9.0.3 it-map: 3.0.4 - it-merge: 3.0.1 + it-merge: 3.0.2 it-pair: 2.0.6 it-parallel: 3.0.4 it-pipe: 3.0.1 @@ -14094,8 +14195,8 @@ packages: p-queue: 7.3.4 p-retry: 5.1.2 private-ip: 3.0.0 - protons-runtime: 5.0.0(uint8arraylist@2.4.3) - rate-limiter-flexible: 2.4.1 + protons-runtime: 5.0.2(uint8arraylist@2.4.3) + rate-limiter-flexible: 2.4.2 uint8arraylist: 2.4.3 uint8arrays: 4.0.6 wherearewe: 2.0.1 @@ -16801,12 +16902,8 @@ packages: resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} engines: {node: '>= 0.6'} - /rate-limiter-flexible@2.4.1: - resolution: {integrity: sha512-dgH4T44TzKVO9CLArNto62hJOwlWJMLUjVVr/ii0uUzZXEXthDNr7/yefW5z/1vvHAfycc1tnuiYyNJ8CTRB3g==} - /rate-limiter-flexible@2.4.2: resolution: {integrity: sha512-rMATGGOdO1suFyf/mI5LYhts71g1sbdhmd6YvdiXO2gJnd42Tt6QS4JUKJKSWVVkMtBacm6l40FR7Trjo6Iruw==} - dev: true /raw-body@2.5.1: resolution: {integrity: sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==} @@ -19501,7 +19598,7 @@ packages: extsprintf: 1.3.0 dev: true - /vite-node@0.29.7(@types/node@20.4.5): + /vite-node@0.29.7(@types/node@20.7.0): resolution: {integrity: sha512-PakCZLvz37yFfUPWBnLa1OYHPCGm5v4pmRrTcFN4V/N/T3I6tyP3z07S//9w+DdeL7vVd0VSeyMZuAh+449ZWw==} engines: {node: '>=v14.16.0'} hasBin: true @@ -19511,7 +19608,7 @@ packages: mlly: 1.3.0 pathe: 1.1.1 picocolors: 1.0.0 - vite: 4.0.4(@types/node@20.4.5) + vite: 4.0.4(@types/node@20.7.0) transitivePeerDependencies: - '@types/node' - less @@ -19634,7 +19731,7 @@ packages: dependencies: '@types/chai': 4.3.5 '@types/chai-subset': 1.3.3 - '@types/node': 20.4.5 + '@types/node': 20.7.0 '@vitest/expect': 0.29.7 '@vitest/runner': 0.29.7 '@vitest/spy': 0.29.7 @@ -19653,8 +19750,8 @@ packages: tinybench: 2.5.0 tinypool: 0.4.0 tinyspy: 1.1.1 - vite: 4.0.4(@types/node@20.4.5) - vite-node: 0.29.7(@types/node@20.4.5) + vite: 4.0.4(@types/node@20.7.0) + vite-node: 0.29.7(@types/node@20.7.0) why-is-node-running: 2.2.2 transitivePeerDependencies: - less From b1a79b1e3def12aa757e2ce8904bc40461fcd240 Mon Sep 17 00:00:00 2001 From: Akim <59872966+akim-bow@users.noreply.github.com> Date: Wed, 11 Oct 2023 18:16:51 +0700 Subject: [PATCH 28/45] Update packages/@tests/smoke/node/src/index.ts Co-authored-by: shamsartem --- packages/@tests/smoke/node/src/index.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/@tests/smoke/node/src/index.ts b/packages/@tests/smoke/node/src/index.ts index 0d97b44f6..86a6207f6 100644 --- a/packages/@tests/smoke/node/src/index.ts +++ b/packages/@tests/smoke/node/src/index.ts @@ -17,6 +17,5 @@ import "@fluencelabs/js-client"; import { runTest } from "@test/aqua_for_test"; -await runTest().then(() => { - console.log("Smoke tests succeed!"); -}); +await runTest() +console.log("Smoke tests succeed!"); From f97397e0d6c12e7f263ed57b9b6d510bd56faa9b Mon Sep 17 00:00:00 2001 From: Akim Mamedov Date: Wed, 11 Oct 2023 18:33:23 +0700 Subject: [PATCH 29/45] Revert package --- packages/core/js-client/package.json | 12 +- .../src/compilerSupport/callFunction.ts | 10 +- .../core/js-client/src/fetchers/browser.ts | 37 ++++- packages/core/js-client/src/fetchers/index.ts | 5 +- .../src/jsServiceHost/JsServiceHost.ts | 6 +- .../src/marine/worker-script/workerLoader.ts | 1 - .../core/js-client/src/particle/Particle.ts | 6 +- pnpm-lock.yaml | 157 +----------------- 8 files changed, 64 insertions(+), 170 deletions(-) diff --git a/packages/core/js-client/package.json b/packages/core/js-client/package.json index 09b33170b..cc1522c50 100644 --- a/packages/core/js-client/package.json +++ b/packages/core/js-client/package.json @@ -9,13 +9,13 @@ "files": [ "dist" ], - "main": "./dist/src/index.js", - "unpkg": "./dist/src/browser/index.umd.js", - "types": "./dist/src/index.d.ts", + "main": "./dist/index.js", + "unpkg": "./dist/browser/index.umd.js", + "types": "./dist/index.d.ts", "exports": { - "types": "./dist/src/index.d.ts", - "node": "./dist/src/index.js", - "default": "./dist/src/browser/index.js" + "types": "./dist/index.d.ts", + "node": "./dist/index.js", + "default": "./dist/browser/index.js" }, "type": "module", "scripts": { diff --git a/packages/core/js-client/src/compilerSupport/callFunction.ts b/packages/core/js-client/src/compilerSupport/callFunction.ts index 830be9dec..7786cee85 100644 --- a/packages/core/js-client/src/compilerSupport/callFunction.ts +++ b/packages/core/js-client/src/compilerSupport/callFunction.ts @@ -79,7 +79,10 @@ export const callAquaFunction = async ({ if (type.tag === "arrow") { // TODO: Add validation here - assert(typeof argVal === "function", "Should not be possible, bad types"); + assert( + typeof argVal === "function", + "Should not be possible, bad types", + ); service = userHandlerService( def.names.callbackSrv, @@ -88,7 +91,10 @@ export const callAquaFunction = async ({ ); } else { // TODO: Add validation here - assert(typeof argVal !== "function", "Should not be possible, bad types"); + assert( + typeof argVal !== "function", + "Should not be possible, bad types", + ); service = injectValueService(def.names.getDataSrv, name, type, argVal); } diff --git a/packages/core/js-client/src/fetchers/browser.ts b/packages/core/js-client/src/fetchers/browser.ts index 62f987b89..b01d5958a 100644 --- a/packages/core/js-client/src/fetchers/browser.ts +++ b/packages/core/js-client/src/fetchers/browser.ts @@ -14,13 +14,42 @@ * limitations under the License. */ -import packageJSON from "../../package.json"; -import type { AvailableDependencies } from './index.js'; +interface PackageJsonContent { + dependencies: Record; + devDependencies: Record; +} + +// This will be substituted in build phase +const packageJsonContentString = `__PACKAGE_JSON_CONTENT__`; +let parsedPackageJsonContent: PackageJsonContent | undefined; const PRIMARY_CDN = "https://unpkg.com/"; -export async function fetchResource(pkg: T, assetPath: string) { - const version = { ...packageJSON.dependencies, ...packageJSON.devDependencies }[pkg]; +export async function fetchResource(pkg: string, assetPath: string) { + const packageJsonContent = + parsedPackageJsonContent ?? + // TODO: Should be validated + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + (parsedPackageJsonContent = JSON.parse( + packageJsonContentString, + ) as PackageJsonContent); + + const version = + packageJsonContent.dependencies[pkg] ?? + packageJsonContent.devDependencies[pkg]; + + if (version === undefined) { + const availableDeps = [ + ...Object.keys(packageJsonContent.dependencies), + ...Object.keys(packageJsonContent.devDependencies), + ]; + + throw new Error( + `Cannot find version of ${pkg} in package.json. Available versions: ${availableDeps.join( + ",", + )}`, + ); + } const refinedAssetPath = assetPath.startsWith("/") ? assetPath.slice(1) diff --git a/packages/core/js-client/src/fetchers/index.ts b/packages/core/js-client/src/fetchers/index.ts index fb8f31f9a..b0c45fb72 100644 --- a/packages/core/js-client/src/fetchers/index.ts +++ b/packages/core/js-client/src/fetchers/index.ts @@ -18,14 +18,11 @@ import process from "process"; import { fetchResource as fetchResourceBrowser } from "./browser.js"; import { fetchResource as fetchResourceNode } from "./node.js"; -import packageJSON from '../../package.json'; const isNode = typeof process !== "undefined" && process.release.name === "node"; -export type AvailableDependencies = (keyof typeof packageJSON['dependencies']) | (keyof typeof packageJSON['devDependencies']); - -export async function fetchResource(pkg: AvailableDependencies, path: string) { +export async function fetchResource(pkg: string, path: string) { switch (true) { case isNode: return fetchResourceNode(pkg, path); diff --git a/packages/core/js-client/src/jsServiceHost/JsServiceHost.ts b/packages/core/js-client/src/jsServiceHost/JsServiceHost.ts index 5c3560e72..961278651 100644 --- a/packages/core/js-client/src/jsServiceHost/JsServiceHost.ts +++ b/packages/core/js-client/src/jsServiceHost/JsServiceHost.ts @@ -58,7 +58,11 @@ export class JsServiceHost implements IJsServiceHost { particleId: string, ): GenericCallServiceHandler | null { const key = serviceFnKey(serviceId, fnName); - return this.particleScopeHandlers.get(particleId)?.get(key) ?? this.commonHandlers.get(key) ?? null; + return ( + this.particleScopeHandlers.get(particleId)?.get(key) ?? + this.commonHandlers.get(key) ?? + null + ); } /** diff --git a/packages/core/js-client/src/marine/worker-script/workerLoader.ts b/packages/core/js-client/src/marine/worker-script/workerLoader.ts index 48d9db7d4..f241850db 100644 --- a/packages/core/js-client/src/marine/worker-script/workerLoader.ts +++ b/packages/core/js-client/src/marine/worker-script/workerLoader.ts @@ -16,7 +16,6 @@ import { Worker } from "../../../node_modules/threads/dist/index.js"; import type { WorkerImplementation } from "../../../node_modules/threads/dist/types/master.js"; - import { LazyLoader } from "../interfaces.js"; export class WorkerLoader extends LazyLoader { diff --git a/packages/core/js-client/src/particle/Particle.ts b/packages/core/js-client/src/particle/Particle.ts index 9614540ac..2bc1ae259 100644 --- a/packages/core/js-client/src/particle/Particle.ts +++ b/packages/core/js-client/src/particle/Particle.ts @@ -75,7 +75,11 @@ export class Particle implements IParticle { const res = particleSchema.safeParse(json); if (!res.success) { - throw new Error(`Particle format invalid. Errors: ${JSON.stringify(res.error.flatten())}`); + throw new Error( + `Particle format invalid. Errors: ${JSON.stringify( + res.error.flatten(), + )}`, + ); } const data = res.data; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5a0a3b95a..e841dd17a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -68,7 +68,7 @@ importers: version: 0.7.2(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@nomicfoundation/hardhat-chai-matchers@1.0.6)(@nomicfoundation/hardhat-network-helpers@1.0.8)(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(@typechain/ethers-v5@10.2.1)(@typechain/hardhat@6.1.6)(@types/chai@4.3.5)(@types/mocha@9.1.1)(@types/node@20.7.0)(chai@4.3.7)(hardhat-gas-reporter@1.0.9)(hardhat@2.15.0)(solidity-coverage@0.7.22)(ts-node@10.9.1)(typechain@8.2.0)(typescript@5.1.6) '@fluencelabs/js-client': specifier: workspace:^ - version: link:../../core/js-client/dist + version: link:../../core/js-client '@fluencelabs/registry': specifier: 0.8.2 version: 0.8.2 @@ -80,7 +80,7 @@ importers: dependencies: '@fluencelabs/js-client': specifier: workspace:* - version: link:../../../core/js-client/dist + version: link:../../../core/js-client '@test/aqua_for_test': specifier: workspace:* version: link:../../aqua @@ -89,7 +89,7 @@ importers: dependencies: '@fluencelabs/js-client': specifier: workspace:* - version: link:../../../core/js-client/dist + version: link:../../../core/js-client '@test/test-utils': specifier: workspace:* version: link:../../test-utils @@ -171,7 +171,7 @@ importers: version: link:../interfaces '@fluencelabs/js-client': specifier: workspace:* - version: link:../js-client/dist + version: link:../js-client '@fluencelabs/registry': specifier: 0.8.7 version: 0.8.7 @@ -315,124 +315,6 @@ importers: specifier: 0.29.7 version: 0.29.7 - packages/core/js-client/dist: - dependencies: - '@chainsafe/libp2p-noise': - specifier: 13.0.0 - version: 13.0.0 - '@chainsafe/libp2p-yamux': - specifier: 5.0.0 - version: 5.0.0 - '@fluencelabs/interfaces': - specifier: workspace:* - version: link:../../interfaces - '@fluencelabs/marine-worker': - specifier: 0.3.3 - version: link:../../marine-worker - '@libp2p/crypto': - specifier: 2.0.3 - version: 2.0.3 - '@libp2p/interface': - specifier: 0.1.2 - version: 0.1.2 - '@libp2p/peer-id': - specifier: 3.0.2 - version: 3.0.2 - '@libp2p/peer-id-factory': - specifier: 3.0.3 - version: 3.0.3 - '@libp2p/websockets': - specifier: 7.0.4 - version: 7.0.4 - '@multiformats/multiaddr': - specifier: 11.3.0 - version: 11.3.0 - async: - specifier: 3.2.4 - version: 3.2.4 - bs58: - specifier: 5.0.0 - version: 5.0.0 - buffer: - specifier: 6.0.3 - version: 6.0.3 - debug: - specifier: 4.3.4 - version: 4.3.4(supports-color@8.1.1) - it-length-prefixed: - specifier: 8.0.4 - version: 8.0.4 - it-map: - specifier: 2.0.0 - version: 2.0.0 - it-pipe: - specifier: 2.0.5 - version: 2.0.5 - js-base64: - specifier: 3.7.5 - version: 3.7.5 - libp2p: - specifier: 0.46.6 - version: 0.46.6 - multiformats: - specifier: 11.0.1 - version: 11.0.1 - rxjs: - specifier: 7.5.5 - version: 7.5.5 - threads: - specifier: 1.7.0 - version: 1.7.0 - ts-pattern: - specifier: 3.3.3 - version: 3.3.3 - uint8arrays: - specifier: 4.0.3 - version: 4.0.3 - uuid: - specifier: 8.3.2 - version: 8.3.2 - zod: - specifier: 3.22.4 - version: 3.22.4 - devDependencies: - '@fluencelabs/aqua-api': - specifier: 0.9.3 - version: 0.9.3 - '@fluencelabs/avm': - specifier: 0.48.0 - version: 0.48.0 - '@fluencelabs/marine-js': - specifier: 0.7.2 - version: 0.7.2 - '@rollup/plugin-inject': - specifier: 5.0.3 - version: 5.0.3 - '@types/bs58': - specifier: 4.0.1 - version: 4.0.1 - '@types/debug': - specifier: 4.1.7 - version: 4.1.7 - '@types/node': - specifier: 20.7.0 - version: 20.7.0 - '@types/uuid': - specifier: 8.3.2 - version: 8.3.2 - hotscript: - specifier: 1.0.13 - version: 1.0.13 - vite: - specifier: 4.0.4 - version: 4.0.4(@types/node@20.7.0) - vite-tsconfig-paths: - specifier: 4.0.3 - version: 4.0.3(typescript@5.1.6)(vite@4.0.4) - vitest: - specifier: 0.29.7 - version: 0.29.7 - packages/core/marine-worker: dependencies: '@fluencelabs/marine-js': @@ -13134,7 +13016,7 @@ packages: resolution: {integrity: sha512-V6Lt9A9usox9iduOX+edU1Vo94E6v9Lt9dOvg3ubFaw1qf5NCxXLi93Ao4fyCHWDYd8Y+DUhadwNtWVyn7qqLg==} engines: {node: '>=16.0.0', npm: '>=7.0.0'} dependencies: - it-pushable: 3.1.3 + it-pushable: 3.2.1 it-reader: 6.0.4 it-stream-types: 2.0.1 p-defer: 4.0.0 @@ -13236,7 +13118,7 @@ packages: dependencies: it-length-prefixed-stream: 1.0.2 it-stream-types: 2.0.1 - protons-runtime: 5.0.0(uint8arraylist@2.4.3) + protons-runtime: 5.0.2(uint8arraylist@2.4.3) uint8arraylist: 2.4.3 /it-pushable@3.1.3: @@ -16670,24 +16552,6 @@ packages: react-is: 16.13.1 dev: false - /protobufjs@7.2.3: - resolution: {integrity: sha512-TtpvOqwB5Gdz/PQmOjgsrGH1nHjAQVCN7JG4A6r1sXRWESL5rNMAiRcBQlCAdKxZcAbstExQePYG8xof/JVRgg==} - engines: {node: '>=12.0.0'} - requiresBuild: true - dependencies: - '@protobufjs/aspromise': 1.1.2 - '@protobufjs/base64': 1.1.2 - '@protobufjs/codegen': 2.0.4 - '@protobufjs/eventemitter': 1.1.0 - '@protobufjs/fetch': 1.1.0 - '@protobufjs/float': 1.0.2 - '@protobufjs/inquire': 1.1.0 - '@protobufjs/path': 1.1.2 - '@protobufjs/pool': 1.1.0 - '@protobufjs/utf8': 1.1.0 - '@types/node': 20.7.0 - long: 5.2.3 - /protobufjs@7.2.4: resolution: {integrity: sha512-AT+RJgD2sH8phPmCf7OUZR8xGdcJRga4+1cOaXJ64hvcSkVhNcRHOwIxUatPH15+nj59WAGTDv3LSGZPEQbJaQ==} engines: {node: '>=12.0.0'} @@ -16706,15 +16570,6 @@ packages: '@types/node': 20.7.0 long: 5.2.3 - /protons-runtime@5.0.0(uint8arraylist@2.4.3): - resolution: {integrity: sha512-QqjGnPGkpvbzq0dITzhG9DVK10rRIHf7nePcU2QQVVpFGuYbwrOWnvGSvei1GcceAzB9syTz6vHzvTPmGRR0PA==} - engines: {node: '>=16.0.0', npm: '>=7.0.0'} - peerDependencies: - uint8arraylist: ^2.3.2 - dependencies: - protobufjs: 7.2.3 - uint8arraylist: 2.4.3 - /protons-runtime@5.0.2(uint8arraylist@2.4.3): resolution: {integrity: sha512-eKppVrIS5dDh+Y61Yj4bDEOs2sQLQbQGIhr7EBiybPQhIMGBynzVXlYILPWl3Td1GDadobc8qevh5D+JwfG9bw==} peerDependencies: From b0479383e365123afb67312d2b355e90119b157a Mon Sep 17 00:00:00 2001 From: Akim Mamedov Date: Wed, 11 Oct 2023 22:38:50 +0700 Subject: [PATCH 30/45] Fix pnpm lock --- pnpm-lock.yaml | 126 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 122 insertions(+), 4 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e841dd17a..5e68042f8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -68,7 +68,7 @@ importers: version: 0.7.2(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@nomicfoundation/hardhat-chai-matchers@1.0.6)(@nomicfoundation/hardhat-network-helpers@1.0.8)(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(@typechain/ethers-v5@10.2.1)(@typechain/hardhat@6.1.6)(@types/chai@4.3.5)(@types/mocha@9.1.1)(@types/node@20.7.0)(chai@4.3.7)(hardhat-gas-reporter@1.0.9)(hardhat@2.15.0)(solidity-coverage@0.7.22)(ts-node@10.9.1)(typechain@8.2.0)(typescript@5.1.6) '@fluencelabs/js-client': specifier: workspace:^ - version: link:../../core/js-client + version: link:../../core/js-client/dist '@fluencelabs/registry': specifier: 0.8.2 version: 0.8.2 @@ -80,7 +80,7 @@ importers: dependencies: '@fluencelabs/js-client': specifier: workspace:* - version: link:../../../core/js-client + version: link:../../../core/js-client/dist '@test/aqua_for_test': specifier: workspace:* version: link:../../aqua @@ -89,7 +89,7 @@ importers: dependencies: '@fluencelabs/js-client': specifier: workspace:* - version: link:../../../core/js-client + version: link:../../../core/js-client/dist '@test/test-utils': specifier: workspace:* version: link:../../test-utils @@ -171,7 +171,7 @@ importers: version: link:../interfaces '@fluencelabs/js-client': specifier: workspace:* - version: link:../js-client + version: link:../js-client/dist '@fluencelabs/registry': specifier: 0.8.7 version: 0.8.7 @@ -315,6 +315,124 @@ importers: specifier: 0.29.7 version: 0.29.7 + packages/core/js-client/dist: + dependencies: + '@chainsafe/libp2p-noise': + specifier: 13.0.0 + version: 13.0.0 + '@chainsafe/libp2p-yamux': + specifier: 5.0.0 + version: 5.0.0 + '@fluencelabs/interfaces': + specifier: workspace:* + version: link:../../interfaces + '@fluencelabs/marine-worker': + specifier: 0.3.3 + version: link:../../marine-worker + '@libp2p/crypto': + specifier: 2.0.3 + version: 2.0.3 + '@libp2p/interface': + specifier: 0.1.2 + version: 0.1.2 + '@libp2p/peer-id': + specifier: 3.0.2 + version: 3.0.2 + '@libp2p/peer-id-factory': + specifier: 3.0.3 + version: 3.0.3 + '@libp2p/websockets': + specifier: 7.0.4 + version: 7.0.4 + '@multiformats/multiaddr': + specifier: 11.3.0 + version: 11.3.0 + async: + specifier: 3.2.4 + version: 3.2.4 + bs58: + specifier: 5.0.0 + version: 5.0.0 + buffer: + specifier: 6.0.3 + version: 6.0.3 + debug: + specifier: 4.3.4 + version: 4.3.4(supports-color@8.1.1) + it-length-prefixed: + specifier: 8.0.4 + version: 8.0.4 + it-map: + specifier: 2.0.0 + version: 2.0.0 + it-pipe: + specifier: 2.0.5 + version: 2.0.5 + js-base64: + specifier: 3.7.5 + version: 3.7.5 + libp2p: + specifier: 0.46.6 + version: 0.46.6 + multiformats: + specifier: 11.0.1 + version: 11.0.1 + rxjs: + specifier: 7.5.5 + version: 7.5.5 + threads: + specifier: 1.7.0 + version: 1.7.0 + ts-pattern: + specifier: 3.3.3 + version: 3.3.3 + uint8arrays: + specifier: 4.0.3 + version: 4.0.3 + uuid: + specifier: 8.3.2 + version: 8.3.2 + zod: + specifier: 3.22.4 + version: 3.22.4 + devDependencies: + '@fluencelabs/aqua-api': + specifier: 0.9.3 + version: 0.9.3 + '@fluencelabs/avm': + specifier: 0.48.0 + version: 0.48.0 + '@fluencelabs/marine-js': + specifier: 0.7.2 + version: 0.7.2 + '@rollup/plugin-inject': + specifier: 5.0.3 + version: 5.0.3 + '@types/bs58': + specifier: 4.0.1 + version: 4.0.1 + '@types/debug': + specifier: 4.1.7 + version: 4.1.7 + '@types/node': + specifier: 20.7.0 + version: 20.7.0 + '@types/uuid': + specifier: 8.3.2 + version: 8.3.2 + hotscript: + specifier: 1.0.13 + version: 1.0.13 + vite: + specifier: 4.0.4 + version: 4.0.4(@types/node@20.7.0) + vite-tsconfig-paths: + specifier: 4.0.3 + version: 4.0.3(typescript@5.1.6)(vite@4.0.4) + vitest: + specifier: 0.29.7 + version: 0.29.7 + packages/core/marine-worker: dependencies: '@fluencelabs/marine-js': From 138c55565eb74706d618d74e8b870eb2c2117002 Mon Sep 17 00:00:00 2001 From: Akim Mamedov Date: Wed, 11 Oct 2023 22:55:54 +0700 Subject: [PATCH 31/45] Lint-fix --- packages/@tests/smoke/node/src/index.ts | 2 +- .../src/keypair/__test__/KeyPair.spec.ts | 45 +++++-- packages/core/js-client/src/keypair/index.ts | 34 ++--- .../core/js-client/src/particle/Particle.ts | 18 +-- pnpm-lock.yaml | 126 +----------------- 5 files changed, 66 insertions(+), 159 deletions(-) diff --git a/packages/@tests/smoke/node/src/index.ts b/packages/@tests/smoke/node/src/index.ts index 86a6207f6..39025990d 100644 --- a/packages/@tests/smoke/node/src/index.ts +++ b/packages/@tests/smoke/node/src/index.ts @@ -17,5 +17,5 @@ import "@fluencelabs/js-client"; import { runTest } from "@test/aqua_for_test"; -await runTest() +await runTest(); console.log("Smoke tests succeed!"); diff --git a/packages/core/js-client/src/keypair/__test__/KeyPair.spec.ts b/packages/core/js-client/src/keypair/__test__/KeyPair.spec.ts index 762529eb7..d560fd231 100644 --- a/packages/core/js-client/src/keypair/__test__/KeyPair.spec.ts +++ b/packages/core/js-client/src/keypair/__test__/KeyPair.spec.ts @@ -15,11 +15,11 @@ */ import bs58 from "bs58"; -import { fromUint8Array, toUint8Array } from 'js-base64'; +import { fromUint8Array, toUint8Array } from "js-base64"; import { it, describe, expect } from "vitest"; -import { fromBase64Sk, KeyPair } from '../index.js'; -import { Particle, serializeToString, buildParticleMessage } from '../../particle/Particle.js'; +import { Particle, buildParticleMessage } from "../../particle/Particle.js"; +import { fromBase64Sk, KeyPair } from "../index.js"; const key = "+cmeYlZKj+MfSa9dpHV+BmLPm6wq4inGlsPlQ1GvtPk="; const keyBytes = toUint8Array(key); @@ -113,24 +113,49 @@ describe("KeyPair tests", () => { }); it("validates particle signature checks", async function () { - const keyPair = await fromBase64Sk("7h48PQ/f1rS9TxacmgODxbD42Il9B3KC117jvOPppPE="); - expect(bs58.encode(keyPair.getLibp2pPeerId().toBytes())).toBe("12D3KooWANqfCDrV79MZdMnMqTvDdqSAPSxdgFY1L6DCq2DVGB4D"); + const keyPair = await fromBase64Sk( + "7h48PQ/f1rS9TxacmgODxbD42Il9B3KC117jvOPppPE=", + ); + + expect(bs58.encode(keyPair.getLibp2pPeerId().toBytes())).toBe( + "12D3KooWANqfCDrV79MZdMnMqTvDdqSAPSxdgFY1L6DCq2DVGB4D", + ); + const message = toUint8Array(btoa("message")); const signature = await keyPair.signBytes(message); const verified = await keyPair.verify(message, signature); expect(verified).toBe(true); - expect(fromUint8Array(signature)).toBe("sBW7H6/1fwAwF86ldwVm9BDu0YH3w30oFQjTWX0Tiu9yTVZHmxkV2OX4GL5jn0Iz0CrasGcOfozzkZwtJBPMBg=="); - const particle = await Particle.createNew("abc", keyPair.getPeerId(), 7000, keyPair, "2883f959-e9e7-4843-8c37-205d393ca372", 1696934545662); + expect(fromUint8Array(signature)).toBe( + "sBW7H6/1fwAwF86ldwVm9BDu0YH3w30oFQjTWX0Tiu9yTVZHmxkV2OX4GL5jn0Iz0CrasGcOfozzkZwtJBPMBg==", + ); + + const particle = await Particle.createNew( + "abc", + keyPair.getPeerId(), + 7000, + keyPair, + "2883f959-e9e7-4843-8c37-205d393ca372", + 1696934545662, + ); const particle_bytes = buildParticleMessage(particle); - expect(fromUint8Array(particle_bytes)).toBe("Mjg4M2Y5NTktZTllNy00ODQzLThjMzctMjA1ZDM5M2NhMzcy/kguGYsBAABYGwAAYWJj"); - const isParticleVerified = await KeyPair.verifyWithPublicKey(keyPair.getPublicKey(), particle_bytes, particle.signature); + expect(fromUint8Array(particle_bytes)).toBe( + "Mjg4M2Y5NTktZTllNy00ODQzLThjMzctMjA1ZDM5M2NhMzcy/kguGYsBAABYGwAAYWJj", + ); + + const isParticleVerified = await KeyPair.verifyWithPublicKey( + keyPair.getPublicKey(), + particle_bytes, + particle.signature, + ); expect(isParticleVerified).toBe(true); - expect(fromUint8Array(particle.signature)).toBe("KceXDnOfqe0dOnAxiDsyWBIvUq6WHoT0ge+VMHXOZsjZvCNH7/10oufdlYfcPomfv28On6E87ZhDcHGBZcb7Bw=="); + expect(fromUint8Array(particle.signature)).toBe( + "KceXDnOfqe0dOnAxiDsyWBIvUq6WHoT0ge+VMHXOZsjZvCNH7/10oufdlYfcPomfv28On6E87ZhDcHGBZcb7Bw==", + ); }); }); diff --git a/packages/core/js-client/src/keypair/index.ts b/packages/core/js-client/src/keypair/index.ts index e4d0b78d9..353488c37 100644 --- a/packages/core/js-client/src/keypair/index.ts +++ b/packages/core/js-client/src/keypair/index.ts @@ -43,23 +43,23 @@ export class KeyPair { return this.libp2pPeerId; } - /** - * Return public key inferred from private key - */ - getPublicKey() { - return this.publicKey.bytes; - } - - /** - * Generates new KeyPair from ed25519 private key represented as a 32 byte array - * @param seed - Any sequence of 32 bytes - * @returns - Promise with the created KeyPair - */ - static async fromEd25519SK(seed: Uint8Array): Promise { - const key = await generateKeyPairFromSeed('Ed25519', seed, 256); - const lib2p2Pid = await createFromPrivKey(key); - return new KeyPair(key, lib2p2Pid); - } + /** + * Return public key inferred from private key + */ + getPublicKey() { + return this.publicKey.bytes; + } + + /** + * Generates new KeyPair from ed25519 private key represented as a 32 byte array + * @param seed - Any sequence of 32 bytes + * @returns - Promise with the created KeyPair + */ + static async fromEd25519SK(seed: Uint8Array): Promise { + const key = await generateKeyPairFromSeed("Ed25519", seed, 256); + const lib2p2Pid = await createFromPrivKey(key); + return new KeyPair(key, lib2p2Pid); + } /** * Generates new KeyPair with a random secret key diff --git a/packages/core/js-client/src/particle/Particle.ts b/packages/core/js-client/src/particle/Particle.ts index b34ac740c..15a5127b4 100644 --- a/packages/core/js-client/src/particle/Particle.ts +++ b/packages/core/js-client/src/particle/Particle.ts @@ -36,15 +36,15 @@ const particleSchema = z.object({ }); export class Particle implements IParticle { - constructor( - public readonly id: string, - public readonly timestamp: number, - public readonly script: string, - public readonly data: Uint8Array, - public readonly ttl: number, - public readonly initPeerId: string, - public readonly signature: Uint8Array - ) {} + constructor( + readonly id: string, + readonly timestamp: number, + readonly script: string, + readonly data: Uint8Array, + readonly ttl: number, + readonly initPeerId: string, + readonly signature: Uint8Array, + ) {} static async createNew( script: string, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5e68042f8..e841dd17a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -68,7 +68,7 @@ importers: version: 0.7.2(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@nomicfoundation/hardhat-chai-matchers@1.0.6)(@nomicfoundation/hardhat-network-helpers@1.0.8)(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(@typechain/ethers-v5@10.2.1)(@typechain/hardhat@6.1.6)(@types/chai@4.3.5)(@types/mocha@9.1.1)(@types/node@20.7.0)(chai@4.3.7)(hardhat-gas-reporter@1.0.9)(hardhat@2.15.0)(solidity-coverage@0.7.22)(ts-node@10.9.1)(typechain@8.2.0)(typescript@5.1.6) '@fluencelabs/js-client': specifier: workspace:^ - version: link:../../core/js-client/dist + version: link:../../core/js-client '@fluencelabs/registry': specifier: 0.8.2 version: 0.8.2 @@ -80,7 +80,7 @@ importers: dependencies: '@fluencelabs/js-client': specifier: workspace:* - version: link:../../../core/js-client/dist + version: link:../../../core/js-client '@test/aqua_for_test': specifier: workspace:* version: link:../../aqua @@ -89,7 +89,7 @@ importers: dependencies: '@fluencelabs/js-client': specifier: workspace:* - version: link:../../../core/js-client/dist + version: link:../../../core/js-client '@test/test-utils': specifier: workspace:* version: link:../../test-utils @@ -171,7 +171,7 @@ importers: version: link:../interfaces '@fluencelabs/js-client': specifier: workspace:* - version: link:../js-client/dist + version: link:../js-client '@fluencelabs/registry': specifier: 0.8.7 version: 0.8.7 @@ -315,124 +315,6 @@ importers: specifier: 0.29.7 version: 0.29.7 - packages/core/js-client/dist: - dependencies: - '@chainsafe/libp2p-noise': - specifier: 13.0.0 - version: 13.0.0 - '@chainsafe/libp2p-yamux': - specifier: 5.0.0 - version: 5.0.0 - '@fluencelabs/interfaces': - specifier: workspace:* - version: link:../../interfaces - '@fluencelabs/marine-worker': - specifier: 0.3.3 - version: link:../../marine-worker - '@libp2p/crypto': - specifier: 2.0.3 - version: 2.0.3 - '@libp2p/interface': - specifier: 0.1.2 - version: 0.1.2 - '@libp2p/peer-id': - specifier: 3.0.2 - version: 3.0.2 - '@libp2p/peer-id-factory': - specifier: 3.0.3 - version: 3.0.3 - '@libp2p/websockets': - specifier: 7.0.4 - version: 7.0.4 - '@multiformats/multiaddr': - specifier: 11.3.0 - version: 11.3.0 - async: - specifier: 3.2.4 - version: 3.2.4 - bs58: - specifier: 5.0.0 - version: 5.0.0 - buffer: - specifier: 6.0.3 - version: 6.0.3 - debug: - specifier: 4.3.4 - version: 4.3.4(supports-color@8.1.1) - it-length-prefixed: - specifier: 8.0.4 - version: 8.0.4 - it-map: - specifier: 2.0.0 - version: 2.0.0 - it-pipe: - specifier: 2.0.5 - version: 2.0.5 - js-base64: - specifier: 3.7.5 - version: 3.7.5 - libp2p: - specifier: 0.46.6 - version: 0.46.6 - multiformats: - specifier: 11.0.1 - version: 11.0.1 - rxjs: - specifier: 7.5.5 - version: 7.5.5 - threads: - specifier: 1.7.0 - version: 1.7.0 - ts-pattern: - specifier: 3.3.3 - version: 3.3.3 - uint8arrays: - specifier: 4.0.3 - version: 4.0.3 - uuid: - specifier: 8.3.2 - version: 8.3.2 - zod: - specifier: 3.22.4 - version: 3.22.4 - devDependencies: - '@fluencelabs/aqua-api': - specifier: 0.9.3 - version: 0.9.3 - '@fluencelabs/avm': - specifier: 0.48.0 - version: 0.48.0 - '@fluencelabs/marine-js': - specifier: 0.7.2 - version: 0.7.2 - '@rollup/plugin-inject': - specifier: 5.0.3 - version: 5.0.3 - '@types/bs58': - specifier: 4.0.1 - version: 4.0.1 - '@types/debug': - specifier: 4.1.7 - version: 4.1.7 - '@types/node': - specifier: 20.7.0 - version: 20.7.0 - '@types/uuid': - specifier: 8.3.2 - version: 8.3.2 - hotscript: - specifier: 1.0.13 - version: 1.0.13 - vite: - specifier: 4.0.4 - version: 4.0.4(@types/node@20.7.0) - vite-tsconfig-paths: - specifier: 4.0.3 - version: 4.0.3(typescript@5.1.6)(vite@4.0.4) - vitest: - specifier: 0.29.7 - version: 0.29.7 - packages/core/marine-worker: dependencies: '@fluencelabs/marine-js': From 49d98983ec979d03c3d0a1300fd202eeb02feb15 Mon Sep 17 00:00:00 2001 From: Akim Mamedov Date: Wed, 11 Oct 2023 23:00:55 +0700 Subject: [PATCH 32/45] Fix CI --- .github/workflows/tests.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 68d80508a..339421bc4 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -88,6 +88,12 @@ jobs: registry-url: "https://npm.fluence.dev" cache: "pnpm" + - name: install workspace root deps + run: pnpm i --filter ./ + + - name: lint all packages + run: pnpm lint-check + - name: Override dependencies uses: fluencelabs/github-actions/pnpm-set-dependency@main with: @@ -99,9 +105,7 @@ jobs: - run: pnpm -r i - run: pnpm -r build - - run: pnpm lint-check - run: pnpm -r test - - name: Dump rust-peer logs if: always() uses: jwalton/gh-docker-logs@v2 \ No newline at end of file From 51229f347930cef0292daa8e049dd3b8434eb56f Mon Sep 17 00:00:00 2001 From: Akim Mamedov Date: Thu, 12 Oct 2023 16:43:06 +0700 Subject: [PATCH 33/45] Update tests --- .github/workflows/tests.yml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 339421bc4..4aa537f16 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -88,11 +88,10 @@ jobs: registry-url: "https://npm.fluence.dev" cache: "pnpm" - - name: install workspace root deps - run: pnpm i --filter ./ + - run: pnpm -r i + - run: pnpm -r build + - run: pnpm lint-check - - name: lint all packages - run: pnpm lint-check - name: Override dependencies uses: fluencelabs/github-actions/pnpm-set-dependency@main @@ -104,7 +103,6 @@ jobs: } - run: pnpm -r i - - run: pnpm -r build - run: pnpm -r test - name: Dump rust-peer logs if: always() From 72ad2df20dfe8a495637e8f1366850eb5d42ce1a Mon Sep 17 00:00:00 2001 From: Akim Mamedov Date: Thu, 12 Oct 2023 17:03:06 +0700 Subject: [PATCH 34/45] Fix build --- packages/@tests/test-utils/tsconfig.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/@tests/test-utils/tsconfig.json b/packages/@tests/test-utils/tsconfig.json index 995a8f672..78eeba951 100644 --- a/packages/@tests/test-utils/tsconfig.json +++ b/packages/@tests/test-utils/tsconfig.json @@ -3,5 +3,6 @@ "compilerOptions": { "outDir": "./dist" }, + "include": ["src"], "exclude": ["node_modules", "dist"] } From 7ea5809ccb8d9a89b3bde6c044af1c8f62376796 Mon Sep 17 00:00:00 2001 From: Akim Mamedov Date: Thu, 12 Oct 2023 17:15:16 +0700 Subject: [PATCH 35/45] Fix import --- packages/core/js-client/src/index.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/core/js-client/src/index.ts b/packages/core/js-client/src/index.ts index 830583cca..1d21bf0dc 100644 --- a/packages/core/js-client/src/index.ts +++ b/packages/core/js-client/src/index.ts @@ -22,7 +22,6 @@ import url from "url"; import type { ClientConfig, ConnectionState, - IFluenceClient, RelayOptions, } from "@fluencelabs/interfaces"; @@ -148,7 +147,7 @@ interface FluencePublicApi { onConnectionStateChange: ( handler: (state: ConnectionState) => void, ) => ConnectionState; - getClient: () => IFluenceClient; + getClient: () => ClientPeer; } export const Fluence: FluencePublicApi = { From 91a985908375108f63f0deb69d8261223520dfe9 Mon Sep 17 00:00:00 2001 From: Akim Mamedov Date: Thu, 12 Oct 2023 20:15:59 +0700 Subject: [PATCH 36/45] Use forked threads dep --- packages/core/js-client/package.json | 2 +- packages/core/js-client/src/index.ts | 2 +- .../js-client/src/marine/deps-loader/node.ts | 3 +-- .../core/js-client/src/marine/interfaces.ts | 2 +- .../src/marine/worker-script/workerLoader.ts | 3 +-- .../core/js-client/src/marine/worker/index.ts | 6 +---- packages/core/marine-worker/package.json | 2 +- packages/core/marine-worker/src/index.ts | 3 +-- pnpm-lock.yaml | 26 ++++++++++++++++--- 9 files changed, 30 insertions(+), 19 deletions(-) diff --git a/packages/core/js-client/package.json b/packages/core/js-client/package.json index 2ced64bb1..6dc1b54a3 100644 --- a/packages/core/js-client/package.json +++ b/packages/core/js-client/package.json @@ -47,7 +47,7 @@ "libp2p": "0.46.6", "multiformats": "11.0.1", "rxjs": "7.5.5", - "threads": "1.7.0", + "threads": "git://github.com/akim-bow/threads.js.git#457fabf2393852980c35ca70ed73a2c0e96dc18a", "ts-pattern": "3.3.3", "uint8arrays": "4.0.3", "uuid": "8.3.2", diff --git a/packages/core/js-client/src/index.ts b/packages/core/js-client/src/index.ts index 1d21bf0dc..8fe28e6f0 100644 --- a/packages/core/js-client/src/index.ts +++ b/packages/core/js-client/src/index.ts @@ -26,7 +26,7 @@ import type { } from "@fluencelabs/interfaces"; // "threads" package has broken type definitions in package.json. This is the workaround. -import { BlobWorker, Worker } from "../node_modules/threads/dist/index.js"; +import { BlobWorker, Worker } from "threads/master"; import { ClientPeer, makeClientPeerConfig } from "./clientPeer/ClientPeer.js"; import { callAquaFunction } from "./compilerSupport/callFunction.js"; diff --git a/packages/core/js-client/src/marine/deps-loader/node.ts b/packages/core/js-client/src/marine/deps-loader/node.ts index dd4b3ffed..9c287a3aa 100644 --- a/packages/core/js-client/src/marine/deps-loader/node.ts +++ b/packages/core/js-client/src/marine/deps-loader/node.ts @@ -19,8 +19,7 @@ import fs from "fs"; import { createRequire } from "module"; import path from "path"; -import { Worker } from "../../../node_modules/threads/dist/index.js"; -import type { WorkerImplementation } from "../../../node_modules/threads/dist/types/master.js"; +import { Worker, type Worker as WorkerImplementation } from "threads/master"; import { LazyLoader } from "../interfaces.js"; const require = createRequire(import.meta.url); diff --git a/packages/core/js-client/src/marine/interfaces.ts b/packages/core/js-client/src/marine/interfaces.ts index be7607b80..a36daa24b 100644 --- a/packages/core/js-client/src/marine/interfaces.ts +++ b/packages/core/js-client/src/marine/interfaces.ts @@ -21,7 +21,7 @@ import { } from "@fluencelabs/avm"; import { JSONObject, JSONValue, JSONArray } from "@fluencelabs/interfaces"; -import type { WorkerImplementation } from "../../node_modules/threads/dist/types/master.js"; +import type { Worker as WorkerImplementation } from "threads/master"; import { IStartable, CallParameters } from "../util/commonTypes.js"; /** diff --git a/packages/core/js-client/src/marine/worker-script/workerLoader.ts b/packages/core/js-client/src/marine/worker-script/workerLoader.ts index f241850db..cb102dc61 100644 --- a/packages/core/js-client/src/marine/worker-script/workerLoader.ts +++ b/packages/core/js-client/src/marine/worker-script/workerLoader.ts @@ -14,8 +14,7 @@ * limitations under the License. */ -import { Worker } from "../../../node_modules/threads/dist/index.js"; -import type { WorkerImplementation } from "../../../node_modules/threads/dist/types/master.js"; +import { Worker, type Worker as WorkerImplementation } from "threads/master"; import { LazyLoader } from "../interfaces.js"; export class WorkerLoader extends LazyLoader { diff --git a/packages/core/js-client/src/marine/worker/index.ts b/packages/core/js-client/src/marine/worker/index.ts index ecf162f01..afb0f18ea 100644 --- a/packages/core/js-client/src/marine/worker/index.ts +++ b/packages/core/js-client/src/marine/worker/index.ts @@ -23,11 +23,7 @@ import type { import { LogFunction, logLevelToEnv } from "@fluencelabs/marine-js/dist/types"; import type { MarineBackgroundInterface } from "@fluencelabs/marine-worker"; -import { - ModuleThread, - Thread, - spawn, -} from "../../../node_modules/threads/dist/master/index.js"; +import { ModuleThread, Thread, spawn } from "threads/master"; import { MarineLogger, marineLogger } from "../../util/logger.js"; import { IMarineHost, IWasmLoader, IWorkerLoader } from "../interfaces.js"; diff --git a/packages/core/marine-worker/package.json b/packages/core/marine-worker/package.json index 3fb19fea5..82da01c12 100644 --- a/packages/core/marine-worker/package.json +++ b/packages/core/marine-worker/package.json @@ -26,6 +26,6 @@ "dependencies": { "@fluencelabs/marine-js": "0.7.2", "observable-fns": "0.6.1", - "threads": "1.7.0" + "threads": "git://github.com/akim-bow/threads.js.git#457fabf2393852980c35ca70ed73a2c0e96dc18a" } } diff --git a/packages/core/marine-worker/src/index.ts b/packages/core/marine-worker/src/index.ts index 5f604de40..c28719055 100644 --- a/packages/core/marine-worker/src/index.ts +++ b/packages/core/marine-worker/src/index.ts @@ -29,8 +29,7 @@ import type { import { JSONValue } from "@fluencelabs/marine-js/dist/types"; import { Observable, Subject } from "observable-fns"; -// "threads" package has broken type definitions in package.json. This is the workaround. -import { expose } from "../node_modules/threads/worker.js"; +import { expose } from "threads/worker"; const createSimpleModuleDescriptor = ( name: string, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e841dd17a..cbb0e79e6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -263,8 +263,8 @@ importers: specifier: 7.5.5 version: 7.5.5 threads: - specifier: 1.7.0 - version: 1.7.0 + specifier: git://github.com/akim-bow/threads.js.git#457fabf2393852980c35ca70ed73a2c0e96dc18a + version: github.com/akim-bow/threads.js/457fabf2393852980c35ca70ed73a2c0e96dc18a ts-pattern: specifier: 3.3.3 version: 3.3.3 @@ -324,8 +324,8 @@ importers: specifier: 0.6.1 version: 0.6.1 threads: - specifier: 1.7.0 - version: 1.7.0 + specifier: git://github.com/akim-bow/threads.js.git#457fabf2393852980c35ca70ed73a2c0e96dc18a + version: github.com/akim-bow/threads.js/457fabf2393852980c35ca70ed73a2c0e96dc18a devDependencies: '@rollup/plugin-inject': specifier: 5.0.3 @@ -18730,6 +18730,7 @@ packages: tiny-worker: 2.3.0 transitivePeerDependencies: - supports-color + dev: true /throat@6.0.2: resolution: {integrity: sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ==} @@ -20992,3 +20993,20 @@ packages: /zod@3.22.4: resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} dev: false + + github.com/akim-bow/threads.js/457fabf2393852980c35ca70ed73a2c0e96dc18a: + resolution: {tarball: https://codeload.github.com/akim-bow/threads.js/tar.gz/457fabf2393852980c35ca70ed73a2c0e96dc18a} + name: threads + version: 1.7.0 + prepare: true + requiresBuild: true + dependencies: + callsites: 3.1.0 + debug: 4.3.4(supports-color@8.1.1) + is-observable: 2.1.0 + observable-fns: 0.6.1 + optionalDependencies: + tiny-worker: 2.3.0 + transitivePeerDependencies: + - supports-color + dev: false From f0a449af3f4327b4cc146ed7aecb1d092cef5ab8 Mon Sep 17 00:00:00 2001 From: Akim Mamedov Date: Fri, 13 Oct 2023 22:15:06 +0700 Subject: [PATCH 37/45] Use fixed version --- packages/core/js-client/package.json | 2 +- packages/core/marine-worker/package.json | 2 +- pnpm-lock.yaml | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/core/js-client/package.json b/packages/core/js-client/package.json index 6dc1b54a3..de7647dbd 100644 --- a/packages/core/js-client/package.json +++ b/packages/core/js-client/package.json @@ -47,7 +47,7 @@ "libp2p": "0.46.6", "multiformats": "11.0.1", "rxjs": "7.5.5", - "threads": "git://github.com/akim-bow/threads.js.git#457fabf2393852980c35ca70ed73a2c0e96dc18a", + "threads": "fluencelabs/threads.js#5e61449d5e9ab290ae5b2220b561f7b5ac27816c", "ts-pattern": "3.3.3", "uint8arrays": "4.0.3", "uuid": "8.3.2", diff --git a/packages/core/marine-worker/package.json b/packages/core/marine-worker/package.json index 82da01c12..3f840f8ff 100644 --- a/packages/core/marine-worker/package.json +++ b/packages/core/marine-worker/package.json @@ -26,6 +26,6 @@ "dependencies": { "@fluencelabs/marine-js": "0.7.2", "observable-fns": "0.6.1", - "threads": "git://github.com/akim-bow/threads.js.git#457fabf2393852980c35ca70ed73a2c0e96dc18a" + "threads": "fluencelabs/threads.js#5e61449d5e9ab290ae5b2220b561f7b5ac27816c" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cbb0e79e6..776e6aa88 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -263,8 +263,8 @@ importers: specifier: 7.5.5 version: 7.5.5 threads: - specifier: git://github.com/akim-bow/threads.js.git#457fabf2393852980c35ca70ed73a2c0e96dc18a - version: github.com/akim-bow/threads.js/457fabf2393852980c35ca70ed73a2c0e96dc18a + specifier: fluencelabs/threads.js#5e61449d5e9ab290ae5b2220b561f7b5ac27816c + version: github.com/fluencelabs/threads.js/5e61449d5e9ab290ae5b2220b561f7b5ac27816c ts-pattern: specifier: 3.3.3 version: 3.3.3 @@ -324,8 +324,8 @@ importers: specifier: 0.6.1 version: 0.6.1 threads: - specifier: git://github.com/akim-bow/threads.js.git#457fabf2393852980c35ca70ed73a2c0e96dc18a - version: github.com/akim-bow/threads.js/457fabf2393852980c35ca70ed73a2c0e96dc18a + specifier: fluencelabs/threads.js#5e61449d5e9ab290ae5b2220b561f7b5ac27816c + version: github.com/fluencelabs/threads.js/5e61449d5e9ab290ae5b2220b561f7b5ac27816c devDependencies: '@rollup/plugin-inject': specifier: 5.0.3 @@ -20994,8 +20994,8 @@ packages: resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} dev: false - github.com/akim-bow/threads.js/457fabf2393852980c35ca70ed73a2c0e96dc18a: - resolution: {tarball: https://codeload.github.com/akim-bow/threads.js/tar.gz/457fabf2393852980c35ca70ed73a2c0e96dc18a} + github.com/fluencelabs/threads.js/5e61449d5e9ab290ae5b2220b561f7b5ac27816c: + resolution: {tarball: https://codeload.github.com/fluencelabs/threads.js/tar.gz/5e61449d5e9ab290ae5b2220b561f7b5ac27816c} name: threads version: 1.7.0 prepare: true From b74c54b9a5fadf615c124f8ab79d3778480f1af3 Mon Sep 17 00:00:00 2001 From: Akim Mamedov Date: Mon, 16 Oct 2023 17:37:28 +0700 Subject: [PATCH 38/45] Update threads --- packages/core/js-client/package.json | 2 +- packages/core/js-client/src/marine/worker/index.ts | 2 -- packages/core/marine-worker/package.json | 2 +- pnpm-lock.yaml | 12 ++++++------ 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/packages/core/js-client/package.json b/packages/core/js-client/package.json index 71b4b15f5..db7dcbff9 100644 --- a/packages/core/js-client/package.json +++ b/packages/core/js-client/package.json @@ -47,7 +47,7 @@ "libp2p": "0.46.6", "multiformats": "11.0.1", "rxjs": "7.5.5", - "threads": "fluencelabs/threads.js#5e61449d5e9ab290ae5b2220b561f7b5ac27816c", + "threads": "fluencelabs/threads.js#d7149e1e455c3dddd8be812cb234a4af172674a1", "ts-pattern": "3.3.3", "uint8arrays": "4.0.3", "uuid": "8.3.2", diff --git a/packages/core/js-client/src/marine/worker/index.ts b/packages/core/js-client/src/marine/worker/index.ts index 68dfdc7bb..21086b8ba 100644 --- a/packages/core/js-client/src/marine/worker/index.ts +++ b/packages/core/js-client/src/marine/worker/index.ts @@ -80,8 +80,6 @@ export class MarineBackgroundRunner implements IMarineHost { serviceLogger[message.level](message.message); }; - // @ts-expect-error This type is bugged - // eslint-disable-next-line @typescript-eslint/no-unsafe-call workerThread.onLogMessage().subscribe(logfn); await workerThread.init(wasm); this.workerThread = workerThread; diff --git a/packages/core/marine-worker/package.json b/packages/core/marine-worker/package.json index 3f840f8ff..49243215f 100644 --- a/packages/core/marine-worker/package.json +++ b/packages/core/marine-worker/package.json @@ -26,6 +26,6 @@ "dependencies": { "@fluencelabs/marine-js": "0.7.2", "observable-fns": "0.6.1", - "threads": "fluencelabs/threads.js#5e61449d5e9ab290ae5b2220b561f7b5ac27816c" + "threads": "fluencelabs/threads.js#d7149e1e455c3dddd8be812cb234a4af172674a1" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 776e6aa88..bba6735d4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -263,8 +263,8 @@ importers: specifier: 7.5.5 version: 7.5.5 threads: - specifier: fluencelabs/threads.js#5e61449d5e9ab290ae5b2220b561f7b5ac27816c - version: github.com/fluencelabs/threads.js/5e61449d5e9ab290ae5b2220b561f7b5ac27816c + specifier: fluencelabs/threads.js#d7149e1e455c3dddd8be812cb234a4af172674a1 + version: github.com/fluencelabs/threads.js/d7149e1e455c3dddd8be812cb234a4af172674a1 ts-pattern: specifier: 3.3.3 version: 3.3.3 @@ -324,8 +324,8 @@ importers: specifier: 0.6.1 version: 0.6.1 threads: - specifier: fluencelabs/threads.js#5e61449d5e9ab290ae5b2220b561f7b5ac27816c - version: github.com/fluencelabs/threads.js/5e61449d5e9ab290ae5b2220b561f7b5ac27816c + specifier: fluencelabs/threads.js#d7149e1e455c3dddd8be812cb234a4af172674a1 + version: github.com/fluencelabs/threads.js/d7149e1e455c3dddd8be812cb234a4af172674a1 devDependencies: '@rollup/plugin-inject': specifier: 5.0.3 @@ -20994,8 +20994,8 @@ packages: resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} dev: false - github.com/fluencelabs/threads.js/5e61449d5e9ab290ae5b2220b561f7b5ac27816c: - resolution: {tarball: https://codeload.github.com/fluencelabs/threads.js/tar.gz/5e61449d5e9ab290ae5b2220b561f7b5ac27816c} + github.com/fluencelabs/threads.js/d7149e1e455c3dddd8be812cb234a4af172674a1: + resolution: {tarball: https://codeload.github.com/fluencelabs/threads.js/tar.gz/d7149e1e455c3dddd8be812cb234a4af172674a1} name: threads version: 1.7.0 prepare: true From 2e1302a11269fe186908f78abfc4d655dd205937 Mon Sep 17 00:00:00 2001 From: Akim Mamedov Date: Mon, 16 Oct 2023 21:49:28 +0700 Subject: [PATCH 39/45] Fix lint --- packages/core/js-client/package.json | 2 +- packages/core/js-client/src/index.ts | 1 - packages/core/marine-worker/package.json | 2 +- pnpm-lock.yaml | 12 ++++++------ 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/packages/core/js-client/package.json b/packages/core/js-client/package.json index db7dcbff9..dbebb5e82 100644 --- a/packages/core/js-client/package.json +++ b/packages/core/js-client/package.json @@ -47,7 +47,7 @@ "libp2p": "0.46.6", "multiformats": "11.0.1", "rxjs": "7.5.5", - "threads": "fluencelabs/threads.js#d7149e1e455c3dddd8be812cb234a4af172674a1", + "threads": "fluencelabs/threads.js#b00a5342380b0278d3ae56dcfb170effb3cad7cd", "ts-pattern": "3.3.3", "uint8arrays": "4.0.3", "uuid": "8.3.2", diff --git a/packages/core/js-client/src/index.ts b/packages/core/js-client/src/index.ts index 8de583ed8..03afb97d5 100644 --- a/packages/core/js-client/src/index.ts +++ b/packages/core/js-client/src/index.ts @@ -24,7 +24,6 @@ import type { ConnectionState, RelayOptions, } from "@fluencelabs/interfaces"; -// "threads" package has broken type definitions in package.json. This is the workaround. import { BlobWorker, Worker } from "threads/master"; import { ClientPeer, makeClientPeerConfig } from "./clientPeer/ClientPeer.js"; diff --git a/packages/core/marine-worker/package.json b/packages/core/marine-worker/package.json index 49243215f..e5bcd714c 100644 --- a/packages/core/marine-worker/package.json +++ b/packages/core/marine-worker/package.json @@ -26,6 +26,6 @@ "dependencies": { "@fluencelabs/marine-js": "0.7.2", "observable-fns": "0.6.1", - "threads": "fluencelabs/threads.js#d7149e1e455c3dddd8be812cb234a4af172674a1" + "threads": "fluencelabs/threads.js#b00a5342380b0278d3ae56dcfb170effb3cad7cd" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bba6735d4..5291363f8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -263,8 +263,8 @@ importers: specifier: 7.5.5 version: 7.5.5 threads: - specifier: fluencelabs/threads.js#d7149e1e455c3dddd8be812cb234a4af172674a1 - version: github.com/fluencelabs/threads.js/d7149e1e455c3dddd8be812cb234a4af172674a1 + specifier: fluencelabs/threads.js#b00a5342380b0278d3ae56dcfb170effb3cad7cd + version: github.com/fluencelabs/threads.js/b00a5342380b0278d3ae56dcfb170effb3cad7cd ts-pattern: specifier: 3.3.3 version: 3.3.3 @@ -324,8 +324,8 @@ importers: specifier: 0.6.1 version: 0.6.1 threads: - specifier: fluencelabs/threads.js#d7149e1e455c3dddd8be812cb234a4af172674a1 - version: github.com/fluencelabs/threads.js/d7149e1e455c3dddd8be812cb234a4af172674a1 + specifier: fluencelabs/threads.js#b00a5342380b0278d3ae56dcfb170effb3cad7cd + version: github.com/fluencelabs/threads.js/b00a5342380b0278d3ae56dcfb170effb3cad7cd devDependencies: '@rollup/plugin-inject': specifier: 5.0.3 @@ -20994,8 +20994,8 @@ packages: resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} dev: false - github.com/fluencelabs/threads.js/d7149e1e455c3dddd8be812cb234a4af172674a1: - resolution: {tarball: https://codeload.github.com/fluencelabs/threads.js/tar.gz/d7149e1e455c3dddd8be812cb234a4af172674a1} + github.com/fluencelabs/threads.js/b00a5342380b0278d3ae56dcfb170effb3cad7cd: + resolution: {tarball: https://codeload.github.com/fluencelabs/threads.js/tar.gz/b00a5342380b0278d3ae56dcfb170effb3cad7cd} name: threads version: 1.7.0 prepare: true From 2157bcc7443d302c31dd42adefbb9e4853e0d180 Mon Sep 17 00:00:00 2001 From: Akim Mamedov Date: Mon, 16 Oct 2023 22:02:07 +0700 Subject: [PATCH 40/45] Fix test --- packages/core/js-client/src/fetchers/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/js-client/src/fetchers/index.ts b/packages/core/js-client/src/fetchers/index.ts index b0c45fb72..030736cbb 100644 --- a/packages/core/js-client/src/fetchers/index.ts +++ b/packages/core/js-client/src/fetchers/index.ts @@ -20,7 +20,7 @@ import { fetchResource as fetchResourceBrowser } from "./browser.js"; import { fetchResource as fetchResourceNode } from "./node.js"; const isNode = - typeof process !== "undefined" && process.release.name === "node"; + typeof process !== "undefined" && process.release?.name === "node"; export async function fetchResource(pkg: string, path: string) { switch (true) { From 49717901519e049e0b0db113d8fffc5c491cdabd Mon Sep 17 00:00:00 2001 From: Akim Mamedov Date: Mon, 16 Oct 2023 23:19:30 +0700 Subject: [PATCH 41/45] Fix test --- packages/core/js-client/src/fetchers/index.ts | 2 ++ packages/core/js-client/tsconfig.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/core/js-client/src/fetchers/index.ts b/packages/core/js-client/src/fetchers/index.ts index 030736cbb..e2f1df0b5 100644 --- a/packages/core/js-client/src/fetchers/index.ts +++ b/packages/core/js-client/src/fetchers/index.ts @@ -20,6 +20,8 @@ import { fetchResource as fetchResourceBrowser } from "./browser.js"; import { fetchResource as fetchResourceNode } from "./node.js"; const isNode = + // process.release is undefined in browser env + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition typeof process !== "undefined" && process.release?.name === "node"; export async function fetchResource(pkg: string, path: string) { diff --git a/packages/core/js-client/tsconfig.json b/packages/core/js-client/tsconfig.json index d2b4fef30..3e9c2cfc8 100644 --- a/packages/core/js-client/tsconfig.json +++ b/packages/core/js-client/tsconfig.json @@ -1,7 +1,7 @@ { "extends": "../../../tsconfig.json", "compilerOptions": { - "types": ["vite/client", "node"], + "types": ["vite/client"], "outDir": "./dist", "esModuleInterop": true, "resolveJsonModule": true From 0b888f228954e6deddd6edd5497882eed4c2610d Mon Sep 17 00:00:00 2001 From: Akim Mamedov Date: Mon, 16 Oct 2023 23:42:54 +0700 Subject: [PATCH 42/45] Add polyfill for assert --- packages/core/js-client/package.json | 1 + packages/core/js-client/src/index.ts | 4 ++- pnpm-lock.yaml | 53 +++++++++++----------------- 3 files changed, 24 insertions(+), 34 deletions(-) diff --git a/packages/core/js-client/package.json b/packages/core/js-client/package.json index dbebb5e82..1218554e1 100644 --- a/packages/core/js-client/package.json +++ b/packages/core/js-client/package.json @@ -36,6 +36,7 @@ "@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", diff --git a/packages/core/js-client/src/index.ts b/packages/core/js-client/src/index.ts index 03afb97d5..a3470e095 100644 --- a/packages/core/js-client/src/index.ts +++ b/packages/core/js-client/src/index.ts @@ -34,7 +34,9 @@ import { MarineBackgroundRunner } from "./marine/worker/index.js"; import { doRegisterNodeUtils } from "./services/NodeUtils.js"; const isNode = - typeof process !== "undefined" && process.release.name === "node"; + // process.release is undefined in browser env + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + typeof process !== "undefined" && process.release?.name === "node"; const fetchWorkerCode = async () => { const resource = await fetchResource( diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5291363f8..095c5f25c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -229,6 +229,9 @@ 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 @@ -7599,6 +7602,16 @@ 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 @@ -9573,7 +9586,7 @@ packages: side-channel: 1.0.4 which-boxed-primitive: 1.0.2 which-collection: 1.0.1 - which-typed-array: 1.1.9 + which-typed-array: 1.1.11 dev: false /deep-extend@0.6.0: @@ -10057,7 +10070,7 @@ packages: is-regex: 1.1.4 is-shared-array-buffer: 1.0.2 is-string: 1.0.7 - is-typed-array: 1.1.10 + is-typed-array: 1.1.12 is-weakref: 1.0.2 object-inspect: 1.12.3 object-keys: 1.1.1 @@ -10069,7 +10082,7 @@ packages: string.prototype.trimstart: 1.0.6 typed-array-length: 1.0.4 unbox-primitive: 1.0.2 - which-typed-array: 1.1.9 + which-typed-array: 1.1.11 /es-abstract@1.22.2: resolution: {integrity: sha512-YoxfFcDmhjOgWPWsV13+2RNjq1F6UQnfs+8TftwNqtzlmFzEXvlUwdrNrYeaizfjQzRMxkZ6ElWMOJIFKdVqwA==} @@ -12616,7 +12629,7 @@ packages: dependencies: call-bind: 1.0.2 get-intrinsic: 1.2.1 - is-typed-array: 1.1.10 + is-typed-array: 1.1.12 /is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} @@ -12699,7 +12712,6 @@ packages: engines: {node: '>= 0.4'} dependencies: has-tostringtag: 1.0.0 - dev: true /is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} @@ -12734,7 +12746,6 @@ packages: dependencies: call-bind: 1.0.2 define-properties: 1.2.0 - dev: true /is-natural-number@4.0.1: resolution: {integrity: sha512-Y4LTamMe0DDQIIAlaer9eKebAlDSV6huy+TWhJVPlzZh2o4tRP5SQWFlLn5N0To4mDD22/qdOq+veo1cSISLgQ==} @@ -12836,22 +12847,11 @@ packages: dependencies: has-symbols: 1.0.3 - /is-typed-array@1.1.10: - resolution: {integrity: sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==} - engines: {node: '>= 0.4'} - dependencies: - available-typed-arrays: 1.0.5 - call-bind: 1.0.2 - for-each: 0.3.3 - gopd: 1.0.1 - has-tostringtag: 1.0.0 - /is-typed-array@1.1.12: resolution: {integrity: sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==} engines: {node: '>= 0.4'} dependencies: which-typed-array: 1.1.11 - dev: true /is-typedarray@1.0.0: resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} @@ -19130,7 +19130,7 @@ packages: dependencies: call-bind: 1.0.2 for-each: 0.3.3 - is-typed-array: 1.1.10 + is-typed-array: 1.1.12 /typedarray-to-buffer@3.1.5: resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} @@ -19384,9 +19384,8 @@ packages: inherits: 2.0.4 is-arguments: 1.1.1 is-generator-function: 1.0.10 - is-typed-array: 1.1.10 - which-typed-array: 1.1.9 - dev: true + is-typed-array: 1.1.12 + which-typed-array: 1.1.11 /utila@0.4.0: resolution: {integrity: sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==} @@ -20461,18 +20460,6 @@ packages: for-each: 0.3.3 gopd: 1.0.1 has-tostringtag: 1.0.0 - dev: true - - /which-typed-array@1.1.9: - resolution: {integrity: sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==} - engines: {node: '>= 0.4'} - dependencies: - available-typed-arrays: 1.0.5 - call-bind: 1.0.2 - for-each: 0.3.3 - gopd: 1.0.1 - has-tostringtag: 1.0.0 - is-typed-array: 1.1.10 /which@1.3.1: resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} From 381d20c80df316b867a7f0be9d2c6f80531b11c5 Mon Sep 17 00:00:00 2001 From: Akim Mamedov Date: Mon, 16 Oct 2023 23:58:54 +0700 Subject: [PATCH 43/45] Add subpath import --- packages/@tests/smoke/web/public/index.js | 125 +++---- packages/core/js-client/package.json | 8 +- packages/core/js-client/src/fetchers/index.ts | 7 +- packages/core/js-client/tsconfig.json | 3 +- packages/core/marine-worker/package.json | 2 +- pnpm-lock.yaml | 317 +++++++++++++++++- 6 files changed, 377 insertions(+), 85 deletions(-) diff --git a/packages/@tests/smoke/web/public/index.js b/packages/@tests/smoke/web/public/index.js index 108155f4d..31228be60 100644 --- a/packages/@tests/smoke/web/public/index.js +++ b/packages/@tests/smoke/web/public/index.js @@ -1,12 +1,13 @@ const fluence = globalThis.fluence; const relay = { - multiaddr: '/ip4/127.0.0.1/tcp/9991/ws/p2p/12D3KooWBM3SdXWqGaawQDGQ6JprtwswEg3FWGvGhmgmMez1vRbR', - peerId: '12D3KooWBM3SdXWqGaawQDGQ6JprtwswEg3FWGvGhmgmMez1vRbR', + multiaddr: + "/ip4/127.0.0.1/tcp/9991/ws/p2p/12D3KooWBM3SdXWqGaawQDGQ6JprtwswEg3FWGvGhmgmMez1vRbR", + peerId: "12D3KooWBM3SdXWqGaawQDGQ6JprtwswEg3FWGvGhmgmMez1vRbR", }; const getRelayTime = () => { - const script = ` + const script = ` (xor (seq (seq @@ -36,75 +37,75 @@ const getRelayTime = () => { (call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 3]) )`; - const def = { - functionName: 'getRelayTime', - arrow: { - tag: 'arrow', - domain: { - tag: 'labeledProduct', - fields: { - relayPeerId: { - tag: 'scalar', - name: 'string', - }, - }, - }, - codomain: { - tag: 'unlabeledProduct', - items: [ - { - tag: 'scalar', - name: 'u64', - }, - ], - }, + const def = { + functionName: "getRelayTime", + arrow: { + tag: "arrow", + domain: { + tag: "labeledProduct", + fields: { + relayPeerId: { + tag: "scalar", + name: "string", + }, }, - names: { - relay: '-relay-', - getDataSrv: 'getDataSrv', - callbackSrv: 'callbackSrv', - responseSrv: 'callbackSrv', - responseFnName: 'response', - errorHandlingSrv: 'errorHandlingSrv', - errorFnName: 'error', - }, - }; + }, + codomain: { + tag: "unlabeledProduct", + items: [ + { + tag: "scalar", + name: "u64", + }, + ], + }, + }, + names: { + relay: "-relay-", + getDataSrv: "getDataSrv", + callbackSrv: "callbackSrv", + responseSrv: "callbackSrv", + responseFnName: "response", + errorHandlingSrv: "errorHandlingSrv", + errorFnName: "error", + }, + }; - const config = {}; + const config = {}; - const args = { relayPeerId: relay.peerId }; - return fluence.callAquaFunction({ - args, - def, - script, - config, - peer: fluence.defaultClient, - }); + const args = { relayPeerId: relay.peerId }; + return fluence.callAquaFunction({ + args, + def, + script, + config, + peer: fluence.defaultClient, + }); }; const main = async () => { - console.log('starting fluence...'); - fluence.defaultClient = await fluence.clientFactory(relay); - console.log('started fluence'); + console.log("starting fluence..."); + fluence.defaultClient = await fluence.clientFactory(relay, {}); + console.log("started fluence"); - console.log('getting relay time...'); - const relayTime = await getRelayTime(); - console.log('got relay time, ', relayTime); + console.log("getting relay time..."); + const relayTime = await getRelayTime(); + console.log("got relay time, ", relayTime); - console.log('stopping fluence...'); - await fluence.defaultClient.stop(); - console.log('stopped fluence...'); + console.log("stopping fluence..."); + await fluence.defaultClient.stop(); + console.log("stopped fluence..."); - return relayTime; + return relayTime; }; -const btn = document.getElementById('btn'); +const btn = document.getElementById("btn"); -btn.addEventListener('click', () => { - main().then((res) => { - const inner = document.createElement('div'); - inner.id = 'res'; - inner.innerText = res; - document.getElementById('res-placeholder').appendChild(inner); - }); +btn.addEventListener("click", () => { + main().then((res) => { + const inner = document.createElement("div"); + inner.id = "res"; + inner.innerText = res; + document.getElementById("res-placeholder").appendChild(inner); + }); }); diff --git a/packages/core/js-client/package.json b/packages/core/js-client/package.json index 1218554e1..a72b3dcc9 100644 --- a/packages/core/js-client/package.json +++ b/packages/core/js-client/package.json @@ -17,6 +17,12 @@ "node": "./dist/index.js", "default": "./dist/browser/index.js" }, + "imports": { + "#fetcher": { + "node": "./dist/fetchers/node.js", + "default": "./dist/fetchers/browser.js" + } + }, "type": "module", "scripts": { "build": "tsc && vite build", @@ -64,7 +70,7 @@ "@types/node": "20.7.0", "@types/uuid": "8.3.2", "hotscript": "1.0.13", - "vite": "4.0.4", + "vite": "4.4.11", "vite-tsconfig-paths": "4.0.3", "vitest": "0.29.7" } diff --git a/packages/core/js-client/src/fetchers/index.ts b/packages/core/js-client/src/fetchers/index.ts index e2f1df0b5..152bc7920 100644 --- a/packages/core/js-client/src/fetchers/index.ts +++ b/packages/core/js-client/src/fetchers/index.ts @@ -16,8 +16,7 @@ import process from "process"; -import { fetchResource as fetchResourceBrowser } from "./browser.js"; -import { fetchResource as fetchResourceNode } from "./node.js"; +import { fetchResource as fetchResourceIsomorphic } from "#fetcher"; const isNode = // process.release is undefined in browser env @@ -27,8 +26,8 @@ const isNode = export async function fetchResource(pkg: string, path: string) { switch (true) { case isNode: - return fetchResourceNode(pkg, path); + return fetchResourceIsomorphic(pkg, path); default: - return fetchResourceBrowser(pkg, path); + return fetchResourceIsomorphic(pkg, path); } } diff --git a/packages/core/js-client/tsconfig.json b/packages/core/js-client/tsconfig.json index 3e9c2cfc8..70f838c90 100644 --- a/packages/core/js-client/tsconfig.json +++ b/packages/core/js-client/tsconfig.json @@ -4,7 +4,8 @@ "types": ["vite/client"], "outDir": "./dist", "esModuleInterop": true, - "resolveJsonModule": true + "resolveJsonModule": true, + "rootDir": "src" }, "include": ["src/**/*"], "exclude": ["node_modules", "dist"] diff --git a/packages/core/marine-worker/package.json b/packages/core/marine-worker/package.json index e5bcd714c..d8420e9d6 100644 --- a/packages/core/marine-worker/package.json +++ b/packages/core/marine-worker/package.json @@ -20,7 +20,7 @@ "@rollup/plugin-inject": "5.0.3", "@types/node": "20.4.5", "node-stdlib-browser": "1.2.0", - "vite": "4.0.4", + "vite": "4.4.11", "vitest": "0.29.7" }, "dependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 095c5f25c..5d9d13dd1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -309,11 +309,11 @@ importers: specifier: 1.0.13 version: 1.0.13 vite: - specifier: 4.0.4 - version: 4.0.4(@types/node@20.7.0) + specifier: 4.4.11 + version: 4.4.11(@types/node@20.7.0) vite-tsconfig-paths: specifier: 4.0.3 - version: 4.0.3(typescript@5.1.6)(vite@4.0.4) + version: 4.0.3(typescript@5.1.6)(vite@4.4.11) vitest: specifier: 0.29.7 version: 0.29.7 @@ -340,8 +340,8 @@ importers: specifier: 1.2.0 version: 1.2.0 vite: - specifier: 4.0.4 - version: 4.0.4(@types/node@20.4.5) + specifier: 4.4.11 + version: 4.4.11(@types/node@20.4.5) vitest: specifier: 0.29.7 version: 0.29.7 @@ -3262,6 +3262,15 @@ packages: dev: true optional: true + /@esbuild/android-arm64@0.18.20: + resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + /@esbuild/android-arm@0.16.17: resolution: {integrity: sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw==} engines: {node: '>=12'} @@ -3271,6 +3280,15 @@ packages: dev: true optional: true + /@esbuild/android-arm@0.18.20: + resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + /@esbuild/android-x64@0.16.17: resolution: {integrity: sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==} engines: {node: '>=12'} @@ -3280,6 +3298,15 @@ packages: dev: true optional: true + /@esbuild/android-x64@0.18.20: + resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + /@esbuild/darwin-arm64@0.16.17: resolution: {integrity: sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==} engines: {node: '>=12'} @@ -3289,6 +3316,15 @@ packages: dev: true optional: true + /@esbuild/darwin-arm64@0.18.20: + resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + /@esbuild/darwin-x64@0.16.17: resolution: {integrity: sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==} engines: {node: '>=12'} @@ -3298,6 +3334,15 @@ packages: dev: true optional: true + /@esbuild/darwin-x64@0.18.20: + resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + /@esbuild/freebsd-arm64@0.16.17: resolution: {integrity: sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==} engines: {node: '>=12'} @@ -3307,6 +3352,15 @@ packages: dev: true optional: true + /@esbuild/freebsd-arm64@0.18.20: + resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/freebsd-x64@0.16.17: resolution: {integrity: sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==} engines: {node: '>=12'} @@ -3316,6 +3370,15 @@ packages: dev: true optional: true + /@esbuild/freebsd-x64@0.18.20: + resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-arm64@0.16.17: resolution: {integrity: sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==} engines: {node: '>=12'} @@ -3325,6 +3388,15 @@ packages: dev: true optional: true + /@esbuild/linux-arm64@0.18.20: + resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-arm@0.16.17: resolution: {integrity: sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==} engines: {node: '>=12'} @@ -3334,6 +3406,15 @@ packages: dev: true optional: true + /@esbuild/linux-arm@0.18.20: + resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-ia32@0.16.17: resolution: {integrity: sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==} engines: {node: '>=12'} @@ -3343,6 +3424,15 @@ packages: dev: true optional: true + /@esbuild/linux-ia32@0.18.20: + resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-loong64@0.16.17: resolution: {integrity: sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ==} engines: {node: '>=12'} @@ -3352,6 +3442,15 @@ packages: dev: true optional: true + /@esbuild/linux-loong64@0.18.20: + resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-mips64el@0.16.17: resolution: {integrity: sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==} engines: {node: '>=12'} @@ -3361,6 +3460,15 @@ packages: dev: true optional: true + /@esbuild/linux-mips64el@0.18.20: + resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-ppc64@0.16.17: resolution: {integrity: sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==} engines: {node: '>=12'} @@ -3370,6 +3478,15 @@ packages: dev: true optional: true + /@esbuild/linux-ppc64@0.18.20: + resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-riscv64@0.16.17: resolution: {integrity: sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==} engines: {node: '>=12'} @@ -3379,6 +3496,15 @@ packages: dev: true optional: true + /@esbuild/linux-riscv64@0.18.20: + resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-s390x@0.16.17: resolution: {integrity: sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==} engines: {node: '>=12'} @@ -3388,6 +3514,15 @@ packages: dev: true optional: true + /@esbuild/linux-s390x@0.18.20: + resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-x64@0.16.17: resolution: {integrity: sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw==} engines: {node: '>=12'} @@ -3397,6 +3532,15 @@ packages: dev: true optional: true + /@esbuild/linux-x64@0.18.20: + resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/netbsd-x64@0.16.17: resolution: {integrity: sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==} engines: {node: '>=12'} @@ -3406,6 +3550,15 @@ packages: dev: true optional: true + /@esbuild/netbsd-x64@0.18.20: + resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/openbsd-x64@0.16.17: resolution: {integrity: sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==} engines: {node: '>=12'} @@ -3415,6 +3568,15 @@ packages: dev: true optional: true + /@esbuild/openbsd-x64@0.18.20: + resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/sunos-x64@0.16.17: resolution: {integrity: sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==} engines: {node: '>=12'} @@ -3424,6 +3586,15 @@ packages: dev: true optional: true + /@esbuild/sunos-x64@0.18.20: + resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + /@esbuild/win32-arm64@0.16.17: resolution: {integrity: sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==} engines: {node: '>=12'} @@ -3433,6 +3604,15 @@ packages: dev: true optional: true + /@esbuild/win32-arm64@0.18.20: + resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@esbuild/win32-ia32@0.16.17: resolution: {integrity: sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==} engines: {node: '>=12'} @@ -3442,6 +3622,15 @@ packages: dev: true optional: true + /@esbuild/win32-ia32@0.18.20: + resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@esbuild/win32-x64@0.16.17: resolution: {integrity: sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==} engines: {node: '>=12'} @@ -3451,6 +3640,15 @@ packages: dev: true optional: true + /@esbuild/win32-x64@0.18.20: + resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@eslint-community/eslint-utils@4.4.0(eslint@8.50.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -10234,6 +10432,36 @@ packages: '@esbuild/win32-x64': 0.16.17 dev: true + /esbuild@0.18.20: + resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.18.20 + '@esbuild/android-arm64': 0.18.20 + '@esbuild/android-x64': 0.18.20 + '@esbuild/darwin-arm64': 0.18.20 + '@esbuild/darwin-x64': 0.18.20 + '@esbuild/freebsd-arm64': 0.18.20 + '@esbuild/freebsd-x64': 0.18.20 + '@esbuild/linux-arm': 0.18.20 + '@esbuild/linux-arm64': 0.18.20 + '@esbuild/linux-ia32': 0.18.20 + '@esbuild/linux-loong64': 0.18.20 + '@esbuild/linux-mips64el': 0.18.20 + '@esbuild/linux-ppc64': 0.18.20 + '@esbuild/linux-riscv64': 0.18.20 + '@esbuild/linux-s390x': 0.18.20 + '@esbuild/linux-x64': 0.18.20 + '@esbuild/netbsd-x64': 0.18.20 + '@esbuild/openbsd-x64': 0.18.20 + '@esbuild/sunos-x64': 0.18.20 + '@esbuild/win32-arm64': 0.18.20 + '@esbuild/win32-ia32': 0.18.20 + '@esbuild/win32-x64': 0.18.20 + dev: true + /escalade@3.1.1: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} engines: {node: '>=6'} @@ -16449,6 +16677,15 @@ packages: picocolors: 1.0.0 source-map-js: 1.0.2 + /postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.6 + picocolors: 1.0.0 + source-map-js: 1.0.2 + dev: true + /prelude-ls@1.1.2: resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==} engines: {node: '>= 0.8.0'} @@ -17391,6 +17628,14 @@ packages: fsevents: 2.3.3 dev: true + /rollup@3.29.4: + resolution: {integrity: sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==} + engines: {node: '>=14.18.0', npm: '>=8.0.0'} + hasBin: true + optionalDependencies: + fsevents: 2.3.3 + dev: true + /run-async@2.4.1: resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==} engines: {node: '>=0.12.0'} @@ -19463,10 +19708,11 @@ packages: mlly: 1.3.0 pathe: 1.1.1 picocolors: 1.0.0 - vite: 4.0.4(@types/node@20.7.0) + vite: 4.4.11(@types/node@20.7.0) transitivePeerDependencies: - '@types/node' - less + - lightningcss - sass - stylus - sugarss @@ -19474,7 +19720,7 @@ packages: - terser dev: true - /vite-tsconfig-paths@4.0.3(typescript@5.1.6)(vite@4.0.4): + /vite-tsconfig-paths@4.0.3(typescript@5.1.6)(vite@4.4.11): resolution: {integrity: sha512-gRO2Q/tOkV+9kMht5tz90+IaEKvW2zCnvwJV3tp2ruPNZOTM5rF+yXorJT4ggmAMYEaJ3nyXjx5P5jY5FwiZ+A==} peerDependencies: vite: '>2.0.0-0' @@ -19482,13 +19728,13 @@ packages: debug: 4.3.4(supports-color@8.1.1) globrex: 0.1.2 tsconfck: 2.1.1(typescript@5.1.6) - vite: 4.0.4(@types/node@20.7.0) + vite: 4.4.11(@types/node@20.7.0) transitivePeerDependencies: - supports-color - typescript dev: true - /vite@4.0.4(@types/node@20.4.5): + /vite@4.0.4(@types/node@20.7.0): resolution: {integrity: sha512-xevPU7M8FU0i/80DMR+YhgrzR5KS2ORy1B4xcX/cXLsvnUWvfHuqMmVU6N0YiJ4JWGRJJsLCgjEzKjG9/GKoSw==} engines: {node: ^14.18.0 || >=16.0.0} hasBin: true @@ -19513,7 +19759,7 @@ packages: terser: optional: true dependencies: - '@types/node': 20.4.5 + '@types/node': 20.7.0 esbuild: 0.16.17 postcss: 8.4.24 resolve: 1.22.4 @@ -19522,13 +19768,14 @@ packages: fsevents: 2.3.3 dev: true - /vite@4.0.4(@types/node@20.7.0): - resolution: {integrity: sha512-xevPU7M8FU0i/80DMR+YhgrzR5KS2ORy1B4xcX/cXLsvnUWvfHuqMmVU6N0YiJ4JWGRJJsLCgjEzKjG9/GKoSw==} + /vite@4.4.11(@types/node@20.4.5): + resolution: {integrity: sha512-ksNZJlkcU9b0lBwAGZGGaZHCMqHsc8OpgtoYhsQ4/I2v5cnpmmmqe5pM4nv/4Hn6G/2GhTdj0DhZh2e+Er1q5A==} engines: {node: ^14.18.0 || >=16.0.0} hasBin: true peerDependencies: '@types/node': '>= 14' less: '*' + lightningcss: ^1.21.0 sass: '*' stylus: '*' sugarss: '*' @@ -19538,6 +19785,44 @@ packages: optional: true less: optional: true + lightningcss: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + dependencies: + '@types/node': 20.4.5 + esbuild: 0.18.20 + postcss: 8.4.31 + rollup: 3.29.4 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /vite@4.4.11(@types/node@20.7.0): + resolution: {integrity: sha512-ksNZJlkcU9b0lBwAGZGGaZHCMqHsc8OpgtoYhsQ4/I2v5cnpmmmqe5pM4nv/4Hn6G/2GhTdj0DhZh2e+Er1q5A==} + engines: {node: ^14.18.0 || >=16.0.0} + hasBin: true + peerDependencies: + '@types/node': '>= 14' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true sass: optional: true stylus: @@ -19548,10 +19833,9 @@ packages: optional: true dependencies: '@types/node': 20.7.0 - esbuild: 0.16.17 - postcss: 8.4.24 - resolve: 1.22.4 - rollup: 3.25.1 + esbuild: 0.18.20 + postcss: 8.4.31 + rollup: 3.29.4 optionalDependencies: fsevents: 2.3.3 dev: true @@ -19610,6 +19894,7 @@ packages: why-is-node-running: 2.2.2 transitivePeerDependencies: - less + - lightningcss - sass - stylus - sugarss From 61a663259cb3923eef19384171d2992d453ada1e Mon Sep 17 00:00:00 2001 From: Akim Mamedov Date: Tue, 17 Oct 2023 00:27:17 +0700 Subject: [PATCH 44/45] Fix tests --- packages/core/aqua-to-js/package.json | 2 +- packages/core/js-client/package.json | 2 +- packages/core/marine-worker/package.json | 2 +- pnpm-lock.yaml | 507 ++++++----------------- 4 files changed, 126 insertions(+), 387 deletions(-) diff --git a/packages/core/aqua-to-js/package.json b/packages/core/aqua-to-js/package.json index 3b88d948e..211d474c2 100644 --- a/packages/core/aqua-to-js/package.json +++ b/packages/core/aqua-to-js/package.json @@ -25,6 +25,6 @@ "@fluencelabs/registry": "0.8.7", "@fluencelabs/spell": "0.5.20", "@fluencelabs/trust-graph": "0.4.7", - "vitest": "0.29.7" + "vitest": "0.34.6" } } diff --git a/packages/core/js-client/package.json b/packages/core/js-client/package.json index a72b3dcc9..54f6c88a0 100644 --- a/packages/core/js-client/package.json +++ b/packages/core/js-client/package.json @@ -72,6 +72,6 @@ "hotscript": "1.0.13", "vite": "4.4.11", "vite-tsconfig-paths": "4.0.3", - "vitest": "0.29.7" + "vitest": "0.34.6" } } diff --git a/packages/core/marine-worker/package.json b/packages/core/marine-worker/package.json index d8420e9d6..d69ffa08d 100644 --- a/packages/core/marine-worker/package.json +++ b/packages/core/marine-worker/package.json @@ -21,7 +21,7 @@ "@types/node": "20.4.5", "node-stdlib-browser": "1.2.0", "vite": "4.4.11", - "vitest": "0.29.7" + "vitest": "0.34.6" }, "dependencies": { "@fluencelabs/marine-js": "0.7.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5d9d13dd1..8e8c478dd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -65,7 +65,7 @@ importers: version: 0.6.0 '@fluencelabs/cli': specifier: 0.7.2 - version: 0.7.2(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@nomicfoundation/hardhat-chai-matchers@1.0.6)(@nomicfoundation/hardhat-network-helpers@1.0.8)(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(@typechain/ethers-v5@10.2.1)(@typechain/hardhat@6.1.6)(@types/chai@4.3.5)(@types/mocha@9.1.1)(@types/node@20.7.0)(chai@4.3.7)(hardhat-gas-reporter@1.0.9)(hardhat@2.15.0)(solidity-coverage@0.7.22)(ts-node@10.9.1)(typechain@8.2.0)(typescript@5.1.6) + version: 0.7.2(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@nomicfoundation/hardhat-chai-matchers@1.0.6)(@nomicfoundation/hardhat-network-helpers@1.0.8)(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(@typechain/ethers-v5@10.2.1)(@typechain/hardhat@6.1.6)(@types/chai@4.3.5)(@types/mocha@9.1.1)(@types/node@20.7.0)(chai@4.3.10)(hardhat-gas-reporter@1.0.9)(hardhat@2.15.0)(solidity-coverage@0.7.22)(ts-node@10.9.1)(typechain@8.2.0)(typescript@5.1.6) '@fluencelabs/js-client': specifier: workspace:^ version: link:../../core/js-client @@ -182,8 +182,8 @@ importers: specifier: 0.4.7 version: 0.4.7 vitest: - specifier: 0.29.7 - version: 0.29.7 + specifier: 0.34.6 + version: 0.34.6 packages/core/interfaces: devDependencies: @@ -315,8 +315,8 @@ importers: specifier: 4.0.3 version: 4.0.3(typescript@5.1.6)(vite@4.4.11) vitest: - specifier: 0.29.7 - version: 0.29.7 + specifier: 0.34.6 + version: 0.34.6 packages/core/marine-worker: dependencies: @@ -343,8 +343,8 @@ importers: specifier: 4.4.11 version: 4.4.11(@types/node@20.4.5) vitest: - specifier: 0.29.7 - version: 0.29.7 + specifier: 0.34.6 + version: 0.34.6 packages: @@ -3253,15 +3253,6 @@ packages: postcss-selector-parser: 6.0.13 dev: false - /@esbuild/android-arm64@0.16.17: - resolution: {integrity: sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - requiresBuild: true - dev: true - optional: true - /@esbuild/android-arm64@0.18.20: resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} engines: {node: '>=12'} @@ -3271,15 +3262,6 @@ packages: dev: true optional: true - /@esbuild/android-arm@0.16.17: - resolution: {integrity: sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw==} - engines: {node: '>=12'} - cpu: [arm] - os: [android] - requiresBuild: true - dev: true - optional: true - /@esbuild/android-arm@0.18.20: resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} engines: {node: '>=12'} @@ -3289,15 +3271,6 @@ packages: dev: true optional: true - /@esbuild/android-x64@0.16.17: - resolution: {integrity: sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - requiresBuild: true - dev: true - optional: true - /@esbuild/android-x64@0.18.20: resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} engines: {node: '>=12'} @@ -3307,15 +3280,6 @@ packages: dev: true optional: true - /@esbuild/darwin-arm64@0.16.17: - resolution: {integrity: sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - /@esbuild/darwin-arm64@0.18.20: resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} engines: {node: '>=12'} @@ -3325,15 +3289,6 @@ packages: dev: true optional: true - /@esbuild/darwin-x64@0.16.17: - resolution: {integrity: sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - /@esbuild/darwin-x64@0.18.20: resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} engines: {node: '>=12'} @@ -3343,15 +3298,6 @@ packages: dev: true optional: true - /@esbuild/freebsd-arm64@0.16.17: - resolution: {integrity: sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - /@esbuild/freebsd-arm64@0.18.20: resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} engines: {node: '>=12'} @@ -3361,15 +3307,6 @@ packages: dev: true optional: true - /@esbuild/freebsd-x64@0.16.17: - resolution: {integrity: sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - /@esbuild/freebsd-x64@0.18.20: resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} engines: {node: '>=12'} @@ -3379,15 +3316,6 @@ packages: dev: true optional: true - /@esbuild/linux-arm64@0.16.17: - resolution: {integrity: sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-arm64@0.18.20: resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} engines: {node: '>=12'} @@ -3397,15 +3325,6 @@ packages: dev: true optional: true - /@esbuild/linux-arm@0.16.17: - resolution: {integrity: sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-arm@0.18.20: resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} engines: {node: '>=12'} @@ -3415,15 +3334,6 @@ packages: dev: true optional: true - /@esbuild/linux-ia32@0.16.17: - resolution: {integrity: sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-ia32@0.18.20: resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} engines: {node: '>=12'} @@ -3433,15 +3343,6 @@ packages: dev: true optional: true - /@esbuild/linux-loong64@0.16.17: - resolution: {integrity: sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ==} - engines: {node: '>=12'} - cpu: [loong64] - os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-loong64@0.18.20: resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} engines: {node: '>=12'} @@ -3451,15 +3352,6 @@ packages: dev: true optional: true - /@esbuild/linux-mips64el@0.16.17: - resolution: {integrity: sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-mips64el@0.18.20: resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} engines: {node: '>=12'} @@ -3469,15 +3361,6 @@ packages: dev: true optional: true - /@esbuild/linux-ppc64@0.16.17: - resolution: {integrity: sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-ppc64@0.18.20: resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} engines: {node: '>=12'} @@ -3487,15 +3370,6 @@ packages: dev: true optional: true - /@esbuild/linux-riscv64@0.16.17: - resolution: {integrity: sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-riscv64@0.18.20: resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} engines: {node: '>=12'} @@ -3505,15 +3379,6 @@ packages: dev: true optional: true - /@esbuild/linux-s390x@0.16.17: - resolution: {integrity: sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-s390x@0.18.20: resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} engines: {node: '>=12'} @@ -3523,15 +3388,6 @@ packages: dev: true optional: true - /@esbuild/linux-x64@0.16.17: - resolution: {integrity: sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-x64@0.18.20: resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} engines: {node: '>=12'} @@ -3541,15 +3397,6 @@ packages: dev: true optional: true - /@esbuild/netbsd-x64@0.16.17: - resolution: {integrity: sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - requiresBuild: true - dev: true - optional: true - /@esbuild/netbsd-x64@0.18.20: resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} engines: {node: '>=12'} @@ -3559,15 +3406,6 @@ packages: dev: true optional: true - /@esbuild/openbsd-x64@0.16.17: - resolution: {integrity: sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - requiresBuild: true - dev: true - optional: true - /@esbuild/openbsd-x64@0.18.20: resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} engines: {node: '>=12'} @@ -3577,15 +3415,6 @@ packages: dev: true optional: true - /@esbuild/sunos-x64@0.16.17: - resolution: {integrity: sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - requiresBuild: true - dev: true - optional: true - /@esbuild/sunos-x64@0.18.20: resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} engines: {node: '>=12'} @@ -3595,15 +3424,6 @@ packages: dev: true optional: true - /@esbuild/win32-arm64@0.16.17: - resolution: {integrity: sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true - optional: true - /@esbuild/win32-arm64@0.18.20: resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} engines: {node: '>=12'} @@ -3613,15 +3433,6 @@ packages: dev: true optional: true - /@esbuild/win32-ia32@0.16.17: - resolution: {integrity: sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true - optional: true - /@esbuild/win32-ia32@0.18.20: resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} engines: {node: '>=12'} @@ -3631,15 +3442,6 @@ packages: dev: true optional: true - /@esbuild/win32-x64@0.16.17: - resolution: {integrity: sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true - /@esbuild/win32-x64@0.18.20: resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} engines: {node: '>=12'} @@ -4061,14 +3863,14 @@ packages: resolution: {integrity: sha512-9sXyKx2jp8JvmGUIddb7iILq9KN6d1PoCNSvrzIej4yP+pCxpiY9elgeaSoGY5yHcPClNnvHBKcenL23mdUckg==} dev: true - /@fluencelabs/cli@0.7.2(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@nomicfoundation/hardhat-chai-matchers@1.0.6)(@nomicfoundation/hardhat-network-helpers@1.0.8)(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(@typechain/ethers-v5@10.2.1)(@typechain/hardhat@6.1.6)(@types/chai@4.3.5)(@types/mocha@9.1.1)(@types/node@20.7.0)(chai@4.3.7)(hardhat-gas-reporter@1.0.9)(hardhat@2.15.0)(solidity-coverage@0.7.22)(ts-node@10.9.1)(typechain@8.2.0)(typescript@5.1.6): + /@fluencelabs/cli@0.7.2(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@nomicfoundation/hardhat-chai-matchers@1.0.6)(@nomicfoundation/hardhat-network-helpers@1.0.8)(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(@typechain/ethers-v5@10.2.1)(@typechain/hardhat@6.1.6)(@types/chai@4.3.5)(@types/mocha@9.1.1)(@types/node@20.7.0)(chai@4.3.10)(hardhat-gas-reporter@1.0.9)(hardhat@2.15.0)(solidity-coverage@0.7.22)(ts-node@10.9.1)(typechain@8.2.0)(typescript@5.1.6): resolution: {integrity: sha512-cXhlXBxNh1i66Twb3Nhpm1mXHpa+8zzoQ5wKJ6zJjOtrw6GWB6WrfIAb+aaLGWJMBnWHcZEkXs5vx9vwvVplcQ==} engines: {node: '=18'} hasBin: true dependencies: '@fluencelabs/air-beautify-wasm': 0.3.2 '@fluencelabs/aqua-api': 0.12.0 - '@fluencelabs/deal-aurora': 0.1.8(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@nomicfoundation/hardhat-chai-matchers@1.0.6)(@nomicfoundation/hardhat-network-helpers@1.0.8)(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(@typechain/ethers-v5@10.2.1)(@typechain/hardhat@6.1.6)(@types/chai@4.3.5)(@types/mocha@9.1.1)(@types/node@20.7.0)(chai@4.3.7)(ethers@5.7.2)(hardhat-gas-reporter@1.0.9)(hardhat@2.15.0)(solidity-coverage@0.7.22)(ts-node@10.9.1)(typechain@8.2.0)(typescript@5.1.6) + '@fluencelabs/deal-aurora': 0.1.8(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@nomicfoundation/hardhat-chai-matchers@1.0.6)(@nomicfoundation/hardhat-network-helpers@1.0.8)(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(@typechain/ethers-v5@10.2.1)(@typechain/hardhat@6.1.6)(@types/chai@4.3.5)(@types/mocha@9.1.1)(@types/node@20.7.0)(chai@4.3.10)(ethers@5.7.2)(hardhat-gas-reporter@1.0.9)(hardhat@2.15.0)(solidity-coverage@0.7.22)(ts-node@10.9.1)(typechain@8.2.0)(typescript@5.1.6) '@fluencelabs/fluence-network-environment': 1.1.2 '@fluencelabs/js-client': 0.0.10 '@iarna/toml': 2.2.5 @@ -4130,10 +3932,10 @@ packages: - utf-8-validate dev: true - /@fluencelabs/deal-aurora@0.1.8(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@nomicfoundation/hardhat-chai-matchers@1.0.6)(@nomicfoundation/hardhat-network-helpers@1.0.8)(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(@typechain/ethers-v5@10.2.1)(@typechain/hardhat@6.1.6)(@types/chai@4.3.5)(@types/mocha@9.1.1)(@types/node@20.7.0)(chai@4.3.7)(ethers@5.7.2)(hardhat-gas-reporter@1.0.9)(hardhat@2.15.0)(solidity-coverage@0.7.22)(ts-node@10.9.1)(typechain@8.2.0)(typescript@5.1.6): + /@fluencelabs/deal-aurora@0.1.8(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@nomicfoundation/hardhat-chai-matchers@1.0.6)(@nomicfoundation/hardhat-network-helpers@1.0.8)(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(@typechain/ethers-v5@10.2.1)(@typechain/hardhat@6.1.6)(@types/chai@4.3.5)(@types/mocha@9.1.1)(@types/node@20.7.0)(chai@4.3.10)(ethers@5.7.2)(hardhat-gas-reporter@1.0.9)(hardhat@2.15.0)(solidity-coverage@0.7.22)(ts-node@10.9.1)(typechain@8.2.0)(typescript@5.1.6): resolution: {integrity: sha512-h2L3F67AsFxJy+mBAAUy8gMUGf85sgT3kuLhqEstdbQ20ASjxrSsXmyVZeVQLUx4nR1ygbGll9Y+FmRFgpNwMQ==} dependencies: - '@nomicfoundation/hardhat-toolbox': 1.0.2(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@nomicfoundation/hardhat-chai-matchers@1.0.6)(@nomicfoundation/hardhat-network-helpers@1.0.8)(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(@typechain/ethers-v5@10.2.1)(@typechain/hardhat@6.1.6)(@types/chai@4.3.5)(@types/mocha@9.1.1)(@types/node@20.7.0)(chai@4.3.7)(ethers@5.7.2)(hardhat-gas-reporter@1.0.9)(hardhat@2.15.0)(solidity-coverage@0.7.22)(ts-node@10.9.1)(typechain@8.2.0)(typescript@5.1.6) + '@nomicfoundation/hardhat-toolbox': 1.0.2(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@nomicfoundation/hardhat-chai-matchers@1.0.6)(@nomicfoundation/hardhat-network-helpers@1.0.8)(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(@typechain/ethers-v5@10.2.1)(@typechain/hardhat@6.1.6)(@types/chai@4.3.5)(@types/mocha@9.1.1)(@types/node@20.7.0)(chai@4.3.10)(ethers@5.7.2)(hardhat-gas-reporter@1.0.9)(hardhat@2.15.0)(solidity-coverage@0.7.22)(ts-node@10.9.1)(typechain@8.2.0)(typescript@5.1.6) '@openzeppelin/contracts': 4.9.2 '@openzeppelin/contracts-upgradeable': 4.9.2 dotenv: 16.3.1 @@ -4456,6 +4258,13 @@ packages: '@sinclair/typebox': 0.24.51 dev: false + /@jest/schemas@29.6.3: + resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@sinclair/typebox': 0.27.8 + dev: true + /@jest/source-map@27.5.1: resolution: {integrity: sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -5185,7 +4994,7 @@ packages: - utf-8-validate dev: true - /@nomicfoundation/hardhat-chai-matchers@1.0.6(@nomiclabs/hardhat-ethers@2.2.3)(chai@4.3.7)(ethers@5.7.2)(hardhat@2.15.0): + /@nomicfoundation/hardhat-chai-matchers@1.0.6(@nomiclabs/hardhat-ethers@2.2.3)(chai@4.3.10)(ethers@5.7.2)(hardhat@2.15.0): resolution: {integrity: sha512-f5ZMNmabZeZegEfuxn/0kW+mm7+yV7VNDxLpMOMGXWFJ2l/Ct3QShujzDRF9cOkK9Ui/hbDeOWGZqyQALDXVCQ==} peerDependencies: '@nomiclabs/hardhat-ethers': ^2.0.0 @@ -5196,8 +5005,8 @@ packages: '@ethersproject/abi': 5.7.0 '@nomiclabs/hardhat-ethers': 2.2.3(ethers@5.7.2)(hardhat@2.15.0) '@types/chai-as-promised': 7.1.5 - chai: 4.3.7 - chai-as-promised: 7.1.1(chai@4.3.7) + chai: 4.3.10 + chai-as-promised: 7.1.1(chai@4.3.10) deep-eql: 4.1.3 ethers: 5.7.2 hardhat: 2.15.0(ts-node@10.9.1)(typescript@5.1.6) @@ -5213,7 +5022,7 @@ packages: hardhat: 2.15.0(ts-node@10.9.1)(typescript@5.1.6) dev: true - /@nomicfoundation/hardhat-toolbox@1.0.2(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@nomicfoundation/hardhat-chai-matchers@1.0.6)(@nomicfoundation/hardhat-network-helpers@1.0.8)(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(@typechain/ethers-v5@10.2.1)(@typechain/hardhat@6.1.6)(@types/chai@4.3.5)(@types/mocha@9.1.1)(@types/node@20.7.0)(chai@4.3.7)(ethers@5.7.2)(hardhat-gas-reporter@1.0.9)(hardhat@2.15.0)(solidity-coverage@0.7.22)(ts-node@10.9.1)(typechain@8.2.0)(typescript@5.1.6): + /@nomicfoundation/hardhat-toolbox@1.0.2(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@nomicfoundation/hardhat-chai-matchers@1.0.6)(@nomicfoundation/hardhat-network-helpers@1.0.8)(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(@typechain/ethers-v5@10.2.1)(@typechain/hardhat@6.1.6)(@types/chai@4.3.5)(@types/mocha@9.1.1)(@types/node@20.7.0)(chai@4.3.10)(ethers@5.7.2)(hardhat-gas-reporter@1.0.9)(hardhat@2.15.0)(solidity-coverage@0.7.22)(ts-node@10.9.1)(typechain@8.2.0)(typescript@5.1.6): resolution: {integrity: sha512-8CEgWSKUK2aMit+76Sez8n7UB0Ze1lwT+LcWxj4EFP30lQWOwOws048t6MTPfThH0BlSWjC6hJRr0LncIkc1Sw==} peerDependencies: '@ethersproject/abi': ^5.4.7 @@ -5238,7 +5047,7 @@ packages: dependencies: '@ethersproject/abi': 5.7.0 '@ethersproject/providers': 5.7.2 - '@nomicfoundation/hardhat-chai-matchers': 1.0.6(@nomiclabs/hardhat-ethers@2.2.3)(chai@4.3.7)(ethers@5.7.2)(hardhat@2.15.0) + '@nomicfoundation/hardhat-chai-matchers': 1.0.6(@nomiclabs/hardhat-ethers@2.2.3)(chai@4.3.10)(ethers@5.7.2)(hardhat@2.15.0) '@nomicfoundation/hardhat-network-helpers': 1.0.8(hardhat@2.15.0) '@nomiclabs/hardhat-ethers': 2.2.3(ethers@5.7.2)(hardhat@2.15.0) '@nomiclabs/hardhat-etherscan': 3.1.7(hardhat@2.15.0) @@ -5247,7 +5056,7 @@ packages: '@types/chai': 4.3.5 '@types/mocha': 9.1.1 '@types/node': 20.7.0 - chai: 4.3.7 + chai: 4.3.10 ethers: 5.7.2 hardhat: 2.15.0(ts-node@10.9.1)(typescript@5.1.6) hardhat-gas-reporter: 1.0.9(hardhat@2.15.0) @@ -5791,6 +5600,10 @@ packages: resolution: {integrity: sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==} dev: false + /@sinclair/typebox@0.27.8: + resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + dev: true + /@sindresorhus/is@0.14.0: resolution: {integrity: sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==} engines: {node: '>=6'} @@ -6961,35 +6774,42 @@ packages: eslint-visitor-keys: 3.4.1 dev: true - /@vitest/expect@0.29.7: - resolution: {integrity: sha512-UtG0tW0DP6b3N8aw7PHmweKDsvPv4wjGvrVZW7OSxaFg76ShtVdMiMcUkZJgCE8QWUmhwaM0aQhbbVLo4F4pkA==} + /@vitest/expect@0.34.6: + resolution: {integrity: sha512-QUzKpUQRc1qC7qdGo7rMK3AkETI7w18gTCUrsNnyjjJKYiuUB9+TQK3QnR1unhCnWRC0AbKv2omLGQDF/mIjOw==} dependencies: - '@vitest/spy': 0.29.7 - '@vitest/utils': 0.29.7 - chai: 4.3.7 + '@vitest/spy': 0.34.6 + '@vitest/utils': 0.34.6 + chai: 4.3.10 dev: true - /@vitest/runner@0.29.7: - resolution: {integrity: sha512-Yt0+csM945+odOx4rjZSjibQfl2ymxqVsmYz6sO2fiO5RGPYDFCo60JF6tLL9pz4G/kjY4irUxadeB1XT+H1jg==} + /@vitest/runner@0.34.6: + resolution: {integrity: sha512-1CUQgtJSLF47NnhN+F9X2ycxUP0kLHQ/JWvNHbeBfwW8CzEGgeskzNnHDyv1ieKTltuR6sdIHV+nmR6kPxQqzQ==} dependencies: - '@vitest/utils': 0.29.7 + '@vitest/utils': 0.34.6 p-limit: 4.0.0 pathe: 1.1.1 dev: true - /@vitest/spy@0.29.7: - resolution: {integrity: sha512-IalL0iO6A6Xz8hthR8sctk6ZS//zVBX48EiNwQguYACdgdei9ZhwMaBFV70mpmeYAFCRAm+DpoFHM5470Im78A==} + /@vitest/snapshot@0.34.6: + resolution: {integrity: sha512-B3OZqYn6k4VaN011D+ve+AA4whM4QkcwcrwaKwAbyyvS/NB1hCWjFIBQxAQQSQir9/RtyAAGuq+4RJmbn2dH4w==} + dependencies: + magic-string: 0.30.5 + pathe: 1.1.1 + pretty-format: 29.7.0 + dev: true + + /@vitest/spy@0.34.6: + resolution: {integrity: sha512-xaCvneSaeBw/cz8ySmF7ZwGvL0lBjfvqc1LpQ/vcdHEvpLn3Ff1vAvjw+CoGn0802l++5L/pxb7whwcWAw+DUQ==} dependencies: - tinyspy: 1.1.1 + tinyspy: 2.2.0 dev: true - /@vitest/utils@0.29.7: - resolution: {integrity: sha512-vNgGadp2eE5XKCXtZXL5UyNEDn68npSct75OC9AlELenSK0DiV1Mb9tfkwJHKjRb69iek+e79iipoJx8+s3SdA==} + /@vitest/utils@0.34.6: + resolution: {integrity: sha512-IG5aDD8S6zlvloDsnzHw0Ut5xczlF+kv2BOTo+iXfPr54Yhi5qbVOgGB1hZaVq4iJ4C/MZ2J0y15IlsV/ZcI0A==} dependencies: - cli-truncate: 3.1.0 - diff: 5.1.0 + diff-sequences: 29.6.3 loupe: 2.3.6 - pretty-format: 27.5.1 + pretty-format: 29.7.0 dev: true /@walletconnect/core@2.8.1(lokijs@1.5.12): @@ -7588,6 +7408,7 @@ packages: /ansi-regex@6.0.1: resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} engines: {node: '>=12'} + dev: false /ansi-styles@3.2.1: resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} @@ -7605,11 +7426,6 @@ packages: resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} engines: {node: '>=10'} - /ansi-styles@6.2.1: - resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} - engines: {node: '>=12'} - dev: true - /ansicolors@0.3.2: resolution: {integrity: sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==} dev: true @@ -8690,23 +8506,23 @@ packages: hasBin: true dev: true - /chai-as-promised@7.1.1(chai@4.3.7): + /chai-as-promised@7.1.1(chai@4.3.10): resolution: {integrity: sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==} peerDependencies: chai: '>= 2.1.2 < 5' dependencies: - chai: 4.3.7 - check-error: 1.0.2 + chai: 4.3.10 + check-error: 1.0.3 dev: true - /chai@4.3.7: - resolution: {integrity: sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==} + /chai@4.3.10: + resolution: {integrity: sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==} engines: {node: '>=4'} dependencies: assertion-error: 1.1.0 - check-error: 1.0.2 + check-error: 1.0.3 deep-eql: 4.1.3 - get-func-name: 2.0.0 + get-func-name: 2.0.2 loupe: 2.3.6 pathval: 1.1.1 type-detect: 4.0.8 @@ -8758,8 +8574,10 @@ packages: resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==} dev: true - /check-error@1.0.2: - resolution: {integrity: sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==} + /check-error@1.0.3: + resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} + dependencies: + get-func-name: 2.0.2 dev: true /check-types@11.2.2: @@ -8909,14 +8727,6 @@ packages: colors: 1.4.0 dev: true - /cli-truncate@3.1.0: - resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dependencies: - slice-ansi: 5.0.0 - string-width: 5.1.2 - dev: true - /cli-width@3.0.0: resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==} engines: {node: '>= 10'} @@ -9926,6 +9736,11 @@ packages: engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dev: false + /diff-sequences@29.6.3: + resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dev: true + /diff@3.5.0: resolution: {integrity: sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==} engines: {node: '>=0.3.1'} @@ -9940,11 +9755,6 @@ packages: engines: {node: '>=0.3.1'} dev: true - /diff@5.1.0: - resolution: {integrity: sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==} - engines: {node: '>=0.3.1'} - dev: true - /diffie-hellman@5.0.3: resolution: {integrity: sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==} dependencies: @@ -10106,10 +9916,6 @@ packages: stream-shift: 1.0.1 dev: true - /eastasianwidth@0.2.0: - resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - dev: true - /ecc-jsbn@0.1.2: resolution: {integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==} dependencies: @@ -10184,6 +9990,7 @@ packages: /emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + dev: false /emojis-list@3.0.0: resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==} @@ -10402,36 +10209,6 @@ packages: ext: 1.7.0 dev: true - /esbuild@0.16.17: - resolution: {integrity: sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==} - engines: {node: '>=12'} - hasBin: true - requiresBuild: true - optionalDependencies: - '@esbuild/android-arm': 0.16.17 - '@esbuild/android-arm64': 0.16.17 - '@esbuild/android-x64': 0.16.17 - '@esbuild/darwin-arm64': 0.16.17 - '@esbuild/darwin-x64': 0.16.17 - '@esbuild/freebsd-arm64': 0.16.17 - '@esbuild/freebsd-x64': 0.16.17 - '@esbuild/linux-arm': 0.16.17 - '@esbuild/linux-arm64': 0.16.17 - '@esbuild/linux-ia32': 0.16.17 - '@esbuild/linux-loong64': 0.16.17 - '@esbuild/linux-mips64el': 0.16.17 - '@esbuild/linux-ppc64': 0.16.17 - '@esbuild/linux-riscv64': 0.16.17 - '@esbuild/linux-s390x': 0.16.17 - '@esbuild/linux-x64': 0.16.17 - '@esbuild/netbsd-x64': 0.16.17 - '@esbuild/openbsd-x64': 0.16.17 - '@esbuild/sunos-x64': 0.16.17 - '@esbuild/win32-arm64': 0.16.17 - '@esbuild/win32-ia32': 0.16.17 - '@esbuild/win32-x64': 0.16.17 - dev: true - /esbuild@0.18.20: resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} engines: {node: '>=12'} @@ -11779,6 +11556,10 @@ packages: resolution: {integrity: sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==} dev: true + /get-func-name@2.0.2: + resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} + dev: true + /get-intrinsic@1.2.1: resolution: {integrity: sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==} dependencies: @@ -12921,11 +12702,6 @@ packages: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} - /is-fullwidth-code-point@4.0.0: - resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} - engines: {node: '>=12'} - dev: true - /is-function@1.0.2: resolution: {integrity: sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==} dev: true @@ -14519,6 +14295,13 @@ packages: '@jridgewell/sourcemap-codec': 1.4.15 dev: true + /magic-string@0.30.5: + resolution: {integrity: sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==} + engines: {node: '>=12'} + dependencies: + '@jridgewell/sourcemap-codec': 1.4.15 + dev: true + /make-dir@1.3.0: resolution: {integrity: sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==} engines: {node: '>=4'} @@ -14790,13 +14573,13 @@ packages: hasBin: true dev: true - /mlly@1.3.0: - resolution: {integrity: sha512-HT5mcgIQKkOrZecOjOX3DJorTikWXwsBfpcr/MGBkhfWcjiqvnaL/9ppxvIUXfjT6xt4DVIAsN9fMUz1ev4bIw==} + /mlly@1.4.2: + resolution: {integrity: sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg==} dependencies: acorn: 8.10.0 pathe: 1.1.1 pkg-types: 1.0.3 - ufo: 1.1.2 + ufo: 1.3.1 dev: true /mnemonist@0.38.5: @@ -15874,7 +15657,7 @@ packages: resolution: {integrity: sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==} dependencies: jsonc-parser: 3.2.0 - mlly: 1.3.0 + mlly: 1.4.2 pathe: 1.1.1 dev: true @@ -16676,6 +16459,7 @@ packages: nanoid: 3.3.6 picocolors: 1.0.0 source-map-js: 1.0.2 + dev: false /postcss@8.4.31: resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} @@ -16731,6 +16515,7 @@ packages: ansi-regex: 5.0.1 ansi-styles: 5.2.0 react-is: 17.0.2 + dev: false /pretty-format@28.1.3: resolution: {integrity: sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==} @@ -16742,6 +16527,15 @@ packages: react-is: 18.2.0 dev: false + /pretty-format@29.7.0: + resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/schemas': 29.6.3 + ansi-styles: 5.2.0 + react-is: 18.2.0 + dev: true + /private-ip@3.0.0: resolution: {integrity: sha512-HkMBs4nMtrP+cvcw0bDi2BAZIGgiKI4Zq8Oc+dMqNBpHS8iGL4+WO/pRtc8Bwnv9rjnV0QwMDwEBymFtqv7Kww==} engines: {node: '>=14.16'} @@ -17090,10 +16884,10 @@ packages: /react-is@17.0.2: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + dev: false /react-is@18.2.0: resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} - dev: false /react-native-fetch-api@3.0.0: resolution: {integrity: sha512-g2rtqPjdroaboDKTsJCTlcmtw54E25OjyaunUP0anOZn4Fuo2IKs8BVfe02zVggA/UysbmfSnRJIqtNkAgggNA==} @@ -17620,14 +17414,6 @@ packages: fsevents: 2.3.3 dev: false - /rollup@3.25.1: - resolution: {integrity: sha512-tywOR+rwIt5m2ZAWSe5AIJcTat8vGlnPFAv15ycCrw33t6iFsXZ6mzHVFh2psSjxQPmI+xgzMZZizUAukBI4aQ==} - engines: {node: '>=14.18.0', npm: '>=8.0.0'} - hasBin: true - optionalDependencies: - fsevents: 2.3.3 - dev: true - /rollup@3.29.4: resolution: {integrity: sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==} engines: {node: '>=14.18.0', npm: '>=8.0.0'} @@ -18103,14 +17889,6 @@ packages: is-fullwidth-code-point: 3.0.0 dev: true - /slice-ansi@5.0.0: - resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} - engines: {node: '>=12'} - dependencies: - ansi-styles: 6.2.1 - is-fullwidth-code-point: 4.0.0 - dev: true - /sockjs@0.3.24: resolution: {integrity: sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==} dependencies: @@ -18428,15 +18206,6 @@ packages: is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 - /string-width@5.1.2: - resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} - engines: {node: '>=12'} - dependencies: - eastasianwidth: 0.2.0 - emoji-regex: 9.2.2 - strip-ansi: 7.1.0 - dev: true - /string.prototype.matchall@4.0.8: resolution: {integrity: sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==} dependencies: @@ -18541,6 +18310,7 @@ packages: engines: {node: '>=12'} dependencies: ansi-regex: 6.0.1 + dev: false /strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} @@ -19018,13 +18788,13 @@ packages: resolution: {integrity: sha512-kRwSG8Zx4tjF9ZiyH4bhaebu+EDz1BOx9hOigYHlUW4xxI/wKIUQUqo018UlU4ar6ATPBsaMrdbKZ+tmPdohFA==} dev: true - /tinypool@0.4.0: - resolution: {integrity: sha512-2ksntHOKf893wSAH4z/+JbPpi92esw8Gn9N2deXX+B0EO92hexAVI9GIZZPx7P5aYo5KULfeOSt3kMOmSOy6uA==} + /tinypool@0.7.0: + resolution: {integrity: sha512-zSYNUlYSMhJ6Zdou4cJwo/p7w5nmAH17GRfU/ui3ctvjXFErXXkruT4MWW6poDeXgCaIBlGLrfU6TbTXxyGMww==} engines: {node: '>=14.0.0'} dev: true - /tinyspy@1.1.1: - resolution: {integrity: sha512-UVq5AXt/gQlti7oxoIg5oi/9r0WpF7DGEVwXgqWSMmyN16+e3tl5lIvTaOpJ3TAtu5xFzWccFRM4R5NaWHF+4g==} + /tinyspy@2.2.0: + resolution: {integrity: sha512-d2eda04AN/cPOR89F7Xv5bK/jrQEhmcLFe6HFldoeO9AJtps+fqEnh486vnT/8y4bw38pSyxDcTCAq+Ks2aJTg==} engines: {node: '>=14.0.0'} dev: true @@ -19401,8 +19171,8 @@ packages: engines: {node: '>=8'} dev: true - /ufo@1.1.2: - resolution: {integrity: sha512-TrY6DsjTQQgyS3E3dBaOXf0TpPD8u9FVrVYmKVegJuFw51n/YB9XPt+U6ydzFG5ZIN7+DIjPbNmXoBj9esYhgQ==} + /ufo@1.3.1: + resolution: {integrity: sha512-uY/99gMLIOlJPwATcMVYfqDSxUR9//AUcgZMzwfSTJPDKzA1S8mX4VLqa+fiAtveraQUBCz4FFcwVZBGbwBXIw==} dev: true /uglify-js@3.17.4: @@ -19698,14 +19468,14 @@ packages: extsprintf: 1.3.0 dev: true - /vite-node@0.29.7(@types/node@20.7.0): - resolution: {integrity: sha512-PakCZLvz37yFfUPWBnLa1OYHPCGm5v4pmRrTcFN4V/N/T3I6tyP3z07S//9w+DdeL7vVd0VSeyMZuAh+449ZWw==} - engines: {node: '>=v14.16.0'} + /vite-node@0.34.6(@types/node@20.7.0): + resolution: {integrity: sha512-nlBMJ9x6n7/Amaz6F3zJ97EBwR2FkzhBRxF5e+jE6LA3yi6Wtc2lyTij1OnDMIr34v5g/tVQtsVAzhT0jc5ygA==} + engines: {node: '>=v14.18.0'} hasBin: true dependencies: cac: 6.7.14 debug: 4.3.4(supports-color@8.1.1) - mlly: 1.3.0 + mlly: 1.4.2 pathe: 1.1.1 picocolors: 1.0.0 vite: 4.4.11(@types/node@20.7.0) @@ -19734,40 +19504,6 @@ packages: - typescript dev: true - /vite@4.0.4(@types/node@20.7.0): - resolution: {integrity: sha512-xevPU7M8FU0i/80DMR+YhgrzR5KS2ORy1B4xcX/cXLsvnUWvfHuqMmVU6N0YiJ4JWGRJJsLCgjEzKjG9/GKoSw==} - engines: {node: ^14.18.0 || >=16.0.0} - hasBin: true - peerDependencies: - '@types/node': '>= 14' - less: '*' - sass: '*' - stylus: '*' - sugarss: '*' - terser: ^5.4.0 - peerDependenciesMeta: - '@types/node': - optional: true - less: - optional: true - sass: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - dependencies: - '@types/node': 20.7.0 - esbuild: 0.16.17 - postcss: 8.4.24 - resolve: 1.22.4 - rollup: 3.25.1 - optionalDependencies: - fsevents: 2.3.3 - dev: true - /vite@4.4.11(@types/node@20.4.5): resolution: {integrity: sha512-ksNZJlkcU9b0lBwAGZGGaZHCMqHsc8OpgtoYhsQ4/I2v5cnpmmmqe5pM4nv/4Hn6G/2GhTdj0DhZh2e+Er1q5A==} engines: {node: ^14.18.0 || >=16.0.0} @@ -19840,9 +19576,9 @@ packages: fsevents: 2.3.3 dev: true - /vitest@0.29.7: - resolution: {integrity: sha512-aWinOSOu4jwTuZHkb+cCyrqQ116Q9TXaJrNKTHudKBknIpR0VplzeaOUuDF9jeZcrbtQKZQt6yrtd+eakbaxHg==} - engines: {node: '>=v14.16.0'} + /vitest@0.34.6: + resolution: {integrity: sha512-+5CALsOvbNKnS+ZHMXtuUC7nL8/7F1F2DnHGjSsszX8zCjWSSviphCb/NuS9Nzf4Q03KyyDRBAXhF/8lffME4Q==} + engines: {node: '>=v14.18.0'} hasBin: true peerDependencies: '@edge-runtime/vm': '*' @@ -19850,6 +19586,7 @@ packages: '@vitest/ui': '*' happy-dom: '*' jsdom: '*' + playwright: '*' safaridriver: '*' webdriverio: '*' peerDependenciesMeta: @@ -19863,6 +19600,8 @@ packages: optional: true jsdom: optional: true + playwright: + optional: true safaridriver: optional: true webdriverio: @@ -19871,26 +19610,26 @@ packages: '@types/chai': 4.3.5 '@types/chai-subset': 1.3.3 '@types/node': 20.7.0 - '@vitest/expect': 0.29.7 - '@vitest/runner': 0.29.7 - '@vitest/spy': 0.29.7 - '@vitest/utils': 0.29.7 + '@vitest/expect': 0.34.6 + '@vitest/runner': 0.34.6 + '@vitest/snapshot': 0.34.6 + '@vitest/spy': 0.34.6 + '@vitest/utils': 0.34.6 acorn: 8.10.0 acorn-walk: 8.2.0 cac: 6.7.14 - chai: 4.3.7 + chai: 4.3.10 debug: 4.3.4(supports-color@8.1.1) local-pkg: 0.4.3 + magic-string: 0.30.5 pathe: 1.1.1 picocolors: 1.0.0 - source-map: 0.6.1 std-env: 3.3.3 strip-literal: 1.0.1 tinybench: 2.5.0 - tinypool: 0.4.0 - tinyspy: 1.1.1 - vite: 4.0.4(@types/node@20.7.0) - vite-node: 0.29.7(@types/node@20.7.0) + tinypool: 0.7.0 + vite: 4.4.11(@types/node@20.7.0) + vite-node: 0.34.6(@types/node@20.7.0) why-is-node-running: 2.2.2 transitivePeerDependencies: - less From 83af1f47780c4e740b50bd35c3efc113835ca8a1 Mon Sep 17 00:00:00 2001 From: Akim Mamedov Date: Tue, 17 Oct 2023 00:50:50 +0700 Subject: [PATCH 45/45] Fix deps --- packages/core/js-client/package.json | 2 +- pnpm-lock.yaml | 11 +++-------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/packages/core/js-client/package.json b/packages/core/js-client/package.json index 54f6c88a0..b6ef1850a 100644 --- a/packages/core/js-client/package.json +++ b/packages/core/js-client/package.json @@ -34,6 +34,7 @@ "dependencies": { "@chainsafe/libp2p-noise": "13.0.0", "@chainsafe/libp2p-yamux": "5.0.0", + "@fluencelabs/avm": "0.48.0", "@fluencelabs/interfaces": "workspace:*", "@fluencelabs/marine-worker": "0.3.3", "@libp2p/crypto": "2.0.3", @@ -62,7 +63,6 @@ }, "devDependencies": { "@fluencelabs/aqua-api": "0.9.3", - "@fluencelabs/avm": "0.48.0", "@fluencelabs/marine-js": "0.7.2", "@rollup/plugin-inject": "5.0.3", "@types/bs58": "4.0.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8e8c478dd..29d3ffa07 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -205,6 +205,9 @@ importers: '@chainsafe/libp2p-yamux': specifier: 5.0.0 version: 5.0.0 + '@fluencelabs/avm': + specifier: 0.48.0 + version: 0.48.0 '@fluencelabs/interfaces': specifier: workspace:* version: link:../interfaces @@ -284,9 +287,6 @@ importers: '@fluencelabs/aqua-api': specifier: 0.9.3 version: 0.9.3 - '@fluencelabs/avm': - specifier: 0.48.0 - version: 0.48.0 '@fluencelabs/marine-js': specifier: 0.7.2 version: 0.7.2 @@ -3861,7 +3861,6 @@ packages: /@fluencelabs/avm@0.48.0: resolution: {integrity: sha512-9sXyKx2jp8JvmGUIddb7iILq9KN6d1PoCNSvrzIej4yP+pCxpiY9elgeaSoGY5yHcPClNnvHBKcenL23mdUckg==} - dev: true /@fluencelabs/cli@0.7.2(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@nomicfoundation/hardhat-chai-matchers@1.0.6)(@nomicfoundation/hardhat-network-helpers@1.0.8)(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(@typechain/ethers-v5@10.2.1)(@typechain/hardhat@6.1.6)(@types/chai@4.3.5)(@types/mocha@9.1.1)(@types/node@20.7.0)(chai@4.3.10)(hardhat-gas-reporter@1.0.9)(hardhat@2.15.0)(solidity-coverage@0.7.22)(ts-node@10.9.1)(typechain@8.2.0)(typescript@5.1.6): resolution: {integrity: sha512-cXhlXBxNh1i66Twb3Nhpm1mXHpa+8zzoQ5wKJ6zJjOtrw6GWB6WrfIAb+aaLGWJMBnWHcZEkXs5vx9vwvVplcQ==} @@ -4453,8 +4452,6 @@ packages: protons-runtime: 5.0.2(uint8arraylist@2.4.3) uint8arraylist: 2.4.3 uint8arrays: 4.0.6 - transitivePeerDependencies: - - supports-color /@libp2p/interface-connection@4.0.0: resolution: {integrity: sha512-6xx/NmEc84HX7QmsjSC3hHredQYjHv4Dkf4G27adAPf+qN+vnPxmQ7gaTnk243a0++DOFTbZ2gKX/15G2B6SRg==} @@ -4624,8 +4621,6 @@ packages: protons-runtime: 5.0.2(uint8arraylist@2.4.3) uint8arraylist: 2.4.3 uint8arrays: 4.0.6 - transitivePeerDependencies: - - supports-color /@libp2p/peer-id@2.0.1: resolution: {integrity: sha512-uGIR4rS+j+IzzIu0kih4MonZEfRmjGNfXaSPMIFOeMxZItZT6TIpxoVNYxHl4YtneSFKzlLnf9yx9EhRcyfy8Q==}