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