@fuzdev/fuz_app 0.55.0 → 0.57.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.
- package/dist/actions/CLAUDE.md +211 -155
- package/dist/actions/action_bridge.d.ts +8 -5
- package/dist/actions/action_bridge.d.ts.map +1 -1
- package/dist/actions/action_bridge.js +1 -11
- package/dist/actions/action_codegen.d.ts +19 -0
- package/dist/actions/action_codegen.d.ts.map +1 -1
- package/dist/actions/action_codegen.js +20 -14
- package/dist/actions/action_registry.d.ts.map +1 -1
- package/dist/actions/action_registry.js +5 -2
- package/dist/actions/action_rpc.d.ts +110 -44
- package/dist/actions/action_rpc.d.ts.map +1 -1
- package/dist/actions/action_rpc.js +92 -287
- package/dist/actions/action_spec.d.ts +55 -16
- package/dist/actions/action_spec.d.ts.map +1 -1
- package/dist/actions/action_spec.js +16 -11
- package/dist/actions/action_types.d.ts +28 -60
- package/dist/actions/action_types.d.ts.map +1 -1
- package/dist/actions/action_types.js +13 -5
- package/dist/actions/broadcast_api.d.ts +2 -2
- package/dist/actions/broadcast_api.js +2 -2
- package/dist/actions/compile_action_registry.d.ts +50 -0
- package/dist/actions/compile_action_registry.d.ts.map +1 -0
- package/dist/actions/compile_action_registry.js +69 -0
- package/dist/actions/heartbeat.d.ts +8 -4
- package/dist/actions/heartbeat.d.ts.map +1 -1
- package/dist/actions/heartbeat.js +5 -4
- package/dist/actions/perform_action.d.ts +145 -0
- package/dist/actions/perform_action.d.ts.map +1 -0
- package/dist/actions/perform_action.js +258 -0
- package/dist/actions/register_action_ws.d.ts +44 -38
- package/dist/actions/register_action_ws.d.ts.map +1 -1
- package/dist/actions/register_action_ws.js +101 -159
- package/dist/actions/register_ws_endpoint.d.ts +2 -10
- package/dist/actions/register_ws_endpoint.d.ts.map +1 -1
- package/dist/actions/register_ws_endpoint.js +32 -10
- package/dist/actions/transports_ws_auth_guard.d.ts +1 -1
- package/dist/actions/transports_ws_auth_guard.js +1 -1
- package/dist/actions/transports_ws_backend.d.ts +1 -1
- package/dist/actions/transports_ws_backend.js +1 -1
- package/dist/auth/CLAUDE.md +673 -442
- package/dist/auth/account_action_specs.d.ts +28 -7
- package/dist/auth/account_action_specs.d.ts.map +1 -1
- package/dist/auth/account_action_specs.js +7 -7
- package/dist/auth/account_actions.d.ts +8 -14
- package/dist/auth/account_actions.d.ts.map +1 -1
- package/dist/auth/account_actions.js +26 -32
- package/dist/auth/account_queries.d.ts +46 -13
- package/dist/auth/account_queries.d.ts.map +1 -1
- package/dist/auth/account_queries.js +73 -33
- package/dist/auth/account_routes.d.ts +4 -3
- package/dist/auth/account_routes.d.ts.map +1 -1
- package/dist/auth/account_routes.js +58 -33
- package/dist/auth/account_schema.d.ts +46 -54
- package/dist/auth/account_schema.d.ts.map +1 -1
- package/dist/auth/account_schema.js +21 -48
- package/dist/auth/admin_action_specs.d.ts +55 -21
- package/dist/auth/admin_action_specs.d.ts.map +1 -1
- package/dist/auth/admin_action_specs.js +42 -26
- package/dist/auth/admin_actions.d.ts +14 -21
- package/dist/auth/admin_actions.d.ts.map +1 -1
- package/dist/auth/admin_actions.js +47 -44
- package/dist/auth/audit_emitter.d.ts +160 -0
- package/dist/auth/audit_emitter.d.ts.map +1 -0
- package/dist/auth/audit_emitter.js +83 -0
- package/dist/auth/audit_log_queries.d.ts +17 -87
- package/dist/auth/audit_log_queries.d.ts.map +1 -1
- package/dist/auth/audit_log_queries.js +17 -96
- package/dist/auth/audit_log_routes.d.ts +1 -1
- package/dist/auth/audit_log_routes.d.ts.map +1 -1
- package/dist/auth/audit_log_routes.js +7 -3
- package/dist/auth/audit_log_schema.d.ts +48 -42
- package/dist/auth/audit_log_schema.d.ts.map +1 -1
- package/dist/auth/audit_log_schema.js +56 -43
- package/dist/auth/auth_guard_resolver.d.ts +44 -0
- package/dist/auth/auth_guard_resolver.d.ts.map +1 -0
- package/dist/auth/auth_guard_resolver.js +56 -0
- package/dist/auth/bootstrap_account.d.ts +7 -7
- package/dist/auth/bootstrap_account.d.ts.map +1 -1
- package/dist/auth/bootstrap_account.js +7 -7
- package/dist/auth/bootstrap_routes.d.ts.map +1 -1
- package/dist/auth/bootstrap_routes.js +11 -10
- package/dist/auth/cleanup.d.ts +20 -26
- package/dist/auth/cleanup.d.ts.map +1 -1
- package/dist/auth/cleanup.js +33 -47
- package/dist/auth/credential_type_schema.d.ts +115 -0
- package/dist/auth/credential_type_schema.d.ts.map +1 -0
- package/dist/auth/credential_type_schema.js +127 -0
- package/dist/auth/daemon_token_middleware.d.ts +1 -1
- package/dist/auth/daemon_token_middleware.js +3 -3
- package/dist/auth/ddl.d.ts +2 -2
- package/dist/auth/ddl.d.ts.map +1 -1
- package/dist/auth/ddl.js +6 -6
- package/dist/auth/deps.d.ts +7 -32
- package/dist/auth/deps.d.ts.map +1 -1
- package/dist/auth/grant_path_schema.d.ts +117 -0
- package/dist/auth/grant_path_schema.d.ts.map +1 -0
- package/dist/auth/grant_path_schema.js +137 -0
- package/dist/auth/invite_queries.d.ts +12 -1
- package/dist/auth/invite_queries.d.ts.map +1 -1
- package/dist/auth/invite_queries.js +12 -1
- package/dist/auth/invite_schema.d.ts +1 -1
- package/dist/auth/invite_schema.d.ts.map +1 -1
- package/dist/auth/invite_schema.js +1 -1
- package/dist/auth/middleware.d.ts.map +1 -1
- package/dist/auth/middleware.js +5 -2
- package/dist/auth/migrations.d.ts +22 -7
- package/dist/auth/migrations.d.ts.map +1 -1
- package/dist/auth/migrations.js +64 -25
- package/dist/auth/request_context.d.ts +157 -170
- package/dist/auth/request_context.d.ts.map +1 -1
- package/dist/auth/request_context.js +224 -268
- package/dist/auth/{permit_offer_action_specs.d.ts → role_grant_offer_action_specs.d.ts} +130 -100
- package/dist/auth/role_grant_offer_action_specs.d.ts.map +1 -0
- package/dist/auth/role_grant_offer_action_specs.js +262 -0
- package/dist/auth/role_grant_offer_actions.d.ts +104 -0
- package/dist/auth/role_grant_offer_actions.d.ts.map +1 -0
- package/dist/auth/{permit_offer_actions.js → role_grant_offer_actions.js} +153 -140
- package/dist/auth/{permit_offer_notifications.d.ts → role_grant_offer_notifications.d.ts} +80 -70
- package/dist/auth/role_grant_offer_notifications.d.ts.map +1 -0
- package/dist/auth/role_grant_offer_notifications.js +182 -0
- package/dist/auth/{permit_offer_queries.d.ts → role_grant_offer_queries.d.ts} +64 -64
- package/dist/auth/role_grant_offer_queries.d.ts.map +1 -0
- package/dist/auth/{permit_offer_queries.js → role_grant_offer_queries.js} +136 -123
- package/dist/auth/role_grant_offer_schema.d.ts +150 -0
- package/dist/auth/role_grant_offer_schema.d.ts.map +1 -0
- package/dist/auth/{permit_offer_schema.js → role_grant_offer_schema.js} +55 -36
- package/dist/auth/role_grant_queries.d.ts +231 -0
- package/dist/auth/role_grant_queries.d.ts.map +1 -0
- package/dist/auth/role_grant_queries.js +320 -0
- package/dist/auth/role_schema.d.ts +150 -40
- package/dist/auth/role_schema.d.ts.map +1 -1
- package/dist/auth/role_schema.js +144 -45
- package/dist/auth/scope_kind_schema.d.ts +96 -0
- package/dist/auth/scope_kind_schema.d.ts.map +1 -0
- package/dist/auth/scope_kind_schema.js +94 -0
- package/dist/auth/self_service_role_action_specs.d.ts +4 -1
- package/dist/auth/self_service_role_action_specs.d.ts.map +1 -1
- package/dist/auth/self_service_role_action_specs.js +2 -2
- package/dist/auth/self_service_role_actions.d.ts +35 -29
- package/dist/auth/self_service_role_actions.d.ts.map +1 -1
- package/dist/auth/self_service_role_actions.js +58 -48
- package/dist/auth/session_cookie.d.ts +43 -6
- package/dist/auth/session_cookie.d.ts.map +1 -1
- package/dist/auth/session_cookie.js +31 -5
- package/dist/auth/session_middleware.d.ts +37 -3
- package/dist/auth/session_middleware.d.ts.map +1 -1
- package/dist/auth/session_middleware.js +33 -7
- package/dist/auth/signup_routes.d.ts.map +1 -1
- package/dist/auth/signup_routes.js +48 -19
- package/dist/auth/standard_action_specs.d.ts +2 -2
- package/dist/auth/standard_action_specs.js +4 -4
- package/dist/auth/standard_rpc_actions.d.ts +23 -19
- package/dist/auth/standard_rpc_actions.d.ts.map +1 -1
- package/dist/auth/standard_rpc_actions.js +12 -12
- package/dist/db/migrate.d.ts +1 -1
- package/dist/db/migrate.js +1 -1
- package/dist/dev/setup.d.ts +2 -2
- package/dist/dev/setup.d.ts.map +1 -1
- package/dist/dev/setup.js +4 -4
- package/dist/env/load.d.ts +1 -1
- package/dist/env/load.js +1 -1
- package/dist/hono_context.d.ts +27 -45
- package/dist/hono_context.d.ts.map +1 -1
- package/dist/hono_context.js +14 -28
- package/dist/http/CLAUDE.md +235 -121
- package/dist/http/auth_shape.d.ts +191 -0
- package/dist/http/auth_shape.d.ts.map +1 -0
- package/dist/http/auth_shape.js +237 -0
- package/dist/http/common_routes.js +3 -3
- package/dist/http/db_routes.d.ts +4 -0
- package/dist/http/db_routes.d.ts.map +1 -1
- package/dist/http/db_routes.js +44 -7
- package/dist/http/error_schemas.d.ts +72 -39
- package/dist/http/error_schemas.d.ts.map +1 -1
- package/dist/http/error_schemas.js +81 -33
- package/dist/http/pending_effects.d.ts +71 -18
- package/dist/http/pending_effects.d.ts.map +1 -1
- package/dist/http/pending_effects.js +87 -18
- package/dist/http/proxy.d.ts +52 -5
- package/dist/http/proxy.d.ts.map +1 -1
- package/dist/http/proxy.js +92 -14
- package/dist/http/route_spec.d.ts +89 -75
- package/dist/http/route_spec.d.ts.map +1 -1
- package/dist/http/route_spec.js +54 -72
- package/dist/http/schema_helpers.d.ts +3 -14
- package/dist/http/schema_helpers.d.ts.map +1 -1
- package/dist/http/schema_helpers.js +2 -14
- package/dist/http/surface.d.ts +2 -10
- package/dist/http/surface.d.ts.map +1 -1
- package/dist/http/surface.js +3 -4
- package/dist/http/surface_query.d.ts +39 -35
- package/dist/http/surface_query.d.ts.map +1 -1
- package/dist/http/surface_query.js +79 -36
- package/dist/primitive_schemas.d.ts +39 -0
- package/dist/primitive_schemas.d.ts.map +1 -0
- package/dist/primitive_schemas.js +40 -0
- package/dist/realtime/sse_auth_guard.d.ts +5 -5
- package/dist/realtime/sse_auth_guard.js +9 -9
- package/dist/runtime/mock.d.ts +1 -1
- package/dist/runtime/mock.js +1 -1
- package/dist/server/app_backend.d.ts +14 -11
- package/dist/server/app_backend.d.ts.map +1 -1
- package/dist/server/app_backend.js +12 -8
- package/dist/server/app_server.d.ts +7 -7
- package/dist/server/app_server.d.ts.map +1 -1
- package/dist/server/app_server.js +35 -40
- package/dist/server/validate_nginx.d.ts +1 -1
- package/dist/server/validate_nginx.js +1 -1
- package/dist/testing/CLAUDE.md +50 -38
- package/dist/testing/admin_integration.d.ts +5 -6
- package/dist/testing/admin_integration.d.ts.map +1 -1
- package/dist/testing/admin_integration.js +87 -85
- package/dist/testing/app_server.d.ts +11 -14
- package/dist/testing/app_server.d.ts.map +1 -1
- package/dist/testing/app_server.js +16 -15
- package/dist/testing/assertions.d.ts.map +1 -1
- package/dist/testing/assertions.js +2 -1
- package/dist/testing/attack_surface.d.ts.map +1 -1
- package/dist/testing/attack_surface.js +15 -9
- package/dist/testing/audit_completeness.d.ts +2 -2
- package/dist/testing/audit_completeness.d.ts.map +1 -1
- package/dist/testing/audit_completeness.js +36 -36
- package/dist/testing/auth_apps.d.ts +5 -4
- package/dist/testing/auth_apps.d.ts.map +1 -1
- package/dist/testing/auth_apps.js +22 -19
- package/dist/testing/data_exposure.d.ts.map +1 -1
- package/dist/testing/data_exposure.js +5 -5
- package/dist/testing/db.d.ts +1 -1
- package/dist/testing/db.d.ts.map +1 -1
- package/dist/testing/db.js +4 -4
- package/dist/testing/db_entities.d.ts +22 -0
- package/dist/testing/db_entities.d.ts.map +1 -0
- package/dist/testing/db_entities.js +28 -0
- package/dist/testing/entities.d.ts +8 -7
- package/dist/testing/entities.d.ts.map +1 -1
- package/dist/testing/entities.js +21 -18
- package/dist/testing/integration.d.ts.map +1 -1
- package/dist/testing/integration.js +13 -14
- package/dist/testing/integration_helpers.d.ts +4 -4
- package/dist/testing/integration_helpers.d.ts.map +1 -1
- package/dist/testing/integration_helpers.js +20 -18
- package/dist/testing/middleware.d.ts +4 -4
- package/dist/testing/middleware.d.ts.map +1 -1
- package/dist/testing/middleware.js +12 -11
- package/dist/testing/rpc_attack_surface.d.ts.map +1 -1
- package/dist/testing/rpc_attack_surface.js +40 -24
- package/dist/testing/rpc_round_trip.d.ts +1 -1
- package/dist/testing/rpc_round_trip.d.ts.map +1 -1
- package/dist/testing/rpc_round_trip.js +14 -13
- package/dist/testing/sse_round_trip.d.ts +3 -4
- package/dist/testing/sse_round_trip.d.ts.map +1 -1
- package/dist/testing/sse_round_trip.js +7 -11
- package/dist/testing/standard.d.ts +1 -1
- package/dist/testing/stubs.d.ts +25 -0
- package/dist/testing/stubs.d.ts.map +1 -1
- package/dist/testing/stubs.js +43 -2
- package/dist/testing/surface_invariants.d.ts +14 -6
- package/dist/testing/surface_invariants.d.ts.map +1 -1
- package/dist/testing/surface_invariants.js +119 -43
- package/dist/testing/ws_round_trip.d.ts +12 -13
- package/dist/testing/ws_round_trip.d.ts.map +1 -1
- package/dist/testing/ws_round_trip.js +19 -11
- package/dist/ui/AdminAccounts.svelte +23 -20
- package/dist/ui/AdminOverview.svelte +15 -13
- package/dist/ui/AdminOverview.svelte.d.ts.map +1 -1
- package/dist/ui/{AdminPermitHistory.svelte → AdminRoleGrantHistory.svelte} +12 -12
- package/dist/ui/AdminRoleGrantHistory.svelte.d.ts +4 -0
- package/dist/ui/AdminRoleGrantHistory.svelte.d.ts.map +1 -0
- package/dist/ui/BootstrapForm.svelte +1 -1
- package/dist/ui/CLAUDE.md +60 -60
- package/dist/ui/{PermitOfferForm.svelte → RoleGrantOfferForm.svelte} +27 -26
- package/dist/ui/{PermitOfferForm.svelte.d.ts → RoleGrantOfferForm.svelte.d.ts} +7 -7
- package/dist/ui/RoleGrantOfferForm.svelte.d.ts.map +1 -0
- package/dist/ui/{PermitOfferHistory.svelte → RoleGrantOfferHistory.svelte} +12 -12
- package/dist/ui/{PermitOfferHistory.svelte.d.ts → RoleGrantOfferHistory.svelte.d.ts} +4 -4
- package/dist/ui/RoleGrantOfferHistory.svelte.d.ts.map +1 -0
- package/dist/ui/{PermitOfferInbox.svelte → RoleGrantOfferInbox.svelte} +14 -14
- package/dist/ui/{PermitOfferInbox.svelte.d.ts → RoleGrantOfferInbox.svelte.d.ts} +4 -4
- package/dist/ui/RoleGrantOfferInbox.svelte.d.ts.map +1 -0
- package/dist/ui/SignupForm.svelte +1 -1
- package/dist/ui/SurfaceExplorer.svelte +35 -15
- package/dist/ui/SurfaceExplorer.svelte.d.ts.map +1 -1
- package/dist/ui/account_sessions_state.svelte.d.ts +2 -3
- package/dist/ui/account_sessions_state.svelte.d.ts.map +1 -1
- package/dist/ui/account_sessions_state.svelte.js +2 -3
- package/dist/ui/admin_accounts_state.svelte.d.ts +18 -18
- package/dist/ui/admin_accounts_state.svelte.d.ts.map +1 -1
- package/dist/ui/admin_accounts_state.svelte.js +16 -16
- package/dist/ui/admin_rpc_adapters.d.ts +20 -20
- package/dist/ui/admin_rpc_adapters.d.ts.map +1 -1
- package/dist/ui/admin_rpc_adapters.js +17 -17
- package/dist/ui/admin_sessions_state.svelte.d.ts +2 -2
- package/dist/ui/admin_sessions_state.svelte.js +2 -2
- package/dist/ui/audit_log_state.svelte.d.ts +7 -7
- package/dist/ui/audit_log_state.svelte.d.ts.map +1 -1
- package/dist/ui/audit_log_state.svelte.js +6 -6
- package/dist/ui/auth_state.svelte.d.ts +3 -3
- package/dist/ui/auth_state.svelte.d.ts.map +1 -1
- package/dist/ui/auth_state.svelte.js +6 -6
- package/dist/ui/format_scope.d.ts +2 -2
- package/dist/ui/format_scope.js +2 -2
- package/dist/ui/{permit_offers_state.svelte.d.ts → role_grant_offers_state.svelte.d.ts} +30 -30
- package/dist/ui/role_grant_offers_state.svelte.d.ts.map +1 -0
- package/dist/ui/{permit_offers_state.svelte.js → role_grant_offers_state.svelte.js} +18 -18
- package/dist/ui/ui_format.js +2 -2
- package/package.json +3 -3
- package/dist/auth/permit_offer_action_specs.d.ts.map +0 -1
- package/dist/auth/permit_offer_action_specs.js +0 -258
- package/dist/auth/permit_offer_actions.d.ts +0 -110
- package/dist/auth/permit_offer_actions.d.ts.map +0 -1
- package/dist/auth/permit_offer_notifications.d.ts.map +0 -1
- package/dist/auth/permit_offer_notifications.js +0 -182
- package/dist/auth/permit_offer_queries.d.ts.map +0 -1
- package/dist/auth/permit_offer_schema.d.ts +0 -125
- package/dist/auth/permit_offer_schema.d.ts.map +0 -1
- package/dist/auth/permit_queries.d.ts +0 -222
- package/dist/auth/permit_queries.d.ts.map +0 -1
- package/dist/auth/permit_queries.js +0 -305
- package/dist/auth/require_keeper.d.ts +0 -20
- package/dist/auth/require_keeper.d.ts.map +0 -1
- package/dist/auth/require_keeper.js +0 -35
- package/dist/auth/route_guards.d.ts +0 -27
- package/dist/auth/route_guards.d.ts.map +0 -1
- package/dist/auth/route_guards.js +0 -38
- package/dist/auth/session_lifecycle.d.ts +0 -37
- package/dist/auth/session_lifecycle.d.ts.map +0 -1
- package/dist/auth/session_lifecycle.js +0 -29
- package/dist/ui/AdminPermitHistory.svelte.d.ts +0 -4
- package/dist/ui/AdminPermitHistory.svelte.d.ts.map +0 -1
- package/dist/ui/PermitOfferForm.svelte.d.ts.map +0 -1
- package/dist/ui/PermitOfferHistory.svelte.d.ts.map +0 -1
- package/dist/ui/PermitOfferInbox.svelte.d.ts.map +0 -1
- package/dist/ui/permit_offers_state.svelte.d.ts.map +0 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
/**
|
|
3
|
-
* Admin accounts table — users with their
|
|
3
|
+
* Admin accounts table — users with their role_grants and pending offers.
|
|
4
4
|
* Consumes `admin_accounts_rpc_context` (read via `AdminAccountsState`)
|
|
5
5
|
* and `format_scope_context` for label rendering. Per-row actions:
|
|
6
|
-
* grant role (`
|
|
7
|
-
* keyed by `actor_id`), retract pending offer (`
|
|
6
|
+
* grant role (`role_grant_offer_create`), revoke role_grant (`role_grant_revoke`,
|
|
7
|
+
* keyed by `actor_id`), retract pending offer (`role_grant_offer_retract`).
|
|
8
8
|
*
|
|
9
9
|
* @module
|
|
10
10
|
*/
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
const get_format_scope = format_scope_context.get();
|
|
23
23
|
const format_scope = $derived(get_format_scope());
|
|
24
24
|
|
|
25
|
-
// `null` global label: global
|
|
25
|
+
// `null` global label: global role_grants render no scope chip — the implicit default in admin tables.
|
|
26
26
|
const scope_label = (scope_id: string | null, role: string): string | null =>
|
|
27
27
|
resolve_scope_label(scope_id, role, format_scope, null);
|
|
28
28
|
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
|
|
31
31
|
const columns: Array<DatatableColumn<AdminAccountEntryJson>> = [
|
|
32
32
|
{key: 'account', label: 'username', width: 180},
|
|
33
|
-
{key: '
|
|
33
|
+
{key: 'role_grants', label: 'role_grants', width: 240},
|
|
34
34
|
{key: 'actor', label: 'grant', width: 200},
|
|
35
35
|
];
|
|
36
36
|
</script>
|
|
@@ -72,31 +72,34 @@
|
|
|
72
72
|
updated {format_relative_time(row.account.updated_at)}
|
|
73
73
|
</div>
|
|
74
74
|
{/if}
|
|
75
|
-
{:else if column.key === '
|
|
76
|
-
{#each row.
|
|
77
|
-
{@const scope = scope_label(
|
|
75
|
+
{:else if column.key === 'role_grants'}
|
|
76
|
+
{#each row.role_grants as role_grant (role_grant.id)}
|
|
77
|
+
{@const scope = scope_label(role_grant.scope_id, role_grant.role)}
|
|
78
78
|
<div class="row">
|
|
79
|
-
<span class="chip color_b">{
|
|
79
|
+
<span class="chip color_b">{role_grant.role}</span>
|
|
80
80
|
{#if scope !== null}
|
|
81
|
-
<span class="text_50 font_size_sm" title={
|
|
81
|
+
<span class="text_50 font_size_sm" title={role_grant.scope_id ?? undefined}>
|
|
82
82
|
{scope}
|
|
83
83
|
</span>
|
|
84
84
|
{/if}
|
|
85
|
-
{#if
|
|
86
|
-
<span
|
|
87
|
-
|
|
85
|
+
{#if role_grant.expires_at}
|
|
86
|
+
<span
|
|
87
|
+
class="text_50 font_size_sm"
|
|
88
|
+
title={format_datetime_local(role_grant.expires_at)}
|
|
89
|
+
>
|
|
90
|
+
expires {format_relative_time(role_grant.expires_at)}
|
|
88
91
|
</span>
|
|
89
92
|
{/if}
|
|
90
93
|
{#if admin_accounts.has_rpc && row.actor}
|
|
91
94
|
{@const actor_id = row.actor.id}
|
|
92
95
|
<ConfirmButton
|
|
93
|
-
onconfirm={() => admin_accounts.
|
|
94
|
-
title="revoke {
|
|
96
|
+
onconfirm={() => admin_accounts.revoke_role_grant(actor_id, role_grant.id)}
|
|
97
|
+
title="revoke {role_grant.role}"
|
|
95
98
|
class="sm"
|
|
96
|
-
disabled={admin_accounts.revoking_ids.has(
|
|
99
|
+
disabled={admin_accounts.revoking_ids.has(role_grant.id)}
|
|
97
100
|
>
|
|
98
101
|
{#snippet children(_popover, _confirm)}
|
|
99
|
-
{admin_accounts.revoking_ids.has(
|
|
102
|
+
{admin_accounts.revoking_ids.has(role_grant.id) ? 'revoking…' : 'revoke'}
|
|
100
103
|
{/snippet}
|
|
101
104
|
</ConfirmButton>
|
|
102
105
|
{/if}
|
|
@@ -130,15 +133,15 @@
|
|
|
130
133
|
{/if}
|
|
131
134
|
</div>
|
|
132
135
|
{/each}
|
|
133
|
-
{#if row.
|
|
136
|
+
{#if row.role_grants.length === 0 && row.pending_offers.length === 0}
|
|
134
137
|
<span class="text_50">none</span>
|
|
135
138
|
{/if}
|
|
136
139
|
{:else if column.key === 'actor'}
|
|
137
140
|
{#if admin_accounts.has_rpc}
|
|
138
141
|
{#each admin_accounts.grantable_roles as role (role)}
|
|
139
|
-
{#if !row.
|
|
142
|
+
{#if !row.role_grants.some((p) => p.role === role) && !row.pending_offers.some((o) => o.role === role)}
|
|
140
143
|
<ConfirmButton
|
|
141
|
-
onconfirm={() => admin_accounts.
|
|
144
|
+
onconfirm={() => admin_accounts.create_role_grant(row.account.id, role)}
|
|
142
145
|
title="offer {role}"
|
|
143
146
|
class="sm"
|
|
144
147
|
disabled={admin_accounts.granting_keys.has(`${row.account.id}:${role}`)}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Admin dashboard — six summary panels (accounts, sessions, invites,
|
|
4
4
|
* recent activity, security, system) fed by parallel `fetch()` calls
|
|
5
5
|
* on mount. Consumes all four admin RPC contexts plus `auth_state_context`;
|
|
6
|
-
* derives `role_counts`, `failed_logins`, and `
|
|
6
|
+
* derives `role_counts`, `failed_logins`, and `role_grant_changes` from the
|
|
7
7
|
* audit log slice.
|
|
8
8
|
*
|
|
9
9
|
* @module
|
|
@@ -39,14 +39,16 @@
|
|
|
39
39
|
// eslint-disable-next-line svelte/prefer-svelte-reactivity
|
|
40
40
|
const counts = new Map<string, number>();
|
|
41
41
|
for (const entry of accounts.accounts) {
|
|
42
|
-
const roles = new Set(entry.
|
|
42
|
+
const roles = new Set(entry.role_grants.map((p) => p.role));
|
|
43
43
|
for (const role of roles) {
|
|
44
44
|
counts.set(role, (counts.get(role) || 0) + 1);
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
return Array.from(counts.entries());
|
|
48
48
|
});
|
|
49
|
-
const unroled_count = $derived(
|
|
49
|
+
const unroled_count = $derived(
|
|
50
|
+
accounts.accounts.filter((a) => a.role_grants.length === 0).length,
|
|
51
|
+
);
|
|
50
52
|
|
|
51
53
|
// sessions
|
|
52
54
|
const unique_users = $derived(new Set(sessions.sessions.map((s) => s.username)).size);
|
|
@@ -63,9 +65,9 @@
|
|
|
63
65
|
const failed_logins = $derived(
|
|
64
66
|
audit_log.events.filter((e) => e.event_type === 'login' && e.outcome === 'failure'),
|
|
65
67
|
);
|
|
66
|
-
const
|
|
68
|
+
const role_grant_changes = $derived(
|
|
67
69
|
audit_log.events.filter(
|
|
68
|
-
(e) => e.event_type === '
|
|
70
|
+
(e) => e.event_type === 'role_grant_create' || e.event_type === 'role_grant_revoke',
|
|
69
71
|
),
|
|
70
72
|
);
|
|
71
73
|
|
|
@@ -108,10 +110,10 @@
|
|
|
108
110
|
{#each accounts.accounts.slice(0, 6) as entry (entry)}
|
|
109
111
|
<li>
|
|
110
112
|
<strong>{entry.account.username}</strong>
|
|
111
|
-
{#each entry.
|
|
112
|
-
<span class="chip font_size_sm">{
|
|
113
|
+
{#each entry.role_grants as role_grant (role_grant.id)}
|
|
114
|
+
<span class="chip font_size_sm">{role_grant.role}</span>
|
|
113
115
|
{/each}
|
|
114
|
-
{#if entry.
|
|
116
|
+
{#if entry.role_grants.length === 0}
|
|
115
117
|
<span class="text_50 font_size_sm">no roles</span>
|
|
116
118
|
{/if}
|
|
117
119
|
</li>
|
|
@@ -244,17 +246,17 @@
|
|
|
244
246
|
<span class="text_50">failed logins</span>
|
|
245
247
|
</div>
|
|
246
248
|
<div class="baseline-row gap_xs">
|
|
247
|
-
<strong class="font_size_lg">{
|
|
248
|
-
<span class="text_50">
|
|
249
|
+
<strong class="font_size_lg">{role_grant_changes.length}</strong>
|
|
250
|
+
<span class="text_50">role_grant changes</span>
|
|
249
251
|
</div>
|
|
250
|
-
{#if
|
|
252
|
+
{#if role_grant_changes.length > 0}
|
|
251
253
|
<ul class="compact-list">
|
|
252
|
-
{#each
|
|
254
|
+
{#each role_grant_changes.slice(0, 4) as event (event.id)}
|
|
253
255
|
<li class="font_size_sm">
|
|
254
256
|
<span class="text_50" title={format_datetime_local(event.created_at)}
|
|
255
257
|
>{format_relative_time(event.created_at)}</span
|
|
256
258
|
>
|
|
257
|
-
<code>{event.event_type === '
|
|
259
|
+
<code>{event.event_type === 'role_grant_create' ? 'grant' : 'revoke'}</code>
|
|
258
260
|
{#if event.metadata?.role}
|
|
259
261
|
<span class="chip font_size_sm">{event.metadata.role}</span>
|
|
260
262
|
{/if}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdminOverview.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/ui/AdminOverview.svelte"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"AdminOverview.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/ui/AdminOverview.svelte"],"names":[],"mappings":"AA4UA,QAAA,MAAM,aAAa,2DAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
* calls `audit_log.
|
|
5
|
-
* `
|
|
3
|
+
* Role grant create/revoke history table. Consumes `audit_log_rpc_context`,
|
|
4
|
+
* calls `audit_log.fetch_role_grant_history()` once on mount (the
|
|
5
|
+
* `audit_log_role_grant_history` RPC). Uses `format_scope_context` to render
|
|
6
6
|
* scope ids as human labels.
|
|
7
7
|
*
|
|
8
8
|
* @module
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
import {format_relative_time, format_datetime_local, truncate_uuid} from './ui_format.js';
|
|
13
13
|
import Datatable from './Datatable.svelte';
|
|
14
14
|
import type {DatatableColumn} from './datatable.js';
|
|
15
|
-
import type {
|
|
15
|
+
import type {RoleGrantHistoryEventJson} from '../auth/audit_log_schema.js';
|
|
16
16
|
import {format_scope_context, resolve_scope_label} from './format_scope.js';
|
|
17
17
|
|
|
18
18
|
const get_rpc = audit_log_rpc_context.get();
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
const get_format_scope = format_scope_context.get();
|
|
21
21
|
const format_scope = $derived(get_format_scope());
|
|
22
22
|
|
|
23
|
-
void audit_log.
|
|
23
|
+
void audit_log.fetch_role_grant_history();
|
|
24
24
|
|
|
25
|
-
const columns: Array<DatatableColumn<
|
|
25
|
+
const columns: Array<DatatableColumn<RoleGrantHistoryEventJson>> = [
|
|
26
26
|
{key: 'event_type', label: 'action', width: 100},
|
|
27
27
|
{key: 'metadata', label: 'role', width: 160},
|
|
28
28
|
{key: 'username', label: 'by', width: 140},
|
|
@@ -38,22 +38,22 @@
|
|
|
38
38
|
</script>
|
|
39
39
|
|
|
40
40
|
<section>
|
|
41
|
-
<h1>
|
|
41
|
+
<h1>role_grant history</h1>
|
|
42
42
|
|
|
43
43
|
{#if audit_log.loading}
|
|
44
|
-
<p class="text_50">loading
|
|
44
|
+
<p class="text_50">loading role_grant history...</p>
|
|
45
45
|
{:else if audit_log.error}
|
|
46
46
|
<p class="color_c_50">{audit_log.error}</p>
|
|
47
47
|
{:else}
|
|
48
|
-
<Datatable {columns} rows={audit_log.
|
|
48
|
+
<Datatable {columns} rows={audit_log.role_grant_history_events} height="400px" row_key="id">
|
|
49
49
|
{#snippet cell(column, row)}
|
|
50
50
|
{#if column.key === 'event_type'}
|
|
51
51
|
<span
|
|
52
52
|
class="chip"
|
|
53
|
-
class:color_b={row.event_type === '
|
|
54
|
-
class:color_c={row.event_type === '
|
|
53
|
+
class:color_b={row.event_type === 'role_grant_create'}
|
|
54
|
+
class:color_c={row.event_type === 'role_grant_revoke'}
|
|
55
55
|
>
|
|
56
|
-
{row.event_type === '
|
|
56
|
+
{row.event_type === 'role_grant_create' ? 'grant' : 'revoke'}
|
|
57
57
|
</span>
|
|
58
58
|
{:else if column.key === 'metadata'}
|
|
59
59
|
{#if row.metadata}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminRoleGrantHistory.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/ui/AdminRoleGrantHistory.svelte"],"names":[],"mappings":"AAiGA,QAAA,MAAM,qBAAqB,2DAAwC,CAAC;AACpE,KAAK,qBAAqB,GAAG,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC;AACtE,eAAe,qBAAqB,CAAC"}
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
import PendingButton from '@fuzdev/fuz_ui/PendingButton.svelte';
|
|
18
18
|
import {autofocus} from '@fuzdev/fuz_ui/autofocus.svelte.js';
|
|
19
19
|
|
|
20
|
-
import {Username} from '../
|
|
20
|
+
import {Username} from '../primitive_schemas.js';
|
|
21
21
|
import {PASSWORD_LENGTH_MIN} from '../auth/password.js';
|
|
22
22
|
import {auth_state_context} from './auth_state.svelte.js';
|
|
23
23
|
import {FormState} from './form_state.svelte.js';
|
package/dist/ui/CLAUDE.md
CHANGED
|
@@ -7,7 +7,7 @@ hold `$state` fields exclusively via runes. Shared dependencies flow
|
|
|
7
7
|
through Svelte context, never through props — RPC adapters in particular
|
|
8
8
|
are provisioned once at the admin shell and read by every `Admin*.svelte`.
|
|
9
9
|
|
|
10
|
-
See ../../docs/usage.md for end-to-end wiring examples (sections "
|
|
10
|
+
See ../../docs/usage.md for end-to-end wiring examples (sections "Role grant
|
|
11
11
|
offer UI" and "Admin UI"). This file is a reference, not a tutorial.
|
|
12
12
|
|
|
13
13
|
## Key patterns
|
|
@@ -19,8 +19,8 @@ Five narrow RPC adapter contexts — `admin_accounts_rpc_context`,
|
|
|
19
19
|
`app_settings_rpc_context`, `account_sessions_rpc_context` — carry a
|
|
20
20
|
reactive `() => Rpc | null` accessor. All five declare a `() => () => null`
|
|
21
21
|
default so components mounted without a provisioner render the "rpc adapter
|
|
22
|
-
not wired" state instead of crashing. (`
|
|
23
|
-
a `
|
|
22
|
+
not wired" state instead of crashing. (`role_grant_offers_state_context` carries
|
|
23
|
+
a `RoleGrantOffersState` directly, not an RPC accessor, and isn't counted
|
|
24
24
|
here.) The standard consumer shape:
|
|
25
25
|
|
|
26
26
|
```ts
|
|
@@ -43,14 +43,13 @@ context — RPC adapters are never threaded through props.
|
|
|
43
43
|
|
|
44
44
|
Every state class backed by a narrow RPC interface exposes a `has_rpc`
|
|
45
45
|
getter. When `false`, `fetch()`, mutations, and `subscribe` no-op and
|
|
46
|
-
set `error` to `'rpc adapter not wired'`.
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
surface.
|
|
46
|
+
set `error` to `'rpc adapter not wired'`. `AdminSessionsState`'s listing
|
|
47
|
+
plus mutations all run through the shared `AdminAccountsRpc`, so
|
|
48
|
+
`has_rpc` gates the whole surface.
|
|
50
49
|
|
|
51
50
|
### `$state.raw` Map keyed by id + `$derived` views
|
|
52
51
|
|
|
53
|
-
`
|
|
52
|
+
`RoleGrantOffersState` maintains a single `Map<string, RoleGrantOfferJson>` in
|
|
54
53
|
`$state.raw`, keyed by offer id, and exposes `incoming` / `outgoing` /
|
|
55
54
|
`history` as `$derived.by` arrays. Writes go through `#merge_offers`
|
|
56
55
|
(clone-and-replace) / `#remove_offer` — never mutate the Map in place
|
|
@@ -58,13 +57,13 @@ because `$state.raw` expects reference swaps.
|
|
|
58
57
|
|
|
59
58
|
### Reducer pattern for WS notifications
|
|
60
59
|
|
|
61
|
-
`
|
|
60
|
+
`RoleGrantOffersState.apply_notification(notification)` is the single
|
|
62
61
|
reducer — `subscribe(subscribe_fn)` is a thin subscription adapter over
|
|
63
|
-
it. Six methods land on the reducer: `
|
|
62
|
+
it. Six methods land on the reducer: `role_grant_offer_received` /
|
|
64
63
|
`_retracted` / `_accepted` / `_declined` / `_supersede` all merge a
|
|
65
|
-
`{offer}` payload; `
|
|
66
|
-
lifecycle lives in auth/
|
|
67
|
-
their payload shapes are defined in `../auth/
|
|
64
|
+
`{offer}` payload; `role_grant_revoke` is ignored at this layer (role_grant
|
|
65
|
+
lifecycle lives in auth/role_grants state). The six notification specs and
|
|
66
|
+
their payload shapes are defined in `../auth/role_grant_offer_notifications.ts`
|
|
68
67
|
(see `../auth/CLAUDE.md` §WS notifications).
|
|
69
68
|
|
|
70
69
|
### Svelte 5 inline `$props` shape
|
|
@@ -76,7 +75,7 @@ conventions.
|
|
|
76
75
|
|
|
77
76
|
### Context over props for shared deps
|
|
78
77
|
|
|
79
|
-
Auth, RPC adapters, sidebar, and
|
|
78
|
+
Auth, RPC adapters, sidebar, and role_grant offers all flow through
|
|
80
79
|
`create_context` from `@fuzdev/fuz_ui/context_helpers.js`. Components
|
|
81
80
|
consume with `const x = x_context.get()` (or a `get_rpc`/`$derived`
|
|
82
81
|
pair when the value may change reactively). New shared state joins the
|
|
@@ -126,9 +125,9 @@ Every admin component below consumes its RPC adapter via the matching
|
|
|
126
125
|
context and delegates rendering to `Datatable` + `ConfirmButton` for
|
|
127
126
|
destructive actions.
|
|
128
127
|
|
|
129
|
-
- `AdminAccounts.svelte` — accounts +
|
|
128
|
+
- `AdminAccounts.svelte` — accounts + role_grants + pending offers.
|
|
130
129
|
Consumes `admin_accounts_rpc_context`. Per-row actions: grant (+role
|
|
131
|
-
chip with `ConfirmButton`), revoke (`actor_id` + `
|
|
130
|
+
chip with `ConfirmButton`), revoke (`actor_id` + `role_grant_id`),
|
|
132
131
|
retract pending offer. Tracks `granting_keys` / `revoking_ids` /
|
|
133
132
|
`retracting_ids` for per-action spinners.
|
|
134
133
|
- `AdminAuditLog.svelte` — audit event stream. Consumes
|
|
@@ -140,11 +139,11 @@ destructive actions.
|
|
|
140
139
|
- `AdminOverview.svelte` — dashboard panels (accounts / sessions /
|
|
141
140
|
invites / recent activity / security / system). Consumes all four
|
|
142
141
|
RPC contexts plus `auth_state_context`; fetches in parallel on mount.
|
|
143
|
-
Derives `role_counts`, `failed_logins`, `
|
|
142
|
+
Derives `role_counts`, `failed_logins`, `role_grant_changes` from
|
|
144
143
|
the audit log.
|
|
145
|
-
- `
|
|
144
|
+
- `AdminRoleGrantHistory.svelte` — role-grant-create/revoke history table.
|
|
146
145
|
Consumes `audit_log_rpc_context`, calls
|
|
147
|
-
`audit_log.
|
|
146
|
+
`audit_log.fetch_role_grant_history()` once on mount.
|
|
148
147
|
- `AdminSessions.svelte` — cross-account active sessions.
|
|
149
148
|
Both listing (`admin_session_list` RPC) and the two revoke-all
|
|
150
149
|
mutations go through `admin_accounts_rpc_context` (reused).
|
|
@@ -161,41 +160,42 @@ destructive actions.
|
|
|
161
160
|
dump `params`/`query`/`input`/`output`/`errors` schemas as JSON.
|
|
162
161
|
Also tables middleware, env, events, and diagnostics.
|
|
163
162
|
|
|
164
|
-
##
|
|
163
|
+
## Role grant offers
|
|
165
164
|
|
|
166
|
-
- `
|
|
167
|
-
`
|
|
165
|
+
- `RoleGrantOfferInbox.svelte` — recipient-side pending inbox; renders
|
|
166
|
+
`RoleGrantOffersState.incoming`. Props: `format_actor?`, `format_scope?`,
|
|
168
167
|
`format_role?` — consumers plug in display names for actor/scope ids.
|
|
169
168
|
Accept is a `PendingButton`; decline is a `ConfirmButton` whose
|
|
170
|
-
popover contains a textarea (max `
|
|
171
|
-
- `
|
|
169
|
+
popover contains a textarea (max `ROLE_GRANT_OFFER_MESSAGE_LENGTH_MAX`).
|
|
170
|
+
- `RoleGrantOfferForm.svelte` — grantor-side create form. Props:
|
|
172
171
|
`to_account_id`, `to_actor_id = null` (optional — narrows the offer
|
|
173
172
|
to a specific actor on the recipient account; default account-grain),
|
|
174
|
-
`roles: Array<string>` (pre-filtered upstream by
|
|
173
|
+
`roles: Array<string>` (pre-filtered upstream by admin-grant-path —
|
|
174
|
+
`RoleSpec.grant_paths` includes `'admin'`),
|
|
175
175
|
`scope_id = null`, `on_created?`, `format_role?`. Surfaces five
|
|
176
|
-
reason codes with friendly copy: `
|
|
177
|
-
`
|
|
178
|
-
`
|
|
179
|
-
— imported from `../auth/
|
|
180
|
-
`../auth/CLAUDE.md` for `
|
|
181
|
-
`
|
|
182
|
-
- `
|
|
176
|
+
reason codes with friendly copy: `ERROR_ROLE_GRANT_OFFER_SELF_TARGET`,
|
|
177
|
+
`ERROR_ROLE_GRANT_OFFER_ROLE_NOT_GRANTABLE`, `ERROR_ROLE_GRANT_OFFER_NOT_AUTHORIZED`,
|
|
178
|
+
`ERROR_ROLE_GRANT_OFFER_ACTOR_ACCOUNT_MISMATCH`, `ERROR_ROLE_GRANT_OFFER_ACTOR_MISMATCH`
|
|
179
|
+
— imported from `../auth/role_grant_offer_action_specs.js` (see
|
|
180
|
+
`../auth/CLAUDE.md` for `role_grant_offer_action_specs.ts` +
|
|
181
|
+
`role_grant_offer_actions.ts`).
|
|
182
|
+
- `RoleGrantOfferHistory.svelte` — both-directions history (recipient +
|
|
183
183
|
grantor, including terminal). Props: `current_actor_id: string | null`
|
|
184
184
|
(classifies row as "sent" vs "received"), `format_actor?`,
|
|
185
185
|
`format_scope?`, `format_role?`. Consumes
|
|
186
|
-
`
|
|
187
|
-
`
|
|
188
|
-
- `
|
|
189
|
-
`Loadable`) + `
|
|
190
|
-
`rpc:
|
|
191
|
-
`actor_id: () => string | null`. The narrow `
|
|
186
|
+
`role_grant_offers_state_context`; caller seeds via
|
|
187
|
+
`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
192
|
interface has six methods: `list`, `history`, `create`, `accept`,
|
|
193
193
|
`decline`, `retract`. `$state.raw` Map keyed by offer id;
|
|
194
194
|
`$derived.by` views: `incoming` (recipient-side pending, soonest-
|
|
195
195
|
expiry first), `outgoing` (grantor-side pending, newest-created
|
|
196
196
|
first), `history` (all known, newest-created first). Reducer
|
|
197
|
-
`apply_notification` handles the six
|
|
198
|
-
methods; `
|
|
197
|
+
`apply_notification` handles the six role-grant-offer notification
|
|
198
|
+
methods; `role_grant_revoke` is deliberately ignored here (auth/role_grants
|
|
199
199
|
concern). `reset()` clears the Map.
|
|
200
200
|
|
|
201
201
|
## State primitives
|
|
@@ -209,8 +209,8 @@ destructive actions.
|
|
|
209
209
|
- `auth_state.svelte.ts` — `AuthState`, `auth_state_context`.
|
|
210
210
|
Fields: `verifying`, `verified`, `verify_error`, `account`, `actor`
|
|
211
211
|
(the caller's own `ActorSummaryJson` — surfaced directly so consumers
|
|
212
|
-
don't derive `actor_id` from the
|
|
213
|
-
`
|
|
212
|
+
don't derive `actor_id` from the role_grant list), `role_grants`,
|
|
213
|
+
`active_role_grants` (derived via `is_role_grant_active`), `roles` (derived),
|
|
214
214
|
`needs_bootstrap`. Methods: `check_session()`
|
|
215
215
|
(GET `/api/account/status`), `login`, `bootstrap`, `signup`,
|
|
216
216
|
`logout`. Handles 401/403/409/429 translations inline.
|
|
@@ -238,24 +238,24 @@ destructive actions.
|
|
|
238
238
|
`account_session_revoke_all` RPC actions. Derived `active_count`.
|
|
239
239
|
- `audit_log_state.svelte.ts` — `AuditLogState` extends `Loadable`
|
|
240
240
|
- `audit_log_rpc_context` + narrow `AuditLogRpc` (`list` +
|
|
241
|
-
`
|
|
241
|
+
`role_grant_history`). Fields: `events`, `role_grant_history_events`,
|
|
242
242
|
`connected`. Internal `#last_seq` for SSE gap fill on reconnect.
|
|
243
|
-
Methods: `fetch(options?)` (RPC), `
|
|
243
|
+
Methods: `fetch(options?)` (RPC), `fetch_role_grant_history`,
|
|
244
244
|
`subscribe()` (opens `EventSource` at `#stream_url`, default
|
|
245
245
|
`/api/admin/audit/stream`; prepends new events; refills gap
|
|
246
246
|
via `since_seq`), `disconnect()`. SSE stays on `EventSource` —
|
|
247
247
|
streaming is not an RPC concern.
|
|
248
248
|
- `admin_accounts_state.svelte.ts` — `AdminAccountsState` extends
|
|
249
249
|
`Loadable` + `admin_accounts_rpc_context` + narrow
|
|
250
|
-
`AdminAccountsRpc` (six methods: `list_accounts`, `
|
|
251
|
-
`
|
|
250
|
+
`AdminAccountsRpc` (six methods: `list_accounts`, `create_role_grant`,
|
|
251
|
+
`revoke_role_grant`, `retract_offer`, `session_revoke_all`,
|
|
252
252
|
`token_revoke_all` — the last two are also reused by
|
|
253
253
|
`AdminSessionsState`). `SvelteSet`s for in-flight tracking:
|
|
254
254
|
`granting_keys` (`${account_id}:${role}` for the account-grain
|
|
255
|
-
default; `${account_id}:${role}:${to_actor_id}` when `
|
|
256
|
-
is called with an actor-targeted offer), `revoking_ids` (
|
|
257
|
-
`retracting_ids` (offer id). `
|
|
258
|
-
(
|
|
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
259
|
listing) with optional `reason`.
|
|
260
260
|
- `admin_invites_state.svelte.ts` — `AdminInvitesState` extends
|
|
261
261
|
`Loadable` + `admin_invites_rpc_context` + narrow
|
|
@@ -280,8 +280,8 @@ destructive actions.
|
|
|
280
280
|
objects. `provide_admin_rpc_contexts(adapters)` calls `set` on all
|
|
281
281
|
four contexts in one shot. One line at the admin shell layout:
|
|
282
282
|
`provide_admin_rpc_contexts(create_admin_rpc_adapters(api))`.
|
|
283
|
-
Method-name mapping is in the module TSDoc (`
|
|
284
|
-
`
|
|
283
|
+
Method-name mapping is in the module TSDoc (`create_role_grant` →
|
|
284
|
+
`role_grant_offer_create`, `retract_offer` → `role_grant_offer_retract`, etc.)
|
|
285
285
|
and the `admin_rpc_adapters.test.ts` fixtures.
|
|
286
286
|
|
|
287
287
|
## RPC adapter contexts
|
|
@@ -299,24 +299,24 @@ provisioner pattern.
|
|
|
299
299
|
- `admin_invites_rpc_context` — `() => AdminInvitesRpc | null`.
|
|
300
300
|
Consumed by `AdminInvites`, `AdminOverview`.
|
|
301
301
|
- `audit_log_rpc_context` — `() => AuditLogRpc | null`. Consumed by
|
|
302
|
-
`AdminAuditLog`, `
|
|
302
|
+
`AdminAuditLog`, `AdminRoleGrantHistory`, `AdminOverview`.
|
|
303
303
|
- `app_settings_rpc_context` — `() => AppSettingsRpc | null`.
|
|
304
304
|
Consumed by `OpenSignupToggle`, `AdminOverview`.
|
|
305
305
|
- `account_sessions_rpc_context` — `() => AccountSessionsRpc | null`.
|
|
306
306
|
Consumed by `AccountSessions`.
|
|
307
|
-
- `
|
|
308
|
-
directly. Consumed by `
|
|
309
|
-
`
|
|
310
|
-
getters), so there's no separate `
|
|
307
|
+
- `role_grant_offers_state_context` — carries `RoleGrantOffersState`
|
|
308
|
+
directly. Consumed by `RoleGrantOfferInbox`, `RoleGrantOfferForm`,
|
|
309
|
+
`RoleGrantOfferHistory`. Wiring is ctor-bound (RPC + account/actor
|
|
310
|
+
getters), so there's no separate `role_grant_offers_rpc_context`.
|
|
311
311
|
- `format_scope_context` — `() => FormatScope` (getter shape, matching
|
|
312
312
|
the RPC contexts above). `FormatScope = ({scope_id, role}) => string |
|
|
313
313
|
null`; default returns `null` so callers fall back to the raw uuid.
|
|
314
314
|
Provisioned by `provide_admin_rpc_contexts(adapters, {format_scope})`.
|
|
315
|
-
Consumed by `AdminAccounts`, `
|
|
316
|
-
`
|
|
315
|
+
Consumed by `AdminAccounts`, `AdminRoleGrantHistory`, `RoleGrantOfferInbox`,
|
|
316
|
+
`RoleGrantOfferHistory` via the `resolve_scope_label(scope_id, role,
|
|
317
317
|
format_scope, global_label)` helper — `global_label = null` renders no
|
|
318
318
|
chip (admin tables); `'global'` renders an explicit label (offer
|
|
319
|
-
surfaces). `
|
|
319
|
+
surfaces). `RoleGrantOfferInbox` / `RoleGrantOfferHistory` accept a
|
|
320
320
|
`format_scope?: FormatScope` prop — same shape as the context, prop
|
|
321
321
|
wins when supplied.
|
|
322
322
|
- `sidebar_state_context` — `() => SidebarState`. Provisioned by
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
/**
|
|
3
|
-
* Grantor-side
|
|
3
|
+
* Grantor-side role_grant offer form.
|
|
4
4
|
*
|
|
5
5
|
* Caller supplies `to_account_id`, the subset of roles the grantor may
|
|
6
|
-
* offer (typically filtered by
|
|
6
|
+
* offer (typically filtered by admin-grant-path — `RoleSpec.grant_paths`
|
|
7
|
+
* includes `'admin'`), an optional `scope_id`,
|
|
7
8
|
* and an optional `on_created` callback for post-submit UX. Errors from
|
|
8
9
|
* the RPC surface the three distinct reason codes — self-target,
|
|
9
10
|
* role-not-grantable, not-authorized — so consumers can render them
|
|
@@ -12,19 +13,19 @@
|
|
|
12
13
|
|
|
13
14
|
import PendingButton from '@fuzdev/fuz_ui/PendingButton.svelte';
|
|
14
15
|
|
|
15
|
-
import {
|
|
16
|
+
import {role_grant_offers_state_context} from './role_grant_offers_state.svelte.js';
|
|
16
17
|
import {FormState} from './form_state.svelte.js';
|
|
17
18
|
import {
|
|
18
|
-
|
|
19
|
-
type
|
|
20
|
-
} from '../auth/
|
|
19
|
+
ROLE_GRANT_OFFER_MESSAGE_LENGTH_MAX,
|
|
20
|
+
type RoleGrantOfferJson,
|
|
21
|
+
} from '../auth/role_grant_offer_schema.js';
|
|
21
22
|
import {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
} from '../auth/
|
|
23
|
+
ERROR_ROLE_GRANT_OFFER_ACTOR_ACCOUNT_MISMATCH,
|
|
24
|
+
ERROR_ROLE_GRANT_OFFER_ACTOR_MISMATCH,
|
|
25
|
+
ERROR_ROLE_GRANT_OFFER_NOT_AUTHORIZED,
|
|
26
|
+
ERROR_ROLE_GRANT_OFFER_ROLE_NOT_GRANTABLE,
|
|
27
|
+
ERROR_ROLE_GRANT_OFFER_SELF_TARGET,
|
|
28
|
+
} from '../auth/role_grant_offer_action_specs.js';
|
|
28
29
|
|
|
29
30
|
const {
|
|
30
31
|
to_account_id,
|
|
@@ -41,15 +42,15 @@
|
|
|
41
42
|
* actor on the recipient account may accept.
|
|
42
43
|
*/
|
|
43
44
|
to_actor_id?: string | null;
|
|
44
|
-
/** Roles the caller may offer — caller filters
|
|
45
|
+
/** Roles the caller may offer — caller filters upstream (default: admin-grant-path). */
|
|
45
46
|
roles: Array<string>;
|
|
46
47
|
/** Resource scope for the offer; `null` (default) yields a global offer. */
|
|
47
48
|
scope_id?: string | null;
|
|
48
|
-
on_created?: (offer:
|
|
49
|
+
on_created?: (offer: RoleGrantOfferJson) => void;
|
|
49
50
|
format_role?: (role: string) => string;
|
|
50
51
|
} = $props();
|
|
51
52
|
|
|
52
|
-
const
|
|
53
|
+
const role_grant_offers = role_grant_offers_state_context.get();
|
|
53
54
|
const form_state = new FormState();
|
|
54
55
|
|
|
55
56
|
let role: string | undefined = $state.raw();
|
|
@@ -57,19 +58,19 @@
|
|
|
57
58
|
let message = $state.raw('');
|
|
58
59
|
let local_error: string | null = $state.raw(null);
|
|
59
60
|
|
|
60
|
-
const submitting = $derived(
|
|
61
|
+
const submitting = $derived(role_grant_offers.loading);
|
|
61
62
|
|
|
62
63
|
const surface_error = (reason: string | null): string | null => {
|
|
63
64
|
switch (reason) {
|
|
64
|
-
case
|
|
65
|
-
return 'You cannot offer a
|
|
66
|
-
case
|
|
65
|
+
case ERROR_ROLE_GRANT_OFFER_SELF_TARGET:
|
|
66
|
+
return 'You cannot offer a role_grant to yourself.';
|
|
67
|
+
case ERROR_ROLE_GRANT_OFFER_ROLE_NOT_GRANTABLE:
|
|
67
68
|
return 'That role cannot be offered through this form.';
|
|
68
|
-
case
|
|
69
|
+
case ERROR_ROLE_GRANT_OFFER_NOT_AUTHORIZED:
|
|
69
70
|
return 'You are not authorized to offer that role.';
|
|
70
|
-
case
|
|
71
|
+
case ERROR_ROLE_GRANT_OFFER_ACTOR_ACCOUNT_MISMATCH:
|
|
71
72
|
return 'That actor is not on the recipient account.';
|
|
72
|
-
case
|
|
73
|
+
case ERROR_ROLE_GRANT_OFFER_ACTOR_MISMATCH:
|
|
73
74
|
return 'This offer is for a different actor on the recipient account.';
|
|
74
75
|
default:
|
|
75
76
|
return null;
|
|
@@ -83,7 +84,7 @@
|
|
|
83
84
|
form_state.focus('role');
|
|
84
85
|
return;
|
|
85
86
|
}
|
|
86
|
-
const offer = await
|
|
87
|
+
const offer = await role_grant_offers.create({
|
|
87
88
|
to_account_id,
|
|
88
89
|
to_actor_id,
|
|
89
90
|
role: selected_role,
|
|
@@ -97,12 +98,12 @@
|
|
|
97
98
|
return;
|
|
98
99
|
}
|
|
99
100
|
// Structured error data carries the reason; fall back to raw error string.
|
|
100
|
-
const data =
|
|
101
|
+
const data = role_grant_offers.error_data as
|
|
101
102
|
| {data?: {reason?: string}; reason?: string}
|
|
102
103
|
| null
|
|
103
104
|
| undefined;
|
|
104
105
|
const reason = data?.data?.reason ?? data?.reason ?? null;
|
|
105
|
-
local_error = surface_error(reason) ??
|
|
106
|
+
local_error = surface_error(reason) ?? role_grant_offers.error;
|
|
106
107
|
};
|
|
107
108
|
</script>
|
|
108
109
|
|
|
@@ -133,7 +134,7 @@
|
|
|
133
134
|
<textarea
|
|
134
135
|
name="message"
|
|
135
136
|
bind:value={message}
|
|
136
|
-
maxlength={
|
|
137
|
+
maxlength={ROLE_GRANT_OFFER_MESSAGE_LENGTH_MAX}
|
|
137
138
|
placeholder="optional note for the recipient"
|
|
138
139
|
disabled={submitting}
|
|
139
140
|
></textarea>
|