@fuzdev/fuz_app 0.67.1 → 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.
- package/dist/auth/CLAUDE.md +99 -5
- package/dist/auth/account_queries.d.ts +87 -4
- package/dist/auth/account_queries.d.ts.map +1 -1
- package/dist/auth/account_queries.js +107 -17
- package/dist/auth/account_schema.d.ts +19 -0
- package/dist/auth/account_schema.d.ts.map +1 -1
- package/dist/auth/account_schema.js +8 -0
- package/dist/auth/admin_action_specs.d.ts +168 -0
- package/dist/auth/admin_action_specs.d.ts.map +1 -1
- package/dist/auth/admin_action_specs.js +146 -1
- package/dist/auth/admin_actions.d.ts.map +1 -1
- package/dist/auth/admin_actions.js +218 -4
- package/dist/auth/audit_log_ddl.d.ts +10 -1
- package/dist/auth/audit_log_ddl.d.ts.map +1 -1
- package/dist/auth/audit_log_ddl.js +13 -4
- package/dist/auth/audit_log_schema.d.ts +34 -1
- package/dist/auth/audit_log_schema.d.ts.map +1 -1
- package/dist/auth/audit_log_schema.js +73 -0
- package/dist/auth/auth_ddl.d.ts +2 -2
- package/dist/auth/auth_ddl.d.ts.map +1 -1
- package/dist/auth/auth_ddl.js +10 -2
- package/dist/auth/cell_action_specs.d.ts +1295 -0
- package/dist/auth/cell_action_specs.d.ts.map +1 -0
- package/dist/auth/cell_action_specs.js +397 -0
- package/dist/auth/cell_actions.d.ts +63 -0
- package/dist/auth/cell_actions.d.ts.map +1 -0
- package/dist/auth/cell_actions.js +546 -0
- package/dist/auth/cell_audit_action_specs.d.ts +131 -0
- package/dist/auth/cell_audit_action_specs.d.ts.map +1 -0
- package/dist/auth/cell_audit_action_specs.js +70 -0
- package/dist/auth/cell_audit_actions.d.ts +18 -0
- package/dist/auth/cell_audit_actions.d.ts.map +1 -0
- package/dist/auth/cell_audit_actions.js +59 -0
- package/dist/auth/cell_audit_events.d.ts +28 -0
- package/dist/auth/cell_audit_events.d.ts.map +1 -0
- package/dist/auth/cell_audit_events.js +42 -0
- package/dist/auth/cell_audit_metadata.d.ts +48 -0
- package/dist/auth/cell_audit_metadata.d.ts.map +1 -0
- package/dist/auth/cell_audit_metadata.js +46 -0
- package/dist/auth/cell_authorize.d.ts +88 -0
- package/dist/auth/cell_authorize.d.ts.map +1 -0
- package/dist/auth/cell_authorize.js +172 -0
- package/dist/auth/cell_data_schema.d.ts +44 -0
- package/dist/auth/cell_data_schema.d.ts.map +1 -0
- package/dist/auth/cell_data_schema.js +42 -0
- package/dist/auth/cell_field_action_specs.d.ts +244 -0
- package/dist/auth/cell_field_action_specs.d.ts.map +1 -0
- package/dist/auth/cell_field_action_specs.js +136 -0
- package/dist/auth/cell_field_actions.d.ts +34 -0
- package/dist/auth/cell_field_actions.d.ts.map +1 -0
- package/dist/auth/cell_field_actions.js +153 -0
- package/dist/auth/cell_field_audit_metadata.d.ts +30 -0
- package/dist/auth/cell_field_audit_metadata.d.ts.map +1 -0
- package/dist/auth/cell_field_audit_metadata.js +28 -0
- package/dist/auth/cell_grant_action_specs.d.ts +333 -0
- package/dist/auth/cell_grant_action_specs.d.ts.map +1 -0
- package/dist/auth/cell_grant_action_specs.js +148 -0
- package/dist/auth/cell_grant_actions.d.ts +50 -0
- package/dist/auth/cell_grant_actions.d.ts.map +1 -0
- package/dist/auth/cell_grant_actions.js +208 -0
- package/dist/auth/cell_grant_audit_metadata.d.ts +75 -0
- package/dist/auth/cell_grant_audit_metadata.d.ts.map +1 -0
- package/dist/auth/cell_grant_audit_metadata.js +54 -0
- package/dist/auth/cell_item_action_specs.d.ts +331 -0
- package/dist/auth/cell_item_action_specs.d.ts.map +1 -0
- package/dist/auth/cell_item_action_specs.js +182 -0
- package/dist/auth/cell_item_actions.d.ts +37 -0
- package/dist/auth/cell_item_actions.d.ts.map +1 -0
- package/dist/auth/cell_item_actions.js +204 -0
- package/dist/auth/cell_item_audit_metadata.d.ts +35 -0
- package/dist/auth/cell_item_audit_metadata.d.ts.map +1 -0
- package/dist/auth/cell_item_audit_metadata.js +32 -0
- package/dist/auth/cell_relation_visibility.d.ts +32 -0
- package/dist/auth/cell_relation_visibility.d.ts.map +1 -0
- package/dist/auth/cell_relation_visibility.js +57 -0
- package/dist/auth/deps.d.ts +9 -0
- package/dist/auth/deps.d.ts.map +1 -1
- package/dist/auth/role_grant_queries.d.ts +30 -0
- package/dist/auth/role_grant_queries.d.ts.map +1 -1
- package/dist/auth/role_grant_queries.js +54 -0
- package/dist/db/CLAUDE.md +118 -0
- package/dist/db/cell_audit_queries.d.ts +26 -0
- package/dist/db/cell_audit_queries.d.ts.map +1 -0
- package/dist/db/cell_audit_queries.js +53 -0
- package/dist/db/cell_ddl.d.ts +151 -0
- package/dist/db/cell_ddl.d.ts.map +1 -0
- package/dist/db/cell_ddl.js +247 -0
- package/dist/db/cell_field_queries.d.ts +105 -0
- package/dist/db/cell_field_queries.d.ts.map +1 -0
- package/dist/db/cell_field_queries.js +113 -0
- package/dist/db/cell_grant_queries.d.ts +132 -0
- package/dist/db/cell_grant_queries.d.ts.map +1 -0
- package/dist/db/cell_grant_queries.js +145 -0
- package/dist/db/cell_history_ddl.d.ts +38 -0
- package/dist/db/cell_history_ddl.d.ts.map +1 -0
- package/dist/db/cell_history_ddl.js +61 -0
- package/dist/db/cell_item_queries.d.ts +107 -0
- package/dist/db/cell_item_queries.d.ts.map +1 -0
- package/dist/db/cell_item_queries.js +119 -0
- package/dist/db/cell_queries.d.ts +327 -0
- package/dist/db/cell_queries.d.ts.map +1 -0
- package/dist/db/cell_queries.js +431 -0
- package/dist/db/fact_ddl.d.ts +38 -0
- package/dist/db/fact_ddl.d.ts.map +1 -0
- package/dist/db/fact_ddl.js +71 -0
- package/dist/db/fact_queries.d.ts +140 -0
- package/dist/db/fact_queries.d.ts.map +1 -0
- package/dist/db/fact_queries.js +161 -0
- package/dist/db/fact_store.d.ts +112 -0
- package/dist/db/fact_store.d.ts.map +1 -0
- package/dist/db/fact_store.js +225 -0
- package/dist/server/env.d.ts +2 -0
- package/dist/server/env.d.ts.map +1 -1
- package/dist/server/env.js +6 -0
- package/dist/server/fact_write.d.ts +32 -0
- package/dist/server/fact_write.d.ts.map +1 -0
- package/dist/server/fact_write.js +56 -0
- package/dist/server/file_fact_fetcher.d.ts +42 -0
- package/dist/server/file_fact_fetcher.d.ts.map +1 -0
- package/dist/server/file_fact_fetcher.js +60 -0
- package/dist/server/file_fact_url.d.ts +53 -0
- package/dist/server/file_fact_url.d.ts.map +1 -0
- package/dist/server/file_fact_url.js +52 -0
- package/dist/server/serve_fact_route.d.ts +78 -0
- package/dist/server/serve_fact_route.d.ts.map +1 -0
- package/dist/server/serve_fact_route.js +205 -0
- package/dist/testing/CLAUDE.md +58 -5
- package/dist/testing/app_server.d.ts +12 -0
- package/dist/testing/app_server.d.ts.map +1 -1
- package/dist/testing/app_server.js +36 -2
- package/dist/testing/audit_completeness.d.ts.map +1 -1
- package/dist/testing/audit_completeness.js +67 -1
- package/dist/testing/cross_backend/account_lifecycle.d.ts +10 -0
- package/dist/testing/cross_backend/account_lifecycle.d.ts.map +1 -0
- package/dist/testing/cross_backend/account_lifecycle.js +76 -0
- package/dist/testing/cross_backend/capabilities.d.ts +31 -0
- package/dist/testing/cross_backend/capabilities.d.ts.map +1 -1
- package/dist/testing/cross_backend/capabilities.js +3 -0
- package/dist/testing/cross_backend/cell_cross_helpers.d.ts +39 -0
- package/dist/testing/cross_backend/cell_cross_helpers.d.ts.map +1 -0
- package/dist/testing/cross_backend/cell_cross_helpers.js +45 -0
- package/dist/testing/cross_backend/cell_crud.d.ts +4 -0
- package/dist/testing/cross_backend/cell_crud.d.ts.map +1 -0
- package/dist/testing/cross_backend/cell_crud.js +168 -0
- package/dist/testing/cross_backend/cell_relations.d.ts +4 -0
- package/dist/testing/cross_backend/cell_relations.d.ts.map +1 -0
- package/dist/testing/cross_backend/cell_relations.js +229 -0
- package/dist/testing/cross_backend/default_backend_configs.d.ts.map +1 -1
- package/dist/testing/cross_backend/default_backend_configs.js +6 -0
- package/dist/testing/cross_backend/setup.d.ts.map +1 -1
- package/dist/testing/cross_backend/setup.js +5 -0
- package/dist/testing/entities.d.ts.map +1 -1
- package/dist/testing/entities.js +4 -0
- package/dist/testing/ws_round_trip.d.ts.map +1 -1
- package/dist/testing/ws_round_trip.js +4 -0
- package/dist/ui/AdminAccounts.svelte +58 -0
- package/dist/ui/AdminAccounts.svelte.d.ts.map +1 -1
- package/dist/ui/admin_accounts_state.svelte.d.ts +30 -2
- package/dist/ui/admin_accounts_state.svelte.d.ts.map +1 -1
- package/dist/ui/admin_accounts_state.svelte.js +45 -1
- package/dist/ui/admin_rpc_adapters.d.ts +6 -2
- package/dist/ui/admin_rpc_adapters.d.ts.map +1 -1
- package/dist/ui/admin_rpc_adapters.js +5 -1
- package/package.json +2 -2
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import '../assert_dev_env.js';
|
|
2
|
+
/**
|
|
3
|
+
* Dedicated cell relation / ACL / audit parity suite for the cross-backend
|
|
4
|
+
* harness — the sibling of `describe_cell_crud_cross_tests` covering every
|
|
5
|
+
* cell verb beyond plain CRUD: `cell_grant_*`, `cell_field_*`,
|
|
6
|
+
* `cell_item_*`, `cell_clone`, and `cell_audit_list`.
|
|
7
|
+
*
|
|
8
|
+
* Like the CRUD suite (and ws / sse), these verbs are live-mounted on the
|
|
9
|
+
* spine RPC path but stay off the standard declared surface, so the generic
|
|
10
|
+
* `describe_rpc_round_trip_tests` never drives them. Every success response
|
|
11
|
+
* is parsed against the verb's declared Zod **output** schema, so a TS↔Rust
|
|
12
|
+
* envelope drift fails the suite — not just a payload-field drift.
|
|
13
|
+
*
|
|
14
|
+
* Coverage (gated on `capabilities.cell_relations`):
|
|
15
|
+
*
|
|
16
|
+
* - **grant lifecycle** — owner grants an actor-shaped editor; the grantee
|
|
17
|
+
* gains edit (was 404 before the grant); `cell_grant_list` is manage-tier
|
|
18
|
+
* (owner sees it, the editor gets the IDOR 404); revoke drops the edit path.
|
|
19
|
+
* - **`cell_visibility_manage_only`** — the editor-grant holder can edit
|
|
20
|
+
* content but flipping `visibility` is 403 (the case the 5-verb CRUD cut
|
|
21
|
+
* couldn't reach without a grant principal).
|
|
22
|
+
* - **fields** — `cell_field_set` UPSERT, forward + reverse `cell_field_list`,
|
|
23
|
+
* idempotent `cell_field_delete`.
|
|
24
|
+
* - **items** — `cell_item_insert` at fractional-index positions, forward
|
|
25
|
+
* (lex-ordered) + reverse `cell_item_list`, `cell_item_move`, idempotent
|
|
26
|
+
* `cell_item_delete`.
|
|
27
|
+
* - **clone** — shallow copies item / field *edges* (shared `child_id` /
|
|
28
|
+
* `target_id`); deep clones each viewable child into a fresh cell at the
|
|
29
|
+
* same position. Both null `path` and stamp the caller as owner.
|
|
30
|
+
* - **audit** — `cell_audit_list` is manage-tier: the owner reads the cell's
|
|
31
|
+
* timeline; a viewer-grant holder who can `cell_get` the cell still gets the
|
|
32
|
+
* IDOR 404 on the timeline (D14).
|
|
33
|
+
*
|
|
34
|
+
* Only **actor-shaped** grants are exercised — role-shaped principals need a
|
|
35
|
+
* closed role registry the Rust spine deliberately lacks, so role-grant
|
|
36
|
+
* parity is out of scope here (the TS impl covers it in-process).
|
|
37
|
+
*
|
|
38
|
+
* `$lib`-free by contract (relative specifiers only) so the suite can be
|
|
39
|
+
* imported from the spawnable cross-process test files.
|
|
40
|
+
*
|
|
41
|
+
* @module
|
|
42
|
+
*/
|
|
43
|
+
import { describe, assert } from 'vitest';
|
|
44
|
+
import { fractional_index_between } from '@fuzdev/fuz_util/fractional_index.js';
|
|
45
|
+
import { CellCreateOutput, CellUpdateOutput, CellCloneOutput } from '../../auth/cell_action_specs.js';
|
|
46
|
+
import { CellGrantCreateOutput, CellGrantListOutput, CellGrantRevokeOutput, } from '../../auth/cell_grant_action_specs.js';
|
|
47
|
+
import { CellFieldDeleteOutput, CellFieldListOutput, CellFieldSetOutput, } from '../../auth/cell_field_action_specs.js';
|
|
48
|
+
import { CellItemDeleteOutput, CellItemInsertOutput, CellItemListOutput, CellItemMoveOutput, } from '../../auth/cell_item_action_specs.js';
|
|
49
|
+
import { CellAuditListOutput } from '../../auth/cell_audit_action_specs.js';
|
|
50
|
+
import { test_if } from './capabilities.js';
|
|
51
|
+
import { cross_rpc_call, error_reason, expect_output, } from './cell_cross_helpers.js';
|
|
52
|
+
import { SPINE_RPC_PATH } from './default_spine_surface.js';
|
|
53
|
+
export const describe_cell_relations_cross_tests = (options) => {
|
|
54
|
+
const { setup_test, capabilities } = options;
|
|
55
|
+
const rpc_path = options.rpc_path ?? SPINE_RPC_PATH;
|
|
56
|
+
describe('cell relations parity', () => {
|
|
57
|
+
test_if(capabilities.cell_relations, 'grant lifecycle: editor grant enables edit; grant_list is manage-tier; revoke drops it', async () => {
|
|
58
|
+
const fixture = await setup_test();
|
|
59
|
+
const owner = await fixture.create_account({ username: 'cell_grant_owner' });
|
|
60
|
+
const editor = await fixture.create_account({ username: 'cell_grant_editor' });
|
|
61
|
+
const t = fixture.fresh_transport();
|
|
62
|
+
const owner_h = owner.create_session_headers();
|
|
63
|
+
const editor_h = editor.create_session_headers();
|
|
64
|
+
const cell = expect_output(await cross_rpc_call(t, rpc_path, 'cell_create', { data: { kind: 'note' } }, owner_h), CellCreateOutput).cell;
|
|
65
|
+
// Before the grant the editor can't even see the private cell.
|
|
66
|
+
const pre = await cross_rpc_call(t, rpc_path, 'cell_update', { cell_id: cell.id, data: { kind: 'note', label: 'x' } }, editor_h);
|
|
67
|
+
assert.ok(!pre.ok, 'non-grantee edited a private cell');
|
|
68
|
+
assert.strictEqual(error_reason(pre), 'cell_not_found');
|
|
69
|
+
// Owner (manage-tier) grants the editor an actor-shaped editor grant.
|
|
70
|
+
const grant = expect_output(await cross_rpc_call(t, rpc_path, 'cell_grant_create', {
|
|
71
|
+
cell_id: cell.id,
|
|
72
|
+
level: 'editor',
|
|
73
|
+
principal: { kind: 'actor', actor_id: editor.actor.id },
|
|
74
|
+
}, owner_h), CellGrantCreateOutput).grant;
|
|
75
|
+
assert.strictEqual(grant.level, 'editor');
|
|
76
|
+
assert.strictEqual(grant.actor_id, editor.actor.id);
|
|
77
|
+
assert.strictEqual(grant.role, null);
|
|
78
|
+
// The editor can now edit content.
|
|
79
|
+
const edited = expect_output(await cross_rpc_call(t, rpc_path, 'cell_update', { cell_id: cell.id, data: { kind: 'note', label: 'by editor' } }, editor_h), CellUpdateOutput);
|
|
80
|
+
assert.strictEqual(edited.cell.updated_by, editor.actor.id);
|
|
81
|
+
// grant_list is manage-tier: owner sees the grant.
|
|
82
|
+
const owner_grants = expect_output(await cross_rpc_call(t, rpc_path, 'cell_grant_list', { cell_id: cell.id }, owner_h), CellGrantListOutput);
|
|
83
|
+
assert.ok(owner_grants.grants.some((g) => g.id === grant.id), 'owner grant_list omitted the grant');
|
|
84
|
+
// The editor (non-manage) gets the IDOR 404 on grant_list.
|
|
85
|
+
const editor_grants = await cross_rpc_call(t, rpc_path, 'cell_grant_list', { cell_id: cell.id }, editor_h);
|
|
86
|
+
assert.ok(!editor_grants.ok, 'editor read the grant list');
|
|
87
|
+
assert.strictEqual(error_reason(editor_grants), 'cell_not_found');
|
|
88
|
+
// Revoke and confirm the edit path is gone.
|
|
89
|
+
const revoked = expect_output(await cross_rpc_call(t, rpc_path, 'cell_grant_revoke', { grant_id: grant.id }, owner_h), CellGrantRevokeOutput);
|
|
90
|
+
assert.strictEqual(revoked.ok, true);
|
|
91
|
+
const post = await cross_rpc_call(t, rpc_path, 'cell_update', { cell_id: cell.id, data: { kind: 'note', label: 'y' } }, editor_h);
|
|
92
|
+
assert.ok(!post.ok, 'revoked editor still edited');
|
|
93
|
+
assert.strictEqual(error_reason(post), 'cell_not_found');
|
|
94
|
+
});
|
|
95
|
+
test_if(capabilities.cell_relations, 'editor-grant holder cannot flip visibility → cell_visibility_manage_only', async () => {
|
|
96
|
+
const fixture = await setup_test();
|
|
97
|
+
const owner = await fixture.create_account({ username: 'cell_vis_owner' });
|
|
98
|
+
const editor = await fixture.create_account({ username: 'cell_vis_editor' });
|
|
99
|
+
const t = fixture.fresh_transport();
|
|
100
|
+
const owner_h = owner.create_session_headers();
|
|
101
|
+
const editor_h = editor.create_session_headers();
|
|
102
|
+
const cell = expect_output(await cross_rpc_call(t, rpc_path, 'cell_create', { data: { kind: 'note' } }, owner_h), CellCreateOutput).cell;
|
|
103
|
+
expect_output(await cross_rpc_call(t, rpc_path, 'cell_grant_create', {
|
|
104
|
+
cell_id: cell.id,
|
|
105
|
+
level: 'editor',
|
|
106
|
+
principal: { kind: 'actor', actor_id: editor.actor.id },
|
|
107
|
+
}, owner_h), CellGrantCreateOutput);
|
|
108
|
+
// Content edits pass (editor tier); a visibility write is manage-tier.
|
|
109
|
+
expect_output(await cross_rpc_call(t, rpc_path, 'cell_update', { cell_id: cell.id, data: { kind: 'note', label: 'ok' } }, editor_h), CellUpdateOutput);
|
|
110
|
+
const vis = await cross_rpc_call(t, rpc_path, 'cell_update', { cell_id: cell.id, visibility: 'public' }, editor_h);
|
|
111
|
+
assert.ok(!vis.ok, 'editor flipped visibility');
|
|
112
|
+
assert.strictEqual(error_reason(vis), 'cell_visibility_manage_only');
|
|
113
|
+
});
|
|
114
|
+
test_if(capabilities.cell_relations, 'field set → forward + reverse list → idempotent delete', async () => {
|
|
115
|
+
const fixture = await setup_test();
|
|
116
|
+
const owner = await fixture.create_account({ username: 'cell_field_owner' });
|
|
117
|
+
const t = fixture.fresh_transport();
|
|
118
|
+
const h = owner.create_session_headers();
|
|
119
|
+
const source = expect_output(await cross_rpc_call(t, rpc_path, 'cell_create', { data: { kind: 'note' } }, h), CellCreateOutput).cell;
|
|
120
|
+
const target = expect_output(await cross_rpc_call(t, rpc_path, 'cell_create', { data: { kind: 'note' } }, h), CellCreateOutput).cell;
|
|
121
|
+
const set = expect_output(await cross_rpc_call(t, rpc_path, 'cell_field_set', { source_id: source.id, name: 'cover', target_id: target.id }, h), CellFieldSetOutput);
|
|
122
|
+
assert.strictEqual(set.field.name, 'cover');
|
|
123
|
+
assert.strictEqual(set.field.source_id, source.id);
|
|
124
|
+
assert.strictEqual(set.field.target_id, target.id);
|
|
125
|
+
const forward = expect_output(await cross_rpc_call(t, rpc_path, 'cell_field_list', { source_id: source.id }, h), CellFieldListOutput);
|
|
126
|
+
assert.ok(forward.fields.some((f) => f.name === 'cover' && f.target_id === target.id), 'forward field_list missing the field');
|
|
127
|
+
const reverse = expect_output(await cross_rpc_call(t, rpc_path, 'cell_field_list', { target_id: target.id }, h), CellFieldListOutput);
|
|
128
|
+
assert.ok(reverse.fields.some((f) => f.source_id === source.id), 'reverse field_list missing the upfield');
|
|
129
|
+
const del = expect_output(await cross_rpc_call(t, rpc_path, 'cell_field_delete', { source_id: source.id, name: 'cover' }, h), CellFieldDeleteOutput);
|
|
130
|
+
assert.strictEqual(del.deleted, true);
|
|
131
|
+
const del2 = expect_output(await cross_rpc_call(t, rpc_path, 'cell_field_delete', { source_id: source.id, name: 'cover' }, h), CellFieldDeleteOutput);
|
|
132
|
+
assert.strictEqual(del2.deleted, false);
|
|
133
|
+
});
|
|
134
|
+
test_if(capabilities.cell_relations, 'item insert → ordered forward + reverse list → move → idempotent delete', async () => {
|
|
135
|
+
const fixture = await setup_test();
|
|
136
|
+
const owner = await fixture.create_account({ username: 'cell_item_owner' });
|
|
137
|
+
const t = fixture.fresh_transport();
|
|
138
|
+
const h = owner.create_session_headers();
|
|
139
|
+
const make = async () => expect_output(await cross_rpc_call(t, rpc_path, 'cell_create', { data: { kind: 'note' } }, h), CellCreateOutput).cell.id;
|
|
140
|
+
const parent = await make();
|
|
141
|
+
const child_a = await make();
|
|
142
|
+
const child_b = await make();
|
|
143
|
+
const pos_a = fractional_index_between(null, null);
|
|
144
|
+
const ins_a = expect_output(await cross_rpc_call(t, rpc_path, 'cell_item_insert', { parent_id: parent, child_id: child_a, position: pos_a }, h), CellItemInsertOutput);
|
|
145
|
+
assert.strictEqual(ins_a.item.child_id, child_a);
|
|
146
|
+
const pos_b = fractional_index_between(pos_a, null);
|
|
147
|
+
expect_output(await cross_rpc_call(t, rpc_path, 'cell_item_insert', { parent_id: parent, child_id: child_b, position: pos_b }, h), CellItemInsertOutput);
|
|
148
|
+
// Forward list is lex-ordered by position; child_a (pos_a < pos_b) first.
|
|
149
|
+
const forward = expect_output(await cross_rpc_call(t, rpc_path, 'cell_item_list', { parent_id: parent }, h), CellItemListOutput);
|
|
150
|
+
assert.strictEqual(forward.items.length, 2);
|
|
151
|
+
assert.strictEqual(forward.items[0].child_id, child_a);
|
|
152
|
+
assert.strictEqual(forward.items[1].child_id, child_b);
|
|
153
|
+
// Reverse list — which parents contain child_a.
|
|
154
|
+
const reverse = expect_output(await cross_rpc_call(t, rpc_path, 'cell_item_list', { child_id: child_a }, h), CellItemListOutput);
|
|
155
|
+
assert.ok(reverse.items.some((i) => i.parent_id === parent), 'reverse item_list missing the parent');
|
|
156
|
+
// Move child_b ahead of child_a.
|
|
157
|
+
const new_pos = fractional_index_between(null, pos_a);
|
|
158
|
+
const moved = expect_output(await cross_rpc_call(t, rpc_path, 'cell_item_move', { parent_id: parent, position: pos_b, new_position: new_pos }, h), CellItemMoveOutput);
|
|
159
|
+
assert.strictEqual(moved.item.position, new_pos);
|
|
160
|
+
assert.strictEqual(moved.item.child_id, child_b);
|
|
161
|
+
// Idempotent delete on the slot key.
|
|
162
|
+
const del = expect_output(await cross_rpc_call(t, rpc_path, 'cell_item_delete', { parent_id: parent, position: pos_a }, h), CellItemDeleteOutput);
|
|
163
|
+
assert.strictEqual(del.deleted, true);
|
|
164
|
+
const del2 = expect_output(await cross_rpc_call(t, rpc_path, 'cell_item_delete', { parent_id: parent, position: pos_a }, h), CellItemDeleteOutput);
|
|
165
|
+
assert.strictEqual(del2.deleted, false);
|
|
166
|
+
});
|
|
167
|
+
test_if(capabilities.cell_relations, 'clone: shallow shares edges; deep clones children', async () => {
|
|
168
|
+
const fixture = await setup_test();
|
|
169
|
+
const owner = await fixture.create_account({ username: 'cell_clone_owner' });
|
|
170
|
+
const t = fixture.fresh_transport();
|
|
171
|
+
const h = owner.create_session_headers();
|
|
172
|
+
const make = async (label) => expect_output(await cross_rpc_call(t, rpc_path, 'cell_create', { data: { kind: 'note', ...(label === undefined ? {} : { label }) } }, h), CellCreateOutput).cell.id;
|
|
173
|
+
const source = await make('orig');
|
|
174
|
+
const child = await make('child');
|
|
175
|
+
const field_target = await make('target');
|
|
176
|
+
const child_pos = fractional_index_between(null, null);
|
|
177
|
+
expect_output(await cross_rpc_call(t, rpc_path, 'cell_item_insert', { parent_id: source, child_id: child, position: child_pos }, h), CellItemInsertOutput);
|
|
178
|
+
expect_output(await cross_rpc_call(t, rpc_path, 'cell_field_set', { source_id: source, name: 'link', target_id: field_target }, h), CellFieldSetOutput);
|
|
179
|
+
// Shallow clone: new owned cell, path nulled, item edge shares the
|
|
180
|
+
// same child_id, field edge shares the same target_id.
|
|
181
|
+
const shallow = expect_output(await cross_rpc_call(t, rpc_path, 'cell_clone', { source_id: source }, h), CellCloneOutput).cell;
|
|
182
|
+
assert.notStrictEqual(shallow.id, source);
|
|
183
|
+
assert.strictEqual(shallow.created_by, owner.actor.id);
|
|
184
|
+
assert.strictEqual(shallow.path, null);
|
|
185
|
+
const shallow_items = expect_output(await cross_rpc_call(t, rpc_path, 'cell_item_list', { parent_id: shallow.id }, h), CellItemListOutput);
|
|
186
|
+
assert.strictEqual(shallow_items.items.length, 1);
|
|
187
|
+
assert.strictEqual(shallow_items.items[0].child_id, child, 'shallow clone re-pointed the child');
|
|
188
|
+
const shallow_fields = expect_output(await cross_rpc_call(t, rpc_path, 'cell_field_list', { source_id: shallow.id }, h), CellFieldListOutput);
|
|
189
|
+
assert.strictEqual(shallow_fields.fields.length, 1);
|
|
190
|
+
assert.strictEqual(shallow_fields.fields[0].target_id, field_target);
|
|
191
|
+
// Deep clone: the child edge points at a NEW cloned cell, not the
|
|
192
|
+
// original child; the field edge still shares the target.
|
|
193
|
+
const deep = expect_output(await cross_rpc_call(t, rpc_path, 'cell_clone', { source_id: source, deep: true }, h), CellCloneOutput).cell;
|
|
194
|
+
const deep_items = expect_output(await cross_rpc_call(t, rpc_path, 'cell_item_list', { parent_id: deep.id }, h), CellItemListOutput);
|
|
195
|
+
assert.strictEqual(deep_items.items.length, 1);
|
|
196
|
+
assert.notStrictEqual(deep_items.items[0].child_id, child, 'deep clone reused the original child');
|
|
197
|
+
const deep_fields = expect_output(await cross_rpc_call(t, rpc_path, 'cell_field_list', { source_id: deep.id }, h), CellFieldListOutput);
|
|
198
|
+
assert.strictEqual(deep_fields.fields.length, 1);
|
|
199
|
+
assert.strictEqual(deep_fields.fields[0].target_id, field_target);
|
|
200
|
+
});
|
|
201
|
+
test_if(capabilities.cell_relations, 'audit_list is manage-tier: owner reads the timeline; viewer-grant gets 404', async () => {
|
|
202
|
+
const fixture = await setup_test();
|
|
203
|
+
const owner = await fixture.create_account({ username: 'cell_audit_owner' });
|
|
204
|
+
const viewer = await fixture.create_account({ username: 'cell_audit_viewer' });
|
|
205
|
+
const t = fixture.fresh_transport();
|
|
206
|
+
const owner_h = owner.create_session_headers();
|
|
207
|
+
const viewer_h = viewer.create_session_headers();
|
|
208
|
+
const cell = expect_output(await cross_rpc_call(t, rpc_path, 'cell_create', { data: { kind: 'note' } }, owner_h), CellCreateOutput).cell;
|
|
209
|
+
// A mutation so the timeline has at least the create + update events.
|
|
210
|
+
expect_output(await cross_rpc_call(t, rpc_path, 'cell_update', { cell_id: cell.id, data: { kind: 'note', label: 'v2' } }, owner_h), CellUpdateOutput);
|
|
211
|
+
// Owner (manage-tier) reads the timeline.
|
|
212
|
+
const timeline = expect_output(await cross_rpc_call(t, rpc_path, 'cell_audit_list', { cell_id: cell.id }, owner_h), CellAuditListOutput);
|
|
213
|
+
assert.ok(timeline.events.length > 0, 'owner audit timeline empty');
|
|
214
|
+
assert.ok(timeline.events.some((e) => e.event_type === 'cell_create'), 'audit timeline missing the create event');
|
|
215
|
+
// Grant the viewer a view-only grant: they can read the cell …
|
|
216
|
+
expect_output(await cross_rpc_call(t, rpc_path, 'cell_grant_create', {
|
|
217
|
+
cell_id: cell.id,
|
|
218
|
+
level: 'viewer',
|
|
219
|
+
principal: { kind: 'actor', actor_id: viewer.actor.id },
|
|
220
|
+
}, owner_h), CellGrantCreateOutput);
|
|
221
|
+
const can_read = await cross_rpc_call(t, rpc_path, 'cell_get', { id: cell.id }, viewer_h);
|
|
222
|
+
assert.ok(can_read.ok, 'viewer-grant holder could not read the cell');
|
|
223
|
+
// … but the timeline is manage-tier, so they get the IDOR 404.
|
|
224
|
+
const denied = await cross_rpc_call(t, rpc_path, 'cell_audit_list', { cell_id: cell.id }, viewer_h);
|
|
225
|
+
assert.ok(!denied.ok, 'viewer read the audit timeline');
|
|
226
|
+
assert.strictEqual(error_reason(denied), 'cell_not_found');
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"default_backend_configs.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/default_backend_configs.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAAK,EAAC,sBAAsB,EAAE,aAAa,EAAC,MAAM,qBAAqB,CAAC;AAC/E,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAA2B,KAAK,gBAAgB,EAAC,MAAM,+BAA+B,CAAC;AAQ9F;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,EAAE,
|
|
1
|
+
{"version":3,"file":"default_backend_configs.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/default_backend_configs.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAAK,EAAC,sBAAsB,EAAE,aAAa,EAAC,MAAM,qBAAqB,CAAC;AAC/E,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAA2B,KAAK,gBAAgB,EAAC,MAAM,+BAA+B,CAAC;AAQ9F;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,EAAE,mBAUpC,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,EAAE,mBAUtC,CAAC;AAeH,MAAM,WAAW,iCAAiC;IACjD,gFAAgF;IAChF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,sCAAsC;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,4DAA4D;IAC5D,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC9C,oDAAoD;IACpD,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,iEAAiE;IACjE,QAAQ,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACtD,6CAA6C;IAC7C,QAAQ,CAAC,YAAY,CAAC,EAAE,mBAAmB,CAAC;IAC5C,wEAAwE;IACxE,QAAQ,CAAC,KAAK,CAAC,EAAE,gBAAgB,CAAC;IAClC,sEAAsE;IACtE,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC,sBAAsB,CAAC,CAAC;IAC/D;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED;;;;;GAKG;AACH,eAAO,MAAM,8BAA8B,GAC1C,MAAM,iCAAiC,KACrC,aAmCF,CAAC;AAEF,MAAM,WAAW,mCAAmC;IACnD,gFAAgF;IAChF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,sCAAsC;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,4DAA4D;IAC5D,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC9C;;;;OAIG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,iEAAiE;IACjE,QAAQ,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACtD,+CAA+C;IAC/C,QAAQ,CAAC,YAAY,CAAC,EAAE,mBAAmB,CAAC;IAC5C,wEAAwE;IACxE,QAAQ,CAAC,KAAK,CAAC,EAAE,gBAAgB,CAAC;IAClC,sEAAsE;IACtE,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC,sBAAsB,CAAC,CAAC;IAC/D;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC,GAC5C,MAAM,mCAAmC,KACvC,aA2CF,CAAC"}
|
|
@@ -13,6 +13,9 @@ export const ts_default_capabilities = Object.freeze({
|
|
|
13
13
|
login_rate_limit: false,
|
|
14
14
|
ws: true,
|
|
15
15
|
sse: false,
|
|
16
|
+
cell_crud: true,
|
|
17
|
+
cell_relations: true,
|
|
18
|
+
account_lifecycle: true,
|
|
16
19
|
in_process_only: false,
|
|
17
20
|
});
|
|
18
21
|
/**
|
|
@@ -27,6 +30,9 @@ export const rust_default_capabilities = Object.freeze({
|
|
|
27
30
|
login_rate_limit: true,
|
|
28
31
|
ws: true,
|
|
29
32
|
sse: false,
|
|
33
|
+
cell_crud: true,
|
|
34
|
+
cell_relations: true,
|
|
35
|
+
account_lifecycle: true,
|
|
30
36
|
in_process_only: false,
|
|
31
37
|
});
|
|
32
38
|
/** Bootstrap block built from the default secrets + supplied paths. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/setup.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/setup.ts"],"names":[],"mappings":"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"}
|
|
@@ -85,6 +85,11 @@ const in_process_fetch_transport = (app) => {
|
|
|
85
85
|
* beyond what `create_test_app` already does.
|
|
86
86
|
*/
|
|
87
87
|
export const default_in_process_setup = (options) => async () => {
|
|
88
|
+
// Per-test fresh db. When `options.migration_namespaces` is set,
|
|
89
|
+
// `create_test_app` provisions an auth+extras PGlite (e.g. the cell
|
|
90
|
+
// layer); otherwise the auth-only default. Either way the factory
|
|
91
|
+
// resets + re-migrates on each `create`, so the per-test keeper
|
|
92
|
+
// bootstrap below lands on a clean DB.
|
|
88
93
|
const test_app = await create_test_app(options);
|
|
89
94
|
// Seed bootstrap-time secondaries against the same DB the keeper
|
|
90
95
|
// just landed on. Direct-insert is the only path for roles whose
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entities.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/entities.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAiB7B,OAAO,KAAK,EAAC,OAAO,EAAE,KAAK,EAAE,SAAS,EAAC,MAAM,2BAA2B,CAAC;AACzE,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,6BAA6B,CAAC;AAC/D,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,4BAA4B,CAAC;AAE/D,sFAAsF;AACtF,MAAM,MAAM,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,GAAG,YAAY,GAAG,YAAY,CAAC,CAAC,GAAG;IAC/F,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,CAAC;AAEF,sDAAsD;AACtD,eAAO,MAAM,mBAAmB,GAAI,YAAY,oBAAoB,KAAG,
|
|
1
|
+
{"version":3,"file":"entities.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/entities.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAiB7B,OAAO,KAAK,EAAC,OAAO,EAAE,KAAK,EAAE,SAAS,EAAC,MAAM,2BAA2B,CAAC;AACzE,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,6BAA6B,CAAC;AAC/D,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,4BAA4B,CAAC;AAE/D,sFAAsF;AACtF,MAAM,MAAM,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,GAAG,YAAY,GAAG,YAAY,CAAC,CAAC,GAAG;IAC/F,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,CAAC;AAEF,sDAAsD;AACtD,eAAO,MAAM,mBAAmB,GAAI,YAAY,oBAAoB,KAAG,OAarE,CAAC;AAEH,oFAAoF;AACpF,MAAM,MAAM,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,GAAG,YAAY,GAAG,YAAY,CAAC,CAAC,GAAG;IAC3F,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,CAAC;AAEF,oDAAoD;AACpD,eAAO,MAAM,iBAAiB,GAAI,YAAY,kBAAkB,KAAG,KAUjE,CAAC;AAEH,yFAAyF;AACzF,MAAM,MAAM,sBAAsB,GAAG,OAAO,CAC3C,IAAI,CACH,SAAS,EACT,IAAI,GAAG,UAAU,GAAG,YAAY,GAAG,UAAU,GAAG,YAAY,GAAG,YAAY,GAAG,iBAAiB,CAC/F,CACD,GAAG;IACH,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC,CAAC;AAEF,wDAAwD;AACxD,eAAO,MAAM,sBAAsB,GAAI,YAAY,sBAAsB,KAAG,SAgB3E,CAAC;AAEF,8EAA8E;AAC9E,eAAO,MAAM,mBAAmB,GAC/B,cAAa,KAAK,CAAC,sBAAsB,CAAQ,KAC/C,cAID,CAAC;AAEH,0FAA0F;AAC1F,MAAM,MAAM,uBAAuB,GAAG,OAAO,CAC5C,IAAI,CAAC,aAAa,EAAE,IAAI,GAAG,UAAU,GAAG,YAAY,GAAG,mBAAmB,GAAG,iBAAiB,CAAC,CAC/F,GAAG;IACH,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC,CAAC;AAEF,4DAA4D;AAC5D,eAAO,MAAM,uBAAuB,GAAI,YAAY,uBAAuB,KAAG,aAa5E,CAAC"}
|
package/dist/testing/entities.js
CHANGED
|
@@ -10,6 +10,8 @@ export const create_test_account = (overrides) => ({
|
|
|
10
10
|
created_by: null,
|
|
11
11
|
updated_at: '2024-01-01T00:00:00Z',
|
|
12
12
|
updated_by: null,
|
|
13
|
+
deleted_at: null,
|
|
14
|
+
deleted_by: null,
|
|
13
15
|
...overrides,
|
|
14
16
|
});
|
|
15
17
|
/** Create a test `Actor` with sensible defaults. */
|
|
@@ -20,6 +22,8 @@ export const create_test_actor = (overrides) => ({
|
|
|
20
22
|
created_at: '2024-01-01T00:00:00Z',
|
|
21
23
|
updated_at: null,
|
|
22
24
|
updated_by: null,
|
|
25
|
+
deleted_at: null,
|
|
26
|
+
deleted_by: null,
|
|
23
27
|
...overrides,
|
|
24
28
|
});
|
|
25
29
|
/** Create a test `RoleGrant` with sensible defaults. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ws_round_trip.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/ws_round_trip.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"ws_round_trip.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/ws_round_trip.ts"],"names":[],"mappings":"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"}
|
|
@@ -157,6 +157,8 @@ const build_multi_role_request_context = (account_id, roles) => {
|
|
|
157
157
|
created_by: null,
|
|
158
158
|
updated_at: now,
|
|
159
159
|
updated_by: null,
|
|
160
|
+
deleted_at: null,
|
|
161
|
+
deleted_by: null,
|
|
160
162
|
},
|
|
161
163
|
actor: {
|
|
162
164
|
id: actor_id,
|
|
@@ -165,6 +167,8 @@ const build_multi_role_request_context = (account_id, roles) => {
|
|
|
165
167
|
created_at: now,
|
|
166
168
|
updated_at: null,
|
|
167
169
|
updated_by: null,
|
|
170
|
+
deleted_at: null,
|
|
171
|
+
deleted_by: null,
|
|
168
172
|
},
|
|
169
173
|
role_grants: roles.map((role) => ({
|
|
170
174
|
id: create_uuid(),
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
{key: 'account', label: 'username', width: 180},
|
|
37
37
|
{key: 'role_grants', label: 'role_grants', width: 240},
|
|
38
38
|
{key: 'actor', label: 'grant', width: 200},
|
|
39
|
+
{key: 'pending_offers', label: 'manage', width: 140},
|
|
39
40
|
];
|
|
40
41
|
</script>
|
|
41
42
|
|
|
@@ -49,6 +50,22 @@
|
|
|
49
50
|
</p>
|
|
50
51
|
{/if}
|
|
51
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}
|
|
68
|
+
|
|
52
69
|
{#if admin_accounts.list.loading}
|
|
53
70
|
<p class="text_50">loading accounts...</p>
|
|
54
71
|
{:else if admin_accounts.list.error}
|
|
@@ -167,6 +184,47 @@
|
|
|
167
184
|
{/if}
|
|
168
185
|
{/each}
|
|
169
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)}
|
|
210
|
+
<ConfirmButton
|
|
211
|
+
onconfirm={() => admin_accounts.submit_delete(row.account.id)}
|
|
212
|
+
title="soft-delete @{row.account.username}"
|
|
213
|
+
class="sm"
|
|
214
|
+
label="delete"
|
|
215
|
+
pending={admin_accounts.soft_delete.loading(row.account.id)}
|
|
216
|
+
>
|
|
217
|
+
{#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>
|
|
220
|
+
</button>
|
|
221
|
+
{/snippet}
|
|
222
|
+
</ConfirmButton>
|
|
223
|
+
{#if delete_error}
|
|
224
|
+
<span class="color_c_50 font_size_sm">{delete_error}</span>
|
|
225
|
+
{/if}
|
|
226
|
+
{/if}
|
|
227
|
+
{/if}
|
|
170
228
|
{/if}
|
|
171
229
|
{/snippet}
|
|
172
230
|
</Datatable>
|
|
@@ -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":"AA2MA,QAAA,MAAM,aAAa,2DAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
|
|
@@ -18,7 +18,7 @@ import { KeyedAsyncSlot } from './keyed_async_slot.svelte.js';
|
|
|
18
18
|
import type { AdminAccountEntryJson } from '../auth/account_schema.js';
|
|
19
19
|
import type { RoleName } from '../auth/role_schema.js';
|
|
20
20
|
import type { RoleGrantOfferJson } from '../auth/role_grant_offer_schema.js';
|
|
21
|
-
import type { AdminAccountListOutput, AdminSessionListOutput, AdminSessionRevokeAllInput, AdminSessionRevokeAllOutput, AdminTokenRevokeAllInput, AdminTokenRevokeAllOutput } from '../auth/admin_action_specs.js';
|
|
21
|
+
import type { AdminAccountListOutput, AccountDeleteOutput, AccountUndeleteOutput, AdminSessionListOutput, AdminSessionRevokeAllInput, AdminSessionRevokeAllOutput, AdminTokenRevokeAllInput, AdminTokenRevokeAllOutput } from '../auth/admin_action_specs.js';
|
|
22
22
|
import type { RoleGrantOfferCreateInput, RoleGrantOfferCreateOutput, RoleGrantOfferOkOutput, RoleGrantRevokeInput, RoleGrantRevokeOutput } from '../auth/role_grant_offer_action_specs.js';
|
|
23
23
|
/**
|
|
24
24
|
* Narrow RPC surface consumed by `AdminAccountsState`. Consumers adapt their
|
|
@@ -40,7 +40,9 @@ import type { RoleGrantOfferCreateInput, RoleGrantOfferCreateOutput, RoleGrantOf
|
|
|
40
40
|
* to bridge to the typed throwing Proxy.
|
|
41
41
|
*/
|
|
42
42
|
export interface AdminAccountsRpc {
|
|
43
|
-
list_accounts: () => Promise<AdminAccountListOutput>;
|
|
43
|
+
list_accounts: (include_deleted?: boolean) => Promise<AdminAccountListOutput>;
|
|
44
|
+
delete_account: (account_id: Uuid) => Promise<AccountDeleteOutput>;
|
|
45
|
+
undelete_account: (account_id: Uuid) => Promise<AccountUndeleteOutput>;
|
|
44
46
|
list_sessions: () => Promise<AdminSessionListOutput>;
|
|
45
47
|
create_role_grant: (params: RoleGrantOfferCreateInput) => Promise<RoleGrantOfferCreateOutput>;
|
|
46
48
|
revoke_role_grant: (params: RoleGrantRevokeInput) => Promise<RoleGrantRevokeOutput>;
|
|
@@ -101,8 +103,15 @@ export declare class AdminAccountsState {
|
|
|
101
103
|
}, string>;
|
|
102
104
|
readonly revoke: KeyedAsyncSlot<string & import("zod").$brand<"Uuid">, void, string>;
|
|
103
105
|
readonly retract: KeyedAsyncSlot<string & import("zod").$brand<"Uuid">, void, string>;
|
|
106
|
+
readonly soft_delete: KeyedAsyncSlot<string & import("zod").$brand<"Uuid">, void, string>;
|
|
107
|
+
readonly undelete: KeyedAsyncSlot<string & import("zod").$brand<"Uuid">, void, string>;
|
|
104
108
|
accounts: Array<AdminAccountEntryJson>;
|
|
105
109
|
grantable_roles: Array<RoleName>;
|
|
110
|
+
/**
|
|
111
|
+
* When `true`, `fetch()` includes soft-deleted (tombstoned) accounts so
|
|
112
|
+
* the admin can reactivate them. Toggled via `set_show_deleted`.
|
|
113
|
+
*/
|
|
114
|
+
show_deleted: boolean;
|
|
106
115
|
readonly account_count: number;
|
|
107
116
|
constructor(options?: AdminAccountsStateOptions);
|
|
108
117
|
/**
|
|
@@ -111,6 +120,25 @@ export declare class AdminAccountsState {
|
|
|
111
120
|
*/
|
|
112
121
|
get has_rpc(): boolean;
|
|
113
122
|
fetch(): Promise<void>;
|
|
123
|
+
/**
|
|
124
|
+
* Toggle whether soft-deleted accounts appear in the listing, then
|
|
125
|
+
* re-fetch. Tombstoned rows are surfaced so an admin can reactivate them
|
|
126
|
+
* via `submit_undelete`.
|
|
127
|
+
*/
|
|
128
|
+
set_show_deleted(value: boolean): Promise<void>;
|
|
129
|
+
/**
|
|
130
|
+
* Soft-delete an account (reversible tombstone) via `account_delete`.
|
|
131
|
+
* Keyed by `account_id` so per-row spinners/errors stay independent.
|
|
132
|
+
* Refreshes the listing on success so the row drops out (active view) or
|
|
133
|
+
* flips to its tombstoned state (`show_deleted` view).
|
|
134
|
+
*/
|
|
135
|
+
submit_delete(account_id: Uuid): Promise<void>;
|
|
136
|
+
/**
|
|
137
|
+
* Reactivate a soft-deleted account via `account_undelete` (admin-only).
|
|
138
|
+
* Keyed by `account_id`; refreshes the listing on success so the row
|
|
139
|
+
* returns to active state.
|
|
140
|
+
*/
|
|
141
|
+
submit_undelete(account_id: Uuid): Promise<void>;
|
|
114
142
|
/**
|
|
115
143
|
* Offer the role to the recipient via the `role_grant_offer_create` RPC.
|
|
116
144
|
* Server returns the pending offer; the recipient must accept before
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin_accounts_state.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/ui/admin_accounts_state.svelte.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,wBAAwB,CAAC;AAEjD,OAAO,EAAC,SAAS,EAAC,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAC,cAAc,EAAC,MAAM,8BAA8B,CAAC;AAC5D,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,2BAA2B,CAAC;AACrE,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,wBAAwB,CAAC;AACrD,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,oCAAoC,CAAC;AAC3E,OAAO,KAAK,EACX,sBAAsB,EACtB,sBAAsB,EACtB,0BAA0B,EAC1B,2BAA2B,EAC3B,wBAAwB,EACxB,yBAAyB,EACzB,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EACX,yBAAyB,EACzB,0BAA0B,EAC1B,sBAAsB,EACtB,oBAAoB,EACpB,qBAAqB,EACrB,MAAM,0CAA0C,CAAC;AAElD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,gBAAgB;IAChC,aAAa,EAAE,
|
|
1
|
+
{"version":3,"file":"admin_accounts_state.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/ui/admin_accounts_state.svelte.ts"],"names":[],"mappings":"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"}
|
|
@@ -39,8 +39,16 @@ export class AdminAccountsState {
|
|
|
39
39
|
grant = new KeyedAsyncSlot();
|
|
40
40
|
revoke = new KeyedAsyncSlot();
|
|
41
41
|
retract = new KeyedAsyncSlot();
|
|
42
|
+
// Per-row account lifecycle slots, keyed by `account_id`.
|
|
43
|
+
soft_delete = new KeyedAsyncSlot();
|
|
44
|
+
undelete = new KeyedAsyncSlot();
|
|
42
45
|
accounts = $state.raw([]);
|
|
43
46
|
grantable_roles = $state.raw([]);
|
|
47
|
+
/**
|
|
48
|
+
* When `true`, `fetch()` includes soft-deleted (tombstoned) accounts so
|
|
49
|
+
* the admin can reactivate them. Toggled via `set_show_deleted`.
|
|
50
|
+
*/
|
|
51
|
+
show_deleted = $state(false);
|
|
44
52
|
account_count = $derived(this.accounts.length);
|
|
45
53
|
constructor(options) {
|
|
46
54
|
this.#get_rpc = options?.get_rpc ?? (() => null);
|
|
@@ -60,11 +68,47 @@ export class AdminAccountsState {
|
|
|
60
68
|
}
|
|
61
69
|
async fetch() {
|
|
62
70
|
await this.list.run(async () => {
|
|
63
|
-
const { accounts, grantable_roles } = await this.#require_rpc().list_accounts();
|
|
71
|
+
const { accounts, grantable_roles } = await this.#require_rpc().list_accounts(this.show_deleted);
|
|
64
72
|
this.accounts = accounts;
|
|
65
73
|
this.grantable_roles = grantable_roles;
|
|
66
74
|
});
|
|
67
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* Toggle whether soft-deleted accounts appear in the listing, then
|
|
78
|
+
* re-fetch. Tombstoned rows are surfaced so an admin can reactivate them
|
|
79
|
+
* via `submit_undelete`.
|
|
80
|
+
*/
|
|
81
|
+
async set_show_deleted(value) {
|
|
82
|
+
if (this.show_deleted === value)
|
|
83
|
+
return;
|
|
84
|
+
this.show_deleted = value;
|
|
85
|
+
await this.fetch();
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Soft-delete an account (reversible tombstone) via `account_delete`.
|
|
89
|
+
* Keyed by `account_id` so per-row spinners/errors stay independent.
|
|
90
|
+
* Refreshes the listing on success so the row drops out (active view) or
|
|
91
|
+
* flips to its tombstoned state (`show_deleted` view).
|
|
92
|
+
*/
|
|
93
|
+
async submit_delete(account_id) {
|
|
94
|
+
await this.soft_delete.run(account_id, async () => {
|
|
95
|
+
await this.#require_rpc().delete_account(account_id);
|
|
96
|
+
});
|
|
97
|
+
if (this.soft_delete.succeeded(account_id))
|
|
98
|
+
await this.fetch();
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Reactivate a soft-deleted account via `account_undelete` (admin-only).
|
|
102
|
+
* Keyed by `account_id`; refreshes the listing on success so the row
|
|
103
|
+
* returns to active state.
|
|
104
|
+
*/
|
|
105
|
+
async submit_undelete(account_id) {
|
|
106
|
+
await this.undelete.run(account_id, async () => {
|
|
107
|
+
await this.#require_rpc().undelete_account(account_id);
|
|
108
|
+
});
|
|
109
|
+
if (this.undelete.succeeded(account_id))
|
|
110
|
+
await this.fetch();
|
|
111
|
+
}
|
|
68
112
|
/**
|
|
69
113
|
* Offer the role to the recipient via the `role_grant_offer_create` RPC.
|
|
70
114
|
* Server returns the pending offer; the recipient must accept before
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
*
|
|
33
33
|
* @module
|
|
34
34
|
*/
|
|
35
|
-
import type { AdminAccountListOutput, AdminSessionListOutput, AdminSessionRevokeAllInput, AdminSessionRevokeAllOutput, AdminTokenRevokeAllInput, AdminTokenRevokeAllOutput, AuditLogListInput, AuditLogListOutput, AuditLogRoleGrantHistoryInput, AuditLogRoleGrantHistoryOutput, InviteCreateInput, InviteCreateOutput, InviteDeleteInput, InviteDeleteOutput, InviteListOutput, AppSettingsGetOutput, AppSettingsUpdateInput, AppSettingsUpdateOutput } from '../auth/admin_action_specs.js';
|
|
35
|
+
import type { AdminAccountListInput, AdminAccountListOutput, AccountDeleteInput, AccountDeleteOutput, AccountUndeleteInput, AccountUndeleteOutput, AdminSessionListOutput, AdminSessionRevokeAllInput, AdminSessionRevokeAllOutput, AdminTokenRevokeAllInput, AdminTokenRevokeAllOutput, AuditLogListInput, AuditLogListOutput, AuditLogRoleGrantHistoryInput, AuditLogRoleGrantHistoryOutput, InviteCreateInput, InviteCreateOutput, InviteDeleteInput, InviteDeleteOutput, InviteListOutput, AppSettingsGetOutput, AppSettingsUpdateInput, AppSettingsUpdateOutput } from '../auth/admin_action_specs.js';
|
|
36
36
|
import type { RoleGrantOfferCreateInput, RoleGrantOfferCreateOutput, RoleGrantOfferRetractInput, RoleGrantOfferOkOutput, RoleGrantRevokeInput, RoleGrantRevokeOutput } from '../auth/role_grant_offer_action_specs.js';
|
|
37
37
|
import { type AdminAccountsRpc } from './admin_accounts_state.svelte.js';
|
|
38
38
|
import { type AdminInvitesRpc } from './admin_invites_state.svelte.js';
|
|
@@ -51,7 +51,9 @@ import { type FormatScope } from './format_scope.js';
|
|
|
51
51
|
* assignable as long as these methods are present at these signatures.
|
|
52
52
|
*/
|
|
53
53
|
export interface AdminRpcApi {
|
|
54
|
-
admin_account_list: () => Promise<AdminAccountListOutput>;
|
|
54
|
+
admin_account_list: (input?: AdminAccountListInput) => Promise<AdminAccountListOutput>;
|
|
55
|
+
account_delete: (input: AccountDeleteInput) => Promise<AccountDeleteOutput>;
|
|
56
|
+
account_undelete: (input: AccountUndeleteInput) => Promise<AccountUndeleteOutput>;
|
|
55
57
|
admin_session_list: () => Promise<AdminSessionListOutput>;
|
|
56
58
|
admin_session_revoke_all: (input: AdminSessionRevokeAllInput) => Promise<AdminSessionRevokeAllOutput>;
|
|
57
59
|
admin_token_revoke_all: (input: AdminTokenRevokeAllInput) => Promise<AdminTokenRevokeAllOutput>;
|
|
@@ -81,6 +83,8 @@ export interface AdminRpcAdapters {
|
|
|
81
83
|
* | Narrow RPC method | Action spec method |
|
|
82
84
|
* | ----------------------------------- | ---------------------------- |
|
|
83
85
|
* | `admin_accounts.list_accounts` | `admin_account_list` |
|
|
86
|
+
* | `admin_accounts.delete_account` | `account_delete` (soft) |
|
|
87
|
+
* | `admin_accounts.undelete_account` | `account_undelete` |
|
|
84
88
|
* | `admin_accounts.list_sessions` | `admin_session_list` |
|
|
85
89
|
* | `admin_accounts.create_role_grant` | `role_grant_offer_create` |
|
|
86
90
|
* | `admin_accounts.revoke_role_grant` | `role_grant_revoke` |
|