@fuzdev/fuz_app 0.59.0 → 0.60.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 +5 -5
- package/dist/actions/action_codegen.d.ts +1 -1
- package/dist/actions/action_codegen.js +2 -2
- package/dist/actions/action_event_helpers.d.ts +3 -3
- package/dist/actions/action_event_helpers.js +8 -8
- package/dist/actions/action_event_types.d.ts +3 -3
- package/dist/actions/action_event_types.js +3 -3
- package/dist/actions/transports_ws_auth_guard.d.ts +2 -2
- package/dist/actions/transports_ws_auth_guard.js +3 -3
- package/dist/auth/CLAUDE.md +157 -15
- package/dist/auth/actor_lookup_action_specs.d.ts +127 -0
- package/dist/auth/actor_lookup_action_specs.d.ts.map +1 -0
- package/dist/auth/actor_lookup_action_specs.js +93 -0
- package/dist/auth/actor_lookup_actions.d.ts +19 -0
- package/dist/auth/actor_lookup_actions.d.ts.map +1 -0
- package/dist/auth/actor_lookup_actions.js +32 -0
- package/dist/auth/actor_lookup_queries.d.ts +44 -0
- package/dist/auth/actor_lookup_queries.d.ts.map +1 -0
- package/dist/auth/actor_lookup_queries.js +42 -0
- package/dist/auth/actor_search_action_specs.d.ts +166 -0
- package/dist/auth/actor_search_action_specs.d.ts.map +1 -0
- package/dist/auth/actor_search_action_specs.js +139 -0
- package/dist/auth/actor_search_actions.d.ts +31 -0
- package/dist/auth/actor_search_actions.d.ts.map +1 -0
- package/dist/auth/actor_search_actions.js +61 -0
- package/dist/auth/actor_search_queries.d.ts +75 -0
- package/dist/auth/actor_search_queries.d.ts.map +1 -0
- package/dist/auth/actor_search_queries.js +91 -0
- package/dist/auth/admin_actions.js +2 -2
- package/dist/auth/all_action_spec_registries.d.ts +55 -0
- package/dist/auth/all_action_spec_registries.d.ts.map +1 -0
- package/dist/auth/all_action_spec_registries.js +59 -0
- package/dist/auth/audit_emitter.d.ts +1 -1
- package/dist/auth/audit_emitter.js +2 -2
- package/dist/auth/audit_log_queries.d.ts +1 -1
- package/dist/auth/audit_log_queries.js +3 -3
- 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 +5 -5
- package/dist/auth/audit_log_schema.js +7 -7
- package/dist/auth/auth_ddl.d.ts +7 -0
- package/dist/auth/auth_ddl.d.ts.map +1 -1
- package/dist/auth/auth_ddl.js +8 -0
- package/dist/auth/credential_type_schema.d.ts +1 -1
- package/dist/auth/credential_type_schema.js +3 -3
- package/dist/auth/grant_path_schema.d.ts +1 -1
- package/dist/auth/grant_path_schema.js +3 -3
- package/dist/auth/migrations.d.ts +4 -4
- package/dist/auth/migrations.d.ts.map +1 -1
- package/dist/auth/migrations.js +7 -6
- package/dist/auth/role_grant_offer_actions.js +2 -2
- package/dist/auth/role_grant_offer_notifications.d.ts +2 -2
- package/dist/auth/role_grant_offer_notifications.js +2 -2
- package/dist/auth/role_grant_queries.d.ts +21 -0
- package/dist/auth/role_grant_queries.d.ts.map +1 -1
- package/dist/auth/role_grant_queries.js +31 -0
- package/dist/auth/role_schema.d.ts +2 -2
- package/dist/auth/role_schema.js +3 -3
- package/dist/auth/self_service_role_actions.d.ts +1 -1
- package/dist/auth/self_service_role_actions.js +2 -2
- package/dist/auth/session_cookie.d.ts +1 -1
- package/dist/auth/session_cookie.js +1 -1
- package/dist/auth/session_middleware.d.ts +1 -1
- package/dist/auth/session_middleware.js +5 -5
- package/dist/rate_limiter.d.ts +5 -5
- package/dist/rate_limiter.js +6 -6
- package/dist/realtime/sse_auth_guard.d.ts +3 -3
- package/dist/realtime/sse_auth_guard.js +4 -4
- package/dist/server/app_backend.d.ts +3 -3
- package/dist/server/app_backend.js +4 -4
- package/dist/server/app_server.d.ts +1 -1
- package/dist/server/app_server.js +10 -10
- package/dist/testing/CLAUDE.md +22 -12
- package/dist/testing/admin_integration.js +4 -4
- package/dist/testing/app_server.d.ts +1 -1
- package/dist/testing/app_server.js +2 -2
- package/dist/testing/attack_surface.d.ts +4 -4
- package/dist/testing/attack_surface.js +6 -6
- package/dist/testing/audit_completeness.js +4 -4
- package/dist/testing/data_exposure.d.ts +2 -2
- package/dist/testing/data_exposure.js +7 -7
- package/dist/testing/db.d.ts +8 -8
- package/dist/testing/db.js +11 -11
- package/dist/testing/integration.js +4 -4
- package/dist/testing/integration_helpers.d.ts +6 -6
- package/dist/testing/integration_helpers.js +7 -7
- package/dist/testing/rate_limiting.js +4 -4
- package/dist/testing/round_trip.js +2 -2
- package/dist/testing/rpc_round_trip.js +2 -2
- package/dist/testing/schema_generators.d.ts.map +1 -1
- package/dist/testing/schema_generators.js +23 -2
- package/dist/testing/sse_round_trip.js +2 -2
- package/dist/testing/surface_invariants.d.ts +4 -4
- package/dist/testing/surface_invariants.js +5 -5
- package/package.json +1 -1
package/dist/actions/CLAUDE.md
CHANGED
|
@@ -464,7 +464,7 @@ persistence + rehydration by the consumer.
|
|
|
464
464
|
wireable via `CreateAppBackendOptions.on_audit_event`. Mirrors the SSE
|
|
465
465
|
guard in `realtime/sse_auth_guard.ts` but targets the WS transport.
|
|
466
466
|
|
|
467
|
-
`
|
|
467
|
+
`ws_disconnect_event_types` (ReadonlySet): `session_revoke`,
|
|
468
468
|
`token_revoke`, `session_revoke_all`, `token_revoke_all`, `password_change`.
|
|
469
469
|
`role_grant_revoke` is intentionally **omitted** — the WS transport does not
|
|
470
470
|
track per-connection role requirements, so role-scoped disconnection would
|
|
@@ -484,7 +484,7 @@ caller close another user's socket by guessing a session hash or token id.
|
|
|
484
484
|
|
|
485
485
|
`create_ws_logout_closer(transport, log)` is the sibling helper for
|
|
486
486
|
user-initiated `logout` events — kept separate because
|
|
487
|
-
`
|
|
487
|
+
`ws_disconnect_event_types` deliberately omits `logout` (admin-initiated
|
|
488
488
|
revocations use `session_revoke`, while `logout` is the user-initiated
|
|
489
489
|
case). Compose the two on `on_audit_event`:
|
|
490
490
|
|
|
@@ -600,9 +600,9 @@ an action through its lifecycle.
|
|
|
600
600
|
|
|
601
601
|
- `ActionExecutor` — `'frontend' | 'backend'`
|
|
602
602
|
- `ActionEventStep` — `'initial' | 'parsed' | 'handling' | 'handled' | 'failed'`
|
|
603
|
-
- `
|
|
604
|
-
- `
|
|
605
|
-
- `
|
|
603
|
+
- `action_event_step_transitions` — valid next-steps: `initial → parsed | failed`, `parsed → handling | failed`, `handling → handled | failed`, `handled`/`failed` terminal.
|
|
604
|
+
- `action_event_phase_by_kind` — valid phases per kind (`request_response` has 6, `remote_notification` has 2, `local_call` has 1).
|
|
605
|
+
- `action_event_phase_transitions` — chained phases: `send_request → receive_response`; `receive_request → send_response`; everything else terminal.
|
|
606
606
|
- `ActionEventEnvironment` — `{executor, lookup_action_handler, lookup_action_spec, log?}`. The ambient registry + handler resolver for an `ActionEvent`.
|
|
607
607
|
|
|
608
608
|
### `action_event_data.ts`
|
|
@@ -182,7 +182,7 @@ export declare const generate_actions_api_method_signature: (spec: ActionSpecUni
|
|
|
182
182
|
/** Discriminator for `generate_action_method_enums` — which method-set enums to emit. */
|
|
183
183
|
export type ActionMethodEnumKind = 'all' | 'request_response' | 'remote_notification' | 'local_call' | 'frontend' | 'backend' | 'frontend_handled' | 'backend_handled' | 'broadcast';
|
|
184
184
|
/** Default emit set — every enum kind. */
|
|
185
|
-
export declare const
|
|
185
|
+
export declare const action_method_enum_kinds_all: ReadonlySet<ActionMethodEnumKind>;
|
|
186
186
|
/**
|
|
187
187
|
* Resolve a per-spec identifier qualifier with the standard default-vs-callback
|
|
188
188
|
* dance. When `qualify_spec` is set, returns the caller's callback verbatim
|
|
@@ -416,7 +416,7 @@ ${lines}
|
|
|
416
416
|
export type ${name} = z.infer<typeof ${name}>;`;
|
|
417
417
|
};
|
|
418
418
|
/** Default emit set — every enum kind. */
|
|
419
|
-
export const
|
|
419
|
+
export const action_method_enum_kinds_all = new Set([
|
|
420
420
|
'all',
|
|
421
421
|
'request_response',
|
|
422
422
|
'remote_notification',
|
|
@@ -483,7 +483,7 @@ export const resolve_spec_qualifier = (imports, options) => {
|
|
|
483
483
|
* `cancel` in the emitted enums. Default `false`.
|
|
484
484
|
*/
|
|
485
485
|
export const generate_action_method_enums = (specs, imports, options) => {
|
|
486
|
-
const emit = options?.emit ??
|
|
486
|
+
const emit = options?.emit ?? action_method_enum_kinds_all;
|
|
487
487
|
const filtered = filter_protocol_actions(specs, options?.include_protocol_actions);
|
|
488
488
|
const registry = new ActionRegistry([...filtered]);
|
|
489
489
|
const blocks = [];
|
|
@@ -59,20 +59,20 @@ export declare const is_notification_send_with_parsed_input: <TMethod extends st
|
|
|
59
59
|
input: unknown;
|
|
60
60
|
};
|
|
61
61
|
/**
|
|
62
|
-
* Validate that a step transition is legal per `
|
|
62
|
+
* Validate that a step transition is legal per `action_event_step_transitions`.
|
|
63
63
|
*
|
|
64
64
|
* @throws Error if `from → to` is not a permitted transition
|
|
65
65
|
*/
|
|
66
66
|
export declare const validate_step_transition: (from: ActionEventStep, to: ActionEventStep) => void;
|
|
67
67
|
/**
|
|
68
68
|
* Validate that `phase` is one of the phases allowed for `kind` per
|
|
69
|
-
* `
|
|
69
|
+
* `action_event_phase_by_kind`.
|
|
70
70
|
*
|
|
71
71
|
* @throws Error if `phase` is not valid for `kind`
|
|
72
72
|
*/
|
|
73
73
|
export declare const validate_phase_for_kind: (kind: ActionKind, phase: ActionEventPhase) => void;
|
|
74
74
|
/**
|
|
75
|
-
* Validate that a phase chain is legal per `
|
|
75
|
+
* Validate that a phase chain is legal per `action_event_phase_transitions`.
|
|
76
76
|
*
|
|
77
77
|
* @throws Error if `from → to` is not the permitted next phase (or `from` is terminal)
|
|
78
78
|
*/
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
6
|
+
import { action_event_step_transitions, action_event_phase_by_kind, action_event_phase_transitions, } from './action_event_types.js';
|
|
7
7
|
// Type guards for action kinds
|
|
8
8
|
export const is_request_response = (data) => data.kind === 'request_response';
|
|
9
9
|
export const is_remote_notification = (data) => data.kind === 'remote_notification';
|
|
@@ -28,33 +28,33 @@ export const is_failed = (data) => data.step === 'failed';
|
|
|
28
28
|
export const is_send_request_with_parsed_input = (data) => is_send_request(data) && (data.step === 'parsed' || data.step === 'handling');
|
|
29
29
|
export const is_notification_send_with_parsed_input = (data) => is_notification_send(data) && (data.step === 'parsed' || data.step === 'handling');
|
|
30
30
|
/**
|
|
31
|
-
* Validate that a step transition is legal per `
|
|
31
|
+
* Validate that a step transition is legal per `action_event_step_transitions`.
|
|
32
32
|
*
|
|
33
33
|
* @throws Error if `from → to` is not a permitted transition
|
|
34
34
|
*/
|
|
35
35
|
export const validate_step_transition = (from, to) => {
|
|
36
|
-
if (!
|
|
36
|
+
if (!action_event_step_transitions[from].includes(to)) {
|
|
37
37
|
throw new Error(`Invalid step transition from '${from}' to '${to}'`);
|
|
38
38
|
}
|
|
39
39
|
};
|
|
40
40
|
/**
|
|
41
41
|
* Validate that `phase` is one of the phases allowed for `kind` per
|
|
42
|
-
* `
|
|
42
|
+
* `action_event_phase_by_kind`.
|
|
43
43
|
*
|
|
44
44
|
* @throws Error if `phase` is not valid for `kind`
|
|
45
45
|
*/
|
|
46
46
|
export const validate_phase_for_kind = (kind, phase) => {
|
|
47
|
-
if (!
|
|
47
|
+
if (!action_event_phase_by_kind[kind].includes(phase)) {
|
|
48
48
|
throw new Error(`Invalid phase '${phase}' for ${kind} action`);
|
|
49
49
|
}
|
|
50
50
|
};
|
|
51
51
|
/**
|
|
52
|
-
* Validate that a phase chain is legal per `
|
|
52
|
+
* Validate that a phase chain is legal per `action_event_phase_transitions`.
|
|
53
53
|
*
|
|
54
54
|
* @throws Error if `from → to` is not the permitted next phase (or `from` is terminal)
|
|
55
55
|
*/
|
|
56
56
|
export const validate_phase_transition = (from, to) => {
|
|
57
|
-
const expected =
|
|
57
|
+
const expected = action_event_phase_transitions[from];
|
|
58
58
|
if (expected !== to) {
|
|
59
59
|
throw new Error(`Invalid phase transition from '${from}' to '${to}'`);
|
|
60
60
|
}
|
|
@@ -79,7 +79,7 @@ export const is_action_complete = (data) => {
|
|
|
79
79
|
if (data.step !== 'handled')
|
|
80
80
|
return false;
|
|
81
81
|
// Check if in terminal phase
|
|
82
|
-
const next_phase =
|
|
82
|
+
const next_phase = action_event_phase_transitions[data.phase];
|
|
83
83
|
return next_phase === null;
|
|
84
84
|
};
|
|
85
85
|
export const create_initial_data = (kind, phase, method, executor, input) => ({
|
|
@@ -19,9 +19,9 @@ export declare const ActionEventStep: z.ZodEnum<{
|
|
|
19
19
|
failed: "failed";
|
|
20
20
|
}>;
|
|
21
21
|
export type ActionEventStep = z.infer<typeof ActionEventStep>;
|
|
22
|
-
export declare const
|
|
23
|
-
export declare const
|
|
24
|
-
export declare const
|
|
22
|
+
export declare const action_event_step_transitions: Record<ActionEventStep, ReadonlyArray<ActionEventStep>>;
|
|
23
|
+
export declare const action_event_phase_by_kind: Record<ActionKind, ReadonlyArray<ActionEventPhase>>;
|
|
24
|
+
export declare const action_event_phase_transitions: Record<ActionEventPhase, ActionEventPhase | null>;
|
|
25
25
|
export interface ActionEventEnvironment {
|
|
26
26
|
readonly executor: ActionExecutor;
|
|
27
27
|
lookup_action_handler: (method: string, phase: ActionEventPhase) => ((event: any) => any) | undefined;
|
|
@@ -12,14 +12,14 @@ export const ActionEventStep = z.enum(['initial', 'parsed', 'handling', 'handled
|
|
|
12
12
|
// value types on the object literal) without narrowing lookups to literal
|
|
13
13
|
// tuple types — a `satisfies` shape forces every `X[k]` reader to widen
|
|
14
14
|
// back to `ReadonlyArray<V>` themselves to call `.includes(...)`.
|
|
15
|
-
export const
|
|
15
|
+
export const action_event_step_transitions = {
|
|
16
16
|
initial: ['parsed', 'failed'],
|
|
17
17
|
parsed: ['handling', 'failed'],
|
|
18
18
|
handling: ['handled', 'failed'],
|
|
19
19
|
handled: [],
|
|
20
20
|
failed: [],
|
|
21
21
|
};
|
|
22
|
-
export const
|
|
22
|
+
export const action_event_phase_by_kind = {
|
|
23
23
|
request_response: [
|
|
24
24
|
'send_request',
|
|
25
25
|
'receive_request',
|
|
@@ -31,7 +31,7 @@ export const ACTION_EVENT_PHASE_BY_KIND = {
|
|
|
31
31
|
remote_notification: ['send', 'receive'],
|
|
32
32
|
local_call: ['execute'],
|
|
33
33
|
};
|
|
34
|
-
export const
|
|
34
|
+
export const action_event_phase_transitions = {
|
|
35
35
|
send_request: 'receive_response',
|
|
36
36
|
receive_request: 'send_response',
|
|
37
37
|
send_response: null,
|
|
@@ -36,7 +36,7 @@ export type AuditEventHandler = (event: AuditLogEvent) => void;
|
|
|
36
36
|
* require either closing all sockets (too aggressive) or new tracking
|
|
37
37
|
* (out of scope). Consumers that need it compose their own callback.
|
|
38
38
|
*/
|
|
39
|
-
export declare const
|
|
39
|
+
export declare const ws_disconnect_event_types: ReadonlySet<string>;
|
|
40
40
|
/**
|
|
41
41
|
* Create an audit event handler that closes WebSocket connections on auth changes.
|
|
42
42
|
*
|
|
@@ -56,7 +56,7 @@ export declare const create_ws_auth_guard: (transport: BackendWebsocketTransport
|
|
|
56
56
|
* user-initiated logout.
|
|
57
57
|
*
|
|
58
58
|
* Sibling helper to `create_ws_auth_guard` — kept separate because
|
|
59
|
-
* `
|
|
59
|
+
* `ws_disconnect_event_types` deliberately omits `logout` (admin-initiated
|
|
60
60
|
* revocations use `session_revoke`, while `logout` is the user-initiated
|
|
61
61
|
* case). Three consumers (tx, undying, zzz) hand-rolled this same branch
|
|
62
62
|
* before extraction.
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* require either closing all sockets (too aggressive) or new tracking
|
|
24
24
|
* (out of scope). Consumers that need it compose their own callback.
|
|
25
25
|
*/
|
|
26
|
-
export const
|
|
26
|
+
export const ws_disconnect_event_types = new Set([
|
|
27
27
|
'session_revoke',
|
|
28
28
|
'token_revoke',
|
|
29
29
|
'session_revoke_all',
|
|
@@ -45,7 +45,7 @@ export const WS_DISCONNECT_EVENT_TYPES = new Set([
|
|
|
45
45
|
*/
|
|
46
46
|
export const create_ws_auth_guard = (transport, log) => {
|
|
47
47
|
return (event) => {
|
|
48
|
-
if (!
|
|
48
|
+
if (!ws_disconnect_event_types.has(event.event_type))
|
|
49
49
|
return;
|
|
50
50
|
// Failed mutations carry attacker-controlled metadata — never act on them.
|
|
51
51
|
if (event.outcome === 'failure')
|
|
@@ -90,7 +90,7 @@ export const create_ws_auth_guard = (transport, log) => {
|
|
|
90
90
|
* user-initiated logout.
|
|
91
91
|
*
|
|
92
92
|
* Sibling helper to `create_ws_auth_guard` — kept separate because
|
|
93
|
-
* `
|
|
93
|
+
* `ws_disconnect_event_types` deliberately omits `logout` (admin-initiated
|
|
94
94
|
* revocations use `session_revoke`, while `logout` is the user-initiated
|
|
95
95
|
* case). Three consumers (tx, undying, zzz) hand-rolled this same branch
|
|
96
96
|
* before extraction.
|
package/dist/auth/CLAUDE.md
CHANGED
|
@@ -21,7 +21,7 @@ sections.
|
|
|
21
21
|
| Module | Exports |
|
|
22
22
|
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
23
23
|
| `keyring.ts` | `Keyring`, `create_keyring`, `validate_keyring`, `create_validated_keyring`, `ValidatedKeyringResult` |
|
|
24
|
-
| `session_cookie.ts` | `SessionOptions<T>`, `SessionCookieOptions`, `
|
|
24
|
+
| `session_cookie.ts` | `SessionOptions<T>`, `SessionCookieOptions`, `session_cookie_options`, `SESSION_AGE_MAX`, `SESSION_REFRESH_THRESHOLD_S`, `ParsedSession`, `ProcessSessionResult`, `parse_session`, `create_session_cookie_value`, `process_session_cookie`, `create_session_config`, `fuz_session_config` |
|
|
25
25
|
| `password.ts` | `Password`, `PasswordProvided`, `PasswordHashDeps`, `PASSWORD_LENGTH_MIN` (12, OWASP), `PASSWORD_LENGTH_MAX` (300) |
|
|
26
26
|
| `password_argon2.ts` | `hash_password`, `verify_password`, `verify_dummy`, `argon2_password_deps` |
|
|
27
27
|
| `api_token.ts` | `API_TOKEN_PREFIX` (`secret_fuz_token_`), `hash_api_token`, `generate_api_token` |
|
|
@@ -179,7 +179,7 @@ those three. Mirrors the open-registry pattern used for `RoleName` /
|
|
|
179
179
|
constant is named `_API_TOKEN` (not `_BEARER`) so wire literal and
|
|
180
180
|
the `api_token` storage table stay in lockstep.
|
|
181
181
|
- `BUILTIN_CREDENTIAL_TYPES` const tuple, `BuiltinCredentialType` Zod
|
|
182
|
-
enum, `
|
|
182
|
+
enum, `builtin_credential_type_meta` admin-UI-facing descriptions.
|
|
183
183
|
- `create_credential_type_schema(consumer_types?)`
|
|
184
184
|
→ `{CredentialType, credential_types: ReadonlyMap}`. Builtins always
|
|
185
185
|
present; consumer collisions / regex failures / duplicates throw at
|
|
@@ -197,7 +197,7 @@ granted. Four builtins (`admin`, `self_service`, `system`, `bootstrap`).
|
|
|
197
197
|
- `GRANT_PATH_ADMIN` / `_SELF_SERVICE` / `_SYSTEM` / `_BOOTSTRAP` —
|
|
198
198
|
builtin literal constants.
|
|
199
199
|
- `BUILTIN_GRANT_PATHS` const tuple, `BuiltinGrantPath` Zod enum,
|
|
200
|
-
`
|
|
200
|
+
`builtin_grant_path_meta` descriptions.
|
|
201
201
|
- `create_grant_path_schema(consumer_paths?)`
|
|
202
202
|
→ `{GrantPath, grant_paths: ReadonlyMap}`. Same construction-time
|
|
203
203
|
guards as the credential-type schema. Pass the result into
|
|
@@ -224,7 +224,7 @@ against the corresponding open registries at construction time.
|
|
|
224
224
|
- `ROLE_KEEPER = 'keeper'` — bootstrap-only via daemon token; `grant_paths: ['bootstrap']`,
|
|
225
225
|
`required_credential_types: ['daemon_token']`.
|
|
226
226
|
- `ROLE_ADMIN = 'admin'` — admin-grantable; `grant_paths: ['admin']`.
|
|
227
|
-
- `BUILTIN_ROLES`, `BuiltinRole` (Zod enum), `
|
|
227
|
+
- `BUILTIN_ROLES`, `BuiltinRole` (Zod enum), `builtin_role_specs_by_name`
|
|
228
228
|
(`ReadonlyMap<string, RoleSpec>`) — not overridable by consumers.
|
|
229
229
|
- `RoleSpec`: `{name, description?, required_credential_types?, applicable_scope_kinds?, grant_paths?}`
|
|
230
230
|
— every cross-axis field is an open-registry string array. Empty
|
|
@@ -302,7 +302,7 @@ Zod enum; `AuditOutcome` is `'success' | 'failure'`.
|
|
|
302
302
|
|
|
303
303
|
#### Metadata schemas
|
|
304
304
|
|
|
305
|
-
- `
|
|
305
|
+
- `audit_metadata_schemas` — per-type `z.looseObject`. Notable shapes:
|
|
306
306
|
- `role_grant_create` — `scope_id`, optional `role_grant_id` (failed grants
|
|
307
307
|
omit — admin-grant-path denial never produces a row), optional
|
|
308
308
|
`source_offer_id`, optional `self_service` (set by
|
|
@@ -376,7 +376,7 @@ Zod enum; `AuditOutcome` is `'success' | 'failure'`.
|
|
|
376
376
|
without validation). Pass the result to `create_app_backend({audit_log_config})`
|
|
377
377
|
— it gets captured inside the bound `AppDeps.audit` emitter, and every
|
|
378
378
|
call to `audit.emit` validates against it (defaults to
|
|
379
|
-
`
|
|
379
|
+
`builtin_audit_log_config` when absent). `query_audit_log` still accepts
|
|
380
380
|
the trailing `config` positional arg for in-transaction emit sites that
|
|
381
381
|
hold a transaction-scoped DB only. Builtin collisions and
|
|
382
382
|
`AuditEventTypeName` format failures throw at construction. The DB
|
|
@@ -396,7 +396,7 @@ Zod enum; `AuditOutcome` is `'success' | 'failure'`.
|
|
|
396
396
|
factory they track the same config, but a hand-rolled `AuditLogConfig`
|
|
397
397
|
(or a cast escape) can fire both on a single emission. Sample via
|
|
398
398
|
`get_*` getters; `reset_*` are test-only. `AUDIT_EVENT_TYPES`,
|
|
399
|
-
`
|
|
399
|
+
`audit_metadata_schemas`, `builtin_audit_log_config`, and the configs
|
|
400
400
|
returned by `create_audit_log_config` are `Object.freeze`'d to convert
|
|
401
401
|
accidental mutation (bugs, test cross-contamination, cast escapes)
|
|
402
402
|
into loud TypeErrors — not a security boundary.
|
|
@@ -470,7 +470,7 @@ exports: `RoleGrantOfferReceivedParams`, `_RetractedParams`, `_AcceptedParams`,
|
|
|
470
470
|
`_DeclinedParams`, `_SupersedeParams`, `RoleGrantRevokeParams`. Notification
|
|
471
471
|
builders: `build_role_grant_offer_received_notification(params)` etc.
|
|
472
472
|
|
|
473
|
-
`
|
|
473
|
+
`role_grant_offer_notification_specs: Array<EventSpec>` — pass to
|
|
474
474
|
`create_app_server`'s `event_specs` so the attack surface reflects them
|
|
475
475
|
and DEV-mode `create_validated_broadcaster` catches payload drift.
|
|
476
476
|
|
|
@@ -521,6 +521,31 @@ account_id = ANY(...))` so `actor.id`s never round-trip back to the
|
|
|
521
521
|
visibility). Returns `Array<AdminAccountEntryJson>`, sorted by
|
|
522
522
|
`created_at`.
|
|
523
523
|
|
|
524
|
+
### `actor_lookup_queries.ts`
|
|
525
|
+
|
|
526
|
+
- `query_actors_by_ids(deps, ids) → Array<ActorLookupRow>` — batched
|
|
527
|
+
`actor` ⨝ `account` INNER JOIN, returns
|
|
528
|
+
`{id, username, display_name}` per resolved actor. Empty input
|
|
529
|
+
fast-paths to `[]`; hard-deleted (or cascade-orphaned) rows silently
|
|
530
|
+
drop. Row shape omits `account_id` — the join is control-plane, not
|
|
531
|
+
wire-visible. Caller bounds `ids.length` (the action spec enforces
|
|
532
|
+
`ACTOR_LOOKUP_IDS_MAX`); SQL does not.
|
|
533
|
+
|
|
534
|
+
### `actor_search_queries.ts`
|
|
535
|
+
|
|
536
|
+
- `query_actor_search(deps, {query, scope_ids?, limit}) → Array<ActorLookupRow>` —
|
|
537
|
+
case-insensitive LIKE-prefix on `actor.name`, backed by the
|
|
538
|
+
`idx_actor_name_lower` functional index in `auth_ddl.ts`. Returns the
|
|
539
|
+
same `{id, username, display_name}` row shape as `query_actors_by_ids`
|
|
540
|
+
so the labels arc stays uniform. LIKE wildcards (`%`, `_`, `\`) in
|
|
541
|
+
the user-supplied `query` are escaped before substitution so the
|
|
542
|
+
prefix-only contract is enforceable. When `scope_ids` is non-empty,
|
|
543
|
+
the result is filtered to actors holding an **active** role_grant
|
|
544
|
+
(`revoked_at IS NULL AND (expires_at IS NULL OR expires_at > NOW())`)
|
|
545
|
+
on one of the supplied scopes; `DISTINCT` collapses multi-grant
|
|
546
|
+
duplicates. When `scope_ids` is empty, no role_grant join — the handler
|
|
547
|
+
enforces admin for that path.
|
|
548
|
+
|
|
524
549
|
### `role_grant_queries.ts`
|
|
525
550
|
|
|
526
551
|
- `query_create_role_grant` — idempotent; `ON CONFLICT` target and fallback
|
|
@@ -551,6 +576,12 @@ account_id = ANY(...))` so `actor.id`s never round-trip back to the
|
|
|
551
576
|
that isn't the request actor (e.g., post-mutation verification, scripts,
|
|
552
577
|
audit-time checks). For the request actor, prefer `has_scoped_role` /
|
|
553
578
|
`has_any_scoped_role` on the in-memory `auth.role_grants` snapshot.
|
|
579
|
+
- `query_account_has_global_role(deps, account_id, role)` — account-grain
|
|
580
|
+
sibling: does any actor on `account_id` hold an active **global**
|
|
581
|
+
(`scope_id IS NULL`) role_grant for `role`? For surfaces with
|
|
582
|
+
`auth: actor: 'none'` that don't load `auth.role_grants` and can't use
|
|
583
|
+
`has_scoped_role`. EXISTS over the `idx_role_grant_actor`-backed
|
|
584
|
+
subquery, stops at the first match.
|
|
554
585
|
- `query_role_grant_find_account_id_for_role(deps, role)` — joins
|
|
555
586
|
role_grant → actor → account, returns first match. Used by daemon token
|
|
556
587
|
middleware to resolve the keeper account.
|
|
@@ -701,7 +732,7 @@ run'` if the seed somehow missed (defensive — migrations always seed).
|
|
|
701
732
|
### `audit_log_queries.ts`
|
|
702
733
|
|
|
703
734
|
- `query_audit_log<T>(deps, input, config?)` — `config` defaults to
|
|
704
|
-
`
|
|
735
|
+
`builtin_audit_log_config`. Membership check runs against
|
|
705
736
|
`config.event_types`; metadata validation runs independently against
|
|
706
737
|
`config.metadata_schemas[event_type]` when present. Mismatches and
|
|
707
738
|
unknown types log + bump their counters (see schema section);
|
|
@@ -769,8 +800,8 @@ without rebuilding `AppDeps`.
|
|
|
769
800
|
|
|
770
801
|
### `migrations.ts`
|
|
771
802
|
|
|
772
|
-
- `AUTH_MIGRATION_NAMESPACE = 'fuz_auth'`, `
|
|
773
|
-
- `
|
|
803
|
+
- `AUTH_MIGRATION_NAMESPACE = 'fuz_auth'`, `auth_migration_ns` (pre-composed), `reserved_migration_namespaces: ReadonlyArray<string>` (membership list `create_app_backend` rejects on; consumer-discoverable instead of probing the runtime throw).
|
|
804
|
+
- `auth_migrations`:
|
|
774
805
|
- **v0 `full_auth_schema`** — every table + index + seed for the v1
|
|
775
806
|
identity system (account, actor, role_grant, auth_session, api_token,
|
|
776
807
|
audit_log, bootstrap_lock, invite, app_settings). All
|
|
@@ -1253,7 +1284,7 @@ of paginated cross-account listings (`admin_account_list`,
|
|
|
1253
1284
|
cross-account reads (`admin_session_list`, `invite_list`). The
|
|
1254
1285
|
dispatcher's per-action hook (shared by HTTP RPC + WS) records every
|
|
1255
1286
|
invocation regardless of outcome so successful probes consume budget.
|
|
1256
|
-
Default `
|
|
1287
|
+
Default `default_action_account_rate_limit` is 1200/15min per actor —
|
|
1257
1288
|
permissive enough for any human admin workflow, slow enough that
|
|
1258
1289
|
scripted oracles surface in audit. Tighten downstream via
|
|
1259
1290
|
`AppServerOptions.action_account_rate_limiter`.
|
|
@@ -1286,7 +1317,7 @@ self-service `account_actions.ts` surface):
|
|
|
1286
1317
|
|
|
1287
1318
|
Closure state:
|
|
1288
1319
|
|
|
1289
|
-
- `grantable_roles` is derived once from `options.roles?.role_specs ??
|
|
1320
|
+
- `grantable_roles` is derived once from `options.roles?.role_specs ?? builtin_role_specs_by_name`
|
|
1290
1321
|
via `list_roles_with_grant_path(_, GRANT_PATH_ADMIN)` and closed over
|
|
1291
1322
|
by the `admin_account_list` handler.
|
|
1292
1323
|
- `options.app_settings` — when provided, captured by the
|
|
@@ -1430,7 +1461,7 @@ Options:
|
|
|
1430
1461
|
|
|
1431
1462
|
- `roles?: RoleSchemaResult` — drives the admin-grant-path lookup
|
|
1432
1463
|
(`role_has_grant_path(_, role, GRANT_PATH_ADMIN)`); defaults to
|
|
1433
|
-
`
|
|
1464
|
+
`builtin_role_specs_by_name`.
|
|
1434
1465
|
- `default_ttl_ms?: number` — applied to new offers (defaults to
|
|
1435
1466
|
`ROLE_GRANT_OFFER_DEFAULT_TTL_MS`).
|
|
1436
1467
|
- `authorize?: RoleGrantOfferCreateAuthorize` — custom policy for
|
|
@@ -1495,6 +1526,14 @@ and `create_frontend_rpc_client({specs})` wiring. Self-service role
|
|
|
1495
1526
|
specs are not included (opt-in, app-specific `eligible_roles`) —
|
|
1496
1527
|
spread `all_self_service_role_action_specs` separately when needed.
|
|
1497
1528
|
|
|
1529
|
+
### `all_action_spec_registries.ts` — walker-only registry-of-registries
|
|
1530
|
+
|
|
1531
|
+
`all_fuz_auth_action_spec_registries` — walker/codegen entry for every
|
|
1532
|
+
fuz-auth action-spec bundle (`admin`, `role_grant_offer`, `account`,
|
|
1533
|
+
`self_service_role`, `actor_lookup`). Not a mounting surface; protocol
|
|
1534
|
+
specs are excluded. Iterated by `../../test/auth/action_spec_input_invariants.test.ts`
|
|
1535
|
+
and `../../test/auth/all_action_spec_registries.acting_biconditional.test.ts`.
|
|
1536
|
+
|
|
1498
1537
|
### `account_action_specs.ts` + `account_actions.ts` — seven self-service RPC actions
|
|
1499
1538
|
|
|
1500
1539
|
Counterpart to `account_routes.ts`. Cookie-lifecycle flows (`login`,
|
|
@@ -1583,7 +1622,7 @@ codegen invariant and grow the surface linearly per role.
|
|
|
1583
1622
|
|
|
1584
1623
|
- `eligible_roles?: ReadonlyArray<string>` — optional override
|
|
1585
1624
|
allowlist. When omitted, eligibility is derived from
|
|
1586
|
-
`roles.role_specs` (or `
|
|
1625
|
+
`roles.role_specs` (or `builtin_role_specs_by_name` when `roles` is
|
|
1587
1626
|
also omitted) by selecting every role whose `RoleSpec.grant_paths`
|
|
1588
1627
|
includes `'self_service'` (`GRANT_PATH_SELF_SERVICE`). Roles outside
|
|
1589
1628
|
the eligible set are rejected with `forbidden` + reason
|
|
@@ -1610,6 +1649,109 @@ Deps: `Pick<RouteFactoryDeps, 'log' | 'audit'>`.
|
|
|
1610
1649
|
`all_self_service_role_action_specs: ReadonlyArray<RequestResponseActionSpec>` —
|
|
1611
1650
|
codegen-ready registry of the single unified spec.
|
|
1612
1651
|
|
|
1652
|
+
### `actor_lookup_action_specs.ts` + `actor_lookup_actions.ts` — opt-in batched actor → label resolver
|
|
1653
|
+
|
|
1654
|
+
One static `request_response` action — `actor_lookup({ids}) → {actors:
|
|
1655
|
+
[{id, username, display_name?}]}` — powers the labels arc for surfaces
|
|
1656
|
+
that stamp an actor id (bylines, owner columns, grantor labels, audit
|
|
1657
|
+
"by" cells). One round trip resolves a batch to display strings;
|
|
1658
|
+
`ACTOR_LOOKUP_IDS_MAX = 50` cap per call.
|
|
1659
|
+
|
|
1660
|
+
**Auth + rate-limit posture.** `{account: 'required', actor: 'none'}` +
|
|
1661
|
+
`rate_limit: 'account'`. Account-grain — the caller need only be signed
|
|
1662
|
+
in; resolution skips the actor phase. The auth gate + per-account rate
|
|
1663
|
+
limit + per-call cap bound the batched username-enumeration surface that
|
|
1664
|
+
a `cell_list` ↔ `actor_lookup` pair would otherwise present. Don't loosen
|
|
1665
|
+
to public — a public-surface byline should resolve via SSR-stamped labels
|
|
1666
|
+
or per-cell embedded actor labels, not by widening this gate.
|
|
1667
|
+
|
|
1668
|
+
**Wire shape — info-leak audit.** Deliberately omitted from
|
|
1669
|
+
`ActorLookupEntryJson`:
|
|
1670
|
+
|
|
1671
|
+
- `account_id` — the actor↔account join is a control-plane detail.
|
|
1672
|
+
- `email`, password/credential fields — never queried.
|
|
1673
|
+
- `created_at` / `updated_at` — timing-oracle avoidance.
|
|
1674
|
+
- role / role_grants / session state — separation of concern.
|
|
1675
|
+
|
|
1676
|
+
`display_name` is omitted (not `null`) when `actor.name` is blank, so
|
|
1677
|
+
clients see `undefined` rather than a sentinel string. Unknown ids are
|
|
1678
|
+
silently absent — by construction this is an existence-oracle (caller
|
|
1679
|
+
diffs response ids against request ids), bounded by rate-limit, the
|
|
1680
|
+
50-id cap, actor-uuid intractability (122-bit random), and the
|
|
1681
|
+
hard-delete-cascade indistinguishability from never-existed (no
|
|
1682
|
+
tombstone oracle). Response order is unspecified — callers index by
|
|
1683
|
+
`id` when needed.
|
|
1684
|
+
|
|
1685
|
+
`create_actor_lookup_actions(deps)` — `deps:
|
|
1686
|
+
Pick<RouteFactoryDeps, 'log'>`. Pure read; no audit, no side effects.
|
|
1687
|
+
Backed by `query_actors_by_ids` (see Queries §
|
|
1688
|
+
[`actor_lookup_queries.ts`](#actor_lookup_queriests)).
|
|
1689
|
+
|
|
1690
|
+
Bundle is **not** included in `create_standard_rpc_actions` — consumers
|
|
1691
|
+
without a byline surface can skip it. Spread
|
|
1692
|
+
`all_actor_lookup_action_specs` alongside the standard bundle when the
|
|
1693
|
+
labels arc is needed.
|
|
1694
|
+
|
|
1695
|
+
### `actor_search_action_specs.ts` + `actor_search_actions.ts` — opt-in prefix-search picker
|
|
1696
|
+
|
|
1697
|
+
One static `request_response` action — `actor_search({query, scope_ids?, limit?}) → {actors: [{id, username, display_name?}]}` —
|
|
1698
|
+
powers person-target pickers. Sibling to `actor_lookup`: that resolves a
|
|
1699
|
+
batch of known ids to labels; this resolves a partial name to candidate
|
|
1700
|
+
actors. Reuses `ActorLookupEntryJson` from
|
|
1701
|
+
`./actor_lookup_action_specs.ts` so the labels arc on the consumer side
|
|
1702
|
+
stays uniform. Default limit `ACTOR_SEARCH_LIMIT_DEFAULT = 20`, hard cap
|
|
1703
|
+
`ACTOR_SEARCH_LIMIT_MAX = 50`. Query string capped at
|
|
1704
|
+
`ACTOR_SEARCH_QUERY_LENGTH_MAX = 50`.
|
|
1705
|
+
|
|
1706
|
+
**Auth + rate-limit posture.** `{account: 'required', actor: 'none'}` +
|
|
1707
|
+
`rate_limit: 'account'`. Same shape as `actor_lookup`. The handler
|
|
1708
|
+
additionally requires the caller to be admin when `scope_ids` is empty —
|
|
1709
|
+
unbounded global search is the admin-only arm; non-admin callers must
|
|
1710
|
+
always pass at least one scope_id and get filtered to actors with active
|
|
1711
|
+
role_grants on those scopes. The admin check is **account-grain** (any
|
|
1712
|
+
actor on the caller's account holds a global `admin` role_grant) via
|
|
1713
|
+
`query_account_has_global_role` — the `actor: 'none'` posture means
|
|
1714
|
+
`auth.role_grants` is empty and the in-memory `has_scoped_role` helper
|
|
1715
|
+
doesn't apply.
|
|
1716
|
+
|
|
1717
|
+
**Caller-passes-scope_ids design.** `scope_ids` is trusted as a filter,
|
|
1718
|
+
not as an authority claim — the SQL filters to actors with role_grants on
|
|
1719
|
+
those scopes regardless of whether the caller has authority over them.
|
|
1720
|
+
Consumers (e.g. visiones' `CellGrantsEditor.svelte`) pre-filter
|
|
1721
|
+
`scope_ids` against their own authority (the teacher-predicate stays in
|
|
1722
|
+
the consumer layer, not in fuz_app). This does **not** widen the
|
|
1723
|
+
scope-existence oracle: an attacker passing a random scope_id never
|
|
1724
|
+
learns the scope existed if no member happens to match the query, and
|
|
1725
|
+
even on a match the result row only carries the matching actor — never
|
|
1726
|
+
"which scope matched".
|
|
1727
|
+
|
|
1728
|
+
**Wire shape — additional info-leak posture beyond `actor_lookup`'s.**
|
|
1729
|
+
|
|
1730
|
+
- Prefix match (`LOWER(name) LIKE LOWER(query) || '%' ESCAPE '\\'`),
|
|
1731
|
+
**not** full `%query%`. LIKE wildcards in the user-supplied query are
|
|
1732
|
+
escaped at the JS layer so a `%xyz` input can't widen to full LIKE
|
|
1733
|
+
and defeat the per-call cap.
|
|
1734
|
+
- Empty result set on no-match — fail-soft like `cell_list`. No "no
|
|
1735
|
+
actor matches" error that would leak an existence boundary on the
|
|
1736
|
+
search-term axis.
|
|
1737
|
+
- Hard-deleted actors silently drop (same `account_id` cascade as
|
|
1738
|
+
`actor_lookup`).
|
|
1739
|
+
|
|
1740
|
+
Reason constant exported for failed-arm matching: `ERROR_ACTOR_SEARCH_SCOPE_REQUIRED`
|
|
1741
|
+
(`'actor_search_scope_required'`) — fired with `invalid_params` when a
|
|
1742
|
+
non-admin caller omits `scope_ids` or passes `[]`. Surfaced on
|
|
1743
|
+
`spec.error_reasons` so codegen + form-state matching can read it
|
|
1744
|
+
declaratively.
|
|
1745
|
+
|
|
1746
|
+
`create_actor_search_actions(deps)` — `deps:
|
|
1747
|
+
Pick<RouteFactoryDeps, 'log'>`. Pure read; no audit, no side effects.
|
|
1748
|
+
Backed by `query_actor_search` (see Queries §`actor_search_queries.ts`).
|
|
1749
|
+
|
|
1750
|
+
Bundle is **not** included in `create_standard_rpc_actions` — consumers
|
|
1751
|
+
without a person-target picker can skip it. Spread
|
|
1752
|
+
`all_actor_search_action_specs` alongside the standard bundle when the
|
|
1753
|
+
picker is needed.
|
|
1754
|
+
|
|
1613
1755
|
## Cleanup
|
|
1614
1756
|
|
|
1615
1757
|
`cleanup.ts` — periodic auth maintenance:
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `actor_lookup` RPC spec — authenticated batched id → username/display_name
|
|
3
|
+
* resolver, keyed by actor id.
|
|
4
|
+
*
|
|
5
|
+
* Powers the labels arc for surfaces that stamp an actor id (bylines,
|
|
6
|
+
* owner columns, grantor labels, audit-log "by" cells). One round trip
|
|
7
|
+
* resolves an array of ids to display strings.
|
|
8
|
+
*
|
|
9
|
+
* ## Auth + rate-limit posture
|
|
10
|
+
*
|
|
11
|
+
* `{account: 'required', actor: 'none'}` + `rate_limit: 'account'`.
|
|
12
|
+
* Account-grain — only that the caller is signed in matters, not which
|
|
13
|
+
* actor is calling, so resolution skips the actor phase. The auth gate
|
|
14
|
+
* + per-account rate limit (default 1200/15min) + the
|
|
15
|
+
* {@link ACTOR_LOOKUP_IDS_MAX | per-call cap} bound the batched
|
|
16
|
+
* username-enumeration surface that the `cell_list` ↔ `actor_lookup`
|
|
17
|
+
* pair would otherwise present.
|
|
18
|
+
*
|
|
19
|
+
* If a public-surface byline ever lands (e.g. an unauthenticated
|
|
20
|
+
* gallery), it should resolve via a separate public-safe mechanism
|
|
21
|
+
* (SSR-stamped labels or a per-cell embedded actor label), **not** by
|
|
22
|
+
* loosening this gate.
|
|
23
|
+
*
|
|
24
|
+
* ## Wire shape — info-leak audit
|
|
25
|
+
*
|
|
26
|
+
* Output: `{actors: [{id, username, display_name?}]}`. Deliberately
|
|
27
|
+
* omitted:
|
|
28
|
+
*
|
|
29
|
+
* - `account_id` — the actor↔account join is a control-plane detail
|
|
30
|
+
* - `email`, password/credential fields — never queried
|
|
31
|
+
* - `created_at` / `updated_at` — timing-oracle avoidance
|
|
32
|
+
* - role / role_grants / session state — separation of concern
|
|
33
|
+
*
|
|
34
|
+
* `display_name` is omitted (not `null`) when `actor.name` is blank, so
|
|
35
|
+
* clients see `undefined` rather than a sentinel string. Unknown ids are
|
|
36
|
+
* silently absent from the response — by construction this is an
|
|
37
|
+
* existence-oracle (the caller can diff response ids against request
|
|
38
|
+
* ids), bounded by:
|
|
39
|
+
*
|
|
40
|
+
* 1. rate-limit (per-account, see above),
|
|
41
|
+
* 2. {@link ACTOR_LOOKUP_IDS_MAX} cap per call,
|
|
42
|
+
* 3. actor-uuid intractability (122-bit random),
|
|
43
|
+
* 4. hard-deleted actors are indistinguishable from never-existed (no
|
|
44
|
+
* tombstone oracle — see `actor_lookup_queries.ts`).
|
|
45
|
+
*
|
|
46
|
+
* Response order is unspecified — callers index by `id` when needed.
|
|
47
|
+
*
|
|
48
|
+
* @module
|
|
49
|
+
*/
|
|
50
|
+
import { z } from 'zod';
|
|
51
|
+
/**
|
|
52
|
+
* Hard cap on the number of ids resolvable in one call. Bounds the
|
|
53
|
+
* batched username-enumeration surface.
|
|
54
|
+
*/
|
|
55
|
+
export declare const ACTOR_LOOKUP_IDS_MAX = 50;
|
|
56
|
+
/** One resolved actor row. `display_name` omitted when blank. */
|
|
57
|
+
export declare const ActorLookupEntryJson: z.ZodObject<{
|
|
58
|
+
id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
|
|
59
|
+
username: z.ZodString;
|
|
60
|
+
display_name: z.ZodOptional<z.ZodString>;
|
|
61
|
+
}, z.core.$strict>;
|
|
62
|
+
export type ActorLookupEntryJson = z.infer<typeof ActorLookupEntryJson>;
|
|
63
|
+
export declare const ActorLookupInput: z.ZodObject<{
|
|
64
|
+
ids: z.ZodArray<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
|
|
65
|
+
}, z.core.$strict>;
|
|
66
|
+
export type ActorLookupInput = z.infer<typeof ActorLookupInput>;
|
|
67
|
+
export declare const ActorLookupOutput: z.ZodObject<{
|
|
68
|
+
actors: z.ZodArray<z.ZodObject<{
|
|
69
|
+
id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
|
|
70
|
+
username: z.ZodString;
|
|
71
|
+
display_name: z.ZodOptional<z.ZodString>;
|
|
72
|
+
}, z.core.$strict>>;
|
|
73
|
+
}, z.core.$strict>;
|
|
74
|
+
export type ActorLookupOutput = z.infer<typeof ActorLookupOutput>;
|
|
75
|
+
export declare const actor_lookup_action_spec: {
|
|
76
|
+
method: string;
|
|
77
|
+
kind: "request_response";
|
|
78
|
+
initiator: "frontend";
|
|
79
|
+
auth: {
|
|
80
|
+
account: "required";
|
|
81
|
+
actor: "none";
|
|
82
|
+
};
|
|
83
|
+
side_effects: false;
|
|
84
|
+
input: z.ZodObject<{
|
|
85
|
+
ids: z.ZodArray<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
|
|
86
|
+
}, z.core.$strict>;
|
|
87
|
+
output: z.ZodObject<{
|
|
88
|
+
actors: z.ZodArray<z.ZodObject<{
|
|
89
|
+
id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
|
|
90
|
+
username: z.ZodString;
|
|
91
|
+
display_name: z.ZodOptional<z.ZodString>;
|
|
92
|
+
}, z.core.$strict>>;
|
|
93
|
+
}, z.core.$strict>;
|
|
94
|
+
async: true;
|
|
95
|
+
rate_limit: "account";
|
|
96
|
+
description: string;
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
* All actor_lookup action specs — independent opt-in registry. Consumers
|
|
100
|
+
* spread alongside `all_standard_action_specs` if they want the labels
|
|
101
|
+
* arc; not folded into the standard bundle because consumers without a
|
|
102
|
+
* byline surface can skip it.
|
|
103
|
+
*/
|
|
104
|
+
export declare const all_actor_lookup_action_specs: readonly [{
|
|
105
|
+
method: string;
|
|
106
|
+
kind: "request_response";
|
|
107
|
+
initiator: "frontend";
|
|
108
|
+
auth: {
|
|
109
|
+
account: "required";
|
|
110
|
+
actor: "none";
|
|
111
|
+
};
|
|
112
|
+
side_effects: false;
|
|
113
|
+
input: z.ZodObject<{
|
|
114
|
+
ids: z.ZodArray<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
|
|
115
|
+
}, z.core.$strict>;
|
|
116
|
+
output: z.ZodObject<{
|
|
117
|
+
actors: z.ZodArray<z.ZodObject<{
|
|
118
|
+
id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
|
|
119
|
+
username: z.ZodString;
|
|
120
|
+
display_name: z.ZodOptional<z.ZodString>;
|
|
121
|
+
}, z.core.$strict>>;
|
|
122
|
+
}, z.core.$strict>;
|
|
123
|
+
async: true;
|
|
124
|
+
rate_limit: "account";
|
|
125
|
+
description: string;
|
|
126
|
+
}];
|
|
127
|
+
//# sourceMappingURL=actor_lookup_action_specs.d.ts.map
|