rivetkit 2.0.2 → 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,591 @@
|
|
|
1
|
+
import { describe, expect, test } from "vitest";
|
|
2
|
+
import type { ActorError } from "@/client/errors";
|
|
3
|
+
import type { DriverTestConfig } from "../mod";
|
|
4
|
+
import { setupDriverTest } from "../utils";
|
|
5
|
+
|
|
6
|
+
export function runActorAuthTests(driverTestConfig: DriverTestConfig) {
|
|
7
|
+
describe("Actor Authentication Tests", () => {
|
|
8
|
+
describe("Basic Authentication", () => {
|
|
9
|
+
test("should allow access with valid auth", async (c) => {
|
|
10
|
+
const { client } = await setupDriverTest(c, driverTestConfig);
|
|
11
|
+
|
|
12
|
+
// Create client with valid auth params
|
|
13
|
+
const instance = client.authActor.getOrCreate(undefined, {
|
|
14
|
+
params: { apiKey: "valid-api-key" },
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
// This should succeed with valid API key
|
|
18
|
+
const authData = await instance.getUserAuth();
|
|
19
|
+
if (driverTestConfig.clientType === "inline") {
|
|
20
|
+
// Inline clients don't have auth data
|
|
21
|
+
expect(authData).toBeUndefined();
|
|
22
|
+
} else {
|
|
23
|
+
// HTTP clients should have auth data
|
|
24
|
+
expect(authData).toEqual({
|
|
25
|
+
userId: "user123",
|
|
26
|
+
token: "valid-api-key",
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Should be able to call actions
|
|
31
|
+
const requests = await instance.getRequests();
|
|
32
|
+
expect(requests).toBe(1);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test("should deny access with invalid auth", async (c) => {
|
|
36
|
+
const { client } = await setupDriverTest(c, driverTestConfig);
|
|
37
|
+
|
|
38
|
+
// This should fail without proper authorization
|
|
39
|
+
const instance = client.authActor.getOrCreate();
|
|
40
|
+
|
|
41
|
+
if (driverTestConfig.clientType === "inline") {
|
|
42
|
+
// Inline clients bypass authentication
|
|
43
|
+
const requests = await instance.getRequests();
|
|
44
|
+
expect(typeof requests).toBe("number");
|
|
45
|
+
} else {
|
|
46
|
+
// HTTP clients should enforce authentication
|
|
47
|
+
try {
|
|
48
|
+
await instance.getRequests();
|
|
49
|
+
expect.fail("Expected authentication error");
|
|
50
|
+
} catch (error) {
|
|
51
|
+
expect((error as ActorError).code).toBe("missing_auth");
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("should expose auth data on connection", async (c) => {
|
|
57
|
+
const { client } = await setupDriverTest(c, driverTestConfig);
|
|
58
|
+
|
|
59
|
+
const instance = client.authActor.getOrCreate(undefined, {
|
|
60
|
+
params: { apiKey: "valid-api-key" },
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Auth data should be available via c.conn.auth
|
|
64
|
+
const authData = await instance.getUserAuth();
|
|
65
|
+
if (driverTestConfig.clientType === "inline") {
|
|
66
|
+
// Inline clients don't have auth data
|
|
67
|
+
expect(authData).toBeUndefined();
|
|
68
|
+
} else {
|
|
69
|
+
// HTTP clients should have auth data
|
|
70
|
+
expect(authData).toBeDefined();
|
|
71
|
+
expect((authData as any).userId).toBe("user123");
|
|
72
|
+
expect((authData as any).token).toBe("valid-api-key");
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
describe("Intent-Based Authentication", () => {
|
|
78
|
+
test("should allow get operations for any role", async (c) => {
|
|
79
|
+
const { client } = await setupDriverTest(c, driverTestConfig);
|
|
80
|
+
|
|
81
|
+
const createdInstance = await client.intentAuthActor.create(["foo"], {
|
|
82
|
+
params: { role: "admin" },
|
|
83
|
+
});
|
|
84
|
+
const actorId = await createdInstance.resolve();
|
|
85
|
+
|
|
86
|
+
if (driverTestConfig.clientType === "inline") {
|
|
87
|
+
// Inline clients bypass authentication
|
|
88
|
+
const instance = client.intentAuthActor.getForId(actorId);
|
|
89
|
+
const value = await instance.getValue();
|
|
90
|
+
expect(value).toBe(0);
|
|
91
|
+
} else {
|
|
92
|
+
// HTTP clients - actions require user or admin role
|
|
93
|
+
const instance = client.intentAuthActor.getForId(actorId, {
|
|
94
|
+
params: { role: "user" }, // Actions require user or admin role
|
|
95
|
+
});
|
|
96
|
+
const value = await instance.getValue();
|
|
97
|
+
expect(value).toBe(0);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test("should require admin role for create operations", async (c) => {
|
|
102
|
+
const { client } = await setupDriverTest(c, driverTestConfig);
|
|
103
|
+
|
|
104
|
+
if (driverTestConfig.clientType === "inline") {
|
|
105
|
+
// Inline clients bypass authentication - should succeed
|
|
106
|
+
const instance = client.intentAuthActor.getOrCreate(undefined, {
|
|
107
|
+
params: { role: "user" },
|
|
108
|
+
});
|
|
109
|
+
const value = await instance.getValue();
|
|
110
|
+
expect(value).toBe(0);
|
|
111
|
+
} else {
|
|
112
|
+
// HTTP clients should enforce authentication
|
|
113
|
+
try {
|
|
114
|
+
const instance = client.intentAuthActor.getOrCreate(undefined, {
|
|
115
|
+
params: { role: "user" },
|
|
116
|
+
});
|
|
117
|
+
await instance.getValue();
|
|
118
|
+
expect.fail("Expected permission error for create operation");
|
|
119
|
+
} catch (error) {
|
|
120
|
+
expect((error as ActorError).code).toBe("insufficient_permissions");
|
|
121
|
+
expect((error as ActorError).message).toContain(
|
|
122
|
+
"Admin role required",
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test("should allow actions for user and admin roles", async (c) => {
|
|
129
|
+
const { client } = await setupDriverTest(c, driverTestConfig);
|
|
130
|
+
|
|
131
|
+
const createdInstance = await client.intentAuthActor.create(["foo"], {
|
|
132
|
+
params: { role: "admin" },
|
|
133
|
+
});
|
|
134
|
+
const actorId = await createdInstance.resolve();
|
|
135
|
+
|
|
136
|
+
// This should fail - actions require user or admin role
|
|
137
|
+
const instance = client.intentAuthActor.getForId(actorId, {
|
|
138
|
+
params: { role: "guest" },
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
if (driverTestConfig.clientType === "inline") {
|
|
142
|
+
// Inline clients bypass authentication - should succeed
|
|
143
|
+
const result = await instance.setValue(42);
|
|
144
|
+
expect(result).toBe(42);
|
|
145
|
+
} else {
|
|
146
|
+
// HTTP clients should enforce authentication
|
|
147
|
+
try {
|
|
148
|
+
await instance.setValue(42);
|
|
149
|
+
expect.fail("Expected permission error for action");
|
|
150
|
+
} catch (error) {
|
|
151
|
+
expect((error as ActorError).code).toBe("insufficient_permissions");
|
|
152
|
+
expect((error as ActorError).message).toContain(
|
|
153
|
+
"User or admin role required",
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
describe("Public Access", () => {
|
|
161
|
+
test("should allow access with empty onAuth", async (c) => {
|
|
162
|
+
const { client } = await setupDriverTest(c, driverTestConfig);
|
|
163
|
+
|
|
164
|
+
// Public actor should allow access without authentication
|
|
165
|
+
const instance = client.publicActor.getOrCreate();
|
|
166
|
+
|
|
167
|
+
const visitors = await instance.visit();
|
|
168
|
+
expect(visitors).toBe(1);
|
|
169
|
+
|
|
170
|
+
// Should be able to call multiple times
|
|
171
|
+
const visitors2 = await instance.visit();
|
|
172
|
+
expect(visitors2).toBe(2);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
test("should deny access without onAuth defined", async (c) => {
|
|
176
|
+
const { client } = await setupDriverTest(c, driverTestConfig);
|
|
177
|
+
|
|
178
|
+
// Actor without onAuth should be blocked
|
|
179
|
+
const instance = client.noAuthActor.getOrCreate();
|
|
180
|
+
|
|
181
|
+
if (driverTestConfig.clientType === "inline") {
|
|
182
|
+
// Inline clients bypass authentication - should succeed
|
|
183
|
+
const value = await instance.getValue();
|
|
184
|
+
expect(value).toBe(42);
|
|
185
|
+
} else {
|
|
186
|
+
// HTTP clients should enforce authentication
|
|
187
|
+
try {
|
|
188
|
+
await instance.getValue();
|
|
189
|
+
expect.fail(
|
|
190
|
+
"Expected access to be denied for actor without onAuth",
|
|
191
|
+
);
|
|
192
|
+
} catch (error) {
|
|
193
|
+
expect((error as ActorError).code).toBe("forbidden");
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
describe("Async Authentication", () => {
|
|
200
|
+
test("should handle promise-based auth", async (c) => {
|
|
201
|
+
const { client } = await setupDriverTest(c, driverTestConfig);
|
|
202
|
+
|
|
203
|
+
const instance = client.asyncAuthActor.getOrCreate(undefined, {
|
|
204
|
+
params: { token: "valid" },
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
// Should succeed with valid token
|
|
208
|
+
const result = await instance.increment();
|
|
209
|
+
expect(result).toBe(1);
|
|
210
|
+
|
|
211
|
+
// Auth data should be available
|
|
212
|
+
const authData = await instance.getAuthData();
|
|
213
|
+
if (driverTestConfig.clientType === "inline") {
|
|
214
|
+
// Inline clients don't have auth data
|
|
215
|
+
expect(authData).toBeUndefined();
|
|
216
|
+
} else {
|
|
217
|
+
// HTTP clients should have auth data
|
|
218
|
+
expect(authData).toBeDefined();
|
|
219
|
+
expect((authData as any).userId).toBe("user-valid");
|
|
220
|
+
expect((authData as any).validated).toBe(true);
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
test("should handle async auth failures", async (c) => {
|
|
225
|
+
const { client } = await setupDriverTest(c, driverTestConfig);
|
|
226
|
+
|
|
227
|
+
const instance = client.asyncAuthActor.getOrCreate();
|
|
228
|
+
|
|
229
|
+
if (driverTestConfig.clientType === "inline") {
|
|
230
|
+
// Inline clients bypass authentication - should succeed
|
|
231
|
+
const result = await instance.increment();
|
|
232
|
+
expect(result).toBe(1);
|
|
233
|
+
} else {
|
|
234
|
+
// HTTP clients should enforce authentication
|
|
235
|
+
try {
|
|
236
|
+
await instance.increment();
|
|
237
|
+
expect.fail("Expected async auth failure");
|
|
238
|
+
} catch (error) {
|
|
239
|
+
expect((error as ActorError).code).toBe("missing_token");
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
describe("Authentication Across Transports", () => {
|
|
246
|
+
if (driverTestConfig.transport === "websocket") {
|
|
247
|
+
test("should authenticate WebSocket connections", async (c) => {
|
|
248
|
+
const { client } = await setupDriverTest(c, driverTestConfig);
|
|
249
|
+
|
|
250
|
+
// Test WebSocket connection auth
|
|
251
|
+
const instance = client.authActor.getOrCreate(undefined, {
|
|
252
|
+
params: { apiKey: "valid-api-key" },
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
// Should be able to establish connection and call actions
|
|
256
|
+
const authData = await instance.getUserAuth();
|
|
257
|
+
expect(authData).toBeDefined();
|
|
258
|
+
expect((authData as any).userId).toBe("user123");
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
test("should authenticate HTTP actions", async (c) => {
|
|
263
|
+
const { client } = await setupDriverTest(c, driverTestConfig);
|
|
264
|
+
|
|
265
|
+
// Test HTTP action auth
|
|
266
|
+
const instance = client.authActor.getOrCreate(undefined, {
|
|
267
|
+
params: { apiKey: "valid-api-key" },
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
// Actions should require authentication
|
|
271
|
+
const requests = await instance.getRequests();
|
|
272
|
+
expect(typeof requests).toBe("number");
|
|
273
|
+
});
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
describe("Error Handling", () => {
|
|
277
|
+
test("should handle auth errors gracefully", async (c) => {
|
|
278
|
+
const { client } = await setupDriverTest(c, driverTestConfig);
|
|
279
|
+
|
|
280
|
+
const instance = client.authActor.getOrCreate();
|
|
281
|
+
|
|
282
|
+
if (driverTestConfig.clientType === "inline") {
|
|
283
|
+
// Inline clients bypass authentication - should succeed
|
|
284
|
+
const requests = await instance.getRequests();
|
|
285
|
+
expect(typeof requests).toBe("number");
|
|
286
|
+
} else {
|
|
287
|
+
// HTTP clients should enforce authentication
|
|
288
|
+
try {
|
|
289
|
+
await instance.getRequests();
|
|
290
|
+
expect.fail("Expected authentication error");
|
|
291
|
+
} catch (error) {
|
|
292
|
+
// Error should be properly structured
|
|
293
|
+
const actorError = error as ActorError;
|
|
294
|
+
expect(actorError.code).toBeDefined();
|
|
295
|
+
expect(actorError.message).toBeDefined();
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
test("should preserve error details for debugging", async (c) => {
|
|
301
|
+
const { client } = await setupDriverTest(c, driverTestConfig);
|
|
302
|
+
|
|
303
|
+
const instance = client.asyncAuthActor.getOrCreate();
|
|
304
|
+
|
|
305
|
+
if (driverTestConfig.clientType === "inline") {
|
|
306
|
+
// Inline clients bypass authentication - should succeed
|
|
307
|
+
const result = await instance.increment();
|
|
308
|
+
expect(result).toBe(1);
|
|
309
|
+
} else {
|
|
310
|
+
// HTTP clients should enforce authentication
|
|
311
|
+
try {
|
|
312
|
+
await instance.increment();
|
|
313
|
+
expect.fail("Expected token error");
|
|
314
|
+
} catch (error) {
|
|
315
|
+
const actorError = error as ActorError;
|
|
316
|
+
expect(actorError.code).toBe("missing_token");
|
|
317
|
+
expect(actorError.message).toBe("Token required");
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
describe("Raw HTTP Authentication", () => {
|
|
324
|
+
test("should allow raw HTTP access with valid auth", async (c) => {
|
|
325
|
+
const { client } = await setupDriverTest(c, driverTestConfig);
|
|
326
|
+
|
|
327
|
+
// Create actor with valid auth
|
|
328
|
+
const instance = client.rawHttpAuthActor.getOrCreate(undefined, {
|
|
329
|
+
params: { apiKey: "valid-api-key" },
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
// Raw HTTP request should succeed
|
|
333
|
+
const response = await instance.fetch("api/auth-info");
|
|
334
|
+
expect(response.ok).toBe(true);
|
|
335
|
+
|
|
336
|
+
const data = (await response.json()) as any;
|
|
337
|
+
expect(data.message).toBe("Authenticated request");
|
|
338
|
+
expect(data.requestCount).toBe(1);
|
|
339
|
+
|
|
340
|
+
// Regular actions should also work
|
|
341
|
+
const count = await instance.getRequestCount();
|
|
342
|
+
expect(count).toBe(1);
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
test("should deny raw HTTP access without auth", async (c) => {
|
|
346
|
+
const { client } = await setupDriverTest(c, driverTestConfig);
|
|
347
|
+
|
|
348
|
+
// Create actor without auth
|
|
349
|
+
const instance = client.rawHttpAuthActor.getOrCreate();
|
|
350
|
+
|
|
351
|
+
// All clients should now enforce authentication for raw endpoints
|
|
352
|
+
const response = await instance.fetch("api/protected");
|
|
353
|
+
if (driverTestConfig.clientType === "inline") {
|
|
354
|
+
expect(response.ok).toBe(true);
|
|
355
|
+
expect(response.status).toBe(200);
|
|
356
|
+
} else {
|
|
357
|
+
expect(response.ok).toBe(false);
|
|
358
|
+
expect(response.status).toBe(400);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Check error details
|
|
362
|
+
try {
|
|
363
|
+
const errorData = (await response.json()) as any;
|
|
364
|
+
expect(errorData.c || errorData.code).toBe("missing_auth");
|
|
365
|
+
} catch {
|
|
366
|
+
// Response might be CBOR encoded, status code check is sufficient
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
test("should deny raw HTTP for actors without onAuth", async (c) => {
|
|
371
|
+
const { client } = await setupDriverTest(c, driverTestConfig);
|
|
372
|
+
|
|
373
|
+
const instance = client.rawHttpNoAuthActor.getOrCreate();
|
|
374
|
+
|
|
375
|
+
// All clients should now enforce authentication for raw endpoints
|
|
376
|
+
const response = await instance.fetch("api/test");
|
|
377
|
+
if (driverTestConfig.clientType === "inline") {
|
|
378
|
+
expect(response.ok).toBe(true);
|
|
379
|
+
expect(response.status).toBe(200);
|
|
380
|
+
} else {
|
|
381
|
+
expect(response.ok).toBe(false);
|
|
382
|
+
expect(response.status).toBe(403);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// Check error details
|
|
386
|
+
try {
|
|
387
|
+
const errorData = (await response.json()) as any;
|
|
388
|
+
expect(errorData.c || errorData.code).toBe("forbidden");
|
|
389
|
+
} catch {
|
|
390
|
+
// Response might be CBOR encoded, status code check is sufficient
|
|
391
|
+
}
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
test("should allow public raw HTTP access", async (c) => {
|
|
395
|
+
const { client } = await setupDriverTest(c, driverTestConfig);
|
|
396
|
+
|
|
397
|
+
const instance = client.rawHttpPublicActor.getOrCreate();
|
|
398
|
+
|
|
399
|
+
// Should work without auth
|
|
400
|
+
const response = await instance.fetch("api/visit");
|
|
401
|
+
expect(response.ok).toBe(true);
|
|
402
|
+
|
|
403
|
+
const data = (await response.json()) as any;
|
|
404
|
+
expect(data.message).toBe("Welcome visitor!");
|
|
405
|
+
expect(data.count).toBe(1);
|
|
406
|
+
|
|
407
|
+
// Second request
|
|
408
|
+
const response2 = await instance.fetch("api/visit");
|
|
409
|
+
const data2 = (await response2.json()) as any;
|
|
410
|
+
expect(data2.count).toBe(2);
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
test("should handle custom auth in onFetch", async (c) => {
|
|
414
|
+
const { client } = await setupDriverTest(c, driverTestConfig);
|
|
415
|
+
|
|
416
|
+
const instance = client.rawHttpCustomAuthActor.getOrCreate();
|
|
417
|
+
|
|
418
|
+
// Request without auth should fail
|
|
419
|
+
const response1 = await instance.fetch("api/data");
|
|
420
|
+
expect(response1.ok).toBe(false);
|
|
421
|
+
expect(response1.status).toBe(401);
|
|
422
|
+
|
|
423
|
+
const error1 = (await response1.json()) as any;
|
|
424
|
+
expect(error1.error).toBe("Unauthorized");
|
|
425
|
+
|
|
426
|
+
// Request with wrong token should fail
|
|
427
|
+
const response2 = await instance.fetch("api/data", {
|
|
428
|
+
headers: {
|
|
429
|
+
Authorization: "Bearer wrong-token",
|
|
430
|
+
},
|
|
431
|
+
});
|
|
432
|
+
expect(response2.ok).toBe(false);
|
|
433
|
+
expect(response2.status).toBe(403);
|
|
434
|
+
|
|
435
|
+
// Request with correct token should succeed
|
|
436
|
+
const response3 = await instance.fetch("api/data", {
|
|
437
|
+
headers: {
|
|
438
|
+
Authorization: "Bearer custom-token",
|
|
439
|
+
},
|
|
440
|
+
});
|
|
441
|
+
expect(response3.ok).toBe(true);
|
|
442
|
+
|
|
443
|
+
const data = (await response3.json()) as any;
|
|
444
|
+
expect(data.message).toBe("Authorized!");
|
|
445
|
+
expect(data.authorized).toBe(1);
|
|
446
|
+
|
|
447
|
+
// Check stats
|
|
448
|
+
const stats = await instance.getStats();
|
|
449
|
+
expect(stats.authorized).toBe(1);
|
|
450
|
+
expect(stats.unauthorized).toBe(2);
|
|
451
|
+
});
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
describe("Raw WebSocket Authentication", () => {
|
|
455
|
+
test("should allow raw WebSocket access with valid auth", async (c) => {
|
|
456
|
+
const { client } = await setupDriverTest(c, driverTestConfig);
|
|
457
|
+
|
|
458
|
+
// Create actor with valid auth
|
|
459
|
+
const instance = client.rawWebSocketAuthActor.getOrCreate(undefined, {
|
|
460
|
+
params: { apiKey: "valid-api-key" },
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
const ws = await instance.websocket();
|
|
464
|
+
|
|
465
|
+
// Wait for welcome message
|
|
466
|
+
const welcomePromise = new Promise((resolve, reject) => {
|
|
467
|
+
ws.addEventListener("message", (event: any) => {
|
|
468
|
+
const data = JSON.parse(event.data);
|
|
469
|
+
if (data.type === "welcome") {
|
|
470
|
+
resolve(data);
|
|
471
|
+
}
|
|
472
|
+
});
|
|
473
|
+
ws.addEventListener("close", () => reject("closed"));
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
const welcomeData = (await welcomePromise) as any;
|
|
477
|
+
expect(welcomeData.message).toBe("Authenticated WebSocket connection");
|
|
478
|
+
expect(welcomeData.connectionCount).toBe(1);
|
|
479
|
+
|
|
480
|
+
ws.close();
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
test("should deny raw WebSocket access without auth", async (c) => {
|
|
484
|
+
const { client } = await setupDriverTest(c, driverTestConfig);
|
|
485
|
+
|
|
486
|
+
const instance = client.rawWebSocketAuthActor.getOrCreate();
|
|
487
|
+
|
|
488
|
+
// All clients should now enforce authentication for raw endpoints
|
|
489
|
+
try {
|
|
490
|
+
await instance.websocket();
|
|
491
|
+
expect.fail("Expected authentication error");
|
|
492
|
+
} catch (error) {
|
|
493
|
+
// WebSocket connection failures may not always have structured error codes
|
|
494
|
+
expect(error).toBeDefined();
|
|
495
|
+
}
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
test("should deny raw WebSocket for actors without onAuth", async (c) => {
|
|
499
|
+
const { client } = await setupDriverTest(c, driverTestConfig);
|
|
500
|
+
|
|
501
|
+
const instance = client.rawWebSocketNoAuthActor.getOrCreate();
|
|
502
|
+
|
|
503
|
+
// All clients should now enforce authentication for raw endpoints
|
|
504
|
+
try {
|
|
505
|
+
await instance.websocket();
|
|
506
|
+
expect.fail("Expected forbidden error");
|
|
507
|
+
} catch (error) {
|
|
508
|
+
// WebSocket connection failures may not always have structured error codes
|
|
509
|
+
expect(error).toBeDefined();
|
|
510
|
+
}
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
test("should allow public raw WebSocket access", async (c) => {
|
|
514
|
+
const { client } = await setupDriverTest(c, driverTestConfig);
|
|
515
|
+
|
|
516
|
+
const instance = client.rawWebSocketPublicActor.getOrCreate();
|
|
517
|
+
|
|
518
|
+
// Should work without auth
|
|
519
|
+
const ws = await instance.websocket();
|
|
520
|
+
|
|
521
|
+
const welcomePromise = new Promise((resolve, reject) => {
|
|
522
|
+
ws.addEventListener("message", (event: any) => {
|
|
523
|
+
const data = JSON.parse(event.data);
|
|
524
|
+
if (data.type === "welcome") {
|
|
525
|
+
resolve(data);
|
|
526
|
+
}
|
|
527
|
+
});
|
|
528
|
+
ws.addEventListener("close", reject);
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
const welcomeData = (await welcomePromise) as any;
|
|
532
|
+
expect(welcomeData.message).toBe("Public WebSocket connection");
|
|
533
|
+
expect(welcomeData.visitorNumber).toBe(1);
|
|
534
|
+
|
|
535
|
+
ws.close();
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
test("should handle custom auth in onWebSocket", async (c) => {
|
|
539
|
+
const { client } = await setupDriverTest(c, driverTestConfig);
|
|
540
|
+
|
|
541
|
+
const instance = client.rawWebSocketCustomAuthActor.getOrCreate();
|
|
542
|
+
|
|
543
|
+
// WebSocket without token should be rejected
|
|
544
|
+
try {
|
|
545
|
+
const ws1 = await instance.websocket();
|
|
546
|
+
|
|
547
|
+
// Listen for error message before close
|
|
548
|
+
const errorPromise = new Promise((resolve, reject) => {
|
|
549
|
+
ws1.addEventListener("message", (event: any) => {
|
|
550
|
+
const data = JSON.parse(event.data);
|
|
551
|
+
if (data.type === "error") {
|
|
552
|
+
resolve(data);
|
|
553
|
+
}
|
|
554
|
+
});
|
|
555
|
+
ws1.addEventListener("close", reject);
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
const errorData = (await errorPromise) as any;
|
|
559
|
+
expect(errorData.type).toBe("error");
|
|
560
|
+
expect(errorData.message).toBe("Unauthorized");
|
|
561
|
+
} catch (error) {
|
|
562
|
+
// Some drivers might reject the connection immediately
|
|
563
|
+
expect(error).toBeDefined();
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
// WebSocket with correct token should succeed
|
|
567
|
+
const ws2 = await instance.websocket("?token=custom-ws-token");
|
|
568
|
+
|
|
569
|
+
const authPromise = new Promise((resolve, reject) => {
|
|
570
|
+
ws2.addEventListener("message", (event: any) => {
|
|
571
|
+
const data = JSON.parse(event.data);
|
|
572
|
+
if (data.type === "authorized") {
|
|
573
|
+
resolve(data);
|
|
574
|
+
}
|
|
575
|
+
});
|
|
576
|
+
ws2.addEventListener("close", reject);
|
|
577
|
+
});
|
|
578
|
+
|
|
579
|
+
const authData = (await authPromise) as any;
|
|
580
|
+
expect(authData.message).toBe("Welcome authenticated user!");
|
|
581
|
+
|
|
582
|
+
ws2.close();
|
|
583
|
+
|
|
584
|
+
// Check stats
|
|
585
|
+
const stats = await instance.getStats();
|
|
586
|
+
expect(stats.authorized).toBeGreaterThanOrEqual(1);
|
|
587
|
+
expect(stats.unauthorized).toBeGreaterThanOrEqual(1);
|
|
588
|
+
});
|
|
589
|
+
});
|
|
590
|
+
});
|
|
591
|
+
}
|