@cosmicdrift/kumiko-framework 0.367.0 → 0.369.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/AGENTS.md +1 -7
- package/README.md +1 -1
- package/agents/examples/access-control.md +2 -2
- package/agents/examples/anonymous-access-multitenant.md +2 -2
- package/agents/examples/anonymous-access.md +3 -3
- package/agents/examples/apex-landing.md +1 -1
- package/agents/examples/apex-surface-auth.md +6 -7
- package/agents/examples/api-worker-split.md +7 -8
- package/agents/examples/auth-claims.md +2 -1
- package/agents/examples/auth-foundation-providers.md +3 -3
- package/agents/examples/auth-mfa.md +3 -4
- package/agents/examples/basic-entity.md +3 -4
- package/agents/examples/chat-channels.md +4 -4
- package/agents/examples/compliance-profiles-demo.md +2 -3
- package/agents/examples/cross-feature-events.md +4 -4
- package/agents/examples/crypto-shredding-hr.md +14 -9
- package/agents/examples/currencies-global.md +3 -4
- package/agents/examples/currencies-per-tenant.md +3 -4
- package/agents/examples/custom-fields-basic.md +2 -3
- package/agents/examples/custom-handlers.md +3 -5
- package/agents/examples/dashboard-stats.md +2 -3
- package/agents/examples/delivery-notifications.md +5 -6
- package/agents/examples/e2e-generator.md +1 -1
- package/agents/examples/embedded-entity-form.md +2 -3
- package/agents/examples/embedded.md +2 -3
- package/agents/examples/encrypted-tenant-config.md +5 -6
- package/agents/examples/error-contract.md +3 -4
- package/agents/examples/event-sourcing.md +19 -23
- package/agents/examples/feature-toggles.md +4 -4
- package/agents/examples/field-access.md +3 -4
- package/agents/examples/files-post-processing.md +12 -13
- package/agents/examples/golden-path.md +208 -0
- package/agents/examples/idempotency.md +2 -2
- package/agents/examples/inbound-mail-triage.md +7 -7
- package/agents/examples/lane-routing.md +3 -3
- package/agents/examples/ledger-banking.md +2 -3
- package/agents/examples/ledger-invoicing.md +2 -3
- package/agents/examples/legal-pages.md +1 -1
- package/agents/examples/lifecycle-hooks.md +3 -3
- package/agents/examples/managed-config.md +3 -4
- package/agents/examples/managed-pages.md +2 -2
- package/agents/examples/notes-history-basic.md +4 -5
- package/agents/examples/ownership.md +3 -5
- package/agents/examples/pdf-audit-export.md +2 -3
- package/agents/examples/pipeline-basics.md +2 -2
- package/agents/examples/public-share-token.md +3 -3
- package/agents/examples/rate-limiting.md +2 -1
- package/agents/examples/realtime-sse.md +2 -3
- package/agents/examples/record-detail-layout.md +1 -1
- package/agents/examples/reference-data.md +3 -3
- package/agents/examples/relations.md +2 -2
- package/agents/examples/screens-nav.md +1 -1
- package/agents/examples/search.md +2 -2
- package/agents/examples/secrets-demo.md +8 -8
- package/agents/examples/security-baseline.md +2 -2
- package/agents/examples/session-revocation.md +7 -8
- package/agents/examples/state-machine.md +181 -165
- package/agents/examples/tags-basic.md +2 -3
- package/agents/examples/tenant-isolation.md +2 -3
- package/agents/examples/tenant-settings.md +2 -2
- package/agents/examples/tier-admin.md +3 -4
- package/agents/examples/timezones.md +3 -3
- package/agents/examples/user-data-rights.md +12 -8
- package/agents/examples/user-profile.md +3 -3
- package/agents/examples/webhook-step.md +2 -3
- package/agents/examples/wizard-form.md +4 -5
- package/agents/examples/workflow-engine.md +7 -3
- package/agents/examples/writeform-section.md +1 -1
- package/agents/examples.md +1 -0
- package/agents/features.md +4 -4
- package/dist/consumer-cli.js +2 -3
- package/dist/crypto/index.d.ts +1 -1
- package/dist/crypto/index.js +1 -1
- package/dist/crypto/owner-transition-rekey.js +2 -0
- package/dist/crypto/pg-kms-adapter.js +1 -1
- package/dist/crypto/subject-resolver.d.ts +2 -0
- package/dist/crypto/subject-resolver.js +30 -15
- package/dist/db/bun-db-deprecated.d.ts +10 -0
- package/dist/{bun-db/index.js → db/bun-db-deprecated.js} +4 -3
- package/dist/db/config-seed.js +1 -1
- package/dist/db/connection.d.ts +23 -5
- package/dist/db/connection.js +10 -5
- package/dist/db/dialect.js +1 -1
- package/dist/db/entity-field-encryption.d.ts +5 -0
- package/dist/db/entity-field-encryption.js +29 -0
- package/dist/db/entity-table-meta.js +6 -5
- package/dist/db/event-store-executor-read.js +26 -5
- package/dist/db/index.d.ts +4 -4
- package/dist/db/index.js +1 -1
- package/dist/db/migrate-runner.js +1 -1
- package/dist/db/queries/backfill-pii.js +16 -9
- package/dist/db/queries/ddl.js +1 -1
- package/dist/db/queries/event-store.d.ts +2 -0
- package/dist/db/queries/event-store.js +26 -0
- package/dist/db/queries/test-stack.js +1 -1
- package/dist/db/query.d.ts +105 -1
- package/dist/db/query.js +1450 -3
- package/dist/{stack/table-helpers.d.ts → db/table-push.d.ts} +5 -15
- package/dist/{stack/table-helpers.js → db/table-push.js} +6 -46
- package/dist/db/tenant-db.d.ts +11 -0
- package/dist/db/tenant-db.js +51 -12
- package/dist/derivatives/derivatives-context.d.ts +1 -1
- package/dist/derivatives/derivatives-context.js +1 -1
- package/dist/engine/boot-validator/gdpr-storage.js +3 -3
- package/dist/engine/boot-validator/pii-retention.js +3 -3
- package/dist/engine/boot-validator/record-owned.js +3 -3
- package/dist/engine/boot-validator/screens.js +37 -1
- package/dist/engine/bridge-stub.d.ts +4 -0
- package/dist/engine/bridge-stub.js +62 -0
- package/dist/engine/build-config-feature-schema.js +197 -65
- package/dist/engine/event-helpers.d.ts +2 -1
- package/dist/engine/event-helpers.js +1 -0
- package/dist/engine/extension-selector-plugins.d.ts +3 -0
- package/dist/engine/extension-selector-plugins.js +14 -0
- package/dist/engine/feature-config-events-jobs.d.ts +2 -0
- package/dist/engine/feature-config-events-jobs.js +3 -2
- package/dist/engine/index.d.ts +1 -0
- package/dist/engine/index.js +1 -0
- package/dist/es-ops/operations-schema.js +1 -1
- package/dist/event-store/admin-api.js +1 -1
- package/dist/event-store/archive.js +1 -1
- package/dist/event-store/errors.d.ts +2 -1
- package/dist/event-store/errors.js +6 -2
- package/dist/event-store/event-store.js +17 -9
- package/dist/event-store/events-schema.js +1 -1
- package/dist/event-store/rebuild-dead-letter.js +3 -3
- package/dist/event-store/snapshot.js +1 -1
- package/dist/event-store/upcaster-dead-letter.js +3 -3
- package/dist/files/create-file-ref-from-bytes.js +1 -1
- package/dist/files/file-routes.js +1 -1
- package/dist/i18n/settings-hub-keys.js +1 -2
- package/dist/internal/stack-support.d.ts +12 -0
- package/dist/internal/stack-support.js +12 -0
- package/dist/internal/testing.d.ts +4 -0
- package/dist/internal/testing.js +5 -0
- package/dist/jobs/job-runner.js +23 -11
- package/dist/migrations/pending-rebuilds.js +1 -1
- package/dist/migrations/pii-event-backfill.js +2 -2
- package/dist/pipeline/dispatch-shared.js +43 -23
- package/dist/pipeline/dispatch-write.js +6 -2
- package/dist/pipeline/dispatcher-utils.js +6 -2
- package/dist/pipeline/event-consumer-state.js +1 -1
- package/dist/pipeline/projection-rebuild.d.ts +1 -0
- package/dist/pipeline/projection-rebuild.js +1 -1
- package/dist/pipeline/projection-state.js +1 -1
- package/dist/pipeline/system-hooks.js +1 -1
- package/dist/schema-cli.js +3 -3
- package/dist/search/purge-subject.js +20 -10
- package/dist/seeding/index.d.ts +1 -0
- package/dist/seeding/index.js +1 -0
- package/dist/stack/index.d.ts +10 -9
- package/dist/stack/index.js +11 -19
- package/dist/testing/e2e-generator.d.ts +5 -49
- package/dist/testing/e2e-generator.js +5 -382
- package/dist/testing/handler-context.d.ts +5 -4
- package/dist/testing/handler-context.js +5 -69
- package/dist/testing/index.d.ts +10 -26
- package/dist/testing/index.js +10 -34
- package/dist/testing/real-providers.d.ts +5 -3
- package/dist/testing/real-providers.js +5 -21
- package/dist/upgrade-cli.js +6 -4
- package/package.json +37 -9
- package/src/changes.json +64 -0
- package/src/scripts/codemod/README.md +43 -0
- package/src/scripts/codemod/codemod-support.ts +276 -0
- package/src/scripts/codemod/db-factory.ts +810 -0
- package/src/scripts/codemod/feature-factory.ts +429 -0
- package/src/scripts/codemod/s3-imports.ts +274 -0
- package/src/scripts/codemod/tenant-db-options.ts +454 -0
- package/src/scripts/codemod/testing-move-targets.ts +161 -0
- package/src/scripts/codemod/testing-move.ts +520 -0
- package/dist/bun-db/connection.d.ts +0 -17
- package/dist/bun-db/connection.js +0 -40
- package/dist/bun-db/index.d.ts +0 -4
- package/dist/bun-db/query.d.ts +0 -106
- package/dist/bun-db/query.js +0 -1457
- package/dist/db/api.d.ts +0 -19
- package/dist/db/api.js +0 -23
- package/dist/db/bun-provider.d.ts +0 -2
- package/dist/db/bun-provider.js +0 -28
- package/dist/db/postgres-provider.d.ts +0 -2
- package/dist/db/postgres-provider.js +0 -21
- package/dist/db/query-api.d.ts +0 -2
- package/dist/db/query-api.js +0 -6
- package/dist/stack/db.d.ts +0 -22
- package/dist/stack/db.js +0 -67
- package/dist/stack/drain-event-consumers.d.ts +0 -4
- package/dist/stack/drain-event-consumers.js +0 -51
- package/dist/stack/drain-jobs.d.ts +0 -22
- package/dist/stack/drain-jobs.js +0 -141
- package/dist/stack/event-collector.d.ts +0 -9
- package/dist/stack/event-collector.js +0 -12
- package/dist/stack/push-entity-projection-tables.d.ts +0 -24
- package/dist/stack/push-entity-projection-tables.js +0 -74
- package/dist/stack/redis.d.ts +0 -17
- package/dist/stack/redis.js +0 -52
- package/dist/stack/request-helper.d.ts +0 -35
- package/dist/stack/request-helper.js +0 -144
- package/dist/stack/test-stack.d.ts +0 -192
- package/dist/stack/test-stack.js +0 -429
- package/dist/testing/access-assertions.d.ts +0 -2
- package/dist/testing/access-assertions.js +0 -13
- package/dist/testing/assertions.d.ts +0 -10
- package/dist/testing/assertions.js +0 -22
- package/dist/testing/boot-validator-fixture.d.ts +0 -3
- package/dist/testing/boot-validator-fixture.js +0 -101
- package/dist/testing/closed-connection-error.d.ts +0 -7
- package/dist/testing/closed-connection-error.js +0 -46
- package/dist/testing/db-cleanup.d.ts +0 -9
- package/dist/testing/db-cleanup.js +0 -31
- package/dist/testing/expect-error.d.ts +0 -2
- package/dist/testing/expect-error.js +0 -22
- package/dist/testing/file-provider-contract.d.ts +0 -2
- package/dist/testing/file-provider-contract.js +0 -102
- package/dist/testing/http-cookies.d.ts +0 -7
- package/dist/testing/http-cookies.js +0 -47
- package/dist/testing/late-bound.d.ts +0 -9
- package/dist/testing/late-bound.js +0 -31
- package/dist/testing/manual-clock.d.ts +0 -14
- package/dist/testing/manual-clock.js +0 -12
- package/dist/testing/multipart-helper.d.ts +0 -22
- package/dist/testing/multipart-helper.js +0 -77
- package/dist/testing/mutable-master-key-provider.d.ts +0 -7
- package/dist/testing/mutable-master-key-provider.js +0 -35
- package/dist/testing/observability-recorder.d.ts +0 -9
- package/dist/testing/observability-recorder.js +0 -29
- package/dist/testing/seed.d.ts +0 -9
- package/dist/testing/seed.js +0 -21
- package/dist/testing/shared-entities.d.ts +0 -286
- package/dist/testing/shared-entities.js +0 -56
- package/dist/testing/utils.d.ts +0 -1
- package/dist/testing/utils.js +0 -1
- package/dist/testing/wait-for.d.ts +0 -20
- package/dist/testing/wait-for.js +0 -47
- package/dist/testing/without-ambient-temporal.d.ts +0 -5
- package/dist/testing/without-ambient-temporal.js +0 -17
- package/dist/testing/zip-fixture.d.ts +0 -1
- package/dist/testing/zip-fixture.js +0 -33
- /package/dist/{stack/test-users.d.ts → seeding/seed-users.d.ts} +0 -0
- /package/dist/{stack/test-users.js → seeding/seed-users.js} +0 -0
|
@@ -43,13 +43,9 @@ bun test
|
|
|
43
43
|
// → cancelled → draft (reopen)
|
|
44
44
|
|
|
45
45
|
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
46
|
-
import {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
type TestStack,
|
|
50
|
-
TestUsers,
|
|
51
|
-
} from "@cosmicdrift/kumiko-framework/stack";
|
|
52
|
-
import { expectErrorIncludes } from "@cosmicdrift/kumiko-framework/testing";
|
|
46
|
+
import { createTestUser, TestUsers } from "@cosmicdrift/kumiko-framework/seeding";
|
|
47
|
+
import { expectErrorIncludes } from "@cosmicdrift/kumiko-testing/helpers";
|
|
48
|
+
import { setupTestStack, type TestStack } from "@cosmicdrift/kumiko-testing/stack";
|
|
53
49
|
import { stateMachineFeature } from "../feature";
|
|
54
50
|
|
|
55
51
|
let stack: TestStack;
|
|
@@ -449,14 +445,14 @@ describe("reduceInvoice", () => {
|
|
|
449
445
|
### src/entities/invoice.ts
|
|
450
446
|
|
|
451
447
|
```ts
|
|
448
|
+
import { buildEntityTable } from "@cosmicdrift/kumiko-framework/db";
|
|
452
449
|
import {
|
|
453
450
|
createEntity,
|
|
454
451
|
createMoneyField,
|
|
455
452
|
createSelectField,
|
|
456
453
|
createTextField,
|
|
457
454
|
defineTransitions,
|
|
458
|
-
} from "@
|
|
459
|
-
import { buildEntityTable } from "@cosmicdrift/kumiko-framework/db";
|
|
455
|
+
} from "@cosmicdrift/kumiko-framework/engine";
|
|
460
456
|
|
|
461
457
|
export const INVOICE_STATES = ["draft", "sent", "paid", "cancelled"] as const;
|
|
462
458
|
|
|
@@ -494,6 +490,9 @@ export const invoiceTable = buildEntityTable("invoice", invoiceEntity);
|
|
|
494
490
|
// strings, so a rename here propagates everywhere instead of silently
|
|
495
491
|
// breaking the reducer.
|
|
496
492
|
|
|
493
|
+
import type { EventDef } from "@cosmicdrift/kumiko-framework/engine";
|
|
494
|
+
import { z } from "zod";
|
|
495
|
+
|
|
497
496
|
export const FEATURE_NAME = "billing";
|
|
498
497
|
export const ENTITY_NAME = "invoice";
|
|
499
498
|
|
|
@@ -521,6 +520,22 @@ export function eventName<const TShort extends string>(
|
|
|
521
520
|
// The auto-generated event the executor emits on create — entity name dot
|
|
522
521
|
// "created", no feature prefix (executor convention).
|
|
523
522
|
export const INVOICE_CREATED_EVENT = `${ENTITY_NAME}.created` as const;
|
|
523
|
+
|
|
524
|
+
export const emptyEventPayload = z.object({});
|
|
525
|
+
export const statusForcedPayload = z.object({
|
|
526
|
+
newStatus: z.enum(["draft", "sent", "paid", "cancelled"]),
|
|
527
|
+
fromStatus: z.enum(["draft", "sent", "paid", "cancelled"]),
|
|
528
|
+
});
|
|
529
|
+
|
|
530
|
+
// The EventDefs r.defineEvent returns inside the feature setup. Handlers receive them so that
|
|
531
|
+
// emitEvent checks each payload against the event's own schema.
|
|
532
|
+
export type InvoiceEvents = {
|
|
533
|
+
readonly sent: EventDef<z.infer<typeof emptyEventPayload>>;
|
|
534
|
+
readonly markedPaid: EventDef<z.infer<typeof emptyEventPayload>>;
|
|
535
|
+
readonly cancelled: EventDef<z.infer<typeof emptyEventPayload>>;
|
|
536
|
+
readonly reopened: EventDef<z.infer<typeof emptyEventPayload>>;
|
|
537
|
+
readonly statusForced: EventDef<z.infer<typeof statusForcedPayload>>;
|
|
538
|
+
};
|
|
524
539
|
```
|
|
525
540
|
|
|
526
541
|
### src/feature.ts
|
|
@@ -549,20 +564,17 @@ export const INVOICE_CREATED_EVENT = `${ENTITY_NAME}.created` as const;
|
|
|
549
564
|
// handlers/create.ts — invoice:create (uses executor)
|
|
550
565
|
// handlers/transitions.ts — the six state-change handlers
|
|
551
566
|
|
|
552
|
-
import { defineFeature, setFields } from "@
|
|
553
|
-
import { z } from "zod";
|
|
567
|
+
import { defineFeature, setFields, typedPayload } from "@cosmicdrift/kumiko-framework/engine";
|
|
554
568
|
import { invoiceEntity, invoiceTable } from "./entities/invoice";
|
|
555
|
-
import { eventName, INVOICE_EVENTS } from "./events";
|
|
556
|
-
import { invoiceCreate } from "./handlers/create";
|
|
557
569
|
import {
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
} from "./handlers/
|
|
565
|
-
import
|
|
570
|
+
emptyEventPayload,
|
|
571
|
+
eventName,
|
|
572
|
+
INVOICE_EVENTS,
|
|
573
|
+
type InvoiceEvents,
|
|
574
|
+
statusForcedPayload,
|
|
575
|
+
} from "./events";
|
|
576
|
+
import { invoiceCreate } from "./handlers/create";
|
|
577
|
+
import { createInvoiceTransitionHandlers } from "./handlers/transitions";
|
|
566
578
|
|
|
567
579
|
export { invoiceEntity } from "./entities/invoice";
|
|
568
580
|
|
|
@@ -573,18 +585,15 @@ export const stateMachineFeature = defineFeature("billing", (r) => {
|
|
|
573
585
|
// and the projection stay in sync. The auto "invoice.created" event from
|
|
574
586
|
// the executor's create-path covers the initial insert, so we only declare
|
|
575
587
|
// the state-change events here.
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
INVOICE_EVENTS.statusForced,
|
|
582
|
-
|
|
583
|
-
newStatus: z.enum(["draft", "sent", "paid", "cancelled"]),
|
|
584
|
-
fromStatus: z.enum(["draft", "sent", "paid", "cancelled"]),
|
|
588
|
+
const events: InvoiceEvents = {
|
|
589
|
+
sent: r.defineEvent(INVOICE_EVENTS.sent, emptyEventPayload, { piiFields: "none" }),
|
|
590
|
+
markedPaid: r.defineEvent(INVOICE_EVENTS.markedPaid, emptyEventPayload, { piiFields: "none" }),
|
|
591
|
+
cancelled: r.defineEvent(INVOICE_EVENTS.cancelled, emptyEventPayload, { piiFields: "none" }),
|
|
592
|
+
reopened: r.defineEvent(INVOICE_EVENTS.reopened, emptyEventPayload, { piiFields: "none" }),
|
|
593
|
+
statusForced: r.defineEvent(INVOICE_EVENTS.statusForced, statusForcedPayload, {
|
|
594
|
+
piiFields: "none",
|
|
585
595
|
}),
|
|
586
|
-
|
|
587
|
-
);
|
|
596
|
+
};
|
|
588
597
|
|
|
589
598
|
// The aggregate table (sample_sm_invoices) is INSERTed by the executor on
|
|
590
599
|
// invoice:create. State-change events update the same row via this inline
|
|
@@ -602,18 +611,19 @@ export const stateMachineFeature = defineFeature("billing", (r) => {
|
|
|
602
611
|
[eventName(INVOICE_EVENTS.cancelled)]: setFields(invoiceTable, { status: "cancelled" }),
|
|
603
612
|
[eventName(INVOICE_EVENTS.reopened)]: setFields(invoiceTable, { status: "draft" }),
|
|
604
613
|
[eventName(INVOICE_EVENTS.statusForced)]: setFields(invoiceTable, (e) => ({
|
|
605
|
-
status: (e.
|
|
614
|
+
status: typedPayload(e, events.statusForced).newStatus,
|
|
606
615
|
})),
|
|
607
616
|
},
|
|
608
617
|
});
|
|
609
618
|
|
|
619
|
+
const transitions = createInvoiceTransitionHandlers(events);
|
|
610
620
|
r.writeHandler(invoiceCreate);
|
|
611
|
-
r.writeHandler(invoiceSend);
|
|
612
|
-
r.writeHandler(invoiceMarkPaid);
|
|
613
|
-
r.writeHandler(invoiceCancel);
|
|
614
|
-
r.writeHandler(invoiceReopen);
|
|
615
|
-
r.writeHandler(invoiceUpdateStatus);
|
|
616
|
-
r.writeHandler(invoiceForceStatus);
|
|
621
|
+
r.writeHandler(transitions.invoiceSend);
|
|
622
|
+
r.writeHandler(transitions.invoiceMarkPaid);
|
|
623
|
+
r.writeHandler(transitions.invoiceCancel);
|
|
624
|
+
r.writeHandler(transitions.invoiceReopen);
|
|
625
|
+
r.writeHandler(transitions.invoiceUpdateStatus);
|
|
626
|
+
r.writeHandler(transitions.invoiceForceStatus);
|
|
617
627
|
});
|
|
618
628
|
```
|
|
619
629
|
|
|
@@ -624,25 +634,25 @@ export const stateMachineFeature = defineFeature("billing", (r) => {
|
|
|
624
634
|
// optionally guardTransition, append the domain event, return a WriteResult
|
|
625
635
|
// that reflects the post-write status.
|
|
626
636
|
|
|
627
|
-
import
|
|
628
|
-
|
|
637
|
+
import {
|
|
638
|
+
type AccessRule,
|
|
639
|
+
defineWriteHandler,
|
|
640
|
+
type EventDef,
|
|
641
|
+
emitEvent,
|
|
642
|
+
guardTransition,
|
|
643
|
+
} from "@cosmicdrift/kumiko-framework/engine";
|
|
629
644
|
import { failNotFound } from "@cosmicdrift/kumiko-framework/errors";
|
|
630
645
|
import { z } from "zod";
|
|
631
646
|
import { INVOICE_TRANSITIONS } from "../entities/invoice";
|
|
632
|
-
import { ENTITY_NAME } from "../events";
|
|
647
|
+
import { ENTITY_NAME, type emptyEventPayload } from "../events";
|
|
633
648
|
import { type InvoiceStatus, loadInvoiceState } from "../reducer";
|
|
634
649
|
|
|
635
|
-
//
|
|
636
|
-
//
|
|
637
|
-
|
|
638
|
-
type EmptyPayloadEvent = {
|
|
639
|
-
[K in keyof KumikoEventTypeMap]: KumikoEventTypeMap[K] extends Record<string, never> ? K : never;
|
|
640
|
-
}[keyof KumikoEventTypeMap];
|
|
641
|
-
|
|
642
|
-
export function transitionHandler<const TEvent extends EmptyPayloadEvent>(opts: {
|
|
650
|
+
// The event carries an empty payload — this helper always emits `{}`, so an EventDef with a
|
|
651
|
+
// non-empty payload is a compile error at the call site.
|
|
652
|
+
export function transitionHandler(opts: {
|
|
643
653
|
name: string;
|
|
644
654
|
toStatus: InvoiceStatus;
|
|
645
|
-
|
|
655
|
+
event: EventDef<z.infer<typeof emptyEventPayload>>;
|
|
646
656
|
access: AccessRule;
|
|
647
657
|
skipGuard?: boolean;
|
|
648
658
|
}) {
|
|
@@ -663,10 +673,9 @@ export function transitionHandler<const TEvent extends EmptyPayloadEvent>(opts:
|
|
|
663
673
|
guardTransition(INVOICE_TRANSITIONS, state.status as InvoiceStatus, opts.toStatus);
|
|
664
674
|
}
|
|
665
675
|
|
|
666
|
-
await ctx.
|
|
676
|
+
await emitEvent(ctx, opts.event, {
|
|
667
677
|
aggregateId: event.payload.id,
|
|
668
678
|
aggregateType: ENTITY_NAME,
|
|
669
|
-
type: opts.eventType,
|
|
670
679
|
payload: {},
|
|
671
680
|
});
|
|
672
681
|
|
|
@@ -701,8 +710,8 @@ export function successResult(id: string, newStatus: InvoiceStatus, previousStat
|
|
|
701
710
|
// keeps amount + amountCurrency flat, while the entity stores them as a
|
|
702
711
|
// money pair.
|
|
703
712
|
|
|
704
|
-
import { defineWriteHandler } from "@app/define";
|
|
705
713
|
import { createEventStoreExecutor } from "@cosmicdrift/kumiko-framework/db";
|
|
714
|
+
import { defineWriteHandler } from "@cosmicdrift/kumiko-framework/engine";
|
|
706
715
|
import { z } from "zod";
|
|
707
716
|
import { invoiceEntity, invoiceTable } from "../entities/invoice";
|
|
708
717
|
|
|
@@ -730,138 +739,145 @@ export const invoiceCreate = defineWriteHandler({
|
|
|
730
739
|
// little extra logic (amount-check, verb routing, dedicated forced-event)
|
|
731
740
|
// and stay inline so the variation is visible at the call site.
|
|
732
741
|
|
|
733
|
-
import {
|
|
742
|
+
import {
|
|
743
|
+
defineWriteHandler,
|
|
744
|
+
emitEvent,
|
|
745
|
+
guardTransition,
|
|
746
|
+
} from "@cosmicdrift/kumiko-framework/engine";
|
|
734
747
|
import { failNotFound, failUnprocessable } from "@cosmicdrift/kumiko-framework/errors";
|
|
735
748
|
import { z } from "zod";
|
|
736
749
|
import { INVOICE_STATES, INVOICE_TRANSITIONS } from "../entities/invoice";
|
|
737
|
-
import { ENTITY_NAME,
|
|
750
|
+
import { ENTITY_NAME, type InvoiceEvents } from "../events";
|
|
738
751
|
import { type InvoiceStatus, loadInvoiceState } from "../reducer";
|
|
739
752
|
import { successResult, transitionHandler } from "./_helpers";
|
|
740
753
|
|
|
741
754
|
const adminOnly = { roles: ["Admin"] } as const;
|
|
742
755
|
|
|
743
|
-
|
|
756
|
+
export function createInvoiceTransitionHandlers(events: InvoiceEvents) {
|
|
757
|
+
// --- Standard transitions (same shape, different target status) ---
|
|
744
758
|
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
});
|
|
759
|
+
const invoiceSend = transitionHandler({
|
|
760
|
+
name: "invoice:send",
|
|
761
|
+
toStatus: "sent",
|
|
762
|
+
event: events.sent,
|
|
763
|
+
access: adminOnly,
|
|
764
|
+
});
|
|
751
765
|
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
});
|
|
766
|
+
const invoiceCancel = transitionHandler({
|
|
767
|
+
name: "invoice:cancel",
|
|
768
|
+
toStatus: "cancelled",
|
|
769
|
+
event: events.cancelled,
|
|
770
|
+
access: adminOnly,
|
|
771
|
+
});
|
|
758
772
|
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
});
|
|
773
|
+
const invoiceReopen = transitionHandler({
|
|
774
|
+
name: "invoice:reopen",
|
|
775
|
+
toStatus: "draft",
|
|
776
|
+
event: events.reopened,
|
|
777
|
+
access: adminOnly,
|
|
778
|
+
});
|
|
765
779
|
|
|
766
|
-
// --- markPaid: same shape + business rule (amount must be > 0).
|
|
767
|
-
// The amount is reduced from the event stream, so the check stays
|
|
768
|
-
// consistent with everything else (no out-of-band DB query).
|
|
780
|
+
// --- markPaid: same shape + business rule (amount must be > 0).
|
|
781
|
+
// The amount is reduced from the event stream, so the check stays
|
|
782
|
+
// consistent with everything else (no out-of-band DB query).
|
|
769
783
|
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
784
|
+
const invoiceMarkPaid = defineWriteHandler({
|
|
785
|
+
name: "invoice:mark-paid",
|
|
786
|
+
schema: z.object({ id: z.uuid() }),
|
|
787
|
+
access: { roles: ["Accounting"] },
|
|
788
|
+
handler: async (event, ctx) => {
|
|
789
|
+
const state = await loadInvoiceState(ctx, event.payload.id);
|
|
790
|
+
if (!state) return failNotFound(ENTITY_NAME, event.payload.id);
|
|
777
791
|
|
|
778
|
-
|
|
792
|
+
guardTransition(INVOICE_TRANSITIONS, state.status as InvoiceStatus, "paid");
|
|
779
793
|
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
794
|
+
if (state.amount === 0) {
|
|
795
|
+
return failUnprocessable("cannot_pay_zero_amount");
|
|
796
|
+
}
|
|
783
797
|
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
});
|
|
798
|
+
await emitEvent(ctx, events.markedPaid, {
|
|
799
|
+
aggregateId: event.payload.id,
|
|
800
|
+
aggregateType: ENTITY_NAME,
|
|
801
|
+
payload: {},
|
|
802
|
+
});
|
|
790
803
|
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
});
|
|
804
|
+
return successResult(event.payload.id, "paid", state.status);
|
|
805
|
+
},
|
|
806
|
+
});
|
|
794
807
|
|
|
795
|
-
// --- updateStatus: relies on the pipeline's auto transition guard.
|
|
796
|
-
// Routes the requested status to the matching domain event so the audit
|
|
797
|
-
// log still reads as a workflow step ("invoice-sent"), not a generic
|
|
798
|
-
// "status set to ...".
|
|
799
|
-
|
|
800
|
-
// `
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
808
|
+
// --- updateStatus: relies on the pipeline's auto transition guard.
|
|
809
|
+
// Routes the requested status to the matching domain event so the audit
|
|
810
|
+
// log still reads as a workflow step ("invoice-sent"), not a generic
|
|
811
|
+
// "status set to ...".
|
|
812
|
+
|
|
813
|
+
// `satisfies Record<InvoiceStatus, ...>` makes a missing status a compile error.
|
|
814
|
+
const verbToEvent = {
|
|
815
|
+
draft: events.reopened,
|
|
816
|
+
sent: events.sent,
|
|
817
|
+
paid: events.markedPaid,
|
|
818
|
+
cancelled: events.cancelled,
|
|
819
|
+
} satisfies Record<InvoiceStatus, InvoiceEvents["sent"]>;
|
|
820
|
+
|
|
821
|
+
const invoiceUpdateStatus = defineWriteHandler({
|
|
822
|
+
name: "invoice:update-status",
|
|
823
|
+
schema: z.object({
|
|
824
|
+
id: z.uuid(),
|
|
825
|
+
changes: z.object({
|
|
826
|
+
status: z.enum(INVOICE_STATES),
|
|
827
|
+
}),
|
|
828
|
+
}),
|
|
829
|
+
access: adminOnly,
|
|
830
|
+
// No skipTransitionGuard — pipeline auto-guards.
|
|
831
|
+
handler: async (event, ctx) => {
|
|
832
|
+
const state = await loadInvoiceState(ctx, event.payload.id);
|
|
833
|
+
if (!state) return failNotFound(ENTITY_NAME, event.payload.id);
|
|
834
|
+
|
|
835
|
+
const target = event.payload.changes.status;
|
|
836
|
+
await emitEvent(ctx, verbToEvent[target], {
|
|
837
|
+
aggregateId: event.payload.id,
|
|
838
|
+
aggregateType: ENTITY_NAME,
|
|
839
|
+
payload: {},
|
|
840
|
+
});
|
|
841
|
+
|
|
842
|
+
return successResult(event.payload.id, target, state.status);
|
|
843
|
+
},
|
|
844
|
+
});
|
|
845
|
+
|
|
846
|
+
// --- forceStatus: skips the guard and emits a dedicated "forced" event so
|
|
847
|
+
// admin overrides stay visually distinct from normal workflow events in
|
|
848
|
+
// the audit log.
|
|
849
|
+
|
|
850
|
+
const invoiceForceStatus = defineWriteHandler({
|
|
851
|
+
name: "invoice:force-status",
|
|
852
|
+
schema: z.object({
|
|
853
|
+
id: z.uuid(),
|
|
818
854
|
status: z.enum(INVOICE_STATES),
|
|
819
855
|
}),
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
if (!state) return failNotFound(ENTITY_NAME, event.payload.id);
|
|
826
|
-
|
|
827
|
-
const target = event.payload.changes.status;
|
|
828
|
-
await ctx.appendEvent({
|
|
829
|
-
aggregateId: event.payload.id,
|
|
830
|
-
aggregateType: ENTITY_NAME,
|
|
831
|
-
type: VERB_TO_EVENT[target],
|
|
832
|
-
payload: {},
|
|
833
|
-
});
|
|
834
|
-
|
|
835
|
-
return successResult(event.payload.id, target, state.status);
|
|
836
|
-
},
|
|
837
|
-
});
|
|
856
|
+
access: adminOnly,
|
|
857
|
+
unsafeSkipTransitionGuard: true,
|
|
858
|
+
handler: async (event, ctx) => {
|
|
859
|
+
const state = await loadInvoiceState(ctx, event.payload.id);
|
|
860
|
+
if (!state) return failNotFound(ENTITY_NAME, event.payload.id);
|
|
838
861
|
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
862
|
+
await emitEvent(ctx, events.statusForced, {
|
|
863
|
+
aggregateId: event.payload.id,
|
|
864
|
+
aggregateType: ENTITY_NAME,
|
|
865
|
+
payload: { newStatus: event.payload.status, fromStatus: state.status as InvoiceStatus },
|
|
866
|
+
});
|
|
842
867
|
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
aggregateId: event.payload.id,
|
|
857
|
-
aggregateType: ENTITY_NAME,
|
|
858
|
-
type: eventName(INVOICE_EVENTS.statusForced),
|
|
859
|
-
payload: { newStatus: event.payload.status, fromStatus: state.status as InvoiceStatus },
|
|
860
|
-
});
|
|
861
|
-
|
|
862
|
-
return successResult(event.payload.id, event.payload.status, state.status);
|
|
863
|
-
},
|
|
864
|
-
});
|
|
868
|
+
return successResult(event.payload.id, event.payload.status, state.status);
|
|
869
|
+
},
|
|
870
|
+
});
|
|
871
|
+
|
|
872
|
+
return {
|
|
873
|
+
invoiceSend,
|
|
874
|
+
invoiceCancel,
|
|
875
|
+
invoiceReopen,
|
|
876
|
+
invoiceMarkPaid,
|
|
877
|
+
invoiceUpdateStatus,
|
|
878
|
+
invoiceForceStatus,
|
|
879
|
+
};
|
|
880
|
+
}
|
|
865
881
|
```
|
|
866
882
|
|
|
867
883
|
### src/reducer.ts
|
|
@@ -876,7 +892,7 @@ export const invoiceForceStatus = defineWriteHandler({
|
|
|
876
892
|
// and update the relevant `case` in `reduceInvoice` — that's the whole
|
|
877
893
|
// contract.
|
|
878
894
|
|
|
879
|
-
import type { HandlerContext } from "@
|
|
895
|
+
import type { HandlerContext } from "@cosmicdrift/kumiko-framework/engine";
|
|
880
896
|
import { eventName, INVOICE_CREATED_EVENT, INVOICE_EVENTS } from "./events";
|
|
881
897
|
|
|
882
898
|
export type InvoiceStatus = "draft" | "sent" | "paid" | "cancelled";
|
|
@@ -131,13 +131,12 @@ import {
|
|
|
131
131
|
tagEntity,
|
|
132
132
|
} from "@cosmicdrift/kumiko-bundled-features/tags";
|
|
133
133
|
import { createEventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
134
|
+
import { createTestUser, testTenantId } from "@cosmicdrift/kumiko-framework/seeding";
|
|
134
135
|
import {
|
|
135
|
-
createTestUser,
|
|
136
136
|
setupTestStack,
|
|
137
137
|
type TestStack,
|
|
138
|
-
testTenantId,
|
|
139
138
|
unsafeCreateEntityTable,
|
|
140
|
-
} from "@cosmicdrift/kumiko-
|
|
139
|
+
} from "@cosmicdrift/kumiko-testing/stack";
|
|
141
140
|
import { noteEntity, noteFeature } from "../feature";
|
|
142
141
|
import { type TagClient, tagFlow } from "../usage";
|
|
143
142
|
|
|
@@ -39,13 +39,12 @@ bun test
|
|
|
39
39
|
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test";
|
|
40
40
|
import type { SaveContext } from "@cosmicdrift/kumiko-framework/engine";
|
|
41
41
|
import { createEventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
42
|
+
import { createTestUser, TestUsers } from "@cosmicdrift/kumiko-framework/seeding";
|
|
42
43
|
import {
|
|
43
|
-
createTestUser,
|
|
44
44
|
setupTestStack,
|
|
45
45
|
type TestStack,
|
|
46
|
-
TestUsers,
|
|
47
46
|
unsafeCreateEntityTable,
|
|
48
|
-
} from "@cosmicdrift/kumiko-
|
|
47
|
+
} from "@cosmicdrift/kumiko-testing/stack";
|
|
49
48
|
import { noteEntity, noteFeature } from "../feature";
|
|
50
49
|
|
|
51
50
|
let stack: TestStack;
|
|
@@ -137,14 +137,14 @@ import {
|
|
|
137
137
|
import { createTenantSettingsFeature } from "@cosmicdrift/kumiko-bundled-features/tenant-settings";
|
|
138
138
|
import type { SessionUser } from "@cosmicdrift/kumiko-framework/engine";
|
|
139
139
|
import { createEventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
140
|
+
import { testTenantId } from "@cosmicdrift/kumiko-framework/seeding";
|
|
140
141
|
import {
|
|
141
142
|
pushEntityProjectionTables,
|
|
142
143
|
setupTestStack,
|
|
143
144
|
type TestStack,
|
|
144
|
-
testTenantId,
|
|
145
145
|
unsafeCreateEntityTable,
|
|
146
146
|
unsafePushTables,
|
|
147
|
-
} from "@cosmicdrift/kumiko-
|
|
147
|
+
} from "@cosmicdrift/kumiko-testing/stack";
|
|
148
148
|
import { invoiceEntity, invoiceFeature } from "../feature";
|
|
149
149
|
|
|
150
150
|
const tenantId = testTenantId(1);
|
|
@@ -119,15 +119,14 @@ import {
|
|
|
119
119
|
import { asRawClient } from "@cosmicdrift/kumiko-framework/db";
|
|
120
120
|
import { findTierResolverUsage, isTierResolverPlugin } from "@cosmicdrift/kumiko-framework/engine";
|
|
121
121
|
import { createEventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
122
|
+
import { createTestUser, testTenantId } from "@cosmicdrift/kumiko-framework/seeding";
|
|
123
|
+
import { createTestEnvelopeCipher } from "@cosmicdrift/kumiko-testing/helpers";
|
|
122
124
|
import {
|
|
123
|
-
createTestUser,
|
|
124
125
|
setupTestStack,
|
|
125
126
|
type TestStack,
|
|
126
|
-
testTenantId,
|
|
127
127
|
unsafeCreateEntityTable,
|
|
128
128
|
unsafePushTables,
|
|
129
|
-
} from "@cosmicdrift/kumiko-
|
|
130
|
-
import { createTestEnvelopeCipher } from "@cosmicdrift/kumiko-framework/testing";
|
|
129
|
+
} from "@cosmicdrift/kumiko-testing/stack";
|
|
131
130
|
import { appTierMap, NOTES_EXPORT_FEATURE, notesExportFeature, tierEngineForApp } from "../feature";
|
|
132
131
|
|
|
133
132
|
const encryptionKey = randomBytes(32).toString("base64");
|
|
@@ -117,13 +117,13 @@ boundary, the `todayRange` day-window, and the `fromCoordinates` provider seam.
|
|
|
117
117
|
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test";
|
|
118
118
|
import type { SaveContext } from "@cosmicdrift/kumiko-framework/engine";
|
|
119
119
|
import { createEventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
120
|
+
import { TestUsers } from "@cosmicdrift/kumiko-framework/seeding";
|
|
121
|
+
import type { GeoTzProvider } from "@cosmicdrift/kumiko-framework/time";
|
|
120
122
|
import {
|
|
121
123
|
setupTestStack,
|
|
122
124
|
type TestStack,
|
|
123
|
-
TestUsers,
|
|
124
125
|
unsafeCreateEntityTable,
|
|
125
|
-
} from "@cosmicdrift/kumiko-
|
|
126
|
-
import type { GeoTzProvider } from "@cosmicdrift/kumiko-framework/time";
|
|
126
|
+
} from "@cosmicdrift/kumiko-testing/stack";
|
|
127
127
|
import { deliveryEntity, timezonesFeature } from "../feature";
|
|
128
128
|
|
|
129
129
|
let stack: TestStack;
|
|
@@ -123,7 +123,7 @@ export const features = [
|
|
|
123
123
|
// löschen — Row bleibt für Multi-User-Refs intakt.
|
|
124
124
|
|
|
125
125
|
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test";
|
|
126
|
-
import {
|
|
126
|
+
import { createAuthFoundationFeature } from "@cosmicdrift/kumiko-bundled-features/auth-foundation";
|
|
127
127
|
import {
|
|
128
128
|
createComplianceProfilesFeature,
|
|
129
129
|
tenantComplianceProfileEntity,
|
|
@@ -148,15 +148,15 @@ import {
|
|
|
148
148
|
runForgetCleanup,
|
|
149
149
|
runUserExport,
|
|
150
150
|
} from "@cosmicdrift/kumiko-bundled-features/user-data-rights";
|
|
151
|
-
import { insertOne, selectMany } from "@cosmicdrift/kumiko-framework/
|
|
151
|
+
import { insertOne, selectMany } from "@cosmicdrift/kumiko-framework/db";
|
|
152
152
|
import { EXT_USER_DATA } from "@cosmicdrift/kumiko-framework/engine";
|
|
153
|
+
import { getTemporal } from "@cosmicdrift/kumiko-framework/time";
|
|
154
|
+
import { seedRow } from "@cosmicdrift/kumiko-testing/helpers";
|
|
153
155
|
import {
|
|
154
156
|
setupTestStack,
|
|
155
157
|
type TestStack,
|
|
156
158
|
unsafeCreateEntityTable,
|
|
157
|
-
} from "@cosmicdrift/kumiko-
|
|
158
|
-
import { seedRow } from "@cosmicdrift/kumiko-framework/testing";
|
|
159
|
-
import { getTemporal } from "@cosmicdrift/kumiko-framework/time";
|
|
159
|
+
} from "@cosmicdrift/kumiko-testing/stack";
|
|
160
160
|
import { noteEntity, notesFeature, notesTable } from "../feature";
|
|
161
161
|
|
|
162
162
|
let stack: TestStack;
|
|
@@ -177,7 +177,7 @@ beforeAll(async () => {
|
|
|
177
177
|
stack = await setupTestStack({
|
|
178
178
|
features: [
|
|
179
179
|
createUserFeature(),
|
|
180
|
-
|
|
180
|
+
createAuthFoundationFeature(),
|
|
181
181
|
createSessionsFeature(),
|
|
182
182
|
createDataRetentionFeature(),
|
|
183
183
|
createComplianceProfilesFeature(),
|
|
@@ -321,8 +321,12 @@ describe("user-data-rights recipe :: EXT_USER_DATA-Hooks integrieren Notes-Domai
|
|
|
321
321
|
// - HTTP-Endpoints fuer create/list
|
|
322
322
|
// - Compliance-Profile-Wiring + Cron-Scheduling
|
|
323
323
|
|
|
324
|
-
import {
|
|
325
|
-
|
|
324
|
+
import {
|
|
325
|
+
deleteMany,
|
|
326
|
+
deriveEntityTableMeta,
|
|
327
|
+
selectMany,
|
|
328
|
+
updateMany,
|
|
329
|
+
} from "@cosmicdrift/kumiko-framework/db";
|
|
326
330
|
import {
|
|
327
331
|
createEntity,
|
|
328
332
|
createTextField,
|
|
@@ -109,7 +109,7 @@ import {
|
|
|
109
109
|
createRegistry,
|
|
110
110
|
validateBoot as validateBootRaw,
|
|
111
111
|
} from "@cosmicdrift/kumiko-framework/engine";
|
|
112
|
-
import { withBootValidatorFixture } from "@cosmicdrift/kumiko-
|
|
112
|
+
import { withBootValidatorFixture } from "@cosmicdrift/kumiko-testing/helpers";
|
|
113
113
|
import { composeAccountApp } from "../feature";
|
|
114
114
|
|
|
115
115
|
function validateBoot(features: Parameters<typeof validateBootRaw>[0]): void {
|
|
@@ -166,7 +166,7 @@ describe("user-profile recipe — boot validation", () => {
|
|
|
166
166
|
// })
|
|
167
167
|
|
|
168
168
|
import { createAuthEmailPasswordFeature } from "@cosmicdrift/kumiko-bundled-features/auth-email-password";
|
|
169
|
-
import {
|
|
169
|
+
import { createAuthFoundationFeature } from "@cosmicdrift/kumiko-bundled-features/auth-foundation";
|
|
170
170
|
import { createComplianceProfilesFeature } from "@cosmicdrift/kumiko-bundled-features/compliance-profiles";
|
|
171
171
|
import { createConfigFeature } from "@cosmicdrift/kumiko-bundled-features/config";
|
|
172
172
|
import { createDataRetentionFeature } from "@cosmicdrift/kumiko-bundled-features/data-retention";
|
|
@@ -211,7 +211,7 @@ export function composeAccountApp(): FeatureDefinition[] {
|
|
|
211
211
|
createAuthEmailPasswordFeature(),
|
|
212
212
|
createDataRetentionFeature(),
|
|
213
213
|
createComplianceProfilesFeature(),
|
|
214
|
-
|
|
214
|
+
createAuthFoundationFeature(),
|
|
215
215
|
createPersonalAccessTokensFeature({ scopes: {} }),
|
|
216
216
|
createSessionsFeature(),
|
|
217
217
|
createFilesFeature(),
|