@byline/admin 1.9.0 → 1.10.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/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/lib/create-command.d.ts +77 -0
- package/dist/lib/create-command.js +25 -0
- package/dist/modules/admin-account/commands.d.ts +12 -14
- package/dist/modules/admin-account/commands.js +19 -22
- package/dist/modules/admin-permissions/commands.d.ts +11 -9
- package/dist/modules/admin-permissions/commands.js +28 -25
- package/dist/modules/admin-roles/commands.d.ts +13 -17
- package/dist/modules/admin-roles/commands.js +55 -49
- package/dist/modules/admin-users/commands.d.ts +15 -25
- package/dist/modules/admin-users/commands.js +58 -49
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
*/
|
|
23
23
|
export { registerAdminAbilities } from './abilities.js';
|
|
24
24
|
export { assertAdminActor, requireAdminActor } from './lib/assert-admin-actor.js';
|
|
25
|
+
export { type Command, type CreateCommandAuthSpec, type CreateCommandHandlerArgs, type CreateCommandSpec, createCommand, } from './lib/create-command.js';
|
|
25
26
|
export * from './modules/admin-account/index.js';
|
|
26
27
|
export * from './modules/admin-permissions/index.js';
|
|
27
28
|
export * from './modules/admin-roles/index.js';
|
package/dist/index.js
CHANGED
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
*/
|
|
23
23
|
export { registerAdminAbilities } from './abilities.js';
|
|
24
24
|
export { assertAdminActor, requireAdminActor } from './lib/assert-admin-actor.js';
|
|
25
|
+
export { createCommand, } from './lib/create-command.js';
|
|
25
26
|
export * from './modules/admin-account/index.js';
|
|
26
27
|
export * from './modules/admin-permissions/index.js';
|
|
27
28
|
export * from './modules/admin-roles/index.js';
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) Infonomic Company Limited
|
|
7
|
+
*/
|
|
8
|
+
import type { AdminAuth, RequestContext } from '@byline/auth';
|
|
9
|
+
import type { ZodType } from 'zod';
|
|
10
|
+
/**
|
|
11
|
+
* `createCommand` — the wrapper that folds the four-step admin command
|
|
12
|
+
* contract (validate → authorise → invoke → shape) into a single
|
|
13
|
+
* declaration.
|
|
14
|
+
*
|
|
15
|
+
* Implements Phase 1 of `docs/CORE-COMPOSITION.md`. Today's scope is
|
|
16
|
+
* `@byline/admin`-internal: it gates against admin actor identity using
|
|
17
|
+
* the existing `assertAdminActor` / `requireAdminActor` helpers, which
|
|
18
|
+
* inherit the super-admin bypass from `AdminAuth.assertAbility`.
|
|
19
|
+
*
|
|
20
|
+
* The `auth` slot is a discriminated union:
|
|
21
|
+
*
|
|
22
|
+
* - `{ ability }` — full admin gate. Requires an `AdminAuth`
|
|
23
|
+
* actor holding the named ability. Maps to
|
|
24
|
+
* `assertAdminActor`.
|
|
25
|
+
* - `{ authenticated }` — identity gate only. Requires an `AdminAuth`
|
|
26
|
+
* actor but does not assert any ability. Used
|
|
27
|
+
* by self-service commands in `admin-account`
|
|
28
|
+
* where the security property is "you may
|
|
29
|
+
* only mutate your own row" and the target
|
|
30
|
+
* id is sourced from `actor.id`.
|
|
31
|
+
*
|
|
32
|
+
* The handler receives an args object so it can cherry-pick what it
|
|
33
|
+
* needs without positional ordering — `context` for downstream calls
|
|
34
|
+
* that need the full request context, `input` (already Zod-parsed),
|
|
35
|
+
* `deps` (typed by the module), and `actor` (already narrowed to
|
|
36
|
+
* `AdminAuth` by the auth step).
|
|
37
|
+
*
|
|
38
|
+
* The returned command preserves today's `(context, input, deps) =>
|
|
39
|
+
* Promise<Output>` signature so existing server-fn call sites keep
|
|
40
|
+
* working without change.
|
|
41
|
+
*
|
|
42
|
+
* Collection-document operations (create / update / delete / status /
|
|
43
|
+
* upload) are gated through a separate helper, `assertActorCanPerform`,
|
|
44
|
+
* which fires inside the `document-lifecycle` service functions in
|
|
45
|
+
* `@byline/core`. They do not flow through this wrapper today; if the
|
|
46
|
+
* two enforcement paths ever converge, the `auth` discriminator can
|
|
47
|
+
* grow a `collection` variant without breaking existing call sites.
|
|
48
|
+
*/
|
|
49
|
+
export type CreateCommandAuthSpec = {
|
|
50
|
+
readonly ability: string;
|
|
51
|
+
readonly authenticated?: never;
|
|
52
|
+
} | {
|
|
53
|
+
readonly authenticated: true;
|
|
54
|
+
readonly ability?: never;
|
|
55
|
+
};
|
|
56
|
+
export interface CreateCommandHandlerArgs<TInput, TDeps> {
|
|
57
|
+
readonly context: RequestContext;
|
|
58
|
+
readonly input: TInput;
|
|
59
|
+
readonly deps: TDeps;
|
|
60
|
+
readonly actor: AdminAuth;
|
|
61
|
+
}
|
|
62
|
+
export interface CreateCommandSpec<TInput, TOutput, TDeps> {
|
|
63
|
+
/**
|
|
64
|
+
* Stable identifier for the command, used in error messages and
|
|
65
|
+
* future telemetry (Phase 1 of `CORE-COMPOSITION.md` calls out
|
|
66
|
+
* uniform logging as a downstream benefit of the wrapper).
|
|
67
|
+
*/
|
|
68
|
+
readonly method: string;
|
|
69
|
+
readonly auth: CreateCommandAuthSpec;
|
|
70
|
+
readonly schemas: {
|
|
71
|
+
readonly input: ZodType<TInput>;
|
|
72
|
+
readonly output: ZodType<TOutput>;
|
|
73
|
+
};
|
|
74
|
+
readonly handler: (args: CreateCommandHandlerArgs<TInput, TDeps>) => Promise<TOutput> | TOutput;
|
|
75
|
+
}
|
|
76
|
+
export type Command<_TInput, TOutput, TDeps> = (context: RequestContext | undefined, input: unknown, deps: TDeps) => Promise<TOutput>;
|
|
77
|
+
export declare function createCommand<TInput, TOutput, TDeps>(spec: CreateCommandSpec<TInput, TOutput, TDeps>): Command<TInput, TOutput, TDeps>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) Infonomic Company Limited
|
|
7
|
+
*/
|
|
8
|
+
import { assertAdminActor, requireAdminActor } from './assert-admin-actor.js';
|
|
9
|
+
export function createCommand(spec) {
|
|
10
|
+
return async function command(context, input, deps) {
|
|
11
|
+
const parsed = spec.schemas.input.parse(input ?? {});
|
|
12
|
+
const actor = spec.auth.ability !== undefined
|
|
13
|
+
? assertAdminActor(context, spec.auth.ability)
|
|
14
|
+
: requireAdminActor(context, spec.method);
|
|
15
|
+
// `context` is non-null after the auth step — both helpers throw
|
|
16
|
+
// `ERR_UNAUTHENTICATED` when the request context is missing.
|
|
17
|
+
const result = await spec.handler({
|
|
18
|
+
context: context,
|
|
19
|
+
input: parsed,
|
|
20
|
+
deps,
|
|
21
|
+
actor,
|
|
22
|
+
});
|
|
23
|
+
return spec.schemas.output.parse(result);
|
|
24
|
+
};
|
|
25
|
+
}
|
|
@@ -5,25 +5,23 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Copyright (c) Infonomic Company Limited
|
|
7
7
|
*/
|
|
8
|
-
import type
|
|
8
|
+
import { type Command } from '../../lib/create-command.js';
|
|
9
9
|
import type { AdminStore } from '../../store.js';
|
|
10
|
-
import type { AccountResponse } from './schemas.js';
|
|
10
|
+
import type { AccountResponse, ChangeAccountPasswordRequest, GetAccountRequest, UpdateAccountRequest } from './schemas.js';
|
|
11
11
|
/**
|
|
12
12
|
* Transport-agnostic commands for admin-account self-service.
|
|
13
13
|
*
|
|
14
|
-
* Same shape as the other admin
|
|
15
|
-
*
|
|
16
|
-
* `
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* no way to express "operate on someone else" because the schemas
|
|
22
|
-
* don't accept one.
|
|
14
|
+
* Same `createCommand` shape as the other admin modules, with one
|
|
15
|
+
* deliberate difference: `auth` is `{ authenticated: true }` rather than
|
|
16
|
+
* `{ ability }`. There is no ability key to gate against — the security
|
|
17
|
+
* property is "you may only mutate your own row," enforced structurally
|
|
18
|
+
* by sourcing the target id from `actor.id` rather than from the request
|
|
19
|
+
* payload. The request schemas do not accept an `id` field, so a caller
|
|
20
|
+
* has no way to express "operate on someone else."
|
|
23
21
|
*/
|
|
24
22
|
export interface AdminAccountCommandDeps {
|
|
25
23
|
store: AdminStore;
|
|
26
24
|
}
|
|
27
|
-
export declare
|
|
28
|
-
export declare
|
|
29
|
-
export declare
|
|
25
|
+
export declare const getAccountCommand: Command<GetAccountRequest, AccountResponse, AdminAccountCommandDeps>;
|
|
26
|
+
export declare const updateAccountCommand: Command<UpdateAccountRequest, AccountResponse, AdminAccountCommandDeps>;
|
|
27
|
+
export declare const changeAccountPasswordCommand: Command<ChangeAccountPasswordRequest, AccountResponse, AdminAccountCommandDeps>;
|
|
@@ -5,31 +5,28 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Copyright (c) Infonomic Company Limited
|
|
7
7
|
*/
|
|
8
|
-
import {
|
|
8
|
+
import { createCommand } from '../../lib/create-command.js';
|
|
9
9
|
import { adminUserResponseSchema } from '../admin-users/schemas.js';
|
|
10
10
|
import { changeAccountPasswordRequestSchema, getAccountRequestSchema, updateAccountRequestSchema, } from './schemas.js';
|
|
11
11
|
import { AdminAccountService } from './service.js';
|
|
12
12
|
function serviceOf(deps) {
|
|
13
13
|
return new AdminAccountService({ repo: deps.store.adminUsers });
|
|
14
14
|
}
|
|
15
|
-
export
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const result = await serviceOf(deps).changePassword(actor.id, parsed);
|
|
34
|
-
return adminUserResponseSchema.parse(result);
|
|
35
|
-
}
|
|
15
|
+
export const getAccountCommand = createCommand({
|
|
16
|
+
method: 'getAccount',
|
|
17
|
+
auth: { authenticated: true },
|
|
18
|
+
schemas: { input: getAccountRequestSchema, output: adminUserResponseSchema },
|
|
19
|
+
handler: ({ deps, actor }) => serviceOf(deps).getAccount(actor.id),
|
|
20
|
+
});
|
|
21
|
+
export const updateAccountCommand = createCommand({
|
|
22
|
+
method: 'updateAccount',
|
|
23
|
+
auth: { authenticated: true },
|
|
24
|
+
schemas: { input: updateAccountRequestSchema, output: adminUserResponseSchema },
|
|
25
|
+
handler: ({ input, deps, actor }) => serviceOf(deps).updateAccount(actor.id, input),
|
|
26
|
+
});
|
|
27
|
+
export const changeAccountPasswordCommand = createCommand({
|
|
28
|
+
method: 'changeAccountPassword',
|
|
29
|
+
auth: { authenticated: true },
|
|
30
|
+
schemas: { input: changeAccountPasswordRequestSchema, output: adminUserResponseSchema },
|
|
31
|
+
handler: ({ input, deps, actor }) => serviceOf(deps).changePassword(actor.id, input),
|
|
32
|
+
});
|
|
@@ -5,15 +5,17 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Copyright (c) Infonomic Company Limited
|
|
7
7
|
*/
|
|
8
|
-
import type { AbilityRegistry
|
|
8
|
+
import type { AbilityRegistry } from '@byline/auth';
|
|
9
|
+
import { type Command } from '../../lib/create-command.js';
|
|
9
10
|
import type { AdminStore } from '../../store.js';
|
|
10
|
-
import type { GetRoleAbilitiesResponse, ListRegisteredAbilitiesResponse, SetRoleAbilitiesResponse, WhoHasAbilityResponse } from './schemas.js';
|
|
11
|
+
import type { GetRoleAbilitiesRequest, GetRoleAbilitiesResponse, ListRegisteredAbilitiesRequest, ListRegisteredAbilitiesResponse, SetRoleAbilitiesRequest, SetRoleAbilitiesResponse, WhoHasAbilityRequest, WhoHasAbilityResponse } from './schemas.js';
|
|
11
12
|
/**
|
|
12
13
|
* Transport-agnostic commands for the admin-permissions inspector.
|
|
13
14
|
*
|
|
14
|
-
*
|
|
15
|
-
* admin actor + ability
|
|
16
|
-
* inspector
|
|
15
|
+
* Built through `createCommand`, which folds the four standard steps
|
|
16
|
+
* (validate → assert admin actor + ability → invoke service → validate
|
|
17
|
+
* output) into one declaration. All inspector reads gate on
|
|
18
|
+
* `admin.permissions.read`; the write gates on `admin.permissions.update`.
|
|
17
19
|
*
|
|
18
20
|
* Deps include the `AbilityRegistry` alongside the `AdminStore` because
|
|
19
21
|
* the inspector reads the registered abilities directly from the
|
|
@@ -23,7 +25,7 @@ export interface AdminPermissionsCommandDeps {
|
|
|
23
25
|
store: AdminStore;
|
|
24
26
|
abilities: AbilityRegistry;
|
|
25
27
|
}
|
|
26
|
-
export declare
|
|
27
|
-
export declare
|
|
28
|
-
export declare
|
|
29
|
-
export declare
|
|
28
|
+
export declare const listRegisteredAbilitiesCommand: Command<ListRegisteredAbilitiesRequest, ListRegisteredAbilitiesResponse, AdminPermissionsCommandDeps>;
|
|
29
|
+
export declare const whoHasAbilityCommand: Command<WhoHasAbilityRequest, WhoHasAbilityResponse, AdminPermissionsCommandDeps>;
|
|
30
|
+
export declare const getRoleAbilitiesCommand: Command<GetRoleAbilitiesRequest, GetRoleAbilitiesResponse, AdminPermissionsCommandDeps>;
|
|
31
|
+
export declare const setRoleAbilitiesCommand: Command<SetRoleAbilitiesRequest, SetRoleAbilitiesResponse, AdminPermissionsCommandDeps>;
|
|
@@ -5,34 +5,37 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Copyright (c) Infonomic Company Limited
|
|
7
7
|
*/
|
|
8
|
-
import {
|
|
8
|
+
import { createCommand } from '../../lib/create-command.js';
|
|
9
9
|
import { ADMIN_PERMISSIONS_ABILITIES } from './abilities.js';
|
|
10
10
|
import { getRoleAbilitiesRequestSchema, getRoleAbilitiesResponseSchema, listRegisteredAbilitiesRequestSchema, listRegisteredAbilitiesResponseSchema, setRoleAbilitiesRequestSchema, setRoleAbilitiesResponseSchema, whoHasAbilityRequestSchema, whoHasAbilityResponseSchema, } from './schemas.js';
|
|
11
11
|
import { AdminPermissionsService } from './service.js';
|
|
12
12
|
function serviceOf(deps) {
|
|
13
13
|
return new AdminPermissionsService({ store: deps.store, abilities: deps.abilities });
|
|
14
14
|
}
|
|
15
|
-
export
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
15
|
+
export const listRegisteredAbilitiesCommand = createCommand({
|
|
16
|
+
method: 'listRegisteredAbilities',
|
|
17
|
+
auth: { ability: ADMIN_PERMISSIONS_ABILITIES.read },
|
|
18
|
+
schemas: {
|
|
19
|
+
input: listRegisteredAbilitiesRequestSchema,
|
|
20
|
+
output: listRegisteredAbilitiesResponseSchema,
|
|
21
|
+
},
|
|
22
|
+
handler: ({ deps }) => serviceOf(deps).listRegisteredAbilities(),
|
|
23
|
+
});
|
|
24
|
+
export const whoHasAbilityCommand = createCommand({
|
|
25
|
+
method: 'whoHasAbility',
|
|
26
|
+
auth: { ability: ADMIN_PERMISSIONS_ABILITIES.read },
|
|
27
|
+
schemas: { input: whoHasAbilityRequestSchema, output: whoHasAbilityResponseSchema },
|
|
28
|
+
handler: ({ input, deps }) => serviceOf(deps).whoHasAbility(input),
|
|
29
|
+
});
|
|
30
|
+
export const getRoleAbilitiesCommand = createCommand({
|
|
31
|
+
method: 'getRoleAbilities',
|
|
32
|
+
auth: { ability: ADMIN_PERMISSIONS_ABILITIES.read },
|
|
33
|
+
schemas: { input: getRoleAbilitiesRequestSchema, output: getRoleAbilitiesResponseSchema },
|
|
34
|
+
handler: ({ input, deps }) => serviceOf(deps).getRoleAbilities(input),
|
|
35
|
+
});
|
|
36
|
+
export const setRoleAbilitiesCommand = createCommand({
|
|
37
|
+
method: 'setRoleAbilities',
|
|
38
|
+
auth: { ability: ADMIN_PERMISSIONS_ABILITIES.update },
|
|
39
|
+
schemas: { input: setRoleAbilitiesRequestSchema, output: setRoleAbilitiesResponseSchema },
|
|
40
|
+
handler: ({ input, deps }) => serviceOf(deps).setRoleAbilities(input),
|
|
41
|
+
});
|
|
@@ -5,19 +5,15 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Copyright (c) Infonomic Company Limited
|
|
7
7
|
*/
|
|
8
|
-
import type
|
|
8
|
+
import { type Command } from '../../lib/create-command.js';
|
|
9
9
|
import type { AdminStore } from '../../store.js';
|
|
10
|
-
import type { AdminRoleListResponse, AdminRoleResponse, OkResponse, UserRolesResponse } from './schemas.js';
|
|
10
|
+
import type { AdminRoleListResponse, AdminRoleResponse, CreateAdminRoleRequest, DeleteAdminRoleRequest, GetAdminRoleRequest, GetRolesForUserRequest, ListAdminRolesRequest, OkResponse, ReorderAdminRolesRequest, SetRolesForUserRequest, UpdateAdminRoleRequest, UserRolesResponse } from './schemas.js';
|
|
11
11
|
/**
|
|
12
12
|
* Transport-agnostic commands for the admin-roles module.
|
|
13
13
|
*
|
|
14
|
-
* Every command
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* actor holding the specific ability.
|
|
18
|
-
* 3. Call the `AdminRolesService` method with the validated input.
|
|
19
|
-
* 4. Parse the response through its output schema (catches
|
|
20
|
-
* schema/DTO drift in tests).
|
|
14
|
+
* Every command goes through `createCommand`, which folds the four
|
|
15
|
+
* standard steps (validate → assert admin actor + ability → invoke
|
|
16
|
+
* service → validate output) into one declaration.
|
|
21
17
|
*
|
|
22
18
|
* Reorder uses the `update` ability — see `abilities.ts` for the
|
|
23
19
|
* rationale (same trust level as content updates; splitting it would
|
|
@@ -26,11 +22,11 @@ import type { AdminRoleListResponse, AdminRoleResponse, OkResponse, UserRolesRes
|
|
|
26
22
|
export interface AdminRolesCommandDeps {
|
|
27
23
|
store: AdminStore;
|
|
28
24
|
}
|
|
29
|
-
export declare
|
|
30
|
-
export declare
|
|
31
|
-
export declare
|
|
32
|
-
export declare
|
|
33
|
-
export declare
|
|
34
|
-
export declare
|
|
35
|
-
export declare
|
|
36
|
-
export declare
|
|
25
|
+
export declare const listAdminRolesCommand: Command<ListAdminRolesRequest, AdminRoleListResponse, AdminRolesCommandDeps>;
|
|
26
|
+
export declare const getAdminRoleCommand: Command<GetAdminRoleRequest, AdminRoleResponse, AdminRolesCommandDeps>;
|
|
27
|
+
export declare const createAdminRoleCommand: Command<CreateAdminRoleRequest, AdminRoleResponse, AdminRolesCommandDeps>;
|
|
28
|
+
export declare const updateAdminRoleCommand: Command<UpdateAdminRoleRequest, AdminRoleResponse, AdminRolesCommandDeps>;
|
|
29
|
+
export declare const deleteAdminRoleCommand: Command<DeleteAdminRoleRequest, OkResponse, AdminRolesCommandDeps>;
|
|
30
|
+
export declare const reorderAdminRolesCommand: Command<ReorderAdminRolesRequest, OkResponse, AdminRolesCommandDeps>;
|
|
31
|
+
export declare const getRolesForUserCommand: Command<GetRolesForUserRequest, UserRolesResponse, AdminRolesCommandDeps>;
|
|
32
|
+
export declare const setRolesForUserCommand: Command<SetRolesForUserRequest, UserRolesResponse, AdminRolesCommandDeps>;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Copyright (c) Infonomic Company Limited
|
|
7
7
|
*/
|
|
8
|
-
import {
|
|
8
|
+
import { createCommand } from '../../lib/create-command.js';
|
|
9
9
|
import { ADMIN_USERS_ABILITIES } from '../admin-users/abilities.js';
|
|
10
10
|
import { ADMIN_ROLES_ABILITIES } from './abilities.js';
|
|
11
11
|
import { adminRoleListResponseSchema, adminRoleResponseSchema, createAdminRoleRequestSchema, deleteAdminRoleRequestSchema, getAdminRoleRequestSchema, getRolesForUserRequestSchema, listAdminRolesRequestSchema, okResponseSchema, reorderAdminRolesRequestSchema, setRolesForUserRequestSchema, updateAdminRoleRequestSchema, userRolesResponseSchema, } from './schemas.js';
|
|
@@ -13,57 +13,63 @@ import { AdminRolesService } from './service.js';
|
|
|
13
13
|
function serviceOf(deps) {
|
|
14
14
|
return new AdminRolesService({ store: deps.store });
|
|
15
15
|
}
|
|
16
|
-
export
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
export
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
export
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
export
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
export
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
|
|
16
|
+
export const listAdminRolesCommand = createCommand({
|
|
17
|
+
method: 'listAdminRoles',
|
|
18
|
+
auth: { ability: ADMIN_ROLES_ABILITIES.read },
|
|
19
|
+
schemas: { input: listAdminRolesRequestSchema, output: adminRoleListResponseSchema },
|
|
20
|
+
handler: ({ deps }) => serviceOf(deps).listRoles(),
|
|
21
|
+
});
|
|
22
|
+
export const getAdminRoleCommand = createCommand({
|
|
23
|
+
method: 'getAdminRole',
|
|
24
|
+
auth: { ability: ADMIN_ROLES_ABILITIES.read },
|
|
25
|
+
schemas: { input: getAdminRoleRequestSchema, output: adminRoleResponseSchema },
|
|
26
|
+
handler: ({ input, deps }) => serviceOf(deps).getRole(input),
|
|
27
|
+
});
|
|
28
|
+
export const createAdminRoleCommand = createCommand({
|
|
29
|
+
method: 'createAdminRole',
|
|
30
|
+
auth: { ability: ADMIN_ROLES_ABILITIES.create },
|
|
31
|
+
schemas: { input: createAdminRoleRequestSchema, output: adminRoleResponseSchema },
|
|
32
|
+
handler: ({ input, deps }) => serviceOf(deps).createRole(input),
|
|
33
|
+
});
|
|
34
|
+
export const updateAdminRoleCommand = createCommand({
|
|
35
|
+
method: 'updateAdminRole',
|
|
36
|
+
auth: { ability: ADMIN_ROLES_ABILITIES.update },
|
|
37
|
+
schemas: { input: updateAdminRoleRequestSchema, output: adminRoleResponseSchema },
|
|
38
|
+
handler: ({ input, deps }) => serviceOf(deps).updateRole(input),
|
|
39
|
+
});
|
|
40
|
+
export const deleteAdminRoleCommand = createCommand({
|
|
41
|
+
method: 'deleteAdminRole',
|
|
42
|
+
auth: { ability: ADMIN_ROLES_ABILITIES.delete },
|
|
43
|
+
schemas: { input: deleteAdminRoleRequestSchema, output: okResponseSchema },
|
|
44
|
+
handler: async ({ input, deps }) => {
|
|
45
|
+
await serviceOf(deps).deleteRole(input);
|
|
46
|
+
return { ok: true };
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
export const reorderAdminRolesCommand = createCommand({
|
|
50
|
+
method: 'reorderAdminRoles',
|
|
51
|
+
auth: { ability: ADMIN_ROLES_ABILITIES.update },
|
|
52
|
+
schemas: { input: reorderAdminRolesRequestSchema, output: okResponseSchema },
|
|
53
|
+
handler: async ({ input, deps }) => {
|
|
54
|
+
await serviceOf(deps).reorderRoles(input);
|
|
55
|
+
return { ok: true };
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
export const getRolesForUserCommand = createCommand({
|
|
59
|
+
method: 'getRolesForUser',
|
|
54
60
|
// Reading a user's role assignments requires read access to admin
|
|
55
61
|
// users — the data is fundamentally about that user.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
60
|
-
export
|
|
61
|
-
|
|
62
|
+
auth: { ability: ADMIN_USERS_ABILITIES.read },
|
|
63
|
+
schemas: { input: getRolesForUserRequestSchema, output: userRolesResponseSchema },
|
|
64
|
+
handler: ({ input, deps }) => serviceOf(deps).getRolesForUser(input),
|
|
65
|
+
});
|
|
66
|
+
export const setRolesForUserCommand = createCommand({
|
|
67
|
+
method: 'setRolesForUser',
|
|
62
68
|
// Editing a user's role-set is at the same trust level as updating
|
|
63
69
|
// their other admin fields. Roll into `admin.users.update` rather
|
|
64
70
|
// than minting a separate `admin.users.assignRoles` key — the role
|
|
65
71
|
// editor's checkbox tree would otherwise need both.
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
72
|
+
auth: { ability: ADMIN_USERS_ABILITIES.update },
|
|
73
|
+
schemas: { input: setRolesForUserRequestSchema, output: userRolesResponseSchema },
|
|
74
|
+
handler: ({ input, deps }) => serviceOf(deps).setRolesForUser(input),
|
|
75
|
+
});
|
|
@@ -5,27 +5,17 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Copyright (c) Infonomic Company Limited
|
|
7
7
|
*/
|
|
8
|
-
import type
|
|
8
|
+
import { type Command } from '../../lib/create-command.js';
|
|
9
9
|
import type { AdminStore } from '../../store.js';
|
|
10
|
-
import type { AdminUserListResponse, AdminUserResponse, OkResponse } from './schemas.js';
|
|
10
|
+
import type { AdminUserListResponse, AdminUserResponse, CreateAdminUserRequest, DeleteAdminUserRequest, DisableAdminUserRequest, EnableAdminUserRequest, GetAdminUserRequest, ListAdminUsersRequest, OkResponse, SetAdminUserPasswordRequest, UpdateAdminUserRequest } from './schemas.js';
|
|
11
11
|
/**
|
|
12
12
|
* Transport-agnostic commands for the admin-users module.
|
|
13
13
|
*
|
|
14
|
-
* Each command is
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* Throws `ZodError` on invalid shape; transport adapters translate
|
|
20
|
-
* that into a 400-ish response.
|
|
21
|
-
* 2. `assertAdminActor(context, ability)` — require an `AdminAuth`
|
|
22
|
-
* actor holding the specific ability. Throws `ERR_UNAUTHENTICATED`
|
|
23
|
-
* or `ERR_FORBIDDEN`.
|
|
24
|
-
* 3. Call the `AdminUsersService` method with the validated input
|
|
25
|
-
* (plus the actor where an invariant needs it).
|
|
26
|
-
* 4. Parse the response through its output schema. In production the
|
|
27
|
-
* check is redundant with the DTO's type; in tests it catches
|
|
28
|
-
* drift between schema and DTO early.
|
|
14
|
+
* Each command is built through `createCommand`, which folds the four
|
|
15
|
+
* standard steps (Zod-validate input → assert admin actor + ability →
|
|
16
|
+
* call the service → Zod-validate output) into a single declaration.
|
|
17
|
+
* The wrapper preserves the historical `(context, input, deps)` call
|
|
18
|
+
* signature so server fns keep working without change.
|
|
29
19
|
*
|
|
30
20
|
* The `deps` argument holds the `AdminStore`. The webapp wraps these in
|
|
31
21
|
* server fns that supply `deps` from the application's singleton store;
|
|
@@ -34,11 +24,11 @@ import type { AdminUserListResponse, AdminUserResponse, OkResponse } from './sch
|
|
|
34
24
|
export interface AdminUsersCommandDeps {
|
|
35
25
|
store: AdminStore;
|
|
36
26
|
}
|
|
37
|
-
export declare
|
|
38
|
-
export declare
|
|
39
|
-
export declare
|
|
40
|
-
export declare
|
|
41
|
-
export declare
|
|
42
|
-
export declare
|
|
43
|
-
export declare
|
|
44
|
-
export declare
|
|
27
|
+
export declare const listAdminUsersCommand: Command<ListAdminUsersRequest, AdminUserListResponse, AdminUsersCommandDeps>;
|
|
28
|
+
export declare const getAdminUserCommand: Command<GetAdminUserRequest, AdminUserResponse, AdminUsersCommandDeps>;
|
|
29
|
+
export declare const createAdminUserCommand: Command<CreateAdminUserRequest, AdminUserResponse, AdminUsersCommandDeps>;
|
|
30
|
+
export declare const updateAdminUserCommand: Command<UpdateAdminUserRequest, AdminUserResponse, AdminUsersCommandDeps>;
|
|
31
|
+
export declare const setAdminUserPasswordCommand: Command<SetAdminUserPasswordRequest, AdminUserResponse, AdminUsersCommandDeps>;
|
|
32
|
+
export declare const enableAdminUserCommand: Command<EnableAdminUserRequest, OkResponse, AdminUsersCommandDeps>;
|
|
33
|
+
export declare const disableAdminUserCommand: Command<DisableAdminUserRequest, OkResponse, AdminUsersCommandDeps>;
|
|
34
|
+
export declare const deleteAdminUserCommand: Command<DeleteAdminUserRequest, OkResponse, AdminUsersCommandDeps>;
|
|
@@ -5,58 +5,67 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Copyright (c) Infonomic Company Limited
|
|
7
7
|
*/
|
|
8
|
-
import {
|
|
8
|
+
import { createCommand } from '../../lib/create-command.js';
|
|
9
9
|
import { ADMIN_USERS_ABILITIES } from './abilities.js';
|
|
10
10
|
import { adminUserListResponseSchema, adminUserResponseSchema, createAdminUserRequestSchema, deleteAdminUserRequestSchema, disableAdminUserRequestSchema, enableAdminUserRequestSchema, getAdminUserRequestSchema, listAdminUsersRequestSchema, okResponseSchema, setAdminUserPasswordRequestSchema, updateAdminUserRequestSchema, } from './schemas.js';
|
|
11
11
|
import { AdminUsersService } from './service.js';
|
|
12
12
|
function serviceOf(deps) {
|
|
13
13
|
return new AdminUsersService({ repo: deps.store.adminUsers });
|
|
14
14
|
}
|
|
15
|
-
export
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
export
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
export
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
export
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
export
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
export
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
15
|
+
export const listAdminUsersCommand = createCommand({
|
|
16
|
+
method: 'listAdminUsers',
|
|
17
|
+
auth: { ability: ADMIN_USERS_ABILITIES.read },
|
|
18
|
+
schemas: { input: listAdminUsersRequestSchema, output: adminUserListResponseSchema },
|
|
19
|
+
handler: ({ input, deps }) => serviceOf(deps).listUsers(input),
|
|
20
|
+
});
|
|
21
|
+
export const getAdminUserCommand = createCommand({
|
|
22
|
+
method: 'getAdminUser',
|
|
23
|
+
auth: { ability: ADMIN_USERS_ABILITIES.read },
|
|
24
|
+
schemas: { input: getAdminUserRequestSchema, output: adminUserResponseSchema },
|
|
25
|
+
handler: ({ input, deps }) => serviceOf(deps).getUser(input),
|
|
26
|
+
});
|
|
27
|
+
export const createAdminUserCommand = createCommand({
|
|
28
|
+
method: 'createAdminUser',
|
|
29
|
+
auth: { ability: ADMIN_USERS_ABILITIES.create },
|
|
30
|
+
schemas: { input: createAdminUserRequestSchema, output: adminUserResponseSchema },
|
|
31
|
+
handler: ({ input, deps }) => serviceOf(deps).createUser(input),
|
|
32
|
+
});
|
|
33
|
+
export const updateAdminUserCommand = createCommand({
|
|
34
|
+
method: 'updateAdminUser',
|
|
35
|
+
auth: { ability: ADMIN_USERS_ABILITIES.update },
|
|
36
|
+
schemas: { input: updateAdminUserRequestSchema, output: adminUserResponseSchema },
|
|
37
|
+
handler: ({ input, deps }) => serviceOf(deps).updateUser(input),
|
|
38
|
+
});
|
|
39
|
+
export const setAdminUserPasswordCommand = createCommand({
|
|
40
|
+
method: 'setAdminUserPassword',
|
|
41
|
+
auth: { ability: ADMIN_USERS_ABILITIES.changePassword },
|
|
42
|
+
schemas: { input: setAdminUserPasswordRequestSchema, output: adminUserResponseSchema },
|
|
43
|
+
handler: ({ input, deps }) => serviceOf(deps).setPassword(input),
|
|
44
|
+
});
|
|
45
|
+
export const enableAdminUserCommand = createCommand({
|
|
46
|
+
method: 'enableAdminUser',
|
|
47
|
+
auth: { ability: ADMIN_USERS_ABILITIES.update },
|
|
48
|
+
schemas: { input: enableAdminUserRequestSchema, output: okResponseSchema },
|
|
49
|
+
handler: async ({ input, deps }) => {
|
|
50
|
+
await serviceOf(deps).enableUser(input);
|
|
51
|
+
return { ok: true };
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
export const disableAdminUserCommand = createCommand({
|
|
55
|
+
method: 'disableAdminUser',
|
|
56
|
+
auth: { ability: ADMIN_USERS_ABILITIES.update },
|
|
57
|
+
schemas: { input: disableAdminUserRequestSchema, output: okResponseSchema },
|
|
58
|
+
handler: async ({ input, deps, actor }) => {
|
|
59
|
+
await serviceOf(deps).disableUser(actor, input);
|
|
60
|
+
return { ok: true };
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
export const deleteAdminUserCommand = createCommand({
|
|
64
|
+
method: 'deleteAdminUser',
|
|
65
|
+
auth: { ability: ADMIN_USERS_ABILITIES.delete },
|
|
66
|
+
schemas: { input: deleteAdminUserRequestSchema, output: okResponseSchema },
|
|
67
|
+
handler: async ({ input, deps, actor }) => {
|
|
68
|
+
await serviceOf(deps).deleteUser(actor, input);
|
|
69
|
+
return { ok: true };
|
|
70
|
+
},
|
|
71
|
+
});
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@byline/admin",
|
|
3
3
|
"private": false,
|
|
4
4
|
"license": "MPL-2.0",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.10.0",
|
|
6
6
|
"engines": {
|
|
7
7
|
"node": ">=20.9.0"
|
|
8
8
|
},
|
|
@@ -68,8 +68,8 @@
|
|
|
68
68
|
"jose": "^6.2.3",
|
|
69
69
|
"uuid": "^14.0.0",
|
|
70
70
|
"zod": "^4.4.2",
|
|
71
|
-
"@byline/auth": "1.
|
|
72
|
-
"@byline/core": "1.
|
|
71
|
+
"@byline/auth": "1.10.0",
|
|
72
|
+
"@byline/core": "1.10.0"
|
|
73
73
|
},
|
|
74
74
|
"devDependencies": {
|
|
75
75
|
"@biomejs/biome": "2.4.14",
|