@rivetkit/effect 0.0.0-sqlite-uds.37f9e48 → 0.0.0-sqlite-profiling-compat.4a9a623

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 (63) hide show
  1. package/dist/Actor.d.ts +3 -2
  2. package/dist/Actor.d.ts.map +1 -1
  3. package/dist/Actor.js +2 -2
  4. package/dist/Actor.js.map +1 -1
  5. package/dist/Client.d.ts.map +1 -1
  6. package/dist/Client.js +4 -6
  7. package/dist/Client.js.map +1 -1
  8. package/dist/Logger.d.ts +29 -0
  9. package/dist/Logger.d.ts.map +1 -0
  10. package/dist/Logger.js +31 -0
  11. package/dist/Logger.js.map +1 -0
  12. package/dist/Registry.d.ts +7 -69
  13. package/dist/Registry.d.ts.map +1 -1
  14. package/dist/Registry.js +40 -93
  15. package/dist/Registry.js.map +1 -1
  16. package/dist/RivetError.d.ts +3 -18
  17. package/dist/RivetError.d.ts.map +1 -1
  18. package/dist/RivetError.js +0 -31
  19. package/dist/RivetError.js.map +1 -1
  20. package/dist/State.d.ts +56 -92
  21. package/dist/State.d.ts.map +1 -1
  22. package/dist/State.js +57 -51
  23. package/dist/State.js.map +1 -1
  24. package/dist/internal/ActorInstanceManager.d.ts.map +1 -1
  25. package/dist/internal/ActorInstanceManager.js +4 -4
  26. package/dist/internal/ActorInstanceManager.js.map +1 -1
  27. package/dist/internal/ActorStateAdapter.d.ts +1 -1
  28. package/dist/internal/ActorStateAdapter.d.ts.map +1 -1
  29. package/dist/internal/ActorStateAdapter.js +7 -2
  30. package/dist/internal/ActorStateAdapter.js.map +1 -1
  31. package/dist/internal/StateOptions.d.ts +0 -1
  32. package/dist/internal/StateOptions.d.ts.map +1 -1
  33. package/dist/internal/logging.d.ts +7 -6
  34. package/dist/internal/logging.d.ts.map +1 -1
  35. package/dist/internal/logging.js +102 -78
  36. package/dist/internal/logging.js.map +1 -1
  37. package/dist/mod.d.ts +1 -1
  38. package/dist/mod.d.ts.map +1 -1
  39. package/dist/mod.js +1 -1
  40. package/dist/mod.js.map +1 -1
  41. package/package.json +8 -3
  42. package/src/Actor.test-d.ts +0 -32
  43. package/src/Actor.ts +4 -29
  44. package/src/Client.test.ts +18 -21
  45. package/src/Client.ts +4 -6
  46. package/src/Logger.ts +43 -0
  47. package/src/Registry.test.ts +11 -7
  48. package/src/Registry.ts +50 -116
  49. package/src/RivetError.test.ts +0 -11
  50. package/src/RivetError.ts +0 -37
  51. package/src/State.test.ts +4 -163
  52. package/src/State.ts +97 -293
  53. package/src/internal/ActorInstanceManager.ts +10 -4
  54. package/src/internal/ActorStateAdapter.ts +11 -5
  55. package/src/internal/StateOptions.ts +0 -4
  56. package/src/internal/logging.test.ts +88 -65
  57. package/src/internal/logging.ts +143 -103
  58. package/src/mod.ts +1 -1
  59. package/dist/RivetLogger.d.ts +0 -41
  60. package/dist/RivetLogger.d.ts.map +0 -1
  61. package/dist/RivetLogger.js +0 -41
  62. package/dist/RivetLogger.js.map +0 -1
  63. package/src/RivetLogger.ts +0 -60
package/src/State.test.ts CHANGED
@@ -36,26 +36,6 @@ 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
-
59
39
  it.effect("update applies f over read/write", () =>
60
40
  Effect.gen(function* () {
61
41
  const { s, cell } = yield* makeCellState(10);
@@ -64,38 +44,6 @@ describe("State", () => {
64
44
  }),
65
45
  );
66
46
 
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
-
99
47
  it.effect("updateAndGet returns the new value and commits it", () =>
100
48
  Effect.gen(function* () {
101
49
  const { s, cell } = yield* makeCellState(10);
@@ -105,17 +53,6 @@ describe("State", () => {
105
53
  }),
106
54
  );
107
55
 
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
-
119
56
  it.effect("modify returns B and commits the new value", () =>
120
57
  Effect.gen(function* () {
121
58
  const { s, cell } = yield* makeCellState("a");
@@ -128,17 +65,6 @@ describe("State", () => {
128
65
  }),
129
66
  );
130
67
 
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
-
142
68
  it.effect(
143
69
  "update is atomic across concurrent fibers (no lost updates)",
144
70
  () =>
@@ -163,7 +89,7 @@ describe("State", () => {
163
89
  );
164
90
  assert.deepStrictEqual(initial, [0]);
165
91
 
166
- yield* s[State.RuntimeTypeId].publishEffect(Effect.succeed(7));
92
+ State.publishUnsafe(s, 7);
167
93
  const later = yield* State.changes(s).pipe(
168
94
  Stream.take(1),
169
95
  Stream.runCollect,
@@ -177,17 +103,11 @@ describe("State", () => {
177
103
  const { s } = yield* makeCellState(0);
178
104
  yield* Effect.scoped(
179
105
  Effect.gen(function* () {
180
- const sub = yield* PubSub.subscribe(
181
- s[State.RuntimeTypeId].pubsub,
182
- );
106
+ const sub = yield* PubSub.subscribe(s.pubsub);
183
107
  assert.strictEqual(yield* PubSub.take(sub), 0);
184
108
 
185
- yield* s[State.RuntimeTypeId].publishEffect(
186
- Effect.succeed(1),
187
- );
188
- yield* s[State.RuntimeTypeId].publishEffect(
189
- Effect.succeed(2),
190
- );
109
+ yield* State.publish(s, 1);
110
+ yield* State.publish(s, 2);
191
111
  assert.strictEqual(yield* PubSub.take(sub), 1);
192
112
  assert.strictEqual(yield* PubSub.take(sub), 2);
193
113
  }),
@@ -195,19 +115,6 @@ describe("State", () => {
195
115
  }),
196
116
  );
197
117
 
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
-
211
118
  it.effect("set does NOT auto-publish — the runtime does", () =>
212
119
  Effect.gen(function* () {
213
120
  const { s } = yield* makeCellState(0);
@@ -239,61 +146,6 @@ describe("State", () => {
239
146
 
240
147
  yield* s.pipe(State.update((n) => n * 2));
241
148
  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);
297
149
  }),
298
150
  );
299
151
 
@@ -326,15 +178,4 @@ describe("State", () => {
326
178
  assert.isTrue(Exit.isFailure(exit));
327
179
  }),
328
180
  );
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
- );
340
181
  });
package/src/State.ts CHANGED
@@ -26,7 +26,6 @@ import {
26
26
  Predicate,
27
27
  PubSub,
28
28
  Semaphore,
29
- Scope,
30
29
  Stream,
31
30
  type Types,
32
31
  } from "effect";
@@ -34,15 +33,6 @@ import { dual } from "effect/Function";
34
33
 
35
34
  const TypeId = "~@rivetkit/effect/State";
36
35
 
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
-
46
36
  /**
47
37
  * A view over a persisted state cell with a subscribable change stream.
48
38
  *
@@ -55,97 +45,17 @@ export interface State<A, E = never, R = never>
55
45
  extends Variance<A, E, R>,
56
46
  Pipeable.Pipeable,
57
47
  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>;
146
48
  readonly read: () => Effect.Effect<A, E, R>;
147
49
  readonly write: (value: A) => Effect.Effect<void, E, R>;
148
50
  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;
149
59
  }
150
60
 
151
61
  export const isState = (u: unknown): u is State<unknown, unknown> =>
@@ -176,192 +86,47 @@ const Proto = {
176
86
  * The current value (per `read()`) is published to the pubsub on
177
87
  * construction so any subscription obtained later replays it.
178
88
  *
179
- * The backing PubSub is scoped and shuts down when the current
180
- * `Scope` closes.
89
+ * The PubSub is not explicitly shut down it's reclaimed by GC when
90
+ * the `State` and any subscribers become unreachable.
181
91
  */
182
92
  export const make = Effect.fnUntraced(function* <A, E, R>(
183
93
  read: () => Effect.Effect<A, E, R>,
184
94
  write: (value: A) => Effect.Effect<void, E, R>,
185
- ): Effect.fn.Return<State<A, E, R>, E, R | Scope.Scope> {
95
+ ): Effect.fn.Return<State<A, E, R>, E, R> {
186
96
  const pubsub = yield* PubSub.unbounded<A>({ replay: 1 });
187
- yield* Effect.addFinalizer(() => PubSub.shutdown(pubsub));
188
97
  const initial = yield* read();
189
- yield* PubSub.publish(pubsub, initial);
98
+ PubSub.publishUnsafe(pubsub, initial);
190
99
  const self = Object.create(Proto);
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);
100
+ self.read = read;
101
+ self.write = write;
102
+ self.pubsub = pubsub;
103
+ self.semaphore = Semaphore.makeUnsafe(1);
275
104
  return self;
276
105
  });
277
106
 
107
+ /**
108
+ * Reads the current value.
109
+ */
278
110
  export const get = <A, E, R>(self: State<A, E, R>): Effect.Effect<A, E, R> =>
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
- );
111
+ self.read();
346
112
 
113
+ /**
114
+ * Replaces the value. Serialized with `update` / `modify` so writes
115
+ * happen in invocation order.
116
+ */
347
117
  export const set: {
348
118
  <A>(value: A): <E, R>(self: State<A, E, R>) => Effect.Effect<void, E, R>;
349
119
  <A, E, R>(self: State<A, E, R>, value: A): Effect.Effect<void, E, R>;
350
120
  } = dual(
351
121
  2,
352
122
  <A, E, R>(self: State<A, E, R>, value: A): Effect.Effect<void, E, R> =>
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),
123
+ Semaphore.withPermit(self.semaphore, self.write(value)),
363
124
  );
364
125
 
126
+ /**
127
+ * Updates the value by applying `f` to the current value. The
128
+ * read/apply/write triple is atomic across fibers.
129
+ */
365
130
  export const update: {
366
131
  <A>(
367
132
  f: (a: A) => A,
@@ -372,49 +137,88 @@ export const update: {
372
137
  <A, E, R>(
373
138
  self: State<A, E, R>,
374
139
  f: (a: A) => A,
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),
140
+ ): Effect.Effect<void, E, R> =>
141
+ Semaphore.withPermit(
142
+ self.semaphore,
143
+ Effect.flatMap(self.read(), (a) => self.write(f(a))),
144
+ ),
392
145
  );
393
146
 
147
+ /**
148
+ * Updates the value by applying `f` and returns the new value. The
149
+ * read/apply/write triple is atomic across fibers.
150
+ */
394
151
  export const updateAndGet: {
395
152
  <A>(f: (a: A) => A): <E, R>(self: State<A, E, R>) => Effect.Effect<A, E, R>;
396
153
  <A, E, R>(self: State<A, E, R>, f: (a: A) => A): Effect.Effect<A, E, R>;
397
154
  } = dual(
398
155
  2,
399
156
  <A, E, R>(self: State<A, E, R>, f: (a: A) => A): Effect.Effect<A, E, R> =>
400
- self.updateAndGet(f),
157
+ Semaphore.withPermit(
158
+ self.semaphore,
159
+ Effect.flatMap(self.read(), (a) => {
160
+ const next = f(a);
161
+ return Effect.as(self.write(next), next);
162
+ }),
163
+ ),
401
164
  );
402
165
 
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>(
166
+ /**
167
+ * Atomically replaces the value with the second element of `f(prev)`
168
+ * and returns the first. The read/apply/write triple is atomic across
169
+ * fibers.
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>(
408
176
  self: State<A, E, R>,
409
- f: (a: A) => Effect.Effect<A, E2, R2>,
410
- ): Effect.Effect<A, E | E2, R | R2>;
177
+ f: (a: A) => readonly [B, A],
178
+ ): Effect.Effect<B, E, R>;
411
179
  } = dual(
412
180
  2,
413
- <A, E, R, E2, R2>(
181
+ <A, E, R, B>(
414
182
  self: State<A, E, R>,
415
- f: (a: A) => Effect.Effect<A, E2, R2>,
416
- ): Effect.Effect<A, E | E2, R | R2> => self.updateAndGetEffect(f),
183
+ f: (a: A) => readonly [B, A],
184
+ ): Effect.Effect<B, E, R> =>
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
+ ),
417
192
  );
418
193
 
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
+ */
419
199
  export const changes = <A, E, R>(self: State<A, E, R>): Stream.Stream<A> =>
420
- self.changes;
200
+ Stream.fromPubSub(self.pubsub);
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);