@fuzdev/fuz_app 0.68.0 → 0.69.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 (95) hide show
  1. package/dist/actions/perform_action.d.ts.map +1 -1
  2. package/dist/actions/perform_action.js +10 -3
  3. package/dist/auth/admin_action_specs.d.ts +2 -3
  4. package/dist/auth/admin_action_specs.d.ts.map +1 -1
  5. package/dist/auth/admin_action_specs.js +2 -3
  6. package/dist/auth/admin_actions.d.ts +4 -14
  7. package/dist/auth/admin_actions.d.ts.map +1 -1
  8. package/dist/auth/admin_actions.js +28 -36
  9. package/dist/auth/signup_routes.d.ts +0 -3
  10. package/dist/auth/signup_routes.d.ts.map +1 -1
  11. package/dist/auth/signup_routes.js +9 -3
  12. package/dist/auth/standard_rpc_actions.d.ts +5 -5
  13. package/dist/auth/standard_rpc_actions.js +4 -4
  14. package/dist/server/app_server.d.ts +1 -7
  15. package/dist/server/app_server.d.ts.map +1 -1
  16. package/dist/server/app_server.js +1 -5
  17. package/dist/testing/CLAUDE.md +85 -2
  18. package/dist/testing/app_server.d.ts +34 -0
  19. package/dist/testing/app_server.d.ts.map +1 -1
  20. package/dist/testing/app_server.js +31 -6
  21. package/dist/testing/cross_backend/account_lifecycle.d.ts.map +1 -1
  22. package/dist/testing/cross_backend/account_lifecycle.js +69 -1
  23. package/dist/testing/cross_backend/actor_lookup.d.ts +10 -0
  24. package/dist/testing/cross_backend/actor_lookup.d.ts.map +1 -0
  25. package/dist/testing/cross_backend/actor_lookup.js +83 -0
  26. package/dist/testing/cross_backend/actor_search.d.ts +6 -0
  27. package/dist/testing/cross_backend/actor_search.d.ts.map +1 -0
  28. package/dist/testing/cross_backend/actor_search.js +92 -0
  29. package/dist/testing/cross_backend/app_settings.d.ts +6 -0
  30. package/dist/testing/cross_backend/app_settings.d.ts.map +1 -0
  31. package/dist/testing/cross_backend/app_settings.js +95 -0
  32. package/dist/testing/cross_backend/backend_config.d.ts +1 -1
  33. package/dist/testing/cross_backend/capabilities.d.ts +0 -9
  34. package/dist/testing/cross_backend/capabilities.d.ts.map +1 -1
  35. package/dist/testing/cross_backend/capabilities.js +0 -1
  36. package/dist/testing/cross_backend/cell_grant_role.d.ts +8 -0
  37. package/dist/testing/cross_backend/cell_grant_role.d.ts.map +1 -0
  38. package/dist/testing/cross_backend/cell_grant_role.js +102 -0
  39. package/dist/testing/cross_backend/conformance_case.d.ts +144 -0
  40. package/dist/testing/cross_backend/conformance_case.d.ts.map +1 -0
  41. package/dist/testing/cross_backend/conformance_case.js +132 -0
  42. package/dist/testing/cross_backend/conformance_table.d.ts +46 -0
  43. package/dist/testing/cross_backend/conformance_table.d.ts.map +1 -0
  44. package/dist/testing/cross_backend/conformance_table.js +199 -0
  45. package/dist/testing/cross_backend/default_backend_configs.d.ts.map +1 -1
  46. package/dist/testing/cross_backend/default_backend_configs.js +0 -2
  47. package/dist/testing/cross_backend/default_spine_surface.d.ts +17 -9
  48. package/dist/testing/cross_backend/default_spine_surface.d.ts.map +1 -1
  49. package/dist/testing/cross_backend/default_spine_surface.js +20 -12
  50. package/dist/testing/cross_backend/origin.d.ts +10 -0
  51. package/dist/testing/cross_backend/origin.d.ts.map +1 -0
  52. package/dist/testing/cross_backend/origin.js +73 -0
  53. package/dist/testing/cross_backend/setup.d.ts +22 -40
  54. package/dist/testing/cross_backend/setup.d.ts.map +1 -1
  55. package/dist/testing/cross_backend/setup.js +34 -5
  56. package/dist/testing/cross_backend/testing_reset_actions.d.ts +90 -2
  57. package/dist/testing/cross_backend/testing_reset_actions.d.ts.map +1 -1
  58. package/dist/testing/cross_backend/testing_reset_actions.js +91 -3
  59. package/dist/testing/cross_backend/xfail.d.ts +15 -0
  60. package/dist/testing/cross_backend/xfail.d.ts.map +1 -0
  61. package/dist/testing/cross_backend/xfail.js +37 -0
  62. package/dist/testing/integration.d.ts +2 -3
  63. package/dist/testing/integration.d.ts.map +1 -1
  64. package/dist/testing/integration.js +20 -85
  65. package/dist/testing/rate_limiting.d.ts +1 -1
  66. package/dist/testing/rpc_helpers.d.ts +3 -3
  67. package/dist/testing/sse_round_trip.d.ts +1 -1
  68. package/dist/testing/stubs.d.ts.map +1 -1
  69. package/dist/testing/stubs.js +0 -1
  70. package/dist/ui/AdminAccounts.svelte +74 -83
  71. package/dist/ui/AdminAccounts.svelte.d.ts.map +1 -1
  72. package/dist/ui/AdminSessions.svelte +21 -23
  73. package/dist/ui/AdminSessions.svelte.d.ts.map +1 -1
  74. package/dist/ui/CLAUDE.md +17 -26
  75. package/dist/ui/OpenSignupToggle.svelte +2 -5
  76. package/dist/ui/OpenSignupToggle.svelte.d.ts.map +1 -1
  77. package/dist/ui/account_sessions_state.svelte.d.ts +9 -10
  78. package/dist/ui/account_sessions_state.svelte.d.ts.map +1 -1
  79. package/dist/ui/account_sessions_state.svelte.js +7 -17
  80. package/dist/ui/admin_accounts_state.svelte.d.ts +12 -19
  81. package/dist/ui/admin_accounts_state.svelte.d.ts.map +1 -1
  82. package/dist/ui/admin_accounts_state.svelte.js +10 -24
  83. package/dist/ui/admin_invites_state.svelte.d.ts +8 -11
  84. package/dist/ui/admin_invites_state.svelte.d.ts.map +1 -1
  85. package/dist/ui/admin_invites_state.svelte.js +7 -16
  86. package/dist/ui/admin_sessions_state.svelte.d.ts +6 -10
  87. package/dist/ui/admin_sessions_state.svelte.d.ts.map +1 -1
  88. package/dist/ui/admin_sessions_state.svelte.js +4 -14
  89. package/dist/ui/app_settings_state.svelte.d.ts +8 -12
  90. package/dist/ui/app_settings_state.svelte.d.ts.map +1 -1
  91. package/dist/ui/app_settings_state.svelte.js +6 -16
  92. package/dist/ui/audit_log_state.svelte.d.ts +9 -8
  93. package/dist/ui/audit_log_state.svelte.d.ts.map +1 -1
  94. package/dist/ui/audit_log_state.svelte.js +8 -20
  95. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xfail.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/xfail.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAyB9B;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,WAAW,GACvB,aAAa,MAAM,EACnB,QAAQ,MAAM,EACd,MAAM,MAAM,EACZ,IAAI,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAC5B,IAEF,CAAC"}
@@ -0,0 +1,37 @@
1
+ import '../assert_dev_env.js';
2
+ /**
3
+ * `xfail_until` — mark a deferred-by-design gap as an expected failure.
4
+ *
5
+ * A thin wrapper over vitest's `test.fails` that bakes a tracking id +
6
+ * reason into the test label. Two properties make it the right tool for
7
+ * declared gaps (distinct from in-scope gaps, which fail loud as a normal
8
+ * red `test`):
9
+ *
10
+ * - **Visible** — the case shows in the report as a distinct expected
11
+ * failure, not a silent `.skip`, so a deferred gap never disappears from
12
+ * view.
13
+ * - **Self-cleaning** — `test.fails` turns **red** the moment the body
14
+ * stops throwing (i.e. the impl starts passing), forcing whoever closed
15
+ * the gap to delete the marker. A `.skip` would rot silently; this can't.
16
+ *
17
+ * Sibling to `test_if` in `capabilities.ts`. No taxonomy — a one-line
18
+ * marker with a tracking id and a reason, nothing more.
19
+ *
20
+ * @module
21
+ */
22
+ import { test } from 'vitest';
23
+ /**
24
+ * Register `fn` as an expected-failure test. Passes while `fn` throws /
25
+ * rejects; **fails** once `fn` succeeds (signalling the gap closed and the
26
+ * marker should be removed).
27
+ *
28
+ * @param tracking_id - descriptive id of the tracked gap (e.g.
29
+ * `'audit-log-sse-rust-spine'`) — a feature/behavior name, not a
30
+ * process/milestone label.
31
+ * @param reason - why the case is deferred-by-design.
32
+ * @param name - the assertion / test label.
33
+ * @param fn - the test body (expected to throw/reject until the gap closes).
34
+ */
35
+ export const xfail_until = (tracking_id, reason, name, fn) => {
36
+ test.fails(`${name} [xfail_until ${tracking_id}: ${reason}]`, fn);
37
+ };
@@ -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 companion to `fixture.in_process` narrowing. */
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 origin-verify
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;AAO9D,OAAO,EAKN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AAkB1B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAU,KAAK,mBAAmB,EAAC,MAAM,iCAAiC,CAAC;AAClF,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,qFAAqF;IACrF,YAAY,EAAE,mBAAmB,CAAC;IAClC;;;;;OAKG;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,IAy5CF,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,IAyzCF,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, create_expired_test_cookie, assert_no_error_info_leakage, } from './integration_helpers.js';
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 { test_if } from './cross_backend/capabilities.js';
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
- test_if(options.capabilities.in_process_only, 'expired cookie returns 401', async () => {
327
- const fixture = await options.setup_test();
328
- assert(fixture.in_process);
329
- const expired_cookie = await create_expired_test_cookie(fixture.keyring, options.session_options);
330
- const res = await rpc_call_for_spec({
331
- app: { request: fixture.transport },
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
- test_if(options.capabilities.in_process_only, 'evil origin is rejected with 403', async () => {
490
- const fixture = await options.setup_test();
491
- assert(fixture.in_process);
492
- // `verify_request_source` runs before the RPC dispatcher and returns a
493
- // plain REST `{error}` body not a JSON-RPC envelope. Skip `rpc_call`.
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', () => {
@@ -938,37 +897,13 @@ export const describe_standard_integration_tests = (options) => {
938
897
  });
939
898
  });
940
899
  // --- 11. Expired credential rejection ---
941
- describe('expired credential rejection', () => {
942
- test_if(options.capabilities.in_process_only, 'expired session cookie returns 401', async () => {
943
- const fixture = await options.setup_test();
944
- assert(fixture.in_process);
945
- const expired_cookie = await create_expired_test_cookie(fixture.keyring, options.session_options);
946
- const res = await rpc_call_for_spec({
947
- app: { request: fixture.transport },
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
- });
900
+ // Expired-credential rejection (read + mutation paths) promoted to the
901
+ // cross-backend conformance table (`conformance_expiry_cases.ts`, the
902
+ // `expired_session` principal) it asserts the authoritative
903
+ // server-side DB-row expiry gate over real auth resolution on every
904
+ // spine. The two near-identical in-process skips this replaced (both an
905
+ // `account_verify` read) collapse into the single read row there; the
906
+ // `/logout` mutation path is the second row.
972
907
  // --- 12. Bearer token browser context on mutation routes ---
973
908
  describe('bearer token browser context silently discarded on mutations', () => {
974
909
  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.app_settings` / `ctx.deps`. The factory must return the same
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.app_settings` / `ctx.deps` (e.g. the canonical
14
- * `create_standard_rpc_actions(ctx.deps, {app_settings: ctx.app_settings})`
15
- * pattern). `create_app_server` resolves either shape natively; test helpers
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.app_settings` / `ctx.deps`. The factory must return the same
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":"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"}
1
+ {"version":3,"file":"stubs.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/stubs.ts"],"names":[],"mappings":"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"}
@@ -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
- {#if admin_accounts.has_rpc}
54
- <label class="row gap_xs font_size_sm">
55
- <input
56
- type="checkbox"
57
- checked={admin_accounts.show_deleted}
58
- onchange={(e) => admin_accounts.set_show_deleted(e.currentTarget.checked)}
59
- />
60
- show deleted
61
- </label>
62
- <p class="text_50 font_size_sm">
63
- “delete” is a reversible soft-delete (tombstone) enable “show deleted” to reactivate an
64
- account. Permanent hard-delete (purge) is keeper/CLI-only and intentionally not available
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 admin_accounts.has_rpc && row.actor}
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
- {#if admin_accounts.has_rpc}
145
- {@const retract_error = admin_accounts.retract.error(offer.id)}
146
- <ConfirmButton
147
- onconfirm={() => admin_accounts.submit_retract(offer.id)}
148
- title="retract offer"
149
- class="sm"
150
- label="retract"
151
- pending={admin_accounts.retract.loading(offer.id)}
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
- {#if admin_accounts.has_rpc}
164
- {#each admin_accounts.grantable_roles as role (role)}
165
- {@const key = grant_key(row.account.id, role)}
166
- {@const grant_error = admin_accounts.grant.error(key)}
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.submit_delete(row.account.id)}
212
- title="soft-delete @{row.account.username}"
163
+ onconfirm={() => admin_accounts.submit_grant(row.account.id, role)}
164
+ title="offer {role}"
213
165
  class="sm"
214
- label="delete"
215
- pending={admin_accounts.soft_delete.loading(row.account.id)}
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="color_c bg_100" onclick={() => do_confirm()}>
219
- <span class="py_sm">soft-delete @{row.account.username} (reversible)</span>
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 delete_error}
224
- <span class="color_c_50 font_size_sm">{delete_error}</span>
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":"AA2MA,QAAA,MAAM,aAAa,2DAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
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
- {#if admin_sessions.has_rpc}
66
- {@const revoke_sessions_error = admin_sessions.revoke_sessions.error(row.account_id)}
67
- {@const revoke_tokens_error = admin_sessions.revoke_tokens.error(row.account_id)}
68
- <ConfirmButton
69
- onconfirm={() => admin_sessions.submit_revoke_sessions(row.account_id)}
70
- title="revoke all sessions for {row.username}"
71
- class="sm"
72
- label="revoke sessions"
73
- pending={admin_sessions.revoke_sessions.loading(row.account_id)}
74
- />
75
- {#if revoke_sessions_error}
76
- <span class="color_c_50 font_size_sm">{revoke_sessions_error}</span>
77
- {/if}
78
- <ConfirmButton
79
- onconfirm={() => admin_sessions.submit_revoke_tokens(row.account_id)}
80
- title="revoke all tokens for {row.username}"
81
- class="sm"
82
- label="revoke tokens"
83
- pending={admin_sessions.revoke_tokens.loading(row.account_id)}
84
- />
85
- {#if revoke_tokens_error}
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":"AAoGA,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"}
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 with `() => null` fallback
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 | null` accessor. All five declare a `() => () => null`
27
- default so components mounted without a provisioner render the "rpc adapter
28
- not wired" state instead of crashing. (`role_grant_offers_state_context` carries
29
- a `RoleGrantOffersState` directly, not an RPC accessor, and isn't counted
30
- here.) The standard consumer shape:
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`; hides gracefully when `has_rpc` is `false`.
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`). `has_rpc` gates the listing + both revoke controls.
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 have a `() => () => null` default and
341
- share the same `has_rpc`-gated state-class shape; consumers wire a typed
342
- RPC client to each narrow interface. See "Key patterns" above for the
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 | null`.
339
+ - `admin_accounts_rpc_context` — `() => AdminAccountsRpc`.
349
340
  Consumed by `AdminAccounts`, `AdminSessions`, `AdminOverview`.
350
- - `admin_invites_rpc_context` — `() => AdminInvitesRpc | null`.
341
+ - `admin_invites_rpc_context` — `() => AdminInvitesRpc`.
351
342
  Consumed by `AdminInvites`, `AdminOverview`.
352
- - `audit_log_rpc_context` — `() => AuditLogRpc | null`. Consumed by
343
+ - `audit_log_rpc_context` — `() => AuditLogRpc`. Consumed by
353
344
  `AdminAuditLog`, `AdminRoleGrantHistory`, `AdminOverview`.
354
- - `app_settings_rpc_context` — `() => AppSettingsRpc | null`.
345
+ - `app_settings_rpc_context` — `() => AppSettingsRpc`.
355
346
  Consumed by `OpenSignupToggle`, `AdminOverview`.
356
- - `account_sessions_rpc_context` — `() => AccountSessionsRpc | null`.
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`,