@cosmicdrift/kumiko-framework 0.373.0 → 0.377.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/apex-landing.md +1 -1
- package/agents/examples/apex-surface-auth.md +3 -3
- package/agents/examples/compose-stacks.md +15 -8
- package/agents/examples/embedded-entity-form.md +1 -1
- package/agents/examples/notes-history-basic.md +1 -1
- package/agents/examples/tags-basic.md +1 -1
- package/agents/examples/user-profile.md +1 -1
- package/agents/examples/wizard-form.md +4 -4
- package/agents/widgets.md +4 -3
- package/dist/api/index.d.ts +1 -1
- package/dist/api/index.js +1 -1
- package/dist/api/routes.js +2 -2
- package/dist/api/server.js +2 -1
- package/dist/config/index.d.ts +4 -0
- package/dist/db/index.d.ts +2 -2
- package/dist/db/index.js +1 -1
- package/dist/db/migrate-runner.js +12 -4
- package/dist/db/money.js +1 -1
- package/dist/db/query.js +14 -14
- package/dist/db/replay-migration-sql.d.ts +1 -0
- package/dist/db/replay-migration-sql.js +115 -11
- package/dist/db/tenant-db.d.ts +7 -0
- package/dist/db/tenant-db.js +17 -5
- package/dist/engine/boot-validator/projection-list-screens.js +28 -37
- package/dist/engine/boot-validator/query-refs.js +26 -8
- package/dist/engine/boot-validator/screens.d.ts +1 -1
- package/dist/engine/boot-validator/screens.js +334 -42
- package/dist/engine/boot-validator/url-prefill-fields.js +3 -0
- package/dist/engine/build-app-schema.js +7 -3
- package/dist/engine/entity-list-searchability.d.ts +5 -0
- package/dist/engine/entity-list-searchability.js +35 -0
- package/dist/engine/feature-ui-extensions.js +5 -2
- package/dist/engine/index.d.ts +3 -1
- package/dist/engine/index.js +2 -0
- package/dist/engine/paged-list.d.ts +29 -0
- package/dist/engine/paged-list.js +56 -0
- package/dist/engine/parse-ref-target.js +1 -1
- package/dist/engine/project-app-schema-for-roles.js +37 -6
- package/dist/engine/provider-plugin-context.d.ts +3 -0
- package/dist/engine/provider-plugin-context.js +28 -0
- package/dist/engine/schema-builder.js +7 -0
- package/dist/engine/types/index.d.ts +2 -2
- package/dist/env/index.js +1 -1
- package/dist/errors/zod-bridge.js +1 -1
- package/dist/files/file-ref-entity.d.ts +6 -6
- package/dist/files/file-ref-table.d.ts +6 -6
- package/dist/files/index.d.ts +1 -1
- package/dist/files/index.js +1 -1
- package/dist/files/provider-resolver.d.ts +17 -17
- package/dist/files/provider-resolver.js +1 -1
- package/dist/http/egress.d.ts +14 -0
- package/dist/http/egress.js +144 -0
- package/dist/http/index.d.ts +3 -2
- package/dist/http/index.js +2 -1
- package/dist/http/policy.d.ts +30 -0
- package/dist/http/policy.js +299 -0
- package/dist/i18n/required-surface-keys.js +52 -2
- package/dist/jobs/job-runner.js +4 -2
- package/dist/pipeline/config-accessor-factory.d.ts +3 -0
- package/dist/pipeline/config-accessor-factory.js +3 -0
- package/dist/pipeline/dispatch-shared.js +7 -5
- package/dist/pipeline/index.d.ts +1 -0
- package/dist/pipeline/index.js +1 -0
- package/dist/ui-types/index.d.ts +1 -1
- package/dist/upgrade-changelog.d.ts +25 -0
- package/dist/upgrade-changelog.js +48 -0
- package/dist/upgrade-cli.js +78 -13
- package/package.json +3 -5
- package/presets/biome-app.json +8 -0
- package/src/changes.json +132 -0
- package/src/scripts/codemod/README.md +25 -0
- package/src/scripts/codemod/codemod-support.ts +64 -6
- package/src/scripts/codemod/package-merge.ts +260 -0
- package/src/scripts/codemod/s3-imports.ts +4 -42
- package/src/scripts/codemod/testing-injection.ts +135 -0
|
@@ -27,6 +27,7 @@ import { ZodObject } from "zod";
|
|
|
27
27
|
import { collectUrlPrefillFieldsByScreenQn } from "./boot-validator/url-prefill-fields.js";
|
|
28
28
|
import { buildConfigFeatureSchema, SETTINGS_HUB_FEATURE, } from "./build-config-feature-schema.js";
|
|
29
29
|
import { isEncryptedAtRest } from "./config-helpers.js";
|
|
30
|
+
import { isListQueryWithoutSearchableFields } from "./entity-list-searchability.js";
|
|
30
31
|
import { QnTypes, qualifyEntityName } from "./qualified-name.js";
|
|
31
32
|
export function buildAppSchema(registry, options = {}) {
|
|
32
33
|
const features = [];
|
|
@@ -341,11 +342,14 @@ function projectConfigEditScreen(screen, encryptedConfigKeyQns) {
|
|
|
341
342
|
return fields === undefined ? screen : { ...screen, fields };
|
|
342
343
|
}
|
|
343
344
|
function projectProjectionListScreen(screen, registry) {
|
|
344
|
-
const
|
|
345
|
-
const capabilities = deriveProjectionListCapabilities(schema);
|
|
345
|
+
const handler = registry.getQueryHandler(screen.query);
|
|
346
|
+
const capabilities = deriveProjectionListCapabilities(handler?.schema);
|
|
347
|
+
// A search box over an entity without searchable fields would never match.
|
|
348
|
+
const searchable = capabilities.searchable &&
|
|
349
|
+
!isListQueryWithoutSearchableFields(screen.query, handler, (name) => registry.getEntity(name));
|
|
346
350
|
return {
|
|
347
351
|
...screen,
|
|
348
|
-
searchable: screen.searchable ??
|
|
352
|
+
searchable: screen.searchable ?? searchable,
|
|
349
353
|
sortable: capabilities.sortable,
|
|
350
354
|
paginated: capabilities.paginated,
|
|
351
355
|
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { EntityDefinition, QueryHandlerDef } from "./types/index.ts";
|
|
2
|
+
export declare function resolveEntityBehindListQuery(queryQn: string, handler: QueryHandlerDef | undefined, lookupEntity: (entityName: string) => EntityDefinition | undefined): EntityDefinition | undefined;
|
|
3
|
+
/** True when the list query is an entity-convention one over an entity with no
|
|
4
|
+
* searchable field — a search box would never match anything. */
|
|
5
|
+
export declare function isListQueryWithoutSearchableFields(queryQn: string, handler: QueryHandlerDef | undefined, lookupEntity: (entityName: string) => EntityDefinition | undefined): boolean;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ENTITY_CONVENTION_QUERY_BRAND } from "@cosmicdrift/kumiko-types/handlers";
|
|
2
|
+
import { parseQn } from "./qualified-name.js";
|
|
3
|
+
// Mirrors buildSearchableSortableCaches (registry-validate.ts): a `search`
|
|
4
|
+
// payload only matches text fields, embedded sub-fields and references that
|
|
5
|
+
// opted in with `searchable: true`.
|
|
6
|
+
function entityHasSearchableField(entity) {
|
|
7
|
+
return Object.values(entity.fields).some((field) => {
|
|
8
|
+
if (field.type === "embedded") {
|
|
9
|
+
return Object.values(field.schema).some((subField) => subField.searchable === true);
|
|
10
|
+
}
|
|
11
|
+
return (field.type === "text" || field.type === "reference") && field.searchable === true;
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
// Entity-convention list queries (ENTITY_CONVENTION_QUERY_BRAND) carry no
|
|
15
|
+
// entity on the handler; the entity name is recovered from the query QN's
|
|
16
|
+
// `<entityName>:list` naming convention. Hand-written handlers resolve to
|
|
17
|
+
// undefined — "capability unknown, no throw".
|
|
18
|
+
export function resolveEntityBehindListQuery(queryQn, handler, lookupEntity) {
|
|
19
|
+
if (handler === undefined || handler[ENTITY_CONVENTION_QUERY_BRAND] !== true)
|
|
20
|
+
return undefined;
|
|
21
|
+
let entityName;
|
|
22
|
+
try {
|
|
23
|
+
entityName = parseQn(queryQn).name.split(":")[0] ?? "";
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
return entityName === "" ? undefined : lookupEntity(entityName);
|
|
29
|
+
}
|
|
30
|
+
/** True when the list query is an entity-convention one over an entity with no
|
|
31
|
+
* searchable field — a search box would never match anything. */
|
|
32
|
+
export function isListQueryWithoutSearchableFields(queryQn, handler, lookupEntity) {
|
|
33
|
+
const entity = resolveEntityBehindListQuery(queryQn, handler, lookupEntity);
|
|
34
|
+
return entity !== undefined && !entityHasSearchableField(entity);
|
|
35
|
+
}
|
|
@@ -31,9 +31,12 @@ function qualifySelectorPanel(featureName, panel) {
|
|
|
31
31
|
throw new Error(`[Feature ${featureName}] extensionSelector screen panel "${panel.id}" must not set a label — ` +
|
|
32
32
|
`the settings dashboard has no i18n namespace for it; the embedded screen carries its own title.`);
|
|
33
33
|
}
|
|
34
|
-
|
|
34
|
+
const qualify = (ref) => ref === "" || isValidQn(ref) ? ref : qualifyEntityName(featureName, "screen", ref);
|
|
35
|
+
const screen = qualify(panel.screen);
|
|
36
|
+
const fallback = panel.fallback === undefined ? undefined : qualify(panel.fallback);
|
|
37
|
+
if (screen === panel.screen && fallback === panel.fallback)
|
|
35
38
|
return panel;
|
|
36
|
-
return { ...panel, screen
|
|
39
|
+
return { ...panel, screen, ...(fallback !== undefined && { fallback }) };
|
|
37
40
|
}
|
|
38
41
|
throw new Error(`[Feature ${featureName}] extensionSelector panel ${JSON.stringify(panel)} has an unsupported kind — ` +
|
|
39
42
|
`only "custom" and "screen" panels are allowed.`);
|
package/dist/engine/index.d.ts
CHANGED
|
@@ -51,11 +51,13 @@ export { i18nKey } from "./i18n-key.ts";
|
|
|
51
51
|
export { buildSessionRoles, findForbiddenMembershipRole, isForbiddenMembershipRole, stripForbiddenMembershipRoles, } from "./membership-roles.ts";
|
|
52
52
|
export type { OwnershipClause, OwnershipMap, OwnershipRef, OwnershipRule } from "./ownership.ts";
|
|
53
53
|
export { buildOwnershipClause, combineClauses, from, normalizeAccessEntry, userCanCreateFieldRow, userCanReadFieldRow, userCanWriteFieldRow, } from "./ownership.ts";
|
|
54
|
+
export { type PagedListRequest, type PagedListRowValue, pagedListSchema, pageRows, } from "./paged-list.ts";
|
|
54
55
|
export type { ParsedRefTarget } from "./parse-ref-target.ts";
|
|
55
56
|
export { parseRefTarget, parseRefTargetEntityName } from "./parse-ref-target.ts";
|
|
56
57
|
export { buildPipelineSteps, stepsPipeline } from "./pipeline.ts";
|
|
57
58
|
export { projectAppSchemaForRoles } from "./project-app-schema-for-roles.ts";
|
|
58
59
|
export { defineApply, defineMspApply, setFields } from "./projection-helpers.ts";
|
|
60
|
+
export { providerPluginContextFromHandler, providerPluginContextFromJob, } from "./provider-plugin-context.ts";
|
|
59
61
|
export type { BuiltinQnType, ParsedQn, QnType } from "./qualified-name.ts";
|
|
60
62
|
export { isValidQn, parseQn, QnTypes, qn, toKebab } from "./qualified-name.ts";
|
|
61
63
|
export { readClaim } from "./read-claim.ts";
|
|
@@ -83,7 +85,7 @@ export { assertNotificationVariables, templateVariable, templateVariablesToZod,
|
|
|
83
85
|
export { type EffectiveFeaturesResolver, findTierResolverUsage, isTierResolverPlugin, requireTierResolverPlugin, TENANT_TIER_RESOLVER_EXT, type TierResolverPlugin, type TrialGate, } from "./tier-resolver-extension.ts";
|
|
84
86
|
export { findOverDeepTransferChain, resolveTransferAdjacency as resolveEntityTransferAdjacency, type TransferAdjacency, type TransferEdge, type TransferEdgeLink, } from "./transfer-adjacency.ts";
|
|
85
87
|
export { isSystemTenant, isUuid, parseTenantId, SYSTEM_TENANT_ID } from "./types/identifiers.ts";
|
|
86
|
-
export type { AccessRule, ActionFormScreenDefinition, ActiveMembership, ActiveMembershipRejection, ActiveMembershipResult, AgentExposure, AgentHandlerHints, AgentRisk, AppContext, AppendEventArgs, AppendEventFn, AuthClaimsContext, AuthClaimsFn, AuthClaimsHookDef, BeforeTransactionPhase, BeforeTransactionResult, BelongsToRelation, BigIntFieldDef, BooleanFieldDef, BootOptionName, 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, StackBootRequirement, 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.ts";
|
|
88
|
+
export type { AccessRule, ActionFormScreenDefinition, ActiveMembership, ActiveMembershipRejection, ActiveMembershipResult, AgentExposure, AgentHandlerHints, AgentRisk, AppContext, AppendEventArgs, AppendEventFn, AuthClaimsContext, AuthClaimsFn, AuthClaimsHookDef, BeforeTransactionPhase, BeforeTransactionResult, BelongsToRelation, BigIntFieldDef, BooleanFieldDef, BootOptionName, 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, DashboardCurrencyFormat, DashboardCustomPanel, DashboardDateParam, DashboardFeedPanel, DashboardFilterDefinition, DashboardI18nText, DashboardListPanel, DashboardMoneyParam, DashboardPanelDefinition, DashboardPanelVisibility, DashboardProgressListPanel, DashboardProgressTone, DashboardRecordBinding, DashboardRefresh, DashboardRelativeTimeFormat, DashboardRelativeTimeParam, DashboardScreenDefinition, DashboardScreenPanel, DashboardStatGroupPanel, DashboardStatPanel, DashboardText, DashboardTextBlock, DashboardTextPanel, 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, ProviderPluginContext, 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, StackBootRequirement, 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.ts";
|
|
87
89
|
export { DEFAULT_CURRENCIES, DEFAULT_LOCALES, DELIVERY_FAILURE_CODES, DELIVERY_SKIP_REASONS, HookPhases, HTTP_ERROR_CODE_PATTERN, isAgentVisibleScreen, isDeliveryErrorCode, isOpenToAllGranted, resolveAgentExposure, } from "./types/index.ts";
|
|
88
90
|
export type { AwaitedEventType, PipelineBuildCtx, PipelineCtx, PipelineDef, StepBuilder, StepDef, StepFailureStrategy, StepInstance, StepKind, StepNamespace, StepResolver, } from "./types/step.ts";
|
|
89
91
|
export { runValidation } from "./validation.ts";
|
package/dist/engine/index.js
CHANGED
|
@@ -51,10 +51,12 @@ export { i18nKey } from "./i18n-key.js";
|
|
|
51
51
|
// surface.
|
|
52
52
|
export { buildSessionRoles, findForbiddenMembershipRole, isForbiddenMembershipRole, stripForbiddenMembershipRoles, } from "./membership-roles.js";
|
|
53
53
|
export { buildOwnershipClause, combineClauses, from, normalizeAccessEntry, userCanCreateFieldRow, userCanReadFieldRow, userCanWriteFieldRow, } from "./ownership.js";
|
|
54
|
+
export { pagedListSchema, pageRows, } from "./paged-list.js";
|
|
54
55
|
export { parseRefTarget, parseRefTargetEntityName } from "./parse-ref-target.js";
|
|
55
56
|
export { buildPipelineSteps, stepsPipeline } from "./pipeline.js";
|
|
56
57
|
export { projectAppSchemaForRoles } from "./project-app-schema-for-roles.js";
|
|
57
58
|
export { defineApply, defineMspApply, setFields } from "./projection-helpers.js";
|
|
59
|
+
export { providerPluginContextFromHandler, providerPluginContextFromJob, } from "./provider-plugin-context.js";
|
|
58
60
|
export { isValidQn, parseQn, QnTypes, qn, toKebab } from "./qualified-name.js";
|
|
59
61
|
export { readClaim } from "./read-claim.js";
|
|
60
62
|
export { createRegistry } from "./registry.js";
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { CursorResult } from "@cosmicdrift/kumiko-types/cursor-types";
|
|
2
|
+
import * as z from "zod";
|
|
3
|
+
export type PagedListRowValue = string | number | boolean | null;
|
|
4
|
+
export declare function pagedListSchema<const TSortField extends string>(sortableFields: readonly [TSortField, ...TSortField[]]): z.ZodObject<{
|
|
5
|
+
limit: z.ZodDefault<z.ZodNumber>;
|
|
6
|
+
offset: z.ZodOptional<z.ZodNumber>;
|
|
7
|
+
search: z.ZodOptional<z.ZodString>;
|
|
8
|
+
sort: z.ZodOptional<z.ZodEnum<{ [k in TSortField]: k; } extends infer T ? { [k in keyof T]: T[k]; } : never>>;
|
|
9
|
+
sortDirection: z.ZodOptional<z.ZodEnum<{
|
|
10
|
+
asc: "asc";
|
|
11
|
+
desc: "desc";
|
|
12
|
+
}>>;
|
|
13
|
+
totalCount: z.ZodOptional<z.ZodBoolean>;
|
|
14
|
+
cursor: z.ZodOptional<z.ZodNever>;
|
|
15
|
+
}, z.core.$strip>;
|
|
16
|
+
export type PagedListRequest<TSortField extends string> = {
|
|
17
|
+
readonly limit: number;
|
|
18
|
+
readonly offset?: number | undefined;
|
|
19
|
+
readonly search?: string | undefined;
|
|
20
|
+
readonly sort?: TSortField | undefined;
|
|
21
|
+
readonly sortDirection?: "asc" | "desc" | undefined;
|
|
22
|
+
readonly totalCount?: boolean | undefined;
|
|
23
|
+
};
|
|
24
|
+
export declare function pageRows<TRow extends Readonly<Record<TSortField, PagedListRowValue>> & {
|
|
25
|
+
readonly id: string;
|
|
26
|
+
}, TSortField extends string>(rows: readonly TRow[], request: PagedListRequest<TSortField>, options: {
|
|
27
|
+
readonly searchFields: readonly TSortField[];
|
|
28
|
+
readonly defaultSort: TSortField;
|
|
29
|
+
}): CursorResult<TRow>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// Search, sort and offset paging for projectionList queries whose rows are
|
|
2
|
+
// assembled in memory (merged from several tables, no single SQL query to
|
|
3
|
+
// page). The projectionList pager sends `offset` + `totalCount`, never a
|
|
4
|
+
// cursor, so `nextCursor` is always null here.
|
|
5
|
+
import * as z from "zod";
|
|
6
|
+
import { MAX_LIST_LIMIT } from "./entity-handlers.js";
|
|
7
|
+
export function pagedListSchema(sortableFields) {
|
|
8
|
+
return z.object({
|
|
9
|
+
limit: z.number().int().min(1).max(MAX_LIST_LIMIT).default(50),
|
|
10
|
+
offset: z.number().int().nonnegative().optional(),
|
|
11
|
+
search: z.string().optional(),
|
|
12
|
+
sort: z.enum(sortableFields).optional(),
|
|
13
|
+
sortDirection: z.enum(["asc", "desc"]).optional(),
|
|
14
|
+
totalCount: z.boolean().optional(),
|
|
15
|
+
// Declared so a caller still paging by cursor gets a 400 instead of page one.
|
|
16
|
+
cursor: z.never({ error: "cursor paging is not supported here; page with offset" }).optional(),
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
function isMissing(value) {
|
|
20
|
+
return value === null || value === undefined;
|
|
21
|
+
}
|
|
22
|
+
// Missing values sort last in both directions; numbers and booleans compare
|
|
23
|
+
// by value, everything else as a locale-aware string.
|
|
24
|
+
function compareRowValues(a, b, directionMultiplier) {
|
|
25
|
+
if (isMissing(a) && isMissing(b))
|
|
26
|
+
return 0;
|
|
27
|
+
if (isMissing(a))
|
|
28
|
+
return 1;
|
|
29
|
+
if (isMissing(b))
|
|
30
|
+
return -1;
|
|
31
|
+
if (typeof a === "number" && typeof b === "number")
|
|
32
|
+
return (a - b) * directionMultiplier;
|
|
33
|
+
if (typeof a === "boolean" && typeof b === "boolean") {
|
|
34
|
+
return (Number(a) - Number(b)) * directionMultiplier;
|
|
35
|
+
}
|
|
36
|
+
return String(a).localeCompare(String(b)) * directionMultiplier;
|
|
37
|
+
}
|
|
38
|
+
export function pageRows(rows, request, options) {
|
|
39
|
+
const needle = request.search?.trim().toLowerCase() ?? "";
|
|
40
|
+
const matching = needle === ""
|
|
41
|
+
? rows
|
|
42
|
+
: rows.filter((row) => options.searchFields.some((field) => String(row[field] ?? "")
|
|
43
|
+
.toLowerCase()
|
|
44
|
+
.includes(needle)));
|
|
45
|
+
const sortField = request.sort ?? options.defaultSort;
|
|
46
|
+
const directionMultiplier = request.sortDirection === "desc" ? -1 : 1;
|
|
47
|
+
// The source rows come unordered, so ties fall back to the id; otherwise a
|
|
48
|
+
// tied row could show up on two pages or on none.
|
|
49
|
+
const sorted = [...matching].sort((a, b) => compareRowValues(a[sortField], b[sortField], directionMultiplier) || a.id.localeCompare(b.id));
|
|
50
|
+
const offset = request.offset ?? 0;
|
|
51
|
+
return {
|
|
52
|
+
rows: sorted.slice(offset, offset + request.limit),
|
|
53
|
+
nextCursor: null,
|
|
54
|
+
...(request.totalCount === true && { total: matching.length }),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// - "users:user" → cross-feature ref (qualifiziert)
|
|
6
6
|
//
|
|
7
7
|
// Lebt im framework-Package damit Server-Validator + Renderer (über
|
|
8
|
-
// Re-Export aus @cosmicdrift/kumiko-headless) denselben Parser nutzen — die
|
|
8
|
+
// Re-Export aus @cosmicdrift/kumiko-renderer/headless) denselben Parser nutzen — die
|
|
9
9
|
// Convention darf nicht zweimal implementiert werden.
|
|
10
10
|
export function parseRefTarget(raw, currentFeature) {
|
|
11
11
|
const idx = raw.indexOf(":");
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
// resolves app-wide via a global short-id map, mirroring
|
|
40
40
|
// resolveRowActionNavigateTarget; kind:"drawer" resolves same-feature
|
|
41
41
|
// only, mirroring validateDrawerTargetAction)
|
|
42
|
-
// - projectionDetail header actions + metrics[].navigate
|
|
43
|
-
// - entityEdit/actionForm/secretMint redirect + actionForm cancelTarget
|
|
42
|
+
// - projectionDetail and dashboard header actions + projectionDetail metrics[].navigate
|
|
43
|
+
// - entityEdit/actionForm/secretMint redirect + actionForm successLinks and cancelTarget
|
|
44
44
|
// (resolveScreenTargetQn: same-feature short id or cross-feature QN)
|
|
45
45
|
// - dashboard DashboardScreenPanel.screen (resolveScreenTargetQn)
|
|
46
46
|
// - every EditSectionSpec kind's own `actions` (fields/extension/writeForm/
|
|
@@ -418,8 +418,27 @@ function projectHeader(header, indices, keptScreenQns) {
|
|
|
418
418
|
return changed ? { ...header, subtitle: nextParts } : header;
|
|
419
419
|
}
|
|
420
420
|
function projectDashboardPanels(panels, feature, keptScreenQns) {
|
|
421
|
-
|
|
422
|
-
|
|
421
|
+
let changed = false;
|
|
422
|
+
const kept = [];
|
|
423
|
+
for (const panel of panels) {
|
|
424
|
+
if (panel.kind !== "screen") {
|
|
425
|
+
kept.push(panel);
|
|
426
|
+
}
|
|
427
|
+
else if (!isScreenTargetKept(feature.featureName, panel.screen, keptScreenQns)) {
|
|
428
|
+
changed = true;
|
|
429
|
+
}
|
|
430
|
+
else if (panel.fallback !== undefined &&
|
|
431
|
+
!isScreenTargetKept(feature.featureName, panel.fallback, keptScreenQns)) {
|
|
432
|
+
// The role cannot reach the stand-in, so the tile just hides.
|
|
433
|
+
const { fallback: _unreachable, ...withoutFallback } = panel;
|
|
434
|
+
kept.push(withoutFallback);
|
|
435
|
+
changed = true;
|
|
436
|
+
}
|
|
437
|
+
else {
|
|
438
|
+
kept.push(panel);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
return changed ? kept : panels;
|
|
423
442
|
}
|
|
424
443
|
// --- per-screen-type projection ---
|
|
425
444
|
function projectListScreenId(listScreenId, indices, keptScreenQns) {
|
|
@@ -512,12 +531,15 @@ function projectEntityEditScreen(screen, feature, indices, keptScreenQns) {
|
|
|
512
531
|
};
|
|
513
532
|
}
|
|
514
533
|
function projectActionFormScreen(screen, feature, indices, keptScreenQns) {
|
|
515
|
-
const { redirect, cancelTarget, layout, listScreenId, ...rest } = screen;
|
|
534
|
+
const { redirect, successLinks, cancelTarget, layout, listScreenId, ...rest } = screen;
|
|
516
535
|
const nextRedirect = projectRedirect(feature.featureName, redirect, keptScreenQns);
|
|
536
|
+
const keptSuccessLinks = successLinks?.filter((link) => isRedirectTargetKept(feature.featureName, link, keptScreenQns));
|
|
537
|
+
const nextSuccessLinks = keptSuccessLinks?.length === 0 ? undefined : keptSuccessLinks;
|
|
517
538
|
const nextCancelTarget = projectCancelTarget(feature.featureName, cancelTarget, keptScreenQns);
|
|
518
539
|
const nextLayout = projectEditLayout(layout, feature, indices, keptScreenQns);
|
|
519
540
|
const nextListScreenId = projectListScreenId(listScreenId, indices, keptScreenQns);
|
|
520
541
|
const unchanged = nextRedirect === redirect &&
|
|
542
|
+
nextSuccessLinks?.length === successLinks?.length &&
|
|
521
543
|
nextCancelTarget === cancelTarget &&
|
|
522
544
|
nextLayout === layout &&
|
|
523
545
|
nextListScreenId === listScreenId;
|
|
@@ -527,6 +549,7 @@ function projectActionFormScreen(screen, feature, indices, keptScreenQns) {
|
|
|
527
549
|
...rest,
|
|
528
550
|
layout: nextLayout,
|
|
529
551
|
...(nextRedirect !== undefined && { redirect: nextRedirect }),
|
|
552
|
+
...(nextSuccessLinks !== undefined && { successLinks: nextSuccessLinks }),
|
|
530
553
|
...(nextCancelTarget !== undefined && { cancelTarget: nextCancelTarget }),
|
|
531
554
|
...(nextListScreenId !== undefined && { listScreenId: nextListScreenId }),
|
|
532
555
|
};
|
|
@@ -565,8 +588,16 @@ function projectScreen(screen, feature, indices, keptScreenQns) {
|
|
|
565
588
|
case "projectionDetail":
|
|
566
589
|
return projectProjectionDetailScreen(screen, feature, indices, keptScreenQns);
|
|
567
590
|
case "dashboard": {
|
|
591
|
+
const { actions, ...rest } = screen;
|
|
568
592
|
const nextPanels = projectDashboardPanels(screen.panels, feature, keptScreenQns);
|
|
569
|
-
|
|
593
|
+
const nextActions = projectRowActionArray(actions, feature, indices, keptScreenQns);
|
|
594
|
+
if (nextPanels === screen.panels && nextActions === actions)
|
|
595
|
+
return screen;
|
|
596
|
+
return {
|
|
597
|
+
...rest,
|
|
598
|
+
panels: nextPanels,
|
|
599
|
+
...(nextActions !== undefined && { actions: nextActions }),
|
|
600
|
+
};
|
|
570
601
|
}
|
|
571
602
|
case "entityEdit":
|
|
572
603
|
return projectEntityEditScreen(screen, feature, indices, keptScreenQns);
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { HandlerContext, JobContext, ProviderPluginContext } from "@cosmicdrift/kumiko-types/handlers";
|
|
2
|
+
export declare function providerPluginContextFromHandler(ctx: HandlerContext): ProviderPluginContext;
|
|
3
|
+
export declare function providerPluginContextFromJob(ctx: JobContext): ProviderPluginContext;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export function providerPluginContextFromHandler(ctx) {
|
|
2
|
+
return {
|
|
3
|
+
db: ctx.db,
|
|
4
|
+
dbOutsideTransaction: ctx.dbOutsideTransaction,
|
|
5
|
+
systemDb: ctx.systemDb,
|
|
6
|
+
registry: ctx.registry,
|
|
7
|
+
user: ctx.user,
|
|
8
|
+
log: ctx.log,
|
|
9
|
+
triggeredBy: ctx.triggeredBy,
|
|
10
|
+
config: ctx.config,
|
|
11
|
+
secrets: ctx.secrets,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
// Jobs have no request user: the job's system user is the acting identity, and no
|
|
15
|
+
// outside-transaction handle exists because jobs never run inside the handler's tx.
|
|
16
|
+
export function providerPluginContextFromJob(ctx) {
|
|
17
|
+
return {
|
|
18
|
+
db: ctx.db,
|
|
19
|
+
dbOutsideTransaction: undefined,
|
|
20
|
+
systemDb: ctx.systemDb,
|
|
21
|
+
registry: ctx.registry,
|
|
22
|
+
user: ctx.systemUser,
|
|
23
|
+
log: ctx.log,
|
|
24
|
+
triggeredBy: ctx.triggeredBy,
|
|
25
|
+
config: ctx.config,
|
|
26
|
+
secrets: ctx.secrets,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
@@ -4,6 +4,7 @@ import { isValidIanaTimeZone } from "../time/index.js";
|
|
|
4
4
|
import { assertUnreachable } from "../utils/index.js";
|
|
5
5
|
import { withDerivedCells } from "./embedded-derived.js";
|
|
6
6
|
import { DEFAULT_CURRENCIES } from "./types/index.js";
|
|
7
|
+
const MONTH_PATTERN = /^\d{4}-(0[1-9]|1[0-2])$/;
|
|
7
8
|
// True if `n` carries at most `scale` decimal places. A relative epsilon
|
|
8
9
|
// tolerates float artifacts (`0.1 + 0.2 = 0.30000000000000004` is accepted at
|
|
9
10
|
// scale 2) — the exact `toFixed`-roundtrip-equality it replaces rejected such
|
|
@@ -106,6 +107,12 @@ export function fieldToZod(field, currencies, opts = {}) {
|
|
|
106
107
|
schema = schema.email();
|
|
107
108
|
if (field.format === "url")
|
|
108
109
|
schema = schema.url();
|
|
110
|
+
if (field.format === "month") {
|
|
111
|
+
// "" stays valid for an optional field; `required` rejects it via min(1) below.
|
|
112
|
+
schema = schema.refine((value) => value === "" || MONTH_PATTERN.test(value), {
|
|
113
|
+
message: "expected a month as YYYY-MM",
|
|
114
|
+
});
|
|
115
|
+
}
|
|
109
116
|
if (field.required)
|
|
110
117
|
schema = schema.min(1);
|
|
111
118
|
return field.default !== undefined && applyDefaults ? schema.default(field.default) : schema;
|
|
@@ -7,7 +7,7 @@ export type { ExtensionOptionsArgs, ExtensionOptionsFor, KumikoExtensionOptionsM
|
|
|
7
7
|
export type { BootCheckContext, BootCheckFn, BootOptionName, EntityObjectDefinition, FeatureDefinition, FeatureMetricDef, FeatureMetricType, FeatureRegistrar, HookDefinition, MetricOptions, Registry, SecretKeyDefinition, SecretKeyHandle, SecretNamespaceDefinition, SecretNamespaceHandle, SecretNamespaceOptions, SecretOptions, StackBootRequirement, StoreTableDef, StoreTableEntry, StoreTableOptions, UiHintOption, UiHints, } from "@cosmicdrift/kumiko-types/feature";
|
|
8
8
|
export type { FieldIconKey } from "@cosmicdrift/kumiko-types/field-icon";
|
|
9
9
|
export type { AnyFileFieldDef, BigIntFieldDef, BooleanFieldDef, ClientDerivedFieldDef, DateFieldDef, DecimalFieldDef, DefaultCurrency, DeriveContext, DerivedFieldDef, DerivedFieldsMap, DerivedValueType, EmbeddedDerivedCellDef, EmbeddedFieldDef, EmbeddedSubFieldDef, EntityDefinition, EntityEventMigration, EntityIndexDef, FieldAccess, FieldDefinition, FieldsMap, FileFieldDef, FilesFieldDef, Findability, ImageFieldDef, ImagesFieldDef, JsonbFieldDef, LocatedTimestampFieldDef, LongTextFieldDef, LongTextFindability, MoneyCurrencySource, MoneyFieldDef, MultiSelectFieldDef, NumberFieldDef, OptionsQueryPayload, OptionsQueryPayloadValue, ParentRefDef, PersonalAnnotations, PersonalAnnotationsLongText, PersonalAnnotationsNoFind, PersonalSubject, ReferenceFieldDef, ResolvedPiiFlags, RetentionDef, SelectFieldDef, SelectOptionTone, TextFieldDef, TimestampFieldDef, TransitionMap, TzFieldDef, } from "@cosmicdrift/kumiko-types/fields";
|
|
10
|
-
export type { AccessRule, ActiveMembership, ActiveMembershipRejection, ActiveMembershipResult, AgentExposure, AgentHandlerHints, AgentRisk, AggregateStreamHandle, AppContext, AppendEventArgs, AppendEventFn, AuthClaimsContext, AuthClaimsFn, AuthClaimsHookDef, BeforeTransactionPhase, BeforeTransactionResult, CamelToKebab, ChatSendFailureCode, ClaimKeyDefinition, ClaimKeyHandle, ClaimKeyJsType, ClaimKeyType, DeclarativeEventMigration, DeliveryErrorCode, DeliveryFailureCode, DeliverySkipReason, DispatchWriteRef, EntityRef, EscapeHatchAuditSink, EscapeHatchDeclaration, EscapeHatchKind, EscapeHatchReporter, EscapeHatchTarget, EscapeHatchUseEvent, EventDef, EventMigrationDef, EventPiiFields, EventPiiStance, EventUpcastCtx, EventUpcastFn, FetchForWritingArgs, HandlerContext, HandlerRef, JobContext, JobRunnerRef, JobTriggerEvent, MemberReader, NameOrRef, NotifyDeferred, NotifyDelivery, NotifyDeliveryStatus, NotifyDispatched, NotifyFactory, NotifyFn, NotifyJobDispatcher, NotifyOptions, NotifyPriority, NotifyResult, OpenToAllAccessRule, OpenToAllDeclaration, OpenToAllPersonalData, PayloadBucketNormalization, PayloadRateLimitOption, PreparedWriteEvent, QualifiedEventName, QueryEvent, QueryHandlerDef, QueryHandlerFn, RateLimitDeclaration, RateLimitDisabled, RateLimitOption, RateLimitOptions, RateLimitPer, RoleAccessPersonalData, RoleAccessRule, SessionUser, SessionUserOrigin, StreamHandlerDef, StreamHandlerFn, TenantWriteTarget, TryAppendEventFn, TryAppendEventResult, UnsafeAppendEventFn, WriteEvent, WriteHandlerDef, WriteHandlerFn, WriteResult, } from "@cosmicdrift/kumiko-types/handlers";
|
|
10
|
+
export type { AccessRule, ActiveMembership, ActiveMembershipRejection, ActiveMembershipResult, AgentExposure, AgentHandlerHints, AgentRisk, AggregateStreamHandle, AppContext, AppendEventArgs, AppendEventFn, AuthClaimsContext, AuthClaimsFn, AuthClaimsHookDef, BeforeTransactionPhase, BeforeTransactionResult, CamelToKebab, ChatSendFailureCode, ClaimKeyDefinition, ClaimKeyHandle, ClaimKeyJsType, ClaimKeyType, DeclarativeEventMigration, DeliveryErrorCode, DeliveryFailureCode, DeliverySkipReason, DispatchWriteRef, EntityRef, EscapeHatchAuditSink, EscapeHatchDeclaration, EscapeHatchKind, EscapeHatchReporter, EscapeHatchTarget, EscapeHatchUseEvent, EventDef, EventMigrationDef, EventPiiFields, EventPiiStance, EventUpcastCtx, EventUpcastFn, FetchForWritingArgs, HandlerContext, HandlerRef, JobContext, JobRunnerRef, JobTriggerEvent, MemberReader, NameOrRef, NotifyDeferred, NotifyDelivery, NotifyDeliveryStatus, NotifyDispatched, NotifyFactory, NotifyFn, NotifyJobDispatcher, NotifyOptions, NotifyPriority, NotifyResult, OpenToAllAccessRule, OpenToAllDeclaration, OpenToAllPersonalData, PayloadBucketNormalization, PayloadRateLimitOption, PreparedWriteEvent, ProviderPluginContext, QualifiedEventName, QueryEvent, QueryHandlerDef, QueryHandlerFn, RateLimitDeclaration, RateLimitDisabled, RateLimitOption, RateLimitOptions, RateLimitPer, RoleAccessPersonalData, RoleAccessRule, SessionUser, SessionUserOrigin, StreamHandlerDef, StreamHandlerFn, TenantWriteTarget, TryAppendEventFn, TryAppendEventResult, UnsafeAppendEventFn, WriteEvent, WriteHandlerDef, WriteHandlerFn, WriteResult, } from "@cosmicdrift/kumiko-types/handlers";
|
|
11
11
|
export { DELIVERY_FAILURE_CODES, DELIVERY_SKIP_REASONS, declaredRateLimitOptions, HTTP_ERROR_CODE_PATTERN, isDeliveryErrorCode, isOpenToAllGranted, isRateLimitDisabled, isRateLimitOption, isUiAccessGranted, } from "@cosmicdrift/kumiko-types/handlers";
|
|
12
12
|
export type { DeleteContext, EntityHookMap, HookMap, HookOwner, HookPhase, LifecycleHookFn, LifecycleResult, OwnedFn, PhasedHook, PostDeleteBatchHookFn, PostDeleteHookFn, PostQueryHookFn, PostSaveBatchHookFn, PostSaveHookFn, PreDeleteHookFn, PreQueryHookFn, PreSaveHookFn, SaveContext, SearchPayloadContributorFn, ValidationError, ValidationHookFn, } from "@cosmicdrift/kumiko-types/hooks";
|
|
13
13
|
export type { HttpRouteDefinition, HttpRouteHandler, HttpRouteHandlerDeps, HttpRouteMethod, } from "@cosmicdrift/kumiko-types/http-route";
|
|
@@ -17,7 +17,7 @@ export type { ContentCollectionDefinition, NavDefinition, NavIconKey, } from "@c
|
|
|
17
17
|
export type { FromRule, FromRuleKind, OwnershipClause, OwnershipMap, OwnershipRef, OwnershipRule, SqlFragment, WhereRule, WhereRuleContext, } from "@cosmicdrift/kumiko-types/ownership";
|
|
18
18
|
export type { EntityProjectionExtension, MspErrorMode, MspErrorPolicy, MultiStreamApplyFn, MultiStreamProjectionDefinition, ProjectionDefinition, ProjectionRowIdOf, ProjectionTable, SingleStreamApplyFn, } from "@cosmicdrift/kumiko-types/projection";
|
|
19
19
|
export type { BelongsToRelation, EntityRelations, HasManyRelation, ManyToManyRelation, RelationDefinition, } from "@cosmicdrift/kumiko-types/relations";
|
|
20
|
-
export type { ActionFormScreenDefinition, ConfigEditScreenDefinition, CustomScreenDefinition, CustomScreenRoute, DashboardChartMarkerKind, DashboardChartPanel, DashboardChartRangeOption, DashboardChartRanges, DashboardCustomPanel, DashboardDateParam, DashboardFeedPanel, DashboardFilterDefinition, DashboardI18nText, DashboardListPanel, DashboardMoneyParam, DashboardPanelDefinition, DashboardPanelGate, DashboardPanelVisibility, DashboardProgressListPanel, DashboardScreenDefinition, DashboardScreenPanel, DashboardStatGroupPanel, DashboardStatPanel, DashboardText, DashboardTextParam, DashboardValueFormat, EditExtensionSection, EditFieldPrefill, EditFieldSpec, EditFieldsSection, EditLayout, EditRelatedListSection, EditSectionSpec, EditWriteFormSection, EmbeddedListEditSpec, EntityEditAction, EntityEditActionPlacement, EntityEditScreenDefinition, EntityListExpandableRow, EntityListScreenDefinition, FieldCondition, FieldFormatRegistry, FieldRenderer, FormatSpec, FormWidth, ListColumnSpec, ListEmptyStateSpec, ListFacetSpec, ListPaginationMode, ListSortDir, ListSortSpec, MetricNavigate, MetricSpec, PlatformComponent, ProjectionDetailScreenDefinition, ProjectionListScreenDefinition, RecordHeaderSpec, RecordHeaderSubtitlePart, RowAction, RowActionNavigate, RowActionNavigateBase, RowActionWriteHandler, RowFieldExtractor, ScreenDefinition, ScreenFilter, ScreenFilterOp, ScreenNavSugar, ScreenSlots, SecretMintConfirmStep, SecretMintScreenDefinition, SecretReveal, SecretRevealField, SecretsEditScreenDefinition, SecretsEditSection, ToolbarAction, UnitKey, } from "@cosmicdrift/kumiko-types/screen";
|
|
20
|
+
export type { ActionFormScreenDefinition, ConfigEditScreenDefinition, CustomScreenDefinition, CustomScreenRoute, DashboardChartMarkerKind, DashboardChartPanel, DashboardChartRangeOption, DashboardChartRanges, DashboardCurrencyFormat, DashboardCustomPanel, DashboardDateParam, DashboardFeedPanel, DashboardFilterDefinition, DashboardI18nText, DashboardListPanel, DashboardMoneyParam, DashboardPanelDefinition, DashboardPanelGate, DashboardPanelVisibility, DashboardProgressListPanel, DashboardProgressTone, DashboardRecordBinding, DashboardRefresh, DashboardRelativeTimeFormat, DashboardRelativeTimeParam, DashboardScreenDefinition, DashboardScreenPanel, DashboardStatGroupPanel, DashboardStatPanel, DashboardText, DashboardTextBlock, DashboardTextPanel, DashboardTextParam, DashboardValueFormat, EditExtensionSection, EditFieldPrefill, EditFieldSpec, EditFieldsSection, EditLayout, EditRelatedListSection, EditSectionSpec, EditWriteFormSection, EmbeddedListEditSpec, EntityEditAction, EntityEditActionPlacement, EntityEditScreenDefinition, EntityListExpandableRow, EntityListScreenDefinition, FieldCondition, FieldFormatRegistry, FieldRenderer, FormatSpec, FormWidth, ListColumnSpec, ListEmptyStateSpec, ListFacetSpec, ListPaginationMode, ListSortDir, ListSortSpec, MetricNavigate, MetricSpec, PlatformComponent, ProjectionDetailScreenDefinition, ProjectionListScreenDefinition, RecordHeaderSpec, RecordHeaderSubtitlePart, RowAction, RowActionNavigate, RowActionNavigateBase, RowActionWriteHandler, RowFieldExtractor, ScreenDefinition, ScreenFilter, ScreenFilterOp, ScreenNavSugar, ScreenSlots, SecretMintConfirmStep, SecretMintScreenDefinition, SecretReveal, SecretRevealField, SecretsEditScreenDefinition, SecretsEditSection, ToolbarAction, UnitKey, } from "@cosmicdrift/kumiko-types/screen";
|
|
21
21
|
export { metricField, relatedListGroupHeaderLabel, relatedListGroupKey, } from "@cosmicdrift/kumiko-types/screen";
|
|
22
22
|
export type { TargetRef } from "@cosmicdrift/kumiko-types/target-ref";
|
|
23
23
|
export type { Subscribe, TreeAction, TreeActionDef, TreeActionsHandle, TreeChildrenSubscribe, TreeNode, TreeNodeState, } from "@cosmicdrift/kumiko-types/tree-node";
|
package/dist/env/index.js
CHANGED
|
@@ -277,7 +277,7 @@ function formatBootError(errors) {
|
|
|
277
277
|
}
|
|
278
278
|
}
|
|
279
279
|
lines.push("");
|
|
280
|
-
lines.push("See:
|
|
280
|
+
lines.push("See: https://github.com/CosmicDriftGameStudio/infra/blob/main/docs/runbooks/standard-deploy-app.md#schritt-1--env-vertrag-lokal-ausgeben");
|
|
281
281
|
return lines.join("\n");
|
|
282
282
|
}
|
|
283
283
|
export class KumikoBootError extends Error {
|
|
@@ -35,7 +35,7 @@ export function validationErrorFromZod(error) {
|
|
|
35
35
|
// `code: "custom"` is zod's catch-all for every superRefine/refine check;
|
|
36
36
|
// left mechanical it'd collapse onto one generic key, so a superRefine can
|
|
37
37
|
// set `params.i18nKey` to override it. Keep in sync with the client mirror
|
|
38
|
-
// (packages/
|
|
38
|
+
// (packages/renderer/src/headless/form/zod-bridge.ts).
|
|
39
39
|
function resolveI18nKey(issue) {
|
|
40
40
|
if (issue.code === "custom") {
|
|
41
41
|
const override = issue.params?.["i18nKey"];
|
|
@@ -14,7 +14,7 @@ export declare const fileRefEntity: import("@cosmicdrift/kumiko-types/fields").E
|
|
|
14
14
|
readonly sensitive?: boolean;
|
|
15
15
|
readonly writeOnly?: boolean;
|
|
16
16
|
readonly readAsInstruction?: boolean;
|
|
17
|
-
readonly format?: "email" | "url" | "phone" | "password";
|
|
17
|
+
readonly format?: "email" | "url" | "phone" | "password" | "month";
|
|
18
18
|
readonly default?: string;
|
|
19
19
|
readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
|
|
20
20
|
readonly multiline?: boolean | {
|
|
@@ -37,7 +37,7 @@ export declare const fileRefEntity: import("@cosmicdrift/kumiko-types/fields").E
|
|
|
37
37
|
readonly sensitive?: boolean;
|
|
38
38
|
readonly writeOnly?: boolean;
|
|
39
39
|
readonly readAsInstruction?: boolean;
|
|
40
|
-
readonly format?: "email" | "url" | "phone" | "password";
|
|
40
|
+
readonly format?: "email" | "url" | "phone" | "password" | "month";
|
|
41
41
|
readonly default?: string;
|
|
42
42
|
readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
|
|
43
43
|
readonly multiline?: boolean | {
|
|
@@ -60,7 +60,7 @@ export declare const fileRefEntity: import("@cosmicdrift/kumiko-types/fields").E
|
|
|
60
60
|
readonly sensitive?: boolean;
|
|
61
61
|
readonly writeOnly?: boolean;
|
|
62
62
|
readonly readAsInstruction?: boolean;
|
|
63
|
-
readonly format?: "email" | "url" | "phone" | "password";
|
|
63
|
+
readonly format?: "email" | "url" | "phone" | "password" | "month";
|
|
64
64
|
readonly default?: string;
|
|
65
65
|
readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
|
|
66
66
|
readonly multiline?: boolean | {
|
|
@@ -95,7 +95,7 @@ export declare const fileRefEntity: import("@cosmicdrift/kumiko-types/fields").E
|
|
|
95
95
|
readonly sensitive?: boolean;
|
|
96
96
|
readonly writeOnly?: boolean;
|
|
97
97
|
readonly readAsInstruction?: boolean;
|
|
98
|
-
readonly format?: "email" | "url" | "phone" | "password";
|
|
98
|
+
readonly format?: "email" | "url" | "phone" | "password" | "month";
|
|
99
99
|
readonly default?: string;
|
|
100
100
|
readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
|
|
101
101
|
readonly multiline?: boolean | {
|
|
@@ -118,7 +118,7 @@ export declare const fileRefEntity: import("@cosmicdrift/kumiko-types/fields").E
|
|
|
118
118
|
readonly sensitive?: boolean;
|
|
119
119
|
readonly writeOnly?: boolean;
|
|
120
120
|
readonly readAsInstruction?: boolean;
|
|
121
|
-
readonly format?: "email" | "url" | "phone" | "password";
|
|
121
|
+
readonly format?: "email" | "url" | "phone" | "password" | "month";
|
|
122
122
|
readonly default?: string;
|
|
123
123
|
readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
|
|
124
124
|
readonly multiline?: boolean | {
|
|
@@ -141,7 +141,7 @@ export declare const fileRefEntity: import("@cosmicdrift/kumiko-types/fields").E
|
|
|
141
141
|
readonly sensitive?: boolean;
|
|
142
142
|
readonly writeOnly?: boolean;
|
|
143
143
|
readonly readAsInstruction?: boolean;
|
|
144
|
-
readonly format?: "email" | "url" | "phone" | "password";
|
|
144
|
+
readonly format?: "email" | "url" | "phone" | "password" | "month";
|
|
145
145
|
readonly default?: string;
|
|
146
146
|
readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
|
|
147
147
|
readonly multiline?: boolean | {
|
|
@@ -13,7 +13,7 @@ export declare const fileRefsTable: import("../db/table-builder.ts").EntityTable
|
|
|
13
13
|
readonly sensitive?: boolean;
|
|
14
14
|
readonly writeOnly?: boolean;
|
|
15
15
|
readonly readAsInstruction?: boolean;
|
|
16
|
-
readonly format?: "email" | "url" | "phone" | "password";
|
|
16
|
+
readonly format?: "email" | "url" | "phone" | "password" | "month";
|
|
17
17
|
readonly default?: string;
|
|
18
18
|
readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
|
|
19
19
|
readonly multiline?: boolean | {
|
|
@@ -36,7 +36,7 @@ export declare const fileRefsTable: import("../db/table-builder.ts").EntityTable
|
|
|
36
36
|
readonly sensitive?: boolean;
|
|
37
37
|
readonly writeOnly?: boolean;
|
|
38
38
|
readonly readAsInstruction?: boolean;
|
|
39
|
-
readonly format?: "email" | "url" | "phone" | "password";
|
|
39
|
+
readonly format?: "email" | "url" | "phone" | "password" | "month";
|
|
40
40
|
readonly default?: string;
|
|
41
41
|
readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
|
|
42
42
|
readonly multiline?: boolean | {
|
|
@@ -59,7 +59,7 @@ export declare const fileRefsTable: import("../db/table-builder.ts").EntityTable
|
|
|
59
59
|
readonly sensitive?: boolean;
|
|
60
60
|
readonly writeOnly?: boolean;
|
|
61
61
|
readonly readAsInstruction?: boolean;
|
|
62
|
-
readonly format?: "email" | "url" | "phone" | "password";
|
|
62
|
+
readonly format?: "email" | "url" | "phone" | "password" | "month";
|
|
63
63
|
readonly default?: string;
|
|
64
64
|
readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
|
|
65
65
|
readonly multiline?: boolean | {
|
|
@@ -94,7 +94,7 @@ export declare const fileRefsTable: import("../db/table-builder.ts").EntityTable
|
|
|
94
94
|
readonly sensitive?: boolean;
|
|
95
95
|
readonly writeOnly?: boolean;
|
|
96
96
|
readonly readAsInstruction?: boolean;
|
|
97
|
-
readonly format?: "email" | "url" | "phone" | "password";
|
|
97
|
+
readonly format?: "email" | "url" | "phone" | "password" | "month";
|
|
98
98
|
readonly default?: string;
|
|
99
99
|
readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
|
|
100
100
|
readonly multiline?: boolean | {
|
|
@@ -117,7 +117,7 @@ export declare const fileRefsTable: import("../db/table-builder.ts").EntityTable
|
|
|
117
117
|
readonly sensitive?: boolean;
|
|
118
118
|
readonly writeOnly?: boolean;
|
|
119
119
|
readonly readAsInstruction?: boolean;
|
|
120
|
-
readonly format?: "email" | "url" | "phone" | "password";
|
|
120
|
+
readonly format?: "email" | "url" | "phone" | "password" | "month";
|
|
121
121
|
readonly default?: string;
|
|
122
122
|
readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
|
|
123
123
|
readonly multiline?: boolean | {
|
|
@@ -140,7 +140,7 @@ export declare const fileRefsTable: import("../db/table-builder.ts").EntityTable
|
|
|
140
140
|
readonly sensitive?: boolean;
|
|
141
141
|
readonly writeOnly?: boolean;
|
|
142
142
|
readonly readAsInstruction?: boolean;
|
|
143
|
-
readonly format?: "email" | "url" | "phone" | "password";
|
|
143
|
+
readonly format?: "email" | "url" | "phone" | "password" | "month";
|
|
144
144
|
readonly default?: string;
|
|
145
145
|
readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
|
|
146
146
|
readonly multiline?: boolean | {
|
package/dist/files/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export { createFileRefFromBytes, createFileRefFromUploadedBytes, uploadFileBytes
|
|
|
5
5
|
export { createFilesFeature, FILES_FEATURE } from "./feature.ts";
|
|
6
6
|
export type { FileContext, FileHandle } from "./file-handle.ts";
|
|
7
7
|
export { createFileContext, createTenantFileContext, deriveKey, storageKeyStemPrefix, } from "./file-handle.ts";
|
|
8
|
-
export { fileRefEntity } from "./file-ref-entity.ts";
|
|
8
|
+
export { FILE_REF_ENTITY_NAME, fileRefEntity } from "./file-ref-entity.ts";
|
|
9
9
|
export { fileRefsTable } from "./file-ref-table.ts";
|
|
10
10
|
export type { FileAccessDecision, FileAccessGuard, FileRef, FileRoutesOptions, } from "./file-routes.ts";
|
|
11
11
|
export { createFileRoutes, readFilesRouteOptions, resolveMaxUploadBodyBytes, } from "./file-routes.ts";
|
package/dist/files/index.js
CHANGED
|
@@ -4,7 +4,7 @@ export { createFilesFeature, FILES_FEATURE } from "./feature.js";
|
|
|
4
4
|
// `createFileHandle` is an implementation detail — construct handles via
|
|
5
5
|
// `createFileContext(provider).ref(key)`, which is the AppContext surface.
|
|
6
6
|
export { createFileContext, createTenantFileContext, deriveKey, storageKeyStemPrefix, } from "./file-handle.js";
|
|
7
|
-
export { fileRefEntity } from "./file-ref-entity.js";
|
|
7
|
+
export { FILE_REF_ENTITY_NAME, fileRefEntity } from "./file-ref-entity.js";
|
|
8
8
|
export { fileRefsTable } from "./file-ref-table.js";
|
|
9
9
|
export { createFileRoutes, readFilesRouteOptions, resolveMaxUploadBodyBytes, } from "./file-routes.js";
|
|
10
10
|
export { createInMemoryFileProvider } from "./in-memory-provider.js";
|
|
@@ -6,30 +6,30 @@ import type { ConfigAccessor, ConfigAccessorFactory, Registry } from "../engine/
|
|
|
6
6
|
import type { SecretsContext } from "../secrets/index.ts";
|
|
7
7
|
import type { FileStorageProvider } from "./types.ts";
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* Narrow surface type for provider plugins. HandlerContext carries tx, actor,
|
|
10
|
+
* signal and more; providers only get the read fields needed for tenant config
|
|
11
|
+
* and secret lookup.
|
|
12
12
|
*
|
|
13
|
-
* **
|
|
14
|
-
* request-
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
13
|
+
* **Why not the full HandlerContext?** On the worker path (r.job) there is no
|
|
14
|
+
* request-bound `tx`/`actor`/`signal`. A provider reading `ctx.tx` would break
|
|
15
|
+
* the whole worker path at runtime, and that would only show up with S3 in
|
|
16
|
+
* production. The narrow surface forces providers to extend it explicitly
|
|
17
|
+
* instead of quietly relying on extra ctx fields.
|
|
18
18
|
*
|
|
19
|
-
* **
|
|
20
|
-
* config
|
|
21
|
-
* registry
|
|
22
|
-
* secrets
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
19
|
+
* **Fields:**
|
|
20
|
+
* config — tenant config reads (bucket/region/endpoint/...)
|
|
21
|
+
* registry — extension lookup in the factory (not plugin-internal)
|
|
22
|
+
* secrets — tenant secret reads (s3.secretAccessKey)
|
|
23
|
+
* auditUserId — audit and authority identity for secret reads. The framework
|
|
24
|
+
* resolver sets SYSTEM_USER_ID because the s3 provider reads
|
|
25
|
+
* `s3.secretAccessKey`, which non-admin request users may not;
|
|
26
|
+
* request-user authorization stays on the route accessGuard.
|
|
27
27
|
*/
|
|
28
28
|
export type FileProviderContext = {
|
|
29
29
|
readonly config?: ConfigAccessor;
|
|
30
30
|
readonly registry?: Registry;
|
|
31
31
|
readonly secrets?: SecretsContext;
|
|
32
|
-
readonly
|
|
32
|
+
readonly auditUserId?: string | undefined;
|
|
33
33
|
};
|
|
34
34
|
/**
|
|
35
35
|
* File-Storage-Plugin contract. Each provider-feature (file-provider-s3,
|