@fuzdev/fuz_app 0.92.0 → 0.94.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 (203) 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 +50 -5
  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/cell_relations.js +1 -1
  122. package/dist/testing/cross_backend/conformance_case.d.ts +4 -0
  123. package/dist/testing/cross_backend/conformance_case.d.ts.map +1 -1
  124. package/dist/testing/cross_backend/conformance_case.js +26 -0
  125. package/dist/testing/cross_backend/conformance_table.d.ts +21 -0
  126. package/dist/testing/cross_backend/conformance_table.d.ts.map +1 -1
  127. package/dist/testing/cross_backend/conformance_table.js +109 -7
  128. package/dist/testing/cross_backend/create_cross_backend_global_setup.d.ts +1 -1
  129. package/dist/testing/cross_backend/create_dual_spawn_global_setup.d.ts +64 -0
  130. package/dist/testing/cross_backend/create_dual_spawn_global_setup.d.ts.map +1 -0
  131. package/dist/testing/cross_backend/{create_schema_parity_global_setup.js → create_dual_spawn_global_setup.js} +1 -1
  132. package/dist/testing/cross_backend/default_backend_configs.d.ts +12 -0
  133. package/dist/testing/cross_backend/default_backend_configs.d.ts.map +1 -1
  134. package/dist/testing/cross_backend/default_backend_configs.js +12 -0
  135. package/dist/testing/cross_backend/default_spine_surface.d.ts +1 -1
  136. package/dist/testing/cross_backend/default_spine_surface.d.ts.map +1 -1
  137. package/dist/testing/cross_backend/default_spine_surface.js +9 -2
  138. package/dist/testing/cross_backend/fact_serving.js +1 -1
  139. package/dist/testing/cross_backend/login_security.d.ts +11 -0
  140. package/dist/testing/cross_backend/login_security.d.ts.map +1 -0
  141. package/dist/testing/cross_backend/login_security.js +130 -0
  142. package/dist/testing/cross_backend/rust_spine_stub_backend_config.d.ts +17 -0
  143. package/dist/testing/cross_backend/rust_spine_stub_backend_config.d.ts.map +1 -1
  144. package/dist/testing/cross_backend/rust_spine_stub_backend_config.js +7 -2
  145. package/dist/testing/cross_backend/setup.d.ts +1 -1
  146. package/dist/testing/cross_backend/setup.js +1 -1
  147. package/dist/testing/cross_backend/testing_reset_actions.js +2 -2
  148. package/dist/testing/cross_backend/testing_server_core.d.ts +1 -1
  149. package/dist/testing/cross_backend/testing_server_core.js +1 -1
  150. package/dist/testing/cross_backend/ts_spine_backend_config.d.ts +11 -0
  151. package/dist/testing/cross_backend/ts_spine_backend_config.d.ts.map +1 -1
  152. package/dist/testing/cross_backend/ts_spine_backend_config.js +23 -7
  153. package/dist/testing/cross_backend/ws_round_trip.js +1 -1
  154. package/dist/testing/db.js +4 -4
  155. package/dist/testing/middleware.js +1 -1
  156. package/dist/testing/role_grant_helpers.d.ts +1 -1
  157. package/dist/testing/rpc_helpers.d.ts +18 -1
  158. package/dist/testing/rpc_helpers.d.ts.map +1 -1
  159. package/dist/testing/rpc_helpers.js +24 -2
  160. package/dist/testing/schema_generators.d.ts +1 -1
  161. package/dist/testing/schema_generators.js +1 -1
  162. package/dist/testing/stubs.js +1 -1
  163. package/dist/testing/testing_rate_limiter.d.ts +1 -1
  164. package/dist/testing/testing_rate_limiter.js +1 -1
  165. package/dist/testing/transports/bootstrap.d.ts +1 -1
  166. package/dist/testing/transports/bootstrap.js +1 -1
  167. package/dist/testing/ws_round_trip.d.ts +2 -2
  168. package/dist/testing/ws_round_trip.js +2 -2
  169. package/dist/ui/AdminSurface.svelte +1 -1
  170. package/dist/ui/AppShell.svelte +1 -1
  171. package/dist/ui/BootstrapForm.svelte +1 -1
  172. package/dist/ui/CLAUDE.md +1 -1
  173. package/dist/ui/ConfirmButton.svelte +2 -2
  174. package/dist/ui/ConfirmButton.svelte.d.ts +1 -1
  175. package/dist/ui/LoginForm.svelte +1 -1
  176. package/dist/ui/MenuLink.svelte +1 -1
  177. package/dist/ui/MenuLink.svelte.d.ts +1 -1
  178. package/dist/ui/PopoverButton.svelte +1 -1
  179. package/dist/ui/PopoverButton.svelte.d.ts +1 -1
  180. package/dist/ui/SignupForm.svelte +1 -1
  181. package/dist/ui/account_sessions_state.svelte.js +1 -1
  182. package/dist/ui/admin_accounts_state.svelte.d.ts +1 -1
  183. package/dist/ui/admin_accounts_state.svelte.js +1 -1
  184. package/dist/ui/admin_invites_state.svelte.d.ts +1 -1
  185. package/dist/ui/admin_invites_state.svelte.js +1 -1
  186. package/dist/ui/admin_sessions_state.svelte.d.ts +1 -1
  187. package/dist/ui/app_settings_state.svelte.js +1 -1
  188. package/dist/ui/async_slot.svelte.d.ts +2 -2
  189. package/dist/ui/async_slot.svelte.js +2 -2
  190. package/dist/ui/audit_log_state.svelte.js +1 -1
  191. package/dist/ui/auth_state.svelte.d.ts +1 -1
  192. package/dist/ui/auth_state.svelte.js +3 -3
  193. package/dist/ui/format_scope.js +1 -1
  194. package/dist/ui/popover.svelte.d.ts +1 -1
  195. package/dist/ui/popover.svelte.js +2 -2
  196. package/dist/ui/position_helpers.js +1 -1
  197. package/dist/ui/role_grant_offers_state.svelte.js +1 -1
  198. package/dist/ui/sidebar_state.svelte.js +1 -1
  199. package/dist/ui/table_state.svelte.d.ts +1 -1
  200. package/dist/ui/table_state.svelte.js +2 -2
  201. package/package.json +3 -2
  202. package/dist/testing/cross_backend/create_schema_parity_global_setup.d.ts +0 -59
  203. package/dist/testing/cross_backend/create_schema_parity_global_setup.d.ts.map +0 -1
@@ -1,5 +1,5 @@
1
1
  import '../assert_dev_env.js';
2
- import { Logger } from '@fuzdev/fuz_util/log.js';
2
+ import { Logger } from '@fuzdev/fuz_util/log.ts';
3
3
  import { write_daemon_info, read_daemon_info, is_daemon_running } from '../../cli/daemon.js';
4
4
  /**
5
5
  * Loopback bind hosts — the only ones the test binary may serve on. It ships
@@ -47,6 +47,17 @@ export interface TsSpineBackendConfigOptions {
47
47
  readonly port?: number;
48
48
  /** Database URL. Default `'memory://'` (in-memory PGlite). */
49
49
  readonly database_url?: string;
50
+ /**
51
+ * Enable the per-IP + per-account login rate limiters on the spawned binary
52
+ * (`FUZ_LOGIN_RATE_LIMIT_ENABLED=true`). Off by default — the standard cross
53
+ * suites fire many loopback logins a live limiter would 429. Set `true` only
54
+ * for the dedicated login-security cross project (`global_setup_login_security.ts`),
55
+ * which drives the 429 + `Retry-After` path and XFF-keyed bucketing over the
56
+ * wire (`login_security.ts`). The binary always wires `trusted_proxies` for
57
+ * `127.0.0.1`/`::1`, so the limiter keys on the resolved `X-Forwarded-For`
58
+ * client IP. Mirrors `SpineStubBackendConfigOptions.enable_login_rate_limit`.
59
+ */
60
+ readonly enable_login_rate_limit?: boolean;
50
61
  }
51
62
  /**
52
63
  * `BackendConfig` for the Node TS spine binary — spawned via `gro run`
@@ -1 +1 @@
1
- {"version":3,"file":"ts_spine_backend_config.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/ts_spine_backend_config.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,qBAAqB,CAAC;AAOvD,8GAA8G;AAC9G,eAAO,MAAM,gBAAgB,6BAA6B,CAAC;AAE3D;;;;;;;;;GASG;AACH,eAAO,MAAM,iBAAiB,4BAA4B,CAAC;AAyB3D,6FAA6F;AAC7F,eAAO,MAAM,0BAA0B,OAAO,CAAC;AAE/C,iDAAiD;AACjD,eAAO,MAAM,0BAA0B,OAAO,CAAC;AAE/C,gDAAgD;AAChD,eAAO,MAAM,yBAAyB,OAAO,CAAC;AAE9C,yDAAyD;AACzD,eAAO,MAAM,mBAAmB,wDAAwD,CAAC;AAEzF,yDAAyD;AACzD,eAAO,MAAM,mBAAmB,wDAAwD,CAAC;AAEzF,wDAAwD;AACxD,eAAO,MAAM,kBAAkB,uDAAuD,CAAC;AAEvF,MAAM,WAAW,2BAA2B;IAC3C,mFAAmF;IACnF,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,8DAA8D;IAC9D,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED;;;GAGG;AACH,eAAO,MAAM,4BAA4B,GACxC,UAAS,2BAAgC,KACvC,aAgBF,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B,GACvC,UAAS,2BAAgC,KACvC,aAgBF,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,4BAA4B,GACxC,UAAS,2BAAgC,KACvC,aA6BF,CAAC"}
1
+ {"version":3,"file":"ts_spine_backend_config.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/ts_spine_backend_config.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,qBAAqB,CAAC;AAQvD,8GAA8G;AAC9G,eAAO,MAAM,gBAAgB,6BAA6B,CAAC;AAE3D;;;;;;;;;GASG;AACH,eAAO,MAAM,iBAAiB,4BAA4B,CAAC;AAyB3D,6FAA6F;AAC7F,eAAO,MAAM,0BAA0B,OAAO,CAAC;AAE/C,iDAAiD;AACjD,eAAO,MAAM,0BAA0B,OAAO,CAAC;AAE/C,gDAAgD;AAChD,eAAO,MAAM,yBAAyB,OAAO,CAAC;AAE9C,yDAAyD;AACzD,eAAO,MAAM,mBAAmB,wDAAwD,CAAC;AAEzF,yDAAyD;AACzD,eAAO,MAAM,mBAAmB,wDAAwD,CAAC;AAEzF,wDAAwD;AACxD,eAAO,MAAM,kBAAkB,uDAAuD,CAAC;AAEvF,MAAM,WAAW,2BAA2B;IAC3C,mFAAmF;IACnF,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,8DAA8D;IAC9D,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B;;;;;;;;;OASG;IACH,QAAQ,CAAC,uBAAuB,CAAC,EAAE,OAAO,CAAC;CAC3C;AAWD;;;GAGG;AACH,eAAO,MAAM,4BAA4B,GACxC,UAAS,2BAAgC,KACvC,aAmBF,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B,GACvC,UAAS,2BAAgC,KACvC,aAmBF,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,4BAA4B,GACxC,UAAS,2BAAgC,KACvC,aAgCF,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import '../assert_dev_env.js';
2
2
  import { build_test_backend_paths } from './build_test_backend_paths.js';
3
- import { make_default_ts_backend_config, ts_default_capabilities, } from './default_backend_configs.js';
3
+ import { LOGIN_RATE_LIMIT_ENABLED_ENV, make_default_ts_backend_config, ts_default_capabilities, } from './default_backend_configs.js';
4
4
  /** Env var naming the backend root dir; `{dir}/run/daemon_token` must match `bootstrap.daemon_token_path`. */
5
5
  export const TS_SPINE_DIR_ENV = 'FUZ_TESTING_TS_SPINE_DIR';
6
6
  /**
@@ -47,12 +47,19 @@ export const TS_SPINE_NODE_ENTRY = 'src/test/cross_backend/testing_spine_server_
47
47
  export const TS_SPINE_DENO_ENTRY = 'src/test/cross_backend/testing_spine_server_deno.ts';
48
48
  /** Entry module spawned for the Bun TS spine binary. */
49
49
  export const TS_SPINE_BUN_ENTRY = 'src/test/cross_backend/testing_spine_server_bun.ts';
50
+ /**
51
+ * `extra_env` carrying the login-rate-limit toggle when enabled. The TS binary
52
+ * reads `FUZ_LOGIN_RATE_LIMIT_ENABLED` directly (a test-only flag, not in
53
+ * `BaseServerEnv`); the same env-var name the Rust spine-stub reads, so one
54
+ * backend-config option drives both impls.
55
+ */
56
+ const login_rate_limit_env = (enable) => enable ? { [LOGIN_RATE_LIMIT_ENABLED_ENV]: 'true' } : {};
50
57
  /**
51
58
  * `BackendConfig` for the Node TS spine binary — spawned via `gro run`
52
59
  * (Gro's TS loader resolves the `$lib`-free entry's relative imports).
53
60
  */
54
61
  export const ts_spine_node_backend_config = (options = {}) => {
55
- const { port = TS_SPINE_NODE_DEFAULT_PORT, database_url } = options;
62
+ const { port = TS_SPINE_NODE_DEFAULT_PORT, database_url, enable_login_rate_limit } = options;
56
63
  const name = 'ts_spine_node';
57
64
  const paths = build_test_backend_paths(name);
58
65
  return {
@@ -62,7 +69,10 @@ export const ts_spine_node_backend_config = (options = {}) => {
62
69
  start_command: ['gro', 'run', TS_SPINE_NODE_ENTRY],
63
70
  database_url,
64
71
  paths,
65
- extra_env: { [TS_SPINE_DIR_ENV]: paths.root },
72
+ extra_env: {
73
+ [TS_SPINE_DIR_ENV]: paths.root,
74
+ ...login_rate_limit_env(enable_login_rate_limit),
75
+ },
66
76
  capabilities: ts_spine_capabilities,
67
77
  }),
68
78
  sse_path: TS_SPINE_SSE_PATH,
@@ -75,7 +85,7 @@ export const ts_spine_node_backend_config = (options = {}) => {
75
85
  * the Node path), and `Bun.serve` + `hono/bun` need no extra deps.
76
86
  */
77
87
  export const ts_spine_bun_backend_config = (options = {}) => {
78
- const { port = TS_SPINE_BUN_DEFAULT_PORT, database_url } = options;
88
+ const { port = TS_SPINE_BUN_DEFAULT_PORT, database_url, enable_login_rate_limit } = options;
79
89
  const name = 'ts_spine_bun';
80
90
  const paths = build_test_backend_paths(name);
81
91
  return {
@@ -85,7 +95,10 @@ export const ts_spine_bun_backend_config = (options = {}) => {
85
95
  start_command: ['bun', 'run', TS_SPINE_BUN_ENTRY],
86
96
  database_url,
87
97
  paths,
88
- extra_env: { [TS_SPINE_DIR_ENV]: paths.root },
98
+ extra_env: {
99
+ [TS_SPINE_DIR_ENV]: paths.root,
100
+ ...login_rate_limit_env(enable_login_rate_limit),
101
+ },
89
102
  capabilities: ts_spine_bun_capabilities,
90
103
  }),
91
104
  sse_path: TS_SPINE_SSE_PATH,
@@ -103,7 +116,7 @@ export const ts_spine_bun_backend_config = (options = {}) => {
103
116
  * built package; this binary tests live source instead.)
104
117
  */
105
118
  export const ts_spine_deno_backend_config = (options = {}) => {
106
- const { port = TS_SPINE_DENO_DEFAULT_PORT, database_url } = options;
119
+ const { port = TS_SPINE_DENO_DEFAULT_PORT, database_url, enable_login_rate_limit } = options;
107
120
  const name = 'ts_spine_deno';
108
121
  const paths = build_test_backend_paths(name);
109
122
  return {
@@ -126,7 +139,10 @@ export const ts_spine_deno_backend_config = (options = {}) => {
126
139
  ],
127
140
  database_url,
128
141
  paths,
129
- extra_env: { [TS_SPINE_DIR_ENV]: paths.root },
142
+ extra_env: {
143
+ [TS_SPINE_DIR_ENV]: paths.root,
144
+ ...login_rate_limit_env(enable_login_rate_limit),
145
+ },
130
146
  capabilities: ts_spine_capabilities,
131
147
  }),
132
148
  sse_path: TS_SPINE_SSE_PATH,
@@ -41,7 +41,7 @@ import '../assert_dev_env.js';
41
41
  * @module
42
42
  */
43
43
  import { assert, describe } from 'vitest';
44
- import { assert_rejects } from '@fuzdev/fuz_util/testing.js';
44
+ import { assert_rejects } from '@fuzdev/fuz_util/testing.ts';
45
45
  import { heartbeat_action_spec } from '../../actions/heartbeat.js';
46
46
  import { account_session_revoke_all_action_spec } from '../../auth/account_action_specs.js';
47
47
  import { create_ws_transport } from '../transports/ws_transport.js';
@@ -8,9 +8,9 @@ import './assert_dev_env.js';
8
8
  *
9
9
  * @example
10
10
  * ```ts
11
- * import {create_pglite_factory, create_pg_factory} from '@fuzdev/fuz_app/testing/db.js';
12
- * import {run_migrations} from '@fuzdev/fuz_app/db/migrate.js';
13
- * import {auth_migration_ns} from '@fuzdev/fuz_app/auth/migrations.js';
11
+ * import {create_pglite_factory, create_pg_factory} from '@fuzdev/fuz_app/testing/db.ts';
12
+ * import {run_migrations} from '@fuzdev/fuz_app/db/migrate.ts';
13
+ * import {auth_migration_ns} from '@fuzdev/fuz_app/auth/migrations.ts';
14
14
  *
15
15
  * const init_schema = async (db) => {
16
16
  * await run_migrations(db, [auth_migration_ns]);
@@ -23,7 +23,7 @@ import './assert_dev_env.js';
23
23
  * @module
24
24
  */
25
25
  import { describe, beforeAll, beforeEach, afterAll } from 'vitest';
26
- import { to_error_message } from '@fuzdev/fuz_util/error.js';
26
+ import { to_error_message } from '@fuzdev/fuz_util/error.ts';
27
27
  import { create_pglite_db } from '../db/db_pglite.js';
28
28
  import { assert_valid_sql_identifier } from '../db/sql_identifier.js';
29
29
  import { create_pg_db } from '../db/db_pg.js';
@@ -10,7 +10,7 @@ import './assert_dev_env.js';
10
10
  */
11
11
  import { vi, test, assert, describe } from 'vitest';
12
12
  import { Hono } from 'hono';
13
- import { Logger } from '@fuzdev/fuz_util/log.js';
13
+ import { Logger } from '@fuzdev/fuz_util/log.ts';
14
14
  import { create_bearer_auth_middleware } from '../auth/bearer_auth.js';
15
15
  import { query_validate_api_token } from '../auth/api_token_queries.js';
16
16
  import { query_account_by_id, query_actor_by_id, query_actors_by_account, } from '../auth/account_queries.js';
@@ -1,5 +1,5 @@
1
1
  import './assert_dev_env.js';
2
- import type { Uuid } from '@fuzdev/fuz_util/id.js';
2
+ import type { Uuid } from '@fuzdev/fuz_util/id.ts';
3
3
  import type { TestAccount, TestApp } from './app_server.js';
4
4
  import type { TestFixture } from './cross_backend/setup.js';
5
5
  import { type RpcCallArgs } from './rpc_helpers.js';
@@ -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":"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"}
@@ -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
@@ -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';
@@ -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';
@@ -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'> & {
@@ -14,7 +14,7 @@
14
14
  import {goto} from '$app/navigation';
15
15
  import {resolve} from '$app/paths';
16
16
  import PendingButton from '@fuzdev/fuz_ui/PendingButton.svelte';
17
- import {autofocus} from '@fuzdev/fuz_ui/autofocus.svelte.js';
17
+ import {autofocus} from '@fuzdev/fuz_ui/autofocus.svelte.ts';
18
18
 
19
19
  import {Username} from '../primitive_schemas.js';
20
20
  import {PASSWORD_LENGTH_MIN} from '../auth/password.js';
@@ -11,7 +11,7 @@
11
11
  *
12
12
  * @module
13
13
  */
14
- import { create_context } from '@fuzdev/fuz_ui/context_helpers.js';
14
+ import { create_context } from '@fuzdev/fuz_ui/context_helpers.ts';
15
15
  import { AsyncSlot } from './async_slot.svelte.js';
16
16
  import { KeyedAsyncSlot } from './keyed_async_slot.svelte.js';
17
17
  /**
@@ -12,7 +12,7 @@
12
12
  *
13
13
  * @module
14
14
  */
15
- import type { Uuid } from '@fuzdev/fuz_util/id.js';
15
+ import type { Uuid } from '@fuzdev/fuz_util/id.ts';
16
16
  import { AsyncSlot } from './async_slot.svelte.js';
17
17
  import { KeyedAsyncSlot } from './keyed_async_slot.svelte.js';
18
18
  import type { AdminAccountEntryJson } from '../auth/account_schema.js';
@@ -12,7 +12,7 @@
12
12
  *
13
13
  * @module
14
14
  */
15
- import { create_context } from '@fuzdev/fuz_ui/context_helpers.js';
15
+ import { create_context } from '@fuzdev/fuz_ui/context_helpers.ts';
16
16
  import { AsyncSlot } from './async_slot.svelte.js';
17
17
  import { KeyedAsyncSlot } from './keyed_async_slot.svelte.js';
18
18
  /**
@@ -13,7 +13,7 @@
13
13
  *
14
14
  * @module
15
15
  */
16
- import type { Uuid } from '@fuzdev/fuz_util/id.js';
16
+ import type { Uuid } from '@fuzdev/fuz_util/id.ts';
17
17
  import { AsyncSlot } from './async_slot.svelte.js';
18
18
  import { KeyedAsyncSlot } from './keyed_async_slot.svelte.js';
19
19
  import type { InviteWithUsernamesJson } from '../auth/invite_schema.js';
@@ -13,7 +13,7 @@
13
13
  *
14
14
  * @module
15
15
  */
16
- import { create_context } from '@fuzdev/fuz_ui/context_helpers.js';
16
+ import { create_context } from '@fuzdev/fuz_ui/context_helpers.ts';
17
17
  import { AsyncSlot } from './async_slot.svelte.js';
18
18
  import { KeyedAsyncSlot } from './keyed_async_slot.svelte.js';
19
19
  /**
@@ -14,7 +14,7 @@
14
14
  *
15
15
  * @module
16
16
  */
17
- import type { Uuid } from '@fuzdev/fuz_util/id.js';
17
+ import type { Uuid } from '@fuzdev/fuz_util/id.ts';
18
18
  import { AsyncSlot } from './async_slot.svelte.js';
19
19
  import { KeyedAsyncSlot } from './keyed_async_slot.svelte.js';
20
20
  import type { AdminAccountsRpc } from './admin_accounts_state.svelte.js';
@@ -11,7 +11,7 @@
11
11
  *
12
12
  * @module
13
13
  */
14
- import { create_context } from '@fuzdev/fuz_ui/context_helpers.js';
14
+ import { create_context } from '@fuzdev/fuz_ui/context_helpers.ts';
15
15
  import { AsyncSlot } from './async_slot.svelte.js';
16
16
  /**
17
17
  * Svelte context carrying the reactive `AppSettingsRpc` accessor. Mirrors
@@ -11,7 +11,7 @@
11
11
  * Core surface:
12
12
  *
13
13
  * - **Explicit four-value `status`** — `AsyncStatus` from
14
- * `@fuzdev/fuz_util/async.js`: `'initial' | 'pending' | 'success' |
14
+ * `@fuzdev/fuz_util/async.ts`: `'initial' | 'pending' | 'success' |
15
15
  * 'failure'`. `loading: false, error: null` would be ambiguous
16
16
  * between "never tried" and "succeeded once and now resting"; the
17
17
  * four-value status removes the need for a per-class `submitted` /
@@ -58,7 +58,7 @@
58
58
  *
59
59
  * @module
60
60
  */
61
- import type { AsyncStatus } from '@fuzdev/fuz_util/async.js';
61
+ import type { AsyncStatus } from '@fuzdev/fuz_util/async.ts';
62
62
  export interface AsyncSlotOptions<T, E = string> {
63
63
  /**
64
64
  * Seed `data` and put the slot in `'success'` before any `run()`. Useful
@@ -11,7 +11,7 @@
11
11
  * Core surface:
12
12
  *
13
13
  * - **Explicit four-value `status`** — `AsyncStatus` from
14
- * `@fuzdev/fuz_util/async.js`: `'initial' | 'pending' | 'success' |
14
+ * `@fuzdev/fuz_util/async.ts`: `'initial' | 'pending' | 'success' |
15
15
  * 'failure'`. `loading: false, error: null` would be ambiguous
16
16
  * between "never tried" and "succeeded once and now resting"; the
17
17
  * four-value status removes the need for a per-class `submitted` /
@@ -58,7 +58,7 @@
58
58
  *
59
59
  * @module
60
60
  */
61
- import { to_error_message } from '@fuzdev/fuz_util/error.js';
61
+ import { to_error_message } from '@fuzdev/fuz_util/error.ts';
62
62
  /**
63
63
  * Reactive container for a single async operation.
64
64
  *
@@ -13,7 +13,7 @@
13
13
  * @module
14
14
  */
15
15
  import { DEV } from 'esm-env';
16
- import { create_context } from '@fuzdev/fuz_ui/context_helpers.js';
16
+ import { create_context } from '@fuzdev/fuz_ui/context_helpers.ts';
17
17
  import { AsyncSlot } from './async_slot.svelte.js';
18
18
  /**
19
19
  * Svelte context carrying the reactive `AuditLogRpc` accessor. Mirrors