rivetkit 2.0.1 → 2.0.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/schemas/actor-persist/v1.ts +228 -0
- package/dist/schemas/client-protocol/v1.ts +429 -0
- package/dist/schemas/file-system-driver/v1.ts +102 -0
- package/dist/tsup/actor/errors.cjs +69 -0
- package/dist/tsup/actor/errors.cjs.map +1 -0
- package/dist/tsup/actor/errors.d.cts +143 -0
- package/dist/tsup/actor/errors.d.ts +143 -0
- package/dist/tsup/actor/errors.js +69 -0
- package/dist/tsup/actor/errors.js.map +1 -0
- package/dist/tsup/chunk-2CRLFV6Z.cjs +202 -0
- package/dist/tsup/chunk-2CRLFV6Z.cjs.map +1 -0
- package/dist/tsup/chunk-3H7O2A7I.js +525 -0
- package/dist/tsup/chunk-3H7O2A7I.js.map +1 -0
- package/dist/tsup/chunk-42I3OZ3Q.js +15 -0
- package/dist/tsup/chunk-42I3OZ3Q.js.map +1 -0
- package/dist/tsup/chunk-4NSUQZ2H.js +1790 -0
- package/dist/tsup/chunk-4NSUQZ2H.js.map +1 -0
- package/dist/tsup/chunk-6PDXBYI5.js +132 -0
- package/dist/tsup/chunk-6PDXBYI5.js.map +1 -0
- package/dist/tsup/chunk-6WKQDDUD.cjs +1790 -0
- package/dist/tsup/chunk-6WKQDDUD.cjs.map +1 -0
- package/dist/tsup/chunk-CTBOSFUH.cjs +116 -0
- package/dist/tsup/chunk-CTBOSFUH.cjs.map +1 -0
- package/dist/tsup/chunk-EGVZZFE2.js +2857 -0
- package/dist/tsup/chunk-EGVZZFE2.js.map +1 -0
- package/dist/tsup/chunk-FCCPJNMA.cjs +132 -0
- package/dist/tsup/chunk-FCCPJNMA.cjs.map +1 -0
- package/dist/tsup/chunk-FLMTTN27.js +244 -0
- package/dist/tsup/chunk-FLMTTN27.js.map +1 -0
- package/dist/tsup/chunk-GIR3AFFI.cjs +315 -0
- package/dist/tsup/chunk-GIR3AFFI.cjs.map +1 -0
- package/dist/tsup/chunk-INGJP237.js +315 -0
- package/dist/tsup/chunk-INGJP237.js.map +1 -0
- package/dist/tsup/chunk-KJCJLKRM.js +116 -0
- package/dist/tsup/chunk-KJCJLKRM.js.map +1 -0
- package/dist/tsup/chunk-KUPQZYUQ.cjs +15 -0
- package/dist/tsup/chunk-KUPQZYUQ.cjs.map +1 -0
- package/dist/tsup/chunk-O2MBYIXO.cjs +2857 -0
- package/dist/tsup/chunk-O2MBYIXO.cjs.map +1 -0
- package/dist/tsup/chunk-OGAPU3UG.cjs +525 -0
- package/dist/tsup/chunk-OGAPU3UG.cjs.map +1 -0
- package/dist/tsup/chunk-OV6AYD4S.js +4406 -0
- package/dist/tsup/chunk-OV6AYD4S.js.map +1 -0
- package/dist/tsup/chunk-PO4VLDWA.js +47 -0
- package/dist/tsup/chunk-PO4VLDWA.js.map +1 -0
- package/dist/tsup/chunk-R2OPSKIV.cjs +244 -0
- package/dist/tsup/chunk-R2OPSKIV.cjs.map +1 -0
- package/dist/tsup/chunk-TZJKSBUQ.cjs +47 -0
- package/dist/tsup/chunk-TZJKSBUQ.cjs.map +1 -0
- package/dist/tsup/chunk-UBUC5C3G.cjs +189 -0
- package/dist/tsup/chunk-UBUC5C3G.cjs.map +1 -0
- package/dist/tsup/chunk-UIM22YJL.cjs +4406 -0
- package/dist/tsup/chunk-UIM22YJL.cjs.map +1 -0
- package/dist/tsup/chunk-URVFQMYI.cjs +230 -0
- package/dist/tsup/chunk-URVFQMYI.cjs.map +1 -0
- package/dist/tsup/chunk-UVUPOS46.js +230 -0
- package/dist/tsup/chunk-UVUPOS46.js.map +1 -0
- package/dist/tsup/chunk-VRRHBNJC.js +189 -0
- package/dist/tsup/chunk-VRRHBNJC.js.map +1 -0
- package/dist/tsup/chunk-XFSS33EQ.js +202 -0
- package/dist/tsup/chunk-XFSS33EQ.js.map +1 -0
- package/dist/tsup/client/mod.cjs +32 -0
- package/dist/tsup/client/mod.cjs.map +1 -0
- package/dist/tsup/client/mod.d.cts +26 -0
- package/dist/tsup/client/mod.d.ts +26 -0
- package/dist/tsup/client/mod.js +32 -0
- package/dist/tsup/client/mod.js.map +1 -0
- package/dist/tsup/common/log.cjs +13 -0
- package/dist/tsup/common/log.cjs.map +1 -0
- package/dist/tsup/common/log.d.cts +20 -0
- package/dist/tsup/common/log.d.ts +20 -0
- package/dist/tsup/common/log.js +13 -0
- package/dist/tsup/common/log.js.map +1 -0
- package/dist/tsup/common/websocket.cjs +10 -0
- package/dist/tsup/common/websocket.cjs.map +1 -0
- package/dist/tsup/common/websocket.d.cts +3 -0
- package/dist/tsup/common/websocket.d.ts +3 -0
- package/dist/tsup/common/websocket.js +10 -0
- package/dist/tsup/common/websocket.js.map +1 -0
- package/dist/tsup/common-CpqORuCq.d.cts +218 -0
- package/dist/tsup/common-CpqORuCq.d.ts +218 -0
- package/dist/tsup/connection-BR_Ve4ku.d.cts +2117 -0
- package/dist/tsup/connection-BwUMoe6n.d.ts +2117 -0
- package/dist/tsup/driver-helpers/mod.cjs +33 -0
- package/dist/tsup/driver-helpers/mod.cjs.map +1 -0
- package/dist/tsup/driver-helpers/mod.d.cts +18 -0
- package/dist/tsup/driver-helpers/mod.d.ts +18 -0
- package/dist/tsup/driver-helpers/mod.js +33 -0
- package/dist/tsup/driver-helpers/mod.js.map +1 -0
- package/dist/tsup/driver-test-suite/mod.cjs +4619 -0
- package/dist/tsup/driver-test-suite/mod.cjs.map +1 -0
- package/dist/tsup/driver-test-suite/mod.d.cts +57 -0
- package/dist/tsup/driver-test-suite/mod.d.ts +57 -0
- package/dist/tsup/driver-test-suite/mod.js +4619 -0
- package/dist/tsup/driver-test-suite/mod.js.map +1 -0
- package/dist/tsup/inspector/mod.cjs +53 -0
- package/dist/tsup/inspector/mod.cjs.map +1 -0
- package/dist/tsup/inspector/mod.d.cts +408 -0
- package/dist/tsup/inspector/mod.d.ts +408 -0
- package/dist/tsup/inspector/mod.js +53 -0
- package/dist/tsup/inspector/mod.js.map +1 -0
- package/dist/tsup/mod.cjs +73 -0
- package/dist/tsup/mod.cjs.map +1 -0
- package/dist/tsup/mod.d.cts +100 -0
- package/dist/tsup/mod.d.ts +100 -0
- package/dist/tsup/mod.js +73 -0
- package/dist/tsup/mod.js.map +1 -0
- package/dist/tsup/router-endpoints-AYkXG8Tl.d.cts +66 -0
- package/dist/tsup/router-endpoints-DAbqVFx2.d.ts +66 -0
- package/dist/tsup/test/mod.cjs +21 -0
- package/dist/tsup/test/mod.cjs.map +1 -0
- package/dist/tsup/test/mod.d.cts +27 -0
- package/dist/tsup/test/mod.d.ts +27 -0
- package/dist/tsup/test/mod.js +21 -0
- package/dist/tsup/test/mod.js.map +1 -0
- package/dist/tsup/utils-CT0cv4jd.d.cts +17 -0
- package/dist/tsup/utils-CT0cv4jd.d.ts +17 -0
- package/dist/tsup/utils.cjs +26 -0
- package/dist/tsup/utils.cjs.map +1 -0
- package/dist/tsup/utils.d.cts +36 -0
- package/dist/tsup/utils.d.ts +36 -0
- package/dist/tsup/utils.js +26 -0
- package/dist/tsup/utils.js.map +1 -0
- package/package.json +208 -5
- package/src/actor/action.ts +182 -0
- package/src/actor/config.ts +765 -0
- package/src/actor/connection.ts +260 -0
- package/src/actor/context.ts +171 -0
- package/src/actor/database.ts +23 -0
- package/src/actor/definition.ts +86 -0
- package/src/actor/driver.ts +84 -0
- package/src/actor/errors.ts +360 -0
- package/src/actor/generic-conn-driver.ts +234 -0
- package/src/actor/instance.ts +1800 -0
- package/src/actor/log.ts +15 -0
- package/src/actor/mod.ts +113 -0
- package/src/actor/persisted.ts +42 -0
- package/src/actor/protocol/old.ts +281 -0
- package/src/actor/protocol/serde.ts +131 -0
- package/src/actor/router-endpoints.ts +685 -0
- package/src/actor/router.ts +263 -0
- package/src/actor/schedule.ts +17 -0
- package/src/actor/unstable-react.ts +110 -0
- package/src/actor/utils.ts +98 -0
- package/src/client/actor-common.ts +30 -0
- package/src/client/actor-conn.ts +804 -0
- package/src/client/actor-handle.ts +208 -0
- package/src/client/client.ts +623 -0
- package/src/client/errors.ts +41 -0
- package/src/client/http-client-driver.ts +326 -0
- package/src/client/log.ts +7 -0
- package/src/client/mod.ts +56 -0
- package/src/client/raw-utils.ts +92 -0
- package/src/client/test.ts +44 -0
- package/src/client/utils.ts +150 -0
- package/src/common/eventsource-interface.ts +47 -0
- package/src/common/eventsource.ts +80 -0
- package/src/common/fake-event-source.ts +266 -0
- package/src/common/inline-websocket-adapter2.ts +445 -0
- package/src/common/log-levels.ts +27 -0
- package/src/common/log.ts +139 -0
- package/src/common/logfmt.ts +228 -0
- package/src/common/network.ts +2 -0
- package/src/common/router.ts +87 -0
- package/src/common/utils.ts +322 -0
- package/src/common/versioned-data.ts +95 -0
- package/src/common/websocket-interface.ts +49 -0
- package/src/common/websocket.ts +43 -0
- package/src/driver-helpers/mod.ts +22 -0
- package/src/driver-helpers/utils.ts +17 -0
- package/src/driver-test-suite/log.ts +7 -0
- package/src/driver-test-suite/mod.ts +213 -0
- package/src/driver-test-suite/test-inline-client-driver.ts +402 -0
- package/src/driver-test-suite/tests/action-features.ts +136 -0
- package/src/driver-test-suite/tests/actor-auth.ts +591 -0
- package/src/driver-test-suite/tests/actor-conn-state.ts +249 -0
- package/src/driver-test-suite/tests/actor-conn.ts +349 -0
- package/src/driver-test-suite/tests/actor-driver.ts +25 -0
- package/src/driver-test-suite/tests/actor-error-handling.ts +158 -0
- package/src/driver-test-suite/tests/actor-handle.ts +259 -0
- package/src/driver-test-suite/tests/actor-inline-client.ts +152 -0
- package/src/driver-test-suite/tests/actor-inspector.ts +570 -0
- package/src/driver-test-suite/tests/actor-metadata.ts +116 -0
- package/src/driver-test-suite/tests/actor-onstatechange.ts +95 -0
- package/src/driver-test-suite/tests/actor-schedule.ts +108 -0
- package/src/driver-test-suite/tests/actor-sleep.ts +413 -0
- package/src/driver-test-suite/tests/actor-state.ts +54 -0
- package/src/driver-test-suite/tests/actor-vars.ts +93 -0
- package/src/driver-test-suite/tests/manager-driver.ts +365 -0
- package/src/driver-test-suite/tests/raw-http-direct-registry.ts +226 -0
- package/src/driver-test-suite/tests/raw-http-request-properties.ts +414 -0
- package/src/driver-test-suite/tests/raw-http.ts +347 -0
- package/src/driver-test-suite/tests/raw-websocket-direct-registry.ts +392 -0
- package/src/driver-test-suite/tests/raw-websocket.ts +484 -0
- package/src/driver-test-suite/tests/request-access.ts +244 -0
- package/src/driver-test-suite/utils.ts +68 -0
- package/src/drivers/default.ts +31 -0
- package/src/drivers/engine/actor-driver.ts +360 -0
- package/src/drivers/engine/api-endpoints.ts +128 -0
- package/src/drivers/engine/api-utils.ts +70 -0
- package/src/drivers/engine/config.ts +39 -0
- package/src/drivers/engine/keys.test.ts +266 -0
- package/src/drivers/engine/keys.ts +89 -0
- package/src/drivers/engine/kv.ts +3 -0
- package/src/drivers/engine/log.ts +7 -0
- package/src/drivers/engine/manager-driver.ts +391 -0
- package/src/drivers/engine/mod.ts +36 -0
- package/src/drivers/engine/ws-proxy.ts +170 -0
- package/src/drivers/file-system/actor.ts +91 -0
- package/src/drivers/file-system/global-state.ts +673 -0
- package/src/drivers/file-system/log.ts +7 -0
- package/src/drivers/file-system/manager.ts +306 -0
- package/src/drivers/file-system/mod.ts +48 -0
- package/src/drivers/file-system/utils.ts +109 -0
- package/src/globals.d.ts +6 -0
- package/src/inline-client-driver/log.ts +7 -0
- package/src/inline-client-driver/mod.ts +385 -0
- package/src/inspector/actor.ts +298 -0
- package/src/inspector/config.ts +83 -0
- package/src/inspector/log.ts +5 -0
- package/src/inspector/manager.ts +86 -0
- package/src/inspector/mod.ts +2 -0
- package/src/inspector/protocol/actor.ts +10 -0
- package/src/inspector/protocol/common.ts +196 -0
- package/src/inspector/protocol/manager.ts +10 -0
- package/src/inspector/protocol/mod.ts +2 -0
- package/src/inspector/utils.ts +76 -0
- package/src/manager/auth.ts +121 -0
- package/src/manager/driver.ts +80 -0
- package/src/manager/hono-websocket-adapter.ts +333 -0
- package/src/manager/log.ts +7 -0
- package/src/manager/mod.ts +2 -0
- package/src/manager/protocol/mod.ts +24 -0
- package/src/manager/protocol/query.ts +89 -0
- package/src/manager/router.ts +1792 -0
- package/src/mod.ts +20 -0
- package/src/registry/config.ts +32 -0
- package/src/registry/log.ts +7 -0
- package/src/registry/mod.ts +124 -0
- package/src/registry/run-config.ts +54 -0
- package/src/registry/serve.ts +53 -0
- package/src/schemas/actor-persist/mod.ts +1 -0
- package/src/schemas/actor-persist/versioned.ts +25 -0
- package/src/schemas/client-protocol/mod.ts +1 -0
- package/src/schemas/client-protocol/versioned.ts +63 -0
- package/src/schemas/file-system-driver/mod.ts +1 -0
- package/src/schemas/file-system-driver/versioned.ts +28 -0
- package/src/serde.ts +84 -0
- package/src/test/config.ts +16 -0
- package/src/test/log.ts +7 -0
- package/src/test/mod.ts +153 -0
- package/src/utils.ts +172 -0
- package/README.md +0 -13
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { apiCall } from "./api-utils";
|
|
2
|
+
import type { Config } from "./config";
|
|
3
|
+
import { serializeActorKey } from "./keys";
|
|
4
|
+
|
|
5
|
+
// MARK: Common types
|
|
6
|
+
export type RivetId = string;
|
|
7
|
+
|
|
8
|
+
export interface Actor {
|
|
9
|
+
actor_id: RivetId;
|
|
10
|
+
name: string;
|
|
11
|
+
key: string;
|
|
12
|
+
namespace_id: RivetId;
|
|
13
|
+
runner_name_selector: string;
|
|
14
|
+
create_ts: number;
|
|
15
|
+
connectable_ts?: number | null;
|
|
16
|
+
destroy_ts?: number | null;
|
|
17
|
+
sleep_ts?: number | null;
|
|
18
|
+
start_ts?: number | null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface ActorsGetResponse {
|
|
22
|
+
actor: Actor;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface ActorsGetByIdResponse {
|
|
26
|
+
actor_id?: RivetId | null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface ActorsGetOrCreateResponse {
|
|
30
|
+
actor: Actor;
|
|
31
|
+
created: boolean;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface ActorsGetOrCreateByIdResponse {
|
|
35
|
+
actor_id: RivetId;
|
|
36
|
+
created: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface ActorsCreateRequest {
|
|
40
|
+
name: string;
|
|
41
|
+
runner_name_selector: string;
|
|
42
|
+
crash_policy: string;
|
|
43
|
+
key?: string | null;
|
|
44
|
+
input?: string | null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface ActorsCreateResponse {
|
|
48
|
+
actor: Actor;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// MARK: Get actor
|
|
52
|
+
export async function getActor(
|
|
53
|
+
config: Config,
|
|
54
|
+
actorId: RivetId,
|
|
55
|
+
): Promise<ActorsGetResponse> {
|
|
56
|
+
return apiCall<never, ActorsGetResponse>(
|
|
57
|
+
config.endpoint,
|
|
58
|
+
config.namespace,
|
|
59
|
+
"GET",
|
|
60
|
+
`/actors/${encodeURIComponent(actorId)}`,
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// MARK: Get actor by id
|
|
65
|
+
export async function getActorById(
|
|
66
|
+
config: Config,
|
|
67
|
+
name: string,
|
|
68
|
+
key: string[],
|
|
69
|
+
): Promise<ActorsGetByIdResponse> {
|
|
70
|
+
const serializedKey = serializeActorKey(key);
|
|
71
|
+
return apiCall<never, ActorsGetByIdResponse>(
|
|
72
|
+
config.endpoint,
|
|
73
|
+
config.namespace,
|
|
74
|
+
"GET",
|
|
75
|
+
`/actors/by-id?name=${encodeURIComponent(name)}&key=${encodeURIComponent(serializedKey)}`,
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// MARK: Get or create actor by id
|
|
80
|
+
export interface ActorsGetOrCreateByIdRequest {
|
|
81
|
+
name: string;
|
|
82
|
+
key: string;
|
|
83
|
+
runner_name_selector: string;
|
|
84
|
+
crash_policy: string;
|
|
85
|
+
input?: string | null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export async function getOrCreateActorById(
|
|
89
|
+
config: Config,
|
|
90
|
+
request: ActorsGetOrCreateByIdRequest,
|
|
91
|
+
): Promise<ActorsGetOrCreateByIdResponse> {
|
|
92
|
+
return apiCall<ActorsGetOrCreateByIdRequest, ActorsGetOrCreateByIdResponse>(
|
|
93
|
+
config.endpoint,
|
|
94
|
+
config.namespace,
|
|
95
|
+
"PUT",
|
|
96
|
+
`/actors/by-id`,
|
|
97
|
+
request,
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// MARK: Create actor
|
|
102
|
+
export async function createActor(
|
|
103
|
+
config: Config,
|
|
104
|
+
request: ActorsCreateRequest,
|
|
105
|
+
): Promise<ActorsCreateResponse> {
|
|
106
|
+
return apiCall<ActorsCreateRequest, ActorsCreateResponse>(
|
|
107
|
+
config.endpoint,
|
|
108
|
+
config.namespace,
|
|
109
|
+
"POST",
|
|
110
|
+
`/actors`,
|
|
111
|
+
request,
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// MARK: Destroy actor
|
|
116
|
+
export type ActorsDeleteResponse = {};
|
|
117
|
+
|
|
118
|
+
export async function destroyActor(
|
|
119
|
+
config: Config,
|
|
120
|
+
actorId: RivetId,
|
|
121
|
+
): Promise<ActorsDeleteResponse> {
|
|
122
|
+
return apiCall<never, ActorsDeleteResponse>(
|
|
123
|
+
config.endpoint,
|
|
124
|
+
config.namespace,
|
|
125
|
+
"DELETE",
|
|
126
|
+
`/actors/${encodeURIComponent(actorId)}`,
|
|
127
|
+
);
|
|
128
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { logger } from "./log";
|
|
2
|
+
|
|
3
|
+
// Error class for Engine API errors
|
|
4
|
+
export class EngineApiError extends Error {
|
|
5
|
+
constructor(
|
|
6
|
+
public readonly group: string,
|
|
7
|
+
public readonly code: string,
|
|
8
|
+
message?: string,
|
|
9
|
+
) {
|
|
10
|
+
super(message || `Engine API error: ${group}/${code}`);
|
|
11
|
+
this.name = "EngineApiError";
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Helper function for making API calls
|
|
16
|
+
export async function apiCall<TInput = unknown, TOutput = unknown>(
|
|
17
|
+
endpoint: string,
|
|
18
|
+
namespace: string,
|
|
19
|
+
method: "GET" | "POST" | "PUT" | "DELETE",
|
|
20
|
+
path: string,
|
|
21
|
+
body?: TInput,
|
|
22
|
+
): Promise<TOutput> {
|
|
23
|
+
const url = `${endpoint}${path}${path.includes("?") ? "&" : "?"}namespace=${encodeURIComponent(namespace)}`;
|
|
24
|
+
|
|
25
|
+
const options: RequestInit = {
|
|
26
|
+
method,
|
|
27
|
+
headers: {
|
|
28
|
+
"Content-Type": "application/json",
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
if (body !== undefined && method !== "GET") {
|
|
33
|
+
options.body = JSON.stringify(body);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
logger().debug("making api call", { method, url });
|
|
37
|
+
|
|
38
|
+
const response = await fetch(url, options);
|
|
39
|
+
|
|
40
|
+
if (!response.ok) {
|
|
41
|
+
const errorText = await response.text();
|
|
42
|
+
logger().error("api call failed", {
|
|
43
|
+
status: response.status,
|
|
44
|
+
statusText: response.statusText,
|
|
45
|
+
error: errorText,
|
|
46
|
+
method,
|
|
47
|
+
path,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Try to parse error response
|
|
51
|
+
try {
|
|
52
|
+
const errorData = JSON.parse(errorText);
|
|
53
|
+
if (errorData.kind === "error" && errorData.group && errorData.code) {
|
|
54
|
+
throw new EngineApiError(
|
|
55
|
+
errorData.group,
|
|
56
|
+
errorData.code,
|
|
57
|
+
errorData.message,
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
} catch (parseError) {
|
|
61
|
+
// If parsing fails or it's not our expected error format, continue
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
throw new Error(
|
|
65
|
+
`API call failed: ${response.status} ${response.statusText}`,
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return response.json() as Promise<TOutput>;
|
|
70
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Hono } from "hono";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { getEnvUniversal } from "@/utils";
|
|
4
|
+
|
|
5
|
+
export const ConfigSchema = z
|
|
6
|
+
.object({
|
|
7
|
+
app: z.custom<Hono>().optional(),
|
|
8
|
+
endpoint: z
|
|
9
|
+
.string()
|
|
10
|
+
.default(
|
|
11
|
+
() => getEnvUniversal("RIVET_ENGINE") ?? "http://localhost:7080",
|
|
12
|
+
),
|
|
13
|
+
pegboardEndpoint: z.string().optional(),
|
|
14
|
+
namespace: z
|
|
15
|
+
.string()
|
|
16
|
+
.default(() => getEnvUniversal("RIVET_NAMESPACE") ?? "default"),
|
|
17
|
+
runnerName: z
|
|
18
|
+
.string()
|
|
19
|
+
.default(() => getEnvUniversal("RIVET_RUNNER") ?? "rivetkit"),
|
|
20
|
+
// TODO: Automatically attempt ot determine key by common env vars (e.g. k8s pod name)
|
|
21
|
+
runnerKey: z
|
|
22
|
+
.string()
|
|
23
|
+
.default(
|
|
24
|
+
() => getEnvUniversal("RIVET_RUNNER_KEY") ?? crypto.randomUUID(),
|
|
25
|
+
),
|
|
26
|
+
totalSlots: z.number().default(100_000),
|
|
27
|
+
addresses: z
|
|
28
|
+
.record(
|
|
29
|
+
z.object({
|
|
30
|
+
host: z.string(),
|
|
31
|
+
port: z.number(),
|
|
32
|
+
}),
|
|
33
|
+
)
|
|
34
|
+
.default({ main: { host: "127.0.0.1", port: 5051 } }),
|
|
35
|
+
})
|
|
36
|
+
.default({});
|
|
37
|
+
|
|
38
|
+
export type InputConfig = z.input<typeof ConfigSchema>;
|
|
39
|
+
export type Config = z.infer<typeof ConfigSchema>;
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import { describe, expect, test } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
deserializeActorKey,
|
|
4
|
+
EMPTY_KEY,
|
|
5
|
+
KEY_SEPARATOR,
|
|
6
|
+
serializeActorKey,
|
|
7
|
+
} from "./keys";
|
|
8
|
+
|
|
9
|
+
describe("Key serialization and deserialization", () => {
|
|
10
|
+
// Test serialization
|
|
11
|
+
describe("serializeActorKey", () => {
|
|
12
|
+
test("serializes empty key array", () => {
|
|
13
|
+
expect(serializeActorKey([])).toBe(EMPTY_KEY);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test("serializes single key", () => {
|
|
17
|
+
expect(serializeActorKey(["test"])).toBe("test");
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test("serializes multiple keys", () => {
|
|
21
|
+
expect(serializeActorKey(["a", "b", "c"])).toBe(
|
|
22
|
+
`a${KEY_SEPARATOR}b${KEY_SEPARATOR}c`,
|
|
23
|
+
);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test("escapes forward slashes in keys", () => {
|
|
27
|
+
expect(serializeActorKey(["a/b"])).toBe("a\\/b");
|
|
28
|
+
expect(serializeActorKey(["a/b", "c"])).toBe(`a\\/b${KEY_SEPARATOR}c`);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test("escapes empty key marker in keys", () => {
|
|
32
|
+
expect(serializeActorKey([EMPTY_KEY])).toBe(`\\${EMPTY_KEY}`);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test("handles complex keys", () => {
|
|
36
|
+
expect(serializeActorKey(["a/b", EMPTY_KEY, "c/d"])).toBe(
|
|
37
|
+
`a\\/b${KEY_SEPARATOR}\\${EMPTY_KEY}${KEY_SEPARATOR}c\\/d`,
|
|
38
|
+
);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// Test deserialization
|
|
43
|
+
describe("deserializeActorKey", () => {
|
|
44
|
+
test("deserializes empty string", () => {
|
|
45
|
+
expect(deserializeActorKey("")).toEqual([]);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test("deserializes undefined/null", () => {
|
|
49
|
+
expect(deserializeActorKey(undefined as unknown as string)).toEqual([]);
|
|
50
|
+
expect(deserializeActorKey(null as unknown as string)).toEqual([]);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test("deserializes empty key marker", () => {
|
|
54
|
+
expect(deserializeActorKey(EMPTY_KEY)).toEqual([]);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test("deserializes single key", () => {
|
|
58
|
+
expect(deserializeActorKey("test")).toEqual(["test"]);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test("deserializes multiple keys", () => {
|
|
62
|
+
expect(
|
|
63
|
+
deserializeActorKey(`a${KEY_SEPARATOR}b${KEY_SEPARATOR}c`),
|
|
64
|
+
).toEqual(["a", "b", "c"]);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test("deserializes keys with escaped forward slashes", () => {
|
|
68
|
+
expect(deserializeActorKey("a\\/b")).toEqual(["a/b"]);
|
|
69
|
+
expect(deserializeActorKey(`a\\/b${KEY_SEPARATOR}c`)).toEqual([
|
|
70
|
+
"a/b",
|
|
71
|
+
"c",
|
|
72
|
+
]);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test("deserializes keys with escaped empty key marker", () => {
|
|
76
|
+
expect(deserializeActorKey(`\\${EMPTY_KEY}`)).toEqual([EMPTY_KEY]);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("deserializes complex keys", () => {
|
|
80
|
+
expect(
|
|
81
|
+
deserializeActorKey(
|
|
82
|
+
`a\\/b${KEY_SEPARATOR}\\${EMPTY_KEY}${KEY_SEPARATOR}c\\/d`,
|
|
83
|
+
),
|
|
84
|
+
).toEqual(["a/b", EMPTY_KEY, "c/d"]);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// Test edge cases
|
|
89
|
+
describe("edge cases", () => {
|
|
90
|
+
test("handles empty string parts", () => {
|
|
91
|
+
const testCases: Array<[string[], string]> = [
|
|
92
|
+
[[""], "\\0"],
|
|
93
|
+
[["a", "", "b"], "a/\\0/b"],
|
|
94
|
+
[["", "a"], "\\0/a"],
|
|
95
|
+
[["a", ""], "a/\\0"],
|
|
96
|
+
[["", "", ""], "\\0/\\0/\\0"],
|
|
97
|
+
[["", "a", "", "b", ""], "\\0/a/\\0/b/\\0"],
|
|
98
|
+
[[], "/"],
|
|
99
|
+
[["test"], "test"],
|
|
100
|
+
[["a", "b", "c"], "a/b/c"],
|
|
101
|
+
[["a/b", "c"], "a\\/b/c"],
|
|
102
|
+
[[EMPTY_KEY], "\\/"],
|
|
103
|
+
[["a/b", EMPTY_KEY, "c/d"], "a\\/b/\\//c\\/d"],
|
|
104
|
+
[
|
|
105
|
+
["special\\chars", "more:complex,keys", "final key"],
|
|
106
|
+
"special\\\\chars/more:complex,keys/final key",
|
|
107
|
+
],
|
|
108
|
+
];
|
|
109
|
+
|
|
110
|
+
for (const [key, expectedSerialized] of testCases) {
|
|
111
|
+
const serialized = serializeActorKey(key);
|
|
112
|
+
expect(serialized).toBe(expectedSerialized);
|
|
113
|
+
const deserialized = deserializeActorKey(serialized);
|
|
114
|
+
expect(deserialized).toEqual(key);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test("differentiates empty array from array with empty string", () => {
|
|
119
|
+
const emptyArray: string[] = [];
|
|
120
|
+
const arrayWithEmptyString = [""];
|
|
121
|
+
|
|
122
|
+
const serialized1 = serializeActorKey(emptyArray);
|
|
123
|
+
const serialized2 = serializeActorKey(arrayWithEmptyString);
|
|
124
|
+
|
|
125
|
+
expect(serialized1).toBe(EMPTY_KEY); // Should be "/"
|
|
126
|
+
expect(serialized2).not.toBe(EMPTY_KEY); // Should NOT be "/"
|
|
127
|
+
expect(serialized2).toBe("\\0"); // Empty string becomes \0 marker
|
|
128
|
+
|
|
129
|
+
expect(deserializeActorKey(serialized1)).toEqual(emptyArray);
|
|
130
|
+
expect(deserializeActorKey(serialized2)).toEqual(arrayWithEmptyString);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test("handles mix of empty strings and forward slash (EMPTY_KEY)", () => {
|
|
134
|
+
const testCases: Array<[string[], string]> = [
|
|
135
|
+
[["", EMPTY_KEY, ""], "\\0/\\//\\0"],
|
|
136
|
+
[[EMPTY_KEY, ""], "\\//\\0"],
|
|
137
|
+
[["", EMPTY_KEY], "\\0/\\/"],
|
|
138
|
+
[["a", "", EMPTY_KEY, "", "b"], "a/\\0/\\//\\0/b"],
|
|
139
|
+
];
|
|
140
|
+
|
|
141
|
+
for (const [key, expectedSerialized] of testCases) {
|
|
142
|
+
const serialized = serializeActorKey(key);
|
|
143
|
+
expect(serialized).toBe(expectedSerialized);
|
|
144
|
+
const deserialized = deserializeActorKey(serialized);
|
|
145
|
+
expect(deserialized).toEqual(key);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
test("handles literal backslash-zero string", () => {
|
|
150
|
+
const testCases: Array<[string[], string]> = [
|
|
151
|
+
[["\\0"], "\\\\0"], // Literal \0 string
|
|
152
|
+
[["a\\0b"], "a\\\\0b"], // Literal \0 in middle
|
|
153
|
+
[["\\0", ""], "\\\\0/\\0"], // Literal \0 with empty string
|
|
154
|
+
[["", "\\0"], "\\0/\\\\0"], // Empty string with literal \0
|
|
155
|
+
];
|
|
156
|
+
|
|
157
|
+
for (const [key, expectedSerialized] of testCases) {
|
|
158
|
+
const serialized = serializeActorKey(key);
|
|
159
|
+
expect(serialized).toBe(expectedSerialized);
|
|
160
|
+
const deserialized = deserializeActorKey(serialized);
|
|
161
|
+
expect(deserialized).toEqual(key);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
test("handles backslash at the end", () => {
|
|
166
|
+
const key = ["abc\\"];
|
|
167
|
+
const serialized = serializeActorKey(key);
|
|
168
|
+
expect(serialized).toBe("abc\\\\");
|
|
169
|
+
const deserialized = deserializeActorKey(serialized);
|
|
170
|
+
expect(deserialized).toEqual(key);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
test("handles backslashes in middle of string", () => {
|
|
174
|
+
const testCases: Array<[string[], string]> = [
|
|
175
|
+
[["abc\\def"], "abc\\\\def"],
|
|
176
|
+
[["abc\\\\def"], "abc\\\\\\\\def"],
|
|
177
|
+
[["path\\to\\file"], "path\\\\to\\\\file"],
|
|
178
|
+
];
|
|
179
|
+
|
|
180
|
+
for (const [key, expectedSerialized] of testCases) {
|
|
181
|
+
const serialized = serializeActorKey(key);
|
|
182
|
+
expect(serialized).toBe(expectedSerialized);
|
|
183
|
+
const deserialized = deserializeActorKey(serialized);
|
|
184
|
+
expect(deserialized).toEqual(key);
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
test("handles forward slashes at the end of strings", () => {
|
|
189
|
+
const serialized = serializeActorKey(["abc\\/"]);
|
|
190
|
+
expect(deserializeActorKey(serialized)).toEqual(["abc\\/"]);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
test("handles mixed backslashes and forward slashes", () => {
|
|
194
|
+
const testCases: Array<[string[], string]> = [
|
|
195
|
+
[["path\\to\\file/dir"], "path\\\\to\\\\file\\/dir"],
|
|
196
|
+
[["file\\with/slash"], "file\\\\with\\/slash"],
|
|
197
|
+
[["path\\to\\file", "with/slash"], "path\\\\to\\\\file/with\\/slash"],
|
|
198
|
+
];
|
|
199
|
+
|
|
200
|
+
for (const [key, expectedSerialized] of testCases) {
|
|
201
|
+
const serialized = serializeActorKey(key);
|
|
202
|
+
expect(serialized).toBe(expectedSerialized);
|
|
203
|
+
const deserialized = deserializeActorKey(serialized);
|
|
204
|
+
expect(deserialized).toEqual(key);
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
test("handles multiple consecutive forward slashes", () => {
|
|
209
|
+
const key = ["a//b"];
|
|
210
|
+
const serialized = serializeActorKey(key);
|
|
211
|
+
expect(serialized).toBe("a\\/\\/b");
|
|
212
|
+
const deserialized = deserializeActorKey(serialized);
|
|
213
|
+
expect(deserialized).toEqual(key);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
test("handles special characters", () => {
|
|
217
|
+
const key = ["a💻b", "c🔑d"];
|
|
218
|
+
const serialized = serializeActorKey(key);
|
|
219
|
+
expect(serialized).toBe("a💻b/c🔑d");
|
|
220
|
+
const deserialized = deserializeActorKey(serialized);
|
|
221
|
+
expect(deserialized).toEqual(key);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
test("handles escaped forward slashes immediately after separator", () => {
|
|
225
|
+
const key = ["abc", "/def"];
|
|
226
|
+
const serialized = serializeActorKey(key);
|
|
227
|
+
expect(serialized).toBe(`abc${KEY_SEPARATOR}\\/def`);
|
|
228
|
+
expect(deserializeActorKey(serialized)).toEqual(key);
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
// Test exact key matching
|
|
233
|
+
describe("exact key matching", () => {
|
|
234
|
+
test("differentiates [a,b] from [a,b,c]", () => {
|
|
235
|
+
const key1 = ["a", "b"];
|
|
236
|
+
const key2 = ["a", "b", "c"];
|
|
237
|
+
|
|
238
|
+
const serialized1 = serializeActorKey(key1);
|
|
239
|
+
const serialized2 = serializeActorKey(key2);
|
|
240
|
+
|
|
241
|
+
expect(serialized1).not.toBe(serialized2);
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
test("differentiates [a,b] from [a]", () => {
|
|
245
|
+
const key1 = ["a", "b"];
|
|
246
|
+
const key2 = ["a"];
|
|
247
|
+
|
|
248
|
+
const serialized1 = serializeActorKey(key1);
|
|
249
|
+
const serialized2 = serializeActorKey(key2);
|
|
250
|
+
|
|
251
|
+
expect(serialized1).not.toBe(serialized2);
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
test("differentiates [a/b] from [a,b]", () => {
|
|
255
|
+
const key1 = ["a/b"];
|
|
256
|
+
const key2 = ["a", "b"];
|
|
257
|
+
|
|
258
|
+
const serialized1 = serializeActorKey(key1);
|
|
259
|
+
const serialized2 = serializeActorKey(key2);
|
|
260
|
+
|
|
261
|
+
expect(serialized1).not.toBe(serialized2);
|
|
262
|
+
expect(deserializeActorKey(serialized1)).toEqual(key1);
|
|
263
|
+
expect(deserializeActorKey(serialized2)).toEqual(key2);
|
|
264
|
+
});
|
|
265
|
+
});
|
|
266
|
+
});
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { ActorKey } from "@/mod";
|
|
2
|
+
|
|
3
|
+
export const EMPTY_KEY = "/";
|
|
4
|
+
export const KEY_SEPARATOR = "/";
|
|
5
|
+
|
|
6
|
+
export function serializeActorKey(key: ActorKey): string {
|
|
7
|
+
// Use a special marker for empty key arrays
|
|
8
|
+
if (key.length === 0) {
|
|
9
|
+
return EMPTY_KEY;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Escape each key part to handle the separator and the empty key marker
|
|
13
|
+
const escapedParts = key.map((part) => {
|
|
14
|
+
// Handle empty strings by using a special marker
|
|
15
|
+
if (part === "") {
|
|
16
|
+
return "\\0"; // Use \0 as a marker for empty strings
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Escape backslashes first to avoid conflicts with our markers
|
|
20
|
+
let escaped = part.replace(/\\/g, "\\\\");
|
|
21
|
+
|
|
22
|
+
// Then escape separators
|
|
23
|
+
escaped = escaped.replace(/\//g, `\\${KEY_SEPARATOR}`);
|
|
24
|
+
|
|
25
|
+
return escaped;
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
return escapedParts.join(KEY_SEPARATOR);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function deserializeActorKey(keyString: string | undefined): ActorKey {
|
|
32
|
+
// Check for special empty key marker
|
|
33
|
+
if (
|
|
34
|
+
keyString === undefined ||
|
|
35
|
+
keyString === null ||
|
|
36
|
+
keyString === EMPTY_KEY
|
|
37
|
+
) {
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Split by unescaped separators and unescape the escaped characters
|
|
42
|
+
const parts: string[] = [];
|
|
43
|
+
let currentPart = "";
|
|
44
|
+
let escaping = false;
|
|
45
|
+
let isEmptyStringMarker = false;
|
|
46
|
+
|
|
47
|
+
for (let i = 0; i < keyString.length; i++) {
|
|
48
|
+
const char = keyString[i];
|
|
49
|
+
|
|
50
|
+
if (escaping) {
|
|
51
|
+
// Handle special escape sequences
|
|
52
|
+
if (char === "0") {
|
|
53
|
+
// \0 represents an empty string marker
|
|
54
|
+
isEmptyStringMarker = true;
|
|
55
|
+
} else {
|
|
56
|
+
// This is an escaped character, add it directly
|
|
57
|
+
currentPart += char;
|
|
58
|
+
}
|
|
59
|
+
escaping = false;
|
|
60
|
+
} else if (char === "\\") {
|
|
61
|
+
// Start of an escape sequence
|
|
62
|
+
escaping = true;
|
|
63
|
+
} else if (char === KEY_SEPARATOR) {
|
|
64
|
+
// This is a separator
|
|
65
|
+
if (isEmptyStringMarker) {
|
|
66
|
+
parts.push("");
|
|
67
|
+
isEmptyStringMarker = false;
|
|
68
|
+
} else {
|
|
69
|
+
parts.push(currentPart);
|
|
70
|
+
}
|
|
71
|
+
currentPart = "";
|
|
72
|
+
} else {
|
|
73
|
+
// Regular character
|
|
74
|
+
currentPart += char;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Add the last part
|
|
79
|
+
if (escaping) {
|
|
80
|
+
// Incomplete escape at the end - treat as literal backslash
|
|
81
|
+
parts.push(currentPart + "\\");
|
|
82
|
+
} else if (isEmptyStringMarker) {
|
|
83
|
+
parts.push("");
|
|
84
|
+
} else if (currentPart !== "" || parts.length > 0) {
|
|
85
|
+
parts.push(currentPart);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return parts;
|
|
89
|
+
}
|