@fuzdev/fuz_app 0.60.0 → 0.61.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 (57) hide show
  1. package/dist/ui/AccountSessions.svelte +21 -6
  2. package/dist/ui/AccountSessions.svelte.d.ts.map +1 -1
  3. package/dist/ui/AdminAccounts.svelte +32 -25
  4. package/dist/ui/AdminAccounts.svelte.d.ts.map +1 -1
  5. package/dist/ui/AdminAuditLog.svelte +3 -3
  6. package/dist/ui/AdminInvites.svelte +20 -15
  7. package/dist/ui/AdminOverview.svelte +19 -21
  8. package/dist/ui/AdminOverview.svelte.d.ts.map +1 -1
  9. package/dist/ui/AdminRoleGrantHistory.svelte +3 -3
  10. package/dist/ui/AdminSessions.svelte +19 -21
  11. package/dist/ui/AdminSessions.svelte.d.ts.map +1 -1
  12. package/dist/ui/AdminSettings.svelte +1 -3
  13. package/dist/ui/AdminSettings.svelte.d.ts.map +1 -1
  14. package/dist/ui/CLAUDE.md +123 -69
  15. package/dist/ui/ConfirmButton.svelte +82 -24
  16. package/dist/ui/ConfirmButton.svelte.d.ts +8 -34
  17. package/dist/ui/ConfirmButton.svelte.d.ts.map +1 -1
  18. package/dist/ui/OpenSignupToggle.svelte +6 -4
  19. package/dist/ui/OpenSignupToggle.svelte.d.ts.map +1 -1
  20. package/dist/ui/RoleGrantOfferForm.svelte +4 -4
  21. package/dist/ui/RoleGrantOfferHistory.svelte +3 -3
  22. package/dist/ui/RoleGrantOfferInbox.svelte +10 -6
  23. package/dist/ui/RoleGrantOfferInbox.svelte.d.ts.map +1 -1
  24. package/dist/ui/account_sessions_state.svelte.d.ts +17 -7
  25. package/dist/ui/account_sessions_state.svelte.d.ts.map +1 -1
  26. package/dist/ui/account_sessions_state.svelte.js +32 -33
  27. package/dist/ui/admin_accounts_state.svelte.d.ts +48 -17
  28. package/dist/ui/admin_accounts_state.svelte.d.ts.map +1 -1
  29. package/dist/ui/admin_accounts_state.svelte.js +58 -76
  30. package/dist/ui/admin_invites_state.svelte.d.ts +14 -7
  31. package/dist/ui/admin_invites_state.svelte.d.ts.map +1 -1
  32. package/dist/ui/admin_invites_state.svelte.js +32 -48
  33. package/dist/ui/admin_sessions_state.svelte.d.ts +15 -8
  34. package/dist/ui/admin_sessions_state.svelte.d.ts.map +1 -1
  35. package/dist/ui/admin_sessions_state.svelte.js +30 -47
  36. package/dist/ui/app_settings_state.svelte.d.ts +8 -3
  37. package/dist/ui/app_settings_state.svelte.d.ts.map +1 -1
  38. package/dist/ui/app_settings_state.svelte.js +19 -27
  39. package/dist/ui/async_slot.svelte.d.ts +173 -0
  40. package/dist/ui/async_slot.svelte.d.ts.map +1 -0
  41. package/dist/ui/async_slot.svelte.js +241 -0
  42. package/dist/ui/audit_log_state.svelte.d.ts +8 -2
  43. package/dist/ui/audit_log_state.svelte.d.ts.map +1 -1
  44. package/dist/ui/audit_log_state.svelte.js +19 -18
  45. package/dist/ui/keyed_async_slot.svelte.d.ts +139 -0
  46. package/dist/ui/keyed_async_slot.svelte.d.ts.map +1 -0
  47. package/dist/ui/keyed_async_slot.svelte.js +177 -0
  48. package/dist/ui/role_grant_offers_state.svelte.d.ts +39 -7
  49. package/dist/ui/role_grant_offers_state.svelte.d.ts.map +1 -1
  50. package/dist/ui/role_grant_offers_state.svelte.js +34 -15
  51. package/dist/ui/table_state.svelte.d.ts +10 -7
  52. package/dist/ui/table_state.svelte.d.ts.map +1 -1
  53. package/dist/ui/table_state.svelte.js +11 -8
  54. package/package.json +1 -1
  55. package/dist/ui/loadable.svelte.d.ts +0 -60
  56. package/dist/ui/loadable.svelte.d.ts.map +0 -1
  57. package/dist/ui/loadable.svelte.js +0 -80
package/dist/ui/CLAUDE.md CHANGED
@@ -2,8 +2,12 @@
2
2
 
3
3
  Frontend subsystem — Svelte 5 components, reactive state classes, and DOM
4
4
  utilities. Cookie-based SPA auth; prerendered static HTML served by Hono
5
- (no SvelteKit SSR for sessions). State classes extend `Loadable` and
6
- hold `$state` fields exclusively via runes. Shared dependencies flow
5
+ (no SvelteKit SSR for sessions). State classes hold one or more `AsyncSlot`s
6
+ via composition (one per distinct async operation — e.g. `list` + `create` +
7
+ `revoke`); per-row write ops use `KeyedAsyncSlot<K, T = void, E = string>`
8
+ (supersedes the old `AsyncSlot` + `SvelteSet<id>` pair) so concurrent rows
9
+ don't abort each other and failures surface per-row via `slot.error(key)`.
10
+ Payload lives as `$state.raw` fields on the class. Shared dependencies flow
7
11
  through Svelte context, never through props — RPC adapters in particular
8
12
  are provisioned once at the admin shell and read by every `Admin*.svelte`.
9
13
 
@@ -128,14 +132,18 @@ destructive actions.
128
132
  - `AdminAccounts.svelte` — accounts + role_grants + pending offers.
129
133
  Consumes `admin_accounts_rpc_context`. Per-row actions: grant (+role
130
134
  chip with `ConfirmButton`), revoke (`actor_id` + `role_grant_id`),
131
- retract pending offer. Tracks `granting_keys` / `revoking_ids` /
132
- `retracting_ids` for per-action spinners.
135
+ retract pending offer. Reads per-row spinner + error state via
136
+ `state.grant.loading(key)` / `state.revoke.loading(role_grant_id)` /
137
+ `state.retract.loading(offer_id)` and their `.error(key)` siblings —
138
+ per-row error displays inline next to the failing button (no
139
+ top-level rollup).
133
140
  - `AdminAuditLog.svelte` — audit event stream. Consumes
134
141
  `audit_log_rpc_context`. Filter by `event_type`, manual refresh,
135
142
  toggle SSE streaming (via `EventSource` — not RPC).
136
143
  - `AdminInvites.svelte` — invite CRUD + embeds `OpenSignupToggle`.
137
- Consumes `admin_invites_rpc_context`. Tracks `creating` +
138
- `deleting_ids`.
144
+ Consumes `admin_invites_rpc_context`. Per-row delete reads
145
+ `state.remove.loading(invite_id)` / `state.remove.error(invite_id)`
146
+ with inline per-row error display.
139
147
  - `AdminOverview.svelte` — dashboard panels (accounts / sessions /
140
148
  invites / recent activity / security / system). Consumes all four
141
149
  RPC contexts plus `auth_state_context`; fetches in parallel on mount.
@@ -185,27 +193,56 @@ destructive actions.
185
193
  `format_scope?`, `format_role?`. Consumes
186
194
  `role_grant_offers_state_context`; caller seeds via
187
195
  `RoleGrantOffersState.fetch_history()`.
188
- - `role_grant_offers_state.svelte.ts` — `RoleGrantOffersState` (extends
189
- `Loadable`) + `role_grant_offers_state_context`. Options:
190
- `rpc: RoleGrantOffersRpc`, `account_id: () => string | null`,
191
- `actor_id: () => string | null`. The narrow `RoleGrantOffersRpc`
192
- interface has six methods: `list`, `history`, `create`, `accept`,
193
- `decline`, `retract`. `$state.raw` Map keyed by offer id;
194
- `$derived.by` views: `incoming` (recipient-side pending, soonest-
195
- expiry first), `outgoing` (grantor-side pending, newest-created
196
- first), `history` (all known, newest-created first). Reducer
197
- `apply_notification` handles the six role-grant-offer notification
198
- methods; `role_grant_revoke` is deliberately ignored here (auth/role_grants
199
- concern). `reset()` clears the Map.
196
+ - `role_grant_offers_state.svelte.ts` — `RoleGrantOffersState` +
197
+ `role_grant_offers_state_context`. Options: `rpc: RoleGrantOffersRpc`,
198
+ `account_id: () => string | null`, `actor_id: () => string | null`.
199
+ The narrow `RoleGrantOffersRpc` interface has six methods: `list`,
200
+ `history`, `create`, `accept`, `decline`, `retract`. Holds six
201
+ `AsyncSlot`s five `AsyncSlot<void>` for status/error tracking
202
+ (`list` / `list_history` / `accept` / `decline` / `retract`) plus
203
+ one `AsyncSlot<RoleGrantOfferJson>` (`create`) that owns the
204
+ created offer so `submit_create` returns it via the slot's
205
+ supersession-safe `data` path. The `$state.raw` Map cache keyed by
206
+ offer id stays on the class (multiple ops + WS notifications merge
207
+ into it). Methods use the `submit_*` prefix to avoid slot-name
208
+ collisions (`submit_create` / `submit_accept` / `submit_decline` /
209
+ `submit_retract`); the fetch slot is named `list_history` so the
210
+ derived view stays natural as `history`. `$derived.by` views:
211
+ `incoming` (recipient-side pending, soonest-expiry first),
212
+ `outgoing` (grantor-side pending, newest-created first), `history`
213
+ (all known, newest-created first). Reducer `apply_notification`
214
+ handles the six role-grant-offer notification methods;
215
+ `role_grant_revoke` is deliberately ignored here (auth/role_grants
216
+ concern). `reset()` clears every slot + the Map.
200
217
 
201
218
  ## State primitives
202
219
 
203
- - `loadable.svelte.ts` — `Loadable<TError = string>` base class.
204
- `loading`, `error`, `error_data` (raw caught value for programmatic
205
- inspection). Protected `run(fn, map_error?)` wraps async operations
206
- with loading + error handling; subclasses add `$state` fields and
207
- call `run`. `reset()` clears state; subclasses override to clear
208
- domain data.
220
+ - `async_slot.svelte.ts` — `AsyncSlot<T = void, E = string>`. Composable
221
+ reactive container for one async operation. Surface: explicit
222
+ four-value `status` (`'initial' | 'pending' | 'success' | 'failure'`),
223
+ derived `initial` / `loading` / `succeeded` / `failed`, supersession
224
+ via internal `AbortController` (a second `run()` aborts the first
225
+ and silently drops its commit), `AbortSignal` threaded to the
226
+ callback + external-signal hookup via `RunOptions`, per-slot
227
+ `map_error` set once in the constructor, opt-in
228
+ `preserve_error_on_retry`, public `run()` / `abort()` / `set()` /
229
+ `reset()`. Slots are HELD by state classes via composition (one per
230
+ distinct async op), not subclassed. Payload typically lives on the
231
+ state class as `$state.raw` fields; `slot.data` is reserved for
232
+ cases where the slot owns the result.
233
+ - `keyed_async_slot.svelte.ts` — `KeyedAsyncSlot<K, T = void, E = string>`.
234
+ Keyed sibling of `AsyncSlot` — lazily creates a child slot per key
235
+ in a `SvelteMap`, propagating `map_error` / `preserve_error_on_retry`
236
+ to each child. Replaces the `AsyncSlot` + `SvelteSet<id>` pair: each
237
+ key has its own `AbortController`, so a `run(b, ...)` does NOT abort
238
+ an in-flight `run(a, ...)`, and `error(key)` surfaces per-row.
239
+ Reactive sugar: `loading(key)`, `error(key)`, `failed(key)`,
240
+ `succeeded(key)`, `has(key)`, `size`, plus `get(key)` for full slot
241
+ access. Resolved entries persist (no auto-cleanup) so components can
242
+ render per-row error indicators after the run completes; call
243
+ `delete(key)` to dismiss an entry or `reset()` to wipe everything.
244
+ `abort(key)` / `abort_all()` cancel without removing entries.
245
+ `entries()` / `keys()` / `values()` iterate for cross-key views.
209
246
  - `auth_state.svelte.ts` — `AuthState`, `auth_state_context`.
210
247
  Fields: `verifying`, `verified`, `verify_error`, `account`, `actor`
211
248
  (the caller's own `ActorSummaryJson` — surfaced directly so consumers
@@ -214,11 +251,14 @@ destructive actions.
214
251
  `needs_bootstrap`. Methods: `check_session()`
215
252
  (GET `/api/account/status`), `login`, `bootstrap`, `signup`,
216
253
  `logout`. Handles 401/403/409/429 translations inline.
217
- - `table_state.svelte.ts` — `TableState` extends `Loadable`.
218
- Paginated DB browser state: `table_name`, `columns`, `rows`,
219
- `total`, `offset`, `limit` (capped by `TABLE_LIMIT_MAX = 1000`),
220
- `primary_key`. Derived `showing_start`/`showing_end`/`has_prev`/
221
- `has_next`. Methods: `fetch`, `go_prev`/`go_next`, `delete_row`.
254
+ - `table_state.svelte.ts` — `TableState`. Paginated DB browser state.
255
+ Holds one `AsyncSlot` (`list`) + payload fields (`table_name`,
256
+ `columns`, `rows`, `total`, `offset`, `limit` capped by
257
+ `TABLE_LIMIT_MAX = 1000`, `primary_key`). Derived
258
+ `showing_start`/`showing_end`/`has_prev`/`has_next`. Methods:
259
+ `fetch`, `go_prev`/`go_next`, `delete_row`. `delete_row` uses
260
+ plain try/catch + scalar `deleting` / `delete_error` fields (no
261
+ slot — error must survive past `list.run()` retries).
222
262
  - `form_state.svelte.ts` — `FormState`. Enter-advance between
223
263
  focusable elements via `keydown`; per-field `touched` set via
224
264
  delegated `focusout`; form-level `attempted` set on submit attempt.
@@ -231,47 +271,61 @@ destructive actions.
231
271
 
232
272
  ## Per-domain state modules
233
273
 
234
- - `account_sessions_state.svelte.ts` `AccountSessionsState` extends
235
- `Loadable` + `account_sessions_rpc_context` + narrow
236
- `AccountSessionsRpc` (`list`, `revoke`, `revoke_all`). Wraps the
237
- `account_session_list` / `account_session_revoke` /
238
- `account_session_revoke_all` RPC actions. Derived `active_count`.
239
- - `audit_log_state.svelte.ts` — `AuditLogState` extends `Loadable`
240
- - `audit_log_rpc_context` + narrow `AuditLogRpc` (`list` +
241
- `role_grant_history`). Fields: `events`, `role_grant_history_events`,
242
- `connected`. Internal `#last_seq` for SSE gap fill on reconnect.
243
- Methods: `fetch(options?)` (RPC), `fetch_role_grant_history`,
244
- `subscribe()` (opens `EventSource` at `#stream_url`, default
245
- `/api/admin/audit/stream`; prepends new events; refills gap
246
- via `since_seq`), `disconnect()`. SSE stays on `EventSource`
247
- streaming is not an RPC concern.
248
- - `admin_accounts_state.svelte.ts` `AdminAccountsState` extends
249
- `Loadable` + `admin_accounts_rpc_context` + narrow
250
- `AdminAccountsRpc` (six methods: `list_accounts`, `create_role_grant`,
274
+ All state classes hold per-op `AsyncSlot`s for the fetch + singular
275
+ write verbs, and `KeyedAsyncSlot`s for per-row write verbs (the
276
+ `SvelteSet<id>` pattern is retired per-row tracking lives on the
277
+ keyed slot's `loading(key)` / `error(key)` accessors). Method names use
278
+ the `submit_*` prefix where the verb collides with a slot name.
279
+
280
+ - `account_sessions_state.svelte.ts` `AccountSessionsState` +
281
+ `account_sessions_rpc_context` + narrow `AccountSessionsRpc`
282
+ (`list`, `revoke`, `revoke_all`). Slots: `list` (AsyncSlot),
283
+ `revoke` (`KeyedAsyncSlot<string, void>` keyed by `session_id` for
284
+ per-row independence), `revoke_all` (AsyncSlot). Methods: `fetch`,
285
+ `submit_revoke(id)`, `submit_revoke_all`. Derived `active_count`.
286
+ - `audit_log_state.svelte.ts` `AuditLogState` +
287
+ `audit_log_rpc_context` + narrow `AuditLogRpc` (`list` +
288
+ `role_grant_history`). Slots: `list`, `role_grant_history`. Fields:
289
+ `events`, `role_grant_history_events`, `connected`. Internal
290
+ `#last_seq` for SSE gap fill on reconnect. Methods:
291
+ `fetch(options?)` (RPC), `fetch_role_grant_history`, `subscribe()`
292
+ (opens `EventSource` at `#stream_url`, default
293
+ `/api/admin/audit/stream`; prepends new events to `events`; refills
294
+ gap via `since_seq`), `disconnect()`. SSE stays on `EventSource` —
295
+ streaming is not an RPC concern.
296
+ - `admin_accounts_state.svelte.ts` — `AdminAccountsState` +
297
+ `admin_accounts_rpc_context` + narrow `AdminAccountsRpc` (seven
298
+ methods: `list_accounts`, `list_sessions`, `create_role_grant`,
251
299
  `revoke_role_grant`, `retract_offer`, `session_revoke_all`,
252
- `token_revoke_all` — the last two are also reused by
253
- `AdminSessionsState`). `SvelteSet`s for in-flight tracking:
254
- `granting_keys` (`${account_id}:${role}` for the account-grain
255
- default; `${account_id}:${role}:${to_actor_id}` when `create_role_grant`
256
- is called with an actor-targeted offer), `revoking_ids` (role_grant id),
257
- `retracting_ids` (offer id). `revoke_role_grant` keys on `actor_id`
258
- (role_grants are actor-scoped matches `row.actor.id` straight from the
259
- listing) with optional `reason`.
260
- - `admin_invites_state.svelte.ts` `AdminInvitesState` extends
261
- `Loadable` + `admin_invites_rpc_context` + narrow
262
- `AdminInvitesRpc` (`list`, `create`, `delete`). Fields:
263
- `invites`, `creating`, `deleting_ids`; derived `invite_count`,
264
- `unclaimed_count`.
265
- - `admin_sessions_state.svelte.ts` `AdminSessionsState` extends
266
- `Loadable`. **Reuses** `admin_accounts_rpc_context` /
267
- `AdminAccountsRpc` for the listing (`list_sessions` wraps
268
- `admin_session_list`) and the two revoke-all mutations. `SvelteSet`s:
269
- `revoking_account_ids`, `revoking_token_account_ids`. `has_rpc`
270
- gates the listing + both revoke controls.
271
- - `app_settings_state.svelte.ts` `AppSettingsState` extends
272
- `Loadable` + `app_settings_rpc_context` + narrow `AppSettingsRpc`
273
- (`get`, `update`). Fields: `settings`, `updating`. Single mutation
274
- `update_open_signup(boolean)`.
300
+ `token_revoke_all` — the last three are also reused by
301
+ `AdminSessionsState`). Slots: `list` (AsyncSlot), `grant`
302
+ (`KeyedAsyncSlot<string, RoleGrantOfferJson>` — slot owns the
303
+ created offer; key composed by exported
304
+ `grant_key(account_id, role, to_actor_id?)`, 2-segment for
305
+ account-grain, 3-segment when actor-targeted), `revoke`
306
+ (`KeyedAsyncSlot<Uuid, void>` keyed by `role_grant_id`), `retract`
307
+ (`KeyedAsyncSlot<Uuid, void>` keyed by `offer_id`). `submit_revoke`
308
+ takes `actor_id` as the first arg (role_grants are actor-scoped —
309
+ matches `row.actor.id` straight from the listing) with optional
310
+ `reason`.
311
+ - `admin_invites_state.svelte.ts` `AdminInvitesState` +
312
+ `admin_invites_rpc_context` + narrow `AdminInvitesRpc` (`list`,
313
+ `create`, `delete`). Slots: `list`, `create` (both AsyncSlot),
314
+ `remove` (`KeyedAsyncSlot<Uuid, void>` keyed by `invite_id`).
315
+ Field: `invites`; derived `invite_count`, `unclaimed_count`.
316
+ Methods: `fetch`, `submit_create`, `submit_delete`. (Slot `remove`
317
+ instead of `delete` to avoid keyword shadowing.)
318
+ - `admin_sessions_state.svelte.ts` `AdminSessionsState`. **Reuses**
319
+ `admin_accounts_rpc_context` / `AdminAccountsRpc` for the listing
320
+ (`list_sessions` wraps `admin_session_list`) and the two revoke-all
321
+ mutations. Slots: `list` (AsyncSlot), `revoke_sessions` /
322
+ `revoke_tokens` (`KeyedAsyncSlot<Uuid, void>` keyed by
323
+ `account_id`). `has_rpc` gates the listing + both revoke controls.
324
+ Methods: `fetch`, `submit_revoke_sessions`, `submit_revoke_tokens`.
325
+ - `app_settings_state.svelte.ts` — `AppSettingsState` +
326
+ `app_settings_rpc_context` + narrow `AppSettingsRpc` (`get`,
327
+ `update`). Slots: `list`, `update`. Field: `settings`. Single
328
+ mutation `update_open_signup(boolean)`.
275
329
  - `admin_rpc_adapters.ts` (plain `.ts`, no reactive state) — bundled
276
330
  wiring for the four admin RPC contexts. `create_admin_rpc_adapters(api)`
277
331
  takes the typed throwing Proxy from `create_frontend_rpc_client` (or
@@ -6,19 +6,31 @@
6
6
  * On confirm, calls `onconfirm` and hides the popover (controlled
7
7
  * by `hide_on_confirm`). Defaults to `position="left"`.
8
8
  *
9
- * Snippets (`children`, `popover_content`, `popover_button_content`)
10
- * receive both the `Popover` instance and a `confirm` callback.
9
+ * Trigger content: pass `label` for a simple string, or a `children`
10
+ * snippet for custom content (the two are mutually exclusive DEV
11
+ * errors when both are set). `pending: boolean` overlays a spinner
12
+ * and disables the trigger, mirroring `PendingButton` semantics so
13
+ * the label stays put while an async operation runs.
11
14
  *
12
15
  * @example
13
16
  * ```svelte
14
17
  * <ConfirmButton
15
18
  * onconfirm={() => delete_item(item.id)}
16
19
  * title="delete item"
17
- * disabled={deleting}
20
+ * label="delete"
21
+ * pending={state.remove.loading(item.id)}
22
+ * />
23
+ * ```
24
+ *
25
+ * @example
26
+ * ```svelte
27
+ * <!-- custom trigger content via the children snippet -->
28
+ * <ConfirmButton
29
+ * onconfirm={() => grant(item.id, role)}
30
+ * title="offer {role}"
31
+ * pending={state.grant.loading(key)}
18
32
  * >
19
- * {#snippet children(_popover, _confirm)}
20
- * {deleting ? 'deleting…' : 'delete'}
21
- * {/snippet}
33
+ * {#snippet children(_popover, _confirm)}+ {role}{/snippet}
22
34
  * </ConfirmButton>
23
35
  * ```
24
36
  *
@@ -34,10 +46,12 @@
34
46
  * @module
35
47
  */
36
48
 
49
+ import {DEV} from 'esm-env';
37
50
  import type {SvelteHTMLElements} from 'svelte/elements';
38
51
  import type {ComponentProps, Snippet} from 'svelte';
39
52
  import type {OmitStrict} from '@fuzdev/fuz_util/types.js';
40
53
  import Glyph from '@fuzdev/fuz_ui/Glyph.svelte';
54
+ import PendingAnimation from '@fuzdev/fuz_ui/PendingAnimation.svelte';
41
55
 
42
56
  import PopoverButton from './PopoverButton.svelte';
43
57
  import type {Popover} from './popover.svelte.js';
@@ -53,6 +67,9 @@
53
67
  popover_button_content,
54
68
  button,
55
69
  children,
70
+ label,
71
+ pending = false,
72
+ disabled: disabled_prop,
56
73
  ...rest
57
74
  }: OmitStrict<ComponentProps<typeof PopoverButton>, 'popover_content' | 'children'> &
58
75
  OmitStrict<SvelteHTMLElements['button'], 'children'> & {
@@ -65,21 +82,34 @@
65
82
  popover_button_content?: Snippet<[popover: Popover, confirm: () => void]> | undefined;
66
83
  /** Unlike on `PopoverButton` this has a `confirm` arg */
67
84
  children?: Snippet<[popover: Popover, confirm: () => void]> | undefined;
85
+ /** Simple string content for the trigger. Mutually exclusive with `children`. */
86
+ label?: string | undefined;
87
+ /**
88
+ * When `true`, the trigger is disabled and a spinner overlays the
89
+ * content (mirrors `PendingButton`). The label / children stay
90
+ * rendered underneath so the button keeps its size.
91
+ */
92
+ pending?: boolean | undefined;
68
93
  } = $props();
69
94
 
70
95
  // TODO @many type union instead of this pattern?
71
- $effect(() => {
72
- if (popover_content_prop && popover_button_attrs) {
73
- console.error(
74
- 'ConfirmButton has both popover_content and popover_attrs defined - popover_content takes precedence',
75
- );
76
- }
77
- if (popover_content_prop && popover_button_content) {
78
- console.error(
79
- 'ConfirmButton has both popover_content and popover_button_content defined - popover_content takes precedence',
80
- );
81
- }
82
- });
96
+ if (DEV) {
97
+ $effect(() => {
98
+ if (popover_content_prop && popover_button_attrs) {
99
+ console.error(
100
+ 'ConfirmButton has both popover_content and popover_button_attrs defined - popover_content takes precedence',
101
+ );
102
+ }
103
+ if (popover_content_prop && popover_button_content) {
104
+ console.error(
105
+ 'ConfirmButton has both popover_content and popover_button_content defined - popover_content takes precedence',
106
+ );
107
+ }
108
+ if (label !== undefined && children) {
109
+ console.error('ConfirmButton has both label and children defined - pick one');
110
+ }
111
+ });
112
+ }
83
113
 
84
114
  const confirm = (popover: Popover): void => {
85
115
  if (hide_on_confirm) popover.hide();
@@ -92,6 +122,7 @@
92
122
  {position}
93
123
  {button}
94
124
  {...rest as any}
125
+ disabled={disabled_prop ?? pending}
95
126
  children={button ? undefined : children_default}
96
127
  >
97
128
  {#snippet popover_content(popover)}
@@ -103,7 +134,7 @@
103
134
  class="color_c bg_100"
104
135
  class:icon_button={!popover_button_content}
105
136
  onclick={() => confirm(popover)}
106
- title="confirm {rest.title || ''}"
137
+ title={rest.title ? `confirm ${rest.title}` : 'confirm'}
107
138
  {...popover_button_attrs}
108
139
  >
109
140
  {#if popover_button_content}
@@ -117,9 +148,36 @@
117
148
  </PopoverButton>
118
149
 
119
150
  {#snippet children_default(popover: Popover)}
120
- {#if children}
121
- {@render children(popover, () => confirm(popover))}
122
- {:else}
123
- <Glyph glyph={GLYPH_REMOVE} />
124
- {/if}
151
+ <span class="trigger" class:pending>
152
+ <span class="content">
153
+ {#if children}
154
+ {@render children(popover, () => confirm(popover))}
155
+ {:else if label !== undefined}
156
+ {label}
157
+ {:else}
158
+ <Glyph glyph={GLYPH_REMOVE} />
159
+ {/if}
160
+ </span>
161
+ {#if pending}
162
+ <span class="animation">
163
+ <PendingAnimation inline />
164
+ </span>
165
+ {/if}
166
+ </span>
125
167
  {/snippet}
168
+
169
+ <style>
170
+ .trigger {
171
+ position: relative;
172
+ }
173
+ .pending .content {
174
+ visibility: hidden;
175
+ }
176
+ .animation {
177
+ position: absolute;
178
+ inset: 0;
179
+ display: flex;
180
+ justify-content: center;
181
+ align-items: center;
182
+ }
183
+ </style>
@@ -1,37 +1,3 @@
1
- /**
2
- * Confirmation popover wrapping `PopoverButton`.
3
- *
4
- * Clicking the trigger opens a popover with a confirm button.
5
- * On confirm, calls `onconfirm` and hides the popover (controlled
6
- * by `hide_on_confirm`). Defaults to `position="left"`.
7
- *
8
- * Snippets (`children`, `popover_content`, `popover_button_content`)
9
- * receive both the `Popover` instance and a `confirm` callback.
10
- *
11
- * @example
12
- * ```svelte
13
- * <ConfirmButton
14
- * onconfirm={() => delete_item(item.id)}
15
- * title="delete item"
16
- * disabled={deleting}
17
- * >
18
- * {#snippet children(_popover, _confirm)}
19
- * {deleting ? 'deleting…' : 'delete'}
20
- * {/snippet}
21
- * </ConfirmButton>
22
- * ```
23
- *
24
- * @example
25
- * ```svelte
26
- * <!-- custom confirm button content -->
27
- * <ConfirmButton onconfirm={handle_revoke} class="icon_button plain" title="revoke">
28
- * revoke
29
- * {#snippet popover_button_content()}revoke{/snippet}
30
- * </ConfirmButton>
31
- * ```
32
- *
33
- * @module
34
- */
35
1
  import type { SvelteHTMLElements } from 'svelte/elements';
36
2
  import type { ComponentProps, Snippet } from 'svelte';
37
3
  import type { OmitStrict } from '@fuzdev/fuz_util/types.js';
@@ -47,6 +13,14 @@ type $$ComponentProps = OmitStrict<ComponentProps<typeof PopoverButton>, 'popove
47
13
  popover_button_content?: Snippet<[popover: Popover, confirm: () => void]> | undefined;
48
14
  /** Unlike on `PopoverButton` this has a `confirm` arg */
49
15
  children?: Snippet<[popover: Popover, confirm: () => void]> | undefined;
16
+ /** Simple string content for the trigger. Mutually exclusive with `children`. */
17
+ label?: string | undefined;
18
+ /**
19
+ * When `true`, the trigger is disabled and a spinner overlays the
20
+ * content (mirrors `PendingButton`). The label / children stay
21
+ * rendered underneath so the button keeps its size.
22
+ */
23
+ pending?: boolean | undefined;
50
24
  };
51
25
  declare const ConfirmButton: import("svelte").Component<$$ComponentProps, {}, "">;
52
26
  type ConfirmButton = ReturnType<typeof ConfirmButton>;
@@ -1 +1 @@
1
- {"version":3,"file":"ConfirmButton.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/ui/ConfirmButton.svelte"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAiCI;AACJ,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,iBAAiB,CAAC;AACxD,OAAO,KAAK,EAAC,cAAc,EAAE,OAAO,EAAC,MAAM,QAAQ,CAAC;AACpD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,2BAA2B,CAAC;AAG1D,OAAO,aAAa,MAAM,wBAAwB,CAAC;AACnD,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,qBAAqB,CAAC;AAEhD,KAAK,gBAAgB,GAAI,UAAU,CAAC,cAAc,CAAC,OAAO,aAAa,CAAC,EAAE,iBAAiB,GAAG,UAAU,CAAC,GACxG,UAAU,CAAC,kBAAkB,CAAC,QAAQ,CAAC,EAAE,UAAU,CAAC,GAAG;IACtD,SAAS,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,oBAAoB,CAAC,EAAE,kBAAkB,CAAC,QAAQ,CAAC,GAAG,SAAS,CAAC;IAChE,eAAe,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACtC,yEAAyE;IACzE,eAAe,CAAC,EAAE,OAAO,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC,CAAC,GAAG,SAAS,CAAC;IAC/E,qCAAqC;IACrC,sBAAsB,CAAC,EAAE,OAAO,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC,CAAC,GAAG,SAAS,CAAC;IACtF,yDAAyD;IACzD,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC,CAAC,GAAG,SAAS,CAAC;CACxE,CAAC;AAyEJ,QAAA,MAAM,aAAa,sDAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"ConfirmButton.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/ui/ConfirmButton.svelte"],"names":[],"mappings":"AAkDA,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,iBAAiB,CAAC;AACxD,OAAO,KAAK,EAAC,cAAc,EAAE,OAAO,EAAC,MAAM,QAAQ,CAAC;AACpD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,2BAA2B,CAAC;AAI1D,OAAO,aAAa,MAAM,wBAAwB,CAAC;AACnD,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,qBAAqB,CAAC;AAEhD,KAAK,gBAAgB,GAAI,UAAU,CAAC,cAAc,CAAC,OAAO,aAAa,CAAC,EAAE,iBAAiB,GAAG,UAAU,CAAC,GACxG,UAAU,CAAC,kBAAkB,CAAC,QAAQ,CAAC,EAAE,UAAU,CAAC,GAAG;IACtD,SAAS,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,oBAAoB,CAAC,EAAE,kBAAkB,CAAC,QAAQ,CAAC,GAAG,SAAS,CAAC;IAChE,eAAe,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACtC,yEAAyE;IACzE,eAAe,CAAC,EAAE,OAAO,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC,CAAC,GAAG,SAAS,CAAC;IAC/E,qCAAqC;IACrC,sBAAsB,CAAC,EAAE,OAAO,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC,CAAC,GAAG,SAAS,CAAC;IACtF,yDAAyD;IACzD,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC,CAAC,GAAG,SAAS,CAAC;IACxE,iFAAiF;IACjF,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC9B,CAAC;AAgGJ,QAAA,MAAM,aAAa,sDAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
@@ -19,7 +19,7 @@
19
19
  <div class="open-signup-toggle">
20
20
  {#if !app_settings.has_rpc}
21
21
  <p class="text_50">rpc adapter not wired</p>
22
- {:else if app_settings.loading}
22
+ {:else if app_settings.list.loading}
23
23
  <p class="text_50">loading settings...</p>
24
24
  {:else if app_settings.settings}
25
25
  <label class="row">
@@ -27,7 +27,7 @@
27
27
  type="checkbox"
28
28
  class="mr_lg"
29
29
  checked={app_settings.settings.open_signup}
30
- disabled={app_settings.updating}
30
+ disabled={app_settings.update.loading}
31
31
  onchange={() => app_settings.update_open_signup(!app_settings.settings!.open_signup)}
32
32
  />
33
33
  <div>
@@ -42,7 +42,9 @@
42
42
  </div>
43
43
  </label>
44
44
  {/if}
45
- {#if app_settings.error}
46
- <p class="color_c_50">{app_settings.error}</p>
45
+ {#if app_settings.list.error}
46
+ <p class="color_c_50">{app_settings.list.error}</p>
47
+ {:else if app_settings.update.error}
48
+ <p class="color_c_50">{app_settings.update.error}</p>
47
49
  {/if}
48
50
  </div>
@@ -1 +1 @@
1
- {"version":3,"file":"OpenSignupToggle.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/ui/OpenSignupToggle.svelte"],"names":[],"mappings":"AA+CA,UAAU,kCAAkC,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,OAAO,GAAG,EAAE,EAAE,QAAQ,GAAG,MAAM;IACpM,KAAK,OAAO,EAAE,OAAO,QAAQ,EAAE,2BAA2B,CAAC,KAAK,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,QAAQ,CAAA;KAAE,GAAG,OAAO,CAAC;IACjK,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,KAAK,CAAA;KAAC,GAAG,OAAO,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,GAAG,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC;IACtG,YAAY,CAAC,EAAE,QAAQ,CAAC;CAC3B;AAKD,QAAA,MAAM,gBAAgB;;kBAA+E,CAAC;AACpF,KAAK,gBAAgB,GAAG,YAAY,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAChE,eAAe,gBAAgB,CAAC"}
1
+ {"version":3,"file":"OpenSignupToggle.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/ui/OpenSignupToggle.svelte"],"names":[],"mappings":"AAiDA,UAAU,kCAAkC,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,OAAO,GAAG,EAAE,EAAE,QAAQ,GAAG,MAAM;IACpM,KAAK,OAAO,EAAE,OAAO,QAAQ,EAAE,2BAA2B,CAAC,KAAK,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,QAAQ,CAAA;KAAE,GAAG,OAAO,CAAC;IACjK,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,KAAK,CAAA;KAAC,GAAG,OAAO,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,GAAG,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC;IACtG,YAAY,CAAC,EAAE,QAAQ,CAAC;CAC3B;AAKD,QAAA,MAAM,gBAAgB;;kBAA+E,CAAC;AACpF,KAAK,gBAAgB,GAAG,YAAY,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAChE,eAAe,gBAAgB,CAAC"}
@@ -58,7 +58,7 @@
58
58
  let message = $state.raw('');
59
59
  let local_error: string | null = $state.raw(null);
60
60
 
61
- const submitting = $derived(role_grant_offers.loading);
61
+ const submitting = $derived(role_grant_offers.create.loading);
62
62
 
63
63
  const surface_error = (reason: string | null): string | null => {
64
64
  switch (reason) {
@@ -84,7 +84,7 @@
84
84
  form_state.focus('role');
85
85
  return;
86
86
  }
87
- const offer = await role_grant_offers.create({
87
+ const offer = await role_grant_offers.submit_create({
88
88
  to_account_id,
89
89
  to_actor_id,
90
90
  role: selected_role,
@@ -98,12 +98,12 @@
98
98
  return;
99
99
  }
100
100
  // Structured error data carries the reason; fall back to raw error string.
101
- const data = role_grant_offers.error_data as
101
+ const data = role_grant_offers.create.error_data as
102
102
  | {data?: {reason?: string}; reason?: string}
103
103
  | null
104
104
  | undefined;
105
105
  const reason = data?.data?.reason ?? data?.reason ?? null;
106
- local_error = surface_error(reason) ?? role_grant_offers.error;
106
+ local_error = surface_error(reason) ?? role_grant_offers.create.error;
107
107
  };
108
108
  </script>
109
109
 
@@ -82,10 +82,10 @@
82
82
  <section>
83
83
  <h2>offer history</h2>
84
84
 
85
- {#if role_grant_offers.loading}
85
+ {#if role_grant_offers.list_history.loading}
86
86
  <p class="text_50">loading history...</p>
87
- {:else if role_grant_offers.error}
88
- <p class="color_c_50">{role_grant_offers.error}</p>
87
+ {:else if role_grant_offers.list_history.error}
88
+ <p class="color_c_50">{role_grant_offers.list_history.error}</p>
89
89
  {:else}
90
90
  <Datatable {columns} rows={role_grant_offers.history} height="400px" row_key="id">
91
91
  {#snippet cell(column, row)}
@@ -48,8 +48,12 @@
48
48
  <section class="role-grant-offer-inbox">
49
49
  <h2>pending offers</h2>
50
50
 
51
- {#if role_grant_offers.error}
52
- <p class="color_c_50">{role_grant_offers.error}</p>
51
+ {#if role_grant_offers.list.error || role_grant_offers.accept.error || role_grant_offers.decline.error}
52
+ <p class="color_c_50">
53
+ {role_grant_offers.list.error ??
54
+ role_grant_offers.accept.error ??
55
+ role_grant_offers.decline.error}
56
+ </p>
53
57
  {/if}
54
58
 
55
59
  {#if role_grant_offers.incoming.length === 0}
@@ -76,9 +80,9 @@
76
80
 
77
81
  <div class="row gap_sm">
78
82
  <PendingButton
79
- pending={role_grant_offers.loading}
80
- disabled={role_grant_offers.loading}
81
- onclick={() => role_grant_offers.accept(offer.id)}
83
+ pending={role_grant_offers.accept.loading}
84
+ disabled={role_grant_offers.accept.loading}
85
+ onclick={() => role_grant_offers.submit_accept(offer.id)}
82
86
  class="color_b"
83
87
  >
84
88
  accept
@@ -89,7 +93,7 @@
89
93
  position="bottom"
90
94
  onconfirm={() => {
91
95
  const reason = decline_reasons.get(offer.id) ?? '';
92
- void role_grant_offers.decline(offer.id, reason || null);
96
+ void role_grant_offers.submit_decline(offer.id, reason || null);
93
97
  decline_reasons.delete(offer.id);
94
98
  }}
95
99
  >
@@ -1 +1 @@
1
- {"version":3,"file":"RoleGrantOfferInbox.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/ui/RoleGrantOfferInbox.svelte"],"names":[],"mappings":"AAmBA,OAAO,EAA4C,KAAK,WAAW,EAAC,MAAM,mBAAmB,CAAC;AAE7F,KAAK,gBAAgB,GAAI;IACxB,uEAAuE;IACvE,YAAY,CAAC,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,MAAM,CAAC;IACjD;;;;OAIG;IACH,YAAY,CAAC,EAAE,WAAW,CAAC;IAC3B,+DAA+D;IAC/D,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CACvC,CAAC;AA2FH,QAAA,MAAM,mBAAmB,sDAAwC,CAAC;AAClE,KAAK,mBAAmB,GAAG,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAClE,eAAe,mBAAmB,CAAC"}
1
+ {"version":3,"file":"RoleGrantOfferInbox.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/ui/RoleGrantOfferInbox.svelte"],"names":[],"mappings":"AAmBA,OAAO,EAA4C,KAAK,WAAW,EAAC,MAAM,mBAAmB,CAAC;AAE7F,KAAK,gBAAgB,GAAI;IACxB,uEAAuE;IACvE,YAAY,CAAC,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,MAAM,CAAC;IACjD;;;;OAIG;IACH,YAAY,CAAC,EAAE,WAAW,CAAC;IAC3B,+DAA+D;IAC/D,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CACvC,CAAC;AA+FH,QAAA,MAAM,mBAAmB,sDAAwC,CAAC;AAClE,KAAK,mBAAmB,GAAG,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAClE,eAAe,mBAAmB,CAAC"}
@@ -1,11 +1,18 @@
1
1
  /**
2
2
  * Reactive state for managing the authenticated account's auth sessions on a
3
- * settings page. Reads and mutations flow through a narrow RPC adapter
4
- * backed by `auth/account_actions.ts`.
3
+ * settings page. Reads and mutations flow through a narrow RPC adapter backed
4
+ * by `auth/account_actions.ts`.
5
+ *
6
+ * Holds two `AsyncSlot`s — `list` for the fetch, `revoke_all` for the bulk
7
+ * revoke — plus one `KeyedAsyncSlot<string, void>` (`revoke`) keyed by
8
+ * `session_id` for per-row revoke (independent supersession across
9
+ * concurrent rows; per-row error surfacing). Method names use the
10
+ * `submit_*` prefix to avoid slot-name collisions.
5
11
  *
6
12
  * @module
7
13
  */
8
- import { Loadable } from './loadable.svelte.js';
14
+ import { AsyncSlot } from './async_slot.svelte.js';
15
+ import { KeyedAsyncSlot } from './keyed_async_slot.svelte.js';
9
16
  import type { AuthSessionJson } from '../auth/account_schema.js';
10
17
  /**
11
18
  * Narrow RPC surface consumed by `AccountSessionsState`. Consumers adapt their
@@ -50,15 +57,18 @@ export interface AccountSessionsStateOptions {
50
57
  */
51
58
  get_rpc?: () => AccountSessionsRpc | null;
52
59
  }
53
- export declare class AccountSessionsState extends Loadable {
60
+ export declare class AccountSessionsState {
54
61
  #private;
62
+ readonly list: AsyncSlot<void, string>;
63
+ readonly revoke: KeyedAsyncSlot<string, void, string>;
64
+ readonly revoke_all: AsyncSlot<void, string>;
55
65
  sessions: Array<AuthSessionJson>;
56
66
  readonly active_count: number;
57
67
  constructor(options?: AccountSessionsStateOptions);
58
- /** True when an RPC adapter is wired. `fetch` / `revoke` / `revoke_all` no-op without it. */
68
+ /** True when an RPC adapter is wired. `fetch` / `submit_revoke` / `submit_revoke_all` no-op without it. */
59
69
  get has_rpc(): boolean;
60
70
  fetch(): Promise<void>;
61
- revoke(id: string): Promise<void>;
62
- revoke_all(): Promise<void>;
71
+ submit_revoke(id: string): Promise<void>;
72
+ submit_revoke_all(): Promise<void>;
63
73
  }
64
74
  //# sourceMappingURL=account_sessions_state.svelte.d.ts.map