@fuzdev/fuz_app 0.93.0 → 0.95.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 (200) hide show
  1. package/README.md +2 -2
  2. package/dist/actions/action_codegen.d.ts +18 -18
  3. package/dist/actions/action_codegen.js +30 -30
  4. package/dist/actions/action_event.js +1 -1
  5. package/dist/actions/action_event_helpers.d.ts +1 -1
  6. package/dist/actions/action_event_types.d.ts +1 -1
  7. package/dist/actions/action_rpc.d.ts +2 -2
  8. package/dist/actions/broadcast_api.d.ts +1 -1
  9. package/dist/actions/broadcast_api.js +1 -1
  10. package/dist/actions/perform_action.d.ts +2 -2
  11. package/dist/actions/register_action_ws.d.ts +2 -2
  12. package/dist/actions/register_action_ws.js +2 -2
  13. package/dist/actions/register_ws_endpoint.js +1 -1
  14. package/dist/actions/request_tracker.svelte.d.ts +1 -1
  15. package/dist/actions/request_tracker.svelte.js +1 -1
  16. package/dist/actions/rpc_client.d.ts +1 -1
  17. package/dist/actions/socket.svelte.d.ts +2 -2
  18. package/dist/actions/transports_ws.js +1 -1
  19. package/dist/actions/transports_ws_auth_guard.d.ts +1 -1
  20. package/dist/actions/transports_ws_backend.d.ts +1 -1
  21. package/dist/actions/transports_ws_backend.js +2 -2
  22. package/dist/auth/account_action_specs.js +1 -1
  23. package/dist/auth/account_schema.d.ts +1 -1
  24. package/dist/auth/account_schema.js +1 -1
  25. package/dist/auth/actor_lookup_action_specs.js +1 -1
  26. package/dist/auth/actor_lookup_queries.d.ts +1 -1
  27. package/dist/auth/actor_search_action_specs.js +1 -1
  28. package/dist/auth/actor_search_queries.d.ts +1 -1
  29. package/dist/auth/admin_action_specs.js +1 -1
  30. package/dist/auth/api_token.js +1 -1
  31. package/dist/auth/api_token_queries.d.ts +1 -1
  32. package/dist/auth/app_settings_schema.d.ts +1 -1
  33. package/dist/auth/app_settings_schema.js +1 -1
  34. package/dist/auth/audit_emitter.d.ts +2 -2
  35. package/dist/auth/audit_log_routes.d.ts +1 -1
  36. package/dist/auth/audit_log_schema.d.ts +1 -1
  37. package/dist/auth/audit_log_schema.js +2 -2
  38. package/dist/auth/bearer_auth.d.ts +1 -1
  39. package/dist/auth/bootstrap_account.d.ts +1 -1
  40. package/dist/auth/bootstrap_route_schema.js +1 -1
  41. package/dist/auth/bootstrap_routes.d.ts +1 -1
  42. package/dist/auth/bootstrap_routes.js +1 -1
  43. package/dist/auth/cell_action_specs.js +2 -2
  44. package/dist/auth/cell_audit_action_specs.js +1 -1
  45. package/dist/auth/cell_audit_metadata.js +1 -1
  46. package/dist/auth/cell_field_action_specs.js +1 -1
  47. package/dist/auth/cell_field_audit_metadata.js +1 -1
  48. package/dist/auth/cell_grant_action_specs.js +1 -1
  49. package/dist/auth/cell_grant_audit_metadata.js +1 -1
  50. package/dist/auth/cell_item_action_specs.d.ts +1 -1
  51. package/dist/auth/cell_item_action_specs.js +3 -3
  52. package/dist/auth/cell_item_audit_metadata.js +1 -1
  53. package/dist/auth/cell_relation_visibility.d.ts +1 -1
  54. package/dist/auth/cleanup.d.ts +1 -1
  55. package/dist/auth/daemon_token_middleware.d.ts +1 -1
  56. package/dist/auth/deps.d.ts +2 -2
  57. package/dist/auth/invite_schema.d.ts +1 -1
  58. package/dist/auth/invite_schema.js +1 -1
  59. package/dist/auth/request_context.d.ts +1 -1
  60. package/dist/auth/role_grant_offer_action_specs.js +1 -1
  61. package/dist/auth/role_grant_offer_notifications.d.ts +1 -1
  62. package/dist/auth/role_grant_offer_notifications.js +1 -1
  63. package/dist/auth/role_grant_offer_queries.d.ts +1 -1
  64. package/dist/auth/role_grant_offer_schema.d.ts +1 -1
  65. package/dist/auth/role_grant_offer_schema.js +1 -1
  66. package/dist/auth/role_grant_queries.d.ts +1 -1
  67. package/dist/auth/session_queries.d.ts +1 -1
  68. package/dist/auth/session_queries.js +1 -1
  69. package/dist/auth/signup_route_schema.js +1 -1
  70. package/dist/cli/args.d.ts +1 -1
  71. package/dist/cli/args.js +2 -2
  72. package/dist/cli/help.d.ts +1 -1
  73. package/dist/cli/help.js +1 -1
  74. package/dist/cli/logger.d.ts +1 -1
  75. package/dist/cli/logger.js +1 -1
  76. package/dist/db/CLAUDE.md +1 -1
  77. package/dist/db/cell_audit_queries.d.ts +1 -1
  78. package/dist/db/cell_field_queries.d.ts +1 -1
  79. package/dist/db/cell_grant_queries.d.ts +1 -1
  80. package/dist/db/cell_item_queries.d.ts +1 -1
  81. package/dist/db/cell_queries.d.ts +3 -3
  82. package/dist/db/cell_queries.js +1 -1
  83. package/dist/db/fact_disk_storage.d.ts +2 -2
  84. package/dist/db/fact_disk_storage.js +4 -4
  85. package/dist/db/fact_queries.d.ts +1 -1
  86. package/dist/db/fact_store.d.ts +3 -3
  87. package/dist/db/fact_store.js +2 -2
  88. package/dist/db/file_fact_url.d.ts +1 -1
  89. package/dist/db/file_fact_url.js +1 -1
  90. package/dist/db/migrate.js +1 -1
  91. package/dist/db/status.js +1 -1
  92. package/dist/http/auth_shape.js +2 -2
  93. package/dist/http/common_routes.d.ts +1 -1
  94. package/dist/http/db_routes.d.ts +1 -1
  95. package/dist/http/origin.js +1 -1
  96. package/dist/http/pending_effects.d.ts +1 -1
  97. package/dist/http/proxy.d.ts +1 -1
  98. package/dist/http/route_spec.d.ts +1 -1
  99. package/dist/rate_limiter.js +1 -1
  100. package/dist/realtime/sse.d.ts +1 -1
  101. package/dist/realtime/sse_auth_guard.d.ts +1 -1
  102. package/dist/runtime/deno.js +1 -1
  103. package/dist/server/app_backend.d.ts +1 -1
  104. package/dist/server/app_backend.js +1 -1
  105. package/dist/server/env.js +1 -1
  106. package/dist/server/fact_write.d.ts +2 -2
  107. package/dist/server/fact_write.js +1 -1
  108. package/dist/server/serve_fact_route.d.ts +1 -1
  109. package/dist/server/serve_fact_route.js +2 -2
  110. package/dist/server/startup.d.ts +1 -1
  111. package/dist/testing/CLAUDE.md +61 -9
  112. package/dist/testing/adversarial_input.js +1 -1
  113. package/dist/testing/app_server.d.ts +1 -1
  114. package/dist/testing/app_server.js +1 -1
  115. package/dist/testing/auth_apps.js +1 -1
  116. package/dist/testing/cross_backend/bench/bench_report.d.ts +1 -1
  117. package/dist/testing/cross_backend/bench/bench_report.js +2 -2
  118. package/dist/testing/cross_backend/bench/run_cross_impl_bench.d.ts +1 -1
  119. package/dist/testing/cross_backend/bench/run_cross_impl_bench.js +1 -1
  120. package/dist/testing/cross_backend/bootstrap_backend.d.ts +1 -1
  121. package/dist/testing/cross_backend/capabilities.d.ts +25 -4
  122. package/dist/testing/cross_backend/capabilities.d.ts.map +1 -1
  123. package/dist/testing/cross_backend/capabilities.js +9 -4
  124. package/dist/testing/cross_backend/cell_relations.js +1 -1
  125. package/dist/testing/cross_backend/conformance_case.d.ts +4 -0
  126. package/dist/testing/cross_backend/conformance_case.d.ts.map +1 -1
  127. package/dist/testing/cross_backend/conformance_case.js +26 -0
  128. package/dist/testing/cross_backend/conformance_table.d.ts +21 -0
  129. package/dist/testing/cross_backend/conformance_table.d.ts.map +1 -1
  130. package/dist/testing/cross_backend/conformance_table.js +109 -7
  131. package/dist/testing/cross_backend/create_cross_backend_global_setup.d.ts +1 -1
  132. package/dist/testing/cross_backend/create_dual_spawn_global_setup.d.ts +1 -1
  133. package/dist/testing/cross_backend/default_backend_configs.d.ts.map +1 -1
  134. package/dist/testing/cross_backend/default_backend_configs.js +7 -0
  135. package/dist/testing/cross_backend/default_spine_surface.d.ts +1 -1
  136. package/dist/testing/cross_backend/fact_serving.js +1 -1
  137. package/dist/testing/cross_backend/peer_ping_ws.d.ts +23 -0
  138. package/dist/testing/cross_backend/peer_ping_ws.d.ts.map +1 -0
  139. package/dist/testing/cross_backend/peer_ping_ws.js +209 -0
  140. package/dist/testing/cross_backend/setup.d.ts +1 -1
  141. package/dist/testing/cross_backend/setup.js +1 -1
  142. package/dist/testing/cross_backend/testing_reset_actions.js +2 -2
  143. package/dist/testing/cross_backend/testing_server_core.d.ts +1 -1
  144. package/dist/testing/cross_backend/testing_server_core.js +1 -1
  145. package/dist/testing/cross_backend/ws_round_trip.js +1 -1
  146. package/dist/testing/db.js +4 -4
  147. package/dist/testing/middleware.js +1 -1
  148. package/dist/testing/role_grant_helpers.d.ts +1 -1
  149. package/dist/testing/rpc_helpers.d.ts +18 -1
  150. package/dist/testing/rpc_helpers.d.ts.map +1 -1
  151. package/dist/testing/rpc_helpers.js +24 -2
  152. package/dist/testing/schema_generators.d.ts +1 -1
  153. package/dist/testing/schema_generators.js +1 -1
  154. package/dist/testing/stubs.js +1 -1
  155. package/dist/testing/testing_rate_limiter.d.ts +1 -1
  156. package/dist/testing/testing_rate_limiter.js +1 -1
  157. package/dist/testing/transports/bootstrap.d.ts +1 -1
  158. package/dist/testing/transports/bootstrap.js +1 -1
  159. package/dist/testing/transports/ws_client.d.ts +40 -1
  160. package/dist/testing/transports/ws_client.d.ts.map +1 -1
  161. package/dist/testing/transports/ws_client.js +46 -1
  162. package/dist/testing/transports/ws_transport.d.ts +10 -1
  163. package/dist/testing/transports/ws_transport.d.ts.map +1 -1
  164. package/dist/testing/transports/ws_transport.js +6 -10
  165. package/dist/testing/ws_round_trip.d.ts +13 -3
  166. package/dist/testing/ws_round_trip.d.ts.map +1 -1
  167. package/dist/testing/ws_round_trip.js +16 -12
  168. package/dist/ui/AdminSurface.svelte +1 -1
  169. package/dist/ui/AppShell.svelte +1 -1
  170. package/dist/ui/BootstrapForm.svelte +1 -1
  171. package/dist/ui/CLAUDE.md +1 -1
  172. package/dist/ui/ConfirmButton.svelte +2 -2
  173. package/dist/ui/ConfirmButton.svelte.d.ts +1 -1
  174. package/dist/ui/LoginForm.svelte +1 -1
  175. package/dist/ui/MenuLink.svelte +1 -1
  176. package/dist/ui/MenuLink.svelte.d.ts +1 -1
  177. package/dist/ui/PopoverButton.svelte +1 -1
  178. package/dist/ui/PopoverButton.svelte.d.ts +1 -1
  179. package/dist/ui/SignupForm.svelte +1 -1
  180. package/dist/ui/account_sessions_state.svelte.js +1 -1
  181. package/dist/ui/admin_accounts_state.svelte.d.ts +1 -1
  182. package/dist/ui/admin_accounts_state.svelte.js +1 -1
  183. package/dist/ui/admin_invites_state.svelte.d.ts +1 -1
  184. package/dist/ui/admin_invites_state.svelte.js +1 -1
  185. package/dist/ui/admin_sessions_state.svelte.d.ts +1 -1
  186. package/dist/ui/app_settings_state.svelte.js +1 -1
  187. package/dist/ui/async_slot.svelte.d.ts +2 -2
  188. package/dist/ui/async_slot.svelte.js +2 -2
  189. package/dist/ui/audit_log_state.svelte.js +1 -1
  190. package/dist/ui/auth_state.svelte.d.ts +1 -1
  191. package/dist/ui/auth_state.svelte.js +3 -3
  192. package/dist/ui/format_scope.js +1 -1
  193. package/dist/ui/popover.svelte.d.ts +1 -1
  194. package/dist/ui/popover.svelte.js +2 -2
  195. package/dist/ui/position_helpers.js +1 -1
  196. package/dist/ui/role_grant_offers_state.svelte.js +1 -1
  197. package/dist/ui/sidebar_state.svelte.js +1 -1
  198. package/dist/ui/table_state.svelte.d.ts +1 -1
  199. package/dist/ui/table_state.svelte.js +2 -2
  200. package/package.json +2 -2
@@ -90,14 +90,29 @@ export type RpcTestTransport = (url: string, init: RequestInit) => Promise<Respo
90
90
  export declare const http_transport: (app: {
91
91
  request: (input: string, init: RequestInit) => Promise<Response> | Response;
92
92
  }) => RpcTestTransport;
93
- /** Discriminated return from `rpc_call`. `status` is the HTTP status. */
93
+ /**
94
+ * Snapshot a `Headers` object into a plain `Record` with lowercased keys
95
+ * (`Headers` iteration normalizes the casing already). Multiple values for one
96
+ * header collapse to the comma-joined form `Headers` exposes; `Set-Cookie` is
97
+ * the lone platform exception these call sites never assert on. Lets a
98
+ * response's headers travel back through `RpcCallResult` for header-level
99
+ * assertions (no-fingerprint, `expect.headers`).
100
+ */
101
+ export declare const headers_to_record: (headers: Headers) => Record<string, string>;
102
+ /**
103
+ * Discriminated return from `rpc_call`. `status` is the HTTP status; `headers`
104
+ * is the response-headers snapshot (lowercased keys) so callers can assert
105
+ * header-level properties (e.g. no backend-fingerprinting headers).
106
+ */
94
107
  export type RpcCallResult = {
95
108
  ok: true;
96
109
  status: number;
110
+ headers: Record<string, string>;
97
111
  result: unknown;
98
112
  } | {
99
113
  ok: false;
100
114
  status: number;
115
+ headers: Record<string, string>;
101
116
  error: {
102
117
  code: number;
103
118
  message: string;
@@ -172,10 +187,12 @@ export declare const rpc_call_non_browser: (args: Omit<RpcCallArgs, "suppress_de
172
187
  export type RpcCallResultForSpec<TSpec extends RequestResponseActionSpec> = {
173
188
  ok: true;
174
189
  status: number;
190
+ headers: Record<string, string>;
175
191
  result: z.infer<TSpec['output']>;
176
192
  } | {
177
193
  ok: false;
178
194
  status: number;
195
+ headers: Record<string, string>;
179
196
  error: {
180
197
  code: number;
181
198
  message: string;
@@ -1 +1 @@
1
- {"version":3,"file":"rpc_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/rpc_helpers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"rpc_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/rpc_helpers.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAa7B,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB,OAAO,EAIN,KAAK,gBAAgB,EACrB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,2BAA2B,CAAC;AACzE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,0BAA0B,CAAC;AACxD,OAAO,KAAK,EAAC,qBAAqB,EAAE,mBAAmB,EAAE,eAAe,EAAC,MAAM,oBAAoB,CAAC;AACpG,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,iCAAiC,CAAC;AACtE,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAG9D;;;;;;;;;GASG;AACH,MAAM,MAAM,uBAAuB,GAChC,KAAK,CAAC,eAAe,CAAC,GACtB,CAAC,CAAC,GAAG,EAAE,gBAAgB,KAAK,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC;AAEvD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,+BAA+B,GAC3C,eAAe,uBAAuB,EACtC,iBAAiB,cAAc,CAAC,MAAM,CAAC,KACrC,KAAK,CAAC,eAAe,CAuBvB,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,oBAAoB,GAChC,QAAQ,MAAM,EACd,SAAS,OAAO,EAChB,KAAI,MAAM,GAAG,MAAe,KAC1B,WAQF,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,GAC9B,eAAe,MAAM,EACrB,QAAQ,MAAM,EACd,SAAS,OAAO,EAChB,KAAI,MAAM,GAAG,MAAe,KAC1B,MAMF,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,6BAA6B,GACzC,MAAM,OAAO,EACb,gBAAgB,gBAAgB,KAC9B,IAUF,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,+BAA+B,GAAI,MAAM,OAAO,EAAE,gBAAgB,CAAC,CAAC,OAAO,KAAG,IAW1F,CAAC;AAIF;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAErF,2DAA2D;AAC3D,eAAO,MAAM,cAAc,GACzB,KAAK;IACL,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC;CAC5E,KAAG,gBAEmB,CAAC;AAEzB;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,GAAI,SAAS,OAAO,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAMzE,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,aAAa,GACtB;IAAC,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAC,GAC5E;IACA,EAAE,EAAE,KAAK,CAAC;IACV,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,KAAK,EAAE;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAC,CAAC;CACtD,CAAC;AAEL;;;;GAIG;AACH,MAAM,MAAM,UAAU,GACnB;IAAC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAA;CAAC,GAC7E,gBAAgB,CAAC;AAEpB,gCAAgC;AAChC,MAAM,WAAW,WAAW;IAC3B,yDAAyD;IACzD,GAAG,EAAE,UAAU,CAAC;IAChB,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,wCAAwC;IACxC,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACrB,mFAAmF;IACnF,IAAI,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IACtB;;;;;OAKG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;CAClC;AAcD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,QAAQ,GAAU,MAAM,WAAW,KAAG,OAAO,CAAC,aAAa,CA4DvE,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,GAChC,MAAM,IAAI,CAAC,WAAW,EAAE,yBAAyB,CAAC,KAChD,OAAO,CAAC,aAAa,CAAuD,CAAC;AAEhF;;;;;GAKG;AACH,MAAM,MAAM,oBAAoB,CAAC,KAAK,SAAS,yBAAyB,IACrE;IAAC,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAA;CAAC,GAC7F;IACA,EAAE,EAAE,KAAK,CAAC;IACV,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,KAAK,EAAE;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAC,CAAC;CACtD,CAAC;AAEL,mFAAmF;AACnF,MAAM,MAAM,kBAAkB,CAAC,KAAK,SAAS,yBAAyB,IAAI,IAAI,CAC7E,WAAW,EACX,QAAQ,GAAG,QAAQ,CACnB,GAAG;IACH,2GAA2G;IAC3G,IAAI,EAAE,KAAK,CAAC;IACZ,0CAA0C;IAC1C,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;CAChC,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,iBAAiB,GAAU,KAAK,SAAS,yBAAyB,EAC9E,MAAM,kBAAkB,CAAC,KAAK,CAAC,KAC7B,OAAO,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAkBrC,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,GAAU,CAAC,EACrC,MAAM,WAAW,EACjB,eAAe,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KACzB,OAAO,CAAC,CAAC,CAcX,CAAC;AAIF;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAC3B,eAAe,aAAa,CAAC,eAAe,CAAC,EAC7C,QAAQ,MAAM,KACZ;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,SAAS,CAAA;CAAC,GAAG,SAOtC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAC3B,eAAe,aAAa,CAAC,qBAAqB,CAAC,EACnD,QAAQ,MAAM,KACZ;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,mBAAmB,CAAA;CAAC,GAAG,SAOrD,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,yBAAyB,GACrC,eAAe,aAAa,CAAC,eAAe,CAAC,KAC3C,MAYF,CAAC"}
@@ -126,6 +126,21 @@ export const assert_jsonrpc_success_response = (body, output_schema) => {
126
126
  };
127
127
  /** Adapt a `Hono`-style app into an `RpcTestTransport`. */
128
128
  export const http_transport = (app) => async (url, init) => app.request(url, init);
129
+ /**
130
+ * Snapshot a `Headers` object into a plain `Record` with lowercased keys
131
+ * (`Headers` iteration normalizes the casing already). Multiple values for one
132
+ * header collapse to the comma-joined form `Headers` exposes; `Set-Cookie` is
133
+ * the lone platform exception these call sites never assert on. Lets a
134
+ * response's headers travel back through `RpcCallResult` for header-level
135
+ * assertions (no-fingerprint, `expect.headers`).
136
+ */
137
+ export const headers_to_record = (headers) => {
138
+ const record = {};
139
+ headers.forEach((value, key) => {
140
+ record[key] = value;
141
+ });
142
+ return record;
143
+ };
129
144
  /** Base default headers merged into every `rpc_call` request. */
130
145
  const RPC_CALL_DEFAULT_HEADERS_BASE = {
131
146
  host: 'localhost',
@@ -174,16 +189,18 @@ export const rpc_call = async (args) => {
174
189
  }
175
190
  const res = await (typeof app === 'function' ? app(url, init) : app.request(url, init));
176
191
  const status = res.status;
192
+ const response_headers = headers_to_record(res.headers);
177
193
  const body = await res.json();
178
194
  const success = JsonrpcResponse.safeParse(body);
179
195
  if (success.success) {
180
- return { ok: true, status, result: success.data.result };
196
+ return { ok: true, status, headers: response_headers, result: success.data.result };
181
197
  }
182
198
  const error = JsonrpcErrorResponse.safeParse(body);
183
199
  if (error.success) {
184
200
  return {
185
201
  ok: false,
186
202
  status,
203
+ headers: response_headers,
187
204
  error: {
188
205
  code: error.data.error.code,
189
206
  message: error.data.error.message,
@@ -226,7 +243,12 @@ export const rpc_call_for_spec = async (args) => {
226
243
  if (!parsed.success) {
227
244
  throw new Error(`rpc_call_for_spec(${spec.method}) result did not match spec.output: ${JSON.stringify(parsed.error.issues)}`);
228
245
  }
229
- return { ok: true, status: res.status, result: parsed.data };
246
+ return {
247
+ ok: true,
248
+ status: res.status,
249
+ headers: res.headers,
250
+ result: parsed.data,
251
+ };
230
252
  };
231
253
  /**
232
254
  * Same as `rpc_call` but parses the success `result` through the given
@@ -9,7 +9,7 @@ import './assert_dev_env.js';
9
9
  * @module
10
10
  */
11
11
  import { z } from 'zod';
12
- import { type ZodFieldInfo } from '@fuzdev/fuz_util/zod.js';
12
+ import { type ZodFieldInfo } from '@fuzdev/fuz_util/zod.ts';
13
13
  /**
14
14
  * Detect format constraints on a field by converting to JSON Schema.
15
15
  * Returns format string (e.g. 'uuid', 'email') or null.
@@ -9,7 +9,7 @@ import './assert_dev_env.js';
9
9
  * @module
10
10
  */
11
11
  import { z } from 'zod';
12
- import { zod_unwrap_def, zod_get_base_type, zod_unwrap_to_object, zod_extract_fields, } from '@fuzdev/fuz_util/zod.js';
12
+ import { zod_unwrap_def, zod_get_base_type, zod_unwrap_to_object, zod_extract_fields, } from '@fuzdev/fuz_util/zod.ts';
13
13
  import { is_null_schema } from '../http/schema_helpers.js';
14
14
  /**
15
15
  * Detect format constraints on a field by converting to JSON Schema.
@@ -7,7 +7,7 @@ import './assert_dev_env.js';
7
7
  *
8
8
  * @module
9
9
  */
10
- import { Logger } from '@fuzdev/fuz_util/log.js';
10
+ import { Logger } from '@fuzdev/fuz_util/log.ts';
11
11
  import { ApiError, RateLimitError } from '../http/error_schemas.js';
12
12
  import { Db } from '../db/db.js';
13
13
  import { prefix_route_specs } from '../http/route_spec.js';
@@ -17,7 +17,7 @@ import './assert_dev_env.js';
17
17
  * Usage in a test binary:
18
18
  *
19
19
  * ```ts
20
- * import {TestingRateLimiter} from '@fuzdev/fuz_app/testing/testing_rate_limiter.js';
20
+ * import {TestingRateLimiter} from '@fuzdev/fuz_app/testing/testing_rate_limiter.ts';
21
21
  *
22
22
  * const limiter = new TestingRateLimiter(default_login_ip_rate_limit);
23
23
  * await create_app_server({backend, ip_rate_limiter: limiter, ...});
@@ -17,7 +17,7 @@ import './assert_dev_env.js';
17
17
  * Usage in a test binary:
18
18
  *
19
19
  * ```ts
20
- * import {TestingRateLimiter} from '@fuzdev/fuz_app/testing/testing_rate_limiter.js';
20
+ * import {TestingRateLimiter} from '@fuzdev/fuz_app/testing/testing_rate_limiter.ts';
21
21
  *
22
22
  * const limiter = new TestingRateLimiter(default_login_ip_rate_limit);
23
23
  * await create_app_server({backend, ip_rate_limiter: limiter, ...});
@@ -1,5 +1,5 @@
1
1
  import '../assert_dev_env.js';
2
- import { Uuid } from '@fuzdev/fuz_util/id.js';
2
+ import { Uuid } from '@fuzdev/fuz_util/id.ts';
3
3
  import type { BackendConfig } from '../cross_backend/backend_config.js';
4
4
  import type { FetchTransport } from './fetch_transport.js';
5
5
  /** Input for `bootstrap()`. */
@@ -19,7 +19,7 @@ import '../assert_dev_env.js';
19
19
  * @module
20
20
  */
21
21
  import { z } from 'zod';
22
- import { Uuid } from '@fuzdev/fuz_util/id.js';
22
+ import { Uuid } from '@fuzdev/fuz_util/id.ts';
23
23
  /**
24
24
  * The `BootstrapOutput` envelope shape the cross-process bootstrap call
25
25
  * cares about. Looser than the full `BootstrapOutput` Zod schema in
@@ -1,5 +1,5 @@
1
1
  import '../assert_dev_env.js';
2
- import { JSONRPC_VERSION } from '../../http/jsonrpc.js';
2
+ import { JSONRPC_VERSION, type JsonrpcRequest } from '../../http/jsonrpc.js';
3
3
  export interface JsonrpcNotificationFrame<P = unknown> {
4
4
  jsonrpc: typeof JSONRPC_VERSION;
5
5
  method: string;
@@ -38,6 +38,45 @@ export declare const is_notification: (method: string) => (msg: unknown) => bool
38
38
  export declare const is_notification_with: <P>(method: string, match: (params: P) => boolean) => (msg: unknown) => msg is JsonrpcNotificationFrame<P>;
39
39
  /** Predicate matching a JSON-RPC response frame (success or error) for the given request id. */
40
40
  export declare const is_response_for: (id: number | string) => (msg: unknown) => boolean;
41
+ /** A pending `wait_for` entry — predicate + its resolver. */
42
+ export interface WsWaiter {
43
+ predicate: (msg: unknown) => boolean;
44
+ resolve: (msg: unknown) => void;
45
+ }
46
+ /**
47
+ * What a `WsRequestResponder` returns for a server-initiated
48
+ * request:
49
+ * - `{result}` → reply with a JSON-RPC success
50
+ * - `{error}` → reply with a JSON-RPC error envelope
51
+ * - `undefined` → send nothing (models a never-replying peer — exercises
52
+ * the server-side `Timeout`)
53
+ */
54
+ export type WsResponderOutcome = {
55
+ result: unknown;
56
+ } | {
57
+ error: JsonrpcErrorResponseFrame['error'];
58
+ } | undefined;
59
+ /**
60
+ * Answers a **server-initiated** request (the server→client direction
61
+ * `ActionPeer` adds). Passed at client construction so it's attached
62
+ * before the upgrade completes — otherwise it races a connect-time ping.
63
+ * Receives the parsed request frame and returns the reply outcome (or a
64
+ * promise of it).
65
+ */
66
+ export type WsRequestResponder = (request: JsonrpcRequest) => WsResponderOutcome | Promise<WsResponderOutcome>;
67
+ /**
68
+ * Deliver one parsed inbound frame to a client's receive sink — the
69
+ * shared parse→(respond|push)→resolve core.
70
+ *
71
+ * A server-initiated **request** (`{method, id}`) is answered by
72
+ * `on_request` when supplied (replying via `reply`) and is **not**
73
+ * surfaced as a normal message; everything else — notifications, replies
74
+ * to the client's own requests, and non-JSON frames — is pushed onto
75
+ * `received` and resolves any matching `waiters`, exactly as before. With
76
+ * no `on_request`, every frame (including a server-initiated request)
77
+ * flows to the sink unchanged, so the seam is purely additive.
78
+ */
79
+ export declare const deliver_inbound: (parsed: unknown, received: Array<unknown>, waiters: Array<WsWaiter>, on_request: WsRequestResponder | undefined, reply: (message: unknown) => void) => void;
41
80
  /**
42
81
  * Default wait-for timeout shared across in-process + cross-process
43
82
  * impls. Tunable per-call via the `timeout_ms` parameter.
@@ -1 +1 @@
1
- {"version":3,"file":"ws_client.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/transports/ws_client.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA2B9B,OAAO,EAAC,eAAe,EAAC,MAAM,uBAAuB,CAAC;AAatD,MAAM,WAAW,wBAAwB,CAAC,CAAC,GAAG,OAAO;IACpD,OAAO,EAAE,OAAO,eAAe,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,CAAC,CAAC;CACV;AAED,MAAM,WAAW,2BAA2B,CAAC,CAAC,GAAG,OAAO;IACvD,OAAO,EAAE,OAAO,eAAe,CAAC;IAChC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,MAAM,EAAE,CAAC,CAAC;CACV;AAED,MAAM,WAAW,yBAAyB,CAAC,CAAC,GAAG,OAAO;IACrD,OAAO,EAAE,OAAO,eAAe,CAAC;IAChC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,KAAK,EAAE;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,CAAC,CAAA;KAAC,CAAC;CACjD;AAQD,6EAA6E;AAC7E,eAAO,MAAM,eAAe,GAC1B,QAAQ,MAAM,MACd,KAAK,OAAO,KAAG,OACsC,CAAC;AAExD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,oBAAoB,GAC/B,CAAC,EAAE,QAAQ,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,KAAK,OAAO,MAChD,KAAK,OAAO,KAAG,GAAG,IAAI,wBAAwB,CAAC,CAAC,CAGE,CAAC;AAErD,gGAAgG;AAChG,eAAO,MAAM,eAAe,GAC1B,IAAI,MAAM,GAAG,MAAM,MACnB,KAAK,OAAO,KAAG,OAC8D,CAAC;AAMhF;;;GAGG;AACH,eAAO,MAAM,4BAA4B,OAAO,CAAC;AAEjD,0EAA0E;AAC1E,MAAM,WAAW,QAAQ;IACxB;;;;;;OAMG;IACH,IAAI,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C;;;;;;;;;;;OAWG;IACH,OAAO,EAAE,CAAC,CAAC,GAAG,OAAO,EACpB,EAAE,EAAE,MAAM,GAAG,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,OAAO,EACf,UAAU,CAAC,EAAE,MAAM,KACf,OAAO,CAAC,CAAC,CAAC,CAAC;IAChB;;;;;OAKG;IACH,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD;;;;;;;;;;OAUG;IACH,cAAc,EAAE,CAAC,UAAU,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1D,2DAA2D;IAC3D,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;IAC1C;;;;;;;;;;;;OAYG;IACH,QAAQ,EAAE;QACT,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,GAAG,IAAI,CAAC,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QAE5E,CAAC,CAAC,GAAG,OAAO,EAAE,SAAS,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;KACrF,CAAC;CACF"}
1
+ {"version":3,"file":"ws_client.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/transports/ws_client.ts"],"names":[],"mappings":"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"}
@@ -18,7 +18,7 @@ import '../assert_dev_env.js';
18
18
  *
19
19
  * @module
20
20
  */
21
- import { is_jsonrpc_error_response, is_jsonrpc_notification, is_jsonrpc_response, } from '../../http/jsonrpc_helpers.js';
21
+ import { create_jsonrpc_error_response, create_jsonrpc_response, is_jsonrpc_error_response, is_jsonrpc_notification, is_jsonrpc_request, is_jsonrpc_response, } from '../../http/jsonrpc_helpers.js';
22
22
  import { JSONRPC_VERSION } from '../../http/jsonrpc.js';
23
23
  // ---------------------------------------------------------------------
24
24
  // Predicates — compose with `WsClient.wait_for` and
@@ -46,6 +46,51 @@ export const is_notification_with = (method, match) => (msg) => is_jsonrpc_notif
46
46
  match(msg.params);
47
47
  /** Predicate matching a JSON-RPC response frame (success or error) for the given request id. */
48
48
  export const is_response_for = (id) => (msg) => (is_jsonrpc_response(msg) || is_jsonrpc_error_response(msg)) && msg.id === id;
49
+ /**
50
+ * Deliver one parsed inbound frame to a client's receive sink — the
51
+ * shared parse→(respond|push)→resolve core.
52
+ *
53
+ * A server-initiated **request** (`{method, id}`) is answered by
54
+ * `on_request` when supplied (replying via `reply`) and is **not**
55
+ * surfaced as a normal message; everything else — notifications, replies
56
+ * to the client's own requests, and non-JSON frames — is pushed onto
57
+ * `received` and resolves any matching `waiters`, exactly as before. With
58
+ * no `on_request`, every frame (including a server-initiated request)
59
+ * flows to the sink unchanged, so the seam is purely additive.
60
+ */
61
+ export const deliver_inbound = (parsed, received, waiters, on_request, reply) => {
62
+ if (on_request && is_jsonrpc_request(parsed)) {
63
+ void answer_request(parsed, on_request, reply);
64
+ return;
65
+ }
66
+ received.push(parsed);
67
+ for (let i = waiters.length - 1; i >= 0; i--) {
68
+ const waiter = waiters[i];
69
+ if (waiter.predicate(parsed)) {
70
+ waiter.resolve(parsed);
71
+ waiters.splice(i, 1);
72
+ }
73
+ }
74
+ };
75
+ const answer_request = async (request, on_request, reply) => {
76
+ let outcome;
77
+ try {
78
+ outcome = await on_request(request);
79
+ }
80
+ catch {
81
+ // A throwing responder models a peer that fails to answer — swallow so
82
+ // the test client surfaces no unhandled rejection; the server then sees
83
+ // a never-reply (→ `Timeout`).
84
+ return;
85
+ }
86
+ if (outcome === undefined)
87
+ return; // swallow — never-replying peer
88
+ reply('error' in outcome
89
+ ? // Test wire-frames keep `code` a plain `number` (not the branded
90
+ // Zod `JsonrpcServerErrorCode`), so cast at the builder boundary.
91
+ create_jsonrpc_error_response(request.id, outcome.error)
92
+ : create_jsonrpc_response(request.id, outcome.result));
93
+ };
49
94
  // ---------------------------------------------------------------------
50
95
  // WsClient — the test-driver surface every impl implements.
51
96
  // ---------------------------------------------------------------------
@@ -1,5 +1,5 @@
1
1
  import '../assert_dev_env.js';
2
- import { type WsClient } from './ws_client.js';
2
+ import { type WsClient, type WsRequestResponder } from './ws_client.js';
3
3
  /** Construction options for `create_ws_transport`. */
4
4
  export interface WsTransportOptions {
5
5
  /** Base URL the binary is reachable at — e.g. `http://localhost:8788`. Converted to `ws://` for the upgrade. */
@@ -25,6 +25,15 @@ export interface WsTransportOptions {
25
25
  * `WS_CLIENT_DEFAULT_TIMEOUT_MS` if omitted.
26
26
  */
27
27
  readonly default_timeout_ms?: number;
28
+ /**
29
+ * Optional responder for **server-initiated** requests (the
30
+ * server→client direction `ActionPeer` adds). Attached before the
31
+ * upgrade so a connect-time or on-demand `peer/ping` is answered as
32
+ * soon as it arrives. Omit for the default observe-only client — a
33
+ * server-initiated request is then surfaced as a normal message (today's
34
+ * behavior).
35
+ */
36
+ readonly on_request?: WsRequestResponder;
28
37
  }
29
38
  /**
30
39
  * Build a real-upgrade WS client pinned to `options.base_url` + `ws_path`.
@@ -1 +1 @@
1
- {"version":3,"file":"ws_transport.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/transports/ws_transport.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAuB9B,OAAO,EAKN,KAAK,QAAQ,EACb,MAAM,gBAAgB,CAAC;AAGxB,sDAAsD;AACtD,MAAM,WAAW,kBAAkB;IAClC,gHAAgH;IAChH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,8DAA8D;IAC9D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACxC;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;CACrC;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,mBAAmB,GAAU,SAAS,kBAAkB,KAAG,OAAO,CAAC,QAAQ,CAsJvF,CAAC"}
1
+ {"version":3,"file":"ws_transport.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/transports/ws_transport.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAuB9B,OAAO,EAMN,KAAK,QAAQ,EACb,KAAK,kBAAkB,EAEvB,MAAM,gBAAgB,CAAC;AAGxB,sDAAsD;AACtD,MAAM,WAAW,kBAAkB;IAClC,gHAAgH;IAChH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,8DAA8D;IAC9D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACxC;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC;;;;;;;OAOG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,kBAAkB,CAAC;CACzC;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,mBAAmB,GAAU,SAAS,kBAAkB,KAAG,OAAO,CAAC,QAAQ,CA8IvF,CAAC"}
@@ -18,7 +18,7 @@ import '../assert_dev_env.js';
18
18
  * @module
19
19
  */
20
20
  import { WebSocket } from 'ws';
21
- import { WS_CLIENT_DEFAULT_TIMEOUT_MS, is_response_for, } from './ws_client.js';
21
+ import { WS_CLIENT_DEFAULT_TIMEOUT_MS, deliver_inbound, is_response_for, } from './ws_client.js';
22
22
  import { create_jsonrpc_request } from '../../http/jsonrpc_helpers.js';
23
23
  /**
24
24
  * Build a real-upgrade WS client pinned to `options.base_url` + `ws_path`.
@@ -34,7 +34,7 @@ import { create_jsonrpc_request } from '../../http/jsonrpc_helpers.js';
34
34
  * cause rather than hanging.
35
35
  */
36
36
  export const create_ws_transport = async (options) => {
37
- const { base_url, ws_path, cookies, origin, default_timeout_ms } = options;
37
+ const { base_url, ws_path, cookies, origin, default_timeout_ms, on_request } = options;
38
38
  const default_timeout = default_timeout_ms ?? WS_CLIENT_DEFAULT_TIMEOUT_MS;
39
39
  const ws_url = `${base_url.replace(/^http/i, 'ws')}${ws_path}`;
40
40
  const headers = {};
@@ -64,14 +64,10 @@ export const create_ws_transport = async (options) => {
64
64
  // it still see the payload.
65
65
  parsed = text;
66
66
  }
67
- received.push(parsed);
68
- for (let i = waiters.length - 1; i >= 0; i--) {
69
- const waiter = waiters[i];
70
- if (waiter.predicate(parsed)) {
71
- waiter.resolve(parsed);
72
- waiters.splice(i, 1);
73
- }
74
- }
67
+ deliver_inbound(parsed, received, waiters, on_request, (message) => {
68
+ if (socket.readyState === WebSocket.OPEN)
69
+ socket.send(JSON.stringify(message));
70
+ });
75
71
  });
76
72
  socket.on('close', () => {
77
73
  for (const resolve of close_resolvers)
@@ -39,8 +39,8 @@ import './assert_dev_env.js';
39
39
  */
40
40
  import type { Context } from 'hono';
41
41
  import { WSContext, type UpgradeWebSocket, type WSEvents } from 'hono/ws';
42
- import { Logger } from '@fuzdev/fuz_util/log.js';
43
- import { type Uuid } from '@fuzdev/fuz_util/id.js';
42
+ import { Logger } from '@fuzdev/fuz_util/log.ts';
43
+ import { type Uuid } from '@fuzdev/fuz_util/id.ts';
44
44
  import type { ActionSpecUnion } from '../actions/action_spec.js';
45
45
  import type { Action } from '../actions/action_types.js';
46
46
  import type { ActionEventEnvironment } from '../actions/action_event_types.js';
@@ -48,7 +48,7 @@ import { type RegisterActionWsOptions } from '../actions/register_action_ws.js';
48
48
  import { BackendWebsocketTransport } from '../actions/transports_ws_backend.js';
49
49
  import { type RequestContext } from '../auth/request_context.js';
50
50
  import { type CredentialType } from '../hono_context.js';
51
- import { type WsClient } from './transports/ws_client.js';
51
+ import { type WsClient, type WsRequestResponder } from './transports/ws_client.js';
52
52
  /**
53
53
  * A `WSContext` paired with capture arrays. Use `sends` to assert on
54
54
  * outgoing frames; use `closes` to assert on revocation / close.
@@ -151,6 +151,16 @@ export interface CreateWsTestHarnessOptions {
151
151
  on_socket_open?: RegisterActionWsOptions['on_socket_open'];
152
152
  /** Threaded straight through to `register_action_ws`. */
153
153
  on_socket_close?: RegisterActionWsOptions['on_socket_close'];
154
+ /**
155
+ * Optional responder for **server-initiated** requests, applied to every
156
+ * `connect()`. Purely additive (and unexercised until the TS server
157
+ * transport gains server-initiated requests — the deferred
158
+ * `BackendWebsocketTransport.send()` convergence): with it set, an
159
+ * inbound server→client request is answered rather than surfaced as a
160
+ * message; without it, behavior is unchanged. Mirrors the cross-process
161
+ * `create_ws_transport` seam so suite bodies share one shape.
162
+ */
163
+ on_request?: WsRequestResponder;
154
164
  }
155
165
  /** A harness instance — transport handle + connection factory. */
156
166
  export interface WsTestHarness {
@@ -1 +1 @@
1
- {"version":3,"file":"ws_round_trip.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/ws_round_trip.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ws_round_trip.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/ws_round_trip.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import './assert_dev_env.js';
2
2
  import { WSContext, createWSMessageEvent, } from 'hono/ws';
3
- import { Logger } from '@fuzdev/fuz_util/log.js';
4
- import { create_uuid } from '@fuzdev/fuz_util/id.js';
3
+ import { Logger } from '@fuzdev/fuz_util/log.ts';
4
+ import { create_uuid } from '@fuzdev/fuz_util/id.ts';
5
5
  import { ActionPeer } from '../actions/action_peer.js';
6
6
  import { create_broadcast_api } from '../actions/broadcast_api.js';
7
7
  import { register_action_ws } from '../actions/register_action_ws.js';
@@ -12,7 +12,7 @@ import { ROLE_KEEPER } from '../auth/role_schema.js';
12
12
  import { ACCOUNT_ID_KEY, AUTH_API_TOKEN_ID_KEY, CREDENTIAL_TYPE_KEY, TEST_CONTEXT_PRESET_KEY, } from '../hono_context.js';
13
13
  import { create_jsonrpc_request } from '../http/jsonrpc_helpers.js';
14
14
  import { create_test_account, create_test_actor, create_test_role_grant } from './entities.js';
15
- import { WS_CLIENT_DEFAULT_TIMEOUT_MS, is_response_for, } from './transports/ws_client.js';
15
+ import { WS_CLIENT_DEFAULT_TIMEOUT_MS, deliver_inbound, is_response_for, } from './transports/ws_client.js';
16
16
  /**
17
17
  * Build a real `WSContext` backed by in-memory `send`/`close` capture.
18
18
  * Parsing of outgoing frames is left to the caller — `sends` holds the
@@ -169,7 +169,7 @@ const build_simple_request_context = (role) => ({
169
169
  * `onOpen`/`onMessage`/`onClose` path against a real `WSContext`.
170
170
  */
171
171
  export const create_ws_test_harness = (options) => {
172
- const { actions, transport = new BackendWebsocketTransport(), heartbeat = false, log = new Logger('[ws-test]', { level: 'off' }), on_socket_open, on_socket_close, } = options;
172
+ const { actions, transport = new BackendWebsocketTransport(), heartbeat = false, log = new Logger('[ws-test]', { level: 'off' }), on_socket_open, on_socket_close, on_request, } = options;
173
173
  const stub = create_stub_upgrade();
174
174
  // Minimal Hono stub — `register_action_ws` only needs `.get(path, handler)`.
175
175
  const stub_app = { get: () => stub_app };
@@ -211,6 +211,12 @@ export const create_ws_test_harness = (options) => {
211
211
  };
212
212
  const received = [];
213
213
  const waiters = [];
214
+ // Reply path for a server-initiated request — assigned to the
215
+ // client→server send below once `send_impl` exists. A `let` (not a
216
+ // direct `send_impl` reference) keeps the `WSContext.send` closure
217
+ // TDZ-safe; it stays a no-op until a responder + server-initiated
218
+ // request are both in play (deferred for the in-process TS server).
219
+ let reply_to_server = () => { };
214
220
  // Resolvers awaiting a server-initiated close — fired by the
215
221
  // `WSContext.close` callback below so `wait_for_close` resolves
216
222
  // whether the dispatcher (e.g. an auth-guard revocation) or the
@@ -228,14 +234,7 @@ export const create_ws_test_harness = (options) => {
228
234
  if (is_closed)
229
235
  return;
230
236
  const parsed = typeof data === 'string' ? JSON.parse(data) : data;
231
- received.push(parsed);
232
- for (let i = waiters.length - 1; i >= 0; i--) {
233
- const waiter = waiters[i];
234
- if (waiter.predicate(parsed)) {
235
- waiter.resolve(parsed);
236
- waiters.splice(i, 1);
237
- }
238
- }
237
+ deliver_inbound(parsed, received, waiters, on_request, reply_to_server);
239
238
  },
240
239
  close: (code, reason) => {
241
240
  if (is_closed)
@@ -302,6 +301,11 @@ export const create_ws_test_harness = (options) => {
302
301
  // handler, send).
303
302
  await events.onMessage?.(message_event, ws);
304
303
  };
304
+ // A responder's reply to a server-initiated request goes back to the
305
+ // server over the same client→server path as any other send.
306
+ reply_to_server = (message) => {
307
+ void send_impl(message);
308
+ };
305
309
  return {
306
310
  get messages() {
307
311
  return received;
@@ -8,7 +8,7 @@
8
8
  * @module
9
9
  */
10
10
 
11
- import {to_error_message} from '@fuzdev/fuz_util/error.js';
11
+ import {to_error_message} from '@fuzdev/fuz_util/error.ts';
12
12
 
13
13
  import type {AppSurface} from '../http/surface.js';
14
14
  import SurfaceExplorer from './SurfaceExplorer.svelte';
@@ -11,7 +11,7 @@
11
11
 
12
12
  import type {Snippet} from 'svelte';
13
13
  import type {SvelteHTMLElements} from 'svelte/elements';
14
- import {is_editable, swallow} from '@fuzdev/fuz_util/dom.js';
14
+ import {is_editable, swallow} from '@fuzdev/fuz_util/dom.ts';
15
15
 
16
16
  import {SidebarState, sidebar_state_context} from './sidebar_state.svelte.js';
17
17
 
@@ -15,7 +15,7 @@
15
15
  import {goto} from '$app/navigation';
16
16
  import {resolve} from '$app/paths';
17
17
  import PendingButton from '@fuzdev/fuz_ui/PendingButton.svelte';
18
- import {autofocus} from '@fuzdev/fuz_ui/autofocus.svelte.js';
18
+ import {autofocus} from '@fuzdev/fuz_ui/autofocus.svelte.ts';
19
19
 
20
20
  import {Username} from '../primitive_schemas.js';
21
21
  import {PASSWORD_LENGTH_MIN} from '../auth/password.js';
package/dist/ui/CLAUDE.md CHANGED
@@ -68,7 +68,7 @@ their payload shapes are defined in `auth/role_grant_offer_notifications.ts`
68
68
  ### Context over props for shared deps
69
69
 
70
70
  Auth, RPC adapters, sidebar, and role_grant offers all flow through
71
- `create_context` from `@fuzdev/fuz_ui/context_helpers.js`. Components
71
+ `create_context` from `@fuzdev/fuz_ui/context_helpers.ts`. Components
72
72
  consume with `const x = x_context.get()` (or a `get_rpc`/`$derived`
73
73
  pair when the value may change reactively). New shared state joins the
74
74
  pattern rather than reintroducing prop-drilling.
@@ -49,8 +49,8 @@
49
49
  import {DEV} from 'esm-env';
50
50
  import type {SvelteHTMLElements} from 'svelte/elements';
51
51
  import type {ComponentProps, Snippet} from 'svelte';
52
- import type {OmitStrict} from '@fuzdev/fuz_util/types.js';
53
- import {icon_remove} from '@fuzdev/fuz_ui/icons.js';
52
+ import type {OmitStrict} from '@fuzdev/fuz_util/types.ts';
53
+ import {icon_remove} from '@fuzdev/fuz_ui/icons.ts';
54
54
  import PendingAnimation from '@fuzdev/fuz_ui/PendingAnimation.svelte';
55
55
  import Svg from '@fuzdev/fuz_ui/Svg.svelte';
56
56
 
@@ -1,6 +1,6 @@
1
1
  import type { SvelteHTMLElements } from 'svelte/elements';
2
2
  import type { ComponentProps, Snippet } from 'svelte';
3
- import type { OmitStrict } from '@fuzdev/fuz_util/types.js';
3
+ import type { OmitStrict } from '@fuzdev/fuz_util/types.ts';
4
4
  import PopoverButton from './PopoverButton.svelte';
5
5
  import type { Popover } from './popover.svelte.js';
6
6
  type $$ComponentProps = OmitStrict<ComponentProps<typeof PopoverButton>, 'popover_content' | 'children'> & OmitStrict<SvelteHTMLElements['button'], 'children'> & {
@@ -11,7 +11,7 @@
11
11
  import {goto} from '$app/navigation';
12
12
  import {resolve} from '$app/paths';
13
13
  import PendingButton from '@fuzdev/fuz_ui/PendingButton.svelte';
14
- import {autofocus} from '@fuzdev/fuz_ui/autofocus.svelte.js';
14
+ import {autofocus} from '@fuzdev/fuz_ui/autofocus.svelte.ts';
15
15
 
16
16
  import {auth_state_context} from './auth_state.svelte.js';
17
17
  import {FormState} from './form_state.svelte.js';
@@ -22,7 +22,7 @@
22
22
  import type {SvelteHTMLElements} from 'svelte/elements';
23
23
  import {page} from '$app/state';
24
24
  import {resolve} from '$app/paths';
25
- import type {OmitStrict} from '@fuzdev/fuz_util/types.js';
25
+ import type {OmitStrict} from '@fuzdev/fuz_util/types.ts';
26
26
 
27
27
  const {
28
28
  path,
@@ -18,7 +18,7 @@
18
18
  */
19
19
  import type { Snippet } from 'svelte';
20
20
  import type { SvelteHTMLElements } from 'svelte/elements';
21
- import type { OmitStrict } from '@fuzdev/fuz_util/types.js';
21
+ import type { OmitStrict } from '@fuzdev/fuz_util/types.ts';
22
22
  type $$ComponentProps = OmitStrict<SvelteHTMLElements['a'], 'href' | 'children'> & {
23
23
  /** Route path passed to `resolve` from `$app/paths` to compute `href`. */
24
24
  path: string;
@@ -46,7 +46,7 @@
46
46
  import type {SvelteHTMLElements} from 'svelte/elements';
47
47
  import type {Snippet} from 'svelte';
48
48
  import {scale} from 'svelte/transition';
49
- import type {OmitStrict} from '@fuzdev/fuz_util/types.js';
49
+ import type {OmitStrict} from '@fuzdev/fuz_util/types.ts';
50
50
 
51
51
  import {Popover} from './popover.svelte.js';
52
52
  import type {Position, Alignment} from './position_helpers.js';
@@ -43,7 +43,7 @@
43
43
  */
44
44
  import type { SvelteHTMLElements } from 'svelte/elements';
45
45
  import type { Snippet } from 'svelte';
46
- import type { OmitStrict } from '@fuzdev/fuz_util/types.js';
46
+ import type { OmitStrict } from '@fuzdev/fuz_util/types.ts';
47
47
  import { Popover } from './popover.svelte.js';
48
48
  import type { Position, Alignment } from './position_helpers.js';
49
49
  type $$ComponentProps = OmitStrict<SvelteHTMLElements['button'], 'children'> & {