@rivetkit/effect 0.0.0-main.879b6a2 → 0.0.0-sqlite-uds.4e59a38

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 (67) hide show
  1. package/dist/Actor.d.ts +2 -3
  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 +6 -4
  7. package/dist/Client.js.map +1 -1
  8. package/dist/Registry.d.ts +69 -7
  9. package/dist/Registry.d.ts.map +1 -1
  10. package/dist/Registry.js +93 -40
  11. package/dist/Registry.js.map +1 -1
  12. package/dist/RivetError.d.ts +18 -3
  13. package/dist/RivetError.d.ts.map +1 -1
  14. package/dist/RivetError.js +31 -0
  15. package/dist/RivetError.js.map +1 -1
  16. package/dist/RivetLogger.d.ts +41 -0
  17. package/dist/RivetLogger.d.ts.map +1 -0
  18. package/dist/RivetLogger.js +41 -0
  19. package/dist/RivetLogger.js.map +1 -0
  20. package/dist/State.d.ts +92 -56
  21. package/dist/State.d.ts.map +1 -1
  22. package/dist/State.js +51 -57
  23. package/dist/State.js.map +1 -1
  24. package/dist/internal/ActionDispatcher.d.ts.map +1 -1
  25. package/dist/internal/ActionDispatcher.js.map +1 -1
  26. package/dist/internal/ActorInstanceManager.d.ts.map +1 -1
  27. package/dist/internal/ActorInstanceManager.js +4 -4
  28. package/dist/internal/ActorInstanceManager.js.map +1 -1
  29. package/dist/internal/ActorStateAdapter.d.ts +1 -1
  30. package/dist/internal/ActorStateAdapter.d.ts.map +1 -1
  31. package/dist/internal/ActorStateAdapter.js +2 -7
  32. package/dist/internal/ActorStateAdapter.js.map +1 -1
  33. package/dist/internal/StateOptions.d.ts +1 -0
  34. package/dist/internal/StateOptions.d.ts.map +1 -1
  35. package/dist/internal/logging.d.ts +6 -7
  36. package/dist/internal/logging.d.ts.map +1 -1
  37. package/dist/internal/logging.js +78 -102
  38. package/dist/internal/logging.js.map +1 -1
  39. package/dist/mod.d.ts +1 -1
  40. package/dist/mod.d.ts.map +1 -1
  41. package/dist/mod.js +1 -1
  42. package/dist/mod.js.map +1 -1
  43. package/package.json +3 -2
  44. package/src/Actor.test-d.ts +32 -0
  45. package/src/Actor.test.ts +4 -1
  46. package/src/Actor.ts +29 -4
  47. package/src/Client.test.ts +22 -26
  48. package/src/Client.ts +6 -4
  49. package/src/Registry.test.ts +12 -23
  50. package/src/Registry.ts +131 -70
  51. package/src/RivetError.test.ts +11 -0
  52. package/src/RivetError.ts +37 -0
  53. package/src/RivetLogger.ts +60 -0
  54. package/src/State.test.ts +163 -4
  55. package/src/State.ts +293 -97
  56. package/src/internal/ActionDispatcher.ts +8 -11
  57. package/src/internal/ActorInstanceManager.ts +32 -38
  58. package/src/internal/ActorStateAdapter.ts +5 -11
  59. package/src/internal/StateOptions.ts +4 -0
  60. package/src/internal/logging.test.ts +107 -121
  61. package/src/internal/logging.ts +103 -143
  62. package/src/mod.ts +1 -1
  63. package/dist/Logger.d.ts +0 -29
  64. package/dist/Logger.d.ts.map +0 -1
  65. package/dist/Logger.js +0 -31
  66. package/dist/Logger.js.map +0 -1
  67. package/src/Logger.ts +0 -43
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 not explicitly shut down it's reclaimed by GC when
90
- * the `State` and any subscribers become unreachable.
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.publishUnsafe(pubsub, initial);
189
+ yield* PubSub.publish(pubsub, initial);
99
190
  const self = Object.create(Proto);
100
- self.read = read;
101
- self.write = write;
102
- self.pubsub = pubsub;
103
- self.semaphore = Semaphore.makeUnsafe(1);
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.read();
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
- Semaphore.withPermit(self.semaphore, self.write(value)),
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
- Semaphore.withPermit(
142
- self.semaphore,
143
- Effect.flatMap(self.read(), (a) => self.write(f(a))),
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
- 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
- ),
400
+ self.updateAndGet(f),
164
401
  );
165
402
 
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>(
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) => readonly [B, A],
178
- ): Effect.Effect<B, E, R>;
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, B>(
413
+ <A, E, R, E2, R2>(
182
414
  self: State<A, E, R>,
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
- ),
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
- 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);
420
+ self.changes;
@@ -10,11 +10,7 @@ import {
10
10
  } from "effect";
11
11
  import * as Rivetkit from "rivetkit";
12
12
  import type * as Action from "../Action.ts";
13
- import type {
14
- ActionHandlersFrom,
15
- ActionRequest,
16
- Actor,
17
- } from "../Actor.ts";
13
+ import type { ActionHandlersFrom, ActionRequest, Actor } from "../Actor.ts";
18
14
  import type * as Client from "../Client.ts";
19
15
  import * as ActionErrorEnvelope from "./ActionErrorEnvelope.ts";
20
16
  import { makeActorLogAnnotations } from "./logging.ts";
@@ -96,12 +92,13 @@ export const make = <
96
92
  const decodedPayload = yield* decodePayload(
97
93
  payloadForDecode,
98
94
  ).pipe(
99
- Effect.mapError(() =>
100
- new Rivetkit.RivetError(
101
- "request",
102
- "invalid",
103
- `Invalid payload for action ${actor.name}/${action._tag}`,
104
- ),
95
+ Effect.mapError(
96
+ () =>
97
+ new Rivetkit.RivetError(
98
+ "request",
99
+ "invalid",
100
+ `Invalid payload for action ${actor.name}/${action._tag}`,
101
+ ),
105
102
  ),
106
103
  );
107
104
  // The payload was decoded with this action's schema,
@@ -71,49 +71,43 @@ export const make = Effect.fnUntraced(function* <
71
71
  const services = yield* Effect.context<any>();
72
72
  const runPromise = Effect.runPromiseWith(services);
73
73
 
74
- const makeInstance = Effect.fnUntraced(function* (
75
- c: WakeContext<StateDefinition, Database>,
76
- ): Effect.fn.Return<Instance<ActionHandlers, StateDefinition>, never, any> {
77
- const scope = yield* Scope.make();
78
- return yield* Effect.gen(function* () {
79
- const state = stateAdapter
80
- ? yield* stateAdapter.makeStateView(c)
81
- : undefined;
82
- const context = makeContext(c, scope);
83
- const actionHandlers = yield* wakeHandler(
84
- makeWakeOptions(c, state),
85
- ).pipe(Effect.provide(context));
86
- const runFork = yield* FiberSet.makeRuntime<
87
- any,
88
- unknown,
89
- unknown
90
- >().pipe(Effect.provide(Context.merge(services, context)));
74
+ const makeInstance = Effect.fnUntraced(function* (
75
+ c: WakeContext<StateDefinition, Database>,
76
+ ): Effect.fn.Return<Instance<ActionHandlers, StateDefinition>, never, any> {
77
+ const scope = yield* Scope.make();
78
+ return yield* Effect.gen(function* () {
79
+ const state = stateAdapter
80
+ ? yield* stateAdapter
81
+ .makeStateView(c)
82
+ .pipe(Effect.provideService(Scope.Scope, scope))
83
+ : undefined;
84
+ const context = makeContext(c, scope);
85
+ const actionHandlers = yield* wakeHandler(
86
+ makeWakeOptions(c, state),
87
+ ).pipe(Effect.provide(context));
88
+ const runFork = yield* FiberSet.makeRuntime<
89
+ any,
90
+ unknown,
91
+ unknown
92
+ >().pipe(Effect.provide(Context.merge(services, context)));
91
93
 
92
- return {
93
- actionHandlers,
94
- runFork,
95
- scope,
96
- state,
97
- };
98
- }).pipe(
99
- Effect.onError((cause) =>
100
- Scope.close(scope, Exit.failCause(cause)),
101
- ),
102
- );
103
- });
94
+ return {
95
+ actionHandlers,
96
+ runFork,
97
+ scope,
98
+ state,
99
+ };
100
+ }).pipe(
101
+ Effect.onError((cause) =>
102
+ Scope.close(scope, Exit.failCause(cause)),
103
+ ),
104
+ );
105
+ });
104
106
 
105
107
  return {
106
108
  get: (actorId: string) => instances.get(actorId),
107
109
  onWake: async (c: WakeContext<StateDefinition, Database>) => {
108
- await runPromise(
109
- makeInstance(c).pipe(
110
- Effect.tap((instance) =>
111
- Effect.sync(() => {
112
- instances.set(c.actorId, instance);
113
- }),
114
- ),
115
- ),
116
- );
110
+ instances.set(c.actorId, await runPromise(makeInstance(c)));
117
111
  },
118
112
  onStateChange: stateAdapter
119
113
  ? (
@@ -1,10 +1,11 @@
1
- import { Effect, type Fiber, Schema, Semaphore } from "effect";
1
+ import { Effect, type Fiber, Schema } from "effect";
2
2
  import * as State from "../State.ts";
3
3
  import type * as StateOptions from "./StateOptions.ts";
4
4
 
5
5
  export type ActorState<StateDefinition extends StateOptions.Any> = State.State<
6
6
  StateOptions.Decoded<StateDefinition>,
7
- Schema.SchemaError
7
+ Schema.SchemaError,
8
+ StateOptions.Services<StateDefinition>
8
9
  >;
9
10
 
10
11
  type StateInstance<StateDefinition extends StateOptions.Any> = {
@@ -71,15 +72,8 @@ export const make = Effect.fnUntraced(function* <
71
72
  const state = yield* Effect.fromNullishOr(
72
73
  instance.state,
73
74
  ).pipe(Effect.orDie);
74
-
75
- yield* Semaphore.withPermit(
76
- state.semaphore,
77
- Effect.gen(function* () {
78
- const decoded = yield* stateCodec
79
- .decodeUnknown(newState)
80
- .pipe(Effect.orDie);
81
- State.publishUnsafe(state, decoded);
82
- }),
75
+ yield* state[State.RuntimeTypeId].publishEffect(
76
+ stateCodec.decodeUnknown(newState).pipe(Effect.orDie),
83
77
  );
84
78
  }),
85
79
  );
@@ -10,6 +10,10 @@ export interface Any {
10
10
  readonly initialValue: () => unknown;
11
11
  }
12
12
 
13
+ export type Services<State extends Any> =
14
+ | State["schema"]["DecodingServices"]
15
+ | State["schema"]["EncodingServices"];
16
+
13
17
  export type Encoded<State extends Any> =
14
18
  | State["schema"]["Encoded"]
15
19
  | ([State] extends [never] ? undefined : never);