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