@dxos/functions 0.5.3-main.6f2dfea → 0.5.3-main.79e0565

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.
Files changed (82) hide show
  1. package/dist/lib/browser/index.mjs +764 -476
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node/index.cjs +745 -471
  5. package/dist/lib/node/index.cjs.map +4 -4
  6. package/dist/lib/node/meta.json +1 -1
  7. package/dist/types/src/function/function-registry.d.ts +24 -0
  8. package/dist/types/src/function/function-registry.d.ts.map +1 -0
  9. package/dist/types/src/function/function-registry.test.d.ts +2 -0
  10. package/dist/types/src/function/function-registry.test.d.ts.map +1 -0
  11. package/dist/types/src/function/index.d.ts +2 -0
  12. package/dist/types/src/function/index.d.ts.map +1 -0
  13. package/dist/types/src/handler.d.ts +32 -12
  14. package/dist/types/src/handler.d.ts.map +1 -1
  15. package/dist/types/src/index.d.ts +2 -0
  16. package/dist/types/src/index.d.ts.map +1 -1
  17. package/dist/types/src/runtime/dev-server.d.ts +7 -10
  18. package/dist/types/src/runtime/dev-server.d.ts.map +1 -1
  19. package/dist/types/src/runtime/scheduler.d.ts +11 -59
  20. package/dist/types/src/runtime/scheduler.d.ts.map +1 -1
  21. package/dist/types/src/testing/functions-integration.test.d.ts +2 -0
  22. package/dist/types/src/testing/functions-integration.test.d.ts.map +1 -0
  23. package/dist/types/src/testing/index.d.ts +4 -0
  24. package/dist/types/src/testing/index.d.ts.map +1 -0
  25. package/dist/types/src/testing/setup.d.ts +5 -0
  26. package/dist/types/src/testing/setup.d.ts.map +1 -0
  27. package/dist/types/src/testing/test/handler.d.ts +1 -0
  28. package/dist/types/src/testing/test/handler.d.ts.map +1 -1
  29. package/dist/types/src/testing/types.d.ts +9 -0
  30. package/dist/types/src/testing/types.d.ts.map +1 -0
  31. package/dist/types/src/testing/util.d.ts +3 -0
  32. package/dist/types/src/testing/util.d.ts.map +1 -0
  33. package/dist/types/src/trigger/index.d.ts +2 -0
  34. package/dist/types/src/trigger/index.d.ts.map +1 -0
  35. package/dist/types/src/trigger/trigger-registry.d.ts +40 -0
  36. package/dist/types/src/trigger/trigger-registry.d.ts.map +1 -0
  37. package/dist/types/src/trigger/trigger-registry.test.d.ts +2 -0
  38. package/dist/types/src/trigger/trigger-registry.test.d.ts.map +1 -0
  39. package/dist/types/src/trigger/type/index.d.ts +5 -0
  40. package/dist/types/src/trigger/type/index.d.ts.map +1 -0
  41. package/dist/types/src/trigger/type/subscription-trigger.d.ts +4 -0
  42. package/dist/types/src/trigger/type/subscription-trigger.d.ts.map +1 -0
  43. package/dist/types/src/trigger/type/timer-trigger.d.ts +4 -0
  44. package/dist/types/src/trigger/type/timer-trigger.d.ts.map +1 -0
  45. package/dist/types/src/trigger/type/webhook-trigger.d.ts +4 -0
  46. package/dist/types/src/trigger/type/webhook-trigger.d.ts.map +1 -0
  47. package/dist/types/src/trigger/type/websocket-trigger.d.ts +13 -0
  48. package/dist/types/src/trigger/type/websocket-trigger.d.ts.map +1 -0
  49. package/dist/types/src/types.d.ts +131 -111
  50. package/dist/types/src/types.d.ts.map +1 -1
  51. package/dist/types/src/util.d.ts +15 -0
  52. package/dist/types/src/util.d.ts.map +1 -0
  53. package/dist/types/src/util.test.d.ts +2 -0
  54. package/dist/types/src/util.test.d.ts.map +1 -0
  55. package/package.json +14 -12
  56. package/schema/functions.json +140 -112
  57. package/src/function/function-registry.test.ts +105 -0
  58. package/src/function/function-registry.ts +90 -0
  59. package/src/function/index.ts +5 -0
  60. package/src/handler.ts +50 -27
  61. package/src/index.ts +2 -0
  62. package/src/runtime/dev-server.test.ts +15 -35
  63. package/src/runtime/dev-server.ts +40 -23
  64. package/src/runtime/scheduler.test.ts +54 -75
  65. package/src/runtime/scheduler.ts +75 -300
  66. package/src/testing/functions-integration.test.ts +99 -0
  67. package/src/testing/index.ts +7 -0
  68. package/src/testing/setup.ts +45 -0
  69. package/src/testing/test/handler.ts +8 -2
  70. package/src/testing/types.ts +9 -0
  71. package/src/testing/util.ts +16 -0
  72. package/src/trigger/index.ts +5 -0
  73. package/src/trigger/trigger-registry.test.ts +255 -0
  74. package/src/trigger/trigger-registry.ts +189 -0
  75. package/src/trigger/type/index.ts +8 -0
  76. package/src/trigger/type/subscription-trigger.ts +80 -0
  77. package/src/trigger/type/timer-trigger.ts +44 -0
  78. package/src/trigger/type/webhook-trigger.ts +47 -0
  79. package/src/trigger/type/websocket-trigger.ts +91 -0
  80. package/src/types.ts +58 -40
  81. package/src/util.test.ts +43 -0
  82. package/src/util.ts +48 -0
@@ -1,26 +1,24 @@
1
1
  {
2
2
  "$schema": "http://json-schema.org/draft-07/schema#",
3
3
  "type": "object",
4
- "required": [
5
- "functions"
6
- ],
4
+ "required": [],
7
5
  "properties": {
8
6
  "functions": {
9
7
  "type": "array",
10
8
  "items": {
11
9
  "type": "object",
12
10
  "required": [
13
- "id",
14
- "path",
11
+ "uri",
12
+ "route",
15
13
  "handler"
16
14
  ],
17
15
  "properties": {
18
- "id": {
16
+ "uri": {
19
17
  "type": "string",
20
18
  "description": "a string",
21
19
  "title": "string"
22
20
  },
23
- "path": {
21
+ "route": {
24
22
  "type": "string",
25
23
  "description": "a string",
26
24
  "title": "string"
@@ -44,135 +42,165 @@
44
42
  "items": {
45
43
  "type": "object",
46
44
  "required": [
47
- "function"
45
+ "function",
46
+ "spec"
48
47
  ],
49
48
  "properties": {
50
49
  "function": {
51
50
  "type": "string",
52
- "description": "Function ID/URI.",
51
+ "description": "Function URI.",
53
52
  "title": "string"
54
53
  },
55
- "context": {
56
- "type": "object",
57
- "required": [],
58
- "properties": {},
59
- "additionalProperties": {
60
- "$id": "/schemas/any",
61
- "title": "any"
62
- }
54
+ "meta": {
55
+ "$ref": "#/$defs/object"
63
56
  },
64
- "timer": {
65
- "type": "object",
66
- "required": [
67
- "cron"
68
- ],
69
- "properties": {
70
- "cron": {
71
- "type": "string",
72
- "description": "a string",
73
- "title": "string"
74
- }
75
- },
76
- "additionalProperties": false
77
- },
78
- "webhook": {
79
- "type": "object",
80
- "required": [
81
- "port"
82
- ],
83
- "properties": {
84
- "port": {
85
- "type": "number",
86
- "description": "a number",
87
- "title": "number"
88
- }
89
- },
90
- "additionalProperties": false
91
- },
92
- "websocket": {
93
- "type": "object",
94
- "required": [
95
- "url"
96
- ],
97
- "properties": {
98
- "url": {
99
- "type": "string",
100
- "description": "a string",
101
- "title": "string"
102
- },
103
- "init": {
57
+ "spec": {
58
+ "anyOf": [
59
+ {
104
60
  "type": "object",
105
- "required": [],
106
- "properties": {},
107
- "additionalProperties": {
108
- "$id": "/schemas/any",
109
- "title": "any"
110
- }
111
- }
112
- },
113
- "additionalProperties": false
114
- },
115
- "subscription": {
116
- "type": "object",
117
- "required": [
118
- "filter"
119
- ],
120
- "properties": {
121
- "spaceKey": {
122
- "type": "string",
123
- "description": "a string",
124
- "title": "string"
125
- },
126
- "filter": {
127
- "type": "array",
128
- "items": {
129
- "type": "object",
130
- "required": [
131
- "type"
132
- ],
133
- "properties": {
134
- "type": {
135
- "type": "string",
136
- "description": "a string",
137
- "title": "string"
138
- },
139
- "props": {
140
- "type": "object",
141
- "required": [],
142
- "properties": {},
143
- "additionalProperties": {
144
- "$id": "/schemas/any",
145
- "title": "any"
146
- }
147
- }
61
+ "required": [
62
+ "type",
63
+ "cron"
64
+ ],
65
+ "properties": {
66
+ "type": {
67
+ "const": "timer"
148
68
  },
149
- "additionalProperties": false
150
- }
69
+ "cron": {
70
+ "type": "string",
71
+ "description": "a string",
72
+ "title": "string"
73
+ }
74
+ },
75
+ "additionalProperties": false
151
76
  },
152
- "options": {
77
+ {
153
78
  "type": "object",
154
- "required": [],
79
+ "required": [
80
+ "type",
81
+ "method"
82
+ ],
155
83
  "properties": {
156
- "deep": {
157
- "type": "boolean",
158
- "description": "a boolean",
159
- "title": "boolean"
84
+ "type": {
85
+ "const": "webhook"
86
+ },
87
+ "method": {
88
+ "type": "string",
89
+ "description": "a string",
90
+ "title": "string"
160
91
  },
161
- "delay": {
92
+ "port": {
162
93
  "type": "number",
163
94
  "description": "a number",
164
95
  "title": "number"
165
96
  }
166
97
  },
167
98
  "additionalProperties": false
99
+ },
100
+ {
101
+ "type": "object",
102
+ "required": [
103
+ "type",
104
+ "url"
105
+ ],
106
+ "properties": {
107
+ "type": {
108
+ "const": "websocket"
109
+ },
110
+ "url": {
111
+ "type": "string",
112
+ "description": "a string",
113
+ "title": "string"
114
+ },
115
+ "init": {
116
+ "type": "object",
117
+ "required": [],
118
+ "properties": {},
119
+ "additionalProperties": {
120
+ "$id": "/schemas/any",
121
+ "title": "any"
122
+ }
123
+ }
124
+ },
125
+ "additionalProperties": false
126
+ },
127
+ {
128
+ "type": "object",
129
+ "required": [
130
+ "type",
131
+ "filter"
132
+ ],
133
+ "properties": {
134
+ "type": {
135
+ "const": "subscription"
136
+ },
137
+ "filter": {
138
+ "type": "array",
139
+ "items": {
140
+ "type": "object",
141
+ "required": [
142
+ "type"
143
+ ],
144
+ "properties": {
145
+ "type": {
146
+ "type": "string",
147
+ "description": "a string",
148
+ "title": "string"
149
+ },
150
+ "props": {
151
+ "type": "object",
152
+ "required": [],
153
+ "properties": {},
154
+ "additionalProperties": {
155
+ "$id": "/schemas/any",
156
+ "title": "any"
157
+ }
158
+ }
159
+ },
160
+ "additionalProperties": false
161
+ }
162
+ },
163
+ "options": {
164
+ "type": "object",
165
+ "required": [],
166
+ "properties": {
167
+ "deep": {
168
+ "type": "boolean",
169
+ "description": "a boolean",
170
+ "title": "boolean"
171
+ },
172
+ "delay": {
173
+ "type": "number",
174
+ "description": "a number",
175
+ "title": "number"
176
+ }
177
+ },
178
+ "additionalProperties": false
179
+ }
180
+ },
181
+ "additionalProperties": false
168
182
  }
169
- },
170
- "additionalProperties": false
183
+ ]
171
184
  }
172
185
  },
173
186
  "additionalProperties": false
174
187
  }
175
188
  }
176
189
  },
177
- "additionalProperties": false
190
+ "additionalProperties": false,
191
+ "$defs": {
192
+ "object": {
193
+ "$id": "/schemas/object",
194
+ "oneOf": [
195
+ {
196
+ "type": "object"
197
+ },
198
+ {
199
+ "type": "array"
200
+ }
201
+ ],
202
+ "description": "an object in the TypeScript meaning, i.e. the `object` type",
203
+ "title": "object"
204
+ }
205
+ }
178
206
  }
@@ -0,0 +1,105 @@
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.functions);
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.functions);
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.registered.on((fn) => {
75
+ functionRegistered.wake(fn.added);
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.registered.on((fn) => {
90
+ expect(fn.added.length).to.eq(1);
91
+ functionRegistered.wake(fn.added[0]);
92
+ });
93
+ await registry.open(ctx);
94
+ await registry.register(space, testManifest.functions);
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
+ });
@@ -0,0 +1,90 @@
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 { log } from '@dxos/log';
11
+ import { ComplexMap } from '@dxos/util';
12
+
13
+ import { FunctionDef, type FunctionManifest } from '../types';
14
+ import { diff } from '../util';
15
+
16
+ export type FunctionsRegisteredEvent = {
17
+ space: Space;
18
+ added: FunctionDef[];
19
+ };
20
+
21
+ export class FunctionRegistry extends Resource {
22
+ private readonly _functionBySpaceKey = new ComplexMap<PublicKey, FunctionDef[]>(PublicKey.hash);
23
+
24
+ public readonly registered = new Event<FunctionsRegisteredEvent>();
25
+
26
+ constructor(private readonly _client: Client) {
27
+ super();
28
+ }
29
+
30
+ public getFunctions(space: Space): FunctionDef[] {
31
+ return this._functionBySpaceKey.get(space.key) ?? [];
32
+ }
33
+
34
+ /**
35
+ * Loads function definitions from the manifest into the space.
36
+ * We first load all the definitions from the space to deduplicate by functionId.
37
+ */
38
+ public async register(space: Space, functions: FunctionManifest['functions']): Promise<void> {
39
+ log('register', { space: space.key, functions: functions?.length ?? 0 });
40
+ if (!functions?.length) {
41
+ return;
42
+ }
43
+ if (!space.db.graph.runtimeSchemaRegistry.hasSchema(FunctionDef)) {
44
+ space.db.graph.runtimeSchemaRegistry.registerSchema(FunctionDef);
45
+ }
46
+
47
+ // Sync definitions.
48
+ const { objects: existing } = await space.db.query(Filter.schema(FunctionDef)).run();
49
+ const { added, removed } = diff(existing, functions, (a, b) => a.uri === b.uri);
50
+ added.forEach((def) => space.db.add(create(FunctionDef, def)));
51
+ // TODO(burdon): Update existing templates.
52
+ removed.forEach((def) => space.db.remove(def));
53
+ }
54
+
55
+ protected override async _open(): Promise<void> {
56
+ const spacesSubscription = this._client.spaces.subscribe(async (spaces) => {
57
+ for (const space of spaces) {
58
+ if (this._functionBySpaceKey.has(space.key)) {
59
+ continue;
60
+ }
61
+
62
+ const registered: FunctionDef[] = [];
63
+ this._functionBySpaceKey.set(space.key, registered);
64
+ await space.waitUntilReady();
65
+ if (this._ctx.disposed) {
66
+ break;
67
+ }
68
+
69
+ // Subscribe to updates.
70
+ this._ctx.onDispose(
71
+ space.db.query(Filter.schema(FunctionDef)).subscribe(({ objects }) => {
72
+ const { added } = diff(registered, objects, (a, b) => a.uri === b.uri);
73
+ // TODO(burdon): Update and remove.
74
+ if (added.length > 0) {
75
+ registered.push(...added);
76
+ this.registered.emit({ space, added });
77
+ }
78
+ }),
79
+ );
80
+ }
81
+ });
82
+
83
+ // TODO(burdon): API: Normalize unsubscribe methods.
84
+ this._ctx.onDispose(() => spacesSubscription.unsubscribe());
85
+ }
86
+
87
+ protected override async _close(_: Context): Promise<void> {
88
+ this._functionBySpaceKey.clear();
89
+ }
90
+ }
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ export * from './function-registry';
package/src/handler.ts CHANGED
@@ -8,38 +8,61 @@ import { type EchoReactiveObject } from '@dxos/echo-schema';
8
8
  import { log } from '@dxos/log';
9
9
  import { nonNullable } from '@dxos/util';
10
10
 
11
- // Lambda-like function definitions.
11
+ // TODO(burdon): Model after http request. Ref Lambda/OpenFaaS.
12
+ // https://docs.aws.amazon.com/lambda/latest/dg/typescript-handler.html
12
13
  // https://www.serverless.com/framework/docs/providers/aws/guide/serverless.yml/#functions
13
14
  // https://www.npmjs.com/package/aws-lambda
14
- // https://docs.aws.amazon.com/lambda/latest/dg/typescript-handler.html
15
15
 
16
- // TODO(burdon): No response?
17
- export interface Response {
18
- status(code: number): Response;
19
- }
16
+ /**
17
+ * Function handler.
18
+ */
19
+ export type FunctionHandler<TData = {}, TMeta = {}> = (params: {
20
+ context: FunctionContext;
21
+ event: FunctionEvent<TData, TMeta>;
22
+ response: FunctionResponse;
23
+ }) => Promise<FunctionResponse | void>;
20
24
 
25
+ /**
26
+ * Function context.
27
+ */
21
28
  export interface FunctionContext {
22
29
  // TODO(burdon): Limit access to individual space.
23
30
  client: Client;
24
31
  // TODO(burdon): Replace with storage service abstraction.
25
32
  dataDir?: string;
26
- // Data passed to function invocation.
27
- data?: any;
28
33
  }
29
34
 
30
- // TODO(burdon): Model after http request. Ref Lambda/OpenFaaS.
31
- export type FunctionHandler<T extends {}> = (params: {
32
- event: T;
33
- context: FunctionContext;
34
- response: Response;
35
- }) => Promise<Response | void>;
35
+ /**
36
+ * Event payload.
37
+ */
38
+ export type FunctionEvent<TData = {}, TMeta = {}> = {
39
+ data: FunctionEventMeta<TMeta> & TData;
40
+ };
41
+
42
+ /**
43
+ * Metadata from trigger.
44
+ */
45
+ export type FunctionEventMeta<TMeta = {}> = {
46
+ meta: TMeta;
47
+ };
48
+
49
+ /**
50
+ * Function response.
51
+ */
52
+ export interface FunctionResponse {
53
+ status(code: number): FunctionResponse;
54
+ }
55
+
56
+ //
57
+ // Subscription utils.
58
+ //
36
59
 
37
- export type RawSubscriptionEvent = {
60
+ export type RawSubscriptionData = {
38
61
  spaceKey?: string;
39
62
  objects?: string[];
40
63
  };
41
64
 
42
- export type SubscriptionEvent = {
65
+ export type SubscriptionData = {
43
66
  space?: Space;
44
67
  objects?: EchoReactiveObject<any>[];
45
68
  };
@@ -54,22 +77,22 @@ export type SubscriptionEvent = {
54
77
  *
55
78
  * NOTE: Get space key from devtools or `dx space list --json`
56
79
  */
57
- export const subscriptionHandler = (
58
- handler: FunctionHandler<SubscriptionEvent>,
59
- ): FunctionHandler<RawSubscriptionEvent> => {
60
- return ({ event, context, ...rest }) => {
80
+ export const subscriptionHandler = <TMeta>(
81
+ handler: FunctionHandler<SubscriptionData, TMeta>,
82
+ ): FunctionHandler<RawSubscriptionData, TMeta> => {
83
+ return ({ event: { data }, context, ...rest }) => {
61
84
  const { client } = context;
62
- const space = event.spaceKey ? client.spaces.get(PublicKey.from(event.spaceKey)) : undefined;
63
- const objects =
64
- space &&
65
- event.objects?.map<EchoReactiveObject<any> | undefined>((id) => space!.db.getObjectById(id)).filter(nonNullable);
85
+ const space = data.spaceKey ? client.spaces.get(PublicKey.from(data.spaceKey)) : undefined;
86
+ const objects = space
87
+ ? data.objects?.map<EchoReactiveObject<any> | undefined>((id) => space!.db.getObjectById(id)).filter(nonNullable)
88
+ : [];
66
89
 
67
- if (!!event.spaceKey && !space) {
68
- log.warn('invalid space', { event });
90
+ if (!!data.spaceKey && !space) {
91
+ log.warn('invalid space', { data });
69
92
  } else {
70
93
  log.info('handler', { space: space?.key.truncate(), objects: objects?.length });
71
94
  }
72
95
 
73
- return handler({ event: { space, objects }, context, ...rest });
96
+ return handler({ event: { data: { ...data, space, objects } }, context, ...rest });
74
97
  };
75
98
  };
package/src/index.ts CHANGED
@@ -2,6 +2,8 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
+ export * from './function';
5
6
  export * from './handler';
6
7
  export * from './runtime';
8
+ export * from './trigger';
7
9
  export * from './types';