@fuzdev/fuz_app 0.42.0 → 0.44.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 +77 -0
- package/dist/actions/action_rpc.d.ts.map +1 -1
- package/dist/actions/action_rpc.js +14 -7
- package/dist/actions/frontend_rpc_client.d.ts +74 -0
- package/dist/actions/frontend_rpc_client.d.ts.map +1 -0
- package/dist/actions/frontend_rpc_client.js +61 -0
- package/dist/actions/rpc_client.d.ts +64 -0
- package/dist/actions/rpc_client.d.ts.map +1 -1
- package/dist/actions/rpc_client.js +77 -0
- package/dist/auth/CLAUDE.md +32 -21
- package/dist/auth/account_action_specs.d.ts +8 -8
- package/dist/auth/account_action_specs.js +4 -4
- package/dist/auth/admin_action_specs.d.ts +8 -8
- package/dist/auth/admin_action_specs.js +4 -4
- package/dist/auth/self_service_role_action_specs.d.ts +20 -48
- package/dist/auth/self_service_role_action_specs.d.ts.map +1 -1
- package/dist/auth/self_service_role_action_specs.js +22 -44
- package/dist/auth/self_service_role_actions.d.ts +9 -9
- package/dist/auth/self_service_role_actions.d.ts.map +1 -1
- package/dist/auth/self_service_role_actions.js +48 -53
- package/dist/auth/standard_action_specs.d.ts +31 -0
- package/dist/auth/standard_action_specs.d.ts.map +1 -0
- package/dist/auth/standard_action_specs.js +36 -0
- package/dist/http/schema_helpers.d.ts +9 -0
- package/dist/http/schema_helpers.d.ts.map +1 -1
- package/dist/http/schema_helpers.js +9 -0
- package/dist/testing/admin_integration.js +9 -9
- package/dist/testing/audit_completeness.js +3 -3
- package/dist/testing/integration.js +36 -36
- package/dist/testing/rpc_helpers.d.ts +14 -6
- package/dist/testing/rpc_helpers.d.ts.map +1 -1
- package/dist/testing/rpc_helpers.js +8 -5
- package/dist/ui/admin_rpc_adapters.js +4 -4
- package/package.json +1 -1
|
@@ -13,9 +13,9 @@ import { AuthSessionJson, ClientApiTokenJson, SessionAccountJson } from './accou
|
|
|
13
13
|
import { ApiTokenId } from './api_token.js';
|
|
14
14
|
// -- Input/output schemas ---------------------------------------------------
|
|
15
15
|
/** Input for `account_verify`. No parameters — the caller is the subject. */
|
|
16
|
-
export const VerifyInput = z.
|
|
16
|
+
export const VerifyInput = z.void();
|
|
17
17
|
/** Input for `account_session_list`. No parameters. */
|
|
18
|
-
export const SessionListInput = z.
|
|
18
|
+
export const SessionListInput = z.void();
|
|
19
19
|
/** Output for `account_session_list`. */
|
|
20
20
|
export const SessionListOutput = z.strictObject({
|
|
21
21
|
sessions: z.array(AuthSessionJson),
|
|
@@ -30,7 +30,7 @@ export const SessionRevokeOutput = z.strictObject({
|
|
|
30
30
|
revoked: z.boolean(),
|
|
31
31
|
});
|
|
32
32
|
/** Input for `account_session_revoke_all`. No parameters. */
|
|
33
|
-
export const SessionRevokeAllInput = z.
|
|
33
|
+
export const SessionRevokeAllInput = z.void();
|
|
34
34
|
/** Output for `account_session_revoke_all`. */
|
|
35
35
|
export const SessionRevokeAllOutput = z.strictObject({
|
|
36
36
|
ok: z.literal(true),
|
|
@@ -51,7 +51,7 @@ export const TokenCreateOutput = z.strictObject({
|
|
|
51
51
|
name: z.string(),
|
|
52
52
|
});
|
|
53
53
|
/** Input for `account_token_list`. No parameters. */
|
|
54
|
-
export const TokenListInput = z.
|
|
54
|
+
export const TokenListInput = z.void();
|
|
55
55
|
/** Output for `account_token_list`. Hashes are excluded. */
|
|
56
56
|
export const TokenListOutput = z.strictObject({
|
|
57
57
|
tokens: z.array(ClientApiTokenJson),
|
|
@@ -20,7 +20,7 @@ import type { RequestResponseActionSpec } from '../actions/action_spec.js';
|
|
|
20
20
|
/** Max audit-log page size. Mirrors the former REST route's clamp. */
|
|
21
21
|
export declare const AUDIT_LOG_LIST_LIMIT_MAX = 200;
|
|
22
22
|
/** Input for `admin_account_list`. No parameters — the caller is the subject. */
|
|
23
|
-
export declare const AdminAccountListInput: z.
|
|
23
|
+
export declare const AdminAccountListInput: z.ZodVoid;
|
|
24
24
|
export type AdminAccountListInput = z.infer<typeof AdminAccountListInput>;
|
|
25
25
|
/** Output for `admin_account_list`. */
|
|
26
26
|
export declare const AdminAccountListOutput: z.ZodObject<{
|
|
@@ -60,7 +60,7 @@ export declare const AdminAccountListOutput: z.ZodObject<{
|
|
|
60
60
|
}, z.core.$strict>;
|
|
61
61
|
export type AdminAccountListOutput = z.infer<typeof AdminAccountListOutput>;
|
|
62
62
|
/** Input for `admin_session_list`. No parameters — reads every active session. */
|
|
63
|
-
export declare const AdminSessionListInput: z.
|
|
63
|
+
export declare const AdminSessionListInput: z.ZodVoid;
|
|
64
64
|
export type AdminSessionListInput = z.infer<typeof AdminSessionListInput>;
|
|
65
65
|
/** Output for `admin_session_list`. Cross-account listing; fan-out already scoped by role auth. */
|
|
66
66
|
export declare const AdminSessionListOutput: z.ZodObject<{
|
|
@@ -183,7 +183,7 @@ export declare const InviteCreateOutput: z.ZodObject<{
|
|
|
183
183
|
}, z.core.$strict>;
|
|
184
184
|
export type InviteCreateOutput = z.infer<typeof InviteCreateOutput>;
|
|
185
185
|
/** Input for `invite_list`. */
|
|
186
|
-
export declare const InviteListInput: z.
|
|
186
|
+
export declare const InviteListInput: z.ZodVoid;
|
|
187
187
|
export type InviteListInput = z.infer<typeof InviteListInput>;
|
|
188
188
|
/** Output for `invite_list`. Uses the enriched row including creator/claimer usernames. */
|
|
189
189
|
export declare const InviteListOutput: z.ZodObject<{
|
|
@@ -211,7 +211,7 @@ export declare const InviteDeleteOutput: z.ZodObject<{
|
|
|
211
211
|
}, z.core.$strict>;
|
|
212
212
|
export type InviteDeleteOutput = z.infer<typeof InviteDeleteOutput>;
|
|
213
213
|
/** Input for `app_settings_get`. No parameters. */
|
|
214
|
-
export declare const AppSettingsGetInput: z.
|
|
214
|
+
export declare const AppSettingsGetInput: z.ZodVoid;
|
|
215
215
|
export type AppSettingsGetInput = z.infer<typeof AppSettingsGetInput>;
|
|
216
216
|
/** Output for `app_settings_get`. */
|
|
217
217
|
export declare const AppSettingsGetOutput: z.ZodObject<{
|
|
@@ -247,7 +247,7 @@ export declare const admin_account_list_action_spec: {
|
|
|
247
247
|
role: string;
|
|
248
248
|
};
|
|
249
249
|
side_effects: false;
|
|
250
|
-
input: z.
|
|
250
|
+
input: z.ZodVoid;
|
|
251
251
|
output: z.ZodObject<{
|
|
252
252
|
accounts: z.ZodArray<z.ZodObject<{
|
|
253
253
|
account: z.ZodObject<{
|
|
@@ -294,7 +294,7 @@ export declare const admin_session_list_action_spec: {
|
|
|
294
294
|
role: string;
|
|
295
295
|
};
|
|
296
296
|
side_effects: false;
|
|
297
|
-
input: z.
|
|
297
|
+
input: z.ZodVoid;
|
|
298
298
|
output: z.ZodObject<{
|
|
299
299
|
sessions: z.ZodArray<z.ZodObject<{
|
|
300
300
|
id: z.ZodString;
|
|
@@ -454,7 +454,7 @@ export declare const invite_list_action_spec: {
|
|
|
454
454
|
role: string;
|
|
455
455
|
};
|
|
456
456
|
side_effects: false;
|
|
457
|
-
input: z.
|
|
457
|
+
input: z.ZodVoid;
|
|
458
458
|
output: z.ZodObject<{
|
|
459
459
|
invites: z.ZodArray<z.ZodObject<{
|
|
460
460
|
id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
|
|
@@ -496,7 +496,7 @@ export declare const app_settings_get_action_spec: {
|
|
|
496
496
|
role: string;
|
|
497
497
|
};
|
|
498
498
|
side_effects: false;
|
|
499
|
-
input: z.
|
|
499
|
+
input: z.ZodVoid;
|
|
500
500
|
output: z.ZodObject<{
|
|
501
501
|
settings: z.ZodObject<{
|
|
502
502
|
open_signup: z.ZodBoolean;
|
|
@@ -26,14 +26,14 @@ import { AppSettingsWithUsernameJson } from './app_settings_schema.js';
|
|
|
26
26
|
export const AUDIT_LOG_LIST_LIMIT_MAX = 200;
|
|
27
27
|
// -- Input/output schemas ---------------------------------------------------
|
|
28
28
|
/** Input for `admin_account_list`. No parameters — the caller is the subject. */
|
|
29
|
-
export const AdminAccountListInput = z.
|
|
29
|
+
export const AdminAccountListInput = z.void();
|
|
30
30
|
/** Output for `admin_account_list`. */
|
|
31
31
|
export const AdminAccountListOutput = z.strictObject({
|
|
32
32
|
accounts: z.array(AdminAccountEntryJson),
|
|
33
33
|
grantable_roles: z.array(RoleName),
|
|
34
34
|
});
|
|
35
35
|
/** Input for `admin_session_list`. No parameters — reads every active session. */
|
|
36
|
-
export const AdminSessionListInput = z.
|
|
36
|
+
export const AdminSessionListInput = z.void();
|
|
37
37
|
/** Output for `admin_session_list`. Cross-account listing; fan-out already scoped by role auth. */
|
|
38
38
|
export const AdminSessionListOutput = z.strictObject({
|
|
39
39
|
sessions: z.array(AdminSessionJson),
|
|
@@ -116,7 +116,7 @@ export const InviteCreateOutput = z.strictObject({
|
|
|
116
116
|
invite: InviteJson,
|
|
117
117
|
});
|
|
118
118
|
/** Input for `invite_list`. */
|
|
119
|
-
export const InviteListInput = z.
|
|
119
|
+
export const InviteListInput = z.void();
|
|
120
120
|
/** Output for `invite_list`. Uses the enriched row including creator/claimer usernames. */
|
|
121
121
|
export const InviteListOutput = z.strictObject({
|
|
122
122
|
invites: z.array(InviteWithUsernamesJson),
|
|
@@ -130,7 +130,7 @@ export const InviteDeleteOutput = z.strictObject({
|
|
|
130
130
|
ok: z.literal(true),
|
|
131
131
|
});
|
|
132
132
|
/** Input for `app_settings_get`. No parameters. */
|
|
133
|
-
export const AppSettingsGetInput = z.
|
|
133
|
+
export const AppSettingsGetInput = z.void();
|
|
134
134
|
/** Output for `app_settings_get`. */
|
|
135
135
|
export const AppSettingsGetOutput = z.strictObject({
|
|
136
136
|
settings: AppSettingsWithUsernameJson,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Unified self-service role toggle action spec — schemas, error reasons,
|
|
3
3
|
* and the codegen-ready registry.
|
|
4
4
|
*
|
|
5
5
|
* Client-safe: no query-layer or audit-write imports. Handler factory
|
|
@@ -11,54 +11,24 @@ import { z } from 'zod';
|
|
|
11
11
|
import type { RequestResponseActionSpec } from '../actions/action_spec.js';
|
|
12
12
|
/** Error reason — caller asked to self-toggle a role outside the configured allowlist. */
|
|
13
13
|
export declare const ERROR_ROLE_NOT_SELF_SERVICE_ELIGIBLE: "role_not_self_service_eligible";
|
|
14
|
-
/** Input for `
|
|
15
|
-
export declare const
|
|
14
|
+
/** Input for `self_service_role_set`. */
|
|
15
|
+
export declare const SelfServiceRoleSetInput: z.ZodObject<{
|
|
16
16
|
role: z.ZodString;
|
|
17
|
+
enabled: z.ZodBoolean;
|
|
17
18
|
}, z.core.$strict>;
|
|
18
|
-
export type
|
|
19
|
+
export type SelfServiceRoleSetInput = z.infer<typeof SelfServiceRoleSetInput>;
|
|
19
20
|
/**
|
|
20
|
-
* Output for `
|
|
21
|
-
*
|
|
22
|
-
*
|
|
21
|
+
* Output for `self_service_role_set`. `enabled` echoes the post-call state
|
|
22
|
+
* (always equals the input `enabled` on success). `changed` is `true` only
|
|
23
|
+
* when the call mutated — re-grants / re-revokes return `false`.
|
|
23
24
|
*/
|
|
24
|
-
export declare const
|
|
25
|
+
export declare const SelfServiceRoleSetOutput: z.ZodObject<{
|
|
25
26
|
ok: z.ZodLiteral<true>;
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
enabled: z.ZodBoolean;
|
|
28
|
+
changed: z.ZodBoolean;
|
|
28
29
|
}, z.core.$strict>;
|
|
29
|
-
export type
|
|
30
|
-
|
|
31
|
-
export declare const SelfServiceRoleRevokeInput: z.ZodObject<{
|
|
32
|
-
role: z.ZodString;
|
|
33
|
-
}, z.core.$strict>;
|
|
34
|
-
export type SelfServiceRoleRevokeInput = z.infer<typeof SelfServiceRoleRevokeInput>;
|
|
35
|
-
/**
|
|
36
|
-
* Output for `self_service_role_revoke`. `revoked` is `false` when the
|
|
37
|
-
* caller held no active global permit for the role (idempotent).
|
|
38
|
-
*/
|
|
39
|
-
export declare const SelfServiceRoleRevokeOutput: z.ZodObject<{
|
|
40
|
-
ok: z.ZodLiteral<true>;
|
|
41
|
-
revoked: z.ZodBoolean;
|
|
42
|
-
}, z.core.$strict>;
|
|
43
|
-
export type SelfServiceRoleRevokeOutput = z.infer<typeof SelfServiceRoleRevokeOutput>;
|
|
44
|
-
export declare const self_service_role_grant_action_spec: {
|
|
45
|
-
method: string;
|
|
46
|
-
kind: "request_response";
|
|
47
|
-
initiator: "frontend";
|
|
48
|
-
auth: "authenticated";
|
|
49
|
-
side_effects: true;
|
|
50
|
-
input: z.ZodObject<{
|
|
51
|
-
role: z.ZodString;
|
|
52
|
-
}, z.core.$strict>;
|
|
53
|
-
output: z.ZodObject<{
|
|
54
|
-
ok: z.ZodLiteral<true>;
|
|
55
|
-
granted: z.ZodBoolean;
|
|
56
|
-
permit_id: z.ZodOptional<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
|
|
57
|
-
}, z.core.$strict>;
|
|
58
|
-
async: true;
|
|
59
|
-
description: string;
|
|
60
|
-
};
|
|
61
|
-
export declare const self_service_role_revoke_action_spec: {
|
|
30
|
+
export type SelfServiceRoleSetOutput = z.infer<typeof SelfServiceRoleSetOutput>;
|
|
31
|
+
export declare const self_service_role_set_action_spec: {
|
|
62
32
|
method: string;
|
|
63
33
|
kind: "request_response";
|
|
64
34
|
initiator: "frontend";
|
|
@@ -66,18 +36,20 @@ export declare const self_service_role_revoke_action_spec: {
|
|
|
66
36
|
side_effects: true;
|
|
67
37
|
input: z.ZodObject<{
|
|
68
38
|
role: z.ZodString;
|
|
39
|
+
enabled: z.ZodBoolean;
|
|
69
40
|
}, z.core.$strict>;
|
|
70
41
|
output: z.ZodObject<{
|
|
71
42
|
ok: z.ZodLiteral<true>;
|
|
72
|
-
|
|
43
|
+
enabled: z.ZodBoolean;
|
|
44
|
+
changed: z.ZodBoolean;
|
|
73
45
|
}, z.core.$strict>;
|
|
74
46
|
async: true;
|
|
75
47
|
description: string;
|
|
76
48
|
};
|
|
77
49
|
/**
|
|
78
|
-
* All self-service role action specs — a codegen-ready registry.
|
|
79
|
-
*
|
|
80
|
-
*
|
|
50
|
+
* All self-service role action specs — a codegen-ready registry. Single-element
|
|
51
|
+
* post-unification, kept for symmetry with the other `all_*_action_specs`
|
|
52
|
+
* exports so codegen and frontend bundles import the same shape.
|
|
81
53
|
*/
|
|
82
|
-
export declare const all_self_service_role_action_specs:
|
|
54
|
+
export declare const all_self_service_role_action_specs: ReadonlyArray<RequestResponseActionSpec>;
|
|
83
55
|
//# sourceMappingURL=self_service_role_action_specs.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"self_service_role_action_specs.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/self_service_role_action_specs.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"self_service_role_action_specs.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/self_service_role_action_specs.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,2BAA2B,CAAC;AAGzE,0FAA0F;AAC1F,eAAO,MAAM,oCAAoC,EAAG,gCAAyC,CAAC;AAE9F,yCAAyC;AACzC,eAAO,MAAM,uBAAuB;;;kBAMlC,CAAC;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAE9E;;;;GAIG;AACH,eAAO,MAAM,wBAAwB;;;;kBAInC,CAAC;AACH,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAEhF,eAAO,MAAM,iCAAiC;;;;;;;;;;;;;;;;;CAWT,CAAC;AAEtC;;;;GAIG;AACH,eAAO,MAAM,kCAAkC,EAAE,aAAa,CAAC,yBAAyB,CAEvF,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Unified self-service role toggle action spec — schemas, error reasons,
|
|
3
3
|
* and the codegen-ready registry.
|
|
4
4
|
*
|
|
5
5
|
* Client-safe: no query-layer or audit-write imports. Handler factory
|
|
@@ -8,64 +8,42 @@
|
|
|
8
8
|
* @module
|
|
9
9
|
*/
|
|
10
10
|
import { z } from 'zod';
|
|
11
|
-
import { Uuid } from '@fuzdev/fuz_util/id.js';
|
|
12
11
|
import { RoleName } from './role_schema.js';
|
|
13
12
|
/** Error reason — caller asked to self-toggle a role outside the configured allowlist. */
|
|
14
13
|
export const ERROR_ROLE_NOT_SELF_SERVICE_ELIGIBLE = 'role_not_self_service_eligible';
|
|
15
|
-
/** Input for `
|
|
16
|
-
export const
|
|
17
|
-
role: RoleName.meta({ description: 'Role to
|
|
14
|
+
/** Input for `self_service_role_set`. */
|
|
15
|
+
export const SelfServiceRoleSetInput = z.strictObject({
|
|
16
|
+
role: RoleName.meta({ description: 'Role to toggle. Must be in the configured allowlist.' }),
|
|
17
|
+
enabled: z.boolean().meta({
|
|
18
|
+
description: 'Desired post-call state. `true` grants if not held; `false` revokes if held. Idempotent in both directions.',
|
|
19
|
+
}),
|
|
18
20
|
});
|
|
19
21
|
/**
|
|
20
|
-
* Output for `
|
|
21
|
-
*
|
|
22
|
-
*
|
|
22
|
+
* Output for `self_service_role_set`. `enabled` echoes the post-call state
|
|
23
|
+
* (always equals the input `enabled` on success). `changed` is `true` only
|
|
24
|
+
* when the call mutated — re-grants / re-revokes return `false`.
|
|
23
25
|
*/
|
|
24
|
-
export const
|
|
26
|
+
export const SelfServiceRoleSetOutput = z.strictObject({
|
|
25
27
|
ok: z.literal(true),
|
|
26
|
-
|
|
27
|
-
|
|
28
|
+
enabled: z.boolean(),
|
|
29
|
+
changed: z.boolean(),
|
|
28
30
|
});
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
role: RoleName.meta({ description: 'Role to self-revoke. Must be in the configured allowlist.' }),
|
|
32
|
-
});
|
|
33
|
-
/**
|
|
34
|
-
* Output for `self_service_role_revoke`. `revoked` is `false` when the
|
|
35
|
-
* caller held no active global permit for the role (idempotent).
|
|
36
|
-
*/
|
|
37
|
-
export const SelfServiceRoleRevokeOutput = z.strictObject({
|
|
38
|
-
ok: z.literal(true),
|
|
39
|
-
revoked: z.boolean(),
|
|
40
|
-
});
|
|
41
|
-
export const self_service_role_grant_action_spec = {
|
|
42
|
-
method: 'self_service_role_grant',
|
|
43
|
-
kind: 'request_response',
|
|
44
|
-
initiator: 'frontend',
|
|
45
|
-
auth: 'authenticated',
|
|
46
|
-
side_effects: true,
|
|
47
|
-
input: SelfServiceRoleGrantInput,
|
|
48
|
-
output: SelfServiceRoleGrantOutput,
|
|
49
|
-
async: true,
|
|
50
|
-
description: 'Self-grant an active permit for an allowlisted role. Idempotent — already-granted callers receive `granted: false`.',
|
|
51
|
-
};
|
|
52
|
-
export const self_service_role_revoke_action_spec = {
|
|
53
|
-
method: 'self_service_role_revoke',
|
|
31
|
+
export const self_service_role_set_action_spec = {
|
|
32
|
+
method: 'self_service_role_set',
|
|
54
33
|
kind: 'request_response',
|
|
55
34
|
initiator: 'frontend',
|
|
56
35
|
auth: 'authenticated',
|
|
57
36
|
side_effects: true,
|
|
58
|
-
input:
|
|
59
|
-
output:
|
|
37
|
+
input: SelfServiceRoleSetInput,
|
|
38
|
+
output: SelfServiceRoleSetOutput,
|
|
60
39
|
async: true,
|
|
61
|
-
description: '
|
|
40
|
+
description: 'Toggle a self-service role. Idempotent in both directions — `changed: false` when post-call state already matched the request.',
|
|
62
41
|
};
|
|
63
42
|
/**
|
|
64
|
-
* All self-service role action specs — a codegen-ready registry.
|
|
65
|
-
*
|
|
66
|
-
*
|
|
43
|
+
* All self-service role action specs — a codegen-ready registry. Single-element
|
|
44
|
+
* post-unification, kept for symmetry with the other `all_*_action_specs`
|
|
45
|
+
* exports so codegen and frontend bundles import the same shape.
|
|
67
46
|
*/
|
|
68
47
|
export const all_self_service_role_action_specs = [
|
|
69
|
-
|
|
70
|
-
self_service_role_revoke_action_spec,
|
|
48
|
+
self_service_role_set_action_spec,
|
|
71
49
|
];
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Unified self-service role toggle RPC action.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* One static `request_response` action — `self_service_role_set` — that
|
|
5
|
+
* takes `{role, enabled}` and toggles a global permit on the caller for an
|
|
6
|
+
* allowlisted role. Idempotent in both directions: re-enabling an
|
|
7
|
+
* already-held role returns `changed: false`; disabling a role the caller
|
|
8
|
+
* doesn't hold returns `changed: false`.
|
|
9
9
|
*
|
|
10
10
|
* The factory takes an `eligible_roles` allowlist (validated against the
|
|
11
11
|
* supplied `roles.role_options` at factory time so typos surface at startup
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
* part of the documented schema surface and is round-trip-validated by
|
|
20
20
|
* `query_audit_log`.
|
|
21
21
|
*
|
|
22
|
-
* Static method
|
|
23
|
-
* so
|
|
22
|
+
* Static method name — `role` lives in the input, not the method name —
|
|
23
|
+
* so the spec is codegen-compatible (`satisfies RequestResponseActionSpec`)
|
|
24
24
|
* and the surface stays constant as consumers add eligible roles. Mirrors
|
|
25
25
|
* the existing `permit_offer_create({role})` precedent rather than
|
|
26
26
|
* generating per-role methods.
|
|
@@ -57,7 +57,7 @@ export interface SelfServiceRoleActionsOptions {
|
|
|
57
57
|
*/
|
|
58
58
|
export type SelfServiceRoleActionDeps = Pick<RouteFactoryDeps, 'log' | 'on_audit_event' | 'audit_log_config'>;
|
|
59
59
|
/**
|
|
60
|
-
* Build the self-service role
|
|
60
|
+
* Build the unified self-service role toggle RPC action.
|
|
61
61
|
*
|
|
62
62
|
* @param deps - `SelfServiceRoleActionDeps` slice of `AppDeps` (`log`, `on_audit_event`, optional `audit_log_config`)
|
|
63
63
|
* @param options - eligible-role allowlist plus optional role schema for typo-checking
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"self_service_role_actions.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/self_service_role_actions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,EAAiC,KAAK,SAAS,EAAC,MAAM,0BAA0B,CAAC;AAExF,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AACvD,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"self_service_role_actions.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/self_service_role_actions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,EAAiC,KAAK,SAAS,EAAC,MAAM,0BAA0B,CAAC;AAExF,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AACvD,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,WAAW,CAAC;AAgBhD,sDAAsD;AACtD,MAAM,WAAW,6BAA6B;IAC7C;;;;OAIG;IACH,cAAc,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACtC;;;;OAIG;IACH,KAAK,CAAC,EAAE,gBAAgB,CAAC;CACzB;AAED;;;;;GAKG;AACH,MAAM,MAAM,yBAAyB,GAAG,IAAI,CAC3C,gBAAgB,EAChB,KAAK,GAAG,gBAAgB,GAAG,kBAAkB,CAC7C,CAAC;AAOF;;;;;;GAMG;AACH,eAAO,MAAM,gCAAgC,GAC5C,MAAM,yBAAyB,EAC/B,SAAS,6BAA6B,KACpC,KAAK,CAAC,SAAS,CA4GjB,CAAC"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Unified self-service role toggle RPC action.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* One static `request_response` action — `self_service_role_set` — that
|
|
5
|
+
* takes `{role, enabled}` and toggles a global permit on the caller for an
|
|
6
|
+
* allowlisted role. Idempotent in both directions: re-enabling an
|
|
7
|
+
* already-held role returns `changed: false`; disabling a role the caller
|
|
8
|
+
* doesn't hold returns `changed: false`.
|
|
9
9
|
*
|
|
10
10
|
* The factory takes an `eligible_roles` allowlist (validated against the
|
|
11
11
|
* supplied `roles.role_options` at factory time so typos surface at startup
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
* part of the documented schema surface and is round-trip-validated by
|
|
20
20
|
* `query_audit_log`.
|
|
21
21
|
*
|
|
22
|
-
* Static method
|
|
23
|
-
* so
|
|
22
|
+
* Static method name — `role` lives in the input, not the method name —
|
|
23
|
+
* so the spec is codegen-compatible (`satisfies RequestResponseActionSpec`)
|
|
24
24
|
* and the surface stays constant as consumers add eligible roles. Mirrors
|
|
25
25
|
* the existing `permit_offer_create({role})` precedent rather than
|
|
26
26
|
* generating per-role methods.
|
|
@@ -35,14 +35,14 @@ import { rpc_action } from '../actions/action_rpc.js';
|
|
|
35
35
|
import { jsonrpc_errors } from '../http/jsonrpc_errors.js';
|
|
36
36
|
import { query_grant_permit, query_permit_find_active_for_actor, query_permit_has_role, query_revoke_permit, } from './permit_queries.js';
|
|
37
37
|
import { audit_log_fire_and_forget } from './audit_log_queries.js';
|
|
38
|
-
import { ERROR_ROLE_NOT_SELF_SERVICE_ELIGIBLE,
|
|
38
|
+
import { ERROR_ROLE_NOT_SELF_SERVICE_ELIGIBLE, self_service_role_set_action_spec, } from './self_service_role_action_specs.js';
|
|
39
39
|
const require_request_auth = (auth) => {
|
|
40
40
|
if (!auth)
|
|
41
41
|
throw new Error('unreachable: action auth guard did not enforce authentication');
|
|
42
42
|
return auth;
|
|
43
43
|
};
|
|
44
44
|
/**
|
|
45
|
-
* Build the self-service role
|
|
45
|
+
* Build the unified self-service role toggle RPC action.
|
|
46
46
|
*
|
|
47
47
|
* @param deps - `SelfServiceRoleActionDeps` slice of `AppDeps` (`log`, `on_audit_event`, optional `audit_log_config`)
|
|
48
48
|
* @param options - eligible-role allowlist plus optional role schema for typo-checking
|
|
@@ -65,45 +65,43 @@ export const create_self_service_role_actions = (deps, options) => {
|
|
|
65
65
|
});
|
|
66
66
|
}
|
|
67
67
|
};
|
|
68
|
-
const
|
|
68
|
+
const handler = async (input, ctx) => {
|
|
69
69
|
const auth = require_request_auth(ctx.auth);
|
|
70
70
|
reject_if_ineligible(input.role);
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
71
|
+
if (input.enabled) {
|
|
72
|
+
// Pre-check for idempotent re-grant. `query_grant_permit` is itself
|
|
73
|
+
// idempotent (returns the existing permit instead of inserting), but
|
|
74
|
+
// it doesn't signal "already existed" vs "newly inserted" — so we
|
|
75
|
+
// peek first. The TOCTOU window is benign for self-service: two
|
|
76
|
+
// concurrent grants both observe "no permit", both call
|
|
77
|
+
// `query_grant_permit`, and one collapses onto the other inside the
|
|
78
|
+
// query's `ON CONFLICT DO NOTHING`. Worst case both responses report
|
|
79
|
+
// `changed: true`; the DB still ends up with exactly one permit.
|
|
80
|
+
const already = await query_permit_has_role(ctx, auth.actor.id, input.role);
|
|
81
|
+
if (already) {
|
|
82
|
+
return { ok: true, enabled: true, changed: false };
|
|
83
|
+
}
|
|
84
|
+
const permit = await query_grant_permit(ctx, {
|
|
85
|
+
actor_id: auth.actor.id,
|
|
86
|
+
role: input.role,
|
|
87
|
+
scope_id: null,
|
|
88
|
+
expires_at: null,
|
|
89
|
+
granted_by: auth.actor.id,
|
|
90
|
+
});
|
|
91
|
+
void audit_log_fire_and_forget(ctx, {
|
|
92
|
+
event_type: 'permit_grant',
|
|
93
|
+
actor_id: auth.actor.id,
|
|
94
|
+
account_id: auth.account.id,
|
|
95
|
+
ip: ctx.client_ip,
|
|
96
|
+
metadata: {
|
|
97
|
+
role: permit.role,
|
|
98
|
+
permit_id: permit.id,
|
|
99
|
+
scope_id: permit.scope_id,
|
|
100
|
+
self_service: true,
|
|
101
|
+
},
|
|
102
|
+
}, deps);
|
|
103
|
+
return { ok: true, enabled: true, changed: true };
|
|
82
104
|
}
|
|
83
|
-
const permit = await query_grant_permit(ctx, {
|
|
84
|
-
actor_id: auth.actor.id,
|
|
85
|
-
role: input.role,
|
|
86
|
-
scope_id: null,
|
|
87
|
-
expires_at: null,
|
|
88
|
-
granted_by: auth.actor.id,
|
|
89
|
-
});
|
|
90
|
-
void audit_log_fire_and_forget(ctx, {
|
|
91
|
-
event_type: 'permit_grant',
|
|
92
|
-
actor_id: auth.actor.id,
|
|
93
|
-
account_id: auth.account.id,
|
|
94
|
-
ip: ctx.client_ip,
|
|
95
|
-
metadata: {
|
|
96
|
-
role: permit.role,
|
|
97
|
-
permit_id: permit.id,
|
|
98
|
-
scope_id: permit.scope_id,
|
|
99
|
-
self_service: true,
|
|
100
|
-
},
|
|
101
|
-
}, deps);
|
|
102
|
-
return { ok: true, granted: true, permit_id: permit.id };
|
|
103
|
-
};
|
|
104
|
-
const revoke_handler = async (input, ctx) => {
|
|
105
|
-
const auth = require_request_auth(ctx.auth);
|
|
106
|
-
reject_if_ineligible(input.role);
|
|
107
105
|
// Find an active global permit for this (actor, role). No dedicated
|
|
108
106
|
// query exists, but `query_permit_find_active_for_actor` returns the
|
|
109
107
|
// short list of every active permit and we filter in JS — fewer
|
|
@@ -111,12 +109,12 @@ export const create_self_service_role_actions = (deps, options) => {
|
|
|
111
109
|
const active = await query_permit_find_active_for_actor(ctx, auth.actor.id);
|
|
112
110
|
const target = active.find((p) => p.role === input.role && p.scope_id === null);
|
|
113
111
|
if (!target) {
|
|
114
|
-
return { ok: true,
|
|
112
|
+
return { ok: true, enabled: false, changed: false };
|
|
115
113
|
}
|
|
116
114
|
const result = await query_revoke_permit(ctx, target.id, auth.actor.id, auth.actor.id);
|
|
117
115
|
if (!result) {
|
|
118
116
|
// Raced with another revoker — treat as already revoked.
|
|
119
|
-
return { ok: true,
|
|
117
|
+
return { ok: true, enabled: false, changed: false };
|
|
120
118
|
}
|
|
121
119
|
void audit_log_fire_and_forget(ctx, {
|
|
122
120
|
event_type: 'permit_revoke',
|
|
@@ -130,10 +128,7 @@ export const create_self_service_role_actions = (deps, options) => {
|
|
|
130
128
|
self_service: true,
|
|
131
129
|
},
|
|
132
130
|
}, deps);
|
|
133
|
-
return { ok: true,
|
|
131
|
+
return { ok: true, enabled: false, changed: true };
|
|
134
132
|
};
|
|
135
|
-
return [
|
|
136
|
-
rpc_action(self_service_role_grant_action_spec, grant_handler),
|
|
137
|
-
rpc_action(self_service_role_revoke_action_spec, revoke_handler),
|
|
138
|
-
];
|
|
133
|
+
return [rpc_action(self_service_role_set_action_spec, handler)];
|
|
139
134
|
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aggregate spec list mirroring `create_standard_rpc_actions` on the backend.
|
|
3
|
+
*
|
|
4
|
+
* `create_standard_rpc_actions` (in `./standard_rpc_actions.js`) bundles three
|
|
5
|
+
* action registries into one mounted RPC surface: admin + permit_offer +
|
|
6
|
+
* account. Frontends mounting that surface need the matching spec list to
|
|
7
|
+
* feed `create_rpc_client` so the typed Proxy knows about every standard
|
|
8
|
+
* method.
|
|
9
|
+
*
|
|
10
|
+
* Without this aggregate, every consumer spreads three (or four with
|
|
11
|
+
* self-service roles) `all_*_action_specs` imports at the typed-client
|
|
12
|
+
* site, the codegen-sources table, and any other registry construction —
|
|
13
|
+
* a triplicate that drifts silently on either side.
|
|
14
|
+
*
|
|
15
|
+
* Self-service role specs are **not** included — they're opt-in (require
|
|
16
|
+
* `eligible_roles` configuration) and not bundled into
|
|
17
|
+
* `create_standard_rpc_actions`. Consumers that mount them spread
|
|
18
|
+
* `all_self_service_role_action_specs` separately.
|
|
19
|
+
*
|
|
20
|
+
* @module
|
|
21
|
+
*/
|
|
22
|
+
import type { RequestResponseActionSpec } from '../actions/action_spec.js';
|
|
23
|
+
/**
|
|
24
|
+
* Combined spec registry for the standard RPC surface (admin +
|
|
25
|
+
* permit_offer + account). Symmetric with `create_standard_rpc_actions`.
|
|
26
|
+
*
|
|
27
|
+
* Spec count is the sum of the three sub-registries. Adding a method to
|
|
28
|
+
* any sub-registry surfaces here automatically.
|
|
29
|
+
*/
|
|
30
|
+
export declare const all_standard_action_specs: ReadonlyArray<RequestResponseActionSpec>;
|
|
31
|
+
//# sourceMappingURL=standard_action_specs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"standard_action_specs.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/standard_action_specs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,2BAA2B,CAAC;AAKzE;;;;;;GAMG;AACH,eAAO,MAAM,yBAAyB,EAAE,aAAa,CAAC,yBAAyB,CAI9E,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aggregate spec list mirroring `create_standard_rpc_actions` on the backend.
|
|
3
|
+
*
|
|
4
|
+
* `create_standard_rpc_actions` (in `./standard_rpc_actions.js`) bundles three
|
|
5
|
+
* action registries into one mounted RPC surface: admin + permit_offer +
|
|
6
|
+
* account. Frontends mounting that surface need the matching spec list to
|
|
7
|
+
* feed `create_rpc_client` so the typed Proxy knows about every standard
|
|
8
|
+
* method.
|
|
9
|
+
*
|
|
10
|
+
* Without this aggregate, every consumer spreads three (or four with
|
|
11
|
+
* self-service roles) `all_*_action_specs` imports at the typed-client
|
|
12
|
+
* site, the codegen-sources table, and any other registry construction —
|
|
13
|
+
* a triplicate that drifts silently on either side.
|
|
14
|
+
*
|
|
15
|
+
* Self-service role specs are **not** included — they're opt-in (require
|
|
16
|
+
* `eligible_roles` configuration) and not bundled into
|
|
17
|
+
* `create_standard_rpc_actions`. Consumers that mount them spread
|
|
18
|
+
* `all_self_service_role_action_specs` separately.
|
|
19
|
+
*
|
|
20
|
+
* @module
|
|
21
|
+
*/
|
|
22
|
+
import { all_admin_action_specs } from './admin_action_specs.js';
|
|
23
|
+
import { all_permit_offer_action_specs } from './permit_offer_action_specs.js';
|
|
24
|
+
import { all_account_action_specs } from './account_action_specs.js';
|
|
25
|
+
/**
|
|
26
|
+
* Combined spec registry for the standard RPC surface (admin +
|
|
27
|
+
* permit_offer + account). Symmetric with `create_standard_rpc_actions`.
|
|
28
|
+
*
|
|
29
|
+
* Spec count is the sum of the three sub-registries. Adding a method to
|
|
30
|
+
* any sub-registry surfaces here automatically.
|
|
31
|
+
*/
|
|
32
|
+
export const all_standard_action_specs = [
|
|
33
|
+
...all_admin_action_specs,
|
|
34
|
+
...all_permit_offer_action_specs,
|
|
35
|
+
...all_account_action_specs,
|
|
36
|
+
];
|
|
@@ -18,6 +18,15 @@ import { type RateLimitKey, type RouteErrorSchemas } from './error_schemas.js';
|
|
|
18
18
|
* but also accept other values.
|
|
19
19
|
*/
|
|
20
20
|
export declare const is_null_schema: (schema: z.ZodType) => boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Check if a schema is exactly `z.void()`.
|
|
23
|
+
*
|
|
24
|
+
* RPC action specs use `z.void()` to declare a parameterless method —
|
|
25
|
+
* JSON-RPC 2.0 forbids `params: null` (params must be omitted or be a
|
|
26
|
+
* Structured value), so `z.void()` is the correct schema for "no params"
|
|
27
|
+
* and the dispatcher maps absent params to `undefined` for these specs.
|
|
28
|
+
*/
|
|
29
|
+
export declare const is_void_schema: (schema: z.ZodType) => boolean;
|
|
21
30
|
/**
|
|
22
31
|
* Check if a schema is a strict object (`z.strictObject()`).
|
|
23
32
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/schema_helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAuB,KAAK,YAAY,EAAE,KAAK,iBAAiB,EAAC,MAAM,oBAAoB,CAAC;AAEnG;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OAAsC,CAAC;AAE1F;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OACe,CAAC;AAE5E;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OAQrD,CAAC;AAoBF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,kBAAkB,GAAI,SAAS,MAAM,EAAE,YAAY,MAAM,KAAG,OAQxE,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,mBAAmB,GAC/B,MAAM;IACL,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;IACpB,UAAU,CAAC,EAAE,YAAY,CAAC;IAC1B,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC3B,EACD,oBAAoB,iBAAiB,GAAG,IAAI,KAC1C,iBAAiB,GAAG,IAUtB,CAAC"}
|
|
1
|
+
{"version":3,"file":"schema_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/schema_helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAuB,KAAK,YAAY,EAAE,KAAK,iBAAiB,EAAC,MAAM,oBAAoB,CAAC;AAEnG;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OAAsC,CAAC;AAE1F;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OAAsC,CAAC;AAE1F;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OACe,CAAC;AAE5E;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OAQrD,CAAC;AAoBF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,kBAAkB,GAAI,SAAS,MAAM,EAAE,YAAY,MAAM,KAAG,OAQxE,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,mBAAmB,GAC/B,MAAM;IACL,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;IACpB,UAAU,CAAC,EAAE,YAAY,CAAC;IAC1B,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC3B,EACD,oBAAoB,iBAAiB,GAAG,IAAI,KAC1C,iBAAiB,GAAG,IAUtB,CAAC"}
|