@fuzdev/fuz_app 0.97.0 → 0.98.1

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.
Files changed (145) hide show
  1. package/dist/actions/CLAUDE.md +57 -23
  2. package/dist/actions/action_bridge.d.ts.map +1 -1
  3. package/dist/actions/action_codegen.d.ts +17 -1
  4. package/dist/actions/action_codegen.d.ts.map +1 -1
  5. package/dist/actions/action_codegen.js +38 -14
  6. package/dist/actions/{action_peer.d.ts → action_dispatcher.d.ts} +12 -12
  7. package/dist/actions/action_dispatcher.d.ts.map +1 -0
  8. package/dist/actions/{action_peer.js → action_dispatcher.js} +2 -2
  9. package/dist/actions/action_event.d.ts.map +1 -1
  10. package/dist/actions/action_rpc.d.ts +9 -0
  11. package/dist/actions/action_rpc.d.ts.map +1 -1
  12. package/dist/actions/broadcast_api.d.ts +2 -2
  13. package/dist/actions/broadcast_api.d.ts.map +1 -1
  14. package/dist/actions/compile_action_registry.d.ts.map +1 -1
  15. package/dist/actions/frontend_rpc_client.d.ts +3 -3
  16. package/dist/actions/frontend_rpc_client.d.ts.map +1 -1
  17. package/dist/actions/frontend_rpc_client.js +3 -3
  18. package/dist/actions/peer_ping.d.ts +147 -0
  19. package/dist/actions/peer_ping.d.ts.map +1 -0
  20. package/dist/actions/peer_ping.js +189 -0
  21. package/dist/actions/peer_request.d.ts +158 -0
  22. package/dist/actions/peer_request.d.ts.map +1 -0
  23. package/dist/actions/peer_request.js +167 -0
  24. package/dist/actions/perform_action.d.ts +8 -0
  25. package/dist/actions/perform_action.d.ts.map +1 -1
  26. package/dist/actions/perform_action.js +2 -1
  27. package/dist/actions/protocol.d.ts +3 -3
  28. package/dist/actions/protocol.d.ts.map +1 -1
  29. package/dist/actions/protocol.js +9 -4
  30. package/dist/actions/register_action_ws.d.ts.map +1 -1
  31. package/dist/actions/register_action_ws.js +28 -1
  32. package/dist/actions/rpc_client.d.ts +4 -4
  33. package/dist/actions/rpc_client.d.ts.map +1 -1
  34. package/dist/actions/socket.svelte.d.ts.map +1 -1
  35. package/dist/actions/transports.d.ts +1 -1
  36. package/dist/actions/transports_http.d.ts.map +1 -1
  37. package/dist/actions/transports_ws.d.ts +12 -5
  38. package/dist/actions/transports_ws.d.ts.map +1 -1
  39. package/dist/actions/transports_ws.js +36 -6
  40. package/dist/actions/transports_ws_backend.d.ts +34 -1
  41. package/dist/actions/transports_ws_backend.d.ts.map +1 -1
  42. package/dist/actions/transports_ws_backend.js +62 -5
  43. package/dist/auth/CLAUDE.md +12 -12
  44. package/dist/auth/actor_lookup_action_specs.d.ts.map +1 -1
  45. package/dist/auth/actor_search_action_specs.d.ts.map +1 -1
  46. package/dist/auth/admin_action_specs.d.ts.map +1 -1
  47. package/dist/auth/admin_actions.d.ts.map +1 -1
  48. package/dist/auth/audit_log_queries.d.ts.map +1 -1
  49. package/dist/auth/audit_log_schema.d.ts.map +1 -1
  50. package/dist/auth/bootstrap_routes.d.ts.map +1 -1
  51. package/dist/auth/role_grant_queries.d.ts +31 -12
  52. package/dist/auth/role_grant_queries.d.ts.map +1 -1
  53. package/dist/auth/role_grant_queries.js +36 -12
  54. package/dist/auth/role_schema.d.ts.map +1 -1
  55. package/dist/auth/self_service_role_actions.d.ts.map +1 -1
  56. package/dist/db/create_db.d.ts.map +1 -1
  57. package/dist/db/fact_store.d.ts.map +1 -1
  58. package/dist/db/status.d.ts.map +1 -1
  59. package/dist/http/auth_shape.d.ts.map +1 -1
  60. package/dist/http/db_routes.d.ts.map +1 -1
  61. package/dist/http/jsonrpc_helpers.d.ts +1 -1
  62. package/dist/http/jsonrpc_helpers.js +1 -1
  63. package/dist/rate_limiter.d.ts.map +1 -1
  64. package/dist/rate_limiter.js +11 -0
  65. package/dist/server/app_backend.d.ts.map +1 -1
  66. package/dist/server/app_server.d.ts.map +1 -1
  67. package/dist/server/serve_fact_route.d.ts.map +1 -1
  68. package/dist/server/serve_fact_route.js +7 -4
  69. package/dist/testing/CLAUDE.md +18 -15
  70. package/dist/testing/admin_integration.d.ts.map +1 -1
  71. package/dist/testing/adversarial_input.d.ts.map +1 -1
  72. package/dist/testing/adversarial_input.js +3 -1
  73. package/dist/testing/attack_surface.d.ts.map +1 -1
  74. package/dist/testing/audit_completeness.d.ts.map +1 -1
  75. package/dist/testing/cross_backend/action_manifest.d.ts +7 -7
  76. package/dist/testing/cross_backend/action_manifest.js +7 -7
  77. package/dist/testing/cross_backend/action_manifest_parity.d.ts.map +1 -1
  78. package/dist/testing/cross_backend/capabilities.d.ts +15 -12
  79. package/dist/testing/cross_backend/capabilities.d.ts.map +1 -1
  80. package/dist/testing/cross_backend/capabilities.js +4 -4
  81. package/dist/testing/cross_backend/cell_cross_helpers.d.ts.map +1 -1
  82. package/dist/testing/cross_backend/conformance_case.d.ts +2 -0
  83. package/dist/testing/cross_backend/conformance_case.d.ts.map +1 -1
  84. package/dist/testing/cross_backend/conformance_case.js +13 -0
  85. package/dist/testing/cross_backend/conformance_table.d.ts.map +1 -1
  86. package/dist/testing/cross_backend/conformance_table.js +32 -3
  87. package/dist/testing/cross_backend/cookie_attributes.d.ts +20 -0
  88. package/dist/testing/cross_backend/cookie_attributes.d.ts.map +1 -0
  89. package/dist/testing/cross_backend/cookie_attributes.js +158 -0
  90. package/dist/testing/cross_backend/credential_header_robustness.d.ts +12 -0
  91. package/dist/testing/cross_backend/credential_header_robustness.d.ts.map +1 -0
  92. package/dist/testing/cross_backend/credential_header_robustness.js +179 -0
  93. package/dist/testing/cross_backend/default_backend_configs.d.ts.map +1 -1
  94. package/dist/testing/cross_backend/default_backend_configs.js +5 -3
  95. package/dist/testing/cross_backend/full_spine_mount.d.ts.map +1 -1
  96. package/dist/testing/cross_backend/full_spine_mount.js +7 -0
  97. package/dist/testing/cross_backend/identity_parity.d.ts.map +1 -1
  98. package/dist/testing/cross_backend/login_security.d.ts.map +1 -1
  99. package/dist/testing/cross_backend/method_coverage.d.ts +3 -7
  100. package/dist/testing/cross_backend/method_coverage.d.ts.map +1 -1
  101. package/dist/testing/cross_backend/method_coverage.js +1 -2
  102. package/dist/testing/cross_backend/peer_ping_ws.js +1 -1
  103. package/dist/testing/cross_backend/role_grant_offer_enumeration.d.ts +26 -0
  104. package/dist/testing/cross_backend/role_grant_offer_enumeration.d.ts.map +1 -0
  105. package/dist/testing/cross_backend/role_grant_offer_enumeration.js +108 -0
  106. package/dist/testing/cross_backend/rust_spine_stub_backend_config.d.ts.map +1 -1
  107. package/dist/testing/cross_backend/setup.d.ts.map +1 -1
  108. package/dist/testing/cross_backend/setup.js +2 -4
  109. package/dist/testing/cross_backend/testing_reset_actions.d.ts +0 -13
  110. package/dist/testing/cross_backend/testing_reset_actions.d.ts.map +1 -1
  111. package/dist/testing/cross_backend/testing_reset_actions.js +12 -4
  112. package/dist/testing/cross_backend/ts_spine_backend_config.d.ts.map +1 -1
  113. package/dist/testing/cross_backend/ts_spine_backend_config.js +9 -3
  114. package/dist/testing/data_exposure.d.ts.map +1 -1
  115. package/dist/testing/db.d.ts.map +1 -1
  116. package/dist/testing/db_entities.d.ts +15 -0
  117. package/dist/testing/db_entities.d.ts.map +1 -1
  118. package/dist/testing/db_entities.js +16 -1
  119. package/dist/testing/error_coverage.d.ts.map +1 -1
  120. package/dist/testing/error_coverage.js +1 -2
  121. package/dist/testing/integration_helpers.d.ts.map +1 -1
  122. package/dist/testing/rate_limiting.d.ts.map +1 -1
  123. package/dist/testing/round_trip.d.ts.map +1 -1
  124. package/dist/testing/rpc_attack_surface.d.ts.map +1 -1
  125. package/dist/testing/rpc_helpers.d.ts.map +1 -1
  126. package/dist/testing/rpc_round_trip.d.ts.map +1 -1
  127. package/dist/testing/schema_generators.d.ts.map +1 -1
  128. package/dist/testing/schema_generators.js +3 -1
  129. package/dist/testing/schema_parity.d.ts.map +1 -1
  130. package/dist/testing/sse_round_trip.d.ts.map +1 -1
  131. package/dist/testing/surface_invariants.d.ts.map +1 -1
  132. package/dist/testing/transports/bootstrap.d.ts.map +1 -1
  133. package/dist/testing/transports/ws_client.d.ts +1 -1
  134. package/dist/testing/transports/ws_transport.d.ts +1 -1
  135. package/dist/testing/ws_round_trip.d.ts +1 -1
  136. package/dist/testing/ws_round_trip.d.ts.map +1 -1
  137. package/dist/testing/ws_round_trip.js +3 -3
  138. package/dist/ui/CLAUDE.md +6 -3
  139. package/dist/ui/auth_state.svelte.d.ts.map +1 -1
  140. package/dist/ui/form_state.svelte.d.ts.map +1 -1
  141. package/dist/ui/role_grant_offers_state.svelte.d.ts +1 -1
  142. package/dist/ui/role_grant_offers_state.svelte.js +1 -1
  143. package/dist/ui/ui_format.d.ts.map +1 -1
  144. package/package.json +2 -2
  145. package/dist/actions/action_peer.d.ts.map +0 -1
@@ -14,13 +14,13 @@ import '../assert_dev_env.js';
14
14
  * the in-repo `spine_method_coverage` gate: that proves *mounted ⟹ covered*;
15
15
  * this proves *TS-mount-set ≡ Rust-mount-set* (method set + auth shape).
16
16
  *
17
- * **Scope — domain + testing surface, not wire protocol.** The manifest is
18
- * built from exactly the spec list its caller passes
19
- * (`build_full_spine_rpc_actions` on the TS spine; the spec list minus
20
- * `PROTOCOL_ACTION_SPECS` on the Rust stub). The protocol actions
21
- * (`heartbeat` / `cancel`) are excluded by the caller on purpose: the two
22
- * impls organize them differently (the TS spine mounts them on the WS
23
- * endpoint only, never the HTTP-RPC endpoint; the Rust stub compiles one
17
+ * **Scope — domain + testing surface, not wire protocol.** Protocol actions
18
+ * (`heartbeat` / `cancel` / `peer/ping`) are excluded: on the TS spine
19
+ * `create_testing_action_manifest_action` filters them via the
20
+ * `protocol_action_specs` method set; the Rust stub drops `PROTOCOL_ACTION_SPECS`. The
21
+ * two impls organize protocol actions differently (`peer/ping` is on the TS
22
+ * spine's WS **and** HTTP-RPC endpoints — it must answer `peer_no_transport`
23
+ * over HTTP — while heartbeat/cancel stay WS-only; the Rust stub compiles one
24
24
  * shared registry serving both transports), so including them would be a
25
25
  * spurious cross-impl diff. This matches the scope of the in-repo
26
26
  * `spine_method_coverage` gate (also over `build_full_spine_rpc_actions`).
@@ -1 +1 @@
1
- {"version":3,"file":"action_manifest_parity.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/action_manifest_parity.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,KAAK,EAAC,cAAc,EAAsB,MAAM,sBAAsB,CAAC;AAW9E,6EAA6E;AAC7E,MAAM,MAAM,kBAAkB,GAC3B;IAAC,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,GAAG,GAAG,GAAG,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAC,GACrF;IACA,QAAQ,CAAC,IAAI,EAAE,qBAAqB,CAAC;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC;CACnB,GACD;IACA,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;IACpC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,GAAG,OAAO,GAAG,kBAAkB,CAAC;IACnE,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAML;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,GACjC,GAAG,cAAc,EACjB,GAAG,cAAc,KACf,KAAK,CAAC,kBAAkB,CA+B1B,CAAC;AAEF,qEAAqE;AACrE,MAAM,WAAW,wBAAwB;IACxC,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,eAAO,MAAM,4BAA4B,GACxC,OAAO,aAAa,CAAC,kBAAkB,CAAC,EACxC,SAAQ,wBAA6B,KACnC,MA4BF,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,6BAA6B,GACzC,GAAG,cAAc,EACjB,GAAG,cAAc,EACjB,SAAQ,wBAA6B,KACnC,IAQF,CAAC"}
1
+ {"version":3,"file":"action_manifest_parity.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/action_manifest_parity.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,KAAK,EAAC,cAAc,EAAsB,MAAM,sBAAsB,CAAC;AAW9E,6EAA6E;AAC7E,MAAM,MAAM,kBAAkB,GAC3B;IAAC,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,GAAG,GAAG,GAAG,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAC,GACrF;IACA,QAAQ,CAAC,IAAI,EAAE,qBAAqB,CAAC;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC;CACnB,GACD;IACA,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;IACpC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,GAAG,OAAO,GAAG,kBAAkB,CAAC;IACnE,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAML;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,GACjC,GAAG,cAAc,EACjB,GAAG,cAAc,KACf,KAAK,CAAC,kBAAkB,CA+B1B,CAAC;AAEF,qEAAqE;AACrE,MAAM,WAAW,wBAAwB;IACxC,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,eAAO,MAAM,4BAA4B,GACxC,OAAO,aAAa,CAAC,kBAAkB,CAAC,EACxC,SAAQ,wBAA6B,KACnC,MA8BF,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,6BAA6B,GACzC,GAAG,cAAc,EACjB,GAAG,cAAc,EACjB,SAAQ,wBAA6B,KACnC,IAUF,CAAC"}
@@ -142,18 +142,21 @@ export interface BackendCapabilities {
142
142
  /**
143
143
  * The backend can **initiate** a JSON-RPC request to a connected client
144
144
  * and await its typed reply (the server→client request/response direction
145
- * `ActionPeer` adds). Gates `describe_peer_ping_ws_tests` — the on-demand
145
+ * ActionPeer adds). Gates `describe_peer_ping_ws_tests` — the on-demand
146
146
  * `peer/ping` round-trip plus its security negatives (unsolicited-response
147
147
  * rejection, per-connection id isolation, never-replying `Timeout`,
148
148
  * wrong-shape reply rejection).
149
149
  *
150
- * `true` for the Rust spine (server-initiated requests landed Rust-first
151
- * canonical); `false` for the TS family — the TS server
152
- * `BackendWebsocketTransport.send()` request path is the deferred
153
- * twin-impl convergence item, so a TS backend can't yet drive the
154
- * round-trip. Like ws/sse/cells, `peer/ping` stays off the standard
155
- * declared surface (it's a protocol action, manifest-excluded), so this
156
- * flag is the only opt-in into the peer parity coverage.
150
+ * `true` for both the Rust spine (server-initiated requests landed
151
+ * Rust-first canonical) and the TS spine
152
+ * (`BackendWebsocketTransport.request_connection` drives the round-trip,
153
+ * correlated by `register_action_ws`). The conservative
154
+ * `ts_default_capabilities` keeps it `false` like sse/ready — a TS backend
155
+ * opts in once it mounts `peer/ping` on a WS endpoint **and** the HTTP RPC
156
+ * endpoint (the no-transport refusal). Like ws/sse/cells, `peer/ping` stays
157
+ * off the standard declared surface (it's a protocol action,
158
+ * manifest-excluded), so this flag is the only opt-in into the peer parity
159
+ * coverage.
157
160
  */
158
161
  readonly peer_request: boolean;
159
162
  }
@@ -161,10 +164,10 @@ export interface BackendCapabilities {
161
164
  * Capability declarations for the in-process Hono transport. Nearly every
162
165
  * flag is `true` because in-process testing exercises the full backend
163
166
  * with no missing optional behaviors. The one exception is `peer_request`:
164
- * the in-process driver runs the **TS** server (`register_action_ws`),
165
- * whose server-initiated request transport is deferred, so it can't drive
166
- * a `peer/ping` round-trip — and `describe_peer_ping_ws_tests` is
167
- * cross-process-only regardless. Cross-process consumers declare each flag
167
+ * `describe_peer_ping_ws_tests` is cross-process-only (it needs a real bound
168
+ * socket with an `on_request` responder via `create_ws_transport`), so the
169
+ * in-process driver never runs it — the transport itself supports
170
+ * server-initiated requests. Cross-process consumers declare each flag
168
171
  * explicitly per backend.
169
172
  */
170
173
  export declare const in_process_capabilities: BackendCapabilities;
@@ -1 +1 @@
1
- {"version":3,"file":"capabilities.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/capabilities.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAwC9B;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,iBAAiB;IACjC;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC;;;;OAIG;IACH,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;CACnC;AAED;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IACnC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB;;;;;OAKG;IACH,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB;;;;;;;OAOG;IACH,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAC;IACpC;;;;;;;;OAQG;IACH,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B;;;;;;;;OAQG;IACH,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB;;;;;;;;OAQG;IACH,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC;;;;;;;;;;;;;;;;;OAiBG;IACH,QAAQ,CAAC,kCAAkC,EAAE,OAAO,CAAC;IACrD;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;CAC/B;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,uBAAuB,EAAE,mBAWpC,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,EAAE,iBAInC,CAAC;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,OAAO,GAAI,MAAM,OAAO,EAAE,MAAM,MAAM,EAAE,IAAI,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAG,IAMrF,CAAC"}
1
+ {"version":3,"file":"capabilities.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/capabilities.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAwC9B;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,iBAAiB;IACjC;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC;;;;OAIG;IACH,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;CACnC;AAED;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IACnC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB;;;;;OAKG;IACH,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB;;;;;;;OAOG;IACH,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAC;IACpC;;;;;;;;OAQG;IACH,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B;;;;;;;;OAQG;IACH,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB;;;;;;;;OAQG;IACH,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC;;;;;;;;;;;;;;;;;OAiBG;IACH,QAAQ,CAAC,kCAAkC,EAAE,OAAO,CAAC;IACrD;;;;;;;;;;;;;;;;;;OAkBG;IACH,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;CAC/B;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,uBAAuB,EAAE,mBAWpC,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,EAAE,iBAInC,CAAC;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,OAAO,GAAI,MAAM,OAAO,EAAE,MAAM,MAAM,EAAE,IAAI,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAG,IAMrF,CAAC"}
@@ -39,10 +39,10 @@ import { test } from 'vitest';
39
39
  * Capability declarations for the in-process Hono transport. Nearly every
40
40
  * flag is `true` because in-process testing exercises the full backend
41
41
  * with no missing optional behaviors. The one exception is `peer_request`:
42
- * the in-process driver runs the **TS** server (`register_action_ws`),
43
- * whose server-initiated request transport is deferred, so it can't drive
44
- * a `peer/ping` round-trip — and `describe_peer_ping_ws_tests` is
45
- * cross-process-only regardless. Cross-process consumers declare each flag
42
+ * `describe_peer_ping_ws_tests` is cross-process-only (it needs a real bound
43
+ * socket with an `on_request` responder via `create_ws_transport`), so the
44
+ * in-process driver never runs it — the transport itself supports
45
+ * server-initiated requests. Cross-process consumers declare each flag
46
46
  * explicitly per backend.
47
47
  */
48
48
  export const in_process_capabilities = Object.freeze({
@@ -1 +1 @@
1
- {"version":3,"file":"cell_cross_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/cell_cross_helpers.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAmB9B,OAAO,KAAK,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAG3B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,kCAAkC,CAAC;AAErE,qEAAqE;AACrE,MAAM,WAAW,SAAS;IACzB,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAC,CAAC;CAC5F;AAED;;;;;GAKG;AACH,eAAO,MAAM,cAAc,GAC1B,WAAW,cAAc,EACzB,MAAM,MAAM,EACZ,QAAQ,MAAM,EACd,QAAQ,OAAO,EACf,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAC7B,OAAO,CAAC,SAAS,CAMnB,CAAC;AAEF,gFAAgF;AAChF,eAAO,MAAM,YAAY,GAAI,GAAG,SAAS,KAAG,OAG/B,CAAC;AAEd;;;GAGG;AACH,eAAO,MAAM,aAAa,GAAI,CAAC,EAAE,GAAG,SAAS,EAAE,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAG,CAQrE,CAAC"}
1
+ {"version":3,"file":"cell_cross_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/cell_cross_helpers.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAmB9B,OAAO,KAAK,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAG3B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,kCAAkC,CAAC;AAErE,qEAAqE;AACrE,MAAM,WAAW,SAAS;IACzB,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAC,CAAC;CAC5F;AAED;;;;;GAKG;AACH,eAAO,MAAM,cAAc,GAC1B,WAAW,cAAc,EACzB,MAAM,MAAM,EACZ,QAAQ,MAAM,EACd,QAAQ,OAAO,EACf,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAC7B,OAAO,CAAC,SAAS,CAMnB,CAAC;AAEF,gFAAgF;AAChF,eAAO,MAAM,YAAY,GAAI,GAAG,SAAS,KAAG,OAG/B,CAAC;AAEd;;;GAGG;AACH,eAAO,MAAM,aAAa,GAAI,CAAC,EAAE,GAAG,SAAS,EAAE,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAG,CAUrE,CAAC"}
@@ -122,6 +122,7 @@ export declare const ConformanceCaseExpectation: z.ZodObject<{
122
122
  status: z.ZodNumber;
123
123
  error_reason: z.ZodOptional<z.ZodString>;
124
124
  fields: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
125
+ absent_fields: z.ZodOptional<z.ZodArray<z.ZodString>>;
125
126
  headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodNullable<z.ZodString>>>;
126
127
  equivalence_group: z.ZodOptional<z.ZodString>;
127
128
  }, z.core.$strict>;
@@ -175,6 +176,7 @@ export declare const ConformanceCase: z.ZodObject<{
175
176
  status: z.ZodNumber;
176
177
  error_reason: z.ZodOptional<z.ZodString>;
177
178
  fields: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
179
+ absent_fields: z.ZodOptional<z.ZodArray<z.ZodString>>;
178
180
  headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodNullable<z.ZodString>>>;
179
181
  equivalence_group: z.ZodOptional<z.ZodString>;
180
182
  }, z.core.$strict>;
@@ -1 +1 @@
1
- {"version":3,"file":"conformance_case.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/conformance_case.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;EAY/B,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAExE,6CAA6C;AAC7C,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;kBAgBjC,CAAC;AACH,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAE5E,8DAA8D;AAC9D,eAAO,MAAM,0BAA0B;;;;;;kBAiDrC,CAAC;AACH,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAEpF;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB;;;kBAK/B,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAExE;;;;;;;;;GASG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAS1B,CAAC;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC"}
1
+ {"version":3,"file":"conformance_case.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/conformance_case.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;EAY/B,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAExE,6CAA6C;AAC7C,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;kBAgBjC,CAAC;AACH,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAE5E,8DAA8D;AAC9D,eAAO,MAAM,0BAA0B;;;;;;;kBA+DrC,CAAC;AACH,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAEpF;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB;;;kBAK/B,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAExE;;;;;;;;;GASG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAS1B,CAAC;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC"}
@@ -130,6 +130,19 @@ export const ConformanceCaseExpectation = z.strictObject({
130
130
  description: 'Specific field-value assertions on the success `result` (2xx) or the error ' +
131
131
  '`error.data` (non-2xx). Each key must deep-equal the corresponding response field.',
132
132
  }),
133
+ absent_fields: z
134
+ .array(z.string())
135
+ .optional()
136
+ .meta({
137
+ description: 'Sensitive field names that must NOT appear ANYWHERE (at any depth) in the ' +
138
+ 'normalized response body — the negative-space twin of `fields`. Each name is ' +
139
+ 'searched recursively through the success `result` / error envelope, so a ' +
140
+ 'secret column (`password_hash`, `token_hash`) that leaks at any nesting level ' +
141
+ '(top-level, inside a list element) fails the case. Pins "this secret never ' +
142
+ 'serializes" on BOTH spines — a serialization regression would otherwise leak ' +
143
+ 'identically and silently on each. Non-vacuous only when the body is known ' +
144
+ 'non-empty (e.g. a list that always contains the caller); note that in the case.',
145
+ }),
133
146
  headers: z
134
147
  .record(z.string(), z.string().nullable())
135
148
  .optional()
@@ -1 +1 @@
1
- {"version":3,"file":"conformance_table.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/conformance_table.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA8B9B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,uBAAuB,CAAC;AAE1D,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,8BAA8B,CAAC;AAOjE,OAAO,EAKN,KAAK,uBAAuB,EAC5B,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAC,KAAK,eAAe,EAA4B,MAAM,uBAAuB,CAAC;AACtF,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EAAC,SAAS,EAAc,MAAM,YAAY,CAAC;AAGvD;;;;;GAKG;AACH,MAAM,WAAW,0BAA0B;IAC1C,iEAAiE;IACjE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,gEAAgE;IAChE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,sDAAsD;AACtD,MAAM,WAAW,uBAAuB;IACvC,8CAA8C;IAC9C,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;IAC/C,+DAA+D;IAC/D,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC;IAC/B,oEAAoE;IACpE,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;IACxC,0EAA0E;IAC1E,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAAC;IAC3C,kEAAkE;IAClE,QAAQ,CAAC,aAAa,EAAE,uBAAuB,CAAC;IAChD,4EAA4E;IAC5E,QAAQ,CAAC,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACjD,4EAA4E;IAC5E,QAAQ,CAAC,UAAU,CAAC,EAAE,0BAA0B,CAAC;IACjD,iEAAiE;IACjE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC7B;AAyJD;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,EAAE,aAAa,CAAC,MAAM,CAIrD,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,6BAA6B,GACzC,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,OAAO,MAAM,KACX,IAQF,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,GACnC,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,UAAU,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,EACvC,OAAO,MAAM,KACX,IAYF,CAAC;AAgKF;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC,GAAI,SAAS,uBAAuB,KAAG,IAkEnF,CAAC"}
1
+ {"version":3,"file":"conformance_table.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/conformance_table.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA8B9B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,uBAAuB,CAAC;AAE1D,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,8BAA8B,CAAC;AAOjE,OAAO,EAKN,KAAK,uBAAuB,EAC5B,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAC,KAAK,eAAe,EAA4B,MAAM,uBAAuB,CAAC;AACtF,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EAAC,SAAS,EAAc,MAAM,YAAY,CAAC;AAGvD;;;;;GAKG;AACH,MAAM,WAAW,0BAA0B;IAC1C,iEAAiE;IACjE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,gEAAgE;IAChE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,sDAAsD;AACtD,MAAM,WAAW,uBAAuB;IACvC,8CAA8C;IAC9C,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;IAC/C,+DAA+D;IAC/D,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC;IAC/B,oEAAoE;IACpE,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;IACxC,0EAA0E;IAC1E,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAAC;IAC3C,kEAAkE;IAClE,QAAQ,CAAC,aAAa,EAAE,uBAAuB,CAAC;IAChD,4EAA4E;IAC5E,QAAQ,CAAC,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACjD,4EAA4E;IAC5E,QAAQ,CAAC,UAAU,CAAC,EAAE,0BAA0B,CAAC;IACjD,iEAAiE;IACjE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC7B;AAuLD;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,EAAE,aAAa,CAAC,MAAM,CAIrD,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,6BAA6B,GACzC,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,OAAO,MAAM,KACX,IAQF,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,GACnC,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,UAAU,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,EACvC,OAAO,MAAM,KACX,IAYF,CAAC;AAuKF;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC,GAAI,SAAS,uBAAuB,KAAG,IAkEnF,CAAC"}
@@ -155,6 +155,29 @@ const assert_fields = (actual, fields, label) => {
155
155
  assert.deepEqual(record[key], expected, `${label}: field '${key}'`);
156
156
  }
157
157
  };
158
+ /**
159
+ * Whether `key` is present as an own property of `value` or any object nested
160
+ * within it (arrays and objects walked recursively). The shape-agnostic test
161
+ * behind `expect.absent_fields` — a secret column leaking at any depth (inside
162
+ * a list element, a nested record) is caught, not just a top-level field.
163
+ */
164
+ const has_key_anywhere = (value, key) => {
165
+ if (Array.isArray(value))
166
+ return value.some((v) => has_key_anywhere(v, key));
167
+ if (value !== null && typeof value === 'object') {
168
+ if (Object.hasOwn(value, key))
169
+ return true;
170
+ return Object.values(value).some((v) => has_key_anywhere(v, key));
171
+ }
172
+ return false;
173
+ };
174
+ /** Assert none of the sensitive field names appear anywhere in the response body. */
175
+ const assert_absent_fields = (body, absent, label) => {
176
+ for (const key of absent) {
177
+ assert.ok(!has_key_anywhere(body, key), `${label}: response must not serialize the sensitive field '${key}' anywhere in its ` +
178
+ `body — a secret column leaked into the wire shape.`);
179
+ }
180
+ };
158
181
  /**
159
182
  * Response headers that fingerprint the backend implementation or framework.
160
183
  * Neither spine emits these; the runner asserts they stay absent on EVERY
@@ -215,10 +238,16 @@ const is_success_status = (status) => status >= 200 && status < 300;
215
238
  const run_case = async (c, options, resolved_rpc_endpoints) => {
216
239
  const fixture = await options.setup_test();
217
240
  const { transport, headers, suppress_default_origin } = await resolve_principal(fixture, c.request.as, options.principals);
218
- if (c.request.method.startsWith('/')) {
219
- return run_rest_case(c, options, transport, headers);
241
+ const normalized = c.request.method.startsWith('/')
242
+ ? await run_rest_case(c, options, transport, headers)
243
+ : await run_rpc_case(c, transport, headers, suppress_default_origin, resolved_rpc_endpoints);
244
+ // Negative-space field check, uniform across REST + RPC and success + error
245
+ // bodies: a sensitive column (`password_hash`, `token_hash`) must not appear
246
+ // anywhere in what the prober sees.
247
+ if (c.expect.absent_fields) {
248
+ assert_absent_fields(normalized.body, c.expect.absent_fields, c.name);
220
249
  }
221
- return run_rpc_case(c, transport, headers, suppress_default_origin, resolved_rpc_endpoints);
250
+ return normalized;
222
251
  };
223
252
  /** Dispatch + assert a case targeting an RPC method. */
224
253
  const run_rpc_case = async (c, transport, headers, suppress_default_origin, resolved_rpc_endpoints) => {
@@ -0,0 +1,20 @@
1
+ import '../assert_dev_env.js';
2
+ import type { SetupTest } from './setup.js';
3
+ /** Options for the session-cookie-attribute parity suite. */
4
+ export interface CookieAttributesCrossTestOptions {
5
+ /** Per-test fixture producer (cross-process only — see the module doc). */
6
+ readonly setup_test: SetupTest;
7
+ /**
8
+ * The spine's session cookie name (`handle.config.cookie_name`, e.g.
9
+ * `fuz_session`). The `Set-Cookie` under test is matched by this name so a
10
+ * future cookie-name change surfaces here as "no session cookie set" rather
11
+ * than a silent miss.
12
+ */
13
+ readonly cookie_name: string;
14
+ /** REST login route path. Default `/api/account/login`. */
15
+ readonly login_path?: string;
16
+ /** REST logout route path. Default `/api/account/logout`. */
17
+ readonly logout_path?: string;
18
+ }
19
+ export declare const describe_cookie_attributes_cross_tests: (options: CookieAttributesCrossTestOptions) => void;
20
+ //# sourceMappingURL=cookie_attributes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cookie_attributes.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/cookie_attributes.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA+C9B,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,YAAY,CAAC;AAE1C,6DAA6D;AAC7D,MAAM,WAAW,gCAAgC;IAChD,2EAA2E;IAC3E,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC;IAC/B;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,2DAA2D;IAC3D,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,6DAA6D;IAC7D,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC9B;AAoED,eAAO,MAAM,sCAAsC,GAClD,SAAS,gCAAgC,KACvC,IAmFF,CAAC"}
@@ -0,0 +1,158 @@
1
+ import '../assert_dev_env.js';
2
+ /**
3
+ * Cross-backend parity suite for **session cookie attributes** over real HTTP.
4
+ *
5
+ * The session cookie's `Set-Cookie` attributes are the load-bearing browser
6
+ * security boundary: `HttpOnly` keeps the token out of JS (XSS can't read it),
7
+ * `Secure` keeps it off plaintext HTTP, `SameSite=Strict` is the primary CSRF
8
+ * defense (the Origin allowlist is only defense-in-depth), and `Path=/` scopes
9
+ * it to the whole app. A regression dropping any one of these is a real
10
+ * downgrade — and it's wire-observable, so both spines must emit the same
11
+ * hardened set. The cross-backend conformance table deliberately keeps
12
+ * `Set-Cookie` *out* of its byte-identity comparison (the signed value
13
+ * legitimately differs per request and per impl), so the attribute contract
14
+ * had no cross-backend pin: the TS spine's attributes were covered by
15
+ * `session_cookie.ts`'s own tests, but the Rust spine's `sign_session_cookie`
16
+ * / `clear_session_cookie` strings were asserted nowhere. This suite closes
17
+ * that gap on both impls by parsing the raw `Set-Cookie` and asserting the
18
+ * attributes directly. Three properties:
19
+ *
20
+ * - **successful login sets a hardened cookie** — `HttpOnly; Secure;
21
+ * SameSite=Strict; Path=/` plus a positive integer `Max-Age` (the session
22
+ * lifetime). The signed value is opaque here; only the attributes are pinned.
23
+ * - **a failed login sets no session cookie** — a denial mints no credential,
24
+ * so there is no `Set-Cookie` for the session name at all. A spine that
25
+ * leaked a (signed-but-unauthenticated) cookie on the 401 would fail here.
26
+ * - **logout clears the cookie with `Max-Age=0` and the same hardened flags** —
27
+ * the clear must not silently drop `Secure` / `HttpOnly` / `SameSite=Strict`
28
+ * (a cleared-but-unhardened `Set-Cookie` is a downgrade window).
29
+ *
30
+ * Both surfaces are flat REST (`POST /api/account/{login,logout}`) on every
31
+ * spine, so this is an imperative suite (not a `conformance_table` row) — the
32
+ * sibling of `origin.ts` / `login_security.ts`. Cross-process only: reading the
33
+ * raw `Set-Cookie` attributes needs the wire response (the in-process
34
+ * `parse_session` / `session_cookie.rs` unit tests cover each impl's cookie
35
+ * codec directly). Cited property: `docs/security.md` §"Session Security"
36
+ * (the "Cookie attributes" bullet — `HttpOnly; Secure; SameSite=Strict; Path=/`).
37
+ *
38
+ * `$lib`-free by contract (relative specifiers only), like the sibling
39
+ * cross-backend suites.
40
+ *
41
+ * @module
42
+ */
43
+ import { describe, test, assert } from 'vitest';
44
+ import { DEFAULT_TEST_PASSWORD } from '../test_credentials.js';
45
+ /**
46
+ * Parse a single `Set-Cookie` header value into `{name, value, attributes}`.
47
+ * Returns `null` for a malformed head (no `=`, empty name). Unlike the
48
+ * transport jar's `parse_set_cookie` (which drops everything after the first
49
+ * `;`), this retains the attributes — they are exactly what the suite asserts.
50
+ */
51
+ const parse_set_cookie = (raw) => {
52
+ const parts = raw.split(';');
53
+ const head = (parts[0] ?? '').trim();
54
+ const eq = head.indexOf('=');
55
+ if (eq <= 0)
56
+ return null;
57
+ const name = head.slice(0, eq).trim();
58
+ if (!name)
59
+ return null;
60
+ const value = head.slice(eq + 1);
61
+ const attributes = new Map();
62
+ for (let i = 1; i < parts.length; i++) {
63
+ const attr = parts[i].trim();
64
+ if (!attr)
65
+ continue;
66
+ const attr_eq = attr.indexOf('=');
67
+ if (attr_eq === -1) {
68
+ attributes.set(attr.toLowerCase(), '');
69
+ }
70
+ else {
71
+ attributes.set(attr.slice(0, attr_eq).trim().toLowerCase(), attr.slice(attr_eq + 1).trim());
72
+ }
73
+ }
74
+ return { name, value, attributes };
75
+ };
76
+ /**
77
+ * Find the `Set-Cookie` for the session cookie among a response's headers.
78
+ * `getSetCookie()` returns each `Set-Cookie` as its own string (the only way
79
+ * to read attributes — `Headers.get()` collapses multiple cookies to one
80
+ * comma-joined string). Returns `undefined` when no session cookie was set.
81
+ */
82
+ const find_session_cookie = (res, cookie_name) => {
83
+ for (const raw of res.headers.getSetCookie()) {
84
+ const parsed = parse_set_cookie(raw);
85
+ if (parsed && parsed.name === cookie_name)
86
+ return parsed;
87
+ }
88
+ return undefined;
89
+ };
90
+ /** Assert the hardened attribute set shared by the set + cleared cookies. */
91
+ const assert_hardened_flags = (cookie, label) => {
92
+ assert.ok(cookie.attributes.has('httponly'), `${label}: cookie must be HttpOnly (no JS read)`);
93
+ assert.ok(cookie.attributes.has('secure'), `${label}: cookie must be Secure (HTTPS-only)`);
94
+ assert.strictEqual(cookie.attributes.get('samesite')?.toLowerCase(), 'strict', `${label}: cookie must be SameSite=Strict (CSRF backstop)`);
95
+ assert.strictEqual(cookie.attributes.get('path'), '/', `${label}: cookie Path must be '/'`);
96
+ };
97
+ export const describe_cookie_attributes_cross_tests = (options) => {
98
+ const { setup_test, cookie_name } = options;
99
+ const login_path = options.login_path ?? '/api/account/login';
100
+ const logout_path = options.logout_path ?? '/api/account/logout';
101
+ // Fresh-keeper-per-test wipes the DB between tests, so a literal username
102
+ // never collides (see `setup.ts`). Each test mints it fresh.
103
+ const username = 'cookie_attr_user';
104
+ describe('session cookie attribute parity', () => {
105
+ test('successful login sets a hardened session cookie (HttpOnly; Secure; SameSite=Strict; Path=/; Max-Age>0)', async () => {
106
+ const fixture = await setup_test();
107
+ await fixture.create_account({ username, password_value: DEFAULT_TEST_PASSWORD });
108
+ // Fresh transport so no pre-existing cookie rides along; the default
109
+ // Origin (= base_url) is allowlisted, so the login clears the Origin gate.
110
+ const res = await fixture.fresh_transport()(login_path, {
111
+ method: 'POST',
112
+ headers: { 'content-type': 'application/json' },
113
+ body: JSON.stringify({ username, password: DEFAULT_TEST_PASSWORD }),
114
+ });
115
+ assert.strictEqual(res.status, 200, 'valid credentials must log in');
116
+ const cookie = find_session_cookie(res, cookie_name);
117
+ assert.ok(cookie, `login must Set-Cookie the '${cookie_name}' session cookie`);
118
+ assert.ok(cookie.value.length > 0, 'the session cookie must carry a signed value');
119
+ assert_hardened_flags(cookie, 'login Set-Cookie');
120
+ const max_age = Number(cookie.attributes.get('max-age'));
121
+ assert.ok(Number.isInteger(max_age) && max_age > 0, `login cookie must carry a positive integer Max-Age (got ${cookie.attributes.get('max-age')})`);
122
+ });
123
+ test('failed login (wrong password) sets no session cookie', async () => {
124
+ const fixture = await setup_test();
125
+ await fixture.create_account({ username, password_value: DEFAULT_TEST_PASSWORD });
126
+ const res = await fixture.fresh_transport()(login_path, {
127
+ method: 'POST',
128
+ headers: { 'content-type': 'application/json' },
129
+ body: JSON.stringify({ username, password: `wrong-${DEFAULT_TEST_PASSWORD}` }),
130
+ });
131
+ assert.strictEqual(res.status, 401, 'wrong password must be rejected');
132
+ assert.strictEqual(find_session_cookie(res, cookie_name), undefined, 'a failed login must not Set-Cookie a session — no credential is minted on denial');
133
+ });
134
+ test('logout clears the session cookie with Max-Age=0 and hardened flags', async () => {
135
+ const fixture = await setup_test();
136
+ await fixture.create_account({ username, password_value: DEFAULT_TEST_PASSWORD });
137
+ // Log in on a fresh transport so its jar carries the session cookie into
138
+ // the logout request (logout is session-authenticated).
139
+ const transport = fixture.fresh_transport();
140
+ const login_res = await transport(login_path, {
141
+ method: 'POST',
142
+ headers: { 'content-type': 'application/json' },
143
+ body: JSON.stringify({ username, password: DEFAULT_TEST_PASSWORD }),
144
+ });
145
+ assert.strictEqual(login_res.status, 200, 'precondition: login must succeed');
146
+ const res = await transport(logout_path, {
147
+ method: 'POST',
148
+ headers: { 'content-type': 'application/json' },
149
+ body: JSON.stringify({}),
150
+ });
151
+ assert.strictEqual(res.status, 200, 'logout must succeed for an authenticated session');
152
+ const cookie = find_session_cookie(res, cookie_name);
153
+ assert.ok(cookie, `logout must Set-Cookie a cleared '${cookie_name}'`);
154
+ assert.strictEqual(cookie.attributes.get('max-age'), '0', 'logout must clear the cookie with Max-Age=0');
155
+ assert_hardened_flags(cookie, 'logout Set-Cookie');
156
+ });
157
+ });
158
+ };
@@ -0,0 +1,12 @@
1
+ import '../assert_dev_env.js';
2
+ /** Options for the credential-header robustness probe — needs the raw URL + a valid daemon token. */
3
+ export interface CredentialHeaderRobustnessCrossTestOptions {
4
+ /** Base URL the spawned backend is reachable at (e.g. `http://localhost:1178`). */
5
+ readonly base_url: string;
6
+ /** RPC endpoint path to target. Default `/api/rpc`. */
7
+ readonly rpc_path?: string;
8
+ /** A valid daemon token (keeper) — `handle.daemon_token`. */
9
+ readonly daemon_token: string;
10
+ }
11
+ export declare const describe_credential_header_robustness_cross_tests: (options: CredentialHeaderRobustnessCrossTestOptions) => void;
12
+ //# sourceMappingURL=credential_header_robustness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential_header_robustness.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/credential_header_robustness.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA2D9B,qGAAqG;AACrG,MAAM,WAAW,0CAA0C;IAC1D,mFAAmF;IACnF,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,uDAAuD;IACvD,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,6DAA6D;IAC7D,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC9B;AAwFD,eAAO,MAAM,iDAAiD,GAC7D,SAAS,0CAA0C,KACjD,IAkHF,CAAC"}
@@ -0,0 +1,179 @@
1
+ import '../assert_dev_env.js';
2
+ /**
3
+ * Cross-backend **credential-header robustness** probe — the auth sibling of
4
+ * `body_size_smuggling.ts`.
5
+ *
6
+ * The auth middleware reads a single credential per header (`Authorization`,
7
+ * `X-Daemon-Token`). What a *duplicated*, *oversized*, or *control-char-injected*
8
+ * credential header does is framework-territory — Hono reads its headers via the
9
+ * Web `Headers` API, axum via `http::HeaderMap` — and the two could resolve a
10
+ * duplicate differently (first-vs-last), cap header size differently, or parse a
11
+ * malformed value differently. None of that is exercised over `fetch` (the
12
+ * `FetchTransport` can't emit a duplicate or malformed header), so it had no
13
+ * cross-impl pin. This raw-socket suite sends hand-framed requests and asserts
14
+ * the **security invariants that must hold regardless of how each framework
15
+ * resolves the ambiguity** — so it pins a real property without blessing one
16
+ * resolution over the other:
17
+ *
18
+ * - **a duplicated credential header never escalates** — a request carrying a
19
+ * valid keeper `X-Daemon-Token` *and* a second, conflicting one must not
20
+ * perform a keeper operation. The target omits `confirm`, so the documented
21
+ * confirm guard (`purge_not_confirmed`) makes the honored-token branch a
22
+ * guaranteed non-2xx with **zero side effect**, and the discarded-token
23
+ * branch is a non-2xx auth/credential refusal — so whichever copy the
24
+ * framework picks, the outcome is non-2xx. The same shape with two garbage
25
+ * `Authorization` headers pins the bearer path can't be escalated either.
26
+ * - **a control-char-injected credential header can't smuggle or authenticate**
27
+ * — embedded `CRLF` / bare `CR` in the value never frames a second request
28
+ * (no smuggle) and never authenticates (the truncated / rejected value is no
29
+ * token).
30
+ * - **no response desync** — each crafted request yields exactly one HTTP
31
+ * response (a duplicate header that reframed the request would surface as a
32
+ * second status line, like the body-size smuggling probe).
33
+ * - **an oversized credential header can't wedge the server** — after a request
34
+ * with a 64 KiB `X-Daemon-Token` (well past both frameworks' header caps), a
35
+ * subsequent normal request on a fresh connection still gets a response. The
36
+ * oversized request's own outcome (4xx / 431 / connection close) is
37
+ * don't-care; surviving it is the property.
38
+ *
39
+ * Raw-socket by necessity (`fetch` can't emit duplicate or malformed headers),
40
+ * so — like `body_size_smuggling.ts` — this is **cross-process only** and
41
+ * fixture-free: it needs only the base URL, the RPC path, and a valid daemon
42
+ * token (`handle.daemon_token`, kept current for the run by the same rotation
43
+ * the `_testing_reset` channel relies on). Cited property: `docs/security.md`
44
+ * §"Credential Type Hierarchy" (a leaked / conflicting credential header can't
45
+ * escalate the credential ceiling) + §"API Token Security" (bearer handling).
46
+ *
47
+ * `$lib`-free by contract (relative + `node:` specifiers only).
48
+ *
49
+ * @module
50
+ */
51
+ import { connect } from 'node:net';
52
+ import { describe, test, assert } from 'vitest';
53
+ import { DAEMON_TOKEN_HEADER } from '../../auth/daemon_token.js';
54
+ import { SPINE_RPC_PATH } from './default_spine_surface.js';
55
+ /** A well-formed UUID that never names a real row. */
56
+ const NIL_UUID = '00000000-0000-0000-0000-000000000000';
57
+ /** A value that is never a real credential — used for the conflicting / garbage copies. */
58
+ const GARBAGE_TOKEN = 'not-a-real-credential-value';
59
+ /**
60
+ * Open a raw TCP socket to `base_url`, write `request_bytes` once, and collect
61
+ * everything the server sends back until it closes or `read_timeout_ms`
62
+ * elapses. Write errors are swallowed (a server closing mid-write on a rejected
63
+ * request is expected behavior); what matters is what we read back. Mirrors
64
+ * `body_size_smuggling.ts`'s `send_raw`.
65
+ */
66
+ const send_raw = (base_url, request_bytes, read_timeout_ms) => new Promise((resolve) => {
67
+ const url = new URL(base_url);
68
+ const port = Number(url.port) || (url.protocol === 'https:' ? 443 : 80);
69
+ const socket = connect({ host: url.hostname, port });
70
+ let received = '';
71
+ let settled = false;
72
+ const finish = () => {
73
+ if (settled)
74
+ return;
75
+ settled = true;
76
+ clearTimeout(timer);
77
+ socket.destroy();
78
+ resolve(received);
79
+ };
80
+ const timer = setTimeout(finish, read_timeout_ms);
81
+ socket.setEncoding('latin1');
82
+ socket.on('connect', () => socket.write(request_bytes));
83
+ socket.on('data', (chunk) => {
84
+ received += chunk;
85
+ });
86
+ socket.on('error', () => { }); // EPIPE/ECONNRESET on mid-write close is expected
87
+ socket.on('close', finish);
88
+ });
89
+ /**
90
+ * Count HTTP response status lines in a raw byte stream. Unanchored so a
91
+ * second (smuggled) response concatenated after the first body — which carries
92
+ * no trailing newline — is still counted; see `body_size_smuggling.ts`.
93
+ */
94
+ const count_responses = (raw) => (raw.match(/HTTP\/1\.[01] \d{3}/g) ?? []).length;
95
+ /** The status code of the first HTTP response in a raw stream, or `null` if none. */
96
+ const first_status = (raw) => {
97
+ const match = /HTTP\/1\.[01] (\d{3})/.exec(raw);
98
+ return match ? Number(match[1]) : null;
99
+ };
100
+ const is_success_status = (status) => status >= 200 && status < 300;
101
+ /**
102
+ * Frame a raw HTTP/1.1 POST with the given extra header lines + JSON body.
103
+ * `Connection: close` so the server closes after one response (the response
104
+ * count is then unambiguous). The body is ASCII JSON, so `body.length` is the
105
+ * byte length — no `Buffer` needed.
106
+ */
107
+ const rpc_post = (host, path, header_lines, body) => `POST ${path} HTTP/1.1\r\n` +
108
+ `Host: ${host}\r\n` +
109
+ `Content-Type: application/json\r\n` +
110
+ header_lines.map((h) => `${h}\r\n`).join('') +
111
+ `Content-Length: ${body.length}\r\n` +
112
+ `Connection: close\r\n` +
113
+ `\r\n` +
114
+ body;
115
+ /**
116
+ * A keeper-gated `account_purge` body with `confirm` OMITTED — the confirm
117
+ * guard (`purge_not_confirmed`, before any deletion) guarantees the
118
+ * valid-credential branch is a non-2xx with zero side effect, so the
119
+ * no-escalation assertion holds regardless of which duplicate header wins.
120
+ */
121
+ const purge_body = (id) => JSON.stringify({ jsonrpc: '2.0', method: 'account_purge', id, params: { account_id: NIL_UUID } });
122
+ export const describe_credential_header_robustness_cross_tests = (options) => {
123
+ const { base_url, daemon_token } = options;
124
+ const rpc_path = options.rpc_path ?? SPINE_RPC_PATH;
125
+ const host = new URL(base_url).host;
126
+ describe('credential-header robustness', () => {
127
+ test('duplicate X-Daemon-Token (valid + conflicting) never escalates → one non-2xx response', async () => {
128
+ const req = rpc_post(host, rpc_path, [`${DAEMON_TOKEN_HEADER}: ${daemon_token}`, `${DAEMON_TOKEN_HEADER}: ${GARBAGE_TOKEN}`], purge_body('dup-daemon'));
129
+ const raw = await send_raw(base_url, req, 2000);
130
+ assert.strictEqual(count_responses(raw), 1, `a duplicated X-Daemon-Token must yield exactly one response (no desync). Raw head: ${raw.slice(0, 120)}`);
131
+ const status = first_status(raw);
132
+ assert.ok(status !== null, `expected an HTTP response. Raw head: ${raw.slice(0, 120)}`);
133
+ assert.ok(!is_success_status(status), `a duplicated daemon token must not perform a keeper operation; whichever copy wins, ` +
134
+ `the result must be non-2xx (got ${status})`);
135
+ });
136
+ test('duplicate Authorization bearer headers (both garbage) do not authenticate → one non-2xx response', async () => {
137
+ const req = rpc_post(host, rpc_path, [`Authorization: Bearer ${GARBAGE_TOKEN}`, `Authorization: Bearer ${GARBAGE_TOKEN}-2`], purge_body('dup-bearer'));
138
+ const raw = await send_raw(base_url, req, 2000);
139
+ assert.strictEqual(count_responses(raw), 1, `duplicate Authorization headers must yield exactly one response (no desync). Raw head: ${raw.slice(0, 120)}`);
140
+ const status = first_status(raw);
141
+ assert.ok(status !== null, `expected an HTTP response. Raw head: ${raw.slice(0, 120)}`);
142
+ assert.ok(!is_success_status(status), `garbage bearer tokens (even duplicated) must not authenticate (got ${status})`);
143
+ });
144
+ test('control-char-injected credential header (CR/LF) cannot smuggle or authenticate', async () => {
145
+ // Embedded CRLF and a bare CR (header-splitting attempts) in a garbage
146
+ // `X-Daemon-Token` value. A strict HTTP parser rejects the request
147
+ // (400 / connection close); a lenient one truncates the value to a
148
+ // non-token or treats the injected line as an extra (harmless) header.
149
+ // Either way the framework-agnostic invariants hold: the injected bytes
150
+ // never frame a SECOND request (no smuggle), and the garbage credential
151
+ // never authenticates (no 2xx). `<= 1` (not `=== 1`) because a strict
152
+ // parser may close without a readable response — that's also "no smuggle".
153
+ const malformed = [
154
+ { label: 'CRLF header-split', value: `${GARBAGE_TOKEN}\r\nX-Injected: 1` },
155
+ { label: 'bare CR', value: `${GARBAGE_TOKEN}\rX-Injected: 1` },
156
+ ];
157
+ for (const { label, value } of malformed) {
158
+ const req = rpc_post(host, rpc_path, [`${DAEMON_TOKEN_HEADER}: ${value}`], purge_body('ctrl-char'));
159
+ const raw = await send_raw(base_url, req, 2000);
160
+ assert.ok(count_responses(raw) <= 1, `${label}: a control-char-injected credential header must not frame a second ` +
161
+ `request (no smuggle). Raw head: ${raw.slice(0, 120)}`);
162
+ const status = first_status(raw);
163
+ assert.ok(status === null || !is_success_status(status), `${label}: a malformed credential header must never authenticate (got ${status})`);
164
+ }
165
+ });
166
+ test('oversized credential header does not crash or wedge the server', async () => {
167
+ // 64 KiB — well past both frameworks' header-size caps, so the request is
168
+ // rejected (4xx / 431 / connection close). Its own outcome is don't-care.
169
+ const oversized = 'a'.repeat(64 * 1024);
170
+ const req = rpc_post(host, rpc_path, [`${DAEMON_TOKEN_HEADER}: ${oversized}`], purge_body('oversized'));
171
+ await send_raw(base_url, req, 2000);
172
+ // The property: the server survives it. A normal request on a fresh
173
+ // connection must still get a response (no crash, no wedged accept loop).
174
+ const probe = `GET ${rpc_path} HTTP/1.1\r\nHost: ${host}\r\nConnection: close\r\n\r\n`;
175
+ const raw = await send_raw(base_url, probe, 2000);
176
+ assert.ok(first_status(raw) !== null, `server must still respond after an oversized-header request (no crash / wedge). Raw head: ${raw.slice(0, 120)}`);
177
+ });
178
+ });
179
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"default_backend_configs.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/default_backend_configs.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,KAAK,EAAC,sBAAsB,EAAE,aAAa,EAAC,MAAM,qBAAqB,CAAC;AAC/E,OAAO,KAAK,EAAC,mBAAmB,EAAE,iBAAiB,EAAC,MAAM,mBAAmB,CAAC;AAC9E,OAAO,EAA2B,KAAK,gBAAgB,EAAC,MAAM,+BAA+B,CAAC;AAQ9F;;;;;;;;;;GAUG;AACH,eAAO,MAAM,4BAA4B,iCAAiC,CAAC;AAE3E;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,EAAE,mBAqBpC,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,EAAE,mBAmBtC,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,EAAE,iBAInC,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,wBAAwB,EAAE,iBAIrC,CAAC;AAeH,MAAM,WAAW,iCAAiC;IACjD,gFAAgF;IAChF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,sCAAsC;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,4DAA4D;IAC5D,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC9C,oDAAoD;IACpD,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,iEAAiE;IACjE,QAAQ,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACtD,6CAA6C;IAC7C,QAAQ,CAAC,YAAY,CAAC,EAAE,mBAAmB,CAAC;IAC5C,wEAAwE;IACxE,QAAQ,CAAC,KAAK,CAAC,EAAE,gBAAgB,CAAC;IAClC,sEAAsE;IACtE,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC,sBAAsB,CAAC,CAAC;IAC/D;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B;;;;;;OAMG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;GAKG;AACH,eAAO,MAAM,8BAA8B,GAC1C,MAAM,iCAAiC,KACrC,aAoCF,CAAC;AAEF,MAAM,WAAW,mCAAmC;IACnD,gFAAgF;IAChF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,sCAAsC;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,4DAA4D;IAC5D,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC9C;;;;OAIG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,iEAAiE;IACjE,QAAQ,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACtD,+CAA+C;IAC/C,QAAQ,CAAC,YAAY,CAAC,EAAE,mBAAmB,CAAC;IAC5C,wEAAwE;IACxE,QAAQ,CAAC,KAAK,CAAC,EAAE,gBAAgB,CAAC;IAClC,sEAAsE;IACtE,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC,sBAAsB,CAAC,CAAC;IAC/D;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC,GAC5C,MAAM,mCAAmC,KACvC,aA4CF,CAAC"}
1
+ {"version":3,"file":"default_backend_configs.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/default_backend_configs.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,KAAK,EAAC,sBAAsB,EAAE,aAAa,EAAC,MAAM,qBAAqB,CAAC;AAC/E,OAAO,KAAK,EAAC,mBAAmB,EAAE,iBAAiB,EAAC,MAAM,mBAAmB,CAAC;AAC9E,OAAO,EAA2B,KAAK,gBAAgB,EAAC,MAAM,+BAA+B,CAAC;AAQ9F;;;;;;;;;;GAUG;AACH,eAAO,MAAM,4BAA4B,iCAAiC,CAAC;AAE3E;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,EAAE,mBAuBpC,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,EAAE,mBAmBtC,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,EAAE,iBAInC,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,wBAAwB,EAAE,iBAIrC,CAAC;AAeH,MAAM,WAAW,iCAAiC;IACjD,gFAAgF;IAChF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,sCAAsC;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,4DAA4D;IAC5D,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC9C,oDAAoD;IACpD,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,iEAAiE;IACjE,QAAQ,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACtD,6CAA6C;IAC7C,QAAQ,CAAC,YAAY,CAAC,EAAE,mBAAmB,CAAC;IAC5C,wEAAwE;IACxE,QAAQ,CAAC,KAAK,CAAC,EAAE,gBAAgB,CAAC;IAClC,sEAAsE;IACtE,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC,sBAAsB,CAAC,CAAC;IAC/D;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B;;;;;;OAMG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;GAKG;AACH,eAAO,MAAM,8BAA8B,GAC1C,MAAM,iCAAiC,KACrC,aAoCF,CAAC;AAEF,MAAM,WAAW,mCAAmC;IACnD,gFAAgF;IAChF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,sCAAsC;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,4DAA4D;IAC5D,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC9C;;;;OAIG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,iEAAiE;IACjE,QAAQ,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACtD,+CAA+C;IAC/C,QAAQ,CAAC,YAAY,CAAC,EAAE,mBAAmB,CAAC;IAC5C,wEAAwE;IACxE,QAAQ,CAAC,KAAK,CAAC,EAAE,gBAAgB,CAAC;IAClC,sEAAsE;IACtE,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC,sBAAsB,CAAC,CAAC;IAC/D;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC,GAC5C,MAAM,mCAAmC,KACvC,aA4CF,CAAC"}