@fuzdev/fuz_app 0.29.0 → 0.31.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 (210) hide show
  1. package/dist/actions/CLAUDE.md +630 -0
  2. package/dist/actions/action_rpc.d.ts +29 -0
  3. package/dist/actions/action_rpc.d.ts.map +1 -1
  4. package/dist/actions/action_rpc.js +42 -6
  5. package/dist/actions/action_types.d.ts +2 -2
  6. package/dist/actions/cancel.d.ts +12 -13
  7. package/dist/actions/cancel.d.ts.map +1 -1
  8. package/dist/actions/cancel.js +10 -13
  9. package/dist/actions/heartbeat.d.ts +8 -13
  10. package/dist/actions/heartbeat.d.ts.map +1 -1
  11. package/dist/actions/heartbeat.js +5 -8
  12. package/dist/actions/register_action_ws.d.ts +3 -3
  13. package/dist/actions/register_action_ws.js +2 -2
  14. package/dist/actions/register_ws_endpoint.d.ts +4 -4
  15. package/dist/actions/register_ws_endpoint.d.ts.map +1 -1
  16. package/dist/actions/register_ws_endpoint.js +3 -3
  17. package/dist/actions/socket.svelte.d.ts +16 -16
  18. package/dist/actions/socket.svelte.d.ts.map +1 -1
  19. package/dist/actions/socket.svelte.js +15 -15
  20. package/dist/actions/transports_ws_auth_guard.d.ts.map +1 -1
  21. package/dist/actions/transports_ws_backend.d.ts +15 -0
  22. package/dist/actions/transports_ws_backend.d.ts.map +1 -1
  23. package/dist/actions/transports_ws_backend.js +17 -0
  24. package/dist/auth/CLAUDE.md +923 -0
  25. package/dist/auth/account_action_specs.d.ts +216 -0
  26. package/dist/auth/account_action_specs.d.ts.map +1 -0
  27. package/dist/auth/account_action_specs.js +159 -0
  28. package/dist/auth/account_actions.d.ts +51 -0
  29. package/dist/auth/account_actions.d.ts.map +1 -0
  30. package/dist/auth/account_actions.js +119 -0
  31. package/dist/auth/account_queries.d.ts +6 -2
  32. package/dist/auth/account_queries.d.ts.map +1 -1
  33. package/dist/auth/account_queries.js +40 -4
  34. package/dist/auth/account_routes.d.ts +94 -16
  35. package/dist/auth/account_routes.d.ts.map +1 -1
  36. package/dist/auth/account_routes.js +108 -180
  37. package/dist/auth/account_schema.d.ts +85 -30
  38. package/dist/auth/account_schema.d.ts.map +1 -1
  39. package/dist/auth/account_schema.js +40 -8
  40. package/dist/auth/admin_action_specs.d.ts +674 -0
  41. package/dist/auth/admin_action_specs.d.ts.map +1 -0
  42. package/dist/auth/admin_action_specs.js +287 -0
  43. package/dist/auth/admin_actions.d.ts +69 -0
  44. package/dist/auth/admin_actions.d.ts.map +1 -0
  45. package/dist/auth/admin_actions.js +256 -0
  46. package/dist/auth/api_token.d.ts +10 -0
  47. package/dist/auth/api_token.d.ts.map +1 -1
  48. package/dist/auth/api_token.js +9 -0
  49. package/dist/auth/api_token_queries.d.ts +3 -3
  50. package/dist/auth/api_token_queries.js +3 -3
  51. package/dist/auth/app_settings_schema.d.ts +4 -3
  52. package/dist/auth/app_settings_schema.d.ts.map +1 -1
  53. package/dist/auth/app_settings_schema.js +2 -1
  54. package/dist/auth/audit_log_routes.d.ts +14 -6
  55. package/dist/auth/audit_log_routes.d.ts.map +1 -1
  56. package/dist/auth/audit_log_routes.js +22 -79
  57. package/dist/auth/audit_log_schema.d.ts +100 -29
  58. package/dist/auth/audit_log_schema.d.ts.map +1 -1
  59. package/dist/auth/audit_log_schema.js +83 -11
  60. package/dist/auth/bootstrap_routes.d.ts +14 -0
  61. package/dist/auth/bootstrap_routes.d.ts.map +1 -1
  62. package/dist/auth/bootstrap_routes.js +10 -3
  63. package/dist/auth/cleanup.d.ts +63 -0
  64. package/dist/auth/cleanup.d.ts.map +1 -0
  65. package/dist/auth/cleanup.js +80 -0
  66. package/dist/auth/invite_schema.d.ts +11 -10
  67. package/dist/auth/invite_schema.d.ts.map +1 -1
  68. package/dist/auth/invite_schema.js +4 -3
  69. package/dist/auth/migrations.d.ts +6 -0
  70. package/dist/auth/migrations.d.ts.map +1 -1
  71. package/dist/auth/migrations.js +28 -0
  72. package/dist/auth/permit_offer_action_specs.d.ts +364 -0
  73. package/dist/auth/permit_offer_action_specs.d.ts.map +1 -0
  74. package/dist/auth/permit_offer_action_specs.js +216 -0
  75. package/dist/auth/permit_offer_actions.d.ts +96 -0
  76. package/dist/auth/permit_offer_actions.d.ts.map +1 -0
  77. package/dist/auth/permit_offer_actions.js +428 -0
  78. package/dist/auth/permit_offer_notifications.d.ts +361 -0
  79. package/dist/auth/permit_offer_notifications.d.ts.map +1 -0
  80. package/dist/auth/permit_offer_notifications.js +179 -0
  81. package/dist/auth/permit_offer_queries.d.ts +165 -0
  82. package/dist/auth/permit_offer_queries.d.ts.map +1 -0
  83. package/dist/auth/permit_offer_queries.js +390 -0
  84. package/dist/auth/permit_offer_schema.d.ts +103 -0
  85. package/dist/auth/permit_offer_schema.d.ts.map +1 -0
  86. package/dist/auth/permit_offer_schema.js +142 -0
  87. package/dist/auth/permit_queries.d.ts +77 -14
  88. package/dist/auth/permit_queries.d.ts.map +1 -1
  89. package/dist/auth/permit_queries.js +119 -24
  90. package/dist/auth/session_queries.d.ts +4 -2
  91. package/dist/auth/session_queries.d.ts.map +1 -1
  92. package/dist/auth/session_queries.js +4 -2
  93. package/dist/auth/signup_routes.d.ts +13 -0
  94. package/dist/auth/signup_routes.d.ts.map +1 -1
  95. package/dist/auth/signup_routes.js +14 -7
  96. package/dist/http/CLAUDE.md +584 -0
  97. package/dist/http/pending_effects.d.ts +29 -0
  98. package/dist/http/pending_effects.d.ts.map +1 -0
  99. package/dist/http/pending_effects.js +31 -0
  100. package/dist/http/route_spec.d.ts.map +1 -1
  101. package/dist/http/route_spec.js +4 -3
  102. package/dist/rate_limiter.d.ts +30 -0
  103. package/dist/rate_limiter.d.ts.map +1 -1
  104. package/dist/rate_limiter.js +25 -2
  105. package/dist/realtime/sse_auth_guard.d.ts +2 -0
  106. package/dist/realtime/sse_auth_guard.d.ts.map +1 -1
  107. package/dist/realtime/sse_auth_guard.js +5 -3
  108. package/dist/testing/CLAUDE.md +668 -1
  109. package/dist/testing/admin_integration.d.ts +10 -7
  110. package/dist/testing/admin_integration.d.ts.map +1 -1
  111. package/dist/testing/admin_integration.js +382 -482
  112. package/dist/testing/app_server.d.ts +7 -6
  113. package/dist/testing/app_server.d.ts.map +1 -1
  114. package/dist/testing/attack_surface.d.ts +9 -3
  115. package/dist/testing/attack_surface.d.ts.map +1 -1
  116. package/dist/testing/attack_surface.js +4 -4
  117. package/dist/testing/audit_completeness.d.ts +6 -0
  118. package/dist/testing/audit_completeness.d.ts.map +1 -1
  119. package/dist/testing/audit_completeness.js +158 -134
  120. package/dist/testing/auth_apps.d.ts.map +1 -1
  121. package/dist/testing/auth_apps.js +4 -33
  122. package/dist/testing/db.d.ts +1 -1
  123. package/dist/testing/db.d.ts.map +1 -1
  124. package/dist/testing/db.js +2 -0
  125. package/dist/testing/entities.d.ts +35 -13
  126. package/dist/testing/entities.d.ts.map +1 -1
  127. package/dist/testing/entities.js +17 -0
  128. package/dist/testing/integration.d.ts +10 -0
  129. package/dist/testing/integration.d.ts.map +1 -1
  130. package/dist/testing/integration.js +352 -340
  131. package/dist/testing/integration_helpers.d.ts +16 -5
  132. package/dist/testing/integration_helpers.d.ts.map +1 -1
  133. package/dist/testing/integration_helpers.js +24 -4
  134. package/dist/testing/rate_limiting.d.ts +7 -0
  135. package/dist/testing/rate_limiting.d.ts.map +1 -1
  136. package/dist/testing/rate_limiting.js +41 -10
  137. package/dist/testing/rpc_helpers.d.ts +153 -1
  138. package/dist/testing/rpc_helpers.d.ts.map +1 -1
  139. package/dist/testing/rpc_helpers.js +184 -8
  140. package/dist/testing/sse_round_trip.d.ts +8 -0
  141. package/dist/testing/sse_round_trip.d.ts.map +1 -1
  142. package/dist/testing/sse_round_trip.js +10 -3
  143. package/dist/testing/standard.d.ts +9 -1
  144. package/dist/testing/standard.d.ts.map +1 -1
  145. package/dist/testing/standard.js +6 -2
  146. package/dist/testing/surface_invariants.d.ts +7 -3
  147. package/dist/testing/surface_invariants.d.ts.map +1 -1
  148. package/dist/testing/surface_invariants.js +5 -4
  149. package/dist/testing/ws_round_trip.d.ts.map +1 -1
  150. package/dist/testing/ws_round_trip.js +9 -38
  151. package/dist/ui/AccountSessions.svelte +8 -4
  152. package/dist/ui/AccountSessions.svelte.d.ts.map +1 -1
  153. package/dist/ui/AdminAccounts.svelte +61 -33
  154. package/dist/ui/AdminAccounts.svelte.d.ts.map +1 -1
  155. package/dist/ui/AdminAuditLog.svelte +3 -2
  156. package/dist/ui/AdminAuditLog.svelte.d.ts.map +1 -1
  157. package/dist/ui/AdminInvites.svelte +3 -2
  158. package/dist/ui/AdminInvites.svelte.d.ts.map +1 -1
  159. package/dist/ui/AdminOverview.svelte +14 -9
  160. package/dist/ui/AdminOverview.svelte.d.ts.map +1 -1
  161. package/dist/ui/AdminPermitHistory.svelte +3 -2
  162. package/dist/ui/AdminPermitHistory.svelte.d.ts.map +1 -1
  163. package/dist/ui/AdminSessions.svelte +29 -25
  164. package/dist/ui/AdminSessions.svelte.d.ts.map +1 -1
  165. package/dist/ui/CLAUDE.md +351 -0
  166. package/dist/ui/OpenSignupToggle.svelte +6 -3
  167. package/dist/ui/OpenSignupToggle.svelte.d.ts.map +1 -1
  168. package/dist/ui/PermitOfferForm.svelte +141 -0
  169. package/dist/ui/PermitOfferForm.svelte.d.ts +14 -0
  170. package/dist/ui/PermitOfferForm.svelte.d.ts.map +1 -0
  171. package/dist/ui/PermitOfferHistory.svelte +109 -0
  172. package/dist/ui/PermitOfferHistory.svelte.d.ts +11 -0
  173. package/dist/ui/PermitOfferHistory.svelte.d.ts.map +1 -0
  174. package/dist/ui/PermitOfferInbox.svelte +121 -0
  175. package/dist/ui/PermitOfferInbox.svelte.d.ts +12 -0
  176. package/dist/ui/PermitOfferInbox.svelte.d.ts.map +1 -0
  177. package/dist/ui/account_sessions_state.svelte.d.ts +53 -3
  178. package/dist/ui/account_sessions_state.svelte.d.ts.map +1 -1
  179. package/dist/ui/account_sessions_state.svelte.js +39 -16
  180. package/dist/ui/admin_accounts_state.svelte.d.ts +118 -2
  181. package/dist/ui/admin_accounts_state.svelte.d.ts.map +1 -1
  182. package/dist/ui/admin_accounts_state.svelte.js +99 -23
  183. package/dist/ui/admin_invites_state.svelte.d.ts +47 -1
  184. package/dist/ui/admin_invites_state.svelte.d.ts.map +1 -1
  185. package/dist/ui/admin_invites_state.svelte.js +38 -26
  186. package/dist/ui/admin_sessions_state.svelte.d.ts +26 -0
  187. package/dist/ui/admin_sessions_state.svelte.d.ts.map +1 -1
  188. package/dist/ui/admin_sessions_state.svelte.js +35 -21
  189. package/dist/ui/app_settings_state.svelte.d.ts +39 -0
  190. package/dist/ui/app_settings_state.svelte.d.ts.map +1 -1
  191. package/dist/ui/app_settings_state.svelte.js +34 -18
  192. package/dist/ui/audit_log_state.svelte.d.ts +40 -3
  193. package/dist/ui/audit_log_state.svelte.d.ts.map +1 -1
  194. package/dist/ui/audit_log_state.svelte.js +36 -42
  195. package/dist/ui/auth_state.svelte.d.ts +4 -3
  196. package/dist/ui/auth_state.svelte.d.ts.map +1 -1
  197. package/dist/ui/auth_state.svelte.js +4 -1
  198. package/dist/ui/permit_offers_state.svelte.d.ts +125 -0
  199. package/dist/ui/permit_offers_state.svelte.d.ts.map +1 -0
  200. package/dist/ui/permit_offers_state.svelte.js +197 -0
  201. package/package.json +3 -3
  202. package/dist/auth/admin_routes.d.ts +0 -29
  203. package/dist/auth/admin_routes.d.ts.map +0 -1
  204. package/dist/auth/admin_routes.js +0 -226
  205. package/dist/auth/app_settings_routes.d.ts +0 -27
  206. package/dist/auth/app_settings_routes.d.ts.map +0 -1
  207. package/dist/auth/app_settings_routes.js +0 -66
  208. package/dist/auth/invite_routes.d.ts +0 -18
  209. package/dist/auth/invite_routes.d.ts.map +0 -1
  210. package/dist/auth/invite_routes.js +0 -129
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Reactive state for the consentful-permits offer flow.
3
+ *
4
+ * Maintains one offer cache keyed by id, seeded by the RPC list/history
5
+ * actions and kept live by the six permit-offer WebSocket notifications.
6
+ * `incoming` (recipient-side pending) and `outgoing` (grantor-side pending)
7
+ * are derived views; `history` is the full cache ordered newest-first for
8
+ * the grantor/admin history view.
9
+ *
10
+ * Wiring is transport-agnostic: the ctor accepts a narrow RPC interface
11
+ * the consumer adapts from their typed client, plus an `account_id` /
12
+ * `actor_id` getter pair (typically bound to `auth_state`). Notification
13
+ * delivery is pull-only via `subscribe()` — the consumer plumbs their
14
+ * `FrontendWebsocketClient` / `ActionPeer` receiver to `apply_notification`.
15
+ *
16
+ * @module
17
+ */
18
+ import { Loadable } from './loadable.svelte.js';
19
+ import type { PermitOfferJson } from '../auth/permit_offer_schema.js';
20
+ /**
21
+ * Svelte context for `PermitOffersState`.
22
+ * Use `permit_offers_state_context.set(state)` in the provider and
23
+ * `permit_offers_state_context.get()` to access.
24
+ */
25
+ export declare const permit_offers_state_context: {
26
+ get: (error_message?: string) => PermitOffersState;
27
+ get_maybe: () => PermitOffersState | undefined;
28
+ set: (value: PermitOffersState) => PermitOffersState;
29
+ };
30
+ /**
31
+ * Narrow RPC surface consumed by `PermitOffersState`. Consumers adapt their
32
+ * typed client (e.g. a `create_rpc_client` Proxy) to this shape — the state
33
+ * class stays decoupled from the client's `Result` return type so tests can
34
+ * inject plain-function stubs.
35
+ */
36
+ export interface PermitOffersRpc {
37
+ list: () => Promise<{
38
+ offers: Array<PermitOfferJson>;
39
+ }>;
40
+ history: (options?: {
41
+ limit?: number;
42
+ offset?: number;
43
+ }) => Promise<{
44
+ offers: Array<PermitOfferJson>;
45
+ }>;
46
+ create: (params: {
47
+ to_account_id: string;
48
+ role: string;
49
+ scope_id?: string | null;
50
+ message?: string | null;
51
+ }) => Promise<{
52
+ offer: PermitOfferJson;
53
+ }>;
54
+ accept: (offer_id: string) => Promise<{
55
+ permit_id: string;
56
+ offer: PermitOfferJson;
57
+ superseded_offer_ids: Array<string>;
58
+ }>;
59
+ decline: (offer_id: string, reason?: string | null) => Promise<{
60
+ ok: true;
61
+ }>;
62
+ retract: (offer_id: string) => Promise<{
63
+ ok: true;
64
+ }>;
65
+ }
66
+ /** Narrow WS notification envelope — method + params, matching `JsonrpcNotification`. */
67
+ export interface PermitOfferNotification {
68
+ method: string;
69
+ params: unknown;
70
+ }
71
+ /** Subscription primitive — consumer wires their WS receiver; returns a disposer. */
72
+ export type PermitOfferSubscribe = (handler: (notification: PermitOfferNotification) => void) => () => void;
73
+ export interface PermitOffersStateOptions {
74
+ rpc: PermitOffersRpc;
75
+ /** Reactive accessor for the current account id; returns `null` when logged out. */
76
+ account_id: () => string | null;
77
+ /**
78
+ * Reactive accessor for the current actor id — required to classify
79
+ * offers as outgoing. Returns `null` when unknown.
80
+ */
81
+ actor_id: () => string | null;
82
+ }
83
+ export declare class PermitOffersState extends Loadable {
84
+ #private;
85
+ /** Pending offers for the current account, soonest-expiring first. */
86
+ readonly incoming: Array<PermitOfferJson>;
87
+ /** Pending offers from the current actor, newest-created first. */
88
+ readonly outgoing: Array<PermitOfferJson>;
89
+ /** Every offer known to this state, newest-created first. Feeds the history view. */
90
+ readonly history: Array<PermitOfferJson>;
91
+ readonly incoming_count: number;
92
+ constructor(options: PermitOffersStateOptions);
93
+ /** Seed the cache with the recipient-side pending inbox. */
94
+ fetch(): Promise<void>;
95
+ /** Seed both-directions history (includes terminal rows). */
96
+ fetch_history(options?: {
97
+ limit?: number;
98
+ offset?: number;
99
+ }): Promise<void>;
100
+ /** Issue a new offer; merges the returned offer into the cache on success. */
101
+ create(params: {
102
+ to_account_id: string;
103
+ role: string;
104
+ scope_id?: string | null;
105
+ message?: string | null;
106
+ }): Promise<PermitOfferJson | undefined>;
107
+ /** Accept an offer; stamps it terminal in the cache and drops any siblings the server superseded. */
108
+ accept(offer_id: string): Promise<void>;
109
+ decline(offer_id: string, reason?: string | null): Promise<void>;
110
+ retract(offer_id: string): Promise<void>;
111
+ /**
112
+ * Wire a notification subscription. The handler dispatches each matching
113
+ * notification into `apply_notification`; the returned disposer unwires.
114
+ */
115
+ subscribe(subscribe_fn: PermitOfferSubscribe): () => void;
116
+ /**
117
+ * Reduce a single WS notification into the cache. Exposed so consumers
118
+ * wiring their WS receiver directly (without `subscribe`) and tests can
119
+ * drive the reducer without allocating a subscription.
120
+ */
121
+ apply_notification(notification: PermitOfferNotification): void;
122
+ /** Clear the cache and reset loading/error state. */
123
+ reset(): void;
124
+ }
125
+ //# sourceMappingURL=permit_offers_state.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permit_offers_state.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/ui/permit_offers_state.svelte.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,197 @@
1
+ /**
2
+ * Reactive state for the consentful-permits offer flow.
3
+ *
4
+ * Maintains one offer cache keyed by id, seeded by the RPC list/history
5
+ * actions and kept live by the six permit-offer WebSocket notifications.
6
+ * `incoming` (recipient-side pending) and `outgoing` (grantor-side pending)
7
+ * are derived views; `history` is the full cache ordered newest-first for
8
+ * the grantor/admin history view.
9
+ *
10
+ * Wiring is transport-agnostic: the ctor accepts a narrow RPC interface
11
+ * the consumer adapts from their typed client, plus an `account_id` /
12
+ * `actor_id` getter pair (typically bound to `auth_state`). Notification
13
+ * delivery is pull-only via `subscribe()` — the consumer plumbs their
14
+ * `FrontendWebsocketClient` / `ActionPeer` receiver to `apply_notification`.
15
+ *
16
+ * @module
17
+ */
18
+ import { create_context } from '@fuzdev/fuz_ui/context_helpers.js';
19
+ import { Loadable } from './loadable.svelte.js';
20
+ import { PERMIT_OFFER_ACCEPTED_NOTIFICATION_METHOD, PERMIT_OFFER_DECLINED_NOTIFICATION_METHOD, PERMIT_OFFER_RECEIVED_NOTIFICATION_METHOD, PERMIT_OFFER_RETRACTED_NOTIFICATION_METHOD, PERMIT_OFFER_SUPERSEDE_NOTIFICATION_METHOD, PERMIT_REVOKE_NOTIFICATION_METHOD, } from '../auth/permit_offer_notifications.js';
21
+ /**
22
+ * Svelte context for `PermitOffersState`.
23
+ * Use `permit_offers_state_context.set(state)` in the provider and
24
+ * `permit_offers_state_context.get()` to access.
25
+ */
26
+ export const permit_offers_state_context = create_context();
27
+ const is_terminal = (o) => o.accepted_at !== null ||
28
+ o.declined_at !== null ||
29
+ o.retracted_at !== null ||
30
+ o.superseded_at !== null;
31
+ export class PermitOffersState extends Loadable {
32
+ #rpc;
33
+ #get_account_id;
34
+ #get_actor_id;
35
+ #offers = $state.raw(new Map());
36
+ /** Pending offers for the current account, soonest-expiring first. */
37
+ incoming = $derived.by(() => {
38
+ const account_id = this.#get_account_id();
39
+ if (!account_id)
40
+ return [];
41
+ const now = Date.now();
42
+ const rows = [];
43
+ for (const o of this.#offers.values()) {
44
+ if (o.to_account_id !== account_id)
45
+ continue;
46
+ if (is_terminal(o))
47
+ continue;
48
+ if (Date.parse(o.expires_at) <= now)
49
+ continue;
50
+ rows.push(o);
51
+ }
52
+ rows.sort((a, b) => Date.parse(a.expires_at) - Date.parse(b.expires_at));
53
+ return rows;
54
+ });
55
+ /** Pending offers from the current actor, newest-created first. */
56
+ outgoing = $derived.by(() => {
57
+ const actor_id = this.#get_actor_id();
58
+ if (!actor_id)
59
+ return [];
60
+ const now = Date.now();
61
+ const rows = [];
62
+ for (const o of this.#offers.values()) {
63
+ if (o.from_actor_id !== actor_id)
64
+ continue;
65
+ if (is_terminal(o))
66
+ continue;
67
+ if (Date.parse(o.expires_at) <= now)
68
+ continue;
69
+ rows.push(o);
70
+ }
71
+ rows.sort((a, b) => Date.parse(b.created_at) - Date.parse(a.created_at));
72
+ return rows;
73
+ });
74
+ /** Every offer known to this state, newest-created first. Feeds the history view. */
75
+ history = $derived.by(() => {
76
+ const rows = Array.from(this.#offers.values());
77
+ rows.sort((a, b) => Date.parse(b.created_at) - Date.parse(a.created_at));
78
+ return rows;
79
+ });
80
+ incoming_count = $derived(this.incoming.length);
81
+ constructor(options) {
82
+ super();
83
+ this.#rpc = options.rpc;
84
+ this.#get_account_id = options.account_id;
85
+ this.#get_actor_id = options.actor_id;
86
+ }
87
+ /** Seed the cache with the recipient-side pending inbox. */
88
+ async fetch() {
89
+ await this.run(async () => {
90
+ const { offers } = await this.#rpc.list();
91
+ this.#merge_offers(offers);
92
+ });
93
+ }
94
+ /** Seed both-directions history (includes terminal rows). */
95
+ async fetch_history(options) {
96
+ await this.run(async () => {
97
+ const { offers } = await this.#rpc.history(options);
98
+ this.#merge_offers(offers);
99
+ });
100
+ }
101
+ /** Issue a new offer; merges the returned offer into the cache on success. */
102
+ async create(params) {
103
+ return this.run(async () => {
104
+ const { offer } = await this.#rpc.create(params);
105
+ this.#merge_offers([offer]);
106
+ return offer;
107
+ });
108
+ }
109
+ /** Accept an offer; stamps it terminal in the cache and drops any siblings the server superseded. */
110
+ async accept(offer_id) {
111
+ await this.run(async () => {
112
+ const result = await this.#rpc.accept(offer_id);
113
+ this.#merge_offers([result.offer]);
114
+ // siblings are authoritatively superseded server-side; the
115
+ // corresponding WS notifications will also arrive, but dropping
116
+ // them eagerly keeps the inbox accurate in the gap.
117
+ for (const sibling_id of result.superseded_offer_ids) {
118
+ this.#remove_offer(sibling_id);
119
+ }
120
+ });
121
+ }
122
+ async decline(offer_id, reason) {
123
+ await this.run(async () => {
124
+ await this.#rpc.decline(offer_id, reason);
125
+ this.#remove_offer(offer_id);
126
+ });
127
+ }
128
+ async retract(offer_id) {
129
+ await this.run(async () => {
130
+ await this.#rpc.retract(offer_id);
131
+ this.#remove_offer(offer_id);
132
+ });
133
+ }
134
+ /**
135
+ * Wire a notification subscription. The handler dispatches each matching
136
+ * notification into `apply_notification`; the returned disposer unwires.
137
+ */
138
+ subscribe(subscribe_fn) {
139
+ return subscribe_fn((notification) => {
140
+ this.apply_notification(notification);
141
+ });
142
+ }
143
+ /**
144
+ * Reduce a single WS notification into the cache. Exposed so consumers
145
+ * wiring their WS receiver directly (without `subscribe`) and tests can
146
+ * drive the reducer without allocating a subscription.
147
+ */
148
+ apply_notification(notification) {
149
+ switch (notification.method) {
150
+ case PERMIT_OFFER_RECEIVED_NOTIFICATION_METHOD:
151
+ case PERMIT_OFFER_RETRACTED_NOTIFICATION_METHOD:
152
+ case PERMIT_OFFER_ACCEPTED_NOTIFICATION_METHOD:
153
+ case PERMIT_OFFER_DECLINED_NOTIFICATION_METHOD:
154
+ case PERMIT_OFFER_SUPERSEDE_NOTIFICATION_METHOD: {
155
+ const params = notification.params;
156
+ if (!params || typeof params !== 'object' || !('offer' in params))
157
+ return;
158
+ const offer = params.offer;
159
+ if (!is_permit_offer_like(offer))
160
+ return;
161
+ this.#merge_offers([offer]);
162
+ return;
163
+ }
164
+ case PERMIT_REVOKE_NOTIFICATION_METHOD:
165
+ // permit_revoke is a permit-lifecycle event — the offer cache
166
+ // is unaffected. Consumers handle it in an auth/permits state.
167
+ return;
168
+ default:
169
+ // unrelated notifications — ignore silently.
170
+ return;
171
+ }
172
+ }
173
+ /** Clear the cache and reset loading/error state. */
174
+ reset() {
175
+ super.reset();
176
+ this.#offers = new Map();
177
+ }
178
+ #merge_offers(offers) {
179
+ const next = new Map(this.#offers);
180
+ for (const offer of offers) {
181
+ next.set(offer.id, offer);
182
+ }
183
+ this.#offers = next;
184
+ }
185
+ #remove_offer(offer_id) {
186
+ if (!this.#offers.has(offer_id))
187
+ return;
188
+ const next = new Map(this.#offers);
189
+ next.delete(offer_id);
190
+ this.#offers = next;
191
+ }
192
+ }
193
+ const is_permit_offer_like = (value) => !!value &&
194
+ typeof value === 'object' &&
195
+ typeof value.id === 'string' &&
196
+ typeof value.to_account_id === 'string' &&
197
+ typeof value.from_actor_id === 'string';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fuzdev/fuz_app",
3
- "version": "0.29.0",
3
+ "version": "0.31.0",
4
4
  "description": "fullstack app library",
5
5
  "glyph": "🗝",
6
6
  "logo": "logo.svg",
@@ -19,7 +19,7 @@
19
19
  },
20
20
  "type": "module",
21
21
  "engines": {
22
- "node": ">=22.15"
22
+ "node": ">=24.14"
23
23
  },
24
24
  "peerDependencies": {
25
25
  "@electric-sql/pglite": ">=0.3",
@@ -46,7 +46,7 @@
46
46
  "@fuzdev/fuz_code": "^0.45.1",
47
47
  "@fuzdev/fuz_css": "^0.58.0",
48
48
  "@fuzdev/fuz_ui": "^0.191.4",
49
- "@fuzdev/fuz_util": "^0.57.0",
49
+ "@fuzdev/fuz_util": "^0.58.0",
50
50
  "@fuzdev/gro": "^0.198.0",
51
51
  "@jridgewell/trace-mapping": "^0.3.31",
52
52
  "@node-rs/argon2": "^2.0.2",
@@ -1,29 +0,0 @@
1
- /**
2
- * Generic admin route specs — account listing, permit management, session and token revocation.
3
- *
4
- * All routes require the `admin` role.
5
- *
6
- * @module
7
- */
8
- import { type RoleSchemaResult } from './role_schema.js';
9
- import { type RouteSpec } from '../http/route_spec.js';
10
- import type { RouteFactoryDeps } from './deps.js';
11
- /** Options for admin route specs. */
12
- export interface AdminRouteOptions {
13
- /**
14
- * Role schema result from `create_role_schema()`. Defaults to builtin roles only.
15
- * Pass the full result to enable extended app-defined roles in the admin UI.
16
- * Both `Role` and `role_options` come from the same call — passing them together
17
- * via this field ensures they stay in sync.
18
- */
19
- roles?: RoleSchemaResult;
20
- }
21
- /**
22
- * Create admin route specs for account listing and permit management.
23
- *
24
- * @param deps - stateless capabilities (log)
25
- * @param options - optional options with role schema for validation
26
- * @returns route specs for admin account management
27
- */
28
- export declare const create_admin_account_route_specs: (deps: Pick<RouteFactoryDeps, "log" | "on_audit_event">, options?: AdminRouteOptions) => Array<RouteSpec>;
29
- //# sourceMappingURL=admin_routes.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"admin_routes.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/admin_routes.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,EAA8C,KAAK,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AAGpG,OAAO,EAAoC,KAAK,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAcxF,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,WAAW,CAAC;AAShD,qCAAqC;AACrC,MAAM,WAAW,iBAAiB;IACjC;;;;;OAKG;IACH,KAAK,CAAC,EAAE,gBAAgB,CAAC;CACzB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,gCAAgC,GAC5C,MAAM,IAAI,CAAC,gBAAgB,EAAE,KAAK,GAAG,gBAAgB,CAAC,EACtD,UAAU,iBAAiB,KACzB,KAAK,CAAC,SAAS,CAoPjB,CAAC"}
@@ -1,226 +0,0 @@
1
- /**
2
- * Generic admin route specs — account listing, permit management, session and token revocation.
3
- *
4
- * All routes require the `admin` role.
5
- *
6
- * @module
7
- */
8
- import { z } from 'zod';
9
- import { BUILTIN_ROLE_OPTIONS, BuiltinRole, RoleName } from './role_schema.js';
10
- import { AdminAccountEntryJson } from './account_schema.js';
11
- import { require_request_context } from './request_context.js';
12
- import { get_route_input, get_route_params } from '../http/route_spec.js';
13
- import { query_account_by_id, query_actor_by_account, query_admin_account_list, } from './account_queries.js';
14
- import { query_grant_permit, query_permit_find_active_role_for_actor, query_revoke_permit, } from './permit_queries.js';
15
- import { query_session_revoke_all_for_account } from './session_queries.js';
16
- import { query_revoke_all_api_tokens_for_account } from './api_token_queries.js';
17
- import { audit_log_fire_and_forget } from './audit_log_queries.js';
18
- import { ERROR_ACCOUNT_NOT_FOUND, ERROR_ROLE_NOT_WEB_GRANTABLE, ERROR_PERMIT_NOT_FOUND, ERROR_INSUFFICIENT_PERMISSIONS, } from '../http/error_schemas.js';
19
- import { get_client_ip } from '../http/proxy.js';
20
- /**
21
- * Create admin route specs for account listing and permit management.
22
- *
23
- * @param deps - stateless capabilities (log)
24
- * @param options - optional options with role schema for validation
25
- * @returns route specs for admin account management
26
- */
27
- export const create_admin_account_route_specs = (deps, options) => {
28
- const role = 'admin';
29
- const { on_audit_event } = deps;
30
- const role_schema = options?.roles?.Role ?? BuiltinRole;
31
- const role_options = options?.roles?.role_options ?? BUILTIN_ROLE_OPTIONS;
32
- const grantable_roles = [];
33
- for (const [name, rc] of role_options) {
34
- if (rc.web_grantable)
35
- grantable_roles.push(name);
36
- }
37
- return [
38
- {
39
- method: 'GET',
40
- path: '/accounts',
41
- auth: { type: 'role', role },
42
- description: 'List all accounts with their permits',
43
- input: z.null(),
44
- output: z.strictObject({
45
- accounts: z.array(AdminAccountEntryJson),
46
- grantable_roles: z.array(RoleName),
47
- }),
48
- handler: async (c, route) => {
49
- const accounts = await query_admin_account_list(route);
50
- return c.json({ accounts, grantable_roles });
51
- },
52
- },
53
- {
54
- method: 'POST',
55
- path: '/accounts/:account_id/permits/grant',
56
- auth: { type: 'role', role },
57
- description: 'Grant a role permit to an account',
58
- params: z.strictObject({ account_id: z.uuid() }),
59
- input: z.strictObject({ role: role_schema }),
60
- output: z.strictObject({
61
- ok: z.literal(true),
62
- permit: z.strictObject({ id: z.string(), role: z.string() }),
63
- }),
64
- errors: {
65
- 403: z.looseObject({
66
- error: z.enum([ERROR_INSUFFICIENT_PERMISSIONS, ERROR_ROLE_NOT_WEB_GRANTABLE]),
67
- }),
68
- 404: z.looseObject({ error: z.literal(ERROR_ACCOUNT_NOT_FOUND) }),
69
- },
70
- handler: async (c, route) => {
71
- const { account_id } = get_route_params(c);
72
- const { role: role_name } = get_route_input(c);
73
- const ctx = require_request_context(c);
74
- // Enforce web_grantable — direct API calls must respect the same
75
- // restrictions as the UI. Keeper role can only be granted via daemon token.
76
- const rc = role_options.get(role_name);
77
- if (!rc?.web_grantable) {
78
- void audit_log_fire_and_forget(route, {
79
- event_type: 'permit_grant',
80
- outcome: 'failure',
81
- actor_id: ctx.actor.id,
82
- account_id: ctx.account.id,
83
- target_account_id: account_id,
84
- ip: get_client_ip(c),
85
- metadata: { role: role_name },
86
- }, deps.log, on_audit_event);
87
- return c.json({ error: ERROR_ROLE_NOT_WEB_GRANTABLE }, 403);
88
- }
89
- const actor = await query_actor_by_account(route, account_id);
90
- if (!actor) {
91
- return c.json({ error: ERROR_ACCOUNT_NOT_FOUND }, 404);
92
- }
93
- const permit = await query_grant_permit(route, {
94
- actor_id: actor.id,
95
- role: role_name,
96
- granted_by: ctx.actor.id,
97
- });
98
- void audit_log_fire_and_forget(route, {
99
- event_type: 'permit_grant',
100
- actor_id: ctx.actor.id,
101
- account_id: ctx.account.id,
102
- target_account_id: account_id,
103
- ip: get_client_ip(c),
104
- metadata: { role: role_name, permit_id: permit.id },
105
- }, deps.log, on_audit_event);
106
- return c.json({ ok: true, permit: { id: permit.id, role: permit.role } });
107
- },
108
- },
109
- {
110
- method: 'POST',
111
- path: '/accounts/:account_id/sessions/revoke-all',
112
- auth: { type: 'role', role },
113
- description: 'Revoke all sessions for an account',
114
- params: z.strictObject({ account_id: z.uuid() }),
115
- input: z.null(),
116
- output: z.strictObject({ ok: z.literal(true), count: z.number() }),
117
- errors: { 404: z.looseObject({ error: z.literal(ERROR_ACCOUNT_NOT_FOUND) }) },
118
- handler: async (c, route) => {
119
- const { account_id } = get_route_params(c);
120
- const account = await query_account_by_id(route, account_id);
121
- if (!account) {
122
- return c.json({ error: ERROR_ACCOUNT_NOT_FOUND }, 404);
123
- }
124
- const ctx = require_request_context(c);
125
- const count = await query_session_revoke_all_for_account(route, account_id);
126
- void audit_log_fire_and_forget(route, {
127
- event_type: 'session_revoke_all',
128
- actor_id: ctx.actor.id,
129
- account_id: ctx.account.id,
130
- target_account_id: account_id,
131
- ip: get_client_ip(c),
132
- metadata: { count },
133
- }, deps.log, on_audit_event);
134
- return c.json({ ok: true, count });
135
- },
136
- },
137
- {
138
- method: 'POST',
139
- path: '/accounts/:account_id/tokens/revoke-all',
140
- auth: { type: 'role', role },
141
- description: 'Revoke all API tokens for an account',
142
- params: z.strictObject({ account_id: z.uuid() }),
143
- input: z.null(),
144
- output: z.strictObject({ ok: z.literal(true), count: z.number() }),
145
- errors: { 404: z.looseObject({ error: z.literal(ERROR_ACCOUNT_NOT_FOUND) }) },
146
- handler: async (c, route) => {
147
- const { account_id } = get_route_params(c);
148
- const account = await query_account_by_id(route, account_id);
149
- if (!account) {
150
- return c.json({ error: ERROR_ACCOUNT_NOT_FOUND }, 404);
151
- }
152
- const ctx = require_request_context(c);
153
- const count = await query_revoke_all_api_tokens_for_account(route, account_id);
154
- void audit_log_fire_and_forget(route, {
155
- event_type: 'token_revoke_all',
156
- actor_id: ctx.actor.id,
157
- account_id: ctx.account.id,
158
- target_account_id: account_id,
159
- ip: get_client_ip(c),
160
- metadata: { count },
161
- }, deps.log, on_audit_event);
162
- return c.json({ ok: true, count });
163
- },
164
- },
165
- {
166
- method: 'POST',
167
- path: '/accounts/:account_id/permits/:permit_id/revoke',
168
- auth: { type: 'role', role },
169
- description: 'Revoke a permit',
170
- params: z.strictObject({ account_id: z.uuid(), permit_id: z.uuid() }),
171
- input: z.null(),
172
- output: z.strictObject({ ok: z.literal(true), revoked: z.literal(true) }),
173
- errors: {
174
- 403: z.looseObject({
175
- error: z.enum([ERROR_INSUFFICIENT_PERMISSIONS, ERROR_ROLE_NOT_WEB_GRANTABLE]),
176
- }),
177
- 404: z.looseObject({
178
- error: z.enum([ERROR_ACCOUNT_NOT_FOUND, ERROR_PERMIT_NOT_FOUND]),
179
- }),
180
- },
181
- handler: async (c, route) => {
182
- const { account_id, permit_id } = get_route_params(c);
183
- const ctx = require_request_context(c);
184
- // resolve the target actor from the URL account_id to prevent IDOR
185
- const target_actor = await query_actor_by_account(route, account_id);
186
- if (!target_actor) {
187
- return c.json({ error: ERROR_ACCOUNT_NOT_FOUND }, 404);
188
- }
189
- // Look up the permit's role so we can enforce web_grantable symmetrically
190
- // with the grant route. Without this, an admin could revoke the keeper
191
- // permit via the web, breaking the "only daemon token manages keeper" invariant.
192
- // Route wraps POST handlers in a transaction, so SELECT-then-UPDATE is atomic.
193
- const permit_row = await query_permit_find_active_role_for_actor(route, permit_id, target_actor.id);
194
- if (!permit_row) {
195
- return c.json({ error: ERROR_PERMIT_NOT_FOUND }, 404);
196
- }
197
- const rc = role_options.get(permit_row.role);
198
- if (!rc?.web_grantable) {
199
- void audit_log_fire_and_forget(route, {
200
- event_type: 'permit_revoke',
201
- outcome: 'failure',
202
- actor_id: ctx.actor.id,
203
- account_id: ctx.account.id,
204
- target_account_id: account_id,
205
- ip: get_client_ip(c),
206
- metadata: { role: permit_row.role, permit_id },
207
- }, deps.log, on_audit_event);
208
- return c.json({ error: ERROR_ROLE_NOT_WEB_GRANTABLE }, 403);
209
- }
210
- const result = await query_revoke_permit(route, permit_id, target_actor.id, ctx.actor.id);
211
- if (!result) {
212
- return c.json({ error: ERROR_PERMIT_NOT_FOUND }, 404);
213
- }
214
- void audit_log_fire_and_forget(route, {
215
- event_type: 'permit_revoke',
216
- actor_id: ctx.actor.id,
217
- account_id: ctx.account.id,
218
- target_account_id: account_id,
219
- ip: get_client_ip(c),
220
- metadata: { role: result.role, permit_id },
221
- }, deps.log, on_audit_event);
222
- return c.json({ ok: true, revoked: true });
223
- },
224
- },
225
- ];
226
- };
@@ -1,27 +0,0 @@
1
- /**
2
- * Admin app settings route specs.
3
- *
4
- * GET and PATCH routes for managing global app settings (e.g. open signup toggle).
5
- * All routes require the `admin` role.
6
- *
7
- * @module
8
- */
9
- import { type RouteSpec } from '../http/route_spec.js';
10
- import { type AppSettings } from './app_settings_schema.js';
11
- import type { RouteFactoryDeps } from './deps.js';
12
- /**
13
- * Per-factory configuration for app settings route specs.
14
- */
15
- export interface AppSettingsRouteOptions {
16
- /** Mutable ref to the in-memory app settings — mutated on PATCH. */
17
- app_settings: AppSettings;
18
- }
19
- /**
20
- * Create admin app settings route specs.
21
- *
22
- * @param deps - stateless capabilities (log, on_audit_event)
23
- * @param options - per-factory configuration
24
- * @returns route specs for app settings management
25
- */
26
- export declare const create_app_settings_route_specs: (deps: Pick<RouteFactoryDeps, "log" | "on_audit_event">, options: AppSettingsRouteOptions) => Array<RouteSpec>;
27
- //# sourceMappingURL=app_settings_routes.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"app_settings_routes.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/app_settings_routes.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,EAAkB,KAAK,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAQtE,OAAO,EAGN,KAAK,WAAW,EAChB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,WAAW,CAAC;AAEhD;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACvC,oEAAoE;IACpE,YAAY,EAAE,WAAW,CAAC;CAC1B;AAED;;;;;;GAMG;AACH,eAAO,MAAM,+BAA+B,GAC3C,MAAM,IAAI,CAAC,gBAAgB,EAAE,KAAK,GAAG,gBAAgB,CAAC,EACtD,SAAS,uBAAuB,KAC9B,KAAK,CAAC,SAAS,CAoDjB,CAAC"}