@cosmicdrift/kumiko-types 0.389.0 → 0.390.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 +1 -2
- package/dist/event-store-executor-types.d.ts +1 -1
- package/dist/event-type-map.js +1 -1
- package/dist/feature-registrar.d.ts +2 -7
- package/dist/feature.d.ts +1 -2
- package/dist/fields.d.ts +1 -1
- package/dist/handler-context-facets.d.ts +109 -0
- package/dist/handler-context-facets.js +1 -0
- package/dist/handler-context-services.d.ts +82 -0
- package/dist/handler-context-services.js +1 -0
- package/dist/handlers.d.ts +38 -105
- package/dist/hooks.d.ts +9 -11
- package/dist/observability/metric.js +1 -1
- package/dist/screen.d.ts +1 -1
- package/dist/secrets-types.js +1 -1
- package/package.json +1 -1
- package/src/changes.json +1 -1
package/dist/config.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import type { ConfigScope } from "./config-scope.ts";
|
|
|
4
4
|
import type { DbConnection } from "./db-connection.ts";
|
|
5
5
|
import type { EntityFieldDefinition, OptionsQueryPayload } from "./fields.ts";
|
|
6
6
|
import type { EscapeHatchDeclaration, JobContext, JobDeferral } from "./handlers.ts";
|
|
7
|
-
import type { PostDeleteHookFn, PostSaveHookFn, PreDeleteHookFn,
|
|
7
|
+
import type { PostDeleteHookFn, PostSaveHookFn, PreDeleteHookFn, PreSaveHookFn } from "./hooks.ts";
|
|
8
8
|
import type { TenantId } from "./identifiers.ts";
|
|
9
9
|
import type { NavIconKey } from "./nav-icon.ts";
|
|
10
10
|
import type { DashboardCustomPanel, DashboardScreenPanel } from "./screen.ts";
|
|
@@ -283,7 +283,6 @@ export type RegistrarExtensionHooks = {
|
|
|
283
283
|
readonly postSave?: PostSaveHookFn;
|
|
284
284
|
readonly preDelete?: PreDeleteHookFn;
|
|
285
285
|
readonly postDelete?: PostDeleteHookFn;
|
|
286
|
-
readonly preQuery?: PreQueryHookFn;
|
|
287
286
|
};
|
|
288
287
|
export type UiExtensionDef = {
|
|
289
288
|
readonly editSection?: string;
|
|
@@ -100,7 +100,7 @@ export type EventStoreExecutor<Row extends Record<string, unknown> = Record<stri
|
|
|
100
100
|
/** Per-call SearchAdapter override. When the
|
|
101
101
|
* executor didn't get a SearchAdapter via Options at build time
|
|
102
102
|
* (defaultEntityQueryHandler path), the caller (handler) can pass
|
|
103
|
-
* one from ctx.searchAdapter here at runtime.
|
|
103
|
+
* one from ctx.services.searchAdapter here at runtime.
|
|
104
104
|
* options.searchAdapter (build-time) wins — the runtime override
|
|
105
105
|
* is the fallback for the default wrapper. */
|
|
106
106
|
runtimeOptions?: ListRuntimeOptions) => Promise<CursorResult<Row>>;
|
package/dist/event-type-map.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Cross-Feature Compile-Time Type Map.
|
|
2
2
|
//
|
|
3
|
-
// Purpose: check ctx.
|
|
3
|
+
// Purpose: check ctx.events.append / ctx.dispatch.queryProjection / dispatcher.write against a
|
|
4
4
|
// statically known schema image instead of failing only at boot or runtime
|
|
5
5
|
// (zod-validate). The Designer/AI layer benefits immediately: autocomplete knows all
|
|
6
6
|
// event types from all loaded features, and payload-shape mismatches appear in the
|
|
@@ -9,7 +9,7 @@ import type { ExtensionOptionsArgs, ExtensionOptionsFor } from "./extension-opti
|
|
|
9
9
|
import type { BootCheckFn, MetricOptions, SecretKeyHandle, SecretNamespaceHandle, SecretNamespaceOptions, SecretOptions, StoreTableOptions, UiHints } from "./feature.ts";
|
|
10
10
|
import type { EntityDefinition } from "./fields.ts";
|
|
11
11
|
import type { AccessRule, AuthClaimsFn, ClaimKeyHandle, ClaimKeyType, DeclarativeEventMigration, EntityRef, EscapeHatchDeclaration, EventDef, EventPiiStance, EventUpcastFn, HandlerRef, NameOrRef, QualifiedEventName, RateLimitDeclaration, StreamHandlerFn } from "./handlers.ts";
|
|
12
|
-
import type { HookPhase, PostDeleteHookFn, PostQueryHookFn, PostSaveHookFn, PreDeleteHookFn,
|
|
12
|
+
import type { HookPhase, PostDeleteHookFn, PostQueryHookFn, PostSaveHookFn, PreDeleteHookFn, PreSaveHookFn, SearchPayloadContributorFn, ValidationHookFn } from "./hooks.ts";
|
|
13
13
|
import type { HttpRouteDefinition } from "./http-route.ts";
|
|
14
14
|
import type { ContentCollectionDefinition, NavDefinition } from "./nav.ts";
|
|
15
15
|
import type { EntityProjectionExtension, MultiStreamProjectionDefinition, ProjectionDefinition } from "./projection.ts";
|
|
@@ -57,11 +57,6 @@ export type HookDefinition = {
|
|
|
57
57
|
readonly target: HookTarget;
|
|
58
58
|
readonly handler: PostDeleteHookFn;
|
|
59
59
|
} & HookEscapeHatch & HookPhaseOption) | ({
|
|
60
|
-
readonly type: "preQuery";
|
|
61
|
-
readonly target: RefOrRefs;
|
|
62
|
-
readonly handler: PreQueryHookFn;
|
|
63
|
-
readonly phase?: never;
|
|
64
|
-
} & HookEscapeHatch) | ({
|
|
65
60
|
readonly type: "postQuery";
|
|
66
61
|
readonly target: HookTarget;
|
|
67
62
|
readonly handler: PostQueryHookFn;
|
|
@@ -88,7 +83,7 @@ export type RequiresApi = ((options: {
|
|
|
88
83
|
* features (apps that opt into the literal-name flavour) get propagated
|
|
89
84
|
* through to `defineEvent` so the returned `EventDef.name` is a literal
|
|
90
85
|
* `${CamelToKebab<TFeature>}:event:${CamelToKebab<TInner>}`. That literal
|
|
91
|
-
* threads through `ctx.
|
|
86
|
+
* threads through `ctx.events.append({ type: eventDef.name, ... })`,
|
|
92
87
|
* keeping strict-mode alive even when handlers route via `eventDef.name`
|
|
93
88
|
* instead of hand-typed string literals.
|
|
94
89
|
*/
|
package/dist/feature.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import type { ConfigKeyDefinition, ConfigSeedDef, ExtensionSelectorDef, Extensio
|
|
|
4
4
|
import type { EntityTableMeta } from "./entity-table-meta-types.ts";
|
|
5
5
|
import type { EntityDefinition } from "./fields.ts";
|
|
6
6
|
import type { AuthClaimsFn, AuthClaimsHookDef, ClaimKeyDefinition, EventDef, EventMigrationDef, EventUpcastFn, QueryHandlerDef, StreamHandlerDef, WriteHandlerDef } from "./handlers.ts";
|
|
7
|
-
import type { EntityHookMap, HookMap, HookPhase, OwnedFn, PostDeleteHookFn, PostQueryHookFn, PostSaveHookFn, PreDeleteHookFn,
|
|
7
|
+
import type { EntityHookMap, HookMap, HookPhase, OwnedFn, PostDeleteHookFn, PostQueryHookFn, PostSaveHookFn, PreDeleteHookFn, PreSaveHookFn, SearchPayloadContributorFn } from "./hooks.ts";
|
|
8
8
|
import type { HttpRouteDefinition } from "./http-route.ts";
|
|
9
9
|
import type { ContentCollectionDefinition, NavDefinition } from "./nav.ts";
|
|
10
10
|
import type { EntityProjectionExtension, MultiStreamProjectionDefinition, ProjectionDefinition } from "./projection.ts";
|
|
@@ -228,7 +228,6 @@ export type Registry = {
|
|
|
228
228
|
getPostSaveHooks(name: string, phase?: HookPhase, effectiveFeatures?: ReadonlySet<string>): readonly PostSaveHookFn[];
|
|
229
229
|
getPreDeleteHooks(name: string, phase?: HookPhase, effectiveFeatures?: ReadonlySet<string>): readonly PreDeleteHookFn[];
|
|
230
230
|
getPostDeleteHooks(name: string, phase?: HookPhase, effectiveFeatures?: ReadonlySet<string>): readonly PostDeleteHookFn[];
|
|
231
|
-
getPreQueryHooks(name: string, effectiveFeatures?: ReadonlySet<string>): readonly PreQueryHookFn[];
|
|
232
231
|
getPostQueryHooks(name: string, effectiveFeatures?: ReadonlySet<string>): readonly PostQueryHookFn[];
|
|
233
232
|
getEntityPostSaveHooks(entityName: string, phase?: HookPhase, effectiveFeatures?: ReadonlySet<string>): readonly PostSaveHookFn[];
|
|
234
233
|
getEntityPreDeleteHooks(entityName: string, phase?: HookPhase, effectiveFeatures?: ReadonlySet<string>): readonly PreDeleteHookFn[];
|
package/dist/fields.d.ts
CHANGED
|
@@ -103,7 +103,7 @@ export type TextFieldDef = {
|
|
|
103
103
|
* (list/detail/write responses) show `true` = set, `null` = empty. Writes:
|
|
104
104
|
* `""` or omitted = unchanged, `null` = clear, string = new value.
|
|
105
105
|
* Server-side: executor reads (detail/list in server handlers) and
|
|
106
|
-
* postSave/postQuery hooks see the plaintext; ctx.query, dispatcher.query,
|
|
106
|
+
* postSave/postQuery hooks see the plaintext; ctx.dispatch.query, dispatcher.query,
|
|
107
107
|
* agent tools and `_refs` see true/null; ctx.db sees the ciphertext.
|
|
108
108
|
* Known limit: masking runs for entity-bound query handlers with array /
|
|
109
109
|
* {rows} / flat results; an unbound custom query handler that returns
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/// <reference types="temporal-polyfill/global" preserve="true" />
|
|
2
|
+
import type { KumikoEventTypeMap } from "./event-type-map.ts";
|
|
3
|
+
import type { HandlerLifecycle } from "./handler-context-services.ts";
|
|
4
|
+
import type { ActiveMembershipResult, AggregateStreamHandle, AppendEventFn, FetchForWritingArgs, HandlerContext, MemberReader, SessionUser, TryAppendEventFn, UnsafeAppendEventFn, WriteResult } from "./handlers.ts";
|
|
5
|
+
import type { TenantId } from "./identifiers.ts";
|
|
6
|
+
import type { Logger } from "./logger.ts";
|
|
7
|
+
import type { Meter, MetricsHandle, Tracer } from "./observability/index.ts";
|
|
8
|
+
import type { TenantDb, UncheckedSystemDb } from "./tenant-db-types.ts";
|
|
9
|
+
/**
|
|
10
|
+
* `ctx.db` plus `outsideTransaction`: the same tenant scoping, but never bound to the handler's
|
|
11
|
+
* tx, so writes through it survive a rollback. `undefined` only in the denial phases
|
|
12
|
+
* (member-resolution, before-transaction) and in platform-metering tenant mode; narrow with
|
|
13
|
+
* `if (ctx.db.outsideTransaction)`. For atomic multi-statement writes outside the tx use
|
|
14
|
+
* `runInOwnTransaction(ctx.db.outsideTransaction, fn)`; `fn` must not touch rows the handler's own
|
|
15
|
+
* tx has locked. For r.systemScope() handlers `ctx.db` is a fail-closed guard; use
|
|
16
|
+
* `systemDb.outsideTransaction`.
|
|
17
|
+
*/
|
|
18
|
+
export type HandlerDb = TenantDb & {
|
|
19
|
+
readonly outsideTransaction: TenantDb | undefined;
|
|
20
|
+
};
|
|
21
|
+
/** Event-store surface of a handler. TMap propagates the strict event-type-map through `append`. */
|
|
22
|
+
export type HandlerEvents<TMap extends object = KumikoEventTypeMap> = {
|
|
23
|
+
/**
|
|
24
|
+
* Default append: a typed domain event on one aggregate stream in the current tx. The runtime
|
|
25
|
+
* bumps the stream version and fires matching projections in the same transaction. A version
|
|
26
|
+
* conflict throws and poisons the transaction.
|
|
27
|
+
*/
|
|
28
|
+
readonly append: AppendEventFn<TMap>;
|
|
29
|
+
/**
|
|
30
|
+
* Untyped append (`payload: unknown`) with the same runtime as `append`. Only for
|
|
31
|
+
* migrations and upcasters, where the event type is not knowable at compile time.
|
|
32
|
+
*/
|
|
33
|
+
readonly unsafeAppend: UnsafeAppendEventFn;
|
|
34
|
+
/**
|
|
35
|
+
* Optimistic append: runs in a savepoint and returns a version conflict as a result instead of
|
|
36
|
+
* throwing, so the handler can continue after losing a race on the same aggregate stream.
|
|
37
|
+
*/
|
|
38
|
+
readonly tryAppend: TryAppendEventFn;
|
|
39
|
+
readonly fetchForWriting: (args: FetchForWritingArgs) => Promise<AggregateStreamHandle>;
|
|
40
|
+
readonly load: (aggregateId: string, options?: {
|
|
41
|
+
readonly asOf?: Temporal.Instant;
|
|
42
|
+
readonly atVersion?: never;
|
|
43
|
+
} | {
|
|
44
|
+
readonly atVersion?: number;
|
|
45
|
+
readonly asOf?: never;
|
|
46
|
+
}) => Promise<readonly import("./event-store-types.ts").StoredEvent[]>;
|
|
47
|
+
readonly archive: (aggregateId: string, args: {
|
|
48
|
+
readonly aggregateType: string;
|
|
49
|
+
readonly reason?: string;
|
|
50
|
+
}) => Promise<void>;
|
|
51
|
+
readonly restore: (aggregateId: string) => Promise<void>;
|
|
52
|
+
readonly isArchived: (aggregateId: string) => Promise<boolean>;
|
|
53
|
+
readonly snapshot: (args: {
|
|
54
|
+
readonly aggregateId: string;
|
|
55
|
+
readonly aggregateType: string;
|
|
56
|
+
readonly version: number;
|
|
57
|
+
readonly state: Record<string, unknown>;
|
|
58
|
+
readonly snapshotVersion?: number;
|
|
59
|
+
}) => Promise<void>;
|
|
60
|
+
readonly loadWithSnapshot: <TState extends Record<string, unknown>>(aggregateId: string, reducer: import("./snapshot-types.ts").SnapshotReducer<TState>, initial: TState, options?: Omit<import("./snapshot-types.ts").LoadAggregateWithSnapshotOptions, "upcastEvent">) => Promise<import("./snapshot-types.ts").LoadAggregateWithSnapshotResult<TState>>;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Cross-feature bridge: `query`/`write` run the target handler AS THE CURRENT USER, sharing the
|
|
64
|
+
* active tx + afterCommit queue. `queryAs`/`writeAs` switch identity; any target other than the
|
|
65
|
+
* caller itself (or a subset of its roles) needs r.systemScope(), a job, or an escapeHatch.
|
|
66
|
+
*/
|
|
67
|
+
export type HandlerDispatch = {
|
|
68
|
+
readonly query: (qn: string, payload: unknown) => Promise<unknown>;
|
|
69
|
+
readonly queryAs: (user: SessionUser, qn: string, payload: unknown) => Promise<unknown>;
|
|
70
|
+
readonly write: (qn: string, payload: unknown) => Promise<WriteResult>;
|
|
71
|
+
readonly writeAs: (user: SessionUser, qn: string, payload: unknown) => Promise<WriteResult>;
|
|
72
|
+
readonly queryAsMember: MemberReader;
|
|
73
|
+
readonly queryProjection: <T = Record<string, unknown>>(qualifiedName: string, options?: {
|
|
74
|
+
readonly unsafeAllTenants?: boolean;
|
|
75
|
+
}) => Promise<readonly T[]>;
|
|
76
|
+
};
|
|
77
|
+
export type HandlerAuth = {
|
|
78
|
+
readonly resolveClaims: (user: SessionUser) => Promise<Record<string, unknown>>;
|
|
79
|
+
readonly resolveActiveMembership: (userId: string, tenantId: TenantId) => Promise<ActiveMembershipResult>;
|
|
80
|
+
};
|
|
81
|
+
export type HandlerObservability = {
|
|
82
|
+
readonly log: Logger;
|
|
83
|
+
readonly tracer: Tracer;
|
|
84
|
+
readonly metrics: MetricsHandle;
|
|
85
|
+
readonly metricsFor: (featureName: string) => MetricsHandle;
|
|
86
|
+
readonly meter?: Meter;
|
|
87
|
+
};
|
|
88
|
+
export type JobEvents = Pick<HandlerEvents, "append">;
|
|
89
|
+
export type JobDispatch = Pick<HandlerDispatch, "write" | "writeAs" | "queryAs" | "queryAsMember">;
|
|
90
|
+
export type JobObservability = Pick<HandlerObservability, "log" | "metricsFor" | "meter">;
|
|
91
|
+
type PhaseWithoutTransaction = "events" | "notify" | "dispatch" | "lifecycle";
|
|
92
|
+
/**
|
|
93
|
+
* ctx of `reserveBeforeTransaction`: nothing bound to the not-yet-open transaction. Reservations
|
|
94
|
+
* write on purpose through `db.outsideTransaction`, so it stays.
|
|
95
|
+
*/
|
|
96
|
+
export type ReservationContext<TMap extends object = KumikoEventTypeMap> = Omit<HandlerContext<TMap>, PhaseWithoutTransaction> & {
|
|
97
|
+
readonly dispatch: Omit<HandlerDispatch, "write" | "writeAs">;
|
|
98
|
+
readonly lifecycle: Omit<HandlerLifecycle, "afterCommit" | "afterRollback">;
|
|
99
|
+
};
|
|
100
|
+
/** ctx of `beforeTransaction`: external I/O and reads only, so the outside-transaction handles are gone too. */
|
|
101
|
+
export type BeforeTransactionContext<TMap extends object = KumikoEventTypeMap> = Omit<ReservationContext<TMap>, "db" | "systemDb"> & {
|
|
102
|
+
readonly db: TenantDb & {
|
|
103
|
+
readonly outsideTransaction: undefined;
|
|
104
|
+
};
|
|
105
|
+
readonly systemDb?: Omit<UncheckedSystemDb, "outsideTransaction"> & {
|
|
106
|
+
readonly outsideTransaction: undefined;
|
|
107
|
+
};
|
|
108
|
+
};
|
|
109
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { Redis } from "ioredis";
|
|
2
|
+
import type { CacheSyncBus } from "./cache-sync-types.ts";
|
|
3
|
+
import type { ConfigAccessor, ConfigResolver } from "./config.ts";
|
|
4
|
+
import type { DerivativesContext } from "./derivatives-types.ts";
|
|
5
|
+
import type { EntityCache } from "./entity-cache.ts";
|
|
6
|
+
import type { EnvelopeCipher } from "./envelope-cipher-types.ts";
|
|
7
|
+
import type { FileContext } from "./file-handle-types.ts";
|
|
8
|
+
import type { FileProviderResolver } from "./file-provider-resolver-types.ts";
|
|
9
|
+
import type { EscapeHatchAuditSink, JobRunnerRef, NotifyFactory, NotifyFn, SessionUser, TenantWriteTarget } from "./handlers.ts";
|
|
10
|
+
import type { TenantId } from "./identifiers.ts";
|
|
11
|
+
import type { KmsAdapter } from "./kms-adapter-types.ts";
|
|
12
|
+
import type { RateLimitResolver } from "./rate-limit-types.ts";
|
|
13
|
+
import type { SearchAdapter } from "./search-adapter.ts";
|
|
14
|
+
import type { MasterKeyProvider, SecretsContext } from "./secrets-types.ts";
|
|
15
|
+
/**
|
|
16
|
+
* Infrastructure the app wired at boot, as the handler or job sees it. extraContext keys the
|
|
17
|
+
* framework does not know land in `extensions`.
|
|
18
|
+
*/
|
|
19
|
+
export type ContextServices = {
|
|
20
|
+
readonly redis?: Redis;
|
|
21
|
+
readonly cacheSync?: CacheSyncBus;
|
|
22
|
+
readonly jobRunner?: JobRunnerRef;
|
|
23
|
+
readonly searchAdapter?: SearchAdapter;
|
|
24
|
+
readonly entityCache?: EntityCache;
|
|
25
|
+
readonly secrets?: SecretsContext;
|
|
26
|
+
readonly kms?: KmsAdapter;
|
|
27
|
+
readonly files?: FileContext;
|
|
28
|
+
readonly derivatives?: DerivativesContext;
|
|
29
|
+
readonly configResolver?: ConfigResolver;
|
|
30
|
+
readonly configEncryption?: EnvelopeCipher;
|
|
31
|
+
readonly rateLimit?: RateLimitResolver;
|
|
32
|
+
readonly effectiveFeatures?: (tenantId: TenantId) => ReadonlySet<string>;
|
|
33
|
+
readonly masterKeyProvider?: MasterKeyProvider;
|
|
34
|
+
readonly _fileProviderResolver?: FileProviderResolver;
|
|
35
|
+
readonly _notifyFactory?: NotifyFactory;
|
|
36
|
+
readonly _notifyInTransactionFactory?: (user: SessionUser, tenantId: TenantId) => NotifyFn;
|
|
37
|
+
readonly _notifyAfterCommitFactory?: (user: SessionUser, tenantId: TenantId) => NotifyFn;
|
|
38
|
+
readonly _escapeHatchAuditSink?: EscapeHatchAuditSink;
|
|
39
|
+
readonly extensions: Readonly<Record<string, unknown>>;
|
|
40
|
+
};
|
|
41
|
+
export type HandlerLifecycle = {
|
|
42
|
+
/**
|
|
43
|
+
* Runs the registered `preSave` hooks (and system preSave hooks) for `handlerName` and returns
|
|
44
|
+
* the hook-transformed `changes`. Entity CRUD handlers forward it to the executor; a custom
|
|
45
|
+
* `r.writeHandler` that bypasses the executor must call it itself. Undefined when no lifecycle
|
|
46
|
+
* pipeline is wired (bare stubs in unit tests).
|
|
47
|
+
*/
|
|
48
|
+
readonly runPreSave?: (handlerName: string, changes: Record<string, unknown>, previous: Readonly<Record<string, unknown>>, isNew: boolean) => Promise<Record<string, unknown>>;
|
|
49
|
+
/**
|
|
50
|
+
* Queues a side-effect to run after the outermost write transaction commits (same sink as
|
|
51
|
+
* ctx.dispatch.write). Absent outside a write pipeline; callers fall back to firing immediately.
|
|
52
|
+
*/
|
|
53
|
+
readonly afterCommit?: (hook: () => Promise<void>) => void;
|
|
54
|
+
/**
|
|
55
|
+
* Runs when the handler transaction (or enclosing savepoint) does not commit, also after a failed
|
|
56
|
+
* COMMIT of unknown outcome, so write it idempotent and outcome-safe. Present only inside a
|
|
57
|
+
* transaction scope.
|
|
58
|
+
*/
|
|
59
|
+
readonly afterRollback?: (hook: () => Promise<void>) => void;
|
|
60
|
+
/**
|
|
61
|
+
* Cancellation. Aborts when the HTTP client disconnects. Undefined for non-HTTP entry points
|
|
62
|
+
* (jobs, MSP-applies). Long-running handlers throw `signal.throwIfAborted()` at chunk boundaries.
|
|
63
|
+
*/
|
|
64
|
+
readonly signal?: AbortSignal;
|
|
65
|
+
};
|
|
66
|
+
export type JobLifecycle = Pick<HandlerLifecycle, "signal">;
|
|
67
|
+
export type HandlerTenants = {
|
|
68
|
+
/**
|
|
69
|
+
* Config accessor resolved for ANOTHER tenant, identity = that tenant's system user. Cross-tenant
|
|
70
|
+
* calls throw AccessDeniedError unless the caller is a system identity or has the SystemAdmin
|
|
71
|
+
* role; the caller's own tenant needs no privilege. Present when the config feature wired its
|
|
72
|
+
* accessor factory.
|
|
73
|
+
*/
|
|
74
|
+
readonly config?: (tenantId: TenantId) => ConfigAccessor;
|
|
75
|
+
/**
|
|
76
|
+
* Write target for ANOTHER tenant: a tenant-mode db bound to it plus the `streamTenantId` to hand
|
|
77
|
+
* the executor, so the event actor stays the operator. Cross-tenant calls throw AccessDeniedError
|
|
78
|
+
* unless the caller is SystemAdmin; the caller's own tenant yields `streamTenantId: undefined`.
|
|
79
|
+
* Write handlers only; absent for r.systemScope() handlers and without a db.
|
|
80
|
+
*/
|
|
81
|
+
readonly writeTarget?: (tenantId: TenantId) => TenantWriteTarget;
|
|
82
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/handlers.d.ts
CHANGED
|
@@ -11,11 +11,15 @@ import type { KumikoEventTypeMap } from "./event-type-map.ts";
|
|
|
11
11
|
import type { FileContext } from "./file-handle-types.ts";
|
|
12
12
|
import type { FileProviderResolver } from "./file-provider-resolver-types.ts";
|
|
13
13
|
import type { GeoTzProvider } from "./geo-tz.ts";
|
|
14
|
+
import type { BeforeTransactionContext, HandlerAuth, HandlerDb, HandlerDispatch, HandlerEvents, HandlerObservability, JobDispatch, JobEvents, JobObservability, ReservationContext } from "./handler-context-facets.ts";
|
|
15
|
+
import type { ContextServices, HandlerLifecycle, HandlerTenants, JobLifecycle } from "./handler-context-services.ts";
|
|
14
16
|
import type { Logger } from "./logger.ts";
|
|
15
|
-
import type { Meter,
|
|
17
|
+
import type { Meter, Tracer } from "./observability/index.ts";
|
|
16
18
|
import type { SearchAdapter } from "./search-adapter.ts";
|
|
17
19
|
import type { CrossTenantReads, TenantDb } from "./tenant-db-types.ts";
|
|
18
20
|
import type { Clock, TzContext } from "./tz-context.ts";
|
|
21
|
+
export type { BeforeTransactionContext, HandlerAuth, HandlerDb, HandlerDispatch, HandlerEvents, HandlerObservability, JobDispatch, JobEvents, JobObservability, ReservationContext, } from "./handler-context-facets.ts";
|
|
22
|
+
export type { ContextServices, HandlerLifecycle, HandlerTenants, JobLifecycle, } from "./handler-context-services.ts";
|
|
19
23
|
export type OpenToAllPersonalData = "tenant-members";
|
|
20
24
|
export type OpenToAllDeclaration = {
|
|
21
25
|
readonly reason: string;
|
|
@@ -214,27 +218,12 @@ type SharedContextFields = {
|
|
|
214
218
|
readonly jobRunner?: JobRunnerRef;
|
|
215
219
|
readonly configResolver?: ConfigResolver;
|
|
216
220
|
readonly config?: ConfigAccessor;
|
|
217
|
-
/**
|
|
218
|
-
* Config accessor resolved for ANOTHER tenant, identity = that tenant's system
|
|
219
|
-
* user (the caller's user-scope config never leaks in). Cross-tenant calls
|
|
220
|
-
* throw AccessDeniedError unless the caller is a system identity or has the
|
|
221
|
-
* SystemAdmin role; the caller's own tenant needs no privilege. Present when
|
|
222
|
-
* the config feature wired its accessor factory.
|
|
223
|
-
*/
|
|
221
|
+
/** Becomes `ctx.tenants.config`. */
|
|
224
222
|
readonly configFor?: (tenantId: TenantId) => ConfigAccessor;
|
|
225
|
-
/**
|
|
226
|
-
* Write target for ANOTHER tenant: a tenant-mode db bound to it plus the
|
|
227
|
-
* `streamTenantId` to hand the executor, so the event actor stays the
|
|
228
|
-
* operator. Cross-tenant calls throw AccessDeniedError unless the caller is
|
|
229
|
-
* SystemAdmin (the tenantIdOverride gate); the caller's own tenant needs no
|
|
230
|
-
* privilege and yields `streamTenantId: undefined`. Write handlers only;
|
|
231
|
-
* absent for r.systemScope() handlers and without a db.
|
|
232
|
-
*/
|
|
223
|
+
/** Becomes `ctx.tenants.writeTarget`. */
|
|
233
224
|
readonly forTenant?: (tenantId: TenantId) => TenantWriteTarget;
|
|
234
225
|
/** Mints the per-request `ctx.config`; set by the boot (`addConfigAccessorFactory`) from the effective `configResolver`, overriding an app-supplied value. */
|
|
235
226
|
readonly configAccessorFactory?: ConfigAccessorFactory;
|
|
236
|
-
/** @deprecated Use `configAccessorFactory`; the underscore name is removed in 0.390.0. */
|
|
237
|
-
readonly _configAccessorFactory?: ConfigAccessorFactory;
|
|
238
227
|
readonly configEncryption?: import("./envelope-cipher-types.ts").EnvelopeCipher;
|
|
239
228
|
readonly rateLimit?: import("./rate-limit-types.ts").RateLimitResolver;
|
|
240
229
|
readonly _rateLimitPayloadDigest?: (value: string) => string;
|
|
@@ -255,11 +244,13 @@ type SharedContextFields = {
|
|
|
255
244
|
readonly meter?: Meter;
|
|
256
245
|
readonly signal?: AbortSignal;
|
|
257
246
|
readonly effectiveFeatures?: (tenantId: TenantId) => ReadonlySet<string>;
|
|
247
|
+
/** Becomes `ctx.lifecycle.afterCommit`. */
|
|
258
248
|
readonly scheduleAfterCommit?: (hook: () => Promise<void>) => void;
|
|
249
|
+
/** Becomes `ctx.lifecycle.afterRollback`. */
|
|
259
250
|
readonly scheduleAfterRollback?: (hook: () => Promise<void>) => void;
|
|
260
|
-
readonly queryAsMember?: MemberReader;
|
|
261
251
|
};
|
|
262
252
|
export type AppContext = SharedContextFields & {
|
|
253
|
+
readonly services?: never;
|
|
263
254
|
readonly db?: DbConnection | TenantDb;
|
|
264
255
|
readonly systemDb?: UncheckedSystemDb;
|
|
265
256
|
readonly registry?: Registry;
|
|
@@ -285,7 +276,7 @@ export type AppContext = SharedContextFields & {
|
|
|
285
276
|
/** Tenant of the current pipeline call. The dispatcher mirrors
|
|
286
277
|
* `user.tenantId` here when building HandlerContext so the lifecycle
|
|
287
278
|
* pipeline and system hooks can access it without the user object.
|
|
288
|
-
* `effectiveFeatures(ctx.
|
|
279
|
+
* `effectiveFeatures(ctx.user.tenantId)` uses it at hook-filter points. */
|
|
289
280
|
readonly _tenantId?: TenantId;
|
|
290
281
|
/** Boot-configured default locale (BCP-47). Last fallback in ctx.locale's
|
|
291
282
|
* Request-Locale → Boot-Default chain (dispatch-shared.ts) — used when
|
|
@@ -293,18 +284,8 @@ export type AppContext = SharedContextFields & {
|
|
|
293
284
|
* Absent falls back to "en". */
|
|
294
285
|
readonly defaultLocale?: string;
|
|
295
286
|
};
|
|
296
|
-
export type HandlerContext<TMap extends object = KumikoEventTypeMap> =
|
|
297
|
-
readonly db:
|
|
298
|
-
/**
|
|
299
|
-
* Same tenant scoping as `db`, but never bound to the handler's tx: writes through it survive
|
|
300
|
-
* a rollback. `undefined` only in the denial phases (member-resolution, before-transaction)
|
|
301
|
-
* and in platform-metering tenant mode; narrow with `hasOutsideTransactionDb(ctx)` or take it
|
|
302
|
-
* via `requireOutsideTransactionDb(ctx)` (`@cosmicdrift/kumiko-framework/db`). For atomic
|
|
303
|
-
* multi-statement writes outside the tx use `runInOwnTransaction(ctx.dbOutsideTransaction, fn)`; `fn`
|
|
304
|
-
* must not touch rows the handler's own tx has locked. For
|
|
305
|
-
* r.systemScope() handlers it is a fail-closed Proxy; use `systemDb.outsideTransaction`.
|
|
306
|
-
*/
|
|
307
|
-
readonly dbOutsideTransaction: TenantDb | undefined;
|
|
287
|
+
export type HandlerContext<TMap extends object = KumikoEventTypeMap> = {
|
|
288
|
+
readonly db: HandlerDb;
|
|
308
289
|
readonly systemDb?: UncheckedSystemDb;
|
|
309
290
|
readonly crossTenantReads?: CrossTenantReads;
|
|
310
291
|
readonly registry: Registry;
|
|
@@ -314,84 +295,35 @@ export type HandlerContext<TMap extends object = KumikoEventTypeMap> = SharedCon
|
|
|
314
295
|
* The value is identical to `event.user`; identity switches still use
|
|
315
296
|
* `queryAs`/`writeAs`. */
|
|
316
297
|
readonly user: SessionUser;
|
|
317
|
-
readonly systemUser?: SessionUser;
|
|
318
|
-
readonly log?: Logger;
|
|
319
|
-
readonly triggeredBy?: {
|
|
320
|
-
readonly id: string;
|
|
321
|
-
readonly tenantId: TenantId;
|
|
322
|
-
} | null;
|
|
323
298
|
/** Keyed digest for handler-owned rate-limit keys, so Redis never holds a
|
|
324
299
|
* plaintext or plainly hashed identifier. Scoped to the running handler:
|
|
325
300
|
* the same input yields a different digest per handler and never matches a
|
|
326
301
|
* dispatcher payload-bucket digest. Absent when the app wires no digest key. */
|
|
327
302
|
readonly rateLimitDigest?: (value: string) => string;
|
|
328
303
|
readonly includeDeleted?: boolean;
|
|
329
|
-
readonly
|
|
330
|
-
readonly query: (qn: string, payload: unknown) => Promise<unknown>;
|
|
331
|
-
readonly queryAs: (user: SessionUser, qn: string, payload: unknown) => Promise<unknown>;
|
|
332
|
-
readonly write: (qn: string, payload: unknown) => Promise<WriteResult>;
|
|
333
|
-
readonly writeAs: (user: SessionUser, qn: string, payload: unknown) => Promise<WriteResult>;
|
|
304
|
+
readonly dispatch: HandlerDispatch;
|
|
334
305
|
readonly hasFeature: (featureName: string) => Promise<boolean>;
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
* bumps the stream version and fires matching projections in the same transaction. A version
|
|
338
|
-
* conflict throws and poisons the transaction.
|
|
339
|
-
*/
|
|
340
|
-
readonly appendEvent: AppendEventFn<TMap>;
|
|
341
|
-
/**
|
|
342
|
-
* Untyped append (`payload: unknown`) with the same runtime as `appendEvent`. Only for
|
|
343
|
-
* migrations and upcasters, where the event type is not knowable at compile time.
|
|
344
|
-
*/
|
|
345
|
-
readonly unsafeAppendEvent: UnsafeAppendEventFn;
|
|
346
|
-
/**
|
|
347
|
-
* Optimistic append: runs in a savepoint and returns a version conflict as a result instead of
|
|
348
|
-
* throwing, so the handler can continue after losing a race on the same aggregate stream.
|
|
349
|
-
*/
|
|
350
|
-
readonly tryAppendEvent: TryAppendEventFn;
|
|
351
|
-
readonly fetchForWriting: (args: FetchForWritingArgs) => Promise<AggregateStreamHandle>;
|
|
352
|
-
readonly loadAggregate: (aggregateId: string, options?: {
|
|
353
|
-
readonly asOf?: Temporal.Instant;
|
|
354
|
-
readonly atVersion?: never;
|
|
355
|
-
} | {
|
|
356
|
-
readonly atVersion?: number;
|
|
357
|
-
readonly asOf?: never;
|
|
358
|
-
}) => Promise<readonly import("./event-store-types.ts").StoredEvent[]>;
|
|
359
|
-
readonly archiveStream: (aggregateId: string, args: {
|
|
360
|
-
readonly aggregateType: string;
|
|
361
|
-
readonly reason?: string;
|
|
362
|
-
}) => Promise<void>;
|
|
363
|
-
readonly restoreStream: (aggregateId: string) => Promise<void>;
|
|
364
|
-
readonly isStreamArchived: (aggregateId: string) => Promise<boolean>;
|
|
365
|
-
readonly snapshotAggregate: (args: {
|
|
366
|
-
readonly aggregateId: string;
|
|
367
|
-
readonly aggregateType: string;
|
|
368
|
-
readonly version: number;
|
|
369
|
-
readonly state: Record<string, unknown>;
|
|
370
|
-
readonly snapshotVersion?: number;
|
|
371
|
-
}) => Promise<void>;
|
|
372
|
-
readonly loadAggregateWithSnapshot: <TState extends Record<string, unknown>>(aggregateId: string, reducer: import("./snapshot-types.ts").SnapshotReducer<TState>, initial: TState, options?: Omit<import("./snapshot-types.ts").LoadAggregateWithSnapshotOptions, "upcastEvent">) => Promise<import("./snapshot-types.ts").LoadAggregateWithSnapshotResult<TState>>;
|
|
373
|
-
readonly queryProjection: <T = Record<string, unknown>>(qualifiedName: string, options?: {
|
|
374
|
-
readonly unsafeAllTenants?: boolean;
|
|
375
|
-
}) => Promise<readonly T[]>;
|
|
376
|
-
readonly metrics: MetricsHandle;
|
|
377
|
-
readonly metricsFor: (featureName: string) => MetricsHandle;
|
|
378
|
-
readonly tracer: Tracer;
|
|
306
|
+
readonly events: HandlerEvents<TMap>;
|
|
307
|
+
readonly obs: HandlerObservability;
|
|
379
308
|
readonly tz: TzContext;
|
|
380
309
|
readonly locale: string;
|
|
381
|
-
readonly
|
|
382
|
-
readonly
|
|
383
|
-
readonly
|
|
310
|
+
readonly auth: HandlerAuth;
|
|
311
|
+
readonly config?: ConfigAccessor;
|
|
312
|
+
readonly notify?: NotifyFn;
|
|
313
|
+
readonly services: ContextServices;
|
|
314
|
+
readonly lifecycle: HandlerLifecycle;
|
|
315
|
+
readonly tenants: HandlerTenants;
|
|
384
316
|
};
|
|
385
317
|
export type JobDeferral = {
|
|
386
318
|
readonly kind: "job-deferral";
|
|
387
319
|
readonly delayMs: number;
|
|
388
320
|
};
|
|
389
|
-
export type JobContext =
|
|
321
|
+
export type JobContext = {
|
|
390
322
|
readonly db: TenantDb;
|
|
323
|
+
readonly events: JobEvents;
|
|
391
324
|
readonly registry: Registry;
|
|
392
325
|
readonly systemUser: SessionUser;
|
|
393
|
-
readonly
|
|
394
|
-
readonly metricsFor: (featureName: string) => MetricsHandle;
|
|
326
|
+
readonly obs: JobObservability;
|
|
395
327
|
readonly tz: TzContext;
|
|
396
328
|
readonly triggeredBy: {
|
|
397
329
|
readonly id: string;
|
|
@@ -400,15 +332,17 @@ export type JobContext = SharedContextFields & {
|
|
|
400
332
|
readonly attempt: number;
|
|
401
333
|
readonly finalAttempt: boolean;
|
|
402
334
|
readonly defer: (delayMs: number) => JobDeferral;
|
|
335
|
+
readonly canDefer: boolean;
|
|
403
336
|
readonly systemDb?: UncheckedSystemDb;
|
|
404
337
|
readonly crossTenantReads?: CrossTenantReads;
|
|
405
|
-
readonly
|
|
406
|
-
readonly writeAs: (user: SessionUser, qn: string, payload: unknown) => Promise<WriteResult>;
|
|
407
|
-
readonly queryAs: (user: SessionUser, qn: string, payload: unknown) => Promise<unknown>;
|
|
408
|
-
readonly queryAsMember: MemberReader;
|
|
338
|
+
readonly dispatch: JobDispatch;
|
|
409
339
|
readonly triggerName?: string;
|
|
410
340
|
readonly triggerEvent?: JobTriggerEvent;
|
|
411
341
|
readonly _tenantId?: TenantId;
|
|
342
|
+
readonly config?: ConfigAccessor;
|
|
343
|
+
readonly notify?: NotifyFn;
|
|
344
|
+
readonly services: ContextServices;
|
|
345
|
+
readonly lifecycle: JobLifecycle;
|
|
412
346
|
};
|
|
413
347
|
export type WriteHandlerFn<TPayload = unknown, TData = unknown> = (event: WriteEvent<TPayload>, context: HandlerContext) => Promise<WriteResult<TData>>;
|
|
414
348
|
export type QueryHandlerFn<TPayload = unknown, TResult = unknown> = (query: QueryEvent<TPayload>, context: HandlerContext) => Promise<TResult>;
|
|
@@ -418,7 +352,7 @@ export type StreamHandlerFn<TPayload = unknown, TChunk = unknown> = (query: Quer
|
|
|
418
352
|
* → kebab-case. Drives the literal-type of `EventDef.name`, so that
|
|
419
353
|
* `r.defineEvent("foo", schema)` inside `defineFeature("driverOrders")`
|
|
420
354
|
* carries `name: "driver-orders:event:foo"` as a literal — strict-mode
|
|
421
|
-
* for `ctx.
|
|
355
|
+
* for `ctx.events.append({ type: eventDef.name, ... })` lights up.
|
|
422
356
|
*
|
|
423
357
|
* Algorithm mirrors the runtime regex pipeline:
|
|
424
358
|
* 1. `.` → `-` (dot acts as word-boundary)
|
|
@@ -606,14 +540,14 @@ export type ReservationHandle = {
|
|
|
606
540
|
* its own short write instead of holding a second connection while the transaction is open.
|
|
607
541
|
* The returned release (or handle.release) runs when the transaction does not commit (failure
|
|
608
542
|
* result, throw, rollback, failed commit). Throwing a KumikoError rejects the write. */
|
|
609
|
-
export type PreTransactionReservation = (event: WriteEvent, ctx:
|
|
543
|
+
export type PreTransactionReservation = (event: WriteEvent, ctx: ReservationContext) => Promise<ReservationRelease | ReservationHandle | undefined>;
|
|
610
544
|
/** 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. */
|
|
611
545
|
export type BeforeTransactionResult<TPrepared = unknown> = {
|
|
612
546
|
readonly isSuccess: true;
|
|
613
547
|
readonly data: TPrepared;
|
|
614
548
|
readonly release?: ReservationRelease;
|
|
615
549
|
} | WriteFailure;
|
|
616
|
-
export type BeforeTransactionPhase<TPayload = unknown, TPrepared = unknown> = (event: WriteEvent<TPayload>, ctx:
|
|
550
|
+
export type BeforeTransactionPhase<TPayload = unknown, TPrepared = unknown> = (event: WriteEvent<TPayload>, ctx: BeforeTransactionContext) => Promise<BeforeTransactionResult<TPrepared>>;
|
|
617
551
|
/** `perCommand`: the handler runs without a transaction of its own. */
|
|
618
552
|
export type WriteHandlerTransactionMode = "perCommand";
|
|
619
553
|
export type WriteHandlerDef = {
|
|
@@ -635,17 +569,17 @@ export type WriteHandlerDef = {
|
|
|
635
569
|
* payload (e.g. `(p) => p.files.length`). Replaces the options' `cost`; results below 1 count as 1. */
|
|
636
570
|
readonly rateLimitCost?: (payload: unknown) => number;
|
|
637
571
|
readonly escapeHatch?: EscapeHatchDeclaration;
|
|
638
|
-
/** Reserves before the handler transaction opens. Reached through a nested ctx.write the
|
|
572
|
+
/** Reserves before the handler transaction opens. Reached through a nested ctx.dispatch.write the
|
|
639
573
|
* reservation cannot run, so the dispatcher rejects it unless the top-level batch reserved it. */
|
|
640
574
|
readonly reserveBeforeTransaction?: PreTransactionReservation;
|
|
641
575
|
/** Runs after all pre-handler gates (and after reserveBeforeTransaction) and before the
|
|
642
576
|
* transaction opens: no transaction and no connection held, for external I/O and reads only.
|
|
643
577
|
* Its `data` reaches the handler as `event.prepared`; a failure result or throw rejects the
|
|
644
|
-
* write before anything is written. A handler with this phase cannot run as a nested ctx.write.
|
|
645
|
-
* `ctx.
|
|
578
|
+
* write before anything is written. A handler with this phase cannot run as a nested ctx.dispatch.write.
|
|
579
|
+
* `ctx.tenants.writeTarget` is available but read-only here: its db denies writes for the own and a
|
|
646
580
|
* foreign tenant alike (a foreign tenant stays gated by the SystemAdmin check). */
|
|
647
581
|
readonly beforeTransaction?: BeforeTransactionPhase;
|
|
648
|
-
/** `"perCommand"`: the handler runs without a transaction of its own. Every ctx.write/writeAs it
|
|
582
|
+
/** `"perCommand"`: the handler runs without a transaction of its own. Every ctx.dispatch.write/writeAs it
|
|
649
583
|
* issues runs as its own top-level command with its own transaction and afterCommit hooks;
|
|
650
584
|
* ctx.db writes and event appends throw. It cannot run as a nested write or inside a
|
|
651
585
|
* multi-command batch, and cannot be combined with beforeTransaction/reserveBeforeTransaction. */
|
|
@@ -692,4 +626,3 @@ export type StreamHandlerDef = {
|
|
|
692
626
|
readonly rateLimit?: RateLimitDeclaration;
|
|
693
627
|
readonly escapeHatch?: EscapeHatchDeclaration;
|
|
694
628
|
};
|
|
695
|
-
export {};
|
package/dist/hooks.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { StoredEvent } from "./event-store-types.ts";
|
|
2
|
-
import type {
|
|
2
|
+
import type { HandlerContext } from "./handlers.ts";
|
|
3
3
|
import type { HookPhase } from "./hook-phase.ts";
|
|
4
4
|
import type { EntityId } from "./identifiers.ts";
|
|
5
5
|
export type ValidationError = {
|
|
@@ -26,23 +26,22 @@ export type DeleteContext = {
|
|
|
26
26
|
readonly lockGuardBypassed?: boolean | undefined;
|
|
27
27
|
};
|
|
28
28
|
export type LifecycleResult = SaveContext | DeleteContext;
|
|
29
|
-
export type PreSaveHookFn = (changes: Record<string, unknown>, context:
|
|
29
|
+
export type PreSaveHookFn = (changes: Record<string, unknown>, context: HandlerContext & {
|
|
30
30
|
readonly previous: Readonly<Record<string, unknown>>;
|
|
31
31
|
readonly isNew: boolean;
|
|
32
32
|
}) => Promise<Record<string, unknown>>;
|
|
33
|
-
export type PostSaveHookFn = (result: SaveContext, context:
|
|
34
|
-
export type PostSaveBatchHookFn = (results: readonly SaveContext[], context:
|
|
35
|
-
export type PreDeleteHookFn = (payload: DeleteContext, context:
|
|
36
|
-
export type PostDeleteHookFn = (payload: DeleteContext, context:
|
|
37
|
-
export type PostDeleteBatchHookFn = (payloads: readonly DeleteContext[], context:
|
|
38
|
-
export type PreQueryHookFn = (payload: Record<string, unknown>, context: AppContext) => Promise<Record<string, unknown>>;
|
|
33
|
+
export type PostSaveHookFn = (result: SaveContext, context: HandlerContext) => Promise<void>;
|
|
34
|
+
export type PostSaveBatchHookFn = (results: readonly SaveContext[], context: HandlerContext) => Promise<void>;
|
|
35
|
+
export type PreDeleteHookFn = (payload: DeleteContext, context: HandlerContext) => Promise<void>;
|
|
36
|
+
export type PostDeleteHookFn = (payload: DeleteContext, context: HandlerContext) => Promise<void>;
|
|
37
|
+
export type PostDeleteBatchHookFn = (payloads: readonly DeleteContext[], context: HandlerContext) => Promise<void>;
|
|
39
38
|
export type PostQueryHookFn = (result: {
|
|
40
39
|
readonly entityName: string | undefined;
|
|
41
40
|
readonly rows: ReadonlyArray<Record<string, unknown>>;
|
|
42
|
-
}, context:
|
|
41
|
+
}, context: HandlerContext) => Promise<{
|
|
43
42
|
rows: ReadonlyArray<Record<string, unknown>>;
|
|
44
43
|
}>;
|
|
45
|
-
export type LifecycleHookFn = PreSaveHookFn | PostSaveHookFn | PreDeleteHookFn | PostDeleteHookFn |
|
|
44
|
+
export type LifecycleHookFn = PreSaveHookFn | PostSaveHookFn | PreDeleteHookFn | PostDeleteHookFn | PostQueryHookFn;
|
|
46
45
|
export type { HookPhase } from "./hook-phase.ts";
|
|
47
46
|
export type HookOwner = {
|
|
48
47
|
readonly featureName?: string;
|
|
@@ -60,7 +59,6 @@ export type HookMap = {
|
|
|
60
59
|
readonly postSave?: Readonly<Record<string, readonly PhasedHook<PostSaveHookFn>[]>>;
|
|
61
60
|
readonly preDelete?: Readonly<Record<string, readonly PhasedHook<PreDeleteHookFn>[]>>;
|
|
62
61
|
readonly postDelete?: Readonly<Record<string, readonly PhasedHook<PostDeleteHookFn>[]>>;
|
|
63
|
-
readonly preQuery?: Readonly<Record<string, readonly OwnedFn<PreQueryHookFn>[]>>;
|
|
64
62
|
readonly postQuery?: Readonly<Record<string, readonly OwnedFn<PostQueryHookFn>[]>>;
|
|
65
63
|
};
|
|
66
64
|
export type EntityHookMap = {
|
package/dist/screen.d.ts
CHANGED
|
@@ -73,7 +73,7 @@ export interface FieldFormatRegistry {
|
|
|
73
73
|
/** FileRef id (or id array) as a download link with the file name. On a
|
|
74
74
|
* read-only detail field it renders a file list with download links and an
|
|
75
75
|
* inline preview for PDFs; elsewhere the raw value is shown.
|
|
76
|
-
* `previewOpenByDefault` opens the
|
|
76
|
+
* `previewOpenByDefault` opens the newest (last) file's PDF preview initially. */
|
|
77
77
|
file: {
|
|
78
78
|
readonly previewOpenByDefault?: boolean;
|
|
79
79
|
};
|
package/dist/secrets-types.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// but the nominal typing stops it from landing in an HTTP response by
|
|
7
7
|
// accident — a response-serializer guard + the reveal() cost make the leak
|
|
8
8
|
// intentional. Framework code that sees `Secret<string>` knows the caller
|
|
9
|
-
// has already gone through the audited ctx.secrets.get path.
|
|
9
|
+
// has already gone through the audited ctx.services.secrets.get path.
|
|
10
10
|
//
|
|
11
11
|
// Registered symbol, matching KUMIKO_*_SYMBOL in schema-table-types.ts. A
|
|
12
12
|
// plain Symbol() is per-copy: two resolved copies of this package brand with
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosmicdrift/kumiko-types",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.390.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": "MIT",
|
|
6
6
|
"author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
|
package/src/changes.json
CHANGED
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"type": "breaking",
|
|
44
44
|
"title": "HandlerContext.outsideTransaction removed",
|
|
45
45
|
"detail": "The deprecated outsideTransaction field no longer exists on HandlerContext. ctx.dbOutsideTransaction together with runInOwnTransaction replaces it.",
|
|
46
|
-
"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."
|
|
46
|
+
"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. Since #4031 the two helpers are internal and no longer exported from /db; narrow ctx.db.outsideTransaction directly (if (ctx.db.outsideTransaction))."
|
|
47
47
|
},
|
|
48
48
|
{
|
|
49
49
|
"version": "0.377.0",
|