@cosmicdrift/kumiko-types 0.362.0 → 0.364.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/cache-sync-types.d.ts +4 -1
- package/dist/config.d.ts +58 -4
- package/dist/define-handler.d.ts +9 -5
- package/dist/feature.d.ts +19 -8
- package/dist/fields.d.ts +2 -1
- package/dist/file-handle-types.d.ts +3 -0
- package/dist/handlers.d.ts +46 -3
- package/dist/hooks.d.ts +1 -0
- package/dist/kms-adapter-types.js +1 -1
- package/dist/nav.d.ts +1 -1
- package/dist/screen.d.ts +7 -3
- package/dist/secrets-types.d.ts +2 -0
- package/dist/type-guards.d.ts +8 -0
- package/dist/type-guards.js +21 -0
- package/dist/write-error-info-types.d.ts +1 -0
- package/package.json +9 -1
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
export type CacheSyncPublishOptions = {
|
|
2
|
+
readonly remoteOnly?: boolean;
|
|
3
|
+
};
|
|
1
4
|
export type CacheSyncBus = {
|
|
2
|
-
publish(topic: string, message: unknown): void;
|
|
5
|
+
publish(topic: string, message: unknown, options?: CacheSyncPublishOptions): void;
|
|
3
6
|
subscribe(topic: string, listener: (message: unknown) => void): () => void;
|
|
4
7
|
onResync(listener: () => void): () => void;
|
|
5
8
|
};
|
package/dist/config.d.ts
CHANGED
|
@@ -30,7 +30,7 @@ export type ConfigValidateContext = {
|
|
|
30
30
|
readonly scope: ConfigScope;
|
|
31
31
|
readonly tenantId: TenantId;
|
|
32
32
|
readonly userId: string | null;
|
|
33
|
-
readonly db:
|
|
33
|
+
readonly db: TenantDb;
|
|
34
34
|
};
|
|
35
35
|
export type ConfigValidateFn<T extends ConfigKeyType = ConfigKeyType> = (value: ConfigValue<T>, ctx: ConfigValidateContext) => Promise<void>;
|
|
36
36
|
export type ConfigBacking = "config" | "secrets";
|
|
@@ -183,14 +183,67 @@ 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: "richText";
|
|
198
|
+
readonly example?: string;
|
|
199
|
+
}) | (TemplateVariableCommon & {
|
|
200
|
+
readonly type: "money";
|
|
201
|
+
readonly example?: number | {
|
|
202
|
+
readonly amount: number;
|
|
203
|
+
readonly currency: string;
|
|
204
|
+
};
|
|
205
|
+
}) | (TemplateVariableCommon & {
|
|
206
|
+
readonly type: "date";
|
|
207
|
+
readonly example?: string;
|
|
208
|
+
});
|
|
209
|
+
export type TemplateListVariableDef = TemplateVariableCommon & {
|
|
210
|
+
readonly type: "list";
|
|
211
|
+
readonly item: Readonly<Record<string, TemplateScalarVariableDef>>;
|
|
212
|
+
readonly example?: readonly Readonly<Record<string, unknown>>[];
|
|
213
|
+
};
|
|
214
|
+
export type TemplateVariableDef = TemplateScalarVariableDef | TemplateListVariableDef;
|
|
215
|
+
export type TemplateVariables = Readonly<Record<string, TemplateVariableDef>>;
|
|
216
|
+
export type NotificationTemplateMeta = {
|
|
217
|
+
readonly subject: string;
|
|
218
|
+
readonly previewText?: string;
|
|
219
|
+
readonly layoutSlug?: string;
|
|
220
|
+
readonly category?: "transactional" | "marketing";
|
|
221
|
+
readonly sender?: string;
|
|
222
|
+
};
|
|
223
|
+
export type NotificationTemplateBody = {
|
|
224
|
+
readonly body: string;
|
|
225
|
+
};
|
|
226
|
+
export type NotificationLocalizedTemplate = Readonly<Record<string, {
|
|
227
|
+
readonly body: string;
|
|
228
|
+
readonly meta: NotificationTemplateMeta;
|
|
229
|
+
}>>;
|
|
230
|
+
export type NotificationRecordMapping = {
|
|
231
|
+
readonly entity: string;
|
|
232
|
+
readonly map: Readonly<Record<string, string>>;
|
|
233
|
+
};
|
|
186
234
|
export type NotificationDefinition = {
|
|
187
235
|
readonly name: string;
|
|
188
|
-
readonly trigger
|
|
236
|
+
readonly trigger?: {
|
|
189
237
|
readonly on: string;
|
|
190
238
|
};
|
|
191
|
-
readonly recipient
|
|
192
|
-
readonly data
|
|
239
|
+
readonly recipient?: NotificationRecipientFn;
|
|
240
|
+
readonly data?: NotificationDataFn;
|
|
193
241
|
readonly templates: Readonly<Record<string, NotificationTemplateFn>> | undefined;
|
|
242
|
+
readonly variables?: TemplateVariables;
|
|
243
|
+
readonly record?: NotificationRecordMapping;
|
|
244
|
+
readonly template?: Readonly<Record<string, NotificationTemplateBody>>;
|
|
245
|
+
readonly meta?: Readonly<Record<string, NotificationTemplateMeta>>;
|
|
246
|
+
readonly localizedTemplate?: () => NotificationLocalizedTemplate;
|
|
194
247
|
};
|
|
195
248
|
export type PluralForms = {
|
|
196
249
|
readonly zero?: string;
|
|
@@ -259,3 +312,4 @@ export type CreateUserSeedOptions = {
|
|
|
259
312
|
readonly tenantId: string;
|
|
260
313
|
readonly userId: string;
|
|
261
314
|
};
|
|
315
|
+
export {};
|
package/dist/define-handler.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type * as z from "zod";
|
|
2
2
|
import type { ZodType } from "zod";
|
|
3
3
|
import type { KumikoEventTypeMap } from "./event-type-map.js";
|
|
4
|
-
import type { AccessRule, AgentHandlerHints, EscapeHatchDeclaration, HandlerContext, PayloadRateLimitOption, PreTransactionReservation, QueryEvent, RateLimitDeclaration,
|
|
4
|
+
import type { AccessRule, AgentHandlerHints, BeforeTransactionPhase, EscapeHatchDeclaration, HandlerContext, PayloadRateLimitOption, PreparedWriteEvent, PreTransactionReservation, QueryEvent, RateLimitDeclaration, WriteHandlerTransactionMode, WriteResult } from "./handlers.js";
|
|
5
5
|
import type { PipelineDef } from "./step.js";
|
|
6
|
-
export type WriteHandlerDefinition<TName extends string = string, TSchema extends ZodType = ZodType, TData = unknown, TMap extends object = KumikoEventTypeMap> = {
|
|
6
|
+
export type WriteHandlerDefinition<TName extends string = string, TSchema extends ZodType = ZodType, TData = unknown, TMap extends object = KumikoEventTypeMap, TPrepared = undefined> = {
|
|
7
7
|
readonly name: TName;
|
|
8
8
|
readonly schema: TSchema;
|
|
9
9
|
readonly access: AccessRule;
|
|
@@ -16,11 +16,13 @@ export type WriteHandlerDefinition<TName extends string = string, TSchema extend
|
|
|
16
16
|
readonly additionalRateLimits?: readonly PayloadRateLimitOption[];
|
|
17
17
|
readonly escapeHatch?: EscapeHatchDeclaration;
|
|
18
18
|
readonly reserveBeforeTransaction?: PreTransactionReservation;
|
|
19
|
+
readonly beforeTransaction?: BeforeTransactionPhase<z.infer<TSchema>, TPrepared>;
|
|
19
20
|
readonly tenantlessAnonymous?: boolean;
|
|
20
|
-
readonly
|
|
21
|
+
readonly transaction?: WriteHandlerTransactionMode;
|
|
22
|
+
readonly handler: (event: PreparedWriteEvent<z.infer<TSchema>, TPrepared>, context: HandlerContext<TMap>) => Promise<WriteResult<TData>>;
|
|
21
23
|
readonly perform?: PipelineDef<z.infer<TSchema>, TData>;
|
|
22
24
|
};
|
|
23
|
-
export type WriteHandlerInput<TName extends string = string, TSchema extends ZodType = ZodType, TData = unknown, TMap extends object = KumikoEventTypeMap> = {
|
|
25
|
+
export type WriteHandlerInput<TName extends string = string, TSchema extends ZodType = ZodType, TData = unknown, TMap extends object = KumikoEventTypeMap, TPrepared = undefined> = {
|
|
24
26
|
readonly name: TName;
|
|
25
27
|
readonly schema: TSchema;
|
|
26
28
|
readonly access: AccessRule;
|
|
@@ -31,9 +33,11 @@ export type WriteHandlerInput<TName extends string = string, TSchema extends Zod
|
|
|
31
33
|
readonly additionalRateLimits?: readonly PayloadRateLimitOption[];
|
|
32
34
|
readonly escapeHatch?: EscapeHatchDeclaration;
|
|
33
35
|
readonly reserveBeforeTransaction?: PreTransactionReservation;
|
|
36
|
+
readonly beforeTransaction?: BeforeTransactionPhase<z.infer<TSchema>, TPrepared>;
|
|
34
37
|
readonly tenantlessAnonymous?: boolean;
|
|
38
|
+
readonly transaction?: WriteHandlerTransactionMode;
|
|
35
39
|
} & ({
|
|
36
|
-
readonly handler: (event:
|
|
40
|
+
readonly handler: (event: PreparedWriteEvent<z.infer<TSchema>, TPrepared>, context: HandlerContext<TMap>) => Promise<WriteResult<TData>>;
|
|
37
41
|
readonly perform?: never;
|
|
38
42
|
} | {
|
|
39
43
|
readonly perform: PipelineDef<z.infer<TSchema>, TData>;
|
package/dist/feature.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
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";
|
|
7
|
+
import type { KumikoEventTypeMap } from "./event-type-map.js";
|
|
7
8
|
import type { ExtensionOptionsArgs, ExtensionOptionsFor } from "./extension-options-map.js";
|
|
8
9
|
import type { EntityDefinition } from "./fields.js";
|
|
9
10
|
import type { AccessRule, AgentHandlerHints, AuthClaimsFn, AuthClaimsHookDef, ClaimKeyDefinition, ClaimKeyHandle, ClaimKeyType, DeclarativeEventMigration, EntityRef, EscapeHatchDeclaration, EventDef, EventMigrationDef, EventPiiStance, EventUpcastFn, HandlerRef, NameOrRef, PayloadRateLimitOption, QualifiedEventName, QueryHandlerDef, QueryHandlerFn, RateLimitDeclaration, StreamHandlerDef, StreamHandlerFn, WriteHandlerDef, WriteHandlerFn } from "./handlers.js";
|
|
@@ -234,7 +235,7 @@ export type FeatureRegistrar<TFeature extends string = string> = {
|
|
|
234
235
|
readonly name: string;
|
|
235
236
|
} & EntityDefinition): EntityRef;
|
|
236
237
|
crud(entityName: string, entity: EntityDefinition, options?: RegisterEntityCrudOptions): void;
|
|
237
|
-
writeHandler<TName extends string, TSchema extends ZodType>(def: WriteHandlerDefinition<TName, TSchema>): HandlerRef;
|
|
238
|
+
writeHandler<TName extends string, TSchema extends ZodType, TPrepared = undefined>(def: WriteHandlerDefinition<TName, TSchema, unknown, KumikoEventTypeMap, TPrepared>): HandlerRef;
|
|
238
239
|
writeHandler<TSchema extends ZodType>(name: string, schema: TSchema, handler: WriteHandlerFn<z.infer<TSchema>>, options: {
|
|
239
240
|
access: AccessRule;
|
|
240
241
|
rateLimit?: RateLimitDeclaration;
|
|
@@ -296,21 +297,31 @@ export type FeatureRegistrar<TFeature extends string = string> = {
|
|
|
296
297
|
job(name: string, options: Omit<JobDefinition, "name" | "handler">, handler: JobHandlerFn): void;
|
|
297
298
|
job(definition: JobDefinition): void;
|
|
298
299
|
notification(name: string, definition: {
|
|
299
|
-
readonly trigger
|
|
300
|
+
readonly trigger?: {
|
|
300
301
|
readonly on: NameOrRef;
|
|
301
302
|
};
|
|
302
|
-
readonly recipient
|
|
303
|
-
readonly data
|
|
303
|
+
readonly recipient?: NotificationRecipientFn;
|
|
304
|
+
readonly data?: NotificationDataFn;
|
|
304
305
|
readonly templates?: Readonly<Record<string, NotificationTemplateFn>>;
|
|
306
|
+
readonly variables?: TemplateVariables;
|
|
307
|
+
readonly record?: NotificationRecordMapping;
|
|
308
|
+
readonly template?: Readonly<Record<string, NotificationTemplateBody>>;
|
|
309
|
+
readonly meta?: Readonly<Record<string, NotificationTemplateMeta>>;
|
|
310
|
+
readonly localizedTemplate?: () => NotificationLocalizedTemplate;
|
|
305
311
|
}): void;
|
|
306
312
|
notification(definition: {
|
|
307
313
|
readonly name: string;
|
|
308
|
-
readonly trigger
|
|
314
|
+
readonly trigger?: {
|
|
309
315
|
readonly on: NameOrRef;
|
|
310
316
|
};
|
|
311
|
-
readonly recipient
|
|
312
|
-
readonly data
|
|
317
|
+
readonly recipient?: NotificationRecipientFn;
|
|
318
|
+
readonly data?: NotificationDataFn;
|
|
313
319
|
readonly templates?: Readonly<Record<string, NotificationTemplateFn>>;
|
|
320
|
+
readonly variables?: TemplateVariables;
|
|
321
|
+
readonly record?: NotificationRecordMapping;
|
|
322
|
+
readonly template?: Readonly<Record<string, NotificationTemplateBody>>;
|
|
323
|
+
readonly meta?: Readonly<Record<string, NotificationTemplateMeta>>;
|
|
324
|
+
readonly localizedTemplate?: () => NotificationLocalizedTemplate;
|
|
314
325
|
}): void;
|
|
315
326
|
translations(def: TranslationsDef): void;
|
|
316
327
|
defineEvent<const TInner extends string, TPayload>(name: TInner, schema: ZodType<TPayload>, options: {
|
package/dist/fields.d.ts
CHANGED
|
@@ -750,7 +750,8 @@ export type EntityDefinition<F extends FieldsMap = FieldsMap, T extends EntityTe
|
|
|
750
750
|
readonly systemStream?: boolean;
|
|
751
751
|
/** Schema version stamped on every lifecycle event (default 1, integer 1..999). Bump it together with a step in `eventMigrations`. */
|
|
752
752
|
readonly eventVersion?: number;
|
|
753
|
-
/** One step per version, fromVersion → fromVersion+1. Transforms run on row-shaped field records; the record may be partial, touch only keys that are present.
|
|
753
|
+
/** One step per version, fromVersion → fromVersion+1. Transforms run on row-shaped field records; the record may be partial, touch only keys that are present.
|
|
754
|
+
* `pii` and `encrypted` fields arrive as stored ciphertext bound to their field name (AAD): pass them through under the same key, never rename or derive from them, or the value can no longer be decrypted. */
|
|
754
755
|
readonly eventMigrations?: readonly EntityEventMigration[];
|
|
755
756
|
readonly searchWeight?: number;
|
|
756
757
|
readonly defaultCurrency?: string;
|
package/dist/handlers.d.ts
CHANGED
|
@@ -101,6 +101,12 @@ export type WriteEvent<TPayload = unknown> = {
|
|
|
101
101
|
readonly payload: TPayload;
|
|
102
102
|
readonly user: SessionUser;
|
|
103
103
|
};
|
|
104
|
+
/** What a handler sees when its `beforeTransaction` phase ran: the phase's `data` as `prepared`; absent for handlers without the phase. */
|
|
105
|
+
export type PreparedWriteEvent<TPayload = unknown, TPrepared = unknown> = WriteEvent<TPayload> & ([TPrepared] extends [undefined] ? {
|
|
106
|
+
readonly prepared?: undefined;
|
|
107
|
+
} : {
|
|
108
|
+
readonly prepared: TPrepared;
|
|
109
|
+
});
|
|
104
110
|
export type QueryEvent<TPayload = unknown> = {
|
|
105
111
|
readonly type: string;
|
|
106
112
|
readonly payload: TPayload;
|
|
@@ -157,16 +163,26 @@ export type NotifyDelivery = {
|
|
|
157
163
|
readonly confirmed?: false;
|
|
158
164
|
readonly deliveryAttemptId?: string;
|
|
159
165
|
};
|
|
160
|
-
export type
|
|
166
|
+
export type NotifyDispatched = {
|
|
167
|
+
readonly kind: "dispatched";
|
|
161
168
|
readonly deliveries: readonly NotifyDelivery[];
|
|
162
169
|
};
|
|
163
|
-
export type
|
|
170
|
+
export type NotifyDeferred = {
|
|
171
|
+
readonly kind: "deferred";
|
|
172
|
+
};
|
|
173
|
+
export type NotifyResult = NotifyDispatched | NotifyDeferred;
|
|
174
|
+
export type NotifyFn = {
|
|
175
|
+
(notificationType: string, options: NotifyOptions & {
|
|
176
|
+
readonly immediate: true;
|
|
177
|
+
}): Promise<NotifyDispatched>;
|
|
178
|
+
(notificationType: string, options: NotifyOptions): Promise<NotifyResult>;
|
|
179
|
+
};
|
|
164
180
|
export type NotifyJobDispatcher = {
|
|
165
181
|
dispatch(jobName: string, payload: Record<string, unknown>, meta?: {
|
|
166
182
|
readonly priority?: number;
|
|
167
183
|
}): Promise<unknown>;
|
|
168
184
|
};
|
|
169
|
-
export type NotifyFactory = (user: SessionUser, tenantId: TenantId, jobDispatcher?: NotifyJobDispatcher) => NotifyFn;
|
|
185
|
+
export type NotifyFactory = (user: SessionUser, tenantId: TenantId, jobDispatcher?: NotifyJobDispatcher, deliveryDb?: DbConnection, fileProviderResolver?: FileProviderResolver) => NotifyFn;
|
|
170
186
|
export type EscapeHatchKind = "unsafe-raw" | "acknowledge-cross-tenant" | "global-write" | "identity-switch" | "unsafe-all-tenants" | "cross-tenant-read";
|
|
171
187
|
export type EscapeHatchTarget = {
|
|
172
188
|
readonly id: string;
|
|
@@ -221,6 +237,7 @@ type SharedContextFields = {
|
|
|
221
237
|
readonly entityCache?: EntityCache;
|
|
222
238
|
readonly notify?: NotifyFn;
|
|
223
239
|
readonly _notifyFactory?: NotifyFactory;
|
|
240
|
+
readonly _notifyInTransactionFactory?: (user: SessionUser, tenantId: TenantId) => NotifyFn;
|
|
224
241
|
readonly _escapeHatchAuditSink?: EscapeHatchAuditSink;
|
|
225
242
|
readonly secrets?: import("./secrets-types.js").SecretsContext;
|
|
226
243
|
readonly masterKeyProvider?: import("./secrets-types.js").MasterKeyProvider;
|
|
@@ -288,6 +305,11 @@ export type HandlerContext<TMap extends object = KumikoEventTypeMap> = SharedCon
|
|
|
288
305
|
} | null;
|
|
289
306
|
readonly _userId?: string | undefined;
|
|
290
307
|
readonly _handlerType?: string | undefined;
|
|
308
|
+
/** Keyed digest for handler-owned rate-limit keys, so Redis never holds a
|
|
309
|
+
* plaintext or plainly hashed identifier. Scoped to the running handler:
|
|
310
|
+
* the same input yields a different digest per handler and never matches a
|
|
311
|
+
* dispatcher payload-bucket digest. Absent when the app wires no digest key. */
|
|
312
|
+
readonly rateLimitDigest?: (value: string) => string;
|
|
291
313
|
readonly includeDeleted?: boolean;
|
|
292
314
|
readonly runPreSave?: (handlerName: string, changes: Record<string, unknown>, previous: Readonly<Record<string, unknown>>, isNew: boolean) => Promise<Record<string, unknown>>;
|
|
293
315
|
readonly query: (qn: string, payload: unknown) => Promise<unknown>;
|
|
@@ -496,11 +518,13 @@ export type RateLimitOption = {
|
|
|
496
518
|
export type RateLimitPayloadBucket = {
|
|
497
519
|
readonly payloadField: string;
|
|
498
520
|
};
|
|
521
|
+
export type PayloadBucketNormalization = "email";
|
|
499
522
|
export type PayloadRateLimitOption = {
|
|
500
523
|
readonly per: RateLimitPayloadBucket;
|
|
501
524
|
readonly limit: number;
|
|
502
525
|
readonly windowSeconds: number;
|
|
503
526
|
readonly cost?: number;
|
|
527
|
+
readonly normalize?: PayloadBucketNormalization;
|
|
504
528
|
};
|
|
505
529
|
export type RateLimitDisabled = {
|
|
506
530
|
readonly disabled: true;
|
|
@@ -541,6 +565,15 @@ export type ReservationHandle = {
|
|
|
541
565
|
* The returned release (or handle.release) runs when the transaction does not commit (failure
|
|
542
566
|
* result, throw, rollback, failed commit). Throwing a KumikoError rejects the write. */
|
|
543
567
|
export type PreTransactionReservation = (event: WriteEvent, ctx: HandlerContext) => Promise<ReservationRelease | ReservationHandle | undefined>;
|
|
568
|
+
/** Outcome of a write handler's pre-transaction phase. `release` runs when the handler transaction does not commit (failure result, throw, rollback, failed commit with unknown outcome), so it must itself tolerate a commit that actually happened. */
|
|
569
|
+
export type BeforeTransactionResult<TPrepared = unknown> = {
|
|
570
|
+
readonly isSuccess: true;
|
|
571
|
+
readonly data: TPrepared;
|
|
572
|
+
readonly release?: ReservationRelease;
|
|
573
|
+
} | WriteFailure;
|
|
574
|
+
export type BeforeTransactionPhase<TPayload = unknown, TPrepared = unknown> = (event: WriteEvent<TPayload>, ctx: HandlerContext) => Promise<BeforeTransactionResult<TPrepared>>;
|
|
575
|
+
/** `perCommand`: the handler runs without a transaction of its own. */
|
|
576
|
+
export type WriteHandlerTransactionMode = "perCommand";
|
|
544
577
|
export type WriteHandlerDef = {
|
|
545
578
|
readonly name: string;
|
|
546
579
|
readonly schema: ZodType;
|
|
@@ -560,6 +593,16 @@ export type WriteHandlerDef = {
|
|
|
560
593
|
/** Reserves before the handler transaction opens. Reached through a nested ctx.write the
|
|
561
594
|
* reservation cannot run, so the dispatcher rejects it unless the top-level batch reserved it. */
|
|
562
595
|
readonly reserveBeforeTransaction?: PreTransactionReservation;
|
|
596
|
+
/** Runs after all pre-handler gates (and after reserveBeforeTransaction) and before the
|
|
597
|
+
* transaction opens: no transaction and no connection held, for external I/O and reads only.
|
|
598
|
+
* Its `data` reaches the handler as `event.prepared`; a failure result or throw rejects the
|
|
599
|
+
* write before anything is written. A handler with this phase cannot run as a nested ctx.write. */
|
|
600
|
+
readonly beforeTransaction?: BeforeTransactionPhase;
|
|
601
|
+
/** `"perCommand"`: the handler runs without a transaction of its own. Every ctx.write/writeAs it
|
|
602
|
+
* issues runs as its own top-level command with its own transaction and afterCommit hooks;
|
|
603
|
+
* ctx.db writes and event appends throw. It cannot run as a nested write or inside a
|
|
604
|
+
* multi-command batch, and cannot be combined with beforeTransaction/reserveBeforeTransaction. */
|
|
605
|
+
readonly transaction?: WriteHandlerTransactionMode;
|
|
563
606
|
/** Lets an anonymous `POST /api/write` for this handler proceed under
|
|
564
607
|
* SYSTEM_TENANT_ID when the host resolves no tenant. Boot requires
|
|
565
608
|
* `access.roles: ["anonymous"]` and a real `rateLimit`. */
|
package/dist/hooks.d.ts
CHANGED
|
@@ -23,6 +23,7 @@ export type DeleteContext = {
|
|
|
23
23
|
readonly data: Readonly<Record<string, unknown>>;
|
|
24
24
|
readonly entityName?: string | undefined;
|
|
25
25
|
readonly event?: StoredEvent | undefined;
|
|
26
|
+
readonly lockGuardBypassed?: boolean | undefined;
|
|
26
27
|
};
|
|
27
28
|
export type LifecycleResult = SaveContext | DeleteContext;
|
|
28
29
|
export type PreSaveHookFn = (changes: Record<string, unknown>, context: AppContext & {
|
|
@@ -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) };
|
|
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
|
@@ -554,8 +554,10 @@ export type ProjectionListScreenDefinition = {
|
|
|
554
554
|
* boot-validator only checks structure (`op:"in"` ⇒ array value). */
|
|
555
555
|
readonly filter?: ScreenFilter;
|
|
556
556
|
/** User-toggleable facet dropdowns — see `ListFacetSpec` doc. `field`
|
|
557
|
-
* must be a declared column
|
|
558
|
-
*
|
|
557
|
+
* must be a declared column, except for `type: "reference"`: it filters
|
|
558
|
+
* by id through the bound query's `filters` and needs a registered
|
|
559
|
+
* `entity` instead. The bound query handler must accept `filters` in its
|
|
560
|
+
* Zod schema — the boot-validator checks both. A
|
|
559
561
|
* "dateRange" facet instead needs its two `params` keys in that schema;
|
|
560
562
|
* it sends no `filters` entry. */
|
|
561
563
|
readonly facets?: readonly ListFacetSpec[];
|
|
@@ -1144,7 +1146,9 @@ export type EditRelatedListSection = {
|
|
|
1144
1146
|
readonly searchable?: boolean;
|
|
1145
1147
|
/** User-toggleable facet dropdowns — same explicit-label `ListFacetSpec` as
|
|
1146
1148
|
* `projectionList.facets` (a relatedList has no entity to derive filterable
|
|
1147
|
-
* fields from). `field` must be a declared column
|
|
1149
|
+
* fields from). `field` must be a declared column, except for
|
|
1150
|
+
* `type: "reference"`: it filters by id through the bound query's
|
|
1151
|
+
* `filters` and needs a registered `entity` instead. The bound query
|
|
1148
1152
|
* handler must accept `filters` in its Zod schema — the boot-validator
|
|
1149
1153
|
* checks both. Selected values ride along as `payload.filters`. */
|
|
1150
1154
|
readonly facets?: readonly ListFacetSpec[];
|
package/dist/secrets-types.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/// <reference types="temporal-polyfill/global" preserve="true" />
|
|
2
|
+
import type { DbRunner } from "./db-connection.js";
|
|
2
3
|
import type { TenantId } from "./identifiers.js";
|
|
3
4
|
declare const SecretBrand: unique symbol;
|
|
4
5
|
export type Secret<T = string> = {
|
|
@@ -21,6 +22,7 @@ export type SecretKeyRef = string | {
|
|
|
21
22
|
readonly name: string;
|
|
22
23
|
};
|
|
23
24
|
export interface SecretsContext {
|
|
25
|
+
withRunner(runner: DbRunner): SecretsContext;
|
|
24
26
|
get(tenantId: TenantId, key: SecretKeyRef, auditCtx?: SecretAuditContext): Promise<Secret<string> | undefined>;
|
|
25
27
|
has(tenantId: TenantId, key: SecretKeyRef): Promise<boolean>;
|
|
26
28
|
set(tenantId: TenantId, key: SecretKeyRef, value: string, opts?: {
|
|
@@ -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.
|
|
3
|
+
"version": "0.364.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"
|