@dxos/functions 0.5.3-main.d7fe7b5 → 0.5.3-main.e76d664
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/index.mjs +429 -802
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +426 -787
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/types/src/handler.d.ts +12 -33
- package/dist/types/src/handler.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +0 -2
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/runtime/dev-server.d.ts +13 -16
- package/dist/types/src/runtime/dev-server.d.ts.map +1 -1
- package/dist/types/src/runtime/scheduler.d.ts +27 -12
- package/dist/types/src/runtime/scheduler.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +101 -129
- package/dist/types/src/types.d.ts.map +1 -1
- package/package.json +13 -18
- package/schema/functions.json +101 -128
- package/src/handler.ts +31 -54
- package/src/index.ts +0 -2
- package/src/runtime/dev-server.ts +52 -104
- package/src/runtime/scheduler.test.ts +73 -56
- package/src/runtime/scheduler.ts +271 -79
- package/src/types.ts +32 -57
- package/dist/types/src/registry/function-registry.d.ts +0 -24
- package/dist/types/src/registry/function-registry.d.ts.map +0 -1
- package/dist/types/src/registry/function-registry.test.d.ts +0 -2
- package/dist/types/src/registry/function-registry.test.d.ts.map +0 -1
- package/dist/types/src/registry/index.d.ts +0 -2
- package/dist/types/src/registry/index.d.ts.map +0 -1
- package/dist/types/src/runtime/dev-server.test.d.ts +0 -2
- package/dist/types/src/runtime/dev-server.test.d.ts.map +0 -1
- package/dist/types/src/testing/functions-integration.test.d.ts +0 -2
- package/dist/types/src/testing/functions-integration.test.d.ts.map +0 -1
- package/dist/types/src/testing/index.d.ts +0 -4
- package/dist/types/src/testing/index.d.ts.map +0 -1
- package/dist/types/src/testing/setup.d.ts +0 -5
- package/dist/types/src/testing/setup.d.ts.map +0 -1
- package/dist/types/src/testing/test/handler.d.ts +0 -4
- package/dist/types/src/testing/test/handler.d.ts.map +0 -1
- package/dist/types/src/testing/test/index.d.ts +0 -3
- package/dist/types/src/testing/test/index.d.ts.map +0 -1
- package/dist/types/src/testing/types.d.ts +0 -9
- package/dist/types/src/testing/types.d.ts.map +0 -1
- package/dist/types/src/testing/util.d.ts +0 -3
- package/dist/types/src/testing/util.d.ts.map +0 -1
- package/dist/types/src/trigger/index.d.ts +0 -2
- package/dist/types/src/trigger/index.d.ts.map +0 -1
- package/dist/types/src/trigger/trigger-registry.d.ts +0 -40
- package/dist/types/src/trigger/trigger-registry.d.ts.map +0 -1
- package/dist/types/src/trigger/trigger-registry.test.d.ts +0 -2
- package/dist/types/src/trigger/trigger-registry.test.d.ts.map +0 -1
- package/dist/types/src/trigger/type/index.d.ts +0 -5
- package/dist/types/src/trigger/type/index.d.ts.map +0 -1
- package/dist/types/src/trigger/type/subscription-trigger.d.ts +0 -4
- package/dist/types/src/trigger/type/subscription-trigger.d.ts.map +0 -1
- package/dist/types/src/trigger/type/timer-trigger.d.ts +0 -4
- package/dist/types/src/trigger/type/timer-trigger.d.ts.map +0 -1
- package/dist/types/src/trigger/type/webhook-trigger.d.ts +0 -4
- package/dist/types/src/trigger/type/webhook-trigger.d.ts.map +0 -1
- package/dist/types/src/trigger/type/websocket-trigger.d.ts +0 -13
- package/dist/types/src/trigger/type/websocket-trigger.d.ts.map +0 -1
- package/src/registry/function-registry.test.ts +0 -105
- package/src/registry/function-registry.ts +0 -84
- package/src/registry/index.ts +0 -5
- package/src/runtime/dev-server.test.ts +0 -60
- package/src/testing/functions-integration.test.ts +0 -99
- package/src/testing/index.ts +0 -7
- package/src/testing/setup.ts +0 -45
- package/src/testing/test/handler.ts +0 -15
- package/src/testing/test/index.ts +0 -7
- package/src/testing/types.ts +0 -9
- package/src/testing/util.ts +0 -16
- package/src/trigger/index.ts +0 -5
- package/src/trigger/trigger-registry.test.ts +0 -229
- package/src/trigger/trigger-registry.ts +0 -176
- package/src/trigger/type/index.ts +0 -8
- package/src/trigger/type/subscription-trigger.ts +0 -73
- package/src/trigger/type/timer-trigger.ts +0 -44
- package/src/trigger/type/webhook-trigger.ts +0 -47
- package/src/trigger/type/websocket-trigger.ts +0 -91
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { Event } from '@dxos/async';
|
|
2
|
-
import { type Client } from '@dxos/client';
|
|
3
|
-
import { type Space } from '@dxos/client/echo';
|
|
4
|
-
import { Context, Resource } from '@dxos/context';
|
|
5
|
-
import { type FunctionManifest, FunctionTrigger, type FunctionTriggerType, type TriggerSpec } from '../types';
|
|
6
|
-
type ResponseCode = number;
|
|
7
|
-
export type TriggerCallback = (args: object) => Promise<ResponseCode>;
|
|
8
|
-
export type TriggerContext = {
|
|
9
|
-
space: Space;
|
|
10
|
-
};
|
|
11
|
-
export type TriggerFactory<Spec extends TriggerSpec, Options = any> = (ctx: Context, context: TriggerContext, spec: Spec, callback: TriggerCallback, options?: Options) => Promise<void>;
|
|
12
|
-
export type TriggerHandlerMap = {
|
|
13
|
-
[type in FunctionTriggerType]: TriggerFactory<any>;
|
|
14
|
-
};
|
|
15
|
-
export type TriggerEvent = {
|
|
16
|
-
space: Space;
|
|
17
|
-
triggers: FunctionTrigger[];
|
|
18
|
-
};
|
|
19
|
-
export declare class TriggerRegistry extends Resource {
|
|
20
|
-
private readonly _client;
|
|
21
|
-
private readonly _options?;
|
|
22
|
-
private readonly _triggersBySpaceKey;
|
|
23
|
-
readonly registered: Event<TriggerEvent>;
|
|
24
|
-
readonly removed: Event<TriggerEvent>;
|
|
25
|
-
constructor(_client: Client, _options?: TriggerHandlerMap | undefined);
|
|
26
|
-
getActiveTriggers(space: Space): FunctionTrigger[];
|
|
27
|
-
getInactiveTriggers(space: Space): FunctionTrigger[];
|
|
28
|
-
activate(triggerCtx: TriggerContext, trigger: FunctionTrigger, callback: TriggerCallback): Promise<void>;
|
|
29
|
-
/**
|
|
30
|
-
* Loads triggers from the manifest into the space.
|
|
31
|
-
*/
|
|
32
|
-
register(space: Space, manifest: FunctionManifest): Promise<void>;
|
|
33
|
-
protected _open(): Promise<void>;
|
|
34
|
-
protected _close(_: Context): Promise<void>;
|
|
35
|
-
private _handleNewTriggers;
|
|
36
|
-
private _handleRemovedTriggers;
|
|
37
|
-
private _getTriggers;
|
|
38
|
-
}
|
|
39
|
-
export {};
|
|
40
|
-
//# sourceMappingURL=trigger-registry.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"trigger-registry.d.ts","sourceRoot":"","sources":["../../../../src/trigger/trigger-registry.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAkB,KAAK,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAOlD,OAAO,EAAE,KAAK,gBAAgB,EAAE,eAAe,EAAE,KAAK,mBAAmB,EAAE,KAAK,WAAW,EAAE,MAAM,UAAU,CAAC;AAE9G,KAAK,YAAY,GAAG,MAAM,CAAC;AAE3B,MAAM,MAAM,eAAe,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;AAEtE,MAAM,MAAM,cAAc,GAAG;IAAE,KAAK,EAAE,KAAK,CAAA;CAAE,CAAC;AAG9C,MAAM,MAAM,cAAc,CAAC,IAAI,SAAS,WAAW,EAAE,OAAO,GAAG,GAAG,IAAI,CACpE,GAAG,EAAE,OAAO,EACZ,OAAO,EAAE,cAAc,EACvB,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,eAAe,EACzB,OAAO,CAAC,EAAE,OAAO,KACd,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnB,MAAM,MAAM,iBAAiB,GAAG;KAAG,IAAI,IAAI,mBAAmB,GAAG,cAAc,CAAC,GAAG,CAAC;CAAE,CAAC;AASvF,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,KAAK,CAAC;IACb,QAAQ,EAAE,eAAe,EAAE,CAAC;CAC7B,CAAC;AAOF,qBAAa,eAAgB,SAAQ,QAAQ;IAOzC,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;IAP5B,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAkE;IAEtG,SAAgB,UAAU,sBAA6B;IACvD,SAAgB,OAAO,sBAA6B;gBAGjC,OAAO,EAAE,MAAM,EACf,QAAQ,CAAC,+BAAmB;IAKxC,iBAAiB,CAAC,KAAK,EAAE,KAAK,GAAG,eAAe,EAAE;IAIlD,mBAAmB,CAAC,KAAK,EAAE,KAAK,GAAG,eAAe,EAAE;IAIrD,QAAQ,CAAC,UAAU,EAAE,cAAc,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAmB9G;;OAEG;IACU,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;cAerD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;cAyBtB,MAAM,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAI1D,OAAO,CAAC,kBAAkB;YAaZ,sBAAsB;IAqBpC,OAAO,CAAC,YAAY;CAIrB"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"trigger-registry.test.d.ts","sourceRoot":"","sources":["../../../../src/trigger/trigger-registry.test.ts"],"names":[],"mappings":""}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/trigger/type/index.ts"],"names":[],"mappings":"AAIA,cAAc,wBAAwB,CAAC;AACvC,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"subscription-trigger.d.ts","sourceRoot":"","sources":["../../../../../src/trigger/type/subscription-trigger.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAA6C,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErG,eAAO,MAAM,yBAAyB,EAAE,cAAc,CAAC,mBAAmB,CA2DzE,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"timer-trigger.d.ts","sourceRoot":"","sources":["../../../../../src/trigger/type/timer-trigger.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAA6C,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErG,eAAO,MAAM,kBAAkB,EAAE,cAAc,CAAC,YAAY,CA8B3D,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"webhook-trigger.d.ts","sourceRoot":"","sources":["../../../../../src/trigger/type/webhook-trigger.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAA6C,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErG,eAAO,MAAM,oBAAoB,EAAE,cAAc,CAAC,cAAc,CAiC/D,CAAC"}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { type WebsocketTrigger } from '../../types';
|
|
2
|
-
import { type TriggerFactory } from '../trigger-registry';
|
|
3
|
-
interface WebsocketTriggerOptions {
|
|
4
|
-
retryDelay: number;
|
|
5
|
-
maxAttempts: number;
|
|
6
|
-
}
|
|
7
|
-
/**
|
|
8
|
-
* Websocket.
|
|
9
|
-
* NOTE: The port must be unique, so the same hook cannot be used for multiple spaces.
|
|
10
|
-
*/
|
|
11
|
-
export declare const createWebsocketTrigger: TriggerFactory<WebsocketTrigger, WebsocketTriggerOptions>;
|
|
12
|
-
export {};
|
|
13
|
-
//# sourceMappingURL=websocket-trigger.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"websocket-trigger.d.ts","sourceRoot":"","sources":["../../../../../src/trigger/type/websocket-trigger.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAA6C,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErG,UAAU,uBAAuB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;GAGG;AACH,eAAO,MAAM,sBAAsB,EAAE,cAAc,CAAC,gBAAgB,EAAE,uBAAuB,CAoE5F,CAAC"}
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2023 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import { expect } from 'chai';
|
|
6
|
-
|
|
7
|
-
import { Trigger } from '@dxos/async';
|
|
8
|
-
import { type Client } from '@dxos/client';
|
|
9
|
-
import { TestBuilder } from '@dxos/client/testing';
|
|
10
|
-
import { Context } from '@dxos/context';
|
|
11
|
-
import { Filter } from '@dxos/echo-db';
|
|
12
|
-
import { create } from '@dxos/echo-schema';
|
|
13
|
-
import { describe, test } from '@dxos/test';
|
|
14
|
-
import { range } from '@dxos/util';
|
|
15
|
-
|
|
16
|
-
import { FunctionRegistry } from './function-registry';
|
|
17
|
-
import { createInitializedClients } from '../testing';
|
|
18
|
-
import { FunctionDef, type FunctionManifest } from '../types';
|
|
19
|
-
|
|
20
|
-
const testManifest: FunctionManifest = {
|
|
21
|
-
functions: [
|
|
22
|
-
{
|
|
23
|
-
uri: 'dxos.functions.test/hello',
|
|
24
|
-
route: '/hello',
|
|
25
|
-
handler: 'test',
|
|
26
|
-
},
|
|
27
|
-
],
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
describe('function registry', () => {
|
|
31
|
-
let ctx: Context;
|
|
32
|
-
let testBuilder: TestBuilder;
|
|
33
|
-
beforeEach(async () => {
|
|
34
|
-
ctx = new Context();
|
|
35
|
-
testBuilder = new TestBuilder();
|
|
36
|
-
});
|
|
37
|
-
afterEach(async () => {
|
|
38
|
-
await ctx.dispose();
|
|
39
|
-
await testBuilder.destroy();
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
describe('register', () => {
|
|
43
|
-
test('creates new functions', async () => {
|
|
44
|
-
const client = (await createInitializedClients(testBuilder))[0];
|
|
45
|
-
const registry = createRegistry(client);
|
|
46
|
-
const space = await client.spaces.create();
|
|
47
|
-
await registry.register(space, testManifest);
|
|
48
|
-
const { objects: definitions } = await space.db.query(Filter.schema(FunctionDef)).run();
|
|
49
|
-
expect(definitions.length).to.eq(1);
|
|
50
|
-
expect(definitions[0].uri).to.eq(testManifest.functions?.[0]?.uri);
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
test('de-duplicates by function URI', async () => {
|
|
54
|
-
const client = (await createInitializedClients(testBuilder))[0];
|
|
55
|
-
const registry = createRegistry(client);
|
|
56
|
-
const space = await client.spaces.create();
|
|
57
|
-
const existing = space.db.add(create(FunctionDef, { ...testManifest.functions![0] }));
|
|
58
|
-
await registry.register(space, testManifest);
|
|
59
|
-
const { objects: definitions } = await space.db.query(Filter.schema(FunctionDef)).run();
|
|
60
|
-
expect(definitions.length).to.eq(1);
|
|
61
|
-
expect(definitions[0].uri).to.eq(existing.uri);
|
|
62
|
-
});
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
describe('onFunctionsRegistered', () => {
|
|
66
|
-
test('called with all registered when opened', async () => {
|
|
67
|
-
const client = (await createInitializedClients(testBuilder))[0];
|
|
68
|
-
const registry = createRegistry(client);
|
|
69
|
-
const space = await client.spaces.create();
|
|
70
|
-
const definitions = range(3, () => create(FunctionDef, { ...testManifest.functions![0] }));
|
|
71
|
-
definitions.forEach((def) => space.db.add(def));
|
|
72
|
-
|
|
73
|
-
const functionRegistered = new Trigger<FunctionDef[]>();
|
|
74
|
-
registry.onFunctionsRegistered.on((fn) => {
|
|
75
|
-
functionRegistered.wake(fn.newFunctions);
|
|
76
|
-
});
|
|
77
|
-
void registry.open(ctx);
|
|
78
|
-
const functions = await functionRegistered.wait();
|
|
79
|
-
const expected = definitions.map((def) => def.uri).sort();
|
|
80
|
-
expect(functions.map((fn) => fn.uri).sort()).to.deep.eq(expected);
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
test('called when a new functions is added', async () => {
|
|
84
|
-
const client = (await createInitializedClients(testBuilder))[0];
|
|
85
|
-
const registry = createRegistry(client);
|
|
86
|
-
const space = await client.spaces.create();
|
|
87
|
-
|
|
88
|
-
const functionRegistered = new Trigger<FunctionDef>();
|
|
89
|
-
registry.onFunctionsRegistered.on((fn) => {
|
|
90
|
-
expect(fn.newFunctions.length).to.eq(1);
|
|
91
|
-
functionRegistered.wake(fn.newFunctions[0]);
|
|
92
|
-
});
|
|
93
|
-
await registry.open(ctx);
|
|
94
|
-
await registry.register(space, testManifest);
|
|
95
|
-
const registered = await functionRegistered.wait();
|
|
96
|
-
expect(registered.uri).to.eq(testManifest.functions![0].uri);
|
|
97
|
-
});
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
const createRegistry = (client: Client) => {
|
|
101
|
-
const registry = new FunctionRegistry(client);
|
|
102
|
-
ctx.onDispose(() => registry.close());
|
|
103
|
-
return registry;
|
|
104
|
-
};
|
|
105
|
-
});
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2024 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import { Event } from '@dxos/async';
|
|
6
|
-
import { type Client } from '@dxos/client';
|
|
7
|
-
import { create, Filter, type Space } from '@dxos/client/echo';
|
|
8
|
-
import { type Context, Resource } from '@dxos/context';
|
|
9
|
-
import { PublicKey } from '@dxos/keys';
|
|
10
|
-
import { ComplexMap } from '@dxos/util';
|
|
11
|
-
|
|
12
|
-
import { FunctionDef, type FunctionManifest } from '../types';
|
|
13
|
-
|
|
14
|
-
export type FunctionsRegisteredEvent = {
|
|
15
|
-
space: Space;
|
|
16
|
-
newFunctions: FunctionDef[];
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export class FunctionRegistry extends Resource {
|
|
20
|
-
private readonly _functionBySpaceKey = new ComplexMap<PublicKey, FunctionDef[]>(PublicKey.hash);
|
|
21
|
-
|
|
22
|
-
public readonly onFunctionsRegistered = new Event<FunctionsRegisteredEvent>();
|
|
23
|
-
|
|
24
|
-
constructor(private readonly _client: Client) {
|
|
25
|
-
super();
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
public getFunctions(space: Space): FunctionDef[] {
|
|
29
|
-
return this._functionBySpaceKey.get(space.key) ?? [];
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* The method loads function definitions from the manifest into the space.
|
|
34
|
-
* We first load all the definitions from the space to deduplicate by functionId.
|
|
35
|
-
*/
|
|
36
|
-
// TODO(burdon): This should not be space specific (they are static for the agent).
|
|
37
|
-
public async register(space: Space, manifest: FunctionManifest): Promise<void> {
|
|
38
|
-
if (!manifest.functions?.length) {
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
if (!space.db.graph.runtimeSchemaRegistry.isSchemaRegistered(FunctionDef)) {
|
|
42
|
-
space.db.graph.runtimeSchemaRegistry.registerSchema(FunctionDef);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const { objects: existingDefinitions } = await space.db.query(Filter.schema(FunctionDef)).run();
|
|
46
|
-
const newDefinitions = getNewDefinitions(manifest.functions, existingDefinitions);
|
|
47
|
-
const reactiveObjects = newDefinitions.map((template) => create(FunctionDef, { ...template }));
|
|
48
|
-
reactiveObjects.forEach((obj) => space.db.add(obj));
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
protected override async _open(): Promise<void> {
|
|
52
|
-
const spaceListSubscription = this._client.spaces.subscribe(async (spaces) => {
|
|
53
|
-
for (const space of spaces) {
|
|
54
|
-
if (this._functionBySpaceKey.has(space.key)) {
|
|
55
|
-
continue;
|
|
56
|
-
}
|
|
57
|
-
const registered: FunctionDef[] = [];
|
|
58
|
-
this._functionBySpaceKey.set(space.key, registered);
|
|
59
|
-
await space.waitUntilReady();
|
|
60
|
-
if (this._ctx.disposed) {
|
|
61
|
-
break;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const functionsSubscription = space.db.query(Filter.schema(FunctionDef)).subscribe((definitions) => {
|
|
65
|
-
const newFunctions = getNewDefinitions(definitions.objects, registered);
|
|
66
|
-
if (newFunctions.length > 0) {
|
|
67
|
-
registered.push(...newFunctions);
|
|
68
|
-
this.onFunctionsRegistered.emit({ space, newFunctions });
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
this._ctx.onDispose(functionsSubscription);
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
this._ctx.onDispose(() => spaceListSubscription.unsubscribe());
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
protected override async _close(_: Context): Promise<void> {
|
|
78
|
-
this._functionBySpaceKey.clear();
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const getNewDefinitions = <T extends { uri: string }>(candidateList: T[], existing: FunctionDef[]): T[] => {
|
|
83
|
-
return candidateList.filter((candidate) => existing.find((def) => def.uri === candidate.uri) == null);
|
|
84
|
-
};
|
package/src/registry/index.ts
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2023 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import { expect } from 'chai';
|
|
6
|
-
import path from 'path';
|
|
7
|
-
|
|
8
|
-
import { waitForCondition } from '@dxos/async';
|
|
9
|
-
import { type Client } from '@dxos/client';
|
|
10
|
-
import { TestBuilder } from '@dxos/client/testing';
|
|
11
|
-
import { describe, test } from '@dxos/test';
|
|
12
|
-
|
|
13
|
-
import { DevServer } from './dev-server';
|
|
14
|
-
import { FunctionRegistry } from '../registry';
|
|
15
|
-
import { createFunctionRuntime } from '../testing';
|
|
16
|
-
import { type FunctionManifest } from '../types';
|
|
17
|
-
|
|
18
|
-
describe('dev server', () => {
|
|
19
|
-
let client: Client;
|
|
20
|
-
let testBuilder: TestBuilder;
|
|
21
|
-
before(async () => {
|
|
22
|
-
testBuilder = new TestBuilder();
|
|
23
|
-
client = await createFunctionRuntime(testBuilder);
|
|
24
|
-
expect(client.services.services.FunctionRegistryService).to.exist;
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
after(async () => {
|
|
28
|
-
await testBuilder.destroy();
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
test('start/stop', async () => {
|
|
32
|
-
const manifest: FunctionManifest = {
|
|
33
|
-
functions: [
|
|
34
|
-
{
|
|
35
|
-
uri: 'example.com/function/test',
|
|
36
|
-
route: 'test',
|
|
37
|
-
handler: 'test',
|
|
38
|
-
},
|
|
39
|
-
],
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
const registry = new FunctionRegistry(client);
|
|
43
|
-
const server = new DevServer(client, registry, {
|
|
44
|
-
baseDir: path.join(__dirname, '../testing'),
|
|
45
|
-
});
|
|
46
|
-
const space = await client.spaces.create();
|
|
47
|
-
await registry.register(space, manifest);
|
|
48
|
-
await server.start();
|
|
49
|
-
|
|
50
|
-
// TODO(burdon): Doesn't shut down cleanly.
|
|
51
|
-
// Error: invariant violation [this._client.services.services.FunctionRegistryService]
|
|
52
|
-
testBuilder.ctx.onDispose(() => server.stop());
|
|
53
|
-
expect(server).to.exist;
|
|
54
|
-
|
|
55
|
-
await waitForCondition({ condition: () => server.functions.length > 0 });
|
|
56
|
-
|
|
57
|
-
await server.invoke('test', {});
|
|
58
|
-
expect(server.stats.seq).to.eq(1);
|
|
59
|
-
});
|
|
60
|
-
});
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2024 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import { expect } from 'chai';
|
|
6
|
-
import path from 'path';
|
|
7
|
-
|
|
8
|
-
import { Trigger, waitForCondition } from '@dxos/async';
|
|
9
|
-
import { type Client } from '@dxos/client';
|
|
10
|
-
import { create, type Space } from '@dxos/client/echo';
|
|
11
|
-
import { performInvitation, TestBuilder } from '@dxos/client/testing';
|
|
12
|
-
import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
|
|
13
|
-
import { describe, test } from '@dxos/test';
|
|
14
|
-
|
|
15
|
-
import { setTestCallHandler } from './test/handler';
|
|
16
|
-
import { FunctionRegistry } from '../registry';
|
|
17
|
-
import { DevServer, Scheduler } from '../runtime';
|
|
18
|
-
import { createFunctionRuntime, createInitializedClients, TestType } from '../testing';
|
|
19
|
-
import { TriggerRegistry } from '../trigger';
|
|
20
|
-
import { FunctionDef, FunctionTrigger } from '../types';
|
|
21
|
-
|
|
22
|
-
describe('functions e2e', () => {
|
|
23
|
-
let testBuilder: TestBuilder;
|
|
24
|
-
before(async () => {
|
|
25
|
-
testBuilder = new TestBuilder();
|
|
26
|
-
});
|
|
27
|
-
after(async () => {
|
|
28
|
-
await testBuilder.destroy();
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
test('a function gets triggered in response to another peer object creations', async () => {
|
|
32
|
-
// TODO(burdon): Create builder pattern.
|
|
33
|
-
const functionRuntime = await createFunctionRuntime(testBuilder);
|
|
34
|
-
const devServer = await startDevServer(functionRuntime);
|
|
35
|
-
const scheduler = await startScheduler(functionRuntime, devServer);
|
|
36
|
-
|
|
37
|
-
const app = (await createInitializedClients(testBuilder, 1))[0];
|
|
38
|
-
const space = await app.spaces.create();
|
|
39
|
-
await inviteMember(space, functionRuntime);
|
|
40
|
-
|
|
41
|
-
const uri = 'example.com/function/test';
|
|
42
|
-
space.db.add(create(FunctionDef, { uri, route: '/test', handler: 'test' }));
|
|
43
|
-
const triggerMeta: FunctionTrigger['meta'] = { name: 'DXOS' };
|
|
44
|
-
space.db.add(
|
|
45
|
-
create(FunctionTrigger, {
|
|
46
|
-
function: uri,
|
|
47
|
-
meta: triggerMeta,
|
|
48
|
-
spec: {
|
|
49
|
-
type: 'subscription',
|
|
50
|
-
filter: [{ type: TestType.typename }],
|
|
51
|
-
},
|
|
52
|
-
}),
|
|
53
|
-
);
|
|
54
|
-
|
|
55
|
-
const called = new Trigger<any>();
|
|
56
|
-
setTestCallHandler(async (args) => {
|
|
57
|
-
called.wake(args.event.data);
|
|
58
|
-
return args.response.status(200);
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
await waitTriggersReplicated(space, scheduler);
|
|
62
|
-
const addedObject = space.db.add(create(TestType, { title: '42' }));
|
|
63
|
-
|
|
64
|
-
const callArgs = await called.wait();
|
|
65
|
-
expect(callArgs.meta).to.deep.eq(triggerMeta);
|
|
66
|
-
expect(callArgs.objects).to.deep.eq([addedObject.id]);
|
|
67
|
-
expect(callArgs.spaceKey).to.eq(space.key.toHex());
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
const waitTriggersReplicated = async (space: Space, scheduler: Scheduler) => {
|
|
71
|
-
await waitForCondition({ condition: () => scheduler.triggers.getActiveTriggers(space).length > 0 });
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
// TODO(burdon): Factor out utils to builder pattern.
|
|
75
|
-
|
|
76
|
-
const startScheduler = async (client: Client, devServer: DevServer) => {
|
|
77
|
-
const functionRegistry = new FunctionRegistry(client);
|
|
78
|
-
const triggerRegistry = new TriggerRegistry(client);
|
|
79
|
-
const scheduler = new Scheduler(functionRegistry, triggerRegistry, { endpoint: devServer.endpoint });
|
|
80
|
-
await scheduler.start();
|
|
81
|
-
testBuilder.ctx.onDispose(() => scheduler.stop());
|
|
82
|
-
return scheduler;
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
const startDevServer = async (client: Client) => {
|
|
86
|
-
const functionRegistry = new FunctionRegistry(client);
|
|
87
|
-
const server = new DevServer(client, functionRegistry, {
|
|
88
|
-
baseDir: path.join(__dirname, '../testing'),
|
|
89
|
-
});
|
|
90
|
-
await server.start();
|
|
91
|
-
testBuilder.ctx.onDispose(() => server.stop());
|
|
92
|
-
return server;
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
const inviteMember = async (host: Space, guest: Client) => {
|
|
96
|
-
const [{ invitation: hostInvitation }] = await Promise.all(performInvitation({ host, guest: guest.spaces }));
|
|
97
|
-
expect(hostInvitation?.state).to.eq(Invitation.State.SUCCESS);
|
|
98
|
-
};
|
|
99
|
-
});
|
package/src/testing/index.ts
DELETED
package/src/testing/setup.ts
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2024 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import { FunctionsPlugin } from '@dxos/agent';
|
|
6
|
-
import { Client, Config } from '@dxos/client';
|
|
7
|
-
import { type TestBuilder } from '@dxos/client/testing';
|
|
8
|
-
import { range } from '@dxos/util';
|
|
9
|
-
|
|
10
|
-
import { TestType } from './types';
|
|
11
|
-
import { FunctionDef, FunctionTrigger } from '../types';
|
|
12
|
-
|
|
13
|
-
// TODO(burdon): Create TestBuilder.
|
|
14
|
-
|
|
15
|
-
export const createInitializedClients = async (testBuilder: TestBuilder, count: number = 1, config?: Config) => {
|
|
16
|
-
const clients = range(count).map(() => new Client({ config, services: testBuilder.createLocalClientServices() }));
|
|
17
|
-
testBuilder.ctx.onDispose(() => Promise.all(clients.map((c) => c.destroy())));
|
|
18
|
-
return Promise.all(
|
|
19
|
-
clients.map(async (client, index) => {
|
|
20
|
-
await client.initialize();
|
|
21
|
-
await client.halo.createIdentity({ displayName: `Peer ${index}` });
|
|
22
|
-
client.addSchema(TestType, FunctionDef, FunctionTrigger);
|
|
23
|
-
return client;
|
|
24
|
-
}),
|
|
25
|
-
);
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
export const createFunctionRuntime = async (testBuilder: TestBuilder): Promise<Client> => {
|
|
29
|
-
const config = new Config({
|
|
30
|
-
runtime: {
|
|
31
|
-
agent: {
|
|
32
|
-
plugins: [{ id: 'dxos.org/agent/plugin/functions', config: { port: 8080 } }],
|
|
33
|
-
},
|
|
34
|
-
},
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
const client = (await createInitializedClients(testBuilder, 1, config))[0];
|
|
38
|
-
|
|
39
|
-
// TODO(burdon): Better way to configure plugin? (Rationalize chess.test).
|
|
40
|
-
const functionsPlugin = new FunctionsPlugin();
|
|
41
|
-
await functionsPlugin.initialize({ client, clientServices: client.services });
|
|
42
|
-
await functionsPlugin.open();
|
|
43
|
-
testBuilder.ctx.onDispose(() => functionsPlugin.close());
|
|
44
|
-
return client;
|
|
45
|
-
};
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2023 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import { type FunctionHandler } from '../../handler';
|
|
6
|
-
|
|
7
|
-
let callHandler: FunctionHandler<any> = async ({ response }) => response.status(200);
|
|
8
|
-
|
|
9
|
-
export const setTestCallHandler = (handler: FunctionHandler<any>) => {
|
|
10
|
-
callHandler = handler;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
export const handler: FunctionHandler<any> = async (args) => {
|
|
14
|
-
return callHandler(args);
|
|
15
|
-
};
|
package/src/testing/types.ts
DELETED
package/src/testing/util.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2024 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import { Filter, type Space } from '@dxos/client/echo';
|
|
6
|
-
import { invariant } from '@dxos/invariant';
|
|
7
|
-
|
|
8
|
-
import { FunctionTrigger } from '../types';
|
|
9
|
-
|
|
10
|
-
export const triggerWebhook = async (space: Space, uri: string) => {
|
|
11
|
-
const trigger = (
|
|
12
|
-
await space.db.query(Filter.schema(FunctionTrigger, (t: FunctionTrigger) => t.function === uri)).run()
|
|
13
|
-
).objects[0];
|
|
14
|
-
invariant(trigger.spec.type === 'webhook');
|
|
15
|
-
void fetch(`http://localhost:${trigger.spec.port}`);
|
|
16
|
-
};
|