@fuzdev/fuz_app 0.128.0 → 0.129.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 (87) hide show
  1. package/dist/actions/register_action_ws.d.ts +0 -1
  2. package/dist/actions/register_action_ws.d.ts.map +1 -1
  3. package/dist/auth/CLAUDE.md +1 -1
  4. package/dist/auth/actor_lookup_action_specs.d.ts +2 -2
  5. package/dist/auth/actor_lookup_action_specs.js +2 -2
  6. package/dist/auth/audit_emitter.d.ts +14 -7
  7. package/dist/auth/audit_emitter.d.ts.map +1 -1
  8. package/dist/auth/audit_emitter.js +6 -8
  9. package/dist/auth/bearer_auth.d.ts +3 -2
  10. package/dist/auth/bearer_auth.d.ts.map +1 -1
  11. package/dist/auth/bearer_auth.js +3 -2
  12. package/dist/auth/request_context.d.ts +1 -1
  13. package/dist/auth/request_context.js +1 -1
  14. package/dist/auth/token_scope.d.ts +4 -2
  15. package/dist/auth/token_scope.d.ts.map +1 -1
  16. package/dist/auth/token_scope.js +10 -2
  17. package/dist/http/CLAUDE.md +3 -4
  18. package/dist/http/auth_shape.d.ts +3 -2
  19. package/dist/http/auth_shape.d.ts.map +1 -1
  20. package/dist/http/auth_shape.js +3 -2
  21. package/dist/http/common_routes.d.ts +1 -14
  22. package/dist/http/common_routes.d.ts.map +1 -1
  23. package/dist/http/common_routes.js +1 -19
  24. package/dist/http/ip_canonical.d.ts +1 -1
  25. package/dist/http/ip_canonical.js +1 -1
  26. package/dist/realtime/sse_auth_guard.d.ts +3 -1
  27. package/dist/realtime/sse_auth_guard.d.ts.map +1 -1
  28. package/dist/realtime/sse_auth_guard.js +3 -1
  29. package/dist/server/app_server.d.ts +118 -7
  30. package/dist/server/app_server.d.ts.map +1 -1
  31. package/dist/server/app_server.js +136 -91
  32. package/dist/server/surface_route.d.ts +32 -0
  33. package/dist/server/surface_route.d.ts.map +1 -0
  34. package/dist/server/surface_route.js +46 -0
  35. package/dist/testing/CLAUDE.md +17 -12
  36. package/dist/testing/app_server.d.ts +39 -4
  37. package/dist/testing/app_server.d.ts.map +1 -1
  38. package/dist/testing/app_server.js +84 -68
  39. package/dist/testing/audit_completeness.js +1 -1
  40. package/dist/testing/audit_drift_guard.d.ts +1 -1
  41. package/dist/testing/cross_backend/default_spine_surface.d.ts +2 -2
  42. package/dist/testing/cross_backend/default_spine_surface.d.ts.map +1 -1
  43. package/dist/testing/cross_backend/default_spine_surface.js +5 -2
  44. package/dist/testing/cross_backend/identity_parity.js +1 -1
  45. package/dist/testing/cross_backend/in_process_setup.d.ts.map +1 -1
  46. package/dist/testing/cross_backend/in_process_setup.js +4 -1
  47. package/dist/testing/cross_backend/method_coverage.d.ts +1 -1
  48. package/dist/testing/cross_backend/method_coverage.d.ts.map +1 -1
  49. package/dist/testing/cross_backend/method_coverage.js +2 -2
  50. package/dist/testing/cross_backend/peer_ping_ws.d.ts +1 -1
  51. package/dist/testing/cross_backend/peer_ping_ws.d.ts.map +1 -1
  52. package/dist/testing/cross_backend/role_grant_offer_notification_ws.d.ts +1 -1
  53. package/dist/testing/cross_backend/role_grant_offer_notification_ws.d.ts.map +1 -1
  54. package/dist/testing/cross_backend/setup.d.ts +4 -4
  55. package/dist/testing/cross_backend/setup.js +1 -1
  56. package/dist/testing/cross_backend/sse_round_trip.d.ts +1 -1
  57. package/dist/testing/cross_backend/sse_round_trip.d.ts.map +1 -1
  58. package/dist/testing/cross_backend/testing_reset_actions.d.ts +24 -14
  59. package/dist/testing/cross_backend/testing_reset_actions.d.ts.map +1 -1
  60. package/dist/testing/cross_backend/testing_reset_actions.js +40 -32
  61. package/dist/testing/cross_backend/testing_server_bun.d.ts +1 -1
  62. package/dist/testing/cross_backend/testing_server_bun.d.ts.map +1 -1
  63. package/dist/testing/cross_backend/testing_server_bun.js +80 -64
  64. package/dist/testing/cross_backend/testing_server_core.d.ts +10 -4
  65. package/dist/testing/cross_backend/testing_server_core.d.ts.map +1 -1
  66. package/dist/testing/cross_backend/testing_server_deno.d.ts +1 -1
  67. package/dist/testing/cross_backend/testing_server_deno.d.ts.map +1 -1
  68. package/dist/testing/cross_backend/testing_server_deno.js +1 -1
  69. package/dist/testing/cross_backend/testing_server_node.d.ts +1 -1
  70. package/dist/testing/cross_backend/testing_server_node.d.ts.map +1 -1
  71. package/dist/testing/cross_backend/testing_server_node.js +2 -2
  72. package/dist/testing/cross_backend/ws_round_trip.d.ts +1 -1
  73. package/dist/testing/cross_backend/ws_round_trip.d.ts.map +1 -1
  74. package/dist/testing/cross_backend/ws_round_trip.js +11 -9
  75. package/dist/testing/stubs.d.ts +45 -7
  76. package/dist/testing/stubs.d.ts.map +1 -1
  77. package/dist/testing/stubs.js +60 -31
  78. package/dist/testing/ws_round_trip.d.ts +1 -3
  79. package/dist/testing/ws_round_trip.d.ts.map +1 -1
  80. package/dist/ui/AdminSurface.svelte +3 -1
  81. package/dist/ui/AdminSurface.svelte.d.ts.map +1 -1
  82. package/dist/ui/CLAUDE.md +3 -1
  83. package/dist/ui/async_slot.svelte.d.ts +4 -4
  84. package/dist/ui/async_slot.svelte.js +4 -4
  85. package/dist/ui/keyed_async_slot.svelte.d.ts +4 -4
  86. package/dist/ui/keyed_async_slot.svelte.js +3 -3
  87. package/package.json +1 -1
@@ -8,12 +8,13 @@ import './assert_dev_env.js';
8
8
  * @module
9
9
  */
10
10
  import { Logger } from '@fuzdev/fuz_util/log.ts';
11
- import { ApiError, RateLimitError } from '../http/error_schemas.js';
11
+ import { ApiError } from '../http/error_schemas.js';
12
12
  import { create_realtime_closer } from '../actions/connection_closer.js';
13
13
  import { Db } from '../db/db.js';
14
14
  import { prefix_route_specs } from '../http/route_spec.js';
15
15
  import { bootstrap_route_shape } from '../auth/bootstrap_route_schema.js';
16
16
  import { create_rpc_endpoint } from '../actions/action_rpc.js';
17
+ import { create_surface_route_spec } from '../server/surface_route.js';
17
18
  import { create_app_surface_spec } from '../http/surface.js';
18
19
  import { resolve_ws_endpoints } from '../actions/ws_endpoint_spec.js';
19
20
  import { AUDIT_LOG_SSE_MAX_PER_SCOPE } from '../realtime/sse_auth_guard.js';
@@ -135,17 +136,6 @@ export const create_stub_audit_sse = () => {
135
136
  registry
136
137
  };
137
138
  };
138
- /** Stub `AppDeps` for auth surface tests — throws on any method access. */
139
- export const stub_app_deps = {
140
- read_secure_file: create_throwing_stub('read_secure_file'),
141
- delete_file: create_throwing_stub('delete_file'),
142
- keyring: create_throwing_stub('keyring'),
143
- password: create_throwing_stub('password'),
144
- db: create_throwing_stub('db'),
145
- log: create_throwing_stub('log'),
146
- audit: create_test_audit_emitter(),
147
- connection_closer: create_realtime_closer()
148
- };
149
139
  /**
150
140
  * Create no-op `AppDeps` for auth surface testing.
151
141
  */
@@ -161,12 +151,30 @@ export const create_stub_app_deps = () => ({
161
151
  audit: create_test_audit_emitter(),
162
152
  connection_closer: create_realtime_closer()
163
153
  });
154
+ /**
155
+ * Create a stub `AppBackend` with no database behind it — no migration
156
+ * results, and a `close` that does nothing unless one is passed. For
157
+ * assembling a server (`create_app_server`) in tests that never reach the
158
+ * database; one whose `close` does nothing can host server after server.
159
+ *
160
+ * @param options - the deps and `close` to use in place of the defaults
161
+ */
162
+ export const create_stub_app_backend = (options) => ({
163
+ db_type: 'pglite-memory',
164
+ db_name: 'test',
165
+ migration_results: [],
166
+ close: options?.close ?? (async () => { }),
167
+ deps: options?.deps ?? create_stub_app_deps()
168
+ });
164
169
  /** A fresh pass-through middleware — a distinct handler per call, unlike the shared `stub_mw`. */
165
170
  const create_stub_mw = () => async (_c, next) => next();
166
171
  /**
167
172
  * Create the API middleware stub array matching `create_auth_middleware_specs`
168
- * output. Like the real factory's, each spec gets its own pass-through handler,
169
- * so `assert_middleware_stack_mounted` can tell the layers apart by identity.
173
+ * output — the same names, paths, order, and declared `errors` (the surface
174
+ * merges middleware errors into every route under the path, so a stub that
175
+ * declared more than the real stack would widen the test surface). Like the
176
+ * real factory's, each spec gets its own pass-through handler, so
177
+ * `assert_middleware_stack_mounted` can tell the layers apart by identity.
170
178
  */
171
179
  export const create_stub_api_middleware = (options) => {
172
180
  const specs = [
@@ -182,7 +190,7 @@ export const create_stub_api_middleware = (options) => {
182
190
  name: 'bearer_auth',
183
191
  path: AUTH_MIDDLEWARE_PATH,
184
192
  handler: create_stub_mw(),
185
- errors: { 401: ApiError, 403: ApiError, 429: RateLimitError }
193
+ errors: {}
186
194
  }
187
195
  ];
188
196
  if (options?.include_daemon_token) {
@@ -190,7 +198,7 @@ export const create_stub_api_middleware = (options) => {
190
198
  name: 'daemon_token',
191
199
  path: AUTH_MIDDLEWARE_PATH,
192
200
  handler: create_stub_mw(),
193
- errors: { 401: ApiError, 500: ApiError, 503: ApiError }
201
+ errors: {}
194
202
  });
195
203
  }
196
204
  return specs;
@@ -204,16 +212,10 @@ export const create_stub_api_middleware = (options) => {
204
212
  * @param session_options - consumer's session config (required — varies per app)
205
213
  */
206
214
  export const create_stub_app_server_context = (session_options) => {
207
- const deps = create_stub_app_deps();
215
+ const backend = create_stub_app_backend();
208
216
  return {
209
- deps,
210
- backend: {
211
- deps,
212
- db_type: 'pglite-memory',
213
- db_name: 'test',
214
- migration_results: [],
215
- close: async () => { }
216
- },
217
+ deps: backend.deps,
218
+ backend,
217
219
  bootstrap_status: { available: false, token_path: null },
218
220
  session_options,
219
221
  login_ip_rate_limiter: null,
@@ -251,13 +253,16 @@ const to_self_resolved_ws_endpoint = (endpoint) => {
251
253
  * suites consume the spec object this function returns, not the JSON
252
254
  * file.
253
255
  *
254
- * Mirrors `create_app_server`'s route assembly: consumer routes +
255
- * factory-managed bootstrap routes + surface generation — including its
256
+ * Mirrors `create_app_server`'s route assembly, in its order: consumer
257
+ * routes, then the factory-managed bootstrap routes, RPC endpoint routes, and
258
+ * `GET /api/surface` (with `surface_route: true`), then surface
259
+ * generation — including its
256
260
  * refusal of an `rpc_endpoints` or `ws_endpoints` path outside the auth
257
261
  * middleware's scope (`assert_endpoint_in_auth_scope`) and of a
258
262
  * `transform_middleware` that doesn't keep the proxy and auth stack mounted
259
263
  * (`assert_middleware_stack_mounted`). The middleware list mirrors the real
260
- * one: a stub `trusted_proxy` spec at `'*'`, then the stub auth stack. If
264
+ * one: a stub `trusted_proxy` spec at `'*'`, then the stub auth stack (with
265
+ * `daemon_token` when `options.daemon_token` is set). If
261
266
  * `create_app_server` changes how it wires routes, update this helper
262
267
  * to stay in sync (single source of truth for all consumers).
263
268
  *
@@ -308,11 +313,33 @@ export const create_test_app_surface_spec = (options) => {
308
313
  { ...bootstrap_route_shape, handler: stub_handler }
309
314
  ])
310
315
  : [];
311
- const route_specs = [...consumer_routes, ...rpc_route_specs, ...bootstrap_route_specs];
316
+ // the surface route mirrors `create_app_server`'s opt-in mount — its handler
317
+ // serves the surface generated below, backfilled into the same ref
318
+ const surface_ref = {
319
+ surface: {
320
+ middleware: [],
321
+ routes: [],
322
+ rpc_endpoints: [],
323
+ ws_endpoints: [],
324
+ env: [],
325
+ events: [],
326
+ diagnostics: []
327
+ }
328
+ };
329
+ const surface_route_specs = options.surface_route
330
+ ? [create_surface_route_spec(surface_ref)]
331
+ : [];
332
+ // `create_app_server`'s order: consumer routes, then the factory routes
333
+ const route_specs = [
334
+ ...consumer_routes,
335
+ ...bootstrap_route_specs,
336
+ ...rpc_route_specs,
337
+ ...surface_route_specs
338
+ ];
312
339
  // mirrors `create_app_server`'s `[proxy_spec, ...auth_middleware]`
313
340
  const stack_specs = [
314
341
  { name: 'trusted_proxy', path: '*', handler: create_stub_mw() },
315
- ...create_stub_api_middleware()
342
+ ...create_stub_api_middleware({ include_daemon_token: options.daemon_token })
316
343
  ];
317
344
  let middleware_specs = stack_specs;
318
345
  if (options.transform_middleware) {
@@ -321,7 +348,7 @@ export const create_test_app_surface_spec = (options) => {
321
348
  middleware_specs = options.transform_middleware(stack_specs.map((spec) => ({ ...spec })));
322
349
  assert_middleware_stack_mounted(stack_specs, middleware_specs);
323
350
  }
324
- return create_app_surface_spec({
351
+ const surface_spec = create_app_surface_spec({
325
352
  middleware_specs,
326
353
  route_specs,
327
354
  env_schema: options.env_schema ?? BaseServerEnv,
@@ -329,4 +356,6 @@ export const create_test_app_surface_spec = (options) => {
329
356
  rpc_endpoints: resolved_rpc_endpoints,
330
357
  ws_endpoints: resolved_ws_endpoints
331
358
  });
359
+ surface_ref.surface = surface_spec.surface;
360
+ return surface_spec;
332
361
  };
@@ -202,9 +202,7 @@ export interface WsTestHarness {
202
202
  /**
203
203
  * Open a mock connection. Resolves after `on_socket_open` (and the
204
204
  * transport's `register_ws`) completes, so broadcasts issued
205
- * immediately after the `await` reach the connection. Earlier
206
- * revisions returned synchronously and required a `settle_open()`
207
- * microtask drain — no longer necessary.
205
+ * immediately after the `await` reach the connection.
208
206
  *
209
207
  * Returns the shared `WsClient` interface — same surface the
210
208
  * cross-process driver in `transports/ws_transport.ts` implements,
@@ -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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"}
@@ -3,7 +3,9 @@
3
3
  * Attack-surface viewer. Fetches `GET /api/surface` (REST — not RPC, since
4
4
  * the surface dump exists outside the action surface) and delegates
5
5
  * rendering to `SurfaceExplorer`. Surfaces a retry button on fetch
6
- * failures.
6
+ * failures. The server must opt in to the route
7
+ * (`create_app_server({surface_route: true})`), which is admin-only and
8
+ * refused to a narrowed API token.
7
9
  *
8
10
  * @module
9
11
  */
@@ -1 +1 @@
1
- {"version":3,"file":"AdminSurface.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/ui/AdminSurface.svelte"],"names":[],"mappings":"AAkEA,QAAA,MAAM,YAAY,2DAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"AdminSurface.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/ui/AdminSurface.svelte"],"names":[],"mappings":"AAoEA,QAAA,MAAM,YAAY,2DAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
package/dist/ui/CLAUDE.md CHANGED
@@ -326,7 +326,9 @@ destructive actions.
326
326
  - `AdminSettings.svelte` — shell for `OpenSignupToggle` + the logged-in
327
327
  account line + logout `ConfirmButton`. No direct RPC calls.
328
328
  - `AdminSurface.svelte` — attack-surface viewer. Fetches
329
- `/api/surface` (REST) and delegates to `SurfaceExplorer`.
329
+ `/api/surface` (REST) and delegates to `SurfaceExplorer`. The server must
330
+ opt in with `create_app_server({surface_route: true})`; the route is
331
+ admin-only and refused to a narrowed API token.
330
332
  - `OpenSignupToggle.svelte` — single checkbox bound to
331
333
  `AppSettingsState.settings.open_signup`. Consumes
332
334
  `app_settings_rpc_context`.
@@ -28,7 +28,7 @@
28
28
  * would otherwise need to compensate for.
29
29
  * - **`AbortSignal` threaded to the callback** — RPC clients that accept
30
30
  * a signal (or `fetch`) get cancellation for free; callers can also
31
- * pass an external `signal` via {@link RunOptions} to bind the slot's
31
+ * pass an external `signal` via `RunOptions` to bind the slot's
32
32
  * lifetime to a component / page.
33
33
  * - **`preserve_error_on_retry`** — opt-in to keeping the previous error
34
34
  * visible while a retry is pending (default clears at the start of
@@ -68,7 +68,7 @@ export interface AsyncSlotOptions<T, E = string> {
68
68
  initial?: T;
69
69
  /**
70
70
  * Convert a caught throw into the error value stored in
71
- * {@link AsyncSlot.error}. Default extracts `Error.message` (falling
71
+ * `AsyncSlot.error`. Default extracts `Error.message` (falling
72
72
  * back to `'Request failed'` for non-Error throws). Pass
73
73
  * `to_rpc_error_message` to unwrap JSON-RPC `data.reason` codes.
74
74
  */
@@ -87,7 +87,7 @@ export interface RunOptions {
87
87
  /**
88
88
  * External signal chained into the slot's internal controller. Aborts
89
89
  * the in-flight run when fired (alongside automatic supersession by
90
- * the next `run()` and manual {@link AsyncSlot.abort} calls).
90
+ * the next `run()` and manual `AsyncSlot.abort` calls).
91
91
  */
92
92
  signal?: AbortSignal;
93
93
  }
@@ -96,7 +96,7 @@ export interface RunOptions {
96
96
  *
97
97
  * @typeParam T - The success payload type. Use `void` for write-only
98
98
  * actions whose response isn't worth retaining.
99
- * @typeParam E - The shape of {@link AsyncSlot.error}. Defaults to
99
+ * @typeParam E - The shape of `AsyncSlot.error`. Defaults to
100
100
  * `string` (set by the default `map_error`). Narrow to a structured
101
101
  * type by providing a `map_error` that returns it.
102
102
  */
@@ -28,7 +28,7 @@
28
28
  * would otherwise need to compensate for.
29
29
  * - **`AbortSignal` threaded to the callback** — RPC clients that accept
30
30
  * a signal (or `fetch`) get cancellation for free; callers can also
31
- * pass an external `signal` via {@link RunOptions} to bind the slot's
31
+ * pass an external `signal` via `RunOptions` to bind the slot's
32
32
  * lifetime to a component / page.
33
33
  * - **`preserve_error_on_retry`** — opt-in to keeping the previous error
34
34
  * visible while a retry is pending (default clears at the start of
@@ -64,7 +64,7 @@ import { to_error_message } from '@fuzdev/fuz_util/error.ts';
64
64
  *
65
65
  * @typeParam T - The success payload type. Use `void` for write-only
66
66
  * actions whose response isn't worth retaining.
67
- * @typeParam E - The shape of {@link AsyncSlot.error}. Defaults to
67
+ * @typeParam E - The shape of `AsyncSlot.error`. Defaults to
68
68
  * `string` (set by the default `map_error`). Narrow to a structured
69
69
  * type by providing a `map_error` that returns it.
70
70
  */
@@ -85,7 +85,7 @@ export class AsyncSlot {
85
85
  #controller = null;
86
86
  /**
87
87
  * Tracks whether any `run()` or `set()` has ever produced a success
88
- * result. Used by {@link abort} to revert to `'success'` (vs `'initial'`)
88
+ * result. Used by `abort` to revert to `'success'` (vs `'initial'`)
89
89
  * — explicit flag instead of inspecting `data` so the discriminator
90
90
  * stays correct for `T = void` (where success-`data` is `undefined`)
91
91
  * and for nullable `T`s where `null` is a legitimate success value.
@@ -183,7 +183,7 @@ export class AsyncSlot {
183
183
  }
184
184
  /**
185
185
  * Abort the in-flight run (if any) and null out the controller field.
186
- * Shared by {@link abort}, {@link set}, and {@link reset}.
186
+ * Shared by `abort`, `set`, and `reset`.
187
187
  */
188
188
  #clear_controller(reason) {
189
189
  this.#controller?.abort(reason);
@@ -46,7 +46,7 @@ import { AsyncSlot, type AsyncSlotOptions, type RunOptions } from './async_slot.
46
46
  * Constructor options for `KeyedAsyncSlot`. Propagated to every child
47
47
  * `AsyncSlot` at lazy creation time.
48
48
  *
49
- * `initial` from {@link AsyncSlotOptions} is deliberately omitted —
49
+ * `initial` from `AsyncSlotOptions` is deliberately omitted —
50
50
  * keyed slots have no per-key seed concept (the entries don't exist
51
51
  * until `run()` creates them).
52
52
  */
@@ -74,7 +74,7 @@ export declare class KeyedAsyncSlot<K, T = void, E = string> {
74
74
  * `undefined` if no `run()` has been issued for it yet. Reactive on
75
75
  * map population and on the slot's `$state.raw` fields.
76
76
  *
77
- * Prefer the sugar getters ({@link loading}, {@link error}) for
77
+ * Prefer the sugar getters (`loading`, `error`) for
78
78
  * templates; reach for `get(key)` when you need `error_data`, `data`,
79
79
  * or to call `abort()` / `set()` / `reset()` on the underlying slot.
80
80
  */
@@ -109,12 +109,12 @@ export declare class KeyedAsyncSlot<K, T = void, E = string> {
109
109
  /**
110
110
  * Abort the in-flight run for `key`, if any. No-op when the key has
111
111
  * no entry. The slot stays in the map at its prior resolved status —
112
- * call {@link delete} to remove the entry entirely.
112
+ * call `delete` to remove the entry entirely.
113
113
  */
114
114
  abort(key: K, reason?: unknown): void;
115
115
  /**
116
116
  * Abort every in-flight run. Resolved entries stay in the map —
117
- * call {@link reset} to clear them too.
117
+ * call `reset` to clear them too.
118
118
  */
119
119
  abort_all(reason?: unknown): void;
120
120
  /**
@@ -73,7 +73,7 @@ export class KeyedAsyncSlot {
73
73
  * `undefined` if no `run()` has been issued for it yet. Reactive on
74
74
  * map population and on the slot's `$state.raw` fields.
75
75
  *
76
- * Prefer the sugar getters ({@link loading}, {@link error}) for
76
+ * Prefer the sugar getters (`loading`, `error`) for
77
77
  * templates; reach for `get(key)` when you need `error_data`, `data`,
78
78
  * or to call `abort()` / `set()` / `reset()` on the underlying slot.
79
79
  */
@@ -131,14 +131,14 @@ export class KeyedAsyncSlot {
131
131
  /**
132
132
  * Abort the in-flight run for `key`, if any. No-op when the key has
133
133
  * no entry. The slot stays in the map at its prior resolved status —
134
- * call {@link delete} to remove the entry entirely.
134
+ * call `delete` to remove the entry entirely.
135
135
  */
136
136
  abort(key, reason) {
137
137
  this.#slots.get(key)?.abort(reason);
138
138
  }
139
139
  /**
140
140
  * Abort every in-flight run. Resolved entries stay in the map —
141
- * call {@link reset} to clear them too.
141
+ * call `reset` to clear them too.
142
142
  */
143
143
  abort_all(reason) {
144
144
  for (const slot of this.#slots.values()) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fuzdev/fuz_app",
3
- "version": "0.128.0",
3
+ "version": "0.129.0",
4
4
  "description": "fullstack app library",
5
5
  "glyph": "🗝",
6
6
  "logo": "logo.svg",