@dxos/functions 0.8.4-main.84f28bd → 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 (156) 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 +1007 -133
  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 +91 -41
  13. package/dist/lib/browser/testing/index.mjs.map +4 -4
  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 +1007 -133
  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 +91 -41
  26. package/dist/lib/node-esm/testing/index.mjs.map +4 -4
  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 +4 -3
  30. package/dist/types/src/edge/functions.d.ts.map +1 -1
  31. package/dist/types/src/errors.d.ts +137 -0
  32. package/dist/types/src/errors.d.ts.map +1 -0
  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 +57 -12
  44. package/dist/types/src/handler.d.ts.map +1 -1
  45. package/dist/types/src/index.d.ts +3 -0
  46. package/dist/types/src/index.d.ts.map +1 -1
  47. package/dist/types/src/schema.d.ts +5 -0
  48. package/dist/types/src/schema.d.ts.map +1 -1
  49. package/dist/types/src/services/credentials.d.ts +17 -3
  50. package/dist/types/src/services/credentials.d.ts.map +1 -1
  51. package/dist/types/src/services/database.d.ts +54 -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/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 +5 -5
  60. package/dist/types/src/services/index.d.ts.map +1 -1
  61. package/dist/types/src/services/local-function-execution.d.ts +32 -0
  62. package/dist/types/src/services/local-function-execution.d.ts.map +1 -0
  63. package/dist/types/src/services/queues.d.ts +31 -4
  64. package/dist/types/src/services/queues.d.ts.map +1 -1
  65. package/dist/types/src/services/remote-function-execution-service.d.ts +20 -0
  66. package/dist/types/src/services/remote-function-execution-service.d.ts.map +1 -0
  67. package/dist/types/src/services/service-container.d.ts +28 -18
  68. package/dist/types/src/services/service-container.d.ts.map +1 -1
  69. package/dist/types/src/services/service-registry.d.ts +29 -0
  70. package/dist/types/src/services/service-registry.d.ts.map +1 -0
  71. package/dist/types/src/services/service-registry.test.d.ts +2 -0
  72. package/dist/types/src/services/service-registry.test.d.ts.map +1 -0
  73. package/dist/types/src/services/tracing.d.ts +46 -4
  74. package/dist/types/src/services/tracing.d.ts.map +1 -1
  75. package/dist/types/src/testing/index.d.ts +1 -0
  76. package/dist/types/src/testing/index.d.ts.map +1 -1
  77. package/dist/types/src/testing/layer.d.ts +17 -0
  78. package/dist/types/src/testing/layer.d.ts.map +1 -0
  79. package/dist/types/src/testing/logger.d.ts +3 -3
  80. package/dist/types/src/testing/logger.d.ts.map +1 -1
  81. package/dist/types/src/testing/persist-database.test.d.ts +2 -0
  82. package/dist/types/src/testing/persist-database.test.d.ts.map +1 -0
  83. package/dist/types/src/testing/services.d.ts +7 -19
  84. package/dist/types/src/testing/services.d.ts.map +1 -1
  85. package/dist/types/src/trace.d.ts +20 -22
  86. package/dist/types/src/trace.d.ts.map +1 -1
  87. package/dist/types/src/triggers/index.d.ts +4 -0
  88. package/dist/types/src/triggers/index.d.ts.map +1 -0
  89. package/dist/types/src/triggers/input-builder.d.ts +3 -0
  90. package/dist/types/src/triggers/input-builder.d.ts.map +1 -0
  91. package/dist/types/src/triggers/invocation-tracer.d.ts +35 -0
  92. package/dist/types/src/triggers/invocation-tracer.d.ts.map +1 -0
  93. package/dist/types/src/triggers/trigger-dispatcher.d.ts +74 -0
  94. package/dist/types/src/triggers/trigger-dispatcher.d.ts.map +1 -0
  95. package/dist/types/src/triggers/trigger-dispatcher.test.d.ts +2 -0
  96. package/dist/types/src/triggers/trigger-dispatcher.test.d.ts.map +1 -0
  97. package/dist/types/src/triggers/trigger-state-store.d.ts +27 -0
  98. package/dist/types/src/triggers/trigger-state-store.d.ts.map +1 -0
  99. package/dist/types/src/types.d.ts +55 -245
  100. package/dist/types/src/types.d.ts.map +1 -1
  101. package/dist/types/src/url.d.ts +10 -6
  102. package/dist/types/src/url.d.ts.map +1 -1
  103. package/dist/types/tsconfig.tsbuildinfo +1 -1
  104. package/package.json +40 -33
  105. package/src/bundler/bundler.test.ts +8 -9
  106. package/src/bundler/bundler.ts +32 -33
  107. package/src/edge/functions.ts +9 -6
  108. package/src/errors.ts +21 -0
  109. package/src/examples/fib.ts +31 -0
  110. package/src/examples/index.ts +7 -0
  111. package/src/examples/reply.ts +19 -0
  112. package/src/examples/sleep.ts +23 -0
  113. package/src/executor/executor.ts +12 -9
  114. package/src/handler.ts +133 -24
  115. package/src/index.ts +3 -2
  116. package/src/schema.ts +11 -0
  117. package/src/services/credentials.ts +88 -4
  118. package/src/services/database.ts +141 -20
  119. package/src/services/event-logger.ts +68 -37
  120. package/src/services/function-invocation-service.test.ts +79 -0
  121. package/src/services/function-invocation-service.ts +82 -0
  122. package/src/services/index.ts +5 -5
  123. package/src/services/local-function-execution.ts +150 -0
  124. package/src/services/queues.ts +48 -8
  125. package/src/services/remote-function-execution-service.ts +61 -0
  126. package/src/services/service-container.ts +45 -58
  127. package/src/services/service-registry.test.ts +42 -0
  128. package/src/services/service-registry.ts +59 -0
  129. package/src/services/tracing.ts +120 -6
  130. package/src/testing/index.ts +1 -0
  131. package/src/testing/layer.ts +112 -0
  132. package/src/testing/logger.ts +4 -4
  133. package/src/testing/persist-database.test.ts +87 -0
  134. package/src/testing/services.ts +11 -70
  135. package/src/trace.ts +17 -19
  136. package/src/triggers/index.ts +7 -0
  137. package/src/triggers/input-builder.ts +35 -0
  138. package/src/triggers/invocation-tracer.ts +99 -0
  139. package/src/triggers/trigger-dispatcher.test.ts +651 -0
  140. package/src/triggers/trigger-dispatcher.ts +522 -0
  141. package/src/triggers/trigger-state-store.ts +60 -0
  142. package/src/types.ts +39 -36
  143. package/src/url.ts +13 -10
  144. package/dist/lib/browser/chunk-54U464M4.mjs +0 -360
  145. package/dist/lib/browser/chunk-54U464M4.mjs.map +0 -7
  146. package/dist/lib/node-esm/chunk-XDSX35BS.mjs +0 -362
  147. package/dist/lib/node-esm/chunk-XDSX35BS.mjs.map +0 -7
  148. package/dist/types/src/services/ai.d.ts +0 -12
  149. package/dist/types/src/services/ai.d.ts.map +0 -1
  150. package/dist/types/src/services/function-call-service.d.ts +0 -16
  151. package/dist/types/src/services/function-call-service.d.ts.map +0 -1
  152. package/dist/types/src/services/tool-resolver.d.ts +0 -14
  153. package/dist/types/src/services/tool-resolver.d.ts.map +0 -1
  154. package/src/services/ai.ts +0 -32
  155. package/src/services/function-call-service.ts +0 -64
  156. package/src/services/tool-resolver.ts +0 -31
@@ -1,48 +1,51 @@
1
1
  import {
2
- AiService,
2
+ ComputeEvent,
3
+ ComputeEventLogger,
4
+ ComputeEventPayload,
3
5
  ConfiguredCredentialsService,
6
+ ContextQueueService,
4
7
  CredentialsService,
5
8
  DatabaseService,
6
- EventLogger,
7
- FunctionCallService,
9
+ FUNCTIONS_META_KEY,
10
+ FUNCTIONS_PRESET_META_KEY,
11
+ FunctionError,
12
+ FunctionNotFoundError,
13
+ MESSAGE_PROPERTY_TOOL_CALL_ID,
8
14
  QueueService,
15
+ RemoteFunctionExecutionService,
9
16
  SERVICE_TAGS,
10
17
  ServiceContainer,
11
- ToolResolverService,
18
+ ServiceNotAvailableError,
12
19
  TracingService,
20
+ TriggerStateNotFoundError,
13
21
  createDefectLogger,
14
22
  createEventLogger,
15
- logCustomEvent
16
- } from "./chunk-54U464M4.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";
17
32
 
18
33
  // src/handler.ts
19
- import { Schema } from "effect";
20
- var defineFunction = (params) => {
21
- if (!Schema.isSchema(params.inputSchema)) {
22
- throw new Error("Input schema must be a valid schema");
23
- }
24
- if (typeof params.handler !== "function") {
25
- throw new Error("Handler must be a function");
26
- }
27
- return {
28
- description: params.description,
29
- inputSchema: params.inputSchema,
30
- outputSchema: params.outputSchema ?? Schema.Any,
31
- handler: params.handler
32
- };
33
- };
34
+ import { Effect, Schema as Schema2 } from "effect";
35
+ import { Obj, Type as Type2 } from "@dxos/echo";
36
+ import { assertArgument } from "@dxos/invariant";
34
37
 
35
38
  // src/schema.ts
36
- import { Schema as Schema2 } from "effect";
39
+ import { Schema } from "effect";
37
40
  import { Type } from "@dxos/echo";
38
41
  import { JsonSchemaType, LabelAnnotation, Ref } from "@dxos/echo-schema";
39
42
  import { DataType } from "@dxos/schema";
40
- var ScriptType = Schema2.Struct({
41
- name: Schema2.optional(Schema2.String),
42
- description: Schema2.optional(Schema2.String),
43
+ var ScriptType = Schema.Struct({
44
+ name: Schema.optional(Schema.String),
45
+ description: Schema.optional(Schema.String),
43
46
  // TODO(burdon): Change to hash of deployed content.
44
47
  // Whether source has changed since last deploy.
45
- changed: Schema2.optional(Schema2.Boolean),
48
+ changed: Schema.optional(Schema.Boolean),
46
49
  source: Ref(DataType.Text)
47
50
  }).pipe(Type.Obj({
48
51
  typename: "dxos.org/type/Script",
@@ -50,18 +53,28 @@ var ScriptType = Schema2.Struct({
50
53
  }), LabelAnnotation.set([
51
54
  "name"
52
55
  ]));
53
- 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
+ }),
54
67
  // TODO(burdon): Rename to id/uri?
55
- name: Schema2.NonEmptyString,
56
- version: Schema2.String,
57
- description: Schema2.optional(Schema2.String),
68
+ name: Schema.NonEmptyString,
69
+ version: Schema.String,
70
+ description: Schema.optional(Schema.String),
58
71
  // Reference to a source script if it exists within ECHO.
59
72
  // TODO(burdon): Don't ref ScriptType directly (core).
60
- source: Schema2.optional(Ref(ScriptType)),
61
- inputSchema: Schema2.optional(JsonSchemaType),
62
- outputSchema: Schema2.optional(JsonSchemaType),
73
+ source: Schema.optional(Ref(ScriptType)),
74
+ inputSchema: Schema.optional(JsonSchemaType),
75
+ outputSchema: Schema.optional(JsonSchemaType),
63
76
  // Local binding to a function name.
64
- binding: Schema2.optional(Schema2.String)
77
+ binding: Schema.optional(Schema.String)
65
78
  }).pipe(Type.Obj({
66
79
  typename: "dxos.org/type/Function",
67
80
  version: "0.1.0"
@@ -69,25 +82,116 @@ var FunctionType = Schema2.Struct({
69
82
  "name"
70
83
  ]));
71
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
+
72
176
  // src/trace.ts
73
177
  import { Schema as Schema4 } from "effect";
74
- import { Type as Type2 } from "@dxos/echo";
178
+ import { Type as Type4 } from "@dxos/echo";
75
179
  import { Queue } from "@dxos/echo-db";
76
180
  import { ObjectId } from "@dxos/echo-schema";
77
181
  import { log } from "@dxos/log";
78
182
 
79
183
  // src/types.ts
80
184
  import { Schema as Schema3, SchemaAST } from "effect";
81
- 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";
82
187
  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
- }({});
188
+ var TriggerKinds = [
189
+ "timer",
190
+ "webhook",
191
+ "subscription",
192
+ "email",
193
+ "queue"
194
+ ];
91
195
  var kindLiteralAnnotations = {
92
196
  title: "Kind"
93
197
  };
@@ -105,6 +209,7 @@ var EmailTriggerSchema = Schema3.Struct({
105
209
  }).pipe(Schema3.mutable);
106
210
  var QueueTriggerSchema = Schema3.Struct({
107
211
  kind: Schema3.Literal("queue").annotations(kindLiteralAnnotations),
212
+ // TODO(dmaretskyi): Change to a reference.
108
213
  queue: DXN.Schema
109
214
  }).pipe(Schema3.mutable);
110
215
  var WebhookTriggerSchema = Schema3.Struct({
@@ -120,21 +225,11 @@ var WebhookTriggerSchema = Schema3.Struct({
120
225
  title: "Port"
121
226
  }))
122
227
  }).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
228
  var SubscriptionTriggerSchema = Schema3.Struct({
135
229
  kind: Schema3.Literal("subscription").annotations(kindLiteralAnnotations),
136
- // TODO(burdon): Define query DSL (from ECHO). Reconcile with Table.Query.
137
- filter: QuerySchema,
230
+ query: QueryAST.Query.annotations({
231
+ title: "Query"
232
+ }),
138
233
  options: Schema3.optional(Schema3.Struct({
139
234
  // Watch changes to object (not just creation).
140
235
  deep: Schema3.optional(Schema3.Boolean.annotations({
@@ -172,14 +267,25 @@ var QueueTriggerOutput = Schema3.mutable(Schema3.Struct({
172
267
  item: Schema3.Any,
173
268
  cursor: Schema3.String
174
269
  }));
175
- var SubscriptionTriggerOutput = Schema3.mutable(Schema3.Struct({
270
+ var SubscriptionTriggerOutput = Schema3.Struct({
271
+ /**
272
+ * Type of the mutation.
273
+ */
274
+ // TODO(dmaretskyi): Specify enum.
176
275
  type: Schema3.String,
177
- changedObjectId: Schema3.String
178
- }));
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);
179
285
  var TimerTriggerOutput = Schema3.mutable(Schema3.Struct({
180
286
  tick: Schema3.Number
181
287
  }));
182
- var FunctionTriggerSchema = Schema3.Struct({
288
+ var FunctionTrigger_ = Schema3.Struct({
183
289
  /**
184
290
  * Function or workflow to invoke.
185
291
  */
@@ -214,12 +320,11 @@ var FunctionTriggerSchema = Schema3.Struct({
214
320
  key: Schema3.String,
215
321
  value: Schema3.Any
216
322
  })))
217
- });
218
- var FunctionTrigger = class extends TypedObject({
323
+ }).pipe(Type3.Obj({
219
324
  typename: "dxos.org/type/FunctionTrigger",
220
325
  version: "0.2.0"
221
- })(FunctionTriggerSchema.fields) {
222
- };
326
+ }));
327
+ var FunctionTrigger = FunctionTrigger_;
223
328
  var FunctionManifestSchema = Schema3.Struct({
224
329
  functions: Schema3.optional(Schema3.mutable(Schema3.Array(RawObject(FunctionType)))),
225
330
  triggers: Schema3.optional(Schema3.mutable(Schema3.Array(RawObject(FunctionTrigger))))
@@ -231,19 +336,19 @@ var FUNCTION_TYPES = [
231
336
 
232
337
  // src/trace.ts
233
338
  var __dxlog_file = "/__w/dxos/dxos/packages/core/functions/src/trace.ts";
234
- var InvocationOutcome = /* @__PURE__ */ function(InvocationOutcome2) {
339
+ var InvocationOutcome = /* @__PURE__ */ (function(InvocationOutcome2) {
235
340
  InvocationOutcome2["SUCCESS"] = "success";
236
341
  InvocationOutcome2["FAILURE"] = "failure";
237
342
  InvocationOutcome2["PENDING"] = "pending";
238
343
  return InvocationOutcome2;
239
- }({});
240
- var InvocationTraceEventType = /* @__PURE__ */ function(InvocationTraceEventType2) {
344
+ })({});
345
+ var InvocationTraceEventType = /* @__PURE__ */ (function(InvocationTraceEventType2) {
241
346
  InvocationTraceEventType2["START"] = "start";
242
347
  InvocationTraceEventType2["END"] = "end";
243
348
  return InvocationTraceEventType2;
244
- }({});
349
+ })({});
245
350
  var TraceEventException = Schema4.Struct({
246
- timestampMs: Schema4.Number,
351
+ timestamp: Schema4.Number,
247
352
  message: Schema4.String,
248
353
  name: Schema4.String,
249
354
  stack: Schema4.optional(Schema4.String)
@@ -261,7 +366,7 @@ var InvocationTraceStartEvent = Schema4.Struct({
261
366
  /**
262
367
  * Event generation time.
263
368
  */
264
- timestampMs: Schema4.Number,
369
+ timestamp: Schema4.Number,
265
370
  /**
266
371
  * Data passed to function / workflow as an argument.
267
372
  */
@@ -270,16 +375,16 @@ var InvocationTraceStartEvent = Schema4.Struct({
270
375
  /**
271
376
  * Queue for function/workflow invocation events.
272
377
  */
273
- invocationTraceQueue: Type2.Ref(Queue),
378
+ invocationTraceQueue: Schema4.optional(Type4.Ref(Queue)),
274
379
  /**
275
380
  * DXN of the invoked function/workflow.
276
381
  */
277
- invocationTarget: Type2.Ref(Type2.Expando),
382
+ invocationTarget: Schema4.optional(Type4.Ref(Type4.Expando)),
278
383
  /**
279
384
  * Present for automatic invocations.
280
385
  */
281
- trigger: Schema4.optional(Type2.Ref(FunctionTrigger))
282
- }).pipe(Type2.Obj({
386
+ trigger: Schema4.optional(Type4.Ref(FunctionTrigger))
387
+ }).pipe(Type4.Obj({
283
388
  typename: "dxos.org/type/InvocationTraceStart",
284
389
  version: "0.1.0"
285
390
  }));
@@ -297,15 +402,15 @@ var InvocationTraceEndEvent = Schema4.Struct({
297
402
  * Event generation time.
298
403
  */
299
404
  // TODO(burdon): Remove ms suffix.
300
- timestampMs: Schema4.Number,
405
+ timestamp: Schema4.Number,
301
406
  outcome: Schema4.Enums(InvocationOutcome),
302
407
  exception: Schema4.optional(TraceEventException)
303
- }).pipe(Type2.Obj({
408
+ }).pipe(Type4.Obj({
304
409
  typename: "dxos.org/type/InvocationTraceEnd",
305
410
  version: "0.1.0"
306
411
  }));
307
412
  var TraceEventLog = Schema4.Struct({
308
- timestampMs: Schema4.Number,
413
+ timestamp: Schema4.Number,
309
414
  level: Schema4.String,
310
415
  message: Schema4.String,
311
416
  context: Schema4.optional(Schema4.Object)
@@ -315,13 +420,11 @@ var TraceEvent = Schema4.Struct({
315
420
  // TODO(burdon): Need enum/numeric result (not string).
316
421
  outcome: Schema4.String,
317
422
  truncated: Schema4.Boolean,
318
- /**
319
- * Time when the event was persisted.
320
- */
321
- ingestionTimestampMs: Schema4.Number,
423
+ /** Time when the event was persisted. */
424
+ ingestionTimestamp: Schema4.Number,
322
425
  logs: Schema4.Array(TraceEventLog),
323
426
  exceptions: Schema4.Array(TraceEventException)
324
- }).pipe(Type2.Obj({
427
+ }).pipe(Type4.Obj({
325
428
  typename: "dxos.org/type/TraceEvent",
326
429
  version: "0.1.0"
327
430
  }));
@@ -354,7 +457,7 @@ var createInvocationSpans = (items) => {
354
457
  invocationId
355
458
  }, {
356
459
  F: __dxlog_file,
357
- L: 160,
460
+ L: 158,
358
461
  S: void 0,
359
462
  C: (f, a) => f(...a)
360
463
  });
@@ -363,8 +466,8 @@ var createInvocationSpans = (items) => {
363
466
  const isInProgress = end === void 0;
364
467
  result.push({
365
468
  id: invocationId,
366
- timestampMs: start.timestampMs,
367
- durationMs: isInProgress ? now - start.timestampMs : end.timestampMs - start.timestampMs,
469
+ timestamp: start.timestamp,
470
+ duration: isInProgress ? now - start.timestamp : end.timestamp - start.timestamp,
368
471
  outcome: end?.outcome ?? "pending",
369
472
  exception: end?.exception,
370
473
  input: start.input,
@@ -376,117 +479,888 @@ var createInvocationSpans = (items) => {
376
479
  return result;
377
480
  };
378
481
 
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:";
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")()) {
384
512
  };
385
- var getUserFunctionUrlInMetadata = (meta) => {
386
- return meta.keys.find((key) => key.source === FUNCTIONS_META_KEY)?.id;
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")()) {
387
607
  };
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");
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));
393
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
+ });
394
627
  } else {
395
- meta.keys.push({
396
- source: FUNCTIONS_META_KEY,
397
- id: functionUrl
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")()) {
634
+ };
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
398
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")()) {
671
+ };
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;
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;
399
754
  }
755
+ return payload;
400
756
  };
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();
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
+ });
773
+ } else {
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")()) {
410
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
820
+ });
821
+ } else {
822
+ obj[key] = value;
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")()) {
829
+ };
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
+ }
1182
+ };
1183
+ var KEY_QUEUE_CURSOR = "dxos.org/key/local-trigger-dispatcher/queue-cursor";
411
1184
 
412
1185
  // src/executor/executor.ts
413
- import { Effect, Schema as Schema5 } from "effect";
1186
+ import { Effect as Effect7, Schema as Schema7 } from "effect";
414
1187
  import { runAndForwardErrors } from "@dxos/effect";
415
- var FunctionExecutor = class {
416
- constructor(_services) {
417
- 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;
418
1198
  }
1199
+ return obj;
1200
+ }
1201
+ var FunctionExecutor = class {
1202
+ /**
1203
+ * Invoke function.
1204
+ */
419
1205
  // TODO(dmaretskyi): Invocation context: queue, space, etc...
420
- async invoke(fnDef, input) {
421
- const assertInput = fnDef.inputSchema.pipe(Schema5.asserts);
1206
+ async invoke(functionDef, input) {
1207
+ const assertInput = functionDef.inputSchema.pipe(Schema7.asserts);
422
1208
  assertInput(input);
423
1209
  const context = {
1210
+ space: void 0,
424
1211
  getService: this._services.getService.bind(this._services),
425
1212
  getSpace: async (_spaceId) => {
426
1213
  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
1214
  }
432
1215
  };
433
- const result = fnDef.handler({
1216
+ const result = functionDef.handler({
434
1217
  context,
435
1218
  data: input
436
1219
  });
437
1220
  let data;
438
- if (Effect.isEffect(result)) {
439
- 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);
440
1223
  } else {
441
1224
  data = await result;
442
1225
  }
443
- const assertOutput = fnDef.outputSchema?.pipe(Schema5.asserts);
1226
+ const assertOutput = functionDef.outputSchema?.pipe(Schema7.asserts);
444
1227
  assertOutput(data);
445
1228
  return data;
446
1229
  }
1230
+ constructor(_services) {
1231
+ _define_property6(this, "_services", void 0);
1232
+ this._services = _services;
1233
+ }
447
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
+ });
448
1305
  export {
449
- AiService,
1306
+ ComputeEvent,
1307
+ ComputeEventLogger,
1308
+ ComputeEventPayload,
450
1309
  ConfiguredCredentialsService,
1310
+ ContextQueueService,
451
1311
  CredentialsService,
452
1312
  DatabaseService,
453
1313
  EmailTriggerOutput,
454
- EventLogger,
1314
+ FUNCTIONS_META_KEY,
455
1315
  FUNCTIONS_PRESET_META_KEY,
456
1316
  FUNCTION_TYPES,
457
- FunctionCallService,
1317
+ FunctionDefinition,
1318
+ FunctionError,
458
1319
  FunctionExecutor,
1320
+ FunctionImplementationResolver,
1321
+ FunctionInvocationService,
459
1322
  FunctionManifestSchema,
1323
+ FunctionNotFoundError,
460
1324
  FunctionTrigger,
461
- FunctionTriggerSchema,
462
1325
  FunctionType,
463
1326
  InvocationOutcome,
464
1327
  InvocationTraceEndEvent,
465
1328
  InvocationTraceEventType,
466
1329
  InvocationTraceStartEvent,
1330
+ InvocationTracer,
1331
+ LocalFunctionExecutionService,
1332
+ MESSAGE_PROPERTY_TOOL_CALL_ID,
467
1333
  QueueService,
468
1334
  QueueTriggerOutput,
1335
+ RemoteFunctionExecutionService,
469
1336
  SERVICE_TAGS,
470
1337
  ScriptType,
471
1338
  ServiceContainer,
1339
+ ServiceNotAvailableError,
472
1340
  SubscriptionTriggerOutput,
473
1341
  TimerTriggerOutput,
474
- ToolResolverService,
475
1342
  TraceEvent,
476
1343
  TraceEventException,
477
1344
  TraceEventLog,
478
1345
  TracingService,
479
- TriggerKind,
1346
+ TriggerDispatcher,
1347
+ TriggerKinds,
480
1348
  TriggerSchema,
1349
+ TriggerState,
1350
+ TriggerStateNotFoundError,
1351
+ TriggerStateStore,
481
1352
  WebhookTriggerOutput,
482
1353
  createDefectLogger,
483
1354
  createEventLogger,
484
1355
  createInvocationSpans,
485
1356
  defineFunction,
1357
+ deserializeFunction,
1358
+ examples_exports as exampleFunctions,
486
1359
  getInvocationUrl,
487
- getUserFunctionUrlInMetadata,
1360
+ getUserFunctionIdInMetadata,
488
1361
  logCustomEvent,
489
- makeFunctionUrl,
490
- setUserFunctionUrlInMetadata
1362
+ serializeFunction,
1363
+ setUserFunctionIdInMetadata,
1364
+ withAuthorization
491
1365
  };
492
1366
  //# sourceMappingURL=index.mjs.map