@fuzdev/fuz_app 0.148.0 → 0.149.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 +2 -2
- package/dist/actions/action_event.d.ts.map +1 -1
- package/dist/actions/action_event.js +14 -1
- package/dist/actions/perform_action.d.ts +17 -1
- package/dist/actions/perform_action.d.ts.map +1 -1
- package/dist/actions/perform_action.js +22 -2
- package/dist/auth/CLAUDE.md +3 -2
- package/dist/auth/account_action_specs.d.ts +12 -0
- package/dist/auth/account_action_specs.d.ts.map +1 -1
- package/dist/auth/account_action_specs.js +16 -2
- package/dist/auth/account_actions.d.ts.map +1 -1
- package/dist/auth/account_actions.js +7 -4
- package/dist/auth/admin_action_specs.d.ts.map +1 -1
- package/dist/auth/admin_action_specs.js +29 -8
- package/dist/auth/audit_emitter.d.ts +14 -0
- package/dist/auth/audit_emitter.d.ts.map +1 -1
- package/dist/auth/audit_emitter.js +5 -1
- package/dist/auth/role_grant_offer_action_specs.d.ts.map +1 -1
- package/dist/auth/role_grant_offer_action_specs.js +5 -3
- package/dist/http/CLAUDE.md +14 -2
- package/dist/http/error_schemas.d.ts +8 -0
- package/dist/http/error_schemas.d.ts.map +1 -1
- package/dist/http/error_schemas.js +12 -0
- package/dist/http/jsonrpc_errors.d.ts +40 -15
- package/dist/http/jsonrpc_errors.d.ts.map +1 -1
- package/dist/http/jsonrpc_errors.js +90 -35
- package/dist/schema_meta.d.ts +60 -0
- package/dist/schema_meta.d.ts.map +1 -1
- package/dist/schema_meta.js +64 -0
- package/dist/testing/CLAUDE.md +162 -61
- package/dist/testing/adversarial_input_cases.d.ts +67 -7
- package/dist/testing/adversarial_input_cases.d.ts.map +1 -1
- package/dist/testing/adversarial_input_cases.js +210 -165
- package/dist/testing/audit_drift_guard.d.ts +3 -2
- package/dist/testing/audit_drift_guard.d.ts.map +1 -1
- package/dist/testing/audit_drift_guard.js +5 -3
- package/dist/testing/cross_backend/audit_cross_helpers.d.ts +6 -0
- package/dist/testing/cross_backend/audit_cross_helpers.d.ts.map +1 -1
- package/dist/testing/cross_backend/audit_cross_helpers.js +11 -0
- package/dist/testing/cross_backend/capabilities.d.ts +27 -4
- package/dist/testing/cross_backend/capabilities.d.ts.map +1 -1
- package/dist/testing/cross_backend/capabilities.js +10 -6
- package/dist/testing/cross_backend/cell_crud.d.ts.map +1 -1
- package/dist/testing/cross_backend/cell_crud.js +117 -2
- package/dist/testing/cross_backend/cross_rpc.d.ts +3 -1
- package/dist/testing/cross_backend/cross_rpc.d.ts.map +1 -1
- package/dist/testing/cross_backend/cross_rpc.js +2 -2
- package/dist/testing/cross_backend/default_backend_configs.d.ts +9 -7
- package/dist/testing/cross_backend/default_backend_configs.d.ts.map +1 -1
- package/dist/testing/cross_backend/default_backend_configs.js +3 -3
- package/dist/testing/cross_backend/rpc_adversarial.d.ts +9 -0
- package/dist/testing/cross_backend/rpc_adversarial.d.ts.map +1 -1
- package/dist/testing/cross_backend/rpc_adversarial.js +16 -6
- package/dist/testing/cross_backend/rust_spine_consumer_surface.d.ts +1 -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 +6 -3
- package/dist/testing/cross_backend/setup.d.ts +2 -2
- package/dist/testing/cross_backend/spine_suites.d.ts +85 -5
- package/dist/testing/cross_backend/spine_suites.d.ts.map +1 -1
- package/dist/testing/cross_backend/spine_suites.js +291 -20
- package/dist/testing/cross_backend/spine_surface_constants.d.ts +15 -0
- package/dist/testing/cross_backend/spine_surface_constants.d.ts.map +1 -1
- package/dist/testing/cross_backend/spine_surface_constants.js +24 -0
- package/dist/testing/cross_backend/testing_backdoor.d.ts +27 -4
- package/dist/testing/cross_backend/testing_backdoor.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_backdoor.js +136 -41
- package/dist/testing/cross_backend/testing_reset_actions.d.ts +30 -15
- package/dist/testing/cross_backend/testing_reset_actions.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_reset_actions.js +52 -35
- package/dist/testing/cross_backend/ts_spine_backend_config.d.ts.map +1 -1
- package/dist/testing/cross_backend/ts_spine_backend_config.js +6 -3
- package/dist/testing/rpc_attack_surface.d.ts +10 -0
- package/dist/testing/rpc_attack_surface.d.ts.map +1 -1
- package/dist/testing/rpc_attack_surface.js +15 -3
- package/dist/testing/rpc_envelope_cases.d.ts +5 -2
- package/dist/testing/rpc_envelope_cases.d.ts.map +1 -1
- package/dist/testing/rpc_envelope_cases.js +4 -1
- package/dist/testing/rpc_round_trip.js +3 -3
- package/dist/testing/schema_generators.d.ts +99 -2
- package/dist/testing/schema_generators.d.ts.map +1 -1
- package/dist/testing/schema_generators.js +244 -76
- package/dist/testing/stubs.d.ts +4 -3
- package/dist/testing/stubs.d.ts.map +1 -1
- package/dist/testing/stubs.js +6 -4
- package/dist/zod.d.ts +9 -0
- package/dist/zod.d.ts.map +1 -1
- package/dist/zod.js +20 -0
- package/package.json +1 -1
|
@@ -13,6 +13,30 @@ export const TESTING_ACTION_AUTH = {
|
|
|
13
13
|
actor: 'none',
|
|
14
14
|
credential_types: ['daemon_token']
|
|
15
15
|
};
|
|
16
|
+
/**
|
|
17
|
+
* Every `_testing_*` backdoor the shipped cross suites know: the daemon-token
|
|
18
|
+
* actions a test binary may mount for the harness to drive. The one list a
|
|
19
|
+
* backend's `capabilities.testing_backdoors` declares from, the
|
|
20
|
+
* testing-backdoor suite probes, and `describe_spine_cross_suites` gates suites
|
|
21
|
+
* on. A consumer's own seams stay off it — the testing-backdoor suite takes
|
|
22
|
+
* those as `extra_methods`.
|
|
23
|
+
*
|
|
24
|
+
* `spine_surface_constants.testing_backdoors.test.ts` holds it to the `_testing_*` methods
|
|
25
|
+
* fuz_app's spine binary mounts, so an action added there fails until it is
|
|
26
|
+
* listed here.
|
|
27
|
+
*/
|
|
28
|
+
export const TESTING_BACKDOOR_METHODS = [
|
|
29
|
+
'_testing_reset',
|
|
30
|
+
'_testing_drain_effects',
|
|
31
|
+
'_testing_mint_session',
|
|
32
|
+
'_testing_put_fact',
|
|
33
|
+
'_testing_flood_notifications',
|
|
34
|
+
'_testing_schema_snapshot',
|
|
35
|
+
'_testing_migration_tracker',
|
|
36
|
+
'_testing_action_manifest',
|
|
37
|
+
'_testing_origin_check',
|
|
38
|
+
'_testing_shorten_credential_expiry'
|
|
39
|
+
];
|
|
16
40
|
/** RPC endpoint mount path — matches the binary's `/api/rpc`. */
|
|
17
41
|
export const SPINE_RPC_PATH = '/api/rpc';
|
|
18
42
|
/** Ungated WebSocket endpoint mount path — matches the binaries' `/api/ws`. */
|
|
@@ -1,14 +1,37 @@
|
|
|
1
1
|
import '../assert_dev_env.js';
|
|
2
|
-
import type {
|
|
2
|
+
import type { RpcPathCapabilityGatedCrossSuiteOptions } from './setup.js';
|
|
3
3
|
import { type WsEndpointTarget } from './ws_endpoint.js';
|
|
4
|
-
/**
|
|
5
|
-
|
|
4
|
+
/**
|
|
5
|
+
* A backdoor the suite fires: its method and a params payload its input
|
|
6
|
+
* schema accepts, so a refusal lands on the credential gate, not on validation.
|
|
7
|
+
*/
|
|
8
|
+
export interface TestingBackdoorProbe {
|
|
9
|
+
readonly method: string;
|
|
10
|
+
readonly params?: unknown;
|
|
11
|
+
}
|
|
12
|
+
/** Options for the testing-backdoor suite. */
|
|
13
|
+
export interface TestingBackdoorCrossTestOptions extends RpcPathCapabilityGatedCrossSuiteOptions {
|
|
6
14
|
/**
|
|
7
15
|
* Where the backend's WebSocket endpoint is, for the session-socket cases.
|
|
8
|
-
* Pass it when the backend serves
|
|
16
|
+
* Pass it when the backend serves its `_testing_*` actions on its WS
|
|
9
17
|
* endpoint too; omitted, those cases are skipped.
|
|
10
18
|
*/
|
|
11
19
|
readonly ws?: WsEndpointTarget;
|
|
20
|
+
/**
|
|
21
|
+
* The backend's own daemon-token seams beyond `TESTING_BACKDOOR_METHODS`,
|
|
22
|
+
* each with params its input accepts — fired with the same refused
|
|
23
|
+
* principals as the known backdoors. Each must start with `_testing_` and
|
|
24
|
+
* not be a known backdoor; the call throws otherwise.
|
|
25
|
+
*/
|
|
26
|
+
readonly extra_methods?: ReadonlyArray<TestingBackdoorProbe>;
|
|
12
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Register the backdoor suite: the declaration check over every known
|
|
30
|
+
* backdoor, then the refused-principal rows over the mounted ones.
|
|
31
|
+
*
|
|
32
|
+
* @param options - the fixture, the backend's capabilities, and the optional
|
|
33
|
+
* WS target and extra seams
|
|
34
|
+
* @throws Error - on a declaration or extra method `resolve_backdoor_probes` refuses
|
|
35
|
+
*/
|
|
13
36
|
export declare const describe_testing_backdoor_cross_tests: (options: TestingBackdoorCrossTestOptions) => void;
|
|
14
37
|
//# sourceMappingURL=testing_backdoor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing_backdoor.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/testing_backdoor.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"testing_backdoor.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/testing_backdoor.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA2F9B,OAAO,KAAK,EAAE,uCAAuC,EAAe,MAAM,YAAY,CAAC;AAMvF,OAAO,EAAmB,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AA0C1E;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;CAC1B;AAkDD,8CAA8C;AAC9C,MAAM,WAAW,+BAAgC,SAAQ,uCAAuC;IAC/F;;;;OAIG;IACH,QAAQ,CAAC,EAAE,CAAC,EAAE,gBAAgB,CAAC;IAC/B;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC,oBAAoB,CAAC,CAAC;CAC7D;AAqDD;;;;;;;GAOG;AACH,eAAO,MAAM,qCAAqC,GACjD,SAAS,+BAA+B,KACtC,IAgHF,CAAC"}
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import '../assert_dev_env.js';
|
|
2
2
|
/**
|
|
3
|
-
* Cross-backend
|
|
4
|
-
*
|
|
3
|
+
* Cross-backend suite for the `_testing_*` backdoor actions: the backend's
|
|
4
|
+
* declaration of which it mounts, and the credential gate on each.
|
|
5
5
|
*
|
|
6
|
-
* `
|
|
7
|
-
* `
|
|
8
|
-
* `
|
|
9
|
-
* `
|
|
6
|
+
* `TESTING_BACKDOOR_METHODS` (`_testing_reset`, `_testing_drain_effects`,
|
|
7
|
+
* `_testing_mint_session`, `_testing_put_fact`,
|
|
8
|
+
* `_testing_flood_notifications`, `_testing_schema_snapshot`,
|
|
9
|
+
* `_testing_migration_tracker`, `_testing_action_manifest`,
|
|
10
|
+
* `_testing_origin_check`, `_testing_shorten_credential_expiry`) are
|
|
10
11
|
* privileged test-binary actions the production
|
|
11
12
|
* wire never exposes — direct DB writes (full auth wipe, forged session row,
|
|
12
|
-
* raw fact insert), a flood of the caller's own connection,
|
|
13
|
-
* reads (the live schema, the `schema_version` migration
|
|
14
|
-
* RPC registry — the highest info-leak of the set were
|
|
15
|
-
* probe of the origin allowlist parser, and a rewrite of
|
|
16
|
-
* credential expiries. Their only structural fence
|
|
13
|
+
* raw fact insert), the audit barrier, a flood of the caller's own connection,
|
|
14
|
+
* introspection reads (the live schema, the `schema_version` migration
|
|
15
|
+
* tracker, and the live RPC registry — the highest info-leak of the set were
|
|
16
|
+
* the gate to break), a probe of the origin allowlist parser, and a rewrite of
|
|
17
|
+
* an account's credential expiries. Their only structural fence
|
|
17
18
|
* is the **daemon-token** credential gate on
|
|
18
19
|
* each spec's `auth` axis. A test binary live-mounts them on its RPC
|
|
19
20
|
* endpoint (and, on fuz_app's spine binary and the Rust stub, its WS
|
|
@@ -24,7 +25,19 @@ import '../assert_dev_env.js';
|
|
|
24
25
|
* (`live_rpc_endpoints`) fires the same refusals through the auth rows
|
|
25
26
|
* `generate_rpc_auth_conformance_cases` generates for them.
|
|
26
27
|
*
|
|
27
|
-
*
|
|
28
|
+
* **The declaration.** A backend states which it mounts in
|
|
29
|
+
* `capabilities.testing_backdoors`, and the suite holds it to that: each known
|
|
30
|
+
* backdoor the declaration leaves out is sent anonymously and must answer
|
|
31
|
+
* `method_not_found` (404) — both spines look a method up before they
|
|
32
|
+
* authenticate the caller, so an unmounted method answers that whatever the
|
|
33
|
+
* credential — and each declared one runs the rows below, whose anonymous row
|
|
34
|
+
* (a 401, not `method_not_found`) proves it mounted. A wrong declaration fails
|
|
35
|
+
* either way, so the suites that skip on an undeclared backdoor
|
|
36
|
+
* (`describe_spine_cross_suites`) skip only what the backend truly lacks. The
|
|
37
|
+
* check runs on every backend, one mounting none of them included.
|
|
38
|
+
*
|
|
39
|
+
* For every declared backdoor, and each `extra_methods` seam (a consumer's own
|
|
40
|
+
* daemon-token action), three principals:
|
|
28
41
|
*
|
|
29
42
|
* - **anonymous** (no credential) → `401` (pre-authorization auth refuses an
|
|
30
43
|
* account-less caller before anything else).
|
|
@@ -55,13 +68,13 @@ import '../assert_dev_env.js';
|
|
|
55
68
|
* on both impls. Cited property: `security.md` §Test Backdoor Actions
|
|
56
69
|
* (daemon-token-gated, off-surface, DEV-excluded).
|
|
57
70
|
*
|
|
58
|
-
*
|
|
59
|
-
* binary, not the in-process app — like the ws/sse
|
|
60
|
-
* `*.cross.test.ts
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
* backend that also serves
|
|
71
|
+
* The credential rows run cross-process only — the `_testing_*` actions are
|
|
72
|
+
* mounted on the spawned binary, not the in-process app — like the ws/sse
|
|
73
|
+
* suites; there, wire from a `*.cross.test.ts`, whose setup fires
|
|
74
|
+
* `_testing_reset`, so the backend must mount that one. In-process, an app
|
|
75
|
+
* mounting none declares none, and the suite runs the declaration rows alone,
|
|
76
|
+
* one per known backdoor. The WS cases run when `ws` is passed — for a
|
|
77
|
+
* backend that also serves its backdoors on its WS endpoint.
|
|
65
78
|
*
|
|
66
79
|
* @module
|
|
67
80
|
*/
|
|
@@ -69,46 +82,49 @@ import { describe, test, assert } from 'vitest';
|
|
|
69
82
|
import { ERROR_CREDENTIAL_TYPE_REQUIRED } from '../../http/error_schemas.js';
|
|
70
83
|
import { JSONRPC_ERROR_CODES } from '../../http/jsonrpc_errors.js';
|
|
71
84
|
import { rpc_call } from '../rpc_helpers.js';
|
|
85
|
+
import { TESTING_METHOD_PREFIX } from '../surface_invariants.js';
|
|
72
86
|
import { is_response_for } from '../transports/ws_client.js';
|
|
73
87
|
import { test_if } from './capabilities.js';
|
|
74
|
-
import { SPINE_RPC_PATH } from './spine_surface_constants.js';
|
|
88
|
+
import { SPINE_RPC_PATH, TESTING_BACKDOOR_METHODS } from './spine_surface_constants.js';
|
|
75
89
|
import { open_session_ws } from './ws_endpoint.js';
|
|
76
90
|
/** A well-formed UUID that never names a real row. */
|
|
77
91
|
const NIL_UUID = '00000000-0000-0000-0000-000000000000';
|
|
78
92
|
/**
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
93
|
+
* A **valid** params payload for each known backdoor (so the session/bearer
|
|
94
|
+
* cases reach the 403 credential gate rather than a 400 on input validation).
|
|
95
|
+
* The handlers never run — the gate refuses first. Keyed by
|
|
96
|
+
* `TestingBackdoorMethod`, so a method added to `TESTING_BACKDOOR_METHODS`
|
|
97
|
+
* fails typecheck here until it has its params.
|
|
82
98
|
*/
|
|
83
|
-
const
|
|
84
|
-
|
|
99
|
+
const BACKDOOR_PARAMS = {
|
|
100
|
+
_testing_reset: {},
|
|
85
101
|
// The audit barrier — its input is void, so the call carries no params.
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
102
|
+
_testing_drain_effects: undefined,
|
|
103
|
+
_testing_mint_session: { account_id: NIL_UUID, expires_in_seconds: -60 },
|
|
104
|
+
_testing_put_fact: { content: 'backdoor-probe' },
|
|
89
105
|
// An empty burst — valid input, so it clears the 400 phase; a refused
|
|
90
106
|
// caller never reaches the handler that would queue it.
|
|
91
|
-
|
|
107
|
+
_testing_flood_notifications: { count: 0, size: 0 },
|
|
92
108
|
// The schema-dump read — `exclude_tables` is optional, so `{}` is valid
|
|
93
109
|
// and clears the 400 phase like the writes above.
|
|
94
|
-
|
|
110
|
+
_testing_schema_snapshot: {},
|
|
95
111
|
// The migration-tracker-dump read — input is an empty strict object, so `{}`
|
|
96
112
|
// is valid and clears the 400 phase, reaching the credential gate like the rest.
|
|
97
|
-
|
|
113
|
+
_testing_migration_tracker: {},
|
|
98
114
|
// The RPC-registry-dump read — input is an empty strict object, so `{}` is
|
|
99
115
|
// valid and clears the 400 phase, reaching the credential gate like the rest.
|
|
100
|
-
|
|
116
|
+
_testing_action_manifest: {},
|
|
101
117
|
// The origin conformance probe — a valid `{patterns, origin}` pair, so it
|
|
102
118
|
// clears the 400 phase like the rest.
|
|
103
|
-
|
|
119
|
+
_testing_origin_check: { patterns: 'http://localhost:*', origin: null },
|
|
104
120
|
// The credential-expiry rewrite — a valid `{account_id, seconds}` pair (a
|
|
105
121
|
// syntactically valid UUID; no row needs to match), so it clears the 400
|
|
106
122
|
// phase like the rest.
|
|
107
|
-
{
|
|
108
|
-
|
|
109
|
-
|
|
123
|
+
_testing_shorten_credential_expiry: {
|
|
124
|
+
account_id: '00000000-0000-4000-8000-000000000000',
|
|
125
|
+
seconds: 30
|
|
110
126
|
}
|
|
111
|
-
|
|
127
|
+
};
|
|
112
128
|
const principals = [
|
|
113
129
|
{
|
|
114
130
|
name: 'anonymous',
|
|
@@ -139,11 +155,89 @@ const principals = [
|
|
|
139
155
|
})
|
|
140
156
|
}
|
|
141
157
|
];
|
|
158
|
+
/**
|
|
159
|
+
* The known backdoors a backend declares, checked against the known list,
|
|
160
|
+
* and its extra seams, checked against the `_testing_` prefix and the list.
|
|
161
|
+
*
|
|
162
|
+
* @throws Error - on a declared method that isn't a known backdoor, an extra
|
|
163
|
+
* method outside the `_testing_` namespace or naming a known backdoor, or a
|
|
164
|
+
* duplicate
|
|
165
|
+
*/
|
|
166
|
+
const resolve_backdoor_probes = (declared, extra_methods) => {
|
|
167
|
+
const known = new Set(TESTING_BACKDOOR_METHODS);
|
|
168
|
+
const seen = new Set();
|
|
169
|
+
for (const method of declared) {
|
|
170
|
+
if (!known.has(method)) {
|
|
171
|
+
throw new Error(`describe_testing_backdoor_cross_tests: capabilities.testing_backdoors declares ` +
|
|
172
|
+
`'${method}', which is not in TESTING_BACKDOOR_METHODS — pass a consumer seam as extra_methods`);
|
|
173
|
+
}
|
|
174
|
+
if (seen.has(method)) {
|
|
175
|
+
throw new Error(`describe_testing_backdoor_cross_tests: capabilities.testing_backdoors declares '${method}' twice`);
|
|
176
|
+
}
|
|
177
|
+
seen.add(method);
|
|
178
|
+
}
|
|
179
|
+
for (const { method } of extra_methods) {
|
|
180
|
+
if (!method.startsWith(TESTING_METHOD_PREFIX) || known.has(method)) {
|
|
181
|
+
throw new Error(`describe_testing_backdoor_cross_tests: extra method '${method}' must start with ` +
|
|
182
|
+
`'${TESTING_METHOD_PREFIX}' and not be a known backdoor (declare those in capabilities.testing_backdoors)`);
|
|
183
|
+
}
|
|
184
|
+
if (seen.has(method)) {
|
|
185
|
+
throw new Error(`describe_testing_backdoor_cross_tests: extra method '${method}' is listed twice`);
|
|
186
|
+
}
|
|
187
|
+
seen.add(method);
|
|
188
|
+
}
|
|
189
|
+
return [
|
|
190
|
+
...TESTING_BACKDOOR_METHODS.filter((method) => declared.includes(method)).map((method) => ({
|
|
191
|
+
method,
|
|
192
|
+
params: BACKDOOR_PARAMS[method]
|
|
193
|
+
})),
|
|
194
|
+
...extra_methods
|
|
195
|
+
];
|
|
196
|
+
};
|
|
197
|
+
/**
|
|
198
|
+
* Register the backdoor suite: the declaration check over every known
|
|
199
|
+
* backdoor, then the refused-principal rows over the mounted ones.
|
|
200
|
+
*
|
|
201
|
+
* @param options - the fixture, the backend's capabilities, and the optional
|
|
202
|
+
* WS target and extra seams
|
|
203
|
+
* @throws Error - on a declaration or extra method `resolve_backdoor_probes` refuses
|
|
204
|
+
*/
|
|
142
205
|
export const describe_testing_backdoor_cross_tests = (options) => {
|
|
143
|
-
const { setup_test, ws } = options;
|
|
206
|
+
const { setup_test, capabilities, ws, extra_methods = [] } = options;
|
|
144
207
|
const rpc_path = options.rpc_path ?? SPINE_RPC_PATH;
|
|
208
|
+
const declared = capabilities.testing_backdoors;
|
|
209
|
+
const probes = resolve_backdoor_probes(declared, extra_methods);
|
|
210
|
+
// a declared backdoor's mount is pinned by its anonymous row below (a 401,
|
|
211
|
+
// not `method_not_found`); an undeclared one must not be mounted, so a
|
|
212
|
+
// backend can't mount one its declaration leaves out
|
|
213
|
+
const undeclared = TESTING_BACKDOOR_METHODS.filter((method) => !declared.includes(method));
|
|
214
|
+
// vitest fails a describe holding no test, so a full declaration registers none
|
|
215
|
+
if (undeclared.length > 0) {
|
|
216
|
+
describe('testing backdoor declaration', () => {
|
|
217
|
+
for (const method of undeclared) {
|
|
218
|
+
test(`${method} is undeclared → method_not_found`, async () => {
|
|
219
|
+
const fixture = await setup_test();
|
|
220
|
+
const res = await rpc_call({
|
|
221
|
+
app: fixture.fresh_transport(),
|
|
222
|
+
path: rpc_path,
|
|
223
|
+
method,
|
|
224
|
+
params: BACKDOOR_PARAMS[method]
|
|
225
|
+
});
|
|
226
|
+
assert.ok(!res.ok, `${method}: undeclared in capabilities.testing_backdoors, but the call succeeded`);
|
|
227
|
+
if (!res.ok) {
|
|
228
|
+
assert.strictEqual(res.error.code, JSONRPC_ERROR_CODES.method_not_found, `${method}: undeclared in capabilities.testing_backdoors, but it answers ` +
|
|
229
|
+
`${res.status} (${res.error.code}) — the backend mounts it, so declare it`);
|
|
230
|
+
}
|
|
231
|
+
assert.strictEqual(res.status, 404, `${method}: status`);
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
// none declared and no extra seam: no rows, and vitest fails an empty describe
|
|
237
|
+
if (probes.length === 0)
|
|
238
|
+
return;
|
|
145
239
|
describe('testing backdoor credential gate parity', () => {
|
|
146
|
-
for (const { method, params } of
|
|
240
|
+
for (const { method, params } of probes) {
|
|
147
241
|
for (const principal of principals) {
|
|
148
242
|
test(`${method} rejects ${principal.name} → ${principal.status}`, async () => {
|
|
149
243
|
const fixture = await setup_test();
|
|
@@ -158,9 +252,10 @@ export const describe_testing_backdoor_cross_tests = (options) => {
|
|
|
158
252
|
});
|
|
159
253
|
const label = `${method} ${principal.name}`;
|
|
160
254
|
assert.ok(!res.ok, `${label}: expected denial (${principal.status}) but the call succeeded`);
|
|
161
|
-
assert.strictEqual(res.status, principal.status, `${label}: status`);
|
|
162
255
|
// `!res.ok` narrows `res` to the error variant for `res.error`.
|
|
163
256
|
if (!res.ok) {
|
|
257
|
+
assert.notStrictEqual(res.error.code, JSONRPC_ERROR_CODES.method_not_found, `${label}: declared but not mounted — the backend answers method_not_found`);
|
|
258
|
+
assert.strictEqual(res.status, principal.status, `${label}: status`);
|
|
164
259
|
assert.strictEqual(res.error.code, principal.code, `${label}: error.code`);
|
|
165
260
|
if (principal.reason !== undefined) {
|
|
166
261
|
const reason = res.error.data?.reason;
|
|
@@ -170,7 +265,7 @@ export const describe_testing_backdoor_cross_tests = (options) => {
|
|
|
170
265
|
});
|
|
171
266
|
}
|
|
172
267
|
}
|
|
173
|
-
for (const { method, params } of
|
|
268
|
+
for (const { method, params } of probes) {
|
|
174
269
|
test_if(ws !== undefined, `${method} over a session socket → forbidden ${ERROR_CREDENTIAL_TYPE_REQUIRED}`, async () => {
|
|
175
270
|
const fixture = await setup_test();
|
|
176
271
|
const client = await open_session_ws(ws, fixture, { admitted: true });
|
|
@@ -29,13 +29,16 @@ import '../assert_dev_env.js';
|
|
|
29
29
|
*
|
|
30
30
|
* `_testing_reset` — full DB wipe + keeper re-seed + optional
|
|
31
31
|
* secondary-account seeding. The
|
|
32
|
-
* handler
|
|
32
|
+
* handler first fires the consumer-supplied domain-state callback (domain
|
|
33
|
+
* rows depend on auth rows, so a domain table with a restricting FK to
|
|
34
|
+
* `actor` empties before the rows it references go), then wipes every
|
|
35
|
+
* auth-namespace row (no keeper-preserve filter),
|
|
33
36
|
* flips `bootstrap_lock` back to its post-bootstrap shape, seeds a
|
|
34
37
|
* fresh keeper account inline (reusing `create_test_account_with_credentials`
|
|
35
|
-
* so cross-process matches in-process write semantics),
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
38
|
+
* so cross-process matches in-process write semantics), queues the
|
|
39
|
+
* daemon-token cache refresh to point at the new keeper once the reset
|
|
40
|
+
* commits, and seeds any caller-requested `extra_accounts` (also
|
|
41
|
+
* direct-inserted at this setup step). The
|
|
39
42
|
* new keeper + secondary credentials return as the action output so
|
|
40
43
|
* the per-test fixture closes over them.
|
|
41
44
|
*
|
|
@@ -177,6 +180,11 @@ export declare const testing_reset_action_spec: {
|
|
|
177
180
|
* not — nor are eager writes outside `emit` (session touch, token usage),
|
|
178
181
|
* which only the dispatching transport's own flush awaits.
|
|
179
182
|
*
|
|
183
|
+
* The output's `tracked` is `AuditEmitter.is_tracking_inflight` — whether the
|
|
184
|
+
* drain could wait on anything. `cross_drain_effects` refuses `tracked: false`,
|
|
185
|
+
* so a binary whose emitter was built without tracking fails its first audit
|
|
186
|
+
* read instead of racing it. The Rust twin answers the same shape.
|
|
187
|
+
*
|
|
180
188
|
* `auth` gates on the daemon-token credential, matching `_testing_reset`.
|
|
181
189
|
*/
|
|
182
190
|
export declare const testing_drain_effects_action_spec: {
|
|
@@ -192,6 +200,7 @@ export declare const testing_drain_effects_action_spec: {
|
|
|
192
200
|
readonly input: z.ZodVoid;
|
|
193
201
|
readonly output: z.ZodObject<{
|
|
194
202
|
ok: z.ZodBoolean;
|
|
203
|
+
tracked: z.ZodBoolean;
|
|
195
204
|
}, z.core.$strict>;
|
|
196
205
|
readonly async: true;
|
|
197
206
|
readonly description: "Test-binary only — await in-flight fire-and-forget audit writes so a following audit_log_list read is authoritative.";
|
|
@@ -251,7 +260,8 @@ export declare const testing_mint_session_action_spec: {
|
|
|
251
260
|
* emitter the backend's handlers emit through (`deps.audit`), built with
|
|
252
261
|
* `track_inflight: true` (see the spec doc). Mount it on any test endpoint
|
|
253
262
|
* whose suite asserts on audit rows (the spine binary bundles it via
|
|
254
|
-
* `create_testing_actions`; in-process suites mount it directly).
|
|
263
|
+
* `create_testing_actions`; in-process suites mount it directly). Answers
|
|
264
|
+
* `{ok: true, tracked}`, `tracked` read from `audit.is_tracking_inflight()`.
|
|
255
265
|
*
|
|
256
266
|
* @param audit - the backend's emitter, whose in-flight writes the action awaits
|
|
257
267
|
*/
|
|
@@ -626,17 +636,22 @@ export interface CreateTestingActionsOptions {
|
|
|
626
636
|
*/
|
|
627
637
|
readonly daemon_token_state: DaemonTokenState;
|
|
628
638
|
/**
|
|
629
|
-
* Consumer-supplied callback invoked
|
|
630
|
-
* the same transactional `Db` the auth wipes
|
|
639
|
+
* Consumer-supplied callback invoked first, before the auth-table wipe and
|
|
640
|
+
* keeper re-seed, passed the same transactional `Db` the auth wipes then
|
|
641
|
+
* run on. It runs while the previous test's accounts and actors still
|
|
642
|
+
* exist, so a domain table with a restricting FK to `actor` / `account`
|
|
643
|
+
* empties before the auth wipe deletes what it references; it must not
|
|
644
|
+
* depend on the fresh keeper, which doesn't exist yet. DB-domain consumers
|
|
631
645
|
* (e.g. fuz_forge truncating its cell / fact / file tables) MUST use this
|
|
632
646
|
* `db` rather than a separately-pooled connection — under the in-memory
|
|
633
|
-
* drivers' single connection (pglet, PGlite) a second connection deadlocks
|
|
634
|
-
* transaction. `testing_zzz_server` clears
|
|
635
|
-
* terminals + scoped-FS scratch (ignores
|
|
636
|
-
* (`testing/cross_backend/full_spine_mount.ts` and
|
|
637
|
-
* the cell and fact tables. Runs inside
|
|
638
|
-
* as the auth-table writes, so a throw
|
|
639
|
-
* JSON-RPC error and the per-test
|
|
647
|
+
* drivers' single connection (pglet, PGlite) a second connection deadlocks
|
|
648
|
+
* against this still-open transaction. `testing_zzz_server` clears
|
|
649
|
+
* in-memory workspace registry + terminals + scoped-FS scratch (ignores
|
|
650
|
+
* `db`); the spine binaries (`testing/cross_backend/full_spine_mount.ts` and
|
|
651
|
+
* the Rust `testing_spine_stub`) empty the cell and fact tables. Runs inside
|
|
652
|
+
* the same RPC dispatch as the auth-table writes, so a throw rolls the whole
|
|
653
|
+
* reset back and surfaces to the caller as a JSON-RPC error and the per-test
|
|
654
|
+
* fixture short-circuits.
|
|
640
655
|
*/
|
|
641
656
|
readonly reset_state?: (db: Db) => Promise<void> | void;
|
|
642
657
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing_reset_actions.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/testing_reset_actions.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B
|
|
1
|
+
{"version":3,"file":"testing_reset_actions.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/testing_reset_actions.ts"],"names":[],"mappings":"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"}
|
|
@@ -29,13 +29,16 @@ import '../assert_dev_env.js';
|
|
|
29
29
|
*
|
|
30
30
|
* `_testing_reset` — full DB wipe + keeper re-seed + optional
|
|
31
31
|
* secondary-account seeding. The
|
|
32
|
-
* handler
|
|
32
|
+
* handler first fires the consumer-supplied domain-state callback (domain
|
|
33
|
+
* rows depend on auth rows, so a domain table with a restricting FK to
|
|
34
|
+
* `actor` empties before the rows it references go), then wipes every
|
|
35
|
+
* auth-namespace row (no keeper-preserve filter),
|
|
33
36
|
* flips `bootstrap_lock` back to its post-bootstrap shape, seeds a
|
|
34
37
|
* fresh keeper account inline (reusing `create_test_account_with_credentials`
|
|
35
|
-
* so cross-process matches in-process write semantics),
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
38
|
+
* so cross-process matches in-process write semantics), queues the
|
|
39
|
+
* daemon-token cache refresh to point at the new keeper once the reset
|
|
40
|
+
* commits, and seeds any caller-requested `extra_accounts` (also
|
|
41
|
+
* direct-inserted at this setup step). The
|
|
39
42
|
* new keeper + secondary credentials return as the action output so
|
|
40
43
|
* the per-test fixture closes over them.
|
|
41
44
|
*
|
|
@@ -179,6 +182,11 @@ export const testing_reset_action_spec = {
|
|
|
179
182
|
* not — nor are eager writes outside `emit` (session touch, token usage),
|
|
180
183
|
* which only the dispatching transport's own flush awaits.
|
|
181
184
|
*
|
|
185
|
+
* The output's `tracked` is `AuditEmitter.is_tracking_inflight` — whether the
|
|
186
|
+
* drain could wait on anything. `cross_drain_effects` refuses `tracked: false`,
|
|
187
|
+
* so a binary whose emitter was built without tracking fails its first audit
|
|
188
|
+
* read instead of racing it. The Rust twin answers the same shape.
|
|
189
|
+
*
|
|
182
190
|
* `auth` gates on the daemon-token credential, matching `_testing_reset`.
|
|
183
191
|
*/
|
|
184
192
|
export const testing_drain_effects_action_spec = {
|
|
@@ -188,7 +196,13 @@ export const testing_drain_effects_action_spec = {
|
|
|
188
196
|
auth: TESTING_ACTION_AUTH,
|
|
189
197
|
side_effects: false,
|
|
190
198
|
input: z.void(),
|
|
191
|
-
output: z.strictObject({
|
|
199
|
+
output: z.strictObject({
|
|
200
|
+
ok: z.boolean(),
|
|
201
|
+
tracked: z.boolean().meta({
|
|
202
|
+
description: "Whether the backend's audit emitter tracks in-flight writes — false means the drain " +
|
|
203
|
+
'waited on nothing and is no barrier.'
|
|
204
|
+
})
|
|
205
|
+
}),
|
|
192
206
|
async: true,
|
|
193
207
|
description: 'Test-binary only — await in-flight fire-and-forget audit writes so a following audit_log_list read is authoritative.'
|
|
194
208
|
};
|
|
@@ -250,13 +264,14 @@ export const testing_mint_session_action_spec = {
|
|
|
250
264
|
* emitter the backend's handlers emit through (`deps.audit`), built with
|
|
251
265
|
* `track_inflight: true` (see the spec doc). Mount it on any test endpoint
|
|
252
266
|
* whose suite asserts on audit rows (the spine binary bundles it via
|
|
253
|
-
* `create_testing_actions`; in-process suites mount it directly).
|
|
267
|
+
* `create_testing_actions`; in-process suites mount it directly). Answers
|
|
268
|
+
* `{ok: true, tracked}`, `tracked` read from `audit.is_tracking_inflight()`.
|
|
254
269
|
*
|
|
255
270
|
* @param audit - the backend's emitter, whose in-flight writes the action awaits
|
|
256
271
|
*/
|
|
257
272
|
export const create_testing_drain_effects_action = (audit) => rpc_action(testing_drain_effects_action_spec, async () => {
|
|
258
273
|
await audit.drain_inflight();
|
|
259
|
-
return { ok: true };
|
|
274
|
+
return { ok: true, tracked: audit.is_tracking_inflight() };
|
|
260
275
|
});
|
|
261
276
|
/**
|
|
262
277
|
* `_testing_put_fact` — seed an **embedded** fact (`fact.bytes`) for the
|
|
@@ -613,8 +628,18 @@ export const create_testing_actions = (deps, options) => {
|
|
|
613
628
|
const log = deps.log;
|
|
614
629
|
return [
|
|
615
630
|
rpc_action(testing_reset_action_spec, async (input, ctx) => {
|
|
616
|
-
log.info('[_testing_reset] resetting auth state + re-seeding keeper');
|
|
617
|
-
// 1.
|
|
631
|
+
log.info('[_testing_reset] resetting domain + auth state + re-seeding keeper');
|
|
632
|
+
// 1. Fire domain-state reset (zzz workspaces/terminals/scratch,
|
|
633
|
+
// fuz_forge cell/fact/file truncation, the spine binaries' cell +
|
|
634
|
+
// fact wipe) first: domain rows depend on auth rows, so a domain
|
|
635
|
+
// table with a restricting FK to `actor` would make the auth wipe
|
|
636
|
+
// below fail once it holds a row.
|
|
637
|
+
// Pass the transactional `ctx.db` so DB-domain truncation runs
|
|
638
|
+
// on the same connection — a separate pool connection deadlocks
|
|
639
|
+
// against this open transaction under the in-memory drivers.
|
|
640
|
+
if (reset_state)
|
|
641
|
+
await reset_state(ctx.db);
|
|
642
|
+
// 2. Wipe every auth-namespace row. No keeper-preserve filter —
|
|
618
643
|
// the fresh-keeper-per-test contract means mutation-cascade
|
|
619
644
|
// tests (password change, revoke-all) and hardcoded-username
|
|
620
645
|
// signup-uniqueness tests can't leak between cases.
|
|
@@ -631,13 +656,13 @@ export const create_testing_actions = (deps, options) => {
|
|
|
631
656
|
await ctx.db.query('DELETE FROM role_grant');
|
|
632
657
|
await ctx.db.query('DELETE FROM actor');
|
|
633
658
|
await ctx.db.query('DELETE FROM account');
|
|
634
|
-
//
|
|
659
|
+
// 3. Reset singleton `app_settings` to production defaults
|
|
635
660
|
// (matches in-process `_build_test_backend` behavior in
|
|
636
661
|
// `app_server.ts`). Tests that flipped `open_signup` mid-run
|
|
637
662
|
// revert.
|
|
638
663
|
await ctx.db.query('UPDATE app_settings SET open_signup = false, updated_at = NULL, updated_by = NULL ' +
|
|
639
664
|
'WHERE open_signup = true OR updated_at IS NOT NULL');
|
|
640
|
-
//
|
|
665
|
+
// 4. Flip `bootstrap_lock` to its post-bootstrap shape. Production
|
|
641
666
|
// `bootstrap_account` flips this to `true` on success; the
|
|
642
667
|
// in-process `bootstrap_test_keeper` mirrors the flip. We're
|
|
643
668
|
// about to seed the keeper here, so the final state needs to
|
|
@@ -645,7 +670,7 @@ export const create_testing_actions = (deps, options) => {
|
|
|
645
670
|
// to `false` — nothing reads it between our DELETEs and the
|
|
646
671
|
// UPDATE.
|
|
647
672
|
await ctx.db.query('UPDATE bootstrap_lock SET bootstrapped = true WHERE id = 1');
|
|
648
|
-
//
|
|
673
|
+
// 5. Seed the fresh keeper inline. Reuses the same primitive
|
|
649
674
|
// in-process tests use (`create_test_account_with_credentials`)
|
|
650
675
|
// so cross-process and in-process write semantics stay in
|
|
651
676
|
// parity — same hash, same account+actor+role_grants+
|
|
@@ -662,7 +687,19 @@ export const create_testing_actions = (deps, options) => {
|
|
|
662
687
|
password_value: DEFAULT_TEST_PASSWORD,
|
|
663
688
|
roles: [ROLE_KEEPER, ROLE_ADMIN, ...(input.extra_keeper_roles ?? [])]
|
|
664
689
|
});
|
|
665
|
-
//
|
|
690
|
+
// 6. Refresh the daemon-token cache so subsequent daemon-token
|
|
691
|
+
// requests resolve to the freshly seeded keeper. The
|
|
692
|
+
// middleware's lazy-refresh path only fires when the cached
|
|
693
|
+
// id is null, so the reset sets it — after the commit, queued as
|
|
694
|
+
// soon as the keeper exists, so a reset that rolls back after it
|
|
695
|
+
// (a failing extra seed, a failed COMMIT) leaves the cache on the
|
|
696
|
+
// keeper still in the database rather than one that never
|
|
697
|
+
// landed, and the next reset can still authenticate.
|
|
698
|
+
const keeper_account_id = keeper.account.id;
|
|
699
|
+
emit_after_commit(ctx, () => {
|
|
700
|
+
daemon_token_state.keeper_account_id = keeper_account_id;
|
|
701
|
+
});
|
|
702
|
+
// 7. Seed any caller-requested extras. These are bootstrap-time
|
|
666
703
|
// secondaries — the bypass exists in the same cradle the
|
|
667
704
|
// keeper does, not as a free-form runtime action.
|
|
668
705
|
const extras = [];
|
|
@@ -678,7 +715,7 @@ export const create_testing_actions = (deps, options) => {
|
|
|
678
715
|
});
|
|
679
716
|
extras.push(seeded);
|
|
680
717
|
}
|
|
681
|
-
//
|
|
718
|
+
// 8. Seed any additional keeper actors. Same bootstrap-cradle
|
|
682
719
|
// bypass as extra_accounts — no production wire path mints a
|
|
683
720
|
// second actor, so the multi-actor `acting` branches need this
|
|
684
721
|
// direct insert. Order-preserving so the fixture can address
|
|
@@ -691,26 +728,6 @@ export const create_testing_actions = (deps, options) => {
|
|
|
691
728
|
const seeded_actor = await create_test_extra_actor(ctx.db, keeper.account.id, name);
|
|
692
729
|
extra_actors.push({ id: seeded_actor.id, name: seeded_actor.name });
|
|
693
730
|
}
|
|
694
|
-
// 6. Refresh the daemon-token cache so subsequent daemon-token
|
|
695
|
-
// requests resolve to the freshly seeded keeper. The
|
|
696
|
-
// middleware's lazy-refresh path only fires when the cached
|
|
697
|
-
// id is null, so the reset sets it — after the commit, so a
|
|
698
|
-
// reset that rolls back (a throwing `reset_state`, a failed
|
|
699
|
-
// COMMIT) leaves the cache on the keeper still in the database
|
|
700
|
-
// rather than one that never landed, and the next reset can
|
|
701
|
-
// still authenticate.
|
|
702
|
-
const keeper_account_id = keeper.account.id;
|
|
703
|
-
emit_after_commit(ctx, () => {
|
|
704
|
-
daemon_token_state.keeper_account_id = keeper_account_id;
|
|
705
|
-
});
|
|
706
|
-
// 7. Fire domain-state reset (zzz workspaces/terminals/scratch,
|
|
707
|
-
// fuz_forge cell/fact/file truncation, the spine binaries' cell +
|
|
708
|
-
// fact wipe).
|
|
709
|
-
// Pass the transactional `ctx.db` so DB-domain truncation runs
|
|
710
|
-
// on the same connection — a separate pool connection deadlocks
|
|
711
|
-
// against this open transaction under the in-memory drivers.
|
|
712
|
-
if (reset_state)
|
|
713
|
-
await reset_state(ctx.db);
|
|
714
731
|
return { ...keeper, extra_accounts: extras, extra_actors };
|
|
715
732
|
}),
|
|
716
733
|
rpc_action(testing_mint_session_action_spec, async (input, ctx) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ts_spine_backend_config.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/ts_spine_backend_config.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"ts_spine_backend_config.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/ts_spine_backend_config.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAgFzD,6FAA6F;AAC7F,eAAO,MAAM,0BAA0B,OAAO,CAAC;AAE/C,iDAAiD;AACjD,eAAO,MAAM,0BAA0B,OAAO,CAAC;AAE/C,gDAAgD;AAChD,eAAO,MAAM,yBAAyB,OAAO,CAAC;AAE9C,yDAAyD;AACzD,eAAO,MAAM,mBAAmB,wDAAwD,CAAC;AAEzF,yDAAyD;AACzD,eAAO,MAAM,mBAAmB,wDAAwD,CAAC;AAEzF,wDAAwD;AACxD,eAAO,MAAM,kBAAkB,uDAAuD,CAAC;AAEvF,MAAM,WAAW,2BAA2B;IAC3C,mFAAmF;IACnF,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,6DAA6D;IAC7D,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B;;;;;;OAMG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;;;;;OASG;IACH,QAAQ,CAAC,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAC3C;;;;;;OAMG;IACH,QAAQ,CAAC,wBAAwB,CAAC,EAAE,OAAO,CAAC;IAC5C;;;;;OAKG;IACH,QAAQ,CAAC,8BAA8B,CAAC,EAAE,MAAM,CAAC;CACjD;AAWD;;;GAGG;AACH,eAAO,MAAM,4BAA4B,GACxC,UAAS,2BAAgC,KACvC,aAwBF,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,GACvC,UAAS,2BAAgC,KACvC,aAwBF,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,4BAA4B,GACxC,UAAS,2BAAgC,KACvC,aAqCF,CAAC"}
|