@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
|
@@ -72,7 +72,7 @@ export function verifyAndParseStripeWebhook(
|
|
|
72
72
|
// mapped throw → HTTP 401.
|
|
73
73
|
let event: Stripe.Event;
|
|
74
74
|
try {
|
|
75
|
-
event = stripe.webhooks.
|
|
75
|
+
event = await stripe.webhooks.constructEventAsync(rawBody, sigHeader, options.webhookSecret);
|
|
76
76
|
} catch (e) {
|
|
77
77
|
const msg = e instanceof Error ? e.message : String(e);
|
|
78
78
|
throw new Error(`subscription-stripe: webhook signature verify failed — ${msg}`);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
1
2
|
import type { DbConnection } from "@cosmicdrift/kumiko-framework/db";
|
|
2
3
|
import { SYSTEM_TENANT_ID } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
4
|
import { createEventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
@@ -10,7 +11,6 @@ import {
|
|
|
10
11
|
unsafeCreateEntityTable,
|
|
11
12
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
12
13
|
import { expectErrorIncludes } from "@cosmicdrift/kumiko-framework/testing";
|
|
13
|
-
import { afterAll, beforeAll, describe, expect, test } from "vitest";
|
|
14
14
|
import { createTemplateResolverFeature } from "../feature";
|
|
15
15
|
import { TemplateResolverHandlers, TemplateResolverQueries } from "../qualified-names";
|
|
16
16
|
import { templateResourceEntity } from "../table";
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
2
|
+
import { insertOne } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
1
3
|
import type { DbConnection } from "@cosmicdrift/kumiko-framework/db";
|
|
2
4
|
import {
|
|
3
5
|
setupTestStack,
|
|
4
6
|
type TestStack,
|
|
5
7
|
unsafeCreateEntityTable,
|
|
6
8
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
7
|
-
import { afterAll, beforeAll, describe, expect, test } from "vitest";
|
|
8
9
|
import { createTemplateResolverApi, TemplateNotFoundError, type TemplateResolverApi } from "../api";
|
|
9
10
|
import {
|
|
10
11
|
type ContentFormat,
|
|
@@ -55,7 +56,7 @@ async function seedTemplate(args: {
|
|
|
55
56
|
linkedResources?: Record<string, string>;
|
|
56
57
|
parentTemplateId?: string;
|
|
57
58
|
}) {
|
|
58
|
-
await db
|
|
59
|
+
await insertOne(db, templateResourcesTable, {
|
|
59
60
|
tenantId: args.tenantId,
|
|
60
61
|
slug: args.slug,
|
|
61
62
|
kind: args.kind,
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
// runtime aus ctx.templateResolver. Pattern symmetrisch zu textContent
|
|
4
4
|
// (siehe text-content/api.ts).
|
|
5
5
|
|
|
6
|
+
import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
6
7
|
import type { DbConnection } from "@cosmicdrift/kumiko-framework/db";
|
|
7
8
|
import type { SessionUser, TenantId } from "@cosmicdrift/kumiko-framework/engine";
|
|
8
9
|
import { InternalError } from "@cosmicdrift/kumiko-framework/errors";
|
|
9
|
-
import { and, eq } from "drizzle-orm";
|
|
10
10
|
import type { ContentFormat, RenderKind } from "./constants";
|
|
11
11
|
import { FALLBACK_LOCALE, SYSTEM_TENANT_ID } from "./constants";
|
|
12
12
|
import { type TemplateResourceRow, templateResourcesTable } from "./table";
|
|
@@ -111,18 +111,12 @@ async function fetchTemplate(
|
|
|
111
111
|
kind: RenderKind,
|
|
112
112
|
locale: string,
|
|
113
113
|
): Promise<TemplateResourceRow | null> {
|
|
114
|
-
const rows = await
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
eq(templateResourcesTable["slug"], slug),
|
|
121
|
-
eq(templateResourcesTable["kind"], kind),
|
|
122
|
-
eq(templateResourcesTable["locale"], locale),
|
|
123
|
-
),
|
|
124
|
-
)
|
|
125
|
-
.limit(1);
|
|
114
|
+
const rows = await selectMany(
|
|
115
|
+
db,
|
|
116
|
+
templateResourcesTable,
|
|
117
|
+
{ tenantId, slug, kind, locale },
|
|
118
|
+
{ limit: 1 },
|
|
119
|
+
);
|
|
126
120
|
// @cast-boundary db-row — db.select returnt unbenanntes unknown[],
|
|
127
121
|
// Row-Shape ist via templateResourcesTable + buildBaseColumns garantiert.
|
|
128
122
|
return (rows[0] as TemplateResourceRow | undefined) ?? null;
|
|
@@ -1,7 +1,6 @@
|
|
|
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 { NotFoundError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
|
|
4
|
-
import { eq } from "drizzle-orm";
|
|
5
4
|
import { z } from "zod";
|
|
6
5
|
import type { TemplateResourceRow } from "../table";
|
|
7
6
|
import { templateResourcesTable } from "../table";
|
|
@@ -15,11 +14,9 @@ export const archiveWrite = defineWriteHandler({
|
|
|
15
14
|
schema: z.object({ id: z.string().min(1) }),
|
|
16
15
|
access: { roles: ["TenantAdmin", "SystemAdmin"] },
|
|
17
16
|
handler: async (event, ctx) => {
|
|
18
|
-
const existing = await fetchOne<TemplateResourceRow>(
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
eq(templateResourcesTable["id"], event.payload.id),
|
|
22
|
-
);
|
|
17
|
+
const existing = await fetchOne<TemplateResourceRow>(ctx.db, templateResourcesTable, {
|
|
18
|
+
id: event.payload.id,
|
|
19
|
+
});
|
|
23
20
|
// ctx.db ist via createTenantDb tenant-scoped — existing ist null wenn
|
|
24
21
|
// das Template einem fremden Tenant gehört (SystemAdmin-Cross-Tenant
|
|
25
22
|
// braucht tenantIdOverride im Schema, M2-Erweiterung).
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { fetchOne } from "@cosmicdrift/kumiko-framework/db";
|
|
1
|
+
import { fetchOne } 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 { type TemplateResourceRow, templateResourcesTable } from "../table";
|
|
6
5
|
|
|
@@ -14,11 +13,9 @@ export const findByIdQuery = defineQueryHandler({
|
|
|
14
13
|
schema: z.object({ id: z.string().min(1) }),
|
|
15
14
|
access: { roles: ["TenantAdmin", "SystemAdmin", "User"] },
|
|
16
15
|
handler: async (query, ctx) => {
|
|
17
|
-
const row = await fetchOne<TemplateResourceRow>(
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
eq(templateResourcesTable["id"], query.payload.id),
|
|
21
|
-
);
|
|
16
|
+
const row = await fetchOne<TemplateResourceRow>(ctx.db, templateResourcesTable, {
|
|
17
|
+
id: query.payload.id,
|
|
18
|
+
});
|
|
22
19
|
if (!row) return null;
|
|
23
20
|
const isSystemAdmin = query.user.roles.includes("SystemAdmin");
|
|
24
21
|
const isOwnTenant = row.tenantId === query.user.tenantId;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
1
2
|
import { defineQueryHandler, SYSTEM_TENANT_ID } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
|
-
import { and, eq, or, type SQL } from "drizzle-orm";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { RENDER_KINDS, TEMPLATE_STATUSES } from "../constants";
|
|
5
5
|
import { type TemplateResourceRow, templateResourcesTable } from "../table";
|
|
@@ -18,43 +18,35 @@ export const listQuery = defineQueryHandler({
|
|
|
18
18
|
access: { roles: ["TenantAdmin", "SystemAdmin", "User"] },
|
|
19
19
|
handler: async (query, ctx) => {
|
|
20
20
|
const isSystemAdmin = query.user.roles.includes("SystemAdmin");
|
|
21
|
-
const
|
|
21
|
+
const where: Record<string, unknown> = {};
|
|
22
22
|
|
|
23
23
|
// Tenant-Scope: SystemAdmin sieht alles, andere nur eigener Tenant + System
|
|
24
24
|
if (!isSystemAdmin) {
|
|
25
25
|
if (query.payload.includeSystem) {
|
|
26
|
-
|
|
27
|
-
eq(templateResourcesTable["tenantId"], query.user.tenantId),
|
|
28
|
-
eq(templateResourcesTable["tenantId"], SYSTEM_TENANT_ID),
|
|
29
|
-
);
|
|
30
|
-
if (scopeCondition) conditions.push(scopeCondition);
|
|
26
|
+
where["tenantId"] = [query.user.tenantId, SYSTEM_TENANT_ID];
|
|
31
27
|
} else {
|
|
32
|
-
|
|
28
|
+
where["tenantId"] = query.user.tenantId;
|
|
33
29
|
}
|
|
34
30
|
} else if (!query.payload.includeSystem) {
|
|
35
|
-
// SystemAdmin mit includeSystem=false →
|
|
36
|
-
|
|
31
|
+
// SystemAdmin mit includeSystem=false → nur eigener Tenant
|
|
32
|
+
where["tenantId"] = query.user.tenantId;
|
|
37
33
|
}
|
|
38
34
|
|
|
39
35
|
if (query.payload.kind) {
|
|
40
|
-
|
|
36
|
+
where["kind"] = query.payload.kind;
|
|
41
37
|
}
|
|
42
38
|
if (query.payload.locale) {
|
|
43
|
-
|
|
39
|
+
where["locale"] = query.payload.locale;
|
|
44
40
|
}
|
|
45
41
|
if (query.payload.status) {
|
|
46
|
-
|
|
42
|
+
where["status"] = query.payload.status;
|
|
47
43
|
}
|
|
48
44
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
// @cast-boundary db-row — db.select returnt unknown[]; Row-Shape ist
|
|
45
|
+
// @cast-boundary db-row — selectMany returnt unknown[]; Row-Shape ist
|
|
52
46
|
// durch templateResourcesTable + buildBaseColumns garantiert.
|
|
53
|
-
const rows = (await ctx.db
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
.where(whereExpr)
|
|
57
|
-
.limit(500)) as TemplateResourceRow[];
|
|
47
|
+
const rows = (await selectMany(ctx.db, templateResourcesTable, where, {
|
|
48
|
+
limit: 500,
|
|
49
|
+
})) as TemplateResourceRow[];
|
|
58
50
|
|
|
59
51
|
return rows.map((row) => ({
|
|
60
52
|
id: String(row.id),
|
|
@@ -1,7 +1,6 @@
|
|
|
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 { NotFoundError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
|
|
4
|
-
import { eq } from "drizzle-orm";
|
|
5
4
|
import { z } from "zod";
|
|
6
5
|
import type { TemplateResourceRow } from "../table";
|
|
7
6
|
import { templateResourcesTable } from "../table";
|
|
@@ -18,11 +17,9 @@ export const publishWrite = defineWriteHandler({
|
|
|
18
17
|
schema: z.object({ id: z.string().min(1) }),
|
|
19
18
|
access: { roles: ["TenantAdmin", "SystemAdmin"] },
|
|
20
19
|
handler: async (event, ctx) => {
|
|
21
|
-
const existing = await fetchOne<TemplateResourceRow>(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
eq(templateResourcesTable["id"], event.payload.id),
|
|
25
|
-
);
|
|
20
|
+
const existing = await fetchOne<TemplateResourceRow>(ctx.db, templateResourcesTable, {
|
|
21
|
+
id: event.payload.id,
|
|
22
|
+
});
|
|
26
23
|
// ctx.db ist via createTenantDb tenant-scoped — existing ist null wenn
|
|
27
24
|
// das Template einem fremden Tenant gehört (SystemAdmin-Cross-Tenant
|
|
28
25
|
// braucht tenantIdOverride im Schema, M2-Erweiterung).
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { fetchOne } from "@cosmicdrift/kumiko-framework/db";
|
|
1
|
+
import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
2
2
|
import {
|
|
3
3
|
defineWriteHandler,
|
|
4
4
|
SYSTEM_TENANT_ID,
|
|
5
5
|
type TenantId,
|
|
6
6
|
} from "@cosmicdrift/kumiko-framework/engine";
|
|
7
|
-
import { eq } from "drizzle-orm";
|
|
8
7
|
import type { TemplateResourceRow } from "../table";
|
|
9
8
|
import { templateResourcesTable } from "../table";
|
|
10
9
|
import { executor, upsertPayloadSchema } from "./shared";
|
|
@@ -27,14 +26,12 @@ export const upsertSystemWrite = defineWriteHandler({
|
|
|
27
26
|
// Pattern symmetrisch zu text-content setWrite Override-Branch.
|
|
28
27
|
const executorUser = { ...event.user, tenantId };
|
|
29
28
|
|
|
30
|
-
const existing = await fetchOne<TemplateResourceRow>(
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
eq(templateResourcesTable["locale"], event.payload.locale),
|
|
37
|
-
);
|
|
29
|
+
const existing = await fetchOne<TemplateResourceRow>(db, templateResourcesTable, {
|
|
30
|
+
tenantId,
|
|
31
|
+
slug: event.payload.slug,
|
|
32
|
+
kind: event.payload.kind,
|
|
33
|
+
locale: event.payload.locale,
|
|
34
|
+
});
|
|
38
35
|
|
|
39
36
|
const fields = {
|
|
40
37
|
slug: event.payload.slug,
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { fetchOne } from "@cosmicdrift/kumiko-framework/db";
|
|
1
|
+
import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
2
2
|
import {
|
|
3
3
|
defineWriteHandler,
|
|
4
4
|
SYSTEM_TENANT_ID,
|
|
5
5
|
type TenantId,
|
|
6
6
|
} from "@cosmicdrift/kumiko-framework/engine";
|
|
7
7
|
import { AccessDeniedError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
|
|
8
|
-
import { eq } from "drizzle-orm";
|
|
9
8
|
import { z } from "zod";
|
|
10
9
|
import type { TemplateResourceRow } from "../table";
|
|
11
10
|
import { templateResourcesTable } from "../table";
|
|
@@ -52,14 +51,12 @@ export const upsertTenantWrite = defineWriteHandler({
|
|
|
52
51
|
const tenantId = (override ?? event.user.tenantId) as TenantId;
|
|
53
52
|
const executorUser = override !== undefined ? { ...event.user, tenantId } : event.user;
|
|
54
53
|
|
|
55
|
-
const existing = await fetchOne<TemplateResourceRow>(
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
eq(templateResourcesTable["locale"], event.payload.locale),
|
|
62
|
-
);
|
|
54
|
+
const existing = await fetchOne<TemplateResourceRow>(db, templateResourcesTable, {
|
|
55
|
+
tenantId,
|
|
56
|
+
slug: event.payload.slug,
|
|
57
|
+
kind: event.payload.kind,
|
|
58
|
+
locale: event.payload.locale,
|
|
59
|
+
});
|
|
63
60
|
|
|
64
61
|
const fields = {
|
|
65
62
|
slug: event.payload.slug,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { buildEntityTable } from "@cosmicdrift/kumiko-framework/db";
|
|
2
2
|
import {
|
|
3
3
|
createEntity,
|
|
4
4
|
createLongTextField,
|
|
@@ -40,10 +40,7 @@ export const templateResourceEntity = createEntity({
|
|
|
40
40
|
],
|
|
41
41
|
});
|
|
42
42
|
|
|
43
|
-
export const templateResourcesTable =
|
|
44
|
-
"template-resource",
|
|
45
|
-
templateResourceEntity,
|
|
46
|
-
);
|
|
43
|
+
export const templateResourcesTable = buildEntityTable("template-resource", templateResourceEntity);
|
|
47
44
|
|
|
48
45
|
// Concrete Row-Type — single-source dafür dass die unknown-Werte die
|
|
49
46
|
// Drizzle aus `Record<string, unknown>` liefert genau einmal benannt
|
|
@@ -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 { createTenantDb, type DbConnection } from "@cosmicdrift/kumiko-framework/db";
|
|
3
4
|
import {
|
|
@@ -21,7 +22,6 @@ import {
|
|
|
21
22
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
22
23
|
import { bridgeStub, sleep } from "@cosmicdrift/kumiko-framework/testing";
|
|
23
24
|
import type { Hono } from "hono";
|
|
24
|
-
import { afterAll, beforeAll, describe, expect, test } from "vitest";
|
|
25
25
|
import { createConfigFeature } from "../../config/feature";
|
|
26
26
|
import { createConfigResolver } from "../../config/resolver";
|
|
27
27
|
import { configValuesTable } from "../../config/table";
|
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
// 4. The `by`-user shows up as insertedById on the projection — so
|
|
12
12
|
// audit-queries that join events→users actually find the actor.
|
|
13
13
|
|
|
14
|
+
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test";
|
|
15
|
+
import { asRawClient, selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
14
16
|
import type { TenantId } from "@cosmicdrift/kumiko-framework/engine";
|
|
15
17
|
import { createEventsTable, eventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
16
18
|
import {
|
|
@@ -21,8 +23,6 @@ import {
|
|
|
21
23
|
unsafeCreateEntityTable,
|
|
22
24
|
unsafePushTables,
|
|
23
25
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
24
|
-
import { and, eq } from "drizzle-orm";
|
|
25
|
-
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
|
26
26
|
import { createConfigFeature } from "../../config/feature";
|
|
27
27
|
import { createConfigResolver } from "../../config/resolver";
|
|
28
28
|
import { configValuesTable } from "../../config/table";
|
|
@@ -53,11 +53,11 @@ afterAll(async () => {
|
|
|
53
53
|
});
|
|
54
54
|
|
|
55
55
|
beforeEach(async () => {
|
|
56
|
-
await stack.db.
|
|
57
|
-
await stack.db.
|
|
56
|
+
await asRawClient(stack.db).unsafe(`DELETE FROM "${tenantMembershipsTable.tableName}"`);
|
|
57
|
+
await asRawClient(stack.db).unsafe(`DELETE FROM "${tenantTable.tableName}"`);
|
|
58
58
|
// Events stay — the idempotency test below inspects how many .created
|
|
59
59
|
// events exist for the same aggregate-key pair across runs.
|
|
60
|
-
await stack.db.
|
|
60
|
+
await asRawClient(stack.db).unsafe(`DELETE FROM "${eventsTable.tableName}"`);
|
|
61
61
|
});
|
|
62
62
|
|
|
63
63
|
describe("seedTenant", () => {
|
|
@@ -69,7 +69,7 @@ describe("seedTenant", () => {
|
|
|
69
69
|
});
|
|
70
70
|
expect(id).toBe(TENANT_A);
|
|
71
71
|
|
|
72
|
-
const rows = await stack.db
|
|
72
|
+
const rows = await selectMany(stack.db, tenantTable, { id: TENANT_A });
|
|
73
73
|
expect(rows).toHaveLength(1);
|
|
74
74
|
expect(rows[0]?.["id"]).toBe(TENANT_A);
|
|
75
75
|
expect(rows[0]?.["key"]).toBe("tenant-a");
|
|
@@ -78,10 +78,7 @@ describe("seedTenant", () => {
|
|
|
78
78
|
|
|
79
79
|
test("emittiert tenant.created-Event auf den Aggregate-Stream", async () => {
|
|
80
80
|
await seedTenant(stack.db, { id: TENANT_A, key: "tenant-a", name: "Tenant A" });
|
|
81
|
-
const events = await stack.db
|
|
82
|
-
.select()
|
|
83
|
-
.from(eventsTable)
|
|
84
|
-
.where(eq(eventsTable.aggregateType, "tenant"));
|
|
81
|
+
const events = await selectMany(stack.db, eventsTable, { aggregateType: "tenant" });
|
|
85
82
|
const createdEvents = events.filter((e) => e.type === "tenant.created");
|
|
86
83
|
expect(createdEvents).toHaveLength(1);
|
|
87
84
|
// Aggregate-id steht im event-row (aggregateId), nicht im payload —
|
|
@@ -97,21 +94,18 @@ describe("seedTenant", () => {
|
|
|
97
94
|
await seedTenant(stack.db, { id: TENANT_A, key: "tenant-a", name: "Tenant A v2" });
|
|
98
95
|
|
|
99
96
|
// Projection bleibt bei Original-name (zweiter Call wurde geskippt, kein update).
|
|
100
|
-
const rows = await stack.db
|
|
97
|
+
const rows = await selectMany(stack.db, tenantTable, { id: TENANT_A });
|
|
101
98
|
expect(rows).toHaveLength(1);
|
|
102
99
|
expect(rows[0]?.["name"]).toBe("Tenant A");
|
|
103
100
|
|
|
104
|
-
const events = await stack.db
|
|
105
|
-
.select()
|
|
106
|
-
.from(eventsTable)
|
|
107
|
-
.where(eq(eventsTable.aggregateType, "tenant"));
|
|
101
|
+
const events = await selectMany(stack.db, eventsTable, { aggregateType: "tenant" });
|
|
108
102
|
expect(events.filter((e) => e.type === "tenant.created")).toHaveLength(1);
|
|
109
103
|
});
|
|
110
104
|
|
|
111
105
|
test("zwei verschiedene Tenants in einem Test — beide in der Projection", async () => {
|
|
112
106
|
await seedTenant(stack.db, { id: TENANT_A, key: "a", name: "A" });
|
|
113
107
|
await seedTenant(stack.db, { id: TENANT_B, key: "b", name: "B" });
|
|
114
|
-
const rows = await stack.db
|
|
108
|
+
const rows = await selectMany(stack.db, tenantTable);
|
|
115
109
|
expect(rows.map((r) => r["id"]).sort()).toEqual([TENANT_A, TENANT_B].sort());
|
|
116
110
|
});
|
|
117
111
|
});
|
|
@@ -124,15 +118,10 @@ describe("seedTenantMembership", () => {
|
|
|
124
118
|
roles: ["Admin", "Billing"],
|
|
125
119
|
});
|
|
126
120
|
|
|
127
|
-
const rows = await stack.db
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
and(
|
|
132
|
-
eq(tenantMembershipsTable.userId, ALICE_ID),
|
|
133
|
-
eq(tenantMembershipsTable.tenantId, TENANT_A),
|
|
134
|
-
),
|
|
135
|
-
);
|
|
121
|
+
const rows = await selectMany(stack.db, tenantMembershipsTable, {
|
|
122
|
+
userId: ALICE_ID,
|
|
123
|
+
tenantId: TENANT_A,
|
|
124
|
+
});
|
|
136
125
|
expect(rows).toHaveLength(1);
|
|
137
126
|
expect(rows[0]?.["userId"]).toBe(ALICE_ID);
|
|
138
127
|
expect(rows[0]?.["tenantId"]).toBe(TENANT_A);
|
|
@@ -146,10 +135,7 @@ describe("seedTenantMembership", () => {
|
|
|
146
135
|
roles: ["User"],
|
|
147
136
|
});
|
|
148
137
|
|
|
149
|
-
const events = await stack.db
|
|
150
|
-
.select()
|
|
151
|
-
.from(eventsTable)
|
|
152
|
-
.where(eq(eventsTable.aggregateType, "tenant-membership"));
|
|
138
|
+
const events = await selectMany(stack.db, eventsTable, { aggregateType: "tenant-membership" });
|
|
153
139
|
const createdEvents = events.filter((e) => e.type === "tenant-membership.created");
|
|
154
140
|
expect(createdEvents).toHaveLength(1);
|
|
155
141
|
// Payload should carry the seeded data — MSPs/audit rely on this.
|
|
@@ -180,16 +166,10 @@ describe("seedTenantMembership", () => {
|
|
|
180
166
|
roles: ["User"],
|
|
181
167
|
});
|
|
182
168
|
|
|
183
|
-
const projectionRows = await stack.db
|
|
184
|
-
.select()
|
|
185
|
-
.from(tenantMembershipsTable)
|
|
186
|
-
.where(eq(tenantMembershipsTable.userId, ALICE_ID));
|
|
169
|
+
const projectionRows = await selectMany(stack.db, tenantMembershipsTable, { userId: ALICE_ID });
|
|
187
170
|
expect(projectionRows).toHaveLength(1);
|
|
188
171
|
|
|
189
|
-
const events = await stack.db
|
|
190
|
-
.select()
|
|
191
|
-
.from(eventsTable)
|
|
192
|
-
.where(eq(eventsTable.aggregateType, "tenant-membership"));
|
|
172
|
+
const events = await selectMany(stack.db, eventsTable, { aggregateType: "tenant-membership" });
|
|
193
173
|
expect(events.filter((e) => e.type === "tenant-membership.created")).toHaveLength(1);
|
|
194
174
|
});
|
|
195
175
|
|
|
@@ -205,10 +185,7 @@ describe("seedTenantMembership", () => {
|
|
|
205
185
|
by: seedActor,
|
|
206
186
|
});
|
|
207
187
|
|
|
208
|
-
const [row] = await stack.db
|
|
209
|
-
.select()
|
|
210
|
-
.from(tenantMembershipsTable)
|
|
211
|
-
.where(eq(tenantMembershipsTable.userId, ALICE_ID));
|
|
188
|
+
const [row] = await selectMany(stack.db, tenantMembershipsTable, { userId: ALICE_ID });
|
|
212
189
|
expect(row?.["insertedById"]).toBe(seedActor.id);
|
|
213
190
|
});
|
|
214
191
|
|
|
@@ -220,10 +197,7 @@ describe("seedTenantMembership", () => {
|
|
|
220
197
|
tenantId: TENANT_A,
|
|
221
198
|
roles: ["User"],
|
|
222
199
|
});
|
|
223
|
-
const [row] = await stack.db
|
|
224
|
-
.select()
|
|
225
|
-
.from(tenantMembershipsTable)
|
|
226
|
-
.where(eq(tenantMembershipsTable.userId, ALICE_ID));
|
|
200
|
+
const [row] = await selectMany(stack.db, tenantMembershipsTable, { userId: ALICE_ID });
|
|
227
201
|
expect(row?.["insertedById"]).toBe(TestUsers.systemAdmin.id);
|
|
228
202
|
});
|
|
229
203
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
1
2
|
import { randomBytes } from "node:crypto";
|
|
2
3
|
import { createEncryptionProvider, type DbConnection } from "@cosmicdrift/kumiko-framework/db";
|
|
3
4
|
import { createEventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
@@ -10,7 +11,6 @@ import {
|
|
|
10
11
|
unsafePushTables,
|
|
11
12
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
12
13
|
import { expectErrorIncludes, rolesOf } from "@cosmicdrift/kumiko-framework/testing";
|
|
13
|
-
import { afterAll, beforeAll, describe, expect, test } from "vitest";
|
|
14
14
|
import { createConfigAccessor, createConfigFeature } from "../../config";
|
|
15
15
|
import { ConfigHandlers, ConfigQueries } from "../../config/constants";
|
|
16
16
|
import { type ConfigResolver, createConfigResolver } from "../../config/resolver";
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
2
2
|
import { defineQueryHandler, SYSTEM_ROLE } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
|
-
import { eq } from "drizzle-orm";
|
|
4
3
|
import { z } from "zod";
|
|
5
4
|
import { tenantTable } from "../schema/tenant";
|
|
6
5
|
|
|
@@ -9,11 +8,7 @@ export const activeTenantIdsQuery = defineQueryHandler({
|
|
|
9
8
|
schema: z.object({}),
|
|
10
9
|
access: { roles: [SYSTEM_ROLE, "SystemAdmin"] },
|
|
11
10
|
handler: async (_query, ctx) => {
|
|
12
|
-
const rows = await ctx.db
|
|
13
|
-
|
|
14
|
-
.from(tenantTable)
|
|
15
|
-
.where(eq(tenantTable["isEnabled"], true));
|
|
16
|
-
|
|
17
|
-
return rows.map((row) => (row as DbRow)["id"] as number); // @cast-boundary db-row
|
|
11
|
+
const rows = await selectMany<{ id: number }>(ctx.db, tenantTable, { isEnabled: true });
|
|
12
|
+
return rows.map((r) => r.id);
|
|
18
13
|
},
|
|
19
14
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
2
|
+
import { createEventStoreExecutor } from "@cosmicdrift/kumiko-framework/db";
|
|
2
3
|
import { defineWriteHandler } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
4
|
import { ConflictError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
|
|
4
|
-
import { eq } from "drizzle-orm";
|
|
5
5
|
import { z } from "zod";
|
|
6
6
|
import { TenantErrors } from "../constants";
|
|
7
7
|
import { tenantMembershipEntity, tenantMembershipsTable } from "../membership-table";
|
|
@@ -20,12 +20,10 @@ export const addMemberWrite = defineWriteHandler({
|
|
|
20
20
|
access: { roles: ["SystemAdmin"] },
|
|
21
21
|
handler: async (event, ctx) => {
|
|
22
22
|
const db = ctx.db;
|
|
23
|
-
const existing = await fetchOne(
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
eq(tenantMembershipsTable.tenantId, event.payload.tenantId),
|
|
28
|
-
);
|
|
23
|
+
const existing = await fetchOne(db, tenantMembershipsTable, {
|
|
24
|
+
userId: event.payload.userId,
|
|
25
|
+
tenantId: event.payload.tenantId,
|
|
26
|
+
});
|
|
29
27
|
if (existing) {
|
|
30
28
|
return writeFailure(
|
|
31
29
|
new ConflictError({
|
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
// invitation = no-op + 200. Cancellen einer non-existent invitation
|
|
11
11
|
// = invitation_not_found.
|
|
12
12
|
|
|
13
|
-
import {
|
|
13
|
+
import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
14
|
+
import { createEventStoreExecutor } from "@cosmicdrift/kumiko-framework/db";
|
|
14
15
|
import { defineWriteHandler } from "@cosmicdrift/kumiko-framework/engine";
|
|
15
16
|
import { NotFoundError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
|
|
16
|
-
import { eq } from "drizzle-orm";
|
|
17
17
|
import { z } from "zod";
|
|
18
18
|
// kumiko-lint-ignore cross-feature-import cancel needs invite-token-store für Redis-cleanup
|
|
19
19
|
import {
|
|
@@ -39,11 +39,9 @@ export const cancelInvitationWrite = defineWriteHandler({
|
|
|
39
39
|
schema: CancelInvitationSchema,
|
|
40
40
|
access: { roles: ["Admin"] },
|
|
41
41
|
handler: async (event, ctx) => {
|
|
42
|
-
const invitation = await fetchOne(
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
eq(tenantInvitationsTable.id, event.payload.invitationId),
|
|
46
|
-
);
|
|
42
|
+
const invitation = await fetchOne(ctx.db.raw, tenantInvitationsTable, {
|
|
43
|
+
id: event.payload.invitationId,
|
|
44
|
+
});
|
|
47
45
|
if (!invitation || invitation["tenantId"] !== event.user.tenantId) {
|
|
48
46
|
return writeFailure(
|
|
49
47
|
new NotFoundError("tenantInvitation", event.payload.invitationId, {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
1
2
|
import { defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
|
-
import { and, eq } from "drizzle-orm";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { INVITATION_STATUS, tenantInvitationsTable } from "../invitation-table";
|
|
5
5
|
|
|
@@ -17,15 +17,10 @@ export const invitationsQuery = defineQueryHandler({
|
|
|
17
17
|
schema: z.object({}),
|
|
18
18
|
access: { roles: ["Admin", "SystemAdmin"] },
|
|
19
19
|
handler: async (query, ctx) => {
|
|
20
|
-
const rows = await ctx.db
|
|
21
|
-
|
|
22
|
-
.
|
|
23
|
-
|
|
24
|
-
and(
|
|
25
|
-
eq(tenantInvitationsTable.tenantId, query.user.tenantId),
|
|
26
|
-
eq(tenantInvitationsTable.status, INVITATION_STATUS.pending),
|
|
27
|
-
),
|
|
28
|
-
);
|
|
20
|
+
const rows = await selectMany(ctx.db, tenantInvitationsTable, {
|
|
21
|
+
tenantId: query.user.tenantId,
|
|
22
|
+
status: INVITATION_STATUS.pending,
|
|
23
|
+
});
|
|
29
24
|
return rows ?? [];
|
|
30
25
|
},
|
|
31
26
|
});
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { fetchOne } from "@cosmicdrift/kumiko-framework/db";
|
|
1
|
+
import { fetchOne } 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 { tenantTable } from "../schema/tenant";
|
|
6
5
|
|
|
@@ -11,7 +10,7 @@ export const meQuery = defineQueryHandler({
|
|
|
11
10
|
schema: z.object({}),
|
|
12
11
|
access: { openToAll: true },
|
|
13
12
|
handler: async (query, ctx) => {
|
|
14
|
-
const row = await fetchOne(ctx.db, tenantTable,
|
|
13
|
+
const row = await fetchOne(ctx.db, tenantTable, { id: query.user.tenantId });
|
|
15
14
|
return row ?? null;
|
|
16
15
|
},
|
|
17
16
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
1
2
|
import { defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
3
|
import { parseRoles } from "@cosmicdrift/kumiko-framework/utils";
|
|
3
|
-
import { eq } from "drizzle-orm";
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
import { tenantMembershipsTable } from "../membership-table";
|
|
6
6
|
|
|
@@ -9,10 +9,9 @@ export const membersQuery = defineQueryHandler({
|
|
|
9
9
|
schema: z.object({}),
|
|
10
10
|
access: { roles: ["Admin", "SystemAdmin"] },
|
|
11
11
|
handler: async (query, ctx) => {
|
|
12
|
-
const rows = await ctx.db
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
.where(eq(tenantMembershipsTable.tenantId, query.user.tenantId));
|
|
12
|
+
const rows = await selectMany(ctx.db, tenantMembershipsTable, {
|
|
13
|
+
tenantId: query.user.tenantId,
|
|
14
|
+
});
|
|
16
15
|
|
|
17
16
|
return rows.map((row) => ({
|
|
18
17
|
...row,
|