@fuzdev/fuz_app 0.38.0 → 0.39.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 (41) hide show
  1. package/dist/actions/transports_ws_auth_guard.d.ts +12 -2
  2. package/dist/actions/transports_ws_auth_guard.d.ts.map +1 -1
  3. package/dist/auth/CLAUDE.md +48 -32
  4. package/dist/auth/audit_log_queries.d.ts +19 -17
  5. package/dist/auth/audit_log_queries.d.ts.map +1 -1
  6. package/dist/auth/audit_log_queries.js +49 -36
  7. package/dist/auth/audit_log_schema.d.ts +81 -10
  8. package/dist/auth/audit_log_schema.d.ts.map +1 -1
  9. package/dist/auth/audit_log_schema.js +67 -10
  10. package/dist/auth/role_schema.d.ts +10 -1
  11. package/dist/auth/role_schema.d.ts.map +1 -1
  12. package/dist/auth/role_schema.js +10 -1
  13. package/dist/http/jsonrpc_errors.d.ts +27 -75
  14. package/dist/http/jsonrpc_errors.d.ts.map +1 -1
  15. package/dist/http/jsonrpc_errors.js +16 -9
  16. package/dist/server/app_backend.d.ts +17 -6
  17. package/dist/server/app_backend.d.ts.map +1 -1
  18. package/dist/server/app_backend.js +17 -6
  19. package/dist/server/app_server.d.ts +6 -7
  20. package/dist/server/app_server.d.ts.map +1 -1
  21. package/dist/server/app_server.js +16 -29
  22. package/dist/ui/AdminAccounts.svelte +19 -0
  23. package/dist/ui/AdminAccounts.svelte.d.ts +2 -17
  24. package/dist/ui/AdminAccounts.svelte.d.ts.map +1 -1
  25. package/dist/ui/AdminPermitHistory.svelte +23 -2
  26. package/dist/ui/AdminPermitHistory.svelte.d.ts +2 -17
  27. package/dist/ui/AdminPermitHistory.svelte.d.ts.map +1 -1
  28. package/dist/ui/CLAUDE.md +11 -0
  29. package/dist/ui/PermitOfferHistory.svelte +11 -5
  30. package/dist/ui/PermitOfferHistory.svelte.d.ts +7 -1
  31. package/dist/ui/PermitOfferHistory.svelte.d.ts.map +1 -1
  32. package/dist/ui/PermitOfferInbox.svelte +12 -7
  33. package/dist/ui/PermitOfferInbox.svelte.d.ts +8 -3
  34. package/dist/ui/PermitOfferInbox.svelte.d.ts.map +1 -1
  35. package/dist/ui/admin_rpc_adapters.d.ts +16 -1
  36. package/dist/ui/admin_rpc_adapters.d.ts.map +1 -1
  37. package/dist/ui/admin_rpc_adapters.js +12 -1
  38. package/dist/ui/format_scope.d.ts +45 -0
  39. package/dist/ui/format_scope.d.ts.map +1 -0
  40. package/dist/ui/format_scope.js +34 -0
  41. package/package.json +1 -1
@@ -4,19 +4,28 @@
4
4
  import Datatable from './Datatable.svelte';
5
5
  import type {DatatableColumn} from './datatable.js';
6
6
  import type {PermitHistoryEventJson} from '../auth/audit_log_schema.js';
7
+ import {format_scope_context, resolve_scope_label} from './format_scope.js';
7
8
 
8
9
  const get_rpc = audit_log_rpc_context.get();
9
10
  const audit_log = new AuditLogState({get_rpc});
11
+ const get_format_scope = format_scope_context.get();
12
+ const format_scope = $derived(get_format_scope());
10
13
 
11
14
  void audit_log.fetch_permit_history();
12
15
 
13
16
  const columns: Array<DatatableColumn<PermitHistoryEventJson>> = [
14
17
  {key: 'event_type', label: 'action', width: 100},
15
- {key: 'metadata', label: 'role', width: 100},
18
+ {key: 'metadata', label: 'role', width: 160},
16
19
  {key: 'username', label: 'by', width: 140},
17
20
  {key: 'target_username', label: 'target', width: 140},
18
21
  {key: 'created_at', label: 'time', width: 100},
19
22
  ];
23
+
24
+ // Metadata is `Record<string, unknown>`; narrow before reusing `resolve_scope_label`.
25
+ const scope_label_from_metadata = (scope_id: unknown, role: string): string | null => {
26
+ if (typeof scope_id !== 'string' || scope_id === '') return null;
27
+ return resolve_scope_label(scope_id, role, format_scope, null);
28
+ };
20
29
  </script>
21
30
 
22
31
  <section>
@@ -39,7 +48,19 @@
39
48
  </span>
40
49
  {:else if column.key === 'metadata'}
41
50
  {#if row.metadata}
42
- <code>{row.metadata.role ?? ''}</code>
51
+ {@const role = typeof row.metadata.role === 'string' ? row.metadata.role : ''}
52
+ <code>{role}</code>
53
+ {@const scope = scope_label_from_metadata(row.metadata.scope_id, role)}
54
+ {#if scope !== null}
55
+ <span
56
+ class="text_50 font_size_sm"
57
+ title={typeof row.metadata.scope_id === 'string'
58
+ ? row.metadata.scope_id
59
+ : undefined}
60
+ >
61
+ {scope}
62
+ </span>
63
+ {/if}
43
64
  {/if}
44
65
  {:else if column.key === 'username'}
45
66
  <span class="text_50">{row.username ?? truncate_uuid(row.account_id ?? '?')}</span>
@@ -1,19 +1,4 @@
1
- interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
2
- new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
3
- $$bindings?: Bindings;
4
- } & Exports;
5
- (internal: unknown, props: {
6
- $$events?: Events;
7
- $$slots?: Slots;
8
- }): Exports & {
9
- $set?: any;
10
- $on?: any;
11
- };
12
- z_$$bindings?: Bindings;
13
- }
14
- declare const AdminPermitHistory: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
15
- [evt: string]: CustomEvent<any>;
16
- }, {}, {}, string>;
17
- type AdminPermitHistory = InstanceType<typeof AdminPermitHistory>;
1
+ declare const AdminPermitHistory: import("svelte").Component<Record<string, never>, {}, "">;
2
+ type AdminPermitHistory = ReturnType<typeof AdminPermitHistory>;
18
3
  export default AdminPermitHistory;
19
4
  //# sourceMappingURL=AdminPermitHistory.svelte.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AdminPermitHistory.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/ui/AdminPermitHistory.svelte"],"names":[],"mappings":"AAoEA,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,kBAAkB;;kBAA+E,CAAC;AACtF,KAAK,kBAAkB,GAAG,YAAY,CAAC,OAAO,kBAAkB,CAAC,CAAC;AACpE,eAAe,kBAAkB,CAAC"}
1
+ {"version":3,"file":"AdminPermitHistory.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/ui/AdminPermitHistory.svelte"],"names":[],"mappings":"AAuFA,QAAA,MAAM,kBAAkB,2DAAwC,CAAC;AACjE,KAAK,kBAAkB,GAAG,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAChE,eAAe,kBAAkB,CAAC"}
package/dist/ui/CLAUDE.md CHANGED
@@ -303,6 +303,17 @@ provisioner pattern.
303
303
  directly. Consumed by `PermitOfferInbox`, `PermitOfferForm`,
304
304
  `PermitOfferHistory`. Wiring is ctor-bound (RPC + account/actor
305
305
  getters), so there's no separate `permit_offers_rpc_context`.
306
+ - `format_scope_context` — `() => FormatScope` (getter shape, matching
307
+ the RPC contexts above). `FormatScope = ({scope_id, role}) => string |
308
+ null`; default returns `null` so callers fall back to the raw uuid.
309
+ Provisioned by `provide_admin_rpc_contexts(adapters, {format_scope})`.
310
+ Consumed by `AdminAccounts`, `AdminPermitHistory`, `PermitOfferInbox`,
311
+ `PermitOfferHistory` via the `resolve_scope_label(scope_id, role,
312
+ format_scope, global_label)` helper — `global_label = null` renders no
313
+ chip (admin tables); `'global'` renders an explicit label (offer
314
+ surfaces). `PermitOfferInbox` / `PermitOfferHistory` accept a
315
+ `format_scope?: FormatScope` prop — same shape as the context, prop
316
+ wins when supplied.
306
317
  - `sidebar_state_context` — `() => SidebarState`. Provisioned by
307
318
  `AppShell`.
308
319
 
@@ -16,6 +16,7 @@
16
16
  import type {DatatableColumn} from './datatable.js';
17
17
  import {format_relative_time, format_datetime_local, truncate_uuid} from './ui_format.js';
18
18
  import type {PermitOfferJson} from '../auth/permit_offer_schema.js';
19
+ import {format_scope_context, resolve_scope_label, type FormatScope} from './format_scope.js';
19
20
 
20
21
  const {
21
22
  current_actor_id,
@@ -26,11 +27,18 @@
26
27
  /** Used to label a row as sent vs received. When `null`, direction shows as `-`. */
27
28
  current_actor_id: string | null;
28
29
  format_actor?: (from_actor_id: string) => string;
29
- format_scope?: (scope_id: string | null, role: string) => string;
30
+ /**
31
+ * Display label for an offer's scope. Bypasses `format_scope_context`
32
+ * when supplied — return `null` to fall back to a truncated uuid (or
33
+ * `'global'` for null scope_id). Omit to use the context value directly.
34
+ */
35
+ format_scope?: FormatScope;
30
36
  format_role?: (role: string) => string;
31
37
  } = $props();
32
38
 
33
39
  const permit_offers = permit_offers_state_context.get();
40
+ const get_format_scope = format_scope_context.get();
41
+ const format_scope_from_context = $derived(get_format_scope());
34
42
 
35
43
  const now = $state.raw(Date.now());
36
44
 
@@ -59,10 +67,8 @@
59
67
  }
60
68
  };
61
69
 
62
- const scope_label = (scope_id: string | null, role: string): string => {
63
- if (format_scope) return format_scope(scope_id, role);
64
- return scope_id === null ? 'global' : truncate_uuid(scope_id);
65
- };
70
+ const scope_label = (scope_id: string | null, role: string): string =>
71
+ resolve_scope_label(scope_id, role, format_scope ?? format_scope_from_context, 'global');
66
72
 
67
73
  const columns: Array<DatatableColumn<PermitOfferJson>> = [
68
74
  {key: 'from_actor_id', label: 'direction', width: 110},
@@ -1,8 +1,14 @@
1
+ import { type FormatScope } from './format_scope.js';
1
2
  type $$ComponentProps = {
2
3
  /** Used to label a row as sent vs received. When `null`, direction shows as `-`. */
3
4
  current_actor_id: string | null;
4
5
  format_actor?: (from_actor_id: string) => string;
5
- format_scope?: (scope_id: string | null, role: string) => string;
6
+ /**
7
+ * Display label for an offer's scope. Bypasses `format_scope_context`
8
+ * when supplied — return `null` to fall back to a truncated uuid (or
9
+ * `'global'` for null scope_id). Omit to use the context value directly.
10
+ */
11
+ format_scope?: FormatScope;
6
12
  format_role?: (role: string) => string;
7
13
  };
8
14
  declare const PermitOfferHistory: import("svelte").Component<$$ComponentProps, {}, "">;
@@ -1 +1 @@
1
- {"version":3,"file":"PermitOfferHistory.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/ui/PermitOfferHistory.svelte"],"names":[],"mappings":"AAoBC,KAAK,gBAAgB,GAAI;IACxB,oFAAoF;IACpF,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,YAAY,CAAC,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,MAAM,CAAC;IACjD,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACjE,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CACvC,CAAC;AAiGH,QAAA,MAAM,kBAAkB,sDAAwC,CAAC;AACjE,KAAK,kBAAkB,GAAG,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAChE,eAAe,kBAAkB,CAAC"}
1
+ {"version":3,"file":"PermitOfferHistory.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/ui/PermitOfferHistory.svelte"],"names":[],"mappings":"AAmBA,OAAO,EAA4C,KAAK,WAAW,EAAC,MAAM,mBAAmB,CAAC;AAE7F,KAAK,gBAAgB,GAAI;IACxB,oFAAoF;IACpF,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,YAAY,CAAC,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,MAAM,CAAC;IACjD;;;;OAIG;IACH,YAAY,CAAC,EAAE,WAAW,CAAC;IAC3B,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CACvC,CAAC;AAkGH,QAAA,MAAM,kBAAkB,sDAAwC,CAAC;AACjE,KAAK,kBAAkB,GAAG,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAChE,eAAe,kBAAkB,CAAC"}
@@ -16,6 +16,7 @@
16
16
  import ConfirmButton from './ConfirmButton.svelte';
17
17
  import {format_relative_time, format_datetime_local, truncate_uuid} from './ui_format.js';
18
18
  import {PERMIT_OFFER_MESSAGE_LENGTH_MAX} from '../auth/permit_offer_schema.js';
19
+ import {format_scope_context, resolve_scope_label, type FormatScope} from './format_scope.js';
19
20
 
20
21
  const {
21
22
  format_actor = truncate_uuid,
@@ -24,18 +25,22 @@
24
25
  }: {
25
26
  /** Display label for `from_actor_id`. Defaults to a truncated uuid. */
26
27
  format_actor?: (from_actor_id: string) => string;
27
- /** Display label for an offer's scope. Defaults to truncated uuid or "global" when `null`. */
28
- format_scope?: (scope_id: string | null, role: string) => string;
29
- /** Display label for a role constant. Defaults to identity (role name as stored). */
28
+ /**
29
+ * Display label for an offer's scope. Bypasses `format_scope_context`
30
+ * when supplied return `null` to fall back to a truncated uuid (or
31
+ * `'global'` for null scope_id). Omit to use the context value directly.
32
+ */
33
+ format_scope?: FormatScope;
34
+ /** Display label for a role constant. Defaults to identity. */
30
35
  format_role?: (role: string) => string;
31
36
  } = $props();
32
37
 
33
38
  const permit_offers = permit_offers_state_context.get();
39
+ const get_format_scope = format_scope_context.get();
40
+ const format_scope_from_context = $derived(get_format_scope());
34
41
 
35
- const scope_label = (scope_id: string | null, role: string): string => {
36
- if (format_scope) return format_scope(scope_id, role);
37
- return scope_id === null ? 'global' : truncate_uuid(scope_id);
38
- };
42
+ const scope_label = (scope_id: string | null, role: string): string =>
43
+ resolve_scope_label(scope_id, role, format_scope ?? format_scope_from_context, 'global');
39
44
 
40
45
  const decline_reasons: SvelteMap<string, string> = new SvelteMap();
41
46
  </script>
@@ -1,9 +1,14 @@
1
+ import { type FormatScope } from './format_scope.js';
1
2
  type $$ComponentProps = {
2
3
  /** Display label for `from_actor_id`. Defaults to a truncated uuid. */
3
4
  format_actor?: (from_actor_id: string) => string;
4
- /** Display label for an offer's scope. Defaults to truncated uuid or "global" when `null`. */
5
- format_scope?: (scope_id: string | null, role: string) => string;
6
- /** Display label for a role constant. Defaults to identity (role name as stored). */
5
+ /**
6
+ * Display label for an offer's scope. Bypasses `format_scope_context`
7
+ * when supplied return `null` to fall back to a truncated uuid (or
8
+ * `'global'` for null scope_id). Omit to use the context value directly.
9
+ */
10
+ format_scope?: FormatScope;
11
+ /** Display label for a role constant. Defaults to identity. */
7
12
  format_role?: (role: string) => string;
8
13
  };
9
14
  declare const PermitOfferInbox: import("svelte").Component<$$ComponentProps, {}, "">;
@@ -1 +1 @@
1
- {"version":3,"file":"PermitOfferInbox.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/ui/PermitOfferInbox.svelte"],"names":[],"mappings":"AAoBC,KAAK,gBAAgB,GAAI;IACxB,uEAAuE;IACvE,YAAY,CAAC,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,MAAM,CAAC;IACjD,8FAA8F;IAC9F,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACjE,qFAAqF;IACrF,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CACvC,CAAC;AA0FH,QAAA,MAAM,gBAAgB,sDAAwC,CAAC;AAC/D,KAAK,gBAAgB,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC5D,eAAe,gBAAgB,CAAC"}
1
+ {"version":3,"file":"PermitOfferInbox.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/ui/PermitOfferInbox.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,gBAAgB,sDAAwC,CAAC;AAC/D,KAAK,gBAAgB,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC5D,eAAe,gBAAgB,CAAC"}
@@ -39,6 +39,7 @@ import { type AdminAccountsRpc } from './admin_accounts_state.svelte.js';
39
39
  import { type AdminInvitesRpc } from './admin_invites_state.svelte.js';
40
40
  import { type AuditLogRpc } from './audit_log_state.svelte.js';
41
41
  import { type AppSettingsRpc } from './app_settings_state.svelte.js';
42
+ import { type FormatScope } from './format_scope.js';
42
43
  /**
43
44
  * Function-shaped contract for dispatching an RPC call by method name.
44
45
  *
@@ -87,6 +88,14 @@ export interface AdminRpcAdapters {
87
88
  * admin surfaces they mount.
88
89
  */
89
90
  export declare const create_admin_rpc_adapters: (rpc_call: AdminRpcCall) => AdminRpcAdapters;
91
+ /** Optional knobs alongside the adapters when wiring admin contexts. */
92
+ export interface ProvideAdminRpcContextsOptions {
93
+ /**
94
+ * Render `{scope_id, role}` as a human label across permit-display
95
+ * components. Omit (or return `null`) to fall back to the raw uuid.
96
+ */
97
+ format_scope?: FormatScope;
98
+ }
90
99
  /**
91
100
  * Wire all four admin RPC contexts in a single call.
92
101
  *
@@ -98,6 +107,12 @@ export declare const create_admin_rpc_adapters: (rpc_call: AdminRpcCall) => Admi
98
107
  * mutating an adapter field on the same object propagates. Replacing the
99
108
  * whole adapter set requires calling `provide_admin_rpc_contexts` again
100
109
  * during init — in practice this is one-shot at layout mount.
110
+ *
111
+ * Pass `options.format_scope` to render permit/offer `scope_id` values as
112
+ * human labels across `AdminAccounts`, `AdminPermitHistory`,
113
+ * `PermitOfferInbox`, `PermitOfferForm`, and `PermitOfferHistory`.
114
+ * Components that accept a `format_scope` prop honor the prop first; the
115
+ * context is the fallback.
101
116
  */
102
- export declare const provide_admin_rpc_contexts: (adapters: AdminRpcAdapters) => void;
117
+ export declare const provide_admin_rpc_contexts: (adapters: AdminRpcAdapters, options?: ProvideAdminRpcContextsOptions) => void;
103
118
  //# sourceMappingURL=admin_rpc_adapters.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"admin_rpc_adapters.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/ui/admin_rpc_adapters.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAA6B,KAAK,gBAAgB,EAAC,MAAM,kCAAkC,CAAC;AACnG,OAAO,EAA4B,KAAK,eAAe,EAAC,MAAM,iCAAiC,CAAC;AAChG,OAAO,EAAwB,KAAK,WAAW,EAAC,MAAM,6BAA6B,CAAC;AACpF,OAAO,EAA2B,KAAK,cAAc,EAAC,MAAM,gCAAgC,CAAC;AAE7F;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,YAAY,GAAG,eAAe,CAAC;AAE3C,sEAAsE;AACtE,MAAM,WAAW,gBAAgB;IAChC,cAAc,EAAE,gBAAgB,CAAC;IACjC,aAAa,EAAE,eAAe,CAAC;IAC/B,SAAS,EAAE,WAAW,CAAC;IACvB,YAAY,EAAE,cAAc,CAAC;CAC7B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,yBAAyB,GAAI,UAAU,YAAY,KAAG,gBAuBjE,CAAC;AAEH;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,0BAA0B,GAAI,UAAU,gBAAgB,KAAG,IAKvE,CAAC"}
1
+ {"version":3,"file":"admin_rpc_adapters.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/ui/admin_rpc_adapters.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAA6B,KAAK,gBAAgB,EAAC,MAAM,kCAAkC,CAAC;AACnG,OAAO,EAA4B,KAAK,eAAe,EAAC,MAAM,iCAAiC,CAAC;AAChG,OAAO,EAAwB,KAAK,WAAW,EAAC,MAAM,6BAA6B,CAAC;AACpF,OAAO,EAA2B,KAAK,cAAc,EAAC,MAAM,gCAAgC,CAAC;AAC7F,OAAO,EAAuB,KAAK,WAAW,EAAC,MAAM,mBAAmB,CAAC;AAEzE;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,YAAY,GAAG,eAAe,CAAC;AAE3C,sEAAsE;AACtE,MAAM,WAAW,gBAAgB;IAChC,cAAc,EAAE,gBAAgB,CAAC;IACjC,aAAa,EAAE,eAAe,CAAC;IAC/B,SAAS,EAAE,WAAW,CAAC;IACvB,YAAY,EAAE,cAAc,CAAC;CAC7B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,yBAAyB,GAAI,UAAU,YAAY,KAAG,gBAuBjE,CAAC;AAEH,wEAAwE;AACxE,MAAM,WAAW,8BAA8B;IAC9C;;;OAGG;IACH,YAAY,CAAC,EAAE,WAAW,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,0BAA0B,GACtC,UAAU,gBAAgB,EAC1B,UAAU,8BAA8B,KACtC,IASF,CAAC"}
@@ -38,6 +38,7 @@ import { admin_accounts_rpc_context } from './admin_accounts_state.svelte.js';
38
38
  import { admin_invites_rpc_context } from './admin_invites_state.svelte.js';
39
39
  import { audit_log_rpc_context } from './audit_log_state.svelte.js';
40
40
  import { app_settings_rpc_context } from './app_settings_state.svelte.js';
41
+ import { format_scope_context } from './format_scope.js';
41
42
  /**
42
43
  * Build the four admin RPC adapters from a single typed `rpc_call`.
43
44
  *
@@ -100,10 +101,20 @@ export const create_admin_rpc_adapters = (rpc_call) => ({
100
101
  * mutating an adapter field on the same object propagates. Replacing the
101
102
  * whole adapter set requires calling `provide_admin_rpc_contexts` again
102
103
  * during init — in practice this is one-shot at layout mount.
104
+ *
105
+ * Pass `options.format_scope` to render permit/offer `scope_id` values as
106
+ * human labels across `AdminAccounts`, `AdminPermitHistory`,
107
+ * `PermitOfferInbox`, `PermitOfferForm`, and `PermitOfferHistory`.
108
+ * Components that accept a `format_scope` prop honor the prop first; the
109
+ * context is the fallback.
103
110
  */
104
- export const provide_admin_rpc_contexts = (adapters) => {
111
+ export const provide_admin_rpc_contexts = (adapters, options) => {
105
112
  admin_accounts_rpc_context.set(() => adapters.admin_accounts);
106
113
  admin_invites_rpc_context.set(() => adapters.admin_invites);
107
114
  audit_log_rpc_context.set(() => adapters.audit_log);
108
115
  app_settings_rpc_context.set(() => adapters.app_settings);
116
+ if (options?.format_scope) {
117
+ const { format_scope } = options;
118
+ format_scope_context.set(() => format_scope);
119
+ }
109
120
  };
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Shared `format_scope` callback contract for permit-display components.
3
+ *
4
+ * Permits and offers carry a `scope_id` that names a consumer-owned resource
5
+ * (e.g. a classroom uuid). The default render is the raw uuid. Consumers wire
6
+ * a `FormatScope` via context to render a human label without per-page
7
+ * lookup or forking the components.
8
+ *
9
+ * @module
10
+ */
11
+ /**
12
+ * Render a `{scope_id, role}` pair as a human label. Return `null` to fall
13
+ * back to the raw scope uuid (or a caller-chosen `global_label` when
14
+ * `scope_id` is `null`).
15
+ *
16
+ * Returning `null` for unknown scope ids (stale cache, revoked resource) is
17
+ * the recommended pattern — components show the raw uuid rather than a
18
+ * misleading blank.
19
+ */
20
+ export type FormatScope = (args: {
21
+ scope_id: string | null;
22
+ role: string;
23
+ }) => string | null;
24
+ /** Default `FormatScope` — always returns `null` so callers fall back to the raw uuid. */
25
+ export declare const default_format_scope: FormatScope;
26
+ /**
27
+ * Svelte context carrying a getter for the consumer's `FormatScope`.
28
+ * Provisioned by `provide_admin_rpc_contexts` from its `format_scope` option.
29
+ * Default getter returns `default_format_scope` so unprovisioned trees render
30
+ * the raw uuid.
31
+ */
32
+ export declare const format_scope_context: {
33
+ get: () => () => FormatScope;
34
+ set: (value?: (() => FormatScope) | undefined) => () => FormatScope;
35
+ };
36
+ /**
37
+ * Resolve a scope label across the context → raw-uuid fallback chain.
38
+ *
39
+ * `global_label` is returned for `scope_id === null`. Callers pass `null`
40
+ * to render no chip (admin tables — global is the implicit default) or
41
+ * `'global'` for explicit labels (offer surfaces). The return type
42
+ * propagates `null` only when `global_label` is `null`.
43
+ */
44
+ export declare const resolve_scope_label: <G extends string | null>(scope_id: string | null, role: string, format_scope: FormatScope, global_label: G) => string | G;
45
+ //# sourceMappingURL=format_scope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format_scope.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/ui/format_scope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH;;;;;;;;GAQG;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,KAAK,MAAM,GAAG,IAAI,CAAC;AAE3F,0FAA0F;AAC1F,eAAO,MAAM,oBAAoB,EAAE,WAAwB,CAAC;AAE5D;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB;qBAAwB,WAAW;yBAAX,WAAW,wBAAX,WAAW;CAEnE,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,GAAI,CAAC,SAAS,MAAM,GAAG,IAAI,EAC1D,UAAU,MAAM,GAAG,IAAI,EACvB,MAAM,MAAM,EACZ,cAAc,WAAW,EACzB,cAAc,CAAC,KACb,MAAM,GAAG,CAGX,CAAC"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Shared `format_scope` callback contract for permit-display components.
3
+ *
4
+ * Permits and offers carry a `scope_id` that names a consumer-owned resource
5
+ * (e.g. a classroom uuid). The default render is the raw uuid. Consumers wire
6
+ * a `FormatScope` via context to render a human label without per-page
7
+ * lookup or forking the components.
8
+ *
9
+ * @module
10
+ */
11
+ import { create_context } from '@fuzdev/fuz_ui/context_helpers.js';
12
+ import { truncate_uuid } from './ui_format.js';
13
+ /** Default `FormatScope` — always returns `null` so callers fall back to the raw uuid. */
14
+ export const default_format_scope = () => null;
15
+ /**
16
+ * Svelte context carrying a getter for the consumer's `FormatScope`.
17
+ * Provisioned by `provide_admin_rpc_contexts` from its `format_scope` option.
18
+ * Default getter returns `default_format_scope` so unprovisioned trees render
19
+ * the raw uuid.
20
+ */
21
+ export const format_scope_context = create_context(() => () => default_format_scope);
22
+ /**
23
+ * Resolve a scope label across the context → raw-uuid fallback chain.
24
+ *
25
+ * `global_label` is returned for `scope_id === null`. Callers pass `null`
26
+ * to render no chip (admin tables — global is the implicit default) or
27
+ * `'global'` for explicit labels (offer surfaces). The return type
28
+ * propagates `null` only when `global_label` is `null`.
29
+ */
30
+ export const resolve_scope_label = (scope_id, role, format_scope, global_label) => {
31
+ if (scope_id === null)
32
+ return global_label;
33
+ return format_scope({ scope_id, role }) ?? truncate_uuid(scope_id);
34
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fuzdev/fuz_app",
3
- "version": "0.38.0",
3
+ "version": "0.39.0",
4
4
  "description": "fullstack app library",
5
5
  "glyph": "🗝",
6
6
  "logo": "logo.svg",