@fuzdev/fuz_app 0.67.0 → 0.68.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 (168) hide show
  1. package/dist/auth/CLAUDE.md +99 -5
  2. package/dist/auth/account_queries.d.ts +87 -4
  3. package/dist/auth/account_queries.d.ts.map +1 -1
  4. package/dist/auth/account_queries.js +107 -17
  5. package/dist/auth/account_schema.d.ts +19 -0
  6. package/dist/auth/account_schema.d.ts.map +1 -1
  7. package/dist/auth/account_schema.js +8 -0
  8. package/dist/auth/admin_action_specs.d.ts +168 -0
  9. package/dist/auth/admin_action_specs.d.ts.map +1 -1
  10. package/dist/auth/admin_action_specs.js +146 -1
  11. package/dist/auth/admin_actions.d.ts.map +1 -1
  12. package/dist/auth/admin_actions.js +218 -4
  13. package/dist/auth/audit_log_ddl.d.ts +10 -1
  14. package/dist/auth/audit_log_ddl.d.ts.map +1 -1
  15. package/dist/auth/audit_log_ddl.js +13 -4
  16. package/dist/auth/audit_log_schema.d.ts +34 -1
  17. package/dist/auth/audit_log_schema.d.ts.map +1 -1
  18. package/dist/auth/audit_log_schema.js +73 -0
  19. package/dist/auth/auth_ddl.d.ts +2 -2
  20. package/dist/auth/auth_ddl.d.ts.map +1 -1
  21. package/dist/auth/auth_ddl.js +10 -2
  22. package/dist/auth/cell_action_specs.d.ts +1295 -0
  23. package/dist/auth/cell_action_specs.d.ts.map +1 -0
  24. package/dist/auth/cell_action_specs.js +397 -0
  25. package/dist/auth/cell_actions.d.ts +63 -0
  26. package/dist/auth/cell_actions.d.ts.map +1 -0
  27. package/dist/auth/cell_actions.js +546 -0
  28. package/dist/auth/cell_audit_action_specs.d.ts +131 -0
  29. package/dist/auth/cell_audit_action_specs.d.ts.map +1 -0
  30. package/dist/auth/cell_audit_action_specs.js +70 -0
  31. package/dist/auth/cell_audit_actions.d.ts +18 -0
  32. package/dist/auth/cell_audit_actions.d.ts.map +1 -0
  33. package/dist/auth/cell_audit_actions.js +59 -0
  34. package/dist/auth/cell_audit_events.d.ts +28 -0
  35. package/dist/auth/cell_audit_events.d.ts.map +1 -0
  36. package/dist/auth/cell_audit_events.js +42 -0
  37. package/dist/auth/cell_audit_metadata.d.ts +48 -0
  38. package/dist/auth/cell_audit_metadata.d.ts.map +1 -0
  39. package/dist/auth/cell_audit_metadata.js +46 -0
  40. package/dist/auth/cell_authorize.d.ts +88 -0
  41. package/dist/auth/cell_authorize.d.ts.map +1 -0
  42. package/dist/auth/cell_authorize.js +172 -0
  43. package/dist/auth/cell_data_schema.d.ts +44 -0
  44. package/dist/auth/cell_data_schema.d.ts.map +1 -0
  45. package/dist/auth/cell_data_schema.js +42 -0
  46. package/dist/auth/cell_field_action_specs.d.ts +244 -0
  47. package/dist/auth/cell_field_action_specs.d.ts.map +1 -0
  48. package/dist/auth/cell_field_action_specs.js +136 -0
  49. package/dist/auth/cell_field_actions.d.ts +34 -0
  50. package/dist/auth/cell_field_actions.d.ts.map +1 -0
  51. package/dist/auth/cell_field_actions.js +153 -0
  52. package/dist/auth/cell_field_audit_metadata.d.ts +30 -0
  53. package/dist/auth/cell_field_audit_metadata.d.ts.map +1 -0
  54. package/dist/auth/cell_field_audit_metadata.js +28 -0
  55. package/dist/auth/cell_grant_action_specs.d.ts +333 -0
  56. package/dist/auth/cell_grant_action_specs.d.ts.map +1 -0
  57. package/dist/auth/cell_grant_action_specs.js +148 -0
  58. package/dist/auth/cell_grant_actions.d.ts +50 -0
  59. package/dist/auth/cell_grant_actions.d.ts.map +1 -0
  60. package/dist/auth/cell_grant_actions.js +208 -0
  61. package/dist/auth/cell_grant_audit_metadata.d.ts +75 -0
  62. package/dist/auth/cell_grant_audit_metadata.d.ts.map +1 -0
  63. package/dist/auth/cell_grant_audit_metadata.js +54 -0
  64. package/dist/auth/cell_item_action_specs.d.ts +331 -0
  65. package/dist/auth/cell_item_action_specs.d.ts.map +1 -0
  66. package/dist/auth/cell_item_action_specs.js +182 -0
  67. package/dist/auth/cell_item_actions.d.ts +37 -0
  68. package/dist/auth/cell_item_actions.d.ts.map +1 -0
  69. package/dist/auth/cell_item_actions.js +204 -0
  70. package/dist/auth/cell_item_audit_metadata.d.ts +35 -0
  71. package/dist/auth/cell_item_audit_metadata.d.ts.map +1 -0
  72. package/dist/auth/cell_item_audit_metadata.js +32 -0
  73. package/dist/auth/cell_relation_visibility.d.ts +32 -0
  74. package/dist/auth/cell_relation_visibility.d.ts.map +1 -0
  75. package/dist/auth/cell_relation_visibility.js +57 -0
  76. package/dist/auth/deps.d.ts +9 -0
  77. package/dist/auth/deps.d.ts.map +1 -1
  78. package/dist/auth/role_grant_queries.d.ts +30 -0
  79. package/dist/auth/role_grant_queries.d.ts.map +1 -1
  80. package/dist/auth/role_grant_queries.js +54 -0
  81. package/dist/db/CLAUDE.md +118 -0
  82. package/dist/db/cell_audit_queries.d.ts +26 -0
  83. package/dist/db/cell_audit_queries.d.ts.map +1 -0
  84. package/dist/db/cell_audit_queries.js +53 -0
  85. package/dist/db/cell_ddl.d.ts +151 -0
  86. package/dist/db/cell_ddl.d.ts.map +1 -0
  87. package/dist/db/cell_ddl.js +247 -0
  88. package/dist/db/cell_field_queries.d.ts +105 -0
  89. package/dist/db/cell_field_queries.d.ts.map +1 -0
  90. package/dist/db/cell_field_queries.js +113 -0
  91. package/dist/db/cell_grant_queries.d.ts +132 -0
  92. package/dist/db/cell_grant_queries.d.ts.map +1 -0
  93. package/dist/db/cell_grant_queries.js +145 -0
  94. package/dist/db/cell_history_ddl.d.ts +38 -0
  95. package/dist/db/cell_history_ddl.d.ts.map +1 -0
  96. package/dist/db/cell_history_ddl.js +61 -0
  97. package/dist/db/cell_item_queries.d.ts +107 -0
  98. package/dist/db/cell_item_queries.d.ts.map +1 -0
  99. package/dist/db/cell_item_queries.js +119 -0
  100. package/dist/db/cell_queries.d.ts +327 -0
  101. package/dist/db/cell_queries.d.ts.map +1 -0
  102. package/dist/db/cell_queries.js +431 -0
  103. package/dist/db/fact_ddl.d.ts +38 -0
  104. package/dist/db/fact_ddl.d.ts.map +1 -0
  105. package/dist/db/fact_ddl.js +71 -0
  106. package/dist/db/fact_queries.d.ts +140 -0
  107. package/dist/db/fact_queries.d.ts.map +1 -0
  108. package/dist/db/fact_queries.js +161 -0
  109. package/dist/db/fact_store.d.ts +112 -0
  110. package/dist/db/fact_store.d.ts.map +1 -0
  111. package/dist/db/fact_store.js +225 -0
  112. package/dist/server/env.d.ts +2 -0
  113. package/dist/server/env.d.ts.map +1 -1
  114. package/dist/server/env.js +6 -0
  115. package/dist/server/fact_write.d.ts +32 -0
  116. package/dist/server/fact_write.d.ts.map +1 -0
  117. package/dist/server/fact_write.js +56 -0
  118. package/dist/server/file_fact_fetcher.d.ts +42 -0
  119. package/dist/server/file_fact_fetcher.d.ts.map +1 -0
  120. package/dist/server/file_fact_fetcher.js +60 -0
  121. package/dist/server/file_fact_url.d.ts +53 -0
  122. package/dist/server/file_fact_url.d.ts.map +1 -0
  123. package/dist/server/file_fact_url.js +52 -0
  124. package/dist/server/serve_fact_route.d.ts +78 -0
  125. package/dist/server/serve_fact_route.d.ts.map +1 -0
  126. package/dist/server/serve_fact_route.js +205 -0
  127. package/dist/testing/CLAUDE.md +58 -5
  128. package/dist/testing/app_server.d.ts +12 -0
  129. package/dist/testing/app_server.d.ts.map +1 -1
  130. package/dist/testing/app_server.js +36 -2
  131. package/dist/testing/audit_completeness.d.ts.map +1 -1
  132. package/dist/testing/audit_completeness.js +67 -1
  133. package/dist/testing/cross_backend/account_lifecycle.d.ts +10 -0
  134. package/dist/testing/cross_backend/account_lifecycle.d.ts.map +1 -0
  135. package/dist/testing/cross_backend/account_lifecycle.js +76 -0
  136. package/dist/testing/cross_backend/capabilities.d.ts +31 -0
  137. package/dist/testing/cross_backend/capabilities.d.ts.map +1 -1
  138. package/dist/testing/cross_backend/capabilities.js +3 -0
  139. package/dist/testing/cross_backend/cell_cross_helpers.d.ts +39 -0
  140. package/dist/testing/cross_backend/cell_cross_helpers.d.ts.map +1 -0
  141. package/dist/testing/cross_backend/cell_cross_helpers.js +45 -0
  142. package/dist/testing/cross_backend/cell_crud.d.ts +4 -0
  143. package/dist/testing/cross_backend/cell_crud.d.ts.map +1 -0
  144. package/dist/testing/cross_backend/cell_crud.js +168 -0
  145. package/dist/testing/cross_backend/cell_relations.d.ts +4 -0
  146. package/dist/testing/cross_backend/cell_relations.d.ts.map +1 -0
  147. package/dist/testing/cross_backend/cell_relations.js +229 -0
  148. package/dist/testing/cross_backend/default_backend_configs.d.ts.map +1 -1
  149. package/dist/testing/cross_backend/default_backend_configs.js +6 -0
  150. package/dist/testing/cross_backend/setup.d.ts.map +1 -1
  151. package/dist/testing/cross_backend/setup.js +5 -0
  152. package/dist/testing/cross_backend/spawn_backend.d.ts.map +1 -1
  153. package/dist/testing/cross_backend/spawn_backend.js +31 -3
  154. package/dist/testing/cross_backend/testing_server_bun.d.ts.map +1 -1
  155. package/dist/testing/cross_backend/testing_server_bun.js +29 -2
  156. package/dist/testing/entities.d.ts.map +1 -1
  157. package/dist/testing/entities.js +4 -0
  158. package/dist/testing/ws_round_trip.d.ts.map +1 -1
  159. package/dist/testing/ws_round_trip.js +4 -0
  160. package/dist/ui/AdminAccounts.svelte +58 -0
  161. package/dist/ui/AdminAccounts.svelte.d.ts.map +1 -1
  162. package/dist/ui/admin_accounts_state.svelte.d.ts +30 -2
  163. package/dist/ui/admin_accounts_state.svelte.d.ts.map +1 -1
  164. package/dist/ui/admin_accounts_state.svelte.js +45 -1
  165. package/dist/ui/admin_rpc_adapters.d.ts +6 -2
  166. package/dist/ui/admin_rpc_adapters.d.ts.map +1 -1
  167. package/dist/ui/admin_rpc_adapters.js +5 -1
  168. package/package.json +4 -2
@@ -1 +1 @@
1
- {"version":3,"file":"app_server.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/app_server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"app_server.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/app_server.ts"],"names":[],"mappings":"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"}
@@ -49,6 +49,35 @@ export const DEFAULT_TEST_PASSWORD = 'test-password-123';
49
49
  const fallback_pglite_factory = create_pglite_factory(async (db) => {
50
50
  await run_migrations(db, [auth_migration_ns]);
51
51
  });
52
+ // Auto-created PGlite factories keyed by extra-namespace identity. Suites
53
+ // whose backend needs tables beyond auth (e.g. the cell layer) share one
54
+ // factory per distinct namespace set — and the worker-cached WASM instance —
55
+ // rather than each hand-building its own. The cell parity suite is the first
56
+ // user.
57
+ const fallback_factories_by_namespaces = new Map();
58
+ /**
59
+ * Resolve the no-`db` PGlite factory for the requested extra migration
60
+ * namespaces. Empty / omitted → the shared auth-only `fallback_pglite_factory`;
61
+ * otherwise a memoized factory whose `init` runs
62
+ * `[auth_migration_ns, ...migration_namespaces]` on each reset. The
63
+ * reset-on-`create` gives the same fresh-db-per-test isolation as the
64
+ * auth-only default. Mirrors `create_app_backend`'s `migration_namespaces`
65
+ * seam at the test layer.
66
+ */
67
+ const resolve_fallback_factory = (migration_namespaces) => {
68
+ if (!migration_namespaces || migration_namespaces.length === 0) {
69
+ return fallback_pglite_factory;
70
+ }
71
+ const key = migration_namespaces.map((ns) => ns.namespace).join(',');
72
+ let factory = fallback_factories_by_namespaces.get(key);
73
+ if (!factory) {
74
+ factory = create_pglite_factory(async (db) => {
75
+ await run_migrations(db, [auth_migration_ns, ...migration_namespaces]);
76
+ });
77
+ fallback_factories_by_namespaces.set(key, factory);
78
+ }
79
+ return factory;
80
+ };
52
81
  /**
53
82
  * Create a test account with credentials. Use for additional accounts
54
83
  * minted alongside the keeper (e.g. `TestApp.create_account` for
@@ -132,7 +161,11 @@ const default_test_fs_stubs = {
132
161
  * resets it to false before this runs).
133
162
  */
134
163
  const _build_test_backend = async (options) => {
135
- const { db: existing_db, db_type = 'pglite-memory', password = stub_password_deps, audit_factory = default_audit_factory, fs_stubs = default_test_fs_stubs, } = options;
164
+ const { db: existing_db, db_type = 'pglite-memory', password = stub_password_deps, audit_factory = default_audit_factory, fs_stubs = default_test_fs_stubs, migration_namespaces, } = options;
165
+ if (existing_db && migration_namespaces && migration_namespaces.length > 0) {
166
+ throw new Error('test app setup: pass either `db` (caller owns migrations) or `migration_namespaces` ' +
167
+ '(harness migrates), not both');
168
+ }
136
169
  const keyring_result = create_validated_keyring(TEST_COOKIE_SECRET);
137
170
  if (!keyring_result.ok) {
138
171
  throw new Error(`Test keyring failed: ${keyring_result.errors.join(', ')}`);
@@ -161,7 +194,8 @@ const _build_test_backend = async (options) => {
161
194
  // In-memory PGlite via cached factory — reuses the WASM instance from test_db.ts
162
195
  // instead of creating a new PGlite each time. Schema is reset and migrations re-run
163
196
  // on each call, but the expensive WASM cold start only happens once per worker thread.
164
- const db = await fallback_pglite_factory.create();
197
+ // `migration_namespaces` selects an auth+extras factory; auth-only is the default.
198
+ const db = await resolve_fallback_factory(migration_namespaces).create();
165
199
  const audit = audit_factory({ db, log: test_log });
166
200
  backend = {
167
201
  db_type: 'pglite-memory',
@@ -1 +1 @@
1
- {"version":3,"file":"audit_completeness.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/audit_completeness.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AA4B7B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAS9D,OAAO,EAKN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AAwB1B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,iCAAiC,CAAC;AACzE,OAAO,KAAK,EAAC,SAAS,EAAc,MAAM,0BAA0B,CAAC;AAErE;;GAEG;AACH,MAAM,WAAW,4BAA4B;IAC5C;;;;;OAKG;IACH,UAAU,EAAE,SAAS,CAAC;IACtB;;;;;;OAMG;IACH,cAAc,EAAE,cAAc,CAAC;IAC/B,uCAAuC;IACvC,YAAY,EAAE,mBAAmB,CAAC;IAClC,yEAAyE;IACzE,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC;;;OAGG;IACH,aAAa,EAAE,uBAAuB,CAAC;CACvC;AA8FD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,iCAAiC,GAAI,SAAS,4BAA4B,KAAG,IAuhBzF,CAAC"}
1
+ {"version":3,"file":"audit_completeness.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/audit_completeness.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AA4B7B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAS9D,OAAO,EAKN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AA2B1B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,iCAAiC,CAAC;AACzE,OAAO,KAAK,EAAC,SAAS,EAAc,MAAM,0BAA0B,CAAC;AAErE;;GAEG;AACH,MAAM,WAAW,4BAA4B;IAC5C;;;;;OAKG;IACH,UAAU,EAAE,SAAS,CAAC;IACtB;;;;;;OAMG;IACH,cAAc,EAAE,cAAc,CAAC;IAC/B,uCAAuC;IACvC,YAAY,EAAE,mBAAmB,CAAC;IAClC,yEAAyE;IACzE,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC;;;OAGG;IACH,aAAa,EAAE,uBAAuB,CAAC;CACvC;AA8FD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,iCAAiC,GAAI,SAAS,4BAA4B,KAAG,IAomBzF,CAAC"}
@@ -30,7 +30,7 @@ import { find_auth_route } from './integration_helpers.js';
30
30
  import { rpc_call_for_spec, require_rpc_endpoint_path, resolve_rpc_endpoints_for_setup, } from './rpc_helpers.js';
31
31
  import { role_grant_offer_and_accept } from './role_grant_helpers.js';
32
32
  import { role_grant_offer_accept_action_spec, role_grant_offer_create_action_spec, role_grant_revoke_action_spec, } from '../auth/role_grant_offer_action_specs.js';
33
- import { admin_session_revoke_all_action_spec, admin_token_revoke_all_action_spec, app_settings_update_action_spec, audit_log_list_action_spec, AUDIT_LOG_LIST_LIMIT_MAX, invite_create_action_spec, invite_delete_action_spec, } from '../auth/admin_action_specs.js';
33
+ import { account_delete_action_spec, account_purge_action_spec, account_undelete_action_spec, admin_session_revoke_all_action_spec, admin_token_revoke_all_action_spec, app_settings_update_action_spec, audit_log_list_action_spec, AUDIT_LOG_LIST_LIMIT_MAX, invite_create_action_spec, invite_delete_action_spec, } from '../auth/admin_action_specs.js';
34
34
  import { 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';
35
35
  /**
36
36
  * Mint a dedicated admin account whose sole job is to read the audit log
@@ -418,6 +418,66 @@ export const describe_audit_completeness_tests = (options) => {
418
418
  assert_has_event(events, 'app_settings_update', 'app_settings_update RPC');
419
419
  });
420
420
  });
421
+ // --- Account deletion RPC actions ---
422
+ describe('account deletion audit events', () => {
423
+ test('account_delete (admin) produces account_delete + actor_delete events', async () => {
424
+ const fixture = await options.setup_test();
425
+ const observer = await create_admin_observer(fixture);
426
+ const target = await fixture.create_account({ username: 'audit_delete_target' });
427
+ const res = await rpc_call_for_spec({
428
+ app: { request: fixture.transport },
429
+ path: rpc_path,
430
+ spec: account_delete_action_spec,
431
+ params: { account_id: target.account.id },
432
+ headers: fixture.create_session_headers(),
433
+ });
434
+ assert.ok(res.ok, `account_delete failed: ${res.ok ? '' : JSON.stringify(res.error)}`);
435
+ const events = await list_audit_events({ request: fixture.transport }, rpc_path, observer);
436
+ assert_has_event(events, 'account_delete', 'account_delete RPC');
437
+ assert_has_event(events, 'actor_delete', 'account_delete RPC (per-actor cascade)');
438
+ });
439
+ test('account_purge (keeper) produces account_purge + actor_purge events', async () => {
440
+ const fixture = await options.setup_test();
441
+ const observer = await create_admin_observer(fixture);
442
+ const target = await fixture.create_account({ username: 'audit_purge_target' });
443
+ const res = await rpc_call_for_spec({
444
+ app: { request: fixture.transport },
445
+ path: rpc_path,
446
+ spec: account_purge_action_spec,
447
+ params: { account_id: target.account.id, confirm: true },
448
+ // Keeper-gated: daemon-token credential, not a session.
449
+ headers: fixture.create_daemon_token_headers(),
450
+ });
451
+ assert.ok(res.ok, `account_purge failed: ${res.ok ? '' : JSON.stringify(res.error)}`);
452
+ const events = await list_audit_events({ request: fixture.transport }, rpc_path, observer);
453
+ assert_has_event(events, 'account_purge', 'account_purge RPC');
454
+ assert_has_event(events, 'actor_purge', 'account_purge RPC (per-actor cascade)');
455
+ });
456
+ test('account_undelete (admin) produces account_undelete + actor_undelete events', async () => {
457
+ const fixture = await options.setup_test();
458
+ const observer = await create_admin_observer(fixture);
459
+ const target = await fixture.create_account({ username: 'audit_undelete_target' });
460
+ const del = await rpc_call_for_spec({
461
+ app: { request: fixture.transport },
462
+ path: rpc_path,
463
+ spec: account_delete_action_spec,
464
+ params: { account_id: target.account.id },
465
+ headers: fixture.create_session_headers(),
466
+ });
467
+ assert.ok(del.ok, `account_delete failed: ${del.ok ? '' : JSON.stringify(del.error)}`);
468
+ const res = await rpc_call_for_spec({
469
+ app: { request: fixture.transport },
470
+ path: rpc_path,
471
+ spec: account_undelete_action_spec,
472
+ params: { account_id: target.account.id },
473
+ headers: fixture.create_session_headers(),
474
+ });
475
+ assert.ok(res.ok, `account_undelete failed: ${res.ok ? '' : JSON.stringify(res.error)}`);
476
+ const events = await list_audit_events({ request: fixture.transport }, rpc_path, observer);
477
+ assert_has_event(events, 'account_undelete', 'account_undelete RPC');
478
+ assert_has_event(events, 'actor_undelete', 'account_undelete RPC (per-actor cascade)');
479
+ });
480
+ });
421
481
  // --- Signup route ---
422
482
  describe('signup audit events', () => {
423
483
  test('signup produces signup event', async () => {
@@ -474,6 +534,12 @@ export const describe_audit_completeness_tests = (options) => {
474
534
  'role_grant_revoke',
475
535
  'invite_create',
476
536
  'invite_delete',
537
+ 'account_delete',
538
+ 'account_purge',
539
+ 'account_undelete',
540
+ 'actor_delete',
541
+ 'actor_purge',
542
+ 'actor_undelete',
477
543
  'app_settings_update',
478
544
  ]);
479
545
  /** Event types excluded with justification. */
@@ -0,0 +1,10 @@
1
+ import '../assert_dev_env.js';
2
+ import { type CellCrossTestOptions } from './cell_cross_helpers.js';
3
+ /**
4
+ * Options for the account-lifecycle parity suite. Shares the shape of the
5
+ * cell suites (`setup_test` / `capabilities` / `rpc_path`); reuses
6
+ * `CellCrossTestOptions` rather than minting a structural duplicate.
7
+ */
8
+ export type AccountLifecycleCrossTestOptions = CellCrossTestOptions;
9
+ export declare const describe_account_lifecycle_cross_tests: (options: AccountLifecycleCrossTestOptions) => void;
10
+ //# sourceMappingURL=account_lifecycle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account_lifecycle.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/account_lifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA+B9B,OAAO,EAIN,KAAK,oBAAoB,EACzB,MAAM,yBAAyB,CAAC;AAGjC;;;;GAIG;AACH,MAAM,MAAM,gCAAgC,GAAG,oBAAoB,CAAC;AAEpE,eAAO,MAAM,sCAAsC,GAClD,SAAS,gCAAgC,KACvC,IA4IF,CAAC"}
@@ -0,0 +1,76 @@
1
+ import '../assert_dev_env.js';
2
+ /**
3
+ * Cross-backend parity suite for the account-lifecycle admin verbs:
4
+ * `account_delete` (soft), `account_undelete` (reactivation), and
5
+ * `account_purge` (keeper hard-delete), plus the keeper guard.
6
+ *
7
+ * Like the cell suites, these verbs can't ride the generic
8
+ * `describe_rpc_round_trip_tests`: they're stateful and destructive (a
9
+ * generic round-trip would tombstone the bootstrapped keeper). They
10
+ * live-mount on every spine's RPC path but stay off the declared surface,
11
+ * so this dedicated suite is their cross-impl validator. Every success
12
+ * `result` is parsed against the verb's declared Zod **output** schema, so
13
+ * a TS↔Rust envelope drift fails the assertion.
14
+ *
15
+ * `$lib`-free by contract (relative specifiers only) so it can be imported
16
+ * from the spawnable cross-process test files.
17
+ *
18
+ * @module
19
+ */
20
+ import { describe, assert } from 'vitest';
21
+ import { AccountDeleteOutput, AccountUndeleteOutput, AccountPurgeOutput, AdminAccountListOutput, ERROR_CANNOT_DELETE_KEEPER, } from '../../auth/admin_action_specs.js';
22
+ import { test_if } from './capabilities.js';
23
+ import { cross_rpc_call, error_reason, expect_output, } from './cell_cross_helpers.js';
24
+ import { SPINE_RPC_PATH } from './default_spine_surface.js';
25
+ export const describe_account_lifecycle_cross_tests = (options) => {
26
+ const { setup_test, capabilities } = options;
27
+ const rpc_path = options.rpc_path ?? SPINE_RPC_PATH;
28
+ describe('account lifecycle parity', () => {
29
+ test_if(capabilities.account_lifecycle, 'soft-delete → undelete round-trip (admin)', async () => {
30
+ const fixture = await setup_test();
31
+ const victim = await fixture.create_account({ username: 'lifecycle_victim' });
32
+ const t = fixture.fresh_transport();
33
+ // Keeper account holds ROLE_ADMIN — its session is admin-capable.
34
+ const admin_headers = fixture.create_session_headers();
35
+ const deleted = expect_output(await cross_rpc_call(t, rpc_path, 'account_delete', { account_id: victim.account.id }, admin_headers), AccountDeleteOutput);
36
+ assert.strictEqual(deleted.deleted, true);
37
+ const undeleted = expect_output(await cross_rpc_call(t, rpc_path, 'account_undelete', { account_id: victim.account.id }, admin_headers), AccountUndeleteOutput);
38
+ assert.strictEqual(undeleted.undeleted, true);
39
+ });
40
+ test_if(capabilities.account_lifecycle, 'purge (keeper, confirmed)', async () => {
41
+ const fixture = await setup_test();
42
+ const victim = await fixture.create_account({ username: 'lifecycle_purge' });
43
+ const t = fixture.fresh_transport({ origin: null });
44
+ // Purge is keeper-gated: daemon-token credential, not a session.
45
+ const purged = expect_output(await cross_rpc_call(t, rpc_path, 'account_purge', { account_id: victim.account.id, confirm: true }, fixture.create_daemon_token_headers()), AccountPurgeOutput);
46
+ assert.strictEqual(purged.purged, true);
47
+ });
48
+ test_if(capabilities.account_lifecycle, 'keeper guard: delete + purge refuse the keeper account', async () => {
49
+ const fixture = await setup_test();
50
+ const t = fixture.fresh_transport();
51
+ const del = await cross_rpc_call(t, rpc_path, 'account_delete', { account_id: fixture.account.id }, fixture.create_session_headers());
52
+ assert.strictEqual(del.ok, false, 'delete of keeper account must be refused');
53
+ assert.strictEqual(error_reason(del), ERROR_CANNOT_DELETE_KEEPER);
54
+ const tp = fixture.fresh_transport({ origin: null });
55
+ const purge = await cross_rpc_call(tp, rpc_path, 'account_purge', { account_id: fixture.account.id, confirm: true }, fixture.create_daemon_token_headers());
56
+ assert.strictEqual(purge.ok, false, 'purge of keeper account must be refused');
57
+ assert.strictEqual(error_reason(purge), ERROR_CANNOT_DELETE_KEEPER);
58
+ });
59
+ test_if(capabilities.account_lifecycle, 'admin_account_list include_deleted surfaces tombstoned rows with deleted_at set', async () => {
60
+ const fixture = await setup_test();
61
+ const victim = await fixture.create_account({ username: 'lifecycle_listed' });
62
+ const admin_headers = fixture.create_session_headers();
63
+ const t = fixture.fresh_transport();
64
+ const deleted = expect_output(await cross_rpc_call(t, rpc_path, 'account_delete', { account_id: victim.account.id }, admin_headers), AccountDeleteOutput);
65
+ assert.strictEqual(deleted.deleted, true);
66
+ // Default listing excludes the tombstone.
67
+ const active_only = expect_output(await cross_rpc_call(t, rpc_path, 'admin_account_list', {}, admin_headers), AdminAccountListOutput);
68
+ assert.ok(!active_only.accounts.some((a) => a.account.id === victim.account.id), 'default listing excludes the soft-deleted account');
69
+ // `include_deleted` surfaces it with `deleted_at` populated.
70
+ const with_deleted = expect_output(await cross_rpc_call(t, rpc_path, 'admin_account_list', { include_deleted: true }, admin_headers), AdminAccountListOutput);
71
+ const row = with_deleted.accounts.find((a) => a.account.id === victim.account.id);
72
+ assert.ok(row, 'include_deleted surfaces the tombstoned row');
73
+ assert.ok(row.account.deleted_at !== null, 'tombstoned row carries a non-null deleted_at on both spines');
74
+ });
75
+ });
76
+ };
@@ -35,6 +35,37 @@ export interface BackendCapabilities {
35
35
  * ignores this flag.
36
36
  */
37
37
  readonly sse: boolean;
38
+ /**
39
+ * Cell CRUD verbs (`cell_create` / `cell_get` / `cell_update` /
40
+ * `cell_delete` / `cell_list`) are live-mounted on the backend's RPC
41
+ * path and its DB carries the `fuz_cell` migration namespace. Gates the
42
+ * dedicated `describe_cell_crud_cross_tests` suite. Like `ws` / `sse`,
43
+ * cells stay off the standard declared surface — only this flag opts a
44
+ * backend into the cell parity coverage.
45
+ */
46
+ readonly cell_crud: boolean;
47
+ /**
48
+ * The relation / ACL / audit cell verbs beyond plain CRUD
49
+ * (`cell_grant_*` / `cell_field_*` / `cell_item_*` / `cell_clone` /
50
+ * `cell_audit_list`) are live-mounted on the backend's RPC path. Gates
51
+ * the dedicated `describe_cell_relations_cross_tests` suite — grant
52
+ * lifecycle, field / item bidirectional relations, clone shallow + deep,
53
+ * manage-tier audit gating, and the now-reachable
54
+ * `cell_visibility_manage_only` 403 (editor-grant principal). Like
55
+ * `cell_crud`, these stay off the standard declared surface; a backend
56
+ * mounting only plain CRUD declares `cell_crud: true, cell_relations: false`.
57
+ */
58
+ readonly cell_relations: boolean;
59
+ /**
60
+ * The account-lifecycle admin verbs (`account_delete` soft-delete,
61
+ * `account_undelete` reactivation, `account_purge` keeper hard-delete)
62
+ * are live-mounted on the backend's RPC path. Gates the dedicated
63
+ * `describe_account_lifecycle_cross_tests` suite. Like cells, these
64
+ * destructive/stateful verbs stay off the standard declared surface (the
65
+ * generic round-trip can't drive them — they delete the subject), so
66
+ * this flag opts a backend into the lifecycle parity coverage.
67
+ */
68
+ readonly account_lifecycle: boolean;
38
69
  /**
39
70
  * Test has direct access to backend-internal state (keyring for
40
71
  * signing cookies, DB pool for FK-structural raw queries). Always
@@ -1 +1 @@
1
- {"version":3,"file":"capabilities.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/capabilities.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAmB9B;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IACnC;;;;OAIG;IACH,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC;;;OAGG;IACH,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;IACnC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB;;;;;OAKG;IACH,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB;;;;;;;OAOG;IACH,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;CAClC;AAED;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,EAAE,mBAOpC,CAAC;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,OAAO,GAAI,MAAM,OAAO,EAAE,MAAM,MAAM,EAAE,IAAI,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAG,IAMrF,CAAC"}
1
+ {"version":3,"file":"capabilities.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/capabilities.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAmB9B;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IACnC;;;;OAIG;IACH,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC;;;OAGG;IACH,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;IACnC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB;;;;;OAKG;IACH,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB;;;;;;;OAOG;IACH,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC;;;;;;;;OAQG;IACH,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAC;IACpC;;;;;;;OAOG;IACH,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;CAClC;AAED;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,EAAE,mBAUpC,CAAC;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,OAAO,GAAI,MAAM,OAAO,EAAE,MAAM,MAAM,EAAE,IAAI,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAG,IAMrF,CAAC"}
@@ -26,6 +26,9 @@ export const in_process_capabilities = Object.freeze({
26
26
  login_rate_limit: true,
27
27
  ws: true,
28
28
  sse: true,
29
+ cell_crud: true,
30
+ cell_relations: true,
31
+ account_lifecycle: true,
29
32
  in_process_only: true,
30
33
  });
31
34
  /**
@@ -0,0 +1,39 @@
1
+ import '../assert_dev_env.js';
2
+ import type { z } from 'zod';
3
+ import type { FetchTransport } from '../transports/fetch_transport.js';
4
+ import type { BackendCapabilities } from './capabilities.js';
5
+ import type { SetupTest } from './setup.js';
6
+ /** Shared options for the cell cross-backend parity suites. */
7
+ export interface CellCrossTestOptions {
8
+ /** Per-test fixture-producing function (fresh keeper + db per call). */
9
+ readonly setup_test: SetupTest;
10
+ /** Backend capability declarations — each suite gates on its own flag. */
11
+ readonly capabilities: BackendCapabilities;
12
+ /** RPC endpoint path the cell verbs are mounted on. Default `/api/rpc`. */
13
+ readonly rpc_path?: string;
14
+ }
15
+ /** Minimal JSON-RPC envelope shape the suites read off responses. */
16
+ export interface RpcResult {
17
+ readonly ok: boolean;
18
+ readonly result?: unknown;
19
+ readonly error?: {
20
+ readonly code: number;
21
+ readonly message: string;
22
+ readonly data?: unknown;
23
+ };
24
+ }
25
+ /**
26
+ * POST a JSON-RPC call over a cross-process `FetchTransport` with the given
27
+ * auth headers. Distinct from `rpc_helpers.ts`'s `app`-based `rpc_call`: this
28
+ * variant drives the cookie-jar `FetchTransport` the cross-backend harness
29
+ * spawns against, and returns the slim `RpcResult` the cell suites read.
30
+ */
31
+ export declare const cross_rpc_call: (transport: FetchTransport, path: string, method: string, params: unknown, headers: Record<string, string>) => Promise<RpcResult>;
32
+ /** Pull `error.data.reason` off an RPC error envelope (undefined if absent). */
33
+ export declare const error_reason: (r: RpcResult) => unknown;
34
+ /**
35
+ * Assert the call succeeded and the `result` matches the verb's declared
36
+ * output schema — the wire-shape parity gate. Returns the parsed output.
37
+ */
38
+ export declare const expect_output: <T>(r: RpcResult, schema: z.ZodType<T>) => T;
39
+ //# sourceMappingURL=cell_cross_helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cell_cross_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/cell_cross_helpers.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAmB9B,OAAO,KAAK,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAG3B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,kCAAkC,CAAC;AACrE,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,YAAY,CAAC;AAE1C,+DAA+D;AAC/D,MAAM,WAAW,oBAAoB;IACpC,wEAAwE;IACxE,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC;IAC/B,0EAA0E;IAC1E,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAAC;IAC3C,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,qEAAqE;AACrE,MAAM,WAAW,SAAS;IACzB,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAC,CAAC;CAC5F;AAED;;;;;GAKG;AACH,eAAO,MAAM,cAAc,GAC1B,WAAW,cAAc,EACzB,MAAM,MAAM,EACZ,QAAQ,MAAM,EACd,QAAQ,OAAO,EACf,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAC7B,OAAO,CAAC,SAAS,CAMnB,CAAC;AAEF,gFAAgF;AAChF,eAAO,MAAM,YAAY,GAAI,GAAG,SAAS,KAAG,OAG/B,CAAC;AAEd;;;GAGG;AACH,eAAO,MAAM,aAAa,GAAI,CAAC,EAAE,GAAG,SAAS,EAAE,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAG,CAQrE,CAAC"}
@@ -0,0 +1,45 @@
1
+ import '../assert_dev_env.js';
2
+ /**
3
+ * Shared call-site primitives for the cell cross-backend parity suites
4
+ * (`cell_crud.ts` + `cell_relations.ts`).
5
+ *
6
+ * The cell verbs are stateful and authz-shaped, so both suites POST raw
7
+ * JSON-RPC envelopes (threading ids + auth headers across calls) and parse
8
+ * every success `result` against the verb's declared Zod **output** schema —
9
+ * the wire-shape parity gate. A TS↔Rust envelope drift, not just a payload
10
+ * field drift, fails the assertion.
11
+ *
12
+ * `$lib`-free by contract (relative specifiers only) so the suites can be
13
+ * imported from the spawnable cross-process test files.
14
+ *
15
+ * @module
16
+ */
17
+ import { assert } from 'vitest';
18
+ import { create_rpc_post_init } from '../rpc_helpers.js';
19
+ /**
20
+ * POST a JSON-RPC call over a cross-process `FetchTransport` with the given
21
+ * auth headers. Distinct from `rpc_helpers.ts`'s `app`-based `rpc_call`: this
22
+ * variant drives the cookie-jar `FetchTransport` the cross-backend harness
23
+ * spawns against, and returns the slim `RpcResult` the cell suites read.
24
+ */
25
+ export const cross_rpc_call = async (transport, path, method, params, headers) => {
26
+ const init = create_rpc_post_init(method, params);
27
+ Object.assign(init.headers, headers);
28
+ const res = await transport(path, init);
29
+ const body = (await res.json());
30
+ return { ok: res.ok, result: body.result, error: body.error };
31
+ };
32
+ /** Pull `error.data.reason` off an RPC error envelope (undefined if absent). */
33
+ export const error_reason = (r) => r.error && typeof r.error.data === 'object' && r.error.data !== null
34
+ ? r.error.data.reason
35
+ : undefined;
36
+ /**
37
+ * Assert the call succeeded and the `result` matches the verb's declared
38
+ * output schema — the wire-shape parity gate. Returns the parsed output.
39
+ */
40
+ export const expect_output = (r, schema) => {
41
+ assert.ok(r.ok, `expected success, got ${JSON.stringify(r.error)}`);
42
+ const parsed = schema.safeParse(r.result);
43
+ assert.ok(parsed.success, `result does not match output schema: ${parsed.success ? '' : JSON.stringify(parsed.error.issues)} (got ${JSON.stringify(r.result)})`);
44
+ return parsed.data;
45
+ };
@@ -0,0 +1,4 @@
1
+ import '../assert_dev_env.js';
2
+ import { type CellCrossTestOptions } from './cell_cross_helpers.js';
3
+ export declare const describe_cell_crud_cross_tests: (options: CellCrossTestOptions) => void;
4
+ //# sourceMappingURL=cell_crud.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cell_crud.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/cell_crud.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAqD9B,OAAO,EAIN,KAAK,oBAAoB,EACzB,MAAM,yBAAyB,CAAC;AAGjC,eAAO,MAAM,8BAA8B,GAAI,SAAS,oBAAoB,KAAG,IAwS9E,CAAC"}
@@ -0,0 +1,168 @@
1
+ import '../assert_dev_env.js';
2
+ /**
3
+ * Dedicated stateful cell-CRUD parity suite for the cross-backend harness.
4
+ *
5
+ * The generic `describe_rpc_round_trip_tests` can't cover cells: the verbs
6
+ * are stateful (update / delete / get-by-id need a real cell id threaded
7
+ * from a prior create) and `cell_get`'s input has a top-level `.refine()`.
8
+ * So cells stay off the standard declared surface (`create_spine_surface_spec`)
9
+ * — exactly like ws / sse — and this suite plus its sibling
10
+ * `describe_cell_relations_cross_tests` (grant / field / item / clone / audit)
11
+ * are the cell validators. This one gates on `capabilities.cell_crud`; it runs
12
+ * against any backend that live-mounts the cell surface (the TS spine binary,
13
+ * the in-process Hono app, and the Rust `testing_spine_stub`).
14
+ *
15
+ * Drives the full lifecycle (create → get → update → delete → list, threading
16
+ * the created id) plus the authz matrix the wire contract guarantees. Every
17
+ * success response is parsed against the verb's declared Zod **output** schema
18
+ * (`CellCreateOutput` / `CellGetOutput` / …), so a TS↔Rust envelope drift —
19
+ * not just a `CellJson` field drift — fails the suite:
20
+ *
21
+ * - owner does full CRUD; responses match the output schemas exactly;
22
+ * - anon sees `public` cells only — `private` is 404 (existence not leaked);
23
+ * - a non-owner non-admin editing / reading / deleting another's private cell
24
+ * gets 404 (IDOR mask), never 403;
25
+ * - admin reaches any cell;
26
+ * - duplicate active `path` → 409 (`cell_path_taken`);
27
+ * - `path` write by a non-admin → 403 (`cell_path_admin_only`), on both create
28
+ * and update (even by the owner);
29
+ * - `cell_get` with neither `id` nor `path` → `invalid_params`;
30
+ * - null-auth `cell_list` with `created_by` → `invalid_params`.
31
+ *
32
+ * The visibility-manage-tier 403 (`cell_visibility_manage_only`) needs a
33
+ * non-owner editor, which only a `cell_grant` can produce, so it lives in
34
+ * `describe_cell_relations_cross_tests` alongside the grant verbs rather than
35
+ * here.
36
+ *
37
+ * `$lib`-free by contract (relative specifiers only) so the suite can be
38
+ * imported from the spawnable cross-process test files.
39
+ *
40
+ * @module
41
+ */
42
+ import { describe, assert } from 'vitest';
43
+ import { CellCreateOutput, CellDeleteOutput, CellGetOutput, CellListOutput, CellUpdateOutput, } from '../../auth/cell_action_specs.js';
44
+ import { test_if } from './capabilities.js';
45
+ import { cross_rpc_call, error_reason, expect_output, } from './cell_cross_helpers.js';
46
+ import { SPINE_RPC_PATH } from './default_spine_surface.js';
47
+ export const describe_cell_crud_cross_tests = (options) => {
48
+ const { setup_test, capabilities } = options;
49
+ const rpc_path = options.rpc_path ?? SPINE_RPC_PATH;
50
+ describe('cell CRUD parity', () => {
51
+ test_if(capabilities.cell_crud, 'owner lifecycle: create → get → update → delete → list', async () => {
52
+ const fixture = await setup_test();
53
+ const owner = await fixture.create_account({ username: 'cell_owner' });
54
+ const t = fixture.fresh_transport();
55
+ const owner_headers = owner.create_session_headers();
56
+ // create — default visibility, owner-stamped, no grants
57
+ const created = expect_output(await cross_rpc_call(t, rpc_path, 'cell_create', { data: { kind: 'note', label: 'hi' } }, owner_headers), CellCreateOutput);
58
+ assert.strictEqual(created.cell.visibility, 'private');
59
+ assert.strictEqual(created.cell.created_by, owner.actor.id);
60
+ assert.strictEqual(created.cell.updated_by, null);
61
+ assert.strictEqual(created.cell.grant_count, 0);
62
+ const cell_id = created.cell.id;
63
+ // get by id — full CellGetOutput envelope; relations empty in the first cut
64
+ const got = expect_output(await cross_rpc_call(t, rpc_path, 'cell_get', { id: cell_id }, owner_headers), CellGetOutput);
65
+ assert.strictEqual(got.cell.id, cell_id);
66
+ assert.deepStrictEqual(got.fields, []);
67
+ assert.deepStrictEqual(got.items, []);
68
+ assert.strictEqual(got.fields_truncated, false);
69
+ assert.strictEqual(got.items_truncated, false);
70
+ assert.strictEqual(got.can_edit, true);
71
+ assert.strictEqual(got.can_grant, true); // owner is manage-tier
72
+ // update data + flip to public (owner is manage-tier, so visibility write is allowed)
73
+ const updated = expect_output(await cross_rpc_call(t, rpc_path, 'cell_update', { cell_id, data: { kind: 'note', label: 'hi2' }, visibility: 'public' }, owner_headers), CellUpdateOutput);
74
+ assert.strictEqual(updated.cell.visibility, 'public');
75
+ assert.strictEqual(updated.cell.updated_by, owner.actor.id);
76
+ // list includes it
77
+ const listed = expect_output(await cross_rpc_call(t, rpc_path, 'cell_list', {}, owner_headers), CellListOutput);
78
+ assert.ok(listed.cells.some((c) => c.id === cell_id), 'owner cell_list omitted the cell');
79
+ // delete → subsequent get is 404
80
+ const deleted = expect_output(await cross_rpc_call(t, rpc_path, 'cell_delete', { cell_id }, owner_headers), CellDeleteOutput);
81
+ assert.strictEqual(deleted.deleted, true);
82
+ const gone = await cross_rpc_call(t, rpc_path, 'cell_get', { id: cell_id }, owner_headers);
83
+ assert.ok(!gone.ok, 'deleted cell still readable');
84
+ assert.strictEqual(error_reason(gone), 'cell_not_found');
85
+ });
86
+ test_if(capabilities.cell_crud, 'anon sees public cells only; private is 404', async () => {
87
+ const fixture = await setup_test();
88
+ const owner = await fixture.create_account({ username: 'cell_anon_owner' });
89
+ const owner_headers = owner.create_session_headers();
90
+ const authed = fixture.fresh_transport();
91
+ const priv = expect_output(await cross_rpc_call(authed, rpc_path, 'cell_create', { data: { kind: 'note' }, visibility: 'private' }, owner_headers), CellCreateOutput).cell;
92
+ const pub = expect_output(await cross_rpc_call(authed, rpc_path, 'cell_create', { data: { kind: 'note' }, visibility: 'public' }, owner_headers), CellCreateOutput).cell;
93
+ const anon = fixture.fresh_transport({ origin: null });
94
+ const anon_pub = await cross_rpc_call(anon, rpc_path, 'cell_get', { id: pub.id }, {});
95
+ assert.ok(anon_pub.ok, `anon could not read public cell: ${JSON.stringify(anon_pub.error)}`);
96
+ const anon_priv = await cross_rpc_call(anon, rpc_path, 'cell_get', { id: priv.id }, {});
97
+ assert.ok(!anon_priv.ok, 'anon read a private cell');
98
+ assert.strictEqual(error_reason(anon_priv), 'cell_not_found');
99
+ const anon_list = expect_output(await cross_rpc_call(anon, rpc_path, 'cell_list', {}, {}), CellListOutput);
100
+ const anon_ids = anon_list.cells.map((c) => c.id);
101
+ assert.ok(anon_ids.includes(pub.id), 'anon list missing public cell');
102
+ assert.ok(!anon_ids.includes(priv.id), 'anon list leaked private cell');
103
+ });
104
+ test_if(capabilities.cell_crud, 'non-owner edit/read/delete of a private cell → 404 (IDOR mask)', async () => {
105
+ const fixture = await setup_test();
106
+ const owner = await fixture.create_account({ username: 'cell_idor_owner' });
107
+ const other = await fixture.create_account({ username: 'cell_idor_other' });
108
+ const t = fixture.fresh_transport();
109
+ const priv = expect_output(await cross_rpc_call(t, rpc_path, 'cell_create', { data: { kind: 'note' } }, owner.create_session_headers()), CellCreateOutput).cell;
110
+ const other_headers = other.create_session_headers();
111
+ const read = await cross_rpc_call(t, rpc_path, 'cell_get', { id: priv.id }, other_headers);
112
+ assert.strictEqual(error_reason(read), 'cell_not_found');
113
+ const edit = await cross_rpc_call(t, rpc_path, 'cell_update', { cell_id: priv.id, data: { kind: 'note', label: 'x' } }, other_headers);
114
+ assert.ok(!edit.ok, 'non-owner edited a private cell');
115
+ assert.strictEqual(error_reason(edit), 'cell_not_found');
116
+ const del = await cross_rpc_call(t, rpc_path, 'cell_delete', { cell_id: priv.id }, other_headers);
117
+ assert.ok(!del.ok, 'non-owner deleted a private cell');
118
+ assert.strictEqual(error_reason(del), 'cell_not_found');
119
+ });
120
+ test_if(capabilities.cell_crud, 'admin (keeper) reaches another actor’s private cell', async () => {
121
+ const fixture = await setup_test();
122
+ const owner = await fixture.create_account({ username: 'cell_admin_owner' });
123
+ const t = fixture.fresh_transport();
124
+ const priv = expect_output(await cross_rpc_call(t, rpc_path, 'cell_create', { data: { kind: 'note' } }, owner.create_session_headers()), CellCreateOutput).cell;
125
+ // `fixture` is the bootstrapped keeper (holds ROLE_ADMIN).
126
+ const admin_read = expect_output(await cross_rpc_call(t, rpc_path, 'cell_get', { id: priv.id }, fixture.create_session_headers()), CellGetOutput);
127
+ assert.strictEqual(admin_read.cell.id, priv.id);
128
+ });
129
+ test_if(capabilities.cell_crud, 'duplicate active path → 409 conflict', async () => {
130
+ const fixture = await setup_test();
131
+ const t = fixture.fresh_transport();
132
+ // `path` writes are admin-only; the keeper is admin.
133
+ const admin_headers = fixture.create_session_headers();
134
+ expect_output(await cross_rpc_call(t, rpc_path, 'cell_create', { data: { kind: 'note' }, path: 'parity/dup' }, admin_headers), CellCreateOutput);
135
+ const dup = await cross_rpc_call(t, rpc_path, 'cell_create', { data: { kind: 'note' }, path: 'parity/dup' }, admin_headers);
136
+ assert.ok(!dup.ok, 'duplicate path was accepted');
137
+ assert.strictEqual(error_reason(dup), 'cell_path_taken');
138
+ });
139
+ test_if(capabilities.cell_crud, 'path write by non-admin → 403 (create and update)', async () => {
140
+ const fixture = await setup_test();
141
+ const owner = await fixture.create_account({ username: 'cell_path_owner' });
142
+ const t = fixture.fresh_transport();
143
+ const owner_headers = owner.create_session_headers();
144
+ const create_with_path = await cross_rpc_call(t, rpc_path, 'cell_create', { data: { kind: 'note' }, path: 'parity/forbidden' }, owner_headers);
145
+ assert.ok(!create_with_path.ok, 'non-admin set a path on create');
146
+ assert.strictEqual(error_reason(create_with_path), 'cell_path_admin_only');
147
+ // Even owning the cell, a non-admin cannot write `path` on update.
148
+ const owned = expect_output(await cross_rpc_call(t, rpc_path, 'cell_create', { data: { kind: 'note' } }, owner_headers), CellCreateOutput).cell;
149
+ const update_path = await cross_rpc_call(t, rpc_path, 'cell_update', { cell_id: owned.id, path: 'parity/owned' }, owner_headers);
150
+ assert.ok(!update_path.ok, 'non-admin set a path on update');
151
+ assert.strictEqual(error_reason(update_path), 'cell_path_admin_only');
152
+ });
153
+ test_if(capabilities.cell_crud, 'cell_get without id or path → invalid_params', async () => {
154
+ const fixture = await setup_test();
155
+ const bad = await cross_rpc_call(fixture.fresh_transport(), rpc_path, 'cell_get', {}, fixture.create_session_headers());
156
+ assert.ok(!bad.ok, 'cell_get with empty params succeeded');
157
+ // -32602 invalid_params (refine or handler guard).
158
+ assert.strictEqual(bad.error?.code, -32602);
159
+ });
160
+ test_if(capabilities.cell_crud, 'null-auth cell_list with created_by → invalid_params', async () => {
161
+ const fixture = await setup_test();
162
+ const anon = fixture.fresh_transport({ origin: null });
163
+ const bad = await cross_rpc_call(anon, rpc_path, 'cell_list', { created_by: fixture.actor.id }, {});
164
+ assert.ok(!bad.ok, 'anon created_by filter accepted');
165
+ assert.strictEqual(error_reason(bad), 'cell_list_created_by_requires_auth');
166
+ });
167
+ });
168
+ };
@@ -0,0 +1,4 @@
1
+ import '../assert_dev_env.js';
2
+ import { type CellCrossTestOptions } from './cell_cross_helpers.js';
3
+ export declare const describe_cell_relations_cross_tests: (options: CellCrossTestOptions) => void;
4
+ //# sourceMappingURL=cell_relations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cell_relations.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/cell_relations.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAkE9B,OAAO,EAIN,KAAK,oBAAoB,EACzB,MAAM,yBAAyB,CAAC;AAGjC,eAAO,MAAM,mCAAmC,GAAI,SAAS,oBAAoB,KAAG,IAsfnF,CAAC"}