@fuzdev/fuz_app 0.63.0 → 0.65.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 (181) hide show
  1. package/dist/actions/CLAUDE.md +525 -827
  2. package/dist/actions/broadcast_api.d.ts +1 -1
  3. package/dist/actions/broadcast_api.js +1 -1
  4. package/dist/actions/cancel.d.ts +2 -2
  5. package/dist/actions/cancel.js +3 -3
  6. package/dist/actions/connection_closer.d.ts +65 -0
  7. package/dist/actions/connection_closer.d.ts.map +1 -0
  8. package/dist/actions/connection_closer.js +38 -0
  9. package/dist/actions/register_action_ws.d.ts +2 -2
  10. package/dist/actions/register_action_ws.d.ts.map +1 -1
  11. package/dist/actions/register_action_ws.js +23 -2
  12. package/dist/actions/register_ws_endpoint.d.ts +12 -10
  13. package/dist/actions/register_ws_endpoint.d.ts.map +1 -1
  14. package/dist/actions/register_ws_endpoint.js +5 -5
  15. package/dist/actions/transports_ws_auth_guard.d.ts +25 -10
  16. package/dist/actions/transports_ws_auth_guard.d.ts.map +1 -1
  17. package/dist/actions/transports_ws_auth_guard.js +24 -9
  18. package/dist/actions/ws_endpoint_spec.d.ts +119 -0
  19. package/dist/actions/ws_endpoint_spec.d.ts.map +1 -0
  20. package/dist/actions/ws_endpoint_spec.js +13 -0
  21. package/dist/auth/CLAUDE.md +592 -1808
  22. package/dist/auth/account_action_specs.d.ts +1 -1
  23. package/dist/auth/account_actions.d.ts +13 -0
  24. package/dist/auth/account_actions.d.ts.map +1 -1
  25. package/dist/auth/account_actions.js +31 -1
  26. package/dist/auth/account_routes.d.ts +12 -2
  27. package/dist/auth/account_routes.d.ts.map +1 -1
  28. package/dist/auth/account_routes.js +55 -8
  29. package/dist/auth/account_schema.d.ts +4 -4
  30. package/dist/auth/account_schema.d.ts.map +1 -1
  31. package/dist/auth/admin_action_specs.d.ts +8 -8
  32. package/dist/auth/admin_actions.d.ts +11 -0
  33. package/dist/auth/admin_actions.d.ts.map +1 -1
  34. package/dist/auth/admin_actions.js +25 -0
  35. package/dist/auth/api_token_queries.js +1 -1
  36. package/dist/auth/audit_emitter.d.ts +56 -12
  37. package/dist/auth/audit_emitter.d.ts.map +1 -1
  38. package/dist/auth/audit_emitter.js +38 -12
  39. package/dist/auth/audit_log_ddl.d.ts +1 -1
  40. package/dist/auth/audit_log_ddl.d.ts.map +1 -1
  41. package/dist/auth/audit_log_ddl.js +1 -1
  42. package/dist/auth/audit_log_schema.d.ts +5 -3
  43. package/dist/auth/audit_log_schema.d.ts.map +1 -1
  44. package/dist/auth/audit_log_schema.js +5 -3
  45. package/dist/auth/bootstrap_account.d.ts.map +1 -1
  46. package/dist/auth/bootstrap_account.js +1 -5
  47. package/dist/auth/bootstrap_routes.d.ts +8 -2
  48. package/dist/auth/bootstrap_routes.d.ts.map +1 -1
  49. package/dist/auth/bootstrap_routes.js +15 -11
  50. package/dist/auth/invite_schema.d.ts +2 -2
  51. package/dist/auth/keyring.d.ts +6 -6
  52. package/dist/auth/keyring.js +8 -8
  53. package/dist/auth/role_grant_offer_actions.d.ts.map +1 -1
  54. package/dist/auth/role_grant_offer_actions.js +4 -2
  55. package/dist/auth/signup_routes.d.ts +1 -1
  56. package/dist/auth/standard_rpc_actions.d.ts +1 -0
  57. package/dist/auth/standard_rpc_actions.d.ts.map +1 -1
  58. package/dist/auth/standard_rpc_actions.js +1 -0
  59. package/dist/db/create_db.d.ts.map +1 -1
  60. package/dist/db/create_db.js +13 -0
  61. package/dist/dev/setup.d.ts +2 -2
  62. package/dist/dev/setup.js +3 -3
  63. package/dist/http/CLAUDE.md +225 -483
  64. package/dist/http/error_schemas.d.ts +0 -4
  65. package/dist/http/error_schemas.d.ts.map +1 -1
  66. package/dist/http/error_schemas.js +0 -4
  67. package/dist/http/ip_canonical.d.ts +100 -0
  68. package/dist/http/ip_canonical.d.ts.map +1 -0
  69. package/dist/http/ip_canonical.js +195 -0
  70. package/dist/http/origin.d.ts +14 -6
  71. package/dist/http/origin.d.ts.map +1 -1
  72. package/dist/http/origin.js +14 -32
  73. package/dist/http/pending_effects.d.ts +1 -1
  74. package/dist/http/pending_effects.js +1 -1
  75. package/dist/http/proxy.d.ts +13 -5
  76. package/dist/http/proxy.d.ts.map +1 -1
  77. package/dist/http/proxy.js +15 -23
  78. package/dist/http/surface.d.ts +50 -0
  79. package/dist/http/surface.d.ts.map +1 -1
  80. package/dist/http/surface.js +27 -1
  81. package/dist/primitive_schemas.d.ts +20 -4
  82. package/dist/primitive_schemas.d.ts.map +1 -1
  83. package/dist/primitive_schemas.js +25 -4
  84. package/dist/realtime/sse_auth_guard.d.ts +16 -4
  85. package/dist/realtime/sse_auth_guard.d.ts.map +1 -1
  86. package/dist/realtime/sse_auth_guard.js +15 -3
  87. package/dist/runtime/mock.js +1 -1
  88. package/dist/server/app_backend.d.ts +66 -19
  89. package/dist/server/app_backend.d.ts.map +1 -1
  90. package/dist/server/app_backend.js +57 -34
  91. package/dist/server/app_server.d.ts +101 -10
  92. package/dist/server/app_server.d.ts.map +1 -1
  93. package/dist/server/app_server.js +105 -6
  94. package/dist/server/env.d.ts +7 -7
  95. package/dist/server/env.d.ts.map +1 -1
  96. package/dist/server/env.js +14 -14
  97. package/dist/server/startup.d.ts.map +1 -1
  98. package/dist/server/startup.js +12 -0
  99. package/dist/server/static.d.ts +4 -4
  100. package/dist/server/static.js +7 -7
  101. package/dist/testing/CLAUDE.md +269 -59
  102. package/dist/testing/admin_integration.d.ts +18 -23
  103. package/dist/testing/admin_integration.d.ts.map +1 -1
  104. package/dist/testing/admin_integration.js +159 -202
  105. package/dist/testing/adversarial_headers.d.ts +6 -0
  106. package/dist/testing/adversarial_headers.d.ts.map +1 -1
  107. package/dist/testing/adversarial_headers.js +13 -5
  108. package/dist/testing/app_server.d.ts +148 -60
  109. package/dist/testing/app_server.d.ts.map +1 -1
  110. package/dist/testing/app_server.js +143 -54
  111. package/dist/testing/attack_surface.d.ts +8 -7
  112. package/dist/testing/attack_surface.d.ts.map +1 -1
  113. package/dist/testing/attack_surface.js +12 -8
  114. package/dist/testing/audit_completeness.d.ts +23 -22
  115. package/dist/testing/audit_completeness.d.ts.map +1 -1
  116. package/dist/testing/audit_completeness.js +199 -158
  117. package/dist/testing/audit_drift_guard.d.ts +116 -0
  118. package/dist/testing/audit_drift_guard.d.ts.map +1 -0
  119. package/dist/testing/audit_drift_guard.js +134 -0
  120. package/dist/testing/bootstrap_success.d.ts +28 -0
  121. package/dist/testing/bootstrap_success.d.ts.map +1 -0
  122. package/dist/testing/bootstrap_success.js +144 -0
  123. package/dist/testing/connection_closer_helpers.d.ts +44 -0
  124. package/dist/testing/connection_closer_helpers.d.ts.map +1 -0
  125. package/dist/testing/connection_closer_helpers.js +48 -0
  126. package/dist/testing/cross_backend/capabilities.d.ts +64 -0
  127. package/dist/testing/cross_backend/capabilities.d.ts.map +1 -0
  128. package/dist/testing/cross_backend/capabilities.js +47 -0
  129. package/dist/testing/cross_backend/setup.d.ts +215 -0
  130. package/dist/testing/cross_backend/setup.d.ts.map +1 -0
  131. package/dist/testing/cross_backend/setup.js +101 -0
  132. package/dist/testing/data_exposure.d.ts +14 -15
  133. package/dist/testing/data_exposure.d.ts.map +1 -1
  134. package/dist/testing/data_exposure.js +127 -146
  135. package/dist/testing/db_entities.d.ts +11 -1
  136. package/dist/testing/db_entities.d.ts.map +1 -1
  137. package/dist/testing/db_entities.js +13 -1
  138. package/dist/testing/integration.d.ts +35 -21
  139. package/dist/testing/integration.d.ts.map +1 -1
  140. package/dist/testing/integration.js +231 -293
  141. package/dist/testing/integration_helpers.d.ts +16 -6
  142. package/dist/testing/integration_helpers.d.ts.map +1 -1
  143. package/dist/testing/integration_helpers.js +7 -7
  144. package/dist/testing/mock_fs.d.ts.map +1 -1
  145. package/dist/testing/mock_fs.js +0 -2
  146. package/dist/testing/rate_limiting.d.ts.map +1 -1
  147. package/dist/testing/rate_limiting.js +13 -4
  148. package/dist/testing/role_grant_helpers.d.ts +31 -0
  149. package/dist/testing/role_grant_helpers.d.ts.map +1 -0
  150. package/dist/testing/role_grant_helpers.js +46 -0
  151. package/dist/testing/round_trip.d.ts +21 -16
  152. package/dist/testing/round_trip.d.ts.map +1 -1
  153. package/dist/testing/round_trip.js +65 -86
  154. package/dist/testing/rpc_helpers.d.ts +2 -1
  155. package/dist/testing/rpc_helpers.d.ts.map +1 -1
  156. package/dist/testing/rpc_round_trip.d.ts +24 -21
  157. package/dist/testing/rpc_round_trip.d.ts.map +1 -1
  158. package/dist/testing/rpc_round_trip.js +91 -106
  159. package/dist/testing/schema_introspect.d.ts +106 -0
  160. package/dist/testing/schema_introspect.d.ts.map +1 -0
  161. package/dist/testing/schema_introspect.js +123 -0
  162. package/dist/testing/schema_parity.d.ts +144 -0
  163. package/dist/testing/schema_parity.d.ts.map +1 -0
  164. package/dist/testing/schema_parity.js +233 -0
  165. package/dist/testing/sse_round_trip.d.ts.map +1 -1
  166. package/dist/testing/sse_round_trip.js +12 -6
  167. package/dist/testing/standard.d.ts +57 -25
  168. package/dist/testing/standard.d.ts.map +1 -1
  169. package/dist/testing/standard.js +62 -5
  170. package/dist/testing/stubs.d.ts +22 -3
  171. package/dist/testing/stubs.d.ts.map +1 -1
  172. package/dist/testing/stubs.js +28 -21
  173. package/dist/testing/surface_invariants.d.ts +66 -1
  174. package/dist/testing/surface_invariants.d.ts.map +1 -1
  175. package/dist/testing/surface_invariants.js +103 -1
  176. package/dist/testing/transports/surface_source.d.ts +51 -0
  177. package/dist/testing/transports/surface_source.d.ts.map +1 -0
  178. package/dist/testing/transports/surface_source.js +19 -0
  179. package/dist/ui/SurfaceExplorer.svelte +161 -2
  180. package/dist/ui/SurfaceExplorer.svelte.d.ts.map +1 -1
  181. package/package.json +4 -4
@@ -0,0 +1,233 @@
1
+ import './assert_dev_env.js';
2
+ /**
3
+ * Structural diff between two snapshots — empty array means parity holds.
4
+ *
5
+ * Order of diffs is deterministic: schema_version first, then tables in
6
+ * sorted order (with column/index/constraint sub-diffs grouped per table),
7
+ * then sequences. Consumers can rely on this for stable diff output.
8
+ */
9
+ export const diff_schema_snapshots = (a, b) => {
10
+ const diffs = [];
11
+ diff_schema_version(a.schema_version, b.schema_version, diffs);
12
+ const all_tables = new Set([...Object.keys(a.tables), ...Object.keys(b.tables)]);
13
+ for (const table of [...all_tables].sort()) {
14
+ const ta = a.tables[table];
15
+ const tb = b.tables[table];
16
+ if (!ta) {
17
+ diffs.push({ kind: 'table_only_in', where: 'b', table });
18
+ continue;
19
+ }
20
+ if (!tb) {
21
+ diffs.push({ kind: 'table_only_in', where: 'a', table });
22
+ continue;
23
+ }
24
+ diff_table(table, ta, tb, diffs);
25
+ }
26
+ const all_sequences = new Set([...Object.keys(a.sequences), ...Object.keys(b.sequences)]);
27
+ for (const sequence of [...all_sequences].sort()) {
28
+ const sa = a.sequences[sequence];
29
+ const sb = b.sequences[sequence];
30
+ if (!sa) {
31
+ diffs.push({ kind: 'sequence_only_in', where: 'b', sequence });
32
+ continue;
33
+ }
34
+ if (!sb) {
35
+ diffs.push({ kind: 'sequence_only_in', where: 'a', sequence });
36
+ continue;
37
+ }
38
+ diff_sequence(sequence, sa, sb, diffs);
39
+ }
40
+ return diffs;
41
+ };
42
+ const diff_schema_version = (a, b, out) => {
43
+ const key = (r) => `${r.namespace}\x00${r.name}`;
44
+ const a_by_key = new Map(a.map((r) => [key(r), r]));
45
+ const b_by_key = new Map(b.map((r) => [key(r), r]));
46
+ const keys = new Set([...a_by_key.keys(), ...b_by_key.keys()]);
47
+ for (const k of [...keys].sort()) {
48
+ const row_a = a_by_key.get(k);
49
+ const row_b = b_by_key.get(k);
50
+ if (!row_a) {
51
+ out.push({ kind: 'schema_version_only_in', where: 'b', row: row_b });
52
+ continue;
53
+ }
54
+ if (!row_b) {
55
+ out.push({ kind: 'schema_version_only_in', where: 'a', row: row_a });
56
+ continue;
57
+ }
58
+ if (row_a.sequence !== row_b.sequence) {
59
+ out.push({
60
+ kind: 'schema_version_sequence_differs',
61
+ namespace: row_a.namespace,
62
+ name: row_a.name,
63
+ a: row_a.sequence,
64
+ b: row_b.sequence,
65
+ });
66
+ }
67
+ }
68
+ };
69
+ const COLUMN_FIELDS = [
70
+ 'data_type',
71
+ 'udt_name',
72
+ 'is_nullable',
73
+ 'column_default',
74
+ 'is_identity',
75
+ ];
76
+ const diff_table = (table, a, b, out) => {
77
+ const all_columns = new Set([...Object.keys(a.columns), ...Object.keys(b.columns)]);
78
+ for (const column of [...all_columns].sort()) {
79
+ const ca = a.columns[column];
80
+ const cb = b.columns[column];
81
+ if (!ca) {
82
+ out.push({ kind: 'column_only_in', where: 'b', table, column });
83
+ continue;
84
+ }
85
+ if (!cb) {
86
+ out.push({ kind: 'column_only_in', where: 'a', table, column });
87
+ continue;
88
+ }
89
+ for (const field of COLUMN_FIELDS) {
90
+ if (ca[field] !== cb[field]) {
91
+ out.push({
92
+ kind: 'column_field_differs',
93
+ table,
94
+ column,
95
+ field,
96
+ a: ca[field],
97
+ b: cb[field],
98
+ });
99
+ }
100
+ }
101
+ }
102
+ const a_indexes = new Map(a.indexes.map((i) => [i.name, i.definition]));
103
+ const b_indexes = new Map(b.indexes.map((i) => [i.name, i.definition]));
104
+ const all_indexes = new Set([...a_indexes.keys(), ...b_indexes.keys()]);
105
+ for (const index of [...all_indexes].sort()) {
106
+ const def_a = a_indexes.get(index);
107
+ const def_b = b_indexes.get(index);
108
+ if (def_a === undefined) {
109
+ out.push({ kind: 'index_only_in', where: 'b', table, index });
110
+ continue;
111
+ }
112
+ if (def_b === undefined) {
113
+ out.push({ kind: 'index_only_in', where: 'a', table, index });
114
+ continue;
115
+ }
116
+ if (def_a !== def_b) {
117
+ out.push({ kind: 'index_definition_differs', table, index, a: def_a, b: def_b });
118
+ }
119
+ }
120
+ const a_constraints = new Map(a.constraints.map((c) => [c.name, c]));
121
+ const b_constraints = new Map(b.constraints.map((c) => [c.name, c]));
122
+ const all_constraints = new Set([...a_constraints.keys(), ...b_constraints.keys()]);
123
+ for (const constraint of [...all_constraints].sort()) {
124
+ const ca = a_constraints.get(constraint);
125
+ const cb = b_constraints.get(constraint);
126
+ if (!ca) {
127
+ out.push({ kind: 'constraint_only_in', where: 'b', table, constraint });
128
+ continue;
129
+ }
130
+ if (!cb) {
131
+ out.push({ kind: 'constraint_only_in', where: 'a', table, constraint });
132
+ continue;
133
+ }
134
+ if (ca.type !== cb.type || ca.definition !== cb.definition) {
135
+ out.push({
136
+ kind: 'constraint_differs',
137
+ table,
138
+ constraint,
139
+ a: { type: ca.type, definition: ca.definition },
140
+ b: { type: cb.type, definition: cb.definition },
141
+ });
142
+ }
143
+ }
144
+ };
145
+ const diff_sequence = (sequence, a, b, out) => {
146
+ if (a.data_type !== b.data_type) {
147
+ out.push({
148
+ kind: 'sequence_data_type_differs',
149
+ sequence,
150
+ a: a.data_type,
151
+ b: b.data_type,
152
+ });
153
+ }
154
+ };
155
+ /**
156
+ * Render a diff list as a human-readable multi-line string. Empty diffs
157
+ * produce an empty string.
158
+ */
159
+ export const format_schema_diffs = (diffs, labels = {}) => {
160
+ if (diffs.length === 0)
161
+ return '';
162
+ const label_a = labels.a ?? 'a';
163
+ const label_b = labels.b ?? 'b';
164
+ const where_label = (where) => (where === 'a' ? label_a : label_b);
165
+ const lines = [];
166
+ for (const d of diffs) {
167
+ switch (d.kind) {
168
+ case 'schema_version_only_in':
169
+ lines.push(` schema_version row only in ${where_label(d.where)}: ${d.row.namespace}/${d.row.name} (sequence ${d.row.sequence})`);
170
+ break;
171
+ case 'schema_version_sequence_differs':
172
+ lines.push(` schema_version sequence differs for ${d.namespace}/${d.name}: ${label_a}=${d.a}, ${label_b}=${d.b}`);
173
+ break;
174
+ case 'table_only_in':
175
+ lines.push(` table ${d.table} only in ${where_label(d.where)}`);
176
+ break;
177
+ case 'column_only_in':
178
+ lines.push(` ${d.table}.${d.column} only in ${where_label(d.where)}`);
179
+ break;
180
+ case 'column_field_differs':
181
+ lines.push(` ${d.table}.${d.column} ${d.field} differs: ${label_a}=${JSON.stringify(d.a)}, ${label_b}=${JSON.stringify(d.b)}`);
182
+ break;
183
+ case 'index_only_in':
184
+ lines.push(` index ${d.index} on ${d.table} only in ${where_label(d.where)}`);
185
+ break;
186
+ case 'index_definition_differs':
187
+ lines.push(` index ${d.index} on ${d.table} differs:\n ${label_a}: ${d.a}\n ${label_b}: ${d.b}`);
188
+ break;
189
+ case 'constraint_only_in':
190
+ lines.push(` constraint ${d.constraint} on ${d.table} only in ${where_label(d.where)}`);
191
+ break;
192
+ case 'constraint_differs':
193
+ lines.push(` constraint ${d.constraint} on ${d.table} differs:\n ${label_a}: ${d.a.type} ${d.a.definition}\n ${label_b}: ${d.b.type} ${d.b.definition}`);
194
+ break;
195
+ case 'sequence_only_in':
196
+ lines.push(` sequence ${d.sequence} only in ${where_label(d.where)}`);
197
+ break;
198
+ case 'sequence_data_type_differs':
199
+ lines.push(` sequence ${d.sequence} data_type differs: ${label_a}=${d.a}, ${label_b}=${d.b}`);
200
+ break;
201
+ default:
202
+ // Compile-time exhaustiveness — a new SchemaDiff variant without a
203
+ // case here makes `d` non-never and fails type-check.
204
+ d;
205
+ break;
206
+ }
207
+ }
208
+ return lines.join('\n');
209
+ };
210
+ /**
211
+ * Throw if the two snapshots disagree. The error message names the impls
212
+ * (via `labels`) and lists every diff, so the failure is self-diagnosing.
213
+ *
214
+ * Consumers wire this after bootstrapping each impl against an isolated DB:
215
+ *
216
+ * ```ts
217
+ * await drop_recreate_db('zzz_test');
218
+ * await spawn_backend(deno_config);
219
+ * const snapshot_deno = await query_schema_snapshot(db, {});
220
+ * await drop_recreate_db('zzz_test');
221
+ * await spawn_backend(rust_config);
222
+ * const snapshot_rust = await query_schema_snapshot(db, {});
223
+ * assert_schema_snapshots_equal(snapshot_deno, snapshot_rust, {a: 'deno', b: 'rust'});
224
+ * ```
225
+ */
226
+ export const assert_schema_snapshots_equal = (a, b, labels = {}) => {
227
+ const diffs = diff_schema_snapshots(a, b);
228
+ if (diffs.length === 0)
229
+ return;
230
+ const label_a = labels.a ?? 'a';
231
+ const label_b = labels.b ?? 'b';
232
+ throw new Error(`Schema parity failed: ${diffs.length} diff(s) between ${label_a} and ${label_b}\n${format_schema_diffs(diffs, labels)}`);
233
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"sse_round_trip.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/sse_round_trip.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAmB7B,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAwB,KAAK,SAAS,EAAuB,MAAM,oBAAoB,CAAC;AAE/F,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAEN,KAAK,eAAe,EACpB,KAAK,OAAO,EACZ,KAAK,WAAW,EAChB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAwB,KAAK,SAAS,EAAC,MAAM,SAAS,CAAC;AAE9D,OAAO,EAIN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AAM1B,gDAAgD;AAChD,MAAM,WAAW,gBAAgB;IAChC,yEAAyE;IACzE,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,OAAO,EAAE,CAAC,GAAG,EAAE;QAAC,QAAQ,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,WAAW,CAAA;KAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3E;;;OAGG;IACH,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAC/B;;;;OAIG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;CAClC;AAED,8CAA8C;AAC9C,MAAM,WAAW,mBAAmB;IACnC,4CAA4C;IAC5C,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC,qDAAqD;IACrD,kBAAkB,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,KAAK,CAAC,SAAS,CAAC,CAAC;IAChE,iDAAiD;IACjD,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,qEAAqE;IACrE,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAChC;;;;;OAKG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAChD;;;;;;;;;;;;OAYG;IACH,aAAa,EAAE,uBAAuB,CAAC;IACvC,8BAA8B;IAC9B,MAAM,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC;CAChC;AAyHD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,wBAAwB,GAAI,SAAS,mBAAmB,KAAG,IA2HvE,CAAC"}
1
+ {"version":3,"file":"sse_round_trip.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/sse_round_trip.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAmB7B,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAwB,KAAK,SAAS,EAAuB,MAAM,oBAAoB,CAAC;AAE/F,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,6BAA6B,CAAC;AAG/D,OAAO,EAEN,KAAK,eAAe,EACpB,KAAK,OAAO,EACZ,KAAK,WAAW,EAChB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAwB,KAAK,SAAS,EAAC,MAAM,SAAS,CAAC;AAE9D,OAAO,EAIN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AAM1B,gDAAgD;AAChD,MAAM,WAAW,gBAAgB;IAChC,yEAAyE;IACzE,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,OAAO,EAAE,CAAC,GAAG,EAAE;QAAC,QAAQ,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,WAAW,CAAA;KAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3E;;;OAGG;IACH,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAC/B;;;;OAIG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;CAClC;AAED,8CAA8C;AAC9C,MAAM,WAAW,mBAAmB;IACnC,4CAA4C;IAC5C,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC,qDAAqD;IACrD,kBAAkB,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,KAAK,CAAC,SAAS,CAAC,CAAC;IAChE,iDAAiD;IACjD,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,qEAAqE;IACrE,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAChC;;;;;OAKG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAChD;;;;;;;;;;;;OAYG;IACH,aAAa,EAAE,uBAAuB,CAAC;IACvC,8BAA8B;IAC9B,MAAM,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC;CAChC;AAyHD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,wBAAwB,GAAI,SAAS,mBAAmB,KAAG,IAgIvE,CAAC"}
@@ -16,6 +16,7 @@ import './assert_dev_env.js';
16
16
  import { describe, test, beforeAll, afterAll, assert } from 'vitest';
17
17
  import { SSE_CONNECTED_COMMENT } from '../realtime/sse.js';
18
18
  import { ROLE_ADMIN } from '../auth/role_schema.js';
19
+ import { create_audit_emitter } from '../auth/audit_emitter.js';
19
20
  import { create_test_app, } from './app_server.js';
20
21
  import { create_pglite_factory } from './db.js';
21
22
  import { find_route_spec, pick_auth_headers } from './integration_helpers.js';
@@ -134,7 +135,7 @@ export const describe_sse_route_tests = (options) => {
134
135
  // Hard-fail early so consumers see a clear setup error instead of a
135
136
  // confusing test failure when `rpc_endpoints` is missing. Factory-form
136
137
  // callers are resolved with a stub ctx purely to extract the endpoint
137
- // path; real handlers run per-test via `app_options.rpc_endpoints`.
138
+ // path; real handlers run per-test via the top-level `rpc_endpoints` slot on `CreateTestAppOptions`.
138
139
  const rpc_endpoints_for_setup = resolve_rpc_endpoints_for_setup(options.rpc_endpoints, options.session_options);
139
140
  const rpc_path = require_rpc_endpoint_path(rpc_endpoints_for_setup);
140
141
  const init_schema = async (db) => {
@@ -153,15 +154,20 @@ export const describe_sse_route_tests = (options) => {
153
154
  let db;
154
155
  beforeAll(async () => {
155
156
  db = await factory.create();
157
+ // Forward the consumer's listener through an `audit_factory`
158
+ // body — the sugar was removed from `TestAppServerOptions`
159
+ // to match the production `CreateAppBackendOptions` shape.
160
+ const { on_audit_event } = options;
161
+ const audit_factory = on_audit_event
162
+ ? (params) => create_audit_emitter({ ...params, on_audit_event })
163
+ : undefined;
156
164
  test_app = await create_test_app({
157
165
  session_options: options.session_options,
158
166
  create_route_specs: options.create_route_specs,
159
167
  db,
160
- app_options: {
161
- ...options.app_options,
162
- rpc_endpoints: options.rpc_endpoints,
163
- },
164
- on_audit_event: options.on_audit_event,
168
+ rpc_endpoints: options.rpc_endpoints,
169
+ app_options: options.app_options,
170
+ audit_factory,
165
171
  });
166
172
  authed_account = await test_app.create_account({
167
173
  username: 'sse_authed',
@@ -2,59 +2,91 @@ import './assert_dev_env.js';
2
2
  /**
3
3
  * Combined standard test suite helper.
4
4
  *
5
- * Convenience wrapper that runs both `describe_standard_integration_tests`
6
- * and `describe_standard_admin_integration_tests` in a single call.
7
- * Existing per-suite calls keep working — this is purely additive.
5
+ * Bundles every DB-backed suite carrying the standard option shape, each
6
+ * gated on its relevant config — silent-skip when the gate isn't met
7
+ * (same precedent as `describe_standard_admin_integration_tests` skipping
8
+ * when `roles` isn't provided). Consumers wire the standard surface in
9
+ * one call instead of seven; forgetting a suite no longer silently loses
10
+ * coverage.
11
+ *
12
+ * Attack surface suites stay separate — their option shape is
13
+ * `{build, snapshot_path, expected_public_routes, ...}` rather than
14
+ * `{setup_test, surface_source, capabilities}`. A peer bundler lives
15
+ * for that side if/when needed.
8
16
  *
9
17
  * @module
10
18
  */
11
19
  import type { SessionOptions } from '../auth/session_cookie.js';
12
- import type { AppServerContext, AppServerOptions } from '../server/app_server.js';
13
- import type { RouteSpec } from '../http/route_spec.js';
14
20
  import type { RoleSchemaResult } from '../auth/role_schema.js';
15
- import type { DbFactory } from './db.js';
21
+ import type { AppServerContext, BootstrapServerOptions } from '../server/app_server.js';
22
+ import type { RouteSpec } from '../http/route_spec.js';
16
23
  import type { RpcEndpointsSuiteOption } from './rpc_helpers.js';
24
+ import type { BackendCapabilities } from './cross_backend/capabilities.js';
25
+ import type { SetupTest } from './cross_backend/setup.js';
26
+ import type { SurfaceSource } from './transports/surface_source.js';
27
+ import type { SuiteAppOptions } from './app_server.js';
17
28
  /**
18
29
  * Configuration for `describe_standard_tests`.
19
30
  */
20
31
  export interface StandardTestOptions {
21
- /** Session config for cookie-based auth. */
22
- session_options: SessionOptions<string>;
23
- /** Route spec factory — same one used in production. */
24
- create_route_specs: (ctx: AppServerContext) => Array<RouteSpec>;
25
- /** Optional overrides for `AppServerOptions`. */
26
- app_options?: Partial<Omit<AppServerOptions, 'backend' | 'session_options' | 'create_route_specs'>>;
32
+ /** Per-test fixture-producing function. */
33
+ setup_test: SetupTest;
27
34
  /**
28
- * Database factories to run tests against. Default: pglite only.
35
+ * Source of the app surface. Currently requires `kind: 'inline'`
36
+ * the cross-process snapshot variant lands alongside the spawned-backend
37
+ * transport plumbing.
29
38
  */
30
- db_factories?: Array<DbFactory>;
39
+ surface_source: SurfaceSource;
40
+ /** Backend capability declarations. */
41
+ capabilities: BackendCapabilities;
42
+ /** Session config — needed for cookie_name + factory-form rpc_endpoints resolution. */
43
+ session_options: SessionOptions<string>;
31
44
  /**
32
- * Role schema result from `create_role_schema()`.
33
- * When provided, admin integration tests are included.
45
+ * Route spec factory same one used in production. Required by
46
+ * `describe_rate_limiting_tests`, which builds a fresh `TestApp` per test
47
+ * (bypasses the shared `setup_test` fixture) so it can pass tight
48
+ * per-test rate-limiter overrides.
34
49
  */
35
- roles?: RoleSchemaResult;
50
+ create_route_specs: (ctx: AppServerContext) => Array<RouteSpec>;
36
51
  /**
37
52
  * RPC endpoint specs — required. The standard integration tests drive
38
53
  * `account_verify`, `account_session_*`, `account_token_*` through the
39
54
  * RPC surface (and admin tests, when wired, drive role_grant grant/revoke
40
55
  * through it too).
41
- *
42
- * Accepts either an array (eager) or a factory
43
- * `(ctx: AppServerContext) => Array<RpcEndpointSpec>`. Round-tripped
44
- * to both sub-suites unchanged — see their docstrings for the full
45
- * factory-form contract.
46
56
  */
47
57
  rpc_endpoints: RpcEndpointsSuiteOption;
58
+ /**
59
+ * Role schema result from `create_role_schema()`.
60
+ * When provided, admin integration + audit completeness suites are included.
61
+ */
62
+ roles?: RoleSchemaResult;
63
+ /**
64
+ * Bootstrap config — when set to `mode: 'live'`, the bootstrap success
65
+ * suite runs against `create_test_app_for_bootstrap`. Other modes
66
+ * (`'disabled'` / `'surface_only'` / omission) silent-skip the suite.
67
+ */
68
+ bootstrap?: BootstrapServerOptions;
69
+ /** Optional overrides forwarded to `describe_rate_limiting_tests`. */
70
+ rate_limiting_app_options?: SuiteAppOptions;
48
71
  /**
49
72
  * Path prefix where admin routes are mounted.
50
73
  * Default `'/api/admin'`.
51
74
  */
52
75
  admin_prefix?: string;
76
+ /**
77
+ * Forwarded to `describe_standard_integration_tests` — overrides the
78
+ * default error-coverage threshold on the scoped REST surface. Set to
79
+ * `0` to skip the assertion entirely.
80
+ */
81
+ error_coverage_min?: number;
82
+ /** Override the bootstrap-success suite's synthetic token. */
83
+ bootstrap_token?: string;
53
84
  }
54
85
  /**
55
- * Run both standard integration and admin integration test suites.
56
- *
57
- * Admin tests are only included when `roles` is provided.
86
+ * Run the full standard test bundle integration, admin (when `roles`
87
+ * provided), audit completeness (when `roles` provided), bootstrap
88
+ * success (when `bootstrap.mode === 'live'`), round trip, RPC round
89
+ * trip, data exposure, rate limiting.
58
90
  */
59
91
  export declare const describe_standard_tests: (options: StandardTestOptions) => void;
60
92
  //# sourceMappingURL=standard.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"standard.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/standard.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAE7B;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAC,gBAAgB,EAAE,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAChF,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,SAAS,CAAC;AAGvC,OAAO,KAAK,EAAC,uBAAuB,EAAC,MAAM,kBAAkB,CAAC;AAE9D;;GAEG;AACH,MAAM,WAAW,mBAAmB;IACnC,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,iDAAiD;IACjD,WAAW,CAAC,EAAE,OAAO,CACpB,IAAI,CAAC,gBAAgB,EAAE,SAAS,GAAG,iBAAiB,GAAG,oBAAoB,CAAC,CAC5E,CAAC;IACF;;OAEG;IACH,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAChC;;;OAGG;IACH,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB;;;;;;;;;;OAUG;IACH,aAAa,EAAE,uBAAuB,CAAC;IACvC;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,GAAI,SAAS,mBAAmB,KAAG,IAStE,CAAC"}
1
+ {"version":3,"file":"standard.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/standard.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAE7B;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,EAAC,gBAAgB,EAAE,sBAAsB,EAAC,MAAM,yBAAyB,CAAC;AACtF,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AASrD,OAAO,KAAK,EAAC,uBAAuB,EAAC,MAAM,kBAAkB,CAAC;AAC9D,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,iCAAiC,CAAC;AACzE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,0BAA0B,CAAC;AACxD,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,gCAAgC,CAAC;AAClE,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,iBAAiB,CAAC;AAErD;;GAEG;AACH,MAAM,WAAW,mBAAmB;IACnC,2CAA2C;IAC3C,UAAU,EAAE,SAAS,CAAC;IACtB;;;;OAIG;IACH,cAAc,EAAE,aAAa,CAAC;IAC9B,uCAAuC;IACvC,YAAY,EAAE,mBAAmB,CAAC;IAClC,uFAAuF;IACvF,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC;;;;;OAKG;IACH,kBAAkB,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,KAAK,CAAC,SAAS,CAAC,CAAC;IAChE;;;;;OAKG;IACH,aAAa,EAAE,uBAAuB,CAAC;IACvC;;;OAGG;IACH,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB;;;;OAIG;IACH,SAAS,CAAC,EAAE,sBAAsB,CAAC;IACnC,sEAAsE;IACtE,yBAAyB,CAAC,EAAE,eAAe,CAAC;IAC5C;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,8DAA8D;IAC9D,eAAe,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,GAAI,SAAS,mBAAmB,KAAG,IA2DtE,CAAC"}
@@ -1,18 +1,75 @@
1
1
  import './assert_dev_env.js';
2
2
  import { describe_standard_integration_tests } from './integration.js';
3
3
  import { describe_standard_admin_integration_tests } from './admin_integration.js';
4
+ import { describe_round_trip_validation } from './round_trip.js';
5
+ import { describe_data_exposure_tests } from './data_exposure.js';
6
+ import { describe_rpc_round_trip_tests } from './rpc_round_trip.js';
7
+ import { describe_audit_completeness_tests } from './audit_completeness.js';
8
+ import { describe_rate_limiting_tests } from './rate_limiting.js';
9
+ import { describe_bootstrap_success_tests } from './bootstrap_success.js';
4
10
  /**
5
- * Run both standard integration and admin integration test suites.
6
- *
7
- * Admin tests are only included when `roles` is provided.
11
+ * Run the full standard test bundle integration, admin (when `roles`
12
+ * provided), audit completeness (when `roles` provided), bootstrap
13
+ * success (when `bootstrap.mode === 'live'`), round trip, RPC round
14
+ * trip, data exposure, rate limiting.
8
15
  */
9
16
  export const describe_standard_tests = (options) => {
10
- describe_standard_integration_tests(options);
17
+ describe_standard_integration_tests({
18
+ setup_test: options.setup_test,
19
+ surface_source: options.surface_source,
20
+ capabilities: options.capabilities,
21
+ session_options: options.session_options,
22
+ rpc_endpoints: options.rpc_endpoints,
23
+ error_coverage_min: options.error_coverage_min,
24
+ });
25
+ describe_round_trip_validation({
26
+ setup_test: options.setup_test,
27
+ surface_source: options.surface_source,
28
+ capabilities: options.capabilities,
29
+ });
30
+ describe_rpc_round_trip_tests({
31
+ setup_test: options.setup_test,
32
+ surface_source: options.surface_source,
33
+ capabilities: options.capabilities,
34
+ session_options: options.session_options,
35
+ rpc_endpoints: options.rpc_endpoints,
36
+ });
37
+ describe_data_exposure_tests({
38
+ setup_test: options.setup_test,
39
+ surface_source: options.surface_source,
40
+ capabilities: options.capabilities,
41
+ });
42
+ describe_rate_limiting_tests({
43
+ session_options: options.session_options,
44
+ create_route_specs: options.create_route_specs,
45
+ rpc_endpoints: options.rpc_endpoints,
46
+ app_options: options.rate_limiting_app_options,
47
+ });
11
48
  if (options.roles) {
12
49
  describe_standard_admin_integration_tests({
13
- ...options,
50
+ setup_test: options.setup_test,
51
+ surface_source: options.surface_source,
52
+ capabilities: options.capabilities,
53
+ session_options: options.session_options,
14
54
  roles: options.roles,
15
55
  rpc_endpoints: options.rpc_endpoints,
56
+ admin_prefix: options.admin_prefix,
57
+ });
58
+ describe_audit_completeness_tests({
59
+ setup_test: options.setup_test,
60
+ surface_source: options.surface_source,
61
+ capabilities: options.capabilities,
62
+ session_options: options.session_options,
63
+ rpc_endpoints: options.rpc_endpoints,
64
+ });
65
+ }
66
+ if (options.bootstrap?.mode === 'live') {
67
+ describe_bootstrap_success_tests({
68
+ session_options: options.session_options,
69
+ create_route_specs: options.create_route_specs,
70
+ rpc_endpoints: options.rpc_endpoints,
71
+ bootstrap: options.bootstrap,
72
+ bootstrap_token: options.bootstrap_token,
16
73
  });
17
74
  }
18
75
  };
@@ -4,10 +4,11 @@ import type { SessionOptions } from '../auth/session_cookie.js';
4
4
  import type { MiddlewareSpec } from '../http/middleware_spec.js';
5
5
  import type { AppDeps } from '../auth/deps.js';
6
6
  import type { AuditEmitter } from '../auth/audit_emitter.js';
7
- import type { AppServerContext } from '../server/app_server.js';
7
+ import type { AppServerContext, BootstrapServerOptions } from '../server/app_server.js';
8
8
  import { Db } from '../db/db.js';
9
9
  import { type RouteSpec } from '../http/route_spec.js';
10
10
  import { type AppSurfaceSpec, type RpcEndpointSpec } from '../http/surface.js';
11
+ import type { WsEndpointSpec } from '../actions/ws_endpoint_spec.js';
11
12
  import type { EventSpec } from '../realtime/sse.js';
12
13
  import { type AuditLogSse } from '../realtime/sse_auth_guard.js';
13
14
  /**
@@ -116,10 +117,28 @@ export interface CreateTestAppSurfaceSpecOptions {
116
117
  * the stub `AppServerContext` this helper already builds.
117
118
  */
118
119
  rpc_endpoints?: Array<RpcEndpointSpec> | ((ctx: AppServerContext) => Array<RpcEndpointSpec>);
120
+ /**
121
+ * WebSocket endpoint specs for surface generation. Symmetric with
122
+ * `create_app_server`'s `ws_endpoints` option — pass the same value
123
+ * to both entry points so the attack surface tests see the same WS
124
+ * endpoints production auto-mounts. The factory runs once against
125
+ * the stub `AppServerContext` this helper already builds. No
126
+ * `upgradeWebSocket` needed — this helper produces an `AppSurfaceSpec`
127
+ * only, never mounts.
128
+ */
129
+ ws_endpoints?: ReadonlyArray<WsEndpointSpec> | ((ctx: AppServerContext) => ReadonlyArray<WsEndpointSpec>);
119
130
  /** Transform middleware array (e.g., tx's `extend_middleware_for_tx_binary`). */
120
131
  transform_middleware?: (specs: Array<MiddlewareSpec>) => Array<MiddlewareSpec>;
121
- /** Bootstrap route prefix (default: `'/api/account'`). */
122
- bootstrap_route_prefix?: string;
132
+ /**
133
+ * Bootstrap config — symmetric with `AppServerOptions.bootstrap`. Discriminated
134
+ * by `mode`: `'disabled'` skips the route (same as omission), `'surface_only'`
135
+ * mounts the route shape, `'live'` accepts a `token_path` for production
136
+ * symmetry (surface assembly only uses it for shape symmetry; the value is a
137
+ * live-execution concern handled by `create_test_app` → `create_app_server`).
138
+ *
139
+ * Surface assembly only reads `route_prefix` (default `'/api/account'`).
140
+ */
141
+ bootstrap?: BootstrapServerOptions;
123
142
  }
124
143
  /**
125
144
  * Create an `AppSurfaceSpec` for attack surface testing.
@@ -1 +1 @@
1
- {"version":3,"file":"stubs.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/stubs.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"stubs.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/stubs.ts"],"names":[],"mappings":"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"}
@@ -17,7 +17,6 @@ import { create_app_surface_spec, } from '../http/surface.js';
17
17
  import { AUDIT_LOG_SSE_MAX_PER_SCOPE } from '../realtime/sse_auth_guard.js';
18
18
  import { SubscriberRegistry } from '../realtime/subscriber_registry.js';
19
19
  import { BaseServerEnv } from '../server/env.js';
20
- /* eslint-disable @typescript-eslint/require-await */
21
20
  /**
22
21
  * Create a Proxy that throws descriptive errors on any property access or method call.
23
22
  *
@@ -102,10 +101,10 @@ const stub_db = create_noop_stub('stub_db');
102
101
  * `create_test_app` already does this on the test backend.
103
102
  */
104
103
  export const create_test_audit_emitter = () => ({
105
- emit: () => { }, // eslint-disable-line @typescript-eslint/no-empty-function
106
- emit_role_grant_target: () => { }, // eslint-disable-line @typescript-eslint/no-empty-function
107
- emit_pool: async () => { }, // eslint-disable-line @typescript-eslint/no-empty-function
108
- notify: () => { }, // eslint-disable-line @typescript-eslint/no-empty-function
104
+ emit: () => { },
105
+ emit_role_grant_target: () => { },
106
+ emit_pool: async () => { },
107
+ notify: () => { },
109
108
  on_event_chain: Object.freeze([]),
110
109
  });
111
110
  /**
@@ -123,9 +122,9 @@ export const create_stub_audit_sse = () => {
123
122
  max_per_scope: AUDIT_LOG_SSE_MAX_PER_SCOPE,
124
123
  });
125
124
  return {
126
- subscribe: () => () => { }, // eslint-disable-line @typescript-eslint/no-empty-function
125
+ subscribe: () => () => { },
127
126
  log: new Logger('test:audit_sse', { level: 'off' }),
128
- on_audit_event: () => { }, // eslint-disable-line @typescript-eslint/no-empty-function
127
+ on_audit_event: () => { },
129
128
  registry,
130
129
  };
131
130
  };
@@ -146,7 +145,7 @@ export const stub_app_deps = {
146
145
  export const create_stub_app_deps = () => ({
147
146
  stat: async () => null,
148
147
  read_text_file: async () => '',
149
- delete_file: async (_path) => { }, // eslint-disable-line @typescript-eslint/no-empty-function
148
+ delete_file: async (_path) => { },
150
149
  keyring: create_noop_stub('keyring'),
151
150
  password: create_noop_stub('password'),
152
151
  db: stub_db,
@@ -193,7 +192,7 @@ export const create_stub_app_server_context = (session_options) => {
193
192
  db_type: 'pglite-memory',
194
193
  db_name: 'test',
195
194
  migration_results: [],
196
- close: async () => { }, // eslint-disable-line @typescript-eslint/no-empty-function
195
+ close: async () => { },
197
196
  },
198
197
  bootstrap_status: { available: false, token_path: null },
199
198
  session_options,
@@ -220,13 +219,6 @@ export const create_stub_app_server_context = (session_options) => {
220
219
  export const create_test_app_surface_spec = (options) => {
221
220
  const ctx = create_stub_app_server_context(options.session_options);
222
221
  const consumer_routes = options.create_route_specs(ctx);
223
- // Mirror create_app_server's factory-managed route assembly
224
- const bootstrap_routes = create_bootstrap_route_specs(ctx.deps, {
225
- session_options: options.session_options,
226
- bootstrap_status: { available: false, token_path: null },
227
- ip_rate_limiter: null,
228
- });
229
- const prefix = options.bootstrap_route_prefix ?? '/api/account';
230
222
  // Auto-mount rpc endpoints (mirrors create_app_server) so consumer
231
223
  // `create_route_specs` does not need to call `create_rpc_endpoint`.
232
224
  const resolved_rpc_endpoints = typeof options.rpc_endpoints === 'function'
@@ -237,11 +229,25 @@ export const create_test_app_surface_spec = (options) => {
237
229
  actions: endpoint.actions,
238
230
  log: ctx.deps.log,
239
231
  })) ?? [];
240
- const route_specs = [
241
- ...consumer_routes,
242
- ...rpc_route_specs,
243
- ...prefix_route_specs(prefix, bootstrap_routes),
244
- ];
232
+ // Resolve ws endpoints (mirrors create_app_server). Surface-only —
233
+ // no `register_ws_endpoint` call here, so no `upgradeWebSocket` needed.
234
+ const resolved_ws_endpoints = typeof options.ws_endpoints === 'function' ? options.ws_endpoints(ctx) : options.ws_endpoints;
235
+ // Bootstrap routes mirror `create_app_server`: mounted for `surface_only`
236
+ // and `live` modes; omitted for `disabled` / undefined. Surface generation
237
+ // uses an `available: false` placeholder regardless of mode — the handler
238
+ // short-circuits to 403 ALREADY_BOOTSTRAPPED, which is what surface tests
239
+ // assert on. Live token_path is passed through for shape symmetry only.
240
+ const bootstrap_route_specs = options.bootstrap && options.bootstrap.mode !== 'disabled'
241
+ ? prefix_route_specs(options.bootstrap.route_prefix ?? '/api/account', create_bootstrap_route_specs(ctx.deps, {
242
+ session_options: options.session_options,
243
+ bootstrap_status: {
244
+ available: false,
245
+ token_path: options.bootstrap.mode === 'live' ? options.bootstrap.token_path : null,
246
+ },
247
+ ip_rate_limiter: null,
248
+ }))
249
+ : [];
250
+ const route_specs = [...consumer_routes, ...rpc_route_specs, ...bootstrap_route_specs];
245
251
  let middleware_specs = create_stub_api_middleware();
246
252
  if (options.transform_middleware) {
247
253
  middleware_specs = options.transform_middleware(middleware_specs);
@@ -252,5 +258,6 @@ export const create_test_app_surface_spec = (options) => {
252
258
  env_schema: options.env_schema ?? BaseServerEnv,
253
259
  event_specs: options.event_specs,
254
260
  rpc_endpoints: resolved_rpc_endpoints,
261
+ ws_endpoints: resolved_ws_endpoints,
255
262
  });
256
263
  };