@dxos/functions 0.8.4-main.67995b8 → 0.8.4-main.a4bbb77

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