@cosmicdrift/kumiko-types 0.377.0 → 0.379.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/config.d.ts CHANGED
@@ -219,7 +219,10 @@ export type TemplateListVariableDef = TemplateVariableCommon & {
219
219
  readonly item: Readonly<Record<string, TemplateScalarVariableDef>>;
220
220
  readonly example?: readonly Readonly<Record<string, unknown>>[];
221
221
  };
222
- export type TemplateVariableDef = TemplateScalarVariableDef | TemplateListVariableDef;
222
+ export type TemplateImagesVariableDef = TemplateVariableCommon & {
223
+ readonly type: "images";
224
+ };
225
+ export type TemplateVariableDef = TemplateScalarVariableDef | TemplateListVariableDef | TemplateImagesVariableDef;
223
226
  export type TemplateVariables = Readonly<Record<string, TemplateVariableDef>>;
224
227
  export type NotificationTemplateMeta = {
225
228
  readonly subject: string;
package/dist/fields.d.ts CHANGED
@@ -489,7 +489,12 @@ export type EmbeddedSubFieldDef = (EmbeddedSubFieldBase & {
489
489
  * precision its target sub-field in `schema` declares (money → integer,
490
490
  * decimal → `scale`) before it's validated. */
491
491
  export type EmbeddedDerivedCellDef = {
492
- readonly op: "multiply" | "sum" | "subtract";
492
+ /** `percent` = `from[0] * from[1] / 100` (exactly two sources, e.g. amount and rate). */
493
+ readonly op: "multiply" | "sum" | "subtract" | "percent";
494
+ readonly from: readonly string[];
495
+ };
496
+ export type EmbeddedTotalDef = string | {
497
+ readonly label: string;
493
498
  readonly from: readonly string[];
494
499
  };
495
500
  export type EmbeddedFieldDef = {
@@ -518,9 +523,12 @@ export type EmbeddedFieldDef = {
518
523
  * sub-fields of the same row, rounded to that sub-field's declared
519
524
  * precision. Only valid with `multiple: true`. */
520
525
  readonly derived?: Readonly<Record<string, EmbeddedDerivedCellDef>>;
521
- /** Renderer metadata: numeric sub-field names to sum in a totals row. Only
522
- * valid with `multiple: true`. */
523
- readonly totals?: readonly string[];
526
+ /** Renderer metadata: footer totals. A string is the sum of that numeric
527
+ * sub-field under the column label; an object shows the sum of all `from`
528
+ * sub-fields under its own i18n `label` (e.g. net, VAT, gross). Display
529
+ * only; the server derivation is unchanged. Only valid with
530
+ * `multiple: true`. */
531
+ readonly totals?: readonly EmbeddedTotalDef[];
524
532
  /** Maps an embedded-list subfield name to a sibling top-level money field
525
533
  * name — the sum of that subfield across all rows must equal the sibling
526
534
  * field's amount. Validated both client- and server-side (schema-builder
@@ -636,6 +644,10 @@ export type FilesFieldDef = {
636
644
  readonly maxSize?: string;
637
645
  readonly accept?: readonly string[];
638
646
  readonly maxCount?: number;
647
+ /** `"list"` (default) shows the picked files as a list with a file picker; `"dropzone"` shows a
648
+ * drag-and-drop zone with one status row per file, a remove action per file and the field's
649
+ * `maxCount`/`accept`/`maxSize` as hints. The stored value is the same array of FileRef ids. */
650
+ readonly display?: "list" | "dropzone";
639
651
  readonly access?: FieldAccess;
640
652
  } & ResolvedPiiFlags;
641
653
  export type ImagesFieldDef = {
@@ -644,6 +656,10 @@ export type ImagesFieldDef = {
644
656
  readonly maxSize?: string;
645
657
  readonly accept?: readonly string[];
646
658
  readonly maxCount?: number;
659
+ /** `"list"` (default) shows the picked files as a list with a file picker; `"dropzone"` shows a
660
+ * drag-and-drop zone with one status row per file, a remove action per file and the field's
661
+ * `maxCount`/`accept`/`maxSize` as hints. The stored value is the same array of FileRef ids. */
662
+ readonly display?: "list" | "dropzone";
647
663
  readonly variants?: Readonly<Record<string, VariantSpec>>;
648
664
  /** Forwarded to the file input's `capture` attribute so a phone opens the
649
665
  * camera instead of the file picker. */
@@ -232,7 +232,7 @@ type SharedContextFields = {
232
232
  readonly forTenant?: (tenantId: TenantId) => TenantWriteTarget;
233
233
  /** Mints the per-request `ctx.config`; set by the boot (`addConfigAccessorFactory`) from the effective `configResolver`, overriding an app-supplied value. */
234
234
  readonly configAccessorFactory?: ConfigAccessorFactory;
235
- /** @deprecated Use `configAccessorFactory`; the underscore name is removed in the next major. */
235
+ /** @deprecated Use `configAccessorFactory`; the underscore name is removed in 0.390.0. */
236
236
  readonly _configAccessorFactory?: ConfigAccessorFactory;
237
237
  readonly configEncryption?: import("./envelope-cipher-types.ts").EnvelopeCipher;
238
238
  readonly rateLimit?: import("./rate-limit-types.ts").RateLimitResolver;
@@ -297,15 +297,12 @@ export type HandlerContext<TMap extends object = KumikoEventTypeMap> = SharedCon
297
297
  * Same tenant scoping as `db`, but never bound to the handler's tx: writes through it survive
298
298
  * a rollback. `undefined` only in the denial phases (member-resolution, before-transaction)
299
299
  * and in platform-metering tenant mode; narrow with `hasOutsideTransactionDb(ctx)` or take it
300
- * via `requireOutsideTransactionDb(ctx)` (`@cosmicdrift/kumiko-framework/db`). For
300
+ * via `requireOutsideTransactionDb(ctx)` (`@cosmicdrift/kumiko-framework/db`). For atomic
301
+ * multi-statement writes outside the tx use `runInOwnTransaction(ctx.dbOutsideTransaction, fn)`; `fn`
302
+ * must not touch rows the handler's own tx has locked. For
301
303
  * r.systemScope() handlers it is a fail-closed Proxy; use `systemDb.outsideTransaction`.
302
304
  */
303
305
  readonly dbOutsideTransaction: TenantDb | undefined;
304
- /**
305
- * @deprecated Use `runInOwnTransaction(ctx.dbOutsideTransaction, fn)` from
306
- * `@cosmicdrift/kumiko-framework/db`; removed in the next major.
307
- */
308
- readonly outsideTransaction?: <T>(fn: (db: TenantDb) => Promise<T>) => Promise<T>;
309
306
  readonly systemDb?: UncheckedSystemDb;
310
307
  readonly registry: Registry;
311
308
  /** Aktiver SessionUser des Handler-Aufrufs — Convenience-Alias zu
@@ -460,7 +457,7 @@ export type EventPiiSubject = {
460
457
  } | {
461
458
  readonly personal: "self";
462
459
  } | {
463
- /** @deprecated use `{ personal: { of: "<ownerField>" } }` instead. */
460
+ /** @deprecated use `{ personal: { of: "<ownerField>" } }` instead. Removed in 0.390.0. */
464
461
  readonly subjectField: string;
465
462
  };
466
463
  export type EventPiiFields = Readonly<Record<string, EventPiiSubject>>;
package/dist/screen.d.ts CHANGED
@@ -63,8 +63,9 @@ export interface FieldFormatRegistry {
63
63
  image: {
64
64
  readonly variant?: string;
65
65
  };
66
- /** List cell: FileRef id (or id array) as a download link with the file name.
67
- * Outside list cells the raw value is shown. */
66
+ /** FileRef id (or id array) as a download link with the file name. On a
67
+ * read-only detail field it renders a file list with download links and an
68
+ * inline preview for PDFs; elsewhere the raw value is shown. */
68
69
  file: object;
69
70
  }
70
71
  export type FormatSpec = {
@@ -924,6 +925,15 @@ export type DashboardTextBlock = {
924
925
  } | {
925
926
  readonly kind: "hint";
926
927
  readonly text: string;
928
+ } | {
929
+ readonly kind: "link";
930
+ /** Link label (i18n key). */
931
+ readonly text: string;
932
+ /** Same-feature short id or cross-feature QN `<feature>:screen:<id>`. */
933
+ readonly screen: string;
934
+ /** Show the link only to users holding one of these roles. Display
935
+ * gate only: the target screen's own `access` stays the enforcement. */
936
+ readonly roles?: readonly string[];
927
937
  };
928
938
  export type DashboardTextPanel = DashboardPanelGate & {
929
939
  readonly kind: "text";
@@ -1522,6 +1532,21 @@ export type EntityEditActionPlacement = "inline" | "menu";
1522
1532
  export type EntityEditAction = RowAction & {
1523
1533
  readonly placement?: EntityEditActionPlacement;
1524
1534
  };
1535
+ /** A form field computed from other fields of the same form. `listSum` adds one
1536
+ * numeric cell over all rows of an embedded list field; its `whenEmpty`
1537
+ * fallback applies while the list has no rows (it must not be a `listSum`). */
1538
+ export type FormFieldDerivation = {
1539
+ readonly op: "sum" | "subtract" | "multiply" | "percent";
1540
+ readonly from: readonly string[];
1541
+ } | {
1542
+ readonly op: "listSum";
1543
+ readonly list: string;
1544
+ readonly cell: string;
1545
+ readonly whenEmpty?: FormFieldDerivationWithoutList;
1546
+ };
1547
+ export type FormFieldDerivationWithoutList = Extract<FormFieldDerivation, {
1548
+ from: unknown;
1549
+ }>;
1525
1550
  export type ActionFormScreenDefinition = {
1526
1551
  readonly id: string;
1527
1552
  readonly type: "actionForm";
@@ -1560,6 +1585,13 @@ export type ActionFormScreenDefinition = {
1560
1585
  * A `money` field here must name its own currency source: this screen
1561
1586
  * has no entity whose `defaultCurrency` it could inherit (fw#2839). */
1562
1587
  readonly fields: Readonly<Record<string, FormFieldDefinition>>;
1588
+ /** Fields computed from other fields, shown read-only and recomputed on every
1589
+ * change. A `listSum` over an empty list without `whenEmpty` leaves the field
1590
+ * a normal input, and then the client value counts. Otherwise the client value
1591
+ * is never trusted: the handler must wrap its schema with
1592
+ * `withFormDerivations(schema, screen)`, which the boot validator enforces.
1593
+ * A field read only as `whenEmpty` operand is read-only while every such list has rows. */
1594
+ readonly derive?: Readonly<Record<string, FormFieldDerivation>>;
1563
1595
  /** Layout analog zu EntityEditScreen: sections mit fields aus dem
1564
1596
  * fields-Map oben. */
1565
1597
  readonly layout: EditLayout;
@@ -1680,6 +1712,11 @@ export type ActionFormLoad = {
1680
1712
  readonly query: string;
1681
1713
  /** Payload key carrying the record id (default "id"). */
1682
1714
  readonly idParam?: string;
1715
+ /** The query picks the row from the caller's tenant/session context, so the
1716
+ * form loads without a record id and the query is called WITHOUT `idParam`
1717
+ * (same semantics as `ProjectionDetailScreenDefinition.singleton`). Boot
1718
+ * rejects declaring `idParam` alongside it. */
1719
+ readonly singleton?: boolean;
1683
1720
  };
1684
1721
  /** One key figure of the success box, read from the handler's success payload. */
1685
1722
  export type ActionFormSuccessFact = {
@@ -46,6 +46,13 @@ export type TenantDb = {
46
46
  selectMany<T = Record<string, unknown>>(table: SchemaTable | EntityTableMeta, where?: WhereObject, options?: SelectOptions): Promise<readonly T[]>;
47
47
  fetchOne<T = Record<string, unknown>>(table: SchemaTable | EntityTableMeta, where: WhereObject): Promise<T | undefined>;
48
48
  count(table: SchemaTable | EntityTableMeta, where?: WhereObject): Promise<number>;
49
+ /**
50
+ * Transaction-scoped advisory lock keyed on (namespace, this handle's tenantId + key); released at
51
+ * commit or rollback. Keys of different tenants never contend. Only serialises inside a transaction.
52
+ */
53
+ advisoryXactLock(namespace: number, key: string): Promise<void>;
54
+ /** Postgres `now()`; inside a transaction this is the transaction start. */
55
+ databaseNow(): Promise<Date>;
49
56
  aggregate(table: SchemaTable | EntityTableMeta, spec: AggregateSpec, where?: WhereObject): Promise<readonly AggregateRow[]>;
50
57
  insertOne<T = Record<string, unknown>>(table: WritableTable, values: Record<string, unknown>): Promise<T | undefined>;
51
58
  updateMany<T = Record<string, unknown>>(table: WritableTable, set: Record<string, unknown>, where: WhereObject): Promise<readonly T[]>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmicdrift/kumiko-types",
3
- "version": "0.377.0",
3
+ "version": "0.379.0",
4
4
  "description": "Framework-Type-Definitions für Kumiko — FeatureDefinition, BootCheck-Types und die reinen Engine-Types. Erlaubt Downstream-Konsumenten, gegen die Type-Contracts zu bauen, ohne das ganze Framework-Package zu importieren. Enthaelt keine identitaets-sensitiven Runtime-Werte mehr (Error-Klassen leben seit #1629 in kumiko-framework, Brand-Symbole nutzen Symbol.for) und ist deshalb eine plain dependency, keine peerDependency.",
5
5
  "license": "BUSL-1.1",
6
6
  "author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
package/src/changes.json CHANGED
@@ -1,4 +1,11 @@
1
1
  [
2
+ {
3
+ "version": "0.379.0",
4
+ "type": "breaking",
5
+ "title": "HandlerContext.outsideTransaction removed",
6
+ "detail": "The deprecated outsideTransaction field no longer exists on HandlerContext. ctx.dbOutsideTransaction together with runInOwnTransaction replaces it.",
7
+ "migration": "Replace ctx.outsideTransaction(fn) with runInOwnTransaction(requireOutsideTransactionDb(ctx), fn); both are exported from @cosmicdrift/kumiko-framework/db and fn keeps its (db) => Promise signature."
8
+ },
2
9
  {
3
10
  "version": "0.377.0",
4
11
  "type": "improvement",