@cosmicdrift/kumiko-types 0.361.0 → 0.363.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
@@ -183,14 +183,64 @@ export type NotificationRecipientFn = (result: import("./hooks.js").SaveContext)
183
183
  } | null;
184
184
  export type NotificationDataFn = (result: import("./hooks.js").SaveContext) => Record<string, unknown>;
185
185
  export type NotificationTemplateFn = (data: Record<string, unknown>) => Record<string, unknown>;
186
+ type TemplateVariableCommon = {
187
+ readonly label?: string;
188
+ readonly required?: boolean;
189
+ };
190
+ export type TemplateScalarVariableDef = (TemplateVariableCommon & {
191
+ readonly type: "text";
192
+ readonly example?: string;
193
+ }) | (TemplateVariableCommon & {
194
+ readonly type: "link";
195
+ readonly example?: string;
196
+ }) | (TemplateVariableCommon & {
197
+ readonly type: "money";
198
+ readonly example?: number | {
199
+ readonly amount: number;
200
+ readonly currency: string;
201
+ };
202
+ }) | (TemplateVariableCommon & {
203
+ readonly type: "date";
204
+ readonly example?: string;
205
+ });
206
+ export type TemplateListVariableDef = TemplateVariableCommon & {
207
+ readonly type: "list";
208
+ readonly item: Readonly<Record<string, TemplateScalarVariableDef>>;
209
+ readonly example?: readonly Readonly<Record<string, unknown>>[];
210
+ };
211
+ export type TemplateVariableDef = TemplateScalarVariableDef | TemplateListVariableDef;
212
+ export type TemplateVariables = Readonly<Record<string, TemplateVariableDef>>;
213
+ export type NotificationTemplateMeta = {
214
+ readonly subject: string;
215
+ readonly previewText?: string;
216
+ readonly layoutSlug?: string;
217
+ readonly category?: "transactional" | "marketing";
218
+ readonly sender?: string;
219
+ };
220
+ export type NotificationTemplateBody = {
221
+ readonly body: string;
222
+ };
223
+ export type NotificationLocalizedTemplate = Readonly<Record<string, {
224
+ readonly body: string;
225
+ readonly meta: NotificationTemplateMeta;
226
+ }>>;
227
+ export type NotificationRecordMapping = {
228
+ readonly entity: string;
229
+ readonly map: Readonly<Record<string, string>>;
230
+ };
186
231
  export type NotificationDefinition = {
187
232
  readonly name: string;
188
- readonly trigger: {
233
+ readonly trigger?: {
189
234
  readonly on: string;
190
235
  };
191
- readonly recipient: NotificationRecipientFn;
192
- readonly data: NotificationDataFn;
236
+ readonly recipient?: NotificationRecipientFn;
237
+ readonly data?: NotificationDataFn;
193
238
  readonly templates: Readonly<Record<string, NotificationTemplateFn>> | undefined;
239
+ readonly variables?: TemplateVariables;
240
+ readonly record?: NotificationRecordMapping;
241
+ readonly template?: Readonly<Record<string, NotificationTemplateBody>>;
242
+ readonly meta?: Readonly<Record<string, NotificationTemplateMeta>>;
243
+ readonly localizedTemplate?: () => NotificationLocalizedTemplate;
194
244
  };
195
245
  export type PluralForms = {
196
246
  readonly zero?: string;
@@ -259,3 +309,4 @@ export type CreateUserSeedOptions = {
259
309
  readonly tenantId: string;
260
310
  readonly userId: string;
261
311
  };
312
+ export {};
package/dist/feature.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type * as z from "zod";
2
2
  import type { ZodType } from "zod";
3
- import type { ConfigKeyDefinition, ConfigKeyHandle, ConfigKeyType, ConfigSeedDef, ExtensionSelectorDef, ExtensionSelectorPanel, JobDefinition, JobHandlerFn, NotificationDataFn, NotificationDefinition, NotificationRecipientFn, NotificationTemplateFn, ReferenceDataDef, RegistrarExtensionDef, RegistrarExtensionRegistration, TranslationKeys, TranslationsDef } from "./config.js";
3
+ import type { ConfigKeyDefinition, ConfigKeyHandle, ConfigKeyType, ConfigSeedDef, ExtensionSelectorDef, ExtensionSelectorPanel, JobDefinition, JobHandlerFn, NotificationDataFn, NotificationDefinition, NotificationLocalizedTemplate, NotificationRecipientFn, NotificationRecordMapping, NotificationTemplateBody, NotificationTemplateFn, NotificationTemplateMeta, ReferenceDataDef, RegistrarExtensionDef, RegistrarExtensionRegistration, TemplateVariables, TranslationKeys, TranslationsDef } from "./config.js";
4
4
  import type { QueryHandlerDefinition, StreamHandlerDefinition, WriteHandlerDefinition } from "./define-handler.js";
5
5
  import type { RegisterEntityCrudOptions } from "./entity-handlers.js";
6
6
  import type { EntityTableMeta } from "./entity-table-meta-types.js";
@@ -296,21 +296,31 @@ export type FeatureRegistrar<TFeature extends string = string> = {
296
296
  job(name: string, options: Omit<JobDefinition, "name" | "handler">, handler: JobHandlerFn): void;
297
297
  job(definition: JobDefinition): void;
298
298
  notification(name: string, definition: {
299
- readonly trigger: {
299
+ readonly trigger?: {
300
300
  readonly on: NameOrRef;
301
301
  };
302
- readonly recipient: NotificationRecipientFn;
303
- readonly data: NotificationDataFn;
302
+ readonly recipient?: NotificationRecipientFn;
303
+ readonly data?: NotificationDataFn;
304
304
  readonly templates?: Readonly<Record<string, NotificationTemplateFn>>;
305
+ readonly variables?: TemplateVariables;
306
+ readonly record?: NotificationRecordMapping;
307
+ readonly template?: Readonly<Record<string, NotificationTemplateBody>>;
308
+ readonly meta?: Readonly<Record<string, NotificationTemplateMeta>>;
309
+ readonly localizedTemplate?: () => NotificationLocalizedTemplate;
305
310
  }): void;
306
311
  notification(definition: {
307
312
  readonly name: string;
308
- readonly trigger: {
313
+ readonly trigger?: {
309
314
  readonly on: NameOrRef;
310
315
  };
311
- readonly recipient: NotificationRecipientFn;
312
- readonly data: NotificationDataFn;
316
+ readonly recipient?: NotificationRecipientFn;
317
+ readonly data?: NotificationDataFn;
313
318
  readonly templates?: Readonly<Record<string, NotificationTemplateFn>>;
319
+ readonly variables?: TemplateVariables;
320
+ readonly record?: NotificationRecordMapping;
321
+ readonly template?: Readonly<Record<string, NotificationTemplateBody>>;
322
+ readonly meta?: Readonly<Record<string, NotificationTemplateMeta>>;
323
+ readonly localizedTemplate?: () => NotificationLocalizedTemplate;
314
324
  }): void;
315
325
  translations(def: TranslationsDef): void;
316
326
  defineEvent<const TInner extends string, TPayload>(name: TInner, schema: ZodType<TPayload>, options: {
@@ -157,16 +157,26 @@ export type NotifyDelivery = {
157
157
  readonly confirmed?: false;
158
158
  readonly deliveryAttemptId?: string;
159
159
  };
160
- export type NotifyResult = {
160
+ export type NotifyDispatched = {
161
+ readonly kind: "dispatched";
161
162
  readonly deliveries: readonly NotifyDelivery[];
162
163
  };
163
- export type NotifyFn = (notificationType: string, options: NotifyOptions) => Promise<NotifyResult>;
164
+ export type NotifyDeferred = {
165
+ readonly kind: "deferred";
166
+ };
167
+ export type NotifyResult = NotifyDispatched | NotifyDeferred;
168
+ export type NotifyFn = {
169
+ (notificationType: string, options: NotifyOptions & {
170
+ readonly immediate: true;
171
+ }): Promise<NotifyDispatched>;
172
+ (notificationType: string, options: NotifyOptions): Promise<NotifyResult>;
173
+ };
164
174
  export type NotifyJobDispatcher = {
165
175
  dispatch(jobName: string, payload: Record<string, unknown>, meta?: {
166
176
  readonly priority?: number;
167
177
  }): Promise<unknown>;
168
178
  };
169
- export type NotifyFactory = (user: SessionUser, tenantId: TenantId, jobDispatcher?: NotifyJobDispatcher) => NotifyFn;
179
+ export type NotifyFactory = (user: SessionUser, tenantId: TenantId, jobDispatcher?: NotifyJobDispatcher, deliveryDb?: DbConnection, fileProviderResolver?: FileProviderResolver) => NotifyFn;
170
180
  export type EscapeHatchKind = "unsafe-raw" | "acknowledge-cross-tenant" | "global-write" | "identity-switch" | "unsafe-all-tenants" | "cross-tenant-read";
171
181
  export type EscapeHatchTarget = {
172
182
  readonly id: string;
@@ -221,6 +231,7 @@ type SharedContextFields = {
221
231
  readonly entityCache?: EntityCache;
222
232
  readonly notify?: NotifyFn;
223
233
  readonly _notifyFactory?: NotifyFactory;
234
+ readonly _notifyInTransactionFactory?: (user: SessionUser, tenantId: TenantId) => NotifyFn;
224
235
  readonly _escapeHatchAuditSink?: EscapeHatchAuditSink;
225
236
  readonly secrets?: import("./secrets-types.js").SecretsContext;
226
237
  readonly masterKeyProvider?: import("./secrets-types.js").MasterKeyProvider;
@@ -34,7 +34,7 @@ export function subjectIdFromKey(key) {
34
34
  if (key.startsWith("user:"))
35
35
  return { kind: "user", userId: key.slice("user:".length) };
36
36
  if (key.startsWith("tenant:")) {
37
- return { kind: "tenant", tenantId: key.slice("tenant:".length) }; // @cast-boundary parse of a key this module minted
37
+ return { kind: "tenant", tenantId: key.slice("tenant:".length) };
38
38
  }
39
39
  if (key.startsWith("record:")) {
40
40
  const rest = key.slice("record:".length);
package/dist/nav.d.ts CHANGED
@@ -18,7 +18,7 @@ export type NavDefinition = {
18
18
  readonly workspaces?: readonly string[];
19
19
  };
20
20
  /** Client editor format for r.contentCollection() — not template body storage formats. */
21
- export type ContentEditorFormat = "plain" | "rich" | "markdown";
21
+ export type ContentEditorFormat = "plain" | "rich" | "markdown" | "document";
22
22
  export type ContentCollectionDefinition = {
23
23
  readonly id: string;
24
24
  readonly kind: string;
package/dist/screen.d.ts CHANGED
@@ -411,6 +411,8 @@ export type EntityListScreenDefinition = {
411
411
  readonly createScreen?: string;
412
412
  /** Set by the role projection when `createScreen` is not reachable for the role: the renderer then shows no create button instead of falling back to the entity's edit screen. Not for app authors. */
413
413
  readonly createUnavailable?: boolean;
414
+ /** `false` hides this list's "+ New" button (and the empty-state create CTA) while the entity's edit screen keeps its create branch for other entry points, e.g. a prefilled action. Default `true`. */
415
+ readonly allowCreate?: boolean;
414
416
  readonly columns: readonly ListColumnSpec[];
415
417
  readonly rowRenderer?: PlatformComponent;
416
418
  readonly cardRenderer?: PlatformComponent;
@@ -732,7 +734,7 @@ export type DashboardStatPanel = DashboardPanelQueryOptions & DashboardPanelGate
732
734
  /** Formats a numeric value as currency (minor units); ignored for string values. The sparkline is not formatted. */
733
735
  readonly valueFormat?: DashboardValueFormat;
734
736
  /** Fixed tone when `toneField` is unset or yields none; not applied while the value is 0. */
735
- readonly tone?: "default" | "positive" | "warn" | "negative";
737
+ readonly tone?: "default" | "positive" | "ok" | "warn" | "negative";
736
738
  /** Record field holding `{ atMs, value | null }[]` (MetricResult.points),
737
739
  * drawn as a sparkline next to the value. */
738
740
  readonly sparklineField?: string;
@@ -0,0 +1,8 @@
1
+ /** Non-null object that is not an array — shared guard for deep-merge and AST extractors. */
2
+ export declare function isPlainObject(value: unknown): value is Record<string, unknown>;
3
+ /** Membership test that narrows `candidate` to the element union of a const tuple. */
4
+ export declare function isOneOf<const T extends readonly unknown[]>(values: T, candidate: unknown): candidate is T[number];
5
+ /** Reads a string `code` (e.g. Node `ErrnoException`, Postgres SQLSTATE) off an unknown thrown value. */
6
+ export declare function errorCodeOf(error: unknown): string | undefined;
7
+ /** Reads one property off an unknown value (object or function); undefined for primitives, null and absent keys. */
8
+ export declare function propertyOf(value: unknown, key: PropertyKey): unknown;
@@ -0,0 +1,21 @@
1
+ /** Non-null object that is not an array — shared guard for deep-merge and AST extractors. */
2
+ export function isPlainObject(value) {
3
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4
+ }
5
+ /** Membership test that narrows `candidate` to the element union of a const tuple. */
6
+ export function isOneOf(values, candidate) {
7
+ return values.some((value) => value === candidate);
8
+ }
9
+ /** Reads a string `code` (e.g. Node `ErrnoException`, Postgres SQLSTATE) off an unknown thrown value. */
10
+ export function errorCodeOf(error) {
11
+ if (typeof error !== "object" || error === null || !("code" in error))
12
+ return undefined;
13
+ return typeof error.code === "string" ? error.code : undefined;
14
+ }
15
+ /** Reads one property off an unknown value (object or function); undefined for primitives, null and absent keys. */
16
+ export function propertyOf(value, key) {
17
+ if ((typeof value !== "object" && typeof value !== "function") || value === null) {
18
+ return undefined;
19
+ }
20
+ return Reflect.get(value, key);
21
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmicdrift/kumiko-types",
3
- "version": "0.361.0",
3
+ "version": "0.363.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>",
@@ -26,6 +26,10 @@
26
26
  "types": "./dist/identifiers.d.ts",
27
27
  "default": "./dist/identifiers.js"
28
28
  },
29
+ "./type-guards": {
30
+ "types": "./dist/type-guards.d.ts",
31
+ "default": "./dist/type-guards.js"
32
+ },
29
33
  "./session-cookies": {
30
34
  "types": "./dist/session-cookies.d.ts",
31
35
  "default": "./dist/session-cookies.js"
@@ -297,6 +301,10 @@
297
301
  "types": "./dist/identifiers.d.ts",
298
302
  "default": "./dist/identifiers.js"
299
303
  },
304
+ "./type-guards": {
305
+ "types": "./dist/type-guards.d.ts",
306
+ "default": "./dist/type-guards.js"
307
+ },
300
308
  "./session-cookies": {
301
309
  "types": "./dist/session-cookies.d.ts",
302
310
  "default": "./dist/session-cookies.js"
package/src/changes.json CHANGED
@@ -1,4 +1,16 @@
1
1
  [
2
+ {
3
+ "version": "0.362.0",
4
+ "type": "improvement",
5
+ "title": "EntityListScreenDefinition.allowCreate",
6
+ "detail": "allowCreate false hides the list's create button and empty-state create action; the entity's edit screen keeps its create branch."
7
+ },
8
+ {
9
+ "version": "0.362.0",
10
+ "type": "improvement",
11
+ "title": "Stat tone \"ok\"",
12
+ "detail": "DashboardStatPanel.tone accepts \"ok\" for a status-green value."
13
+ },
2
14
  {
3
15
  "version": "0.361.0",
4
16
  "type": "improvement",