@rivetkit/effect 0.0.0-main.879b6a2 → 0.0.0-main.b2d3b94
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/Actor.d.ts +2 -3
- package/dist/Actor.d.ts.map +1 -1
- package/dist/Actor.js +2 -2
- package/dist/Actor.js.map +1 -1
- package/dist/Client.d.ts.map +1 -1
- package/dist/Client.js +6 -4
- package/dist/Client.js.map +1 -1
- package/dist/Registry.d.ts +69 -7
- package/dist/Registry.d.ts.map +1 -1
- package/dist/Registry.js +93 -40
- package/dist/Registry.js.map +1 -1
- package/dist/RivetError.d.ts +45 -3
- package/dist/RivetError.d.ts.map +1 -1
- package/dist/RivetError.js +112 -0
- package/dist/RivetError.js.map +1 -1
- package/dist/RivetLogger.d.ts +41 -0
- package/dist/RivetLogger.d.ts.map +1 -0
- package/dist/RivetLogger.js +41 -0
- package/dist/RivetLogger.js.map +1 -0
- package/dist/State.d.ts +92 -56
- package/dist/State.d.ts.map +1 -1
- package/dist/State.js +51 -57
- package/dist/State.js.map +1 -1
- package/dist/internal/ActionDispatcher.d.ts.map +1 -1
- package/dist/internal/ActionDispatcher.js.map +1 -1
- package/dist/internal/ActorInstanceManager.d.ts.map +1 -1
- package/dist/internal/ActorInstanceManager.js +4 -4
- package/dist/internal/ActorInstanceManager.js.map +1 -1
- package/dist/internal/ActorStateAdapter.d.ts +1 -1
- package/dist/internal/ActorStateAdapter.d.ts.map +1 -1
- package/dist/internal/ActorStateAdapter.js +2 -7
- package/dist/internal/ActorStateAdapter.js.map +1 -1
- package/dist/internal/StateOptions.d.ts +1 -0
- package/dist/internal/StateOptions.d.ts.map +1 -1
- package/dist/internal/logging.d.ts +6 -7
- package/dist/internal/logging.d.ts.map +1 -1
- package/dist/internal/logging.js +78 -102
- package/dist/internal/logging.js.map +1 -1
- package/dist/mod.d.ts +1 -1
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +1 -1
- package/dist/mod.js.map +1 -1
- package/package.json +8 -2
- package/src/Actor.test-d.ts +38 -0
- package/src/Actor.test.ts +4 -1
- package/src/Actor.ts +29 -4
- package/src/Client.test.ts +22 -26
- package/src/Client.ts +6 -4
- package/src/Registry.test.ts +12 -23
- package/src/Registry.ts +131 -70
- package/src/RivetError.test.ts +11 -0
- package/src/RivetError.ts +119 -0
- package/src/RivetLogger.ts +60 -0
- package/src/State.test.ts +163 -4
- package/src/State.ts +293 -97
- package/src/internal/ActionDispatcher.ts +8 -11
- package/src/internal/ActorInstanceManager.ts +32 -38
- package/src/internal/ActorStateAdapter.ts +5 -11
- package/src/internal/StateOptions.ts +4 -0
- package/src/internal/logging.test.ts +107 -121
- package/src/internal/logging.ts +103 -143
- package/src/mod.ts +1 -1
- package/dist/Logger.d.ts +0 -29
- package/dist/Logger.d.ts.map +0 -1
- package/dist/Logger.js +0 -31
- package/dist/Logger.js.map +0 -1
- package/src/Logger.ts +0 -43
package/src/RivetError.ts
CHANGED
|
@@ -31,6 +31,9 @@ export class Forbidden extends Schema.TaggedErrorClass<Forbidden>(
|
|
|
31
31
|
get public() {
|
|
32
32
|
return this.cause.public;
|
|
33
33
|
}
|
|
34
|
+
get rayId() {
|
|
35
|
+
return this.cause.rayId;
|
|
36
|
+
}
|
|
34
37
|
get isRetryable(): boolean {
|
|
35
38
|
return false;
|
|
36
39
|
}
|
|
@@ -63,6 +66,9 @@ export class ActorNotFound extends Schema.TaggedErrorClass<ActorNotFound>(
|
|
|
63
66
|
get public() {
|
|
64
67
|
return this.cause.public;
|
|
65
68
|
}
|
|
69
|
+
get rayId() {
|
|
70
|
+
return this.cause.rayId;
|
|
71
|
+
}
|
|
66
72
|
get isRetryable(): boolean {
|
|
67
73
|
return false;
|
|
68
74
|
}
|
|
@@ -95,6 +101,9 @@ export class ActorStopping extends Schema.TaggedErrorClass<ActorStopping>(
|
|
|
95
101
|
get public() {
|
|
96
102
|
return this.cause.public;
|
|
97
103
|
}
|
|
104
|
+
get rayId() {
|
|
105
|
+
return this.cause.rayId;
|
|
106
|
+
}
|
|
98
107
|
get isRetryable(): boolean {
|
|
99
108
|
return true;
|
|
100
109
|
}
|
|
@@ -127,6 +136,9 @@ export class ActorRestarting extends Schema.TaggedErrorClass<ActorRestarting>(
|
|
|
127
136
|
get public() {
|
|
128
137
|
return this.cause.public;
|
|
129
138
|
}
|
|
139
|
+
get rayId() {
|
|
140
|
+
return this.cause.rayId;
|
|
141
|
+
}
|
|
130
142
|
get isRetryable(): boolean {
|
|
131
143
|
return true;
|
|
132
144
|
}
|
|
@@ -167,6 +179,9 @@ export class ActionNotFound extends Schema.TaggedErrorClass<ActionNotFound>(
|
|
|
167
179
|
get public() {
|
|
168
180
|
return this.cause.public;
|
|
169
181
|
}
|
|
182
|
+
get rayId() {
|
|
183
|
+
return this.cause.rayId;
|
|
184
|
+
}
|
|
170
185
|
get isRetryable(): boolean {
|
|
171
186
|
return false;
|
|
172
187
|
}
|
|
@@ -197,6 +212,9 @@ export class ActionTimedOut extends Schema.TaggedErrorClass<ActionTimedOut>(
|
|
|
197
212
|
get public() {
|
|
198
213
|
return this.cause.public;
|
|
199
214
|
}
|
|
215
|
+
get rayId() {
|
|
216
|
+
return this.cause.rayId;
|
|
217
|
+
}
|
|
200
218
|
get isRetryable(): boolean {
|
|
201
219
|
return true;
|
|
202
220
|
}
|
|
@@ -229,6 +247,9 @@ export class ActionAborted extends Schema.TaggedErrorClass<ActionAborted>(
|
|
|
229
247
|
get public() {
|
|
230
248
|
return this.cause.public;
|
|
231
249
|
}
|
|
250
|
+
get rayId() {
|
|
251
|
+
return this.cause.rayId;
|
|
252
|
+
}
|
|
232
253
|
get isRetryable(): boolean {
|
|
233
254
|
return false;
|
|
234
255
|
}
|
|
@@ -261,6 +282,9 @@ export class ActorOverloaded extends Schema.TaggedErrorClass<ActorOverloaded>(
|
|
|
261
282
|
get public() {
|
|
262
283
|
return this.cause.public;
|
|
263
284
|
}
|
|
285
|
+
get rayId() {
|
|
286
|
+
return this.cause.rayId;
|
|
287
|
+
}
|
|
264
288
|
get isRetryable(): boolean {
|
|
265
289
|
return true;
|
|
266
290
|
}
|
|
@@ -293,6 +317,9 @@ export class IncomingMessageTooLong extends Schema.TaggedErrorClass<IncomingMess
|
|
|
293
317
|
get public() {
|
|
294
318
|
return this.cause.public;
|
|
295
319
|
}
|
|
320
|
+
get rayId() {
|
|
321
|
+
return this.cause.rayId;
|
|
322
|
+
}
|
|
296
323
|
get isRetryable(): boolean {
|
|
297
324
|
return false;
|
|
298
325
|
}
|
|
@@ -325,6 +352,9 @@ export class OutgoingMessageTooLong extends Schema.TaggedErrorClass<OutgoingMess
|
|
|
325
352
|
get public() {
|
|
326
353
|
return this.cause.public;
|
|
327
354
|
}
|
|
355
|
+
get rayId() {
|
|
356
|
+
return this.cause.rayId;
|
|
357
|
+
}
|
|
328
358
|
get isRetryable(): boolean {
|
|
329
359
|
return false;
|
|
330
360
|
}
|
|
@@ -357,6 +387,9 @@ export class InvalidEncoding extends Schema.TaggedErrorClass<InvalidEncoding>(
|
|
|
357
387
|
get public() {
|
|
358
388
|
return this.cause.public;
|
|
359
389
|
}
|
|
390
|
+
get rayId() {
|
|
391
|
+
return this.cause.rayId;
|
|
392
|
+
}
|
|
360
393
|
get isRetryable(): boolean {
|
|
361
394
|
return false;
|
|
362
395
|
}
|
|
@@ -389,6 +422,9 @@ export class InvalidRequest extends Schema.TaggedErrorClass<InvalidRequest>(
|
|
|
389
422
|
get public() {
|
|
390
423
|
return this.cause.public;
|
|
391
424
|
}
|
|
425
|
+
get rayId() {
|
|
426
|
+
return this.cause.rayId;
|
|
427
|
+
}
|
|
392
428
|
get isRetryable(): boolean {
|
|
393
429
|
return false;
|
|
394
430
|
}
|
|
@@ -421,6 +457,44 @@ export class GuardActorReadyTimeout extends Schema.TaggedErrorClass<GuardActorRe
|
|
|
421
457
|
get public() {
|
|
422
458
|
return this.cause.public;
|
|
423
459
|
}
|
|
460
|
+
get rayId() {
|
|
461
|
+
return this.cause.rayId;
|
|
462
|
+
}
|
|
463
|
+
get isRetryable(): boolean {
|
|
464
|
+
return true;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
export class GuardActorWakeRetriesExceeded extends Schema.TaggedErrorClass<GuardActorWakeRetriesExceeded>(
|
|
469
|
+
`${ReasonTypeId}/GuardActorWakeRetriesExceeded`,
|
|
470
|
+
)("GuardActorWakeRetriesExceeded", {
|
|
471
|
+
cause: Schema.instanceOf(RivetkitErrors.RivetError),
|
|
472
|
+
}) {
|
|
473
|
+
readonly [ReasonTypeId] = ReasonTypeId;
|
|
474
|
+
override get message() {
|
|
475
|
+
return this.cause.message;
|
|
476
|
+
}
|
|
477
|
+
get group() {
|
|
478
|
+
return this.cause.group;
|
|
479
|
+
}
|
|
480
|
+
get code() {
|
|
481
|
+
return this.cause.code;
|
|
482
|
+
}
|
|
483
|
+
get metadata() {
|
|
484
|
+
return this.cause.metadata;
|
|
485
|
+
}
|
|
486
|
+
get actor() {
|
|
487
|
+
return this.cause.actor;
|
|
488
|
+
}
|
|
489
|
+
get statusCode() {
|
|
490
|
+
return this.cause.statusCode;
|
|
491
|
+
}
|
|
492
|
+
get public() {
|
|
493
|
+
return this.cause.public;
|
|
494
|
+
}
|
|
495
|
+
get rayId() {
|
|
496
|
+
return this.cause.rayId;
|
|
497
|
+
}
|
|
424
498
|
get isRetryable(): boolean {
|
|
425
499
|
return true;
|
|
426
500
|
}
|
|
@@ -453,6 +527,9 @@ export class GuardActorRunnerFailed extends Schema.TaggedErrorClass<GuardActorRu
|
|
|
453
527
|
get public() {
|
|
454
528
|
return this.cause.public;
|
|
455
529
|
}
|
|
530
|
+
get rayId() {
|
|
531
|
+
return this.cause.rayId;
|
|
532
|
+
}
|
|
456
533
|
get isRetryable(): boolean {
|
|
457
534
|
return false;
|
|
458
535
|
}
|
|
@@ -485,6 +562,9 @@ export class GuardServiceUnavailable extends Schema.TaggedErrorClass<GuardServic
|
|
|
485
562
|
get public() {
|
|
486
563
|
return this.cause.public;
|
|
487
564
|
}
|
|
565
|
+
get rayId() {
|
|
566
|
+
return this.cause.rayId;
|
|
567
|
+
}
|
|
488
568
|
get isRetryable(): boolean {
|
|
489
569
|
return true;
|
|
490
570
|
}
|
|
@@ -517,6 +597,9 @@ export class GuardActorStoppedWhileWaiting extends Schema.TaggedErrorClass<Guard
|
|
|
517
597
|
get public() {
|
|
518
598
|
return this.cause.public;
|
|
519
599
|
}
|
|
600
|
+
get rayId() {
|
|
601
|
+
return this.cause.rayId;
|
|
602
|
+
}
|
|
520
603
|
get isRetryable(): boolean {
|
|
521
604
|
return true;
|
|
522
605
|
}
|
|
@@ -549,6 +632,9 @@ export class GuardTunnelRequestAborted extends Schema.TaggedErrorClass<GuardTunn
|
|
|
549
632
|
get public() {
|
|
550
633
|
return this.cause.public;
|
|
551
634
|
}
|
|
635
|
+
get rayId() {
|
|
636
|
+
return this.cause.rayId;
|
|
637
|
+
}
|
|
552
638
|
get isRetryable(): boolean {
|
|
553
639
|
return true;
|
|
554
640
|
}
|
|
@@ -581,6 +667,9 @@ export class GuardTunnelMessageTimeout extends Schema.TaggedErrorClass<GuardTunn
|
|
|
581
667
|
get public() {
|
|
582
668
|
return this.cause.public;
|
|
583
669
|
}
|
|
670
|
+
get rayId() {
|
|
671
|
+
return this.cause.rayId;
|
|
672
|
+
}
|
|
584
673
|
get isRetryable(): boolean {
|
|
585
674
|
return true;
|
|
586
675
|
}
|
|
@@ -613,6 +702,9 @@ export class GuardTunnelResponseClosed extends Schema.TaggedErrorClass<GuardTunn
|
|
|
613
702
|
get public() {
|
|
614
703
|
return this.cause.public;
|
|
615
704
|
}
|
|
705
|
+
get rayId() {
|
|
706
|
+
return this.cause.rayId;
|
|
707
|
+
}
|
|
616
708
|
get isRetryable(): boolean {
|
|
617
709
|
return true;
|
|
618
710
|
}
|
|
@@ -645,6 +737,9 @@ export class GuardGatewayResponseStartTimeout extends Schema.TaggedErrorClass<Gu
|
|
|
645
737
|
get public() {
|
|
646
738
|
return this.cause.public;
|
|
647
739
|
}
|
|
740
|
+
get rayId() {
|
|
741
|
+
return this.cause.rayId;
|
|
742
|
+
}
|
|
648
743
|
get isRetryable(): boolean {
|
|
649
744
|
return true;
|
|
650
745
|
}
|
|
@@ -677,6 +772,9 @@ export class InternalError extends Schema.TaggedErrorClass<InternalError>(
|
|
|
677
772
|
get public() {
|
|
678
773
|
return this.cause.public;
|
|
679
774
|
}
|
|
775
|
+
get rayId() {
|
|
776
|
+
return this.cause.rayId;
|
|
777
|
+
}
|
|
680
778
|
get isRetryable(): boolean {
|
|
681
779
|
return false;
|
|
682
780
|
}
|
|
@@ -710,6 +808,9 @@ export class ActionErrorDecodeFailed extends Schema.TaggedErrorClass<ActionError
|
|
|
710
808
|
get public() {
|
|
711
809
|
return this.rivetError.public;
|
|
712
810
|
}
|
|
811
|
+
get rayId() {
|
|
812
|
+
return this.rivetError.rayId;
|
|
813
|
+
}
|
|
713
814
|
get isRetryable(): boolean {
|
|
714
815
|
return false;
|
|
715
816
|
}
|
|
@@ -750,6 +851,9 @@ export class UnknownUserError extends Schema.TaggedErrorClass<UnknownUserError>(
|
|
|
750
851
|
get public() {
|
|
751
852
|
return this.cause.public;
|
|
752
853
|
}
|
|
854
|
+
get rayId() {
|
|
855
|
+
return this.cause.rayId;
|
|
856
|
+
}
|
|
753
857
|
get isRetryable(): boolean {
|
|
754
858
|
return false;
|
|
755
859
|
}
|
|
@@ -797,6 +901,11 @@ export class UnknownError extends Schema.TaggedErrorClass<UnknownError>(
|
|
|
797
901
|
? this.cause.public
|
|
798
902
|
: undefined;
|
|
799
903
|
}
|
|
904
|
+
get rayId() {
|
|
905
|
+
return this.cause instanceof RivetkitErrors.RivetError
|
|
906
|
+
? this.cause.rayId
|
|
907
|
+
: undefined;
|
|
908
|
+
}
|
|
800
909
|
get isRetryable(): boolean {
|
|
801
910
|
return false;
|
|
802
911
|
}
|
|
@@ -816,6 +925,7 @@ export type RivetErrorReason =
|
|
|
816
925
|
| InvalidEncoding
|
|
817
926
|
| InvalidRequest
|
|
818
927
|
| GuardActorReadyTimeout
|
|
928
|
+
| GuardActorWakeRetriesExceeded
|
|
819
929
|
| GuardActorRunnerFailed
|
|
820
930
|
| GuardServiceUnavailable
|
|
821
931
|
| GuardActorStoppedWhileWaiting
|
|
@@ -843,6 +953,7 @@ export const RivetErrorReason: Schema.Union<
|
|
|
843
953
|
typeof InvalidEncoding,
|
|
844
954
|
typeof InvalidRequest,
|
|
845
955
|
typeof GuardActorReadyTimeout,
|
|
956
|
+
typeof GuardActorWakeRetriesExceeded,
|
|
846
957
|
typeof GuardActorRunnerFailed,
|
|
847
958
|
typeof GuardServiceUnavailable,
|
|
848
959
|
typeof GuardActorStoppedWhileWaiting,
|
|
@@ -869,6 +980,7 @@ export const RivetErrorReason: Schema.Union<
|
|
|
869
980
|
InvalidEncoding,
|
|
870
981
|
InvalidRequest,
|
|
871
982
|
GuardActorReadyTimeout,
|
|
983
|
+
GuardActorWakeRetriesExceeded,
|
|
872
984
|
GuardActorRunnerFailed,
|
|
873
985
|
GuardServiceUnavailable,
|
|
874
986
|
GuardActorStoppedWhileWaiting,
|
|
@@ -952,6 +1064,11 @@ export class RivetError extends Schema.TaggedErrorClass<RivetError>(
|
|
|
952
1064
|
return "public" in this.reason ? this.reason.public : undefined;
|
|
953
1065
|
}
|
|
954
1066
|
|
|
1067
|
+
/** Delegates to the underlying reason's `rayId` if present. */
|
|
1068
|
+
get rayId(): string | undefined {
|
|
1069
|
+
return "rayId" in this.reason ? this.reason.rayId : undefined;
|
|
1070
|
+
}
|
|
1071
|
+
|
|
955
1072
|
/** Delegates to the underlying reason's `isRetryable` getter. */
|
|
956
1073
|
get isRetryable(): boolean {
|
|
957
1074
|
return this.reason.isRetryable;
|
|
@@ -993,6 +1110,8 @@ const reasonByCode: { [key: string]: MakeRivetErrorReason | undefined } = {
|
|
|
993
1110
|
"request.invalid": (error) => new InvalidRequest({ cause: error }),
|
|
994
1111
|
"guard.actor_ready_timeout": (error) =>
|
|
995
1112
|
new GuardActorReadyTimeout({ cause: error }),
|
|
1113
|
+
"guard.actor_wake_retries_exceeded": (error) =>
|
|
1114
|
+
new GuardActorWakeRetriesExceeded({ cause: error }),
|
|
996
1115
|
"guard.actor_runner_failed": (error) =>
|
|
997
1116
|
new GuardActorRunnerFailed({ cause: error }),
|
|
998
1117
|
"guard.service_unavailable": (error) =>
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Effect, Logger, Layer } from "effect";
|
|
2
|
+
import * as RivetkitLog from "rivetkit/log";
|
|
3
|
+
import {
|
|
4
|
+
BaseLogger,
|
|
5
|
+
getOrCreateBaseLogger,
|
|
6
|
+
makeLogger,
|
|
7
|
+
} from "./internal/logging.ts";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Builds an Effect logger from a custom Pino-compatible logger.
|
|
11
|
+
*
|
|
12
|
+
* Use this with Effect's `Logger.layer` when you only need to customize Effect
|
|
13
|
+
* log output. Use {@link layerFromPino} when RivetKit's underlying TypeScript SDK
|
|
14
|
+
* logs should use the same logger too.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* import { Logger } from "effect"
|
|
19
|
+
* import { RivetLogger } from "@rivetkit/effect"
|
|
20
|
+
* import { pino } from "pino"
|
|
21
|
+
*
|
|
22
|
+
* const baseLogger = pino({ transport: { target: "pino-pretty" } })
|
|
23
|
+
* const LoggerLive = Logger.layer([RivetLogger.fromPino(baseLogger)])
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export const fromPino = (
|
|
27
|
+
baseLogger: RivetkitLog.Logger,
|
|
28
|
+
): Logger.Logger<unknown, void> => makeLogger(baseLogger);
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Builds a logging layer from a custom Pino-compatible logger.
|
|
32
|
+
*
|
|
33
|
+
* The layer installs the matching Effect logger and configures the underlying
|
|
34
|
+
* RivetKit TypeScript SDK logs to go through the same logger. The Effect tracer
|
|
35
|
+
* logger is installed alongside the Pino adapter so log events remain attached
|
|
36
|
+
* to active traces.
|
|
37
|
+
*/
|
|
38
|
+
export const layerFromPino = (
|
|
39
|
+
baseLogger: RivetkitLog.Logger,
|
|
40
|
+
options?: {
|
|
41
|
+
readonly mergeWithExisting?: boolean | undefined;
|
|
42
|
+
},
|
|
43
|
+
): Layer.Layer<BaseLogger> =>
|
|
44
|
+
Layer.mergeAll(
|
|
45
|
+
Layer.succeed(BaseLogger, baseLogger),
|
|
46
|
+
Logger.layer([Logger.tracerLogger, fromPino(baseLogger)], {
|
|
47
|
+
mergeWithExisting: options?.mergeWithExisting,
|
|
48
|
+
}),
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Default RivetKit Effect logging layer.
|
|
53
|
+
*
|
|
54
|
+
* The layer creates a base logger from RivetKit log configuration and installs
|
|
55
|
+
* the Effect logger adapter. Applications that want custom formatting or
|
|
56
|
+
* transports should provide {@link layerFromPino} instead.
|
|
57
|
+
*/
|
|
58
|
+
export const defaultLayer: Layer.Layer<never> = Layer.unwrap(
|
|
59
|
+
Effect.map(getOrCreateBaseLogger, layerFromPino),
|
|
60
|
+
);
|
package/src/State.test.ts
CHANGED
|
@@ -36,6 +36,26 @@ describe("State", () => {
|
|
|
36
36
|
}),
|
|
37
37
|
);
|
|
38
38
|
|
|
39
|
+
it.effect(
|
|
40
|
+
"getAndSet returns the previous value and commits the new value",
|
|
41
|
+
() =>
|
|
42
|
+
Effect.gen(function* () {
|
|
43
|
+
const { s, cell } = yield* makeCellState(10);
|
|
44
|
+
const previous = yield* State.getAndSet(s, 15);
|
|
45
|
+
assert.strictEqual(previous, 10);
|
|
46
|
+
assert.strictEqual(cell.value, 15);
|
|
47
|
+
}),
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
it.effect("setAndGet returns the committed value", () =>
|
|
51
|
+
Effect.gen(function* () {
|
|
52
|
+
const { s, cell } = yield* makeCellState(10);
|
|
53
|
+
const next = yield* State.setAndGet(s, 15);
|
|
54
|
+
assert.strictEqual(next, 15);
|
|
55
|
+
assert.strictEqual(cell.value, 15);
|
|
56
|
+
}),
|
|
57
|
+
);
|
|
58
|
+
|
|
39
59
|
it.effect("update applies f over read/write", () =>
|
|
40
60
|
Effect.gen(function* () {
|
|
41
61
|
const { s, cell } = yield* makeCellState(10);
|
|
@@ -44,6 +64,38 @@ describe("State", () => {
|
|
|
44
64
|
}),
|
|
45
65
|
);
|
|
46
66
|
|
|
67
|
+
it.effect("updateEffect applies an Effectful f over read/write", () =>
|
|
68
|
+
Effect.gen(function* () {
|
|
69
|
+
const { s, cell } = yield* makeCellState(10);
|
|
70
|
+
yield* State.updateEffect(s, (n) => Effect.succeed(n + 5));
|
|
71
|
+
assert.strictEqual(cell.value, 15);
|
|
72
|
+
}),
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
it.effect(
|
|
76
|
+
"getAndUpdate returns the previous value and commits the new value",
|
|
77
|
+
() =>
|
|
78
|
+
Effect.gen(function* () {
|
|
79
|
+
const { s, cell } = yield* makeCellState(10);
|
|
80
|
+
const previous = yield* State.getAndUpdate(s, (n) => n + 5);
|
|
81
|
+
assert.strictEqual(previous, 10);
|
|
82
|
+
assert.strictEqual(cell.value, 15);
|
|
83
|
+
}),
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
it.effect(
|
|
87
|
+
"getAndUpdateEffect returns the previous value and commits the new value",
|
|
88
|
+
() =>
|
|
89
|
+
Effect.gen(function* () {
|
|
90
|
+
const { s, cell } = yield* makeCellState(10);
|
|
91
|
+
const previous = yield* State.getAndUpdateEffect(s, (n) =>
|
|
92
|
+
Effect.succeed(n + 5),
|
|
93
|
+
);
|
|
94
|
+
assert.strictEqual(previous, 10);
|
|
95
|
+
assert.strictEqual(cell.value, 15);
|
|
96
|
+
}),
|
|
97
|
+
);
|
|
98
|
+
|
|
47
99
|
it.effect("updateAndGet returns the new value and commits it", () =>
|
|
48
100
|
Effect.gen(function* () {
|
|
49
101
|
const { s, cell } = yield* makeCellState(10);
|
|
@@ -53,6 +105,17 @@ describe("State", () => {
|
|
|
53
105
|
}),
|
|
54
106
|
);
|
|
55
107
|
|
|
108
|
+
it.effect("updateAndGetEffect returns the new value and commits it", () =>
|
|
109
|
+
Effect.gen(function* () {
|
|
110
|
+
const { s, cell } = yield* makeCellState(10);
|
|
111
|
+
const next = yield* State.updateAndGetEffect(s, (n) =>
|
|
112
|
+
Effect.succeed(n + 5),
|
|
113
|
+
);
|
|
114
|
+
assert.strictEqual(next, 15);
|
|
115
|
+
assert.strictEqual(cell.value, 15);
|
|
116
|
+
}),
|
|
117
|
+
);
|
|
118
|
+
|
|
56
119
|
it.effect("modify returns B and commits the new value", () =>
|
|
57
120
|
Effect.gen(function* () {
|
|
58
121
|
const { s, cell } = yield* makeCellState("a");
|
|
@@ -65,6 +128,17 @@ describe("State", () => {
|
|
|
65
128
|
}),
|
|
66
129
|
);
|
|
67
130
|
|
|
131
|
+
it.effect("modifyEffect returns B and commits the new value", () =>
|
|
132
|
+
Effect.gen(function* () {
|
|
133
|
+
const { s, cell } = yield* makeCellState("a");
|
|
134
|
+
const b = yield* State.modifyEffect(s, (str) =>
|
|
135
|
+
Effect.succeed([str.length, `${str}b`] as const),
|
|
136
|
+
);
|
|
137
|
+
assert.strictEqual(b, 1);
|
|
138
|
+
assert.strictEqual(cell.value, "ab");
|
|
139
|
+
}),
|
|
140
|
+
);
|
|
141
|
+
|
|
68
142
|
it.effect(
|
|
69
143
|
"update is atomic across concurrent fibers (no lost updates)",
|
|
70
144
|
() =>
|
|
@@ -89,7 +163,7 @@ describe("State", () => {
|
|
|
89
163
|
);
|
|
90
164
|
assert.deepStrictEqual(initial, [0]);
|
|
91
165
|
|
|
92
|
-
State.
|
|
166
|
+
yield* s[State.RuntimeTypeId].publishEffect(Effect.succeed(7));
|
|
93
167
|
const later = yield* State.changes(s).pipe(
|
|
94
168
|
Stream.take(1),
|
|
95
169
|
Stream.runCollect,
|
|
@@ -103,11 +177,17 @@ describe("State", () => {
|
|
|
103
177
|
const { s } = yield* makeCellState(0);
|
|
104
178
|
yield* Effect.scoped(
|
|
105
179
|
Effect.gen(function* () {
|
|
106
|
-
const sub = yield* PubSub.subscribe(
|
|
180
|
+
const sub = yield* PubSub.subscribe(
|
|
181
|
+
s[State.RuntimeTypeId].pubsub,
|
|
182
|
+
);
|
|
107
183
|
assert.strictEqual(yield* PubSub.take(sub), 0);
|
|
108
184
|
|
|
109
|
-
yield* State.
|
|
110
|
-
|
|
185
|
+
yield* s[State.RuntimeTypeId].publishEffect(
|
|
186
|
+
Effect.succeed(1),
|
|
187
|
+
);
|
|
188
|
+
yield* s[State.RuntimeTypeId].publishEffect(
|
|
189
|
+
Effect.succeed(2),
|
|
190
|
+
);
|
|
111
191
|
assert.strictEqual(yield* PubSub.take(sub), 1);
|
|
112
192
|
assert.strictEqual(yield* PubSub.take(sub), 2);
|
|
113
193
|
}),
|
|
@@ -115,6 +195,19 @@ describe("State", () => {
|
|
|
115
195
|
}),
|
|
116
196
|
);
|
|
117
197
|
|
|
198
|
+
it.effect("shuts down the backing pubsub when its scope closes", () =>
|
|
199
|
+
Effect.gen(function* () {
|
|
200
|
+
const pubsub = yield* Effect.scoped(
|
|
201
|
+
Effect.gen(function* () {
|
|
202
|
+
const { s } = yield* makeCellState(0);
|
|
203
|
+
return s[State.RuntimeTypeId].pubsub;
|
|
204
|
+
}),
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
assert.isTrue(yield* PubSub.isShutdown(pubsub));
|
|
208
|
+
}),
|
|
209
|
+
);
|
|
210
|
+
|
|
118
211
|
it.effect("set does NOT auto-publish — the runtime does", () =>
|
|
119
212
|
Effect.gen(function* () {
|
|
120
213
|
const { s } = yield* makeCellState(0);
|
|
@@ -146,6 +239,61 @@ describe("State", () => {
|
|
|
146
239
|
|
|
147
240
|
yield* s.pipe(State.update((n) => n * 2));
|
|
148
241
|
assert.strictEqual(yield* State.get(s), 10);
|
|
242
|
+
|
|
243
|
+
yield* s.pipe(State.updateEffect((n) => Effect.succeed(n + 1)));
|
|
244
|
+
assert.strictEqual(yield* State.get(s), 11);
|
|
245
|
+
}),
|
|
246
|
+
);
|
|
247
|
+
|
|
248
|
+
it.effect("supports instance methods", () =>
|
|
249
|
+
Effect.gen(function* () {
|
|
250
|
+
const { s, cell } = yield* makeCellState(0);
|
|
251
|
+
assert.strictEqual(yield* s.get, 0);
|
|
252
|
+
|
|
253
|
+
yield* s.set(5);
|
|
254
|
+
assert.strictEqual(cell.value, 5);
|
|
255
|
+
|
|
256
|
+
const beforeSet = yield* s.getAndSet(6);
|
|
257
|
+
assert.strictEqual(beforeSet, 5);
|
|
258
|
+
assert.strictEqual(cell.value, 6);
|
|
259
|
+
|
|
260
|
+
const afterSet = yield* s.setAndGet(7);
|
|
261
|
+
assert.strictEqual(afterSet, 7);
|
|
262
|
+
assert.strictEqual(cell.value, 7);
|
|
263
|
+
|
|
264
|
+
yield* s.update((n) => n * 2);
|
|
265
|
+
assert.strictEqual(yield* s.get, 14);
|
|
266
|
+
|
|
267
|
+
yield* s.updateEffect((n) => Effect.succeed(n + 1));
|
|
268
|
+
assert.strictEqual(yield* s.get, 15);
|
|
269
|
+
|
|
270
|
+
const previousUpdate = yield* s.getAndUpdate((n) => n + 1);
|
|
271
|
+
assert.strictEqual(previousUpdate, 15);
|
|
272
|
+
assert.strictEqual(yield* s.get, 16);
|
|
273
|
+
|
|
274
|
+
const previousEffectUpdate = yield* s.getAndUpdateEffect((n) =>
|
|
275
|
+
Effect.succeed(n + 1),
|
|
276
|
+
);
|
|
277
|
+
assert.strictEqual(previousEffectUpdate, 16);
|
|
278
|
+
assert.strictEqual(yield* s.get, 17);
|
|
279
|
+
|
|
280
|
+
const next = yield* s.updateAndGet((n) => n + 1);
|
|
281
|
+
assert.strictEqual(next, 18);
|
|
282
|
+
|
|
283
|
+
const effectNext = yield* s.updateAndGetEffect((n) =>
|
|
284
|
+
Effect.succeed(n + 1),
|
|
285
|
+
);
|
|
286
|
+
assert.strictEqual(effectNext, 19);
|
|
287
|
+
|
|
288
|
+
const previous = yield* s.modify((n) => [n, n + 1] as const);
|
|
289
|
+
assert.strictEqual(previous, 19);
|
|
290
|
+
assert.strictEqual(yield* s.get, 20);
|
|
291
|
+
|
|
292
|
+
const effectPrevious = yield* s.modifyEffect((n) =>
|
|
293
|
+
Effect.succeed([n, n + 1] as const),
|
|
294
|
+
);
|
|
295
|
+
assert.strictEqual(effectPrevious, 20);
|
|
296
|
+
assert.strictEqual(yield* s.get, 21);
|
|
149
297
|
}),
|
|
150
298
|
);
|
|
151
299
|
|
|
@@ -178,4 +326,15 @@ describe("State", () => {
|
|
|
178
326
|
assert.isTrue(Exit.isFailure(exit));
|
|
179
327
|
}),
|
|
180
328
|
);
|
|
329
|
+
|
|
330
|
+
it.effect("Effectful update failure does not write", () =>
|
|
331
|
+
Effect.gen(function* () {
|
|
332
|
+
const { s, cell } = yield* makeCellState(0);
|
|
333
|
+
const exit = yield* Effect.exit(
|
|
334
|
+
State.updateEffect(s, () => Effect.fail("boom" as const)),
|
|
335
|
+
);
|
|
336
|
+
assert.isTrue(Exit.isFailure(exit));
|
|
337
|
+
assert.strictEqual(cell.value, 0);
|
|
338
|
+
}),
|
|
339
|
+
);
|
|
181
340
|
});
|