@fuzdev/fuz_app 0.68.0 → 0.70.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/perform_action.d.ts.map +1 -1
- package/dist/actions/perform_action.js +10 -3
- package/dist/auth/admin_action_specs.d.ts +2 -3
- package/dist/auth/admin_action_specs.d.ts.map +1 -1
- package/dist/auth/admin_action_specs.js +2 -3
- package/dist/auth/admin_actions.d.ts +4 -14
- package/dist/auth/admin_actions.d.ts.map +1 -1
- package/dist/auth/admin_actions.js +28 -36
- package/dist/auth/signup_routes.d.ts +0 -3
- package/dist/auth/signup_routes.d.ts.map +1 -1
- package/dist/auth/signup_routes.js +9 -3
- package/dist/auth/standard_rpc_actions.d.ts +5 -5
- package/dist/auth/standard_rpc_actions.js +4 -4
- package/dist/server/app_server.d.ts +1 -7
- package/dist/server/app_server.d.ts.map +1 -1
- package/dist/server/app_server.js +1 -5
- package/dist/testing/CLAUDE.md +98 -10
- package/dist/testing/app_server.d.ts +34 -0
- package/dist/testing/app_server.d.ts.map +1 -1
- package/dist/testing/app_server.js +31 -6
- package/dist/testing/cross_backend/account_lifecycle.d.ts.map +1 -1
- package/dist/testing/cross_backend/account_lifecycle.js +69 -1
- package/dist/testing/cross_backend/actor_lookup.d.ts +10 -0
- package/dist/testing/cross_backend/actor_lookup.d.ts.map +1 -0
- package/dist/testing/cross_backend/actor_lookup.js +83 -0
- package/dist/testing/cross_backend/actor_search.d.ts +6 -0
- package/dist/testing/cross_backend/actor_search.d.ts.map +1 -0
- package/dist/testing/cross_backend/actor_search.js +92 -0
- package/dist/testing/cross_backend/app_settings.d.ts +6 -0
- package/dist/testing/cross_backend/app_settings.d.ts.map +1 -0
- package/dist/testing/cross_backend/app_settings.js +95 -0
- package/dist/testing/cross_backend/backend_config.d.ts +1 -1
- package/dist/testing/cross_backend/capabilities.d.ts +0 -9
- package/dist/testing/cross_backend/capabilities.d.ts.map +1 -1
- package/dist/testing/cross_backend/capabilities.js +0 -1
- package/dist/testing/cross_backend/cell_grant_role.d.ts +8 -0
- package/dist/testing/cross_backend/cell_grant_role.d.ts.map +1 -0
- package/dist/testing/cross_backend/cell_grant_role.js +102 -0
- package/dist/testing/cross_backend/conformance_case.d.ts +144 -0
- package/dist/testing/cross_backend/conformance_case.d.ts.map +1 -0
- package/dist/testing/cross_backend/conformance_case.js +132 -0
- package/dist/testing/cross_backend/conformance_table.d.ts +46 -0
- package/dist/testing/cross_backend/conformance_table.d.ts.map +1 -0
- package/dist/testing/cross_backend/conformance_table.js +199 -0
- package/dist/testing/cross_backend/create_cross_backend_global_setup.d.ts +57 -0
- package/dist/testing/cross_backend/create_cross_backend_global_setup.d.ts.map +1 -0
- package/dist/testing/cross_backend/create_cross_backend_global_setup.js +31 -0
- package/dist/testing/cross_backend/default_backend_configs.d.ts +13 -0
- package/dist/testing/cross_backend/default_backend_configs.d.ts.map +1 -1
- package/dist/testing/cross_backend/default_backend_configs.js +4 -6
- package/dist/testing/cross_backend/default_spine_surface.d.ts +17 -9
- package/dist/testing/cross_backend/default_spine_surface.d.ts.map +1 -1
- package/dist/testing/cross_backend/default_spine_surface.js +20 -12
- package/dist/testing/cross_backend/make_cross_backend_project.d.ts +72 -0
- package/dist/testing/cross_backend/make_cross_backend_project.d.ts.map +1 -0
- package/dist/testing/cross_backend/make_cross_backend_project.js +51 -0
- package/dist/testing/cross_backend/origin.d.ts +10 -0
- package/dist/testing/cross_backend/origin.d.ts.map +1 -0
- package/dist/testing/cross_backend/origin.js +73 -0
- package/dist/testing/cross_backend/setup.d.ts +22 -40
- package/dist/testing/cross_backend/setup.d.ts.map +1 -1
- package/dist/testing/cross_backend/setup.js +34 -5
- package/dist/testing/cross_backend/standard.d.ts +8 -0
- package/dist/testing/cross_backend/standard.d.ts.map +1 -1
- package/dist/testing/cross_backend/standard.js +1 -0
- package/dist/testing/cross_backend/testing_reset_actions.d.ts +102 -10
- package/dist/testing/cross_backend/testing_reset_actions.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_reset_actions.js +96 -5
- package/dist/testing/cross_backend/xfail.d.ts +15 -0
- package/dist/testing/cross_backend/xfail.d.ts.map +1 -0
- package/dist/testing/cross_backend/xfail.js +37 -0
- package/dist/testing/integration.d.ts +2 -3
- package/dist/testing/integration.d.ts.map +1 -1
- package/dist/testing/integration.js +40 -88
- package/dist/testing/rate_limiting.d.ts +1 -1
- package/dist/testing/rpc_helpers.d.ts +3 -3
- package/dist/testing/sse_round_trip.d.ts +1 -1
- package/dist/testing/stubs.d.ts.map +1 -1
- package/dist/testing/stubs.js +0 -1
- package/dist/ui/AdminAccounts.svelte +74 -83
- package/dist/ui/AdminAccounts.svelte.d.ts.map +1 -1
- package/dist/ui/AdminSessions.svelte +21 -23
- package/dist/ui/AdminSessions.svelte.d.ts.map +1 -1
- package/dist/ui/CLAUDE.md +17 -26
- package/dist/ui/OpenSignupToggle.svelte +2 -5
- package/dist/ui/OpenSignupToggle.svelte.d.ts.map +1 -1
- package/dist/ui/account_sessions_state.svelte.d.ts +9 -10
- package/dist/ui/account_sessions_state.svelte.d.ts.map +1 -1
- package/dist/ui/account_sessions_state.svelte.js +7 -17
- package/dist/ui/admin_accounts_state.svelte.d.ts +12 -19
- package/dist/ui/admin_accounts_state.svelte.d.ts.map +1 -1
- package/dist/ui/admin_accounts_state.svelte.js +10 -24
- package/dist/ui/admin_invites_state.svelte.d.ts +8 -11
- package/dist/ui/admin_invites_state.svelte.d.ts.map +1 -1
- package/dist/ui/admin_invites_state.svelte.js +7 -16
- package/dist/ui/admin_sessions_state.svelte.d.ts +6 -10
- package/dist/ui/admin_sessions_state.svelte.d.ts.map +1 -1
- package/dist/ui/admin_sessions_state.svelte.js +4 -14
- package/dist/ui/app_settings_state.svelte.d.ts +8 -12
- package/dist/ui/app_settings_state.svelte.d.ts.map +1 -1
- package/dist/ui/app_settings_state.svelte.js +6 -16
- package/dist/ui/audit_log_state.svelte.d.ts +9 -8
- package/dist/ui/audit_log_state.svelte.d.ts.map +1 -1
- package/dist/ui/audit_log_state.svelte.js +8 -20
- package/package.json +1 -1
|
@@ -25,13 +25,12 @@ export interface StandardIntegrationTestOptions {
|
|
|
25
25
|
* not the source the test runtime reads from.
|
|
26
26
|
*/
|
|
27
27
|
surface_source: AppSurfaceSpec;
|
|
28
|
-
/** Backend capability declarations
|
|
28
|
+
/** Backend capability declarations for capability-gated cases. */
|
|
29
29
|
capabilities: BackendCapabilities;
|
|
30
30
|
/**
|
|
31
31
|
* Session config — needed to resolve factory-form `rpc_endpoints`
|
|
32
32
|
* against a stub `AppServerContext` at setup time and to read
|
|
33
|
-
* `cookie_name` for manual cookie composition in the
|
|
34
|
-
* cases.
|
|
33
|
+
* `cookie_name` for manual cookie composition in the session cases.
|
|
35
34
|
*/
|
|
36
35
|
session_options: SessionOptions<string>;
|
|
37
36
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"integration.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/integration.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAsB7B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"integration.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/integration.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAsB7B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAM9D,OAAO,EAKN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AAiB1B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAC,KAAK,mBAAmB,EAAC,MAAM,iCAAiC,CAAC;AACzE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,0BAA0B,CAAC;AAGxD;;GAEG;AACH,MAAM,WAAW,8BAA8B;IAC9C;;;;OAIG;IACH,UAAU,EAAE,SAAS,CAAC;IACtB;;;;;;;;;OASG;IACH,cAAc,EAAE,cAAc,CAAC;IAC/B,kEAAkE;IAClE,YAAY,EAAE,mBAAmB,CAAC;IAClC;;;;OAIG;IACH,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC;;;;;;;;;;;;OAYG;IACH,aAAa,EAAE,uBAAuB,CAAC;IACvC;;;;;;;OAOG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,mCAAmC,GAC/C,SAAS,8BAA8B,KACrC,IA60CF,CAAC"}
|
|
@@ -17,14 +17,13 @@ import './assert_dev_env.js';
|
|
|
17
17
|
* @module
|
|
18
18
|
*/
|
|
19
19
|
import { describe, test, assert, afterAll } from 'vitest';
|
|
20
|
-
import { find_auth_route, assert_response_matches_spec,
|
|
20
|
+
import { find_auth_route, assert_response_matches_spec, assert_no_error_info_leakage, } from './integration_helpers.js';
|
|
21
21
|
import { find_rpc_action, rpc_call_for_spec, require_rpc_endpoint_path, resolve_rpc_endpoints_for_setup, } from './rpc_helpers.js';
|
|
22
22
|
import { ErrorCoverageCollector, assert_error_coverage, DEFAULT_INTEGRATION_ERROR_COVERAGE, } from './error_coverage.js';
|
|
23
|
-
import { ApiError, ERROR_FORBIDDEN_ORIGIN } from '../http/error_schemas.js';
|
|
24
23
|
import { is_public_auth } from '../http/auth_shape.js';
|
|
25
24
|
import { account_verify_action_spec, account_session_list_action_spec, account_session_revoke_action_spec, account_session_revoke_all_action_spec, account_token_create_action_spec, account_token_list_action_spec, account_token_revoke_action_spec, } from '../auth/account_action_specs.js';
|
|
26
25
|
import { invite_create_action_spec } from '../auth/admin_action_specs.js';
|
|
27
|
-
import {
|
|
26
|
+
import {} from './cross_backend/capabilities.js';
|
|
28
27
|
import { DEFAULT_TEST_PASSWORD } from './app_server.js';
|
|
29
28
|
/**
|
|
30
29
|
* Standard integration test suite for fuz_app auth routes.
|
|
@@ -323,19 +322,12 @@ export const describe_standard_integration_tests = (options) => {
|
|
|
323
322
|
});
|
|
324
323
|
assert.strictEqual(res.status, 401);
|
|
325
324
|
});
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
path: rpc_path,
|
|
333
|
-
spec: account_verify_action_spec,
|
|
334
|
-
params: undefined,
|
|
335
|
-
headers: { cookie: `${cookie_name}=${expired_cookie}` },
|
|
336
|
-
});
|
|
337
|
-
assert.strictEqual(res.status, 401);
|
|
338
|
-
});
|
|
325
|
+
// Expired-session rejection promoted to the cross-backend conformance
|
|
326
|
+
// table (the `expired_session` principal, `conformance_expiry_cases.ts`) —
|
|
327
|
+
// it exercises the authoritative server-side DB-row expiry gate over
|
|
328
|
+
// real auth resolution on every spine, not the cookie-payload gate a
|
|
329
|
+
// backdated-payload forge hit here. The payload gate stays covered by
|
|
330
|
+
// `parse_session`'s own unit tests.
|
|
339
331
|
});
|
|
340
332
|
// --- 4. Session revocation ---
|
|
341
333
|
describe('session revocation', () => {
|
|
@@ -486,29 +478,11 @@ export const describe_standard_integration_tests = (options) => {
|
|
|
486
478
|
});
|
|
487
479
|
// --- 5. Origin verification ---
|
|
488
480
|
describe('origin verification', () => {
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
const res = await fixture.transport(rpc_path, {
|
|
495
|
-
method: 'POST',
|
|
496
|
-
headers: {
|
|
497
|
-
host: 'localhost',
|
|
498
|
-
origin: 'http://evil.com',
|
|
499
|
-
'content-type': 'application/json',
|
|
500
|
-
cookie: `${cookie_name}=${fixture.backend_internals.session_cookie}`,
|
|
501
|
-
},
|
|
502
|
-
body: JSON.stringify({
|
|
503
|
-
jsonrpc: '2.0',
|
|
504
|
-
method: account_verify_action_spec.method,
|
|
505
|
-
id: 'evil-origin',
|
|
506
|
-
}),
|
|
507
|
-
});
|
|
508
|
-
assert.strictEqual(res.status, 403);
|
|
509
|
-
const body = ApiError.parse(await res.json());
|
|
510
|
-
assert.strictEqual(body.error, ERROR_FORBIDDEN_ORIGIN);
|
|
511
|
-
});
|
|
481
|
+
// Disallowed-Origin → 403 and absent-Origin → pass promoted to the
|
|
482
|
+
// dedicated cross-backend origin parity suite (`cross_backend/origin.ts`,
|
|
483
|
+
// both legs) — it drives raw transport calls against each spine's real
|
|
484
|
+
// origin middleware. This positive control stays here as a basic
|
|
485
|
+
// happy-path check in the consumer integration bundle.
|
|
512
486
|
test('valid origin is accepted', async () => {
|
|
513
487
|
const fixture = await options.setup_test();
|
|
514
488
|
const res = await rpc_call_for_spec({
|
|
@@ -520,21 +494,6 @@ export const describe_standard_integration_tests = (options) => {
|
|
|
520
494
|
});
|
|
521
495
|
assert.strictEqual(res.status, 200);
|
|
522
496
|
});
|
|
523
|
-
test_if(options.capabilities.in_process_only, 'no origin header is allowed (direct access)', async () => {
|
|
524
|
-
const fixture = await options.setup_test();
|
|
525
|
-
assert(fixture.in_process);
|
|
526
|
-
// Probe the "no Origin / no Referer" path; `suppress_default_origin`
|
|
527
|
-
// skips the default `origin` header.
|
|
528
|
-
const res = await rpc_call_for_spec({
|
|
529
|
-
app: { request: fixture.transport },
|
|
530
|
-
path: rpc_path,
|
|
531
|
-
spec: account_verify_action_spec,
|
|
532
|
-
params: undefined,
|
|
533
|
-
headers: { cookie: `${cookie_name}=${fixture.backend_internals.session_cookie}` },
|
|
534
|
-
suppress_default_origin: true,
|
|
535
|
-
});
|
|
536
|
-
assert.notStrictEqual(res.status, 403);
|
|
537
|
-
});
|
|
538
497
|
});
|
|
539
498
|
// --- 6. Bearer auth ---
|
|
540
499
|
describe('bearer auth', () => {
|
|
@@ -646,13 +605,30 @@ export const describe_standard_integration_tests = (options) => {
|
|
|
646
605
|
test('non-admin cannot access admin routes', async () => {
|
|
647
606
|
const fixture = await options.setup_test();
|
|
648
607
|
// admin routes are optional in the base suite — admin-specific coverage
|
|
649
|
-
// lives in describe_standard_admin_integration_tests
|
|
650
|
-
|
|
608
|
+
// lives in describe_standard_admin_integration_tests.
|
|
609
|
+
//
|
|
610
|
+
// Pick an admin REST route where a clean role-denial 403 is
|
|
611
|
+
// reachable: account-grain (`actor: 'none'`, so the authorization
|
|
612
|
+
// phase doesn't first demand an acting actor → `actor_required`)
|
|
613
|
+
// and input/param/query-free (so input validation doesn't 400
|
|
614
|
+
// first, per the 401 → 400 → 403 phase order). Admin surfaces are
|
|
615
|
+
// RPC-first now; a consumer may expose no such REST route (fuz_app
|
|
616
|
+
// itself, zzz) — then this REST-era check is a no-op and RPC denial
|
|
617
|
+
// is covered by `describe_rpc_attack_surface_tests`.
|
|
618
|
+
const admin_route = route_specs.find((s) => (s.auth.roles?.includes('admin') ?? false) &&
|
|
619
|
+
s.auth.actor === 'none' &&
|
|
620
|
+
!s.input &&
|
|
621
|
+
!s.params &&
|
|
622
|
+
!s.query);
|
|
651
623
|
if (!admin_route)
|
|
652
624
|
return;
|
|
625
|
+
// Probe with a freshly-created account — it holds no admin role
|
|
626
|
+
// (the keeper fixture behind `create_session_headers` does, so it
|
|
627
|
+
// would pass the gate).
|
|
628
|
+
const non_admin = await fixture.create_account({ username: 'non_admin_admin_probe' });
|
|
653
629
|
const res = await fixture.transport(admin_route.path, {
|
|
654
630
|
method: admin_route.method,
|
|
655
|
-
headers:
|
|
631
|
+
headers: { cookie: `${cookie_name}=${non_admin.session_cookie}` },
|
|
656
632
|
});
|
|
657
633
|
assert.strictEqual(res.status, 403);
|
|
658
634
|
const body = await res.json();
|
|
@@ -938,37 +914,13 @@ export const describe_standard_integration_tests = (options) => {
|
|
|
938
914
|
});
|
|
939
915
|
});
|
|
940
916
|
// --- 11. Expired credential rejection ---
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
path: rpc_path,
|
|
949
|
-
spec: account_verify_action_spec,
|
|
950
|
-
params: undefined,
|
|
951
|
-
headers: { cookie: `${cookie_name}=${expired_cookie}` },
|
|
952
|
-
});
|
|
953
|
-
assert.strictEqual(res.status, 401, 'Expired session cookie should be rejected');
|
|
954
|
-
});
|
|
955
|
-
test_if(options.capabilities.in_process_only, 'expired session cookie returns 401 on mutation route', async () => {
|
|
956
|
-
const fixture = await options.setup_test();
|
|
957
|
-
assert(fixture.in_process);
|
|
958
|
-
const logout_route = find_auth_route(route_specs, '/logout', 'POST');
|
|
959
|
-
assert.ok(logout_route, 'Expected POST /logout route — ensure create_route_specs includes account routes');
|
|
960
|
-
const expired_cookie = await create_expired_test_cookie(fixture.keyring, options.session_options);
|
|
961
|
-
const res = await fixture.transport(logout_route.path, {
|
|
962
|
-
method: 'POST',
|
|
963
|
-
headers: {
|
|
964
|
-
host: 'localhost',
|
|
965
|
-
cookie: `${cookie_name}=${expired_cookie}`,
|
|
966
|
-
},
|
|
967
|
-
});
|
|
968
|
-
assert.strictEqual(res.status, 401, 'Expired session cookie should be rejected on POST');
|
|
969
|
-
error_collector.record(route_specs, 'POST', logout_route.path, 401);
|
|
970
|
-
});
|
|
971
|
-
});
|
|
917
|
+
// Expired-credential rejection (read + mutation paths) promoted to the
|
|
918
|
+
// cross-backend conformance table (`conformance_expiry_cases.ts`, the
|
|
919
|
+
// `expired_session` principal) — it asserts the authoritative
|
|
920
|
+
// server-side DB-row expiry gate over real auth resolution on every
|
|
921
|
+
// spine. The two near-identical in-process skips this replaced (both an
|
|
922
|
+
// `account_verify` read) collapse into the single read row there; the
|
|
923
|
+
// `/logout` mutation path is the second row.
|
|
972
924
|
// --- 12. Bearer token browser context on mutation routes ---
|
|
973
925
|
describe('bearer token browser context silently discarded on mutations', () => {
|
|
974
926
|
test('bearer token with Origin header discarded on POST logout', async () => {
|
|
@@ -32,7 +32,7 @@ export interface RateLimitingTestOptions {
|
|
|
32
32
|
* Accepts either an array (eager) or a factory
|
|
33
33
|
* `(ctx: AppServerContext) => Array<RpcEndpointSpec>` — the factory form
|
|
34
34
|
* is required when action handlers must close over the per-test
|
|
35
|
-
* `ctx.
|
|
35
|
+
* `ctx.deps`. The factory must return the same
|
|
36
36
|
* endpoint `path` regardless of ctx — it is invoked once at setup with
|
|
37
37
|
* a stub ctx for path lookup and again per-test by `create_app_server`
|
|
38
38
|
* for live dispatch.
|
|
@@ -10,9 +10,9 @@ import type { SessionOptions } from '../auth/session_cookie.js';
|
|
|
10
10
|
* Union accepted by the suite-level `rpc_endpoints` option — eager array or
|
|
11
11
|
* a factory that takes an `AppServerContext` and returns endpoint specs. The
|
|
12
12
|
* factory form is required when action handlers must close over the
|
|
13
|
-
* per-test `ctx.
|
|
14
|
-
* `create_standard_rpc_actions(ctx.deps
|
|
15
|
-
*
|
|
13
|
+
* per-test `ctx.deps` (e.g. the canonical
|
|
14
|
+
* `create_standard_rpc_actions(ctx.deps)` pattern). `create_app_server`
|
|
15
|
+
* resolves either shape natively; test helpers
|
|
16
16
|
* forward the raw value to the top-level `rpc_endpoints` slot on
|
|
17
17
|
* `CreateTestAppOptions` for live dispatch.
|
|
18
18
|
*/
|
|
@@ -57,7 +57,7 @@ export interface SseRouteTestOptions {
|
|
|
57
57
|
* Accepts either an array (eager) or a factory
|
|
58
58
|
* `(ctx: AppServerContext) => Array<RpcEndpointSpec>` — the factory form
|
|
59
59
|
* is required when action handlers must close over the per-test
|
|
60
|
-
* `ctx.
|
|
60
|
+
* `ctx.deps`. The factory must return the same
|
|
61
61
|
* endpoint `path` regardless of ctx — it is invoked once at setup with
|
|
62
62
|
* a stub ctx for path lookup and again per-test by `create_app_server`
|
|
63
63
|
* for live dispatch.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stubs.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/stubs.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAa7B,OAAO,KAAK,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAE3B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,4BAA4B,CAAC;AAE/D,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,0BAA0B,CAAC;AAE3D,OAAO,KAAK,EAAC,gBAAgB,EAAE,sBAAsB,EAAC,MAAM,yBAAyB,CAAC;AACtF,OAAO,EAAC,EAAE,EAAC,MAAM,aAAa,CAAC;AAC/B,OAAO,EAAqB,KAAK,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAGzE,OAAO,EAEN,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,gCAAgC,CAAC;AACnE,OAAO,KAAK,EAAC,SAAS,EAAkB,MAAM,oBAAoB,CAAC;AACnE,OAAO,EAA8B,KAAK,WAAW,EAAC,MAAM,+BAA+B,CAAC;AAI5F;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,oBAAoB,GAAI,CAAC,GAAG,GAAG,EAAE,OAAO,MAAM,KAAG,CAqBtD,CAAC;AAET;;;;;;;;;GASG;AACH,eAAO,MAAM,gBAAgB,GAAI,CAAC,GAAG,GAAG,EAAE,QAAQ,MAAM,EAAE,YAAY,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,CAOxF,CAAC;AAET,iEAAiE;AACjE,eAAO,MAAM,IAAI,EAAE,GAAkC,CAAC;AAEtD;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,QAAO,EAI/B,CAAC;AAEJ,gDAAgD;AAChD,eAAO,MAAM,YAAY,QAAO,QAAgC,CAAC;AAEjE,2CAA2C;AAC3C,eAAO,MAAM,OAAO,GAAU,IAAI,GAAG,EAAE,MAAM,GAAG,KAAG,OAAO,CAAC,IAAI,CAAW,CAAC;AAI3E;;;;;;;;;;GAUG;AACH,eAAO,MAAM,yBAAyB,QAAO,YAM3C,CAAC;AAEH;;;;;;;;;GASG;AACH,eAAO,MAAM,qBAAqB,QAAO,WAUxC,CAAC;AAEF,2EAA2E;AAC3E,eAAO,MAAM,aAAa,EAAE,OAS3B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,oBAAoB,QAAO,OAStC,CAAC;AAEH,2FAA2F;AAC3F,eAAO,MAAM,0BAA0B,GAAI,UAAU;IACpD,iDAAiD;IACjD,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAC/B,KAAG,KAAK,CAAC,cAAc,CAqBvB,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,8BAA8B,GAC1C,iBAAiB,cAAc,CAAC,MAAM,CAAC,KACrC,
|
|
1
|
+
{"version":3,"file":"stubs.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/stubs.ts"],"names":[],"mappings":"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"}
|
package/dist/testing/stubs.js
CHANGED
|
@@ -201,7 +201,6 @@ export const create_stub_app_server_context = (session_options) => {
|
|
|
201
201
|
signup_account_rate_limiter: null,
|
|
202
202
|
action_ip_rate_limiter: null,
|
|
203
203
|
action_account_rate_limiter: null,
|
|
204
|
-
app_settings: { open_signup: false, updated_at: null, updated_by: null },
|
|
205
204
|
audit_sse: null,
|
|
206
205
|
};
|
|
207
206
|
};
|
|
@@ -50,21 +50,18 @@
|
|
|
50
50
|
</p>
|
|
51
51
|
{/if}
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
<
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
here.
|
|
66
|
-
</p>
|
|
67
|
-
{/if}
|
|
53
|
+
<label class="row gap_xs font_size_sm">
|
|
54
|
+
<input
|
|
55
|
+
type="checkbox"
|
|
56
|
+
checked={admin_accounts.show_deleted}
|
|
57
|
+
onchange={(e) => admin_accounts.set_show_deleted(e.currentTarget.checked)}
|
|
58
|
+
/>
|
|
59
|
+
show deleted
|
|
60
|
+
</label>
|
|
61
|
+
<p class="text_50 font_size_sm">
|
|
62
|
+
“delete” is a reversible soft-delete (tombstone) — enable “show deleted” to reactivate an
|
|
63
|
+
account. Permanent hard-delete (purge) is keeper/CLI-only and intentionally not available here.
|
|
64
|
+
</p>
|
|
68
65
|
|
|
69
66
|
{#if admin_accounts.list.loading}
|
|
70
67
|
<p class="text_50">loading accounts...</p>
|
|
@@ -111,7 +108,7 @@
|
|
|
111
108
|
expires {format_relative_time(role_grant.expires_at)}
|
|
112
109
|
</span>
|
|
113
110
|
{/if}
|
|
114
|
-
{#if
|
|
111
|
+
{#if row.actor}
|
|
115
112
|
{@const actor_id = row.actor.id}
|
|
116
113
|
{@const revoke_error = admin_accounts.revoke.error(role_grant.id)}
|
|
117
114
|
<ConfirmButton
|
|
@@ -129,6 +126,7 @@
|
|
|
129
126
|
{/each}
|
|
130
127
|
{#each row.pending_offers as offer (offer.id)}
|
|
131
128
|
{@const offer_scope = scope_label(offer.scope_id, offer.role)}
|
|
129
|
+
{@const retract_error = admin_accounts.retract.error(offer.id)}
|
|
132
130
|
<div class="row">
|
|
133
131
|
<span
|
|
134
132
|
class="chip"
|
|
@@ -141,18 +139,15 @@
|
|
|
141
139
|
{offer_scope}
|
|
142
140
|
</span>
|
|
143
141
|
{/if}
|
|
144
|
-
|
|
145
|
-
{
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
{#if retract_error}
|
|
154
|
-
<span class="color_c_50 font_size_sm">{retract_error}</span>
|
|
155
|
-
{/if}
|
|
142
|
+
<ConfirmButton
|
|
143
|
+
onconfirm={() => admin_accounts.submit_retract(offer.id)}
|
|
144
|
+
title="retract offer"
|
|
145
|
+
class="sm"
|
|
146
|
+
label="retract"
|
|
147
|
+
pending={admin_accounts.retract.loading(offer.id)}
|
|
148
|
+
/>
|
|
149
|
+
{#if retract_error}
|
|
150
|
+
<span class="color_c_50 font_size_sm">{retract_error}</span>
|
|
156
151
|
{/if}
|
|
157
152
|
</div>
|
|
158
153
|
{/each}
|
|
@@ -160,70 +155,66 @@
|
|
|
160
155
|
<span class="text_50">none</span>
|
|
161
156
|
{/if}
|
|
162
157
|
{:else if column.key === 'actor'}
|
|
163
|
-
{#
|
|
164
|
-
{
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
{#if !row.role_grants.some((p) => p.role === role) && !row.pending_offers.some((o) => o.role === role)}
|
|
168
|
-
<ConfirmButton
|
|
169
|
-
onconfirm={() => admin_accounts.submit_grant(row.account.id, role)}
|
|
170
|
-
title="offer {role}"
|
|
171
|
-
class="sm"
|
|
172
|
-
label={`+ ${role}`}
|
|
173
|
-
pending={admin_accounts.grant.loading(key)}
|
|
174
|
-
>
|
|
175
|
-
{#snippet popover_content(_popover, do_confirm)}
|
|
176
|
-
<button type="button" class="color_b bg_100" onclick={() => do_confirm()}>
|
|
177
|
-
<span class="py_sm">offer '{role}' to @{row.account.username}</span>
|
|
178
|
-
</button>
|
|
179
|
-
{/snippet}
|
|
180
|
-
</ConfirmButton>
|
|
181
|
-
{#if grant_error}
|
|
182
|
-
<span class="color_c_50 font_size_sm">{grant_error}</span>
|
|
183
|
-
{/if}
|
|
184
|
-
{/if}
|
|
185
|
-
{/each}
|
|
186
|
-
{/if}
|
|
187
|
-
{:else if column.key === 'pending_offers'}
|
|
188
|
-
{#if admin_accounts.has_rpc}
|
|
189
|
-
{#if row.account.deleted_at}
|
|
190
|
-
{@const undelete_error = admin_accounts.undelete.error(row.account.id)}
|
|
191
|
-
<span
|
|
192
|
-
class="chip font_size_sm color_c"
|
|
193
|
-
title={format_datetime_local(row.account.deleted_at)}
|
|
194
|
-
>
|
|
195
|
-
deleted {format_relative_time(row.account.deleted_at)}
|
|
196
|
-
</span>
|
|
197
|
-
<button
|
|
198
|
-
type="button"
|
|
199
|
-
class="sm"
|
|
200
|
-
disabled={admin_accounts.undelete.loading(row.account.id)}
|
|
201
|
-
onclick={() => admin_accounts.submit_undelete(row.account.id)}
|
|
202
|
-
>
|
|
203
|
-
reactivate
|
|
204
|
-
</button>
|
|
205
|
-
{#if undelete_error}
|
|
206
|
-
<span class="color_c_50 font_size_sm">{undelete_error}</span>
|
|
207
|
-
{/if}
|
|
208
|
-
{:else}
|
|
209
|
-
{@const delete_error = admin_accounts.soft_delete.error(row.account.id)}
|
|
158
|
+
{#each admin_accounts.grantable_roles as role (role)}
|
|
159
|
+
{@const key = grant_key(row.account.id, role)}
|
|
160
|
+
{@const grant_error = admin_accounts.grant.error(key)}
|
|
161
|
+
{#if !row.role_grants.some((p) => p.role === role) && !row.pending_offers.some((o) => o.role === role)}
|
|
210
162
|
<ConfirmButton
|
|
211
|
-
onconfirm={() => admin_accounts.
|
|
212
|
-
title="
|
|
163
|
+
onconfirm={() => admin_accounts.submit_grant(row.account.id, role)}
|
|
164
|
+
title="offer {role}"
|
|
213
165
|
class="sm"
|
|
214
|
-
label=
|
|
215
|
-
pending={admin_accounts.
|
|
166
|
+
label={`+ ${role}`}
|
|
167
|
+
pending={admin_accounts.grant.loading(key)}
|
|
216
168
|
>
|
|
217
169
|
{#snippet popover_content(_popover, do_confirm)}
|
|
218
|
-
<button type="button" class="
|
|
219
|
-
<span class="py_sm">
|
|
170
|
+
<button type="button" class="color_b bg_100" onclick={() => do_confirm()}>
|
|
171
|
+
<span class="py_sm">offer '{role}' to @{row.account.username}</span>
|
|
220
172
|
</button>
|
|
221
173
|
{/snippet}
|
|
222
174
|
</ConfirmButton>
|
|
223
|
-
{#if
|
|
224
|
-
<span class="color_c_50 font_size_sm">{
|
|
175
|
+
{#if grant_error}
|
|
176
|
+
<span class="color_c_50 font_size_sm">{grant_error}</span>
|
|
225
177
|
{/if}
|
|
226
178
|
{/if}
|
|
179
|
+
{/each}
|
|
180
|
+
{:else if column.key === 'pending_offers'}
|
|
181
|
+
{#if row.account.deleted_at}
|
|
182
|
+
{@const undelete_error = admin_accounts.undelete.error(row.account.id)}
|
|
183
|
+
<span
|
|
184
|
+
class="chip font_size_sm color_c"
|
|
185
|
+
title={format_datetime_local(row.account.deleted_at)}
|
|
186
|
+
>
|
|
187
|
+
deleted {format_relative_time(row.account.deleted_at)}
|
|
188
|
+
</span>
|
|
189
|
+
<button
|
|
190
|
+
type="button"
|
|
191
|
+
class="sm"
|
|
192
|
+
disabled={admin_accounts.undelete.loading(row.account.id)}
|
|
193
|
+
onclick={() => admin_accounts.submit_undelete(row.account.id)}
|
|
194
|
+
>
|
|
195
|
+
reactivate
|
|
196
|
+
</button>
|
|
197
|
+
{#if undelete_error}
|
|
198
|
+
<span class="color_c_50 font_size_sm">{undelete_error}</span>
|
|
199
|
+
{/if}
|
|
200
|
+
{:else}
|
|
201
|
+
{@const delete_error = admin_accounts.soft_delete.error(row.account.id)}
|
|
202
|
+
<ConfirmButton
|
|
203
|
+
onconfirm={() => admin_accounts.submit_delete(row.account.id)}
|
|
204
|
+
title="soft-delete @{row.account.username}"
|
|
205
|
+
class="sm"
|
|
206
|
+
label="delete"
|
|
207
|
+
pending={admin_accounts.soft_delete.loading(row.account.id)}
|
|
208
|
+
>
|
|
209
|
+
{#snippet popover_content(_popover, do_confirm)}
|
|
210
|
+
<button type="button" class="color_c bg_100" onclick={() => do_confirm()}>
|
|
211
|
+
<span class="py_sm">soft-delete @{row.account.username} (reversible)</span>
|
|
212
|
+
</button>
|
|
213
|
+
{/snippet}
|
|
214
|
+
</ConfirmButton>
|
|
215
|
+
{#if delete_error}
|
|
216
|
+
<span class="color_c_50 font_size_sm">{delete_error}</span>
|
|
217
|
+
{/if}
|
|
227
218
|
{/if}
|
|
228
219
|
{/if}
|
|
229
220
|
{/snippet}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdminAccounts.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/ui/AdminAccounts.svelte"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"AdminAccounts.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/ui/AdminAccounts.svelte"],"names":[],"mappings":"AAkMA,QAAA,MAAM,aAAa,2DAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
|
|
@@ -62,29 +62,27 @@
|
|
|
62
62
|
{format_relative_time(row.expires_at)}
|
|
63
63
|
</span>
|
|
64
64
|
{:else if column.key === 'account_id'}
|
|
65
|
-
{
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
{
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
{
|
|
86
|
-
<span class="color_c_50 font_size_sm">{revoke_tokens_error}</span>
|
|
87
|
-
{/if}
|
|
65
|
+
{@const revoke_sessions_error = admin_sessions.revoke_sessions.error(row.account_id)}
|
|
66
|
+
{@const revoke_tokens_error = admin_sessions.revoke_tokens.error(row.account_id)}
|
|
67
|
+
<ConfirmButton
|
|
68
|
+
onconfirm={() => admin_sessions.submit_revoke_sessions(row.account_id)}
|
|
69
|
+
title="revoke all sessions for {row.username}"
|
|
70
|
+
class="sm"
|
|
71
|
+
label="revoke sessions"
|
|
72
|
+
pending={admin_sessions.revoke_sessions.loading(row.account_id)}
|
|
73
|
+
/>
|
|
74
|
+
{#if revoke_sessions_error}
|
|
75
|
+
<span class="color_c_50 font_size_sm">{revoke_sessions_error}</span>
|
|
76
|
+
{/if}
|
|
77
|
+
<ConfirmButton
|
|
78
|
+
onconfirm={() => admin_sessions.submit_revoke_tokens(row.account_id)}
|
|
79
|
+
title="revoke all tokens for {row.username}"
|
|
80
|
+
class="sm"
|
|
81
|
+
label="revoke tokens"
|
|
82
|
+
pending={admin_sessions.revoke_tokens.loading(row.account_id)}
|
|
83
|
+
/>
|
|
84
|
+
{#if revoke_tokens_error}
|
|
85
|
+
<span class="color_c_50 font_size_sm">{revoke_tokens_error}</span>
|
|
88
86
|
{/if}
|
|
89
87
|
{:else if column.format}
|
|
90
88
|
{column.format(row[column.key], row)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdminSessions.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/ui/AdminSessions.svelte"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"AdminSessions.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/ui/AdminSessions.svelte"],"names":[],"mappings":"AAkGA,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,aAAa;;kBAA+E,CAAC;AACjF,KAAK,aAAa,GAAG,YAAY,CAAC,OAAO,aAAa,CAAC,CAAC;AAC1D,eAAe,aAAa,CAAC"}
|
package/dist/ui/CLAUDE.md
CHANGED
|
@@ -18,16 +18,17 @@ file is a reference, not a tutorial.
|
|
|
18
18
|
|
|
19
19
|
## Key patterns
|
|
20
20
|
|
|
21
|
-
### RPC adapter contexts
|
|
21
|
+
### RPC adapter contexts (required, no fallback)
|
|
22
22
|
|
|
23
23
|
Five narrow RPC adapter contexts — `admin_accounts_rpc_context`,
|
|
24
24
|
`admin_invites_rpc_context`, `audit_log_rpc_context`,
|
|
25
25
|
`app_settings_rpc_context`, `account_sessions_rpc_context` — carry a
|
|
26
|
-
reactive `() => Rpc
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
here.) The standard consumer
|
|
26
|
+
reactive `() => Rpc` accessor. None declares a fallback, so `get()` throws
|
|
27
|
+
when a component mounts without a provisioner above it — the adapter is
|
|
28
|
+
required, and a missing wire fails loudly at mount rather than degrading
|
|
29
|
+
silently. (`role_grant_offers_state_context` carries a `RoleGrantOffersState`
|
|
30
|
+
directly, not an RPC accessor, and isn't counted here.) The standard consumer
|
|
31
|
+
shape:
|
|
31
32
|
|
|
32
33
|
```ts
|
|
33
34
|
const get_rpc = admin_accounts_rpc_context.get();
|
|
@@ -45,14 +46,6 @@ The provisioner calls `context.set(() => rpc)` once at the admin route
|
|
|
45
46
|
shell. Every admin component plus `OpenSignupToggle.svelte` consumes the
|
|
46
47
|
context — RPC adapters are never threaded through props.
|
|
47
48
|
|
|
48
|
-
### `has_rpc` gates fetch and mutations
|
|
49
|
-
|
|
50
|
-
Every state class backed by a narrow RPC interface exposes a `has_rpc`
|
|
51
|
-
getter. When `false`, `fetch()`, mutations, and `subscribe` no-op and
|
|
52
|
-
set `error` to `'rpc adapter not wired'`. `AdminSessionsState`'s listing
|
|
53
|
-
plus mutations all run through the shared `AdminAccountsRpc`, so
|
|
54
|
-
`has_rpc` gates the whole surface.
|
|
55
|
-
|
|
56
49
|
### `$state.raw` Map keyed by id + `$derived` views
|
|
57
50
|
|
|
58
51
|
`RoleGrantOffersState` maintains a single `Map<string, RoleGrantOfferJson>` in
|
|
@@ -159,7 +152,7 @@ destructive actions.
|
|
|
159
152
|
`/api/surface` (REST) and delegates to `SurfaceExplorer`.
|
|
160
153
|
- `OpenSignupToggle.svelte` — single checkbox bound to
|
|
161
154
|
`AppSettingsState.settings.open_signup`. Consumes
|
|
162
|
-
`app_settings_rpc_context
|
|
155
|
+
`app_settings_rpc_context`.
|
|
163
156
|
- `SurfaceExplorer.svelte` — reads-only `AppSurface` renderer. Props:
|
|
164
157
|
`surface: AppSurface`. Filter routes by auth type; expand a row to
|
|
165
158
|
dump `params`/`query`/`input`/`output`/`errors` schemas as JSON.
|
|
@@ -317,8 +310,7 @@ the `submit_*` prefix where the verb collides with a slot name.
|
|
|
317
310
|
(`list_sessions` wraps `admin_session_list`) and the two revoke-all
|
|
318
311
|
mutations. Slots: `list` (AsyncSlot), `revoke_sessions` /
|
|
319
312
|
`revoke_tokens` (`KeyedAsyncSlot<Uuid, void>` keyed by
|
|
320
|
-
`account_id`). `
|
|
321
|
-
Methods: `fetch`, `submit_revoke_sessions`, `submit_revoke_tokens`.
|
|
313
|
+
`account_id`). Methods: `fetch`, `submit_revoke_sessions`, `submit_revoke_tokens`.
|
|
322
314
|
- `app_settings_state.svelte.ts` — `AppSettingsState` +
|
|
323
315
|
`app_settings_rpc_context` + narrow `AppSettingsRpc` (`get`,
|
|
324
316
|
`update`). Slots: `list`, `update`. Field: `settings`. Single
|
|
@@ -337,23 +329,22 @@ the `submit_*` prefix where the verb collides with a slot name.
|
|
|
337
329
|
|
|
338
330
|
## RPC adapter contexts
|
|
339
331
|
|
|
340
|
-
All five RPC-carrying contexts
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
provisioner pattern.
|
|
332
|
+
All five RPC-carrying contexts are required (no fallback) — `get()` throws
|
|
333
|
+
when unprovisioned; consumers wire a typed RPC client to each narrow
|
|
334
|
+
interface. See "Key patterns" above for the provisioner pattern.
|
|
344
335
|
|
|
345
336
|
- `auth_state_context` — carries `AuthState` directly (not an RPC
|
|
346
337
|
accessor). Used by every auth form, `AdminOverview`,
|
|
347
338
|
`AdminSettings`, `AccountSessions`, `LogoutButton`.
|
|
348
|
-
- `admin_accounts_rpc_context` — `() => AdminAccountsRpc
|
|
339
|
+
- `admin_accounts_rpc_context` — `() => AdminAccountsRpc`.
|
|
349
340
|
Consumed by `AdminAccounts`, `AdminSessions`, `AdminOverview`.
|
|
350
|
-
- `admin_invites_rpc_context` — `() => AdminInvitesRpc
|
|
341
|
+
- `admin_invites_rpc_context` — `() => AdminInvitesRpc`.
|
|
351
342
|
Consumed by `AdminInvites`, `AdminOverview`.
|
|
352
|
-
- `audit_log_rpc_context` — `() => AuditLogRpc
|
|
343
|
+
- `audit_log_rpc_context` — `() => AuditLogRpc`. Consumed by
|
|
353
344
|
`AdminAuditLog`, `AdminRoleGrantHistory`, `AdminOverview`.
|
|
354
|
-
- `app_settings_rpc_context` — `() => AppSettingsRpc
|
|
345
|
+
- `app_settings_rpc_context` — `() => AppSettingsRpc`.
|
|
355
346
|
Consumed by `OpenSignupToggle`, `AdminOverview`.
|
|
356
|
-
- `account_sessions_rpc_context` — `() => AccountSessionsRpc
|
|
347
|
+
- `account_sessions_rpc_context` — `() => AccountSessionsRpc`.
|
|
357
348
|
Consumed by `AccountSessions`.
|
|
358
349
|
- `role_grant_offers_state_context` — carries `RoleGrantOffersState`
|
|
359
350
|
directly. Consumed by `RoleGrantOfferInbox`, `RoleGrantOfferForm`,
|