@dxos/functions 0.8.4-main.5acf9ea → 0.8.4-main.5ea62a8

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 (100) hide show
  1. package/dist/lib/browser/bundler/index.mjs +54 -38
  2. package/dist/lib/browser/bundler/index.mjs.map +3 -3
  3. package/dist/lib/browser/chunk-7NQ77AIQ.mjs +618 -0
  4. package/dist/lib/browser/chunk-7NQ77AIQ.mjs.map +7 -0
  5. package/dist/lib/browser/edge/index.mjs +20 -8
  6. package/dist/lib/browser/edge/index.mjs.map +3 -3
  7. package/dist/lib/browser/index.mjs +141 -77
  8. package/dist/lib/browser/index.mjs.map +4 -4
  9. package/dist/lib/browser/meta.json +1 -1
  10. package/dist/lib/browser/testing/index.mjs +68 -5
  11. package/dist/lib/browser/testing/index.mjs.map +3 -3
  12. package/dist/lib/node-esm/bundler/index.mjs +54 -38
  13. package/dist/lib/node-esm/bundler/index.mjs.map +3 -3
  14. package/dist/lib/node-esm/chunk-KCGC6QQT.mjs +620 -0
  15. package/dist/lib/node-esm/chunk-KCGC6QQT.mjs.map +7 -0
  16. package/dist/lib/node-esm/edge/index.mjs +20 -8
  17. package/dist/lib/node-esm/edge/index.mjs.map +3 -3
  18. package/dist/lib/node-esm/index.mjs +141 -77
  19. package/dist/lib/node-esm/index.mjs.map +4 -4
  20. package/dist/lib/node-esm/meta.json +1 -1
  21. package/dist/lib/node-esm/testing/index.mjs +68 -5
  22. package/dist/lib/node-esm/testing/index.mjs.map +3 -3
  23. package/dist/types/src/bundler/bundler.d.ts +11 -12
  24. package/dist/types/src/bundler/bundler.d.ts.map +1 -1
  25. package/dist/types/src/edge/functions.d.ts +3 -2
  26. package/dist/types/src/edge/functions.d.ts.map +1 -1
  27. package/dist/types/src/errors.d.ts +10 -8
  28. package/dist/types/src/errors.d.ts.map +1 -1
  29. package/dist/types/src/examples/fib.d.ts +7 -0
  30. package/dist/types/src/examples/fib.d.ts.map +1 -0
  31. package/dist/types/src/examples/reply.d.ts +3 -0
  32. package/dist/types/src/examples/reply.d.ts.map +1 -0
  33. package/dist/types/src/examples/sleep.d.ts +5 -0
  34. package/dist/types/src/examples/sleep.d.ts.map +1 -0
  35. package/dist/types/src/executor/executor.d.ts +4 -1
  36. package/dist/types/src/executor/executor.d.ts.map +1 -1
  37. package/dist/types/src/handler.d.ts +10 -7
  38. package/dist/types/src/handler.d.ts.map +1 -1
  39. package/dist/types/src/schema.d.ts +7 -2
  40. package/dist/types/src/schema.d.ts.map +1 -1
  41. package/dist/types/src/services/credentials.d.ts +15 -3
  42. package/dist/types/src/services/credentials.d.ts.map +1 -1
  43. package/dist/types/src/services/database.d.ts +74 -6
  44. package/dist/types/src/services/database.d.ts.map +1 -1
  45. package/dist/types/src/services/event-logger.d.ts +1 -1
  46. package/dist/types/src/services/event-logger.d.ts.map +1 -1
  47. package/dist/types/src/services/local-function-execution.d.ts +2 -1
  48. package/dist/types/src/services/local-function-execution.d.ts.map +1 -1
  49. package/dist/types/src/services/queues.d.ts +18 -5
  50. package/dist/types/src/services/queues.d.ts.map +1 -1
  51. package/dist/types/src/services/remote-function-execution-service.d.ts.map +1 -1
  52. package/dist/types/src/services/service-container.d.ts +1 -1
  53. package/dist/types/src/services/service-container.d.ts.map +1 -1
  54. package/dist/types/src/services/service-registry.d.ts.map +1 -1
  55. package/dist/types/src/services/tracing.d.ts +33 -3
  56. package/dist/types/src/services/tracing.d.ts.map +1 -1
  57. package/dist/types/src/testing/layer.d.ts +6 -2
  58. package/dist/types/src/testing/layer.d.ts.map +1 -1
  59. package/dist/types/src/testing/logger.d.ts.map +1 -1
  60. package/dist/types/src/testing/persist-database.test.d.ts +2 -0
  61. package/dist/types/src/testing/persist-database.test.d.ts.map +1 -0
  62. package/dist/types/src/testing/services.d.ts +1 -1
  63. package/dist/types/src/testing/services.d.ts.map +1 -1
  64. package/dist/types/src/trace.d.ts +34 -8
  65. package/dist/types/src/trace.d.ts.map +1 -1
  66. package/dist/types/src/types.d.ts +141 -224
  67. package/dist/types/src/types.d.ts.map +1 -1
  68. package/dist/types/src/url.d.ts +10 -6
  69. package/dist/types/src/url.d.ts.map +1 -1
  70. package/dist/types/tsconfig.tsbuildinfo +1 -1
  71. package/package.json +40 -39
  72. package/src/bundler/bundler.test.ts +8 -9
  73. package/src/bundler/bundler.ts +32 -33
  74. package/src/edge/functions.ts +8 -5
  75. package/src/examples/fib.ts +30 -0
  76. package/src/examples/reply.ts +18 -0
  77. package/src/examples/sleep.ts +22 -0
  78. package/src/executor/executor.ts +9 -9
  79. package/src/handler.ts +12 -10
  80. package/src/schema.ts +11 -0
  81. package/src/services/credentials.ts +78 -5
  82. package/src/services/database.ts +114 -18
  83. package/src/services/event-logger.ts +2 -2
  84. package/src/services/local-function-execution.ts +20 -13
  85. package/src/services/queues.ts +29 -10
  86. package/src/services/remote-function-execution-service.ts +2 -22
  87. package/src/services/service-container.ts +4 -3
  88. package/src/services/service-registry.ts +1 -1
  89. package/src/services/tracing.ts +95 -5
  90. package/src/testing/layer.ts +69 -3
  91. package/src/testing/logger.ts +1 -1
  92. package/src/testing/persist-database.test.ts +87 -0
  93. package/src/testing/services.ts +2 -1
  94. package/src/trace.ts +5 -7
  95. package/src/types.ts +17 -25
  96. package/src/url.ts +13 -10
  97. package/dist/lib/browser/chunk-6PTFLPCO.mjs +0 -462
  98. package/dist/lib/browser/chunk-6PTFLPCO.mjs.map +0 -7
  99. package/dist/lib/node-esm/chunk-NYJ2TSXO.mjs +0 -464
  100. package/dist/lib/node-esm/chunk-NYJ2TSXO.mjs.map +0 -7
@@ -0,0 +1,87 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { describe, expect, it } from '@effect/vitest';
6
+ import { Effect } from 'effect';
7
+
8
+ import { Filter, Obj, Query, Type } from '@dxos/echo';
9
+ import { DataType } from '@dxos/schema';
10
+
11
+ import { DatabaseService } from '../services';
12
+
13
+ import { TestDatabaseLayer, testStoragePath } from './layer';
14
+
15
+ describe('TestDatabaseLayer', { timeout: 600_000 }, () => {
16
+ it.effect(
17
+ 'persist database to disk',
18
+ Effect.fnUntraced(function* ({ expect: _ }) {
19
+ const DbLayer = TestDatabaseLayer({
20
+ storagePath: testStoragePath({ name: `feed-test-${Date.now()}` }),
21
+ });
22
+
23
+ yield* Effect.gen(function* () {
24
+ yield* DatabaseService.add(Obj.make(Type.Expando, { label: 'test' }));
25
+ yield* DatabaseService.flush({ indexes: true });
26
+ }).pipe(Effect.provide(DbLayer));
27
+
28
+ yield* Effect.gen(function* () {
29
+ const { objects } = yield* DatabaseService.runQuery(Query.select(Filter.everything()));
30
+ expect(objects[0]?.label).toEqual('test');
31
+ }).pipe(Effect.provide(DbLayer));
32
+ }),
33
+ );
34
+
35
+ it.effect(
36
+ 'reload database -- save index before restart',
37
+ Effect.fnUntraced(function* ({ expect: _ }) {
38
+ const NUM_OBJECTS = 500;
39
+ const DbLayer = TestDatabaseLayer({
40
+ types: [DataType.Person],
41
+ storagePath: testStoragePath({ name: `reload-test-${Date.now()}` }),
42
+ });
43
+
44
+ yield* Effect.gen(function* () {
45
+ for (let i = 0; i < NUM_OBJECTS; i++) {
46
+ yield* DatabaseService.add(Obj.make(DataType.Person, { nickname: `Person ${i}` }));
47
+ }
48
+ yield* DatabaseService.flush({ indexes: true });
49
+ }).pipe(Effect.provide(DbLayer));
50
+
51
+ yield* Effect.gen(function* () {
52
+ const { objects } = yield* DatabaseService.runQuery(Query.select(Filter.type(DataType.Person)));
53
+ expect(objects.length).toEqual(NUM_OBJECTS);
54
+ }).pipe(Effect.provide(DbLayer));
55
+ }),
56
+ );
57
+
58
+ it.effect.skip(
59
+ 'reload database -- save index before restart [manual]',
60
+ Effect.fnUntraced(
61
+ function* ({ expect: _ }) {
62
+ const NUM_OBJECTS = 500;
63
+
64
+ {
65
+ const { objects } = yield* DatabaseService.runQuery(Query.select(Filter.type(DataType.Person)));
66
+ console.log({ count: objects.length });
67
+ }
68
+
69
+ for (let i = 0; i < NUM_OBJECTS; i++) {
70
+ yield* DatabaseService.add(Obj.make(DataType.Person, { nickname: `Person ${i}` }));
71
+ }
72
+ yield* DatabaseService.flush({ indexes: true });
73
+
74
+ {
75
+ const { objects } = yield* DatabaseService.runQuery(Query.select(Filter.type(DataType.Person)));
76
+ console.log({ count: objects.length });
77
+ }
78
+ },
79
+ Effect.provide(
80
+ TestDatabaseLayer({
81
+ types: [DataType.Person],
82
+ storagePath: testStoragePath({ name: `reload-test` }),
83
+ }),
84
+ ),
85
+ ),
86
+ );
87
+ });
@@ -9,15 +9,16 @@ import type { EchoDatabase, QueueFactory } from '@dxos/echo-db';
9
9
  import { assertArgument } from '@dxos/invariant';
10
10
 
11
11
  import {
12
+ type ComputeEventLogger,
12
13
  ConfiguredCredentialsService,
13
14
  type CredentialsService,
14
15
  DatabaseService,
15
- type ComputeEventLogger,
16
16
  QueueService,
17
17
  ServiceContainer,
18
18
  type ServiceCredential,
19
19
  type TracingService,
20
20
  } from '../services';
21
+
21
22
  import { consoleLogger, noopLogger } from './logger';
22
23
 
23
24
  // TODO(burdon): Factor out.
package/src/trace.ts CHANGED
@@ -4,12 +4,12 @@
4
4
 
5
5
  import { Schema } from 'effect';
6
6
 
7
- import { Type, type Ref } from '@dxos/echo';
7
+ import { type Ref, Type } from '@dxos/echo';
8
8
  import { Queue } from '@dxos/echo-db';
9
9
  import { ObjectId } from '@dxos/echo-schema';
10
10
  import { log } from '@dxos/log';
11
11
 
12
- import { FunctionTrigger, type FunctionTriggerType } from './types';
12
+ import { FunctionTrigger } from './types';
13
13
 
14
14
  export enum InvocationOutcome {
15
15
  SUCCESS = 'success',
@@ -101,10 +101,8 @@ export const TraceEvent = Schema.Struct({
101
101
  // TODO(burdon): Need enum/numeric result (not string).
102
102
  outcome: Schema.String,
103
103
  truncated: Schema.Boolean,
104
- /**
105
- * Time when the event was persisted.
106
- */
107
- ingestionTimestampMs: Schema.Number,
104
+ /** Time when the event was persisted. */
105
+ ingestionTimestamp: Schema.Number,
108
106
  logs: Schema.Array(TraceEventLog),
109
107
  exceptions: Schema.Array(TraceEventException),
110
108
  }).pipe(Type.Obj({ typename: 'dxos.org/type/TraceEvent', version: '0.1.0' }));
@@ -123,7 +121,7 @@ export type InvocationSpan = {
123
121
  durationMs: number;
124
122
  invocationTraceQueue: Ref.Ref<Queue>;
125
123
  invocationTarget: Ref.Ref<Type.Expando>;
126
- trigger?: Ref.Ref<FunctionTriggerType>;
124
+ trigger?: Ref.Ref<FunctionTrigger>;
127
125
  exception?: TraceEventException;
128
126
  };
129
127
 
package/src/types.ts CHANGED
@@ -4,7 +4,8 @@
4
4
 
5
5
  import { Schema, SchemaAST } from 'effect';
6
6
 
7
- import { Expando, OptionsAnnotationId, TypedObject, Ref, RawObject } from '@dxos/echo-schema';
7
+ import { Type } from '@dxos/echo';
8
+ import { Expando, OptionsAnnotationId, RawObject, Ref } from '@dxos/echo-schema';
8
9
  import { DXN } from '@dxos/keys';
9
10
 
10
11
  import { FunctionType } from './schema';
@@ -14,13 +15,8 @@ import { FunctionType } from './schema';
14
15
  * Every spec has a type field of type TriggerKind that we can use to understand which type we're working with.
15
16
  * https://www.typescriptlang.org/docs/handbook/2/narrowing.html#discriminated-unions
16
17
  */
17
- export enum TriggerKind {
18
- Timer = 'timer',
19
- Webhook = 'webhook',
20
- Subscription = 'subscription',
21
- Email = 'email',
22
- Queue = 'queue',
23
- }
18
+ export const TriggerKinds = ['timer', 'webhook', 'subscription', 'email', 'queue'] as const;
19
+ export type TriggerKind = (typeof TriggerKinds)[number];
24
20
 
25
21
  const kindLiteralAnnotations = { title: 'Kind' };
26
22
 
@@ -28,7 +24,7 @@ const kindLiteralAnnotations = { title: 'Kind' };
28
24
  * Cron timer.
29
25
  */
30
26
  const TimerTriggerSchema = Schema.Struct({
31
- kind: Schema.Literal(TriggerKind.Timer).annotations(kindLiteralAnnotations),
27
+ kind: Schema.Literal('timer').annotations(kindLiteralAnnotations),
32
28
  cron: Schema.String.annotations({
33
29
  title: 'Cron',
34
30
  [SchemaAST.ExamplesAnnotationId]: ['0 0 * * *'],
@@ -37,12 +33,12 @@ const TimerTriggerSchema = Schema.Struct({
37
33
  export type TimerTrigger = Schema.Schema.Type<typeof TimerTriggerSchema>;
38
34
 
39
35
  const EmailTriggerSchema = Schema.Struct({
40
- kind: Schema.Literal(TriggerKind.Email).annotations(kindLiteralAnnotations),
36
+ kind: Schema.Literal('email').annotations(kindLiteralAnnotations),
41
37
  }).pipe(Schema.mutable);
42
38
  export type EmailTrigger = Schema.Schema.Type<typeof EmailTriggerSchema>;
43
39
 
44
40
  const QueueTriggerSchema = Schema.Struct({
45
- kind: Schema.Literal(TriggerKind.Queue).annotations(kindLiteralAnnotations),
41
+ kind: Schema.Literal('queue').annotations(kindLiteralAnnotations),
46
42
  queue: DXN.Schema,
47
43
  }).pipe(Schema.mutable);
48
44
  export type QueueTrigger = Schema.Schema.Type<typeof QueueTriggerSchema>;
@@ -51,7 +47,7 @@ export type QueueTrigger = Schema.Schema.Type<typeof QueueTriggerSchema>;
51
47
  * Webhook.
52
48
  */
53
49
  const WebhookTriggerSchema = Schema.Struct({
54
- kind: Schema.Literal(TriggerKind.Webhook).annotations(kindLiteralAnnotations),
50
+ kind: Schema.Literal('webhook').annotations(kindLiteralAnnotations),
55
51
  method: Schema.optional(
56
52
  Schema.String.annotations({
57
53
  title: 'Method',
@@ -76,7 +72,7 @@ const QuerySchema = Schema.Struct({
76
72
  * Subscription.
77
73
  */
78
74
  const SubscriptionTriggerSchema = Schema.Struct({
79
- kind: Schema.Literal(TriggerKind.Subscription).annotations(kindLiteralAnnotations),
75
+ kind: Schema.Literal('subscription').annotations(kindLiteralAnnotations),
80
76
  // TODO(burdon): Define query DSL (from ECHO). Reconcile with Table.Query.
81
77
  filter: QuerySchema,
82
78
  options: Schema.optional(
@@ -155,7 +151,7 @@ export type TimerTriggerOutput = Schema.Schema.Type<typeof TimerTriggerOutput>;
155
151
  * Function is invoked with the `payload` passed as input data.
156
152
  * The event that triggers the function is available in the function context.
157
153
  */
158
- export const FunctionTriggerSchema = Schema.Struct({
154
+ export const FunctionTrigger = Schema.Struct({
159
155
  /**
160
156
  * Function or workflow to invoke.
161
157
  */
@@ -185,17 +181,13 @@ export const FunctionTriggerSchema = Schema.Struct({
185
181
  * }
186
182
  */
187
183
  input: Schema.optional(Schema.mutable(Schema.Record({ key: Schema.String, value: Schema.Any }))),
188
- });
189
-
190
- export type FunctionTriggerType = Schema.Schema.Type<typeof FunctionTriggerSchema>;
191
-
192
- /**
193
- * Function trigger.
194
- */
195
- export class FunctionTrigger extends TypedObject({
196
- typename: 'dxos.org/type/FunctionTrigger',
197
- version: '0.2.0',
198
- })(FunctionTriggerSchema.fields) {}
184
+ }).pipe(
185
+ Type.Obj({
186
+ typename: 'dxos.org/type/FunctionTrigger',
187
+ version: '0.2.0',
188
+ }),
189
+ );
190
+ export type FunctionTrigger = Schema.Schema.Type<typeof FunctionTrigger>;
199
191
 
200
192
  // TODO(wittjosiah): Remove?
201
193
 
package/src/url.ts CHANGED
@@ -6,7 +6,7 @@ import { type ObjectMeta } from '@dxos/echo-schema';
6
6
  import { type SpaceId } from '@dxos/keys';
7
7
 
8
8
  // TODO: use URL scheme for source?
9
- const FUNCTIONS_META_KEY = 'dxos.org/service/function';
9
+ export const FUNCTIONS_META_KEY = 'dxos.org/service/function';
10
10
 
11
11
  export const FUNCTIONS_PRESET_META_KEY = 'dxos.org/service/function-preset';
12
12
 
@@ -14,32 +14,35 @@ const isSecure = (protocol: string) => {
14
14
  return protocol === 'https:' || protocol === 'wss:';
15
15
  };
16
16
 
17
- export const getUserFunctionUrlInMetadata = (meta: ObjectMeta) => {
17
+ /**
18
+ * NOTE: functionId is backend ID, not ECHO object id.
19
+ */
20
+ export const getUserFunctionIdInMetadata = (meta: ObjectMeta) => {
18
21
  return meta.keys.find((key) => key.source === FUNCTIONS_META_KEY)?.id;
19
22
  };
20
23
 
21
- export const setUserFunctionUrlInMetadata = (meta: ObjectMeta, functionUrl: string) => {
24
+ /**
25
+ * NOTE: functionId is backend ID, not ECHO object id.
26
+ */
27
+ export const setUserFunctionIdInMetadata = (meta: ObjectMeta, functionId: string) => {
22
28
  const key = meta.keys.find((key) => key.source === FUNCTIONS_META_KEY);
23
29
  if (key) {
24
- if (key.id !== functionUrl) {
30
+ if (key.id !== functionId) {
25
31
  throw new Error('Metadata mismatch');
26
32
  }
27
33
  } else {
28
- meta.keys.push({ source: FUNCTIONS_META_KEY, id: functionUrl });
34
+ meta.keys.push({ source: FUNCTIONS_META_KEY, id: functionId });
29
35
  }
30
36
  };
31
37
 
32
38
  /**
33
39
  * NOTE: functionId is backend ID, not ECHO object id.
34
40
  */
35
- export const makeFunctionUrl = (fn: { functionId: string }) => `/${fn.functionId}`;
36
-
37
- export const getInvocationUrl = (functionUrl: string, edgeUrl: string, options: InvocationOptions = {}) => {
41
+ export const getInvocationUrl = (functionId: string, edgeUrl: string, options: InvocationOptions = {}) => {
38
42
  const baseUrl = new URL('functions/', edgeUrl);
39
43
 
40
44
  // Leading slashes cause the URL to be treated as an absolute path.
41
- const relativeUrl = functionUrl.replace(/^\//, '');
42
- const url = new URL(`./${relativeUrl}`, baseUrl.toString());
45
+ const url = new URL(`./${functionId}`, baseUrl.toString());
43
46
  options.spaceId && url.searchParams.set('spaceId', options.spaceId);
44
47
  options.subjectId && url.searchParams.set('subjectId', options.subjectId);
45
48
  url.protocol = isSecure(url.protocol) ? 'https' : 'http';