@dxos/functions 0.8.4-main.9be5663bfe → 0.8.4-main.abd8ff62ef

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 (96) hide show
  1. package/dist/lib/neutral/index.mjs +126 -917
  2. package/dist/lib/neutral/index.mjs.map +4 -4
  3. package/dist/lib/neutral/meta.json +1 -1
  4. package/dist/types/src/index.d.ts +0 -6
  5. package/dist/types/src/index.d.ts.map +1 -1
  6. package/dist/types/src/protocol/functions-ai-http-client.d.ts.map +1 -1
  7. package/dist/types/src/protocol/protocol.d.ts +1 -1
  8. package/dist/types/src/protocol/protocol.d.ts.map +1 -1
  9. package/dist/types/src/sdk.d.ts +3 -7
  10. package/dist/types/src/sdk.d.ts.map +1 -1
  11. package/dist/types/src/services/credentials.d.ts +15 -38
  12. package/dist/types/src/services/credentials.d.ts.map +1 -1
  13. package/dist/types/src/services/function-invocation-service.d.ts +3 -5
  14. package/dist/types/src/services/function-invocation-service.d.ts.map +1 -1
  15. package/dist/types/src/services/index.d.ts +1 -4
  16. package/dist/types/src/services/index.d.ts.map +1 -1
  17. package/dist/types/src/services/queues.d.ts +1 -49
  18. package/dist/types/src/services/queues.d.ts.map +1 -1
  19. package/dist/types/src/services/tracing.d.ts +1 -107
  20. package/dist/types/src/services/tracing.d.ts.map +1 -1
  21. package/dist/types/src/types/index.d.ts +0 -3
  22. package/dist/types/src/types/index.d.ts.map +1 -1
  23. package/dist/types/src/types/url.d.ts +1 -1
  24. package/dist/types/src/types/url.d.ts.map +1 -1
  25. package/dist/types/tsconfig.tsbuildinfo +1 -1
  26. package/package.json +15 -20
  27. package/src/index.ts +0 -6
  28. package/src/protocol/protocol.test.ts +10 -10
  29. package/src/protocol/protocol.ts +37 -12
  30. package/src/sdk.ts +5 -15
  31. package/src/services/credentials.ts +75 -118
  32. package/src/services/function-invocation-service.ts +3 -9
  33. package/src/services/index.ts +1 -4
  34. package/src/services/queues.ts +1 -87
  35. package/src/services/tracing.ts +0 -192
  36. package/src/types/index.ts +0 -3
  37. package/src/types/url.ts +1 -1
  38. package/dist/lib/neutral/Trace.mjs +0 -38
  39. package/dist/lib/neutral/Trace.mjs.map +0 -7
  40. package/dist/lib/neutral/chunk-5T7GOX2V.mjs +0 -149
  41. package/dist/lib/neutral/chunk-5T7GOX2V.mjs.map +0 -7
  42. package/dist/lib/neutral/chunk-IVDUS56O.mjs +0 -49
  43. package/dist/lib/neutral/chunk-IVDUS56O.mjs.map +0 -7
  44. package/dist/lib/neutral/chunk-J5LGTIGS.mjs +0 -10
  45. package/dist/lib/neutral/chunk-J5LGTIGS.mjs.map +0 -7
  46. package/dist/lib/neutral/fib-N45KAC7C.mjs +0 -23
  47. package/dist/lib/neutral/fib-N45KAC7C.mjs.map +0 -7
  48. package/dist/lib/neutral/reply-EUEPKNJF.mjs +0 -19
  49. package/dist/lib/neutral/reply-EUEPKNJF.mjs.map +0 -7
  50. package/dist/lib/neutral/sleep-PUK3D4FF.mjs +0 -15
  51. package/dist/lib/neutral/sleep-PUK3D4FF.mjs.map +0 -7
  52. package/dist/types/src/Trace.d.ts +0 -155
  53. package/dist/types/src/Trace.d.ts.map +0 -1
  54. package/dist/types/src/errors.d.ts +0 -121
  55. package/dist/types/src/errors.d.ts.map +0 -1
  56. package/dist/types/src/example/definitions.d.ts +0 -11
  57. package/dist/types/src/example/definitions.d.ts.map +0 -1
  58. package/dist/types/src/example/fib.d.ts +0 -8
  59. package/dist/types/src/example/fib.d.ts.map +0 -1
  60. package/dist/types/src/example/forex-effect.d.ts +0 -3
  61. package/dist/types/src/example/forex-effect.d.ts.map +0 -1
  62. package/dist/types/src/example/index.d.ts +0 -4
  63. package/dist/types/src/example/index.d.ts.map +0 -1
  64. package/dist/types/src/example/reply.d.ts +0 -4
  65. package/dist/types/src/example/reply.d.ts.map +0 -1
  66. package/dist/types/src/example/sleep.d.ts +0 -6
  67. package/dist/types/src/example/sleep.d.ts.map +0 -1
  68. package/dist/types/src/process/Process.d.ts +0 -247
  69. package/dist/types/src/process/Process.d.ts.map +0 -1
  70. package/dist/types/src/process/ServiceResolver.d.ts +0 -74
  71. package/dist/types/src/process/ServiceResolver.d.ts.map +0 -1
  72. package/dist/types/src/process/StorageService.d.ts +0 -58
  73. package/dist/types/src/process/StorageService.d.ts.map +0 -1
  74. package/dist/types/src/services/event-logger.d.ts +0 -81
  75. package/dist/types/src/services/event-logger.d.ts.map +0 -1
  76. package/dist/types/src/types/Script.d.ts +0 -22
  77. package/dist/types/src/types/Script.d.ts.map +0 -1
  78. package/dist/types/src/types/Trigger.d.ts +0 -120
  79. package/dist/types/src/types/Trigger.d.ts.map +0 -1
  80. package/dist/types/src/types/TriggerEvent.d.ts +0 -75
  81. package/dist/types/src/types/TriggerEvent.d.ts.map +0 -1
  82. package/src/Trace.ts +0 -202
  83. package/src/errors.ts +0 -21
  84. package/src/example/definitions.ts +0 -49
  85. package/src/example/fib.ts +0 -23
  86. package/src/example/forex-effect.ts +0 -40
  87. package/src/example/index.ts +0 -12
  88. package/src/example/reply.ts +0 -19
  89. package/src/example/sleep.ts +0 -17
  90. package/src/process/Process.ts +0 -486
  91. package/src/process/ServiceResolver.ts +0 -174
  92. package/src/process/StorageService.ts +0 -99
  93. package/src/services/event-logger.ts +0 -127
  94. package/src/types/Script.ts +0 -38
  95. package/src/types/Trigger.ts +0 -154
  96. package/src/types/TriggerEvent.ts +0 -62
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/functions",
3
- "version": "0.8.4-main.9be5663bfe",
3
+ "version": "0.8.4-main.abd8ff62ef",
4
4
  "description": "Functions API.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -17,11 +17,6 @@
17
17
  "source": "./src/index.ts",
18
18
  "types": "./dist/types/src/index.d.ts",
19
19
  "default": "./dist/lib/neutral/index.mjs"
20
- },
21
- "./Trace": {
22
- "source": "./src/Trace.ts",
23
- "types": "./dist/types/src/Trace.d.ts",
24
- "default": "./dist/lib/neutral/Trace.mjs"
25
20
  }
26
21
  },
27
22
  "types": "dist/types/src/index.d.ts",
@@ -35,20 +30,20 @@
35
30
  "@effect/ai-anthropic": "0.23.0",
36
31
  "@effect/platform": "0.94.4",
37
32
  "effect": "3.20.0",
38
- "@dxos/ai": "0.8.4-main.9be5663bfe",
39
- "@dxos/echo": "0.8.4-main.9be5663bfe",
40
- "@dxos/context": "0.8.4-main.9be5663bfe",
41
- "@dxos/echo-db": "0.8.4-main.9be5663bfe",
42
- "@dxos/errors": "0.8.4-main.9be5663bfe",
43
- "@dxos/keys": "0.8.4-main.9be5663bfe",
44
- "@dxos/log": "0.8.4-main.9be5663bfe",
45
- "@dxos/operation": "0.8.4-main.9be5663bfe",
46
- "@dxos/protocols": "0.8.4-main.9be5663bfe",
47
- "@dxos/node-std": "0.8.4-main.9be5663bfe",
48
- "@dxos/schema": "0.8.4-main.9be5663bfe",
49
- "@dxos/effect": "0.8.4-main.9be5663bfe",
50
- "@dxos/types": "0.8.4-main.9be5663bfe",
51
- "@dxos/invariant": "0.8.4-main.9be5663bfe"
33
+ "@dxos/ai": "0.8.4-main.abd8ff62ef",
34
+ "@dxos/context": "0.8.4-main.abd8ff62ef",
35
+ "@dxos/compute": "0.8.4-main.abd8ff62ef",
36
+ "@dxos/echo": "0.8.4-main.abd8ff62ef",
37
+ "@dxos/effect": "0.8.4-main.abd8ff62ef",
38
+ "@dxos/echo-db": "0.8.4-main.abd8ff62ef",
39
+ "@dxos/errors": "0.8.4-main.abd8ff62ef",
40
+ "@dxos/invariant": "0.8.4-main.abd8ff62ef",
41
+ "@dxos/keys": "0.8.4-main.abd8ff62ef",
42
+ "@dxos/log": "0.8.4-main.abd8ff62ef",
43
+ "@dxos/node-std": "0.8.4-main.abd8ff62ef",
44
+ "@dxos/protocols": "0.8.4-main.abd8ff62ef",
45
+ "@dxos/schema": "0.8.4-main.abd8ff62ef",
46
+ "@dxos/types": "0.8.4-main.abd8ff62ef"
52
47
  },
53
48
  "publishConfig": {
54
49
  "access": "public"
package/src/index.ts CHANGED
@@ -2,13 +2,7 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- export * from './errors';
6
- export * from './example';
7
- export * as Process from './process/Process';
8
- export * as ServiceResolver from './process/ServiceResolver';
9
- export * from './process/StorageService';
10
5
  export * from './sdk';
11
6
  export * from './services';
12
7
  export * from './types';
13
8
  export * from './protocol';
14
- export * as Trace from './Trace';
@@ -4,16 +4,16 @@
4
4
 
5
5
  import { describe, test } from 'vitest';
6
6
 
7
- import { FunctionError } from '../errors';
8
- import fibFunc from '../example/fib';
9
- import replyFunc from '../example/reply';
7
+ import { InvalidOperationInputError } from '@dxos/compute';
8
+ import { FibonacciHandler, ReplyHandler } from '@dxos/compute/testing';
9
+
10
10
  import { wrapFunctionHandler } from './protocol';
11
11
 
12
12
  describe('wrapFunctionHandler', () => {
13
13
  test('wraps reply function and executes handler', async ({ expect }) => {
14
- const wrapped = wrapFunctionHandler(replyFunc);
14
+ const wrapped = wrapFunctionHandler(ReplyHandler);
15
15
 
16
- expect(wrapped.meta.key).toBe('example.org/function/reply');
16
+ expect(wrapped.meta.key).toBe('org.example.function.reply');
17
17
  expect(wrapped.meta.name).toBe('Reply');
18
18
 
19
19
  const testData = { message: 'hello' };
@@ -28,9 +28,9 @@ describe('wrapFunctionHandler', () => {
28
28
  });
29
29
 
30
30
  test('wraps fibonacci function with valid input', async ({ expect }) => {
31
- const wrapped = wrapFunctionHandler(fibFunc);
31
+ const wrapped = wrapFunctionHandler(FibonacciHandler);
32
32
 
33
- expect(wrapped.meta.key).toBe('example.org/function/fib');
33
+ expect(wrapped.meta.key).toBe('org.example.function.fib');
34
34
  expect(wrapped.meta.name).toBe('Fibonacci');
35
35
 
36
36
  const result = await wrapped.handler({
@@ -43,8 +43,8 @@ describe('wrapFunctionHandler', () => {
43
43
  expect(result).toEqual({ result: '55' });
44
44
  });
45
45
 
46
- test('throws FunctionError on invalid input schema for fibonacci', async ({ expect }) => {
47
- const wrapped = wrapFunctionHandler(fibFunc);
46
+ test('throws InvalidOperationInputError on invalid input schema for fibonacci', async ({ expect }) => {
47
+ const wrapped = wrapFunctionHandler(FibonacciHandler);
48
48
 
49
49
  await expect(
50
50
  wrapped.handler({
@@ -53,6 +53,6 @@ describe('wrapFunctionHandler', () => {
53
53
  services: {},
54
54
  },
55
55
  }),
56
- ).rejects.toThrow(FunctionError);
56
+ ).rejects.toThrow(InvalidOperationInputError);
57
57
  });
58
58
  });
@@ -10,6 +10,13 @@ import * as SchemaAST from 'effect/SchemaAST';
10
10
 
11
11
  import { AiModelResolver, AiService } from '@dxos/ai';
12
12
  import { AnthropicResolver } from '@dxos/ai/resolvers';
13
+ import {
14
+ FunctionError,
15
+ InvalidOperationInputError,
16
+ InvalidOperationOutputError,
17
+ Operation,
18
+ Trace,
19
+ } from '@dxos/compute';
13
20
  import { LifecycleState, Resource } from '@dxos/context';
14
21
  import { Database, Feed, JsonSchema, Ref, type Type } from '@dxos/echo';
15
22
  import { EchoClient, type EchoDatabaseImpl, type QueueFactory, createFeedServiceLayer } from '@dxos/echo-db';
@@ -17,13 +24,15 @@ import { refFromEncodedReference } from '@dxos/echo/internal';
17
24
  import { runAndForwardErrors } from '@dxos/effect';
18
25
  import { assertState, failedInvariant, invariant } from '@dxos/invariant';
19
26
  import { PublicKey } from '@dxos/keys';
20
- import { Operation } from '@dxos/operation';
21
27
  import { type FunctionProtocol } from '@dxos/protocols';
22
28
 
23
- import { FunctionError } from '../errors';
24
29
  import { type FunctionServices } from '../sdk';
25
- import { CredentialsService, FunctionInvocationService, QueueService, TracingService } from '../services';
26
- import * as Trace from '../Trace';
30
+ import {
31
+ configuredCredentialsLayer,
32
+ credentialsLayerFromDatabase,
33
+ FunctionInvocationService,
34
+ QueueService,
35
+ } from '../services';
27
36
  import { FunctionsAiHttpClient } from './functions-ai-http-client';
28
37
 
29
38
  /**
@@ -61,9 +70,12 @@ export const wrapFunctionHandler = (func: Operation.WithHandler<Operation.Defini
61
70
  try {
62
71
  if (!SchemaAST.isAnyKeyword(func.input.ast)) {
63
72
  try {
64
- Schema.validateSync(func.input)(data);
65
- } catch (error) {
66
- throw new FunctionError({ message: 'Invalid input schema', cause: error });
73
+ Schema.validateSync(func.input, { onExcessProperty: 'error' })(data);
74
+ } catch (error: any) {
75
+ throw new InvalidOperationInputError({
76
+ message: `Operation input did not match schema (${func.meta.key}): ${error.message}`,
77
+ cause: error,
78
+ });
67
79
  }
68
80
  }
69
81
 
@@ -91,7 +103,14 @@ export const wrapFunctionHandler = (func: Operation.WithHandler<Operation.Defini
91
103
  }
92
104
 
93
105
  if (func.output && !SchemaAST.isAnyKeyword(func.output.ast)) {
94
- Schema.validateSync(func.output)(result);
106
+ try {
107
+ Schema.validateSync(func.output, { onExcessProperty: 'error' })(result);
108
+ } catch (error: any) {
109
+ throw new InvalidOperationOutputError({
110
+ message: `Operation output did not match schema (${func.meta.key}): ${error.message}`,
111
+ cause: error,
112
+ });
113
+ }
95
114
  }
96
115
 
97
116
  return result;
@@ -154,10 +173,10 @@ class FunctionContext extends Resource {
154
173
  const queuesLayer = this.queues ? QueueService.layer(this.queues) : QueueService.notAvailable;
155
174
  const feedLayer = this.queues ? createFeedServiceLayer(this.queues) : Feed.notAvailable;
156
175
  const credentials = dbLayer
157
- ? CredentialsService.layerFromDatabase({ caching: true }).pipe(Layer.provide(dbLayer))
158
- : CredentialsService.configuredLayer([]);
176
+ ? credentialsLayerFromDatabase({ caching: true }).pipe(Layer.provide(dbLayer))
177
+ : configuredCredentialsLayer([]);
159
178
  const functionInvocationService = MockedFunctionInvocationService;
160
- const tracing = TracingService.layerNoop;
179
+ const operationServiceLayer = MockedOperationServiceLayer;
161
180
 
162
181
  const aiLayer = this.context.services.functionsAiService
163
182
  ? AiModelResolver.AiModelResolver.buildAiService.pipe(
@@ -180,8 +199,8 @@ class FunctionContext extends Resource {
180
199
  feedLayer,
181
200
  credentials,
182
201
  functionInvocationService,
202
+ operationServiceLayer,
183
203
  aiLayer,
184
- tracing,
185
204
  // TODO(dmaretskyi): Forward trace events.
186
205
  Trace.writerLayerNoop,
187
206
  );
@@ -193,6 +212,12 @@ const MockedFunctionInvocationService = Layer.succeed(FunctionInvocationService,
193
212
  resolveFunction: () => Effect.die('Not implemented.'),
194
213
  });
195
214
 
215
+ const MockedOperationServiceLayer = Layer.succeed(Operation.Service, {
216
+ invoke: () => Effect.die('Calling operations from functions is not implemented yet.'),
217
+ schedule: () => Effect.die('Not implemented.'),
218
+ invokePromise: async () => ({ error: new Error('Not implemented') }),
219
+ } as any);
220
+
196
221
  const decodeRefsFromSchema = (ast: SchemaAST.AST, value: unknown, db: EchoDatabaseImpl): unknown => {
197
222
  if (value == null) {
198
223
  return value;
package/src/sdk.ts CHANGED
@@ -3,37 +3,27 @@
3
3
  //
4
4
 
5
5
  import { type AiService } from '@dxos/ai';
6
+ import { type Credential, type Operation, type Trace } from '@dxos/compute';
6
7
  import { type Database, type Feed } from '@dxos/echo';
7
- import { type Trace } from '@dxos/functions';
8
8
 
9
- import {
10
- type CredentialsService,
11
- type FunctionInvocationService,
12
- type QueueService,
13
- type TracingService,
14
- } from './services';
9
+ import { type FunctionInvocationService, type QueueService } from './services';
15
10
 
16
11
  // TODO(burdon): Model after http request. Ref Lambda/OpenFaaS.
17
12
  // https://docs.aws.amazon.com/lambda/latest/dg/typescript-handler.html
18
13
  // https://www.serverless.com/framework/docs/providers/aws/guide/serverless.yml/#functions
19
14
  // https://www.npmjs.com/package/aws-lambda
20
15
 
21
- /**
22
- * Services that are provided at the function call site by the caller.
23
- */
24
- export type InvocationServices = TracingService;
25
-
26
16
  /**
27
17
  * Services that are available to invoked functions.
28
18
  * @deprecated
29
19
  */
30
20
  export type FunctionServices =
31
- | InvocationServices
32
21
  | AiService.AiService
33
- | CredentialsService
22
+ | Credential.CredentialsService
34
23
  | Database.Service
35
24
  // TODO(wittjosiah): Remove QueueService — use Feed.FeedService instead.
36
25
  | QueueService
37
26
  | Feed.FeedService
38
27
  | Trace.TraceService
39
- | FunctionInvocationService;
28
+ | FunctionInvocationService
29
+ | Operation.Service;
@@ -10,136 +10,24 @@ import * as Effect from 'effect/Effect';
10
10
  import * as Layer from 'effect/Layer';
11
11
  import * as Redacted from 'effect/Redacted';
12
12
 
13
+ import { Credential } from '@dxos/compute';
13
14
  import { Query } from '@dxos/echo';
14
15
  import { Database } from '@dxos/echo';
15
16
  import { AccessToken } from '@dxos/types';
16
17
 
17
- export type CredentialQuery = {
18
- service?: string;
19
- };
20
-
21
- // TODO(dmaretskyi): Unify with other apis.
22
- // packages/sdk/schema/src/common/access-token.ts
23
- export type ServiceCredential = {
24
- service: string;
25
-
26
- // TODO(dmaretskyi): Build out.
27
- apiKey?: string;
28
- };
29
-
30
- export class CredentialsService extends Context.Tag('@dxos/functions/CredentialsService')<
31
- CredentialsService,
32
- {
33
- /**
34
- * Query all.
35
- */
36
- queryCredentials: (query: CredentialQuery) => Promise<ServiceCredential[]>;
37
-
38
- /**
39
- * Get a single credential.
40
- * @throws {Error} If no credential is found.
41
- */
42
- getCredential: (query: CredentialQuery) => Promise<ServiceCredential>;
43
- }
44
- >() {
45
- static getCredential = (query: CredentialQuery): Effect.Effect<ServiceCredential, never, CredentialsService> =>
46
- Effect.gen(function* () {
47
- const credentials = yield* CredentialsService;
48
- return yield* Effect.promise(() => credentials.getCredential(query));
49
- });
50
-
51
- static getApiKey = (query: CredentialQuery): Effect.Effect<Redacted.Redacted<string>, never, CredentialsService> =>
52
- Effect.gen(function* () {
53
- const credential = yield* CredentialsService.getCredential(query);
54
- if (!credential.apiKey) {
55
- throw new Error(`API key not found for service: ${query.service}`);
56
- }
57
- return Redacted.make(credential.apiKey);
58
- });
59
-
60
- static configuredLayer = (credentials: ServiceCredential[]) =>
61
- Layer.succeed(CredentialsService, new ConfiguredCredentialsService(credentials));
62
-
63
- static layerConfig = (
64
- credentials: {
65
- service: string;
66
- apiKey: Config.Config<Redacted.Redacted<string>>;
67
- }[],
68
- ) =>
69
- Layer.effect(
70
- CredentialsService,
71
- Effect.gen(function* () {
72
- const serviceCredentials = yield* Effect.forEach(credentials, ({ service, apiKey }) =>
73
- Effect.gen(function* () {
74
- return {
75
- service,
76
- apiKey: Redacted.value(yield* apiKey),
77
- };
78
- }),
79
- );
80
-
81
- return new ConfiguredCredentialsService(serviceCredentials);
82
- }),
83
- );
84
-
85
- static layerFromDatabase = ({ caching = false }: { caching?: boolean } = {}) =>
86
- Layer.effect(
87
- CredentialsService,
88
- Effect.gen(function* () {
89
- const dbService = yield* Database.Service;
90
- const cache = new Map<string, ServiceCredential[]>();
91
-
92
- const queryCredentials = async (query: CredentialQuery): Promise<ServiceCredential[]> => {
93
- const cacheKey = JSON.stringify(query);
94
- if (caching && cache.has(cacheKey)) {
95
- return cache.get(cacheKey)!;
96
- }
97
-
98
- const accessTokens = await dbService.db.query(Query.type(AccessToken.AccessToken)).run();
99
- const credentials = accessTokens
100
- .filter((accessToken) => accessToken.source === query.service)
101
- .map((accessToken) => ({
102
- service: accessToken.source,
103
- apiKey: accessToken.token,
104
- }));
105
-
106
- if (caching) {
107
- cache.set(cacheKey, credentials);
108
- }
18
+ export class ConfiguredCredentialsService implements Context.Tag.Service<Credential.CredentialsService> {
19
+ constructor(private readonly credentials: Credential.ServiceCredential[] = []) {}
109
20
 
110
- return credentials;
111
- };
112
-
113
- return {
114
- getCredential: async (query) => {
115
- const credentials = await queryCredentials(query);
116
- if (credentials.length === 0) {
117
- throw new Error(`Credential not found for service: ${query.service}`);
118
- }
119
-
120
- return credentials[0];
121
- },
122
- queryCredentials: async (query) => {
123
- return queryCredentials(query);
124
- },
125
- };
126
- }),
127
- );
128
- }
129
-
130
- export class ConfiguredCredentialsService implements Context.Tag.Service<CredentialsService> {
131
- constructor(private readonly credentials: ServiceCredential[] = []) {}
132
-
133
- addCredentials(credentials: ServiceCredential[]): ConfiguredCredentialsService {
21
+ addCredentials(credentials: Credential.ServiceCredential[]): ConfiguredCredentialsService {
134
22
  this.credentials.push(...credentials);
135
23
  return this;
136
24
  }
137
25
 
138
- async queryCredentials(query: CredentialQuery): Promise<ServiceCredential[]> {
26
+ async queryCredentials(query: Credential.CredentialQuery): Promise<Credential.ServiceCredential[]> {
139
27
  return this.credentials.filter((credential) => credential.service === query.service);
140
28
  }
141
29
 
142
- async getCredential(query: CredentialQuery): Promise<ServiceCredential> {
30
+ async getCredential(query: Credential.CredentialQuery): Promise<Credential.ServiceCredential> {
143
31
  const credential = this.credentials.find((credential) => credential.service === query.service);
144
32
  if (!credential) {
145
33
  throw new Error(`Credential not found for service: ${query.service}`);
@@ -157,3 +45,72 @@ export const withAuthorization = (token: string, kind?: 'Bearer' | 'Basic') =>
157
45
  const authorization = kind ? `${kind} ${token}` : token;
158
46
  return HttpClientRequest.setHeader(request, 'Authorization', authorization);
159
47
  });
48
+
49
+ export const configuredCredentialsLayer = (credentials: Credential.ServiceCredential[]) =>
50
+ Layer.succeed(Credential.CredentialsService, new ConfiguredCredentialsService(credentials));
51
+
52
+ export const credentialsLayerConfig = (
53
+ credentials: {
54
+ service: string;
55
+ apiKey: Config.Config<Redacted.Redacted<string>>;
56
+ }[],
57
+ ) =>
58
+ Layer.effect(
59
+ Credential.CredentialsService,
60
+ Effect.gen(function* () {
61
+ const serviceCredentials = yield* Effect.forEach(credentials, ({ service, apiKey }) =>
62
+ Effect.gen(function* () {
63
+ return {
64
+ service,
65
+ apiKey: Redacted.value(yield* apiKey),
66
+ };
67
+ }),
68
+ );
69
+
70
+ return new ConfiguredCredentialsService(serviceCredentials);
71
+ }),
72
+ );
73
+
74
+ export const credentialsLayerFromDatabase = ({ caching = false }: { caching?: boolean } = {}) =>
75
+ Layer.effect(
76
+ Credential.CredentialsService,
77
+ Effect.gen(function* () {
78
+ const dbService = yield* Database.Service;
79
+ const cache = new Map<string, Credential.ServiceCredential[]>();
80
+
81
+ const queryCredentials = async (query: Credential.CredentialQuery): Promise<Credential.ServiceCredential[]> => {
82
+ const cacheKey = JSON.stringify(query);
83
+ if (caching && cache.has(cacheKey)) {
84
+ return cache.get(cacheKey)!;
85
+ }
86
+
87
+ const accessTokens = await dbService.db.query(Query.type(AccessToken.AccessToken)).run();
88
+ const credentials = accessTokens
89
+ .filter((accessToken) => accessToken.source === query.service)
90
+ .map((accessToken) => ({
91
+ service: accessToken.source,
92
+ apiKey: accessToken.token,
93
+ }));
94
+
95
+ if (caching) {
96
+ cache.set(cacheKey, credentials);
97
+ }
98
+
99
+ return credentials;
100
+ };
101
+
102
+ return {
103
+ getCredential: async (query) => {
104
+ const credentials = await queryCredentials(query);
105
+ if (credentials.length === 0) {
106
+ throw new Error(`Credential not found for service: ${query.service}`);
107
+ }
108
+
109
+ return credentials[0];
110
+ },
111
+ queryCredentials: async (query) => {
112
+ return queryCredentials(query);
113
+ },
114
+ };
115
+ }),
116
+ );
@@ -5,18 +5,12 @@ import * as Context from 'effect/Context';
5
5
  import * as Effect from 'effect/Effect';
6
6
  import * as Layer from 'effect/Layer';
7
7
 
8
- import { Operation } from '@dxos/operation';
9
-
10
- import type { FunctionNotFoundError } from '../errors';
11
- import { type InvocationServices } from '../sdk';
8
+ import { type FunctionNotFoundError, Operation } from '@dxos/compute';
12
9
 
13
10
  export class FunctionInvocationService extends Context.Tag('@dxos/functions/FunctionInvocationService')<
14
11
  FunctionInvocationService,
15
12
  {
16
- invokeFunction<I, O>(
17
- functionDef: Operation.Definition<I, O, any>,
18
- input: I,
19
- ): Effect.Effect<O, never, InvocationServices>;
13
+ invokeFunction<I, O>(functionDef: Operation.Definition<I, O, any>, input: I): Effect.Effect<O>;
20
14
 
21
15
  resolveFunction(key: string): Effect.Effect<Operation.Definition.Any, FunctionNotFoundError>;
22
16
  }
@@ -29,7 +23,7 @@ export class FunctionInvocationService extends Context.Tag('@dxos/functions/Func
29
23
  static invokeFunction = <I, O>(
30
24
  functionDef: Operation.Definition<I, O, any>,
31
25
  input: I,
32
- ): Effect.Effect<O, never, FunctionInvocationService | InvocationServices> =>
26
+ ): Effect.Effect<O, never, FunctionInvocationService> =>
33
27
  Effect.serviceFunctionEffect(FunctionInvocationService, (service) => service.invokeFunction)(functionDef, input);
34
28
 
35
29
  static resolveFunction = (
@@ -3,9 +3,6 @@
3
3
  //
4
4
 
5
5
  export * from './credentials';
6
- export { ConfiguredCredentialsService, type ServiceCredential } from './credentials';
7
- export * from './event-logger';
8
- export { createEventLogger, createDefectLogger } from './event-logger';
9
6
  export * from './function-invocation-service';
10
7
  export * from './queues';
11
- export * from './tracing';
8
+ export { MESSAGE_PROPERTY_TOOL_CALL_ID } from './tracing';
@@ -2,90 +2,4 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import * as Context from 'effect/Context';
6
- import * as Effect from 'effect/Effect';
7
- import * as Layer from 'effect/Layer';
8
-
9
- import { type Entity } from '@dxos/echo';
10
- import { createFeedServiceLayer, type Queue, type QueueAPI, type QueueFactory } from '@dxos/echo-db';
11
- import type { DXN, QueueSubspaceTag } from '@dxos/keys';
12
-
13
- /**
14
- * Gives access to all queues.
15
- * @deprecated Use Feed.FeedService instead.
16
- */
17
- export class QueueService extends Context.Tag('@dxos/functions/QueueService')<
18
- QueueService,
19
- {
20
- /**
21
- * API to access the queues.
22
- */
23
- readonly queues: QueueAPI;
24
-
25
- /**
26
- * The queue that is used to store the context of the current research.
27
- * @deprecated Use `ContextQueueService` instead.
28
- */
29
- readonly queue: Queue | undefined;
30
- }
31
- >() {
32
- static notAvailable = Layer.succeed(QueueService, {
33
- queues: {
34
- get(_dxn) {
35
- throw new Error('Queues not available');
36
- },
37
- create() {
38
- throw new Error('Queues not available');
39
- },
40
- },
41
- queue: undefined,
42
- });
43
-
44
- static make = (queues: QueueFactory, queue?: Queue): Context.Tag.Service<QueueService> => {
45
- return {
46
- queues,
47
- queue,
48
- };
49
- };
50
-
51
- static layer = (queues: QueueFactory, queue?: Queue): Layer.Layer<QueueService> =>
52
- Layer.succeed(QueueService, QueueService.make(queues, queue));
53
-
54
- /**
55
- * Gets a queue by its DXN.
56
- */
57
- static getQueue = <T extends Entity.Unknown = Entity.Unknown>(
58
- dxn: DXN,
59
- ): Effect.Effect<Queue<T>, never, QueueService> => QueueService.pipe(Effect.map(({ queues }) => queues.get<T>(dxn)));
60
-
61
- /**
62
- * Creates a new queue.
63
- */
64
- static createQueue = <T extends Entity.Unknown = Entity.Unknown>(options?: {
65
- subspaceTag?: QueueSubspaceTag;
66
- }): Effect.Effect<Queue<T>, never, QueueService> =>
67
- QueueService.pipe(Effect.map(({ queues }) => queues.create<T>(options)));
68
-
69
- static append = <T extends Entity.Unknown = Entity.Unknown>(queue: Queue<T>, objects: T[]): Effect.Effect<void> =>
70
- Effect.promise(() => queue.append(objects));
71
- }
72
-
73
- /**
74
- * Gives access to a specific queue passed as a context.
75
- * @deprecated Use Feed.FeedService instead.
76
- */
77
- export class ContextQueueService extends Context.Tag('@dxos/functions/ContextQueueService')<
78
- ContextQueueService,
79
- {
80
- readonly queue: Queue;
81
- }
82
- >() {
83
- static layer = (queue: Queue) => Layer.succeed(ContextQueueService, { queue });
84
- }
85
-
86
- export const feedServiceFromQueueServiceLayer = Layer.unwrapEffect(
87
- Effect.gen(function* () {
88
- const { queues } = yield* QueueService;
89
- return createFeedServiceLayer(queues);
90
- }),
91
- );
5
+ export { ContextQueueService, QueueService, feedServiceFromQueueServiceLayer } from '@dxos/echo-db';