@rivetkit/effect 2.3.3-rc.1 → 2.3.3
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 +18 -3
- package/dist/RivetError.d.ts.map +1 -1
- package/dist/RivetError.js +31 -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/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 +3 -3
- package/src/Actor.test-d.ts +32 -0
- package/src/Actor.ts +29 -4
- package/src/Client.test.ts +21 -18
- package/src/Client.ts +6 -4
- package/src/Registry.test.ts +7 -11
- package/src/Registry.ts +116 -50
- package/src/RivetError.test.ts +11 -0
- package/src/RivetError.ts +37 -0
- package/src/RivetLogger.ts +60 -0
- package/src/State.test.ts +163 -4
- package/src/State.ts +293 -97
- package/src/internal/ActorInstanceManager.ts +4 -10
- package/src/internal/ActorStateAdapter.ts +5 -11
- package/src/internal/StateOptions.ts +4 -0
- package/src/internal/logging.test.ts +65 -88
- 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/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
|
});
|
package/src/State.ts
CHANGED
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
Predicate,
|
|
27
27
|
PubSub,
|
|
28
28
|
Semaphore,
|
|
29
|
+
Scope,
|
|
29
30
|
Stream,
|
|
30
31
|
type Types,
|
|
31
32
|
} from "effect";
|
|
@@ -33,6 +34,15 @@ import { dual } from "effect/Function";
|
|
|
33
34
|
|
|
34
35
|
const TypeId = "~@rivetkit/effect/State";
|
|
35
36
|
|
|
37
|
+
/**
|
|
38
|
+
* Internal access to `State`'s backing store and publish machinery.
|
|
39
|
+
*
|
|
40
|
+
* @internal
|
|
41
|
+
*/
|
|
42
|
+
export const RuntimeTypeId: unique symbol = Symbol.for(
|
|
43
|
+
"~@rivetkit/effect/State/Runtime",
|
|
44
|
+
) as never;
|
|
45
|
+
|
|
36
46
|
/**
|
|
37
47
|
* A view over a persisted state cell with a subscribable change stream.
|
|
38
48
|
*
|
|
@@ -45,17 +55,97 @@ export interface State<A, E = never, R = never>
|
|
|
45
55
|
extends Variance<A, E, R>,
|
|
46
56
|
Pipeable.Pipeable,
|
|
47
57
|
Inspectable.Inspectable {
|
|
58
|
+
/**
|
|
59
|
+
* Retrieves the persisted value.
|
|
60
|
+
*/
|
|
61
|
+
readonly get: Effect.Effect<A, E, R>;
|
|
62
|
+
/**
|
|
63
|
+
* Retrieves the persisted value and sets a new value atomically.
|
|
64
|
+
*/
|
|
65
|
+
readonly getAndSet: (value: A) => Effect.Effect<A, E, R>;
|
|
66
|
+
/**
|
|
67
|
+
* Retrieves the current value and updates it atomically with the result of
|
|
68
|
+
* applying a function.
|
|
69
|
+
*/
|
|
70
|
+
readonly getAndUpdate: (f: (a: A) => A) => Effect.Effect<A, E, R>;
|
|
71
|
+
/**
|
|
72
|
+
* Retrieves the current value and updates it atomically with the result of
|
|
73
|
+
* applying an effectful function.
|
|
74
|
+
*/
|
|
75
|
+
readonly getAndUpdateEffect: <E2, R2>(
|
|
76
|
+
f: (a: A) => Effect.Effect<A, E2, R2>,
|
|
77
|
+
) => Effect.Effect<A, E | E2, R | R2>;
|
|
78
|
+
/**
|
|
79
|
+
* Modifies atomically with a function that computes a return value and
|
|
80
|
+
* a new value.
|
|
81
|
+
*/
|
|
82
|
+
readonly modify: <B>(
|
|
83
|
+
f: (a: A) => readonly [B, A],
|
|
84
|
+
) => Effect.Effect<B, E, R>;
|
|
85
|
+
/**
|
|
86
|
+
* Modifies atomically with an effectful function that computes a return value
|
|
87
|
+
* and a new value.
|
|
88
|
+
*/
|
|
89
|
+
readonly modifyEffect: <B, E2, R2>(
|
|
90
|
+
f: (a: A) => Effect.Effect<readonly [B, A], E2, R2>,
|
|
91
|
+
) => Effect.Effect<B, E | E2, R | R2>;
|
|
92
|
+
/**
|
|
93
|
+
* Writes the persisted value.
|
|
94
|
+
*/
|
|
95
|
+
readonly set: (value: A) => Effect.Effect<void, E, R>;
|
|
96
|
+
/**
|
|
97
|
+
* Sets the persisted value and returns the new value.
|
|
98
|
+
*/
|
|
99
|
+
readonly setAndGet: (value: A) => Effect.Effect<A, E, R>;
|
|
100
|
+
/**
|
|
101
|
+
* Updates the persisted value with the result of applying a function.
|
|
102
|
+
*/
|
|
103
|
+
readonly update: (f: (a: A) => A) => Effect.Effect<void, E, R>;
|
|
104
|
+
/**
|
|
105
|
+
* Updates the persisted value with the result of applying an effectful function.
|
|
106
|
+
*/
|
|
107
|
+
readonly updateEffect: <E2, R2>(
|
|
108
|
+
f: (a: A) => Effect.Effect<A, E2, R2>,
|
|
109
|
+
) => Effect.Effect<void, E | E2, R | R2>;
|
|
110
|
+
/**
|
|
111
|
+
* Updates the persisted value with the result of applying an effectful function
|
|
112
|
+
* and returns the new value.
|
|
113
|
+
*/
|
|
114
|
+
readonly updateAndGet: (f: (a: A) => A) => Effect.Effect<A, E, R>;
|
|
115
|
+
/**
|
|
116
|
+
* Updates the persisted value with the result of applying an effectful function
|
|
117
|
+
* and returns the new value.
|
|
118
|
+
*/
|
|
119
|
+
readonly updateAndGetEffect: <E2, R2>(
|
|
120
|
+
f: (a: A) => Effect.Effect<A, E2, R2>,
|
|
121
|
+
) => Effect.Effect<A, E | E2, R | R2>;
|
|
122
|
+
/**
|
|
123
|
+
* Creates a stream that emits the current persisted value and all subsequent
|
|
124
|
+
* changes.
|
|
125
|
+
*/
|
|
126
|
+
readonly changes: Stream.Stream<A>;
|
|
127
|
+
/**
|
|
128
|
+
* Internal access to `State`'s backing store and publish machinery.
|
|
129
|
+
*
|
|
130
|
+
* @internal
|
|
131
|
+
*/
|
|
132
|
+
readonly [RuntimeTypeId]: StateRuntime<A, E, R>;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Runtime-only hooks for wiring actor state persistence and change
|
|
137
|
+
* notifications.
|
|
138
|
+
*
|
|
139
|
+
* @internal
|
|
140
|
+
*/
|
|
141
|
+
export interface StateRuntime<A, E = never, R = never> {
|
|
142
|
+
readonly publish: (value: A) => Effect.Effect<boolean>;
|
|
143
|
+
readonly publishEffect: <E2, R2>(
|
|
144
|
+
effect: Effect.Effect<A, E2, R2>,
|
|
145
|
+
) => Effect.Effect<boolean, E2, R2>;
|
|
48
146
|
readonly read: () => Effect.Effect<A, E, R>;
|
|
49
147
|
readonly write: (value: A) => Effect.Effect<void, E, R>;
|
|
50
148
|
readonly pubsub: PubSub.PubSub<A>;
|
|
51
|
-
/**
|
|
52
|
-
* Serializes writes (`set`, `update`, `modify`) so the read/apply/
|
|
53
|
-
* write triple is atomic. The runtime may also use this semaphore
|
|
54
|
-
* to serialize its own decode-and-publish work from
|
|
55
|
-
* `onStateChange`, keeping the change stream's order consistent
|
|
56
|
-
* with the write order.
|
|
57
|
-
*/
|
|
58
|
-
readonly semaphore: Semaphore.Semaphore;
|
|
59
149
|
}
|
|
60
150
|
|
|
61
151
|
export const isState = (u: unknown): u is State<unknown, unknown> =>
|
|
@@ -86,47 +176,192 @@ const Proto = {
|
|
|
86
176
|
* The current value (per `read()`) is published to the pubsub on
|
|
87
177
|
* construction so any subscription obtained later replays it.
|
|
88
178
|
*
|
|
89
|
-
* The PubSub is
|
|
90
|
-
*
|
|
179
|
+
* The backing PubSub is scoped and shuts down when the current
|
|
180
|
+
* `Scope` closes.
|
|
91
181
|
*/
|
|
92
182
|
export const make = Effect.fnUntraced(function* <A, E, R>(
|
|
93
183
|
read: () => Effect.Effect<A, E, R>,
|
|
94
184
|
write: (value: A) => Effect.Effect<void, E, R>,
|
|
95
|
-
): Effect.fn.Return<State<A, E, R>, E, R> {
|
|
185
|
+
): Effect.fn.Return<State<A, E, R>, E, R | Scope.Scope> {
|
|
96
186
|
const pubsub = yield* PubSub.unbounded<A>({ replay: 1 });
|
|
187
|
+
yield* Effect.addFinalizer(() => PubSub.shutdown(pubsub));
|
|
97
188
|
const initial = yield* read();
|
|
98
|
-
PubSub.
|
|
189
|
+
yield* PubSub.publish(pubsub, initial);
|
|
99
190
|
const self = Object.create(Proto);
|
|
100
|
-
|
|
101
|
-
self
|
|
102
|
-
|
|
103
|
-
|
|
191
|
+
const semaphore = yield* Semaphore.make(1);
|
|
192
|
+
self[RuntimeTypeId] = {
|
|
193
|
+
read,
|
|
194
|
+
write,
|
|
195
|
+
pubsub,
|
|
196
|
+
publish: (value: A) => PubSub.publish(pubsub, value),
|
|
197
|
+
publishEffect: <E2, R2>(effect: Effect.Effect<A, E2, R2>) =>
|
|
198
|
+
Semaphore.withPermit(
|
|
199
|
+
semaphore,
|
|
200
|
+
Effect.flatMap(effect, (value) =>
|
|
201
|
+
PubSub.publish(pubsub, value),
|
|
202
|
+
),
|
|
203
|
+
),
|
|
204
|
+
};
|
|
205
|
+
self.get = Effect.suspend(() => self[RuntimeTypeId].read());
|
|
206
|
+
self.set = (value: A) => Semaphore.withPermit(semaphore, write(value));
|
|
207
|
+
self.getAndSet = (value: A) =>
|
|
208
|
+
Semaphore.withPermit(
|
|
209
|
+
semaphore,
|
|
210
|
+
Effect.flatMap(read(), (previous) =>
|
|
211
|
+
Effect.as(write(value), previous),
|
|
212
|
+
),
|
|
213
|
+
);
|
|
214
|
+
self.setAndGet = (value: A) =>
|
|
215
|
+
Semaphore.withPermit(semaphore, Effect.as(write(value), value));
|
|
216
|
+
self.update = (f: (a: A) => A) =>
|
|
217
|
+
Semaphore.withPermit(
|
|
218
|
+
semaphore,
|
|
219
|
+
Effect.flatMap(read(), (a) => write(f(a))),
|
|
220
|
+
);
|
|
221
|
+
self.updateEffect = <E2, R2>(f: (a: A) => Effect.Effect<A, E2, R2>) =>
|
|
222
|
+
Semaphore.withPermit(
|
|
223
|
+
semaphore,
|
|
224
|
+
Effect.flatMap(read(), (a) => Effect.flatMap(f(a), write)),
|
|
225
|
+
);
|
|
226
|
+
self.getAndUpdate = (f: (a: A) => A) =>
|
|
227
|
+
Semaphore.withPermit(
|
|
228
|
+
semaphore,
|
|
229
|
+
Effect.flatMap(read(), (previous) =>
|
|
230
|
+
Effect.as(write(f(previous)), previous),
|
|
231
|
+
),
|
|
232
|
+
);
|
|
233
|
+
self.getAndUpdateEffect = <E2, R2>(f: (a: A) => Effect.Effect<A, E2, R2>) =>
|
|
234
|
+
Semaphore.withPermit(
|
|
235
|
+
semaphore,
|
|
236
|
+
Effect.flatMap(read(), (previous) =>
|
|
237
|
+
Effect.flatMap(f(previous), (next) =>
|
|
238
|
+
Effect.as(write(next), previous),
|
|
239
|
+
),
|
|
240
|
+
),
|
|
241
|
+
);
|
|
242
|
+
self.updateAndGet = (f: (a: A) => A) =>
|
|
243
|
+
Semaphore.withPermit(
|
|
244
|
+
semaphore,
|
|
245
|
+
Effect.flatMap(read(), (a) => {
|
|
246
|
+
const next = f(a);
|
|
247
|
+
return Effect.as(write(next), next);
|
|
248
|
+
}),
|
|
249
|
+
);
|
|
250
|
+
self.updateAndGetEffect = <E2, R2>(f: (a: A) => Effect.Effect<A, E2, R2>) =>
|
|
251
|
+
Semaphore.withPermit(
|
|
252
|
+
semaphore,
|
|
253
|
+
Effect.flatMap(read(), (a) =>
|
|
254
|
+
Effect.flatMap(f(a), (next) => Effect.as(write(next), next)),
|
|
255
|
+
),
|
|
256
|
+
);
|
|
257
|
+
self.modify = <B>(f: (a: A) => readonly [B, A]) =>
|
|
258
|
+
Semaphore.withPermit(
|
|
259
|
+
semaphore,
|
|
260
|
+
Effect.flatMap(read(), (a) => {
|
|
261
|
+
const [b, next] = f(a);
|
|
262
|
+
return Effect.as(write(next), b);
|
|
263
|
+
}),
|
|
264
|
+
);
|
|
265
|
+
self.modifyEffect = <B, E2, R2>(
|
|
266
|
+
f: (a: A) => Effect.Effect<readonly [B, A], E2, R2>,
|
|
267
|
+
) =>
|
|
268
|
+
Semaphore.withPermit(
|
|
269
|
+
semaphore,
|
|
270
|
+
Effect.flatMap(read(), (a) =>
|
|
271
|
+
Effect.flatMap(f(a), ([b, next]) => Effect.as(write(next), b)),
|
|
272
|
+
),
|
|
273
|
+
);
|
|
274
|
+
self.changes = Stream.fromPubSub(pubsub);
|
|
104
275
|
return self;
|
|
105
276
|
});
|
|
106
277
|
|
|
107
|
-
/**
|
|
108
|
-
* Reads the current value.
|
|
109
|
-
*/
|
|
110
278
|
export const get = <A, E, R>(self: State<A, E, R>): Effect.Effect<A, E, R> =>
|
|
111
|
-
self.
|
|
279
|
+
self.get;
|
|
280
|
+
|
|
281
|
+
export const getAndSet: {
|
|
282
|
+
<A>(value: A): <E, R>(self: State<A, E, R>) => Effect.Effect<A, E, R>;
|
|
283
|
+
<A, E, R>(self: State<A, E, R>, value: A): Effect.Effect<A, E, R>;
|
|
284
|
+
} = dual(
|
|
285
|
+
2,
|
|
286
|
+
<A, E, R>(self: State<A, E, R>, value: A): Effect.Effect<A, E, R> =>
|
|
287
|
+
self.getAndSet(value),
|
|
288
|
+
);
|
|
289
|
+
|
|
290
|
+
export const getAndUpdate: {
|
|
291
|
+
<A>(f: (a: A) => A): <E, R>(self: State<A, E, R>) => Effect.Effect<A, E, R>;
|
|
292
|
+
<A, E, R>(self: State<A, E, R>, f: (a: A) => A): Effect.Effect<A, E, R>;
|
|
293
|
+
} = dual(
|
|
294
|
+
2,
|
|
295
|
+
<A, E, R>(self: State<A, E, R>, f: (a: A) => A): Effect.Effect<A, E, R> =>
|
|
296
|
+
self.getAndUpdate(f),
|
|
297
|
+
);
|
|
298
|
+
|
|
299
|
+
export const getAndUpdateEffect: {
|
|
300
|
+
<A, E2, R2>(
|
|
301
|
+
f: (a: A) => Effect.Effect<A, E2, R2>,
|
|
302
|
+
): <E, R>(self: State<A, E, R>) => Effect.Effect<A, E | E2, R | R2>;
|
|
303
|
+
<A, E, R, E2, R2>(
|
|
304
|
+
self: State<A, E, R>,
|
|
305
|
+
f: (a: A) => Effect.Effect<A, E2, R2>,
|
|
306
|
+
): Effect.Effect<A, E | E2, R | R2>;
|
|
307
|
+
} = dual(
|
|
308
|
+
2,
|
|
309
|
+
<A, E, R, E2, R2>(
|
|
310
|
+
self: State<A, E, R>,
|
|
311
|
+
f: (a: A) => Effect.Effect<A, E2, R2>,
|
|
312
|
+
): Effect.Effect<A, E | E2, R | R2> => self.getAndUpdateEffect(f),
|
|
313
|
+
);
|
|
314
|
+
|
|
315
|
+
export const modify: {
|
|
316
|
+
<A, B>(
|
|
317
|
+
f: (a: A) => readonly [B, A],
|
|
318
|
+
): <E, R>(self: State<A, E, R>) => Effect.Effect<B, E, R>;
|
|
319
|
+
<A, E, R, B>(
|
|
320
|
+
self: State<A, E, R>,
|
|
321
|
+
f: (a: A) => readonly [B, A],
|
|
322
|
+
): Effect.Effect<B, E, R>;
|
|
323
|
+
} = dual(
|
|
324
|
+
2,
|
|
325
|
+
<A, E, R, B>(
|
|
326
|
+
self: State<A, E, R>,
|
|
327
|
+
f: (a: A) => readonly [B, A],
|
|
328
|
+
): Effect.Effect<B, E, R> => self.modify(f),
|
|
329
|
+
);
|
|
330
|
+
|
|
331
|
+
export const modifyEffect: {
|
|
332
|
+
<A, B, E2, R2>(
|
|
333
|
+
f: (a: A) => Effect.Effect<readonly [B, A], E2, R2>,
|
|
334
|
+
): <E, R>(self: State<A, E, R>) => Effect.Effect<B, E | E2, R | R2>;
|
|
335
|
+
<A, E, R, B, E2, R2>(
|
|
336
|
+
self: State<A, E, R>,
|
|
337
|
+
f: (a: A) => Effect.Effect<readonly [B, A], E2, R2>,
|
|
338
|
+
): Effect.Effect<B, E | E2, R | R2>;
|
|
339
|
+
} = dual(
|
|
340
|
+
2,
|
|
341
|
+
<A, E, R, B, E2, R2>(
|
|
342
|
+
self: State<A, E, R>,
|
|
343
|
+
f: (a: A) => Effect.Effect<readonly [B, A], E2, R2>,
|
|
344
|
+
): Effect.Effect<B, E | E2, R | R2> => self.modifyEffect(f),
|
|
345
|
+
);
|
|
112
346
|
|
|
113
|
-
/**
|
|
114
|
-
* Replaces the value. Serialized with `update` / `modify` so writes
|
|
115
|
-
* happen in invocation order.
|
|
116
|
-
*/
|
|
117
347
|
export const set: {
|
|
118
348
|
<A>(value: A): <E, R>(self: State<A, E, R>) => Effect.Effect<void, E, R>;
|
|
119
349
|
<A, E, R>(self: State<A, E, R>, value: A): Effect.Effect<void, E, R>;
|
|
120
350
|
} = dual(
|
|
121
351
|
2,
|
|
122
352
|
<A, E, R>(self: State<A, E, R>, value: A): Effect.Effect<void, E, R> =>
|
|
123
|
-
|
|
353
|
+
self.set(value),
|
|
354
|
+
);
|
|
355
|
+
|
|
356
|
+
export const setAndGet: {
|
|
357
|
+
<A>(value: A): <E, R>(self: State<A, E, R>) => Effect.Effect<A, E, R>;
|
|
358
|
+
<A, E, R>(self: State<A, E, R>, value: A): Effect.Effect<A, E, R>;
|
|
359
|
+
} = dual(
|
|
360
|
+
2,
|
|
361
|
+
<A, E, R>(self: State<A, E, R>, value: A): Effect.Effect<A, E, R> =>
|
|
362
|
+
self.setAndGet(value),
|
|
124
363
|
);
|
|
125
364
|
|
|
126
|
-
/**
|
|
127
|
-
* Updates the value by applying `f` to the current value. The
|
|
128
|
-
* read/apply/write triple is atomic across fibers.
|
|
129
|
-
*/
|
|
130
365
|
export const update: {
|
|
131
366
|
<A>(
|
|
132
367
|
f: (a: A) => A,
|
|
@@ -137,88 +372,49 @@ export const update: {
|
|
|
137
372
|
<A, E, R>(
|
|
138
373
|
self: State<A, E, R>,
|
|
139
374
|
f: (a: A) => A,
|
|
140
|
-
): Effect.Effect<void, E, R> =>
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
375
|
+
): Effect.Effect<void, E, R> => self.update(f),
|
|
376
|
+
);
|
|
377
|
+
|
|
378
|
+
export const updateEffect: {
|
|
379
|
+
<A, E2, R2>(
|
|
380
|
+
f: (a: A) => Effect.Effect<A, E2, R2>,
|
|
381
|
+
): <E, R>(self: State<A, E, R>) => Effect.Effect<void, E | E2, R | R2>;
|
|
382
|
+
<A, E, R, E2, R2>(
|
|
383
|
+
self: State<A, E, R>,
|
|
384
|
+
f: (a: A) => Effect.Effect<A, E2, R2>,
|
|
385
|
+
): Effect.Effect<void, E | E2, R | R2>;
|
|
386
|
+
} = dual(
|
|
387
|
+
2,
|
|
388
|
+
<A, E, R, E2, R2>(
|
|
389
|
+
self: State<A, E, R>,
|
|
390
|
+
f: (a: A) => Effect.Effect<A, E2, R2>,
|
|
391
|
+
): Effect.Effect<void, E | E2, R | R2> => self.updateEffect(f),
|
|
145
392
|
);
|
|
146
393
|
|
|
147
|
-
/**
|
|
148
|
-
* Updates the value by applying `f` and returns the new value. The
|
|
149
|
-
* read/apply/write triple is atomic across fibers.
|
|
150
|
-
*/
|
|
151
394
|
export const updateAndGet: {
|
|
152
395
|
<A>(f: (a: A) => A): <E, R>(self: State<A, E, R>) => Effect.Effect<A, E, R>;
|
|
153
396
|
<A, E, R>(self: State<A, E, R>, f: (a: A) => A): Effect.Effect<A, E, R>;
|
|
154
397
|
} = dual(
|
|
155
398
|
2,
|
|
156
399
|
<A, E, R>(self: State<A, E, R>, f: (a: A) => A): Effect.Effect<A, E, R> =>
|
|
157
|
-
|
|
158
|
-
self.semaphore,
|
|
159
|
-
Effect.flatMap(self.read(), (a) => {
|
|
160
|
-
const next = f(a);
|
|
161
|
-
return Effect.as(self.write(next), next);
|
|
162
|
-
}),
|
|
163
|
-
),
|
|
400
|
+
self.updateAndGet(f),
|
|
164
401
|
);
|
|
165
402
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
export const modify: {
|
|
172
|
-
<A, B>(
|
|
173
|
-
f: (a: A) => readonly [B, A],
|
|
174
|
-
): <E, R>(self: State<A, E, R>) => Effect.Effect<B, E, R>;
|
|
175
|
-
<A, E, R, B>(
|
|
403
|
+
export const updateAndGetEffect: {
|
|
404
|
+
<A, E2, R2>(
|
|
405
|
+
f: (a: A) => Effect.Effect<A, E2, R2>,
|
|
406
|
+
): <E, R>(self: State<A, E, R>) => Effect.Effect<A, E | E2, R | R2>;
|
|
407
|
+
<A, E, R, E2, R2>(
|
|
176
408
|
self: State<A, E, R>,
|
|
177
|
-
f: (a: A) =>
|
|
178
|
-
): Effect.Effect<
|
|
409
|
+
f: (a: A) => Effect.Effect<A, E2, R2>,
|
|
410
|
+
): Effect.Effect<A, E | E2, R | R2>;
|
|
179
411
|
} = dual(
|
|
180
412
|
2,
|
|
181
|
-
<A, E, R,
|
|
413
|
+
<A, E, R, E2, R2>(
|
|
182
414
|
self: State<A, E, R>,
|
|
183
|
-
f: (a: A) =>
|
|
184
|
-
): Effect.Effect<
|
|
185
|
-
Semaphore.withPermit(
|
|
186
|
-
self.semaphore,
|
|
187
|
-
Effect.flatMap(self.read(), (a) => {
|
|
188
|
-
const [b, next] = f(a);
|
|
189
|
-
return Effect.as(self.write(next), b);
|
|
190
|
-
}),
|
|
191
|
-
),
|
|
415
|
+
f: (a: A) => Effect.Effect<A, E2, R2>,
|
|
416
|
+
): Effect.Effect<A, E | E2, R | R2> => self.updateAndGetEffect(f),
|
|
192
417
|
);
|
|
193
418
|
|
|
194
|
-
/**
|
|
195
|
-
* Stream of every value published to this `State`. New subscribers
|
|
196
|
-
* immediately see the most recent value (replay = 1), then every
|
|
197
|
-
* subsequent publish.
|
|
198
|
-
*/
|
|
199
419
|
export const changes = <A, E, R>(self: State<A, E, R>): Stream.Stream<A> =>
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* Publish a value to the change stream as an `Effect`. Does not
|
|
204
|
-
* modify the underlying store.
|
|
205
|
-
*/
|
|
206
|
-
export const publish: {
|
|
207
|
-
<A>(value: A): <E, R>(self: State<A, E, R>) => Effect.Effect<boolean>;
|
|
208
|
-
<A, E, R>(self: State<A, E, R>, value: A): Effect.Effect<boolean>;
|
|
209
|
-
} = dual(
|
|
210
|
-
2,
|
|
211
|
-
<A, E, R>(self: State<A, E, R>, value: A): Effect.Effect<boolean> =>
|
|
212
|
-
PubSub.publish(self.pubsub, value),
|
|
213
|
-
);
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Synchronous variant of {@link publish}. Returns `true` when the
|
|
217
|
-
* publish succeeded, `false` if the pubsub is shut down. The runtime
|
|
218
|
-
* uses this from rivetkit's `onStateChange` callback to feed the
|
|
219
|
-
* change stream.
|
|
220
|
-
*/
|
|
221
|
-
export const publishUnsafe = <A, E, R>(
|
|
222
|
-
self: State<A, E, R>,
|
|
223
|
-
value: A,
|
|
224
|
-
): boolean => PubSub.publishUnsafe(self.pubsub, value);
|
|
420
|
+
self.changes;
|