@dxos/functions 0.8.3 → 0.8.4-main.1da679c

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