@cosmicdrift/kumiko-bundled-features 0.14.0 → 0.16.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/package.json +2 -2
- package/src/__tests__/env-schemas.test.ts +1 -1
- package/src/__tests__/es-ops-e2e.integration.ts +10 -9
- package/src/audit/__tests__/audit.integration.ts +3 -3
- package/src/audit/handlers/list.query.ts +39 -51
- package/src/auth-email-password/__tests__/account-lockout-no-redis.integration.ts +4 -3
- package/src/auth-email-password/__tests__/account-lockout.integration.ts +4 -3
- package/src/auth-email-password/__tests__/auth-claims.integration.ts +5 -4
- package/src/auth-email-password/__tests__/auth.integration.ts +4 -3
- package/src/auth-email-password/__tests__/confirm-token-flow.test.ts +1 -1
- package/src/auth-email-password/__tests__/email-templates.test.ts +1 -1
- package/src/auth-email-password/__tests__/email-verification.integration.ts +7 -10
- package/src/auth-email-password/__tests__/identity-v3-hash.test.ts +1 -1
- package/src/auth-email-password/__tests__/identity-v3-login.integration.ts +4 -3
- package/src/auth-email-password/__tests__/invite-flow.integration.ts +16 -43
- package/src/auth-email-password/__tests__/multi-roles.integration.ts +6 -9
- package/src/auth-email-password/__tests__/password-reset.integration.ts +8 -7
- package/src/auth-email-password/__tests__/public-routes-rate-limit.integration.ts +4 -3
- package/src/auth-email-password/__tests__/seed-admin.integration.ts +19 -32
- package/src/auth-email-password/__tests__/session-callbacks.integration.ts +6 -5
- package/src/auth-email-password/__tests__/session-strict-mode.integration.ts +1 -1
- package/src/auth-email-password/__tests__/signed-token.test.ts +1 -1
- package/src/auth-email-password/__tests__/signup-flow.integration.ts +11 -15
- package/src/auth-email-password/handlers/invite-accept-with-login.write.ts +26 -26
- package/src/auth-email-password/handlers/invite-accept.write.ts +24 -21
- package/src/auth-email-password/handlers/invite-create.write.ts +3 -8
- package/src/auth-email-password/handlers/invite-signup-complete.write.ts +20 -17
- package/src/auth-email-password/handlers/signup-confirm.write.ts +3 -7
- package/src/auth-email-password/seeding.ts +1 -1
- package/src/auth-email-password/web/__tests__/auth-gate.test.tsx +1 -2
- package/src/auth-email-password/web/__tests__/forgot-password-screen.test.tsx +10 -19
- package/src/auth-email-password/web/__tests__/login-screen.test.tsx +12 -18
- package/src/auth-email-password/web/__tests__/reset-password-screen.test.tsx +12 -17
- package/src/auth-email-password/web/__tests__/session-roles.test.ts +1 -1
- package/src/auth-email-password/web/__tests__/tenant-switcher.test.tsx +1 -8
- package/src/auth-email-password/web/__tests__/test-utils.tsx +4 -8
- package/src/auth-email-password/web/__tests__/user-menu.test.tsx +2 -8
- package/src/auth-email-password/web/__tests__/verify-email-screen.test.tsx +10 -15
- package/src/billing-foundation/__tests__/billing-foundation.integration.ts +1 -1
- package/src/billing-foundation/__tests__/feature.test.ts +1 -1
- package/src/billing-foundation/__tests__/webhook-handler.test.ts +6 -5
- package/src/billing-foundation/db/queries/subscription-projection.ts +15 -0
- package/src/billing-foundation/get-subscription-for-tenant.ts +2 -6
- package/src/billing-foundation/handlers/create-portal-session.write.ts +2 -2
- package/src/billing-foundation/handlers/list-subscriptions.query.ts +4 -1
- package/src/billing-foundation/projection.ts +32 -13
- package/src/cap-counter/__tests__/cap-counter.integration.ts +1 -1
- package/src/cap-counter/__tests__/enforce-cap.test.ts +37 -32
- package/src/cap-counter/__tests__/with-cap-enforcement.integration.ts +1 -1
- package/src/cap-counter/enforce-cap.ts +14 -20
- package/src/cap-counter/handlers/get-counter.query.ts +7 -13
- package/src/cap-counter/handlers/increment.write.ts +2 -2
- package/src/cap-counter/handlers/mark-soft-warned.write.ts +2 -2
- package/src/channel-in-app/handlers/inbox.query.ts +7 -13
- package/src/channel-in-app/handlers/mark-all-read.write.ts +7 -9
- package/src/channel-in-app/handlers/mark-read.write.ts +8 -14
- package/src/channel-in-app/handlers/unread-count.query.ts +10 -9
- package/src/channel-in-app/in-app-channel.ts +10 -12
- package/src/channel-in-app/tables.ts +1 -1
- package/src/compliance-profiles/__tests__/compliance-profiles.integration.ts +1 -1
- package/src/compliance-profiles/__tests__/seeding.integration.ts +1 -1
- package/src/compliance-profiles/_internal/parse-override.ts +19 -0
- package/src/compliance-profiles/handlers/for-tenant.query.ts +10 -32
- package/src/compliance-profiles/handlers/needs-profile.query.ts +4 -7
- package/src/compliance-profiles/handlers/set-profile.write.ts +5 -7
- package/src/compliance-profiles/resolve-for-tenant.ts +11 -27
- package/src/compliance-profiles/schema/profile-selection.ts +2 -2
- package/src/compliance-profiles/seeding.ts +4 -7
- package/src/config/__tests__/app-overrides.test.ts +1 -1
- package/src/config/__tests__/cascade.integration.ts +1 -1
- package/src/config/__tests__/config.integration.ts +8 -27
- package/src/config/db/queries/resolver.ts +47 -0
- package/src/config/handlers/__tests__/prepare-config-write.test.ts +1 -1
- package/src/config/resolver.ts +14 -62
- package/src/config/table.ts +4 -4
- package/src/config/write-helpers.ts +7 -11
- package/src/custom-fields/__tests__/audit-integration.integration.ts +6 -6
- package/src/custom-fields/__tests__/custom-fields.integration.ts +7 -7
- package/src/custom-fields/__tests__/feature.test.ts +1 -1
- package/src/custom-fields/__tests__/field-access.integration.ts +6 -6
- package/src/custom-fields/__tests__/quota.integration.ts +6 -6
- package/src/custom-fields/__tests__/retention.integration.ts +12 -10
- package/src/custom-fields/__tests__/user-data-rights.integration.ts +27 -17
- package/src/custom-fields/__tests__/wire-for-entity.test.ts +5 -5
- package/src/custom-fields/db/queries/field-access.ts +16 -0
- package/src/custom-fields/db/queries/projection.ts +43 -0
- package/src/custom-fields/db/queries/quota.ts +14 -0
- package/src/custom-fields/db/queries/retention.ts +39 -0
- package/src/custom-fields/db/queries/user-data-rights.ts +54 -0
- package/src/custom-fields/lib/field-access.ts +2 -41
- package/src/custom-fields/lib/quota.ts +2 -25
- package/src/custom-fields/run-retention.ts +19 -21
- package/src/custom-fields/wire-for-entity.ts +30 -23
- package/src/custom-fields/wire-user-data-rights.ts +33 -85
- package/src/data-retention/__tests__/data-retention.integration.ts +1 -1
- package/src/data-retention/__tests__/keep-for.test.ts +1 -1
- package/src/data-retention/__tests__/override-schema.test.ts +1 -1
- package/src/data-retention/__tests__/policy-for.integration.ts +1 -1
- package/src/data-retention/__tests__/resolver.test.ts +1 -1
- package/src/data-retention/handlers/policy-for.query.ts +5 -8
- package/src/data-retention/resolve-for-tenant.ts +6 -8
- package/src/data-retention/schema/tenant-retention-override.ts +2 -2
- package/src/delivery/__tests__/delivery-events.integration.ts +8 -21
- package/src/delivery/__tests__/delivery.integration.ts +100 -190
- package/src/delivery/db/queries/preferences.ts +30 -0
- package/src/delivery/delivery-service.ts +8 -36
- package/src/delivery/feature.ts +10 -2
- package/src/delivery/handlers/log.query.ts +5 -7
- package/src/delivery/handlers/preferences.query.ts +2 -5
- package/src/delivery/tables.ts +26 -1
- package/src/delivery/upsert-preference.ts +8 -14
- package/src/feature-toggles/__tests__/feature-toggles.integration.ts +30 -30
- package/src/feature-toggles/__tests__/registered-system-tenant.test.ts +7 -6
- package/src/feature-toggles/db/queries/toggle-state.ts +25 -0
- package/src/feature-toggles/feature.ts +16 -2
- package/src/feature-toggles/global-feature-state-table.ts +1 -1
- package/src/feature-toggles/handlers/list.query.ts +9 -2
- package/src/feature-toggles/handlers/registered.query.ts +3 -7
- package/src/feature-toggles/handlers/set.write.ts +37 -25
- package/src/feature-toggles/toggle-runtime.ts +3 -6
- package/src/file-foundation/__tests__/feature.test.ts +1 -1
- package/src/file-foundation/__tests__/file-foundation.integration.ts +1 -1
- package/src/file-provider-inmemory/__tests__/feature.test.ts +1 -1
- package/src/file-provider-s3/__tests__/feature.test.ts +1 -1
- package/src/files/__tests__/files.integration.ts +18 -7
- package/src/files/schema/file-ref.ts +1 -1
- package/src/files-provider-s3/__tests__/env-helper.test.ts +1 -1
- package/src/files-provider-s3/__tests__/s3-provider.integration.ts +1 -1
- package/src/files-provider-s3/__tests__/s3-provider.test.ts +1 -1
- package/src/jobs/__tests__/job-system-user.integration.ts +1 -1
- package/src/jobs/__tests__/jobs-events.integration.ts +8 -21
- package/src/jobs/__tests__/jobs-feature.integration.ts +1 -1
- package/src/jobs/feature.ts +26 -15
- package/src/jobs/handlers/detail.query.ts +10 -8
- package/src/jobs/handlers/list.query.ts +9 -21
- package/src/jobs/handlers/retry.write.ts +2 -7
- package/src/jobs/job-run-logger.ts +3 -9
- package/src/jobs/job-run-table.ts +49 -17
- package/src/legal-pages/__tests__/legal-pages.integration.ts +1 -1
- package/src/mail-foundation/__tests__/feature.test.ts +1 -1
- package/src/mail-foundation/__tests__/mail-foundation.integration.ts +1 -1
- package/src/mail-transport-inmemory/__tests__/feature.test.ts +1 -1
- package/src/mail-transport-smtp/__tests__/feature.test.ts +1 -1
- package/src/rate-limiting/__tests__/rate-limiting.integration.ts +1 -1
- package/src/renderer-foundation/__tests__/api.test.ts +2 -2
- package/src/renderer-foundation/__tests__/collect-plugins.integration.ts +1 -1
- package/src/renderer-simple/__tests__/adapter.test.ts +2 -2
- package/src/renderer-simple/__tests__/simple-renderer.test.ts +1 -1
- package/src/secrets/__tests__/require-secrets-context.test.ts +6 -5
- package/src/secrets/__tests__/rotate.integration.ts +6 -9
- package/src/secrets/__tests__/secrets-events.integration.ts +6 -12
- package/src/secrets/__tests__/secrets.integration.ts +6 -11
- package/src/secrets/db/queries/read.ts +16 -0
- package/src/secrets/handlers/list.query.ts +16 -17
- package/src/secrets/handlers/rotate.job.ts +8 -12
- package/src/secrets/secrets-context.ts +9 -21
- package/src/secrets/table.ts +1 -1
- package/src/sessions/__tests__/cleanup.integration.ts +8 -6
- package/src/sessions/__tests__/password-auto-revoke.integration.ts +7 -6
- package/src/sessions/__tests__/sessions.integration.ts +23 -38
- package/src/sessions/__tests__/test-helpers.ts +1 -1
- package/src/sessions/db/queries/cleanup.ts +21 -0
- package/src/sessions/handlers/cleanup.job.ts +6 -29
- package/src/sessions/handlers/list.query.ts +24 -24
- package/src/sessions/handlers/mine.query.ts +24 -23
- package/src/sessions/handlers/revoke-all-for-user.write.ts +7 -11
- package/src/sessions/handlers/revoke-all-others.write.ts +7 -12
- package/src/sessions/handlers/revoke.write.ts +11 -18
- package/src/sessions/schema/user-session.ts +2 -2
- package/src/sessions/session-callbacks.ts +19 -21
- package/src/subscription-mollie/__tests__/feature.test.ts +1 -1
- package/src/subscription-mollie/__tests__/mollie-foundation.integration.ts +1 -1
- package/src/subscription-mollie/__tests__/verify-webhook.test.ts +8 -7
- package/src/subscription-stripe/__tests__/feature.test.ts +1 -1
- package/src/subscription-stripe/__tests__/plugin-methods.test.ts +14 -15
- package/src/subscription-stripe/__tests__/stripe-foundation.integration.ts +1 -1
- package/src/subscription-stripe/__tests__/verify-webhook.test.ts +14 -14
- package/src/subscription-stripe/verify-webhook.ts +1 -1
- package/src/template-resolver/__tests__/handlers.integration.ts +1 -1
- package/src/template-resolver/__tests__/template-resolver.integration.ts +3 -2
- package/src/template-resolver/api.ts +7 -13
- package/src/template-resolver/handlers/archive.write.ts +4 -7
- package/src/template-resolver/handlers/find-by-id.query.ts +4 -7
- package/src/template-resolver/handlers/list.query.ts +13 -21
- package/src/template-resolver/handlers/publish.write.ts +4 -7
- package/src/template-resolver/handlers/upsert-system.write.ts +7 -10
- package/src/template-resolver/handlers/upsert-tenant.write.ts +7 -10
- package/src/template-resolver/table.ts +2 -5
- package/src/tenant/__tests__/multi-tenant.integration.ts +1 -1
- package/src/tenant/__tests__/seed-testing.integration.ts +19 -45
- package/src/tenant/__tests__/tenant.integration.ts +1 -1
- package/src/tenant/handlers/active-tenant-ids.query.ts +3 -8
- package/src/tenant/handlers/add-member.write.ts +6 -8
- package/src/tenant/handlers/cancel-invitation.write.ts +5 -7
- package/src/tenant/handlers/invitations.query.ts +5 -10
- package/src/tenant/handlers/me.query.ts +2 -3
- package/src/tenant/handlers/members.query.ts +4 -5
- package/src/tenant/handlers/memberships.query.ts +2 -5
- package/src/tenant/handlers/remove-member.write.ts +6 -8
- package/src/tenant/handlers/resolve-user-ids.query.ts +6 -16
- package/src/tenant/handlers/update-member-roles.write.ts +6 -8
- package/src/tenant/invitation-table.ts +2 -5
- package/src/tenant/membership-table.ts +3 -6
- package/src/tenant/schema/tenant.ts +2 -2
- package/src/tenant/seeding.ts +12 -18
- package/src/text-content/README.md +1 -1
- package/src/text-content/__tests__/text-content.integration.ts +2 -2
- package/src/text-content/api.ts +2 -9
- package/src/text-content/handlers/by-slug.query.ts +6 -9
- package/src/text-content/handlers/by-tenant.query.ts +2 -2
- package/src/text-content/handlers/set.write.ts +7 -9
- package/src/text-content/seeding.ts +6 -9
- package/src/text-content/table.ts +2 -2
- package/src/text-content/web/__tests__/editor-read-only.test.tsx +31 -45
- package/src/text-content/web/__tests__/group-blocks.test.ts +1 -18
- package/src/text-content/web/client-plugin.tsx +11 -23
- package/src/tier-engine/__tests__/auto-default-tier.integration.ts +10 -16
- package/src/tier-engine/__tests__/compose-app.test.ts +1 -1
- package/src/tier-engine/__tests__/drift.test.ts +1 -1
- package/src/tier-engine/__tests__/resolver.integration.ts +6 -6
- package/src/tier-engine/__tests__/tier-engine.integration.ts +1 -1
- package/src/tier-engine/feature.ts +9 -16
- package/src/user/__tests__/seed-testing.integration.ts +10 -22
- package/src/user/__tests__/user-status.test.ts +1 -1
- package/src/user/__tests__/user.integration.ts +6 -5
- package/src/user/handlers/create.write.ts +5 -7
- package/src/user/handlers/find-for-auth.query.ts +5 -7
- package/src/user/schema/user.ts +2 -2
- package/src/user/seeding.ts +2 -3
- package/src/user-data-rights/__tests__/audit-log.integration.ts +24 -12
- package/src/user-data-rights/__tests__/cross-data-matrix.integration.ts +64 -37
- package/src/user-data-rights/__tests__/download.integration.ts +29 -46
- package/src/user-data-rights/__tests__/export-job-idempotency.integration.ts +35 -28
- package/src/user-data-rights/__tests__/export-job-schema.test.ts +2 -2
- package/src/user-data-rights/__tests__/policy-to-strategy.test.ts +1 -1
- package/src/user-data-rights/__tests__/request-cancel-deletion.integration.ts +11 -15
- package/src/user-data-rights/__tests__/request-deletion-callback.integration.ts +10 -12
- package/src/user-data-rights/__tests__/request-export.integration.ts +23 -16
- package/src/user-data-rights/__tests__/restriction-flow.integration.ts +24 -32
- package/src/user-data-rights/__tests__/run-export-jobs.integration.ts +142 -137
- package/src/user-data-rights/__tests__/run-forget-cleanup.integration.ts +46 -28
- package/src/user-data-rights/__tests__/run-user-export.integration.ts +20 -14
- package/src/user-data-rights/__tests__/token-helpers.test.ts +1 -1
- package/src/user-data-rights/__tests__/user-data-rights.integration.ts +1 -1
- package/src/user-data-rights/__tests__/zip-path.test.ts +1 -1
- package/src/user-data-rights/audit-download.ts +3 -3
- package/src/user-data-rights/db/queries/export-jobs.ts +23 -0
- package/src/user-data-rights/db/queries/forget-cleanup.ts +13 -0
- package/src/user-data-rights/handlers/cancel-deletion.write.ts +28 -22
- package/src/user-data-rights/handlers/download-by-job.query.ts +11 -21
- package/src/user-data-rights/handlers/download-by-token.query.ts +20 -35
- package/src/user-data-rights/handlers/export-status.query.ts +19 -33
- package/src/user-data-rights/handlers/lift-restriction.write.ts +7 -12
- package/src/user-data-rights/handlers/list-download-attempts.query.ts +14 -23
- package/src/user-data-rights/handlers/my-audit-log.query.ts +33 -23
- package/src/user-data-rights/handlers/request-deletion.write.ts +15 -15
- package/src/user-data-rights/handlers/request-export.write.ts +7 -11
- package/src/user-data-rights/handlers/restrict-account.write.ts +12 -12
- package/src/user-data-rights/run-export-jobs.ts +20 -60
- package/src/user-data-rights/run-forget-cleanup.ts +19 -33
- package/src/user-data-rights/run-user-export.ts +4 -6
- package/src/user-data-rights/schema/download-attempt.ts +2 -2
- package/src/user-data-rights/schema/download-token.ts +2 -2
- package/src/user-data-rights/schema/export-job.ts +2 -3
- package/src/user-data-rights-defaults/__tests__/user-data-rights-defaults.integration.ts +37 -30
- package/src/user-data-rights-defaults/db/queries/user-hook.ts +17 -0
- package/src/user-data-rights-defaults/hooks/file-ref.userdata-hook.ts +12 -27
- package/src/user-data-rights-defaults/hooks/user.userdata-hook.ts +16 -18
- package/CHANGELOG.md +0 -689
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
1
2
|
import { randomBytes } from "node:crypto";
|
|
2
3
|
import {
|
|
3
4
|
createEncryptionProvider,
|
|
@@ -26,7 +27,6 @@ import {
|
|
|
26
27
|
unsafePushTables,
|
|
27
28
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
28
29
|
import { bridgeStub, sleep } from "@cosmicdrift/kumiko-framework/testing";
|
|
29
|
-
import { afterAll, beforeAll, describe, expect, test } from "vitest";
|
|
30
30
|
import { ConfigHandlers } from "../../config/constants";
|
|
31
31
|
import { createConfigAccessor, createConfigFeature } from "../../config/feature";
|
|
32
32
|
import { type ConfigResolver, createConfigResolver } from "../../config/resolver";
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
// projection side (list + detail queries). This file covers the event
|
|
9
9
|
// side — complementary coverage, minimal overlap.
|
|
10
10
|
|
|
11
|
+
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test";
|
|
12
|
+
import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
11
13
|
import { createRegistry, SYSTEM_TENANT_ID } from "@cosmicdrift/kumiko-framework/engine";
|
|
12
14
|
import { createEventsTable, eventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
13
15
|
import {
|
|
@@ -17,8 +19,7 @@ import {
|
|
|
17
19
|
type TestRedis,
|
|
18
20
|
unsafePushTables,
|
|
19
21
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
20
|
-
import {
|
|
21
|
-
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
|
22
|
+
import { resetTestTables } from "@cosmicdrift/kumiko-framework/testing";
|
|
22
23
|
import { runCompletedSchema, runFailedSchema, runStartedSchema } from "../events";
|
|
23
24
|
import { createJobsFeature } from "../feature";
|
|
24
25
|
import {
|
|
@@ -48,9 +49,7 @@ afterAll(async () => {
|
|
|
48
49
|
});
|
|
49
50
|
|
|
50
51
|
beforeEach(async () => {
|
|
51
|
-
await testDb.db
|
|
52
|
-
await testDb.db.delete(jobRunsTable);
|
|
53
|
-
await testDb.db.delete(jobRunLogsTable);
|
|
52
|
+
await resetTestTables(testDb.db, [eventsTable, jobRunsTable, jobRunLogsTable]);
|
|
54
53
|
});
|
|
55
54
|
|
|
56
55
|
describe("jobRun event shapes", () => {
|
|
@@ -69,10 +68,7 @@ describe("jobRun event shapes", () => {
|
|
|
69
68
|
attempt: 1,
|
|
70
69
|
});
|
|
71
70
|
|
|
72
|
-
const events = await testDb.db
|
|
73
|
-
.select()
|
|
74
|
-
.from(eventsTable)
|
|
75
|
-
.where(eq(eventsTable.type, JOB_RUN_STARTED_EVENT));
|
|
71
|
+
const events = await selectMany(testDb.db, eventsTable, { type: JOB_RUN_STARTED_EVENT });
|
|
76
72
|
|
|
77
73
|
expect(events.length).toBe(1);
|
|
78
74
|
const e = events[0];
|
|
@@ -95,10 +91,7 @@ describe("jobRun event shapes", () => {
|
|
|
95
91
|
{ level: "info", message: "done", timestamp: Temporal.Now.instant() },
|
|
96
92
|
]);
|
|
97
93
|
|
|
98
|
-
const events = await testDb.db
|
|
99
|
-
.select()
|
|
100
|
-
.from(eventsTable)
|
|
101
|
-
.where(eq(eventsTable.type, JOB_RUN_COMPLETED_EVENT));
|
|
94
|
+
const events = await selectMany(testDb.db, eventsTable, { type: JOB_RUN_COMPLETED_EVENT });
|
|
102
95
|
|
|
103
96
|
expect(events.length).toBe(1);
|
|
104
97
|
const p = runCompletedSchema.parse(events[0]?.payload);
|
|
@@ -113,10 +106,7 @@ describe("jobRun event shapes", () => {
|
|
|
113
106
|
{ level: "error", message: "kaboom", timestamp: Temporal.Now.instant() },
|
|
114
107
|
]);
|
|
115
108
|
|
|
116
|
-
const events = await testDb.db
|
|
117
|
-
.select()
|
|
118
|
-
.from(eventsTable)
|
|
119
|
-
.where(eq(eventsTable.type, JOB_RUN_FAILED_EVENT));
|
|
109
|
+
const events = await selectMany(testDb.db, eventsTable, { type: JOB_RUN_FAILED_EVENT });
|
|
120
110
|
|
|
121
111
|
expect(events.length).toBe(1);
|
|
122
112
|
const p = runFailedSchema.parse(events[0]?.payload);
|
|
@@ -131,10 +121,7 @@ describe("jobRun event shapes", () => {
|
|
|
131
121
|
// Both events should share the same aggregateId — that's what makes
|
|
132
122
|
// the jobRun a single stream and lets ctx.loadAggregate() reduce
|
|
133
123
|
// them into a coherent state.
|
|
134
|
-
const events = await testDb.db
|
|
135
|
-
.select()
|
|
136
|
-
.from(eventsTable)
|
|
137
|
-
.where(eq(eventsTable.aggregateType, "jobRun"));
|
|
124
|
+
const events = await selectMany(testDb.db, eventsTable, { aggregateType: "jobRun" });
|
|
138
125
|
|
|
139
126
|
expect(events.length).toBe(2);
|
|
140
127
|
const ids = new Set(events.map((e) => e.aggregateId));
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
1
2
|
import { buildServer, type JwtHelper } from "@cosmicdrift/kumiko-framework/api";
|
|
2
3
|
import type { DbConnection } from "@cosmicdrift/kumiko-framework/db";
|
|
3
4
|
import {
|
|
@@ -18,7 +19,6 @@ import {
|
|
|
18
19
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
19
20
|
import { sleep } from "@cosmicdrift/kumiko-framework/testing";
|
|
20
21
|
import type { Hono } from "hono";
|
|
21
|
-
import { afterAll, beforeAll, describe, expect, test } from "vitest";
|
|
22
22
|
import { JobHandlers, JobQueries } from "../constants";
|
|
23
23
|
import { createJobsFeature } from "../feature";
|
|
24
24
|
import { createJobRunLogger } from "../job-run-logger";
|
package/src/jobs/feature.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import { insertMany, insertOne, updateMany } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
1
2
|
import {
|
|
2
3
|
defineApply,
|
|
3
4
|
defineFeature,
|
|
4
5
|
type FeatureDefinition,
|
|
5
6
|
} from "@cosmicdrift/kumiko-framework/engine";
|
|
6
|
-
import { eq } from "drizzle-orm";
|
|
7
7
|
import type { z } from "zod";
|
|
8
8
|
// Event-payload schemas live in a sibling module so the logger can import
|
|
9
9
|
// them without the cycle jobs-feature ↔ job-run-logger. The logger parses
|
|
@@ -19,11 +19,14 @@ import {
|
|
|
19
19
|
JOB_RUN_FAILED_EVENT,
|
|
20
20
|
JOB_RUN_STARTED_EVENT,
|
|
21
21
|
} from "./job-run-logger";
|
|
22
|
-
import { jobRunLogsTable, jobRunsTable } from "./job-run-table";
|
|
22
|
+
import { jobRunLogsTable, jobRunLogsTableMeta, jobRunsTable } from "./job-run-table";
|
|
23
23
|
|
|
24
24
|
export function createJobsFeature(): FeatureDefinition {
|
|
25
25
|
return defineFeature("jobs", (r) => {
|
|
26
26
|
r.systemScope();
|
|
27
|
+
r.unmanagedTable(jobRunLogsTableMeta, {
|
|
28
|
+
reason: "read_side.job_run_logs",
|
|
29
|
+
});
|
|
27
30
|
// Events-only aggregate: "jobRun" has no r.entity registration, because
|
|
28
31
|
// the entire lifecycle is driven by BullMQ-callback → r.defineEvent
|
|
29
32
|
// (no executor, no CRUD). The boot-validator accepts the two
|
|
@@ -44,7 +47,7 @@ export function createJobsFeature(): FeatureDefinition {
|
|
|
44
47
|
[JOB_RUN_STARTED_EVENT]: defineApply<z.infer<typeof runStartedSchema>>(
|
|
45
48
|
async (event, tx) => {
|
|
46
49
|
const p = event.payload;
|
|
47
|
-
await tx
|
|
50
|
+
await insertOne(tx, jobRunsTable, {
|
|
48
51
|
id: event.aggregateId,
|
|
49
52
|
tenantId: event.tenantId,
|
|
50
53
|
version: event.version,
|
|
@@ -63,24 +66,27 @@ export function createJobsFeature(): FeatureDefinition {
|
|
|
63
66
|
[JOB_RUN_COMPLETED_EVENT]: defineApply<z.infer<typeof runCompletedSchema>>(
|
|
64
67
|
async (event, tx) => {
|
|
65
68
|
const p = event.payload;
|
|
66
|
-
await
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
await updateMany(
|
|
70
|
+
tx,
|
|
71
|
+
jobRunsTable,
|
|
72
|
+
{
|
|
69
73
|
status: "completed",
|
|
70
74
|
duration: p.duration,
|
|
71
75
|
finishedAt: Temporal.Instant.from(p.finishedAt),
|
|
72
76
|
version: event.version,
|
|
73
77
|
modifiedAt: event.createdAt,
|
|
74
78
|
modifiedById: event.metadata?.userId ?? "system",
|
|
75
|
-
}
|
|
76
|
-
|
|
79
|
+
},
|
|
80
|
+
{ id: event.aggregateId },
|
|
81
|
+
);
|
|
77
82
|
},
|
|
78
83
|
),
|
|
79
84
|
[JOB_RUN_FAILED_EVENT]: defineApply<z.infer<typeof runFailedSchema>>(async (event, tx) => {
|
|
80
85
|
const p = event.payload;
|
|
81
|
-
await
|
|
82
|
-
|
|
83
|
-
|
|
86
|
+
await updateMany(
|
|
87
|
+
tx,
|
|
88
|
+
jobRunsTable,
|
|
89
|
+
{
|
|
84
90
|
status: "failed",
|
|
85
91
|
error: p.error,
|
|
86
92
|
duration: p.duration,
|
|
@@ -88,8 +94,9 @@ export function createJobsFeature(): FeatureDefinition {
|
|
|
88
94
|
version: event.version,
|
|
89
95
|
modifiedAt: event.createdAt,
|
|
90
96
|
modifiedById: event.metadata?.userId ?? "system",
|
|
91
|
-
}
|
|
92
|
-
|
|
97
|
+
},
|
|
98
|
+
{ id: event.aggregateId },
|
|
99
|
+
);
|
|
93
100
|
}),
|
|
94
101
|
},
|
|
95
102
|
});
|
|
@@ -109,7 +116,9 @@ export function createJobsFeature(): FeatureDefinition {
|
|
|
109
116
|
// to insert; the completed-event alone already updated the run's
|
|
110
117
|
// status via the sibling job-runs projection.
|
|
111
118
|
if (p.logs.length === 0) return;
|
|
112
|
-
await
|
|
119
|
+
await insertMany(
|
|
120
|
+
tx,
|
|
121
|
+
jobRunLogsTable,
|
|
113
122
|
p.logs.map((log) => ({
|
|
114
123
|
runId: event.aggregateId,
|
|
115
124
|
level: log.level,
|
|
@@ -123,7 +132,9 @@ export function createJobsFeature(): FeatureDefinition {
|
|
|
123
132
|
const p = event.payload;
|
|
124
133
|
// skip: empty log batch — the worker ran silent (mirror of completed)
|
|
125
134
|
if (p.logs.length === 0) return;
|
|
126
|
-
await
|
|
135
|
+
await insertMany(
|
|
136
|
+
tx,
|
|
137
|
+
jobRunLogsTable,
|
|
127
138
|
p.logs.map((log) => ({
|
|
128
139
|
runId: event.aggregateId,
|
|
129
140
|
level: log.level,
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { fetchOne } from "@cosmicdrift/kumiko-framework/db";
|
|
1
|
+
import { fetchOne, selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
2
2
|
import { defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
|
-
import { eq } from "drizzle-orm";
|
|
4
3
|
import { z } from "zod";
|
|
5
4
|
import { jobRunLogsTable, jobRunsTable } from "../job-run-table";
|
|
6
5
|
|
|
@@ -15,15 +14,18 @@ export const detailQuery = defineQueryHandler({
|
|
|
15
14
|
handler: async (query, ctx) => {
|
|
16
15
|
const db = ctx.db;
|
|
17
16
|
|
|
18
|
-
const row = await fetchOne(db, jobRunsTable,
|
|
17
|
+
const row = await fetchOne(db, jobRunsTable, { id: query.payload.runId });
|
|
19
18
|
|
|
20
19
|
if (!row) return null;
|
|
21
20
|
|
|
22
|
-
const logs = await
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
21
|
+
const logs = await selectMany(
|
|
22
|
+
db,
|
|
23
|
+
jobRunLogsTable,
|
|
24
|
+
{ runId: query.payload.runId },
|
|
25
|
+
{
|
|
26
|
+
orderBy: { col: "id", direction: "asc" },
|
|
27
|
+
},
|
|
28
|
+
);
|
|
27
29
|
|
|
28
30
|
return { ...row, logs };
|
|
29
31
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { selectMany, type WhereObject } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
1
2
|
import { defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
|
-
import { and, desc, eq, type SQL } from "drizzle-orm";
|
|
3
3
|
import { z } from "zod";
|
|
4
|
-
import {
|
|
4
|
+
import { jobRunsTable } from "../job-run-table";
|
|
5
5
|
|
|
6
6
|
export const listQuery = defineQueryHandler({
|
|
7
7
|
name: "list",
|
|
@@ -12,25 +12,13 @@ export const listQuery = defineQueryHandler({
|
|
|
12
12
|
}),
|
|
13
13
|
access: { roles: ["SystemAdmin"] },
|
|
14
14
|
handler: async (query, ctx) => {
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
conditions.push(eq(jobRunsTable.status, query.payload.status as JobRunStatus)); // @cast-boundary engine-payload
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const limit = query.payload.limit ?? 50;
|
|
26
|
-
|
|
27
|
-
const rows = await db
|
|
28
|
-
.select()
|
|
29
|
-
.from(jobRunsTable)
|
|
30
|
-
.where(conditions.length > 0 ? and(...conditions) : undefined)
|
|
31
|
-
.orderBy(desc(jobRunsTable.id))
|
|
32
|
-
.limit(limit);
|
|
33
|
-
|
|
15
|
+
const where: WhereObject = {};
|
|
16
|
+
if (query.payload.jobName) where["jobName"] = query.payload.jobName;
|
|
17
|
+
if (query.payload.status) where["status"] = query.payload.status;
|
|
18
|
+
const rows = await selectMany(ctx.db, jobRunsTable, where, {
|
|
19
|
+
orderBy: { col: "id", direction: "desc" },
|
|
20
|
+
limit: query.payload.limit ?? 50,
|
|
21
|
+
});
|
|
34
22
|
return { rows };
|
|
35
23
|
},
|
|
36
24
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { fetchOne } from "@cosmicdrift/kumiko-framework/db";
|
|
1
|
+
import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
2
2
|
import { defineWriteHandler } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
3
|
import {
|
|
4
4
|
NotFoundError,
|
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
} from "@cosmicdrift/kumiko-framework/errors";
|
|
8
8
|
import type { JobRunner } from "@cosmicdrift/kumiko-framework/jobs";
|
|
9
9
|
import { parseJsonOrThrow } from "@cosmicdrift/kumiko-framework/utils";
|
|
10
|
-
import { eq } from "drizzle-orm";
|
|
11
10
|
import { z } from "zod";
|
|
12
11
|
import { JobErrors } from "../constants";
|
|
13
12
|
import { jobRunsTable } from "../job-run-table";
|
|
@@ -29,11 +28,7 @@ export const retryWrite = defineWriteHandler({
|
|
|
29
28
|
// @cast-boundary engine-payload — JobRunner attached by app-boot via ctx-extension
|
|
30
29
|
const jobRunner = ctx["jobRunner"] as JobRunner;
|
|
31
30
|
|
|
32
|
-
const run = await fetchOne<JobRunRow>(
|
|
33
|
-
db,
|
|
34
|
-
jobRunsTable,
|
|
35
|
-
eq(jobRunsTable.id, event.payload.runId),
|
|
36
|
-
);
|
|
31
|
+
const run = await fetchOne<JobRunRow>(db, jobRunsTable, { id: event.payload.runId });
|
|
37
32
|
|
|
38
33
|
if (!run) {
|
|
39
34
|
return writeFailure(
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
+
import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
1
2
|
import type { DbConnection } from "@cosmicdrift/kumiko-framework/db";
|
|
2
3
|
import { type Registry, SYSTEM_TENANT_ID } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
4
|
import { append, getStreamVersion } from "@cosmicdrift/kumiko-framework/event-store";
|
|
4
5
|
import type { JobLogEntry, JobMeta, JobRunnerOptions } from "@cosmicdrift/kumiko-framework/jobs";
|
|
5
6
|
import { runProjectionsForEvent } from "@cosmicdrift/kumiko-framework/pipeline";
|
|
6
7
|
import { generateId } from "@cosmicdrift/kumiko-framework/utils";
|
|
7
|
-
import { eq } from "drizzle-orm";
|
|
8
8
|
import { runCompletedSchema, runFailedSchema, runStartedSchema } from "./events";
|
|
9
9
|
import { jobRunsTable } from "./job-run-table";
|
|
10
10
|
|
|
@@ -86,10 +86,7 @@ export function createJobRunLogger(opts: JobRunLoggerOptions): JobRunLoggerCallb
|
|
|
86
86
|
async function resolveRunId(bullJobId: string): Promise<string | undefined> {
|
|
87
87
|
const cached = cacheGet(bullJobId);
|
|
88
88
|
if (cached) return cached;
|
|
89
|
-
const
|
|
90
|
-
.select({ id: jobRunsTable.id })
|
|
91
|
-
.from(jobRunsTable)
|
|
92
|
-
.where(eq(jobRunsTable.bullJobId, bullJobId));
|
|
89
|
+
const row = await fetchOne<{ id: string | number }>(db, jobRunsTable, { bullJobId });
|
|
93
90
|
// buildBaseColumns's signature types `id` as `string | number` because
|
|
94
91
|
// it returns both branches of the idType union. We know this table
|
|
95
92
|
// was built with idType: "uuid" (see job-run-table.ts), so narrowing
|
|
@@ -181,10 +178,7 @@ export function createJobRunLogger(opts: JobRunLoggerOptions): JobRunLoggerCallb
|
|
|
181
178
|
// symmetrically to onJobComplete (which gets duration from the
|
|
182
179
|
// worker). The projection already has started_at from the
|
|
183
180
|
// run-started inline-apply.
|
|
184
|
-
const
|
|
185
|
-
.select({ startedAt: jobRunsTable.startedAt })
|
|
186
|
-
.from(jobRunsTable)
|
|
187
|
-
.where(eq(jobRunsTable.id, runId));
|
|
181
|
+
const row = await fetchOne<{ startedAt: Temporal.Instant }>(db, jobRunsTable, { id: runId });
|
|
188
182
|
const now = Temporal.Now.instant();
|
|
189
183
|
const duration = row ? Number(now.since(row.startedAt).total({ unit: "millisecond" })) : 0;
|
|
190
184
|
const payload = runFailedSchema.parse({
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
2
|
+
buildEntityTable,
|
|
3
|
+
defineUnmanagedTable,
|
|
4
|
+
type EntityTableMeta,
|
|
3
5
|
instant,
|
|
4
|
-
integer,
|
|
5
6
|
table as pgTable,
|
|
6
7
|
serial,
|
|
7
8
|
text,
|
|
8
9
|
} from "@cosmicdrift/kumiko-framework/db";
|
|
10
|
+
import {
|
|
11
|
+
createEntity,
|
|
12
|
+
createNumberField,
|
|
13
|
+
createTextField,
|
|
14
|
+
createTimestampField,
|
|
15
|
+
} from "@cosmicdrift/kumiko-framework/engine";
|
|
9
16
|
|
|
10
17
|
export type JobRunStatus = "queued" | "running" | "completed" | "failed";
|
|
11
18
|
export type JobLogLevel = "info" | "warn" | "error";
|
|
@@ -24,23 +31,30 @@ export type JobLogLevel = "info" | "warn" | "error";
|
|
|
24
31
|
// expands the batch into N rows in jobRunLogsTable, keeping the pre-ES
|
|
25
32
|
// detail-query-shape intact.
|
|
26
33
|
//
|
|
27
|
-
//
|
|
28
|
-
//
|
|
29
|
-
//
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
34
|
+
// Entity-derived table — Phase 3b of drizzle-replacement. Earlier this was
|
|
35
|
+
// a hand-written pgTable; the entity-form is the single source for both
|
|
36
|
+
// the drizzle-table (query API) and the future EntityTableMeta-based
|
|
37
|
+
// migration generator. status/$type<JobRunStatus> ist nicht im entity-
|
|
38
|
+
// schema modelliert — Drizzle's column-type ist text mit CHECK-Constraint
|
|
39
|
+
// als App-Boundary (gleicher Pattern wie template-resolver kind/scope).
|
|
40
|
+
export const jobRunEntity = createEntity({
|
|
41
|
+
table: "read_job_runs",
|
|
42
|
+
fields: {
|
|
43
|
+
jobName: createTextField({ required: true }),
|
|
44
|
+
bullJobId: createTextField({ required: true }),
|
|
45
|
+
status: createTextField({ required: true }),
|
|
46
|
+
payload: createTextField(),
|
|
47
|
+
error: createTextField(),
|
|
48
|
+
attempt: createNumberField({ required: true, default: 1 }),
|
|
49
|
+
startedAt: createTimestampField({ required: true }),
|
|
50
|
+
finishedAt: createTimestampField(),
|
|
51
|
+
duration: createNumberField(),
|
|
52
|
+
triggeredById: createTextField(),
|
|
53
|
+
},
|
|
42
54
|
});
|
|
43
55
|
|
|
56
|
+
export const jobRunsTable = buildEntityTable("job-run", jobRunEntity);
|
|
57
|
+
|
|
44
58
|
// Child projection keyed by the jobRun aggregate id. Pre-ES used a serial
|
|
45
59
|
// PK + integer runId; post-ES runId is still exposed but now holds the
|
|
46
60
|
// uuid of the parent jobRun. Existing detail-query callers treat it as an
|
|
@@ -53,3 +67,21 @@ export const jobRunLogsTable = pgTable("read_job_run_logs", {
|
|
|
53
67
|
message: text("message").notNull(),
|
|
54
68
|
timestamp: instant("timestamp").notNull(),
|
|
55
69
|
});
|
|
70
|
+
|
|
71
|
+
// **Unmanaged table** — bewusst KEIN createEntity. Begründung:
|
|
72
|
+
// - serial PK (kein uuid) — pre-ES legacy, kompatibilität mit existing rows
|
|
73
|
+
// - KEIN tenant_id — child-Tabelle von jobRun, tenant-context lebt am parent
|
|
74
|
+
// - keine base-columns (kein version/inserted_at/inserted_by_id) — append-
|
|
75
|
+
// only log, kein in-place-update, keine Audit-Spalten gewünscht
|
|
76
|
+
// pgTable bleibt source-of-truth für Query-API; Phase 4 leitet das pgTable
|
|
77
|
+
// aus dieser Meta ab.
|
|
78
|
+
export const jobRunLogsTableMeta: EntityTableMeta = defineUnmanagedTable({
|
|
79
|
+
tableName: "read_job_run_logs",
|
|
80
|
+
columns: [
|
|
81
|
+
{ name: "id", pgType: "serial", notNull: true, primaryKey: true },
|
|
82
|
+
{ name: "run_id", pgType: "text", notNull: true },
|
|
83
|
+
{ name: "level", pgType: "text", notNull: true },
|
|
84
|
+
{ name: "message", pgType: "text", notNull: true },
|
|
85
|
+
{ name: "timestamp", pgType: "timestamptz", notNull: true },
|
|
86
|
+
],
|
|
87
|
+
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
1
2
|
import type { TextContentApi } from "@cosmicdrift/kumiko-bundled-features/text-content";
|
|
2
3
|
import {
|
|
3
4
|
createTextContentApi,
|
|
@@ -13,7 +14,6 @@ import {
|
|
|
13
14
|
type TestStack,
|
|
14
15
|
unsafeCreateEntityTable,
|
|
15
16
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
16
|
-
import { afterAll, beforeAll, describe, expect, test } from "vitest";
|
|
17
17
|
import { createLegalPagesFeature, runLegalPagesBootCheck } from "../feature";
|
|
18
18
|
import { renderMarkdownToHtml, wrapInLayout } from "../markdown";
|
|
19
19
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// declares an extension-point + a single selector config-key, nothing
|
|
7
7
|
// provider-concrete.
|
|
8
8
|
|
|
9
|
-
import { describe, expect, test } from "
|
|
9
|
+
import { describe, expect, test } from "bun:test";
|
|
10
10
|
import { mailFoundationFeature } from "../feature";
|
|
11
11
|
|
|
12
12
|
describe("mailFoundationFeature — shape", () => {
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
// it saw. That's the cheapest way to get a real `HandlerContext` in a
|
|
9
9
|
// test without re-implementing the dispatcher.
|
|
10
10
|
|
|
11
|
+
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
11
12
|
import { randomBytes } from "node:crypto";
|
|
12
13
|
import { createEncryptionProvider, type DbConnection } from "@cosmicdrift/kumiko-framework/db";
|
|
13
14
|
import { defineFeature, defineWriteHandler } from "@cosmicdrift/kumiko-framework/engine";
|
|
@@ -25,7 +26,6 @@ import {
|
|
|
25
26
|
createMutableMasterKeyProvider,
|
|
26
27
|
type MutableMasterKeyProvider,
|
|
27
28
|
} from "@cosmicdrift/kumiko-framework/testing";
|
|
28
|
-
import { afterAll, beforeAll, describe, expect, test } from "vitest";
|
|
29
29
|
import { z } from "zod";
|
|
30
30
|
import { createConfigFeature } from "../../config";
|
|
31
31
|
import { ConfigHandlers } from "../../config/constants";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// feature.ts contract tests for mail-transport-inmemory.
|
|
2
2
|
|
|
3
|
-
import { describe, expect, test } from "
|
|
3
|
+
import { describe, expect, test } from "bun:test";
|
|
4
4
|
import { clearInbox, getInbox, mailTransportInMemoryFeature } from "../feature";
|
|
5
5
|
|
|
6
6
|
describe("mailTransportInMemoryFeature — shape", () => {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// Plugin-registration shape is also pinned (drift-pin: name "smtp",
|
|
4
4
|
// build-fn presence).
|
|
5
5
|
|
|
6
|
-
import { describe, expect, test } from "
|
|
6
|
+
import { describe, expect, test } from "bun:test";
|
|
7
7
|
import { mailTransportSmtpFeature, SMTP_PASSWORD } from "../feature";
|
|
8
8
|
|
|
9
9
|
describe("mailTransportSmtpFeature — shape", () => {
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
// L3 dispatcher hook + resolver wiring are tested in framework-side
|
|
6
6
|
// suites; here we only verify the feature's own surface area.
|
|
7
7
|
|
|
8
|
+
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test";
|
|
8
9
|
import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
|
|
9
10
|
import { setupTestStack, type TestStack, TestUsers } from "@cosmicdrift/kumiko-framework/stack";
|
|
10
|
-
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
|
11
11
|
import { z } from "zod";
|
|
12
12
|
import { createRateLimitingFeature } from "../feature";
|
|
13
13
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
1
2
|
import type { TenantId } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
|
-
import { describe, expect, test } from "vitest";
|
|
3
3
|
import { createRendererFoundationApi } from "../api";
|
|
4
4
|
import {
|
|
5
5
|
type RendererContext,
|
|
@@ -132,7 +132,7 @@ describe("renderer-foundation :: Plugin-Selection", () => {
|
|
|
132
132
|
const api = createRendererFoundationApi([]);
|
|
133
133
|
try {
|
|
134
134
|
api.createRendererForTenant({ tenantId: TENANT, kind: "notification" });
|
|
135
|
-
|
|
135
|
+
throw new Error("expected RendererError");
|
|
136
136
|
} catch (e) {
|
|
137
137
|
expect(e).toBeInstanceOf(RendererError);
|
|
138
138
|
expect((e as RendererError).code).toBe("no_plugin_for_kind");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
1
2
|
import { defineFeature, type TenantId } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
3
|
import { setupTestStack, type TestStack } from "@cosmicdrift/kumiko-framework/stack";
|
|
3
|
-
import { afterAll, beforeAll, describe, expect, test } from "vitest";
|
|
4
4
|
import { createTemplateResolverFeature } from "../../template-resolver/feature";
|
|
5
5
|
import { createRendererFoundationApi } from "../api";
|
|
6
6
|
import { collectRendererPlugins, createRendererFoundationFeature } from "../feature";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { describe, expect, test } from "
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
2
|
import { RendererError } from "../../renderer-foundation";
|
|
3
3
|
import { adaptToFoundation } from "../feature";
|
|
4
4
|
|
|
@@ -41,7 +41,7 @@ describe("renderer-simple :: adaptToFoundation", () => {
|
|
|
41
41
|
kind: "document-pdf",
|
|
42
42
|
payload: { content: "test", contentFormat: "markdown" },
|
|
43
43
|
});
|
|
44
|
-
|
|
44
|
+
throw new Error("expected RendererError");
|
|
45
45
|
} catch (e) {
|
|
46
46
|
expect(e).toBeInstanceOf(RendererError);
|
|
47
47
|
expect((e as RendererError).code).toBe("invalid_payload");
|
|
@@ -12,16 +12,16 @@
|
|
|
12
12
|
// + FileProviderContext-shape direkt) und prueft dass beide den happy-path
|
|
13
13
|
// + den fehlt-_userId-throw durchlaufen.
|
|
14
14
|
|
|
15
|
+
import { describe, expect, mock, test } from "bun:test";
|
|
15
16
|
import { SYSTEM_USER_ID } from "@cosmicdrift/kumiko-framework/engine";
|
|
16
17
|
import type { SecretsContext } from "@cosmicdrift/kumiko-framework/secrets";
|
|
17
|
-
import { describe, expect, test, vi } from "vitest";
|
|
18
18
|
import { requireSecretsContext } from "../feature";
|
|
19
19
|
|
|
20
20
|
function makeRawSecretsContext(): SecretsContext {
|
|
21
21
|
return {
|
|
22
|
-
get:
|
|
23
|
-
set:
|
|
24
|
-
delete:
|
|
22
|
+
get: mock(),
|
|
23
|
+
set: mock(),
|
|
24
|
+
delete: mock(),
|
|
25
25
|
};
|
|
26
26
|
}
|
|
27
27
|
|
|
@@ -72,7 +72,8 @@ describe("requireSecretsContext :: FileProviderContext surface", () => {
|
|
|
72
72
|
"any-key" as unknown as Parameters<SecretsContext["get"]>[1],
|
|
73
73
|
);
|
|
74
74
|
// Erste-Aufruf-args: [tenantId, key, audit-Object]
|
|
75
|
-
|
|
75
|
+
// biome-ignore lint/suspicious/noExplicitAny: Bun mock API requires any cast
|
|
76
|
+
const audit = (raw.get as any).mock.calls[0]?.[2];
|
|
76
77
|
expect(audit).toEqual({
|
|
77
78
|
userId: SYSTEM_USER_ID,
|
|
78
79
|
handlerName: "user-data-rights:run-export-jobs",
|
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
// asserts the job bails after maxFailures instead of spraying the log
|
|
4
4
|
// with every row's identical error.
|
|
5
5
|
|
|
6
|
+
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
6
7
|
import { randomBytes } from "node:crypto";
|
|
8
|
+
import { deleteMany, insertOne, selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
7
9
|
import type { AppContext } from "@cosmicdrift/kumiko-framework/engine";
|
|
8
10
|
import {
|
|
9
11
|
createEnvMasterKeyProvider,
|
|
@@ -16,8 +18,6 @@ import {
|
|
|
16
18
|
type TestStack,
|
|
17
19
|
unsafePushTables,
|
|
18
20
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
19
|
-
import { eq, sql } from "drizzle-orm";
|
|
20
|
-
import { afterAll, beforeAll, describe, expect, test } from "vitest";
|
|
21
21
|
import { createSecretsFeature } from "../feature";
|
|
22
22
|
import { rotateJob } from "../handlers/rotate.job";
|
|
23
23
|
import { createSecretsContext } from "../secrets-context";
|
|
@@ -83,7 +83,7 @@ beforeAll(async () => {
|
|
|
83
83
|
// Seed 20 V1 rows directly — too many for any maxFailures default.
|
|
84
84
|
for (let i = 0; i < 20; i++) {
|
|
85
85
|
const envelope = await encryptValue(`secret-${i}`, seedProvider);
|
|
86
|
-
await stack.db
|
|
86
|
+
await insertOne(stack.db, tenantSecretsTable, {
|
|
87
87
|
tenantId: admin.tenantId,
|
|
88
88
|
key: `test:secret:k-${i}`,
|
|
89
89
|
envelope: {
|
|
@@ -100,7 +100,7 @@ beforeAll(async () => {
|
|
|
100
100
|
|
|
101
101
|
afterAll(async () => {
|
|
102
102
|
// Clean up the seeded fixtures so downstream suites don't see them.
|
|
103
|
-
await stack.db
|
|
103
|
+
await deleteMany(stack.db, tenantSecretsTable, { tenantId: admin.tenantId });
|
|
104
104
|
await stack.cleanup();
|
|
105
105
|
});
|
|
106
106
|
|
|
@@ -128,11 +128,8 @@ function jobCtx(provider: MasterKeyProvider): Parameters<typeof rotateJob>[1] {
|
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
async function countV1Rows(): Promise<number> {
|
|
131
|
-
const rows = await stack.db
|
|
132
|
-
|
|
133
|
-
.from(tenantSecretsTable)
|
|
134
|
-
.where(sql`${tenantSecretsTable.tenantId} = ${admin.tenantId}`);
|
|
135
|
-
return rows.filter((r) => r.kekVersion === 1).length;
|
|
131
|
+
const rows = await selectMany(stack.db, tenantSecretsTable, { tenantId: admin.tenantId });
|
|
132
|
+
return rows.filter((r: Record<string, unknown>) => r["kekVersion"] === 1).length;
|
|
136
133
|
}
|
|
137
134
|
|
|
138
135
|
describe("rotate-job circuit-breaker", () => {
|