@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
|
@@ -32,6 +32,7 @@ import { type SessionCapCrossTestOptions } from './session_cap.js';
|
|
|
32
32
|
import { type SessionCookieCodecCrossTestOptions } from './session_cookie_codec.js';
|
|
33
33
|
import { type CrossProcessSetupOptions, type ReconstructedBootstrappedBackendHandle, type RpcPathCapabilityGatedCrossSuiteOptions } from './setup.js';
|
|
34
34
|
import { type SimpleRequestCrossTestOptions } from './simple_request.js';
|
|
35
|
+
import { type TestingBackdoorMethod } from './spine_surface_constants.js';
|
|
35
36
|
import { type CrossProcessSseTestOptions } from './sse_round_trip.js';
|
|
36
37
|
import { type StandardCrossProcessTestOptions } from './standard.js';
|
|
37
38
|
import { type TestingBackdoorCrossTestOptions } from './testing_backdoor.js';
|
|
@@ -61,6 +62,13 @@ export type StandaloneSuiteName = 'conformance_table' | 'differential' | 'login_
|
|
|
61
62
|
* one call.
|
|
62
63
|
*/
|
|
63
64
|
export declare const STANDALONE_CROSS_SUITES: Readonly<Record<StandaloneSuiteName, string>>;
|
|
65
|
+
/**
|
|
66
|
+
* The backdoors `describe_spine_cross_suites` requires of every backend, since
|
|
67
|
+
* the suites share them: `_testing_reset` is every `setup_test`'s per-test
|
|
68
|
+
* reset, and `_testing_drain_effects` the barrier every audit read waits on. A
|
|
69
|
+
* backend whose `capabilities.testing_backdoors` lacks one fails at collection.
|
|
70
|
+
*/
|
|
71
|
+
export declare const SPINE_SUITES_REQUIRED_BACKDOORS: ReadonlyArray<TestingBackdoorMethod>;
|
|
64
72
|
/** The options each suite takes, by `SuiteName` — what `overrides` entries are partials of. */
|
|
65
73
|
export interface SuiteOptionsMap {
|
|
66
74
|
account_lifecycle: AccountLifecycleCrossTestOptions;
|
|
@@ -117,6 +125,13 @@ export type SuiteOverride<K extends SuiteName> = Partial<SuiteOptionsMap[K]> | (
|
|
|
117
125
|
export type SuiteOverrides = {
|
|
118
126
|
readonly [K in SuiteName]?: SuiteOverride<K>;
|
|
119
127
|
};
|
|
128
|
+
/**
|
|
129
|
+
* Per-suite test exclusions: each test's name path — its describe titles and
|
|
130
|
+
* its own name, joined with `' > '`, as the reporter prints it after the file
|
|
131
|
+
* (and after any `describe` wrapping the call) — mapped to why it can't run on
|
|
132
|
+
* this backend.
|
|
133
|
+
*/
|
|
134
|
+
export type SuiteCaseExclusions = Readonly<Partial<Record<SuiteName, Readonly<Record<string, string>>>>>;
|
|
120
135
|
/** The suite options a backend's `BackendConfig` supplies. */
|
|
121
136
|
export interface CrossSuiteHandleOptions {
|
|
122
137
|
readonly capabilities: BackendCapabilities;
|
|
@@ -181,9 +196,17 @@ export interface SpineCrossSuitesOptions {
|
|
|
181
196
|
readonly setup?: CrossProcessSetupOptions;
|
|
182
197
|
/**
|
|
183
198
|
* Suites this backend doesn't run, each with a non-empty reason. Each shows
|
|
184
|
-
* in the run as one skipped test carrying the reason.
|
|
199
|
+
* in the run as one skipped test carrying the reason. Not `testing_backdoor`,
|
|
200
|
+
* nor a suite that already skips itself for an undeclared backdoor.
|
|
185
201
|
*/
|
|
186
202
|
readonly exclude?: Readonly<Partial<Record<SuiteName, string>>>;
|
|
203
|
+
/**
|
|
204
|
+
* Single tests this backend doesn't run, by suite, each by its name path
|
|
205
|
+
* (`SuiteCaseExclusions`) with a non-empty reason; each shows in the run as
|
|
206
|
+
* skipped with its reason. An entry naming a suite the call doesn't run,
|
|
207
|
+
* `testing_backdoor`, or a path no collected test of that suite has, fails.
|
|
208
|
+
*/
|
|
209
|
+
readonly exclude_cases?: SuiteCaseExclusions;
|
|
187
210
|
/** Per-suite option overrides, a shallow merge over what the handle gives. */
|
|
188
211
|
readonly overrides?: SuiteOverrides;
|
|
189
212
|
/** The roles the role-shaped suites use, when the backend lacks the spine's own. */
|
|
@@ -214,18 +237,75 @@ export interface SpineCrossSuitesOptions {
|
|
|
214
237
|
readonly rpc_success_fixtures?: RpcSuccessFixtures;
|
|
215
238
|
/** Forwarded to the standard bundle (`StandardCrossProcessTestOptions.rpc_skip_methods`). */
|
|
216
239
|
readonly rpc_skip_methods?: Array<string>;
|
|
217
|
-
/**
|
|
240
|
+
/**
|
|
241
|
+
* Forwarded to the standard bundle (`StandardCrossProcessTestOptions.rpc_input_overrides`)
|
|
242
|
+
* and to `rpc_adversarial` (`RpcAdversarialCrossTestOptions.input_overrides`),
|
|
243
|
+
* where each override seeds the method's params cases. Those cases are sent
|
|
244
|
+
* as a single-actor principal, so an override omits `acting`. A key naming a
|
|
245
|
+
* method on neither the declared surface nor `live_rpc_endpoints` throws at
|
|
246
|
+
* collection.
|
|
247
|
+
*/
|
|
218
248
|
readonly rpc_input_overrides?: Map<string, Record<string, unknown>>;
|
|
219
249
|
}
|
|
250
|
+
/**
|
|
251
|
+
* The backdoors every case of `name` drives beyond
|
|
252
|
+
* `SPINE_SUITES_REQUIRED_BACKDOORS` — a backend not declaring one skips the
|
|
253
|
+
* suite.
|
|
254
|
+
*
|
|
255
|
+
* @param name - the suite
|
|
256
|
+
* @returns its `SuiteEntry.backdoors`, empty for a suite needing none
|
|
257
|
+
* @internal
|
|
258
|
+
*/
|
|
259
|
+
export declare const get_spine_suite_backdoors: (name: SuiteName) => ReadonlyArray<TestingBackdoorMethod>;
|
|
260
|
+
/** The top-level tasks one suite registered, as indices into the calling suite's tasks. */
|
|
261
|
+
export interface SuiteTaskRange {
|
|
262
|
+
readonly name: SuiteName;
|
|
263
|
+
readonly start: number;
|
|
264
|
+
readonly end: number;
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Check every `exclude_cases` entry against the test paths each suite
|
|
268
|
+
* collected — the static half of the case exclusions, which the closing test
|
|
269
|
+
* `register_spine_case_exclusions` registers runs.
|
|
270
|
+
*
|
|
271
|
+
* @param exclude_cases - the entries, by suite
|
|
272
|
+
* @param collected - each run suite's collected test paths
|
|
273
|
+
* @throws Error - naming every entry whose suite collected no test at its path
|
|
274
|
+
* @internal
|
|
275
|
+
*/
|
|
276
|
+
export declare const check_spine_case_exclusions: (exclude_cases: SuiteCaseExclusions, collected: ReadonlyMap<SuiteName, ReadonlySet<string>>) => void;
|
|
277
|
+
/**
|
|
278
|
+
* Skip the `exclude_cases` tests, and fail on an entry no collected test has.
|
|
279
|
+
* `describe_spine_cross_suites` calls it after registering the suites, in the
|
|
280
|
+
* same suite.
|
|
281
|
+
*
|
|
282
|
+
* One `beforeEach` on the calling suite: it finds the test's top-level task
|
|
283
|
+
* among the ranges the suites registered, and calls `ctx.skip(reason)` when
|
|
284
|
+
* that suite's entries name the test's path — so the suite files stay as they
|
|
285
|
+
* are, and the test shows as skipped with its reason. A closing test holds
|
|
286
|
+
* every entry to a test its suite collected (`check_spine_case_exclusions`;
|
|
287
|
+
* the paths are read at collection, so a filtered run still checks them).
|
|
288
|
+
* A skipped test's own `beforeEach` hooks don't run, but its `afterEach`
|
|
289
|
+
* hooks and its suite's `beforeAll` still do.
|
|
290
|
+
*
|
|
291
|
+
* @param exclude_cases - the entries, by suite
|
|
292
|
+
* @param ranges - each run suite's top-level tasks in the calling suite
|
|
293
|
+
* @internal
|
|
294
|
+
*/
|
|
295
|
+
export declare const register_spine_case_exclusions: (exclude_cases: SuiteCaseExclusions, ranges: ReadonlyArray<SuiteTaskRange>) => void;
|
|
220
296
|
/**
|
|
221
297
|
* Run every shipped single-backend cross suite against one spawned backend —
|
|
222
298
|
* see the module doc for what the options add and what stays outside.
|
|
223
299
|
*
|
|
224
300
|
* @param handle - the backend, as `inject_backend_handle()` returns it
|
|
225
|
-
* @param options - the declared surface, plus excludes and overrides
|
|
301
|
+
* @param options - the declared surface, plus excludes, case exclusions and overrides
|
|
226
302
|
* @throws Error - on an exclude with no reason, an unknown suite name, a suite
|
|
227
|
-
* both excluded and overridden,
|
|
228
|
-
*
|
|
303
|
+
* both excluded and overridden, an excluded `testing_backdoor` (or one of
|
|
304
|
+
* its cases, or an override changing its `capabilities.testing_backdoors`), an exclude,
|
|
305
|
+
* override or `exclude_cases` entry for a suite that skips itself or isn't
|
|
306
|
+
* run, a backend not declaring `SPINE_SUITES_REQUIRED_BACKDOORS` (or
|
|
307
|
+
* `_testing_put_fact` with `fact_serving`), or a suite missing an input the
|
|
308
|
+
* handle doesn't carry
|
|
229
309
|
*/
|
|
230
310
|
export declare const describe_spine_cross_suites: (handle: ReconstructedBootstrappedBackendHandle, options: SpineCrossSuitesOptions) => void;
|
|
231
311
|
//# sourceMappingURL=spine_suites.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spine_suites.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/spine_suites.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"spine_suites.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/spine_suites.ts"],"names":[],"mappings":"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"}
|
|
@@ -17,7 +17,14 @@ import '../assert_dev_env.js';
|
|
|
17
17
|
*
|
|
18
18
|
* - `exclude` names a suite with the reason it can't run on this backend; the
|
|
19
19
|
* reason is required and shows in the run as a skipped test, so a skip is
|
|
20
|
-
* stated in code and visible in the report.
|
|
20
|
+
* stated in code and visible in the report. `testing_backdoor` can't be
|
|
21
|
+
* excluded, by suite or by case, nor its `capabilities.testing_backdoors`
|
|
22
|
+
* changed: it checks the declaration the backdoor gating reads.
|
|
23
|
+
* - `exclude_cases` names single tests of a suite that does run, each by its
|
|
24
|
+
* name path (describe titles and test name, joined with `' > '`) with a
|
|
25
|
+
* required reason; one `beforeEach` skips them at run time, so each shows as
|
|
26
|
+
* skipped with its reason, and an entry matching no collected test of its
|
|
27
|
+
* suite fails the closing check test.
|
|
21
28
|
* - `overrides` replaces a suite's derived options, field by field (a shallow
|
|
22
29
|
* merge over what the handle gives) — a role list the backend's WS upgrade
|
|
23
30
|
* requires, an `xfail` for a tracked divergence, a narrower capability set.
|
|
@@ -25,7 +32,10 @@ import '../assert_dev_env.js';
|
|
|
25
32
|
* built on a derived value. A required option the merge leaves `undefined`
|
|
26
33
|
* throws at collection.
|
|
27
34
|
* - `rpc_success_fixtures` / `rpc_skip_methods` / `rpc_input_overrides` go to
|
|
28
|
-
* the standard bundle's RPC round-trip
|
|
35
|
+
* the standard bundle's RPC round-trip; `rpc_input_overrides` also seeds
|
|
36
|
+
* `rpc_adversarial`'s params cases (each override is the valid base they
|
|
37
|
+
* break one field of). A key naming a method on neither the declared surface
|
|
38
|
+
* nor `live_rpc_endpoints` throws at collection.
|
|
29
39
|
* - `ws_required_roles` names the roles the backend's WS upgrade requires, so the
|
|
30
40
|
* suites that open sockets for accounts they create give them those roles.
|
|
31
41
|
* - `suite_roles` names the roles the role-shaped suites use when the backend's
|
|
@@ -41,6 +51,15 @@ import '../assert_dev_env.js';
|
|
|
41
51
|
* config's `SECRET_FUZ_COOKIE_KEYS`), else from `overrides`; when neither has
|
|
42
52
|
* it, the call throws naming the suite — provide it or exclude the suite.
|
|
43
53
|
*
|
|
54
|
+
* **Backdoors.** The backend's `capabilities.testing_backdoors` must declare
|
|
55
|
+
* `SPINE_SUITES_REQUIRED_BACKDOORS` (the per-test reset and the audit
|
|
56
|
+
* barrier), and `_testing_put_fact` when it declares `fact_serving`; the call
|
|
57
|
+
* throws otherwise. A suite every case of which drives another backdoor
|
|
58
|
+
* (`credential_deadline`, `origin_conformance`, `ws_outbound_overflow`) skips
|
|
59
|
+
* itself on a backend not declaring it, shown like an exclude with a reason
|
|
60
|
+
* naming the backdoor — so an exclude, override or `exclude_cases` entry for
|
|
61
|
+
* it is refused as dead.
|
|
62
|
+
*
|
|
44
63
|
* **Not in the one call** (`STANDALONE_CROSS_SUITES`, with the reasons): the
|
|
45
64
|
* suites that need two handles (the differential), a backend spawned with live
|
|
46
65
|
* limiters (`login_security`, `ws_action_rate_limit` — the standard suites would
|
|
@@ -48,11 +67,13 @@ import '../assert_dev_env.js';
|
|
|
48
67
|
* cases. Each keeps its own entry point.
|
|
49
68
|
*
|
|
50
69
|
* Suites are registered without a wrapping `describe`, so their test names are
|
|
51
|
-
* the same as when each is called on its own
|
|
70
|
+
* the same as when each is called on its own — and an `exclude_cases` path is
|
|
71
|
+
* the name the reporter prints after the file and any `describe` wrapping the
|
|
72
|
+
* call.
|
|
52
73
|
*
|
|
53
74
|
* @module
|
|
54
75
|
*/
|
|
55
|
-
import { describe, test } from 'vitest';
|
|
76
|
+
import { beforeAll, beforeEach, describe, test, TestRunner } from 'vitest';
|
|
56
77
|
import { ROLE_KEEPER, ROLE_ADMIN } from '../../auth/role_schema.js';
|
|
57
78
|
import { resolve_rpc_endpoints_for_setup } from '../rpc_helpers.js';
|
|
58
79
|
import { describe_account_lifecycle_cross_tests } from './account_lifecycle.js';
|
|
@@ -161,6 +182,16 @@ export const STANDALONE_CROSS_SUITES = {
|
|
|
161
182
|
ws_action_rate_limit: 'needs a backend spawned with the action limiters enabled, which the standard suites would exhaust',
|
|
162
183
|
conformance_table: "a runner over the consumer's own cases, not a suite"
|
|
163
184
|
};
|
|
185
|
+
/**
|
|
186
|
+
* The backdoors `describe_spine_cross_suites` requires of every backend, since
|
|
187
|
+
* the suites share them: `_testing_reset` is every `setup_test`'s per-test
|
|
188
|
+
* reset, and `_testing_drain_effects` the barrier every audit read waits on. A
|
|
189
|
+
* backend whose `capabilities.testing_backdoors` lacks one fails at collection.
|
|
190
|
+
*/
|
|
191
|
+
export const SPINE_SUITES_REQUIRED_BACKDOORS = Object.freeze([
|
|
192
|
+
'_testing_reset',
|
|
193
|
+
'_testing_drain_effects'
|
|
194
|
+
]);
|
|
164
195
|
/**
|
|
165
196
|
* The suite options a handle's `config` supplies — the fields most cross
|
|
166
197
|
* suites take beside `setup_test`. For a suite called on its own:
|
|
@@ -268,7 +299,8 @@ const SUITE_ENTRIES = {
|
|
|
268
299
|
ws_account_roles: c.options.ws_required_roles
|
|
269
300
|
}),
|
|
270
301
|
describe: describe_credential_deadline_cross_tests,
|
|
271
|
-
required: { setup_test: true, capabilities: true, base_url: true, ws_path: true }
|
|
302
|
+
required: { setup_test: true, capabilities: true, base_url: true, ws_path: true },
|
|
303
|
+
backdoors: ['_testing_shorten_credential_expiry']
|
|
272
304
|
},
|
|
273
305
|
credential_header_robustness: {
|
|
274
306
|
derive: (c) => ({
|
|
@@ -301,7 +333,8 @@ const SUITE_ENTRIES = {
|
|
|
301
333
|
origin_conformance: {
|
|
302
334
|
derive: (c) => ({ setup_test: c.setup(), rpc_path: c.config.rpc_path }),
|
|
303
335
|
describe: describe_origin_conformance_cross_tests,
|
|
304
|
-
required: { setup_test: true }
|
|
336
|
+
required: { setup_test: true },
|
|
337
|
+
backdoors: ['_testing_origin_check']
|
|
305
338
|
},
|
|
306
339
|
origin_scope: {
|
|
307
340
|
derive: (c) => ({
|
|
@@ -385,7 +418,8 @@ const SUITE_ENTRIES = {
|
|
|
385
418
|
surface_source: c.options.surface_source,
|
|
386
419
|
live_rpc_endpoints: c.options.live_rpc_endpoints &&
|
|
387
420
|
resolve_rpc_endpoints_for_setup(c.options.live_rpc_endpoints, c.options.session_options),
|
|
388
|
-
rpc_path: c.config.rpc_path
|
|
421
|
+
rpc_path: c.config.rpc_path,
|
|
422
|
+
input_overrides: c.options.rpc_input_overrides
|
|
389
423
|
}),
|
|
390
424
|
describe: describe_rpc_adversarial_cross_tests,
|
|
391
425
|
required: { setup_test: true, surface_source: true }
|
|
@@ -451,9 +485,9 @@ const SUITE_ENTRIES = {
|
|
|
451
485
|
}
|
|
452
486
|
},
|
|
453
487
|
testing_backdoor: {
|
|
454
|
-
derive: (c) => ({
|
|
488
|
+
derive: (c) => ({ ...rpc_gated(c), ws: c.ws }),
|
|
455
489
|
describe: describe_testing_backdoor_cross_tests,
|
|
456
|
-
required: { setup_test: true }
|
|
490
|
+
required: { setup_test: true, capabilities: true }
|
|
457
491
|
},
|
|
458
492
|
token_lifetime: {
|
|
459
493
|
derive: (c) => ({ setup_test: c.setup(), rpc_path: c.config.rpc_path }),
|
|
@@ -506,7 +540,8 @@ const SUITE_ENTRIES = {
|
|
|
506
540
|
rpc_path: c.config.rpc_path
|
|
507
541
|
}),
|
|
508
542
|
describe: describe_ws_outbound_overflow_cross_tests,
|
|
509
|
-
required: { setup_test: true, capabilities: true, base_url: true, ws_path: true }
|
|
543
|
+
required: { setup_test: true, capabilities: true, base_url: true, ws_path: true },
|
|
544
|
+
backdoors: ['_testing_flood_notifications']
|
|
510
545
|
},
|
|
511
546
|
ws_role_gated: {
|
|
512
547
|
// the reference spines' role-gated endpoint; a backend mounting its own
|
|
@@ -553,12 +588,62 @@ const merge_setup_options = (base, seed) => ({
|
|
|
553
588
|
extra_accounts: [...(base?.extra_accounts ?? []), ...(seed?.extra_accounts ?? [])],
|
|
554
589
|
extra_actors: [...(base?.extra_actors ?? []), ...(seed?.extra_actors ?? [])]
|
|
555
590
|
});
|
|
591
|
+
/**
|
|
592
|
+
* The backdoors every case of `name` drives beyond
|
|
593
|
+
* `SPINE_SUITES_REQUIRED_BACKDOORS` — a backend not declaring one skips the
|
|
594
|
+
* suite.
|
|
595
|
+
*
|
|
596
|
+
* @param name - the suite
|
|
597
|
+
* @returns its `SuiteEntry.backdoors`, empty for a suite needing none
|
|
598
|
+
* @internal
|
|
599
|
+
*/
|
|
600
|
+
export const get_spine_suite_backdoors = (name) => SUITE_ENTRIES[name].backdoors ?? [];
|
|
556
601
|
const is_suite_name = (name) => SUITE_NAMES.includes(name);
|
|
557
602
|
/**
|
|
558
|
-
*
|
|
559
|
-
*
|
|
603
|
+
* Each suite whose backdoors `declared` lacks, with the generated reason it is
|
|
604
|
+
* skipped — the suites whose every case drives a backdoor (`SuiteEntry.backdoors`).
|
|
560
605
|
*/
|
|
561
|
-
const
|
|
606
|
+
const to_backdoor_skips = (declared) => {
|
|
607
|
+
const skips = new Map();
|
|
608
|
+
for (const name of SUITE_NAMES) {
|
|
609
|
+
const missing = get_spine_suite_backdoors(name).filter((m) => !declared.includes(m));
|
|
610
|
+
if (missing.length > 0) {
|
|
611
|
+
skips.set(name, `needs ${missing.map((m) => `\`${m}\``).join(', ')}, which capabilities.testing_backdoors doesn't declare`);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
return skips;
|
|
615
|
+
};
|
|
616
|
+
/**
|
|
617
|
+
* Refuse an exclude with an empty reason, an unknown suite name, a suite both
|
|
618
|
+
* excluded and overridden, a backend missing a backdoor the suites share, an
|
|
619
|
+
* exclude or override of a suite that skips itself for an undeclared
|
|
620
|
+
* backdoor, any exclusion of `testing_backdoor`, and an `exclude_cases` entry
|
|
621
|
+
* naming a suite the call doesn't run or carrying no reason — before anything
|
|
622
|
+
* is registered.
|
|
623
|
+
*/
|
|
624
|
+
const validate_spine_cross_suites_options = (options, declared, backdoor_skips, capabilities) => {
|
|
625
|
+
if (options.rpc_input_overrides?.size) {
|
|
626
|
+
// a key the round-trip (the declared surface) and `rpc_adversarial` (that
|
|
627
|
+
// and the live mount) both lack would be ignored silently — a typo
|
|
628
|
+
const methods = new Set();
|
|
629
|
+
for (const endpoint of options.surface_source.surface.rpc_endpoints) {
|
|
630
|
+
for (const method of endpoint.methods)
|
|
631
|
+
methods.add(method.name);
|
|
632
|
+
}
|
|
633
|
+
if (options.live_rpc_endpoints) {
|
|
634
|
+
const live = resolve_rpc_endpoints_for_setup(options.live_rpc_endpoints, options.session_options);
|
|
635
|
+
for (const endpoint of live) {
|
|
636
|
+
for (const action of endpoint.actions)
|
|
637
|
+
methods.add(action.spec.method);
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
for (const method of options.rpc_input_overrides.keys()) {
|
|
641
|
+
if (!methods.has(method)) {
|
|
642
|
+
throw new Error(`describe_spine_cross_suites: rpc_input_overrides names '${method}', ` +
|
|
643
|
+
`a method on neither the declared surface nor the live mount`);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
}
|
|
562
647
|
for (const [name, reason] of Object.entries(options.exclude ?? {})) {
|
|
563
648
|
if (!is_suite_name(name)) {
|
|
564
649
|
throw new Error(`describe_spine_cross_suites: exclude names unknown suite '${name}'`);
|
|
@@ -569,11 +654,58 @@ const validate_spine_cross_suites_options = (options) => {
|
|
|
569
654
|
if (options.overrides?.[name] !== undefined) {
|
|
570
655
|
throw new Error(`describe_spine_cross_suites: '${name}' is both excluded and overridden`);
|
|
571
656
|
}
|
|
657
|
+
if (name === 'testing_backdoor') {
|
|
658
|
+
throw new Error("describe_spine_cross_suites: 'testing_backdoor' can't be excluded — it checks the " +
|
|
659
|
+
'capabilities.testing_backdoors declaration the other suites gate on');
|
|
660
|
+
}
|
|
661
|
+
const skip = backdoor_skips.get(name);
|
|
662
|
+
if (skip !== undefined) {
|
|
663
|
+
throw new Error(`describe_spine_cross_suites: exclude '${name}' is redundant — the suite skips itself (${skip})`);
|
|
664
|
+
}
|
|
572
665
|
}
|
|
573
666
|
for (const name of Object.keys(options.overrides ?? {})) {
|
|
574
667
|
if (!is_suite_name(name)) {
|
|
575
668
|
throw new Error(`describe_spine_cross_suites: overrides names unknown suite '${name}'`);
|
|
576
669
|
}
|
|
670
|
+
const skip = backdoor_skips.get(name);
|
|
671
|
+
if (skip !== undefined) {
|
|
672
|
+
throw new Error(`describe_spine_cross_suites: overrides names '${name}', which skips itself (${skip})`);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
for (const [name, cases] of Object.entries(options.exclude_cases ?? {})) {
|
|
676
|
+
if (!is_suite_name(name)) {
|
|
677
|
+
throw new Error(`describe_spine_cross_suites: exclude_cases names unknown suite '${name}'`);
|
|
678
|
+
}
|
|
679
|
+
if (options.exclude?.[name] !== undefined) {
|
|
680
|
+
throw new Error(`describe_spine_cross_suites: '${name}' is excluded, so its exclude_cases entries name nothing`);
|
|
681
|
+
}
|
|
682
|
+
if (name === 'testing_backdoor') {
|
|
683
|
+
throw new Error("describe_spine_cross_suites: exclude_cases can't name 'testing_backdoor' — it checks the " +
|
|
684
|
+
'capabilities.testing_backdoors declaration the other suites gate on, and a declared ' +
|
|
685
|
+
'backdoor failing its credential row is a bug, not a case to skip');
|
|
686
|
+
}
|
|
687
|
+
const skip = backdoor_skips.get(name);
|
|
688
|
+
if (skip !== undefined) {
|
|
689
|
+
throw new Error(`describe_spine_cross_suites: exclude_cases names '${name}', which skips itself (${skip})`);
|
|
690
|
+
}
|
|
691
|
+
const entries = Object.entries(cases ?? {});
|
|
692
|
+
if (entries.length === 0) {
|
|
693
|
+
throw new Error(`describe_spine_cross_suites: exclude_cases '${name}' names no test`);
|
|
694
|
+
}
|
|
695
|
+
for (const [test_name, reason] of entries) {
|
|
696
|
+
if (typeof reason !== 'string' || reason.trim() === '') {
|
|
697
|
+
throw new Error(`describe_spine_cross_suites: exclude_cases '${name}' › '${test_name}' needs a reason`);
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
const missing = SPINE_SUITES_REQUIRED_BACKDOORS.filter((m) => !declared.includes(m));
|
|
702
|
+
if (missing.length > 0) {
|
|
703
|
+
throw new Error(`describe_spine_cross_suites: capabilities.testing_backdoors must declare ${missing.join(', ')} ` +
|
|
704
|
+
'— every suite resets through _testing_reset and reads audit rows behind _testing_drain_effects');
|
|
705
|
+
}
|
|
706
|
+
if (capabilities.fact_serving && !declared.includes('_testing_put_fact')) {
|
|
707
|
+
throw new Error('describe_spine_cross_suites: capabilities.fact_serving needs _testing_put_fact in ' +
|
|
708
|
+
'capabilities.testing_backdoors — the fact suites seed through it');
|
|
577
709
|
}
|
|
578
710
|
};
|
|
579
711
|
const run_suite = (name, context) => {
|
|
@@ -589,21 +721,146 @@ const run_suite = (name, context) => {
|
|
|
589
721
|
`nor the override gives — pass \`overrides.${name}\` with it or exclude '${name}' with a reason`);
|
|
590
722
|
}
|
|
591
723
|
}
|
|
724
|
+
// the backdoor suite checks the declaration the gating read, so an override
|
|
725
|
+
// can't hand it another; it reads nothing else of `capabilities`, so a copy
|
|
726
|
+
// keeping the list passes
|
|
727
|
+
if (name === 'testing_backdoor') {
|
|
728
|
+
const checked = suite_options.capabilities
|
|
729
|
+
.testing_backdoors;
|
|
730
|
+
const declared = context.config.capabilities.testing_backdoors;
|
|
731
|
+
// the same entries, each as often, in any order
|
|
732
|
+
if ([...checked].sort().join(' ') !== [...declared].sort().join(' ')) {
|
|
733
|
+
throw new Error("describe_spine_cross_suites: overrides can't change 'testing_backdoor' " +
|
|
734
|
+
'capabilities.testing_backdoors — it checks the declaration the other suites gate on');
|
|
735
|
+
}
|
|
736
|
+
}
|
|
592
737
|
entry.describe(suite_options);
|
|
593
738
|
};
|
|
739
|
+
/**
|
|
740
|
+
* Where `task` sits below `root`: its name path (its describe titles and its
|
|
741
|
+
* name) and its top-level ancestor, one of `root`'s own tasks — or `null`
|
|
742
|
+
* outside `root`.
|
|
743
|
+
*/
|
|
744
|
+
const locate_task = (task, root) => {
|
|
745
|
+
const path = [];
|
|
746
|
+
let current = task;
|
|
747
|
+
for (;;) {
|
|
748
|
+
path.unshift(current.name);
|
|
749
|
+
// a test or describe at a file's top level has no `suite`, only its `file`
|
|
750
|
+
const parent = current.suite ?? current.file;
|
|
751
|
+
if (parent === root)
|
|
752
|
+
return { path, top: current };
|
|
753
|
+
if (!parent || parent === current)
|
|
754
|
+
return null;
|
|
755
|
+
current = parent;
|
|
756
|
+
}
|
|
757
|
+
};
|
|
758
|
+
/** Every test under `task`, as name paths starting with `prefix`. */
|
|
759
|
+
const collect_test_paths = (task, prefix, out) => {
|
|
760
|
+
const path = [...prefix, task.name];
|
|
761
|
+
if (task.type === 'suite') {
|
|
762
|
+
for (const child of task.tasks)
|
|
763
|
+
collect_test_paths(child, path, out);
|
|
764
|
+
}
|
|
765
|
+
else {
|
|
766
|
+
out.add(path.join(' > '));
|
|
767
|
+
}
|
|
768
|
+
};
|
|
769
|
+
/**
|
|
770
|
+
* Check every `exclude_cases` entry against the test paths each suite
|
|
771
|
+
* collected — the static half of the case exclusions, which the closing test
|
|
772
|
+
* `register_spine_case_exclusions` registers runs.
|
|
773
|
+
*
|
|
774
|
+
* @param exclude_cases - the entries, by suite
|
|
775
|
+
* @param collected - each run suite's collected test paths
|
|
776
|
+
* @throws Error - naming every entry whose suite collected no test at its path
|
|
777
|
+
* @internal
|
|
778
|
+
*/
|
|
779
|
+
export const check_spine_case_exclusions = (exclude_cases, collected) => {
|
|
780
|
+
const dead = [];
|
|
781
|
+
for (const [name, cases] of Object.entries(exclude_cases)) {
|
|
782
|
+
const paths = collected.get(name);
|
|
783
|
+
for (const test_name of Object.keys(cases ?? {})) {
|
|
784
|
+
if (!paths?.has(test_name))
|
|
785
|
+
dead.push(`${name} › ${test_name}`);
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
if (dead.length > 0) {
|
|
789
|
+
throw new Error(`exclude_cases entries naming no collected test of their suite (a renamed or removed ` +
|
|
790
|
+
`test, or a path missing a describe title): ${dead.join('; ')}`);
|
|
791
|
+
}
|
|
792
|
+
};
|
|
793
|
+
/**
|
|
794
|
+
* Skip the `exclude_cases` tests, and fail on an entry no collected test has.
|
|
795
|
+
* `describe_spine_cross_suites` calls it after registering the suites, in the
|
|
796
|
+
* same suite.
|
|
797
|
+
*
|
|
798
|
+
* One `beforeEach` on the calling suite: it finds the test's top-level task
|
|
799
|
+
* among the ranges the suites registered, and calls `ctx.skip(reason)` when
|
|
800
|
+
* that suite's entries name the test's path — so the suite files stay as they
|
|
801
|
+
* are, and the test shows as skipped with its reason. A closing test holds
|
|
802
|
+
* every entry to a test its suite collected (`check_spine_case_exclusions`;
|
|
803
|
+
* the paths are read at collection, so a filtered run still checks them).
|
|
804
|
+
* A skipped test's own `beforeEach` hooks don't run, but its `afterEach`
|
|
805
|
+
* hooks and its suite's `beforeAll` still do.
|
|
806
|
+
*
|
|
807
|
+
* @param exclude_cases - the entries, by suite
|
|
808
|
+
* @param ranges - each run suite's top-level tasks in the calling suite
|
|
809
|
+
* @internal
|
|
810
|
+
*/
|
|
811
|
+
export const register_spine_case_exclusions = (exclude_cases, ranges) => {
|
|
812
|
+
let root;
|
|
813
|
+
const collected = new Map();
|
|
814
|
+
const suite_of = (index) => ranges.find((r) => index >= r.start && index < r.end)?.name;
|
|
815
|
+
// vitest passes the suite a hook is registered on as the second argument,
|
|
816
|
+
// and requires the first be destructured
|
|
817
|
+
// eslint-disable-next-line no-empty-pattern
|
|
818
|
+
beforeAll(({}, suite) => {
|
|
819
|
+
root = suite;
|
|
820
|
+
for (const range of ranges) {
|
|
821
|
+
const paths = new Set();
|
|
822
|
+
for (const task of suite.tasks.slice(range.start, range.end)) {
|
|
823
|
+
collect_test_paths(task, [], paths);
|
|
824
|
+
}
|
|
825
|
+
collected.set(range.name, paths);
|
|
826
|
+
}
|
|
827
|
+
});
|
|
828
|
+
beforeEach((ctx) => {
|
|
829
|
+
if (!root)
|
|
830
|
+
return;
|
|
831
|
+
const located = locate_task(ctx.task, root);
|
|
832
|
+
if (!located)
|
|
833
|
+
return;
|
|
834
|
+
const name = suite_of(root.tasks.indexOf(located.top));
|
|
835
|
+
if (name === undefined)
|
|
836
|
+
return;
|
|
837
|
+
const reason = exclude_cases[name]?.[located.path.join(' > ')];
|
|
838
|
+
if (reason !== undefined)
|
|
839
|
+
ctx.skip(`excluded on this backend: ${reason}`);
|
|
840
|
+
});
|
|
841
|
+
test('spine cross suites: every exclude_cases entry names a collected test', () => {
|
|
842
|
+
check_spine_case_exclusions(exclude_cases, collected);
|
|
843
|
+
});
|
|
844
|
+
};
|
|
594
845
|
/**
|
|
595
846
|
* Run every shipped single-backend cross suite against one spawned backend —
|
|
596
847
|
* see the module doc for what the options add and what stays outside.
|
|
597
848
|
*
|
|
598
849
|
* @param handle - the backend, as `inject_backend_handle()` returns it
|
|
599
|
-
* @param options - the declared surface, plus excludes and overrides
|
|
850
|
+
* @param options - the declared surface, plus excludes, case exclusions and overrides
|
|
600
851
|
* @throws Error - on an exclude with no reason, an unknown suite name, a suite
|
|
601
|
-
* both excluded and overridden,
|
|
602
|
-
*
|
|
852
|
+
* both excluded and overridden, an excluded `testing_backdoor` (or one of
|
|
853
|
+
* its cases, or an override changing its `capabilities.testing_backdoors`), an exclude,
|
|
854
|
+
* override or `exclude_cases` entry for a suite that skips itself or isn't
|
|
855
|
+
* run, a backend not declaring `SPINE_SUITES_REQUIRED_BACKDOORS` (or
|
|
856
|
+
* `_testing_put_fact` with `fact_serving`), or a suite missing an input the
|
|
857
|
+
* handle doesn't carry
|
|
603
858
|
*/
|
|
604
859
|
export const describe_spine_cross_suites = (handle, options) => {
|
|
605
|
-
validate_spine_cross_suites_options(options);
|
|
606
860
|
const config = to_cross_suite_options(handle);
|
|
861
|
+
const declared = config.capabilities.testing_backdoors;
|
|
862
|
+
const backdoor_skips = to_backdoor_skips(declared);
|
|
863
|
+
validate_spine_cross_suites_options(options, declared, backdoor_skips, config.capabilities);
|
|
607
864
|
const context = {
|
|
608
865
|
handle,
|
|
609
866
|
config,
|
|
@@ -611,15 +868,29 @@ export const describe_spine_cross_suites = (handle, options) => {
|
|
|
611
868
|
setup: (seed) => default_cross_process_setup(handle, merge_setup_options(options.setup, seed)),
|
|
612
869
|
ws: config.capabilities.ws ? { base_url: config.base_url, ws_path: config.ws_path } : undefined
|
|
613
870
|
};
|
|
614
|
-
|
|
871
|
+
// each suite's top-level tasks, by index, so the case exclusions know which
|
|
872
|
+
// suite a test belongs to
|
|
873
|
+
const collector = TestRunner.getCurrentSuite();
|
|
874
|
+
const ranges = [];
|
|
875
|
+
const skipped = Object.entries(options.exclude ?? {});
|
|
615
876
|
for (const name of SUITE_NAMES) {
|
|
616
877
|
if (options.exclude?.[name] !== undefined)
|
|
617
878
|
continue;
|
|
879
|
+
const skip = backdoor_skips.get(name);
|
|
880
|
+
if (skip !== undefined) {
|
|
881
|
+
skipped.push([name, skip]);
|
|
882
|
+
continue;
|
|
883
|
+
}
|
|
884
|
+
const start = collector.tasks.length;
|
|
618
885
|
run_suite(name, context);
|
|
886
|
+
ranges.push({ name, start, end: collector.tasks.length });
|
|
887
|
+
}
|
|
888
|
+
if (Object.keys(options.exclude_cases ?? {}).length > 0) {
|
|
889
|
+
register_spine_case_exclusions(options.exclude_cases, ranges);
|
|
619
890
|
}
|
|
620
|
-
if (
|
|
891
|
+
if (skipped.length > 0) {
|
|
621
892
|
describe('spine cross suites excluded on this backend', () => {
|
|
622
|
-
for (const [name, reason] of
|
|
893
|
+
for (const [name, reason] of skipped)
|
|
623
894
|
test.skip(`${name}: ${reason}`, () => { });
|
|
624
895
|
});
|
|
625
896
|
}
|
|
@@ -13,6 +13,21 @@ export declare const TESTING_ACTION_AUTH: {
|
|
|
13
13
|
readonly actor: "none";
|
|
14
14
|
readonly credential_types: readonly ["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 declare const TESTING_BACKDOOR_METHODS: readonly ["_testing_reset", "_testing_drain_effects", "_testing_mint_session", "_testing_put_fact", "_testing_flood_notifications", "_testing_schema_snapshot", "_testing_migration_tracker", "_testing_action_manifest", "_testing_origin_check", "_testing_shorten_credential_expiry"];
|
|
29
|
+
/** A `_testing_*` backdoor the shipped cross suites know — see `TESTING_BACKDOOR_METHODS`. */
|
|
30
|
+
export type TestingBackdoorMethod = (typeof TESTING_BACKDOOR_METHODS)[number];
|
|
16
31
|
/** RPC endpoint mount path — matches the binary's `/api/rpc`. */
|
|
17
32
|
export declare const SPINE_RPC_PATH = "/api/rpc";
|
|
18
33
|
/** Ungated WebSocket endpoint mount path — matches the binaries' `/api/ws`. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spine_surface_constants.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/spine_surface_constants.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA4B9B;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB;;;;CAIF,CAAC;AAE/B,iEAAiE;AACjE,eAAO,MAAM,cAAc,aAAa,CAAC;AAEzC,+EAA+E;AAC/E,eAAO,MAAM,aAAa,YAAY,CAAC;AAEvC;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,iBAAiB,CAAC;AAExD,wBAAwB;AACxB,eAAO,MAAM,wBAAwB,uBAAuB,CAAC;AAE7D,yBAAyB;AACzB,eAAO,MAAM,yBAAyB,wBAAwB,CAAC;AAE/D,kCAAkC;AAClC,eAAO,MAAM,2BAA2B,0BAA0B,CAAC;AAEnE,iCAAiC;AACjC,eAAO,MAAM,yBAAyB,wBAAwB,CAAC;AAE/D,yBAAyB;AACzB,eAAO,MAAM,yBAAyB,wBAAwB,CAAC;AAE/D,yEAAyE;AACzE,eAAO,MAAM,4BAA4B,2BAA2B,CAAC;AAErE;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,4BAA4B,CAAC;AAExD;;;;;;;GAOG;AACH,eAAO,MAAM,8BAA8B,QAAc,CAAC;AAE1D;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,gBAAgB,CAAC;AAEpD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,sBAAsB,gBAAgB,CAAC;AAEpD;;;;;;;;;GASG;AACH,eAAO,MAAM,wBAAwB,kBAAkB,CAAC;AAExD;;;;;;GAMG;AACH,eAAO,MAAM,yBAAyB,EAAE,aAAa,CAAC,MAAM,CAG1D,CAAC;AAEH;;;;;;;;;;GAUG;AACH,eAAO,MAAM,yBAAyB,EAAE,GAAwD,CAAC;AAEjG;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,iCAAiC,CAAC;AAE3E;;;;;;;;GAQG;AACH,eAAO,MAAM,6BAA6B,kCAAkC,CAAC;AAE7E;;;;;;GAMG;AACH,eAAO,MAAM,kCAAkC,uCAAuC,CAAC;AAEvF;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,6BAA6B,CAAC"}
|
|
1
|
+
{"version":3,"file":"spine_surface_constants.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/spine_surface_constants.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA4B9B;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB;;;;CAIF,CAAC;AAE/B;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,wBAAwB,0RAW3B,CAAC;AAEX,8FAA8F;AAC9F,MAAM,MAAM,qBAAqB,GAAG,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE9E,iEAAiE;AACjE,eAAO,MAAM,cAAc,aAAa,CAAC;AAEzC,+EAA+E;AAC/E,eAAO,MAAM,aAAa,YAAY,CAAC;AAEvC;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,iBAAiB,CAAC;AAExD,wBAAwB;AACxB,eAAO,MAAM,wBAAwB,uBAAuB,CAAC;AAE7D,yBAAyB;AACzB,eAAO,MAAM,yBAAyB,wBAAwB,CAAC;AAE/D,kCAAkC;AAClC,eAAO,MAAM,2BAA2B,0BAA0B,CAAC;AAEnE,iCAAiC;AACjC,eAAO,MAAM,yBAAyB,wBAAwB,CAAC;AAE/D,yBAAyB;AACzB,eAAO,MAAM,yBAAyB,wBAAwB,CAAC;AAE/D,yEAAyE;AACzE,eAAO,MAAM,4BAA4B,2BAA2B,CAAC;AAErE;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,4BAA4B,CAAC;AAExD;;;;;;;GAOG;AACH,eAAO,MAAM,8BAA8B,QAAc,CAAC;AAE1D;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,gBAAgB,CAAC;AAEpD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,sBAAsB,gBAAgB,CAAC;AAEpD;;;;;;;;;GASG;AACH,eAAO,MAAM,wBAAwB,kBAAkB,CAAC;AAExD;;;;;;GAMG;AACH,eAAO,MAAM,yBAAyB,EAAE,aAAa,CAAC,MAAM,CAG1D,CAAC;AAEH;;;;;;;;;;GAUG;AACH,eAAO,MAAM,yBAAyB,EAAE,GAAwD,CAAC;AAEjG;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,iCAAiC,CAAC;AAE3E;;;;;;;;GAQG;AACH,eAAO,MAAM,6BAA6B,kCAAkC,CAAC;AAE7E;;;;;;GAMG;AACH,eAAO,MAAM,kCAAkC,uCAAuC,CAAC;AAEvF;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,6BAA6B,CAAC"}
|