@dxos/compute 0.13.0 → 0.14.0
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.
- package/dist/lib/AgentService.mjs.map +1 -1
- package/dist/lib/Operation.mjs +41 -14
- package/dist/lib/Operation.mjs.map +1 -1
- package/dist/lib/OperationHandlerSet.mjs +1 -1
- package/dist/lib/Process.mjs +34 -2
- package/dist/lib/Process.mjs.map +1 -1
- package/dist/lib/ShellService.mjs +24 -0
- package/dist/lib/ShellService.mjs.map +1 -0
- package/dist/lib/chunk-SqlService.mjs +2 -2
- package/dist/lib/errors.mjs +7 -1
- package/dist/lib/errors.mjs.map +1 -1
- package/dist/lib/index.mjs +2 -1
- package/dist/lib/types/Project.mjs +8 -0
- package/dist/lib/types/Project.mjs.map +1 -1
- package/dist/lib/types/Skill.mjs +7 -1
- package/dist/lib/types/Skill.mjs.map +1 -1
- package/dist/lib/types/Trigger.mjs +6 -5
- package/dist/lib/types/Trigger.mjs.map +1 -1
- package/dist/types/src/AgentService.d.ts +2 -1
- package/dist/types/src/AgentService.d.ts.map +1 -1
- package/dist/types/src/Operation.d.ts +64 -11
- package/dist/types/src/Operation.d.ts.map +1 -1
- package/dist/types/src/Process.d.ts +53 -31
- package/dist/types/src/Process.d.ts.map +1 -1
- package/dist/types/src/ShellService.d.ts +85 -0
- package/dist/types/src/ShellService.d.ts.map +1 -0
- package/dist/types/src/errors.d.ts +31 -0
- package/dist/types/src/errors.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/types/Project.d.ts +2 -0
- package/dist/types/src/types/Project.d.ts.map +1 -1
- package/dist/types/src/types/Skill.d.ts +8 -0
- package/dist/types/src/types/Skill.d.ts.map +1 -1
- package/dist/types/src/types/Trigger.d.ts +11 -9
- package/dist/types/src/types/Trigger.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +20 -15
- package/src/AgentService.ts +2 -1
- package/src/DurableOperation.tst.ts +155 -0
- package/src/Operation.ts +121 -46
- package/src/Process.ts +99 -41
- package/src/ShellService.ts +71 -0
- package/src/errors.ts +7 -0
- package/src/index.ts +1 -0
- package/src/types/Project.ts +11 -0
- package/src/types/Skill.ts +9 -0
- package/src/types/Trigger.ts +9 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/compute",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "Umbrella package for AI-aware DXOS compute primitives.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -114,6 +114,11 @@
|
|
|
114
114
|
"types": "./dist/types/src/types/Skill.d.ts",
|
|
115
115
|
"import": "./dist/lib/types/Skill.mjs"
|
|
116
116
|
},
|
|
117
|
+
"./ShellService": {
|
|
118
|
+
"source": "./src/ShellService.ts",
|
|
119
|
+
"types": "./dist/types/src/ShellService.d.ts",
|
|
120
|
+
"import": "./dist/lib/ShellService.mjs"
|
|
121
|
+
},
|
|
117
122
|
"./SqlService": {
|
|
118
123
|
"source": "./src/SqlService.ts",
|
|
119
124
|
"types": "./dist/types/src/SqlService.d.ts",
|
|
@@ -156,24 +161,24 @@
|
|
|
156
161
|
"src"
|
|
157
162
|
],
|
|
158
163
|
"dependencies": {
|
|
159
|
-
"@dxos/ai": "0.
|
|
160
|
-
"@dxos/echo": "0.
|
|
161
|
-
"@dxos/effect": "0.
|
|
162
|
-
"@dxos/errors": "0.
|
|
163
|
-
"@dxos/invariant": "0.
|
|
164
|
-
"@dxos/
|
|
165
|
-
"@dxos/
|
|
166
|
-
"@dxos/
|
|
167
|
-
"@dxos/protocols": "0.
|
|
168
|
-
"@dxos/schema": "0.
|
|
169
|
-
"@dxos/types": "0.
|
|
170
|
-
"@dxos/vendor-kbn-handlebars": "0.
|
|
164
|
+
"@dxos/ai": "0.14.0",
|
|
165
|
+
"@dxos/echo": "0.14.0",
|
|
166
|
+
"@dxos/effect": "0.14.0",
|
|
167
|
+
"@dxos/errors": "0.14.0",
|
|
168
|
+
"@dxos/invariant": "0.14.0",
|
|
169
|
+
"@dxos/keys": "0.14.0",
|
|
170
|
+
"@dxos/log": "0.14.0",
|
|
171
|
+
"@dxos/link": "0.14.0",
|
|
172
|
+
"@dxos/protocols": "0.14.0",
|
|
173
|
+
"@dxos/schema": "0.14.0",
|
|
174
|
+
"@dxos/types": "0.14.0",
|
|
175
|
+
"@dxos/vendor-kbn-handlebars": "0.14.0"
|
|
171
176
|
},
|
|
172
177
|
"devDependencies": {
|
|
173
178
|
"effect": "4.0.0",
|
|
174
179
|
"vitest": "4.1.10",
|
|
175
|
-
"@dxos/echo-client": "0.
|
|
176
|
-
"@dxos/sql-sqlite": "0.
|
|
180
|
+
"@dxos/echo-client": "0.14.0",
|
|
181
|
+
"@dxos/sql-sqlite": "0.14.0"
|
|
177
182
|
},
|
|
178
183
|
"peerDependencies": {
|
|
179
184
|
"effect": "4.0.0"
|
package/src/AgentService.ts
CHANGED
|
@@ -14,6 +14,7 @@ import type { Database, Feed, Obj, Ref } from '@dxos/echo';
|
|
|
14
14
|
import { DXN } from '@dxos/keys';
|
|
15
15
|
import type { ContentBlock } from '@dxos/types';
|
|
16
16
|
|
|
17
|
+
import type * as Process from './Process.ts';
|
|
17
18
|
import type * as Trace from './Trace.ts';
|
|
18
19
|
import { Instructions } from './types/index.ts';
|
|
19
20
|
|
|
@@ -120,7 +121,7 @@ export interface Session {
|
|
|
120
121
|
* `runPromise(Effect.forEach(subscribe))`), use {@link Effect.forkDetach} so the
|
|
121
122
|
* stream survives after the parent scope closes; interrupt it on dispose.
|
|
122
123
|
*/
|
|
123
|
-
subscribeEphemeral: () => Stream.Stream<Trace.Message>;
|
|
124
|
+
subscribeEphemeral: (options?: Process.SubscribeEphemeralOptions) => Stream.Stream<Trace.Message>;
|
|
124
125
|
}
|
|
125
126
|
|
|
126
127
|
export const getSession = (...args: Parameters<Context.Service.Shape<typeof AgentService>['getSession']>) =>
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
// This file needs invalid usage, so the diagnostic reporting it is the assertion.
|
|
6
|
+
/** @effect-diagnostics unnecessaryEffectGen:skip-file */
|
|
7
|
+
|
|
8
|
+
import * as Context from 'effect/Context';
|
|
9
|
+
import * as Effect from 'effect/Effect';
|
|
10
|
+
import * as Rpc from 'effect/rpc/Rpc';
|
|
11
|
+
import * as RpcGroup from 'effect/rpc/RpcGroup';
|
|
12
|
+
import * as Schema from 'effect/Schema';
|
|
13
|
+
import { describe, expect, it } from 'tstyche';
|
|
14
|
+
|
|
15
|
+
import * as Operation from './Operation.ts';
|
|
16
|
+
import * as StorageService from './StorageService.ts';
|
|
17
|
+
|
|
18
|
+
class DeclaredService extends Context.Service<DeclaredService, { declared: () => void }>()('@test/DeclaredService') {}
|
|
19
|
+
class UndeclaredService extends Context.Service<UndeclaredService, { undeclared: () => void }>()(
|
|
20
|
+
'@test/UndeclaredService',
|
|
21
|
+
) {}
|
|
22
|
+
|
|
23
|
+
const rpcs = RpcGroup.make(Rpc.make('getValue', { success: Schema.Number }));
|
|
24
|
+
|
|
25
|
+
const definition = Operation.makeDurable({
|
|
26
|
+
key: 'test.durable',
|
|
27
|
+
input: Schema.String,
|
|
28
|
+
output: Schema.Number,
|
|
29
|
+
services: [DeclaredService],
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const withRpcs = Operation.makeDurable({
|
|
33
|
+
key: 'test.durable-rpcs',
|
|
34
|
+
input: Schema.Void,
|
|
35
|
+
output: Schema.Void,
|
|
36
|
+
services: [],
|
|
37
|
+
rpcs,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
describe('Operation.makeDurable', () => {
|
|
41
|
+
it('infers input, output and services from the props', () => {
|
|
42
|
+
expect(definition).type.toBe<Operation.DurableDefinition<string, number, DeclaredService, never>>();
|
|
43
|
+
expect<Operation.DurableDefinition.Input<typeof definition>>().type.toBe<string>();
|
|
44
|
+
expect<Operation.DurableDefinition.Output<typeof definition>>().type.toBe<number>();
|
|
45
|
+
expect<Operation.DurableDefinition.Requirements<typeof definition>>().type.toBe<DeclaredService>();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('carries the declared RPC group', () => {
|
|
49
|
+
expect<Operation.DurableDefinition.Rpcs<typeof withRpcs>>().type.toBe<RpcGroup.Rpcs<typeof rpcs>>();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('rejects unknown props', () => {
|
|
53
|
+
expect(
|
|
54
|
+
Operation.makeDurable({
|
|
55
|
+
key: 'test.durable',
|
|
56
|
+
input: Schema.Void,
|
|
57
|
+
output: Schema.Void,
|
|
58
|
+
services: [],
|
|
59
|
+
unknown: true,
|
|
60
|
+
}),
|
|
61
|
+
).type.toRaiseError();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('is not runnable without a handler', () => {
|
|
65
|
+
expect(definition).type.not.toBeAssignableTo<Operation.Durable.Any>();
|
|
66
|
+
expect(definition).type.not.toHaveProperty('create');
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
describe('Operation.withDurableHandler', () => {
|
|
71
|
+
it('produces a durable operation when called directly', () => {
|
|
72
|
+
expect(Operation.withDurableHandler(definition, () => Effect.succeed({}))).type.toBe<
|
|
73
|
+
Operation.Durable<string, number, DeclaredService, never>
|
|
74
|
+
>();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('produces a durable operation when piped', () => {
|
|
78
|
+
const durable = definition.pipe(Operation.withDurableHandler(() => Effect.succeed({})));
|
|
79
|
+
expect(durable).type.toBe<Operation.Durable<string, number, DeclaredService, never>>();
|
|
80
|
+
expect(durable).type.toBeAssignableTo<Operation.Durable.Any>();
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('types the input and output through the context', () => {
|
|
84
|
+
expect(
|
|
85
|
+
definition.pipe(
|
|
86
|
+
Operation.withDurableHandler((ctx) =>
|
|
87
|
+
Effect.succeed({
|
|
88
|
+
onInput: (input) => Effect.sync(() => ctx.submitOutput(input.length)),
|
|
89
|
+
}),
|
|
90
|
+
),
|
|
91
|
+
),
|
|
92
|
+
).type.not.toRaiseError();
|
|
93
|
+
|
|
94
|
+
expect(
|
|
95
|
+
definition.pipe(
|
|
96
|
+
Operation.withDurableHandler((ctx) =>
|
|
97
|
+
Effect.succeed({
|
|
98
|
+
onInput: (input) => Effect.sync(() => ctx.submitOutput(input)),
|
|
99
|
+
}),
|
|
100
|
+
),
|
|
101
|
+
),
|
|
102
|
+
).type.toRaiseError("Argument of type 'string' is not assignable to parameter of type 'number'.");
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('accepts declared and base services', () => {
|
|
106
|
+
expect(
|
|
107
|
+
Operation.withDurableHandler(definition, () =>
|
|
108
|
+
Effect.gen(function* () {
|
|
109
|
+
yield* DeclaredService;
|
|
110
|
+
yield* StorageService.StorageService;
|
|
111
|
+
return {};
|
|
112
|
+
}),
|
|
113
|
+
),
|
|
114
|
+
).type.not.toRaiseError();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('rejects a service the definition does not declare', () => {
|
|
118
|
+
expect(
|
|
119
|
+
Operation.withDurableHandler(definition, () =>
|
|
120
|
+
Effect.gen(function* () {
|
|
121
|
+
yield* UndeclaredService;
|
|
122
|
+
return {};
|
|
123
|
+
}),
|
|
124
|
+
),
|
|
125
|
+
).type.toRaiseError();
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('rejects a callback that does not match the handler', () => {
|
|
129
|
+
expect(
|
|
130
|
+
Operation.withDurableHandler(definition, () => Effect.succeed({ onInput: (_input: number) => Effect.void })),
|
|
131
|
+
).type.toRaiseError();
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('types RPC handlers against the declared group', () => {
|
|
135
|
+
expect(
|
|
136
|
+
withRpcs.pipe(
|
|
137
|
+
Operation.withDurableHandler(() =>
|
|
138
|
+
Effect.gen(function* () {
|
|
139
|
+
return { rpcHandlers: yield* rpcs.toHandlers({ getValue: () => Effect.succeed(1) }) };
|
|
140
|
+
}),
|
|
141
|
+
),
|
|
142
|
+
),
|
|
143
|
+
).type.toBe<Operation.Durable<void, void, never, RpcGroup.Rpcs<typeof rpcs>>>();
|
|
144
|
+
|
|
145
|
+
expect(
|
|
146
|
+
withRpcs.pipe(
|
|
147
|
+
Operation.withDurableHandler(() =>
|
|
148
|
+
Effect.gen(function* () {
|
|
149
|
+
return { rpcHandlers: yield* rpcs.toHandlers({ getValue: () => Effect.succeed('one') }) };
|
|
150
|
+
}),
|
|
151
|
+
),
|
|
152
|
+
),
|
|
153
|
+
).type.toRaiseError();
|
|
154
|
+
});
|
|
155
|
+
});
|
package/src/Operation.ts
CHANGED
|
@@ -8,6 +8,7 @@ import * as Cause from 'effect/Cause';
|
|
|
8
8
|
import * as Context from 'effect/Context';
|
|
9
9
|
import * as Effect from 'effect/Effect';
|
|
10
10
|
import type * as Exit from 'effect/Exit';
|
|
11
|
+
import * as Function from 'effect/Function';
|
|
11
12
|
import * as Layer from 'effect/Layer';
|
|
12
13
|
import * as Option from 'effect/Option';
|
|
13
14
|
import * as Pipeable from 'effect/Pipeable';
|
|
@@ -446,21 +447,15 @@ export interface DurableContext<I, O> {
|
|
|
446
447
|
setAlarm(timeout?: number): Effect.Effect<void>;
|
|
447
448
|
}
|
|
448
449
|
|
|
449
|
-
export const
|
|
450
|
-
export type
|
|
450
|
+
export const DurableDefinitionTypeId = '~@dxos/operation/DurableDefinition' as const;
|
|
451
|
+
export type DurableDefinitionTypeId = typeof DurableDefinitionTypeId;
|
|
451
452
|
|
|
452
453
|
/**
|
|
453
|
-
*
|
|
454
|
-
*
|
|
455
|
-
* `create` is used to instantiate a new process.
|
|
456
|
-
* Can store runtime state in scope of `create` function.
|
|
454
|
+
* Declaration of a durable operation, without its handler.
|
|
455
|
+
* Created by {@link makeDurable}; {@link withDurableHandler} attaches the handler factory to produce a {@link Durable}.
|
|
457
456
|
*/
|
|
458
|
-
export interface
|
|
459
|
-
_Input,
|
|
460
|
-
_Output,
|
|
461
|
-
_Requirements = never,
|
|
462
|
-
_Rpcs extends Rpc.Any = never,
|
|
463
|
-
> extends Durable.Variance<_Input, _Output, _Requirements, _Rpcs> {
|
|
457
|
+
export interface DurableDefinition<_Input, _Output, _Requirements = never, _Rpcs extends Rpc.Any = never>
|
|
458
|
+
extends Pipeable.Pipeable, DurableDefinition.Variance<_Input, _Output, _Requirements, _Rpcs> {
|
|
464
459
|
/**
|
|
465
460
|
* Unique identifier for the executable in the reverse DNS format.
|
|
466
461
|
*/
|
|
@@ -490,7 +485,59 @@ export interface Durable<
|
|
|
490
485
|
// The precise group is carried by the covariant `Variance` phantom and recovered at `spawn`.
|
|
491
486
|
// See design spec §4.4.
|
|
492
487
|
readonly rpcs: RpcGroup.RpcGroup<any>;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
export declare namespace DurableDefinition {
|
|
491
|
+
export interface Variance<_Input, _Output, _Requirements, _Rpcs> {
|
|
492
|
+
readonly [DurableDefinitionTypeId]: {
|
|
493
|
+
readonly _Input: Types.Contravariant<_Input>;
|
|
494
|
+
readonly _Output: Types.Covariant<_Output>;
|
|
495
|
+
readonly _Requirements: Types.Covariant<_Requirements>;
|
|
496
|
+
|
|
497
|
+
// Phantom-covariant: lets `never`-RPC processes stay assignable to `Durable.Any` while
|
|
498
|
+
// `spawn` still recovers the precise group from this slot. See design spec §4.4.
|
|
499
|
+
readonly _Rpcs: Types.Covariant<_Rpcs>;
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
export type Any = DurableDefinition<any, any, any, any>;
|
|
504
|
+
|
|
505
|
+
export type Input<T extends Any> = T extends Variance<infer I, infer _O, infer _R, infer _P> ? I : never;
|
|
506
|
+
export type Output<T extends Any> = T extends Variance<infer _I, infer O, infer _R, infer _P> ? O : never;
|
|
507
|
+
export type Requirements<T extends Any> = T extends Variance<infer _I, infer _O, infer R, infer _P> ? R : never;
|
|
508
|
+
export type Rpcs<T extends Any> =
|
|
509
|
+
T extends Variance<infer _I, infer _O, infer _R, infer P extends Rpc.Any> ? P : never;
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* The handler factory {@link withDurableHandler} accepts for a definition: callbacks may be omitted and default to no-ops.
|
|
513
|
+
*/
|
|
514
|
+
export type Create<T extends Any> = (
|
|
515
|
+
ctx: DurableContext<Input<T>, Output<T>>,
|
|
516
|
+
) => Effect.Effect<
|
|
517
|
+
Partial<DurableHandler<Input<T>, Output<T>, Requirements<T>, Rpcs<T>>>,
|
|
518
|
+
never,
|
|
519
|
+
Requirements<T> | BaseServices | Scope.Scope
|
|
520
|
+
>;
|
|
521
|
+
|
|
522
|
+
/**
|
|
523
|
+
* The durable operation produced by attaching a handler to a definition.
|
|
524
|
+
*/
|
|
525
|
+
export type WithHandler<T extends Any> = Durable<Input<T>, Output<T>, Requirements<T>, Rpcs<T>>;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
export const DurableTypeId = '~@dxos/operation/Durable' as const;
|
|
529
|
+
export type DurableTypeId = typeof DurableTypeId;
|
|
493
530
|
|
|
531
|
+
/**
|
|
532
|
+
* A durable operation: declaration plus a handler factory, run by a process runtime.
|
|
533
|
+
* Can be instantiated multiple times to produce new process instances with separate state and handlers.
|
|
534
|
+
* `create` is used to instantiate a new process.
|
|
535
|
+
* Can store runtime state in scope of `create` function.
|
|
536
|
+
*/
|
|
537
|
+
export interface Durable<_Input, _Output, _Requirements = never, _Rpcs extends Rpc.Any = never>
|
|
538
|
+
extends
|
|
539
|
+
DurableDefinition<_Input, _Output, _Requirements, _Rpcs>,
|
|
540
|
+
Durable.Variance<_Input, _Output, _Requirements, _Rpcs> {
|
|
494
541
|
/**
|
|
495
542
|
* Create a new instance of the process.
|
|
496
543
|
*/
|
|
@@ -503,6 +550,9 @@ export interface Durable<
|
|
|
503
550
|
>;
|
|
504
551
|
}
|
|
505
552
|
|
|
553
|
+
export const isDurableDefinition = (value: unknown): value is DurableDefinition.Any =>
|
|
554
|
+
typeof value === 'object' && value !== null && DurableDefinitionTypeId in value;
|
|
555
|
+
|
|
506
556
|
export const isDurable = (executable: unknown): executable is Durable.Any =>
|
|
507
557
|
typeof executable === 'object' && executable !== null && DurableTypeId in executable;
|
|
508
558
|
|
|
@@ -512,9 +562,6 @@ export namespace Durable {
|
|
|
512
562
|
readonly _Input: Types.Contravariant<_Input>;
|
|
513
563
|
readonly _Output: Types.Covariant<_Output>;
|
|
514
564
|
readonly _Requirements: Types.Covariant<_Requirements>;
|
|
515
|
-
|
|
516
|
-
// Phantom-covariant: lets `never`-RPC processes stay assignable to `Durable.Any` while
|
|
517
|
-
// `spawn` still recovers the precise group from this slot. See design spec §4.4.
|
|
518
565
|
readonly _Rpcs: Types.Covariant<_Rpcs>;
|
|
519
566
|
};
|
|
520
567
|
}
|
|
@@ -528,6 +575,11 @@ export interface DurableProps {
|
|
|
528
575
|
*/
|
|
529
576
|
readonly key: string;
|
|
530
577
|
|
|
578
|
+
/**
|
|
579
|
+
* Human-readable label; `Process.spawn` names the process after it.
|
|
580
|
+
*/
|
|
581
|
+
readonly name?: string;
|
|
582
|
+
|
|
531
583
|
readonly input: Schema.Codec<any, any>;
|
|
532
584
|
readonly output: Schema.Codec<any, any>;
|
|
533
585
|
readonly services: readonly Context.Key<any, any>[];
|
|
@@ -545,25 +597,20 @@ export interface DurableProps {
|
|
|
545
597
|
}
|
|
546
598
|
|
|
547
599
|
/**
|
|
548
|
-
*
|
|
600
|
+
* Declares a durable operation; attach its handler factory with {@link withDurableHandler}.
|
|
601
|
+
*
|
|
602
|
+
* @example
|
|
603
|
+
* ```ts
|
|
604
|
+
* const Counter = Operation.makeDurable({ key: 'example.counter', input: Schema.Number, output: Schema.Number, services: [] }).pipe(
|
|
605
|
+
* Operation.withDurableHandler((ctx) =>
|
|
606
|
+
* Effect.succeed({ onInput: (input) => Effect.sync(() => ctx.submitOutput(input + 1)) }),
|
|
607
|
+
* ),
|
|
608
|
+
* );
|
|
609
|
+
* ```
|
|
549
610
|
*/
|
|
550
611
|
export const makeDurable = <const Opts extends Types.NoExcessProperties<DurableProps, Opts>>(
|
|
551
612
|
opts: Opts,
|
|
552
|
-
|
|
553
|
-
ctx: DurableContext<Schema.Schema.Type<Opts['input']>, Schema.Schema.Type<Opts['output']>>,
|
|
554
|
-
) => Effect.Effect<
|
|
555
|
-
Partial<
|
|
556
|
-
DurableHandler<
|
|
557
|
-
Schema.Schema.Type<Opts['input']>,
|
|
558
|
-
Schema.Schema.Type<Opts['output']>,
|
|
559
|
-
Context.Service.Identifier<NonNullable<Opts['services']>[number]>,
|
|
560
|
-
RpcGroup.Rpcs<Opts['rpcs']>
|
|
561
|
-
>
|
|
562
|
-
>,
|
|
563
|
-
never,
|
|
564
|
-
Context.Service.Identifier<NonNullable<Opts['services']>[number]> | BaseServices | Scope.Scope
|
|
565
|
-
>,
|
|
566
|
-
): Durable<
|
|
613
|
+
): DurableDefinition<
|
|
567
614
|
Schema.Schema.Type<Opts['input']>,
|
|
568
615
|
Schema.Schema.Type<Opts['output']>,
|
|
569
616
|
Context.Service.Identifier<NonNullable<Opts['services']>[number]>,
|
|
@@ -571,26 +618,54 @@ export const makeDurable = <const Opts extends Types.NoExcessProperties<DurableP
|
|
|
571
618
|
> => {
|
|
572
619
|
assertArgument(/^[a-z0-9]([a-z0-9.\-/]*[a-z0-9])?$/i.test(opts.key), 'key', 'Invalid key');
|
|
573
620
|
return {
|
|
574
|
-
[
|
|
621
|
+
[DurableDefinitionTypeId]: {} as any,
|
|
575
622
|
...opts,
|
|
576
623
|
rpcs: opts.rpcs ?? RpcGroup.make(),
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
onInput: () => Effect.void,
|
|
582
|
-
onAlarm: () => Effect.void,
|
|
583
|
-
onChildEvent: () => Effect.void,
|
|
584
|
-
...partial,
|
|
585
|
-
rpcHandlers: sanitizeRpcs(opts.rpcs, partial.rpcHandlers),
|
|
586
|
-
})),
|
|
587
|
-
),
|
|
624
|
+
pipe() {
|
|
625
|
+
// eslint-disable-next-line prefer-rest-params
|
|
626
|
+
return Pipeable.pipeArguments(this, arguments);
|
|
627
|
+
},
|
|
588
628
|
};
|
|
589
629
|
};
|
|
590
630
|
|
|
631
|
+
/**
|
|
632
|
+
* Attaches the handler factory to a durable operation definition.
|
|
633
|
+
* Dual API: can be called directly or used in a pipe.
|
|
634
|
+
*/
|
|
635
|
+
export const withDurableHandler: {
|
|
636
|
+
<Def extends DurableDefinition.Any>(
|
|
637
|
+
create: DurableDefinition.Create<Def>,
|
|
638
|
+
): (def: Def) => DurableDefinition.WithHandler<Def>;
|
|
639
|
+
<Def extends DurableDefinition.Any>(
|
|
640
|
+
def: Def,
|
|
641
|
+
create: DurableDefinition.Create<Def>,
|
|
642
|
+
): DurableDefinition.WithHandler<Def>;
|
|
643
|
+
} = Function.dual(2, <Def extends DurableDefinition.Any>(def: Def, create: DurableDefinition.Create<Def>) =>
|
|
644
|
+
attachDurableHandler(def, create),
|
|
645
|
+
);
|
|
646
|
+
|
|
647
|
+
const attachDurableHandler = <Def extends DurableDefinition.Any>(
|
|
648
|
+
def: Def,
|
|
649
|
+
create: DurableDefinition.Create<Def>,
|
|
650
|
+
): DurableDefinition.WithHandler<Def> => ({
|
|
651
|
+
...def,
|
|
652
|
+
[DurableTypeId]: {} as any,
|
|
653
|
+
create: (ctx) =>
|
|
654
|
+
create(ctx).pipe(
|
|
655
|
+
Effect.map((partial) => ({
|
|
656
|
+
onSpawn: () => Effect.void,
|
|
657
|
+
onInput: () => Effect.void,
|
|
658
|
+
onAlarm: () => Effect.void,
|
|
659
|
+
onChildEvent: () => Effect.void,
|
|
660
|
+
...partial,
|
|
661
|
+
rpcHandlers: sanitizeRpcs(def.rpcs, partial.rpcHandlers),
|
|
662
|
+
})),
|
|
663
|
+
),
|
|
664
|
+
});
|
|
665
|
+
|
|
591
666
|
// Returns `Context.Context<any>`: the runtime handler bag is stored untyped because
|
|
592
667
|
// `DurableHandler.rpcHandlers` is contravariant in `_Rpcs` (see design spec §4.4); the precise
|
|
593
|
-
// handler contract is enforced by `
|
|
668
|
+
// handler contract is enforced by `withDurableHandler`'s `create` parameter, not by this internal helper.
|
|
594
669
|
const sanitizeRpcs = <Rpcs extends Rpc.Any>(
|
|
595
670
|
defined: RpcGroup.RpcGroup<Rpcs> | undefined,
|
|
596
671
|
provided: Context.Context<Rpc.ToHandler<Rpcs>> | undefined,
|
|
@@ -936,9 +1011,9 @@ export interface InvokeOptions {
|
|
|
936
1011
|
*/
|
|
937
1012
|
conversation?: URI.URI;
|
|
938
1013
|
/**
|
|
939
|
-
*
|
|
1014
|
+
* Tracing metadata stamped on the process that runs the invocation.
|
|
940
1015
|
*/
|
|
941
|
-
tracing?:
|
|
1016
|
+
tracing?: Trace.Meta;
|
|
942
1017
|
|
|
943
1018
|
/**
|
|
944
1019
|
* Specifies the runtime environment for the operation.
|