@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.
- 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/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 +3 -2
- package/src/Actor.test-d.ts +32 -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 +37 -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/Actor.ts
CHANGED
|
@@ -175,7 +175,8 @@ type WakeOptionsFor<
|
|
|
175
175
|
: {
|
|
176
176
|
readonly state: State.State<
|
|
177
177
|
StateOptions.Decoded<StateDefinition>,
|
|
178
|
-
Schema.SchemaError
|
|
178
|
+
Schema.SchemaError,
|
|
179
|
+
StateOptions.Services<StateDefinition>
|
|
179
180
|
>;
|
|
180
181
|
});
|
|
181
182
|
|
|
@@ -232,6 +233,7 @@ type ToLayerRequirements<
|
|
|
232
233
|
| ExcludeBuiltInWakeServices<R, State>
|
|
233
234
|
| ExcludeBuiltInWakeServices<RX, State>
|
|
234
235
|
| UnknownToNever<ActionHandlerServices<ActionHandlers>>
|
|
236
|
+
| UnknownToNever<StateOptions.Services<State>>
|
|
235
237
|
| UnknownToNever<Action.ServicesServer<Actions>>
|
|
236
238
|
| UnknownToNever<Action.ServicesClient<Actions>>
|
|
237
239
|
| Registry.Registry;
|
|
@@ -334,9 +336,9 @@ const Proto: Omit<Actor<any, any>, "name" | "actions"> = {
|
|
|
334
336
|
>(wake),
|
|
335
337
|
options,
|
|
336
338
|
}).pipe(
|
|
337
|
-
Effect.
|
|
339
|
+
Effect.tap((rivetKitActor) =>
|
|
338
340
|
Registry.Registry.pipe(
|
|
339
|
-
Effect.
|
|
341
|
+
Effect.tap((registry) =>
|
|
340
342
|
Effect.sync(() =>
|
|
341
343
|
registry.rivetkitActors.set(
|
|
342
344
|
this.name,
|
|
@@ -375,6 +377,29 @@ export const make = <
|
|
|
375
377
|
return self;
|
|
376
378
|
};
|
|
377
379
|
|
|
380
|
+
/**
|
|
381
|
+
* Normalizes any supported actor wake declaration into a wake function.
|
|
382
|
+
*
|
|
383
|
+
* @remarks
|
|
384
|
+
* {@link Actor.toLayer|`Actor.toLayer()`} accepts several equivalent shapes so actor
|
|
385
|
+
* implementations can choose the amount of initialization they need:
|
|
386
|
+
*
|
|
387
|
+
* - a plain action-handler object
|
|
388
|
+
* - an `Effect` that builds an action-handler object
|
|
389
|
+
* - a wake function that receives `wakeOptions` and returns handlers
|
|
390
|
+
* - a wake function that returns an `Effect` of handlers
|
|
391
|
+
* - an `Effect` that builds one of those wake functions
|
|
392
|
+
*
|
|
393
|
+
* This helper resolves those forms lazily for each actor wake and returns a
|
|
394
|
+
* single `(wakeOptions) => Effect<handlers>` representation. It does not run a
|
|
395
|
+
* wake function until the returned function is invoked, so per-wake resources,
|
|
396
|
+
* services, and state are scoped to the specific actor instance that is waking.
|
|
397
|
+
*
|
|
398
|
+
* @param wake - A supported wake declaration shape.
|
|
399
|
+
* @returns A function that resolves action handlers for one actor wake.
|
|
400
|
+
*
|
|
401
|
+
* @internal
|
|
402
|
+
*/
|
|
378
403
|
export function toWakeHandler<
|
|
379
404
|
ActionHandlers extends object,
|
|
380
405
|
R,
|
|
@@ -443,7 +468,7 @@ export function toWakeHandler<
|
|
|
443
468
|
|
|
444
469
|
return wakeEffect.pipe(
|
|
445
470
|
Effect.flatMap((resolvedWake) => {
|
|
446
|
-
if (
|
|
471
|
+
if (Predicate.isFunction(resolvedWake)) {
|
|
447
472
|
const actionHandlers = resolvedWake(wakeOptions);
|
|
448
473
|
return Effect.isEffect(actionHandlers)
|
|
449
474
|
? actionHandlers
|
package/src/Client.test.ts
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
import { assert, describe, it } from "@effect/vitest";
|
|
2
|
-
import { Client,
|
|
2
|
+
import { Client, RivetError, RivetLogger } from "@rivetkit/effect";
|
|
3
3
|
import { Effect, Layer, Schema } from "effect";
|
|
4
4
|
import * as RivetkitErrors from "rivetkit/errors";
|
|
5
|
-
import
|
|
6
|
-
configureDefaultLogger,
|
|
7
|
-
getBaseLogger,
|
|
8
|
-
type Logger as PinoLogger,
|
|
9
|
-
} from "rivetkit/log";
|
|
5
|
+
import * as RivetkitLog from "rivetkit/log";
|
|
10
6
|
import * as ActionErrorEnvelope from "./internal/ActionErrorEnvelope";
|
|
11
7
|
|
|
12
8
|
function makeTestLogger(
|
|
@@ -15,19 +11,12 @@ function makeTestLogger(
|
|
|
15
11
|
readonly fields: Record<string, unknown>;
|
|
16
12
|
readonly msg: string | undefined;
|
|
17
13
|
}>,
|
|
18
|
-
):
|
|
14
|
+
): RivetkitLog.Logger {
|
|
19
15
|
const logger: Record<string, unknown> = {
|
|
20
16
|
level: "debug",
|
|
21
17
|
child: () => logger,
|
|
22
18
|
};
|
|
23
|
-
for (const level of [
|
|
24
|
-
"trace",
|
|
25
|
-
"debug",
|
|
26
|
-
"info",
|
|
27
|
-
"warn",
|
|
28
|
-
"error",
|
|
29
|
-
"fatal",
|
|
30
|
-
]) {
|
|
19
|
+
for (const level of ["trace", "debug", "info", "warn", "error", "fatal"]) {
|
|
31
20
|
logger[level] = (
|
|
32
21
|
fields: Record<string, unknown>,
|
|
33
22
|
msg?: string,
|
|
@@ -36,7 +25,7 @@ function makeTestLogger(
|
|
|
36
25
|
};
|
|
37
26
|
}
|
|
38
27
|
|
|
39
|
-
return logger as unknown as
|
|
28
|
+
return logger as unknown as RivetkitLog.Logger;
|
|
40
29
|
}
|
|
41
30
|
|
|
42
31
|
describe("Client", () => {
|
|
@@ -46,13 +35,15 @@ describe("Client", () => {
|
|
|
46
35
|
const baseLogger = makeTestLogger();
|
|
47
36
|
|
|
48
37
|
yield* Effect.addFinalizer(() =>
|
|
49
|
-
Effect.sync(() =>
|
|
38
|
+
Effect.sync(() =>
|
|
39
|
+
RivetkitLog.configureDefaultLogger("silent"),
|
|
40
|
+
),
|
|
50
41
|
);
|
|
51
42
|
yield* Client.make({
|
|
52
43
|
endpoint: "http://127.0.0.1:6420",
|
|
53
|
-
}).pipe(Effect.provide(
|
|
44
|
+
}).pipe(Effect.provide(RivetLogger.layerFromPino(baseLogger)));
|
|
54
45
|
|
|
55
|
-
assert.strictEqual(getBaseLogger(), baseLogger);
|
|
46
|
+
assert.strictEqual(RivetkitLog.getBaseLogger(), baseLogger);
|
|
56
47
|
}),
|
|
57
48
|
),
|
|
58
49
|
);
|
|
@@ -68,7 +59,9 @@ describe("Client", () => {
|
|
|
68
59
|
const baseLogger = makeTestLogger(entries);
|
|
69
60
|
|
|
70
61
|
yield* Effect.addFinalizer(() =>
|
|
71
|
-
Effect.sync(() =>
|
|
62
|
+
Effect.sync(() =>
|
|
63
|
+
RivetkitLog.configureDefaultLogger("silent"),
|
|
64
|
+
),
|
|
72
65
|
);
|
|
73
66
|
yield* Effect.gen(function* () {
|
|
74
67
|
yield* Client.Client;
|
|
@@ -80,16 +73,19 @@ describe("Client", () => {
|
|
|
80
73
|
Client.layer({
|
|
81
74
|
endpoint: "http://127.0.0.1:6420",
|
|
82
75
|
}).pipe(
|
|
83
|
-
Layer.provideMerge(
|
|
76
|
+
Layer.provideMerge(
|
|
77
|
+
RivetLogger.layerFromPino(baseLogger),
|
|
78
|
+
),
|
|
84
79
|
),
|
|
85
80
|
),
|
|
86
81
|
);
|
|
87
82
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
83
|
+
const entry = entries[0];
|
|
84
|
+
assert.ok(entry !== undefined);
|
|
85
|
+
assert.strictEqual(entry.level, "info");
|
|
86
|
+
assert.strictEqual(entry.msg, "client effect log");
|
|
87
|
+
assert.strictEqual(entry.fields.clientId, "test-client");
|
|
88
|
+
assert.strictEqual(typeof entry.fields.fiberId, "string");
|
|
93
89
|
assert.ok(
|
|
94
90
|
entries.some(
|
|
95
91
|
(entry) =>
|
package/src/Client.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { Context, Effect, Layer, Record, Result, Schema } from "effect";
|
|
2
2
|
import * as RivetkitClient from "rivetkit/client";
|
|
3
3
|
import * as RivetkitErrors from "rivetkit/errors";
|
|
4
|
-
import
|
|
4
|
+
import * as RivetkitLog from "rivetkit/log";
|
|
5
5
|
import type * as Action from "./Action.ts";
|
|
6
6
|
import type * as Actor from "./Actor.ts";
|
|
7
7
|
import * as ActionErrorEnvelope from "./internal/ActionErrorEnvelope.ts";
|
|
8
8
|
import { getOrCreateBaseLogger } from "./internal/logging.ts";
|
|
9
9
|
import { rpcSystem, type TraceMeta } from "./internal/tracing.ts";
|
|
10
|
-
import * as
|
|
10
|
+
import * as RivetLogger from "./RivetLogger.ts";
|
|
11
11
|
import * as RivetError from "./RivetError.ts";
|
|
12
12
|
|
|
13
13
|
const TypeId = "~@rivetkit/effect/Client";
|
|
@@ -49,7 +49,9 @@ export const make = Effect.fnUntraced(function* (options: Options = {}) {
|
|
|
49
49
|
const baseLogger = yield* getOrCreateBaseLogger;
|
|
50
50
|
const rivetkitClient = yield* Effect.acquireRelease(
|
|
51
51
|
Effect.sync(() => {
|
|
52
|
-
|
|
52
|
+
// Raw RivetKit clients do not accept a logger in their config,
|
|
53
|
+
// so install the Effect-selected logger before construction.
|
|
54
|
+
RivetkitLog.configureBaseLogger(baseLogger);
|
|
53
55
|
return RivetkitClient.createClient(options);
|
|
54
56
|
}),
|
|
55
57
|
(c) => Effect.promise(() => c.dispose()),
|
|
@@ -146,7 +148,7 @@ export const layer = (options: Options = {}): Layer.Layer<Client> =>
|
|
|
146
148
|
Layer.unwrap(
|
|
147
149
|
Effect.map(getOrCreateBaseLogger, (baseLogger) =>
|
|
148
150
|
Layer.effect(Client, make(options)).pipe(
|
|
149
|
-
Layer.provideMerge(
|
|
151
|
+
Layer.provideMerge(RivetLogger.layerFromPino(baseLogger)),
|
|
150
152
|
),
|
|
151
153
|
),
|
|
152
154
|
);
|
package/src/Registry.test.ts
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
import { assert, describe, it } from "@effect/vitest";
|
|
2
|
-
import { Action, Actor,
|
|
2
|
+
import { Action, Actor, Registry, RivetLogger } from "@rivetkit/effect";
|
|
3
3
|
import { Effect, Layer } from "effect";
|
|
4
4
|
import { HttpEffect } from "effect/unstable/http";
|
|
5
|
-
import
|
|
6
|
-
configureDefaultLogger,
|
|
7
|
-
getBaseLogger,
|
|
8
|
-
type Logger as PinoLogger,
|
|
9
|
-
} from "rivetkit/log";
|
|
5
|
+
import * as RivetkitLog from "rivetkit/log";
|
|
10
6
|
import { vi } from "vitest";
|
|
11
7
|
|
|
12
8
|
const TestActor = Actor.make("TestActor", {
|
|
@@ -28,23 +24,16 @@ const RegistryLive = ActorsLayer.pipe(
|
|
|
28
24
|
),
|
|
29
25
|
);
|
|
30
26
|
|
|
31
|
-
function makeTestLogger():
|
|
27
|
+
function makeTestLogger(): RivetkitLog.Logger {
|
|
32
28
|
const logger: Record<string, unknown> = {
|
|
33
29
|
level: "debug",
|
|
34
30
|
child: () => logger,
|
|
35
31
|
};
|
|
36
|
-
for (const level of [
|
|
37
|
-
"trace",
|
|
38
|
-
"debug",
|
|
39
|
-
"info",
|
|
40
|
-
"warn",
|
|
41
|
-
"error",
|
|
42
|
-
"fatal",
|
|
43
|
-
]) {
|
|
32
|
+
for (const level of ["trace", "debug", "info", "warn", "error", "fatal"]) {
|
|
44
33
|
logger[level] = (): void => {};
|
|
45
34
|
}
|
|
46
35
|
|
|
47
|
-
return logger as unknown as
|
|
36
|
+
return logger as unknown as RivetkitLog.Logger;
|
|
48
37
|
}
|
|
49
38
|
|
|
50
39
|
describe("Registry.toWebHandler", () => {
|
|
@@ -207,8 +196,7 @@ describe("Registry.toWebHandler", () => {
|
|
|
207
196
|
}),
|
|
208
197
|
),
|
|
209
198
|
);
|
|
210
|
-
const { handler, dispose } =
|
|
211
|
-
Registry.toWebHandler(WelcomeRegistryLive);
|
|
199
|
+
const { handler, dispose } = Registry.toWebHandler(WelcomeRegistryLive);
|
|
212
200
|
|
|
213
201
|
try {
|
|
214
202
|
const first = await handler(
|
|
@@ -232,10 +220,11 @@ describe("Registry.toWebHandler", () => {
|
|
|
232
220
|
it("uses a custom logger layer for the underlying RivetKit registry", async () => {
|
|
233
221
|
const baseLogger = makeTestLogger();
|
|
234
222
|
const CustomLoggerRegistryLive = RegistryLive.pipe(
|
|
235
|
-
Layer.provide(
|
|
223
|
+
Layer.provide(RivetLogger.layerFromPino(baseLogger)),
|
|
224
|
+
);
|
|
225
|
+
const { handler, dispose } = Registry.toWebHandler(
|
|
226
|
+
CustomLoggerRegistryLive,
|
|
236
227
|
);
|
|
237
|
-
const { handler, dispose } =
|
|
238
|
-
Registry.toWebHandler(CustomLoggerRegistryLive);
|
|
239
228
|
|
|
240
229
|
try {
|
|
241
230
|
const response = await handler(
|
|
@@ -243,10 +232,10 @@ describe("Registry.toWebHandler", () => {
|
|
|
243
232
|
);
|
|
244
233
|
|
|
245
234
|
assert.strictEqual(response.status, 200);
|
|
246
|
-
assert.strictEqual(getBaseLogger(), baseLogger);
|
|
235
|
+
assert.strictEqual(RivetkitLog.getBaseLogger(), baseLogger);
|
|
247
236
|
} finally {
|
|
248
237
|
await dispose();
|
|
249
|
-
configureDefaultLogger("silent");
|
|
238
|
+
RivetkitLog.configureDefaultLogger("silent");
|
|
250
239
|
}
|
|
251
240
|
});
|
|
252
241
|
|
package/src/Registry.ts
CHANGED
|
@@ -7,13 +7,10 @@ import {
|
|
|
7
7
|
type HttpServerResponse,
|
|
8
8
|
} from "effect/unstable/http";
|
|
9
9
|
import * as Rivetkit from "rivetkit";
|
|
10
|
-
import
|
|
11
|
-
configureBaseLogger,
|
|
12
|
-
type Logger as PinoLogger,
|
|
13
|
-
} from "rivetkit/log";
|
|
10
|
+
import * as RivetkitLog from "rivetkit/log";
|
|
14
11
|
import * as Client from "./Client.ts";
|
|
15
12
|
import { BaseLogger, getOrCreateBaseLogger } from "./internal/logging.ts";
|
|
16
|
-
import * as
|
|
13
|
+
import * as RivetLogger from "./RivetLogger.ts";
|
|
17
14
|
|
|
18
15
|
const TypeId = "~@rivetkit/effect/Registry";
|
|
19
16
|
type ServerlessOptions = NonNullable<
|
|
@@ -22,7 +19,7 @@ type ServerlessOptions = NonNullable<
|
|
|
22
19
|
|
|
23
20
|
export type Options = Pick<
|
|
24
21
|
Rivetkit.RegistryConfigInput<Rivetkit.RegistryActors>,
|
|
25
|
-
"endpoint" | "token" | "namespace" | "noWelcome"
|
|
22
|
+
"endpoint" | "token" | "namespace" | "noWelcome" | "sqlite"
|
|
26
23
|
>;
|
|
27
24
|
|
|
28
25
|
export interface Registry {
|
|
@@ -30,7 +27,7 @@ export interface Registry {
|
|
|
30
27
|
|
|
31
28
|
readonly options: Options;
|
|
32
29
|
|
|
33
|
-
readonly baseLogger:
|
|
30
|
+
readonly baseLogger: RivetkitLog.Logger;
|
|
34
31
|
|
|
35
32
|
readonly rivetkitActors: Map<string, Rivetkit.AnyActorDefinition>;
|
|
36
33
|
}
|
|
@@ -38,20 +35,49 @@ export interface Registry {
|
|
|
38
35
|
export const Registry: Context.Service<Registry, Registry> =
|
|
39
36
|
Context.Service<Registry>("@rivetkit/effect/Registry");
|
|
40
37
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
|
|
38
|
+
/**
|
|
39
|
+
* Creates the shared registry that actor layers register into.
|
|
40
|
+
*
|
|
41
|
+
* @remarks
|
|
42
|
+
* Actor layers created with {@link Actor.Actor.toLayer|`Actor.toLayer()`}
|
|
43
|
+
* register into this service. Registry entrypoints such as
|
|
44
|
+
* {@link serve|`Registry.serve()`}, {@link toWebHandler|`Registry.toWebHandler()`},
|
|
45
|
+
* and {@link toHttpEffect|`Registry.toHttpEffect()`} later use the collected
|
|
46
|
+
* actors to create the underlying RivetKit runtime.
|
|
47
|
+
*
|
|
48
|
+
* @param options - RivetKit runtime options shared by the registered actors.
|
|
49
|
+
*
|
|
50
|
+
* @returns A layer that provides the {@link Registry|`Registry.Registry`}
|
|
51
|
+
* service.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```ts
|
|
55
|
+
* import { Registry } from "@rivetkit/effect"
|
|
56
|
+
* import { Layer } from "effect"
|
|
57
|
+
*
|
|
58
|
+
* const ActorsLayer = Layer.mergeAll(ChatRoomLive, ModeratorLive)
|
|
59
|
+
*
|
|
60
|
+
* const MainLayer = Registry.serve(ActorsLayer).pipe(
|
|
61
|
+
* Layer.provide(Registry.layer({ endpoint: "http://127.0.0.1:6420" }))
|
|
62
|
+
* )
|
|
63
|
+
* ```
|
|
64
|
+
*
|
|
65
|
+
* @see {@link serve|`Registry.serve()`} for starting a long-running actor
|
|
66
|
+
* server.
|
|
67
|
+
* @see {@link toWebHandler|`Registry.toWebHandler()`} for Fetch-compatible
|
|
68
|
+
* serverless handlers.
|
|
69
|
+
* @see {@link toHttpEffect|`Registry.toHttpEffect()`} for Effect HTTP handlers.
|
|
70
|
+
*/
|
|
50
71
|
export const layer = (options: Options = {}): Layer.Layer<Registry> =>
|
|
51
72
|
Layer.effect(
|
|
52
73
|
Registry,
|
|
53
74
|
Effect.map(getOrCreateBaseLogger, (baseLogger) =>
|
|
54
|
-
|
|
75
|
+
Registry.of({
|
|
76
|
+
[TypeId]: TypeId,
|
|
77
|
+
options,
|
|
78
|
+
baseLogger,
|
|
79
|
+
rivetkitActors: new Map(),
|
|
80
|
+
}),
|
|
55
81
|
),
|
|
56
82
|
);
|
|
57
83
|
|
|
@@ -60,40 +86,70 @@ const setupRivetkitRegistry = (
|
|
|
60
86
|
options?: {
|
|
61
87
|
readonly serverless?: ServerlessOptions | undefined;
|
|
62
88
|
},
|
|
63
|
-
) =>
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
89
|
+
) =>
|
|
90
|
+
Effect.sync(() =>
|
|
91
|
+
Rivetkit.setup({
|
|
92
|
+
use: Object.fromEntries(registry.rivetkitActors),
|
|
93
|
+
...registry.options,
|
|
94
|
+
logging: { baseLogger: registry.baseLogger },
|
|
95
|
+
...(options?.serverless === undefined
|
|
96
|
+
? {}
|
|
97
|
+
: { serverless: options.serverless }),
|
|
98
|
+
}),
|
|
99
|
+
);
|
|
74
100
|
|
|
75
101
|
/**
|
|
76
|
-
*
|
|
102
|
+
* Serves the actors registered by `actorsLayer`.
|
|
103
|
+
*
|
|
104
|
+
* @remarks
|
|
105
|
+
* Provide this with {@link layer|`Registry.layer()`} at the application root.
|
|
106
|
+
* Building the returned layer evaluates the actor layer, collects its registered
|
|
107
|
+
* actors, and starts the underlying RivetKit runtime using the options from
|
|
108
|
+
* {@link layer|`Registry.layer()`}. Launch the resulting layer with
|
|
109
|
+
* {@link Layer.launch|`Layer.launch()`} to keep the server process alive.
|
|
110
|
+
*
|
|
111
|
+
* @param actorsLayer - A layer containing one or more
|
|
112
|
+
* {@link Actor.Actor.toLayer|`Actor.toLayer()`} registrations.
|
|
113
|
+
*
|
|
114
|
+
* @returns A side-effecting startup layer that requires the
|
|
115
|
+
* {@link Registry|`Registry.Registry`} service and the services required by
|
|
116
|
+
* `actorsLayer`.
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```ts
|
|
120
|
+
* import { Registry } from "@rivetkit/effect"
|
|
121
|
+
* import { Layer } from "effect"
|
|
122
|
+
*
|
|
123
|
+
* const ActorsLayer = Layer.mergeAll(ChatRoomLive, ModeratorLive)
|
|
124
|
+
*
|
|
125
|
+
* const MainLayer = Registry.serve(ActorsLayer).pipe(
|
|
126
|
+
* Layer.provide(Registry.layer({ endpoint: "http://127.0.0.1:6420" }))
|
|
127
|
+
* )
|
|
128
|
+
*
|
|
129
|
+
* Layer.launch(MainLayer).pipe(NodeRuntime.runMain);
|
|
130
|
+
* ```
|
|
131
|
+
*
|
|
132
|
+
* @see {@link toWebHandler|`Registry.toWebHandler()`} for Fetch-compatible
|
|
133
|
+
* serverless handlers.
|
|
134
|
+
* @see {@link toHttpEffect|`Registry.toHttpEffect()`} for Effect HTTP handlers.
|
|
77
135
|
*
|
|
78
|
-
* The actor layer is built in the server layer scope. Registered Rivet Actors
|
|
79
|
-
* are collected from `Registry`, materialized into a single underlying RivetKit
|
|
80
|
-
* registry, and started.
|
|
81
136
|
*/
|
|
82
137
|
export const serve = <E, R>(
|
|
83
138
|
actorsLayer: Layer.Layer<never, E, R>,
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
139
|
+
): Layer.Layer<never, E, R | Registry> =>
|
|
140
|
+
Layer.effectDiscard(
|
|
141
|
+
Effect.gen(function* () {
|
|
142
|
+
const registry = yield* Registry;
|
|
143
|
+
yield* Layer.build(
|
|
144
|
+
actorsLayer.pipe(
|
|
145
|
+
Layer.provideMerge(
|
|
146
|
+
RivetLogger.layerFromPino(registry.baseLogger),
|
|
92
147
|
),
|
|
93
|
-
)
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
148
|
+
),
|
|
149
|
+
);
|
|
150
|
+
const rivetkitRegistry = yield* setupRivetkitRegistry(registry);
|
|
151
|
+
yield* Effect.sync(() => rivetkitRegistry.start());
|
|
152
|
+
}),
|
|
97
153
|
);
|
|
98
154
|
|
|
99
155
|
/**
|
|
@@ -110,7 +166,7 @@ export const test: Layer.Layer<Client.Client, never, Registry> = Layer.effect(
|
|
|
110
166
|
Client.Client,
|
|
111
167
|
Effect.gen(function* () {
|
|
112
168
|
const registry = yield* Registry;
|
|
113
|
-
const rivetkitRegistry = setupRivetkitRegistry(registry);
|
|
169
|
+
const rivetkitRegistry = yield* setupRivetkitRegistry(registry);
|
|
114
170
|
rivetkitRegistry.config.test = {
|
|
115
171
|
...rivetkitRegistry.config.test,
|
|
116
172
|
enabled: true,
|
|
@@ -137,30 +193,32 @@ export const test: Layer.Layer<Client.Client, never, Registry> = Layer.effect(
|
|
|
137
193
|
// to its (warning-emitting) default.
|
|
138
194
|
const resolvedEndpoint = rivetkitRegistry.parseConfig().endpoint;
|
|
139
195
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}),
|
|
147
|
-
);
|
|
196
|
+
return yield* Client.make({
|
|
197
|
+
...registry.options,
|
|
198
|
+
endpoint: registry.options.endpoint ?? resolvedEndpoint,
|
|
199
|
+
}).pipe(Effect.provideService(BaseLogger, registry.baseLogger));
|
|
200
|
+
}),
|
|
201
|
+
);
|
|
148
202
|
|
|
149
203
|
const makeHttpEffect = (
|
|
150
204
|
registry: Registry,
|
|
151
205
|
options?: ToHttpEffectOptions,
|
|
152
206
|
): Effect.Effect<
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
207
|
+
Effect.Effect<
|
|
208
|
+
HttpServerResponse.HttpServerResponse,
|
|
209
|
+
HttpServerError.HttpServerError,
|
|
210
|
+
HttpServerRequest.HttpServerRequest
|
|
211
|
+
>
|
|
212
|
+
> =>
|
|
213
|
+
Effect.map(
|
|
214
|
+
setupRivetkitRegistry(registry, {
|
|
215
|
+
serverless: options,
|
|
216
|
+
}),
|
|
217
|
+
(rivetkitRegistry) =>
|
|
218
|
+
HttpEffect.fromWebHandler((request) =>
|
|
219
|
+
rivetkitRegistry.handler(request),
|
|
220
|
+
),
|
|
162
221
|
);
|
|
163
|
-
};
|
|
164
222
|
|
|
165
223
|
export type ToHttpEffectOptions = ServerlessOptions;
|
|
166
224
|
|
|
@@ -184,12 +242,14 @@ export const toHttpEffect = Effect.fnUntraced(function* <E>(
|
|
|
184
242
|
Scope.Scope
|
|
185
243
|
> {
|
|
186
244
|
const context = yield* Layer.build(
|
|
187
|
-
registryLayer.pipe(Layer.provideMerge(
|
|
245
|
+
registryLayer.pipe(Layer.provideMerge(RivetLogger.defaultLayer)),
|
|
188
246
|
);
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
247
|
+
const httpEffect = yield* makeHttpEffect(
|
|
248
|
+
Context.get(context, Registry),
|
|
249
|
+
options,
|
|
192
250
|
);
|
|
251
|
+
// @effect-diagnostics-next-line returnEffectInGen:off
|
|
252
|
+
return httpEffect.pipe(Effect.provide(context));
|
|
193
253
|
});
|
|
194
254
|
|
|
195
255
|
export type ToWebHandlerOptions = ServerlessOptions & {
|
|
@@ -226,16 +286,17 @@ export const toWebHandler = <E>(
|
|
|
226
286
|
}
|
|
227
287
|
|
|
228
288
|
const registryLayerWithLogging = registryLayer.pipe(
|
|
229
|
-
Layer.provideMerge(
|
|
289
|
+
Layer.provideMerge(RivetLogger.defaultLayer),
|
|
230
290
|
);
|
|
231
291
|
|
|
232
292
|
return HttpEffect.toWebHandlerLayerWith(registryLayerWithLogging, {
|
|
233
293
|
toHandler: (context) =>
|
|
234
|
-
Effect.
|
|
294
|
+
Effect.map(
|
|
235
295
|
makeHttpEffect(
|
|
236
296
|
Context.get(context, Registry),
|
|
237
297
|
serverlessOptions,
|
|
238
|
-
)
|
|
298
|
+
),
|
|
299
|
+
(httpEffect) => httpEffect.pipe(Effect.provide(context)),
|
|
239
300
|
),
|
|
240
301
|
middleware,
|
|
241
302
|
memoMap,
|
package/src/RivetError.test.ts
CHANGED
|
@@ -121,6 +121,13 @@ describe("RivetError", () => {
|
|
|
121
121
|
"actor ready timeout",
|
|
122
122
|
),
|
|
123
123
|
);
|
|
124
|
+
const wakeRetriesExceeded = RivetError.fromUnknown(
|
|
125
|
+
new RivetkitErrors.RivetError(
|
|
126
|
+
"guard",
|
|
127
|
+
"actor_wake_retries_exceeded",
|
|
128
|
+
"actor wake retries exceeded",
|
|
129
|
+
),
|
|
130
|
+
);
|
|
124
131
|
const tunnelTimeout = RivetError.fromUnknown(
|
|
125
132
|
new RivetkitErrors.RivetError(
|
|
126
133
|
"guard",
|
|
@@ -137,6 +144,10 @@ describe("RivetError", () => {
|
|
|
137
144
|
readyTimeout.reason,
|
|
138
145
|
RivetError.GuardActorReadyTimeout,
|
|
139
146
|
);
|
|
147
|
+
assert.instanceOf(
|
|
148
|
+
wakeRetriesExceeded.reason,
|
|
149
|
+
RivetError.GuardActorWakeRetriesExceeded,
|
|
150
|
+
);
|
|
140
151
|
assert.instanceOf(
|
|
141
152
|
tunnelTimeout.reason,
|
|
142
153
|
RivetError.GuardTunnelMessageTimeout,
|
package/src/RivetError.ts
CHANGED
|
@@ -426,6 +426,38 @@ export class GuardActorReadyTimeout extends Schema.TaggedErrorClass<GuardActorRe
|
|
|
426
426
|
}
|
|
427
427
|
}
|
|
428
428
|
|
|
429
|
+
export class GuardActorWakeRetriesExceeded extends Schema.TaggedErrorClass<GuardActorWakeRetriesExceeded>(
|
|
430
|
+
`${ReasonTypeId}/GuardActorWakeRetriesExceeded`,
|
|
431
|
+
)("GuardActorWakeRetriesExceeded", {
|
|
432
|
+
cause: Schema.instanceOf(RivetkitErrors.RivetError),
|
|
433
|
+
}) {
|
|
434
|
+
readonly [ReasonTypeId] = ReasonTypeId;
|
|
435
|
+
override get message() {
|
|
436
|
+
return this.cause.message;
|
|
437
|
+
}
|
|
438
|
+
get group() {
|
|
439
|
+
return this.cause.group;
|
|
440
|
+
}
|
|
441
|
+
get code() {
|
|
442
|
+
return this.cause.code;
|
|
443
|
+
}
|
|
444
|
+
get metadata() {
|
|
445
|
+
return this.cause.metadata;
|
|
446
|
+
}
|
|
447
|
+
get actor() {
|
|
448
|
+
return this.cause.actor;
|
|
449
|
+
}
|
|
450
|
+
get statusCode() {
|
|
451
|
+
return this.cause.statusCode;
|
|
452
|
+
}
|
|
453
|
+
get public() {
|
|
454
|
+
return this.cause.public;
|
|
455
|
+
}
|
|
456
|
+
get isRetryable(): boolean {
|
|
457
|
+
return true;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
429
461
|
export class GuardActorRunnerFailed extends Schema.TaggedErrorClass<GuardActorRunnerFailed>(
|
|
430
462
|
`${ReasonTypeId}/GuardActorRunnerFailed`,
|
|
431
463
|
)("GuardActorRunnerFailed", {
|
|
@@ -816,6 +848,7 @@ export type RivetErrorReason =
|
|
|
816
848
|
| InvalidEncoding
|
|
817
849
|
| InvalidRequest
|
|
818
850
|
| GuardActorReadyTimeout
|
|
851
|
+
| GuardActorWakeRetriesExceeded
|
|
819
852
|
| GuardActorRunnerFailed
|
|
820
853
|
| GuardServiceUnavailable
|
|
821
854
|
| GuardActorStoppedWhileWaiting
|
|
@@ -843,6 +876,7 @@ export const RivetErrorReason: Schema.Union<
|
|
|
843
876
|
typeof InvalidEncoding,
|
|
844
877
|
typeof InvalidRequest,
|
|
845
878
|
typeof GuardActorReadyTimeout,
|
|
879
|
+
typeof GuardActorWakeRetriesExceeded,
|
|
846
880
|
typeof GuardActorRunnerFailed,
|
|
847
881
|
typeof GuardServiceUnavailable,
|
|
848
882
|
typeof GuardActorStoppedWhileWaiting,
|
|
@@ -869,6 +903,7 @@ export const RivetErrorReason: Schema.Union<
|
|
|
869
903
|
InvalidEncoding,
|
|
870
904
|
InvalidRequest,
|
|
871
905
|
GuardActorReadyTimeout,
|
|
906
|
+
GuardActorWakeRetriesExceeded,
|
|
872
907
|
GuardActorRunnerFailed,
|
|
873
908
|
GuardServiceUnavailable,
|
|
874
909
|
GuardActorStoppedWhileWaiting,
|
|
@@ -993,6 +1028,8 @@ const reasonByCode: { [key: string]: MakeRivetErrorReason | undefined } = {
|
|
|
993
1028
|
"request.invalid": (error) => new InvalidRequest({ cause: error }),
|
|
994
1029
|
"guard.actor_ready_timeout": (error) =>
|
|
995
1030
|
new GuardActorReadyTimeout({ cause: error }),
|
|
1031
|
+
"guard.actor_wake_retries_exceeded": (error) =>
|
|
1032
|
+
new GuardActorWakeRetriesExceeded({ cause: error }),
|
|
996
1033
|
"guard.actor_runner_failed": (error) =>
|
|
997
1034
|
new GuardActorRunnerFailed({ cause: error }),
|
|
998
1035
|
"guard.service_unavailable": (error) =>
|