@fuzdev/fuz_app 0.64.0 → 0.66.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.
Files changed (223) hide show
  1. package/dist/actions/CLAUDE.md +510 -946
  2. package/dist/actions/action_codegen.d.ts +1 -1
  3. package/dist/actions/action_codegen.js +1 -1
  4. package/dist/actions/action_event_data.d.ts +1 -1
  5. package/dist/actions/broadcast_api.d.ts +1 -1
  6. package/dist/actions/broadcast_api.js +1 -1
  7. package/dist/actions/cancel.d.ts +2 -2
  8. package/dist/actions/cancel.js +3 -3
  9. package/dist/actions/connection_closer.d.ts +1 -4
  10. package/dist/actions/connection_closer.d.ts.map +1 -1
  11. package/dist/actions/connection_closer.js +1 -4
  12. package/dist/actions/register_action_ws.d.ts +2 -2
  13. package/dist/actions/register_ws_endpoint.d.ts +1 -1
  14. package/dist/actions/transports_ws_auth_guard.d.ts +1 -2
  15. package/dist/actions/transports_ws_auth_guard.d.ts.map +1 -1
  16. package/dist/actions/transports_ws_auth_guard.js +1 -2
  17. package/dist/auth/CLAUDE.md +570 -1871
  18. package/dist/auth/account_schema.d.ts +1 -1
  19. package/dist/auth/account_schema.d.ts.map +1 -1
  20. package/dist/auth/api_token_queries.js +1 -1
  21. package/dist/auth/audit_log_ddl.d.ts +1 -1
  22. package/dist/auth/audit_log_ddl.d.ts.map +1 -1
  23. package/dist/auth/audit_log_ddl.js +1 -1
  24. package/dist/auth/audit_log_schema.js +2 -2
  25. package/dist/auth/bootstrap_account.d.ts.map +1 -1
  26. package/dist/auth/bootstrap_account.js +1 -5
  27. package/dist/auth/bootstrap_routes.d.ts +7 -1
  28. package/dist/auth/bootstrap_routes.d.ts.map +1 -1
  29. package/dist/auth/bootstrap_routes.js +15 -11
  30. package/dist/auth/daemon_token_middleware.d.ts +15 -5
  31. package/dist/auth/daemon_token_middleware.d.ts.map +1 -1
  32. package/dist/auth/daemon_token_middleware.js +24 -15
  33. package/dist/auth/invite_queries.d.ts +17 -7
  34. package/dist/auth/invite_queries.d.ts.map +1 -1
  35. package/dist/auth/invite_queries.js +19 -8
  36. package/dist/auth/keyring.d.ts +6 -6
  37. package/dist/auth/keyring.js +8 -8
  38. package/dist/auth/role_grant_offer_actions.d.ts.map +1 -1
  39. package/dist/auth/role_grant_offer_actions.js +4 -2
  40. package/dist/auth/signup_routes.d.ts +47 -1
  41. package/dist/auth/signup_routes.d.ts.map +1 -1
  42. package/dist/auth/signup_routes.js +103 -52
  43. package/dist/db/create_db.d.ts.map +1 -1
  44. package/dist/db/create_db.js +13 -0
  45. package/dist/dev/setup.d.ts +2 -2
  46. package/dist/dev/setup.js +3 -3
  47. package/dist/env/resolve.d.ts +44 -7
  48. package/dist/env/resolve.d.ts.map +1 -1
  49. package/dist/env/resolve.js +94 -27
  50. package/dist/http/CLAUDE.md +243 -522
  51. package/dist/http/error_schemas.d.ts +0 -4
  52. package/dist/http/error_schemas.d.ts.map +1 -1
  53. package/dist/http/error_schemas.js +0 -4
  54. package/dist/http/ip_canonical.d.ts +5 -4
  55. package/dist/http/ip_canonical.d.ts.map +1 -1
  56. package/dist/http/ip_canonical.js +8 -4
  57. package/dist/http/jsonrpc.d.ts +23 -7
  58. package/dist/http/jsonrpc.d.ts.map +1 -1
  59. package/dist/http/jsonrpc.js +19 -3
  60. package/dist/http/origin.d.ts +1 -1
  61. package/dist/http/origin.js +1 -1
  62. package/dist/http/surface.d.ts +9 -2
  63. package/dist/http/surface.d.ts.map +1 -1
  64. package/dist/runtime/mock.d.ts +1 -1
  65. package/dist/runtime/mock.js +2 -2
  66. package/dist/server/app_server.d.ts +41 -10
  67. package/dist/server/app_server.d.ts.map +1 -1
  68. package/dist/server/app_server.js +10 -4
  69. package/dist/server/env.d.ts +7 -7
  70. package/dist/server/env.d.ts.map +1 -1
  71. package/dist/server/env.js +14 -14
  72. package/dist/server/static.d.ts +4 -4
  73. package/dist/server/static.js +7 -7
  74. package/dist/testing/CLAUDE.md +740 -418
  75. package/dist/testing/admin_integration.d.ts +18 -23
  76. package/dist/testing/admin_integration.d.ts.map +1 -1
  77. package/dist/testing/admin_integration.js +230 -216
  78. package/dist/testing/app_server.d.ts +141 -39
  79. package/dist/testing/app_server.d.ts.map +1 -1
  80. package/dist/testing/app_server.js +157 -44
  81. package/dist/testing/audit_completeness.d.ts +25 -22
  82. package/dist/testing/audit_completeness.d.ts.map +1 -1
  83. package/dist/testing/audit_completeness.js +198 -159
  84. package/dist/testing/bootstrap_success.d.ts +28 -0
  85. package/dist/testing/bootstrap_success.d.ts.map +1 -0
  86. package/dist/testing/bootstrap_success.js +144 -0
  87. package/dist/testing/cross_backend/backend_config.d.ts +113 -0
  88. package/dist/testing/cross_backend/backend_config.d.ts.map +1 -0
  89. package/dist/testing/cross_backend/backend_config.js +1 -0
  90. package/dist/testing/cross_backend/bench/bench_report.d.ts +46 -0
  91. package/dist/testing/cross_backend/bench/bench_report.d.ts.map +1 -0
  92. package/dist/testing/cross_backend/bench/bench_report.js +83 -0
  93. package/dist/testing/cross_backend/bench/run_cross_impl_bench.d.ts +44 -0
  94. package/dist/testing/cross_backend/bench/run_cross_impl_bench.d.ts.map +1 -0
  95. package/dist/testing/cross_backend/bench/run_cross_impl_bench.js +38 -0
  96. package/dist/testing/cross_backend/bench/scenario.d.ts +57 -0
  97. package/dist/testing/cross_backend/bench/scenario.d.ts.map +1 -0
  98. package/dist/testing/cross_backend/bench/scenario.js +28 -0
  99. package/dist/testing/cross_backend/bootstrap_backend.d.ts +41 -0
  100. package/dist/testing/cross_backend/bootstrap_backend.d.ts.map +1 -0
  101. package/dist/testing/cross_backend/bootstrap_backend.js +34 -0
  102. package/dist/testing/cross_backend/build_test_backend_paths.d.ts +24 -0
  103. package/dist/testing/cross_backend/build_test_backend_paths.d.ts.map +1 -0
  104. package/dist/testing/cross_backend/build_test_backend_paths.js +33 -0
  105. package/dist/testing/cross_backend/capabilities.d.ts +65 -0
  106. package/dist/testing/cross_backend/capabilities.d.ts.map +1 -0
  107. package/dist/testing/cross_backend/capabilities.js +47 -0
  108. package/dist/testing/cross_backend/default_backend_configs.d.ts +122 -0
  109. package/dist/testing/cross_backend/default_backend_configs.d.ts.map +1 -0
  110. package/dist/testing/cross_backend/default_backend_configs.js +111 -0
  111. package/dist/testing/cross_backend/default_secrets.d.ts +40 -0
  112. package/dist/testing/cross_backend/default_secrets.d.ts.map +1 -0
  113. package/dist/testing/cross_backend/default_secrets.js +39 -0
  114. package/dist/testing/cross_backend/default_spine_surface.d.ts +64 -0
  115. package/dist/testing/cross_backend/default_spine_surface.d.ts.map +1 -0
  116. package/dist/testing/cross_backend/default_spine_surface.js +121 -0
  117. package/dist/testing/cross_backend/setup.d.ts +451 -0
  118. package/dist/testing/cross_backend/setup.d.ts.map +1 -0
  119. package/dist/testing/cross_backend/setup.js +581 -0
  120. package/dist/testing/cross_backend/spawn_backend.d.ts +58 -0
  121. package/dist/testing/cross_backend/spawn_backend.d.ts.map +1 -0
  122. package/dist/testing/cross_backend/spawn_backend.js +229 -0
  123. package/dist/testing/cross_backend/spine_stub_backend_config.d.ts +66 -0
  124. package/dist/testing/cross_backend/spine_stub_backend_config.d.ts.map +1 -0
  125. package/dist/testing/cross_backend/spine_stub_backend_config.js +49 -0
  126. package/dist/testing/cross_backend/sse_round_trip.d.ts +37 -0
  127. package/dist/testing/cross_backend/sse_round_trip.d.ts.map +1 -0
  128. package/dist/testing/cross_backend/sse_round_trip.js +137 -0
  129. package/dist/testing/cross_backend/standard.d.ts +96 -0
  130. package/dist/testing/cross_backend/standard.d.ts.map +1 -0
  131. package/dist/testing/cross_backend/standard.js +49 -0
  132. package/dist/testing/cross_backend/testing_reset_actions.d.ts +171 -0
  133. package/dist/testing/cross_backend/testing_reset_actions.d.ts.map +1 -0
  134. package/dist/testing/cross_backend/testing_reset_actions.js +213 -0
  135. package/dist/testing/cross_backend/testing_server_bun.d.ts +5 -0
  136. package/dist/testing/cross_backend/testing_server_bun.d.ts.map +1 -0
  137. package/dist/testing/cross_backend/testing_server_bun.js +59 -0
  138. package/dist/testing/cross_backend/testing_server_core.d.ts +140 -0
  139. package/dist/testing/cross_backend/testing_server_core.d.ts.map +1 -0
  140. package/dist/testing/cross_backend/testing_server_core.js +68 -0
  141. package/dist/testing/cross_backend/testing_server_deno.d.ts +5 -0
  142. package/dist/testing/cross_backend/testing_server_deno.d.ts.map +1 -0
  143. package/dist/testing/cross_backend/testing_server_deno.js +37 -0
  144. package/dist/testing/cross_backend/testing_server_node.d.ts +5 -0
  145. package/dist/testing/cross_backend/testing_server_node.d.ts.map +1 -0
  146. package/dist/testing/cross_backend/testing_server_node.js +50 -0
  147. package/dist/testing/cross_backend/ts_spine_backend_config.d.ts +72 -0
  148. package/dist/testing/cross_backend/ts_spine_backend_config.d.ts.map +1 -0
  149. package/dist/testing/cross_backend/ts_spine_backend_config.js +112 -0
  150. package/dist/testing/cross_backend/ws_round_trip.d.ts +35 -0
  151. package/dist/testing/cross_backend/ws_round_trip.d.ts.map +1 -0
  152. package/dist/testing/cross_backend/ws_round_trip.js +113 -0
  153. package/dist/testing/data_exposure.d.ts +11 -14
  154. package/dist/testing/data_exposure.d.ts.map +1 -1
  155. package/dist/testing/data_exposure.js +123 -146
  156. package/dist/testing/db_entities.d.ts +22 -1
  157. package/dist/testing/db_entities.d.ts.map +1 -1
  158. package/dist/testing/db_entities.js +24 -1
  159. package/dist/testing/integration.d.ts +56 -21
  160. package/dist/testing/integration.d.ts.map +1 -1
  161. package/dist/testing/integration.js +294 -319
  162. package/dist/testing/integration_helpers.d.ts +16 -6
  163. package/dist/testing/integration_helpers.d.ts.map +1 -1
  164. package/dist/testing/integration_helpers.js +7 -7
  165. package/dist/testing/mock_fs.d.ts.map +1 -1
  166. package/dist/testing/mock_fs.js +0 -2
  167. package/dist/testing/rate_limiting.d.ts.map +1 -1
  168. package/dist/testing/rate_limiting.js +9 -0
  169. package/dist/testing/role_grant_helpers.d.ts +31 -0
  170. package/dist/testing/role_grant_helpers.d.ts.map +1 -0
  171. package/dist/testing/role_grant_helpers.js +46 -0
  172. package/dist/testing/round_trip.d.ts +20 -16
  173. package/dist/testing/round_trip.d.ts.map +1 -1
  174. package/dist/testing/round_trip.js +61 -86
  175. package/dist/testing/rpc_helpers.d.ts +10 -4
  176. package/dist/testing/rpc_helpers.d.ts.map +1 -1
  177. package/dist/testing/rpc_helpers.js +1 -1
  178. package/dist/testing/rpc_round_trip.d.ts +24 -21
  179. package/dist/testing/rpc_round_trip.d.ts.map +1 -1
  180. package/dist/testing/rpc_round_trip.js +87 -104
  181. package/dist/testing/schema_introspect.d.ts +106 -0
  182. package/dist/testing/schema_introspect.d.ts.map +1 -0
  183. package/dist/testing/schema_introspect.js +123 -0
  184. package/dist/testing/schema_parity.d.ts +144 -0
  185. package/dist/testing/schema_parity.d.ts.map +1 -0
  186. package/dist/testing/schema_parity.js +233 -0
  187. package/dist/testing/sse_round_trip.d.ts.map +1 -1
  188. package/dist/testing/sse_round_trip.js +1 -68
  189. package/dist/testing/standard.d.ts +56 -25
  190. package/dist/testing/standard.d.ts.map +1 -1
  191. package/dist/testing/standard.js +62 -5
  192. package/dist/testing/stubs.d.ts +21 -6
  193. package/dist/testing/stubs.d.ts.map +1 -1
  194. package/dist/testing/stubs.js +33 -23
  195. package/dist/testing/testing_rate_limiter.d.ts +59 -0
  196. package/dist/testing/testing_rate_limiter.d.ts.map +1 -0
  197. package/dist/testing/testing_rate_limiter.js +74 -0
  198. package/dist/testing/transports/bootstrap.d.ts +52 -0
  199. package/dist/testing/transports/bootstrap.d.ts.map +1 -0
  200. package/dist/testing/transports/bootstrap.js +70 -0
  201. package/dist/testing/transports/fetch_transport.d.ts +81 -0
  202. package/dist/testing/transports/fetch_transport.d.ts.map +1 -0
  203. package/dist/testing/transports/fetch_transport.js +74 -0
  204. package/dist/testing/transports/sse_frame_reader.d.ts +41 -0
  205. package/dist/testing/transports/sse_frame_reader.d.ts.map +1 -0
  206. package/dist/testing/transports/sse_frame_reader.js +84 -0
  207. package/dist/testing/transports/sse_transport.d.ts +54 -0
  208. package/dist/testing/transports/sse_transport.d.ts.map +1 -0
  209. package/dist/testing/transports/sse_transport.js +51 -0
  210. package/dist/testing/transports/ws_client.d.ts +108 -0
  211. package/dist/testing/transports/ws_client.d.ts.map +1 -0
  212. package/dist/testing/transports/ws_client.js +56 -0
  213. package/dist/testing/transports/ws_transport.d.ts +43 -0
  214. package/dist/testing/transports/ws_transport.d.ts.map +1 -0
  215. package/dist/testing/transports/ws_transport.js +169 -0
  216. package/dist/testing/ws_round_trip.d.ts +21 -103
  217. package/dist/testing/ws_round_trip.d.ts.map +1 -1
  218. package/dist/testing/ws_round_trip.js +42 -40
  219. package/dist/ui/CLAUDE.md +5 -3
  220. package/dist/ui/MenuLink.svelte +16 -16
  221. package/dist/ui/MenuLink.svelte.d.ts +13 -4
  222. package/dist/ui/MenuLink.svelte.d.ts.map +1 -1
  223. package/package.json +10 -4
@@ -19,7 +19,7 @@ import type { Db, DbType } from '../db/db.js';
19
19
  import type { PasswordHashDeps } from '../auth/password.js';
20
20
  import { type SessionOptions } from '../auth/session_cookie.js';
21
21
  import { type AppBackend, type AuditFactory } from '../server/app_backend.js';
22
- import { type AppServerOptions, type AppServerContext } from '../server/app_server.js';
22
+ import { type AppServerOptions, type AppServerContext, type BootstrapServerOptions, type BootstrapLiveOptions } from '../server/app_server.js';
23
23
  import type { AppSurface, AppSurfaceSpec } from '../http/surface.js';
24
24
  import type { RouteSpec } from '../http/route_spec.js';
25
25
  import type { RpcEndpointsSuiteOption } from './rpc_helpers.js';
@@ -33,9 +33,27 @@ export declare const stub_password_deps: PasswordHashDeps;
33
33
  /** 64-hex-char test cookie secret — deterministic, never used in production. */
34
34
  export declare const TEST_COOKIE_SECRET: string;
35
35
  /**
36
- * Options for `bootstrap_test_account`.
36
+ * Default password for bootstrapped test accounts. Shared between the
37
+ * in-process keeper bootstrap (`bootstrap_test_keeper`,
38
+ * `create_test_account_with_credentials`, `create_test_app_server`,
39
+ * `TestApp.create_account`) and the cross-process bootstrap
40
+ * (`cross_backend/setup.ts`). The two paths MUST agree — when they
41
+ * diverged during the 3d cross-process lift, ~20 login tests 401'd
42
+ * silently against the cross-process backend because the per-test
43
+ * fixture minted accounts under a different default than the
44
+ * integration suite's hardcoded login bodies expected. Consumers
45
+ * hardcoding the literal string in test bodies should import this
46
+ * constant instead so a future divergence becomes a typecheck miss
47
+ * rather than a runtime password mismatch.
37
48
  */
38
- export interface BootstrapTestAccountOptions {
49
+ export declare const DEFAULT_TEST_PASSWORD = "test-password-123";
50
+ /**
51
+ * Options for `bootstrap_test_keeper` and `create_test_account_with_credentials`.
52
+ *
53
+ * Same shape for both — the data inserted is identical; the only behavioral
54
+ * difference is the lock flip on the keeper path.
55
+ */
56
+ export interface CreateTestAccountWithCredentialsOptions {
39
57
  db: Db;
40
58
  keyring: Keyring;
41
59
  session_options: SessionOptions<string>;
@@ -44,17 +62,48 @@ export interface BootstrapTestAccountOptions {
44
62
  password_value?: string;
45
63
  roles?: Array<string>;
46
64
  }
65
+ /** Alias for the keeper-flavored call site. Same shape. */
66
+ export type BootstrapTestKeeperOptions = CreateTestAccountWithCredentialsOptions;
47
67
  /**
48
- * Bootstrap a test account with credentials.
68
+ * Create a test account with credentials. Use for additional accounts
69
+ * minted alongside the keeper (e.g. `TestApp.create_account` for
70
+ * cross-account / multi-user tests). Does NOT flip `bootstrap_lock` —
71
+ * non-keeper accounts should not appear to the system as bootstrap
72
+ * having happened.
49
73
  *
50
74
  * Creates an account with actor, grants roles, creates an API token,
51
- * creates a session, and signs a session cookie. Shared by
52
- * `create_test_app_server` and `TestApp.create_account`.
75
+ * creates a session, and signs a session cookie.
53
76
  *
54
77
  * @mutates the underlying `options.db` — inserts rows into `account`, `actor`,
55
78
  * `role_grant` (one per role), `api_token`, and `auth_session`.
56
79
  */
57
- export declare const bootstrap_test_account: (options: BootstrapTestAccountOptions) => Promise<{
80
+ export declare const create_test_account_with_credentials: (options: CreateTestAccountWithCredentialsOptions) => Promise<{
81
+ account: {
82
+ id: Uuid;
83
+ username: string;
84
+ };
85
+ actor: {
86
+ id: Uuid;
87
+ };
88
+ api_token: string;
89
+ session_cookie: string;
90
+ }>;
91
+ /**
92
+ * Bootstrap the test-DB keeper. Direct-query shortcut for the default
93
+ * `create_test_app` path — bootstrap is not what most tests exercise, so
94
+ * we skip the real `bootstrap_account` flow (no audit row, no
95
+ * `on_bootstrap` callback). Tests that need the full success-path flow
96
+ * use `create_test_app_for_bootstrap` instead.
97
+ *
98
+ * Flips `bootstrap_lock.bootstrapped = true` so the post-insert DB state
99
+ * matches a real bootstrap completion — production code can trust the
100
+ * lock as the single signal without a belt-and-suspenders
101
+ * `query_account_has_any` defense.
102
+ *
103
+ * @mutates the underlying `options.db` — inserts the account/actor/roles/
104
+ * API token/session_cookie rows AND flips `bootstrap_lock.bootstrapped`.
105
+ */
106
+ export declare const bootstrap_test_keeper: (options: BootstrapTestKeeperOptions) => Promise<{
58
107
  account: {
59
108
  id: Uuid;
60
109
  username: string;
@@ -101,7 +150,7 @@ export interface TestAppServerOptions {
101
150
  password?: PasswordHashDeps;
102
151
  /** Username for the bootstrapped account. Default: `'keeper'`. */
103
152
  username?: string;
104
- /** Password for the bootstrapped account. Default: `'test-password-123'`. */
153
+ /** Password for the bootstrapped account. Default: `DEFAULT_TEST_PASSWORD`. */
105
154
  password_value?: string;
106
155
  /** Roles to grant. Default: `[ROLE_KEEPER]`. */
107
156
  roles?: Array<string>;
@@ -122,26 +171,6 @@ export interface TestAppServerOptions {
122
171
  */
123
172
  audit_factory?: AuditFactory;
124
173
  }
125
- /**
126
- * Create an app server with a bootstrapped account for testing.
127
- *
128
- * Sets up:
129
- * - Auth tables (via cached PGlite factory, or reuses existing `db`)
130
- * - A keeper account with hashed password
131
- * - Role role_grants for each role in `options.roles`
132
- * - An API token for Bearer auth
133
- * - A session with a signed cookie value
134
- *
135
- * Uses `stub_password_deps` by default — deterministic hashing that works
136
- * correctly for login/logout tests without Argon2 overhead.
137
- *
138
- * @param options - session options and optional overrides
139
- * @returns a `TestAppServer` ready for HTTP testing
140
- * @mutates the underlying database — when `db` is supplied, resets singleton
141
- * state (`bootstrap_lock.bootstrapped`, `app_settings.open_signup`) before
142
- * bootstrapping; in either branch inserts an account, actor, role role_grants,
143
- * API token, and session row.
144
- */
145
174
  export declare const create_test_app_server: (options: TestAppServerOptions) => Promise<TestAppServer>;
146
175
  /**
147
176
  * Configuration for `create_test_app`.
@@ -159,23 +188,35 @@ export interface CreateTestAppOptions extends TestAppServerOptions {
159
188
  */
160
189
  rpc_endpoints?: RpcEndpointsSuiteOption;
161
190
  /**
162
- * Optional overrides for `AppServerOptions`. The four fields
163
- * `create_test_app` manages are excluded: `backend`, `session_options`,
164
- * `create_route_specs`, and `rpc_endpoints` (see top-level slot above).
191
+ * Bootstrap config symmetric with `AppServerOptions.bootstrap`. Same
192
+ * single-source-of-truth precedent as `rpc_endpoints`: setup-time surface
193
+ * generation and runtime dispatch both read this slot, so the equivalent
194
+ * field under `app_options` is `Omit`'d. Discriminated union over
195
+ * `{mode: 'disabled' | 'surface_only' | 'live'}`. Omit (or pass
196
+ * `{mode: 'disabled'}`) for the default — no bootstrap route mounted.
197
+ *
198
+ * For tests that exercise the bootstrap success path against a real
199
+ * token + empty DB, use `create_test_app_for_bootstrap` instead — it
200
+ * skips the keeper pre-creation that blocks the success branch.
201
+ */
202
+ bootstrap?: BootstrapServerOptions;
203
+ /**
204
+ * Optional overrides for `AppServerOptions`. Excludes fields
205
+ * `create_test_app` manages directly: `backend`, `session_options`,
206
+ * `create_route_specs`, `rpc_endpoints`, `bootstrap` (top-level slots
207
+ * above).
165
208
  */
166
209
  app_options?: SuiteAppOptions;
167
210
  }
168
211
  /**
169
212
  * `app_options` shape accepted by `create_test_app` and the DB-backed suite
170
- * helpers (`describe_standard_integration_tests`,
171
- * `describe_audit_completeness_tests`, etc.). Excludes the four fields the
172
- * helpers manage directly — `backend` / `session_options` /
173
- * `create_route_specs` are constructed by the helper itself; `rpc_endpoints`
174
- * lives on the top-level option (hard-failed by `require_rpc_endpoint_path`
175
- * in the suites) so setup-time path lookup and runtime dispatch read from
176
- * one source of truth.
213
+ * helpers. Excludes fields the helpers manage directly — `backend` /
214
+ * `session_options` / `create_route_specs` are constructed by the helper
215
+ * itself; `rpc_endpoints` and `bootstrap` live on top-level options so
216
+ * setup-time surface lookup and runtime dispatch read from one source of
217
+ * truth.
177
218
  */
178
- export type SuiteAppOptions = Partial<Omit<AppServerOptions, 'backend' | 'session_options' | 'create_route_specs' | 'rpc_endpoints'>>;
219
+ export type SuiteAppOptions = Partial<Omit<AppServerOptions, 'backend' | 'session_options' | 'create_route_specs' | 'rpc_endpoints' | 'bootstrap'>>;
179
220
  /**
180
221
  * A bootstrapped test account with credentials.
181
222
  */
@@ -234,4 +275,65 @@ export interface TestApp {
234
275
  * @returns a `TestApp` ready for HTTP testing
235
276
  */
236
277
  export declare const create_test_app: (options: CreateTestAppOptions) => Promise<TestApp>;
278
+ /**
279
+ * Configuration for `create_test_app_for_bootstrap`. Like
280
+ * `CreateTestAppOptions` but the keeper-related fields drop (no
281
+ * pre-bootstrap keeper) and `bootstrap` is required + narrowed to
282
+ * `live` mode (the helper exists specifically to drive the success
283
+ * path).
284
+ */
285
+ export interface CreateTestAppForBootstrapOptions {
286
+ session_options: SessionOptions<string>;
287
+ create_route_specs: (context: AppServerContext) => Array<RouteSpec>;
288
+ rpc_endpoints?: RpcEndpointsSuiteOption;
289
+ app_options?: SuiteAppOptions;
290
+ /** Live bootstrap config — the test drives `POST /bootstrap` against this. */
291
+ bootstrap: BootstrapLiveOptions;
292
+ /**
293
+ * Token contents the stub fs returns when reading `bootstrap.token_path`.
294
+ * The test posts a body containing this same value as `token` to satisfy
295
+ * the timing-safe equality check inside `bootstrap_account`.
296
+ */
297
+ bootstrap_token: string;
298
+ db?: Db;
299
+ db_type?: DbType;
300
+ password?: PasswordHashDeps;
301
+ audit_factory?: AuditFactory;
302
+ }
303
+ /**
304
+ * A fully assembled test app in the pre-bootstrap state — empty DB,
305
+ * `bootstrap_lock.bootstrapped = false`, no keeper account. Test drives
306
+ * `POST /bootstrap` itself.
307
+ */
308
+ export interface TestAppForBootstrap {
309
+ app: Hono;
310
+ backend: AppBackend;
311
+ surface_spec: AppSurfaceSpec;
312
+ surface: AppSurface;
313
+ route_specs: Array<RouteSpec>;
314
+ /** Build host/origin request headers for the anonymous bootstrap POST. */
315
+ create_request_headers: (extra?: Record<string, string>) => Record<string, string>;
316
+ /** Release test resources (no-op when DB is injected or factory-cached). */
317
+ cleanup: () => Promise<void>;
318
+ }
319
+ /**
320
+ * Create a test app in the pre-bootstrap state for exercising the
321
+ * bootstrap success path end-to-end.
322
+ *
323
+ * Skips the keeper pre-creation `create_test_app` does by default —
324
+ * `bootstrap_lock.bootstrapped` stays at `false` and the DB has no
325
+ * accounts. The fs stubs return `options.bootstrap_token` when the
326
+ * bootstrap handler reads `bootstrap.token_path`, so a `POST /bootstrap`
327
+ * with `{token: bootstrap_token, username, password}` reaches the
328
+ * success branch.
329
+ *
330
+ * Pair with `describe_bootstrap_success_tests` for the consumer-runnable
331
+ * suite that drives the full happy path + adjacent assertions on
332
+ * observable state (account exists, audit row emitted, on_bootstrap
333
+ * callback fired).
334
+ *
335
+ * @param options - bootstrap config + factory inputs
336
+ * @returns a `TestAppForBootstrap` ready for the test to drive bootstrap
337
+ */
338
+ export declare const create_test_app_for_bootstrap: (options: CreateTestAppForBootstrapOptions) => Promise<TestAppForBootstrap>;
237
339
  //# sourceMappingURL=app_server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"app_server.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/app_server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"app_server.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/app_server.ts"],"names":[],"mappings":"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"}
@@ -15,7 +15,6 @@ import { default_audit_factory } from '../server/app_backend.js';
15
15
  import { create_app_server, } from '../server/app_server.js';
16
16
  import { generate_daemon_token, DAEMON_TOKEN_HEADER, } from '../auth/daemon_token.js';
17
17
  import { create_pglite_factory } from './db.js';
18
- /* eslint-disable @typescript-eslint/require-await */
19
18
  /**
20
19
  * Fast password stub for tests that don't exercise login/password flows.
21
20
  *
@@ -29,6 +28,21 @@ export const stub_password_deps = {
29
28
  };
30
29
  /** 64-hex-char test cookie secret — deterministic, never used in production. */
31
30
  export const TEST_COOKIE_SECRET = 'a'.repeat(64);
31
+ /**
32
+ * Default password for bootstrapped test accounts. Shared between the
33
+ * in-process keeper bootstrap (`bootstrap_test_keeper`,
34
+ * `create_test_account_with_credentials`, `create_test_app_server`,
35
+ * `TestApp.create_account`) and the cross-process bootstrap
36
+ * (`cross_backend/setup.ts`). The two paths MUST agree — when they
37
+ * diverged during the 3d cross-process lift, ~20 login tests 401'd
38
+ * silently against the cross-process backend because the per-test
39
+ * fixture minted accounts under a different default than the
40
+ * integration suite's hardcoded login bodies expected. Consumers
41
+ * hardcoding the literal string in test bodies should import this
42
+ * constant instead so a future divergence becomes a typecheck miss
43
+ * rather than a runtime password mismatch.
44
+ */
45
+ export const DEFAULT_TEST_PASSWORD = 'test-password-123';
32
46
  // Module-level PGlite factory for create_test_app_server when no db is provided.
33
47
  // Shares the WASM instance cache from test_db.ts, avoiding redundant cold starts
34
48
  // within the same vitest worker thread. Schema is reset on each create() call.
@@ -36,17 +50,20 @@ const fallback_pglite_factory = create_pglite_factory(async (db) => {
36
50
  await run_migrations(db, [auth_migration_ns]);
37
51
  });
38
52
  /**
39
- * Bootstrap a test account with credentials.
53
+ * Create a test account with credentials. Use for additional accounts
54
+ * minted alongside the keeper (e.g. `TestApp.create_account` for
55
+ * cross-account / multi-user tests). Does NOT flip `bootstrap_lock` —
56
+ * non-keeper accounts should not appear to the system as bootstrap
57
+ * having happened.
40
58
  *
41
59
  * Creates an account with actor, grants roles, creates an API token,
42
- * creates a session, and signs a session cookie. Shared by
43
- * `create_test_app_server` and `TestApp.create_account`.
60
+ * creates a session, and signs a session cookie.
44
61
  *
45
62
  * @mutates the underlying `options.db` — inserts rows into `account`, `actor`,
46
63
  * `role_grant` (one per role), `api_token`, and `auth_session`.
47
64
  */
48
- export const bootstrap_test_account = async (options) => {
49
- const { db, keyring, session_options, password, username = 'keeper', password_value = 'test-password-123', roles = [], } = options;
65
+ export const create_test_account_with_credentials = async (options) => {
66
+ const { db, keyring, session_options, password, username = 'keeper', password_value = DEFAULT_TEST_PASSWORD, roles = [], } = options;
50
67
  const deps = { db };
51
68
  const password_hash = await password.hash_password(password_value);
52
69
  const { account, actor } = await query_create_account_with_actor(deps, {
@@ -73,54 +90,63 @@ export const bootstrap_test_account = async (options) => {
73
90
  session_cookie,
74
91
  };
75
92
  };
76
- /** Silent logger for tests — suppresses all output. */
77
- const test_log = new Logger('test', { level: 'off' });
78
93
  /**
79
- * Create an app server with a bootstrapped account for testing.
94
+ * Bootstrap the test-DB keeper. Direct-query shortcut for the default
95
+ * `create_test_app` path — bootstrap is not what most tests exercise, so
96
+ * we skip the real `bootstrap_account` flow (no audit row, no
97
+ * `on_bootstrap` callback). Tests that need the full success-path flow
98
+ * use `create_test_app_for_bootstrap` instead.
80
99
  *
81
- * Sets up:
82
- * - Auth tables (via cached PGlite factory, or reuses existing `db`)
83
- * - A keeper account with hashed password
84
- * - Role role_grants for each role in `options.roles`
85
- * - An API token for Bearer auth
86
- * - A session with a signed cookie value
100
+ * Flips `bootstrap_lock.bootstrapped = true` so the post-insert DB state
101
+ * matches a real bootstrap completion production code can trust the
102
+ * lock as the single signal without a belt-and-suspenders
103
+ * `query_account_has_any` defense.
87
104
  *
88
- * Uses `stub_password_deps` by default deterministic hashing that works
89
- * correctly for login/logout tests without Argon2 overhead.
105
+ * @mutates the underlying `options.db` — inserts the account/actor/roles/
106
+ * API token/session_cookie rows AND flips `bootstrap_lock.bootstrapped`.
107
+ */
108
+ export const bootstrap_test_keeper = async (options) => {
109
+ const result = await create_test_account_with_credentials(options);
110
+ // Lock flip — mirrors production `bootstrap_account` so test/prod write
111
+ // semantics stay in parity.
112
+ await options.db.query('UPDATE bootstrap_lock SET bootstrapped = true WHERE id = 1 AND bootstrapped = false');
113
+ return result;
114
+ };
115
+ /** Silent logger for tests — suppresses all output. */
116
+ const test_log = new Logger('test', { level: 'off' });
117
+ const default_test_fs_stubs = {
118
+ stat: async () => null,
119
+ read_text_file: async () => '',
120
+ delete_file: async () => { },
121
+ };
122
+ /**
123
+ * Shared backend-assembly path for `create_test_app_server` and
124
+ * `create_test_app_for_bootstrap`. Returns the raw `AppBackend` + the
125
+ * keyring used to sign session cookies; callers wrap with their own
126
+ * concerns (keeper pre-creation vs. pre-bootstrap state).
90
127
  *
91
- * @param options - session options and optional overrides
92
- * @returns a `TestAppServer` ready for HTTP testing
93
- * @mutates the underlying database — when `db` is supplied, resets singleton
94
- * state (`bootstrap_lock.bootstrapped`, `app_settings.open_signup`) before
95
- * bootstrapping; in either branch inserts an account, actor, role role_grants,
96
- * API token, and session row.
128
+ * Resets `app_settings` singleton row for caller-supplied DBs so prior
129
+ * tests don't leak `open_signup`. Does NOT reset `bootstrap_lock` —
130
+ * callers own that policy (`create_test_app_server` lets
131
+ * `bootstrap_test_keeper` flip it; `create_test_app_for_bootstrap`
132
+ * resets it to false before this runs).
97
133
  */
98
- export const create_test_app_server = async (options) => {
99
- const { session_options, db: existing_db, db_type = 'pglite-memory', password = stub_password_deps, username = 'keeper', password_value = 'test-password-123', roles = [ROLE_KEEPER], audit_factory = default_audit_factory, } = options;
100
- // Keyring from test secret
134
+ const _build_test_backend = async (options) => {
135
+ const { db: existing_db, db_type = 'pglite-memory', password = stub_password_deps, audit_factory = default_audit_factory, fs_stubs = default_test_fs_stubs, } = options;
101
136
  const keyring_result = create_validated_keyring(TEST_COOKIE_SECRET);
102
137
  if (!keyring_result.ok) {
103
138
  throw new Error(`Test keyring failed: ${keyring_result.errors.join(', ')}`);
104
139
  }
105
- const fs_stubs = {
106
- stat: async () => null,
107
- read_text_file: async () => '',
108
- delete_file: async (_path) => { }, // eslint-disable-line @typescript-eslint/no-empty-function
109
- };
110
140
  let backend;
111
141
  if (existing_db) {
112
- // Reset singleton config rows that may retain state from a previous test.
113
- // Harmless for fresh pglite (these are already at defaults).
114
- await existing_db.query('UPDATE bootstrap_lock SET bootstrapped = false WHERE bootstrapped = true');
142
+ // Reset singleton config row from a previous test (harmless on fresh pglite).
115
143
  await existing_db.query('UPDATE app_settings SET open_signup = false, updated_at = NULL, updated_by = NULL WHERE open_signup = true OR updated_at IS NOT NULL');
116
- // Use the caller's database — tables already created by the factory's init_schema.
117
- // Caller owns the DB lifecycle — close is a no-op.
118
144
  const audit = audit_factory({ db: existing_db, log: test_log });
119
145
  backend = {
120
146
  db_type,
121
147
  db_name: 'test',
122
- migration_results: [], // migrations ran in the factory's init_schema, results not captured
123
- close: async () => { }, // eslint-disable-line @typescript-eslint/no-empty-function
148
+ migration_results: [], // migrations ran in the factory's init_schema
149
+ close: async () => { },
124
150
  deps: {
125
151
  keyring: keyring_result.keyring,
126
152
  password,
@@ -141,7 +167,7 @@ export const create_test_app_server = async (options) => {
141
167
  db_type: 'pglite-memory',
142
168
  db_name: '(memory)',
143
169
  migration_results: [],
144
- close: async () => { }, // eslint-disable-line @typescript-eslint/no-empty-function
170
+ close: async () => { },
145
171
  deps: {
146
172
  keyring: keyring_result.keyring,
147
173
  password,
@@ -152,9 +178,14 @@ export const create_test_app_server = async (options) => {
152
178
  },
153
179
  };
154
180
  }
155
- const bootstrapped = await bootstrap_test_account({
181
+ return { backend, keyring: keyring_result.keyring };
182
+ };
183
+ export const create_test_app_server = async (options) => {
184
+ const { session_options, password = stub_password_deps, username = 'keeper', password_value = DEFAULT_TEST_PASSWORD, roles = [ROLE_KEEPER], } = options;
185
+ const { backend, keyring } = await _build_test_backend(options);
186
+ const bootstrapped = await bootstrap_test_keeper({
156
187
  db: backend.deps.db,
157
- keyring: keyring_result.keyring,
188
+ keyring,
158
189
  session_options,
159
190
  password,
160
191
  username,
@@ -164,7 +195,7 @@ export const create_test_app_server = async (options) => {
164
195
  return {
165
196
  ...backend,
166
197
  ...bootstrapped,
167
- keyring: keyring_result.keyring,
198
+ keyring,
168
199
  cleanup: () => backend.close(),
169
200
  };
170
201
  };
@@ -205,6 +236,7 @@ export const create_test_app = async (options) => {
205
236
  await_pending_effects: true,
206
237
  daemon_token_state,
207
238
  rpc_endpoints: options.rpc_endpoints,
239
+ bootstrap: options.bootstrap,
208
240
  ...options.app_options,
209
241
  create_route_specs: options.create_route_specs,
210
242
  });
@@ -230,13 +262,13 @@ export const create_test_app = async (options) => {
230
262
  let account_counter = 0;
231
263
  const create_account = async (account_options) => {
232
264
  account_counter++;
233
- const bootstrapped = await bootstrap_test_account({
265
+ const bootstrapped = await create_test_account_with_credentials({
234
266
  db: test_server.deps.db,
235
267
  keyring: test_server.keyring,
236
268
  session_options: options.session_options,
237
269
  password,
238
270
  username: account_options?.username ?? `test_user_${account_counter}`,
239
- password_value: account_options?.password_value ?? 'test-password-123',
271
+ password_value: account_options?.password_value ?? DEFAULT_TEST_PASSWORD,
240
272
  roles: account_options?.roles ?? [],
241
273
  });
242
274
  return {
@@ -267,3 +299,84 @@ export const create_test_app = async (options) => {
267
299
  cleanup: () => test_server.cleanup(),
268
300
  };
269
301
  };
302
+ /**
303
+ * Create a test app in the pre-bootstrap state for exercising the
304
+ * bootstrap success path end-to-end.
305
+ *
306
+ * Skips the keeper pre-creation `create_test_app` does by default —
307
+ * `bootstrap_lock.bootstrapped` stays at `false` and the DB has no
308
+ * accounts. The fs stubs return `options.bootstrap_token` when the
309
+ * bootstrap handler reads `bootstrap.token_path`, so a `POST /bootstrap`
310
+ * with `{token: bootstrap_token, username, password}` reaches the
311
+ * success branch.
312
+ *
313
+ * Pair with `describe_bootstrap_success_tests` for the consumer-runnable
314
+ * suite that drives the full happy path + adjacent assertions on
315
+ * observable state (account exists, audit row emitted, on_bootstrap
316
+ * callback fired).
317
+ *
318
+ * @param options - bootstrap config + factory inputs
319
+ * @returns a `TestAppForBootstrap` ready for the test to drive bootstrap
320
+ */
321
+ export const create_test_app_for_bootstrap = async (options) => {
322
+ const { session_options, bootstrap, bootstrap_token } = options;
323
+ // Caller-supplied DB may carry lock state from a prior test — reset to false
324
+ // before `_build_test_backend` runs (which doesn't touch the lock itself).
325
+ // Fresh pglite already starts at false (factory init).
326
+ if (options.db) {
327
+ await options.db.query('UPDATE bootstrap_lock SET bootstrapped = false WHERE bootstrapped = true');
328
+ }
329
+ // Token-aware fs stubs: the bootstrap route's filesystem operations resolve
330
+ // against the configured token_path; everything else returns no-op defaults.
331
+ let token_file_deleted = false;
332
+ const fs_stubs = {
333
+ stat: async (path) => path === bootstrap.token_path && !token_file_deleted
334
+ ? { is_file: true, is_directory: false }
335
+ : null,
336
+ read_text_file: async (path) => path === bootstrap.token_path && !token_file_deleted ? bootstrap_token : '',
337
+ delete_file: async (path) => {
338
+ if (path === bootstrap.token_path)
339
+ token_file_deleted = true;
340
+ },
341
+ };
342
+ const { backend } = await _build_test_backend({ ...options, fs_stubs });
343
+ // Daemon token state isn't reachable pre-bootstrap (no keeper account)
344
+ // but the field is required by AppServerOptions; pass a placeholder.
345
+ const daemon_token_state = {
346
+ current_token: generate_daemon_token(),
347
+ previous_token: null,
348
+ rotated_at: new Date(),
349
+ keeper_account_id: null,
350
+ };
351
+ const result = await create_app_server({
352
+ backend,
353
+ session_options,
354
+ allowed_origins: [/^http:\/\/localhost/],
355
+ proxy: { trusted_proxies: ['127.0.0.1'], get_connection_ip: () => '127.0.0.1' },
356
+ env_schema: z.object({}),
357
+ ip_rate_limiter: null,
358
+ login_account_rate_limiter: null,
359
+ signup_account_rate_limiter: null,
360
+ bearer_ip_rate_limiter: null,
361
+ await_pending_effects: true,
362
+ daemon_token_state,
363
+ rpc_endpoints: options.rpc_endpoints,
364
+ bootstrap,
365
+ ...options.app_options,
366
+ create_route_specs: options.create_route_specs,
367
+ });
368
+ const create_request_headers = (extra) => ({
369
+ host: 'localhost',
370
+ origin: 'http://localhost:5173',
371
+ ...extra,
372
+ });
373
+ return {
374
+ app: result.app,
375
+ backend,
376
+ surface_spec: result.surface_spec,
377
+ surface: result.surface_spec.surface,
378
+ route_specs: result.surface_spec.route_specs,
379
+ create_request_headers,
380
+ cleanup: () => backend.close(),
381
+ };
382
+ };
@@ -1,42 +1,45 @@
1
1
  import './assert_dev_env.js';
2
2
  import type { SessionOptions } from '../auth/session_cookie.js';
3
- import type { AppServerContext } from '../server/app_server.js';
4
- import type { RouteSpec } from '../http/route_spec.js';
5
- import { type SuiteAppOptions } from './app_server.js';
6
- import { type DbFactory } from './db.js';
7
3
  import { type RpcEndpointsSuiteOption } from './rpc_helpers.js';
4
+ import type { AppSurfaceSpec } from '../http/surface.js';
5
+ import type { BackendCapabilities } from './cross_backend/capabilities.js';
6
+ import type { SetupTest } from './cross_backend/setup.js';
8
7
  /**
9
8
  * Configuration for `describe_audit_completeness_tests`.
10
9
  */
11
10
  export interface AuditCompletenessTestOptions {
12
- /** Session config for cookie-based auth. */
11
+ /**
12
+ * Per-test fixture-producing function. The audit suite calls this
13
+ * in every `test()` body — `auth_integration_truncate_tables` clears
14
+ * the audit log between tests, so each test re-bootstraps the
15
+ * keeper and the observer admin against a fresh table.
16
+ */
17
+ setup_test: SetupTest;
18
+ /**
19
+ * App surface (with route specs). Constructed in TS by the consumer;
20
+ * same shape for in-process and cross-process tests. The audit suite is
21
+ * Tier 2 today (stays in-process per the cross-backend-integration
22
+ * design), but takes the same surface shape as Tier 1 suites for
23
+ * options uniformity.
24
+ */
25
+ surface_source: AppSurfaceSpec;
26
+ /** Backend capability declarations. */
27
+ capabilities: BackendCapabilities;
28
+ /** Session config — needed for factory-form rpc_endpoints resolution. */
13
29
  session_options: SessionOptions<string>;
14
- /** Route spec factory — same one used in production. */
15
- create_route_specs: (ctx: AppServerContext) => Array<RouteSpec>;
16
30
  /**
17
- * RPC endpoint specs — the source `RpcAction` arrays. Required; the
18
- * admin role_grant flow is RPC-only and the suite hard-fails without it.
19
- *
20
- * Accepts either an array (eager) or a factory
21
- * `(ctx: AppServerContext) => Array<RpcEndpointSpec>` — the factory form
22
- * is required when action handlers must close over the per-test
23
- * `ctx.app_settings` / `ctx.deps` (e.g. exercising `app_settings_update`).
24
- * The factory must return the same endpoint `path` regardless of ctx —
25
- * it is invoked once at setup with a stub ctx for path lookup and again
26
- * per-test by `create_app_server` for live dispatch.
31
+ * RPC endpoint specs — required. The admin role_grant flow is RPC-only
32
+ * and the suite hard-fails without it.
27
33
  */
28
34
  rpc_endpoints: RpcEndpointsSuiteOption;
29
- /** Optional overrides for `AppServerOptions`. */
30
- app_options?: SuiteAppOptions;
31
- /** Database factories to run tests against. Default: pglite only. */
32
- db_factories?: Array<DbFactory>;
33
35
  }
34
36
  /**
35
37
  * Composable audit log completeness test suite.
36
38
  *
37
39
  * Verifies that every auth mutation route produces the correct audit log
38
40
  * event type. Exercises routes via HTTP requests against a real PGlite
39
- * database, then queries the `audit_log` table to verify events.
41
+ * database, then reads events back through the `audit_log_list` RPC
42
+ * (the production observation path the admin UI consumes).
40
43
  *
41
44
  * @throws Error at setup time when `options.rpc_endpoints` is empty — the
42
45
  * mutation-audit tests drive role_grant flow, session/token revoke-all, and
@@ -1 +1 @@
1
- {"version":3,"file":"audit_completeness.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/audit_completeness.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAkB7B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAIrD,OAAO,EAGN,KAAK,eAAe,EAEpB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAIN,KAAK,SAAS,EACd,MAAM,SAAS,CAAC;AAKjB,OAAO,EAIN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AAqB1B;;GAEG;AACH,MAAM,WAAW,4BAA4B;IAC5C,4CAA4C;IAC5C,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC,wDAAwD;IACxD,kBAAkB,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,KAAK,CAAC,SAAS,CAAC,CAAC;IAChE;;;;;;;;;;;OAWG;IACH,aAAa,EAAE,uBAAuB,CAAC;IACvC,iDAAiD;IACjD,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,qEAAqE;IACrE,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;CAChC;AAyED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,iCAAiC,GAAI,SAAS,4BAA4B,KAAG,IAihBzF,CAAC"}
1
+ {"version":3,"file":"audit_completeness.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/audit_completeness.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AA4B7B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAS9D,OAAO,EAKN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AAwB1B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,iCAAiC,CAAC;AACzE,OAAO,KAAK,EAAC,SAAS,EAAc,MAAM,0BAA0B,CAAC;AAErE;;GAEG;AACH,MAAM,WAAW,4BAA4B;IAC5C;;;;;OAKG;IACH,UAAU,EAAE,SAAS,CAAC;IACtB;;;;;;OAMG;IACH,cAAc,EAAE,cAAc,CAAC;IAC/B,uCAAuC;IACvC,YAAY,EAAE,mBAAmB,CAAC;IAClC,yEAAyE;IACzE,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC;;;OAGG;IACH,aAAa,EAAE,uBAAuB,CAAC;CACvC;AA8FD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,iCAAiC,GAAI,SAAS,4BAA4B,KAAG,IAuhBzF,CAAC"}