@dxos/functions 0.8.4-main.a4bbb77 → 0.8.4-main.ae835ea
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/browser/bundler/index.mjs +16 -25
- package/dist/lib/browser/bundler/index.mjs.map +3 -3
- package/dist/lib/browser/chunk-M6EXIREF.mjs +610 -0
- package/dist/lib/browser/chunk-M6EXIREF.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +957 -977
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +8 -6
- package/dist/lib/browser/testing/index.mjs.map +3 -3
- package/dist/lib/node-esm/bundler/index.mjs +16 -25
- package/dist/lib/node-esm/bundler/index.mjs.map +3 -3
- package/dist/lib/node-esm/chunk-P3IATZMZ.mjs +612 -0
- package/dist/lib/node-esm/chunk-P3IATZMZ.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +957 -977
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/testing/index.mjs +8 -6
- package/dist/lib/node-esm/testing/index.mjs.map +3 -3
- package/dist/types/src/bundler/bundler.d.ts.map +1 -1
- package/dist/types/src/e2e/deploy.test.d.ts +2 -0
- package/dist/types/src/e2e/deploy.test.d.ts.map +1 -0
- package/dist/types/src/example/fib.d.ts.map +1 -0
- package/dist/types/src/example/forex-effect.d.ts +3 -0
- package/dist/types/src/example/forex-effect.d.ts.map +1 -0
- package/dist/types/src/example/index.d.ts +12 -0
- package/dist/types/src/example/index.d.ts.map +1 -0
- package/dist/types/src/example/reply.d.ts.map +1 -0
- package/dist/types/src/example/sleep.d.ts.map +1 -0
- package/dist/types/src/executor/executor.d.ts.map +1 -1
- package/dist/types/src/handler.d.ts +20 -24
- package/dist/types/src/handler.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +4 -5
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/services/credentials.d.ts +6 -2
- package/dist/types/src/services/credentials.d.ts.map +1 -1
- package/dist/types/src/services/database.d.ts +6 -2
- package/dist/types/src/services/database.d.ts.map +1 -1
- package/dist/types/src/services/event-logger.d.ts +4 -1
- package/dist/types/src/services/event-logger.d.ts.map +1 -1
- package/dist/types/src/services/function-invocation-service.d.ts +5 -3
- package/dist/types/src/services/function-invocation-service.d.ts.map +1 -1
- package/dist/types/src/services/local-function-execution.d.ts +5 -3
- package/dist/types/src/services/local-function-execution.d.ts.map +1 -1
- package/dist/types/src/services/queues.d.ts +3 -1
- package/dist/types/src/services/queues.d.ts.map +1 -1
- package/dist/types/src/services/remote-function-execution-service.d.ts +3 -1
- package/dist/types/src/services/remote-function-execution-service.d.ts.map +1 -1
- package/dist/types/src/services/service-container.d.ts +2 -1
- package/dist/types/src/services/service-container.d.ts.map +1 -1
- package/dist/types/src/services/service-registry.d.ts +3 -1
- package/dist/types/src/services/service-registry.d.ts.map +1 -1
- package/dist/types/src/services/tracing.d.ts +4 -2
- package/dist/types/src/services/tracing.d.ts.map +1 -1
- package/dist/types/src/testing/layer.d.ts +3 -2
- package/dist/types/src/testing/layer.d.ts.map +1 -1
- package/dist/types/src/testing/logger.d.ts +1 -1
- package/dist/types/src/testing/logger.d.ts.map +1 -1
- package/dist/types/src/testing/services.d.ts +1 -1
- package/dist/types/src/testing/services.d.ts.map +1 -1
- package/dist/types/src/trace.d.ts +4 -4
- package/dist/types/src/trace.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +2 -2
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/triggers/input-builder.d.ts +2 -2
- package/dist/types/src/triggers/input-builder.d.ts.map +1 -1
- package/dist/types/src/triggers/invocation-tracer.d.ts +5 -3
- package/dist/types/src/triggers/invocation-tracer.d.ts.map +1 -1
- package/dist/types/src/triggers/trigger-dispatcher.d.ts +10 -6
- package/dist/types/src/triggers/trigger-dispatcher.d.ts.map +1 -1
- package/dist/types/src/triggers/trigger-state-store.d.ts +5 -4
- package/dist/types/src/triggers/trigger-state-store.d.ts.map +1 -1
- package/dist/types/src/types/Function.d.ts +47 -0
- package/dist/types/src/types/Function.d.ts.map +1 -0
- package/dist/types/src/types/Script.d.ts +28 -0
- package/dist/types/src/types/Script.d.ts.map +1 -0
- package/dist/types/src/types/Trigger.d.ts +139 -0
- package/dist/types/src/types/Trigger.d.ts.map +1 -0
- package/dist/types/src/types/TriggerEvent.d.ts +44 -0
- package/dist/types/src/types/TriggerEvent.d.ts.map +1 -0
- package/dist/types/src/types/index.d.ts +5 -0
- package/dist/types/src/types/index.d.ts.map +1 -0
- package/dist/types/src/url.d.ts +1 -1
- package/dist/types/src/url.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +24 -36
- package/src/bundler/bundler.ts +7 -3
- package/src/e2e/deploy.test.ts +69 -0
- package/src/{examples → example}/fib.ts +2 -1
- package/src/example/forex-effect.ts +40 -0
- package/src/example/index.ts +13 -0
- package/src/{examples → example}/reply.ts +3 -1
- package/src/{examples → example}/sleep.ts +2 -1
- package/src/executor/executor.ts +2 -1
- package/src/handler.ts +23 -19
- package/src/index.ts +4 -5
- package/src/services/credentials.ts +7 -2
- package/src/services/database.ts +6 -2
- package/src/services/event-logger.ts +4 -1
- package/src/services/function-invocation-service.test.ts +3 -1
- package/src/services/function-invocation-service.ts +5 -3
- package/src/services/local-function-execution.ts +10 -7
- package/src/services/queues.ts +3 -1
- package/src/services/remote-function-execution-service.ts +3 -1
- package/src/services/service-container.ts +2 -1
- package/src/services/service-registry.test.ts +4 -1
- package/src/services/service-registry.ts +7 -3
- package/src/services/tracing.ts +4 -2
- package/src/testing/layer.ts +6 -4
- package/src/testing/logger.ts +2 -1
- package/src/testing/persist-database.test.ts +1 -1
- package/src/testing/services.ts +1 -1
- package/src/trace.ts +5 -5
- package/src/translations.ts +2 -2
- package/src/triggers/input-builder.ts +2 -2
- package/src/triggers/invocation-tracer.ts +5 -3
- package/src/triggers/trigger-dispatcher.test.ts +57 -44
- package/src/triggers/trigger-dispatcher.ts +26 -27
- package/src/triggers/trigger-state-store.ts +6 -5
- package/src/{schema.ts → types/Function.ts} +9 -26
- package/src/types/Script.ts +33 -0
- package/src/types/Trigger.ts +139 -0
- package/src/types/TriggerEvent.ts +62 -0
- package/src/types/index.ts +8 -0
- package/src/url.ts +1 -1
- package/dist/lib/browser/chunk-C2Z7LCJ2.mjs +0 -649
- package/dist/lib/browser/chunk-C2Z7LCJ2.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-AH3AZM2U.mjs +0 -651
- package/dist/lib/node-esm/chunk-AH3AZM2U.mjs.map +0 -7
- package/dist/types/src/examples/fib.d.ts.map +0 -1
- package/dist/types/src/examples/index.d.ts +0 -4
- package/dist/types/src/examples/index.d.ts.map +0 -1
- package/dist/types/src/examples/reply.d.ts.map +0 -1
- package/dist/types/src/examples/sleep.d.ts.map +0 -1
- package/dist/types/src/schema.d.ts +0 -43
- package/dist/types/src/schema.d.ts.map +0 -1
- package/dist/types/src/types.d.ts +0 -221
- package/dist/types/src/types.d.ts.map +0 -1
- package/src/examples/index.ts +0 -7
- package/src/types.ts +0 -214
- /package/dist/types/src/{examples → example}/fib.d.ts +0 -0
- /package/dist/types/src/{examples → example}/reply.d.ts +0 -0
- /package/dist/types/src/{examples → example}/sleep.d.ts +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/functions",
|
|
3
|
-
"version": "0.8.4-main.
|
|
3
|
+
"version": "0.8.4-main.ae835ea",
|
|
4
4
|
"description": "Functions API and runtime.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -52,45 +52,33 @@
|
|
|
52
52
|
],
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"@effect/platform": "0.92.1",
|
|
55
|
-
"@preact/signals-core": "^1.12.1",
|
|
56
|
-
"cron": "^3.1.6",
|
|
57
|
-
"cron-schedule": "^5.0.4",
|
|
58
55
|
"effect": "3.18.3",
|
|
59
56
|
"esbuild-wasm": "^0.16.14",
|
|
60
|
-
"express": "^4.19.2",
|
|
61
|
-
"get-port-please": "^3.1.1",
|
|
62
57
|
"i18next": "^24.2.1",
|
|
63
58
|
"iso-did": "^1.6.0",
|
|
64
|
-
"
|
|
65
|
-
"@dxos/
|
|
66
|
-
"@dxos/
|
|
67
|
-
"@dxos/client": "0.8.4-main.
|
|
68
|
-
"@dxos/
|
|
69
|
-
"@dxos/
|
|
70
|
-
"@dxos/
|
|
71
|
-
"@dxos/
|
|
72
|
-
"@dxos/echo
|
|
73
|
-
"@dxos/echo": "0.8.4-main.
|
|
74
|
-
"@dxos/echo-
|
|
75
|
-
"@dxos/
|
|
76
|
-
"@dxos/
|
|
77
|
-
"@dxos/
|
|
78
|
-
"@dxos/
|
|
79
|
-
"@dxos/
|
|
80
|
-
"@dxos/
|
|
81
|
-
"@dxos/
|
|
82
|
-
"@dxos/
|
|
83
|
-
"@dxos/
|
|
84
|
-
"@dxos/
|
|
85
|
-
"@dxos/
|
|
86
|
-
"@dxos/
|
|
87
|
-
"@dxos/schema": "0.8.4-main.a4bbb77",
|
|
88
|
-
"@dxos/util": "0.8.4-main.a4bbb77"
|
|
89
|
-
},
|
|
90
|
-
"devDependencies": {
|
|
91
|
-
"@types/express": "^4.17.17",
|
|
92
|
-
"@types/ws": "^7.4.0",
|
|
93
|
-
"@dxos/agent": "0.8.4-main.a4bbb77"
|
|
59
|
+
"@dxos/ai": "0.8.4-main.ae835ea",
|
|
60
|
+
"@dxos/async": "0.8.4-main.ae835ea",
|
|
61
|
+
"@dxos/client": "0.8.4-main.ae835ea",
|
|
62
|
+
"@dxos/client-protocol": "0.8.4-main.ae835ea",
|
|
63
|
+
"@dxos/context": "0.8.4-main.ae835ea",
|
|
64
|
+
"@dxos/crypto": "0.8.4-main.ae835ea",
|
|
65
|
+
"@dxos/echo-db": "0.8.4-main.ae835ea",
|
|
66
|
+
"@dxos/debug": "0.8.4-main.ae835ea",
|
|
67
|
+
"@dxos/echo": "0.8.4-main.ae835ea",
|
|
68
|
+
"@dxos/echo-pipeline": "0.8.4-main.ae835ea",
|
|
69
|
+
"@dxos/echo-protocol": "0.8.4-main.ae835ea",
|
|
70
|
+
"@dxos/edge-client": "0.8.4-main.ae835ea",
|
|
71
|
+
"@dxos/effect": "0.8.4-main.ae835ea",
|
|
72
|
+
"@dxos/errors": "0.8.4-main.ae835ea",
|
|
73
|
+
"@dxos/invariant": "0.8.4-main.ae835ea",
|
|
74
|
+
"@dxos/kv-store": "0.8.4-main.ae835ea",
|
|
75
|
+
"@dxos/live-object": "0.8.4-main.ae835ea",
|
|
76
|
+
"@dxos/log": "0.8.4-main.ae835ea",
|
|
77
|
+
"@dxos/node-std": "0.8.4-main.ae835ea",
|
|
78
|
+
"@dxos/schema": "0.8.4-main.ae835ea",
|
|
79
|
+
"@dxos/protocols": "0.8.4-main.ae835ea",
|
|
80
|
+
"@dxos/util": "0.8.4-main.ae835ea",
|
|
81
|
+
"@dxos/keys": "0.8.4-main.ae835ea"
|
|
94
82
|
},
|
|
95
83
|
"publishConfig": {
|
|
96
84
|
"access": "public"
|
package/src/bundler/bundler.ts
CHANGED
|
@@ -2,8 +2,12 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
import
|
|
5
|
+
import * as FetchHttpClient from '@effect/platform/FetchHttpClient';
|
|
6
|
+
import * as HttpClient from '@effect/platform/HttpClient';
|
|
7
|
+
import * as Duration from 'effect/Duration';
|
|
8
|
+
import * as Effect from 'effect/Effect';
|
|
9
|
+
import * as Function from 'effect/Function';
|
|
10
|
+
import * as Schedule from 'effect/Schedule';
|
|
7
11
|
import { type BuildOptions, type BuildResult, type Loader, type Plugin, build, initialize } from 'esbuild-wasm';
|
|
8
12
|
|
|
9
13
|
import { subtleCrypto } from '@dxos/crypto';
|
|
@@ -277,7 +281,7 @@ const httpPlugin: Plugin = {
|
|
|
277
281
|
return { contents: text, loader: 'jsx' as Loader };
|
|
278
282
|
}).pipe(
|
|
279
283
|
Effect.retry(
|
|
280
|
-
pipe(
|
|
284
|
+
Function.pipe(
|
|
281
285
|
Schedule.exponential(Duration.millis(INITIAL_DELAY)),
|
|
282
286
|
Schedule.jittered,
|
|
283
287
|
Schedule.intersect(Schedule.recurs(MAX_RETRIES - 1)),
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { readFile } from 'node:fs/promises';
|
|
6
|
+
|
|
7
|
+
import { describe, expect, test } from 'vitest';
|
|
8
|
+
|
|
9
|
+
import { Client, Config } from '@dxos/client';
|
|
10
|
+
import { createEdgeIdentity } from '@dxos/client/edge';
|
|
11
|
+
import { Bundler } from '@dxos/functions/bundler';
|
|
12
|
+
import { uploadWorkerFunction } from '@dxos/functions/edge';
|
|
13
|
+
import { invariant } from '@dxos/invariant';
|
|
14
|
+
import { log } from '@dxos/log';
|
|
15
|
+
|
|
16
|
+
describe.runIf(process.env.DX_TEST_TAGS?.includes('functions-e2e'))('Functions deployment', () => {
|
|
17
|
+
test('deploys FOREX (effect) function and invokes it via EDGE (main)', { timeout: 120_000 }, async () => {
|
|
18
|
+
const config = new Config({
|
|
19
|
+
version: 1,
|
|
20
|
+
runtime: {
|
|
21
|
+
services: {
|
|
22
|
+
edge: { url: 'https://edge-main.dxos.workers.dev' },
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const client = new Client({ config });
|
|
28
|
+
await client.initialize();
|
|
29
|
+
await client.halo.createIdentity();
|
|
30
|
+
|
|
31
|
+
const space = await client.spaces.create();
|
|
32
|
+
await space.waitUntilReady();
|
|
33
|
+
|
|
34
|
+
// Inline echo function source.
|
|
35
|
+
const source = await readFile(new URL('../examples/forex-effect.ts', import.meta.url), 'utf-8');
|
|
36
|
+
|
|
37
|
+
// Bundle and upload.
|
|
38
|
+
const bundler = new Bundler({ platform: 'node', sandboxedModules: [], remoteModules: {} });
|
|
39
|
+
const buildResult = await bundler.bundle({ source });
|
|
40
|
+
if ('error' in buildResult) {
|
|
41
|
+
throw buildResult.error ?? new Error('Bundle creation failed');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const { functionId } = await uploadWorkerFunction({
|
|
45
|
+
client,
|
|
46
|
+
ownerPublicKey: space.key,
|
|
47
|
+
version: '0.0.1',
|
|
48
|
+
entryPoint: buildResult.entryPoint,
|
|
49
|
+
assets: { [buildResult.entryPoint]: buildResult.asset },
|
|
50
|
+
name: 'e2e-echo',
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
expect(functionId).toBeDefined();
|
|
54
|
+
|
|
55
|
+
// Invoke deployed function via EDGE directly.
|
|
56
|
+
const edgeClient = client.edge;
|
|
57
|
+
invariant(edgeClient, 'edgeClient is required');
|
|
58
|
+
edgeClient.setIdentity(createEdgeIdentity(client));
|
|
59
|
+
|
|
60
|
+
const input = { from: 'USD', to: 'EUR' };
|
|
61
|
+
const result = await edgeClient.invokeFunction({ functionId }, input);
|
|
62
|
+
log.info('>>> result', { result, functionId });
|
|
63
|
+
const resultNumber = Number(result);
|
|
64
|
+
expect(resultNumber).toBeGreaterThan(0);
|
|
65
|
+
expect(resultNumber).toBeLessThan(100);
|
|
66
|
+
|
|
67
|
+
await client.destroy();
|
|
68
|
+
});
|
|
69
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
// @ts-ignore
|
|
6
|
+
import { S, defineFunction } from 'dxos:functions';
|
|
7
|
+
import {
|
|
8
|
+
FetchHttpClient,
|
|
9
|
+
HttpClient,
|
|
10
|
+
HttpClientRequest,
|
|
11
|
+
// @ts-ignore
|
|
12
|
+
} from 'https://esm.sh/@effect/platform@0.89.0?deps=effect@3.17.0&bundle=false';
|
|
13
|
+
// @ts-ignore
|
|
14
|
+
import { Effect, Schedule } from 'https://esm.sh/effect@3.17.0?bundle=false';
|
|
15
|
+
|
|
16
|
+
export default defineFunction({
|
|
17
|
+
key: 'dxos.org/script/forex-effect',
|
|
18
|
+
name: 'Forex Effect',
|
|
19
|
+
description: 'Returns the exchange rate between two currencies.',
|
|
20
|
+
|
|
21
|
+
inputSchema: S.Struct({
|
|
22
|
+
from: S.String.annotations({ description: 'The source currency' }),
|
|
23
|
+
to: S.String.annotations({ description: 'The target currency' }),
|
|
24
|
+
}),
|
|
25
|
+
|
|
26
|
+
outputSchema: S.String.annotations({ description: 'The exchange rate between the two currencies' }),
|
|
27
|
+
|
|
28
|
+
handler: async ({ data: { from, to } }: any) =>
|
|
29
|
+
Effect.gen(function* () {
|
|
30
|
+
const res = yield* HttpClientRequest.get(`https://free.ratesdb.com/v1/rates?from=${from}&to=${to}`).pipe(
|
|
31
|
+
HttpClient.execute,
|
|
32
|
+
Effect.flatMap((res: any) => res.json),
|
|
33
|
+
Effect.timeout('1 second'),
|
|
34
|
+
Effect.retry(Schedule.exponential(1_000).pipe(Schedule.compose(Schedule.recurs(3)))),
|
|
35
|
+
Effect.scoped,
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
return res.data.rates[to].toString();
|
|
39
|
+
}).pipe(Effect.provide(FetchHttpClient.layer)),
|
|
40
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { default as fib$ } from './fib';
|
|
6
|
+
import { default as reply$ } from './reply';
|
|
7
|
+
import { default as sleep$ } from './sleep';
|
|
8
|
+
|
|
9
|
+
export namespace Example {
|
|
10
|
+
export const fib = fib$;
|
|
11
|
+
export const reply = reply$;
|
|
12
|
+
export const sleep = sleep$;
|
|
13
|
+
}
|
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import * as Console from 'effect/Console';
|
|
6
|
+
import * as Effect from 'effect/Effect';
|
|
7
|
+
import * as Schema from 'effect/Schema';
|
|
6
8
|
|
|
7
9
|
import { defineFunction } from '../handler';
|
|
8
10
|
|
package/src/executor/executor.ts
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import * as Effect from 'effect/Effect';
|
|
6
|
+
import * as Schema from 'effect/Schema';
|
|
6
7
|
|
|
7
8
|
import { type SpaceId } from '@dxos/client/echo';
|
|
8
9
|
import { runAndForwardErrors } from '@dxos/effect';
|
package/src/handler.ts
CHANGED
|
@@ -2,17 +2,19 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import type * as Context from 'effect/Context';
|
|
6
|
+
import * as Effect from 'effect/Effect';
|
|
7
|
+
import * as Schema from 'effect/Schema';
|
|
6
8
|
|
|
7
9
|
import { Obj, Type } from '@dxos/echo';
|
|
10
|
+
import { type HasId } from '@dxos/echo/internal';
|
|
8
11
|
import { type EchoDatabase } from '@dxos/echo-db';
|
|
9
|
-
import { type HasId } from '@dxos/echo-schema';
|
|
10
12
|
import { assertArgument } from '@dxos/invariant';
|
|
11
13
|
import { type DXN, type SpaceId } from '@dxos/keys';
|
|
12
14
|
import { type QueryResult } from '@dxos/protocols';
|
|
13
15
|
|
|
14
|
-
import { FunctionType } from './schema';
|
|
15
16
|
import { type Services } from './services';
|
|
17
|
+
import { Function } from './types';
|
|
16
18
|
import { getUserFunctionIdInMetadata, setUserFunctionIdInMetadata } from './url';
|
|
17
19
|
|
|
18
20
|
// TODO(burdon): Model after http request. Ref Lambda/OpenFaaS.
|
|
@@ -104,23 +106,25 @@ export type FunctionDefinition<T = any, O = any> = {
|
|
|
104
106
|
* deployedFunctionId:
|
|
105
107
|
* - Backend deployment ID assigned by the EDGE function service (typically a UUID).
|
|
106
108
|
* - Used for remote invocation via `FunctionInvocationService` → `RemoteFunctionExecutionService`.
|
|
107
|
-
* - Persisted on the corresponding ECHO `
|
|
109
|
+
* - Persisted on the corresponding ECHO `Function.Function` object's metadata under the
|
|
108
110
|
* `FUNCTIONS_META_KEY` and retrieved with `getUserFunctionIdInMetadata`.
|
|
109
111
|
*/
|
|
110
112
|
deployedFunctionId?: string;
|
|
111
113
|
};
|
|
112
114
|
};
|
|
113
115
|
|
|
116
|
+
export type FunctionProps<T, O> = {
|
|
117
|
+
key: string;
|
|
118
|
+
name: string;
|
|
119
|
+
description?: string;
|
|
120
|
+
inputSchema: Schema.Schema<T, any>;
|
|
121
|
+
outputSchema?: Schema.Schema<O, any>;
|
|
122
|
+
handler: FunctionHandler<T, O>;
|
|
123
|
+
};
|
|
124
|
+
|
|
114
125
|
// TODO(dmaretskyi): Output type doesn't get typechecked.
|
|
115
126
|
export const defineFunction: {
|
|
116
|
-
<I, O>(params:
|
|
117
|
-
key: string;
|
|
118
|
-
name: string;
|
|
119
|
-
description?: string;
|
|
120
|
-
inputSchema: Schema.Schema<I, any>;
|
|
121
|
-
outputSchema?: Schema.Schema<O, any>;
|
|
122
|
-
handler: Types.NoInfer<FunctionHandler<I, O>>;
|
|
123
|
-
}): FunctionDefinition<I, O>;
|
|
127
|
+
<I, O>(params: FunctionProps<I, O>): FunctionDefinition<I, O>;
|
|
124
128
|
} = ({ key, name, description, inputSchema, outputSchema = Schema.Any, handler }) => {
|
|
125
129
|
if (!Schema.isSchema(inputSchema)) {
|
|
126
130
|
throw new Error('Input schema must be a valid schema');
|
|
@@ -166,7 +170,7 @@ export const defineFunction: {
|
|
|
166
170
|
inputSchema,
|
|
167
171
|
outputSchema,
|
|
168
172
|
handler: handlerWithSpan,
|
|
169
|
-
};
|
|
173
|
+
} satisfies FunctionDefinition.Any;
|
|
170
174
|
};
|
|
171
175
|
|
|
172
176
|
export const FunctionDefinition = {
|
|
@@ -174,12 +178,12 @@ export const FunctionDefinition = {
|
|
|
174
178
|
isFunction: (value: unknown): value is FunctionDefinition.Any => {
|
|
175
179
|
return typeof value === 'object' && value !== null && Symbol.for('@dxos/functions/FunctionDefinition') in value;
|
|
176
180
|
},
|
|
177
|
-
serialize: (functionDef: FunctionDefinition.Any):
|
|
181
|
+
serialize: (functionDef: FunctionDefinition.Any): Function.Function => {
|
|
178
182
|
assertArgument(FunctionDefinition.isFunction(functionDef), 'functionDef');
|
|
179
183
|
return serializeFunction(functionDef);
|
|
180
184
|
},
|
|
181
|
-
deserialize: (functionObj:
|
|
182
|
-
assertArgument(Obj.instanceOf(
|
|
185
|
+
deserialize: (functionObj: Function.Function): FunctionDefinition.Any => {
|
|
186
|
+
assertArgument(Obj.instanceOf(Function.Function, functionObj), 'functionObj');
|
|
183
187
|
return deserializeFunction(functionObj);
|
|
184
188
|
},
|
|
185
189
|
};
|
|
@@ -189,8 +193,8 @@ export declare namespace FunctionDefinition {
|
|
|
189
193
|
export type Output<T extends FunctionDefinition> = T extends FunctionDefinition<any, infer O> ? O : never;
|
|
190
194
|
}
|
|
191
195
|
|
|
192
|
-
export const serializeFunction = (functionDef: FunctionDefinition<any, any>):
|
|
193
|
-
const fn =
|
|
196
|
+
export const serializeFunction = (functionDef: FunctionDefinition<any, any>): Function.Function => {
|
|
197
|
+
const fn = Function.make({
|
|
194
198
|
key: functionDef.key,
|
|
195
199
|
name: functionDef.name,
|
|
196
200
|
version: '0.1.0',
|
|
@@ -204,7 +208,7 @@ export const serializeFunction = (functionDef: FunctionDefinition<any, any>): Fu
|
|
|
204
208
|
return fn;
|
|
205
209
|
};
|
|
206
210
|
|
|
207
|
-
export const deserializeFunction = (functionObj:
|
|
211
|
+
export const deserializeFunction = (functionObj: Function.Function): FunctionDefinition<unknown, unknown> => {
|
|
208
212
|
return {
|
|
209
213
|
[typeId]: true,
|
|
210
214
|
// TODO(dmaretskyi): Fix key.
|
package/src/index.ts
CHANGED
|
@@ -3,12 +3,11 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
export * from './errors';
|
|
6
|
+
export * from './example';
|
|
7
|
+
export * from './executor';
|
|
6
8
|
export * from './handler';
|
|
7
|
-
export * from './
|
|
9
|
+
export * from './services';
|
|
8
10
|
export * from './trace';
|
|
11
|
+
export * from './triggers';
|
|
9
12
|
export * from './types';
|
|
10
13
|
export * from './url';
|
|
11
|
-
export * from './triggers';
|
|
12
|
-
export * from './services';
|
|
13
|
-
export * from './executor';
|
|
14
|
-
export * as exampleFunctions from './examples';
|
|
@@ -2,8 +2,13 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
import
|
|
5
|
+
import * as HttpClient from '@effect/platform/HttpClient';
|
|
6
|
+
import * as HttpClientRequest from '@effect/platform/HttpClientRequest';
|
|
7
|
+
import type * as Config from 'effect/Config';
|
|
8
|
+
import * as Context from 'effect/Context';
|
|
9
|
+
import * as Effect from 'effect/Effect';
|
|
10
|
+
import * as Layer from 'effect/Layer';
|
|
11
|
+
import * as Redacted from 'effect/Redacted';
|
|
7
12
|
|
|
8
13
|
import { Query } from '@dxos/echo';
|
|
9
14
|
import { DataType } from '@dxos/schema';
|
package/src/services/database.ts
CHANGED
|
@@ -2,7 +2,11 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import * as Context from 'effect/Context';
|
|
6
|
+
import * as Effect from 'effect/Effect';
|
|
7
|
+
import * as Layer from 'effect/Layer';
|
|
8
|
+
import * as Option from 'effect/Option';
|
|
9
|
+
import type * as Schema from 'effect/Schema';
|
|
6
10
|
|
|
7
11
|
import {
|
|
8
12
|
type Filter,
|
|
@@ -14,9 +18,9 @@ import {
|
|
|
14
18
|
type Relation,
|
|
15
19
|
type Type,
|
|
16
20
|
} from '@dxos/echo';
|
|
21
|
+
import type { EchoSchema } from '@dxos/echo/internal';
|
|
17
22
|
import type { EchoDatabase, FlushOptions, OneShotQueryResult, QueryResult, SchemaRegistryQuery } from '@dxos/echo-db';
|
|
18
23
|
import type { SchemaRegistryPreparedQuery } from '@dxos/echo-db';
|
|
19
|
-
import type { EchoSchema } from '@dxos/echo-schema';
|
|
20
24
|
import { promiseWithCauseCapture } from '@dxos/effect';
|
|
21
25
|
import { invariant } from '@dxos/invariant';
|
|
22
26
|
import type { DXN } from '@dxos/keys';
|
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import * as Context from 'effect/Context';
|
|
6
|
+
import * as Effect from 'effect/Effect';
|
|
7
|
+
import * as Layer from 'effect/Layer';
|
|
8
|
+
import * as Schema from 'effect/Schema';
|
|
6
9
|
|
|
7
10
|
import { Obj, Type } from '@dxos/echo';
|
|
8
11
|
import { invariant } from '@dxos/invariant';
|
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { describe, expect, it } from '@effect/vitest';
|
|
6
|
-
import
|
|
6
|
+
import * as Effect from 'effect/Effect';
|
|
7
|
+
import * as Layer from 'effect/Layer';
|
|
8
|
+
import * as Schema from 'effect/Schema';
|
|
7
9
|
|
|
8
10
|
import { AiService } from '@dxos/ai';
|
|
9
11
|
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
//
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
|
-
import
|
|
4
|
+
import * as Context from 'effect/Context';
|
|
5
|
+
import * as Effect from 'effect/Effect';
|
|
6
|
+
import * as Layer from 'effect/Layer';
|
|
5
7
|
|
|
6
8
|
import { AiService } from '@dxos/ai';
|
|
7
9
|
|
|
@@ -51,7 +53,7 @@ export class FunctionInvocationService extends Context.Tag('@dxos/functions/Func
|
|
|
51
53
|
static layerTest = ({
|
|
52
54
|
functions = [],
|
|
53
55
|
}: {
|
|
54
|
-
functions?: FunctionDefinition<any, any>[];
|
|
56
|
+
functions?: readonly FunctionDefinition<any, any>[];
|
|
55
57
|
} = {}): Layer.Layer<
|
|
56
58
|
FunctionInvocationService,
|
|
57
59
|
never,
|
|
@@ -71,7 +73,7 @@ export class FunctionInvocationService extends Context.Tag('@dxos/functions/Func
|
|
|
71
73
|
static layerTestMocked = ({
|
|
72
74
|
functions,
|
|
73
75
|
}: {
|
|
74
|
-
functions
|
|
76
|
+
functions?: readonly FunctionDefinition<any, any>[];
|
|
75
77
|
}): Layer.Layer<FunctionInvocationService> =>
|
|
76
78
|
FunctionInvocationService.layerTest({ functions }).pipe(
|
|
77
79
|
Layer.provide(AiService.notAvailable),
|
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import * as Context from 'effect/Context';
|
|
6
|
+
import * as Effect from 'effect/Effect';
|
|
7
|
+
import * as Layer from 'effect/Layer';
|
|
8
|
+
import * as Schema from 'effect/Schema';
|
|
6
9
|
|
|
7
10
|
import { AiService } from '@dxos/ai';
|
|
8
11
|
import { todo } from '@dxos/debug';
|
|
@@ -16,7 +19,7 @@ import { DatabaseService } from './database';
|
|
|
16
19
|
import { type ComputeEventLogger } from './event-logger';
|
|
17
20
|
import { QueueService } from './queues';
|
|
18
21
|
import { RemoteFunctionExecutionService } from './remote-function-execution-service';
|
|
19
|
-
import type
|
|
22
|
+
import { type Services } from './service-container';
|
|
20
23
|
import { type TracingService } from './tracing';
|
|
21
24
|
|
|
22
25
|
/**
|
|
@@ -76,7 +79,7 @@ const invokeFunction = (
|
|
|
76
79
|
input: any,
|
|
77
80
|
): Effect.Effect<unknown, never, Services> =>
|
|
78
81
|
Effect.gen(function* () {
|
|
79
|
-
// Assert input matches schema
|
|
82
|
+
// Assert input matches schema.
|
|
80
83
|
try {
|
|
81
84
|
const assertInput = functionDef.inputSchema.pipe(Schema.asserts);
|
|
82
85
|
(assertInput as any)(input);
|
|
@@ -92,7 +95,7 @@ const invokeFunction = (
|
|
|
92
95
|
},
|
|
93
96
|
};
|
|
94
97
|
|
|
95
|
-
log.info('
|
|
98
|
+
log.info('invoking function', { name: functionDef.name, input });
|
|
96
99
|
|
|
97
100
|
// TODO(dmaretskyi): This should be delegated to a function invoker service.
|
|
98
101
|
const data = yield* Effect.gen(function* () {
|
|
@@ -116,9 +119,9 @@ const invokeFunction = (
|
|
|
116
119
|
),
|
|
117
120
|
);
|
|
118
121
|
|
|
119
|
-
log.info('
|
|
122
|
+
log.info('completed', { function: functionDef.name, input, data });
|
|
120
123
|
|
|
121
|
-
// Assert output matches schema
|
|
124
|
+
// Assert output matches schema.
|
|
122
125
|
try {
|
|
123
126
|
const assertOutput = functionDef.outputSchema?.pipe(Schema.asserts);
|
|
124
127
|
(assertOutput as any)(data);
|
|
@@ -137,7 +140,7 @@ export class FunctionImplementationResolver extends Context.Tag('@dxos/functions
|
|
|
137
140
|
): Effect.Effect<FunctionDefinition<I, O>, FunctionNotFoundError>;
|
|
138
141
|
}
|
|
139
142
|
>() {
|
|
140
|
-
static layerTest = ({ functions }: { functions: FunctionDefinition<any, any>[] }) =>
|
|
143
|
+
static layerTest = ({ functions }: { functions: readonly FunctionDefinition<any, any>[] }) =>
|
|
141
144
|
Layer.succeed(FunctionImplementationResolver, {
|
|
142
145
|
resolveFunctionImplementation: <I, O>(functionDef: FunctionDefinition<I, O>) => {
|
|
143
146
|
const resolved = functions.find((f) => f.key === functionDef.key);
|
package/src/services/queues.ts
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import * as Context from 'effect/Context';
|
|
6
|
+
import * as Effect from 'effect/Effect';
|
|
7
|
+
import * as Layer from 'effect/Layer';
|
|
6
8
|
|
|
7
9
|
import type { Obj, Relation } from '@dxos/echo';
|
|
8
10
|
import type { Queue, QueueAPI, QueueFactory } from '@dxos/echo-db';
|
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import * as Context from 'effect/Context';
|
|
6
|
+
import * as Effect from 'effect/Effect';
|
|
7
|
+
import * as Layer from 'effect/Layer';
|
|
6
8
|
|
|
7
9
|
import type { SpaceId } from '@dxos/keys';
|
|
8
10
|
|
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { describe, it } from '@effect/vitest';
|
|
6
|
-
import
|
|
6
|
+
import * as Context from 'effect/Context';
|
|
7
|
+
import * as Effect from 'effect/Effect';
|
|
8
|
+
import * as Layer from 'effect/Layer';
|
|
9
|
+
import * as Option from 'effect/Option';
|
|
7
10
|
|
|
8
11
|
import { ServiceRegistry } from './service-registry';
|
|
9
12
|
|
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import * as Context from 'effect/Context';
|
|
6
|
+
import * as Effect from 'effect/Effect';
|
|
7
|
+
import * as Function from 'effect/Function';
|
|
8
|
+
import type * as Option from 'effect/Option';
|
|
6
9
|
|
|
7
10
|
import { ServiceNotAvailableError } from '../errors';
|
|
8
11
|
|
|
@@ -40,7 +43,8 @@ export class ServiceRegistry extends Context.Tag('@dxos/functions/ServiceRegistr
|
|
|
40
43
|
E | ServiceNotAvailableError,
|
|
41
44
|
Exclude<R, { [K in keyof Tags]: Context.Tag.Identifier<Tags[K]> }[number]> | ServiceRegistry
|
|
42
45
|
>;
|
|
43
|
-
} = (...tags) =>
|
|
46
|
+
} = (...tags) =>
|
|
47
|
+
(Function.flow as any)(...tags.map((tag) => Effect.provideServiceEffect(tag, ServiceRegistry.resolve(tag))));
|
|
44
48
|
|
|
45
49
|
static provideOrDie: {
|
|
46
50
|
<Tags extends [Context.Tag<any, any>, ...Context.Tag<any, any>[]]>(
|
|
@@ -53,7 +57,7 @@ export class ServiceRegistry extends Context.Tag('@dxos/functions/ServiceRegistr
|
|
|
53
57
|
Exclude<R, { [K in keyof Tags]: Context.Tag.Identifier<Tags[K]> }[number]> | ServiceRegistry
|
|
54
58
|
>;
|
|
55
59
|
} = (...tags) =>
|
|
56
|
-
(flow as any)(
|
|
60
|
+
(Function.flow as any)(
|
|
57
61
|
...tags.map((tag) => Effect.provideServiceEffect(tag, ServiceRegistry.resolve(tag).pipe(Effect.orDie))),
|
|
58
62
|
);
|
|
59
63
|
}
|
package/src/services/tracing.ts
CHANGED
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import * as Context from 'effect/Context';
|
|
6
|
+
import * as Effect from 'effect/Effect';
|
|
7
|
+
import * as Layer from 'effect/Layer';
|
|
6
8
|
|
|
7
9
|
import { AgentStatus } from '@dxos/ai';
|
|
8
10
|
import { Obj } from '@dxos/echo';
|
|
11
|
+
import type { ObjectId } from '@dxos/echo/internal';
|
|
9
12
|
import type { Queue } from '@dxos/echo-db';
|
|
10
|
-
import type { ObjectId } from '@dxos/echo-schema';
|
|
11
13
|
import { log } from '@dxos/log';
|
|
12
14
|
import { DataType } from '@dxos/schema';
|
|
13
15
|
|