@cosmicdrift/kumiko-framework 0.304.0 → 0.306.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 (92) hide show
  1. package/package.json +4 -4
  2. package/src/api/__tests__/extra-route-rejection.test.ts +38 -0
  3. package/src/api/__tests__/extra-routes.integration.test.ts +30 -0
  4. package/src/api/__tests__/server-boot-guards.test.ts +1 -0
  5. package/src/api/__tests__/server-error-logging.test.ts +104 -0
  6. package/src/api/api-constants.ts +13 -0
  7. package/src/api/extra-route.ts +33 -4
  8. package/src/api/index.ts +1 -0
  9. package/src/api/request-context.ts +5 -4
  10. package/src/api/routes.ts +26 -1
  11. package/src/api/server.ts +8 -2
  12. package/src/bun-db/__tests__/closed-connection-retry.integration.test.ts +159 -0
  13. package/src/bun-db/__tests__/select-many-retry.integration.test.ts +138 -0
  14. package/src/bun-db/query.ts +42 -18
  15. package/src/changes.json +108 -0
  16. package/src/db/__tests__/pg-error.test.ts +14 -0
  17. package/src/db/__tests__/system-db-view-export.test.ts +107 -0
  18. package/src/db/__tests__/tenant-db-no-raw.test.ts +10 -0
  19. package/src/db/__tests__/with-systemdb-unsafe-raw-grant.test.ts +71 -0
  20. package/src/db/event-store-executor-write.ts +7 -0
  21. package/src/db/index.ts +1 -1
  22. package/src/db/pg-error.ts +13 -0
  23. package/src/db/queries/__tests__/{unsafe-read-retrying.test.ts → unsafe-read-retrying.integration.test.ts} +28 -28
  24. package/src/db/tenant-db.ts +140 -16
  25. package/src/engine/__tests__/boot-validator-gdpr-storage.test.ts +6 -1
  26. package/src/engine/__tests__/boot-validator-s0-integration.test.ts +2 -2
  27. package/src/engine/__tests__/boot-validator.test.ts +1 -1
  28. package/src/engine/__tests__/tier-resolver-extension.test.ts +1 -1
  29. package/src/engine/boot-validator/access-declarations.ts +5 -66
  30. package/src/engine/extension-names.ts +55 -25
  31. package/src/engine/extensions/storage-provider.ts +14 -41
  32. package/src/engine/extensions/tenant-data.ts +4 -0
  33. package/src/engine/extensions/tenant-resource.ts +40 -0
  34. package/src/engine/extensions/user-data.ts +8 -7
  35. package/src/engine/feature-ast/__tests__/handler-header-roundtrip.test.ts +669 -0
  36. package/src/engine/feature-ast/__tests__/parse.test.ts +5 -3
  37. package/src/engine/feature-ast/__tests__/patch-update.test.ts +718 -0
  38. package/src/engine/feature-ast/__tests__/pattern-change-schema.test.ts +819 -0
  39. package/src/engine/feature-ast/entity-field-types.ts +41 -0
  40. package/src/engine/feature-ast/extractors/handlers.ts +217 -84
  41. package/src/engine/feature-ast/extractors/hooks.ts +72 -15
  42. package/src/engine/feature-ast/extractors/round2.ts +21 -0
  43. package/src/engine/feature-ast/extractors/shared.ts +9 -0
  44. package/src/engine/feature-ast/index.ts +11 -1
  45. package/src/engine/feature-ast/patch.ts +338 -5
  46. package/src/engine/feature-ast/patcher.ts +2 -2
  47. package/src/engine/feature-ast/pattern-change-schema.ts +1411 -0
  48. package/src/engine/feature-ast/patterns.ts +22 -15
  49. package/src/engine/feature-ast/render.ts +1 -0
  50. package/src/engine/feature-ui-extensions.ts +8 -7
  51. package/src/engine/index.ts +23 -5
  52. package/src/engine/personal-data-fields.ts +66 -0
  53. package/src/engine/registry-validate.ts +15 -0
  54. package/src/engine/registry.ts +2 -0
  55. package/src/engine/types/extension-options-map.ts +1 -0
  56. package/src/engine/types/index.ts +8 -0
  57. package/src/env/__tests__/dry-run.test.ts +43 -3
  58. package/src/env/dry-run.ts +28 -15
  59. package/src/errors/__tests__/write-failures.test.ts +47 -4
  60. package/src/errors/i18n/de.yaml +12 -0
  61. package/src/errors/i18n/en.yaml +12 -0
  62. package/src/errors/reasons.ts +4 -0
  63. package/src/errors/write-error-info.ts +12 -3
  64. package/src/jobs/__tests__/job-backoff.integration.test.ts +155 -0
  65. package/src/jobs/__tests__/job-retention.integration.test.ts +316 -0
  66. package/src/jobs/__tests__/job-retry-enqueue-paths.integration.test.ts +309 -0
  67. package/src/jobs/__tests__/jobs.integration.test.ts +38 -3
  68. package/src/jobs/job-runner.ts +170 -19
  69. package/src/pipeline/__tests__/ctx-bridge.integration.test.ts +113 -26
  70. package/src/pipeline/__tests__/dispatcher.test.ts +5 -0
  71. package/src/pipeline/__tests__/hook-systemdb-escape-hatch.integration.test.ts +246 -0
  72. package/src/pipeline/__tests__/idempotency-transient-failure.integration.test.ts +198 -0
  73. package/src/pipeline/__tests__/public-intake-runtime-gate.integration.test.ts +425 -0
  74. package/src/pipeline/__tests__/redis-pipeline.integration.test.ts +59 -0
  75. package/src/pipeline/active-membership.ts +5 -1
  76. package/src/pipeline/dispatch-batch.ts +59 -13
  77. package/src/pipeline/dispatch-query.ts +16 -5
  78. package/src/pipeline/dispatch-shared.ts +12 -5
  79. package/src/pipeline/dispatch-stream.ts +7 -2
  80. package/src/pipeline/dispatch-write.ts +22 -5
  81. package/src/pipeline/dispatcher.ts +9 -2
  82. package/src/pipeline/idempotency.ts +16 -0
  83. package/src/pipeline/member-reader.ts +3 -1
  84. package/src/pipeline/system-identity-switch.ts +22 -4
  85. package/src/pipeline/write-origin.ts +107 -0
  86. package/src/rate-limit/__tests__/middleware.integration.test.ts +40 -0
  87. package/src/rate-limit/middleware.ts +3 -0
  88. package/src/stack/__tests__/setup-test-stack-metrics.integration.test.ts +79 -0
  89. package/src/stack/test-stack.ts +5 -0
  90. package/src/testing/closed-connection-error.ts +62 -0
  91. package/src/testing/index.ts +1 -0
  92. package/src/bun-db/__tests__/select-many-retry.test.ts +0 -79
@@ -1,43 +1,16 @@
1
- // Hook signature types for EXT_STORAGE_PROVIDER (tenant-destroy binary cleanup).
2
- //
3
- // Mirror of tenant-data.ts, but the destroyTenant hook takes (tenantId, ctx)
4
- // rather than just (ctx) — runExtensionDestroyHooks (tenant-lifecycle/stages.ts)
5
- // passes tenantId as its own positional arg for every EXT_*_RESOURCE-style
6
- // extension point, not just this one. ctx here guarantees tenantId, db, plus
7
- // the optional fileProviderResolver/log; the richer stage-runner ctx
8
- // (tenant-lifecycle's DestructionStageCtx) is a structural superset, so a hook
9
- // typed against this minimal ctx is safely assignable wherever that richer ctx
10
- // is passed.
11
- //
12
- // `db` is a raw DbRunner, NOT a tenant-scoped TenantDb — unlike
13
- // TenantDataHookCtx.db (EXT_TENANT_DATA), runExtensionDestroyHooks hands every
14
- // EXT_*_RESOURCE-style hook (this one included) the stage runner's own
15
- // DestructionStageCtx.db straight through, with no tenant filter and no
16
- // escapeHatch/unsafeRaw gate — there is nothing to declare, because nothing
17
- // ever wraps it. That's deliberate for this stage family: wiping a whole
18
- // search index, an S3 prefix, or infra resources is inherently a cross-tenant,
19
- // bulk operation, not a row-scoped one. A hook that needs a plain read across
20
- // tenants (kumiko-framework#3035: does a foreign tenant's file_refs row still
1
+ // EXT_STORAGE_PROVIDER (tenant-destroy binary cleanup) is one of the four
2
+ // EXT_*_RESOURCE-style extension points — see tenant-resource.ts for the
3
+ // shared hook-signature contract. Kept as aliases so the existing public
4
+ // exports/imports stay valid; a hook that needs a plain cross-tenant read
5
+ // (kumiko-framework#3035: does a foreign tenant's file_refs row still
21
6
  // reference a key under THIS tenant's storage prefix) uses `db` directly via
22
- // executeRawQueryRead — there is no `ctx.systemDb` here (that belongs to
23
- // HandlerContext / r.systemScope() write-handler dispatch, a different code
24
- // path this stage runner never goes through).
25
- import type { FileProviderResolver } from "@cosmicdrift/kumiko-types/file-provider-resolver-types";
26
- import type { DbRunner } from "../../db/connection";
27
- import type { TenantId } from "../types";
7
+ // executeRawQueryRead — there is no `ctx.systemDb` here.
8
+ import type {
9
+ TenantResourceDestroyHook,
10
+ TenantResourceExtensionHooks,
11
+ TenantResourceHookCtx,
12
+ } from "./tenant-resource";
28
13
 
29
- export interface StorageProviderHookCtx {
30
- readonly tenantId: TenantId;
31
- readonly db: DbRunner;
32
- readonly fileProviderResolver?: FileProviderResolver;
33
- readonly log?: (message: string) => void;
34
- }
35
-
36
- export type StorageProviderDestroyTenantHook = (
37
- tenantId: TenantId,
38
- ctx: StorageProviderHookCtx,
39
- ) => Promise<void>;
40
-
41
- export interface StorageProviderExtensionHooks {
42
- readonly destroyTenant: StorageProviderDestroyTenantHook;
43
- }
14
+ export type StorageProviderHookCtx = TenantResourceHookCtx;
15
+ export type StorageProviderDestroyTenantHook = TenantResourceDestroyHook;
16
+ export type StorageProviderExtensionHooks = TenantResourceExtensionHooks;
@@ -28,3 +28,7 @@ export type TenantDataDestroyHook = (ctx: TenantDataHookCtx) => Promise<void>;
28
28
  export interface TenantDataExtensionHooks {
29
29
  readonly destroy: TenantDataDestroyHook;
30
30
  }
31
+
32
+ export function isTenantDataExtensionHooks(o: unknown): o is TenantDataExtensionHooks {
33
+ return typeof o === "object" && o !== null && "destroy" in o && typeof o.destroy === "function";
34
+ }
@@ -0,0 +1,40 @@
1
+ // Hook signature types shared by the four EXT_*_RESOURCE-style extension
2
+ // points (storageProvider, searchAdapter, externalResource, infraResource).
3
+ // runExtensionDestroyHooks (tenant-lifecycle/stages.ts) passes tenantId as
4
+ // its own positional arg for all of them, not just storageProvider — the
5
+ // stage runner's DestructionStageCtx is a structural superset of the ctx
6
+ // below, so a hook typed against it is safely assignable wherever the
7
+ // richer ctx is passed.
8
+ //
9
+ // `db` is a raw DbRunner, not a tenant-scoped TenantDb: wiping a whole
10
+ // search index, an S3 prefix, or infra resources is inherently a
11
+ // cross-tenant, bulk operation, not a row-scoped one — there is no
12
+ // escapeHatch/unsafeRaw gate here because nothing ever wraps `db`.
13
+ import type { FileProviderResolver } from "@cosmicdrift/kumiko-types/file-provider-resolver-types";
14
+ import type { DbRunner } from "../../db/connection";
15
+ import type { TenantId } from "../types";
16
+
17
+ export interface TenantResourceHookCtx {
18
+ readonly tenantId: TenantId;
19
+ readonly db: DbRunner;
20
+ readonly fileProviderResolver?: FileProviderResolver;
21
+ readonly log?: (message: string) => void;
22
+ }
23
+
24
+ export type TenantResourceDestroyHook = (
25
+ tenantId: TenantId,
26
+ ctx: TenantResourceHookCtx,
27
+ ) => Promise<void>;
28
+
29
+ export interface TenantResourceExtensionHooks {
30
+ readonly destroyTenant: TenantResourceDestroyHook;
31
+ }
32
+
33
+ export function isTenantResourceExtensionHooks(o: unknown): o is TenantResourceExtensionHooks {
34
+ return (
35
+ typeof o === "object" &&
36
+ o !== null &&
37
+ "destroyTenant" in o &&
38
+ typeof o.destroyTenant === "function"
39
+ );
40
+ }
@@ -166,15 +166,16 @@ export type UserDataDeleteHook = (
166
166
  ) => Promise<UserDataDeleteHookResult>;
167
167
 
168
168
  /**
169
- * Komplette Hook-Tafel für EXT_USER_DATA. Sprint 2 user-data-rights
170
- * deklariert das via `r.extendsRegistrar(EXT_USER_DATA, { hooks: ... })`,
171
- * konsumierende Features liefern beide Hooks via
172
- * `r.useExtension(EXT_USER_DATA, "<entity>", { export, delete })`.
173
- *
174
- * Kein Hook ist optional — beide MÜSSEN registriert sein. Boot-Check
175
- * (Sprint 2) prüft das.
169
+ * Full hook table for EXT_USER_DATA. Export-only is a legitimate partial
170
+ * contract, so registrations are typed by `UserDataExtensionOptions`.
176
171
  */
177
172
  export interface UserDataExtensionHooks {
178
173
  readonly export: UserDataExportHook;
179
174
  readonly delete: UserDataDeleteHook;
180
175
  }
176
+
177
+ // At least one hook is required: an empty bag would silently register neither export nor forget.
178
+ export type UserDataExtensionOptions = (
179
+ | { readonly export: UserDataExportHook; readonly delete?: UserDataDeleteHook }
180
+ | { readonly export?: UserDataExportHook; readonly delete: UserDataDeleteHook }
181
+ ) & { readonly order?: number };