@dxos/functions 0.8.4-main.c1de068 → 0.8.4-main.e098934

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 (138) hide show
  1. package/dist/lib/browser/bundler/index.mjs +56 -38
  2. package/dist/lib/browser/bundler/index.mjs.map +3 -3
  3. package/dist/lib/browser/chunk-D2XO7XXY.mjs +611 -0
  4. package/dist/lib/browser/chunk-D2XO7XXY.mjs.map +7 -0
  5. package/dist/lib/browser/chunk-J5LGTIGS.mjs +10 -0
  6. package/dist/lib/browser/chunk-J5LGTIGS.mjs.map +7 -0
  7. package/dist/lib/browser/edge/index.mjs +22 -8
  8. package/dist/lib/browser/edge/index.mjs.map +3 -3
  9. package/dist/lib/browser/index.mjs +902 -130
  10. package/dist/lib/browser/index.mjs.map +4 -4
  11. package/dist/lib/browser/meta.json +1 -1
  12. package/dist/lib/browser/testing/index.mjs +76 -6
  13. package/dist/lib/browser/testing/index.mjs.map +3 -3
  14. package/dist/lib/node-esm/bundler/index.mjs +55 -38
  15. package/dist/lib/node-esm/bundler/index.mjs.map +3 -3
  16. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +11 -0
  17. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs.map +7 -0
  18. package/dist/lib/node-esm/chunk-Z4CJ62WS.mjs +613 -0
  19. package/dist/lib/node-esm/chunk-Z4CJ62WS.mjs.map +7 -0
  20. package/dist/lib/node-esm/edge/index.mjs +21 -8
  21. package/dist/lib/node-esm/edge/index.mjs.map +3 -3
  22. package/dist/lib/node-esm/index.mjs +902 -130
  23. package/dist/lib/node-esm/index.mjs.map +4 -4
  24. package/dist/lib/node-esm/meta.json +1 -1
  25. package/dist/lib/node-esm/testing/index.mjs +76 -6
  26. package/dist/lib/node-esm/testing/index.mjs.map +3 -3
  27. package/dist/types/src/bundler/bundler.d.ts +11 -12
  28. package/dist/types/src/bundler/bundler.d.ts.map +1 -1
  29. package/dist/types/src/edge/functions.d.ts +3 -2
  30. package/dist/types/src/edge/functions.d.ts.map +1 -1
  31. package/dist/types/src/errors.d.ts +89 -20
  32. package/dist/types/src/errors.d.ts.map +1 -1
  33. package/dist/types/src/examples/fib.d.ts +7 -0
  34. package/dist/types/src/examples/fib.d.ts.map +1 -0
  35. package/dist/types/src/examples/index.d.ts +4 -0
  36. package/dist/types/src/examples/index.d.ts.map +1 -0
  37. package/dist/types/src/examples/reply.d.ts +3 -0
  38. package/dist/types/src/examples/reply.d.ts.map +1 -0
  39. package/dist/types/src/examples/sleep.d.ts +5 -0
  40. package/dist/types/src/examples/sleep.d.ts.map +1 -0
  41. package/dist/types/src/executor/executor.d.ts +4 -1
  42. package/dist/types/src/executor/executor.d.ts.map +1 -1
  43. package/dist/types/src/handler.d.ts +40 -8
  44. package/dist/types/src/handler.d.ts.map +1 -1
  45. package/dist/types/src/index.d.ts +3 -1
  46. package/dist/types/src/index.d.ts.map +1 -1
  47. package/dist/types/src/schema.d.ts +6 -1
  48. package/dist/types/src/schema.d.ts.map +1 -1
  49. package/dist/types/src/services/credentials.d.ts +16 -3
  50. package/dist/types/src/services/credentials.d.ts.map +1 -1
  51. package/dist/types/src/services/database.d.ts +40 -6
  52. package/dist/types/src/services/database.d.ts.map +1 -1
  53. package/dist/types/src/services/event-logger.d.ts +65 -30
  54. package/dist/types/src/services/event-logger.d.ts.map +1 -1
  55. package/dist/types/src/services/index.d.ts +2 -1
  56. package/dist/types/src/services/index.d.ts.map +1 -1
  57. package/dist/types/src/services/local-function-execution.d.ts +25 -0
  58. package/dist/types/src/services/local-function-execution.d.ts.map +1 -0
  59. package/dist/types/src/services/queues.d.ts +21 -6
  60. package/dist/types/src/services/queues.d.ts.map +1 -1
  61. package/dist/types/src/services/remote-function-execution-service.d.ts +15 -0
  62. package/dist/types/src/services/remote-function-execution-service.d.ts.map +1 -0
  63. package/dist/types/src/services/service-container.d.ts +5 -5
  64. package/dist/types/src/services/service-container.d.ts.map +1 -1
  65. package/dist/types/src/services/service-registry.d.ts +1 -1
  66. package/dist/types/src/services/service-registry.d.ts.map +1 -1
  67. package/dist/types/src/services/tracing.d.ts +37 -5
  68. package/dist/types/src/services/tracing.d.ts.map +1 -1
  69. package/dist/types/src/testing/layer.d.ts +7 -2
  70. package/dist/types/src/testing/layer.d.ts.map +1 -1
  71. package/dist/types/src/testing/logger.d.ts +3 -3
  72. package/dist/types/src/testing/logger.d.ts.map +1 -1
  73. package/dist/types/src/testing/persist-database.test.d.ts +2 -0
  74. package/dist/types/src/testing/persist-database.test.d.ts.map +1 -0
  75. package/dist/types/src/testing/services.d.ts +2 -2
  76. package/dist/types/src/testing/services.d.ts.map +1 -1
  77. package/dist/types/src/trace.d.ts +20 -22
  78. package/dist/types/src/trace.d.ts.map +1 -1
  79. package/dist/types/src/triggers/index.d.ts +4 -0
  80. package/dist/types/src/triggers/index.d.ts.map +1 -0
  81. package/dist/types/src/triggers/input-builder.d.ts +3 -0
  82. package/dist/types/src/triggers/input-builder.d.ts.map +1 -0
  83. package/dist/types/src/triggers/invocation-tracer.d.ts +35 -0
  84. package/dist/types/src/triggers/invocation-tracer.d.ts.map +1 -0
  85. package/dist/types/src/triggers/trigger-dispatcher.d.ts +75 -0
  86. package/dist/types/src/triggers/trigger-dispatcher.d.ts.map +1 -0
  87. package/dist/types/src/triggers/trigger-dispatcher.test.d.ts +2 -0
  88. package/dist/types/src/triggers/trigger-dispatcher.test.d.ts.map +1 -0
  89. package/dist/types/src/triggers/trigger-state-store.d.ts +27 -0
  90. package/dist/types/src/triggers/trigger-state-store.d.ts.map +1 -0
  91. package/dist/types/src/types.d.ts +49 -249
  92. package/dist/types/src/types.d.ts.map +1 -1
  93. package/dist/types/src/url.d.ts +10 -6
  94. package/dist/types/src/url.d.ts.map +1 -1
  95. package/dist/types/tsconfig.tsbuildinfo +1 -1
  96. package/package.json +39 -34
  97. package/src/bundler/bundler.test.ts +8 -9
  98. package/src/bundler/bundler.ts +32 -33
  99. package/src/edge/functions.ts +8 -5
  100. package/src/errors.ts +13 -5
  101. package/src/examples/fib.ts +30 -0
  102. package/src/examples/index.ts +7 -0
  103. package/src/examples/reply.ts +18 -0
  104. package/src/examples/sleep.ts +22 -0
  105. package/src/executor/executor.ts +9 -9
  106. package/src/handler.ts +99 -18
  107. package/src/index.ts +3 -3
  108. package/src/schema.ts +11 -0
  109. package/src/services/credentials.ts +79 -3
  110. package/src/services/database.ts +119 -18
  111. package/src/services/event-logger.ts +68 -37
  112. package/src/services/index.ts +2 -1
  113. package/src/services/local-function-execution.ts +114 -0
  114. package/src/services/queues.ts +37 -10
  115. package/src/services/remote-function-execution-service.ts +46 -0
  116. package/src/services/service-container.ts +11 -10
  117. package/src/services/service-registry.ts +5 -2
  118. package/src/services/tracing.ts +105 -7
  119. package/src/testing/layer.ts +83 -3
  120. package/src/testing/logger.ts +4 -4
  121. package/src/testing/persist-database.test.ts +87 -0
  122. package/src/testing/services.ts +4 -3
  123. package/src/trace.ts +17 -19
  124. package/src/triggers/index.ts +7 -0
  125. package/src/triggers/input-builder.ts +35 -0
  126. package/src/triggers/invocation-tracer.ts +99 -0
  127. package/src/triggers/trigger-dispatcher.test.ts +652 -0
  128. package/src/triggers/trigger-dispatcher.ts +512 -0
  129. package/src/triggers/trigger-state-store.ts +60 -0
  130. package/src/types.ts +22 -33
  131. package/src/url.ts +13 -10
  132. package/dist/lib/browser/chunk-3NGCSUEW.mjs +0 -328
  133. package/dist/lib/browser/chunk-3NGCSUEW.mjs.map +0 -7
  134. package/dist/lib/node-esm/chunk-FJ2MU7TL.mjs +0 -330
  135. package/dist/lib/node-esm/chunk-FJ2MU7TL.mjs.map +0 -7
  136. package/dist/types/src/services/function-call-service.d.ts +0 -16
  137. package/dist/types/src/services/function-call-service.d.ts.map +0 -1
  138. package/src/services/function-call-service.ts +0 -64
@@ -1,48 +1,74 @@
1
1
  import {
2
+ ComputeEvent,
3
+ ComputeEventLogger,
4
+ ComputeEventPayload,
2
5
  ConfiguredCredentialsService,
3
6
  ContextQueueService,
4
7
  CredentialsService,
5
8
  DatabaseService,
6
- EventLogger,
7
- FunctionCallService,
9
+ FUNCTIONS_META_KEY,
10
+ FUNCTIONS_PRESET_META_KEY,
11
+ MESSAGE_PROPERTY_TOOL_CALL_ID,
8
12
  QueueService,
13
+ RemoteFunctionExecutionService,
9
14
  SERVICE_TAGS,
10
15
  ServiceContainer,
11
16
  TracingService,
12
17
  createDefectLogger,
13
18
  createEventLogger,
14
- logCustomEvent
15
- } from "./chunk-3NGCSUEW.mjs";
19
+ getInvocationUrl,
20
+ getUserFunctionIdInMetadata,
21
+ logCustomEvent,
22
+ setUserFunctionIdInMetadata,
23
+ withAuthorization
24
+ } from "./chunk-D2XO7XXY.mjs";
25
+ import {
26
+ __export
27
+ } from "./chunk-J5LGTIGS.mjs";
16
28
 
17
- // src/handler.ts
18
- import { Schema } from "effect";
19
- var defineFunction = ({ name, description, inputSchema, outputSchema = Schema.Any, handler }) => {
20
- if (!Schema.isSchema(inputSchema)) {
21
- throw new Error("Input schema must be a valid schema");
29
+ // src/errors.ts
30
+ import { BaseError } from "@dxos/errors";
31
+ var ServiceNotAvailableError = class extends BaseError.extend("SERVICE_NOT_AVAILABLE", "Service not available") {
32
+ constructor(service, options) {
33
+ super({
34
+ context: {
35
+ service
36
+ },
37
+ ...options
38
+ });
22
39
  }
23
- if (typeof handler !== "function") {
24
- throw new Error("Handler must be a function");
40
+ };
41
+ var FunctionNotFoundError = class extends BaseError.extend("FUNCTION_NOT_FOUND", "Function not found") {
42
+ constructor(functionKey, options) {
43
+ super({
44
+ context: {
45
+ function: functionKey
46
+ },
47
+ ...options
48
+ });
25
49
  }
26
- return {
27
- name,
28
- description,
29
- inputSchema,
30
- outputSchema,
31
- handler
32
- };
50
+ };
51
+ var FunctionError = class extends BaseError.extend("FUNCTION_ERROR", "Function invocation error") {
52
+ };
53
+ var TriggerStateNotFoundError = class extends BaseError.extend("TRIGGER_STATE_NOT_FOUND", "Trigger state not found") {
33
54
  };
34
55
 
56
+ // src/handler.ts
57
+ import { Effect, Schema as Schema2 } from "effect";
58
+ import { Obj, Type as Type2 } from "@dxos/echo";
59
+ import { assertArgument } from "@dxos/invariant";
60
+
35
61
  // src/schema.ts
36
- import { Schema as Schema2 } from "effect";
62
+ import { Schema } from "effect";
37
63
  import { Type } from "@dxos/echo";
38
64
  import { JsonSchemaType, LabelAnnotation, Ref } from "@dxos/echo-schema";
39
65
  import { DataType } from "@dxos/schema";
40
- var ScriptType = Schema2.Struct({
41
- name: Schema2.optional(Schema2.String),
42
- description: Schema2.optional(Schema2.String),
66
+ var ScriptType = Schema.Struct({
67
+ name: Schema.optional(Schema.String),
68
+ description: Schema.optional(Schema.String),
43
69
  // TODO(burdon): Change to hash of deployed content.
44
70
  // Whether source has changed since last deploy.
45
- changed: Schema2.optional(Schema2.Boolean),
71
+ changed: Schema.optional(Schema.Boolean),
46
72
  source: Ref(DataType.Text)
47
73
  }).pipe(Type.Obj({
48
74
  typename: "dxos.org/type/Script",
@@ -50,18 +76,28 @@ var ScriptType = Schema2.Struct({
50
76
  }), LabelAnnotation.set([
51
77
  "name"
52
78
  ]));
53
- var FunctionType = Schema2.Struct({
79
+ var FunctionType = Schema.Struct({
80
+ /**
81
+ * Global registry ID.
82
+ * NOTE: The `key` property refers to the original registry entry.
83
+ */
84
+ // TODO(burdon): Create Format type for DXN-like ids, such as this and schema type.
85
+ // TODO(dmaretskyi): Consider making it part of ECHO meta.
86
+ // TODO(dmaretskyi): Make required.
87
+ key: Schema.optional(Schema.String).annotations({
88
+ description: "Unique registration key for the blueprint"
89
+ }),
54
90
  // TODO(burdon): Rename to id/uri?
55
- name: Schema2.NonEmptyString,
56
- version: Schema2.String,
57
- description: Schema2.optional(Schema2.String),
91
+ name: Schema.NonEmptyString,
92
+ version: Schema.String,
93
+ description: Schema.optional(Schema.String),
58
94
  // Reference to a source script if it exists within ECHO.
59
95
  // TODO(burdon): Don't ref ScriptType directly (core).
60
- source: Schema2.optional(Ref(ScriptType)),
61
- inputSchema: Schema2.optional(JsonSchemaType),
62
- outputSchema: Schema2.optional(JsonSchemaType),
96
+ source: Schema.optional(Ref(ScriptType)),
97
+ inputSchema: Schema.optional(JsonSchemaType),
98
+ outputSchema: Schema.optional(JsonSchemaType),
63
99
  // Local binding to a function name.
64
- binding: Schema2.optional(Schema2.String)
100
+ binding: Schema.optional(Schema.String)
65
101
  }).pipe(Type.Obj({
66
102
  typename: "dxos.org/type/Function",
67
103
  version: "0.1.0"
@@ -69,25 +105,106 @@ var FunctionType = Schema2.Struct({
69
105
  "name"
70
106
  ]));
71
107
 
108
+ // src/handler.ts
109
+ var typeId = Symbol.for("@dxos/functions/FunctionDefinition");
110
+ var defineFunction = ({ key, name, description, inputSchema, outputSchema = Schema2.Any, handler }) => {
111
+ if (!Schema2.isSchema(inputSchema)) {
112
+ throw new Error("Input schema must be a valid schema");
113
+ }
114
+ if (typeof handler !== "function") {
115
+ throw new Error("Handler must be a function");
116
+ }
117
+ const limit = Error.stackTraceLimit;
118
+ Error.stackTraceLimit = 2;
119
+ const traceError = new Error();
120
+ Error.stackTraceLimit = limit;
121
+ let cache = false;
122
+ const captureStackTrace = () => {
123
+ if (cache !== false) {
124
+ return cache;
125
+ }
126
+ if (traceError.stack !== void 0) {
127
+ const stack = traceError.stack.split("\n");
128
+ if (stack[2] !== void 0) {
129
+ cache = stack[2].trim();
130
+ return cache;
131
+ }
132
+ }
133
+ };
134
+ const handlerWithSpan = (...args) => {
135
+ const result = handler(...args);
136
+ if (Effect.isEffect(result)) {
137
+ return Effect.withSpan(result, `${key ?? name}`, {
138
+ captureStackTrace
139
+ });
140
+ }
141
+ return result;
142
+ };
143
+ return {
144
+ [typeId]: true,
145
+ key: key ?? name,
146
+ name,
147
+ description,
148
+ inputSchema,
149
+ outputSchema,
150
+ handler: handlerWithSpan
151
+ };
152
+ };
153
+ var FunctionDefinition = {
154
+ make: defineFunction,
155
+ isFunction: (value) => {
156
+ return typeof value === "object" && value !== null && Symbol.for("@dxos/functions/FunctionDefinition") in value;
157
+ },
158
+ serialize: (functionDef) => {
159
+ assertArgument(FunctionDefinition.isFunction(functionDef), "functionDef");
160
+ return serializeFunction(functionDef);
161
+ },
162
+ deserialize: (functionObj) => {
163
+ assertArgument(Obj.instanceOf(FunctionType, functionObj), "functionObj");
164
+ return deserializeFunction(functionObj);
165
+ }
166
+ };
167
+ var serializeFunction = (functionDef) => Obj.make(FunctionType, {
168
+ key: functionDef.name,
169
+ name: functionDef.name,
170
+ version: "0.1.0",
171
+ description: functionDef.description,
172
+ inputSchema: Type2.toJsonSchema(functionDef.inputSchema),
173
+ outputSchema: !functionDef.outputSchema ? void 0 : Type2.toJsonSchema(functionDef.outputSchema)
174
+ });
175
+ var deserializeFunction = (functionObj) => {
176
+ return {
177
+ [typeId]: true,
178
+ // TODO(dmaretskyi): Fix key.
179
+ key: functionObj.key ?? functionObj.name,
180
+ name: functionObj.name,
181
+ description: functionObj.description,
182
+ inputSchema: !functionObj.inputSchema ? Schema2.Unknown : Type2.toEffectSchema(functionObj.inputSchema),
183
+ outputSchema: !functionObj.outputSchema ? void 0 : Type2.toEffectSchema(functionObj.outputSchema),
184
+ handler: () => {
185
+ }
186
+ };
187
+ };
188
+
72
189
  // src/trace.ts
73
190
  import { Schema as Schema4 } from "effect";
74
- import { Type as Type2 } from "@dxos/echo";
191
+ import { Type as Type4 } from "@dxos/echo";
75
192
  import { Queue } from "@dxos/echo-db";
76
193
  import { ObjectId } from "@dxos/echo-schema";
77
194
  import { log } from "@dxos/log";
78
195
 
79
196
  // src/types.ts
80
197
  import { Schema as Schema3, SchemaAST } from "effect";
81
- import { Expando, OptionsAnnotationId, TypedObject, Ref as Ref2, RawObject } from "@dxos/echo-schema";
198
+ import { QueryAST, Type as Type3 } from "@dxos/echo";
199
+ import { Expando, OptionsAnnotationId, RawObject, Ref as Ref2 } from "@dxos/echo-schema";
82
200
  import { DXN } from "@dxos/keys";
83
- var TriggerKind = /* @__PURE__ */ function(TriggerKind2) {
84
- TriggerKind2["Timer"] = "timer";
85
- TriggerKind2["Webhook"] = "webhook";
86
- TriggerKind2["Subscription"] = "subscription";
87
- TriggerKind2["Email"] = "email";
88
- TriggerKind2["Queue"] = "queue";
89
- return TriggerKind2;
90
- }({});
201
+ var TriggerKinds = [
202
+ "timer",
203
+ "webhook",
204
+ "subscription",
205
+ "email",
206
+ "queue"
207
+ ];
91
208
  var kindLiteralAnnotations = {
92
209
  title: "Kind"
93
210
  };
@@ -105,6 +222,7 @@ var EmailTriggerSchema = Schema3.Struct({
105
222
  }).pipe(Schema3.mutable);
106
223
  var QueueTriggerSchema = Schema3.Struct({
107
224
  kind: Schema3.Literal("queue").annotations(kindLiteralAnnotations),
225
+ // TODO(dmaretskyi): Change to a reference.
108
226
  queue: DXN.Schema
109
227
  }).pipe(Schema3.mutable);
110
228
  var WebhookTriggerSchema = Schema3.Struct({
@@ -120,21 +238,11 @@ var WebhookTriggerSchema = Schema3.Struct({
120
238
  title: "Port"
121
239
  }))
122
240
  }).pipe(Schema3.mutable);
123
- var QuerySchema = Schema3.Struct({
124
- type: Schema3.optional(Schema3.String.annotations({
125
- title: "Type"
126
- })),
127
- props: Schema3.optional(Schema3.Record({
128
- key: Schema3.String,
129
- value: Schema3.Any
130
- }))
131
- }).annotations({
132
- title: "Query"
133
- });
134
241
  var SubscriptionTriggerSchema = Schema3.Struct({
135
242
  kind: Schema3.Literal("subscription").annotations(kindLiteralAnnotations),
136
- // TODO(burdon): Define query DSL (from ECHO). Reconcile with Table.Query.
137
- filter: QuerySchema,
243
+ query: QueryAST.Query.annotations({
244
+ title: "Query"
245
+ }),
138
246
  options: Schema3.optional(Schema3.Struct({
139
247
  // Watch changes to object (not just creation).
140
248
  deep: Schema3.optional(Schema3.Boolean.annotations({
@@ -179,7 +287,7 @@ var SubscriptionTriggerOutput = Schema3.mutable(Schema3.Struct({
179
287
  var TimerTriggerOutput = Schema3.mutable(Schema3.Struct({
180
288
  tick: Schema3.Number
181
289
  }));
182
- var FunctionTriggerSchema = Schema3.Struct({
290
+ var FunctionTrigger_ = Schema3.Struct({
183
291
  /**
184
292
  * Function or workflow to invoke.
185
293
  */
@@ -214,12 +322,11 @@ var FunctionTriggerSchema = Schema3.Struct({
214
322
  key: Schema3.String,
215
323
  value: Schema3.Any
216
324
  })))
217
- });
218
- var FunctionTrigger = class extends TypedObject({
325
+ }).pipe(Type3.Obj({
219
326
  typename: "dxos.org/type/FunctionTrigger",
220
327
  version: "0.2.0"
221
- })(FunctionTriggerSchema.fields) {
222
- };
328
+ }));
329
+ var FunctionTrigger = FunctionTrigger_;
223
330
  var FunctionManifestSchema = Schema3.Struct({
224
331
  functions: Schema3.optional(Schema3.mutable(Schema3.Array(RawObject(FunctionType)))),
225
332
  triggers: Schema3.optional(Schema3.mutable(Schema3.Array(RawObject(FunctionTrigger))))
@@ -243,7 +350,7 @@ var InvocationTraceEventType = /* @__PURE__ */ function(InvocationTraceEventType
243
350
  return InvocationTraceEventType2;
244
351
  }({});
245
352
  var TraceEventException = Schema4.Struct({
246
- timestampMs: Schema4.Number,
353
+ timestamp: Schema4.Number,
247
354
  message: Schema4.String,
248
355
  name: Schema4.String,
249
356
  stack: Schema4.optional(Schema4.String)
@@ -261,7 +368,7 @@ var InvocationTraceStartEvent = Schema4.Struct({
261
368
  /**
262
369
  * Event generation time.
263
370
  */
264
- timestampMs: Schema4.Number,
371
+ timestamp: Schema4.Number,
265
372
  /**
266
373
  * Data passed to function / workflow as an argument.
267
374
  */
@@ -270,16 +377,16 @@ var InvocationTraceStartEvent = Schema4.Struct({
270
377
  /**
271
378
  * Queue for function/workflow invocation events.
272
379
  */
273
- invocationTraceQueue: Type2.Ref(Queue),
380
+ invocationTraceQueue: Schema4.optional(Type4.Ref(Queue)),
274
381
  /**
275
382
  * DXN of the invoked function/workflow.
276
383
  */
277
- invocationTarget: Type2.Ref(Type2.Expando),
384
+ invocationTarget: Schema4.optional(Type4.Ref(Type4.Expando)),
278
385
  /**
279
386
  * Present for automatic invocations.
280
387
  */
281
- trigger: Schema4.optional(Type2.Ref(FunctionTrigger))
282
- }).pipe(Type2.Obj({
388
+ trigger: Schema4.optional(Type4.Ref(FunctionTrigger))
389
+ }).pipe(Type4.Obj({
283
390
  typename: "dxos.org/type/InvocationTraceStart",
284
391
  version: "0.1.0"
285
392
  }));
@@ -297,15 +404,15 @@ var InvocationTraceEndEvent = Schema4.Struct({
297
404
  * Event generation time.
298
405
  */
299
406
  // TODO(burdon): Remove ms suffix.
300
- timestampMs: Schema4.Number,
407
+ timestamp: Schema4.Number,
301
408
  outcome: Schema4.Enums(InvocationOutcome),
302
409
  exception: Schema4.optional(TraceEventException)
303
- }).pipe(Type2.Obj({
410
+ }).pipe(Type4.Obj({
304
411
  typename: "dxos.org/type/InvocationTraceEnd",
305
412
  version: "0.1.0"
306
413
  }));
307
414
  var TraceEventLog = Schema4.Struct({
308
- timestampMs: Schema4.Number,
415
+ timestamp: Schema4.Number,
309
416
  level: Schema4.String,
310
417
  message: Schema4.String,
311
418
  context: Schema4.optional(Schema4.Object)
@@ -315,13 +422,11 @@ var TraceEvent = Schema4.Struct({
315
422
  // TODO(burdon): Need enum/numeric result (not string).
316
423
  outcome: Schema4.String,
317
424
  truncated: Schema4.Boolean,
318
- /**
319
- * Time when the event was persisted.
320
- */
321
- ingestionTimestampMs: Schema4.Number,
425
+ /** Time when the event was persisted. */
426
+ ingestionTimestamp: Schema4.Number,
322
427
  logs: Schema4.Array(TraceEventLog),
323
428
  exceptions: Schema4.Array(TraceEventException)
324
- }).pipe(Type2.Obj({
429
+ }).pipe(Type4.Obj({
325
430
  typename: "dxos.org/type/TraceEvent",
326
431
  version: "0.1.0"
327
432
  }));
@@ -354,7 +459,7 @@ var createInvocationSpans = (items) => {
354
459
  invocationId
355
460
  }, {
356
461
  F: __dxlog_file,
357
- L: 160,
462
+ L: 158,
358
463
  S: void 0,
359
464
  C: (f, a) => f(...a)
360
465
  });
@@ -363,8 +468,8 @@ var createInvocationSpans = (items) => {
363
468
  const isInProgress = end === void 0;
364
469
  result.push({
365
470
  id: invocationId,
366
- timestampMs: start.timestampMs,
367
- durationMs: isInProgress ? now - start.timestampMs : end.timestampMs - start.timestampMs,
471
+ timestamp: start.timestamp,
472
+ duration: isInProgress ? now - start.timestamp : end.timestamp - start.timestamp,
368
473
  outcome: end?.outcome ?? "pending",
369
474
  exception: end?.exception,
370
475
  input: start.input,
@@ -376,107 +481,767 @@ var createInvocationSpans = (items) => {
376
481
  return result;
377
482
  };
378
483
 
379
- // src/url.ts
380
- var FUNCTIONS_META_KEY = "dxos.org/service/function";
381
- var FUNCTIONS_PRESET_META_KEY = "dxos.org/service/function-preset";
382
- var isSecure = (protocol) => {
383
- return protocol === "https:" || protocol === "wss:";
484
+ // src/triggers/invocation-tracer.ts
485
+ import { Context as Context2, Effect as Effect3, Layer as Layer2 } from "effect";
486
+ import { Obj as Obj2, Ref as Ref3 } from "@dxos/echo";
487
+ import { DXN as DXN2, ObjectId as ObjectId2 } from "@dxos/keys";
488
+
489
+ // src/services/local-function-execution.ts
490
+ import { Context, Effect as Effect2, Layer, Schema as Schema5 } from "effect";
491
+ import { todo } from "@dxos/debug";
492
+ function _define_property(obj, key, value) {
493
+ if (key in obj) {
494
+ Object.defineProperty(obj, key, {
495
+ value,
496
+ enumerable: true,
497
+ configurable: true,
498
+ writable: true
499
+ });
500
+ } else {
501
+ obj[key] = value;
502
+ }
503
+ return obj;
504
+ }
505
+ var _Context_Tag;
506
+ var LocalFunctionExecutionService = class extends (_Context_Tag = Context.Tag("@dxos/functions/LocalFunctionExecutionService")()) {
384
507
  };
385
- var getUserFunctionUrlInMetadata = (meta) => {
386
- return meta.keys.find((key) => key.source === FUNCTIONS_META_KEY)?.id;
508
+ _define_property(LocalFunctionExecutionService, "layer", Layer.succeed(LocalFunctionExecutionService, {
509
+ invokeFunction: (functionDef, input) => invokeFunction(functionDef, input)
510
+ }));
511
+ _define_property(LocalFunctionExecutionService, "layerLive", Layer.effect(LocalFunctionExecutionService, Effect2.gen(function* () {
512
+ const resolver = yield* FunctionImplementationResolver;
513
+ return {
514
+ invokeFunction: Effect2.fn("invokeFunction")(function* (functionDef, input) {
515
+ const resolved = yield* resolver.resolveFunctionImplementation(functionDef).pipe(Effect2.orDie);
516
+ return yield* invokeFunction(resolved, input);
517
+ })
518
+ };
519
+ })));
520
+ _define_property(LocalFunctionExecutionService, "invokeFunction", Effect2.serviceFunctionEffect(LocalFunctionExecutionService, (_) => _.invokeFunction));
521
+ var invokeFunction = (functionDef, input) => Effect2.gen(function* () {
522
+ const assertInput = functionDef.inputSchema.pipe(Schema5.asserts);
523
+ assertInput(input);
524
+ const context = {
525
+ space: void 0,
526
+ getService: () => todo(),
527
+ getSpace: async (_spaceId) => {
528
+ throw new Error("Not available. Use the database service instead.");
529
+ }
530
+ };
531
+ const data = yield* Effect2.gen(function* () {
532
+ const result = functionDef.handler({
533
+ context,
534
+ data: input
535
+ });
536
+ if (Effect2.isEffect(result)) {
537
+ return yield* result.pipe(Effect2.orDie);
538
+ } else if (typeof result === "object" && result !== null && "then" in result && typeof result.then === "function") {
539
+ return yield* Effect2.promise(() => result);
540
+ } else {
541
+ return result;
542
+ }
543
+ }).pipe(Effect2.orDie, Effect2.catchAllDefect((defect) => Effect2.die(new FunctionError({
544
+ context: {
545
+ name: functionDef.name
546
+ },
547
+ cause: defect
548
+ }))));
549
+ const assertOutput = functionDef.outputSchema?.pipe(Schema5.asserts);
550
+ assertOutput(data);
551
+ return data;
552
+ }).pipe(Effect2.withSpan("invokeFunction", {
553
+ attributes: {
554
+ name: functionDef.name
555
+ }
556
+ }));
557
+ var _Context_Tag1;
558
+ var FunctionImplementationResolver = class extends (_Context_Tag1 = Context.Tag("@dxos/functions/FunctionImplementationResolver")()) {
559
+ };
560
+ _define_property(FunctionImplementationResolver, "layerTest", ({ functions }) => Layer.succeed(FunctionImplementationResolver, {
561
+ resolveFunctionImplementation: (functionDef) => {
562
+ const resolved = functions.find((f) => f.name === functionDef.name);
563
+ if (!resolved) {
564
+ return Effect2.fail(new FunctionNotFoundError(functionDef.name));
565
+ }
566
+ return Effect2.succeed(resolved);
567
+ }
568
+ }));
569
+
570
+ // src/triggers/invocation-tracer.ts
571
+ function _define_property2(obj, key, value) {
572
+ if (key in obj) {
573
+ Object.defineProperty(obj, key, {
574
+ value,
575
+ enumerable: true,
576
+ configurable: true,
577
+ writable: true
578
+ });
579
+ } else {
580
+ obj[key] = value;
581
+ }
582
+ return obj;
583
+ }
584
+ var _Context_Tag2;
585
+ var InvocationTracer = class extends (_Context_Tag2 = Context2.Tag("@dxos/functions/InvocationTracer")()) {
387
586
  };
388
- var setUserFunctionUrlInMetadata = (meta, functionUrl) => {
389
- const key = meta.keys.find((key2) => key2.source === FUNCTIONS_META_KEY);
390
- if (key) {
391
- if (key.id !== functionUrl) {
392
- throw new Error("Metadata mismatch");
587
+ _define_property2(InvocationTracer, "layerLive", (opts) => Layer2.effect(InvocationTracer, Effect3.gen(function* () {
588
+ return {
589
+ traceInvocationStart: Effect3.fn("traceInvocationStart")(function* ({ payload, target }) {
590
+ const invocationId = ObjectId2.random();
591
+ const invocationTraceQueue = yield* QueueService.createQueue({
592
+ subspaceTag: "trace"
593
+ });
594
+ const now = Date.now();
595
+ const traceEvent = Obj2.make(InvocationTraceStartEvent, {
596
+ type: InvocationTraceEventType.START,
597
+ invocationId,
598
+ timestamp: now,
599
+ // TODO(dmaretskyi): Not json-stringifying this makes ECHO fail when one ECHO object becomes embedded in another ECHO object.
600
+ input: JSON.parse(JSON.stringify(payload.data ?? {})),
601
+ invocationTraceQueue: Ref3.fromDXN(invocationTraceQueue.dxn),
602
+ invocationTarget: target ? Ref3.fromDXN(target) : void 0,
603
+ trigger: payload.trigger ? Ref3.fromDXN(DXN2.fromLocalObjectId(payload.trigger.id)) : void 0
604
+ });
605
+ yield* QueueService.append(opts.invocationTraceQueue, [
606
+ traceEvent
607
+ ]);
608
+ return {
609
+ invocationId,
610
+ invocationTraceQueue
611
+ };
612
+ }),
613
+ traceInvocationEnd: Effect3.fn("traceInvocationEnd")(function* ({ trace, exception }) {
614
+ const now = Date.now();
615
+ const traceEvent = Obj2.make(InvocationTraceEndEvent, {
616
+ type: InvocationTraceEventType.END,
617
+ invocationId: trace.invocationId,
618
+ timestamp: now,
619
+ outcome: exception ? InvocationOutcome.FAILURE : InvocationOutcome.SUCCESS,
620
+ exception: exception ? {
621
+ name: exception.constructor.name,
622
+ timestamp: now,
623
+ message: exception?.message ?? "Unknown error",
624
+ stack: exception?.stack
625
+ } : void 0
626
+ });
627
+ yield* QueueService.append(opts.invocationTraceQueue, [
628
+ traceEvent
629
+ ]);
630
+ })
631
+ };
632
+ })));
633
+ _define_property2(InvocationTracer, "layerTest", Layer2.unwrapEffect(Effect3.gen(function* () {
634
+ const queue = yield* QueueService.createQueue({
635
+ subspaceTag: "trace"
636
+ });
637
+ return InvocationTracer.layerLive({
638
+ invocationTraceQueue: queue
639
+ });
640
+ })));
641
+
642
+ // src/triggers/trigger-dispatcher.ts
643
+ import { Cause, Context as Context4, Cron, Duration, Effect as Effect5, Either, Exit, Fiber, Layer as Layer4, Option as Option2, Record, Schedule } from "effect";
644
+ import { DXN as DXN3, Filter, Obj as Obj3, Query } from "@dxos/echo";
645
+ import { causeToError } from "@dxos/effect";
646
+ import { invariant } from "@dxos/invariant";
647
+ import { log as log2 } from "@dxos/log";
648
+ import { KEY_QUEUE_POSITION } from "@dxos/protocols";
649
+
650
+ // src/triggers/input-builder.ts
651
+ var createInvocationPayload = (trigger, event) => {
652
+ if (!trigger.input) {
653
+ return event;
654
+ }
655
+ const payload = {};
656
+ for (const [key, value] of Object.entries(trigger.input)) {
657
+ if (typeof value !== "string" || !(value.startsWith("{{") && value.endsWith("}}"))) {
658
+ payload[key] = value;
659
+ continue;
393
660
  }
661
+ const propertyPath = value.slice(2, -2);
662
+ let valueSubstitution = propertyPath.startsWith("trigger.") ? trigger : propertyPath.startsWith("event.") ? event : void 0;
663
+ for (const pathSegment of propertyPath.split(".").slice(1)) {
664
+ if (valueSubstitution && typeof valueSubstitution === "object") {
665
+ valueSubstitution = valueSubstitution[pathSegment];
666
+ }
667
+ }
668
+ payload[key] = valueSubstitution;
669
+ }
670
+ return payload;
671
+ };
672
+
673
+ // src/triggers/trigger-state-store.ts
674
+ import { KeyValueStore } from "@effect/platform";
675
+ import { Context as Context3 } from "effect";
676
+ import { Schema as Schema6 } from "effect";
677
+ import { Effect as Effect4, Layer as Layer3 } from "effect";
678
+ import { Option } from "effect";
679
+ import { ObjectId as ObjectId3 } from "@dxos/keys";
680
+ function _define_property3(obj, key, value) {
681
+ if (key in obj) {
682
+ Object.defineProperty(obj, key, {
683
+ value,
684
+ enumerable: true,
685
+ configurable: true,
686
+ writable: true
687
+ });
394
688
  } else {
395
- meta.keys.push({
396
- source: FUNCTIONS_META_KEY,
397
- id: functionUrl
689
+ obj[key] = value;
690
+ }
691
+ return obj;
692
+ }
693
+ var TriggerState = Schema6.Struct({
694
+ version: Schema6.Literal("1"),
695
+ triggerId: Schema6.String,
696
+ state: Schema6.optional(Schema6.Union(Schema6.TaggedStruct("subscription", {
697
+ processedVersions: Schema6.Record({
698
+ key: ObjectId3,
699
+ value: Schema6.String
700
+ })
701
+ })))
702
+ });
703
+ var _Context_Tag3;
704
+ var TriggerStateStore = class extends (_Context_Tag3 = Context3.Tag("@dxos/functions/TriggerStateStore")()) {
705
+ };
706
+ _define_property3(TriggerStateStore, "getState", Effect4.serviceFunctionEffect(TriggerStateStore, (_) => _.getState));
707
+ _define_property3(TriggerStateStore, "saveState", Effect4.serviceFunctionEffect(TriggerStateStore, (_) => _.saveState));
708
+ _define_property3(TriggerStateStore, "layerKv", Layer3.effect(TriggerStateStore, Effect4.gen(function* () {
709
+ const kv = yield* KeyValueStore.KeyValueStore;
710
+ const schemaStore = kv.forSchema(Schema6.parseJson(TriggerState));
711
+ const store = {
712
+ getState: Effect4.fn("TriggerStateStore.getState")(function* (triggerId) {
713
+ const valueOption = yield* schemaStore.get(triggerId).pipe(Effect4.orDie);
714
+ if (Option.isNone(valueOption)) {
715
+ return yield* Effect4.fail(new TriggerStateNotFoundError());
716
+ }
717
+ return valueOption.value;
718
+ }),
719
+ saveState: Effect4.fn("TriggerStateStore.saveState")(function* (state) {
720
+ yield* schemaStore.set(state.triggerId, state).pipe(Effect4.orDie);
721
+ })
722
+ };
723
+ return store;
724
+ })));
725
+ _define_property3(TriggerStateStore, "layerMemory", TriggerStateStore.layerKv.pipe(Layer3.provide(KeyValueStore.layerMemory)));
726
+
727
+ // src/triggers/trigger-dispatcher.ts
728
+ function _define_property4(obj, key, value) {
729
+ if (key in obj) {
730
+ Object.defineProperty(obj, key, {
731
+ value,
732
+ enumerable: true,
733
+ configurable: true,
734
+ writable: true
398
735
  });
736
+ } else {
737
+ obj[key] = value;
399
738
  }
739
+ return obj;
740
+ }
741
+ var __dxlog_file2 = "/__w/dxos/dxos/packages/core/functions/src/triggers/trigger-dispatcher.ts";
742
+ var _Context_Tag4;
743
+ var TriggerDispatcher = class extends (_Context_Tag4 = Context4.Tag("@dxos/functions/TriggerDispatcher")()) {
400
744
  };
401
- var makeFunctionUrl = (fn) => `/${fn.functionId}`;
402
- var getInvocationUrl = (functionUrl, edgeUrl, options = {}) => {
403
- const baseUrl = new URL("functions/", edgeUrl);
404
- const relativeUrl = functionUrl.replace(/^\//, "");
405
- const url = new URL(`./${relativeUrl}`, baseUrl.toString());
406
- options.spaceId && url.searchParams.set("spaceId", options.spaceId);
407
- options.subjectId && url.searchParams.set("subjectId", options.subjectId);
408
- url.protocol = isSecure(url.protocol) ? "https" : "http";
409
- return url.toString();
745
+ _define_property4(TriggerDispatcher, "layer", (options) => Layer4.effect(TriggerDispatcher, Effect5.gen(function* () {
746
+ return new TriggerDispatcherImpl(options);
747
+ })));
748
+ var TriggerDispatcherImpl = class {
749
+ get running() {
750
+ return this._running;
751
+ }
752
+ constructor(options) {
753
+ _define_property4(this, "livePollInterval", void 0);
754
+ _define_property4(this, "timeControl", void 0);
755
+ _define_property4(this, "_running", false);
756
+ _define_property4(this, "_internalTime", void 0);
757
+ _define_property4(this, "_timerFiber", void 0);
758
+ _define_property4(this, "_scheduledTriggers", /* @__PURE__ */ new Map());
759
+ _define_property4(this, "start", () => Effect5.gen(this, function* () {
760
+ if (this._running) {
761
+ return;
762
+ }
763
+ this._running = true;
764
+ if (this.timeControl === "natural") {
765
+ this._timerFiber = yield* this._startNaturalTimeProcessing().pipe(Effect5.tapErrorCause((cause) => {
766
+ const error = causeToError(cause);
767
+ log2.error("trigger dispatcher error", {
768
+ error
769
+ }, {
770
+ F: __dxlog_file2,
771
+ L: 170,
772
+ S: this,
773
+ C: (f, a) => f(...a)
774
+ });
775
+ this._running = false;
776
+ return Effect5.void;
777
+ }), Effect5.forkDaemon);
778
+ } else {
779
+ return yield* Effect5.dieMessage("TriggerDispatcher started in manual time control mode");
780
+ }
781
+ log2.info("TriggerDispatcher started", {
782
+ timeControl: this.timeControl
783
+ }, {
784
+ F: __dxlog_file2,
785
+ L: 180,
786
+ S: this,
787
+ C: (f, a) => f(...a)
788
+ });
789
+ }));
790
+ _define_property4(this, "stop", () => Effect5.gen(this, function* () {
791
+ if (!this._running) {
792
+ return;
793
+ }
794
+ this._running = false;
795
+ if (this._timerFiber) {
796
+ yield* Fiber.interrupt(this._timerFiber);
797
+ this._timerFiber = void 0;
798
+ }
799
+ this._scheduledTriggers.clear();
800
+ log2.info("TriggerDispatcher stopped", void 0, {
801
+ F: __dxlog_file2,
802
+ L: 200,
803
+ S: this,
804
+ C: (f, a) => f(...a)
805
+ });
806
+ }));
807
+ _define_property4(this, "invokeTrigger", (options2) => Effect5.gen(this, function* () {
808
+ const { trigger, event } = options2;
809
+ log2.info("running trigger", {
810
+ triggerId: trigger.id,
811
+ spec: trigger.spec,
812
+ event
813
+ }, {
814
+ F: __dxlog_file2,
815
+ L: 208,
816
+ S: this,
817
+ C: (f, a) => f(...a)
818
+ });
819
+ const tracer = yield* InvocationTracer;
820
+ const trace = yield* tracer.traceInvocationStart({
821
+ target: trigger.function?.dxn,
822
+ payload: {
823
+ trigger: {
824
+ id: trigger.id,
825
+ // TODO(dmaretskyi): Is `spec` always there>
826
+ kind: trigger.spec.kind
827
+ },
828
+ data: event
829
+ }
830
+ });
831
+ const result = yield* Effect5.gen(this, function* () {
832
+ if (!trigger.enabled) {
833
+ return yield* Effect5.dieMessage("Attempting to invoke disabled trigger");
834
+ }
835
+ if (!trigger.function) {
836
+ return yield* Effect5.dieMessage("Trigger has no function reference");
837
+ }
838
+ const serialiedFunction = yield* DatabaseService.load(trigger.function).pipe(Effect5.orDie);
839
+ invariant(Obj3.instanceOf(FunctionType, serialiedFunction), void 0, {
840
+ F: __dxlog_file2,
841
+ L: 235,
842
+ S: this,
843
+ A: [
844
+ "Obj.instanceOf(FunctionType, serialiedFunction)",
845
+ ""
846
+ ]
847
+ });
848
+ const functionDef = deserializeFunction(serialiedFunction);
849
+ const inputData = this._prepareInputData(trigger, event);
850
+ return yield* LocalFunctionExecutionService.invokeFunction(functionDef, inputData).pipe(Effect5.provide(ComputeEventLogger.layerFromTracing.pipe(Layer4.provideMerge(TracingService.layerQueue(trace.invocationTraceQueue)))));
851
+ }).pipe(Effect5.exit);
852
+ const triggerExecutionResult = {
853
+ triggerId: trigger.id,
854
+ result
855
+ };
856
+ if (Exit.isSuccess(result)) {
857
+ log2.info("trigger execution success", {
858
+ triggerId: trigger.id
859
+ }, {
860
+ F: __dxlog_file2,
861
+ L: 256,
862
+ S: this,
863
+ C: (f, a) => f(...a)
864
+ });
865
+ } else {
866
+ log2.error("trigger execution failure", {
867
+ error: causeToError(result.cause)
868
+ }, {
869
+ F: __dxlog_file2,
870
+ L: 260,
871
+ S: this,
872
+ C: (f, a) => f(...a)
873
+ });
874
+ }
875
+ yield* tracer.traceInvocationEnd({
876
+ trace,
877
+ // TODO(dmaretskyi): Might miss errors.
878
+ exception: Exit.isFailure(result) ? Cause.prettyErrors(result.cause)[0] : void 0
879
+ });
880
+ return triggerExecutionResult;
881
+ }));
882
+ _define_property4(this, "invokeScheduledTriggers", ({ kinds = [
883
+ "timer",
884
+ "queue",
885
+ "subscription"
886
+ ] } = {}) => Effect5.gen(this, function* () {
887
+ const invocations = [];
888
+ for (const kind of kinds) {
889
+ switch (kind) {
890
+ case "timer":
891
+ {
892
+ yield* this.refreshTriggers();
893
+ const now = this.getCurrentTime();
894
+ const triggersToInvoke = [];
895
+ for (const [triggerId, scheduledTrigger] of this._scheduledTriggers.entries()) {
896
+ if (scheduledTrigger.nextExecution <= now) {
897
+ triggersToInvoke.push(scheduledTrigger.trigger);
898
+ scheduledTrigger.nextExecution = Cron.next(scheduledTrigger.cron, now);
899
+ }
900
+ }
901
+ invocations.push(...yield* Effect5.forEach(triggersToInvoke, (trigger) => this.invokeTrigger({
902
+ trigger,
903
+ event: {
904
+ tick: now.getTime()
905
+ }
906
+ }), {
907
+ concurrency: 1
908
+ }));
909
+ }
910
+ break;
911
+ case "queue": {
912
+ const triggers = yield* this._fetchTriggers();
913
+ for (const trigger of triggers) {
914
+ const spec = trigger.spec;
915
+ if (spec?.kind !== "queue") {
916
+ continue;
917
+ }
918
+ const cursor = Obj3.getKeys(trigger, KEY_QUEUE_CURSOR).at(0)?.id;
919
+ const queue = yield* QueueService.getQueue(DXN3.parse(spec.queue));
920
+ const objects = yield* Effect5.promise(() => queue.queryObjects());
921
+ for (const object of objects) {
922
+ const objectPos = Obj3.getKeys(object, KEY_QUEUE_POSITION).at(0)?.id;
923
+ if (!objectPos || cursor && parseInt(cursor) >= parseInt(objectPos)) {
924
+ continue;
925
+ }
926
+ invocations.push(yield* this.invokeTrigger({
927
+ trigger,
928
+ event: {
929
+ queue: spec.queue,
930
+ item: object,
931
+ cursor: objectPos
932
+ }
933
+ }));
934
+ Obj3.deleteKeys(trigger, KEY_QUEUE_CURSOR);
935
+ Obj3.getMeta(trigger).keys.push({
936
+ source: KEY_QUEUE_CURSOR,
937
+ id: objectPos
938
+ });
939
+ yield* DatabaseService.flush();
940
+ break;
941
+ }
942
+ }
943
+ break;
944
+ }
945
+ case "subscription": {
946
+ const triggers = yield* this._fetchTriggers();
947
+ for (const trigger of triggers) {
948
+ const spec = Obj3.getSnapshot(trigger).spec;
949
+ if (spec?.kind !== "subscription") {
950
+ continue;
951
+ }
952
+ const { objects } = yield* DatabaseService.runQuery(Query.fromAst(spec.query));
953
+ const state = yield* TriggerStateStore.getState(trigger.id).pipe(Effect5.catchTag("TRIGGER_STATE_NOT_FOUND", () => Effect5.succeed({
954
+ version: "1",
955
+ triggerId: trigger.id,
956
+ state: {
957
+ _tag: "subscription",
958
+ processedVersions: {}
959
+ }
960
+ })));
961
+ invariant(state.state?._tag === "subscription", void 0, {
962
+ F: __dxlog_file2,
963
+ L: 373,
964
+ S: this,
965
+ A: [
966
+ "state.state?._tag === 'subscription'",
967
+ ""
968
+ ]
969
+ });
970
+ let updated = false;
971
+ for (const object of objects) {
972
+ const existingVersion = Record.get(state.state.processedVersions, object.id).pipe(Option2.map(Obj3.decodeVersion));
973
+ const currentVersion = Obj3.version(object);
974
+ const run = Option2.isNone(existingVersion) || Obj3.compareVersions(currentVersion, existingVersion.value) === "different";
975
+ if (!run) {
976
+ continue;
977
+ }
978
+ invocations.push(yield* this.invokeTrigger({
979
+ trigger,
980
+ event: {
981
+ // TODO(dmaretskyi): Change type not supported.
982
+ type: "unknown",
983
+ changedObjectId: object.id
984
+ }
985
+ }));
986
+ state.state.processedVersions[object.id] = Obj3.encodeVersion(currentVersion);
987
+ updated = true;
988
+ }
989
+ if (updated) {
990
+ yield* TriggerStateStore.saveState(state);
991
+ }
992
+ }
993
+ break;
994
+ }
995
+ default: {
996
+ return yield* Effect5.dieMessage(`Unknown trigger kind: ${kind}`);
997
+ }
998
+ }
999
+ }
1000
+ return invocations;
1001
+ }));
1002
+ _define_property4(this, "advanceTime", (duration) => Effect5.gen(this, function* () {
1003
+ if (this.timeControl !== "manual") {
1004
+ return yield* Effect5.dieMessage("advanceTime can only be used in manual time control mode");
1005
+ }
1006
+ const millis = Duration.toMillis(duration);
1007
+ this._internalTime = new Date(this._internalTime.getTime() + millis);
1008
+ log2("Advanced internal time", {
1009
+ newTime: this._internalTime,
1010
+ advancedBy: Duration.format(duration)
1011
+ }, {
1012
+ F: __dxlog_file2,
1013
+ L: 426,
1014
+ S: this,
1015
+ C: (f, a) => f(...a)
1016
+ });
1017
+ }).pipe(Effect5.orDie));
1018
+ _define_property4(this, "getCurrentTime", () => {
1019
+ if (this.timeControl === "natural") {
1020
+ return /* @__PURE__ */ new Date();
1021
+ } else {
1022
+ return new Date(this._internalTime);
1023
+ }
1024
+ });
1025
+ _define_property4(this, "refreshTriggers", () => Effect5.gen(this, function* () {
1026
+ const triggers = yield* this._fetchTriggers();
1027
+ const currentTriggerIds = new Set(triggers.map((t) => t.id));
1028
+ for (const triggerId of this._scheduledTriggers.keys()) {
1029
+ if (!currentTriggerIds.has(triggerId)) {
1030
+ this._scheduledTriggers.delete(triggerId);
1031
+ }
1032
+ }
1033
+ for (const trigger of triggers) {
1034
+ if (trigger.spec?.kind === "timer" && trigger.enabled) {
1035
+ const timerSpec = trigger.spec;
1036
+ const cronEither = Cron.parse(timerSpec.cron);
1037
+ if (Either.isRight(cronEither)) {
1038
+ const cron = cronEither.right;
1039
+ const existing = this._scheduledTriggers.get(trigger.id);
1040
+ const now = this.getCurrentTime();
1041
+ const nextExecution = existing?.nextExecution ?? Cron.next(cron, now);
1042
+ log2("Updated scheduled trigger", {
1043
+ triggerId: trigger.id,
1044
+ cron: timerSpec.cron,
1045
+ nextExecution,
1046
+ now
1047
+ }, {
1048
+ F: __dxlog_file2,
1049
+ L: 466,
1050
+ S: this,
1051
+ C: (f, a) => f(...a)
1052
+ });
1053
+ this._scheduledTriggers.set(trigger.id, {
1054
+ trigger,
1055
+ cron,
1056
+ nextExecution
1057
+ });
1058
+ } else {
1059
+ log2.error("Invalid cron expression", {
1060
+ triggerId: trigger.id,
1061
+ cron: timerSpec.cron,
1062
+ error: cronEither.left.message
1063
+ }, {
1064
+ F: __dxlog_file2,
1065
+ L: 478,
1066
+ S: this,
1067
+ C: (f, a) => f(...a)
1068
+ });
1069
+ }
1070
+ }
1071
+ }
1072
+ log2("Updated scheduled triggers", {
1073
+ count: this._scheduledTriggers.size
1074
+ }, {
1075
+ F: __dxlog_file2,
1076
+ L: 487,
1077
+ S: this,
1078
+ C: (f, a) => f(...a)
1079
+ });
1080
+ }).pipe(Effect5.withSpan("TriggerDispatcher.refreshTriggers")));
1081
+ _define_property4(this, "_fetchTriggers", () => Effect5.gen(this, function* () {
1082
+ const { objects } = yield* DatabaseService.runQuery(Filter.type(FunctionTrigger));
1083
+ return objects;
1084
+ }).pipe(Effect5.withSpan("TriggerDispatcher.fetchTriggers")));
1085
+ _define_property4(this, "_startNaturalTimeProcessing", () => Effect5.gen(this, function* () {
1086
+ yield* this.invokeScheduledTriggers();
1087
+ }).pipe(Effect5.repeat(Schedule.fixed(this.livePollInterval)), Effect5.asVoid));
1088
+ _define_property4(this, "_prepareInputData", (trigger, event) => {
1089
+ return createInvocationPayload(trigger, event);
1090
+ });
1091
+ this.timeControl = options.timeControl;
1092
+ this.livePollInterval = options.livePollInterval ?? Duration.seconds(1);
1093
+ this._internalTime = options.startingTime ?? /* @__PURE__ */ new Date();
1094
+ }
410
1095
  };
1096
+ var KEY_QUEUE_CURSOR = "dxos.org/key/local-trigger-dispatcher/queue-cursor";
411
1097
 
412
1098
  // src/executor/executor.ts
413
- import { Effect, Schema as Schema5 } from "effect";
1099
+ import { Effect as Effect6, Schema as Schema7 } from "effect";
414
1100
  import { runAndForwardErrors } from "@dxos/effect";
415
- var FunctionExecutor = class {
416
- constructor(_services) {
417
- this._services = _services;
1101
+ function _define_property5(obj, key, value) {
1102
+ if (key in obj) {
1103
+ Object.defineProperty(obj, key, {
1104
+ value,
1105
+ enumerable: true,
1106
+ configurable: true,
1107
+ writable: true
1108
+ });
1109
+ } else {
1110
+ obj[key] = value;
418
1111
  }
1112
+ return obj;
1113
+ }
1114
+ var FunctionExecutor = class {
1115
+ /**
1116
+ * Invoke function.
1117
+ */
419
1118
  // TODO(dmaretskyi): Invocation context: queue, space, etc...
420
- async invoke(fnDef, input) {
421
- const assertInput = fnDef.inputSchema.pipe(Schema5.asserts);
1119
+ async invoke(functionDef, input) {
1120
+ const assertInput = functionDef.inputSchema.pipe(Schema7.asserts);
422
1121
  assertInput(input);
423
1122
  const context = {
1123
+ space: void 0,
424
1124
  getService: this._services.getService.bind(this._services),
425
1125
  getSpace: async (_spaceId) => {
426
1126
  throw new Error("Not available. Use the database service instead.");
427
- },
428
- space: void 0,
429
- get ai() {
430
- throw new Error("Not available. Use the ai service instead.");
431
1127
  }
432
1128
  };
433
- const result = fnDef.handler({
1129
+ const result = functionDef.handler({
434
1130
  context,
435
1131
  data: input
436
1132
  });
437
1133
  let data;
438
- if (Effect.isEffect(result)) {
439
- data = await result.pipe(Effect.provide(this._services.createLayer()), runAndForwardErrors);
1134
+ if (Effect6.isEffect(result)) {
1135
+ data = await result.pipe(Effect6.provide(this._services.createLayer()), runAndForwardErrors);
440
1136
  } else {
441
1137
  data = await result;
442
1138
  }
443
- const assertOutput = fnDef.outputSchema?.pipe(Schema5.asserts);
1139
+ const assertOutput = functionDef.outputSchema?.pipe(Schema7.asserts);
444
1140
  assertOutput(data);
445
1141
  return data;
446
1142
  }
447
- };
448
-
449
- // src/errors.ts
450
- import { BaseError } from "@dxos/errors";
451
- var ServiceNotAvailableError = class extends BaseError.extend("SERVICE_NOT_AVAILABLE") {
452
- constructor(serviceName) {
453
- super(`Service not available: ${serviceName}`);
1143
+ constructor(_services) {
1144
+ _define_property5(this, "_services", void 0);
1145
+ this._services = _services;
454
1146
  }
455
1147
  };
456
- var FunctionError = class extends BaseError.extend("FUNCTION_ERROR") {
457
- };
1148
+
1149
+ // src/examples/index.ts
1150
+ var examples_exports = {};
1151
+ __export(examples_exports, {
1152
+ fib: () => fib_default,
1153
+ reply: () => reply_default,
1154
+ sleep: () => sleep_default
1155
+ });
1156
+
1157
+ // src/examples/fib.ts
1158
+ import { Effect as Effect7, Schema as Schema8 } from "effect";
1159
+ var fib_default = defineFunction({
1160
+ name: "example.org/function/fib",
1161
+ description: "Function that calculates a Fibonacci number",
1162
+ inputSchema: Schema8.Struct({
1163
+ iterations: Schema8.optional(Schema8.Number).annotations({
1164
+ description: "Number of iterations",
1165
+ default: 1e5
1166
+ })
1167
+ }),
1168
+ outputSchema: Schema8.Struct({
1169
+ result: Schema8.String
1170
+ }),
1171
+ handler: Effect7.fn(function* ({ data: { iterations = 1e5 } }) {
1172
+ let a = 0n;
1173
+ let b = 1n;
1174
+ for (let i = 0; i < iterations; i++) {
1175
+ a += b;
1176
+ b = a - b;
1177
+ }
1178
+ return {
1179
+ result: a.toString()
1180
+ };
1181
+ })
1182
+ });
1183
+
1184
+ // src/examples/reply.ts
1185
+ import { Console, Effect as Effect8, Schema as Schema9 } from "effect";
1186
+ var reply_default = defineFunction({
1187
+ name: "example.org/function/reply",
1188
+ description: "Function that echoes the input",
1189
+ inputSchema: Schema9.Any,
1190
+ outputSchema: Schema9.Any,
1191
+ handler: Effect8.fn(function* ({ data }) {
1192
+ yield* Console.log("reply", {
1193
+ data
1194
+ });
1195
+ return data;
1196
+ })
1197
+ });
1198
+
1199
+ // src/examples/sleep.ts
1200
+ import { Effect as Effect9, Schema as Schema10 } from "effect";
1201
+ var sleep_default = defineFunction({
1202
+ name: "example.org/function/sleep",
1203
+ description: "Function that sleeps for a given amount of time",
1204
+ inputSchema: Schema10.Struct({
1205
+ duration: Schema10.optional(Schema10.Number).annotations({
1206
+ description: "Milliseconds to sleep",
1207
+ default: 1e5
1208
+ })
1209
+ }),
1210
+ outputSchema: Schema10.Void,
1211
+ handler: Effect9.fn(function* ({ data: { duration = 1e5 } }) {
1212
+ yield* Effect9.sleep(duration);
1213
+ })
1214
+ });
458
1215
  export {
1216
+ ComputeEvent,
1217
+ ComputeEventLogger,
1218
+ ComputeEventPayload,
459
1219
  ConfiguredCredentialsService,
460
1220
  ContextQueueService,
461
1221
  CredentialsService,
462
1222
  DatabaseService,
463
1223
  EmailTriggerOutput,
464
- EventLogger,
1224
+ FUNCTIONS_META_KEY,
465
1225
  FUNCTIONS_PRESET_META_KEY,
466
1226
  FUNCTION_TYPES,
467
- FunctionCallService,
1227
+ FunctionDefinition,
468
1228
  FunctionError,
469
1229
  FunctionExecutor,
1230
+ FunctionImplementationResolver,
470
1231
  FunctionManifestSchema,
1232
+ FunctionNotFoundError,
471
1233
  FunctionTrigger,
472
- FunctionTriggerSchema,
473
1234
  FunctionType,
474
1235
  InvocationOutcome,
475
1236
  InvocationTraceEndEvent,
476
1237
  InvocationTraceEventType,
477
1238
  InvocationTraceStartEvent,
1239
+ InvocationTracer,
1240
+ LocalFunctionExecutionService,
1241
+ MESSAGE_PROPERTY_TOOL_CALL_ID,
478
1242
  QueueService,
479
1243
  QueueTriggerOutput,
1244
+ RemoteFunctionExecutionService,
480
1245
  SERVICE_TAGS,
481
1246
  ScriptType,
482
1247
  ServiceContainer,
@@ -487,17 +1252,24 @@ export {
487
1252
  TraceEventException,
488
1253
  TraceEventLog,
489
1254
  TracingService,
490
- TriggerKind,
1255
+ TriggerDispatcher,
1256
+ TriggerKinds,
491
1257
  TriggerSchema,
1258
+ TriggerState,
1259
+ TriggerStateNotFoundError,
1260
+ TriggerStateStore,
492
1261
  WebhookTriggerOutput,
493
1262
  createDefectLogger,
494
1263
  createEventLogger,
495
1264
  createInvocationSpans,
496
1265
  defineFunction,
1266
+ deserializeFunction,
1267
+ examples_exports as exampleFunctions,
497
1268
  getInvocationUrl,
498
- getUserFunctionUrlInMetadata,
1269
+ getUserFunctionIdInMetadata,
499
1270
  logCustomEvent,
500
- makeFunctionUrl,
501
- setUserFunctionUrlInMetadata
1271
+ serializeFunction,
1272
+ setUserFunctionIdInMetadata,
1273
+ withAuthorization
502
1274
  };
503
1275
  //# sourceMappingURL=index.mjs.map