@fuzdev/fuz_app 0.113.0 → 0.115.0
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/actions/CLAUDE.md +46 -20
- package/dist/actions/action_dispatcher.d.ts +1 -1
- package/dist/actions/action_dispatcher.d.ts.map +1 -1
- package/dist/actions/action_dispatcher.js +22 -16
- package/dist/actions/action_event.d.ts +18 -2
- package/dist/actions/action_event.d.ts.map +1 -1
- package/dist/actions/action_event.js +63 -19
- package/dist/actions/action_event_types.d.ts +22 -0
- package/dist/actions/action_event_types.d.ts.map +1 -1
- package/dist/actions/action_event_types.js +19 -0
- package/dist/actions/compile_action_registry.d.ts +4 -2
- package/dist/actions/compile_action_registry.d.ts.map +1 -1
- package/dist/actions/compile_action_registry.js +8 -3
- package/dist/actions/frontend_rpc_client.d.ts +6 -0
- package/dist/actions/frontend_rpc_client.d.ts.map +1 -1
- package/dist/actions/frontend_rpc_client.js +2 -1
- package/dist/actions/heartbeat.d.ts +8 -4
- package/dist/actions/heartbeat.d.ts.map +1 -1
- package/dist/actions/heartbeat.js +8 -4
- package/dist/actions/peer_ping.d.ts.map +1 -1
- package/dist/actions/peer_ping.js +3 -1
- package/dist/actions/perform_action.d.ts +1 -1
- package/dist/actions/perform_action.d.ts.map +1 -1
- package/dist/actions/perform_action.js +6 -4
- package/dist/actions/register_action_ws.d.ts +13 -0
- package/dist/actions/register_action_ws.d.ts.map +1 -1
- package/dist/actions/register_action_ws.js +23 -2
- package/dist/actions/rpc_client.d.ts +1 -1
- package/dist/actions/rpc_client.d.ts.map +1 -1
- package/dist/actions/rpc_client.js +2 -1
- package/dist/actions/socket.svelte.d.ts +53 -10
- package/dist/actions/socket.svelte.d.ts.map +1 -1
- package/dist/actions/socket.svelte.js +84 -23
- package/dist/actions/transports.d.ts +24 -0
- package/dist/actions/transports.d.ts.map +1 -1
- package/dist/actions/transports.js +30 -0
- package/dist/actions/transports_http.d.ts +11 -4
- package/dist/actions/transports_http.d.ts.map +1 -1
- package/dist/actions/transports_http.js +63 -18
- package/dist/actions/transports_ws.d.ts +28 -3
- package/dist/actions/transports_ws.d.ts.map +1 -1
- package/dist/actions/transports_ws.js +33 -4
- package/dist/actions/ws_endpoint_spec.d.ts +7 -0
- package/dist/actions/ws_endpoint_spec.d.ts.map +1 -1
- package/dist/auth/CLAUDE.md +52 -8
- package/dist/auth/admin_actions.d.ts.map +1 -1
- package/dist/auth/admin_actions.js +4 -3
- package/dist/auth/audit_log_schema.d.ts +3 -1
- package/dist/auth/audit_log_schema.d.ts.map +1 -1
- package/dist/auth/audit_log_schema.js +13 -3
- package/dist/auth/cell_action_specs.js +1 -1
- package/dist/auth/cell_actions.d.ts.map +1 -1
- package/dist/auth/cell_actions.js +33 -4
- package/dist/auth/cell_authorize.d.ts +3 -0
- package/dist/auth/cell_authorize.d.ts.map +1 -1
- package/dist/auth/cell_authorize.js +7 -4
- package/dist/auth/request_context.d.ts +12 -3
- package/dist/auth/request_context.d.ts.map +1 -1
- package/dist/auth/request_context.js +12 -3
- package/dist/auth/role_grant_offer_action_specs.d.ts +30 -5
- package/dist/auth/role_grant_offer_action_specs.d.ts.map +1 -1
- package/dist/auth/role_grant_offer_action_specs.js +53 -17
- package/dist/auth/role_grant_offer_actions.d.ts +23 -12
- package/dist/auth/role_grant_offer_actions.d.ts.map +1 -1
- package/dist/auth/role_grant_offer_actions.js +132 -38
- package/dist/auth/role_grant_offer_queries.d.ts +36 -0
- package/dist/auth/role_grant_offer_queries.d.ts.map +1 -1
- package/dist/auth/role_grant_offer_queries.js +76 -0
- package/dist/auth/role_schema.d.ts +12 -0
- package/dist/auth/role_schema.d.ts.map +1 -1
- package/dist/auth/role_schema.js +12 -0
- package/dist/auth/self_service_role_actions.d.ts +14 -0
- package/dist/auth/self_service_role_actions.d.ts.map +1 -1
- package/dist/auth/self_service_role_actions.js +25 -1
- package/dist/http/CLAUDE.md +7 -3
- package/dist/http/jsonrpc_helpers.d.ts +0 -5
- package/dist/http/jsonrpc_helpers.d.ts.map +1 -1
- package/dist/http/jsonrpc_helpers.js +0 -13
- package/dist/http/schema_helpers.d.ts +56 -0
- package/dist/http/schema_helpers.d.ts.map +1 -1
- package/dist/http/schema_helpers.js +91 -0
- package/dist/server/app_server.d.ts.map +1 -1
- package/dist/server/app_server.js +1 -0
- package/dist/server/serve_fact_route.d.ts +3 -1
- package/dist/server/serve_fact_route.d.ts.map +1 -1
- package/dist/server/serve_fact_route.js +7 -4
- package/dist/testing/CLAUDE.md +29 -16
- package/dist/testing/cross_backend/cell_gated_create.d.ts.map +1 -1
- package/dist/testing/cross_backend/cell_gated_create.js +23 -1
- package/dist/testing/cross_backend/peer_ping_ws.d.ts.map +1 -1
- package/dist/testing/cross_backend/peer_ping_ws.js +18 -0
- package/dist/testing/cross_backend/role_grant_participation.d.ts.map +1 -1
- package/dist/testing/cross_backend/role_grant_participation.js +34 -0
- package/dist/testing/cross_backend/rust_spine_stub_backend_config.d.ts +12 -1
- package/dist/testing/cross_backend/rust_spine_stub_backend_config.d.ts.map +1 -1
- package/dist/testing/cross_backend/rust_spine_stub_backend_config.js +13 -1
- package/dist/testing/cross_backend/test_cell_gated_create_authorize.d.ts.map +1 -1
- package/dist/testing/cross_backend/test_cell_gated_create_authorize.js +9 -7
- package/dist/testing/cross_backend/ws_round_trip.d.ts +11 -3
- package/dist/testing/cross_backend/ws_round_trip.d.ts.map +1 -1
- package/dist/testing/cross_backend/ws_round_trip.js +74 -12
- package/dist/testing/entities.d.ts +6 -3
- package/dist/testing/entities.d.ts.map +1 -1
- package/dist/testing/entities.js +4 -1
- package/dist/testing/transports/ws_client.d.ts +6 -0
- package/dist/testing/transports/ws_client.d.ts.map +1 -1
- package/dist/testing/transports/ws_transport.d.ts.map +1 -1
- package/dist/testing/transports/ws_transport.js +6 -1
- package/dist/testing/ws_round_trip.d.ts.map +1 -1
- package/dist/testing/ws_round_trip.js +5 -0
- package/dist/ui/BootstrapForm.svelte +14 -10
- package/dist/ui/BootstrapForm.svelte.d.ts.map +1 -1
- package/dist/ui/CLAUDE.md +19 -7
- package/dist/ui/LoginForm.svelte +8 -4
- package/dist/ui/LoginForm.svelte.d.ts.map +1 -1
- package/dist/ui/RoleGrantOfferForm.svelte +29 -14
- package/dist/ui/RoleGrantOfferForm.svelte.d.ts +2 -3
- package/dist/ui/RoleGrantOfferForm.svelte.d.ts.map +1 -1
- package/dist/ui/SignupForm.svelte +14 -13
- package/dist/ui/form_state.svelte.d.ts +24 -11
- package/dist/ui/form_state.svelte.d.ts.map +1 -1
- package/dist/ui/form_state.svelte.js +38 -10
- package/dist/ui/role_grant_offers_state.svelte.d.ts +25 -15
- package/dist/ui/role_grant_offers_state.svelte.d.ts.map +1 -1
- package/dist/ui/role_grant_offers_state.svelte.js +7 -1
- package/package.json +2 -22
- package/dist/actions/request_tracker.svelte.d.ts +0 -77
- package/dist/actions/request_tracker.svelte.d.ts.map +0 -1
- package/dist/actions/request_tracker.svelte.js +0 -169
package/dist/testing/CLAUDE.md
CHANGED
|
@@ -544,16 +544,17 @@ Three layers:
|
|
|
544
544
|
3. **Round-trip helpers** — predicates + wire-frame types live in `transports/ws_client.ts` (shared with the cross-process `ws_transport.ts` impl): `is_notification(method)`, `is_notification_with<P>(method, match)` (type-guard combinator — narrows `wait_for` return type), `is_response_for(id)`, `JsonrpcNotificationFrame<P>` / `JsonrpcSuccessResponseFrame<R>` / `JsonrpcErrorResponseFrame<D>` (typed wire-frame shapes distinct from the runtime Zod schemas in `http/jsonrpc.ts` — generic over `params` / `result` / `data` so tests narrow without casts). `build_broadcast_api<TApi>({harness, specs})` (in `ws_round_trip.ts`) wires a typed broadcast API against the harness transport.
|
|
545
545
|
|
|
546
546
|
`WsClient` (in `transports/ws_client.ts`):
|
|
547
|
-
`{send, request<R>, close, messages, wait_for, wait_for_close}`.
|
|
548
|
-
harness's `connect()` returns this shape; the cross-process
|
|
547
|
+
`{send, request<R>, close, messages, wait_for, wait_for_close, close_code}`.
|
|
548
|
+
The harness's `connect()` returns this shape; the cross-process
|
|
549
549
|
`create_ws_transport` in `transports/ws_transport.ts` implements the same
|
|
550
550
|
interface so assertion helpers and suite bodies work against either impl.
|
|
551
551
|
`wait_for_close(timeout_ms?)` resolves `true` if the server closes the
|
|
552
552
|
socket within the timeout, `false` on timeout (and `true` immediately when
|
|
553
553
|
already closed) — the signal for server-initiated close (e.g. an auth-guard
|
|
554
554
|
revocation), distinct from client-initiated `close()`. Mirrors the SSE frame
|
|
555
|
-
reader's `wait_for_close`. `
|
|
556
|
-
|
|
555
|
+
reader's `wait_for_close`. `close_code` is the connection's close code once
|
|
556
|
+
closed (`1006` for a drop without a close frame), `null` while open.
|
|
557
|
+
`request` throws with code + message + data on error frames (so asserting `result.foo` on a
|
|
557
558
|
failed request surfaces the real cause, not a `Cannot read property 'foo'
|
|
558
559
|
of undefined`). `wait_for(predicate, timeout_ms?)` checks already-received
|
|
559
560
|
messages first, then waits for new arrivals (default 1000ms); drops the
|
|
@@ -1079,10 +1080,13 @@ call (not folded into `describe_standard_cross_process_tests`) because it
|
|
|
1079
1080
|
needs raw `base_url` / `ws_path` the standard bundle doesn't carry, mirroring
|
|
1080
1081
|
how `describe_ws_round_trip_tests` sits beside `describe_standard_tests`
|
|
1081
1082
|
in-process. `describe_cross_process_ws_tests({setup_test, capabilities,
|
|
1082
|
-
base_url, ws_path, origin?, rpc_path?})` opens a live
|
|
1083
|
-
`create_ws_transport` (the `ws` npm package) and asserts
|
|
1084
|
-
against the upgrade stack `register_ws_endpoint` wires (origin →
|
|
1083
|
+
base_url, ws_path, origin?, rpc_path?, max_message_bytes?})` opens a live
|
|
1084
|
+
`WebSocket` via `create_ws_transport` (the `ws` npm package) and asserts
|
|
1085
|
+
cases against the upgrade stack `register_ws_endpoint` wires (origin →
|
|
1085
1086
|
`require_auth` → dispatch): authed upgrade round-trips `heartbeat`,
|
|
1087
|
+
`heartbeat` admits only the parameterless shapes (a declared param →
|
|
1088
|
+
`invalid_params`), a message past `max_message_bytes` (default
|
|
1089
|
+
`DEFAULT_WS_MAX_MESSAGE_BYTES`) closes with `WS_CLOSE_MESSAGE_TOO_BIG`,
|
|
1086
1090
|
anonymous upgrade refused, disallowed-origin upgrade refused, and — gated on
|
|
1087
1091
|
`rpc_path` — a live socket drops when the account's sessions are revoked
|
|
1088
1092
|
mid-connection (`account_session_revoke_all` over the keeper session channel
|
|
@@ -1144,11 +1148,12 @@ drives the whole round-trip and every outcome (success / `Timeout` / wrong-shape
|
|
|
1144
1148
|
`on_request` responder **at construction** (the `create_ws_transport` seam) so
|
|
1145
1149
|
the inbound server-initiated request is answered as soon as it arrives; the
|
|
1146
1150
|
security negatives use the raw `WsClient.send` to inject unsolicited /
|
|
1147
|
-
cross-connection frames.
|
|
1151
|
+
cross-connection frames. Cases: the positive round-trip plus
|
|
1148
1152
|
unsolicited-response rejection, per-connection id isolation, never-reply
|
|
1149
|
-
`Timeout`, wrong-shape rejection,
|
|
1150
|
-
|
|
1151
|
-
|
|
1153
|
+
`Timeout`, wrong-shape rejection, an undeclared reply key accepted and dropped
|
|
1154
|
+
(both spines read the reply forward-compatibly), client-error forwarding, and
|
|
1155
|
+
the HTTP no-transport path. Gated on `capabilities.peer_request` — `true` on
|
|
1156
|
+
both the Rust spine and the TS spine (the `BackendWebsocketTransport.request_connection`
|
|
1152
1157
|
path + `register_action_ws` response correlation); `peer/ping` is a protocol
|
|
1153
1158
|
action (manifest-excluded), so parity is behavioral here, not via the manifest
|
|
1154
1159
|
gate. Cross-process only; fuz_app's own wiring is
|
|
@@ -1232,8 +1237,11 @@ the option type states whether the bundle is read.
|
|
|
1232
1237
|
(gate on `capabilities.cell_gated_create`, **cross-only**) — the parent-aware
|
|
1233
1238
|
cell-creation authorizer (`CellCreateAuthorize`, **directory model**) +
|
|
1234
1239
|
the `cell_moderate` verb parity proofs. Both spines mount the same
|
|
1235
|
-
`test_cell_gated_create_authorize` policy
|
|
1236
|
-
|
|
1240
|
+
`test_cell_gated_create_authorize` policy (its admin bypass and `min_role`
|
|
1241
|
+
read the **global** grant): a `kind: 'space'` **root** is
|
|
1242
|
+
admin-only (a non-admin → **403** `cell_create_forbidden`, and the same for a
|
|
1243
|
+
non-admin `cell_clone` of a viewable space — clone runs the authorizer for
|
|
1244
|
+
every cell it writes); a **contribution**
|
|
1237
1245
|
under a space is gated by the root's `data.policy[kind] = {min_role,
|
|
1238
1246
|
moderation_required}`, with `moderation` set per the verdict (`pending`+private
|
|
1239
1247
|
vs `approved`+author-visibility); a **hidden** parent **404**-masks vs a
|
|
@@ -1284,7 +1292,7 @@ are `src/test/auth/cell_crud_parity.db.test.ts`
|
|
|
1284
1292
|
transport carries the keeper session cookie in its jar after this call
|
|
1285
1293
|
resolves.
|
|
1286
1294
|
- `testing/transports/ws_client.ts` — shared `WsClient` interface (`send` /
|
|
1287
|
-
`request` / `close` / `messages` / `wait_for` / `wait_for_close`),
|
|
1295
|
+
`request` / `close` / `messages` / `wait_for` / `wait_for_close` / `close_code`),
|
|
1288
1296
|
wire-frame types, and
|
|
1289
1297
|
predicates (`is_notification`, `is_response_for`, ...). Both in-process
|
|
1290
1298
|
(`ws_round_trip.ts`) and cross-process (`ws_transport.ts`) impls satisfy
|
|
@@ -1614,12 +1622,17 @@ non-admin _holder_ of `participant` (and a fresh non-admin) can't offer it (403
|
|
|
1614
1622
|
`role_grant_assign` is admin-only** — non-admin holder / fresh → 403
|
|
1615
1623
|
`insufficient_permissions` (dispatcher gate), anon → 401; plus the
|
|
1616
1624
|
`to_actor_id`-must-belong-to-`to_account_id` resolution arm (400
|
|
1617
|
-
`role_grant_offer_actor_account_mismatch`)
|
|
1625
|
+
`role_grant_offer_actor_account_mismatch`); **(d) builtin roles are
|
|
1626
|
+
global-only** — an unpaired `scope_kind` / `scope_id` → 400 on assign + offer,
|
|
1627
|
+
a scoped `admin` → 400 `role_grant_builtin_scoped` on assign + offer, a builtin
|
|
1628
|
+
offer from a non-global-admin → 403 `role_grant_offer_not_authorized`.
|
|
1618
1629
|
|
|
1619
1630
|
`describe_role_grant_participation_cross_tests` (this module) is the **imperative
|
|
1620
1631
|
escape hatch** for the multi-step success paths a static row can't express (they
|
|
1621
1632
|
need a real recipient): admin **assigns** `participant` to a fresh account
|
|
1622
|
-
(`{ok, role_grant_id}` + idempotent re-assign),
|
|
1633
|
+
(`{ok, role_grant_id}` + idempotent re-assign), admin **assigns** a scoped
|
|
1634
|
+
`participant` whose `scope_kind` + `scope_id` round-trip through
|
|
1635
|
+
`admin_account_list` (distinct from the global grant), and admin **offers**
|
|
1623
1636
|
`participant` → recipient **accepts** → a role_grant lands. The `role_holder`
|
|
1624
1637
|
principal is seeded via `extra_accounts: [{username, roles: ['participant']}]`
|
|
1625
1638
|
(bootstrap-cradle direct grant) and named through `principals.role_holder`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cell_gated_create.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/cell_gated_create.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"cell_gated_create.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/cell_gated_create.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAyD9B,OAAO,KAAK,EAAE,uCAAuC,EAAE,MAAM,YAAY,CAAC;AAkB1E,eAAO,MAAM,sCAAsC,GAClD,SAAS,uCAAuC,KAC9C,IAwPF,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,kCAAkC,GAC9C,SAAS,uCAAuC,KAC9C,IAyKF,CAAC"}
|
|
@@ -30,6 +30,9 @@ import '../assert_dev_env.js';
|
|
|
30
30
|
* **private** space the caller can't view → **404** `cell_not_found` (the
|
|
31
31
|
* parent is masked); under a **public** space → **403** (you see it, you
|
|
32
32
|
* can't contribute).
|
|
33
|
+
* - **clone is no side door** — `cell_clone` runs the authorizer for every cell
|
|
34
|
+
* it writes as a parentless create, so a non-admin clone of a viewable
|
|
35
|
+
* `space` root → **403** `cell_create_forbidden`; admin → succeeds.
|
|
33
36
|
*
|
|
34
37
|
* Gated on `capabilities.cell_gated_create` — `true` only on the reference
|
|
35
38
|
* spine binaries that mount the policy, so it skips for generic consumers and
|
|
@@ -41,7 +44,8 @@ import '../assert_dev_env.js';
|
|
|
41
44
|
* @module
|
|
42
45
|
*/
|
|
43
46
|
import { describe, assert } from 'vitest';
|
|
44
|
-
import { CellCreateOutput, CellModerateOutput } from '../../auth/cell_action_specs.js';
|
|
47
|
+
import { CellCloneOutput, CellCreateOutput, CellModerateOutput } from '../../auth/cell_action_specs.js';
|
|
48
|
+
import { JSONRPC_ERROR_CODES } from '../../http/jsonrpc_errors.js';
|
|
45
49
|
import { test_if } from './capabilities.js';
|
|
46
50
|
import { cross_rpc_call, error_reason, expect_output } from './cell_cross_helpers.js';
|
|
47
51
|
import { SPINE_RPC_PATH } from './spine_surface_constants.js';
|
|
@@ -211,4 +215,22 @@ export const describe_cell_moderate_cross_tests = (options) => {
|
|
|
211
215
|
assert.strictEqual(moderated.cell.visibility, 'private', 'rejection leaves the post private');
|
|
212
216
|
});
|
|
213
217
|
});
|
|
218
|
+
describe('cell_clone runs the creation authorizer (parity)', () => {
|
|
219
|
+
test_if(capabilities.cell_gated_create, 'a non-admin clone of a viewable `space` root → 403, admin clone succeeds', async () => {
|
|
220
|
+
const fixture = await setup_test();
|
|
221
|
+
const space = expect_output(await cross_rpc_call(fixture.transport, rpc_path, 'cell_create', { kind: SPACE_CELL_KIND, data: SPACE_POLICY, visibility: 'public' }, fixture.create_session_headers()), CellCreateOutput);
|
|
222
|
+
// Every cell a clone writes is a parentless create of the source's
|
|
223
|
+
// kind, gated like `cell_create` — so a caller denied a `space` root
|
|
224
|
+
// can't clone one they can see into one they own.
|
|
225
|
+
const stranger = await fixture.create_account({ username: 'clone_stranger' });
|
|
226
|
+
const denied = await cross_rpc_call(fixture.transport, rpc_path, 'cell_clone', { source_id: space.cell.id }, stranger.create_session_headers());
|
|
227
|
+
assert.ok(!denied.ok, 'a non-admin must not clone a space root');
|
|
228
|
+
assert.strictEqual(denied.error?.code, JSONRPC_ERROR_CODES.forbidden, 'a 403');
|
|
229
|
+
assert.strictEqual(error_reason(denied), 'cell_create_forbidden');
|
|
230
|
+
const cloned = expect_output(await cross_rpc_call(fixture.transport, rpc_path, 'cell_clone', { source_id: space.cell.id }, fixture.create_session_headers()), CellCloneOutput);
|
|
231
|
+
assert.strictEqual(cloned.cell.kind, SPACE_CELL_KIND, 'the admin clones the space');
|
|
232
|
+
assert.notStrictEqual(cloned.cell.id, space.cell.id);
|
|
233
|
+
assert.strictEqual(cloned.cell.moderation, null, 'a clone stamps no moderation');
|
|
234
|
+
});
|
|
235
|
+
});
|
|
214
236
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"peer_ping_ws.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/peer_ping_ws.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAkD9B,OAAO,EAAE,KAAK,mBAAmB,EAAW,MAAM,mBAAmB,CAAC;AACtE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAuB5C,6DAA6D;AAC7D,MAAM,WAAW,qBAAqB;IACrC,8EAA8E;IAC9E,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC;IAC/B,iFAAiF;IACjF,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAAC;IAC3C,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,+DAA+D;IAC/D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,GAAI,SAAS,qBAAqB,KAAG,
|
|
1
|
+
{"version":3,"file":"peer_ping_ws.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/peer_ping_ws.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAkD9B,OAAO,EAAE,KAAK,mBAAmB,EAAW,MAAM,mBAAmB,CAAC;AACtE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAuB5C,6DAA6D;AAC7D,MAAM,WAAW,qBAAqB;IACrC,8EAA8E;IAC9E,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC;IAC/B,iFAAiF;IACjF,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAAC;IAC3C,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,+DAA+D;IAC/D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,GAAI,SAAS,qBAAqB,KAAG,IA8O5E,CAAC"}
|
|
@@ -136,6 +136,24 @@ export const describe_peer_ping_ws_tests = (options) => {
|
|
|
136
136
|
await ws.close();
|
|
137
137
|
}
|
|
138
138
|
});
|
|
139
|
+
// A newer client may add reply fields: both spines read the reply
|
|
140
|
+
// forward-compatibly (serde's default / `safe_parse_dropping_unknown_keys`)
|
|
141
|
+
// and return only the declared shape.
|
|
142
|
+
test_if(capabilities.peer_request, 'a reply with an undeclared key is accepted and the key is dropped', async () => {
|
|
143
|
+
const fixture = await setup_test();
|
|
144
|
+
const ws = await open_ws(fixture.create_session_headers().cookie, (req) => {
|
|
145
|
+
const nonce = req.params?.nonce ?? 0;
|
|
146
|
+
return { result: { ...valid_reply(nonce), added_later: true } };
|
|
147
|
+
});
|
|
148
|
+
try {
|
|
149
|
+
const frame = await ping_raw(ws, 6, { nonce: 5, timeout_ms: 2000 });
|
|
150
|
+
assert.ok('result' in frame, `expected success, got ${JSON.stringify(frame)}`);
|
|
151
|
+
assert.deepStrictEqual(frame.result, valid_reply(5));
|
|
152
|
+
}
|
|
153
|
+
finally {
|
|
154
|
+
await ws.close();
|
|
155
|
+
}
|
|
156
|
+
});
|
|
139
157
|
test_if(capabilities.peer_request, 'a client JSON-RPC error reply surfaces as the action error (ClientError forwarded)', async () => {
|
|
140
158
|
const fixture = await setup_test();
|
|
141
159
|
const ws = await open_ws(fixture.create_session_headers().cookie, () => ({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"role_grant_participation.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/role_grant_participation.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"role_grant_participation.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/role_grant_participation.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAyC9B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,0EAA0E;AAC1E,MAAM,WAAW,sCAAsC;IACtD,+DAA+D;IAC/D,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC;IAC/B,6CAA6C;IAC7C,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,eAAO,MAAM,6CAA6C,GACzD,SAAS,sCAAsC,KAC7C,IA8IF,CAAC"}
|
|
@@ -15,6 +15,9 @@ import '../assert_dev_env.js';
|
|
|
15
15
|
* re-assigning the active grant is idempotent (same id).
|
|
16
16
|
* - **consent flow** — `role_grant_offer_create` of `participant` (admin-only)
|
|
17
17
|
* → the recipient `role_grant_offer_accept`s → a role_grant lands.
|
|
18
|
+
* - **scoped assign** — `role_grant_assign` of `participant` with a paired
|
|
19
|
+
* `scope_kind` + `scope_id` lands a scoped grant carrying both, read back
|
|
20
|
+
* through `admin_account_list`, distinct from the global grant.
|
|
18
21
|
*
|
|
19
22
|
* The single-request gate/denial matrix (grantability refusal, admin-only
|
|
20
23
|
* conferral, dispatcher admin gate, auth) lives in the declarative table
|
|
@@ -55,6 +58,37 @@ export const describe_role_grant_participation_cross_tests = (options) => {
|
|
|
55
58
|
assert.ok(second.ok, `re-assign must succeed: ${JSON.stringify(second)}`);
|
|
56
59
|
assert.strictEqual(second.result.role_grant_id, assigned.role_grant_id, 're-assigning an active grant returns the existing role_grant id');
|
|
57
60
|
});
|
|
61
|
+
test('admin assigns a scoped participant grant that round-trips scope_kind', async () => {
|
|
62
|
+
const fixture = await setup_test();
|
|
63
|
+
const recipient = await fixture.create_account({ username: 'participation_scoped' });
|
|
64
|
+
const scope_id = '33333333-3333-4333-8333-333333333333';
|
|
65
|
+
const scoped = await rpc(fixture.transport, 'role_grant_assign', {
|
|
66
|
+
to_account_id: recipient.account.id,
|
|
67
|
+
role: SPINE_PARTICIPANT_ROLE,
|
|
68
|
+
scope_kind: 'space',
|
|
69
|
+
scope_id
|
|
70
|
+
}, fixture.create_session_headers());
|
|
71
|
+
assert.ok(scoped.ok, `scoped assign must succeed: ${JSON.stringify(scoped)}`);
|
|
72
|
+
const scoped_id = scoped.result.role_grant_id;
|
|
73
|
+
const global = await rpc(fixture.transport, 'role_grant_assign', { to_account_id: recipient.account.id, role: SPINE_PARTICIPANT_ROLE }, fixture.create_session_headers());
|
|
74
|
+
assert.ok(global.ok, `global assign must succeed: ${JSON.stringify(global)}`);
|
|
75
|
+
const global_id = global.result.role_grant_id;
|
|
76
|
+
assert.notStrictEqual(global_id, scoped_id, 'the global grant is a distinct row');
|
|
77
|
+
const listed = await rpc(fixture.transport, 'admin_account_list', {}, fixture.create_session_headers());
|
|
78
|
+
assert.ok(listed.ok, `admin_account_list must succeed: ${JSON.stringify(listed)}`);
|
|
79
|
+
const entry = listed.result.accounts.find((a) => a.account.id === recipient.account.id);
|
|
80
|
+
assert.ok(entry, 'the recipient is listed');
|
|
81
|
+
const by_id = new Map(entry.role_grants.map((g) => [g.id, g]));
|
|
82
|
+
const scoped_row = by_id.get(scoped_id);
|
|
83
|
+
assert.ok(scoped_row, 'the scoped grant is listed');
|
|
84
|
+
assert.strictEqual(scoped_row.role, SPINE_PARTICIPANT_ROLE);
|
|
85
|
+
assert.strictEqual(scoped_row.scope_kind, 'space', 'scope_kind round-trips');
|
|
86
|
+
assert.strictEqual(scoped_row.scope_id, scope_id, 'scope_id round-trips');
|
|
87
|
+
const global_row = by_id.get(global_id);
|
|
88
|
+
assert.ok(global_row, 'the global grant is listed');
|
|
89
|
+
assert.strictEqual(global_row.scope_kind, null);
|
|
90
|
+
assert.strictEqual(global_row.scope_id, null);
|
|
91
|
+
});
|
|
58
92
|
test('admin offers the participant app-role and the recipient accepts', async () => {
|
|
59
93
|
const fixture = await setup_test();
|
|
60
94
|
const recipient = await fixture.create_account({ username: 'participation_offeree' });
|
|
@@ -2,6 +2,14 @@ import '../assert_dev_env.js';
|
|
|
2
2
|
import type { BackendConfig } from './backend_config.js';
|
|
3
3
|
/** Env var naming the prebuilt `testing_spine_stub` binary. Required when `binary_path` is omitted. */
|
|
4
4
|
export declare const RUST_SPINE_STUB_BIN_ENV = "FUZ_TESTING_RUST_SPINE_STUB_BIN";
|
|
5
|
+
/**
|
|
6
|
+
* Env var overriding the stub's Postgres URL when `database_url` is omitted —
|
|
7
|
+
* e.g. a scratch cluster on a spare port, keeping the run off the machine's
|
|
8
|
+
* default server. Pair it with the libpq `PGHOST` / `PGPORT` the runner's
|
|
9
|
+
* idempotent `createdb` reads, so the database it ensures is the one the URL
|
|
10
|
+
* names.
|
|
11
|
+
*/
|
|
12
|
+
export declare const RUST_SPINE_STUB_DATABASE_URL_ENV = "FUZ_TESTING_RUST_SPINE_STUB_DATABASE_URL";
|
|
5
13
|
/**
|
|
6
14
|
* Env var the stub reads for the absolute path of the committed
|
|
7
15
|
* `expected_schema.json` its `/ready` gate introspects against. Pointed at the
|
|
@@ -16,7 +24,10 @@ export declare const RUST_SPINE_STUB_DEFAULT_DATABASE_URL = "postgres://localhos
|
|
|
16
24
|
export interface SpineStubBackendConfigOptions {
|
|
17
25
|
/** Listening port. Default `RUST_SPINE_STUB_DEFAULT_PORT`. */
|
|
18
26
|
readonly port?: number;
|
|
19
|
-
/**
|
|
27
|
+
/**
|
|
28
|
+
* Postgres connection URL. Default `$FUZ_TESTING_RUST_SPINE_STUB_DATABASE_URL`,
|
|
29
|
+
* then `RUST_SPINE_STUB_DEFAULT_DATABASE_URL`.
|
|
30
|
+
*/
|
|
20
31
|
readonly database_url?: string;
|
|
21
32
|
/**
|
|
22
33
|
* Prebuilt binary path. Overrides the `FUZ_TESTING_RUST_SPINE_STUB_BIN` env
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rust_spine_stub_backend_config.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/rust_spine_stub_backend_config.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"rust_spine_stub_backend_config.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/rust_spine_stub_backend_config.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA0C9B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AASzD,uGAAuG;AACvG,eAAO,MAAM,uBAAuB,oCAAoC,CAAC;AAEzE;;;;;;GAMG;AACH,eAAO,MAAM,gCAAgC,6CAA6C,CAAC;AAE3F;;;;;GAKG;AACH,eAAO,MAAM,wCAAwC,6CAA6C,CAAC;AAkBnG,kGAAkG;AAClG,eAAO,MAAM,4BAA4B,OAAO,CAAC;AAEjD,0FAA0F;AAC1F,eAAO,MAAM,oCAAoC,sDACG,CAAC;AAErD,MAAM,WAAW,6BAA6B;IAC7C,8DAA8D;IAC9D,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B;;;OAGG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;;;;OAOG;IACH,QAAQ,CAAC,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAC3C;;;;;;OAMG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;CAClC;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,8BAA8B,GAC1C,UAAS,6BAAkC,KACzC,aAkDF,CAAC"}
|
|
@@ -25,6 +25,9 @@ import '../assert_dev_env.js';
|
|
|
25
25
|
* createdb fuz_app_test_rust_spine_stub 2>/dev/null || true
|
|
26
26
|
* ```
|
|
27
27
|
*
|
|
28
|
+
* `FUZ_TESTING_RUST_SPINE_STUB_DATABASE_URL` points the stub at another
|
|
29
|
+
* server (e.g. a scratch cluster on a spare port).
|
|
30
|
+
*
|
|
28
31
|
* The binary self-wipes the auth-namespace schema on every boot
|
|
29
32
|
* (`FUZ_TESTING_RESET_DB_ON_STARTUP=true`, set by the Rust-family builder),
|
|
30
33
|
* so no manual `DROP TABLE` between sessions is needed; per-test reset is
|
|
@@ -39,6 +42,14 @@ import { SPINE_EXPECTED_SCHEMA_URL } from './spine_surface_constants.js';
|
|
|
39
42
|
import { LOGIN_RATE_LIMIT_ENABLED_ENV, make_default_rust_backend_config, rust_default_capabilities } from './default_backend_configs.js';
|
|
40
43
|
/** Env var naming the prebuilt `testing_spine_stub` binary. Required when `binary_path` is omitted. */
|
|
41
44
|
export const RUST_SPINE_STUB_BIN_ENV = 'FUZ_TESTING_RUST_SPINE_STUB_BIN';
|
|
45
|
+
/**
|
|
46
|
+
* Env var overriding the stub's Postgres URL when `database_url` is omitted —
|
|
47
|
+
* e.g. a scratch cluster on a spare port, keeping the run off the machine's
|
|
48
|
+
* default server. Pair it with the libpq `PGHOST` / `PGPORT` the runner's
|
|
49
|
+
* idempotent `createdb` reads, so the database it ensures is the one the URL
|
|
50
|
+
* names.
|
|
51
|
+
*/
|
|
52
|
+
export const RUST_SPINE_STUB_DATABASE_URL_ENV = 'FUZ_TESTING_RUST_SPINE_STUB_DATABASE_URL';
|
|
42
53
|
/**
|
|
43
54
|
* Env var the stub reads for the absolute path of the committed
|
|
44
55
|
* `expected_schema.json` its `/ready` gate introspects against. Pointed at the
|
|
@@ -77,7 +88,8 @@ export const RUST_SPINE_STUB_DEFAULT_DATABASE_URL = 'postgres://localhost/fuz_ap
|
|
|
77
88
|
* @throws Error when no binary path is available.
|
|
78
89
|
*/
|
|
79
90
|
export const rust_spine_stub_backend_config = (options = {}) => {
|
|
80
|
-
const { port = RUST_SPINE_STUB_DEFAULT_PORT, database_url =
|
|
91
|
+
const { port = RUST_SPINE_STUB_DEFAULT_PORT, database_url = process.env[RUST_SPINE_STUB_DATABASE_URL_ENV] ||
|
|
92
|
+
RUST_SPINE_STUB_DEFAULT_DATABASE_URL, binary_path = process.env[RUST_SPINE_STUB_BIN_ENV], enable_login_rate_limit, trusted_proxies } = options;
|
|
81
93
|
if (!binary_path) {
|
|
82
94
|
throw new Error(`rust_spine_stub_backend_config: no binary path — set ${RUST_SPINE_STUB_BIN_ENV} to a prebuilt ` +
|
|
83
95
|
'`testing_spine_stub` binary (build it with `cargo build -p testing_spine_stub --release`) ' +
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test_cell_gated_create_authorize.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/test_cell_gated_create_authorize.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA+B9B,OAAO,KAAK,EACX,mBAAmB,EAGnB,MAAM,4BAA4B,CAAC;AAGpC,8EAA8E;AAC9E,eAAO,MAAM,eAAe,UAAU,CAAC;AAEvC;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,gBAAyB,CAAC;AAEzD,yFAAyF;AACzF,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAYD;;;;GAIG;AACH,eAAO,MAAM,gCAAgC,EAAE,
|
|
1
|
+
{"version":3,"file":"test_cell_gated_create_authorize.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/test_cell_gated_create_authorize.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA+B9B,OAAO,KAAK,EACX,mBAAmB,EAGnB,MAAM,4BAA4B,CAAC;AAGpC,8EAA8E;AAC9E,eAAO,MAAM,eAAe,UAAU,CAAC;AAEvC;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,gBAAyB,CAAC;AAEzD,yFAAyF;AACzF,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAYD;;;;GAIG;AACH,eAAO,MAAM,gCAAgC,EAAE,mBAsB9C,CAAC"}
|
|
@@ -6,15 +6,15 @@ import '../assert_dev_env.js';
|
|
|
6
6
|
* the parent-aware cell-creation authorizer agrees TS↔Rust. The twin of the
|
|
7
7
|
* Rust `TestCellGatedCreateAuthorize`, **directory model**.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
* a
|
|
9
|
+
* A **global** admin bypasses everything (`{allow: true, moderation_required:
|
|
10
|
+
* false}`) — a scoped `admin` row is no admin here. For anyone else:
|
|
11
11
|
*
|
|
12
12
|
* - **Root creation** (`root_id` null): `kind: 'space'` is admin-only (denied);
|
|
13
13
|
* every other parentless kind stays open, so the plain-create `cell_crud` /
|
|
14
14
|
* `cell_relations` suites are unaffected.
|
|
15
15
|
* - **Contribution** (`root_id` set): the governing root's
|
|
16
16
|
* `data.policy[kind] = {min_role?, moderation_required?}` decides — a missing
|
|
17
|
-
* entry denies, a present `min_role` the actor lacks denies, and otherwise it
|
|
17
|
+
* entry denies, a present `min_role` the actor lacks globally denies, and otherwise it
|
|
18
18
|
* admits with the entry's `moderation_required` folded into the verdict. The
|
|
19
19
|
* root's `data` arrives in `input.root_data` (the handler read it in-tx), so
|
|
20
20
|
* the predicate is **pure** — no DB read of its own (which also dodges the
|
|
@@ -25,7 +25,7 @@ import '../assert_dev_env.js';
|
|
|
25
25
|
*
|
|
26
26
|
* @module
|
|
27
27
|
*/
|
|
28
|
-
import {
|
|
28
|
+
import { has_scoped_role } from '../../auth/request_context.js';
|
|
29
29
|
import { ROLE_ADMIN } from '../../auth/role_schema.js';
|
|
30
30
|
import { SPINE_PARTICIPANT_ROLE } from './spine_surface_constants.js';
|
|
31
31
|
/** The admin-only root kind the test policy gates (talk's `space` analog). */
|
|
@@ -54,8 +54,9 @@ const get_contribution_rule = (data, kind) => {
|
|
|
54
54
|
* handler). Byte-equivalent with the Rust `TestCellGatedCreateAuthorize`.
|
|
55
55
|
*/
|
|
56
56
|
export const test_cell_gated_create_authorize = (auth, input) => {
|
|
57
|
-
// Admin bypass — admins create roots + any kind, live immediately.
|
|
58
|
-
|
|
57
|
+
// Admin bypass — admins create roots + any kind, live immediately. The
|
|
58
|
+
// global grant only: a scoped `admin` row bypasses nothing.
|
|
59
|
+
if (has_scoped_role(auth, ROLE_ADMIN, null))
|
|
59
60
|
return { allow: true, moderation_required: false };
|
|
60
61
|
// Root creation (no governing root): `space` is admin-only; other parentless
|
|
61
62
|
// kinds stay open (the plain-create suites).
|
|
@@ -68,7 +69,8 @@ export const test_cell_gated_create_authorize = (auth, input) => {
|
|
|
68
69
|
const rule = get_contribution_rule(input.root_data, input.kind ?? '');
|
|
69
70
|
if (!rule)
|
|
70
71
|
return { allow: false };
|
|
71
|
-
|
|
72
|
+
// `min_role` names no scope, so only the global grant satisfies it.
|
|
73
|
+
const admitted = rule.min_role === undefined || has_scoped_role(auth, rule.min_role, null);
|
|
72
74
|
return admitted
|
|
73
75
|
? { allow: true, moderation_required: rule.moderation_required ?? false }
|
|
74
76
|
: { allow: false };
|
|
@@ -24,11 +24,19 @@ export interface CrossProcessWsTestOptions {
|
|
|
24
24
|
* actions being mounted on the RPC endpoint.
|
|
25
25
|
*/
|
|
26
26
|
readonly rpc_path?: string;
|
|
27
|
+
/**
|
|
28
|
+
* The backend's inbound WebSocket message cap, in bytes — the
|
|
29
|
+
* oversized-message case sends a message just past it. Defaults to
|
|
30
|
+
* `DEFAULT_WS_MAX_MESSAGE_BYTES`; pass the consumer's value when it raises
|
|
31
|
+
* the server cap.
|
|
32
|
+
*/
|
|
33
|
+
readonly max_message_bytes?: number;
|
|
27
34
|
}
|
|
28
35
|
/**
|
|
29
|
-
* Register the cross-process WS round-trip suite
|
|
30
|
-
*
|
|
31
|
-
*
|
|
36
|
+
* Register the cross-process WS round-trip suite over a real upgrade: authed
|
|
37
|
+
* `heartbeat` round-trip, `heartbeat`'s parameterless-shape contract, an
|
|
38
|
+
* oversized message closing with `WS_CLOSE_MESSAGE_TOO_BIG`, anonymous-upgrade
|
|
39
|
+
* refusal, disallowed-origin refusal, and — when `rpc_path` is supplied —
|
|
32
40
|
* session-revocation closing the live socket.
|
|
33
41
|
*/
|
|
34
42
|
export declare const describe_cross_process_ws_tests: (options: CrossProcessWsTestOptions) => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ws_round_trip.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/ws_round_trip.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"ws_round_trip.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/ws_round_trip.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAoE9B,OAAO,EAAE,KAAK,mBAAmB,EAAW,MAAM,mBAAmB,CAAC;AACtE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAK5C,iEAAiE;AACjE,MAAM,WAAW,yBAAyB;IACzC;;;;OAIG;IACH,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC;IAC/B,uEAAuE;IACvE,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAAC;IAC3C,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,+DAA+D;IAC/D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,oEAAoE;IACpE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;;OAKG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CACpC;AAED;;;;;;GAMG;AACH,eAAO,MAAM,+BAA+B,GAAI,SAAS,yBAAyB,KAAG,IAwIpF,CAAC"}
|
|
@@ -24,7 +24,13 @@ import '../assert_dev_env.js';
|
|
|
24
24
|
* upgrade time (not per message), so the negative cases assert the upgrade
|
|
25
25
|
* itself rejects rather than a per-message error frame.
|
|
26
26
|
*
|
|
27
|
-
*
|
|
27
|
+
* Two spine-parity cases follow: `heartbeat` answers the parameterless shapes
|
|
28
|
+
* (absent, `{}`) and refuses a declared param with `invalid_params`, and a
|
|
29
|
+
* message over the backend's cap (`max_message_bytes`, default
|
|
30
|
+
* `DEFAULT_WS_MAX_MESSAGE_BYTES`) closes the socket with
|
|
31
|
+
* `WS_CLOSE_MESSAGE_TOO_BIG`.
|
|
32
|
+
*
|
|
33
|
+
* A final case (gated on `rpc_path`) covers server-initiated close: an
|
|
28
34
|
* authenticated socket is dropped when the account's sessions are revoked
|
|
29
35
|
* mid-connection. Per-message dispatch never re-checks credential validity,
|
|
30
36
|
* so the live socket survives on the audit-fed `create_ws_auth_guard` seam —
|
|
@@ -43,29 +49,31 @@ import '../assert_dev_env.js';
|
|
|
43
49
|
import { assert, describe } from 'vitest';
|
|
44
50
|
import { assert_rejects } from '@fuzdev/fuz_util/testing.ts';
|
|
45
51
|
import { heartbeat_action_spec } from '../../actions/heartbeat.js';
|
|
52
|
+
import { DEFAULT_WS_MAX_MESSAGE_BYTES, WS_CLOSE_MESSAGE_TOO_BIG } from '../../actions/transports.js';
|
|
46
53
|
import { account_session_revoke_all_action_spec } from '../../auth/account_action_specs.js';
|
|
54
|
+
import { JSONRPC_ERROR_CODES } from '../../http/jsonrpc_errors.js';
|
|
55
|
+
import { is_response_for } from '../transports/ws_client.js';
|
|
47
56
|
import { create_ws_transport } from '../transports/ws_transport.js';
|
|
48
57
|
import { create_rpc_post_init } from '../rpc_helpers.js';
|
|
49
58
|
import { test_if } from './capabilities.js';
|
|
50
59
|
/** Origin guaranteed to fail the `http://localhost:*` allowlist the test backends run with. */
|
|
51
60
|
const DISALLOWED_ORIGIN = 'http://disallowed.example';
|
|
52
61
|
/**
|
|
53
|
-
* Register the cross-process WS round-trip suite
|
|
54
|
-
*
|
|
55
|
-
*
|
|
62
|
+
* Register the cross-process WS round-trip suite over a real upgrade: authed
|
|
63
|
+
* `heartbeat` round-trip, `heartbeat`'s parameterless-shape contract, an
|
|
64
|
+
* oversized message closing with `WS_CLOSE_MESSAGE_TOO_BIG`, anonymous-upgrade
|
|
65
|
+
* refusal, disallowed-origin refusal, and — when `rpc_path` is supplied —
|
|
56
66
|
* session-revocation closing the live socket.
|
|
57
67
|
*/
|
|
58
68
|
export const describe_cross_process_ws_tests = (options) => {
|
|
59
|
-
const { setup_test, capabilities, base_url, ws_path, origin, rpc_path } = options;
|
|
69
|
+
const { setup_test, capabilities, base_url, ws_path, origin, rpc_path, max_message_bytes = DEFAULT_WS_MAX_MESSAGE_BYTES } = options;
|
|
70
|
+
const open_authed = async () => {
|
|
71
|
+
const fixture = await setup_test();
|
|
72
|
+
return create_ws_transport({ base_url, ws_path, cookies: fixture.transport.cookies(), origin });
|
|
73
|
+
};
|
|
60
74
|
describe('cross-process websocket', () => {
|
|
61
75
|
test_if(capabilities.ws, 'authenticated upgrade round-trips heartbeat', async () => {
|
|
62
|
-
const
|
|
63
|
-
const client = await create_ws_transport({
|
|
64
|
-
base_url,
|
|
65
|
-
ws_path,
|
|
66
|
-
cookies: fixture.transport.cookies(),
|
|
67
|
-
origin
|
|
68
|
-
});
|
|
76
|
+
const client = await open_authed();
|
|
69
77
|
try {
|
|
70
78
|
const result = await client.request(1, heartbeat_action_spec.method, {});
|
|
71
79
|
assert.deepStrictEqual(result, {}, 'heartbeat returns an empty result over the wire');
|
|
@@ -74,6 +82,60 @@ export const describe_cross_process_ws_tests = (options) => {
|
|
|
74
82
|
await client.close();
|
|
75
83
|
}
|
|
76
84
|
});
|
|
85
|
+
// `heartbeat` is parameterless on both spines (`z.void()` /
|
|
86
|
+
// `require_void_params`): the empty shapes are the no-arg call, and a
|
|
87
|
+
// declared param is `invalid_params`, not ignored.
|
|
88
|
+
test_if(capabilities.ws, 'heartbeat admits only the parameterless shapes', async () => {
|
|
89
|
+
const client = await open_authed();
|
|
90
|
+
try {
|
|
91
|
+
const cases = [
|
|
92
|
+
[1, {}, true],
|
|
93
|
+
[2, { params: {} }, true],
|
|
94
|
+
[3, { params: { stray: 1 } }, false]
|
|
95
|
+
];
|
|
96
|
+
for (const [id, params, ok] of cases) {
|
|
97
|
+
await client.send({
|
|
98
|
+
jsonrpc: '2.0',
|
|
99
|
+
id,
|
|
100
|
+
method: heartbeat_action_spec.method,
|
|
101
|
+
...params
|
|
102
|
+
});
|
|
103
|
+
const frame = await client.wait_for(is_response_for(id));
|
|
104
|
+
const label = JSON.stringify(params);
|
|
105
|
+
if (ok) {
|
|
106
|
+
assert.ok('result' in frame, `${label}: ${JSON.stringify(frame)}`);
|
|
107
|
+
assert.deepStrictEqual(frame.result, {}, label);
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
assert.ok('error' in frame, `${label}: ${JSON.stringify(frame)}`);
|
|
111
|
+
assert.strictEqual(frame.error.code, JSONRPC_ERROR_CODES.invalid_params, label);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
finally {
|
|
116
|
+
await client.close();
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
// Both spines cap an inbound message (`DEFAULT_WS_MAX_MESSAGE_BYTES` by
|
|
120
|
+
// default) and close the socket on a larger one rather than replying.
|
|
121
|
+
test_if(capabilities.ws, 'an oversized message closes the socket with WS_CLOSE_MESSAGE_TOO_BIG', async () => {
|
|
122
|
+
const client = await open_authed();
|
|
123
|
+
try {
|
|
124
|
+
await client.send({
|
|
125
|
+
jsonrpc: '2.0',
|
|
126
|
+
id: 1,
|
|
127
|
+
method: heartbeat_action_spec.method,
|
|
128
|
+
params: { pad: 'x'.repeat(max_message_bytes) }
|
|
129
|
+
});
|
|
130
|
+
const closed = await client.wait_for_close(5000);
|
|
131
|
+
assert.ok(closed, 'socket did not close within 5s of an oversized message');
|
|
132
|
+
assert.strictEqual(client.close_code, WS_CLOSE_MESSAGE_TOO_BIG);
|
|
133
|
+
}
|
|
134
|
+
finally {
|
|
135
|
+
// the server may reset the connection under the unread tail
|
|
136
|
+
await client.close().catch(() => { });
|
|
137
|
+
}
|
|
138
|
+
});
|
|
77
139
|
// Per-connection auth fires at upgrade time (`require_auth`), so an
|
|
78
140
|
// anonymous socket never opens — the upgrade is refused outright.
|
|
79
141
|
test_if(capabilities.ws, 'anonymous upgrade is refused', async () => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import './assert_dev_env.js';
|
|
2
2
|
import type { Account, Actor, RoleGrant } from '../auth/account_schema.js';
|
|
3
3
|
import type { AuditLogEvent } from '../auth/audit_log_schema.js';
|
|
4
|
-
import type {
|
|
4
|
+
import type { RequestActorContext } from '../auth/request_context.js';
|
|
5
5
|
/** Override type for `create_test_account` — id-like fields accept plain `string`. */
|
|
6
6
|
export type TestAccountOverrides = Partial<Omit<Account, 'id' | 'created_by' | 'updated_by'>> & {
|
|
7
7
|
id?: string;
|
|
@@ -30,8 +30,11 @@ export type TestRoleGrantOverrides = Partial<Omit<RoleGrant, 'id' | 'actor_id' |
|
|
|
30
30
|
};
|
|
31
31
|
/** Create a test `RoleGrant` with sensible defaults. */
|
|
32
32
|
export declare const create_test_role_grant: (overrides?: TestRoleGrantOverrides) => RoleGrant;
|
|
33
|
-
/**
|
|
34
|
-
|
|
33
|
+
/**
|
|
34
|
+
* Create a test `RequestActorContext` (a `RequestContext` with a resolved
|
|
35
|
+
* actor) with role_grants from partial overrides.
|
|
36
|
+
*/
|
|
37
|
+
export declare const create_test_context: (role_grants?: Array<TestRoleGrantOverrides>) => RequestActorContext;
|
|
35
38
|
/** Override type for `create_test_audit_event` — id-like fields accept plain `string`. */
|
|
36
39
|
export type TestAuditEventOverrides = Partial<Omit<AuditLogEvent, 'id' | 'actor_id' | 'account_id' | 'target_account_id' | 'target_actor_id'>> & {
|
|
37
40
|
id?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entities.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/entities.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAiB7B,OAAO,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC3E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"entities.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/entities.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAiB7B,OAAO,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC3E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAEtE,sFAAsF;AACtF,MAAM,MAAM,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,GAAG,YAAY,GAAG,YAAY,CAAC,CAAC,GAAG;IAC/F,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,CAAC;AAEF,sDAAsD;AACtD,eAAO,MAAM,mBAAmB,GAAI,YAAY,oBAAoB,KAAG,OAarE,CAAC;AAEH,oFAAoF;AACpF,MAAM,MAAM,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,GAAG,YAAY,GAAG,YAAY,CAAC,CAAC,GAAG;IAC3F,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,CAAC;AAEF,oDAAoD;AACpD,eAAO,MAAM,iBAAiB,GAAI,YAAY,kBAAkB,KAAG,KAUjE,CAAC;AAEH,yFAAyF;AACzF,MAAM,MAAM,sBAAsB,GAAG,OAAO,CAC3C,IAAI,CACH,SAAS,EACT,IAAI,GAAG,UAAU,GAAG,YAAY,GAAG,UAAU,GAAG,YAAY,GAAG,YAAY,GAAG,iBAAiB,CAC/F,CACD,GAAG;IACH,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC,CAAC;AAEF,wDAAwD;AACxD,eAAO,MAAM,sBAAsB,GAAI,YAAY,sBAAsB,KAAG,SAgB3E,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,mBAAmB,GAC/B,cAAa,KAAK,CAAC,sBAAsB,CAAQ,KAC/C,mBAID,CAAC;AAEH,0FAA0F;AAC1F,MAAM,MAAM,uBAAuB,GAAG,OAAO,CAC5C,IAAI,CAAC,aAAa,EAAE,IAAI,GAAG,UAAU,GAAG,YAAY,GAAG,mBAAmB,GAAG,iBAAiB,CAAC,CAC/F,GAAG;IACH,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC,CAAC;AAEF,4DAA4D;AAC5D,eAAO,MAAM,uBAAuB,GAAI,YAAY,uBAAuB,KAAG,aAa5E,CAAC"}
|
package/dist/testing/entities.js
CHANGED
|
@@ -44,7 +44,10 @@ export const create_test_role_grant = (overrides) => {
|
|
|
44
44
|
};
|
|
45
45
|
return overrides ? { ...base, ...overrides } : base;
|
|
46
46
|
};
|
|
47
|
-
/**
|
|
47
|
+
/**
|
|
48
|
+
* Create a test `RequestActorContext` (a `RequestContext` with a resolved
|
|
49
|
+
* actor) with role_grants from partial overrides.
|
|
50
|
+
*/
|
|
48
51
|
export const create_test_context = (role_grants = [{}]) => ({
|
|
49
52
|
account: create_test_account(),
|
|
50
53
|
actor: create_test_actor(),
|
|
@@ -124,6 +124,12 @@ export interface WsClient {
|
|
|
124
124
|
* in `testing/sse_round_trip.ts`.
|
|
125
125
|
*/
|
|
126
126
|
wait_for_close: (timeout_ms?: number) => Promise<boolean>;
|
|
127
|
+
/**
|
|
128
|
+
* The close code of the connection once it has closed — the server's
|
|
129
|
+
* (e.g. `WS_CLOSE_MESSAGE_TOO_BIG`), the test's own, or `1006` when the
|
|
130
|
+
* connection dropped without a close frame. `null` while open.
|
|
131
|
+
*/
|
|
132
|
+
readonly close_code: number | null;
|
|
127
133
|
/** Every message the server has sent, in arrival order. */
|
|
128
134
|
readonly messages: ReadonlyArray<unknown>;
|
|
129
135
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ws_client.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/transports/ws_client.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA8B9B,OAAO,EAAE,eAAe,EAAE,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAa7E,MAAM,WAAW,wBAAwB,CAAC,CAAC,GAAG,OAAO;IACpD,OAAO,EAAE,OAAO,eAAe,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,CAAC,CAAC;CACV;AAED,MAAM,WAAW,2BAA2B,CAAC,CAAC,GAAG,OAAO;IACvD,OAAO,EAAE,OAAO,eAAe,CAAC;IAChC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,MAAM,EAAE,CAAC,CAAC;CACV;AAED,MAAM,WAAW,yBAAyB,CAAC,CAAC,GAAG,OAAO;IACrD,OAAO,EAAE,OAAO,eAAe,CAAC;IAChC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,CAAC,CAAA;KAAE,CAAC;CACnD;AAQD,6EAA6E;AAC7E,eAAO,MAAM,eAAe,GAC1B,QAAQ,MAAM,MACd,KAAK,OAAO,KAAG,OACsC,CAAC;AAExD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,oBAAoB,GAC/B,CAAC,EAAE,QAAQ,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,KAAK,OAAO,MAChD,KAAK,OAAO,KAAG,GAAG,IAAI,wBAAwB,CAAC,CAAC,CAGE,CAAC;AAErD,gGAAgG;AAChG,eAAO,MAAM,eAAe,GAC1B,IAAI,MAAM,GAAG,MAAM,MACnB,KAAK,OAAO,KAAG,OAC8D,CAAC;AAQhF,6DAA6D;AAC7D,MAAM,WAAW,QAAQ;IACxB,SAAS,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC;IACrC,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;CAChC;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,kBAAkB,GAC7B;IAAE,MAAM,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,yBAAyB,CAAC,OAAO,CAAC,CAAA;CAAE,GAAG,SAAS,CAAC;AAEjF;;;;;;GAMG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAChC,OAAO,EAAE,cAAc,KACnB,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;AAEtD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,eAAe,GAC3B,QAAQ,OAAO,EACf,UAAU,KAAK,CAAC,OAAO,CAAC,EACxB,SAAS,KAAK,CAAC,QAAQ,CAAC,EACxB,YAAY,kBAAkB,GAAG,SAAS,EAC1C,OAAO,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,KAC/B,IAaF,CAAC;AA8BF;;;GAGG;AACH,eAAO,MAAM,4BAA4B,OAAO,CAAC;AAEjD,0EAA0E;AAC1E,MAAM,WAAW,QAAQ;IACxB;;;;;;OAMG;IACH,IAAI,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C;;;;;;;;;;;OAWG;IACH,OAAO,EAAE,CAAC,CAAC,GAAG,OAAO,EACpB,EAAE,EAAE,MAAM,GAAG,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,OAAO,EACf,UAAU,CAAC,EAAE,MAAM,KACf,OAAO,CAAC,CAAC,CAAC,CAAC;IAChB;;;;;OAKG;IACH,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD;;;;;;;;;;OAUG;IACH,cAAc,EAAE,CAAC,UAAU,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1D,2DAA2D;IAC3D,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;IAC1C;;;;;;;;;;;;OAYG;IACH,QAAQ,EAAE;QACT,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,GAAG,IAAI,CAAC,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QAE5E,CAAC,CAAC,GAAG,OAAO,EAAE,SAAS,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;KACrF,CAAC;CACF"}
|
|
1
|
+
{"version":3,"file":"ws_client.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/transports/ws_client.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ws_transport.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/transports/ws_transport.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAuB9B,OAAO,EAMN,KAAK,QAAQ,EACb,KAAK,kBAAkB,EAEvB,MAAM,gBAAgB,CAAC;AAGxB,sDAAsD;AACtD,MAAM,WAAW,kBAAkB;IAClC,gHAAgH;IAChH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,8DAA8D;IAC9D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACxC;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC;;;;;;;OAOG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,kBAAkB,CAAC;CACzC;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,mBAAmB,GAAU,SAAS,kBAAkB,KAAG,OAAO,CAAC,QAAQ,
|
|
1
|
+
{"version":3,"file":"ws_transport.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/transports/ws_transport.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAuB9B,OAAO,EAMN,KAAK,QAAQ,EACb,KAAK,kBAAkB,EAEvB,MAAM,gBAAgB,CAAC;AAGxB,sDAAsD;AACtD,MAAM,WAAW,kBAAkB;IAClC,gHAAgH;IAChH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,8DAA8D;IAC9D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACxC;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC;;;;;;;OAOG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,kBAAkB,CAAC;CACzC;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,mBAAmB,GAAU,SAAS,kBAAkB,KAAG,OAAO,CAAC,QAAQ,CAmJvF,CAAC"}
|