/** * This Source Code is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright (c) Infonomic Company Limited */ import type { AdminAuth, RequestContext } from '@byline/auth'; import type { ZodType } from 'zod'; /** * `createCommand` — the wrapper that folds the four-step admin command * contract (validate → authorise → invoke → shape) into a single * declaration. * * Implements Phase 1 of `docs/03-architecture/02-core-composition.md`. Today's scope is * `@byline/admin`-internal: it gates against admin actor identity using * the existing `assertAdminActor` / `requireAdminActor` helpers, which * inherit the super-admin bypass from `AdminAuth.assertAbility`. * * The `auth` slot is a discriminated union: * * - `{ ability }` — full admin gate. Requires an `AdminAuth` * actor holding the named ability. Maps to * `assertAdminActor`. * - `{ authenticated }` — identity gate only. Requires an `AdminAuth` * actor but does not assert any ability. Used * by self-service commands in `admin-account` * where the security property is "you may * only mutate your own row" and the target * id is sourced from `actor.id`. * * The handler receives an args object so it can cherry-pick what it * needs without positional ordering — `context` for downstream calls * that need the full request context, `input` (already Zod-parsed), * `deps` (typed by the module), and `actor` (already narrowed to * `AdminAuth` by the auth step). * * The returned command preserves today's `(context, input, deps) => * Promise` signature so existing server-fn call sites keep * working without change. * * Collection-document operations (create / update / delete / status / * upload) are gated through a separate helper, `assertActorCanPerform`, * which fires inside the `document-lifecycle` service functions in * `@byline/core`. They do not flow through this wrapper today; if the * two enforcement paths ever converge, the `auth` discriminator can * grow a `collection` variant without breaking existing call sites. */ export type CreateCommandAuthSpec = { readonly ability: string; readonly authenticated?: never; } | { readonly authenticated: true; readonly ability?: never; }; export interface CreateCommandHandlerArgs { readonly context: RequestContext; readonly input: TInput; readonly deps: TDeps; readonly actor: AdminAuth; } export interface CreateCommandSpec { /** * Stable identifier for the command, used in error messages and * future telemetry (Phase 1 of `CORE-COMPOSITION.md` calls out * uniform logging as a downstream benefit of the wrapper). */ readonly method: string; readonly auth: CreateCommandAuthSpec; readonly schemas: { readonly input: ZodType; readonly output: ZodType; }; readonly handler: (args: CreateCommandHandlerArgs) => Promise | TOutput; } export type Command<_TInput, TOutput, TDeps> = (context: RequestContext | undefined, input: unknown, deps: TDeps) => Promise; export declare function createCommand(spec: CreateCommandSpec): Command;