@atscript/moost-db 0.1.57 → 0.1.59

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.cts CHANGED
@@ -1,10 +1,11 @@
1
1
  import * as _atscript_typescript_utils0 from "@atscript/typescript/utils";
2
2
  import { TAtscriptAnnotatedType, TAtscriptDataType, TSerializeOptions, Validator } from "@atscript/typescript/utils";
3
3
  import * as _uniqu_url0 from "@uniqu/url";
4
- import { AtscriptDbReadable, AtscriptDbTable, FilterExpr, TCrudOp, TCrudPermissions, TCrudPermissions as TCrudPermissions$1, TDbActionInfo, TDbActionInfo as TDbActionInfo$1, TDbActionIntent, TDbActionIntent as TDbActionIntent$1, TDbActionLevel, TDbActionLevel as TDbActionLevel$1, TDbActionProcessor, TDbFieldMeta, TMetaResponse, Uniquery, UniqueryControls } from "@atscript/db";
4
+ import { AtscriptDbReadable, AtscriptDbTable, FilterExpr, FlatOf, TCrudOp, TCrudPermissions, TCrudPermissions as TCrudPermissions$1, TDbActionInfo, TDbActionInfo as TDbActionInfo$1, TDbActionIntent, TDbActionIntent as TDbActionIntent$1, TDbActionLevel, TDbActionLevel as TDbActionLevel$1, TDbActionProcessor, TDbFieldMeta, TIdentification, TMetaResponse, Uniquery, UniqueryControls } from "@atscript/db";
5
5
  import { HttpError } from "@moostjs/event-http";
6
6
  import * as moost from "moost";
7
7
  import { Moost, TConsoleBase } from "moost";
8
+ import * as _wooksjs_event_core0 from "@wooksjs/event-core";
8
9
 
9
10
  //#region src/as-readable.controller.d.ts
10
11
  /**
@@ -153,6 +154,9 @@ declare class AsDbReadableController<T extends TAtscriptAnnotatedType = TAtscrip
153
154
  /** Reference to the underlying readable (table or view). */
154
155
  protected readable: AtscriptDbReadable<T>;
155
156
  private readonly _gates;
157
+ private readonly _preferredIdSet;
158
+ private readonly _compositeIdShapes;
159
+ private readonly _overlayIsNoOp;
156
160
  constructor(readable: AtscriptDbReadable<T>, app: Moost);
157
161
  private _buildGates;
158
162
  private _collectAnnotated;
@@ -175,6 +179,27 @@ declare class AsDbReadableController<T extends TAtscriptAnnotatedType = TAtscrip
175
179
  * May return a Promise for async lookups.
176
180
  */
177
181
  protected transformProjection(projection?: UniqueryControls["$select"]): UniqueryControls["$select"] | undefined | Promise<UniqueryControls["$select"] | undefined>;
182
+ private widenPreferredIdProjection;
183
+ private _widenArrayProjection;
184
+ private _widenMapProjection;
185
+ /** WHY: the URL parser only auto-coerces `$count`; every other boolean control reaches us as `"true"`/`"1"` and would fail DTO validation. */
186
+ private _coerceActionsControl;
187
+ /** Normalize a post-`widenPreferredIdProjection` $select into `string[] | null` (`null` = all fields). */
188
+ private _resolveProjectionForAugmenter;
189
+ /** WHY: filter row/rows envelopes by the per-request `applyMetaOverlay` action set; skip `meta()` when overlay is identity. */
190
+ private _resolveAugmentEnvelopes;
191
+ /** Returns a widened `$select` only when at least one `requiredFields` entry is missing; `null` means "no widening needed". */
192
+ private _widenSelectForActions;
193
+ private _prepareAugmentation;
194
+ private _resolveReadStrategy;
195
+ /**
196
+ * Shared `query` / `pages` pipeline: prepare actions augmentation + read
197
+ * strategy in parallel, pre-widen $select for `requiredFields`, run
198
+ * `exec`, and augment `result.data` with `$actions` when the request set
199
+ * `$actions=true`. Caller dispatches the strategy to its read-method
200
+ * family (count vs no-count).
201
+ */
202
+ private _runReadWithActions;
178
203
  /**
179
204
  * Extracts a composite identifier object from query params.
180
205
  * Tries composite primary key first, then compound unique indexes.
@@ -203,6 +228,7 @@ declare class AsDbReadableController<T extends TAtscriptAnnotatedType = TAtscrip
203
228
  * (composite primary key or compound unique index).
204
229
  */
205
230
  getOneComposite(query: Record<string, string>, url: string): Promise<DataType | HttpError>;
231
+ private _findByIdAndAugment;
206
232
  /**
207
233
  * **GET /meta** — returns table/view metadata for UI.
208
234
  *
@@ -460,16 +486,84 @@ declare const validationErrorTransform: () => moost.TInterceptorDef;
460
486
  declare const UseValidationErrorTransform: () => ClassDecorator & MethodDecorator;
461
487
  //#endregion
462
488
  //#region src/actions/types.d.ts
489
+ /** `'rows'`-level batch policy — controls whether failing rows reject or are filtered out. */
490
+ type TOnDisabledRows = "reject" | "skip";
463
491
  /**
464
- * Options accepted by `@DbAction(name, opts?)`. Structurally derived from
465
- * {@link TDbActionInfo} so every addition to the wire shape automatically
466
- * propagates here. Fields owned by the framework (`name`, `level`, `processor`,
467
- * `value`) are excluded `name` comes from the decorator argument, `level` is
468
- * inferred from `@DbActionPK*` usage, `processor` is fixed to `'backend'` for
469
- * method-decorator actions, and `value` is filled from the `@Post` path.
492
+ * Dot-notation field paths of `TRow`'s flat type. Drives both the runtime
493
+ * projection widening and the type narrowing of the `disabled` predicate's
494
+ * row argument. Relations are absent from `FlatOf<T>` listing a relation
495
+ * field is therefore a compile error.
496
+ *
497
+ * Permissive fallback when `TRow = unknown` (no explicit decorator generic):
498
+ * any string is allowed and the `disabled` predicate's row arg is `any[]`,
499
+ * preserving the prior loose typing for un-annotated call sites.
470
500
  */
471
- type DbActionOpts = Partial<Omit<TDbActionInfo$1, "name" | "level" | "processor" | "value">>;
472
- interface DbActionsEntryCommon {
501
+ type FlatKey<TRow> = unknown extends TRow ? string : keyof FlatOf<TRow> & string;
502
+ /** Row-shape narrowing for the `disabled` predicate. Falls back to `any` when `TRow = unknown`. */
503
+ type DisabledRowsArg<TRow, R extends readonly FlatKey<TRow>[]> = unknown extends TRow ? any[] : Pick<FlatOf<TRow>, R[number] & keyof FlatOf<TRow>>[];
504
+ interface NoGate {
505
+ requiredFields?: never;
506
+ disabled?: never;
507
+ onDisabledRows?: never;
508
+ }
509
+ interface WithGate<TRow, R extends readonly FlatKey<TRow>[]> {
510
+ /**
511
+ * Dot-notation field paths the predicate references. SERVER-INTERNAL —
512
+ * never emitted on the `/meta` wire. Consumed verbatim to widen the DB
513
+ * projection so `disabled` always sees the fields it declared.
514
+ */
515
+ requiredFields: R;
516
+ /**
517
+ * Sync batch gate predicate — returns a parallel `boolean[]` aligned with
518
+ * the input. `true` = disabled for the corresponding row. The `rows`
519
+ * argument is type-narrowed to `Pick<FlatOf<TRow>, R[number]>[]`; reading
520
+ * a field not listed in `requiredFields` is a compile error.
521
+ *
522
+ * Promise return is NOT permitted — the predicate is consumed in the
523
+ * same tick by the gate and the augmenter.
524
+ */
525
+ disabled?: (rows: DisabledRowsArg<TRow, R>) => boolean[];
526
+ /**
527
+ * `'rows'`-level batch policy. Default `'reject'`.
528
+ *
529
+ * - `'reject'`: evaluate every row before throwing; if any row fails, the
530
+ * error body lists ALL failing IDs; handler not invoked.
531
+ * - `'skip'`: filter cached rows + cached IDs to passing-only; zero
532
+ * survivors → reject. Handler runs against the survivors.
533
+ *
534
+ * Ignored for `'row'` and `'table'` level actions.
535
+ */
536
+ onDisabledRows?: TOnDisabledRows;
537
+ }
538
+ /**
539
+ * Loose gate shape used when `TRow = unknown` (no explicit decorator generic).
540
+ * Preserves the prior un-typed call-site flexibility; the runtime still drops
541
+ * actions where `disabled` is set without `requiredFields`.
542
+ */
543
+ interface LooseGate {
544
+ requiredFields?: string[];
545
+ disabled?: (rows: any[]) => boolean[];
546
+ onDisabledRows?: TOnDisabledRows;
547
+ }
548
+ type GateOpts<TRow, R extends readonly FlatKey<TRow>[]> = unknown extends TRow ? LooseGate : NoGate | WithGate<TRow, R>;
549
+ interface BaseActionOpts extends Partial<Omit<TDbActionInfo$1, "name" | "level" | "processor" | "value" | "disabled">> {
550
+ /**
551
+ * Bound table reference. REQUIRED on non-`AsDbReadableController` classes
552
+ * when `disabled` is set OR a `@DbActionRow*` parameter is declared.
553
+ *
554
+ * Silently ignored on `AsDbReadableController` subclasses (which include
555
+ * `AsDbController`) — the bound table from the controller wins.
556
+ */
557
+ table?: AtscriptDbTable<any>;
558
+ }
559
+ /**
560
+ * Options accepted by `@DbAction(name, opts?)`. Generic over `TRow` (the
561
+ * controller's bound atscript type) and `R` (the literal `requiredFields`
562
+ * tuple). Both are inferred at the call site via the decorator's `<TRow>`
563
+ * argument plus `const R` generic.
564
+ */
565
+ type DbActionOpts<TRow = unknown, R extends readonly FlatKey<TRow>[] = []> = BaseActionOpts & GateOpts<TRow, R>;
566
+ interface DbActionsEntryCommonBase {
473
567
  label: string;
474
568
  level: TDbActionLevel$1;
475
569
  icon?: string;
@@ -477,52 +571,55 @@ interface DbActionsEntryCommon {
477
571
  description?: string;
478
572
  order?: number;
479
573
  default?: boolean;
480
- promptText?: string;
574
+ /** Mirrors {@link TDbActionInfo.promptText} — singular/plural via tuple. */
575
+ promptText?: string | [string, string];
576
+ /** Mirrors {@link TDbActionInfo.shortcut} — single-character UI hint. */
577
+ shortcut?: string;
481
578
  }
579
+ type DbActionsEntryWithGate<TRow, R extends readonly FlatKey<TRow>[]> = DbActionsEntryCommonBase & GateOpts<TRow, R>;
482
580
  /**
483
581
  * Class-level dict entry. `value` semantics by processor:
484
582
  *
485
- * - `'navigate'` — REQUIRED, non-empty. The URL template (with `$1` substituted client-side).
486
- * - `'backend'` — REQUIRED, non-empty. The full HTTP POST path the UI client should invoke.
487
- * For row/rows entries the dev-supplied path MUST point to a `@Post`-bound
488
- * handler accepting the PK-shaped JSON body (single PK scalar / composite
489
- * object / array thereof) — typically a method using `@DbActionPK()` or
490
- * `@DbActionPKs()`. The meta builder does NOT validate this.
583
+ * - `'navigate'` — REQUIRED, non-empty. URL template (`$1` substituted client-side).
584
+ * - `'backend'` — REQUIRED, non-empty. Full HTTP POST path the UI client invokes.
491
585
  * - `'custom'` — `value` is forbidden in the entry; the meta builder fills it
492
586
  * with the dict key.
493
587
  */
494
- type TDbActionsEntry = (DbActionsEntryCommon & {
588
+ type TDbActionsEntry<TRow = unknown, R extends readonly FlatKey<TRow>[] = []> = (DbActionsEntryWithGate<TRow, R> & {
495
589
  processor: "navigate";
496
590
  value: string;
497
- }) | (DbActionsEntryCommon & {
591
+ }) | (DbActionsEntryWithGate<TRow, R> & {
498
592
  processor: "custom";
499
593
  value?: never;
500
- }) | (DbActionsEntryCommon & {
594
+ }) | (DbActionsEntryWithGate<TRow, R> & {
501
595
  processor: "backend";
502
596
  value: string;
503
597
  });
504
598
  /** Distributes `Omit` across the discriminated union members. */
505
599
  type DistributiveOmit<T, K extends keyof T> = T extends T ? Omit<T, K> : never;
506
600
  /** Same as {@link TDbActionsEntry} but without the `level` field — used by the level-pinned shortcuts. */
507
- type TDbActionsEntryUnpinned = DistributiveOmit<TDbActionsEntry, "level">;
601
+ type TDbActionsEntryUnpinned<TRow = unknown, R extends readonly FlatKey<TRow>[] = []> = DistributiveOmit<TDbActionsEntry<TRow, R>, "level">;
602
+ type DbActionsDictBase = Record<string, unknown>;
603
+ type EntryRequiredFields<E, TRow> = E extends {
604
+ requiredFields: infer R;
605
+ } ? R extends readonly FlatKey<TRow>[] ? R : [] : [];
606
+ type ValidatedDict<TRow, D extends DbActionsDictBase> = { [K in keyof D]: TDbActionsEntry<TRow, EntryRequiredFields<D[K], TRow>> };
607
+ type ValidatedUnpinnedDict<TRow, D extends DbActionsDictBase> = { [K in keyof D]: TDbActionsEntryUnpinned<TRow, EntryRequiredFields<D[K], TRow>> };
508
608
  //#endregion
509
609
  //#region src/actions/db-action.decorator.d.ts
510
610
  /**
511
- * Mark a controller method as a database action surfaced via `/meta`.
512
- *
513
- * Metadata-only pair with `@Post(...)` for Moost to bind the route. The
514
- * meta builder reads this metadata plus the bound POST path lazily and
515
- * emits the action with `processor: 'backend'`. Order vs.
516
- * `@DbActionDefault()` does not matter — both merge into the same slot.
611
+ * Mark a controller method as a database action surfaced via `/meta`. Writes
612
+ * `MOOST_DB_ACTION` metadata and registers a Moost interceptor when needed
613
+ * (gate when `disabled` is set, thin bound-table injector when only
614
+ * `@DbActionRow*` is present). Stacking two `@DbAction` on the same method
615
+ * is undefined and emits a warning.
517
616
  *
518
- * @example
519
- * ```ts
520
- * @Post('actions/block')
521
- * @DbAction('block', { label: 'Block', icon: 'i-as-block', intent: 'negative' })
522
- * async blockUser(@DbActionPK() id: string) { ... }
523
- * ```
617
+ * Generic over `TRow` (annotate at the call site: `@DbAction<Order>(...)`)
618
+ * and `R` (the literal `requiredFields` tuple, inferred via `const R`).
619
+ * The `disabled` predicate's `rows` argument is type-narrowed to
620
+ * `Pick<FlatOf<TRow>, R[number]>[]`.
524
621
  */
525
- declare function DbAction(name: string, opts?: DbActionOpts): MethodDecorator;
622
+ declare function DbAction<TRow = unknown, const R extends readonly FlatKey<TRow>[] = []>(name: string, opts?: DbActionOpts<TRow, R>): MethodDecorator;
526
623
  //#endregion
527
624
  //#region src/actions/db-action-default.decorator.d.ts
528
625
  /**
@@ -531,35 +628,74 @@ declare function DbAction(name: string, opts?: DbActionOpts): MethodDecorator;
531
628
  */
532
629
  declare function DbActionDefault(): MethodDecorator;
533
630
  //#endregion
534
- //#region src/actions/db-action-pk.decorator.d.ts
631
+ //#region src/actions/db-action-id.decorator.d.ts
535
632
  /**
536
- * Parameter resolver that reads the primary key from the JSON request body
537
- * and validates it against the bound table's PK schema.
633
+ * Parameter resolver that reads a row identifier from the JSON request body
634
+ * and validates it against the bound table's legitimate identifiers.
635
+ *
636
+ * Body shape is always a JSON object — no scalar form. The object's key set
637
+ * MUST exactly match one of the table's legitimate identifications:
538
638
  *
539
- * - Single-field PK → JSON-encoded scalar (`"abc"`, `42`, `true`).
540
- * - Composite PK → JSON object with all PK fields.
639
+ * - Single-field PK → `{ id: "abc" }` (or whatever the PK prop is named).
640
+ * - Composite PK → `{ tenantId: "...", userId: "..." }`.
641
+ * - Single-field unique index → `{ slug: "alpha" }`.
642
+ * - Compound unique index → `{ tenantId: "...", slug: "..." }`.
541
643
  *
542
- * Validation is strict no type coercion. Mismatches throw a
644
+ * Strict unknown fields are rejected, no type coercion. Mismatches throw a
543
645
  * `ValidatorError` which the existing validation interceptor surfaces as
544
646
  * HTTP 400 with the same envelope as DTO failures.
545
647
  *
546
648
  * Marks the param so {@link discoverActions} can infer the action's `level`
547
649
  * as `'row'`.
650
+ *
651
+ * Implementation note: the resolver is a thin reader of the cached ID wook
652
+ * — validation logic lives in the wook factory, which runs once per request
653
+ * regardless of how many readers consume the value.
548
654
  */
549
- declare function DbActionPK(): ParameterDecorator;
655
+ declare function DbActionID(): ParameterDecorator;
550
656
  //#endregion
551
- //#region src/actions/db-action-pks.decorator.d.ts
657
+ //#region src/actions/db-action-ids.decorator.d.ts
552
658
  /**
553
- * Parameter resolver that reads a JSON array of primary keys from the request
554
- * body and validates each entry against the bound table's PK schema.
659
+ * Parameter resolver that reads a JSON array of row identifiers from the
660
+ * request body and validates each entry against the bound table.
555
661
  *
556
- * - Scalar PK JSON array of scalars (`["a","b","c"]`).
557
- * - Composite PK JSON array of objects.
662
+ * Body shape is always a JSON array of objects — no scalar form. Each
663
+ * element's key set MUST exactly match one of the table's legitimate
664
+ * identifications (PK or any unique index). Elements MAY mix shapes:
665
+ * `[{ id: "1" }, { slug: "alpha" }]` is valid when both `id` is the PK
666
+ * and `slug` is a unique index.
558
667
  *
559
- * Validation is strict no type coercion. Marks the param so
560
- * {@link discoverActions} can infer the action's `level` as `'rows'`.
668
+ * Strict unknown fields are rejected, no type coercion. Marks the param
669
+ * so {@link discoverActions} can infer the action's `level` as `'rows'`.
670
+ *
671
+ * In `'rows'` skip mode the resolved value reflects the gate interceptor's
672
+ * filtered subset (the cached ID slot is overwritten in place); see
673
+ * {@link dbActionIdsSlot} for precedence details.
561
674
  */
562
- declare function DbActionPKs(): ParameterDecorator;
675
+ declare function DbActionIDs(): ParameterDecorator;
676
+ //#endregion
677
+ //#region src/actions/db-action-row.decorator.d.ts
678
+ /**
679
+ * Parameter decorator that injects the row whose identifier was supplied in
680
+ * the request body.
681
+ *
682
+ * Marks the param so {@link discoverActions} infers the action's `level` as
683
+ * `'row'`. Co-occurrence with `@DbActionRows()` (or any multi-cardinality
684
+ * decorator) drops the action with a warning.
685
+ *
686
+ * In `'skip'` mode this returns the gate's filtered row; the original
687
+ * request-body row is not retrievable.
688
+ */
689
+ declare function DbActionRow(): ParameterDecorator;
690
+ /**
691
+ * Parameter decorator that injects the rows fetched by the identifiers
692
+ * supplied in the request body.
693
+ *
694
+ * Marks the param so {@link discoverActions} infers the action's `level` as
695
+ * `'rows'`. In `'rows'` + `'skip'` mode the resolved value contains only the
696
+ * gate's surviving rows.
697
+ */
698
+ declare function DbActionRows(): ParameterDecorator;
563
699
  //#endregion
564
700
  //#region src/actions/db-actions.decorator.d.ts
565
701
  /**
@@ -569,47 +705,114 @@ declare function DbActionPKs(): ParameterDecorator;
569
705
  * the level-pinned shortcuts (`@DbTableActions`, `@DbRowActions`,
570
706
  * `@DbRowsActions`) to avoid repeating `level`.
571
707
  *
572
- * The dictionary key serves as the action `name`. Entries do NOT bind any
573
- * HTTP route the meta builder surfaces them in `/meta` only. For
574
- * `processor: 'backend'`, the dev-supplied `value` MUST point to a real
575
- * `@Post`-bound endpoint accepting the level-determined body shape.
708
+ * Generic over `TRow` (annotate at the call site: `@DbActions<Order>(...)`)
709
+ * and `D` (the literal dict, captured via `const D`). Each entry's
710
+ * `disabled` predicate is type-narrowed by its own `requiredFields` literal.
576
711
  *
577
712
  * Multiple `@DbActions` (and shortcut) decorators on the same class
578
713
  * accumulate.
579
714
  */
580
- declare function DbActions(dict: Record<string, TDbActionsEntry>): ClassDecorator;
715
+ declare function DbActions<TRow = unknown, const D extends Record<string, unknown> = {}>(dict: D & ValidatedDict<TRow, D>): ClassDecorator;
581
716
  /** Sugar for `@DbActions` with `level: 'table'` injected into each entry. */
582
- declare function DbTableActions(dict: Record<string, TDbActionsEntryUnpinned>): ClassDecorator;
717
+ declare function DbTableActions<TRow = unknown, const D extends Record<string, unknown> = {}>(dict: D & ValidatedUnpinnedDict<TRow, D>): ClassDecorator;
583
718
  /** Sugar for `@DbActions` with `level: 'row'` injected into each entry. */
584
- declare function DbRowActions(dict: Record<string, TDbActionsEntryUnpinned>): ClassDecorator;
719
+ declare function DbRowActions<TRow = unknown, const D extends Record<string, unknown> = {}>(dict: D & ValidatedUnpinnedDict<TRow, D>): ClassDecorator;
585
720
  /** Sugar for `@DbActions` with `level: 'rows'` injected into each entry. */
586
- declare function DbRowsActions(dict: Record<string, TDbActionsEntryUnpinned>): ClassDecorator;
721
+ declare function DbRowsActions<TRow = unknown, const D extends Record<string, unknown> = {}>(dict: D & ValidatedUnpinnedDict<TRow, D>): ClassDecorator;
587
722
  //#endregion
588
723
  //#region src/actions/discover.d.ts
589
724
  /**
590
- * Discover all actions declared on a controller and produce the `/meta` array.
591
- * Reads class + method metadata via `getMoostMate()` and resolves bound POST
592
- * paths through the Moost controller overview.
593
- *
594
- * Result is memoized per controller constructor — discovery walks every
595
- * handler entry and reads decorator metadata, which is wasted work to repeat
596
- * across instances.
725
+ * Pairs the wire-shaped `info` with the original decorator opts / dict entry,
726
+ * so the augmenter can invoke the live `disabled` reference (deliberately
727
+ * absent from the wire `info`).
597
728
  */
598
- declare function discoverActions(controllerCtor: Function, app: Moost, logger: TConsoleBase): TDbActionInfo$1[];
729
+ interface TDbActionEnvelope {
730
+ info: TDbActionInfo$1;
731
+ raw: DbActionOpts | TDbActionsEntry;
732
+ }
733
+ /** Discover actions on a controller, memoized per ctor. `info`-only callers map `e => e.info`. */
734
+ declare function discoverActions(controllerCtor: Function, app: Moost, logger: TConsoleBase): TDbActionEnvelope[];
735
+ //#endregion
736
+ //#region src/actions/id-validation.d.ts
737
+ interface IdValidationSource {
738
+ getIdentifications(): readonly TIdentification[];
739
+ fieldDescriptors: readonly TDbFieldMeta[];
740
+ }
741
+ //#endregion
742
+ //#region src/actions/id-cache.d.ts
743
+ declare const useDbActionId: _wooksjs_event_core0.WookComposable<{
744
+ load: () => Promise<Record<string, unknown>>;
745
+ }>;
746
+ declare const useDbActionIds: _wooksjs_event_core0.WookComposable<{
747
+ load: () => Promise<Record<string, unknown>[]>;
748
+ }>;
599
749
  //#endregion
600
- //#region src/actions/pk-validation.d.ts
750
+ //#region src/actions/row-cache.d.ts
751
+ declare const useDbActionRow: _wooksjs_event_core0.WookComposable<{
752
+ load: () => Promise<unknown>;
753
+ }>;
754
+ declare const useDbActionRows: _wooksjs_event_core0.WookComposable<{
755
+ load: () => Promise<(Record<string, unknown> | undefined)[]>;
756
+ }>;
757
+ //#endregion
758
+ //#region src/actions/action-disabled-error.d.ts
601
759
  /**
602
- * Minimal shape required to validate PKs against a table — supplied by the
603
- * controller's underlying `AtscriptDbReadable`/`AtscriptDbTable`.
760
+ * Wire-body shape for server-side gate rejections. The `name` discriminator
761
+ * lets `@atscript/db-client` recognise the response and construct the typed
762
+ * `ActionDisabledError` subclass. The shape extends Moost's standard
763
+ * `ServerError` envelope (`{ message, statusCode, errors? }`) with three
764
+ * additional fields:
765
+ *
766
+ * - `name: 'ActionDisabledError'` — discriminator the client matches.
767
+ * - `action` — the `@DbAction` name that rejected the request.
768
+ * - `id?` — present only for `'row'`-level rejections.
769
+ * - `ids?` — present only for `'rows'`-level rejections.
770
+ *
771
+ * `message` is populated with a human-readable string so generic
772
+ * `ClientError` consumers (which read `body.message`) still get something
773
+ * useful without typed-catch dispatch.
604
774
  */
605
- interface PkValidationSource {
606
- primaryKeys: readonly string[];
607
- fieldDescriptors: readonly TDbFieldMeta[];
775
+ interface ActionDisabledErrorBody {
776
+ name: "ActionDisabledError";
777
+ message: string;
778
+ statusCode: 409;
779
+ action: string;
780
+ id?: Record<string, unknown>;
781
+ ids?: Record<string, unknown>[];
782
+ }
783
+ /**
784
+ * Thrown by the gate interceptor when `disabled` returns truthy. Composes
785
+ * with Moost's existing error mapper to produce HTTP 409 with the wire body
786
+ * defined by {@link ActionDisabledErrorBody}.
787
+ *
788
+ * - `'row'`-level rejection: pass `(action, id)` — the body emits `id`.
789
+ * - `'rows'`-level rejection: pass `(action, undefined, ids)` — the body
790
+ * emits `ids` (the FULL list of failing IDs in reject mode; the FULL list
791
+ * of request IDs in skip mode with zero survivors).
792
+ */
793
+ declare class ActionDisabledError extends HttpError<ActionDisabledErrorBody> {
794
+ name: string;
795
+ constructor(action: string, id?: Record<string, unknown>, ids?: Record<string, unknown>[]);
608
796
  }
609
797
  //#endregion
798
+ //#region src/actions/per-row.d.ts
799
+ /**
800
+ * Lift a per-row predicate into the batch shape required by
801
+ * `@DbAction` opts.`disabled` and class-level dict `disabled`. Polarity is
802
+ * preserved — `true` from `fn` means the action is disabled for that row.
803
+ *
804
+ * ```ts
805
+ * @DbAction<Order>('archive', {
806
+ * requiredFields: ['status'],
807
+ * disabled: perRow(r => r.status === 'archived'),
808
+ * })
809
+ * ```
810
+ */
811
+ declare const perRow: <TRow>(fn: (row: TRow) => boolean) => (rows: TRow[]) => boolean[];
812
+ //#endregion
610
813
  //#region src/permissions/crud-controls.d.ts
611
814
  declare const QUERY_CONTROLS: readonly string[];
612
815
  declare const PAGES_CONTROLS: readonly string[];
613
816
  declare const ONE_CONTROLS: readonly string[];
614
817
  //#endregion
615
- export { AsDbController, AsDbReadableController, AsJsonValueHelpController, AsReadableController, AsValueHelpController, DbAction, DbActionDefault, DbActionOpts, DbActionPK, DbActionPKs, DbActions, DbRowActions, DbRowsActions, DbTableActions, ONE_CONTROLS, PAGES_CONTROLS, PkValidationSource, QUERY_CONTROLS, READABLE_DEF, ReadableController, ReadableGates, TABLE_DEF, type TCrudOp, type TCrudPermissions, type TDbActionInfo, type TDbActionIntent, type TDbActionLevel, type TDbActionProcessor, TDbActionsEntry, TDbActionsEntryUnpinned, TableController, UseValidationErrorTransform, ValueHelpQuery, ViewController, discoverActions, validationErrorTransform };
818
+ export { ActionDisabledError, ActionDisabledErrorBody, AsDbController, AsDbReadableController, AsJsonValueHelpController, AsReadableController, AsValueHelpController, DbAction, DbActionDefault, DbActionID, DbActionIDs, DbActionOpts, DbActionRow, DbActionRows, DbActions, DbRowActions, DbRowsActions, DbTableActions, IdValidationSource, ONE_CONTROLS, PAGES_CONTROLS, QUERY_CONTROLS, READABLE_DEF, ReadableController, ReadableGates, TABLE_DEF, type TCrudOp, type TCrudPermissions, type TDbActionInfo, type TDbActionIntent, type TDbActionLevel, type TDbActionProcessor, TDbActionsEntry, TDbActionsEntryUnpinned, TableController, UseValidationErrorTransform, ValueHelpQuery, ViewController, discoverActions, perRow, useDbActionId, useDbActionIds, useDbActionRow, useDbActionRows, validationErrorTransform };