@cosmicdrift/kumiko-bundled-features 0.367.0 → 0.368.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/audit/handlers/details.query.js +1 -1
- package/dist/audit/handlers/list.query.js +1 -1
- package/dist/audit/run-escape-hatch-retention.js +1 -1
- package/dist/auth-email-password/bootstrap.js +1 -1
- package/dist/auth-email-password/handlers/invite-accept-with-login.write.js +6 -3
- package/dist/auth-email-password/handlers/invite-accept.write.js +6 -3
- package/dist/auth-email-password/handlers/invite-info.query.js +1 -1
- package/dist/auth-email-password/handlers/invite-signup-complete.write.js +6 -3
- package/dist/auth-email-password/handlers/signup-confirm.write.js +1 -1
- package/dist/auth-email-password/seeding.js +2 -2
- package/dist/auth-foundation/feature.d.ts +4 -0
- package/dist/auth-foundation/feature.js +37 -33
- package/dist/auth-foundation/index.d.ts +1 -1
- package/dist/auth-foundation/index.js +1 -1
- package/dist/auth-mfa/db/queries.js +1 -2
- package/dist/auth-mfa/handlers/enable-confirm-preauth.write.js +1 -1
- package/dist/auth-mfa/handlers/enable-start-preauth.write.js +1 -1
- package/dist/auth-mfa/handlers/reencrypt.job.js +2 -3
- package/dist/auth-mfa/handlers/status.query.js +1 -1
- package/dist/auth-mfa/handlers/verify.write.js +1 -1
- package/dist/auth-mfa/mfa-code-verifier.js +1 -1
- package/dist/auth-mfa/mfa-status-checker.js +1 -1
- package/dist/auth-mfa-user-data/index.d.ts +4 -0
- package/dist/auth-mfa-user-data/index.js +13 -9
- package/dist/billing-foundation/billing-info-query.js +1 -1
- package/dist/billing-foundation/feature.d.ts +1 -0
- package/dist/billing-foundation/feature.js +5 -6
- package/dist/billing-foundation/handlers/create-portal-session.write.js +1 -1
- package/dist/billing-foundation/projection.js +1 -2
- package/dist/cap-counter/calendar-cap-usage-reservation.d.ts +7 -0
- package/dist/cap-counter/calendar-cap-usage-reservation.js +28 -2
- package/dist/cap-counter/cap-reservation.d.ts +16 -0
- package/dist/cap-counter/cap-reservation.js +144 -14
- package/dist/cap-counter/feature.d.ts +4 -0
- package/dist/cap-counter/feature.js +74 -68
- package/dist/cap-counter/handlers/increment-rolling.write.js +3 -4
- package/dist/cap-counter/index.d.ts +3 -2
- package/dist/cap-counter/index.js +3 -2
- package/dist/cap-counter/tables.js +10 -3
- package/dist/cap-overview/handlers/caps-usage.query.js +1 -2
- package/dist/cap-overview/handlers/tenant-caps-list.query.js +1 -2
- package/dist/cap-overview/handlers/tenant-options.query.js +1 -1
- package/dist/channel-in-app/handlers/inbox.query.js +1 -1
- package/dist/channel-in-app/handlers/mark-all-read.write.js +1 -1
- package/dist/channel-in-app/handlers/mark-read.write.js +1 -1
- package/dist/channel-in-app/handlers/unread-count.query.js +1 -1
- package/dist/channel-in-app/tables.js +1 -2
- package/dist/compliance-profiles/handlers/for-tenant.query.js +1 -1
- package/dist/compliance-profiles/handlers/needs-profile.query.js +1 -1
- package/dist/compliance-profiles/handlers/set-profile.write.js +1 -2
- package/dist/compliance-profiles/resolve-for-tenant.js +1 -1
- package/dist/compliance-profiles/seeding.js +3 -5
- package/dist/compliance-profiles-ops/index.d.ts +8 -0
- package/dist/compliance-profiles-ops/index.js +19 -15
- package/dist/config/db/queries/resolver.js +1 -1
- package/dist/config/handlers/reencrypt.job.js +2 -2
- package/dist/config/resolver.js +1 -1
- package/dist/config/write-helpers.js +1 -1
- package/dist/crypto-shredding/handlers/forget-subject.write.js +6 -3
- package/dist/custom-fields/db/queries/field-access.js +1 -1
- package/dist/custom-fields/db/queries/projection.js +1 -1
- package/dist/custom-fields/db/queries/quota.js +1 -1
- package/dist/custom-fields/db/queries/retention.js +1 -2
- package/dist/custom-fields/db/queries/user-data-rights.js +1 -1
- package/dist/custom-fields/feature.d.ts +20 -2
- package/dist/custom-fields/feature.js +9 -13
- package/dist/custom-fields/handlers/clear-custom-field.write.js +2 -2
- package/dist/custom-fields/handlers/delete-system-field.write.js +2 -2
- package/dist/custom-fields/handlers/delete-tenant-field.write.js +2 -2
- package/dist/custom-fields/handlers/set-custom-field.write.js +2 -2
- package/dist/custom-fields/wire-for-entity.js +4 -4
- package/dist/data-retention/resolve-for-tenant.js +1 -1
- package/dist/data-retention/run-retention-cleanup.js +17 -13
- package/dist/delivery/address-opt-out.js +1 -2
- package/dist/delivery/attempt-log-retention.js +1 -1
- package/dist/delivery/channel-context.js +1 -1
- package/dist/delivery/db/queries/address-opt-outs.js +1 -1
- package/dist/delivery/db/queries/preferences.js +1 -1
- package/dist/delivery/delivery-service.js +16 -7
- package/dist/delivery/feature.js +1 -1
- package/dist/delivery/handlers/log.query.js +2 -3
- package/dist/delivery/handlers/preferences.query.js +1 -1
- package/dist/delivery/upsert-preference.js +1 -2
- package/dist/derivatives-sharp/feature.d.ts +4 -0
- package/dist/derivatives-sharp/feature.js +15 -11
- package/dist/derivatives-sharp/index.d.ts +1 -1
- package/dist/derivatives-sharp/index.js +1 -1
- package/dist/document-ingest-foundation/feature.d.ts +7 -0
- package/dist/document-ingest-foundation/feature.js +94 -90
- package/dist/document-ingest-foundation/forget-extract-with-file-ref.js +3 -3
- package/dist/document-ingest-foundation/index.d.ts +1 -1
- package/dist/document-ingest-foundation/index.js +1 -1
- package/dist/feature-toggles/global-feature-state-table.js +1 -2
- package/dist/feature-toggles/handlers/set.write.js +3 -5
- package/dist/feature-toggles/toggle-runtime.js +1 -1
- package/dist/file-derivatives/feature.d.ts +1 -0
- package/dist/file-derivatives/feature.js +2 -1
- package/dist/file-derivatives/handlers/public-variant-by-file-ref.query.js +1 -1
- package/dist/file-derivatives/handlers/public-variant.query.js +1 -1
- package/dist/file-foundation/feature.d.ts +6 -0
- package/dist/file-foundation/feature.js +29 -25
- package/dist/file-foundation/index.d.ts +1 -1
- package/dist/file-foundation/index.js +1 -1
- package/dist/file-foundation/read-file-ref-content.js +1 -1
- package/dist/file-provider-inmemory/feature.d.ts +4 -0
- package/dist/file-provider-inmemory/feature.js +24 -20
- package/dist/file-provider-inmemory/index.d.ts +1 -1
- package/dist/file-provider-inmemory/index.js +1 -1
- package/dist/file-provider-s3/env-feature.d.ts +3 -0
- package/dist/file-provider-s3/env-feature.js +46 -0
- package/dist/file-provider-s3/feature.d.ts +26 -0
- package/dist/file-provider-s3/feature.js +84 -72
- package/dist/file-provider-s3/index.d.ts +1 -1
- package/dist/file-provider-s3/index.js +1 -1
- package/dist/file-provider-s3/lib/index.d.ts +3 -0
- package/dist/file-provider-s3/lib/index.js +2 -0
- package/dist/{files-provider-s3 → file-provider-s3/lib}/s3-provider.js +19 -19
- package/dist/file-provider-s3-env/index.d.ts +8 -1
- package/dist/file-provider-s3-env/index.js +7 -2
- package/dist/files-provider-s3/index.d.ts +5 -3
- package/dist/files-provider-s3/index.js +5 -2
- package/dist/files-tenant-data/handlers/sweep-orphaned-derivatives.job.js +1 -1
- package/dist/files-tenant-data/hooks.js +1 -2
- package/dist/folders/feature.d.ts +6 -2
- package/dist/folders/feature.js +4 -2
- package/dist/folders-user-data/index.d.ts +4 -0
- package/dist/folders-user-data/index.js +21 -17
- package/dist/form-draft/db/queries/cleanup.js +1 -1
- package/dist/form-draft/db/queries/draft-count.js +1 -1
- package/dist/form-draft/db/queries/owned-file-refs.js +1 -2
- package/dist/form-draft/feature.d.ts +4 -0
- package/dist/form-draft/feature.js +5 -1
- package/dist/form-draft/handlers/cleanup.job.js +2 -2
- package/dist/form-draft/index.d.ts +1 -1
- package/dist/form-draft/index.js +1 -1
- package/dist/form-draft/lookup.js +1 -1
- package/dist/form-draft-user-data/index.d.ts +4 -0
- package/dist/form-draft-user-data/index.js +13 -9
- package/dist/inbound-mail-foundation/feature.d.ts +4 -0
- package/dist/inbound-mail-foundation/feature.js +151 -147
- package/dist/inbound-mail-foundation/handlers/ingest-message.write.js +1 -2
- package/dist/inbound-mail-foundation/index.d.ts +1 -1
- package/dist/inbound-mail-foundation/index.js +1 -1
- package/dist/inbound-mail-foundation/oauth-access-token.js +1 -2
- package/dist/inbound-mail-foundation/projection.js +1 -2
- package/dist/inbound-mail-foundation/watch-supervisor.js +1 -1
- package/dist/inbound-provider-imap/feature.d.ts +4 -0
- package/dist/inbound-provider-imap/feature.js +16 -12
- package/dist/inbound-provider-imap/index.d.ts +1 -1
- package/dist/inbound-provider-imap/index.js +1 -1
- package/dist/inbound-provider-inmemory/feature.d.ts +4 -0
- package/dist/inbound-provider-inmemory/feature.js +14 -10
- package/dist/inbound-provider-inmemory/index.d.ts +1 -1
- package/dist/inbound-provider-inmemory/index.js +1 -1
- package/dist/jobs/db/queries/retention.js +1 -1
- package/dist/jobs/db/queries/stale-run-sweep.js +1 -1
- package/dist/jobs/handlers/detail.query.js +1 -1
- package/dist/jobs/handlers/list.query.js +1 -2
- package/dist/jobs/handlers/retry.write.js +1 -1
- package/dist/jobs/handlers/tenant-failures.query.js +1 -1
- package/dist/jobs/handlers/tenant-runs.query.js +1 -1
- package/dist/jobs/job-run-logger.js +1 -2
- package/dist/jobs/tenant-job-failure-table.js +1 -2
- package/dist/jobs/tenant-job-run-table.js +1 -2
- package/dist/ledger/feature.d.ts +6 -2
- package/dist/ledger/feature.js +4 -2
- package/dist/mail-foundation/feature.d.ts +7 -0
- package/dist/mail-foundation/feature.js +48 -42
- package/dist/mail-foundation/index.d.ts +1 -1
- package/dist/mail-foundation/index.js +1 -1
- package/dist/mail-transport-inmemory/feature.d.ts +4 -0
- package/dist/mail-transport-inmemory/feature.js +20 -16
- package/dist/mail-transport-inmemory/index.d.ts +1 -1
- package/dist/mail-transport-inmemory/index.js +1 -1
- package/dist/mail-transport-smtp/feature.d.ts +16 -0
- package/dist/mail-transport-smtp/feature.js +85 -79
- package/dist/mail-transport-smtp/index.d.ts +1 -1
- package/dist/mail-transport-smtp/index.js +1 -1
- package/dist/managed-pages/handlers/by-slug.query.js +1 -1
- package/dist/managed-pages/handlers/by-tenant-published.query.js +1 -2
- package/dist/managed-pages/handlers/set.write.js +1 -2
- package/dist/managed-pages/seeding.js +3 -5
- package/dist/metrics/compute.d.ts +1 -1
- package/dist/metrics/filters.d.ts +1 -1
- package/dist/metrics/filters.js +1 -1
- package/dist/metrics/validate.js +1 -1
- package/dist/notes-history/feature.d.ts +7 -2
- package/dist/notes-history/feature.js +4 -2
- package/dist/notes-history/handlers/add-note.write.js +1 -1
- package/dist/notes-history-user-data/hooks.js +1 -1
- package/dist/notes-history-user-data/index.d.ts +4 -0
- package/dist/notes-history-user-data/index.js +21 -17
- package/dist/personal-access-tokens/feature.d.ts +4 -1
- package/dist/personal-access-tokens/feature.js +10 -2
- package/dist/personal-access-tokens/handlers/create.write.js +1 -1
- package/dist/personal-access-tokens/handlers/list.query.js +2 -2
- package/dist/personal-access-tokens/handlers/revoke.write.js +1 -1
- package/dist/personal-access-tokens/resolver.js +1 -1
- package/dist/personal-access-tokens/revoke-for-user.js +1 -1
- package/dist/personal-access-tokens/roles.js +3 -5
- package/dist/personal-access-tokens/screens.js +2 -0
- package/dist/readiness/feature.d.ts +8 -0
- package/dist/readiness/feature.js +18 -14
- package/dist/readiness/index.d.ts +1 -1
- package/dist/readiness/index.js +1 -1
- package/dist/secrets/db/queries/read.js +1 -1
- package/dist/secrets/feature.d.ts +3 -0
- package/dist/secrets/feature.js +3 -2
- package/dist/secrets/handlers/rotate.job.js +2 -3
- package/dist/secrets/secrets-context.js +3 -4
- package/dist/sessions/db/queries/cleanup.js +1 -1
- package/dist/sessions/handlers/detail.query.js +1 -1
- package/dist/sessions/handlers/list.query.js +2 -2
- package/dist/sessions/handlers/mine.query.js +1 -1
- package/dist/sessions/handlers/revoke-all-for-user.write.js +1 -1
- package/dist/sessions/handlers/revoke-all-others.write.js +1 -1
- package/dist/sessions/handlers/revoke.write.js +1 -1
- package/dist/sessions/session-callbacks.js +4 -6
- package/dist/sessions/testing.d.ts +1 -1
- package/dist/tags/feature.d.ts +6 -2
- package/dist/tags/feature.js +4 -2
- package/dist/template-resolver/api.js +1 -1
- package/dist/template-resolver/handlers/bundle-import.js +1 -1
- package/dist/template-resolver/handlers/by-slug.query.js +1 -1
- package/dist/template-resolver/handlers/by-tenant.query.js +1 -2
- package/dist/template-resolver/handlers/collection-item.query.js +1 -1
- package/dist/template-resolver/handlers/collection-list.query.js +1 -2
- package/dist/template-resolver/handlers/collection-set.write.js +1 -1
- package/dist/template-resolver/handlers/copy-locale.write.js +1 -1
- package/dist/template-resolver/handlers/diff-to-system.query.js +1 -1
- package/dist/template-resolver/handlers/export-bundle.query.js +1 -1
- package/dist/template-resolver/handlers/find-by-id.query.js +1 -1
- package/dist/template-resolver/handlers/layout-source.query.js +1 -1
- package/dist/template-resolver/handlers/list.query.js +1 -1
- package/dist/template-resolver/handlers/overview.query.js +1 -1
- package/dist/template-resolver/handlers/reset-to-system.write.js +1 -1
- package/dist/template-resolver/handlers/resource-remove.write.js +1 -1
- package/dist/template-resolver/handlers/set.write.js +1 -1
- package/dist/template-resolver/handlers/template-write.js +1 -1
- package/dist/template-resolver/handlers/tenant-overrides.query.js +1 -1
- package/dist/template-resolver/handlers/toggle-status.write.js +1 -1
- package/dist/template-resolver/handlers/usage.query.js +1 -1
- package/dist/template-resolver/handlers/validate.query.js +1 -1
- package/dist/template-resolver/seeding.js +3 -4
- package/dist/template-resolver/store-template-resource.js +1 -1
- package/dist/template-resolver/template-preview.js +1 -1
- package/dist/template-resolver/template-resources.js +1 -1
- package/dist/template-resolver/testing.js +1 -1
- package/dist/template-resolver-user-data/index.d.ts +4 -0
- package/dist/template-resolver-user-data/index.js +17 -13
- package/dist/tenant/handlers/active-tenant-ids.query.js +1 -1
- package/dist/tenant/handlers/add-member.write.js +1 -2
- package/dist/tenant/handlers/cancel-invitation.write.js +1 -1
- package/dist/tenant/handlers/invitations.query.js +1 -1
- package/dist/tenant/handlers/me.query.js +1 -1
- package/dist/tenant/handlers/member-directory.query.js +1 -1
- package/dist/tenant/handlers/members.query.js +1 -1
- package/dist/tenant/handlers/memberships.query.js +1 -1
- package/dist/tenant/handlers/remove-member.write.js +1 -2
- package/dist/tenant/handlers/resolve-user-ids.query.js +1 -1
- package/dist/tenant/handlers/team-list.query.js +1 -1
- package/dist/tenant/handlers/tenant-directory.query.js +1 -1
- package/dist/tenant/handlers/update-member-roles.write.js +1 -2
- package/dist/tenant/invited-membership.js +2 -3
- package/dist/tenant/last-tenant-admin.js +1 -2
- package/dist/tenant/seeding.js +12 -6
- package/dist/tenant-lifecycle/handlers/cancel-destruction.write.js +1 -2
- package/dist/tenant-lifecycle/handlers/request-destruction.write.js +1 -2
- package/dist/tenant-lifecycle/lib/revoke-tenant-sessions.js +1 -1
- package/dist/tenant-lifecycle/lifecycle-gate.js +1 -1
- package/dist/tenant-lifecycle/run-tenant-destroy.js +3 -5
- package/dist/tenant-lifecycle/stages.js +10 -6
- package/dist/tenant-lifecycle/testing.d.ts +1 -1
- package/dist/tenant-lifecycle/testing.js +2 -2
- package/dist/tenant-settings/feature.d.ts +1 -0
- package/dist/tenant-settings/feature.js +2 -1
- package/dist/tier-engine/feature.d.ts +1 -8
- package/dist/tier-engine/feature.js +71 -78
- package/dist/tier-engine/handlers/get-tenant-tier.query.js +2 -3
- package/dist/tier-engine/handlers/set-tenant-tier.write.js +1 -2
- package/dist/user/db/queries/stream-tenant-backfill.js +1 -1
- package/dist/user/handlers/create.write.js +1 -2
- package/dist/user/handlers/find-for-auth.query.js +1 -1
- package/dist/user/handlers/list.query.js +1 -1
- package/dist/user/handlers/update-roles.js +1 -2
- package/dist/user/index.d.ts +1 -1
- package/dist/user/index.js +1 -1
- package/dist/user/invited-global-roles.js +2 -3
- package/dist/user/principal-status.d.ts +4 -0
- package/dist/user/principal-status.js +9 -3
- package/dist/user/resolve-display-names.js +1 -1
- package/dist/user/seeding.js +5 -6
- package/dist/user-data-rights/audit-download.js +2 -2
- package/dist/user-data-rights/db/queries/export-jobs.js +1 -1
- package/dist/user-data-rights/db/queries/forget-cleanup.js +1 -1
- package/dist/user-data-rights/handlers/download-by-job.query.js +1 -1
- package/dist/user-data-rights/handlers/download-by-token.query.js +1 -1
- package/dist/user-data-rights/handlers/export-status.query.js +1 -1
- package/dist/user-data-rights/handlers/list-download-attempts.query.js +1 -1
- package/dist/user-data-rights/handlers/my-audit-log.query.js +1 -1
- package/dist/user-data-rights/handlers/request-export.write.js +1 -2
- package/dist/user-data-rights/handlers/run-forget-cleanup.write.js +3 -3
- package/dist/user-data-rights/lib/deny-if-target-outside-admin-tenant.d.ts +1 -1
- package/dist/user-data-rights/lib/deny-if-target-outside-admin-tenant.js +1 -1
- package/dist/user-data-rights/lib/update-user-lifecycle.d.ts +1 -0
- package/dist/user-data-rights/lib/update-user-lifecycle.js +3 -3
- package/dist/user-data-rights/run-export-jobs.js +2 -3
- package/dist/user-data-rights/run-forget-cleanup.js +9 -5
- package/dist/user-data-rights/run-user-export.js +9 -5
- package/dist/waitlist/handlers/invite.write.js +1 -2
- package/dist/waitlist/handlers/reject.write.js +1 -1
- package/dist/waitlist/lib.js +1 -2
- package/dist/workflow-runner/event-subscriber.js +1 -1
- package/dist/workflow-runner/feature.d.ts +4 -0
- package/dist/workflow-runner/feature.js +44 -40
- package/dist/workflow-runner/handlers/resume-run.write.js +1 -1
- package/dist/workflow-runner/index.d.ts +1 -1
- package/dist/workflow-runner/index.js +1 -1
- package/dist/workflow-runner/pending-projection.js +1 -1
- package/package.json +28 -11
- package/src/cap-counter/changes.json +13 -0
- package/src/crypto-shredding/changes.json +6 -0
- package/src/file-provider-s3/changes.json +10 -1
- package/src/personal-access-tokens/changes.json +6 -0
- package/src/user/changes.json +6 -0
- package/dist/file-provider-s3-env/feature.d.ts +0 -3
- package/dist/file-provider-s3-env/feature.js +0 -46
- /package/dist/{files-provider-s3 → file-provider-s3/lib}/env-helper.d.ts +0 -0
- /package/dist/{files-provider-s3 → file-provider-s3/lib}/env-helper.js +0 -0
- /package/dist/{files-provider-s3 → file-provider-s3/lib}/s3-provider.d.ts +0 -0
|
@@ -11,18 +11,22 @@
|
|
|
11
11
|
// per-tenant picker (the vast majority) stay unaffected.
|
|
12
12
|
import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
|
|
13
13
|
import { tenantsMissingProfileQuery } from "./handlers/tenants-missing-profile.query.js";
|
|
14
|
-
export
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
14
|
+
export function createComplianceProfilesOpsFeature() {
|
|
15
|
+
return defineFeature("compliance-profiles-ops", (r) => {
|
|
16
|
+
r.describe("Platform-wide SystemAdmin counterpart to `compliance-profiles`' `needs-profile` query (#2089): `tenants-missing-profile` lists every enabled tenant with no row in `tenantComplianceProfile` at all, tenant-wide instead of scoped to the caller's own tenant. Mount alongside `compliance-profiles` and `tenant` when an operator UI needs to see which tenants still silently run on `minimal-no-region`.");
|
|
17
|
+
r.uiHints({
|
|
18
|
+
displayLabel: "Compliance Profiles · Operator Visibility",
|
|
19
|
+
category: "compliance",
|
|
20
|
+
recommended: false,
|
|
21
|
+
});
|
|
22
|
+
r.systemScope();
|
|
23
|
+
r.requires({ features: ["compliance-profiles"] });
|
|
24
|
+
r.requires({ features: ["tenant"] });
|
|
25
|
+
const queries = {
|
|
26
|
+
tenantsMissingProfile: r.queryHandler(tenantsMissingProfileQuery),
|
|
27
|
+
};
|
|
28
|
+
return { queries };
|
|
29
|
+
}, { dedupeOptions: {} });
|
|
30
|
+
}
|
|
31
|
+
/** @deprecated Use createComplianceProfilesOpsFeature(). Run `bun kumiko-upgrade --apply`. Removed in the first release after 2026-10-29. */
|
|
32
|
+
export const complianceProfilesOpsFeature = createComplianceProfilesOpsFeature();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { selectMany } from "@cosmicdrift/kumiko-framework/
|
|
1
|
+
import { selectMany } from "@cosmicdrift/kumiko-framework/db";
|
|
2
2
|
import { configValuesTable } from "../../table.js";
|
|
3
3
|
// Method-form so a tenant-mode TenantDb stays filtered. Two parallel selects
|
|
4
4
|
// (disjoint via userId IS NULL) instead of one OR query: the buckets don't share
|
|
@@ -84,7 +84,7 @@ export const reencryptJob = async (rawPayload, ctx) => {
|
|
|
84
84
|
function tdbFor(tenantId) {
|
|
85
85
|
let existing = tdbCache.get(tenantId);
|
|
86
86
|
if (!existing) {
|
|
87
|
-
existing = createTenantDb(db, tenantId, "system");
|
|
87
|
+
existing = createTenantDb({ db, tenantId, mode: "system" });
|
|
88
88
|
tdbCache.set(tenantId, existing);
|
|
89
89
|
}
|
|
90
90
|
return existing;
|
|
@@ -102,7 +102,7 @@ export const reencryptJob = async (rawPayload, ctx) => {
|
|
|
102
102
|
// to acknowledge the cross-tenant scan below, never bound to a real
|
|
103
103
|
// tenant's writes — sharing it with sdbFor(SYSTEM_TENANT_ID) would make a
|
|
104
104
|
// write-path cache entry double as the scan's ack gate.
|
|
105
|
-
const scanDb = createSystemDbView(createTenantDb(db, SYSTEM_TENANT_ID, "system"), undefined, reportEscapeHatchFor(SYSTEM_TENANT_ID));
|
|
105
|
+
const scanDb = createSystemDbView(createTenantDb({ db, tenantId: SYSTEM_TENANT_ID, mode: "system" }), undefined, reportEscapeHatchFor(SYSTEM_TENANT_ID));
|
|
106
106
|
let alreadyCurrent = 0;
|
|
107
107
|
const targetVersion = provider.currentVersion();
|
|
108
108
|
// ponytail: one full candidate scan — config rows are operator-scale
|
package/dist/config/resolver.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { requestContext } from "@cosmicdrift/kumiko-framework/api";
|
|
2
|
-
import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
3
2
|
import { configuredPiiSubjectKms, decryptPiiValueForSubject, } from "@cosmicdrift/kumiko-framework/crypto";
|
|
3
|
+
import { fetchOne } from "@cosmicdrift/kumiko-framework/db";
|
|
4
4
|
import { SYSTEM_TENANT_ID } from "@cosmicdrift/kumiko-framework/engine";
|
|
5
5
|
import { InternalError } from "@cosmicdrift/kumiko-framework/errors";
|
|
6
6
|
import { assertUnreachable, parseJsonOrThrow } from "@cosmicdrift/kumiko-framework/utils";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Shared helpers for the config feature's write + query handlers.
|
|
2
2
|
// Extracted from set.write.ts so reset.write.ts + values.query.ts don't
|
|
3
3
|
// have to cross-import from another handler file.
|
|
4
|
-
import { fetchOne } from "@cosmicdrift/kumiko-framework/
|
|
4
|
+
import { fetchOne } from "@cosmicdrift/kumiko-framework/db";
|
|
5
5
|
import { ConfigScopes, extensionSelectorTargets, isEncryptedAtRest, SYSTEM_ROLE, SYSTEM_TENANT_ID, selectablePluginIds, } from "@cosmicdrift/kumiko-framework/engine";
|
|
6
6
|
import { AccessDeniedError, InternalError, NotFoundError, UnprocessableError, ValidationError, writeFailure, } from "@cosmicdrift/kumiko-framework/errors";
|
|
7
7
|
import { assertUnreachable } from "@cosmicdrift/kumiko-framework/utils";
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { requestContext } from "@cosmicdrift/kumiko-framework/api";
|
|
2
2
|
import { ROLES } from "@cosmicdrift/kumiko-framework/auth";
|
|
3
|
-
import { fetchOne, runInSavepointIfSupported, runnerCanBeginTransaction, transaction, } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
4
3
|
import { computeBlindIndex, configuredBlindIndexKey, configuredPiiSubjectKms, subjectIdSchema, subjectIdToKey, } from "@cosmicdrift/kumiko-framework/crypto";
|
|
5
|
-
import { nullBlindIndexesForSubject, recordEventsOwnedExclusivelyByTenant, recordRowExistsInTenant, recordRowOwningTenantId, subjectRowExistsInTenant, WritePurposes, } from "@cosmicdrift/kumiko-framework/db";
|
|
4
|
+
import { fetchOne, nullBlindIndexesForSubject, recordEventsOwnedExclusivelyByTenant, recordRowExistsInTenant, recordRowOwningTenantId, runInSavepointIfSupported, runnerCanBeginTransaction, subjectRowExistsInTenant, transaction, WritePurposes, } from "@cosmicdrift/kumiko-framework/db";
|
|
6
5
|
import { defineWriteHandler, } from "@cosmicdrift/kumiko-framework/engine";
|
|
7
6
|
import { AccessDeniedError, InternalError, writeFailure, } from "@cosmicdrift/kumiko-framework/errors";
|
|
8
7
|
import { appendDomainEventCore, assertIrreversibleOperationAllowed, } from "@cosmicdrift/kumiko-framework/pipeline";
|
|
@@ -254,7 +253,11 @@ async function closeUserLoginDoor(ctx, userId, outsideRunner, handlerTxRunner) {
|
|
|
254
253
|
if (!userRow)
|
|
255
254
|
return;
|
|
256
255
|
const closeDoor = async (runner) => {
|
|
257
|
-
await updateUserLifecycle(runner, userId, { status: USER_STATUS.Deleted },
|
|
256
|
+
await updateUserLifecycle(runner, userId, { status: USER_STATUS.Deleted },
|
|
257
|
+
// includeDeleted: a user whose stream is already deleted but whose status
|
|
258
|
+
// still reads active would otherwise fail with not_found (500) and keep
|
|
259
|
+
// sessions and PATs alive.
|
|
260
|
+
{ writePurpose: WritePurposes.erasure, includeDeleted: true });
|
|
258
261
|
if (ctx.registry.features.has("personal-access-tokens")) {
|
|
259
262
|
await revokeAllPatTokensForUser(runner, userId);
|
|
260
263
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { unsafeReadRetrying } from "@cosmicdrift/kumiko-framework/
|
|
1
|
+
import { unsafeReadRetrying } from "@cosmicdrift/kumiko-framework/db";
|
|
2
2
|
export async function selectSerializedFieldDefinition(runner, tenantId, entityName, fieldKey) {
|
|
3
3
|
const rows = await unsafeReadRetrying(runner, "SELECT serialized_field FROM read_custom_field_definitions WHERE entity_name = $1 AND field_key = $2 AND tenant_id = $3 LIMIT 1", [entityName, fieldKey, tenantId]);
|
|
4
4
|
const first = rows[0]; // @cast-boundary db-row
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { unsafeReadRetrying } from "@cosmicdrift/kumiko-framework/
|
|
1
|
+
import { unsafeReadRetrying } from "@cosmicdrift/kumiko-framework/db";
|
|
2
2
|
export async function countTenantFieldDefinitions(runner, tenantId) {
|
|
3
3
|
// Active definitions only — delete soft-deletes (the deterministic stream is
|
|
4
4
|
// kept so a re-define can restore it), so isDeleted rows must not consume quota.
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { asRawClient, unsafeReadRetrying } from "@cosmicdrift/kumiko-framework/
|
|
2
|
-
import { toPostgresArrayLiteral } from "@cosmicdrift/kumiko-framework/db";
|
|
1
|
+
import { asRawClient, toPostgresArrayLiteral, unsafeReadRetrying, } from "@cosmicdrift/kumiko-framework/db";
|
|
3
2
|
export async function selectHostRowsWithCustomFields(db, tableName, tenantId) {
|
|
4
3
|
const quoted = `"${tableName.replace(/"/g, '""')}"`;
|
|
5
4
|
const rowsResult = await unsafeReadRetrying(db, `SELECT id, modified_at, custom_fields FROM ${quoted} WHERE tenant_id = $1 AND custom_fields IS NOT NULL`, [tenantId]);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
declare const defaultCustomFieldsFeature: import("@cosmicdrift/kumiko-types/feature").FeatureDefinition & {
|
|
2
2
|
readonly exports: {
|
|
3
3
|
setEvent: import("@cosmicdrift/kumiko-types/handlers").EventDef<{
|
|
4
4
|
fieldKey: string;
|
|
@@ -44,4 +44,22 @@ export type CustomFieldsFeatureOptions = {
|
|
|
44
44
|
readonly fieldDefinitionWriteRoles?: readonly string[];
|
|
45
45
|
};
|
|
46
46
|
export declare function resolveFieldDefinitionListRoles(opts: Pick<CustomFieldsFeatureOptions, "valueWriteRoles" | "fieldDefinitionListRoles" | "fieldDefinitionWriteRoles">): readonly string[];
|
|
47
|
-
export declare function createCustomFieldsFeature(opts?: CustomFieldsFeatureOptions): typeof
|
|
47
|
+
export declare function createCustomFieldsFeature(opts?: CustomFieldsFeatureOptions): typeof defaultCustomFieldsFeature;
|
|
48
|
+
/** @deprecated Use createCustomFieldsFeature(). Run `bun kumiko-upgrade --apply`. Removed in the first release after 2026-10-29. */
|
|
49
|
+
export declare const customFieldsFeature: import("@cosmicdrift/kumiko-types/feature").FeatureDefinition & {
|
|
50
|
+
readonly exports: {
|
|
51
|
+
setEvent: import("@cosmicdrift/kumiko-types/handlers").EventDef<{
|
|
52
|
+
fieldKey: string;
|
|
53
|
+
value?: unknown;
|
|
54
|
+
}, "custom-fields:event:custom-field-set">;
|
|
55
|
+
clearedEvent: import("@cosmicdrift/kumiko-types/handlers").EventDef<{
|
|
56
|
+
fieldKey: string;
|
|
57
|
+
}, "custom-fields:event:custom-field-cleared">;
|
|
58
|
+
fieldDefinitionDeletedEvent: import("@cosmicdrift/kumiko-types/handlers").EventDef<{
|
|
59
|
+
entityName: string;
|
|
60
|
+
fieldKey: string;
|
|
61
|
+
tenantId?: string | undefined;
|
|
62
|
+
}, "custom-fields:event:field-definition-deleted">;
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
export {};
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
// `customFieldsField()` (jsonb) deklarieren.
|
|
34
34
|
//
|
|
35
35
|
// **Exports-Pattern (2026-05-23 refactor)**:
|
|
36
|
-
// `
|
|
36
|
+
// `createCustomFieldsFeature().exports.{setEvent,clearedEvent,fieldDefinitionDeletedEvent}`
|
|
37
37
|
// liefern typed EventDef-handles. Handler + wire-for-entity nutzen
|
|
38
38
|
// `<event>.name` als compile-time-literal-typed qualified-string — keine
|
|
39
39
|
// hand-gebauten Template-Literals mehr (T1 hat den toKebab-collapse-drift
|
|
@@ -117,12 +117,9 @@ function registerCustomFields(r, variant) {
|
|
|
117
117
|
}));
|
|
118
118
|
return { setEvent, clearedEvent, fieldDefinitionDeletedEvent };
|
|
119
119
|
}
|
|
120
|
-
//
|
|
121
|
-
//
|
|
122
|
-
|
|
123
|
-
// (feature.ts -> handlers/*.write.ts -> feature.ts) löst sich auf weil
|
|
124
|
-
// kein top-level-access stattfindet.
|
|
125
|
-
export const customFieldsFeature = defineFeature(CUSTOM_FIELDS_FEATURE_NAME, (r) => registerCustomFields(r, {
|
|
120
|
+
// Handlers and wire-for-entity read `.exports.<event>.name` lazily inside their runtime
|
|
121
|
+
// arrow functions, which resolves the module cycle (feature.ts -> handlers/*.write.ts -> feature.ts).
|
|
122
|
+
const defaultCustomFieldsFeature = defineFeature(CUSTOM_FIELDS_FEATURE_NAME, (r) => registerCustomFields(r, {
|
|
126
123
|
defineTenantHandler: defineTenantFieldHandler,
|
|
127
124
|
updateTenantHandler: updateTenantFieldHandler,
|
|
128
125
|
deleteTenantHandler: deleteTenantFieldHandler,
|
|
@@ -146,18 +143,15 @@ export function resolveFieldDefinitionListRoles(opts) {
|
|
|
146
143
|
]),
|
|
147
144
|
];
|
|
148
145
|
}
|
|
149
|
-
//
|
|
150
|
-
//
|
|
151
|
-
// module-level-Singleton — kein neuer build pro Aufruf, was für consumer
|
|
152
|
-
// nicht erkennbar ist (read-only inspection). Jede gesetzte Option baut
|
|
153
|
-
// eine frische Feature-Definition mit den Varianten-Handlern.
|
|
146
|
+
// Without options this returns the module-level singleton (no rebuild per call); every
|
|
147
|
+
// option builds a fresh feature definition with the variant handlers.
|
|
154
148
|
export function createCustomFieldsFeature(opts = {}) {
|
|
155
149
|
const hasOptions = opts.fieldDefinitionLimitPerTenant !== undefined ||
|
|
156
150
|
opts.valueWriteRoles !== undefined ||
|
|
157
151
|
opts.fieldDefinitionListRoles !== undefined ||
|
|
158
152
|
opts.fieldDefinitionWriteRoles !== undefined;
|
|
159
153
|
if (!hasOptions) {
|
|
160
|
-
return
|
|
154
|
+
return defaultCustomFieldsFeature;
|
|
161
155
|
}
|
|
162
156
|
const limit = opts.fieldDefinitionLimitPerTenant;
|
|
163
157
|
const definitionWriteRoles = opts.fieldDefinitionWriteRoles;
|
|
@@ -179,3 +173,5 @@ export function createCustomFieldsFeature(opts = {}) {
|
|
|
179
173
|
fieldDefinitionListRoles: resolveFieldDefinitionListRoles(opts),
|
|
180
174
|
}));
|
|
181
175
|
}
|
|
176
|
+
/** @deprecated Use createCustomFieldsFeature(). Run `bun kumiko-upgrade --apply`. Removed in the first release after 2026-10-29. */
|
|
177
|
+
export const customFieldsFeature = createCustomFieldsFeature();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { failNotFound, failUnprocessable } from "@cosmicdrift/kumiko-framework/errors";
|
|
2
2
|
import * as z from "zod";
|
|
3
3
|
import { DEFAULT_VALUE_WRITE_ROLES } from "../constants.js";
|
|
4
|
-
import {
|
|
4
|
+
import { createCustomFieldsFeature } from "../feature.js";
|
|
5
5
|
import { checkFieldAccessForWrite } from "../lib/field-access.js";
|
|
6
6
|
export const clearCustomFieldPayloadSchema = z.object({
|
|
7
7
|
entityName: z.string().min(1).max(64),
|
|
@@ -47,7 +47,7 @@ export const clearCustomFieldHandler = {
|
|
|
47
47
|
await ctx.unsafeAppendEvent({
|
|
48
48
|
aggregateId: payload.entityId,
|
|
49
49
|
aggregateType: payload.entityName,
|
|
50
|
-
type:
|
|
50
|
+
type: createCustomFieldsFeature().exports.clearedEvent.name,
|
|
51
51
|
payload: { fieldKey: payload.fieldKey },
|
|
52
52
|
});
|
|
53
53
|
return {
|
|
@@ -3,7 +3,7 @@ import { requireForTenant } from "../../shared/index.js";
|
|
|
3
3
|
import { fieldDefinitionAggregateId } from "../aggregate-id.js";
|
|
4
4
|
import { FIELD_DEFINITION_AGGREGATE_TYPE } from "../constants.js";
|
|
5
5
|
import { fieldDefinitionExecutor } from "../executor.js";
|
|
6
|
-
import {
|
|
6
|
+
import { createCustomFieldsFeature } from "../feature.js";
|
|
7
7
|
import { deleteFieldPayloadSchema } from "../schemas.js";
|
|
8
8
|
// delete-system-field — SystemAdmin entfernt eine system-weite Field-
|
|
9
9
|
// Definition. Konsequenz: KEIN Tenant kann mehr neue Werte dafür setzen,
|
|
@@ -29,7 +29,7 @@ export const deleteSystemFieldHandler = {
|
|
|
29
29
|
await ctx.unsafeAppendEvent({
|
|
30
30
|
aggregateId,
|
|
31
31
|
aggregateType: FIELD_DEFINITION_AGGREGATE_TYPE,
|
|
32
|
-
type:
|
|
32
|
+
type: createCustomFieldsFeature().exports.fieldDefinitionDeletedEvent.name,
|
|
33
33
|
payload: {
|
|
34
34
|
entityName: payload.entityName,
|
|
35
35
|
fieldKey: payload.fieldKey,
|
|
@@ -2,7 +2,7 @@ import { isSystemTenant } from "@cosmicdrift/kumiko-framework/engine";
|
|
|
2
2
|
import { fieldDefinitionAggregateId } from "../aggregate-id.js";
|
|
3
3
|
import { DEFAULT_FIELD_DEFINITION_WRITE_ROLES, FIELD_DEFINITION_AGGREGATE_TYPE, } from "../constants.js";
|
|
4
4
|
import { fieldDefinitionExecutor } from "../executor.js";
|
|
5
|
-
import {
|
|
5
|
+
import { createCustomFieldsFeature } from "../feature.js";
|
|
6
6
|
import { deleteFieldPayloadSchema } from "../schemas.js";
|
|
7
7
|
export function createDeleteTenantFieldHandler(opts = {}) {
|
|
8
8
|
return {
|
|
@@ -26,7 +26,7 @@ export function createDeleteTenantFieldHandler(opts = {}) {
|
|
|
26
26
|
await ctx.unsafeAppendEvent({
|
|
27
27
|
aggregateId,
|
|
28
28
|
aggregateType: FIELD_DEFINITION_AGGREGATE_TYPE,
|
|
29
|
-
type:
|
|
29
|
+
type: createCustomFieldsFeature().exports.fieldDefinitionDeletedEvent.name,
|
|
30
30
|
payload: { entityName: payload.entityName, fieldKey: payload.fieldKey, tenantId },
|
|
31
31
|
});
|
|
32
32
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { failNotFound, failUnprocessable } from "@cosmicdrift/kumiko-framework/errors";
|
|
2
2
|
import * as z from "zod";
|
|
3
3
|
import { DEFAULT_VALUE_WRITE_ROLES } from "../constants.js";
|
|
4
|
-
import {
|
|
4
|
+
import { createCustomFieldsFeature } from "../feature.js";
|
|
5
5
|
import { fieldWriteAccessDeniedRoles, loadFieldDefinition } from "../lib/field-access.js";
|
|
6
6
|
import { buildCustomFieldValueSchema } from "../lib/value-schema.js";
|
|
7
7
|
export const setCustomFieldPayloadSchema = z.object({
|
|
@@ -87,7 +87,7 @@ export const setCustomFieldHandler = {
|
|
|
87
87
|
await ctx.unsafeAppendEvent({
|
|
88
88
|
aggregateId: payload.entityId,
|
|
89
89
|
aggregateType: payload.entityName,
|
|
90
|
-
type:
|
|
90
|
+
type: createCustomFieldsFeature().exports.setEvent.name,
|
|
91
91
|
payload: { fieldKey: payload.fieldKey, value: payload.value },
|
|
92
92
|
});
|
|
93
93
|
return {
|
|
@@ -2,7 +2,7 @@ import { extractTableName } from "@cosmicdrift/kumiko-framework/db";
|
|
|
2
2
|
import { createJsonbField, isSystemTenant, } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
3
|
import { CUSTOM_FIELDS_EXTENSION, FIELD_DEFINITION_AGGREGATE_TYPE } from "./constants.js";
|
|
4
4
|
import { clearCustomFieldKey, removeCustomFieldKeyForTenant, removeCustomFieldKeyFromAllTenants, setCustomFieldValue, } from "./db/queries/projection.js";
|
|
5
|
-
import {
|
|
5
|
+
import { createCustomFieldsFeature } from "./feature.js";
|
|
6
6
|
// Helper für entity-definitions — fügt eine `customFields jsonb`-Spalte
|
|
7
7
|
// hinzu. Consumer:
|
|
8
8
|
//
|
|
@@ -69,9 +69,9 @@ export function wireCustomFieldsFor(r, entityName, entityTable) {
|
|
|
69
69
|
// Qualified event-type-names — sourced from typed EventDef.name handles
|
|
70
70
|
// (compile-time literal-typed, no Template-Literal-Drift à la toKebab-
|
|
71
71
|
// collapse-bug die T1 aufgedeckt hat).
|
|
72
|
-
const setEventType =
|
|
73
|
-
const clearedEventType =
|
|
74
|
-
const fieldDefDeletedType =
|
|
72
|
+
const setEventType = createCustomFieldsFeature().exports.setEvent.name;
|
|
73
|
+
const clearedEventType = createCustomFieldsFeature().exports.clearedEvent.name;
|
|
74
|
+
const fieldDefDeletedType = createCustomFieldsFeature().exports.fieldDefinitionDeletedEvent.name;
|
|
75
75
|
// Geteilte apply-Bodies: die MSP liefert sie live (async cursor), die
|
|
76
76
|
// entity-projection-extension replayt sie in rebuildProjection — gleiche
|
|
77
77
|
// SQL-Helper, beide idempotent. 2-Param-Signatur ist die gemeinsame
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Single implementation of the three-layer policy resolution: the cleanup cron,
|
|
2
2
|
// the forget runner and the `policy-for` query all go through here, so a caller
|
|
3
3
|
// cannot skip a layer (e.g. the tenant preset) by accident.
|
|
4
|
-
import { fetchOne } from "@cosmicdrift/kumiko-framework/
|
|
4
|
+
import { fetchOne } from "@cosmicdrift/kumiko-framework/db";
|
|
5
5
|
import { isTenantDb } from "../shared/index.js";
|
|
6
6
|
import { parseRetentionOverrideOrNull } from "./_internal/parse-override.js";
|
|
7
7
|
import { resolveTenantRetentionPreset } from "./resolve-tenant-preset.js";
|
|
@@ -37,9 +37,8 @@
|
|
|
37
37
|
// taegliche Re-Lauf appended also null Events. Der WHERE matcht anonymisierte
|
|
38
38
|
// Rows weiter (reference bleibt alt), deshalb id-Cursor-Paging statt einer
|
|
39
39
|
// einzelnen Page — sonst verstopfen erledigte Rows das batchLimit-Fenster.
|
|
40
|
-
import {
|
|
41
|
-
import {
|
|
42
|
-
import { createEventStoreExecutor, createTenantDb, nullBlindIndexesForSubject, WritePurposes, } from "@cosmicdrift/kumiko-framework/db";
|
|
40
|
+
import { collectPiiSubjectFields, configuredPiiSubjectKms, isRecordKeyedField, isSelfPiiField, resolveSubjectForField, subjectIdToKey, } from "@cosmicdrift/kumiko-framework/crypto";
|
|
41
|
+
import { createEventStoreExecutor, createTenantDb, nullBlindIndexesForSubject, selectMany, WritePurposes, } from "@cosmicdrift/kumiko-framework/db";
|
|
43
42
|
import { deleteFileRefBytes } from "@cosmicdrift/kumiko-framework/derivatives";
|
|
44
43
|
import { createSystemUser, entityHasAnonymizableSubjectField, } from "@cosmicdrift/kumiko-framework/engine";
|
|
45
44
|
import { fileRefEntity, fileRefsTable, } from "@cosmicdrift/kumiko-framework/files";
|
|
@@ -81,24 +80,29 @@ async function purgeMatchingRows(db, table, where, batchLimit, op) {
|
|
|
81
80
|
// (purgeMatchingRows's hardDelete select) is enough; the with-files path's
|
|
82
81
|
// full row works the same way.
|
|
83
82
|
//
|
|
84
|
-
// userOwned/tenantOwned are explicitly excluded:
|
|
83
|
+
// userOwned/tenantOwned are explicitly excluded (except a whenAbsent: "self" field
|
|
84
|
+
// of an ownerless row, which resolves to this row's own record key): hardDelete only destroys
|
|
85
85
|
// THIS row's own data, but the owning user's/tenant's key may still protect
|
|
86
86
|
// OTHER live rows that reference the same subject — erasing it here would
|
|
87
87
|
// be a silent cross-row data-loss bug, not a retention fix.
|
|
88
|
+
function mayResolveToOwnRecordKey(field) {
|
|
89
|
+
if ("tenantOwned" in field && field.tenantOwned === true)
|
|
90
|
+
return false;
|
|
91
|
+
if ("userOwned" in field && field.userOwned !== undefined)
|
|
92
|
+
return isRecordKeyedField(field);
|
|
93
|
+
return ("recordOwned" in field && field.recordOwned === true) || isSelfPiiField(field);
|
|
94
|
+
}
|
|
88
95
|
function collectHardDeleteEraseSubjects(entity, entityName, tenantId, row) {
|
|
89
96
|
const subjectsByKey = new Map();
|
|
90
97
|
for (const fieldName of collectPiiSubjectFields(entity)) {
|
|
91
98
|
const field = entity.fields[fieldName];
|
|
92
|
-
if (!field)
|
|
99
|
+
if (!field || !mayResolveToOwnRecordKey(field))
|
|
93
100
|
continue;
|
|
94
|
-
const
|
|
101
|
+
const subject = resolveSubjectForField(entity, fieldName, row, { tenantId, entityName });
|
|
102
|
+
// whenAbsent: "self" resolves to the owner's key while the row has an owner — never erased here
|
|
95
103
|
const isUserOwned = "userOwned" in field && field.userOwned !== undefined;
|
|
96
|
-
|
|
97
|
-
if (isUserOwned || isTenantOwned)
|
|
98
|
-
continue; // never erase — see header comment
|
|
99
|
-
if (!isRecordOwned && !isSelfPiiField(field))
|
|
104
|
+
if (isUserOwned && subject?.kind !== "record")
|
|
100
105
|
continue;
|
|
101
|
-
const subject = resolveSubjectForField(entity, fieldName, row, { tenantId, entityName });
|
|
102
106
|
if (subject)
|
|
103
107
|
subjectsByKey.set(subjectIdToKey(subject), subject);
|
|
104
108
|
}
|
|
@@ -132,7 +136,7 @@ async function eraseHardDeletedRowKeys(args) {
|
|
|
132
136
|
// unconfined and leave the row gone with its key still live.
|
|
133
137
|
async function forgetRowAndEraseKeys(args) {
|
|
134
138
|
return runInSubTransaction(args.db, async (sp) => {
|
|
135
|
-
const tdb = createTenantDb(sp, args.tenantId, "system");
|
|
139
|
+
const tdb = createTenantDb({ db: sp, tenantId: args.tenantId, mode: "system" });
|
|
136
140
|
const result = await args.executor.forget({ id: args.row["id"] }, args.systemUser, tdb);
|
|
137
141
|
if (!result.isSuccess)
|
|
138
142
|
return { isSuccess: false };
|
|
@@ -445,7 +449,7 @@ export async function runRetentionCleanup(args) {
|
|
|
445
449
|
// the daily cron converges (hardDelete removes rows, softDelete's isDeleted
|
|
446
450
|
// filter shrinks the set). A single batched forget/delete event is a follow-up.
|
|
447
451
|
const systemUser = createSystemUser(tenantId);
|
|
448
|
-
const tdb = createTenantDb(db, tenantId, "system");
|
|
452
|
+
const tdb = createTenantDb({ db, tenantId, mode: "system" });
|
|
449
453
|
const fileHolders = collectSingleFileHolders(registry);
|
|
450
454
|
// Pre-load every override row for this tenant ONCE — N entities × M
|
|
451
455
|
// tenants would otherwise mean one fetchOne per entity per tenant, even
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
2
1
|
import { computeBlindIndex, configuredBlindIndexKey } from "@cosmicdrift/kumiko-framework/crypto";
|
|
3
|
-
import { createEventStoreExecutor } from "@cosmicdrift/kumiko-framework/db";
|
|
2
|
+
import { createEventStoreExecutor, fetchOne, } from "@cosmicdrift/kumiko-framework/db";
|
|
4
3
|
import { ConflictError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
|
|
5
4
|
import { generateDeterministicId } from "@cosmicdrift/kumiko-framework/utils";
|
|
6
5
|
import { DeliveryErrors } from "./public-names.js";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { deleteManyBatched } from "@cosmicdrift/kumiko-framework/
|
|
1
|
+
import { deleteManyBatched } from "@cosmicdrift/kumiko-framework/db";
|
|
2
2
|
import { pruneEvents } from "@cosmicdrift/kumiko-framework/pipeline";
|
|
3
3
|
import { deliveryAttemptsTable } from "./tables.js";
|
|
4
4
|
export const DEFAULT_ATTEMPT_LOG_RETENTION_DAYS = 90;
|
|
@@ -87,7 +87,7 @@ export function createEmailAttachmentReader(db, registry, tenantId, config, file
|
|
|
87
87
|
// and it never runs through a job).
|
|
88
88
|
export function buildChannelContext(db, registry, sseBroker, tenantId, secrets, tenantConfig, filesForTenant) {
|
|
89
89
|
return {
|
|
90
|
-
db: createTenantDb(db, tenantId),
|
|
90
|
+
db: createTenantDb({ db, tenantId }),
|
|
91
91
|
registry,
|
|
92
92
|
sseBroker,
|
|
93
93
|
tenantId,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { selectMany } from "@cosmicdrift/kumiko-framework/
|
|
1
|
+
import { selectMany } from "@cosmicdrift/kumiko-framework/db";
|
|
2
2
|
import { notificationAddressOptOutsTable } from "../../tables.js";
|
|
3
3
|
export function addressOptOutKey(addressHash, channel) {
|
|
4
4
|
return `${addressHash}|${channel}`;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { unsafeReadRetrying } from "@cosmicdrift/kumiko-framework/
|
|
1
|
+
import { unsafeReadRetrying } from "@cosmicdrift/kumiko-framework/db";
|
|
2
2
|
// @wrapper-known semantic-alias
|
|
3
3
|
export async function selectNotificationPreferences(db, tenantId, userId, notificationTypeNames, channelName) {
|
|
4
4
|
return unsafeReadRetrying(db, `SELECT notification_type AS "notificationType", channel, enabled
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { createSystemDbView, createTenantDb } from "@cosmicdrift/kumiko-framework/db";
|
|
2
|
-
import { assertNotificationVariables, createSystemUser, } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
|
+
import { assertNotificationVariables, bridgeStub, createSystemUser, } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
3
|
import { createFallbackLogger } from "@cosmicdrift/kumiko-framework/logging";
|
|
4
4
|
import { assertNotifyTargetsOwnTenant, createEscapeHatchReporter, } from "@cosmicdrift/kumiko-framework/pipeline";
|
|
5
|
-
import { bridgeStub } from "@cosmicdrift/kumiko-framework/testing/handler-context";
|
|
6
5
|
import { generateId } from "@cosmicdrift/kumiko-framework/utils";
|
|
7
6
|
import { fileContextFromResolver } from "../file-foundation/index.js";
|
|
8
7
|
import { redactErrorText } from "../shared/index.js";
|
|
@@ -125,17 +124,27 @@ export function createDeliveryService(options) {
|
|
|
125
124
|
// path a cross-tenant read the dispatcher never allows. Cross-tenant reach only
|
|
126
125
|
// exists through the grant-carrying systemDb view below.
|
|
127
126
|
const isSystem = registry.isHandlerSystemScoped(tenantUserIdsQuery);
|
|
128
|
-
const tenantDb = createTenantDb(
|
|
129
|
-
|
|
127
|
+
const tenantDb = createTenantDb({
|
|
128
|
+
db: run.db,
|
|
129
|
+
tenantId,
|
|
130
|
+
mode: "tenant",
|
|
131
|
+
grants: {
|
|
132
|
+
report,
|
|
133
|
+
},
|
|
130
134
|
});
|
|
131
135
|
// The dispatcher grants a systemScope handler's ctx.systemDb.unsafeRaw() ungated —
|
|
132
136
|
// the grant comes from the handler's own r.systemScope() registration, not from this
|
|
133
137
|
// caller. Only the systemDb view's own source TenantDb carries the grant, so it
|
|
134
138
|
// can't leak onto ctx.db.
|
|
135
139
|
const systemDbSourceTenantDb = isSystem
|
|
136
|
-
? createTenantDb(
|
|
137
|
-
|
|
138
|
-
|
|
140
|
+
? createTenantDb({
|
|
141
|
+
db: run.db,
|
|
142
|
+
tenantId,
|
|
143
|
+
mode: "system",
|
|
144
|
+
grants: {
|
|
145
|
+
report,
|
|
146
|
+
unsafeRaw: { reason: `r.systemScope() handler "${tenantUserIdsQuery}"` },
|
|
147
|
+
},
|
|
139
148
|
})
|
|
140
149
|
: undefined;
|
|
141
150
|
// Hand-built context, not routed through the dispatcher — this needs both
|
package/dist/delivery/feature.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { updateMany, upsertByPk } from "@cosmicdrift/kumiko-framework/
|
|
1
|
+
import { updateMany, upsertByPk } from "@cosmicdrift/kumiko-framework/db";
|
|
2
2
|
import { access, defineFeature, i18nKey, } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
3
|
import { ConsumerLagError } from "@cosmicdrift/kumiko-framework/pipeline";
|
|
4
4
|
import { resolveAttemptLogRetentionDays, runAttemptLogRetention } from "./attempt-log-retention.js";
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { selectMany } from "@cosmicdrift/kumiko-framework/
|
|
2
|
-
import { decodeKeysetCursor, encodeKeysetCursor, } from "@cosmicdrift/kumiko-framework/db";
|
|
1
|
+
import { decodeKeysetCursor, encodeKeysetCursor, selectMany, } from "@cosmicdrift/kumiko-framework/db";
|
|
3
2
|
import { access, definePagedQueryHandler, isDeliveryErrorCode, isUuid, MAX_LIST_LIMIT, SYSTEM_USER_ID, } from "@cosmicdrift/kumiko-framework/engine";
|
|
4
3
|
import { InternalError } from "@cosmicdrift/kumiko-framework/errors";
|
|
5
4
|
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
@@ -30,7 +29,7 @@ function isDeliveryLogSortField(value) {
|
|
|
30
29
|
return value in DELIVERY_LOG_SORT_COLUMNS;
|
|
31
30
|
}
|
|
32
31
|
// createdAt round-trips through Temporal.Instant (matches how the WHERE
|
|
33
|
-
// builder coerces timestamptz values — see
|
|
32
|
+
// builder coerces timestamptz values — see db/query.ts prepareValue);
|
|
34
33
|
// every other whitelisted column is a plain text column. Keyed by the
|
|
35
34
|
// PHYSICAL column, not the display alias — row only has the DB field names
|
|
36
35
|
// (e.g. notificationType), never the alias (e.g. "type").
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { selectMany } from "@cosmicdrift/kumiko-framework/
|
|
1
|
+
import { selectMany } from "@cosmicdrift/kumiko-framework/db";
|
|
2
2
|
import { defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
3
|
import { InternalError } from "@cosmicdrift/kumiko-framework/errors";
|
|
4
4
|
import * as z from "zod";
|
|
@@ -12,8 +12,7 @@
|
|
|
12
12
|
// loser's create() comes back as a `version_conflict` failure; re-lookup and
|
|
13
13
|
// fall through to update, or no-op if the winner already set the target
|
|
14
14
|
// `enabled` state.
|
|
15
|
-
import { fetchOne } from "@cosmicdrift/kumiko-framework/
|
|
16
|
-
import { createEventStoreExecutor } from "@cosmicdrift/kumiko-framework/db";
|
|
15
|
+
import { createEventStoreExecutor, fetchOne, } from "@cosmicdrift/kumiko-framework/db";
|
|
17
16
|
import { generateDeterministicId } from "@cosmicdrift/kumiko-framework/utils";
|
|
18
17
|
import { notificationPreferenceEntity, notificationPreferencesTable } from "./tables.js";
|
|
19
18
|
const executor = createEventStoreExecutor(notificationPreferencesTable, notificationPreferenceEntity, { entityName: "notification-preference" });
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
export declare function createDerivativesSharpFeature(): import("@cosmicdrift/kumiko-types/feature").FeatureDefinition & {
|
|
2
|
+
readonly exports: void;
|
|
3
|
+
};
|
|
4
|
+
/** @deprecated Use createDerivativesSharpFeature(). Run `bun kumiko-upgrade --apply`. Removed in the first release after 2026-10-29. */
|
|
1
5
|
export declare const derivativesSharpFeature: import("@cosmicdrift/kumiko-types/feature").FeatureDefinition & {
|
|
2
6
|
readonly exports: void;
|
|
3
7
|
};
|
|
@@ -2,14 +2,18 @@
|
|
|
2
2
|
import { defineFeature, EXT_DERIVATIVE_RENDERER } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
3
|
import { renderImage } from "./render.js";
|
|
4
4
|
const FEATURE_NAME = "derivatives-sharp";
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
5
|
+
export function createDerivativesSharpFeature() {
|
|
6
|
+
return defineFeature(FEATURE_NAME, (r) => {
|
|
7
|
+
r.describe("Registers an `image/*` renderer against the `derivativeRenderer` extension point declared by `file-derivatives`, backed by sharp. Supports resize/fit (cover, inside, contain), format conversion with quality (webp, avif, jpeg), whole-image blur, and blurring individual regions burned in before resize (see BlurRegion). EXIF orientation is applied and then normalized away, and all other EXIF (including GPS) is dropped. Server-only: sharp is a native binding — never import this from client code.");
|
|
8
|
+
r.uiHints({
|
|
9
|
+
displayLabel: "File Derivatives · Sharp",
|
|
10
|
+
category: "storage",
|
|
11
|
+
recommended: false,
|
|
12
|
+
});
|
|
13
|
+
r.requires({ features: ["file-derivatives"] });
|
|
14
|
+
const plugin = { render: renderImage };
|
|
15
|
+
r.useExtension(EXT_DERIVATIVE_RENDERER, "image/*", plugin);
|
|
16
|
+
}, { dedupeOptions: {} });
|
|
17
|
+
}
|
|
18
|
+
/** @deprecated Use createDerivativesSharpFeature(). Run `bun kumiko-upgrade --apply`. Removed in the first release after 2026-10-29. */
|
|
19
|
+
export const derivativesSharpFeature = createDerivativesSharpFeature();
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { derivativesSharpFeature } from "./feature.js";
|
|
1
|
+
export { createDerivativesSharpFeature, derivativesSharpFeature } from "./feature.js";
|
|
2
2
|
export { imageMetadata } from "./render.js";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { derivativesSharpFeature } from "./feature.js";
|
|
1
|
+
export { createDerivativesSharpFeature, derivativesSharpFeature } from "./feature.js";
|
|
2
2
|
export { imageMetadata } from "./render.js";
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
export declare function createDocumentIngestFoundationFeature(): import("@cosmicdrift/kumiko-types/feature").FeatureDefinition & {
|
|
2
|
+
readonly exports: {
|
|
3
|
+
ocrLanguageConfigKey: import("@cosmicdrift/kumiko-types/config").ConfigKeyHandle<"text">;
|
|
4
|
+
maxPagesPerFileConfigKey: import("@cosmicdrift/kumiko-types/config").ConfigKeyHandle<"number">;
|
|
5
|
+
};
|
|
6
|
+
};
|
|
7
|
+
/** @deprecated Use createDocumentIngestFoundationFeature(). Run `bun kumiko-upgrade --apply`. Removed in the first release after 2026-10-29. */
|
|
1
8
|
export declare const documentIngestFoundationFeature: import("@cosmicdrift/kumiko-types/feature").FeatureDefinition & {
|
|
2
9
|
readonly exports: {
|
|
3
10
|
ocrLanguageConfigKey: import("@cosmicdrift/kumiko-types/config").ConfigKeyHandle<"text">;
|