@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.
Files changed (76) hide show
  1. package/AGENTS.md +2 -2
  2. package/agents/examples/apex-landing.md +1 -1
  3. package/agents/examples/apex-surface-auth.md +3 -3
  4. package/agents/examples/compose-stacks.md +15 -8
  5. package/agents/examples/embedded-entity-form.md +1 -1
  6. package/agents/examples/notes-history-basic.md +1 -1
  7. package/agents/examples/tags-basic.md +1 -1
  8. package/agents/examples/user-profile.md +1 -1
  9. package/agents/examples/wizard-form.md +4 -4
  10. package/agents/widgets.md +4 -3
  11. package/dist/api/index.d.ts +1 -1
  12. package/dist/api/index.js +1 -1
  13. package/dist/api/routes.js +2 -2
  14. package/dist/api/server.js +2 -1
  15. package/dist/config/index.d.ts +4 -0
  16. package/dist/db/index.d.ts +2 -2
  17. package/dist/db/index.js +1 -1
  18. package/dist/db/migrate-runner.js +12 -4
  19. package/dist/db/money.js +1 -1
  20. package/dist/db/query.js +14 -14
  21. package/dist/db/replay-migration-sql.d.ts +1 -0
  22. package/dist/db/replay-migration-sql.js +115 -11
  23. package/dist/db/tenant-db.d.ts +7 -0
  24. package/dist/db/tenant-db.js +17 -5
  25. package/dist/engine/boot-validator/projection-list-screens.js +28 -37
  26. package/dist/engine/boot-validator/query-refs.js +26 -8
  27. package/dist/engine/boot-validator/screens.d.ts +1 -1
  28. package/dist/engine/boot-validator/screens.js +334 -42
  29. package/dist/engine/boot-validator/url-prefill-fields.js +3 -0
  30. package/dist/engine/build-app-schema.js +7 -3
  31. package/dist/engine/entity-list-searchability.d.ts +5 -0
  32. package/dist/engine/entity-list-searchability.js +35 -0
  33. package/dist/engine/feature-ui-extensions.js +5 -2
  34. package/dist/engine/index.d.ts +3 -1
  35. package/dist/engine/index.js +2 -0
  36. package/dist/engine/paged-list.d.ts +29 -0
  37. package/dist/engine/paged-list.js +56 -0
  38. package/dist/engine/parse-ref-target.js +1 -1
  39. package/dist/engine/project-app-schema-for-roles.js +37 -6
  40. package/dist/engine/provider-plugin-context.d.ts +3 -0
  41. package/dist/engine/provider-plugin-context.js +28 -0
  42. package/dist/engine/schema-builder.js +7 -0
  43. package/dist/engine/types/index.d.ts +2 -2
  44. package/dist/env/index.js +1 -1
  45. package/dist/errors/zod-bridge.js +1 -1
  46. package/dist/files/file-ref-entity.d.ts +6 -6
  47. package/dist/files/file-ref-table.d.ts +6 -6
  48. package/dist/files/index.d.ts +1 -1
  49. package/dist/files/index.js +1 -1
  50. package/dist/files/provider-resolver.d.ts +17 -17
  51. package/dist/files/provider-resolver.js +1 -1
  52. package/dist/http/egress.d.ts +14 -0
  53. package/dist/http/egress.js +144 -0
  54. package/dist/http/index.d.ts +3 -2
  55. package/dist/http/index.js +2 -1
  56. package/dist/http/policy.d.ts +30 -0
  57. package/dist/http/policy.js +299 -0
  58. package/dist/i18n/required-surface-keys.js +52 -2
  59. package/dist/jobs/job-runner.js +4 -2
  60. package/dist/pipeline/config-accessor-factory.d.ts +3 -0
  61. package/dist/pipeline/config-accessor-factory.js +3 -0
  62. package/dist/pipeline/dispatch-shared.js +7 -5
  63. package/dist/pipeline/index.d.ts +1 -0
  64. package/dist/pipeline/index.js +1 -0
  65. package/dist/ui-types/index.d.ts +1 -1
  66. package/dist/upgrade-changelog.d.ts +25 -0
  67. package/dist/upgrade-changelog.js +48 -0
  68. package/dist/upgrade-cli.js +78 -13
  69. package/package.json +3 -5
  70. package/presets/biome-app.json +8 -0
  71. package/src/changes.json +132 -0
  72. package/src/scripts/codemod/README.md +25 -0
  73. package/src/scripts/codemod/codemod-support.ts +64 -6
  74. package/src/scripts/codemod/package-merge.ts +260 -0
  75. package/src/scripts/codemod/s3-imports.ts +4 -42
  76. 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 schema = registry.getQueryHandler(screen.query)?.schema;
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 ?? capabilities.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
- if (panel.screen === "" || isValidQn(panel.screen))
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: qualifyEntityName(featureName, "screen", 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.`);
@@ -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";
@@ -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
- const kept = panels.filter((p) => p.kind !== "screen" || isScreenTargetKept(feature.featureName, p.screen, keptScreenQns));
422
- return kept.length === panels.length ? panels : kept;
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
- return nextPanels === screen.panels ? screen : { ...screen, panels: nextPanels };
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: kumiko-platform/docs/runbooks/standard-deploy-app.md#step-1-boot-dry-run-lokal");
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/headless/src/form/zod-bridge.ts).
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 | {
@@ -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";
@@ -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
- * Schmaler Surface-Type fuer Provider-Plugins. HandlerContext ist zu fett
10
- * (haelt tx, actor, signal etc.) — Provider sollen sich auf die read-Felder
11
- * beschraenken die fuer Tenant-Config + Secret-Lookup gebraucht werden.
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
- * **Warum nicht voller HandlerContext?** Im Worker-Pfad (r.job) gibt es keinen
14
- * request-bezogenen `tx`/`actor`/`signal`. Wenn ein Provider `ctx.tx` lesen
15
- * wuerde, wuerde der ganze Worker-Pfad zur Runtime brechen — und das wuerde NUR
16
- * mit S3 und nur in production auffallen. Die schmale Surface zwingt Provider
17
- * zur expliziten Erweiterung statt silent ctx-feld-ausnutzen.
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
- * **Felder:**
20
- * config — fuer tenant-config-reads (bucket/region/endpoint/...)
21
- * registry — fuer extension-Lookup in der Factory (nicht Plugin-intern)
22
- * secrets — fuer tenant-secret-reads (s3.secretAccessKey)
23
- * _userId — Audit-/Authority-Identity fuer secret-reads. Der Framework-
24
- * Resolver setzt das auf SYSTEM_USER_ID — der s3-Provider liest
25
- * `s3.secretAccessKey`, was Nicht-Admin-Request-User nicht duerfen;
26
- * die Request-User-Autorisierung bleibt am Route-accessGuard.
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 _userId?: string | undefined;
32
+ readonly auditUserId?: string | undefined;
33
33
  };
34
34
  /**
35
35
  * File-Storage-Plugin contract. Each provider-feature (file-provider-s3,