@cosmicdrift/kumiko-framework 0.381.0 → 0.383.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 (94) hide show
  1. package/agents/examples/api-worker-split.md +57 -0
  2. package/agents/examples/record-detail-layout.md +20 -18
  3. package/agents/examples/screens-nav.md +3 -2
  4. package/agents/examples/writeform-section.md +2 -1
  5. package/dist/api/api-constants.d.ts +1 -0
  6. package/dist/api/api-constants.js +2 -0
  7. package/dist/api/auth-middleware.d.ts +1 -0
  8. package/dist/api/auth-middleware.js +17 -0
  9. package/dist/api/auth-routes.d.ts +1 -0
  10. package/dist/api/auth-routes.js +14 -4
  11. package/dist/api/client-error-route.d.ts +12 -0
  12. package/dist/api/client-error-route.js +113 -0
  13. package/dist/api/request-context.d.ts +6 -0
  14. package/dist/api/request-context.js +9 -0
  15. package/dist/api/routes.js +7 -4
  16. package/dist/api/server.js +11 -1
  17. package/dist/db/connection.d.ts +7 -0
  18. package/dist/db/connection.js +40 -0
  19. package/dist/db/index.d.ts +2 -1
  20. package/dist/db/index.js +2 -1
  21. package/dist/db/migrate-runner.js +4 -0
  22. package/dist/db/queries/backfill-pii.js +5 -1
  23. package/dist/db/queries/event-store.js +9 -2
  24. package/dist/db/statement-timeout.d.ts +2 -0
  25. package/dist/db/statement-timeout.js +18 -0
  26. package/dist/db/tenant-db.js +5 -12
  27. package/dist/engine/boot-validator/access-declarations.js +17 -18
  28. package/dist/engine/boot-validator/query-output-columns.js +1 -2
  29. package/dist/engine/boot-validator/screens.js +12 -16
  30. package/dist/engine/boot-validator/url-prefill-fields.js +1 -3
  31. package/dist/engine/build-config-feature-schema.js +4 -4
  32. package/dist/engine/entity-handlers.js +5 -7
  33. package/dist/engine/escape-hatch-declaration.d.ts +1 -1
  34. package/dist/engine/escape-hatch-declaration.js +5 -2
  35. package/dist/engine/escape-hatch-reason.d.ts +2 -0
  36. package/dist/engine/escape-hatch-reason.js +35 -0
  37. package/dist/engine/extensions/escape-hatch-usage.js +2 -1
  38. package/dist/engine/feature-config-events-jobs.js +6 -4
  39. package/dist/engine/feature-ui-extensions.js +12 -6
  40. package/dist/engine/iban.d.ts +2 -0
  41. package/dist/engine/iban.js +19 -0
  42. package/dist/engine/index.d.ts +1 -1
  43. package/dist/engine/project-app-schema-for-roles.js +1 -1
  44. package/dist/engine/registry-validate.d.ts +1 -0
  45. package/dist/engine/registry-validate.js +8 -0
  46. package/dist/engine/registry.js +2 -1
  47. package/dist/engine/schema-builder.js +9 -0
  48. package/dist/engine/screen-helpers.d.ts +3 -3
  49. package/dist/engine/screen-helpers.js +1 -2
  50. package/dist/engine/steps/_read-source.js +2 -0
  51. package/dist/engine/types/index.d.ts +2 -2
  52. package/dist/engine/types/index.js +1 -1
  53. package/dist/engine/types/screen.d.ts +1 -1
  54. package/dist/engine/types/screen.js +1 -1
  55. package/dist/entrypoint/index.d.ts +1 -0
  56. package/dist/entrypoint/index.js +1 -0
  57. package/dist/event-store/event-store.d.ts +0 -3
  58. package/dist/event-store/event-store.js +1 -26
  59. package/dist/event-store/index.d.ts +1 -1
  60. package/dist/event-store/index.js +1 -1
  61. package/dist/event-store/snapshot.js +6 -1
  62. package/dist/files/file-ref-entity.d.ts +6 -6
  63. package/dist/files/file-ref-table.d.ts +6 -6
  64. package/dist/i18n/required-surface-keys.js +0 -1
  65. package/dist/jobs/job-runner.d.ts +1 -0
  66. package/dist/jobs/job-runner.js +74 -7
  67. package/dist/logging/index.d.ts +2 -1
  68. package/dist/logging/index.js +2 -1
  69. package/dist/logging/pino-logger.d.ts +1 -0
  70. package/dist/logging/pino-logger.js +35 -0
  71. package/dist/logging/request-log-fields.d.ts +1 -0
  72. package/dist/logging/request-log-fields.js +21 -0
  73. package/dist/logging/scrub.d.ts +2 -0
  74. package/dist/logging/scrub.js +21 -0
  75. package/dist/logging/utils.d.ts +1 -0
  76. package/dist/logging/utils.js +40 -6
  77. package/dist/migrations/pii-event-backfill.js +5 -1
  78. package/dist/observability/standard-metrics.d.ts +1 -0
  79. package/dist/observability/standard-metrics.js +9 -0
  80. package/dist/pipeline/msp-rebuild.js +5 -1
  81. package/dist/pipeline/projection-rebuild.js +5 -1
  82. package/dist/rate-limit/middleware.d.ts +8 -3
  83. package/dist/rate-limit/middleware.js +28 -10
  84. package/dist/rate-limit/resolver.js +10 -0
  85. package/dist/redis/client.d.ts +2 -0
  86. package/dist/redis/client.js +20 -0
  87. package/dist/redis/index.d.ts +1 -1
  88. package/dist/redis/index.js +1 -1
  89. package/dist/search/purge-subject.js +6 -8
  90. package/dist/search/reindex-entity.js +11 -10
  91. package/dist/ui-types/index.d.ts +1 -1
  92. package/dist/ui-types/index.js +1 -1
  93. package/package.json +3 -3
  94. package/src/changes.json +64 -0
@@ -0,0 +1,2 @@
1
+ export declare function normalizeIban(value: string): string;
2
+ export declare function isValidIban(value: string): boolean;
@@ -0,0 +1,19 @@
1
+ const IBAN_SHAPE = /^[A-Z]{2}\d{2}[A-Z0-9]{11,30}$/;
2
+ const MOD_97_RESIDUE = 1;
3
+ export function normalizeIban(value) {
4
+ return value.replace(/\s+/g, "").toUpperCase();
5
+ }
6
+ // Digit-wise reduction keeps every intermediate below 2^31, so no BigInt is needed for up to 34 characters.
7
+ export function isValidIban(value) {
8
+ const iban = normalizeIban(value);
9
+ if (!IBAN_SHAPE.test(iban))
10
+ return false;
11
+ const rearranged = iban.slice(4) + iban.slice(0, 4);
12
+ let remainder = 0;
13
+ for (const char of rearranged) {
14
+ const digits = char >= "A" ? String(char.charCodeAt(0) - 55) : char;
15
+ for (const digit of digits)
16
+ remainder = (remainder * 10 + Number(digit)) % 97;
17
+ }
18
+ return remainder === MOD_97_RESIDUE;
19
+ }
@@ -87,7 +87,7 @@ export { assertNotificationVariables, templateVariable, templateVariablesToZod,
87
87
  export { type EffectiveFeaturesResolver, findTierResolverUsage, isTierResolverPlugin, requireTierResolverPlugin, TENANT_TIER_RESOLVER_EXT, type TierResolverPlugin, type TrialGate, } from "./tier-resolver-extension.ts";
88
88
  export { findOverDeepTransferChain, resolveTransferAdjacency as resolveEntityTransferAdjacency, type TransferAdjacency, type TransferEdge, type TransferEdgeLink, } from "./transfer-adjacency.ts";
89
89
  export { isSystemTenant, isUuid, parseTenantId, SYSTEM_TENANT_ID } from "./types/identifiers.ts";
90
- 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, TemplateImagesVariableDef, 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";
90
+ 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, JobDeferral, 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, TemplateImagesVariableDef, 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";
91
91
  export { DEFAULT_CURRENCIES, DEFAULT_LOCALES, DELIVERY_FAILURE_CODES, DELIVERY_SKIP_REASONS, HookPhases, HTTP_ERROR_CODE_PATTERN, isAgentVisibleScreen, isDeliveryErrorCode, isOpenToAllGranted, resolveAgentExposure, } from "./types/index.ts";
92
92
  export type { AwaitedEventType, PipelineBuildCtx, PipelineCtx, PipelineDef, StepBuilder, StepDef, StepFailureStrategy, StepInstance, StepKind, StepNamespace, StepResolver, } from "./types/step.ts";
93
93
  export { runValidation } from "./validation.ts";
@@ -391,7 +391,7 @@ function projectMetrics(metrics, indices, keptScreenQns) {
391
391
  return undefined;
392
392
  let changed = false;
393
393
  const next = metrics.map((m) => {
394
- if (typeof m === "string" || m.navigate === undefined)
394
+ if (m.navigate === undefined)
395
395
  return m;
396
396
  if (keepMetricNavigate(m.navigate, indices, keptScreenQns))
397
397
  return m;
@@ -27,6 +27,7 @@ export declare function resolveJobTriggers(state: RegistryState): void;
27
27
  export declare function validateLiveEntities(state: RegistryState): void;
28
28
  export declare function validateBootGates(state: RegistryState): void;
29
29
  export declare function validateJobBackoff(state: RegistryState): void;
30
+ export declare function validateMaxDefers(state: RegistryState): void;
30
31
  export declare function validateMaxPerTenant(state: RegistryState): void;
31
32
  export declare function validateExtensionUsageTargets(state: RegistryState): void;
32
33
  export declare function computeHasRateLimitedHandler(state: RegistryState): void;
@@ -767,6 +767,14 @@ export function validateJobBackoff(state) {
767
767
  }
768
768
  }
769
769
  }
770
+ export function validateMaxDefers(state) {
771
+ for (const [jobName, jobDef] of state.jobMap) {
772
+ const { maxDefers } = jobDef;
773
+ if (maxDefers !== undefined && (!Number.isInteger(maxDefers) || maxDefers <= 0)) {
774
+ throw new Error(`Job "${jobName}" maxDefers must be a positive integer (got ${maxDefers})`);
775
+ }
776
+ }
777
+ }
770
778
  export function validateMaxPerTenant(state) {
771
779
  for (const [jobName, jobDef] of state.jobMap) {
772
780
  const resolved = resolveMaxPerTenant(jobDef);
@@ -3,7 +3,7 @@ import { dedupeFeatures } from "./dedupe-features.js";
3
3
  import { buildRegistryFacade } from "./registry-facade.js";
4
4
  import { populateClaimsAndAuth, populateConfigKeys, populateEvents, populateExtensionsAndSeeds, populateFeatureCore, populateHandlers, populateHooks, populateJobsAndNotifications, populateMetricsAndSecrets, populateProjectionsAndTables, populateScreensNavWorkspaces, populateSystemEvents, populateTranslations, } from "./registry-ingest.js";
5
5
  import { createInitialState } from "./registry-state.js";
6
- import { applyExtensionUsages, autoWireSoftDeleteJobs, buildEntityEventUpcasterChains, buildEventUpcasterChains, buildImplicitProjections, buildIncomingRelations, buildSearchableSortableCaches, computeHasRateLimitedHandler, finalizeWorkspaceNavMembership, populateHandlerEntityMappings, publishEventPiiCatalog, resolveJobTriggers, resolveNotificationTriggersAndRegisterHooks, validateBootGates, validateEntityHookTargets, validateEventMigrationVersions, validateExtensionSelectors, validateExtensionUsageTargets, validateFieldAccessHandlersAreEntityMapped, validateJobBackoff, validateLifecycleHookTargets, validateLiveEntities, validateMaxPerTenant, validateNotificationRecordMappings, validateNotificationRenamedFrom, validateProjectionApplyKeys, validateRelationTargetsExist, validateRequiredFeatures, } from "./registry-validate.js";
6
+ import { applyExtensionUsages, autoWireSoftDeleteJobs, buildEntityEventUpcasterChains, buildEventUpcasterChains, buildImplicitProjections, buildIncomingRelations, buildSearchableSortableCaches, computeHasRateLimitedHandler, finalizeWorkspaceNavMembership, populateHandlerEntityMappings, publishEventPiiCatalog, resolveJobTriggers, resolveNotificationTriggersAndRegisterHooks, validateBootGates, validateEntityHookTargets, validateEventMigrationVersions, validateExtensionSelectors, validateExtensionUsageTargets, validateFieldAccessHandlersAreEntityMapped, validateJobBackoff, validateLifecycleHookTargets, validateLiveEntities, validateMaxDefers, validateMaxPerTenant, validateNotificationRecordMappings, validateNotificationRenamedFrom, validateProjectionApplyKeys, validateRelationTargetsExist, validateRequiredFeatures, } from "./registry-validate.js";
7
7
  // This is where the magic happens. By "magic" I mean: precomputed maps.
8
8
  // I build everything once at boot (hooks, relations, searchable fields, ...)
9
9
  // so nothing has to iterate over objects at runtime. O(1) instead of O(n*m).
@@ -49,6 +49,7 @@ export function createRegistry(rawFeatures) {
49
49
  validateBootGates(state);
50
50
  validateLiveEntities(state);
51
51
  validateJobBackoff(state);
52
+ validateMaxDefers(state);
52
53
  validateMaxPerTenant(state);
53
54
  validateExtensionUsageTargets(state);
54
55
  computeHasRateLimitedHandler(state);
@@ -3,6 +3,7 @@ import { moneyPayloadToMinorUnits } from "../db/money.js";
3
3
  import { isValidIanaTimeZone } from "../time/index.js";
4
4
  import { assertUnreachable } from "../utils/index.js";
5
5
  import { withDerivedCells } from "./embedded-derived.js";
6
+ import { isValidIban } from "./iban.js";
6
7
  import { DEFAULT_CURRENCIES } from "./types/index.js";
7
8
  const MONTH_PATTERN = /^\d{4}-(0[1-9]|1[0-2])$/;
8
9
  // True if `n` carries at most `scale` decimal places. A relative epsilon
@@ -107,6 +108,14 @@ export function fieldToZod(field, currencies, opts = {}) {
107
108
  schema = schema.email();
108
109
  if (field.format === "url")
109
110
  schema = schema.url();
111
+ if (field.format === "iban") {
112
+ // "" stays valid for an optional field; `required` rejects it via min(1) below.
113
+ schema = schema.superRefine((value, ctx) => {
114
+ if (value !== "" && !isValidIban(value)) {
115
+ ctx.addIssue({ code: "invalid_format", format: "iban", input: value });
116
+ }
117
+ });
118
+ }
110
119
  if (field.format === "month") {
111
120
  // "" stays valid for an optional field; `required` rejects it via min(1) below.
112
121
  schema = schema.refine((value) => value === "" || MONTH_PATTERN.test(value), {
@@ -8,10 +8,10 @@ export declare function isEditLayoutScreen(screen: ScreenDefinition): screen is
8
8
  export declare function isExtensionEditSection(section: EditSectionSpec): section is EditExtensionSection;
9
9
  export declare function isFieldsEditSection(section: EditSectionSpec): section is EditFieldsSection;
10
10
  export declare function isWriteFormEditSection(section: EditSectionSpec): section is EditWriteFormSection;
11
- /** Structural shape of every section that can carry `fields` and/or `groups` —
12
- * matches EditWriteFormSection (no `groups`) too, so callers need no narrowing. */
11
+ /** Structural reader contract for every section that can carry `fields` and/or `groups`: the
12
+ * `EditFieldsSection` union members and `EditWriteFormSection` all assign without narrowing. */
13
13
  export type FieldsOrGroupsSection = {
14
- readonly fields: readonly EditFieldSpec[];
14
+ readonly fields?: readonly EditFieldSpec[];
15
15
  readonly groups?: readonly {
16
16
  readonly title: string;
17
17
  readonly fields: readonly EditFieldSpec[];
@@ -73,8 +73,7 @@ export function isWriteFormEditSection(section) {
73
73
  // one runs after the fields-XOR-groups check, collectors run without it and must
74
74
  // not drop a source (fw#2986).
75
75
  export function sectionFieldSpecs(section) {
76
- // kumiko-lint-ignore section-fields-raw this IS the union reader — the groups source is added on the same line
77
- return [...section.fields, ...(section.groups?.flatMap((group) => group.fields) ?? [])];
76
+ return [...(section.fields ?? []), ...(section.groups?.flatMap((group) => group.fields) ?? [])];
78
77
  }
79
78
  // Type guard — narrows FieldRenderer to FormatSpec. Useful for renderer
80
79
  // authors who branch on the three FieldRenderer variants without manual
@@ -1,5 +1,6 @@
1
1
  import { requestedTenantIds, unsafeRawForDeclaredStep } from "../../db/tenant-db.js";
2
2
  import { InternalError } from "../../errors/classes.js";
3
+ import { assertReason } from "../escape-hatch-reason.js";
3
4
  import { SYSTEM_TENANT_ID } from "../types/identifiers.js";
4
5
  // unsafeRaw fails closed without the handler's escapeHatch (or systemScope) and reports the use.
5
6
  export function readSourceFor(ctx, unsafeAllTenants) {
@@ -12,6 +13,7 @@ export function readSourceFor(ctx, unsafeAllTenants) {
12
13
  message: "unsafeAllTenants on a read step must be { reason: string }",
13
14
  });
14
15
  }
16
+ assertReason("unsafeAllTenants", unsafeAllTenants.reason);
15
17
  return unsafeRawForDeclaredStep(ctx.systemDb ?? ctx.db, unsafeAllTenants.reason);
16
18
  }
17
19
  // TenantDb silently narrows a foreign where.tenantId to the caller's scope; the step keeps that
@@ -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, 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";
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, JobDeferral, 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";
@@ -18,7 +18,7 @@ export type { FromRule, FromRuleKind, OwnershipClause, OwnershipMap, OwnershipRe
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
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, FormFieldDerivation, 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
- export { metricField, relatedListGroupHeaderLabel, relatedListGroupKey, } from "@cosmicdrift/kumiko-types/screen";
21
+ export { 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";
24
24
  export type { WebSocketConnection, WebSocketMessageData, WebSocketRouteConnectDeps, WebSocketRouteDefinition, WebSocketSessionHandlers, } from "@cosmicdrift/kumiko-types/websocket-route";
@@ -3,7 +3,7 @@
3
3
  export { isAgentVisibleScreen, resolveAgentExposure, } from "@cosmicdrift/kumiko-types/agent-exposure";
4
4
  export { DELIVERY_FAILURE_CODES, DELIVERY_SKIP_REASONS, declaredRateLimitOptions, HTTP_ERROR_CODE_PATTERN, isDeliveryErrorCode, isOpenToAllGranted, isRateLimitDisabled, isRateLimitOption, isUiAccessGranted, } from "@cosmicdrift/kumiko-types/handlers";
5
5
  export { isSystemTenant, isUuid, parseTenantId, SYSTEM_TENANT_ID, } from "@cosmicdrift/kumiko-types/identifiers";
6
- export { metricField, relatedListGroupHeaderLabel, relatedListGroupKey, } from "@cosmicdrift/kumiko-types/screen";
6
+ export { relatedListGroupHeaderLabel, relatedListGroupKey, } from "@cosmicdrift/kumiko-types/screen";
7
7
  export { DEFAULT_CURRENCIES, DEFAULT_LOCALES, isFileField } from "../field-helpers.js";
8
8
  export { resolveName, withResponseData } from "../handler-helpers.js";
9
9
  export { HookPhases } from "../hook-helpers.js";
@@ -1,2 +1,2 @@
1
1
  export type * from "@cosmicdrift/kumiko-types/screen";
2
- export { metricField, relatedListGroupHeaderLabel, relatedListGroupKey, } from "@cosmicdrift/kumiko-types/screen";
2
+ export { relatedListGroupHeaderLabel, relatedListGroupKey, } from "@cosmicdrift/kumiko-types/screen";
@@ -1 +1 @@
1
- export { metricField, relatedListGroupHeaderLabel, relatedListGroupKey, } from "@cosmicdrift/kumiko-types/screen";
1
+ export { relatedListGroupHeaderLabel, relatedListGroupKey, } from "@cosmicdrift/kumiko-types/screen";
@@ -29,6 +29,7 @@ type JobsBlock = {
29
29
  readonly onJobStart?: JobRunnerOptions["onJobStart"];
30
30
  readonly onJobComplete?: JobRunnerOptions["onJobComplete"];
31
31
  readonly onJobFailed?: JobRunnerOptions["onJobFailed"];
32
+ readonly onJobDeferred?: JobRunnerOptions["onJobDeferred"];
32
33
  readonly onJobQueued?: JobRunnerOptions["onJobQueued"];
33
34
  readonly onJobDropped?: JobRunnerOptions["onJobDropped"];
34
35
  };
@@ -174,6 +174,7 @@ function buildJobRunnerWithHook(registry, context, jobs, consumerLane, lifecycle
174
174
  onJobStart: jobs.onJobStart,
175
175
  onJobComplete: jobs.onJobComplete,
176
176
  onJobFailed: jobs.onJobFailed,
177
+ onJobDeferred: jobs.onJobDeferred,
177
178
  onJobQueued: jobs.onJobQueued,
178
179
  onJobDropped: jobs.onJobDropped,
179
180
  });
@@ -41,7 +41,4 @@ export declare function getUnscopedAggregateStreamMaxVersion(db: DbRunner, aggre
41
41
  export declare function getUnscopedStreamMaxVersionForSeed(...args: Parameters<typeof getUnscopedAggregateStreamMaxVersion>): ReturnType<typeof getUnscopedAggregateStreamMaxVersion>;
42
42
  export declare function getEventsHighWaterMark(db: DbRunner): Promise<bigint>;
43
43
  export declare function loadEventsAfterVersion(db: DbRunner, aggregateId: string, tenantId: TenantId, afterVersion: number): Promise<readonly StoredEvent[]>;
44
- export declare const LOAD_ALL_EVENTS_ROW_LIMIT = 100000;
45
- /** Buffers ALL matching events in memory — a memory cliff for large stores. Use `streamAllEventsByType` (yields batchwise) for production reads; this is test-only in practice. */
46
- export declare function loadAllEventsByType(db: DbRunner, aggregateType: string, rowLimit?: number): Promise<readonly StoredEvent[]>;
47
44
  export declare function streamAllEventsByType(db: DbRunner, aggregateType: string, batchSize?: number, signal?: AbortSignal): AsyncIterable<StoredEvent>;
@@ -284,30 +284,6 @@ export async function loadEventsAfterVersion(db, aggregateId, tenantId, afterVer
284
284
  const rows = await selectMany(db, eventsTable, { aggregateId, tenantId, version: { gt: afterVersion } }, { orderBy: { col: "version", direction: "asc" } });
285
285
  return rows.map(toStoredEvent);
286
286
  }
287
- // Load every event for an aggregate_type across all tenants. Ordered by
288
- // (created_at, id) — chronological replay order for projection rebuilds.
289
- // Mostly called from tests today — production rebuild goes through
290
- // projection-rebuild's own streaming path.
291
- //
292
- // Fails loud past LOAD_ALL_EVENTS_ROW_LIMIT rather than silently buffering
293
- // an unbounded result set — that's the memory cliff this guard exists to
294
- // prevent.
295
- export const LOAD_ALL_EVENTS_ROW_LIMIT = 100_000;
296
- /** Buffers ALL matching events in memory — a memory cliff for large stores. Use `streamAllEventsByType` (yields batchwise) for production reads; this is test-only in practice. */
297
- export async function loadAllEventsByType(db, aggregateType, rowLimit = LOAD_ALL_EVENTS_ROW_LIMIT) {
298
- const rows = await selectMany(db, eventsTable, { aggregateType }, {
299
- orderBy: [
300
- { col: "createdAt", direction: "asc" },
301
- { col: "id", direction: "asc" },
302
- ],
303
- limit: rowLimit + 1,
304
- });
305
- if (rows.length > rowLimit) {
306
- throw new Error(`loadAllEventsByType("${aggregateType}") exceeds ${rowLimit} rows — ` +
307
- "use streamAllEventsByType instead of buffering the full result set in memory.");
308
- }
309
- return rows.map(toStoredEvent);
310
- }
311
287
  // Stream every event for an aggregate_type across all tenants, batchwise
312
288
  // instead of buffered. Memory-bounded: never more than `batchSize` rows
313
289
  // resident. Cursor walks `events.id` (bigserial monotonic, but ids are
@@ -317,8 +293,7 @@ export async function loadAllEventsByType(db, aggregateType, rowLimit = LOAD_ALL
317
293
  // (projection-rebuild, tests) that don't need live, just-committed rows.
318
294
  //
319
295
  // Use case: projection-rebuild on a large event log (>100k events per
320
- // aggregate-type). loadAllEventsByType would OOM; this iterator yields
321
- // in batches and the caller accumulates only what it needs.
296
+ // aggregate-type); the caller accumulates only what it needs.
322
297
  //
323
298
  // Default batchSize 1000 — trade-off between DB round-trips (smaller =
324
299
  // more queries) and memory (larger = more resident).
@@ -3,7 +3,7 @@ export { backfillEventPiiEncryption, backfillEventPiiEncryptionBatch, type PiiBa
3
3
  export { type DeleteRowsWithoutReplayableStreamArgs, deleteRowsWithoutReplayableStream, } from "../db/queries/event-store-orphan-rows.ts";
4
4
  export { type ArchiveStreamArgs, archivedStreamsTable, archiveStream, createArchivedStreamsTable, isStreamArchived, restoreStream, } from "./archive.ts";
5
5
  export { ArchivedStreamError, IdempotentAppendConflictError, SeedTimeOrderError, VersionConflictError, } from "./errors.ts";
6
- export { append, EVENTS_PUBSUB_CHANNEL, type EventMetadata, type EventToAppend, getEventsHighWaterMark, getStreamVersion, getStreamVersions, getUnscopedAggregateStreamMaxVersion, getUnscopedStreamMaxVersionForSeed, LOAD_ALL_EVENTS_ROW_LIMIT, loadAggregate, loadAggregateAsOf, loadAllEventsByType, loadEventsAfterVersion, type StoredEvent, streamAllEventsByType, } from "./event-store.ts";
6
+ export { append, EVENTS_PUBSUB_CHANNEL, type EventMetadata, type EventToAppend, getEventsHighWaterMark, getStreamVersion, getStreamVersions, getUnscopedAggregateStreamMaxVersion, getUnscopedStreamMaxVersionForSeed, loadAggregate, loadAggregateAsOf, loadEventsAfterVersion, type StoredEvent, streamAllEventsByType, } from "./event-store.ts";
7
7
  export { createEventsTable, eventsTable } from "./events-schema.ts";
8
8
  export { appendProvenanceEvent, type ProvenanceEventInput } from "./provenance-append.ts";
9
9
  export { createRebuildDeadLetterTable, listRebuildDeadLetters, type RebuildDeadLetterRow, rebuildDeadLetterTable, recordRebuildDeadLetters, type SkippedApply, } from "./rebuild-dead-letter.ts";
@@ -3,7 +3,7 @@ export { backfillEventPiiEncryption, backfillEventPiiEncryptionBatch, } from "..
3
3
  export { deleteRowsWithoutReplayableStream, } from "../db/queries/event-store-orphan-rows.js";
4
4
  export { archivedStreamsTable, archiveStream, createArchivedStreamsTable, isStreamArchived, restoreStream, } from "./archive.js";
5
5
  export { ArchivedStreamError, IdempotentAppendConflictError, SeedTimeOrderError, VersionConflictError, } from "./errors.js";
6
- export { append, EVENTS_PUBSUB_CHANNEL, getEventsHighWaterMark, getStreamVersion, getStreamVersions, getUnscopedAggregateStreamMaxVersion, getUnscopedStreamMaxVersionForSeed, LOAD_ALL_EVENTS_ROW_LIMIT, loadAggregate, loadAggregateAsOf, loadAllEventsByType, loadEventsAfterVersion, streamAllEventsByType, } from "./event-store.js";
6
+ export { append, EVENTS_PUBSUB_CHANNEL, getEventsHighWaterMark, getStreamVersion, getStreamVersions, getUnscopedAggregateStreamMaxVersion, getUnscopedStreamMaxVersionForSeed, loadAggregate, loadAggregateAsOf, loadEventsAfterVersion, streamAllEventsByType, } from "./event-store.js";
7
7
  export { createEventsTable, eventsTable } from "./events-schema.js";
8
8
  export { appendProvenanceEvent } from "./provenance-append.js";
9
9
  export { createRebuildDeadLetterTable, listRebuildDeadLetters, rebuildDeadLetterTable, recordRebuildDeadLetters, } from "./rebuild-dead-letter.js";
@@ -5,6 +5,7 @@ import { ensureSnapshotVersionColumn, upsertSnapshot } from "../db/queries/event
5
5
  import { selectMany } from "../db/query.js";
6
6
  import { tableExists } from "../db/schema-inspection.js";
7
7
  import { unsafePushTables } from "../db/table-push.js";
8
+ import { createFallbackLogger, scrubLogText } from "../logging/index.js";
8
9
  import { isStreamArchived } from "./archive.js";
9
10
  import { loadEventsAfterVersion } from "./event-store.js";
10
11
  // Marten-aligned snapshot store. A snapshot is a point-in-time materialised
@@ -153,8 +154,12 @@ export async function loadAggregateWithSnapshot(db, aggregateId, tenantId, reduc
153
154
  snapshotVersion: generationFor(lastDelta.aggregateType),
154
155
  });
155
156
  }
156
- catch {
157
+ catch (err) {
157
158
  // Best-effort cache write — losing it only costs the next load a replay.
159
+ createFallbackLogger("snapshot").warn("snapshot save failed", {
160
+ aggregateType: lastDelta.aggregateType,
161
+ error: scrubLogText(err instanceof Error ? err.message : String(err)),
162
+ });
158
163
  }
159
164
  }
160
165
  return {
@@ -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" | "month";
17
+ readonly format?: "email" | "url" | "phone" | "password" | "month" | "iban";
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" | "month";
40
+ readonly format?: "email" | "url" | "phone" | "password" | "month" | "iban";
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" | "month";
63
+ readonly format?: "email" | "url" | "phone" | "password" | "month" | "iban";
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" | "month";
98
+ readonly format?: "email" | "url" | "phone" | "password" | "month" | "iban";
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" | "month";
121
+ readonly format?: "email" | "url" | "phone" | "password" | "month" | "iban";
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" | "month";
144
+ readonly format?: "email" | "url" | "phone" | "password" | "month" | "iban";
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" | "month";
16
+ readonly format?: "email" | "url" | "phone" | "password" | "month" | "iban";
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" | "month";
39
+ readonly format?: "email" | "url" | "phone" | "password" | "month" | "iban";
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" | "month";
62
+ readonly format?: "email" | "url" | "phone" | "password" | "month" | "iban";
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" | "month";
97
+ readonly format?: "email" | "url" | "phone" | "password" | "month" | "iban";
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" | "month";
120
+ readonly format?: "email" | "url" | "phone" | "password" | "month" | "iban";
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" | "month";
143
+ readonly format?: "email" | "url" | "phone" | "password" | "month" | "iban";
144
144
  readonly default?: string;
145
145
  readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
146
146
  readonly multiline?: boolean | {
@@ -412,7 +412,6 @@ export function requiredKeysFromScreen(featureName, screen, options = {}) {
412
412
  pushKey(out, section.title);
413
413
  pushKey(out, section.description);
414
414
  pushKey(out, section.submitLabel);
415
- // kumiko-lint-ignore section-fields-raw writeForm sections carry no groups (EditWriteFormSection)
416
415
  for (const f of section.fields) {
417
416
  pushEditFieldTextKeys(out, f);
418
417
  const fieldName = editFieldName(f);
@@ -70,6 +70,7 @@ export type JobRunnerOptions = {
70
70
  onJobStart?: (jobName: string, jobId: string, meta: JobMeta) => void;
71
71
  onJobComplete?: (jobName: string, jobId: string, duration: number, logs: JobLogEntry[], outcome?: JobOutcomeMeta) => void;
72
72
  onJobFailed?: (jobName: string, jobId: string, error: string, logs: JobLogEntry[], outcome?: JobOutcomeMeta) => void;
73
+ onJobDeferred?: (jobName: string, jobId: string, meta: JobMeta) => void;
73
74
  onJobQueued?: (jobName: string, jobId: string, meta: JobQueuedMeta) => void;
74
75
  onJobDropped?: (jobName: string, jobId: string, meta: JobDroppedMeta) => void;
75
76
  };