@cosmicdrift/kumiko-framework 0.365.1 → 0.366.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/AGENTS.md +2 -2
- package/agents/examples/access-control.md +32 -30
- package/agents/examples/anonymous-access-multitenant.md +14 -16
- package/agents/examples/anonymous-access.md +36 -43
- package/agents/examples/auth-foundation-providers.md +1 -1
- package/agents/examples/basic-entity.md +1 -1
- package/agents/examples/boot-check.md +3 -3
- package/agents/examples/chat-channels.md +1 -1
- package/agents/examples/cross-feature-events.md +7 -7
- package/agents/examples/currencies-global.md +3 -3
- package/agents/examples/currencies-per-tenant.md +2 -2
- package/agents/examples/custom-fields-basic.md +4 -3
- package/agents/examples/custom-handlers.md +40 -44
- package/agents/examples/dashboard-stats.md +6 -6
- package/agents/examples/delivery-notifications.md +9 -9
- package/agents/examples/designer-demo.md +2 -1
- package/agents/examples/embedded-entity-form.md +13 -13
- package/agents/examples/embedded.md +1 -1
- package/agents/examples/encrypted-tenant-config.md +1 -1
- package/agents/examples/error-contract.md +25 -25
- package/agents/examples/event-sourcing.md +96 -76
- package/agents/examples/feature-toggles.md +29 -21
- package/agents/examples/files-post-processing.md +22 -26
- package/agents/examples/idempotency.md +17 -19
- package/agents/examples/inbound-mail-triage.md +1 -1
- package/agents/examples/lane-routing.md +10 -12
- package/agents/examples/legal-pages.md +1 -1
- package/agents/examples/lifecycle-hooks.md +59 -39
- package/agents/examples/managed-config.md +9 -9
- package/agents/examples/managed-pages.md +1 -1
- package/agents/examples/notes-history-basic.md +3 -3
- package/agents/examples/pdf-audit-export.md +7 -7
- package/agents/examples/pipeline-basics.md +8 -8
- package/agents/examples/public-share-token.md +1 -1
- package/agents/examples/rate-limiting.md +7 -9
- package/agents/examples/record-detail-layout.md +26 -20
- package/agents/examples/reference-data.md +1 -1
- package/agents/examples/relations.md +2 -2
- package/agents/examples/screens-nav.md +2 -2
- package/agents/examples/search.md +17 -19
- package/agents/examples/security-baseline.md +1 -1
- package/agents/examples/state-machine.md +1 -1
- package/agents/examples/tags-basic.md +3 -3
- package/agents/examples/tenant-settings.md +2 -2
- package/agents/examples/timezones.md +12 -12
- package/agents/examples/user-data-rights.md +3 -3
- package/agents/examples/user-profile.md +1 -1
- package/agents/examples/webhook-step.md +1 -1
- package/agents/examples/writeform-section.md +21 -15
- package/agents/widgets.md +5 -0
- package/dist/api/server.js +12 -4
- package/dist/bun-db/query.js +16 -1
- package/dist/db/entity-table-meta.js +4 -4
- package/dist/engine/boot-validator/api-ext.js +2 -2
- package/dist/engine/boot-validator/config-deps.js +1 -1
- package/dist/engine/boot-validator/handler-field-references.js +3 -10
- package/dist/engine/boot-validator/screens.js +1 -1
- package/dist/engine/build-app-schema.js +3 -6
- package/dist/engine/define-feature.js +5 -5
- package/dist/engine/entity-handlers.d.ts +2 -2
- package/dist/engine/entity-handlers.js +5 -5
- package/dist/engine/factories.d.ts +11 -11
- package/dist/engine/factories.js +11 -11
- package/dist/engine/feature-ast/extractors/round2.js +16 -2
- package/dist/engine/feature-ast/render.js +4 -7
- package/dist/engine/feature-config-events-jobs.d.ts +2 -0
- package/dist/engine/feature-config-events-jobs.js +3 -0
- package/dist/engine/feature-entity-handlers.d.ts +4 -23
- package/dist/engine/feature-entity-handlers.js +77 -100
- package/dist/engine/feature-ui-extensions.d.ts +9 -14
- package/dist/engine/feature-ui-extensions.js +22 -14
- package/dist/engine/handler-field-references.d.ts +25 -0
- package/dist/engine/handler-field-references.js +80 -6
- package/dist/engine/index.d.ts +3 -3
- package/dist/engine/index.js +2 -2
- package/dist/engine/object-form.d.ts +2 -0
- package/dist/engine/object-form.js +13 -10
- package/dist/engine/registry-state.js +2 -2
- package/dist/engine/registry-validate.d.ts +1 -0
- package/dist/engine/registry-validate.js +21 -2
- package/dist/engine/registry.js +2 -1
- package/dist/engine/strip-disabled-features-from-app-schema.d.ts +6 -0
- package/dist/engine/strip-disabled-features-from-app-schema.js +89 -0
- package/dist/engine/types/index.d.ts +1 -1
- package/dist/files/feature.js +1 -1
- package/dist/jobs/job-runner.js +16 -2
- package/dist/pipeline/dispatch-query.js +1 -1
- package/dist/pipeline/dispatch-shared.d.ts +2 -1
- package/dist/pipeline/dispatch-shared.js +3 -6
- package/dist/pipeline/tenant-timezone-config-key.d.ts +1 -0
- package/dist/pipeline/tenant-timezone-config-key.js +6 -0
- package/dist/testing/index.d.ts +1 -0
- package/dist/testing/index.js +1 -0
- package/dist/testing/manual-clock.d.ts +14 -0
- package/dist/testing/manual-clock.js +12 -0
- package/dist/time/index.d.ts +1 -1
- package/dist/time/tz-context.d.ts +1 -1
- package/dist/time/tz-context.js +9 -4
- package/dist/upgrade-cli.js +13 -2
- package/package.json +4 -4
- package/src/changes.json +40 -0
- package/src/scripts/codemod/README.md +23 -0
- package/src/scripts/codemod/object-form.ts +709 -0
|
@@ -217,6 +217,9 @@ export function buildConfigEventsJobsMethods(state, name) {
|
|
|
217
217
|
...(resolvedDefinition.localizedTemplate !== undefined
|
|
218
218
|
? { localizedTemplate: resolvedDefinition.localizedTemplate }
|
|
219
219
|
: {}),
|
|
220
|
+
...(resolvedDefinition.renamedFrom !== undefined
|
|
221
|
+
? { renamedFrom: resolvedDefinition.renamedFrom }
|
|
222
|
+
: {}),
|
|
220
223
|
};
|
|
221
224
|
},
|
|
222
225
|
translations(def) {
|
|
@@ -3,34 +3,15 @@ import type { ZodType } from "zod";
|
|
|
3
3
|
import { type QueryHandlerDefinition, type StreamHandlerDefinition, type WriteHandlerDefinition } from "./define-handler.js";
|
|
4
4
|
import type { RegisterEntityCrudOptions } from "./entity-handlers.js";
|
|
5
5
|
import type { FeatureBuilderState } from "./feature-builder-state.js";
|
|
6
|
-
import type { AccessRule,
|
|
6
|
+
import type { AccessRule, EntityDefinition, EntityObjectDefinition, EntityRef, EscapeHatchDeclaration, HandlerRef, KumikoEventTypeMap, NameOrRef, RateLimitDeclaration, RelationDefinition, StreamHandlerFn } from "./types/index.js";
|
|
7
7
|
export declare function buildEntityHandlerMethods<TName extends string>(state: FeatureBuilderState, name: TName): {
|
|
8
|
-
entity(
|
|
9
|
-
readonly name: string;
|
|
10
|
-
} & EntityDefinition), definition?: EntityDefinition, options?: {
|
|
11
|
-
readonly table?: unknown;
|
|
12
|
-
}): EntityRef;
|
|
8
|
+
entity(definition: EntityObjectDefinition): EntityRef;
|
|
13
9
|
relation(entityRefOrDefinition: NameOrRef | ({
|
|
14
10
|
readonly entity: NameOrRef;
|
|
15
11
|
readonly name: string;
|
|
16
12
|
} & RelationDefinition), relationName?: string, definition?: RelationDefinition): void;
|
|
17
|
-
writeHandler<TName_1 extends string, TSchema extends ZodType, TPrepared = undefined>(
|
|
18
|
-
|
|
19
|
-
rateLimit?: RateLimitDeclaration;
|
|
20
|
-
additionalRateLimits?: readonly PayloadRateLimitOption[];
|
|
21
|
-
description?: string;
|
|
22
|
-
agent?: AgentHandlerHints;
|
|
23
|
-
escapeHatch?: EscapeHatchDeclaration;
|
|
24
|
-
}): HandlerRef;
|
|
25
|
-
queryHandler<TName_1 extends string, TSchema extends ZodType>(nameOrDef: string | QueryHandlerDefinition<TName_1, TSchema>, schema?: TSchema, handler?: QueryHandlerFn<z.infer<TSchema>>, options?: {
|
|
26
|
-
access: AccessRule;
|
|
27
|
-
rateLimit?: RateLimitDeclaration;
|
|
28
|
-
outputSchema?: ZodType;
|
|
29
|
-
liveEntities?: readonly string[];
|
|
30
|
-
description?: string;
|
|
31
|
-
agent?: AgentHandlerHints;
|
|
32
|
-
escapeHatch?: EscapeHatchDeclaration;
|
|
33
|
-
}): HandlerRef;
|
|
13
|
+
writeHandler<TName_1 extends string, TSchema extends ZodType, TPrepared = undefined>(def: WriteHandlerDefinition<TName_1, TSchema, unknown, KumikoEventTypeMap, TPrepared>): HandlerRef;
|
|
14
|
+
queryHandler<TName_1 extends string, TSchema extends ZodType>(def: QueryHandlerDefinition<TName_1, TSchema>): HandlerRef;
|
|
34
15
|
streamHandler<TName_1 extends string, TSchema extends ZodType>(nameOrDef: string | StreamHandlerDefinition<TName_1, TSchema>, schema?: TSchema, handler?: StreamHandlerFn<z.infer<TSchema>>, options?: {
|
|
35
16
|
access: AccessRule;
|
|
36
17
|
rateLimit?: RateLimitDeclaration;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { ENTITY_CONVENTION_QUERY_BRAND } from "@cosmicdrift/kumiko-types/handlers";
|
|
2
2
|
import { toTableName } from "../db/table-builder.js";
|
|
3
3
|
import { isEntityConventionQueryHandler, isPagedQueryHandler, PAGED_QUERY_HANDLER_BRAND, } from "./define-handler.js";
|
|
4
|
-
import {
|
|
4
|
+
import { registerCrudHandlers } from "./entity-handlers.js";
|
|
5
5
|
import { resolveName } from "./handler-helpers.js";
|
|
6
|
-
import {
|
|
6
|
+
import { isObjectArgument, throwPositionalFormRemoved } from "./object-form.js";
|
|
7
7
|
const CRUD_VERBS = new Set(["create", "update", "delete"]);
|
|
8
8
|
const CRUD_REGISTERED_VERBS = new Set([...CRUD_VERBS, "restore", "list", "detail"]);
|
|
9
9
|
// A silent overwrite would drop framework behaviour that rides on the r.crud
|
|
@@ -65,6 +65,13 @@ function transactionPhaseSlots(def) {
|
|
|
65
65
|
...(def.transaction && { transaction: def.transaction }),
|
|
66
66
|
};
|
|
67
67
|
}
|
|
68
|
+
// Typed callers cannot omit `access`; untyped ones (JS, designer output) must not get a
|
|
69
|
+
// handler that silently falls through to the boot-time default-deny.
|
|
70
|
+
function assertHandlerHasAccess(featureName, method, handlerName, access) {
|
|
71
|
+
if (access === undefined || access === null) {
|
|
72
|
+
throw new Error(`[Feature ${featureName}] r.${method}({ name: "${handlerName}" }) requires an access rule (access: { roles: [...] } or { openToAll: { reason } })`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
68
75
|
function requireInlineHandlerArgs(kind, schema, handler, options) {
|
|
69
76
|
if (!schema || !handler || !options?.access) {
|
|
70
77
|
throw new Error(`${kind} inline form requires schema + handler + options.access`);
|
|
@@ -75,13 +82,13 @@ function requireInlineHandlerArgs(kind, schema, handler, options) {
|
|
|
75
82
|
// methods that create or reference entities.
|
|
76
83
|
export function buildEntityHandlerMethods(state, name) {
|
|
77
84
|
const methods = {
|
|
78
|
-
entity(
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
85
|
+
entity(definition) {
|
|
86
|
+
if (!isObjectArgument(definition))
|
|
87
|
+
throwPositionalFormRemoved(name, "entity");
|
|
88
|
+
const { name: entityName, backingTable, ...entityDefinition } = definition;
|
|
82
89
|
state.entities[entityName] = entityDefinition;
|
|
83
|
-
if (
|
|
84
|
-
state.entityTables[entityName] =
|
|
90
|
+
if (backingTable !== undefined)
|
|
91
|
+
state.entityTables[entityName] = backingTable;
|
|
85
92
|
return { name: entityName, table: entityDefinition.table ?? toTableName(entityName) };
|
|
86
93
|
},
|
|
87
94
|
relation(entityRefOrDefinition, relationName, definition) {
|
|
@@ -96,105 +103,75 @@ export function buildEntityHandlerMethods(state, name) {
|
|
|
96
103
|
state.relations[entityName] = {};
|
|
97
104
|
state.relations[entityName][resolvedRelationName] = resolvedDefinition;
|
|
98
105
|
},
|
|
99
|
-
writeHandler(
|
|
100
|
-
if (
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
};
|
|
134
|
-
tryMapEntity(state, name, def.name);
|
|
135
|
-
return { name: def.name };
|
|
136
|
-
}
|
|
137
|
-
const inline = requireInlineHandlerArgs("writeHandler", schema, handler, options);
|
|
138
|
-
assertHandlerNameFree(state, name, "write", nameOrDef);
|
|
139
|
-
state.writeHandlers[nameOrDef] = {
|
|
140
|
-
name: nameOrDef,
|
|
141
|
-
schema: inline.schema,
|
|
142
|
-
handler: inline.handler, // @cast-boundary engine-bridge
|
|
143
|
-
access: inline.options.access,
|
|
144
|
-
...agentSlots(inline.options),
|
|
145
|
-
...(inline.options.rateLimit && { rateLimit: inline.options.rateLimit }),
|
|
146
|
-
...(inline.options.additionalRateLimits && {
|
|
147
|
-
additionalRateLimits: inline.options.additionalRateLimits,
|
|
106
|
+
writeHandler(def) {
|
|
107
|
+
if (!isObjectArgument(def))
|
|
108
|
+
throwPositionalFormRemoved(name, "writeHandler");
|
|
109
|
+
assertHandlerHasAccess(name, "writeHandler", def.name, def.access);
|
|
110
|
+
assertHandlerNameFree(state, name, "write", def.name);
|
|
111
|
+
state.writeHandlers[def.name] = {
|
|
112
|
+
name: def.name,
|
|
113
|
+
schema: def.schema,
|
|
114
|
+
// @cast-boundary engine-bridge — typed Dev-API's handler is
|
|
115
|
+
// generic over the schema's parsed payload (`WriteEvent<output<TSchema>>`),
|
|
116
|
+
// the storage form WriteHandlerFn carries `WriteEvent<unknown>`.
|
|
117
|
+
// Function-arg variance: TS sees the typed handler as stricter
|
|
118
|
+
// than the loose storage shape and rejects direct assignment.
|
|
119
|
+
// The runtime value is identical — the cast crosses that boundary.
|
|
120
|
+
// `satisfies` does not work here (it asserts assignability, which
|
|
121
|
+
// is what fails). Explicit cast is the right tool.
|
|
122
|
+
handler: def.handler,
|
|
123
|
+
access: def.access,
|
|
124
|
+
...agentSlots(def),
|
|
125
|
+
...(def.excludedFields && { excludedFields: def.excludedFields }),
|
|
126
|
+
...(def.unsafeSkipTransitionGuard && { unsafeSkipTransitionGuard: true }),
|
|
127
|
+
...(def.rateLimit && { rateLimit: def.rateLimit }),
|
|
128
|
+
...(def.additionalRateLimits && { additionalRateLimits: def.additionalRateLimits }),
|
|
129
|
+
...(def.escapeHatch && { escapeHatch: def.escapeHatch }),
|
|
130
|
+
...transactionPhaseSlots(def),
|
|
131
|
+
...(def.tenantlessAnonymous && { tenantlessAnonymous: true }),
|
|
132
|
+
// Forward the pipeline-build closure so boot-validators and
|
|
133
|
+
// Designer/AI tooling can inspect the step list. Absent on
|
|
134
|
+
// free-form handlers — defineWriteHandler only sets `perform`
|
|
135
|
+
// when the author used the pipeline form. Variance cast
|
|
136
|
+
// mirrors the handler-cast above: PipelineDef<output<TSchema>>
|
|
137
|
+
// is stricter than PipelineDef<unknown> for the same reason.
|
|
138
|
+
...(def.perform !== undefined && {
|
|
139
|
+
perform: def.perform,
|
|
148
140
|
}),
|
|
149
|
-
...(inline.options.escapeHatch && { escapeHatch: inline.options.escapeHatch }),
|
|
150
141
|
};
|
|
151
|
-
tryMapEntity(state, name,
|
|
152
|
-
return { name:
|
|
142
|
+
tryMapEntity(state, name, def.name);
|
|
143
|
+
return { name: def.name };
|
|
153
144
|
},
|
|
154
|
-
queryHandler(
|
|
155
|
-
if (
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
}
|
|
176
|
-
tryMapEntity(state, name, def.name);
|
|
177
|
-
return { name: def.name };
|
|
178
|
-
}
|
|
179
|
-
const inline = requireInlineHandlerArgs("queryHandler", schema, handler, options);
|
|
180
|
-
assertHandlerNameFree(state, name, "query", nameOrDef);
|
|
181
|
-
state.queryHandlers[nameOrDef] = {
|
|
182
|
-
name: nameOrDef,
|
|
183
|
-
schema: inline.schema,
|
|
184
|
-
handler: inline.handler, // @cast-boundary engine-bridge
|
|
185
|
-
access: inline.options.access,
|
|
186
|
-
...agentSlots(inline.options),
|
|
187
|
-
...(inline.options.rateLimit && { rateLimit: inline.options.rateLimit }),
|
|
188
|
-
...(inline.options.outputSchema && { outputSchema: inline.options.outputSchema }),
|
|
189
|
-
...(inline.options.liveEntities && { liveEntities: inline.options.liveEntities }),
|
|
190
|
-
...(inline.options.escapeHatch && { escapeHatch: inline.options.escapeHatch }),
|
|
145
|
+
queryHandler(def) {
|
|
146
|
+
if (!isObjectArgument(def))
|
|
147
|
+
throwPositionalFormRemoved(name, "queryHandler");
|
|
148
|
+
assertHandlerHasAccess(name, "queryHandler", def.name, def.access);
|
|
149
|
+
assertHandlerNameFree(state, name, "query", def.name);
|
|
150
|
+
state.queryHandlers[def.name] = {
|
|
151
|
+
name: def.name,
|
|
152
|
+
schema: def.schema,
|
|
153
|
+
// @cast-boundary engine-bridge — typed Dev-API → erased internal storage
|
|
154
|
+
handler: def.handler, // @cast-boundary engine-bridge
|
|
155
|
+
access: def.access,
|
|
156
|
+
...agentSlots(def),
|
|
157
|
+
...(def.rateLimit && { rateLimit: def.rateLimit }),
|
|
158
|
+
...(def.outputSchema && { outputSchema: def.outputSchema }),
|
|
159
|
+
...(def.liveEntities && { liveEntities: def.liveEntities }),
|
|
160
|
+
...(def.escapeHatch && { escapeHatch: def.escapeHatch }),
|
|
161
|
+
// Carry the definePagedQueryHandler brand through — this rebuild
|
|
162
|
+
// drops any field not explicitly listed.
|
|
163
|
+
...(isPagedQueryHandler(def) && { [PAGED_QUERY_HANDLER_BRAND]: true }),
|
|
164
|
+
...(isEntityConventionQueryHandler(def) && {
|
|
165
|
+
[ENTITY_CONVENTION_QUERY_BRAND]: true,
|
|
166
|
+
}),
|
|
191
167
|
};
|
|
192
|
-
tryMapEntity(state, name,
|
|
193
|
-
return { name:
|
|
168
|
+
tryMapEntity(state, name, def.name);
|
|
169
|
+
return { name: def.name };
|
|
194
170
|
},
|
|
195
171
|
streamHandler(nameOrDef, schema, handler, options) {
|
|
196
172
|
if (typeof nameOrDef === "object") {
|
|
197
173
|
const def = nameOrDef;
|
|
174
|
+
assertHandlerHasAccess(name, "streamHandler", def.name, def.access);
|
|
198
175
|
state.streamHandlers[def.name] = {
|
|
199
176
|
name: def.name,
|
|
200
177
|
schema: def.schema,
|
|
@@ -221,7 +198,7 @@ export function buildEntityHandlerMethods(state, name) {
|
|
|
221
198
|
return {
|
|
222
199
|
...methods,
|
|
223
200
|
crud(entityName, entity, options) {
|
|
224
|
-
|
|
201
|
+
registerCrudHandlers(methods, entityName, entity, options);
|
|
225
202
|
},
|
|
226
203
|
};
|
|
227
204
|
}
|
|
@@ -2,17 +2,12 @@ import { type WebSocketRouteDefinition } from "@cosmicdrift/kumiko-types/websock
|
|
|
2
2
|
import type { EntityTableMeta } from "../db/entity-table-meta.js";
|
|
3
3
|
import type { FeatureBuilderState } from "./feature-builder-state.js";
|
|
4
4
|
import type { HttpRouteDefinition } from "./types/http-route.js";
|
|
5
|
-
import type { BootCheckFn, EntityProjectionExtension,
|
|
5
|
+
import type { BootCheckFn, EntityProjectionExtension, ExtensionSelectorPanel, HookDefinition, MultiStreamProjectionDefinition, NameOrRef, ProjectionDefinition, RegistrarExtensionDef, SearchPayloadContributorFn, StoreTableOptions, TreeActionDef, TreeActionsHandle } from "./types/index.js";
|
|
6
6
|
import type { ContentCollectionDefinition, NavDefinition } from "./types/nav.js";
|
|
7
7
|
import type { ScreenDefinition } from "./types/screen.js";
|
|
8
8
|
import type { WorkspaceDefinition } from "./types/workspace.js";
|
|
9
9
|
export declare function buildUiExtensionsMethods<TName extends string>(state: FeatureBuilderState, name: TName): {
|
|
10
|
-
hook(
|
|
11
|
-
readonly allOf: NameOrRef;
|
|
12
|
-
}, fn: LifecycleHookFn | ValidationHookFn, options?: {
|
|
13
|
-
phase?: HookPhase;
|
|
14
|
-
escapeHatch?: EscapeHatchDeclaration;
|
|
15
|
-
}): void;
|
|
10
|
+
hook(definition: HookDefinition): void;
|
|
16
11
|
searchPayloadExtension(entityRef: NameOrRef, fn: SearchPayloadContributorFn): void;
|
|
17
12
|
extendsRegistrar(extensionName: string, def: RegistrarExtensionDef): void;
|
|
18
13
|
useExtension(extensionNameOrDefinition: string | ({
|
|
@@ -25,20 +20,20 @@ export declare function buildUiExtensionsMethods<TName extends string>(state: Fe
|
|
|
25
20
|
readonly panels?: readonly ExtensionSelectorPanel[];
|
|
26
21
|
}): void;
|
|
27
22
|
/**
|
|
28
|
-
* Marker
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
23
|
+
* Marker declaration: this feature provides a cross-feature API under
|
|
24
|
+
* the given name. The implementation is registered separately as a query
|
|
25
|
+
* or write handler under the QN pattern; r.exposesApi only feeds the
|
|
26
|
+
* boot check.
|
|
32
27
|
*
|
|
33
|
-
*
|
|
28
|
+
* Example:
|
|
34
29
|
* defineFeature("compliance-profiles", (r) => {
|
|
35
30
|
* r.exposesApi("compliance.forTenant");
|
|
36
31
|
* r.queryHandler({ name: "compliance:query:for-tenant", ... });
|
|
37
32
|
* });
|
|
38
33
|
* defineFeature("user-data-rights", (r) => {
|
|
39
|
-
* r.requires("compliance-profiles");
|
|
34
|
+
* r.requires({ features: ["compliance-profiles"] });
|
|
40
35
|
* r.usesApi("compliance.forTenant");
|
|
41
|
-
* //
|
|
36
|
+
* // in a handler: ctx.callQuery("compliance:query:for-tenant", ...)
|
|
42
37
|
* });
|
|
43
38
|
*/
|
|
44
39
|
exposesApi(apiName: string): void;
|
|
@@ -4,6 +4,7 @@ import { WEBSOCKET_MAX_CONNECTIONS_PER_USER_LIMIT, WEBSOCKET_MAX_PAYLOAD_BYTES,
|
|
|
4
4
|
import { bindHookEscapeHatchGrant } from "../pipeline/system-identity-switch.js";
|
|
5
5
|
import { LifecycleHookTypes } from "./constants.js";
|
|
6
6
|
import { resolveName } from "./handler-helpers.js";
|
|
7
|
+
import { isObjectArgument, throwPositionalFormRemoved } from "./object-form.js";
|
|
7
8
|
import { isKebabSegment, isValidQn, qualifyEntityName, toKebab } from "./qualified-name.js";
|
|
8
9
|
import { HookPhases } from "./types/index.js";
|
|
9
10
|
// Builds hooks/extensions/projections/screens/nav/workspace/tables/tree-actions
|
|
@@ -43,8 +44,8 @@ function isEntityWideHookType(type) {
|
|
|
43
44
|
type === LifecycleHookTypes.postDelete ||
|
|
44
45
|
type === LifecycleHookTypes.postQuery);
|
|
45
46
|
}
|
|
46
|
-
// r.hook(type, { allOf: entity },
|
|
47
|
-
// entity"
|
|
47
|
+
// r.hook({ type, target: { allOf: entity }, handler }) — "all write/query handlers of
|
|
48
|
+
// this entity". Hook-fn casts
|
|
48
49
|
// below: @cast-boundary engine-bridge — typed Dev-API (LifecycleHookFn) →
|
|
49
50
|
// erased Map<entityName, fn>.
|
|
50
51
|
function registerEntityWideHook(state, featureName, type, entityName, fn, options) {
|
|
@@ -107,21 +108,28 @@ export function buildUiExtensionsMethods(state, name) {
|
|
|
107
108
|
state.navs[navDefinition.id] = Object.fromEntries(Object.entries(navDefinition).filter(([, value]) => value !== undefined));
|
|
108
109
|
}
|
|
109
110
|
return {
|
|
110
|
-
hook(
|
|
111
|
+
hook(definition) {
|
|
112
|
+
if (!isObjectArgument(definition))
|
|
113
|
+
throwPositionalFormRemoved(name, "hook");
|
|
114
|
+
const { type, target, handler: fn } = definition;
|
|
115
|
+
const options = {
|
|
116
|
+
...(definition.phase !== undefined && { phase: definition.phase }),
|
|
117
|
+
...(definition.escapeHatch !== undefined && { escapeHatch: definition.escapeHatch }),
|
|
118
|
+
};
|
|
111
119
|
if (type === "validation") {
|
|
112
120
|
if (options?.escapeHatch !== undefined) {
|
|
113
|
-
throw new Error(`[Feature ${name}] r.hook("validation",
|
|
121
|
+
throw new Error(`[Feature ${name}] r.hook({ type: "validation", … }) does not accept escapeHatch — ` +
|
|
114
122
|
"validation hooks receive no context to switch identity with.");
|
|
115
123
|
}
|
|
116
124
|
}
|
|
117
125
|
else if (options?.escapeHatch !== undefined &&
|
|
118
126
|
options.escapeHatch.reason.trim().length === 0) {
|
|
119
|
-
throw new Error(`[Feature ${name}] r.hook("${type}",
|
|
127
|
+
throw new Error(`[Feature ${name}] r.hook({ type: "${type}", … }) declares escapeHatch: { reason: "" } — ` +
|
|
120
128
|
"the reason must be a non-empty string explaining why this hook switches identity to SYSTEM.");
|
|
121
129
|
}
|
|
122
130
|
const hookGrantsProblem = options?.escapeHatch && escapeHatchGrantsProblem(options.escapeHatch);
|
|
123
131
|
if (hookGrantsProblem) {
|
|
124
|
-
throw new Error(`[Feature ${name}] r.hook("${type}",
|
|
132
|
+
throw new Error(`[Feature ${name}] r.hook({ type: "${type}", … }) declares an invalid escapeHatch — ${hookGrantsProblem}`);
|
|
125
133
|
}
|
|
126
134
|
// Wrapped once for both branches below; validation hooks stay unwrapped (no context).
|
|
127
135
|
const hookLabel = `${type} hook of feature "${name}"`;
|
|
@@ -135,7 +143,7 @@ export function buildUiExtensionsMethods(state, name) {
|
|
|
135
143
|
!Array.isArray(target) &&
|
|
136
144
|
"allOf" in target) {
|
|
137
145
|
if (!isEntityWideHookType(type)) {
|
|
138
|
-
throw new Error(`[Feature ${name}] r.hook("${type}", { allOf },
|
|
146
|
+
throw new Error(`[Feature ${name}] r.hook({ type: "${type}", target: { allOf }, … }) only supports ` +
|
|
139
147
|
`postSave/preDelete/postDelete/postQuery, not "${type}".`);
|
|
140
148
|
}
|
|
141
149
|
registerEntityWideHook(state, name, type, resolveName(target.allOf), wrapped, // @cast-boundary engine-bridge
|
|
@@ -241,20 +249,20 @@ export function buildUiExtensionsMethods(state, name) {
|
|
|
241
249
|
});
|
|
242
250
|
},
|
|
243
251
|
/**
|
|
244
|
-
* Marker
|
|
245
|
-
*
|
|
246
|
-
*
|
|
247
|
-
*
|
|
252
|
+
* Marker declaration: this feature provides a cross-feature API under
|
|
253
|
+
* the given name. The implementation is registered separately as a query
|
|
254
|
+
* or write handler under the QN pattern; r.exposesApi only feeds the
|
|
255
|
+
* boot check.
|
|
248
256
|
*
|
|
249
|
-
*
|
|
257
|
+
* Example:
|
|
250
258
|
* defineFeature("compliance-profiles", (r) => {
|
|
251
259
|
* r.exposesApi("compliance.forTenant");
|
|
252
260
|
* r.queryHandler({ name: "compliance:query:for-tenant", ... });
|
|
253
261
|
* });
|
|
254
262
|
* defineFeature("user-data-rights", (r) => {
|
|
255
|
-
* r.requires("compliance-profiles");
|
|
263
|
+
* r.requires({ features: ["compliance-profiles"] });
|
|
256
264
|
* r.usesApi("compliance.forTenant");
|
|
257
|
-
* //
|
|
265
|
+
* // in a handler: ctx.callQuery("compliance:query:for-tenant", ...)
|
|
258
266
|
* });
|
|
259
267
|
*/
|
|
260
268
|
exposesApi(apiName) {
|
|
@@ -18,5 +18,30 @@ export type HandlerFieldReferenceReading = {
|
|
|
18
18
|
readonly kind: "ok";
|
|
19
19
|
readonly reference: HandlerFieldReference;
|
|
20
20
|
};
|
|
21
|
+
export type HandlerFieldPathSegment = {
|
|
22
|
+
readonly kind: "field";
|
|
23
|
+
readonly name: string;
|
|
24
|
+
} | {
|
|
25
|
+
readonly kind: "element";
|
|
26
|
+
} | {
|
|
27
|
+
readonly kind: "recordKey";
|
|
28
|
+
} | {
|
|
29
|
+
readonly kind: "recordValue";
|
|
30
|
+
};
|
|
31
|
+
export type HandlerFieldReferenceAtPath = {
|
|
32
|
+
readonly path: string;
|
|
33
|
+
readonly segments: readonly HandlerFieldPathSegment[];
|
|
34
|
+
readonly reading: Exclude<HandlerFieldReferenceReading, {
|
|
35
|
+
kind: "none";
|
|
36
|
+
}>;
|
|
37
|
+
};
|
|
21
38
|
export declare function readHandlerFieldReference(schema: z.ZodType, field: string): HandlerFieldReferenceReading;
|
|
39
|
+
/** All reference metas of a handler input schema, including fields nested in arrays,
|
|
40
|
+
* objects and records. `z.lazy()` is not followed. */
|
|
41
|
+
export declare function readHandlerFieldReferences(schema: z.ZodType): readonly HandlerFieldReferenceAtPath[];
|
|
42
|
+
export declare function handlerFieldReferences(schema: z.ZodType): readonly {
|
|
43
|
+
readonly path: string;
|
|
44
|
+
readonly segments: readonly HandlerFieldPathSegment[];
|
|
45
|
+
readonly reference: HandlerFieldReference;
|
|
46
|
+
}[];
|
|
22
47
|
export declare function handlerFieldReference(schema: z.ZodType, field: string): HandlerFieldReference | undefined;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as z from "zod";
|
|
2
|
-
import { zodDef, zodMeta, zodShapeField } from "../env/_zod-introspect.js";
|
|
2
|
+
import { zodDef, zodMeta, zodShape, zodShapeField } from "../env/_zod-introspect.js";
|
|
3
3
|
export const HANDLER_FIELD_REFERENCES_META_KEY = "references";
|
|
4
4
|
const MAX_WRAPPER_DEPTH = 8;
|
|
5
|
+
const MAX_NESTING_DEPTH = 8;
|
|
5
6
|
const referenceMetaSchema = z.union([
|
|
6
7
|
z.string().min(1),
|
|
7
8
|
z.object({ entity: z.string().min(1), by: z.string().min(1).optional() }),
|
|
@@ -42,11 +43,7 @@ function isArrayField(field) {
|
|
|
42
43
|
}
|
|
43
44
|
return false;
|
|
44
45
|
}
|
|
45
|
-
|
|
46
|
-
const objectSchema = unwrapObjectSchema(schema);
|
|
47
|
-
const fieldSchema = objectSchema && zodShapeField(objectSchema, field);
|
|
48
|
-
if (fieldSchema === undefined)
|
|
49
|
-
return { kind: "none" };
|
|
46
|
+
function readFieldReference(fieldSchema) {
|
|
50
47
|
const raw = findRawReferenceMeta(fieldSchema);
|
|
51
48
|
if (raw === undefined)
|
|
52
49
|
return { kind: "none" };
|
|
@@ -63,6 +60,83 @@ export function readHandlerFieldReference(schema, field) {
|
|
|
63
60
|
},
|
|
64
61
|
};
|
|
65
62
|
}
|
|
63
|
+
export function readHandlerFieldReference(schema, field) {
|
|
64
|
+
const objectSchema = unwrapObjectSchema(schema);
|
|
65
|
+
const fieldSchema = objectSchema && zodShapeField(objectSchema, field);
|
|
66
|
+
if (fieldSchema === undefined)
|
|
67
|
+
return { kind: "none" };
|
|
68
|
+
return readFieldReference(fieldSchema);
|
|
69
|
+
}
|
|
70
|
+
function pathOf(segments) {
|
|
71
|
+
let path = "";
|
|
72
|
+
for (const segment of segments) {
|
|
73
|
+
if (segment.kind === "field")
|
|
74
|
+
path += path === "" ? segment.name : `.${segment.name}`;
|
|
75
|
+
else if (segment.kind === "element")
|
|
76
|
+
path += "[]";
|
|
77
|
+
else if (segment.kind === "recordKey")
|
|
78
|
+
path += "{key}";
|
|
79
|
+
else
|
|
80
|
+
path += "{}";
|
|
81
|
+
}
|
|
82
|
+
return path;
|
|
83
|
+
}
|
|
84
|
+
function collectAt(schema, segments, out) {
|
|
85
|
+
const reading = readFieldReference(schema);
|
|
86
|
+
if (reading.kind !== "none")
|
|
87
|
+
out.push({ path: pathOf(segments), segments, reading });
|
|
88
|
+
}
|
|
89
|
+
function walkNested(schema, segments, depth, out) {
|
|
90
|
+
// skip: schemas nested deeper than MAX_NESTING_DEPTH are not inspected
|
|
91
|
+
if (depth > MAX_NESTING_DEPTH)
|
|
92
|
+
return;
|
|
93
|
+
let current = schema;
|
|
94
|
+
let currentSegments = segments;
|
|
95
|
+
for (let layer = 0; layer < MAX_WRAPPER_DEPTH && current !== undefined; layer++) {
|
|
96
|
+
if (current instanceof z.ZodObject) {
|
|
97
|
+
walkObject(current, currentSegments, depth, out);
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
if (current instanceof z.ZodRecord) {
|
|
101
|
+
const { keyType, valueType } = current;
|
|
102
|
+
if (keyType instanceof z.ZodType) {
|
|
103
|
+
collectAt(keyType, [...currentSegments, { kind: "recordKey" }], out);
|
|
104
|
+
}
|
|
105
|
+
if (valueType instanceof z.ZodType) {
|
|
106
|
+
const valueSegments = [...currentSegments, { kind: "recordValue" }];
|
|
107
|
+
collectAt(valueType, valueSegments, out);
|
|
108
|
+
walkNested(valueType, valueSegments, depth + 1, out);
|
|
109
|
+
}
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
if (current instanceof z.ZodArray) {
|
|
113
|
+
currentSegments = [...currentSegments, { kind: "element" }];
|
|
114
|
+
current = zodDef(current)?.element;
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
current = zodDef(current)?.innerType;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
function walkObject(objectSchema, segments, depth, out) {
|
|
121
|
+
for (const [name, fieldSchema] of Object.entries(zodShape(objectSchema))) {
|
|
122
|
+
const fieldSegments = [...segments, { kind: "field", name }];
|
|
123
|
+
collectAt(fieldSchema, fieldSegments, out);
|
|
124
|
+
walkNested(fieldSchema, fieldSegments, depth + 1, out);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/** All reference metas of a handler input schema, including fields nested in arrays,
|
|
128
|
+
* objects and records. `z.lazy()` is not followed. */
|
|
129
|
+
export function readHandlerFieldReferences(schema) {
|
|
130
|
+
const objectSchema = unwrapObjectSchema(schema);
|
|
131
|
+
if (objectSchema === undefined)
|
|
132
|
+
return [];
|
|
133
|
+
const out = [];
|
|
134
|
+
walkObject(objectSchema, [], 0, out);
|
|
135
|
+
return out;
|
|
136
|
+
}
|
|
137
|
+
export function handlerFieldReferences(schema) {
|
|
138
|
+
return readHandlerFieldReferences(schema).flatMap(({ path, segments, reading }) => reading.kind === "ok" ? [{ path, segments, reference: reading.reference }] : []);
|
|
139
|
+
}
|
|
66
140
|
export function handlerFieldReference(schema, field) {
|
|
67
141
|
const reading = readHandlerFieldReference(schema, field);
|
|
68
142
|
return reading.kind === "ok" ? reading.reference : undefined;
|
package/dist/engine/index.d.ts
CHANGED
|
@@ -25,7 +25,7 @@ export type { WorkflowDefinition, WorkflowInput, WorkflowTrigger } from "./defin
|
|
|
25
25
|
export { computeDefinitionFingerprint, defineWorkflow } from "./define-workflow.js";
|
|
26
26
|
export type { ToggleReader } from "./effective-features.js";
|
|
27
27
|
export { computeEffectiveFeatures, isToggleableFeature } from "./effective-features.js";
|
|
28
|
-
export { createEntityExecutor, defineEntityCreateHandler, defineEntityDeleteHandler, defineEntityDetailHandler, defineEntityListHandler, defineEntityQueryHandler, defineEntityRestoreHandler, defineEntityUpdateHandler, defineEntityWriteHandler, defineProjectionQueryHandler, type EntityCrudRegistrar, entityListSchema, MAX_LIST_LIMIT, type RegisterEntityCrudOptions,
|
|
28
|
+
export { createEntityExecutor, defineEntityCreateHandler, defineEntityDeleteHandler, defineEntityDetailHandler, defineEntityListHandler, defineEntityQueryHandler, defineEntityRestoreHandler, defineEntityUpdateHandler, defineEntityWriteHandler, defineProjectionQueryHandler, type EntityCrudRegistrar, entityListSchema, MAX_LIST_LIMIT, type RegisterEntityCrudOptions, } from "./entity-handlers.js";
|
|
29
29
|
export { declareEscapeHatch } from "./escape-hatch-declaration.js";
|
|
30
30
|
export type { EmitCtx } from "./event-helpers.js";
|
|
31
31
|
export { emitEvent, typedPayload } from "./event-helpers.js";
|
|
@@ -43,7 +43,7 @@ export { addPattern, applyChanges, createFeaturePatcher, getPatternSchema, group
|
|
|
43
43
|
export { type ChangelogEntry, type ChangelogType, compareVersions, type FeatureChangelog, filterEntriesAfter, parseFeatureChangelog, sortEntries, validateChangelog, } from "./feature-changelog.js";
|
|
44
44
|
export { type BuildManifestOptions, buildManifestFromRegistry, type FeatureManifest, type ManifestConfigKey, type ManifestExtension, type ManifestFeature, type ManifestSecret, type ManifestSystemEvent, serializeManifest, } from "./feature-manifest.js";
|
|
45
45
|
export { checkWriteFieldOwnership, checkWriteFieldRoles, filterReadFields, maskWriteOnlyFields, } from "./field-access.js";
|
|
46
|
-
export { HANDLER_FIELD_REFERENCES_META_KEY, type HandlerFieldReference, type HandlerFieldReferenceMeta, handlerFieldReference, } from "./handler-field-references.js";
|
|
46
|
+
export { HANDLER_FIELD_REFERENCES_META_KEY, type HandlerFieldPathSegment, type HandlerFieldReference, type HandlerFieldReferenceAtPath, type HandlerFieldReferenceMeta, handlerFieldReference, handlerFieldReferences, readHandlerFieldReferences, } from "./handler-field-references.js";
|
|
47
47
|
export { resolveName, withResponseData } from "./handler-helpers.js";
|
|
48
48
|
export { i18nKey } from "./i18n-key.js";
|
|
49
49
|
export { buildSessionRoles, findForbiddenMembershipRole, isForbiddenMembershipRole, stripForbiddenMembershipRoles, } from "./membership-roles.js";
|
|
@@ -81,7 +81,7 @@ export { assertNotificationVariables, templateVariable, templateVariablesToZod,
|
|
|
81
81
|
export { type EffectiveFeaturesResolver, findTierResolverUsage, isTierResolverPlugin, requireTierResolverPlugin, TENANT_TIER_RESOLVER_EXT, type TierResolverPlugin, type TrialGate, } from "./tier-resolver-extension.js";
|
|
82
82
|
export { findOverDeepTransferChain, resolveTransferAdjacency as resolveEntityTransferAdjacency, type TransferAdjacency, type TransferEdge, type TransferEdgeLink, } from "./transfer-adjacency.js";
|
|
83
83
|
export { isSystemTenant, isUuid, parseTenantId, SYSTEM_TENANT_ID } from "./types/identifiers.js";
|
|
84
|
-
export type { AccessRule, ActionFormScreenDefinition, ActiveMembership, ActiveMembershipRejection, ActiveMembershipResult, AgentExposure, AgentHandlerHints, AgentRisk, AppContext, AppendEventArgs, AppendEventFn, AuthClaimsContext, AuthClaimsFn, AuthClaimsHookDef, BeforeTransactionPhase, BeforeTransactionResult, BelongsToRelation, BigIntFieldDef, BooleanFieldDef, CamelToKebab, ChatSendFailureCode, ClaimKeyDefinition, ClaimKeyHandle, ClaimKeyJsType, ClaimKeyType, ConcurrencyMode, ConfigAccessor, ConfigAccessorFactory, ConfigBacking, ConfigCascade, ConfigCascadeLevel, ConfigDefinition, ConfigEditScreenDefinition, ConfigKeyAccess, ConfigKeyDefinition, ConfigKeyHandle, ConfigKeyType, ConfigMask, ConfigResolver, ConfigScope, ConfigSecretsReader, ConfigSeedDef, ConfigStoredRow, ConfigStoredRowWithSource, ConfigValidateContext, ConfigValidateFn, ConfigValue, ConfigValueSource, ConfigValueWithSource, ContentCollectionDefinition, CreateSeedOptions, CreateTenantSeedOptions, CreateUserSeedOptions, CustomScreenDefinition, CustomScreenRoute, DashboardChartPanel, DashboardCustomPanel, DashboardDateParam, DashboardFeedPanel, DashboardFilterDefinition, DashboardI18nText, DashboardListPanel, DashboardMoneyParam, DashboardPanelDefinition, DashboardPanelVisibility, DashboardProgressListPanel, DashboardScreenDefinition, DashboardScreenPanel, DashboardStatGroupPanel, DashboardStatPanel, DashboardText, DashboardTextParam, DashboardValueFormat, DateFieldDef, DecimalFieldDef, DeleteContext, DeliveryErrorCode, DeliveryFailureCode, DeliverySkipReason, DeriveContext, DerivedFieldDef, DerivedFieldsMap, DerivedValueType, EditExtensionSection, EditFieldPrefill, EditFieldSpec, EditFieldsSection, EditLayout, EditRelatedListSection, EditSectionSpec, EmbeddedListEditSpec, EntityDefinition, EntityEditAction, EntityEditActionPlacement, EntityEditScreenDefinition, EntityId, EntityListExpandableRow, EntityListScreenDefinition, EntityRef, EntityRelations, EscapeHatchAuditSink, EscapeHatchDeclaration, EscapeHatchKind, EscapeHatchReporter, EscapeHatchTarget, EscapeHatchUseEvent, EventDef, ExtensionOptionsArgs, ExtensionOptionsFor, FeatureDefinition, FeatureRegistrar, FieldAccess, FieldCondition, FieldDefinition, FieldFormatRegistry, FieldIconKey, FieldRenderer, FileFieldDef, FilesFieldDef, Findability, FormatSpec, FormWidth, HandlerContext, HasManyRelation, HookMap, ImageFieldDef, ImagesFieldDef, JobBackoff, JobBackoffStrategy, JobContext, JobDefinition, JobHandlerFn, JobTrigger, JobTriggerEvent, JsonbFieldDef, KumikoEntityTypeMap, KumikoEventTypeMap, KumikoExtensionOptionsMap, KumikoHandlerPayloadMap, KumikoHandlerResultMap, LifecycleHookType, ListColumnSpec, ListFacetSpec, ListPaginationMode, ListSortDir, ListSortSpec, LongTextFindability, ManyToManyRelation, MaxPerTenantOptions, MemberReader, MetricNavigate, MetricSpec, MspErrorMode, MspErrorPolicy, MultiSelectFieldDef, MultiStreamApplyFn, MultiStreamProjectionDefinition, NameOrRef, NavDefinition, NavIconKey, NotificationDataFn, NotificationDefinition, NotificationLocalizedTemplate, NotificationRecipientFn, NotificationRecordMapping, NotificationTemplateBody, NotificationTemplateFn, NotificationTemplateMeta, NotifyDeferred, NotifyDelivery, NotifyDeliveryStatus, NotifyDispatched, NotifyFactory, NotifyFn, NotifyJobDispatcher, NotifyOptions, NotifyPriority, NotifyResult, NumberFieldDef, OnDeleteStrategy, OpenToAllAccessRule, OpenToAllDeclaration, OpenToAllPersonalData, ParentRefDef, PersonalAnnotations, PersonalAnnotationsLongText, PersonalAnnotationsNoFind, PersonalSubject, PlatformComponent, PluralForms, PostDeleteHookFn, PostSaveHookFn, PreDeleteHookFn, PreparedWriteEvent, PreQueryHookFn, PreSaveHookFn, ProjectionDefinition, ProjectionDetailScreenDefinition, ProjectionListScreenDefinition, ProjectionTable, QualifiedEventName, QueryEvent, QueryHandlerDef, QueryHandlerFn, RateLimitPer, RecordHeaderSpec, RecordHeaderSubtitlePart, ReferenceDataDef, Registry, RelationDefinition, ResolvedPiiFlags, RetentionDef, RoleAccessPersonalData, RoleAccessRule, RowAction, RowActionNavigate, RowActionNavigateBase, RowActionWriteHandler, RowFieldExtractor, SaveContext, ScreenDefinition, ScreenFilter, ScreenFilterOp, ScreenNavSugar, ScreenSlots, SecretKeyDefinition, SecretKeyHandle, SecretMintConfirmStep, SecretMintScreenDefinition, SecretNamespaceDefinition, SecretNamespaceHandle, SecretNamespaceOptions, SecretReveal, SecretRevealField, SecretsEditScreenDefinition, SecretsEditSection, SelectFieldDef, SessionUser, SessionUserOrigin, StreamHandlerDef, StreamHandlerFn, Subscribe, TargetRef, TemplateListVariableDef, TemplateScalarVariableDef, TemplateVariableDef, TemplateVariables, TenantId, TenantWriteTarget, TextFieldDef, ToolbarAction, TranslationEntry, TranslationKeys, TranslationsDef, TranslationValue, TreeAction, TreeActionDef, TreeActionsHandle, TreeChildrenSubscribe, TreeNode, TreeNodeState, UnitKey, UnsafeAppendEventFn, ValidationError, ValidationHookFn, WorkspaceDefinition, WriteEvent, WriteHandlerDef, WriteHandlerFn, WriteResult, } from "./types/index.js";
|
|
84
|
+
export type { AccessRule, ActionFormScreenDefinition, ActiveMembership, ActiveMembershipRejection, ActiveMembershipResult, AgentExposure, AgentHandlerHints, AgentRisk, AppContext, AppendEventArgs, AppendEventFn, AuthClaimsContext, AuthClaimsFn, AuthClaimsHookDef, BeforeTransactionPhase, BeforeTransactionResult, BelongsToRelation, BigIntFieldDef, BooleanFieldDef, CamelToKebab, ChatSendFailureCode, ClaimKeyDefinition, ClaimKeyHandle, ClaimKeyJsType, ClaimKeyType, ConcurrencyMode, ConfigAccessor, ConfigAccessorFactory, ConfigBacking, ConfigCascade, ConfigCascadeLevel, ConfigDefinition, ConfigEditScreenDefinition, ConfigKeyAccess, ConfigKeyDefinition, ConfigKeyHandle, ConfigKeyType, ConfigMask, ConfigResolver, ConfigScope, ConfigSecretsReader, ConfigSeedDef, ConfigStoredRow, ConfigStoredRowWithSource, ConfigValidateContext, ConfigValidateFn, ConfigValue, ConfigValueSource, ConfigValueWithSource, ContentCollectionDefinition, CreateSeedOptions, CreateTenantSeedOptions, CreateUserSeedOptions, CustomScreenDefinition, CustomScreenRoute, DashboardChartPanel, DashboardCustomPanel, DashboardDateParam, DashboardFeedPanel, DashboardFilterDefinition, DashboardI18nText, DashboardListPanel, DashboardMoneyParam, DashboardPanelDefinition, DashboardPanelVisibility, DashboardProgressListPanel, DashboardScreenDefinition, DashboardScreenPanel, DashboardStatGroupPanel, DashboardStatPanel, DashboardText, DashboardTextParam, DashboardValueFormat, DateFieldDef, DecimalFieldDef, DeleteContext, DeliveryErrorCode, DeliveryFailureCode, DeliverySkipReason, DeriveContext, DerivedFieldDef, DerivedFieldsMap, DerivedValueType, EditExtensionSection, EditFieldPrefill, EditFieldSpec, EditFieldsSection, EditLayout, EditRelatedListSection, EditSectionSpec, EmbeddedListEditSpec, EntityDefinition, EntityEditAction, EntityEditActionPlacement, EntityEditScreenDefinition, EntityId, EntityListExpandableRow, EntityListScreenDefinition, EntityObjectDefinition, EntityRef, EntityRelations, EscapeHatchAuditSink, EscapeHatchDeclaration, EscapeHatchKind, EscapeHatchReporter, EscapeHatchTarget, EscapeHatchUseEvent, EventDef, ExtensionOptionsArgs, ExtensionOptionsFor, FeatureDefinition, FeatureRegistrar, FieldAccess, FieldCondition, FieldDefinition, FieldFormatRegistry, FieldIconKey, FieldRenderer, FileFieldDef, FilesFieldDef, Findability, FormatSpec, FormWidth, HandlerContext, HasManyRelation, HookDefinition, HookMap, ImageFieldDef, ImagesFieldDef, JobBackoff, JobBackoffStrategy, JobContext, JobDefinition, JobHandlerFn, JobTrigger, JobTriggerEvent, JsonbFieldDef, KumikoEntityTypeMap, KumikoEventTypeMap, KumikoExtensionOptionsMap, KumikoHandlerPayloadMap, KumikoHandlerResultMap, LifecycleHookType, ListColumnSpec, ListFacetSpec, ListPaginationMode, ListSortDir, ListSortSpec, LongTextFindability, ManyToManyRelation, MaxPerTenantOptions, MemberReader, MetricNavigate, MetricSpec, MspErrorMode, MspErrorPolicy, MultiSelectFieldDef, MultiStreamApplyFn, MultiStreamProjectionDefinition, NameOrRef, NavDefinition, NavIconKey, NotificationDataFn, NotificationDefinition, NotificationLocalizedTemplate, NotificationRecipientFn, NotificationRecordMapping, NotificationTemplateBody, NotificationTemplateFn, NotificationTemplateMeta, NotifyDeferred, NotifyDelivery, NotifyDeliveryStatus, NotifyDispatched, NotifyFactory, NotifyFn, NotifyJobDispatcher, NotifyOptions, NotifyPriority, NotifyResult, NumberFieldDef, OnDeleteStrategy, OpenToAllAccessRule, OpenToAllDeclaration, OpenToAllPersonalData, ParentRefDef, PersonalAnnotations, PersonalAnnotationsLongText, PersonalAnnotationsNoFind, PersonalSubject, PlatformComponent, PluralForms, PostDeleteHookFn, PostSaveHookFn, PreDeleteHookFn, PreparedWriteEvent, PreQueryHookFn, PreSaveHookFn, ProjectionDefinition, ProjectionDetailScreenDefinition, ProjectionListScreenDefinition, ProjectionTable, QualifiedEventName, QueryEvent, QueryHandlerDef, QueryHandlerFn, RateLimitPer, RecordHeaderSpec, RecordHeaderSubtitlePart, ReferenceDataDef, Registry, RelationDefinition, ResolvedPiiFlags, RetentionDef, RoleAccessPersonalData, RoleAccessRule, RowAction, RowActionNavigate, RowActionNavigateBase, RowActionWriteHandler, RowFieldExtractor, SaveContext, ScreenDefinition, ScreenFilter, ScreenFilterOp, ScreenNavSugar, ScreenSlots, SecretKeyDefinition, SecretKeyHandle, SecretMintConfirmStep, SecretMintScreenDefinition, SecretNamespaceDefinition, SecretNamespaceHandle, SecretNamespaceOptions, SecretReveal, SecretRevealField, SecretsEditScreenDefinition, SecretsEditSection, SelectFieldDef, SessionUser, SessionUserOrigin, StreamHandlerDef, StreamHandlerFn, Subscribe, TargetRef, TemplateListVariableDef, TemplateScalarVariableDef, TemplateVariableDef, TemplateVariables, TenantId, TenantWriteTarget, TextFieldDef, ToolbarAction, TranslationEntry, TranslationKeys, TranslationsDef, TranslationValue, TreeAction, TreeActionDef, TreeActionsHandle, TreeChildrenSubscribe, TreeNode, TreeNodeState, UnitKey, UnsafeAppendEventFn, ValidationError, ValidationHookFn, WorkspaceDefinition, WriteEvent, WriteHandlerDef, WriteHandlerFn, WriteResult, } from "./types/index.js";
|
|
85
85
|
export { DEFAULT_CURRENCIES, DEFAULT_LOCALES, DELIVERY_FAILURE_CODES, DELIVERY_SKIP_REASONS, HookPhases, HTTP_ERROR_CODE_PATTERN, isAgentVisibleScreen, isDeliveryErrorCode, isOpenToAllGranted, resolveAgentExposure, } from "./types/index.js";
|
|
86
86
|
export type { AwaitedEventType, PipelineBuildCtx, PipelineCtx, PipelineDef, StepBuilder, StepDef, StepFailureStrategy, StepInstance, StepKind, StepNamespace, StepResolver, } from "./types/step.js";
|
|
87
87
|
export { runValidation } from "./validation.js";
|
package/dist/engine/index.js
CHANGED
|
@@ -25,7 +25,7 @@ export { createEntityExecutor, defineEntityCreateHandler, defineEntityDeleteHand
|
|
|
25
25
|
// Apps nehmen die verb-spezifischen Wrapper oben. Existierende
|
|
26
26
|
// Caller (Integration-Tests, alte bundled-features) bleiben so
|
|
27
27
|
// unverändert lauffähig.
|
|
28
|
-
defineEntityQueryHandler, defineEntityRestoreHandler, defineEntityUpdateHandler, defineEntityWriteHandler, defineProjectionQueryHandler, entityListSchema, MAX_LIST_LIMIT,
|
|
28
|
+
defineEntityQueryHandler, defineEntityRestoreHandler, defineEntityUpdateHandler, defineEntityWriteHandler, defineProjectionQueryHandler, entityListSchema, MAX_LIST_LIMIT, } from "./entity-handlers.js";
|
|
29
29
|
export { declareEscapeHatch } from "./escape-hatch-declaration.js";
|
|
30
30
|
export { emitEvent, typedPayload } from "./event-helpers.js";
|
|
31
31
|
export { EXT_ASSIGNABLE_ROLE, EXT_DERIVATIVE_OVERLAY_RESOLVER, EXT_DERIVATIVE_PUBLIC_PREDICATE, EXT_DERIVATIVE_RENDERER, EXT_EXTERNAL_RESOURCE, EXT_FILE_PROVIDER, EXT_INFRA_RESOURCE, EXT_PRINCIPAL_STATUS, EXT_SEARCH_ADAPTER, EXT_STORAGE_PROVIDER, EXT_TENANT_DATA, EXT_TENANT_LIFECYCLE_STATUS, EXT_USER_DATA, EXT_USER_DATA_ORDER, FILE_PROVIDER_CONFIG_KEY, FILE_STORAGE_PROVIDER_BOOT_SENTINEL, FILE_STORAGE_PROVIDER_ENV, TENANT_MEMBERSHIPS_QUERY, } from "./extension-names.js";
|
|
@@ -38,7 +38,7 @@ export { addPattern, applyChanges, createFeaturePatcher, getPatternSchema, group
|
|
|
38
38
|
export { compareVersions, filterEntriesAfter, parseFeatureChangelog, sortEntries, validateChangelog, } from "./feature-changelog.js";
|
|
39
39
|
export { buildManifestFromRegistry, serializeManifest, } from "./feature-manifest.js";
|
|
40
40
|
export { checkWriteFieldOwnership, checkWriteFieldRoles, filterReadFields, maskWriteOnlyFields, } from "./field-access.js";
|
|
41
|
-
export { HANDLER_FIELD_REFERENCES_META_KEY, handlerFieldReference, } from "./handler-field-references.js";
|
|
41
|
+
export { HANDLER_FIELD_REFERENCES_META_KEY, handlerFieldReference, handlerFieldReferences, readHandlerFieldReferences, } from "./handler-field-references.js";
|
|
42
42
|
export { resolveName, withResponseData } from "./handler-helpers.js";
|
|
43
43
|
export { i18nKey } from "./i18n-key.js";
|
|
44
44
|
// findForbiddenMembershipRole/isForbiddenMembershipRole/
|