@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.
Files changed (89) hide show
  1. package/dist/Action.d.ts +104 -0
  2. package/dist/Action.d.ts.map +1 -0
  3. package/dist/Action.js +50 -0
  4. package/dist/Action.js.map +1 -0
  5. package/dist/Actor.d.ts +133 -0
  6. package/dist/Actor.d.ts.map +1 -0
  7. package/dist/Actor.js +104 -0
  8. package/dist/Actor.js.map +1 -0
  9. package/dist/Client.d.ts +31 -0
  10. package/dist/Client.d.ts.map +1 -0
  11. package/dist/Client.js +98 -0
  12. package/dist/Client.js.map +1 -0
  13. package/dist/Logger.d.ts +29 -0
  14. package/dist/Logger.d.ts.map +1 -0
  15. package/dist/Logger.js +31 -0
  16. package/dist/Logger.js.map +1 -0
  17. package/dist/Registry.d.ts +72 -0
  18. package/dist/Registry.d.ts.map +1 -0
  19. package/dist/Registry.js +125 -0
  20. package/dist/Registry.js.map +1 -0
  21. package/dist/RivetError.d.ts +438 -0
  22. package/dist/RivetError.d.ts.map +1 -0
  23. package/dist/RivetError.js +873 -0
  24. package/dist/RivetError.js.map +1 -0
  25. package/dist/State.d.ts +123 -0
  26. package/dist/State.d.ts.map +1 -0
  27. package/dist/State.js +104 -0
  28. package/dist/State.js.map +1 -0
  29. package/dist/internal/ActionDispatcher.d.ts +14 -0
  30. package/dist/internal/ActionDispatcher.d.ts.map +1 -0
  31. package/dist/internal/ActionDispatcher.js +100 -0
  32. package/dist/internal/ActionDispatcher.js.map +1 -0
  33. package/dist/internal/ActionErrorEnvelope.d.ts +11 -0
  34. package/dist/internal/ActionErrorEnvelope.d.ts.map +1 -0
  35. package/dist/internal/ActionErrorEnvelope.js +14 -0
  36. package/dist/internal/ActionErrorEnvelope.js.map +1 -0
  37. package/dist/internal/ActorInstanceManager.d.ts +28 -0
  38. package/dist/internal/ActorInstanceManager.d.ts.map +1 -0
  39. package/dist/internal/ActorInstanceManager.js +51 -0
  40. package/dist/internal/ActorInstanceManager.js.map +1 -0
  41. package/dist/internal/ActorStateAdapter.d.ts +18 -0
  42. package/dist/internal/ActorStateAdapter.d.ts.map +1 -0
  43. package/dist/internal/ActorStateAdapter.js +29 -0
  44. package/dist/internal/ActorStateAdapter.js.map +1 -0
  45. package/dist/internal/StateOptions.d.ts +12 -0
  46. package/dist/internal/StateOptions.d.ts.map +1 -0
  47. package/dist/internal/StateOptions.js +2 -0
  48. package/dist/internal/StateOptions.js.map +1 -0
  49. package/dist/internal/logging.d.ts +23 -0
  50. package/dist/internal/logging.d.ts.map +1 -0
  51. package/dist/internal/logging.js +162 -0
  52. package/dist/internal/logging.js.map +1 -0
  53. package/dist/internal/tracing.d.ts +23 -0
  54. package/dist/internal/tracing.d.ts.map +1 -0
  55. package/dist/internal/tracing.js +30 -0
  56. package/dist/internal/tracing.js.map +1 -0
  57. package/dist/internal/utils.d.ts +7 -0
  58. package/dist/internal/utils.d.ts.map +1 -0
  59. package/dist/internal/utils.js +7 -0
  60. package/dist/internal/utils.js.map +1 -0
  61. package/dist/mod.d.ts +8 -0
  62. package/dist/mod.d.ts.map +1 -0
  63. package/dist/mod.js +8 -0
  64. package/dist/mod.js.map +1 -0
  65. package/package.json +46 -0
  66. package/src/Action.ts +231 -0
  67. package/src/Actor.test-d.ts +603 -0
  68. package/src/Actor.test.ts +206 -0
  69. package/src/Actor.ts +550 -0
  70. package/src/Client.test.ts +210 -0
  71. package/src/Client.ts +216 -0
  72. package/src/Logger.ts +43 -0
  73. package/src/Registry.test-d.ts +126 -0
  74. package/src/Registry.test.ts +411 -0
  75. package/src/Registry.ts +243 -0
  76. package/src/RivetError.test.ts +188 -0
  77. package/src/RivetError.ts +1044 -0
  78. package/src/State.test.ts +181 -0
  79. package/src/State.ts +224 -0
  80. package/src/internal/ActionDispatcher.ts +192 -0
  81. package/src/internal/ActionErrorEnvelope.ts +19 -0
  82. package/src/internal/ActorInstanceManager.ts +143 -0
  83. package/src/internal/ActorStateAdapter.ts +88 -0
  84. package/src/internal/StateOptions.ts +17 -0
  85. package/src/internal/logging.test.ts +288 -0
  86. package/src/internal/logging.ts +237 -0
  87. package/src/internal/tracing.ts +42 -0
  88. package/src/internal/utils.ts +12 -0
  89. 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
+ });