@dxos/functions 0.8.4-main.5ad4a44 → 0.8.4-main.66e292d

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 (191) hide show
  1. package/dist/lib/browser/index.mjs +830 -1195
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node-esm/index.mjs +830 -1195
  5. package/dist/lib/node-esm/index.mjs.map +4 -4
  6. package/dist/lib/node-esm/meta.json +1 -1
  7. package/dist/types/src/errors.d.ts +28 -36
  8. package/dist/types/src/errors.d.ts.map +1 -1
  9. package/dist/types/src/{examples → example}/fib.d.ts +1 -1
  10. package/dist/types/src/example/fib.d.ts.map +1 -0
  11. package/dist/types/src/example/forex-effect.d.ts +3 -0
  12. package/dist/types/src/example/forex-effect.d.ts.map +1 -0
  13. package/dist/types/src/example/index.d.ts +12 -0
  14. package/dist/types/src/example/index.d.ts.map +1 -0
  15. package/dist/types/src/{examples → example}/reply.d.ts +1 -1
  16. package/dist/types/src/example/reply.d.ts.map +1 -0
  17. package/dist/types/src/{examples → example}/sleep.d.ts +1 -1
  18. package/dist/types/src/example/sleep.d.ts.map +1 -0
  19. package/dist/types/src/index.d.ts +4 -8
  20. package/dist/types/src/index.d.ts.map +1 -1
  21. package/dist/types/src/protocol/index.d.ts +2 -0
  22. package/dist/types/src/protocol/index.d.ts.map +1 -0
  23. package/dist/types/src/protocol/protocol.d.ts +7 -0
  24. package/dist/types/src/protocol/protocol.d.ts.map +1 -0
  25. package/dist/types/src/protocol/protocol.test.d.ts +2 -0
  26. package/dist/types/src/protocol/protocol.test.d.ts.map +1 -0
  27. package/dist/types/src/sdk.d.ts +100 -0
  28. package/dist/types/src/sdk.d.ts.map +1 -0
  29. package/dist/types/src/services/credentials.d.ts +1 -1
  30. package/dist/types/src/services/credentials.d.ts.map +1 -1
  31. package/dist/types/src/services/event-logger.d.ts +16 -4
  32. package/dist/types/src/services/event-logger.d.ts.map +1 -1
  33. package/dist/types/src/services/function-invocation-service.d.ts +3 -20
  34. package/dist/types/src/services/function-invocation-service.d.ts.map +1 -1
  35. package/dist/types/src/services/index.d.ts +3 -4
  36. package/dist/types/src/services/index.d.ts.map +1 -1
  37. package/dist/types/src/services/queues.d.ts +4 -4
  38. package/dist/types/src/services/queues.d.ts.map +1 -1
  39. package/dist/types/src/services/tracing.d.ts +5 -10
  40. package/dist/types/src/services/tracing.d.ts.map +1 -1
  41. package/dist/types/src/types/Function.d.ts +63 -0
  42. package/dist/types/src/types/Function.d.ts.map +1 -0
  43. package/dist/types/src/types/Script.d.ts +28 -0
  44. package/dist/types/src/types/Script.d.ts.map +1 -0
  45. package/dist/types/src/types/Trigger.d.ts +141 -0
  46. package/dist/types/src/types/Trigger.d.ts.map +1 -0
  47. package/dist/types/src/types/TriggerEvent.d.ts +43 -0
  48. package/dist/types/src/types/TriggerEvent.d.ts.map +1 -0
  49. package/dist/types/src/types/index.d.ts +6 -0
  50. package/dist/types/src/types/index.d.ts.map +1 -0
  51. package/dist/types/src/{url.d.ts → types/url.d.ts} +0 -9
  52. package/dist/types/src/types/url.d.ts.map +1 -0
  53. package/dist/types/tsconfig.tsbuildinfo +1 -1
  54. package/package.json +15 -59
  55. package/src/{examples → example}/fib.ts +1 -1
  56. package/src/example/forex-effect.ts +40 -0
  57. package/src/example/index.ts +13 -0
  58. package/src/{examples → example}/reply.ts +1 -1
  59. package/src/{examples → example}/sleep.ts +1 -1
  60. package/src/index.ts +4 -8
  61. package/src/{executor → protocol}/index.ts +1 -1
  62. package/src/protocol/protocol.test.ts +59 -0
  63. package/src/protocol/protocol.ts +156 -0
  64. package/src/{handler.ts → sdk.ts} +96 -81
  65. package/src/services/credentials.ts +3 -4
  66. package/src/services/event-logger.ts +8 -2
  67. package/src/services/function-invocation-service.ts +10 -71
  68. package/src/services/index.ts +4 -4
  69. package/src/services/queues.ts +5 -7
  70. package/src/services/tracing.ts +8 -43
  71. package/src/types/Function.ts +80 -0
  72. package/src/types/Script.ts +33 -0
  73. package/src/types/Trigger.ts +140 -0
  74. package/src/types/TriggerEvent.ts +62 -0
  75. package/src/types/index.ts +9 -0
  76. package/src/{url.ts → types/url.ts} +0 -24
  77. package/dist/lib/browser/bundler/index.mjs +0 -269
  78. package/dist/lib/browser/bundler/index.mjs.map +0 -7
  79. package/dist/lib/browser/chunk-J5LGTIGS.mjs +0 -10
  80. package/dist/lib/browser/chunk-J5LGTIGS.mjs.map +0 -7
  81. package/dist/lib/browser/chunk-LKYT2SAL.mjs +0 -665
  82. package/dist/lib/browser/chunk-LKYT2SAL.mjs.map +0 -7
  83. package/dist/lib/browser/edge/index.mjs +0 -83
  84. package/dist/lib/browser/edge/index.mjs.map +0 -7
  85. package/dist/lib/browser/testing/index.mjs +0 -131
  86. package/dist/lib/browser/testing/index.mjs.map +0 -7
  87. package/dist/lib/node-esm/bundler/index.mjs +0 -270
  88. package/dist/lib/node-esm/bundler/index.mjs.map +0 -7
  89. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +0 -11
  90. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs.map +0 -7
  91. package/dist/lib/node-esm/chunk-NAQIKLZB.mjs +0 -667
  92. package/dist/lib/node-esm/chunk-NAQIKLZB.mjs.map +0 -7
  93. package/dist/lib/node-esm/edge/index.mjs +0 -84
  94. package/dist/lib/node-esm/edge/index.mjs.map +0 -7
  95. package/dist/lib/node-esm/testing/index.mjs +0 -132
  96. package/dist/lib/node-esm/testing/index.mjs.map +0 -7
  97. package/dist/types/src/bundler/bundler.d.ts +0 -49
  98. package/dist/types/src/bundler/bundler.d.ts.map +0 -1
  99. package/dist/types/src/bundler/bundler.test.d.ts +0 -2
  100. package/dist/types/src/bundler/bundler.test.d.ts.map +0 -1
  101. package/dist/types/src/bundler/index.d.ts +0 -2
  102. package/dist/types/src/bundler/index.d.ts.map +0 -1
  103. package/dist/types/src/edge/functions.d.ts +0 -17
  104. package/dist/types/src/edge/functions.d.ts.map +0 -1
  105. package/dist/types/src/edge/index.d.ts +0 -2
  106. package/dist/types/src/edge/index.d.ts.map +0 -1
  107. package/dist/types/src/examples/fib.d.ts.map +0 -1
  108. package/dist/types/src/examples/index.d.ts +0 -4
  109. package/dist/types/src/examples/index.d.ts.map +0 -1
  110. package/dist/types/src/examples/reply.d.ts.map +0 -1
  111. package/dist/types/src/examples/sleep.d.ts.map +0 -1
  112. package/dist/types/src/executor/executor.d.ts +0 -14
  113. package/dist/types/src/executor/executor.d.ts.map +0 -1
  114. package/dist/types/src/executor/index.d.ts +0 -2
  115. package/dist/types/src/executor/index.d.ts.map +0 -1
  116. package/dist/types/src/handler.d.ts +0 -109
  117. package/dist/types/src/handler.d.ts.map +0 -1
  118. package/dist/types/src/schema.d.ts +0 -43
  119. package/dist/types/src/schema.d.ts.map +0 -1
  120. package/dist/types/src/services/database.d.ts +0 -67
  121. package/dist/types/src/services/database.d.ts.map +0 -1
  122. package/dist/types/src/services/function-invocation-service.test.d.ts +0 -2
  123. package/dist/types/src/services/function-invocation-service.test.d.ts.map +0 -1
  124. package/dist/types/src/services/local-function-execution.d.ts +0 -34
  125. package/dist/types/src/services/local-function-execution.d.ts.map +0 -1
  126. package/dist/types/src/services/remote-function-execution-service.d.ts +0 -22
  127. package/dist/types/src/services/remote-function-execution-service.d.ts.map +0 -1
  128. package/dist/types/src/services/service-container.d.ts +0 -57
  129. package/dist/types/src/services/service-container.d.ts.map +0 -1
  130. package/dist/types/src/services/service-registry.d.ts +0 -31
  131. package/dist/types/src/services/service-registry.d.ts.map +0 -1
  132. package/dist/types/src/services/service-registry.test.d.ts +0 -2
  133. package/dist/types/src/services/service-registry.test.d.ts.map +0 -1
  134. package/dist/types/src/testing/index.d.ts +0 -3
  135. package/dist/types/src/testing/index.d.ts.map +0 -1
  136. package/dist/types/src/testing/layer.d.ts +0 -18
  137. package/dist/types/src/testing/layer.d.ts.map +0 -1
  138. package/dist/types/src/testing/logger.d.ts +0 -5
  139. package/dist/types/src/testing/logger.d.ts.map +0 -1
  140. package/dist/types/src/testing/persist-database.test.d.ts +0 -2
  141. package/dist/types/src/testing/persist-database.test.d.ts.map +0 -1
  142. package/dist/types/src/testing/services.d.ts +0 -59
  143. package/dist/types/src/testing/services.d.ts.map +0 -1
  144. package/dist/types/src/trace.d.ts +0 -122
  145. package/dist/types/src/trace.d.ts.map +0 -1
  146. package/dist/types/src/translations.d.ts +0 -12
  147. package/dist/types/src/translations.d.ts.map +0 -1
  148. package/dist/types/src/triggers/index.d.ts +0 -4
  149. package/dist/types/src/triggers/index.d.ts.map +0 -1
  150. package/dist/types/src/triggers/input-builder.d.ts +0 -3
  151. package/dist/types/src/triggers/input-builder.d.ts.map +0 -1
  152. package/dist/types/src/triggers/invocation-tracer.d.ts +0 -37
  153. package/dist/types/src/triggers/invocation-tracer.d.ts.map +0 -1
  154. package/dist/types/src/triggers/trigger-dispatcher.d.ts +0 -78
  155. package/dist/types/src/triggers/trigger-dispatcher.d.ts.map +0 -1
  156. package/dist/types/src/triggers/trigger-dispatcher.test.d.ts +0 -2
  157. package/dist/types/src/triggers/trigger-dispatcher.test.d.ts.map +0 -1
  158. package/dist/types/src/triggers/trigger-state-store.d.ts +0 -28
  159. package/dist/types/src/triggers/trigger-state-store.d.ts.map +0 -1
  160. package/dist/types/src/types.d.ts +0 -230
  161. package/dist/types/src/types.d.ts.map +0 -1
  162. package/dist/types/src/url.d.ts.map +0 -1
  163. package/src/bundler/bundler.test.ts +0 -58
  164. package/src/bundler/bundler.ts +0 -295
  165. package/src/bundler/index.ts +0 -5
  166. package/src/edge/functions.ts +0 -67
  167. package/src/edge/index.ts +0 -9
  168. package/src/examples/index.ts +0 -7
  169. package/src/executor/executor.ts +0 -58
  170. package/src/schema.ts +0 -71
  171. package/src/services/database.ts +0 -175
  172. package/src/services/function-invocation-service.test.ts +0 -81
  173. package/src/services/local-function-execution.ts +0 -153
  174. package/src/services/remote-function-execution-service.ts +0 -63
  175. package/src/services/service-container.ts +0 -115
  176. package/src/services/service-registry.test.ts +0 -45
  177. package/src/services/service-registry.ts +0 -63
  178. package/src/testing/index.ts +0 -6
  179. package/src/testing/layer.ts +0 -114
  180. package/src/testing/logger.ts +0 -17
  181. package/src/testing/persist-database.test.ts +0 -87
  182. package/src/testing/services.ts +0 -115
  183. package/src/trace.ts +0 -178
  184. package/src/translations.ts +0 -20
  185. package/src/triggers/index.ts +0 -7
  186. package/src/triggers/input-builder.ts +0 -35
  187. package/src/triggers/invocation-tracer.ts +0 -101
  188. package/src/triggers/trigger-dispatcher.test.ts +0 -665
  189. package/src/triggers/trigger-dispatcher.ts +0 -533
  190. package/src/triggers/trigger-state-store.ts +0 -61
  191. package/src/types.ts +0 -218
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dxos/functions",
3
- "version": "0.8.4-main.5ad4a44",
4
- "description": "Functions API and runtime.",
3
+ "version": "0.8.4-main.66e292d",
4
+ "description": "Functions API.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
7
7
  "license": "MIT",
@@ -14,37 +14,9 @@
14
14
  "types": "./dist/types/src/index.d.ts",
15
15
  "browser": "./dist/lib/browser/index.mjs",
16
16
  "node": "./dist/lib/node-esm/index.mjs"
17
- },
18
- "./bundler": {
19
- "source": "./src/bundler/index.ts",
20
- "types": "./dist/types/src/bundler/index.d.ts",
21
- "browser": "./dist/lib/browser/bundler/index.mjs",
22
- "node": "./dist/lib/node-esm/bundler/index.mjs"
23
- },
24
- "./edge": {
25
- "source": "./src/edge/index.ts",
26
- "types": "./dist/types/src/edge/index.d.ts",
27
- "browser": "./dist/lib/browser/edge/index.mjs",
28
- "node": "./dist/lib/node-esm/edge/index.mjs"
29
- },
30
- "./testing": {
31
- "source": "./src/testing/index.ts",
32
- "types": "./dist/types/src/testing/index.d.ts",
33
- "browser": "./dist/lib/browser/testing/index.mjs",
34
- "node": "./dist/lib/node-esm/testing/index.mjs"
35
17
  }
36
18
  },
37
19
  "types": "dist/types/src/index.d.ts",
38
- "typesVersions": {
39
- "*": {
40
- "bundler": [
41
- "dist/types/src/bundler/index.d.ts"
42
- ],
43
- "edge": [
44
- "dist/types/src/edge/index.d.ts"
45
- ]
46
- }
47
- },
48
20
  "files": [
49
21
  "dist",
50
22
  "schema",
@@ -53,35 +25,19 @@
53
25
  "dependencies": {
54
26
  "@effect/platform": "0.92.1",
55
27
  "effect": "3.18.3",
56
- "esbuild-wasm": "^0.16.14",
57
- "i18next": "^24.2.1",
58
- "iso-did": "^1.6.0",
59
- "@dxos/ai": "0.8.4-main.5ad4a44",
60
- "@dxos/async": "0.8.4-main.5ad4a44",
61
- "@dxos/client": "0.8.4-main.5ad4a44",
62
- "@dxos/client-protocol": "0.8.4-main.5ad4a44",
63
- "@dxos/context": "0.8.4-main.5ad4a44",
64
- "@dxos/crypto": "0.8.4-main.5ad4a44",
65
- "@dxos/debug": "0.8.4-main.5ad4a44",
66
- "@dxos/echo": "0.8.4-main.5ad4a44",
67
- "@dxos/echo-db": "0.8.4-main.5ad4a44",
68
- "@dxos/echo-protocol": "0.8.4-main.5ad4a44",
69
- "@dxos/echo-pipeline": "0.8.4-main.5ad4a44",
70
- "@dxos/edge-client": "0.8.4-main.5ad4a44",
71
- "@dxos/effect": "0.8.4-main.5ad4a44",
72
- "@dxos/errors": "0.8.4-main.5ad4a44",
73
- "@dxos/invariant": "0.8.4-main.5ad4a44",
74
- "@dxos/keys": "0.8.4-main.5ad4a44",
75
- "@dxos/kv-store": "0.8.4-main.5ad4a44",
76
- "@dxos/live-object": "0.8.4-main.5ad4a44",
77
- "@dxos/log": "0.8.4-main.5ad4a44",
78
- "@dxos/node-std": "0.8.4-main.5ad4a44",
79
- "@dxos/protocols": "0.8.4-main.5ad4a44",
80
- "@dxos/util": "0.8.4-main.5ad4a44",
81
- "@dxos/schema": "0.8.4-main.5ad4a44"
82
- },
83
- "devDependencies": {
84
- "@dxos/agent": "0.8.4-main.5ad4a44"
28
+ "@dxos/ai": "0.8.4-main.66e292d",
29
+ "@dxos/context": "0.8.4-main.66e292d",
30
+ "@dxos/echo-db": "0.8.4-main.66e292d",
31
+ "@dxos/effect": "0.8.4-main.66e292d",
32
+ "@dxos/echo": "0.8.4-main.66e292d",
33
+ "@dxos/errors": "0.8.4-main.66e292d",
34
+ "@dxos/invariant": "0.8.4-main.66e292d",
35
+ "@dxos/log": "0.8.4-main.66e292d",
36
+ "@dxos/node-std": "0.8.4-main.66e292d",
37
+ "@dxos/protocols": "0.8.4-main.66e292d",
38
+ "@dxos/keys": "0.8.4-main.66e292d",
39
+ "@dxos/types": "0.8.4-main.66e292d",
40
+ "@dxos/schema": "0.8.4-main.66e292d"
85
41
  },
86
42
  "publishConfig": {
87
43
  "access": "public"
@@ -5,7 +5,7 @@
5
5
  import * as Effect from 'effect/Effect';
6
6
  import * as Schema from 'effect/Schema';
7
7
 
8
- import { defineFunction } from '../handler';
8
+ import { defineFunction } from '../sdk';
9
9
 
10
10
  export default defineFunction({
11
11
  key: 'example.org/function/fib',
@@ -0,0 +1,40 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ // @ts-ignore
6
+ import { S, defineFunction } from 'dxos:functions';
7
+ import {
8
+ FetchHttpClient,
9
+ HttpClient,
10
+ HttpClientRequest,
11
+ // @ts-ignore
12
+ } from 'https://esm.sh/@effect/platform@0.89.0?deps=effect@3.17.0&bundle=false';
13
+ // @ts-ignore
14
+ import { Effect, Schedule } from 'https://esm.sh/effect@3.17.0?bundle=false';
15
+
16
+ export default defineFunction({
17
+ key: 'dxos.org/script/forex-effect',
18
+ name: 'Forex Effect',
19
+ description: 'Returns the exchange rate between two currencies.',
20
+
21
+ inputSchema: S.Struct({
22
+ from: S.String.annotations({ description: 'The source currency' }),
23
+ to: S.String.annotations({ description: 'The target currency' }),
24
+ }),
25
+
26
+ outputSchema: S.String.annotations({ description: 'The exchange rate between the two currencies' }),
27
+
28
+ handler: async ({ data: { from, to } }: any) =>
29
+ Effect.gen(function* () {
30
+ const res = yield* HttpClientRequest.get(`https://free.ratesdb.com/v1/rates?from=${from}&to=${to}`).pipe(
31
+ HttpClient.execute,
32
+ Effect.flatMap((res: any) => res.json),
33
+ Effect.timeout('1 second'),
34
+ Effect.retry(Schedule.exponential(1_000).pipe(Schedule.compose(Schedule.recurs(3)))),
35
+ Effect.scoped,
36
+ );
37
+
38
+ return res.data.rates[to].toString();
39
+ }).pipe(Effect.provide(FetchHttpClient.layer)),
40
+ });
@@ -0,0 +1,13 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { default as fib$ } from './fib';
6
+ import { default as reply$ } from './reply';
7
+ import { default as sleep$ } from './sleep';
8
+
9
+ export namespace Example {
10
+ export const fib = fib$;
11
+ export const reply = reply$;
12
+ export const sleep = sleep$;
13
+ }
@@ -6,7 +6,7 @@ import * as Console from 'effect/Console';
6
6
  import * as Effect from 'effect/Effect';
7
7
  import * as Schema from 'effect/Schema';
8
8
 
9
- import { defineFunction } from '../handler';
9
+ import { defineFunction } from '../sdk';
10
10
 
11
11
  export default defineFunction({
12
12
  key: 'example.org/function/reply',
@@ -5,7 +5,7 @@
5
5
  import * as Effect from 'effect/Effect';
6
6
  import * as Schema from 'effect/Schema';
7
7
 
8
- import { defineFunction } from '../handler';
8
+ import { defineFunction } from '../sdk';
9
9
 
10
10
  export default defineFunction({
11
11
  key: 'example.org/function/sleep',
package/src/index.ts CHANGED
@@ -3,12 +3,8 @@
3
3
  //
4
4
 
5
5
  export * from './errors';
6
- export * from './handler';
7
- export * from './schema';
8
- export * from './trace';
9
- export * from './types';
10
- export * from './url';
11
- export * from './triggers';
6
+ export * from './example';
7
+ export * from './sdk';
12
8
  export * from './services';
13
- export * from './executor';
14
- export * as exampleFunctions from './examples';
9
+ export * from './types';
10
+ export * from './protocol';
@@ -2,4 +2,4 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- export * from './executor';
5
+ export * from './protocol';
@@ -0,0 +1,59 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { describe, test } from 'vitest';
6
+
7
+ import { FunctionError } from '../errors';
8
+ import fibFunc from '../example/fib';
9
+ import replyFunc from '../example/reply';
10
+
11
+ import { wrapFunctionHandler } from './protocol';
12
+
13
+ describe('wrapFunctionHandler', () => {
14
+ test('wraps reply function and executes handler', async ({ expect }) => {
15
+ const wrapped = wrapFunctionHandler(replyFunc);
16
+
17
+ expect(wrapped.meta.key).toBe('example.org/function/reply');
18
+ expect(wrapped.meta.name).toBe('Reply');
19
+
20
+ const testData = { message: 'hello' };
21
+ const result = await wrapped.handler({
22
+ data: testData,
23
+ context: {
24
+ services: {},
25
+ },
26
+ });
27
+
28
+ expect(result).toEqual(testData);
29
+ });
30
+
31
+ test('wraps fibonacci function with valid input', async ({ expect }) => {
32
+ const wrapped = wrapFunctionHandler(fibFunc);
33
+
34
+ expect(wrapped.meta.key).toBe('example.org/function/fib');
35
+ expect(wrapped.meta.name).toBe('Fibonacci');
36
+
37
+ const result = await wrapped.handler({
38
+ data: { iterations: 10 },
39
+ context: {
40
+ services: {},
41
+ },
42
+ });
43
+
44
+ expect(result).toEqual({ result: '55' });
45
+ });
46
+
47
+ test('throws FunctionError on invalid input schema for fibonacci', async ({ expect }) => {
48
+ const wrapped = wrapFunctionHandler(fibFunc);
49
+
50
+ await expect(
51
+ wrapped.handler({
52
+ data: { iterations: 'invalid' },
53
+ context: {
54
+ services: {},
55
+ },
56
+ }),
57
+ ).rejects.toThrow(FunctionError);
58
+ });
59
+ });
@@ -0,0 +1,156 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import * as Effect from 'effect/Effect';
6
+ import * as Layer from 'effect/Layer';
7
+ import * as Schema from 'effect/Schema';
8
+ import * as SchemaAST from 'effect/SchemaAST';
9
+
10
+ import { AiService } from '@dxos/ai';
11
+ import { LifecycleState, Resource } from '@dxos/context';
12
+ import { Type } from '@dxos/echo';
13
+ import { EchoClient, type EchoDatabaseImpl, type QueueFactory } from '@dxos/echo-db';
14
+ import { assertState, failedInvariant, invariant } from '@dxos/invariant';
15
+ import { PublicKey } from '@dxos/keys';
16
+ import { type FunctionProtocol } from '@dxos/protocols';
17
+
18
+ import { FunctionError } from '../errors';
19
+ import { FunctionDefinition, type FunctionServices } from '../sdk';
20
+ import { CredentialsService, DatabaseService, FunctionInvocationService, TracingService } from '../services';
21
+ import { QueueService } from '../services';
22
+
23
+ /**
24
+ * Wraps a function handler made with `defineFunction` to a protocol that the functions-runtime expects.
25
+ */
26
+ export const wrapFunctionHandler = (func: FunctionDefinition): FunctionProtocol.Func => {
27
+ if (!FunctionDefinition.isFunction(func)) {
28
+ throw new TypeError('Invalid function definition');
29
+ }
30
+
31
+ return {
32
+ meta: {
33
+ key: func.key,
34
+ name: func.name,
35
+ description: func.description,
36
+ inputSchema: Type.toJsonSchema(func.inputSchema),
37
+ outputSchema: func.outputSchema === undefined ? undefined : Type.toJsonSchema(func.outputSchema),
38
+ services: func.services,
39
+ },
40
+ handler: async ({ data, context }) => {
41
+ if (
42
+ (func.services.includes(DatabaseService.key) || func.services.includes(QueueService.key)) &&
43
+ (!context.services.dataService || !context.services.queryService)
44
+ ) {
45
+ throw new FunctionError({
46
+ message: 'Services not provided: dataService, queryService',
47
+ });
48
+ }
49
+
50
+ // eslint-disable-next-line no-useless-catch
51
+ try {
52
+ if (!SchemaAST.isAnyKeyword(func.inputSchema.ast)) {
53
+ try {
54
+ Schema.validateSync(func.inputSchema)(data);
55
+ } catch (error) {
56
+ throw new FunctionError({ message: 'Invalid input schema', cause: error });
57
+ }
58
+ }
59
+
60
+ await using funcContext = await new FunctionContext(context).open();
61
+
62
+ if (func.types.length > 0) {
63
+ invariant(funcContext.db, 'Database is required for functions with types');
64
+ funcContext.db.graph.schemaRegistry.addSchema(func.types);
65
+ }
66
+
67
+ let result = await func.handler({
68
+ // TODO(dmaretskyi): Fix the types.
69
+ context: context as any,
70
+ data,
71
+ });
72
+
73
+ if (Effect.isEffect(result)) {
74
+ result = await Effect.runPromise(
75
+ (result as Effect.Effect<unknown, unknown, FunctionServices>).pipe(
76
+ Effect.orDie,
77
+ Effect.provide(funcContext.createLayer()),
78
+ ),
79
+ );
80
+ }
81
+
82
+ if (func.outputSchema && !SchemaAST.isAnyKeyword(func.outputSchema.ast)) {
83
+ Schema.validateSync(func.outputSchema)(result);
84
+ }
85
+
86
+ return result;
87
+ } catch (error) {
88
+ // TODO(dmaretskyi): We might do error wrapping here and add extra context.
89
+ throw error;
90
+ }
91
+ },
92
+ };
93
+ };
94
+
95
+ /**
96
+ * Container for services and context for a function.
97
+ */
98
+ class FunctionContext extends Resource {
99
+ readonly context: FunctionProtocol.Context;
100
+ readonly client: EchoClient | undefined;
101
+ db: EchoDatabaseImpl | undefined;
102
+ queues: QueueFactory | undefined;
103
+
104
+ constructor(context: FunctionProtocol.Context) {
105
+ super();
106
+ this.context = context;
107
+ if (context.services.dataService && context.services.queryService) {
108
+ this.client = new EchoClient().connectToService({
109
+ dataService: context.services.dataService,
110
+ queryService: context.services.queryService,
111
+ queueService: context.services.queueService,
112
+ });
113
+ }
114
+ }
115
+
116
+ override async _open() {
117
+ await this.client?.open();
118
+ this.db =
119
+ this.client && this.context.spaceId
120
+ ? this.client.constructDatabase({
121
+ spaceId: this.context.spaceId ?? failedInvariant(),
122
+ spaceKey: PublicKey.fromHex(this.context.spaceKey ?? failedInvariant('spaceKey missing in context')),
123
+ reactiveSchemaQuery: false,
124
+ })
125
+ : undefined;
126
+
127
+ await this.db?.setSpaceRoot(this.context.spaceRootUrl ?? failedInvariant('spaceRootUrl missing in context'));
128
+ await this.db?.open();
129
+ this.queues =
130
+ this.client && this.context.spaceId ? this.client.constructQueueFactory(this.context.spaceId) : undefined;
131
+ }
132
+
133
+ override async _close() {
134
+ await this.db?.close();
135
+ await this.client?.close();
136
+ }
137
+
138
+ createLayer(): Layer.Layer<FunctionServices> {
139
+ assertState(this._lifecycleState === LifecycleState.OPEN, 'FunctionContext is not open');
140
+
141
+ const dbLayer = this.db ? DatabaseService.layer(this.db) : DatabaseService.notAvailable;
142
+ const queuesLayer = this.queues ? QueueService.layer(this.queues) : QueueService.notAvailable;
143
+ const credentials = dbLayer
144
+ ? CredentialsService.layerFromDatabase().pipe(Layer.provide(dbLayer))
145
+ : CredentialsService.configuredLayer([]);
146
+ const functionInvocationService = MockedFunctionInvocationService;
147
+ const aiService = AiService.notAvailable;
148
+ const tracing = TracingService.layerNoop;
149
+
150
+ return Layer.mergeAll(dbLayer, queuesLayer, credentials, functionInvocationService, aiService, tracing);
151
+ }
152
+ }
153
+
154
+ const MockedFunctionInvocationService = Layer.succeed(FunctionInvocationService, {
155
+ invokeFunction: () => Effect.die('Calling functions from functions is not implemented yet.'),
156
+ });