@rivetkit/effect 0.0.0-06-09-refactor-rivetkit-split-workflow-context-into-workflowcontext-workflowstepcontext.e0c9540
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/Action.d.ts +104 -0
- package/dist/Action.d.ts.map +1 -0
- package/dist/Action.js +50 -0
- package/dist/Action.js.map +1 -0
- package/dist/Actor.d.ts +133 -0
- package/dist/Actor.d.ts.map +1 -0
- package/dist/Actor.js +104 -0
- package/dist/Actor.js.map +1 -0
- package/dist/Client.d.ts +31 -0
- package/dist/Client.d.ts.map +1 -0
- package/dist/Client.js +98 -0
- package/dist/Client.js.map +1 -0
- package/dist/Logger.d.ts +29 -0
- package/dist/Logger.d.ts.map +1 -0
- package/dist/Logger.js +31 -0
- package/dist/Logger.js.map +1 -0
- package/dist/Registry.d.ts +72 -0
- package/dist/Registry.d.ts.map +1 -0
- package/dist/Registry.js +125 -0
- package/dist/Registry.js.map +1 -0
- package/dist/RivetError.d.ts +438 -0
- package/dist/RivetError.d.ts.map +1 -0
- package/dist/RivetError.js +873 -0
- package/dist/RivetError.js.map +1 -0
- package/dist/State.d.ts +123 -0
- package/dist/State.d.ts.map +1 -0
- package/dist/State.js +104 -0
- package/dist/State.js.map +1 -0
- package/dist/internal/ActionDispatcher.d.ts +14 -0
- package/dist/internal/ActionDispatcher.d.ts.map +1 -0
- package/dist/internal/ActionDispatcher.js +100 -0
- package/dist/internal/ActionDispatcher.js.map +1 -0
- package/dist/internal/ActionErrorEnvelope.d.ts +11 -0
- package/dist/internal/ActionErrorEnvelope.d.ts.map +1 -0
- package/dist/internal/ActionErrorEnvelope.js +14 -0
- package/dist/internal/ActionErrorEnvelope.js.map +1 -0
- package/dist/internal/ActorInstanceManager.d.ts +28 -0
- package/dist/internal/ActorInstanceManager.d.ts.map +1 -0
- package/dist/internal/ActorInstanceManager.js +51 -0
- package/dist/internal/ActorInstanceManager.js.map +1 -0
- package/dist/internal/ActorStateAdapter.d.ts +18 -0
- package/dist/internal/ActorStateAdapter.d.ts.map +1 -0
- package/dist/internal/ActorStateAdapter.js +29 -0
- package/dist/internal/ActorStateAdapter.js.map +1 -0
- package/dist/internal/StateOptions.d.ts +12 -0
- package/dist/internal/StateOptions.d.ts.map +1 -0
- package/dist/internal/StateOptions.js +2 -0
- package/dist/internal/StateOptions.js.map +1 -0
- package/dist/internal/logging.d.ts +23 -0
- package/dist/internal/logging.d.ts.map +1 -0
- package/dist/internal/logging.js +162 -0
- package/dist/internal/logging.js.map +1 -0
- package/dist/internal/tracing.d.ts +23 -0
- package/dist/internal/tracing.d.ts.map +1 -0
- package/dist/internal/tracing.js +30 -0
- package/dist/internal/tracing.js.map +1 -0
- package/dist/internal/utils.d.ts +7 -0
- package/dist/internal/utils.d.ts.map +1 -0
- package/dist/internal/utils.js +7 -0
- package/dist/internal/utils.js.map +1 -0
- package/dist/mod.d.ts +8 -0
- package/dist/mod.d.ts.map +1 -0
- package/dist/mod.js +8 -0
- package/dist/mod.js.map +1 -0
- package/package.json +46 -0
- package/src/Action.ts +231 -0
- package/src/Actor.test-d.ts +603 -0
- package/src/Actor.test.ts +206 -0
- package/src/Actor.ts +550 -0
- package/src/Client.test.ts +210 -0
- package/src/Client.ts +216 -0
- package/src/Logger.ts +43 -0
- package/src/Registry.test-d.ts +126 -0
- package/src/Registry.test.ts +411 -0
- package/src/Registry.ts +243 -0
- package/src/RivetError.test.ts +188 -0
- package/src/RivetError.ts +1044 -0
- package/src/State.test.ts +181 -0
- package/src/State.ts +224 -0
- package/src/internal/ActionDispatcher.ts +192 -0
- package/src/internal/ActionErrorEnvelope.ts +19 -0
- package/src/internal/ActorInstanceManager.ts +143 -0
- package/src/internal/ActorStateAdapter.ts +88 -0
- package/src/internal/StateOptions.ts +17 -0
- package/src/internal/logging.test.ts +288 -0
- package/src/internal/logging.ts +237 -0
- package/src/internal/tracing.ts +42 -0
- package/src/internal/utils.ts +12 -0
- package/src/mod.ts +7 -0
|
@@ -0,0 +1,603 @@
|
|
|
1
|
+
import { Action, Actor, Client, type State } from "@rivetkit/effect";
|
|
2
|
+
import {
|
|
3
|
+
Context,
|
|
4
|
+
Effect,
|
|
5
|
+
type Layer,
|
|
6
|
+
Schema,
|
|
7
|
+
SchemaTransformation,
|
|
8
|
+
} from "effect";
|
|
9
|
+
import type { RawAccess } from "rivetkit/db";
|
|
10
|
+
import { db } from "rivetkit/db";
|
|
11
|
+
import { describe, expectTypeOf, it, test } from "@effect/vitest";
|
|
12
|
+
|
|
13
|
+
class SomeDep extends Context.Service<SomeDep, { readonly x: number }>()(
|
|
14
|
+
"SomeDep",
|
|
15
|
+
) {}
|
|
16
|
+
|
|
17
|
+
const Ping = Action.make("Ping", {
|
|
18
|
+
success: Schema.Number,
|
|
19
|
+
error: Schema.String,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const TestActor = Actor.make("TestActor", {
|
|
23
|
+
actions: [Ping],
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const TestState = {
|
|
27
|
+
schema: Schema.Struct({
|
|
28
|
+
count: Schema.Number,
|
|
29
|
+
}),
|
|
30
|
+
initialValue: () => ({ count: 0 }),
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const TagsCsv = Schema.String.pipe(
|
|
34
|
+
Schema.decodeTo(
|
|
35
|
+
Schema.Array(Schema.String),
|
|
36
|
+
SchemaTransformation.transform({
|
|
37
|
+
decode: (s: string): ReadonlyArray<string> => s.split(","),
|
|
38
|
+
encode: (arr: ReadonlyArray<string>) => arr.join(","),
|
|
39
|
+
}),
|
|
40
|
+
),
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
const ServiceDependentNumber = Schema.Number.pipe(
|
|
44
|
+
Schema.decodeTo(
|
|
45
|
+
Schema.Number,
|
|
46
|
+
SchemaTransformation.transformOrFail({
|
|
47
|
+
decode: (n: number) =>
|
|
48
|
+
Effect.gen(function* () {
|
|
49
|
+
const dep = yield* SomeDep;
|
|
50
|
+
return n + dep.x;
|
|
51
|
+
}),
|
|
52
|
+
encode: (n: number) =>
|
|
53
|
+
Effect.gen(function* () {
|
|
54
|
+
const dep = yield* SomeDep;
|
|
55
|
+
return n - dep.x;
|
|
56
|
+
}),
|
|
57
|
+
}),
|
|
58
|
+
),
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
class ServiceDependentError extends Schema.TaggedErrorClass<ServiceDependentError>()(
|
|
62
|
+
"ServiceDependentError",
|
|
63
|
+
{
|
|
64
|
+
limit: ServiceDependentNumber,
|
|
65
|
+
message: Schema.String,
|
|
66
|
+
},
|
|
67
|
+
) {}
|
|
68
|
+
|
|
69
|
+
const ServiceDependentAction = Action.make("ServiceDependentAction", {
|
|
70
|
+
payload: { amount: ServiceDependentNumber },
|
|
71
|
+
success: ServiceDependentNumber,
|
|
72
|
+
error: ServiceDependentError,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const ServiceDependentActor = Actor.make("ServiceDependentActor", {
|
|
76
|
+
actions: [ServiceDependentAction],
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
const TransformedState = {
|
|
80
|
+
schema: Schema.Struct({
|
|
81
|
+
when: Schema.DateFromString,
|
|
82
|
+
url: Schema.URLFromString,
|
|
83
|
+
id: Schema.BigIntFromString,
|
|
84
|
+
bytes: Schema.Uint8ArrayFromBase64,
|
|
85
|
+
tags: TagsCsv,
|
|
86
|
+
history: Schema.Array(
|
|
87
|
+
Schema.Struct({
|
|
88
|
+
at: Schema.DateFromString,
|
|
89
|
+
payload: Schema.Uint8ArrayFromBase64,
|
|
90
|
+
}),
|
|
91
|
+
),
|
|
92
|
+
}),
|
|
93
|
+
initialValue: () => ({
|
|
94
|
+
when: new Date("2024-01-15T10:30:00.000Z"),
|
|
95
|
+
url: new URL("https://rivet.dev/docs"),
|
|
96
|
+
id: 1n,
|
|
97
|
+
bytes: new Uint8Array([1, 2, 3]),
|
|
98
|
+
tags: ["alpha", "beta"],
|
|
99
|
+
history: [
|
|
100
|
+
{
|
|
101
|
+
at: new Date("2024-01-15T10:30:00.000Z"),
|
|
102
|
+
payload: new Uint8Array([4, 5, 6]),
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
}),
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
describe("Actor.make", () => {
|
|
109
|
+
test("preserves the name literal", () => {
|
|
110
|
+
expectTypeOf(TestActor.name).toEqualTypeOf<"TestActor">();
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
describe("Actor.make(...).toLayer", () => {
|
|
115
|
+
test("is a function", () => {
|
|
116
|
+
expectTypeOf(TestActor.toLayer).toBeFunction();
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test("accepts a plain action handlers object", () => {
|
|
120
|
+
expectTypeOf(TestActor.toLayer).toBeCallableWith({
|
|
121
|
+
Ping: () => Effect.succeed(0),
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test("accepts an effect of action handlers", () => {
|
|
126
|
+
expectTypeOf(TestActor.toLayer).toBeCallableWith(
|
|
127
|
+
Effect.gen(function* () {
|
|
128
|
+
return {
|
|
129
|
+
Ping: () => Effect.succeed(0),
|
|
130
|
+
};
|
|
131
|
+
}),
|
|
132
|
+
);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test("accepts a function returning a plain action handlers object", () => {
|
|
136
|
+
expectTypeOf(TestActor.toLayer).toBeCallableWith(
|
|
137
|
+
(_wakeOptions: any) => ({
|
|
138
|
+
Ping: () => Effect.succeed(0),
|
|
139
|
+
}),
|
|
140
|
+
);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
test("wake options omit state without a configured state type", () => {
|
|
144
|
+
TestActor.toLayer((wakeOptions) => {
|
|
145
|
+
// @ts-expect-error: stateless actors do not expose wakeOptions.state
|
|
146
|
+
wakeOptions.state;
|
|
147
|
+
expectTypeOf(
|
|
148
|
+
wakeOptions.rawRivetkitContext.state,
|
|
149
|
+
).toEqualTypeOf<never>();
|
|
150
|
+
|
|
151
|
+
return {
|
|
152
|
+
Ping: () => Effect.succeed(0),
|
|
153
|
+
};
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
TestActor.toLayer((wakeOptions) => {
|
|
157
|
+
// @ts-expect-error: actors without a state option do not expose wakeOptions.state
|
|
158
|
+
wakeOptions.state;
|
|
159
|
+
|
|
160
|
+
expectTypeOf(
|
|
161
|
+
wakeOptions.rawRivetkitContext.state,
|
|
162
|
+
).toEqualTypeOf<never>();
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
Ping: () => Effect.succeed(0),
|
|
166
|
+
};
|
|
167
|
+
}, {});
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
test("wake options carry the configured state type", () => {
|
|
171
|
+
TestActor.toLayer(
|
|
172
|
+
(wakeOptions) => {
|
|
173
|
+
expectTypeOf(wakeOptions.state).toEqualTypeOf<
|
|
174
|
+
State.State<{ readonly count: number }, Schema.SchemaError>
|
|
175
|
+
>();
|
|
176
|
+
|
|
177
|
+
return {
|
|
178
|
+
Ping: () => Effect.succeed(0),
|
|
179
|
+
};
|
|
180
|
+
},
|
|
181
|
+
{ state: TestState },
|
|
182
|
+
);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
test("wake options carry the transformed state type", () => {
|
|
186
|
+
TestActor.toLayer(
|
|
187
|
+
(wakeOptions) => {
|
|
188
|
+
expectTypeOf(wakeOptions.state).toEqualTypeOf<
|
|
189
|
+
State.State<
|
|
190
|
+
{
|
|
191
|
+
readonly when: Date;
|
|
192
|
+
readonly url: URL;
|
|
193
|
+
readonly id: bigint;
|
|
194
|
+
readonly bytes: Uint8Array;
|
|
195
|
+
readonly tags: ReadonlyArray<string>;
|
|
196
|
+
readonly history: ReadonlyArray<{
|
|
197
|
+
readonly at: Date;
|
|
198
|
+
readonly payload: Uint8Array;
|
|
199
|
+
}>;
|
|
200
|
+
},
|
|
201
|
+
Schema.SchemaError
|
|
202
|
+
>
|
|
203
|
+
>();
|
|
204
|
+
|
|
205
|
+
return {
|
|
206
|
+
Ping: () => Effect.succeed(0),
|
|
207
|
+
};
|
|
208
|
+
},
|
|
209
|
+
{ state: TransformedState },
|
|
210
|
+
);
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
test("wake options carry the raw RivetKit context with the encoded configured state type", () => {
|
|
214
|
+
TestActor.toLayer(
|
|
215
|
+
(wakeOptions) => {
|
|
216
|
+
expectTypeOf(
|
|
217
|
+
wakeOptions.rawRivetkitContext.state,
|
|
218
|
+
).toEqualTypeOf<{ readonly count: number }>();
|
|
219
|
+
|
|
220
|
+
return {
|
|
221
|
+
Ping: () => Effect.succeed(0),
|
|
222
|
+
};
|
|
223
|
+
},
|
|
224
|
+
{ state: TestState },
|
|
225
|
+
);
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
test("wake options carry the raw RivetKit context with the encoded transformed state type", () => {
|
|
229
|
+
TestActor.toLayer(
|
|
230
|
+
(wakeOptions) => {
|
|
231
|
+
expectTypeOf(
|
|
232
|
+
wakeOptions.rawRivetkitContext.state,
|
|
233
|
+
).toEqualTypeOf<{
|
|
234
|
+
readonly when: string;
|
|
235
|
+
readonly url: string;
|
|
236
|
+
readonly id: string;
|
|
237
|
+
readonly bytes: string;
|
|
238
|
+
readonly tags: string;
|
|
239
|
+
readonly history: ReadonlyArray<{
|
|
240
|
+
readonly at: string;
|
|
241
|
+
readonly payload: string;
|
|
242
|
+
}>;
|
|
243
|
+
}>();
|
|
244
|
+
|
|
245
|
+
return {
|
|
246
|
+
Ping: () => Effect.succeed(0),
|
|
247
|
+
};
|
|
248
|
+
},
|
|
249
|
+
{ state: TransformedState },
|
|
250
|
+
);
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
test("wake options carry the configured database client type", () => {
|
|
254
|
+
TestActor.toLayer(
|
|
255
|
+
(wakeOptions) => {
|
|
256
|
+
expectTypeOf(
|
|
257
|
+
wakeOptions.rawRivetkitContext.db,
|
|
258
|
+
).toEqualTypeOf<RawAccess>();
|
|
259
|
+
|
|
260
|
+
return {
|
|
261
|
+
Ping: () => Effect.succeed(0),
|
|
262
|
+
};
|
|
263
|
+
},
|
|
264
|
+
{ db: db() },
|
|
265
|
+
);
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
test("accepts a function returning an effect of action handlers", () => {
|
|
269
|
+
expectTypeOf(TestActor.toLayer).toBeCallableWith((_wakeOptions: any) =>
|
|
270
|
+
Effect.gen(function* () {
|
|
271
|
+
return {
|
|
272
|
+
Ping: () => Effect.succeed(0),
|
|
273
|
+
};
|
|
274
|
+
}),
|
|
275
|
+
);
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
test("accepts an effect that resolves to a wake function", () => {
|
|
279
|
+
expectTypeOf(TestActor.toLayer).toBeCallableWith(
|
|
280
|
+
Effect.gen(function* () {
|
|
281
|
+
// Allow for initialization logic before the per-entity wake function is called
|
|
282
|
+
|
|
283
|
+
return (_wakeOptions: any) =>
|
|
284
|
+
Effect.gen(function* () {
|
|
285
|
+
return {
|
|
286
|
+
Ping: () => Effect.succeed(0),
|
|
287
|
+
};
|
|
288
|
+
});
|
|
289
|
+
}),
|
|
290
|
+
);
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
test("accepts an Effect.fn returning action handlers", () => {
|
|
294
|
+
expectTypeOf(TestActor.toLayer).toBeCallableWith(
|
|
295
|
+
Effect.fn("wake")(function* (_wakeOptions) {
|
|
296
|
+
return {
|
|
297
|
+
Ping: () => Effect.succeed(0),
|
|
298
|
+
};
|
|
299
|
+
}),
|
|
300
|
+
);
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
test("returns a Layer", () => {
|
|
304
|
+
expectTypeOf(TestActor.toLayer).returns.toExtend<Layer.Any>();
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
test("action handler's envelope is typed against the action", () => {
|
|
308
|
+
TestActor.toLayer({
|
|
309
|
+
Ping: (envelope) => {
|
|
310
|
+
expectTypeOf(envelope._tag).toEqualTypeOf<"Ping">();
|
|
311
|
+
expectTypeOf(envelope.action).toExtend<Action.Any>();
|
|
312
|
+
return Effect.succeed(0);
|
|
313
|
+
},
|
|
314
|
+
});
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
test("action handler return success is type checked", () => {
|
|
318
|
+
// Plain action handlers object.
|
|
319
|
+
expectTypeOf(TestActor.toLayer).toBeCallableWith({
|
|
320
|
+
Ping: () => Effect.succeed(0),
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
TestActor.toLayer({
|
|
324
|
+
// @ts-expect-error: Ping must return the declared number success type.
|
|
325
|
+
Ping: () => Effect.succeed("not a number"),
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
// Effect of action handlers.
|
|
329
|
+
expectTypeOf(TestActor.toLayer).toBeCallableWith(
|
|
330
|
+
Effect.gen(function* () {
|
|
331
|
+
return {
|
|
332
|
+
Ping: () => Effect.succeed(0),
|
|
333
|
+
};
|
|
334
|
+
}),
|
|
335
|
+
);
|
|
336
|
+
|
|
337
|
+
TestActor.toLayer(
|
|
338
|
+
// @ts-expect-error: Ping must return the declared number success type.
|
|
339
|
+
Effect.gen(function* () {
|
|
340
|
+
return {
|
|
341
|
+
Ping: () => Effect.succeed("not a number"),
|
|
342
|
+
};
|
|
343
|
+
}),
|
|
344
|
+
);
|
|
345
|
+
|
|
346
|
+
// Function returning a plain action handlers object.
|
|
347
|
+
expectTypeOf(TestActor.toLayer).toBeCallableWith(() => ({
|
|
348
|
+
Ping: () => Effect.succeed(0),
|
|
349
|
+
}));
|
|
350
|
+
|
|
351
|
+
// @ts-expect-error: Ping must return the declared number success type.
|
|
352
|
+
TestActor.toLayer(() => ({
|
|
353
|
+
Ping: () => Effect.succeed("not a number"),
|
|
354
|
+
}));
|
|
355
|
+
|
|
356
|
+
// Function returning an effect of action handlers.
|
|
357
|
+
expectTypeOf(TestActor.toLayer).toBeCallableWith(() =>
|
|
358
|
+
Effect.gen(function* () {
|
|
359
|
+
return {
|
|
360
|
+
Ping: () => Effect.succeed(0),
|
|
361
|
+
};
|
|
362
|
+
}),
|
|
363
|
+
);
|
|
364
|
+
|
|
365
|
+
// @ts-expect-error: Ping must return the declared number success type.
|
|
366
|
+
TestActor.toLayer(() =>
|
|
367
|
+
Effect.gen(function* () {
|
|
368
|
+
return {
|
|
369
|
+
Ping: () => Effect.succeed("not a number"),
|
|
370
|
+
};
|
|
371
|
+
}),
|
|
372
|
+
);
|
|
373
|
+
|
|
374
|
+
// Effect that resolves to a wake function.
|
|
375
|
+
expectTypeOf(TestActor.toLayer).toBeCallableWith(
|
|
376
|
+
Effect.gen(function* () {
|
|
377
|
+
return () => ({
|
|
378
|
+
Ping: () => Effect.succeed(0),
|
|
379
|
+
});
|
|
380
|
+
}),
|
|
381
|
+
);
|
|
382
|
+
|
|
383
|
+
TestActor.toLayer(
|
|
384
|
+
// @ts-expect-error: Ping must return the declared number success type.
|
|
385
|
+
Effect.gen(function* () {
|
|
386
|
+
return () => ({
|
|
387
|
+
Ping: () => Effect.succeed("not a number"),
|
|
388
|
+
});
|
|
389
|
+
}),
|
|
390
|
+
);
|
|
391
|
+
|
|
392
|
+
// Effect.fn returning action handlers.
|
|
393
|
+
expectTypeOf(TestActor.toLayer).toBeCallableWith(
|
|
394
|
+
Effect.fn("wake")(function* () {
|
|
395
|
+
return {
|
|
396
|
+
Ping: () => Effect.succeed(0),
|
|
397
|
+
};
|
|
398
|
+
}),
|
|
399
|
+
);
|
|
400
|
+
|
|
401
|
+
TestActor.toLayer(
|
|
402
|
+
// @ts-expect-error: Ping must return the declared number success type.
|
|
403
|
+
Effect.fn("wake")(function* () {
|
|
404
|
+
return {
|
|
405
|
+
Ping: () => Effect.succeed("not a number"),
|
|
406
|
+
};
|
|
407
|
+
}),
|
|
408
|
+
);
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
test("action handler return error is type checked", () => {
|
|
412
|
+
// Plain action handlers object.
|
|
413
|
+
expectTypeOf(TestActor.toLayer).toBeCallableWith({
|
|
414
|
+
Ping: () => Effect.succeed(0),
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
TestActor.toLayer({
|
|
418
|
+
// @ts-expect-error: Ping can only fail with its declared action error type.
|
|
419
|
+
// @effect-diagnostics effect/missingEffectError:off
|
|
420
|
+
Ping: () => Effect.fail(1),
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
// Effect of action handlers.
|
|
424
|
+
expectTypeOf(TestActor.toLayer).toBeCallableWith(
|
|
425
|
+
Effect.gen(function* () {
|
|
426
|
+
return {
|
|
427
|
+
Ping: () => Effect.succeed(0),
|
|
428
|
+
};
|
|
429
|
+
}),
|
|
430
|
+
);
|
|
431
|
+
|
|
432
|
+
TestActor.toLayer(
|
|
433
|
+
// @ts-expect-error: Ping can only fail with its declared action error type.
|
|
434
|
+
Effect.gen(function* () {
|
|
435
|
+
return {
|
|
436
|
+
// @effect-diagnostics effect/missingEffectError:off
|
|
437
|
+
Ping: () => Effect.fail(1),
|
|
438
|
+
};
|
|
439
|
+
}),
|
|
440
|
+
);
|
|
441
|
+
|
|
442
|
+
// Function returning a plain action handlers object.
|
|
443
|
+
expectTypeOf(TestActor.toLayer).toBeCallableWith(() => ({
|
|
444
|
+
Ping: () => Effect.succeed(0),
|
|
445
|
+
}));
|
|
446
|
+
|
|
447
|
+
// @ts-expect-error: Ping can only fail with its declared action error type.
|
|
448
|
+
TestActor.toLayer(() => ({
|
|
449
|
+
// @effect-diagnostics effect/missingEffectError:off
|
|
450
|
+
Ping: () => Effect.fail(1),
|
|
451
|
+
}));
|
|
452
|
+
|
|
453
|
+
// Function returning an effect of action handlers.
|
|
454
|
+
expectTypeOf(TestActor.toLayer).toBeCallableWith(() =>
|
|
455
|
+
Effect.gen(function* () {
|
|
456
|
+
return {
|
|
457
|
+
Ping: () => Effect.succeed(0),
|
|
458
|
+
};
|
|
459
|
+
}),
|
|
460
|
+
);
|
|
461
|
+
|
|
462
|
+
// @ts-expect-error: Ping can only fail with its declared action error type.
|
|
463
|
+
TestActor.toLayer(() =>
|
|
464
|
+
Effect.gen(function* () {
|
|
465
|
+
return {
|
|
466
|
+
// @effect-diagnostics effect/missingEffectError:off
|
|
467
|
+
Ping: () => Effect.fail(1),
|
|
468
|
+
};
|
|
469
|
+
}),
|
|
470
|
+
);
|
|
471
|
+
|
|
472
|
+
// Effect that resolves to a wake function.
|
|
473
|
+
expectTypeOf(TestActor.toLayer).toBeCallableWith(
|
|
474
|
+
Effect.gen(function* () {
|
|
475
|
+
return () => ({
|
|
476
|
+
Ping: () => Effect.succeed(0),
|
|
477
|
+
});
|
|
478
|
+
}),
|
|
479
|
+
);
|
|
480
|
+
|
|
481
|
+
TestActor.toLayer(
|
|
482
|
+
// @ts-expect-error: Ping can only fail with its declared action error type.
|
|
483
|
+
Effect.gen(function* () {
|
|
484
|
+
return () => ({
|
|
485
|
+
// @effect-diagnostics effect/missingEffectError:off
|
|
486
|
+
Ping: () => Effect.fail(1),
|
|
487
|
+
});
|
|
488
|
+
}),
|
|
489
|
+
);
|
|
490
|
+
|
|
491
|
+
// Effect.fn returning action handlers.
|
|
492
|
+
expectTypeOf(TestActor.toLayer).toBeCallableWith(
|
|
493
|
+
Effect.fn("wake")(function* () {
|
|
494
|
+
return {
|
|
495
|
+
Ping: () => Effect.succeed(0),
|
|
496
|
+
};
|
|
497
|
+
}),
|
|
498
|
+
);
|
|
499
|
+
|
|
500
|
+
TestActor.toLayer(
|
|
501
|
+
// @ts-expect-error: Ping can only fail with its declared action error type.
|
|
502
|
+
Effect.fn("wake")(function* () {
|
|
503
|
+
return {
|
|
504
|
+
// @effect-diagnostics effect/missingEffectError:off
|
|
505
|
+
Ping: () => Effect.fail(1),
|
|
506
|
+
};
|
|
507
|
+
}),
|
|
508
|
+
);
|
|
509
|
+
});
|
|
510
|
+
|
|
511
|
+
test("missing action handler is rejected", () => {
|
|
512
|
+
// @ts-expect-error: Ping handler is required
|
|
513
|
+
TestActor.toLayer({});
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
test.todo("unknown action handler key is rejected", () => {
|
|
517
|
+
TestActor.toLayer({
|
|
518
|
+
Ping: () => Effect.succeed(0),
|
|
519
|
+
// TODO: toLayer should reject unknown action handler keys
|
|
520
|
+
Unknown: () => Effect.void,
|
|
521
|
+
});
|
|
522
|
+
});
|
|
523
|
+
|
|
524
|
+
test.todo("wake-effect requirements surface in the Layer", () => {
|
|
525
|
+
const layer = TestActor.toLayer(
|
|
526
|
+
Effect.gen(function* () {
|
|
527
|
+
yield* SomeDep;
|
|
528
|
+
return { Ping: () => Effect.succeed(0) };
|
|
529
|
+
}),
|
|
530
|
+
);
|
|
531
|
+
type Reqs =
|
|
532
|
+
typeof layer extends Layer.Layer<any, any, infer R> ? R : never;
|
|
533
|
+
// @ts-expect-error: TODO - expectTypeOf<T>() no-arg generic form not resolving
|
|
534
|
+
expectTypeOf<SomeDep>().toExtend<Reqs>();
|
|
535
|
+
});
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
describe("Actor.make(...).of", () => {
|
|
539
|
+
test("preserves the action handlers object type", () => {
|
|
540
|
+
const handlers = {
|
|
541
|
+
Ping: () => Effect.succeed(0),
|
|
542
|
+
};
|
|
543
|
+
|
|
544
|
+
expectTypeOf(TestActor.of(handlers)).toEqualTypeOf<typeof handlers>();
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
test("action handler's envelope is typed against the action", () => {
|
|
548
|
+
TestActor.of({
|
|
549
|
+
Ping: (envelope) => {
|
|
550
|
+
expectTypeOf(envelope._tag).toEqualTypeOf<"Ping">();
|
|
551
|
+
expectTypeOf(envelope.action).toEqualTypeOf<typeof Ping>();
|
|
552
|
+
return Effect.succeed(0);
|
|
553
|
+
},
|
|
554
|
+
});
|
|
555
|
+
});
|
|
556
|
+
|
|
557
|
+
test("action handler return success is type checked", () => {
|
|
558
|
+
expectTypeOf(TestActor.of).toBeCallableWith({
|
|
559
|
+
Ping: () => Effect.succeed(0),
|
|
560
|
+
});
|
|
561
|
+
|
|
562
|
+
TestActor.of({
|
|
563
|
+
// @ts-expect-error: Ping must return the declared number success type.
|
|
564
|
+
Ping: () => Effect.succeed("not a number"),
|
|
565
|
+
});
|
|
566
|
+
});
|
|
567
|
+
|
|
568
|
+
test("action handler return error is type checked", () => {
|
|
569
|
+
expectTypeOf(TestActor.of).toBeCallableWith({
|
|
570
|
+
Ping: () => Effect.succeed(0),
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
TestActor.of({
|
|
574
|
+
// @ts-expect-error: Ping can only fail with its declared action error type.
|
|
575
|
+
// @effect-diagnostics effect/missingEffectError:off
|
|
576
|
+
Ping: () => Effect.fail(1),
|
|
577
|
+
});
|
|
578
|
+
});
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
describe("Actor.make(...).client", () => {
|
|
582
|
+
test("yields a typed Accessor", () => {
|
|
583
|
+
expectTypeOf(TestActor.client).toEqualTypeOf<
|
|
584
|
+
Effect.Effect<
|
|
585
|
+
Actor.Accessor<(typeof TestActor.actions)[number]>,
|
|
586
|
+
never,
|
|
587
|
+
Client.Client
|
|
588
|
+
>
|
|
589
|
+
>();
|
|
590
|
+
});
|
|
591
|
+
|
|
592
|
+
it.effect("handle calls require client-side schema services", () =>
|
|
593
|
+
Effect.gen(function* () {
|
|
594
|
+
const actor = (yield* ServiceDependentActor.client).getOrCreate(
|
|
595
|
+
"t-service-dependent",
|
|
596
|
+
);
|
|
597
|
+
const actionEffect = actor.ServiceDependentAction({ amount: 10 });
|
|
598
|
+
type ActionClientServices = Effect.Services<typeof actionEffect>;
|
|
599
|
+
|
|
600
|
+
expectTypeOf<SomeDep>().toExtend<ActionClientServices>();
|
|
601
|
+
}).pipe(Effect.provide(Client.layer())),
|
|
602
|
+
);
|
|
603
|
+
});
|