@fuzdev/fuz_app 0.62.0 → 0.63.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions/CLAUDE.md +15 -13
- package/dist/actions/action_rpc.d.ts +10 -0
- package/dist/actions/action_rpc.d.ts.map +1 -1
- package/dist/actions/action_rpc.js +1 -1
- package/dist/actions/action_spec.d.ts +1 -1
- package/dist/actions/action_spec.js +1 -1
- package/dist/actions/perform_action.d.ts.map +1 -1
- package/dist/actions/perform_action.js +1 -0
- package/dist/auth/CLAUDE.md +45 -24
- package/dist/auth/account_action_specs.d.ts +6 -0
- package/dist/auth/account_action_specs.d.ts.map +1 -1
- package/dist/auth/account_action_specs.js +11 -4
- package/dist/auth/account_actions.d.ts.map +1 -1
- package/dist/auth/account_actions.js +9 -4
- package/dist/auth/account_routes.d.ts.map +1 -1
- package/dist/auth/account_routes.js +8 -4
- package/dist/auth/account_schema.d.ts +2 -2
- package/dist/auth/account_schema.js +2 -2
- package/dist/auth/actor_lookup_actions.d.ts +1 -1
- package/dist/auth/actor_lookup_actions.js +1 -1
- package/dist/auth/actor_lookup_queries.d.ts +1 -1
- package/dist/auth/actor_lookup_queries.js +1 -1
- package/dist/auth/actor_search_action_specs.d.ts +1 -1
- package/dist/auth/actor_search_action_specs.js +1 -1
- package/dist/auth/actor_search_actions.d.ts +1 -1
- package/dist/auth/actor_search_actions.js +1 -1
- package/dist/auth/actor_search_queries.d.ts +1 -1
- package/dist/auth/actor_search_queries.js +1 -1
- package/dist/auth/all_action_spec_registries.d.ts +2 -2
- package/dist/auth/all_action_spec_registries.js +2 -2
- package/dist/auth/audit_log_routes.d.ts +1 -1
- package/dist/auth/audit_log_routes.js +1 -1
- package/dist/auth/audit_log_schema.d.ts +25 -0
- package/dist/auth/audit_log_schema.d.ts.map +1 -1
- package/dist/auth/audit_log_schema.js +16 -0
- package/dist/auth/request_context.d.ts +1 -1
- package/dist/env/update_env_variable.js +1 -1
- package/dist/http/CLAUDE.md +15 -15
- package/dist/testing/CLAUDE.md +28 -44
- package/dist/testing/audit_completeness.d.ts.map +1 -1
- package/dist/testing/audit_completeness.js +17 -1
- package/dist/ui/CLAUDE.md +13 -18
- package/dist/ui/keyed_async_slot.svelte.d.ts +1 -1
- package/dist/ui/keyed_async_slot.svelte.js +1 -1
- package/package.json +1 -1
|
@@ -27,12 +27,23 @@ import { admin_session_revoke_all_action_spec, admin_token_revoke_all_action_spe
|
|
|
27
27
|
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';
|
|
28
28
|
/** Query audit log events from the database. */
|
|
29
29
|
const query_audit_events = async (db) => {
|
|
30
|
-
return db.query('SELECT event_type, seq FROM audit_log ORDER BY seq');
|
|
30
|
+
return db.query('SELECT event_type, seq, metadata FROM audit_log ORDER BY seq');
|
|
31
31
|
};
|
|
32
32
|
/** Assert that audit events contain the expected event type. */
|
|
33
33
|
const assert_has_event = (events, expected, context) => {
|
|
34
34
|
assert.ok(events.some((e) => e.event_type === expected), `Expected '${expected}' audit event after ${context}`);
|
|
35
35
|
};
|
|
36
|
+
/**
|
|
37
|
+
* Assert that an event type was emitted with the expected `credential_type`
|
|
38
|
+
* recorded in metadata — defense-in-depth coverage for the spec gate
|
|
39
|
+
* documented in `docs/security.md` §Credential-channel gating.
|
|
40
|
+
*/
|
|
41
|
+
const assert_event_credential_type = (events, expected, credential_type, context) => {
|
|
42
|
+
const match = events.find((e) => e.event_type === expected);
|
|
43
|
+
assert.ok(match, `Expected '${expected}' audit event after ${context}`);
|
|
44
|
+
const recorded = (match.metadata ?? {}).credential_type;
|
|
45
|
+
assert.strictEqual(recorded, credential_type, `Expected '${expected}' audit metadata.credential_type === '${credential_type}' after ${context} (got ${JSON.stringify(recorded)})`);
|
|
46
|
+
};
|
|
36
47
|
/** Build CreateTestAppOptions with admin+keeper roles. */
|
|
37
48
|
const build_options = (options, db) => ({
|
|
38
49
|
session_options: options.session_options,
|
|
@@ -138,6 +149,7 @@ export const describe_audit_completeness_tests = (options) => {
|
|
|
138
149
|
assert.ok(res.ok, `account_token_create failed: ${res.ok ? '' : JSON.stringify(res.error)}`);
|
|
139
150
|
const events = await query_audit_events(test_app.backend.deps.db);
|
|
140
151
|
assert_has_event(events, 'token_create', 'account_token_create RPC');
|
|
152
|
+
assert_event_credential_type(events, 'token_create', 'session', 'account_token_create RPC');
|
|
141
153
|
});
|
|
142
154
|
test('token revoke produces token_revoke event', async () => {
|
|
143
155
|
const test_app = await create_test_app(build_options(options, get_db()));
|
|
@@ -162,6 +174,7 @@ export const describe_audit_completeness_tests = (options) => {
|
|
|
162
174
|
assert.ok(res.ok, `account_token_revoke failed: ${res.ok ? '' : JSON.stringify(res.error)}`);
|
|
163
175
|
const events = await query_audit_events(test_app.backend.deps.db);
|
|
164
176
|
assert_has_event(events, 'token_revoke', 'account_token_revoke RPC');
|
|
177
|
+
assert_event_credential_type(events, 'token_revoke', 'session', 'account_token_revoke RPC');
|
|
165
178
|
});
|
|
166
179
|
test('session revoke produces session_revoke event', async () => {
|
|
167
180
|
const test_app = await create_test_app(build_options(options, get_db()));
|
|
@@ -198,6 +211,7 @@ export const describe_audit_completeness_tests = (options) => {
|
|
|
198
211
|
assert.ok(res.ok, `account_session_revoke failed: ${res.ok ? '' : JSON.stringify(res.error)}`);
|
|
199
212
|
const events = await query_audit_events(test_app.backend.deps.db);
|
|
200
213
|
assert_has_event(events, 'session_revoke', 'account_session_revoke RPC');
|
|
214
|
+
assert_event_credential_type(events, 'session_revoke', 'session', 'account_session_revoke RPC');
|
|
201
215
|
});
|
|
202
216
|
test('session revoke-all produces session_revoke_all event', async () => {
|
|
203
217
|
const test_app = await create_test_app(build_options(options, get_db()));
|
|
@@ -211,6 +225,7 @@ export const describe_audit_completeness_tests = (options) => {
|
|
|
211
225
|
assert.ok(res.ok, `account_session_revoke_all failed: ${res.ok ? '' : JSON.stringify(res.error)}`);
|
|
212
226
|
const events = await query_audit_events(test_app.backend.deps.db);
|
|
213
227
|
assert_has_event(events, 'session_revoke_all', 'account_session_revoke_all RPC');
|
|
228
|
+
assert_event_credential_type(events, 'session_revoke_all', 'session', 'account_session_revoke_all RPC');
|
|
214
229
|
});
|
|
215
230
|
test('password change produces password_change event', async () => {
|
|
216
231
|
const test_app = await create_test_app(build_options(options, get_db()));
|
|
@@ -227,6 +242,7 @@ export const describe_audit_completeness_tests = (options) => {
|
|
|
227
242
|
assert.strictEqual(res.status, 200);
|
|
228
243
|
const events = await query_audit_events(test_app.backend.deps.db);
|
|
229
244
|
assert_has_event(events, 'password_change', 'POST /password');
|
|
245
|
+
assert_event_credential_type(events, 'password_change', 'session', 'POST /password');
|
|
230
246
|
});
|
|
231
247
|
});
|
|
232
248
|
// --- Admin routes ---
|
package/dist/ui/CLAUDE.md
CHANGED
|
@@ -5,14 +5,16 @@ utilities. Cookie-based SPA auth; prerendered static HTML served by Hono
|
|
|
5
5
|
(no SvelteKit SSR for sessions). State classes hold one or more `AsyncSlot`s
|
|
6
6
|
via composition (one per distinct async operation — e.g. `list` + `create` +
|
|
7
7
|
`revoke`); per-row write ops use `KeyedAsyncSlot<K, T = void, E = string>`
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
so concurrent rows don't abort each other and failures surface per-row via
|
|
9
|
+
`slot.error(key)`. Payload lives as `$state.raw` fields on the class.
|
|
10
|
+
Shared dependencies flow through Svelte context, never through props —
|
|
11
|
+
RPC adapters are provisioned once at the admin shell and read by every
|
|
12
|
+
`Admin*.svelte`.
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
For Svelte 5 patterns (runes, inline `$props`, contexts, snippets,
|
|
15
|
+
attachments), see Skill(fuz-stack) svelte-patterns. See ../../docs/usage.md
|
|
16
|
+
for end-to-end wiring examples ("Role grant offer UI", "Admin UI"). This
|
|
17
|
+
file is a reference, not a tutorial.
|
|
16
18
|
|
|
17
19
|
## Key patterns
|
|
18
20
|
|
|
@@ -67,15 +69,8 @@ it. Six methods land on the reducer: `role_grant_offer_received` /
|
|
|
67
69
|
`_retracted` / `_accepted` / `_declined` / `_supersede` all merge a
|
|
68
70
|
`{offer}` payload; `role_grant_revoke` is ignored at this layer (role_grant
|
|
69
71
|
lifecycle lives in auth/role_grants state). The six notification specs and
|
|
70
|
-
their payload shapes are defined in
|
|
71
|
-
(see
|
|
72
|
-
|
|
73
|
-
### Svelte 5 inline `$props` shape
|
|
74
|
-
|
|
75
|
-
Always `const {...}: {...} = $props()` — never `interface Props`.
|
|
76
|
-
Destructure defaults in the binding list; put the type literal inline.
|
|
77
|
-
This matches the user-memory Svelte props rule and the existing file
|
|
78
|
-
conventions.
|
|
72
|
+
their payload shapes are defined in `auth/role_grant_offer_notifications.ts`
|
|
73
|
+
(see `auth/CLAUDE.md` §WS notifications).
|
|
79
74
|
|
|
80
75
|
### Context over props for shared deps
|
|
81
76
|
|
|
@@ -184,8 +179,8 @@ destructive actions.
|
|
|
184
179
|
reason codes with friendly copy: `ERROR_ROLE_GRANT_OFFER_SELF_TARGET`,
|
|
185
180
|
`ERROR_ROLE_GRANT_OFFER_ROLE_NOT_GRANTABLE`, `ERROR_ROLE_GRANT_OFFER_NOT_AUTHORIZED`,
|
|
186
181
|
`ERROR_ROLE_GRANT_OFFER_ACTOR_ACCOUNT_MISMATCH`, `ERROR_ROLE_GRANT_OFFER_ACTOR_MISMATCH`
|
|
187
|
-
— imported from
|
|
188
|
-
|
|
182
|
+
— imported from `auth/role_grant_offer_action_specs.js` (see
|
|
183
|
+
`auth/CLAUDE.md` for `role_grant_offer_action_specs.ts` +
|
|
189
184
|
`role_grant_offer_actions.ts`).
|
|
190
185
|
- `RoleGrantOfferHistory.svelte` — both-directions history (recipient +
|
|
191
186
|
grantor, including terminal). Props: `current_actor_id: string | null`
|
|
@@ -56,7 +56,7 @@ export type KeyedAsyncSlotOptions<T, E = string> = Omit<AsyncSlotOptions<T, E>,
|
|
|
56
56
|
*
|
|
57
57
|
* @typeParam K - The key type. Map identity is SameValueZero — branded
|
|
58
58
|
* strings (`Uuid`) work directly. For composite keys, stringify at
|
|
59
|
-
* the call site (e.g.
|
|
59
|
+
* the call site (e.g. "`${account_id}:${role}`").
|
|
60
60
|
* @typeParam T - The success payload type. Use `void` for write-only
|
|
61
61
|
* actions whose response isn't worth retaining.
|
|
62
62
|
* @typeParam E - The shape of per-key `error(key)`. Defaults to
|
|
@@ -48,7 +48,7 @@ import { AsyncSlot } from './async_slot.svelte.js';
|
|
|
48
48
|
*
|
|
49
49
|
* @typeParam K - The key type. Map identity is SameValueZero — branded
|
|
50
50
|
* strings (`Uuid`) work directly. For composite keys, stringify at
|
|
51
|
-
* the call site (e.g.
|
|
51
|
+
* the call site (e.g. "`${account_id}:${role}`").
|
|
52
52
|
* @typeParam T - The success payload type. Use `void` for write-only
|
|
53
53
|
* actions whose response isn't worth retaining.
|
|
54
54
|
* @typeParam E - The shape of per-key `error(key)`. Defaults to
|