@cosmicdrift/kumiko-bundled-features 0.307.0 → 0.308.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 +9 -9
- package/src/__tests__/access-invalidation-consumer.integration.test.ts +107 -0
- package/src/__tests__/access-invalidation-stream.integration.test.ts +1 -1
- package/src/__tests__/credential-scoped-sse-revoke.integration.test.ts +296 -0
- package/src/agent-tools/__tests__/agent-doc-lint.test.ts +1 -1
- package/src/agent-tools/__tests__/agent-manifest.test.ts +1 -1
- package/src/agent-tools/__tests__/agent-optout.test.ts +1 -1
- package/src/agent-tools/__tests__/agent-tools.integration.test.ts +1 -1
- package/src/agent-tools/__tests__/feature.test.ts +1 -1
- package/src/agent-tools/__tests__/tool-catalog.test.ts +1 -1
- package/src/agent-tools/agent-manifest.ts +1 -1
- package/src/audit/__tests__/escape-hatch-audit.integration.test.ts +1 -1
- package/src/audit/escape-hatch-audit-sink.ts +1 -1
- package/src/audit/handlers/details.query.ts +1 -1
- package/src/audit/handlers/list.query.ts +1 -1
- package/src/auth-email-password/__tests__/query-as-member.integration.test.ts +1 -1
- package/src/auth-email-password/feature.ts +1 -1
- package/src/auth-email-password/handlers/change-password.write.ts +1 -1
- package/src/auth-email-password/handlers/confirm-account-unlock.write.ts +1 -1
- package/src/auth-email-password/handlers/invite-accept-with-login.write.ts +1 -1
- package/src/auth-email-password/handlers/invite-accept.write.ts +1 -1
- package/src/auth-email-password/handlers/invite-create.write.ts +1 -1
- package/src/auth-email-password/handlers/invite-signup-complete.write.ts +1 -1
- package/src/auth-email-password/handlers/login.write.ts +1 -1
- package/src/auth-email-password/handlers/logout.write.ts +1 -1
- package/src/auth-email-password/handlers/reset-password.write.ts +1 -1
- package/src/auth-email-password/handlers/self-registration-status.query.ts +1 -1
- package/src/auth-email-password/handlers/signup-confirm.write.ts +1 -1
- package/src/auth-email-password/handlers/signup-request.write.ts +1 -1
- package/src/auth-email-password/handlers/token-request-handler.ts +1 -1
- package/src/auth-email-password/handlers/verify-email.write.ts +1 -1
- package/src/auth-email-password/password-policy.ts +1 -1
- package/src/auth-mfa/__tests__/session-scoped-sse-revoke.integration.test.ts +1 -1
- package/src/auth-mfa/handlers/disable.write.ts +1 -1
- package/src/auth-mfa/handlers/enable-confirm-preauth.write.ts +1 -1
- package/src/auth-mfa/handlers/enable-confirm.write.ts +1 -1
- package/src/auth-mfa/handlers/enable-start-preauth.write.ts +1 -1
- package/src/auth-mfa/handlers/enable-start.write.ts +1 -1
- package/src/auth-mfa/handlers/regenerate-recovery.write.ts +1 -1
- package/src/auth-mfa/handlers/status.query.ts +1 -1
- package/src/auth-mfa/handlers/verify.write.ts +1 -1
- package/src/billing-foundation/billing-info-query.ts +1 -1
- package/src/billing-foundation/events.ts +1 -1
- package/src/billing-foundation/handlers/create-checkout-session.write.ts +1 -1
- package/src/billing-foundation/handlers/create-portal-session.write.ts +1 -1
- package/src/billing-foundation/handlers/list-subscriptions.query.ts +1 -1
- package/src/billing-foundation/handlers/process-event.write.ts +1 -1
- package/src/billing-foundation/handlers/process-payment-event.write.ts +1 -1
- package/src/cap-counter/__tests__/cap-counter.integration.test.ts +1 -1
- package/src/cap-counter/__tests__/stock-cap-guard.integration.test.ts +1 -1
- package/src/cap-counter/__tests__/with-cap-enforcement.integration.test.ts +1 -1
- package/src/cap-counter/book-cap-usage.ts +1 -1
- package/src/cap-counter/handlers/get-counter.query.ts +1 -1
- package/src/cap-counter/handlers/increment-rolling.write.ts +1 -1
- package/src/cap-counter/handlers/increment.write.ts +1 -1
- package/src/cap-counter/handlers/mark-soft-warned.write.ts +1 -1
- package/src/cap-overview/handlers/caps-usage.query.ts +1 -1
- package/src/cap-overview/handlers/tenant-caps-list.query.ts +1 -1
- package/src/cap-overview/handlers/tenant-options.query.ts +1 -1
- package/src/channel-in-app/handlers/inbox.query.ts +1 -1
- package/src/channel-in-app/handlers/mark-all-read.write.ts +1 -1
- package/src/channel-in-app/handlers/mark-read.write.ts +1 -1
- package/src/channel-in-app/handlers/unread-count.query.ts +1 -1
- package/src/compliance-profiles/handlers/for-tenant.query.ts +1 -1
- package/src/compliance-profiles/handlers/list-profiles.query.ts +1 -1
- package/src/compliance-profiles/handlers/needs-profile.query.ts +1 -1
- package/src/compliance-profiles/handlers/set-profile.write.ts +1 -1
- package/src/compliance-profiles/handlers/sub-processors.query.ts +1 -1
- package/src/compliance-profiles-ops/handlers/tenants-missing-profile.query.ts +1 -1
- package/src/config/__tests__/backing-secrets.integration.test.ts +1 -1
- package/src/config/__tests__/config.integration.test.ts +1 -1
- package/src/config/__tests__/tz-resolution.integration.test.ts +1 -1
- package/src/config/handlers/cascade.query.ts +1 -1
- package/src/config/handlers/readiness.query.ts +1 -1
- package/src/config/handlers/reset.write.ts +1 -1
- package/src/config/handlers/schema.query.ts +1 -1
- package/src/config/handlers/set.write.ts +1 -1
- package/src/config/handlers/values.query.ts +1 -1
- package/src/crypto-shredding/handlers/forget-subject.write.ts +1 -1
- package/src/custom-fields/__tests__/audit-integration.integration.test.ts +1 -1
- package/src/custom-fields/__tests__/cross-tenant-field-delete.integration.test.ts +1 -1
- package/src/custom-fields/__tests__/cross-tenant-set-write.integration.test.ts +1 -1
- package/src/custom-fields/__tests__/custom-fields.integration.test.ts +1 -1
- package/src/custom-fields/__tests__/field-access.integration.test.ts +1 -1
- package/src/custom-fields/__tests__/quota.integration.test.ts +1 -1
- package/src/custom-fields/__tests__/retention.integration.test.ts +1 -1
- package/src/custom-fields/__tests__/user-data-rights.integration.test.ts +1 -1
- package/src/custom-fields/events.ts +1 -1
- package/src/custom-fields/feature.ts +1 -1
- package/src/custom-fields/handlers/clear-custom-field.write.ts +1 -1
- package/src/custom-fields/handlers/set-custom-field.write.ts +1 -1
- package/src/custom-fields/lib/value-schema.ts +1 -1
- package/src/custom-fields/schemas.ts +1 -1
- package/src/data-retention/handlers/policy-for.query.ts +1 -1
- package/src/data-retention/override-schema.ts +1 -1
- package/src/delivery/__tests__/delivery-pii-kms.integration.test.ts +1 -1
- package/src/delivery/__tests__/delivery.integration.test.ts +1 -1
- package/src/delivery/events.ts +1 -1
- package/src/delivery/feature.ts +1 -1
- package/src/delivery/handlers/log.query.ts +1 -1
- package/src/delivery/handlers/preferences.query.ts +1 -1
- package/src/delivery/handlers/set-preference.write.ts +1 -1
- package/src/delivery/jobs.ts +1 -1
- package/src/delivery/unsubscribe.ts +1 -1
- package/src/derivatives-sharp/__tests__/derivatives-sharp.integration.test.ts +1 -1
- package/src/document-ingest-foundation/events.ts +1 -1
- package/src/document-ingest-foundation/feature.ts +1 -1
- package/src/feature-toggles/__tests__/feature-toggles.integration.test.ts +1 -1
- package/src/feature-toggles/events.ts +1 -1
- package/src/feature-toggles/handlers/list.query.ts +1 -1
- package/src/feature-toggles/handlers/registered.query.ts +1 -1
- package/src/feature-toggles/handlers/set.write.ts +1 -1
- package/src/file-derivatives/handlers/public-variant.query.ts +1 -1
- package/src/file-foundation/__tests__/file-foundation.integration.test.ts +1 -1
- package/src/files-tenant-data/handlers/sweep-orphaned-derivatives.job.ts +1 -1
- package/src/folders/handlers/delete-folder.write.ts +1 -1
- package/src/folders/schemas.ts +1 -1
- package/src/form-draft/schemas.ts +1 -1
- package/src/inbound-mail-foundation/events.ts +1 -1
- package/src/inbound-mail-foundation/handlers/connect-account.write.ts +1 -1
- package/src/inbound-mail-foundation/handlers/disconnect-account.write.ts +1 -1
- package/src/inbound-mail-foundation/handlers/ingest-message.write.ts +1 -1
- package/src/inbound-mail-foundation/handlers/list-accounts.query.ts +1 -1
- package/src/inbound-mail-foundation/handlers/list-messages.query.ts +1 -1
- package/src/inbound-mail-foundation/handlers/update-account.write.ts +1 -1
- package/src/inbound-provider-imap/credential-document.ts +1 -1
- package/src/jobs/__tests__/jobs-catalog.integration.test.ts +1 -1
- package/src/jobs/__tests__/tenant-job-failures.integration.test.ts +1 -1
- package/src/jobs/events.ts +1 -1
- package/src/jobs/handlers/catalog.query.ts +1 -1
- package/src/jobs/handlers/detail.query.ts +1 -1
- package/src/jobs/handlers/list.query.ts +1 -1
- package/src/jobs/handlers/projection-rebuild.job.ts +1 -1
- package/src/jobs/handlers/reindex-entity.job.ts +1 -1
- package/src/jobs/handlers/retry.write.ts +1 -1
- package/src/jobs/handlers/tenant-failures.query.ts +1 -1
- package/src/jobs/handlers/trigger.write.ts +1 -1
- package/src/ledger/handlers/reports.query.ts +1 -1
- package/src/ledger/schemas.ts +1 -1
- package/src/mail-foundation/__tests__/mail-foundation.integration.test.ts +1 -1
- package/src/managed-pages/handlers/branding.query.ts +1 -1
- package/src/managed-pages/handlers/by-slug.query.ts +1 -1
- package/src/managed-pages/handlers/by-tenant-published.query.ts +1 -1
- package/src/managed-pages/handlers/set.write.ts +1 -1
- package/src/notes-history/changes.json +7 -0
- package/src/notes-history/schemas.ts +1 -1
- package/src/notes-history/web/notes-section.tsx +37 -36
- package/src/personal-access-tokens/feature.ts +10 -0
- package/src/personal-access-tokens/handlers/available-scopes.query.ts +1 -1
- package/src/personal-access-tokens/handlers/create.write.ts +1 -1
- package/src/personal-access-tokens/handlers/list.query.ts +1 -1
- package/src/personal-access-tokens/handlers/revoke.write.ts +18 -2
- package/src/personal-access-tokens/index.ts +7 -0
- package/src/personal-access-tokens/pat-revoked-event.ts +23 -0
- package/src/personal-access-tokens/revoke-for-user.ts +31 -0
- package/src/rate-limiting/__tests__/rate-limiting.integration.test.ts +1 -1
- package/src/rate-limiting/handlers/status.query.ts +1 -1
- package/src/readiness/handlers/status.query.ts +1 -1
- package/src/secrets/feature.ts +1 -1
- package/src/secrets/handlers/delete.write.ts +1 -1
- package/src/secrets/handlers/list.query.ts +1 -1
- package/src/secrets/handlers/set.write.ts +1 -1
- package/src/secrets/secrets-context.ts +1 -1
- package/src/seo/handlers/seo-config.query.ts +1 -1
- package/src/sessions/handlers/detail.query.ts +1 -1
- package/src/sessions/handlers/list.query.ts +1 -1
- package/src/sessions/handlers/mine.query.ts +1 -1
- package/src/sessions/handlers/revoke-all-for-user.write.ts +1 -1
- package/src/sessions/handlers/revoke-all-others.write.ts +1 -1
- package/src/sessions/handlers/revoke.write.ts +1 -1
- package/src/sessions/session-callbacks.ts +25 -1
- package/src/sessions/session-revoked-event.ts +6 -1
- package/src/shared/__tests__/row-bound-grant.integration.test.ts +1 -1
- package/src/step-dispatcher/mail-runner.ts +1 -1
- package/src/step-dispatcher/webhook-runner.ts +1 -1
- package/src/subscription-mollie/feature.ts +1 -1
- package/src/subscription-stripe/feature.ts +1 -1
- package/src/tags/schemas.ts +1 -1
- package/src/template-resolver/handlers/by-slug.query.ts +1 -1
- package/src/template-resolver/handlers/by-tenant.query.ts +1 -1
- package/src/template-resolver/handlers/collection-item.query.ts +1 -1
- package/src/template-resolver/handlers/collection-list.query.ts +1 -1
- package/src/template-resolver/handlers/collection-set.write.ts +1 -1
- package/src/template-resolver/handlers/find-by-id.query.ts +1 -1
- package/src/template-resolver/handlers/list.query.ts +1 -1
- package/src/template-resolver/handlers/set.write.ts +1 -1
- package/src/template-resolver/handlers/shared.ts +1 -1
- package/src/template-resolver/handlers/toggle-status.write.ts +1 -1
- package/src/template-resolver/handlers/upsert-tenant.write.ts +1 -1
- package/src/tenant/__tests__/tenant-timezone-boot.integration.test.ts +1 -1
- package/src/tenant/handlers/active-tenant-ids.query.ts +1 -1
- package/src/tenant/handlers/add-member.write.ts +1 -1
- package/src/tenant/handlers/cancel-invitation.write.ts +1 -1
- package/src/tenant/handlers/create.write.ts +1 -1
- package/src/tenant/handlers/invitations.query.ts +1 -1
- package/src/tenant/handlers/list.query.ts +1 -1
- package/src/tenant/handlers/me.query.ts +1 -1
- package/src/tenant/handlers/member-directory.query.ts +1 -1
- package/src/tenant/handlers/members.query.ts +1 -1
- package/src/tenant/handlers/memberships.query.ts +1 -1
- package/src/tenant/handlers/remove-member.write.ts +1 -1
- package/src/tenant/handlers/resolve-user-ids.query.ts +1 -1
- package/src/tenant/handlers/team-list.query.ts +1 -1
- package/src/tenant/handlers/tenant-directory.query.ts +1 -1
- package/src/tenant/handlers/toggle-enabled.write.ts +1 -1
- package/src/tenant/handlers/update-member-roles.write.ts +1 -1
- package/src/tenant/handlers/update.write.ts +1 -1
- package/src/tenant-handover/events.ts +1 -1
- package/src/tenant-handover/handlers/claim.write.ts +1 -1
- package/src/tenant-lifecycle/events.ts +1 -1
- package/src/tenant-lifecycle/handlers/cancel-destruction.write.ts +1 -1
- package/src/tenant-lifecycle/handlers/request-destruction.write.ts +1 -1
- package/src/tenant-settings/tenant-defaults.ts +1 -1
- package/src/tier-engine/__tests__/tier-resolver.integration.test.ts +1 -1
- package/src/tier-engine/feature.ts +1 -1
- package/src/tier-engine/handlers/active-tier.query.ts +1 -1
- package/src/tier-engine/handlers/get-tenant-tier.query.ts +1 -1
- package/src/tier-engine/handlers/set-tenant-tier.write.ts +1 -1
- package/src/user/__tests__/user-global-tenancy.integration.test.ts +1 -1
- package/src/user/handlers/create.write.ts +1 -1
- package/src/user/handlers/find-for-auth.query.ts +1 -1
- package/src/user/handlers/me.query.ts +1 -1
- package/src/user/handlers/update.write.ts +1 -1
- package/src/user/roles-input-schema.ts +1 -1
- package/src/user-data-rights/__tests__/boot-checks.test.ts +1 -1
- package/src/user-data-rights/changes.json +6 -0
- package/src/user-data-rights/feature.ts +1 -0
- package/src/user-data-rights/handlers/cancel-deletion.write.ts +1 -1
- package/src/user-data-rights/handlers/confirm-deletion-by-token.write.ts +1 -1
- package/src/user-data-rights/handlers/download-by-job.query.ts +1 -1
- package/src/user-data-rights/handlers/download-by-token.query.ts +1 -1
- package/src/user-data-rights/handlers/export-status.query.ts +1 -1
- package/src/user-data-rights/handlers/lift-restriction.write.ts +1 -1
- package/src/user-data-rights/handlers/list-download-attempts.query.ts +1 -1
- package/src/user-data-rights/handlers/my-audit-log.query.ts +1 -1
- package/src/user-data-rights/handlers/request-deletion-by-email.write.ts +1 -1
- package/src/user-data-rights/handlers/request-deletion.write.ts +1 -1
- package/src/user-data-rights/handlers/request-export.write.ts +1 -1
- package/src/user-data-rights/handlers/restrict-account.write.ts +1 -1
- package/src/user-data-rights/handlers/run-forget-cleanup.write.ts +1 -1
- package/src/user-profile/handlers/change-email.write.ts +1 -1
- package/src/workflow-runner/__tests__/pending-projection.integration.test.ts +1 -1
- package/src/workflow-runner/handlers/resume-run.write.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosmicdrift/kumiko-bundled-features",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.308.0",
|
|
4
4
|
"description": "Built-in features — tenant, user, auth, delivery. The stuff you'd rewrite anyway, already typed.",
|
|
5
5
|
"license": "BUSL-1.1",
|
|
6
6
|
"author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
|
|
@@ -133,12 +133,12 @@
|
|
|
133
133
|
"./workflow-runner": "./src/workflow-runner/index.ts"
|
|
134
134
|
},
|
|
135
135
|
"dependencies": {
|
|
136
|
-
"@cosmicdrift/kumiko-dispatcher-live": "0.
|
|
137
|
-
"@cosmicdrift/kumiko-framework": "0.
|
|
138
|
-
"@cosmicdrift/kumiko-headless": "0.
|
|
139
|
-
"@cosmicdrift/kumiko-renderer": "0.
|
|
140
|
-
"@cosmicdrift/kumiko-renderer-web": "0.
|
|
141
|
-
"@cosmicdrift/kumiko-types": "0.
|
|
136
|
+
"@cosmicdrift/kumiko-dispatcher-live": "0.308.0",
|
|
137
|
+
"@cosmicdrift/kumiko-framework": "0.308.0",
|
|
138
|
+
"@cosmicdrift/kumiko-headless": "0.308.0",
|
|
139
|
+
"@cosmicdrift/kumiko-renderer": "0.308.0",
|
|
140
|
+
"@cosmicdrift/kumiko-renderer-web": "0.308.0",
|
|
141
|
+
"@cosmicdrift/kumiko-types": "0.308.0",
|
|
142
142
|
"@mollie/api-client": "^4.5.0",
|
|
143
143
|
"@node-rs/argon2": "^2.0.2",
|
|
144
144
|
"@types/mailparser": "^3.4.6",
|
|
@@ -167,8 +167,8 @@
|
|
|
167
167
|
],
|
|
168
168
|
"devDependencies": {
|
|
169
169
|
"@testing-library/user-event": "^14.6.1",
|
|
170
|
-
"@cosmicdrift/kumiko-locale-de": "0.
|
|
171
|
-
"@cosmicdrift/kumiko-locale-es": "0.
|
|
170
|
+
"@cosmicdrift/kumiko-locale-de": "0.308.0",
|
|
171
|
+
"@cosmicdrift/kumiko-locale-es": "0.308.0",
|
|
172
172
|
"jsqr": "^1.4.0"
|
|
173
173
|
}
|
|
174
174
|
}
|
|
@@ -44,6 +44,11 @@ import { createAuthEmailPasswordFeature } from "../auth-email-password/feature";
|
|
|
44
44
|
import { createConfigFeature } from "../config";
|
|
45
45
|
import { createConfigResolver } from "../config/resolver";
|
|
46
46
|
import { configValuesTable } from "../config/table";
|
|
47
|
+
import { PatHandlers } from "../personal-access-tokens/constants";
|
|
48
|
+
import { createPersonalAccessTokensFeature } from "../personal-access-tokens/feature";
|
|
49
|
+
import { revokeAllPatTokensForUser } from "../personal-access-tokens/revoke-for-user";
|
|
50
|
+
import { apiTokenEntity, apiTokenTable } from "../personal-access-tokens/schema/api-token";
|
|
51
|
+
import type { PatScopeConfig } from "../personal-access-tokens/scopes";
|
|
47
52
|
import { makeSessionHelpers } from "../sessions/__tests__/test-helpers";
|
|
48
53
|
import { SessionHandlers } from "../sessions/constants";
|
|
49
54
|
import { createSessionsFeature } from "../sessions/feature";
|
|
@@ -66,6 +71,10 @@ const callbacks = createLateBoundHolder<SessionCallbacks>("session-callbacks");
|
|
|
66
71
|
const encryptionKey = randomBytes(32).toString("base64");
|
|
67
72
|
const TENANT = testTenantId(1);
|
|
68
73
|
|
|
74
|
+
const PAT_SCOPES: PatScopeConfig = {
|
|
75
|
+
probe: { label: "Probe", read: ["personal-access-tokens:query:mine"] },
|
|
76
|
+
};
|
|
77
|
+
|
|
69
78
|
// Collects every userId the consumer pushed an invalidation for during the
|
|
70
79
|
// running test, in push order. Reset in beforeEach.
|
|
71
80
|
let invalidated: string[];
|
|
@@ -90,6 +99,10 @@ beforeAll(async () => {
|
|
|
90
99
|
createAuthEmailPasswordFeature(),
|
|
91
100
|
authFoundationFeature,
|
|
92
101
|
createSessionsFeature({ autoRevokeOnPasswordChange: bound.asMassRevoker() }),
|
|
102
|
+
createPersonalAccessTokensFeature({
|
|
103
|
+
scopes: PAT_SCOPES,
|
|
104
|
+
autoRevokeOnPasswordChange: (userId) => revokeAllPatTokensForUser(stack.db, userId),
|
|
105
|
+
}),
|
|
93
106
|
],
|
|
94
107
|
extraContext: { configResolver: resolver, configEncryption: encryption },
|
|
95
108
|
authConfig: {
|
|
@@ -107,6 +120,7 @@ beforeAll(async () => {
|
|
|
107
120
|
await unsafeCreateEntityTable(stack.db, userEntity);
|
|
108
121
|
await unsafeCreateEntityTable(stack.db, tenantEntity);
|
|
109
122
|
await unsafeCreateEntityTable(stack.db, userSessionEntity);
|
|
123
|
+
await unsafeCreateEntityTable(stack.db, apiTokenEntity);
|
|
110
124
|
await unsafePushTables(stack.db, { configValuesTable, tenantMembershipsTable });
|
|
111
125
|
});
|
|
112
126
|
|
|
@@ -119,6 +133,7 @@ beforeEach(async () => {
|
|
|
119
133
|
userTable,
|
|
120
134
|
tenantMembershipsTable,
|
|
121
135
|
userSessionTable,
|
|
136
|
+
apiTokenTable,
|
|
122
137
|
eventsTable,
|
|
123
138
|
]);
|
|
124
139
|
invalidated = [];
|
|
@@ -309,4 +324,96 @@ describe("access-invalidation event consumer", () => {
|
|
|
309
324
|
expect(sessionRow).toBeTruthy();
|
|
310
325
|
expect(sessionRow?.revokedAt).not.toBeNull();
|
|
311
326
|
});
|
|
327
|
+
|
|
328
|
+
test("session-revoked via logout (sessionRevoker, streamScope: revoked-sessions) still pushes an invalidation for that user", async () => {
|
|
329
|
+
const { userId } = await h.seedUser("logout-invalidates@example.com", "pw-long-enough");
|
|
330
|
+
const { token } = await h.login("logout-invalidates@example.com", "pw-long-enough");
|
|
331
|
+
trackInvalidation(userId);
|
|
332
|
+
|
|
333
|
+
// The raw sessionRevoker callback behind /api/auth/logout used to append
|
|
334
|
+
// no event at all — it now sets streamScope: "revoked-sessions"
|
|
335
|
+
// instead of the old userwide default, but a broad
|
|
336
|
+
// subscribeAccessInvalidation listener (no credential passed here, same
|
|
337
|
+
// as every other test in this file) still fires: this proves the new
|
|
338
|
+
// narrow scope still reaches the consumer, not just the pre-existing
|
|
339
|
+
// userwide paths above.
|
|
340
|
+
const logoutRes = await h.authedPost("/api/auth/logout", token);
|
|
341
|
+
expect(logoutRes.status).toBe(200);
|
|
342
|
+
|
|
343
|
+
const events = await selectMany(stack.db, eventsTable, {
|
|
344
|
+
type: "sessions:event:session-revoked",
|
|
345
|
+
});
|
|
346
|
+
expect(events.length).toBeGreaterThan(0);
|
|
347
|
+
|
|
348
|
+
await stack.eventDispatcher?.runOnce();
|
|
349
|
+
|
|
350
|
+
expect(invalidated).toEqual([userId]);
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
test("pat-revoked (self-service PAT revoke) pushes an invalidation for that user", async () => {
|
|
354
|
+
const { userId } = await h.seedUser("pat-revoke-invalidates@example.com", "pw-long-enough");
|
|
355
|
+
const { token } = await h.login("pat-revoke-invalidates@example.com", "pw-long-enough");
|
|
356
|
+
trackInvalidation(userId);
|
|
357
|
+
|
|
358
|
+
const mint = await h.authedPost("/api/write", token, {
|
|
359
|
+
type: PatHandlers.create,
|
|
360
|
+
payload: {
|
|
361
|
+
name: "probe",
|
|
362
|
+
scopes: ["probe:read"],
|
|
363
|
+
currentPassword: "pw-long-enough",
|
|
364
|
+
},
|
|
365
|
+
});
|
|
366
|
+
expect(mint.status).toBe(200);
|
|
367
|
+
const { data } = (await mint.json()) as { data: { id: string } };
|
|
368
|
+
|
|
369
|
+
const revokeRes = await h.authedPost("/api/write", token, {
|
|
370
|
+
type: PatHandlers.revoke,
|
|
371
|
+
payload: { id: data.id },
|
|
372
|
+
});
|
|
373
|
+
expect(revokeRes.status).toBe(200);
|
|
374
|
+
|
|
375
|
+
const events = await selectMany(stack.db, eventsTable, {
|
|
376
|
+
type: "personal-access-tokens:event:pat-revoked",
|
|
377
|
+
});
|
|
378
|
+
expect(events.length).toBeGreaterThan(0);
|
|
379
|
+
|
|
380
|
+
await stack.eventDispatcher?.runOnce();
|
|
381
|
+
|
|
382
|
+
expect(invalidated).toEqual([userId]);
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
test("revokeAllPatTokensForUser (password-change auto-revoke) pushes an invalidation for that user", async () => {
|
|
386
|
+
const { userId } = await h.seedUser("pat-mass-invalidates@example.com", "old-pw-long-enough");
|
|
387
|
+
const { token } = await h.login("pat-mass-invalidates@example.com", "old-pw-long-enough");
|
|
388
|
+
trackInvalidation(userId);
|
|
389
|
+
|
|
390
|
+
const mint = await h.authedPost("/api/write", token, {
|
|
391
|
+
type: PatHandlers.create,
|
|
392
|
+
payload: {
|
|
393
|
+
name: "probe",
|
|
394
|
+
scopes: ["probe:read"],
|
|
395
|
+
currentPassword: "old-pw-long-enough",
|
|
396
|
+
},
|
|
397
|
+
});
|
|
398
|
+
expect(mint.status).toBe(200);
|
|
399
|
+
|
|
400
|
+
const res = await h.authedPost("/api/write", token, {
|
|
401
|
+
type: AuthHandlers.changePassword,
|
|
402
|
+
payload: { oldPassword: "old-pw-long-enough", newPassword: "new-pw-long-enough" },
|
|
403
|
+
});
|
|
404
|
+
expect(res.status).toBe(200);
|
|
405
|
+
|
|
406
|
+
const events = await selectMany(stack.db, eventsTable, {
|
|
407
|
+
type: "personal-access-tokens:event:pat-revoked",
|
|
408
|
+
});
|
|
409
|
+
expect(events.length).toBeGreaterThan(0);
|
|
410
|
+
|
|
411
|
+
await stack.eventDispatcher?.runOnce();
|
|
412
|
+
|
|
413
|
+
// A password change fires both sessionMassRevoker (userwide,
|
|
414
|
+
// session-revoked) and this suite's PAT autoRevokeOnPasswordChange
|
|
415
|
+
// (pat-tokens-scoped, pat-revoked) — the broad listener here (no
|
|
416
|
+
// credential passed) fires once per publish, so twice for the same user.
|
|
417
|
+
expect(invalidated).toEqual([userId, userId]);
|
|
418
|
+
});
|
|
312
419
|
});
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
createTestEnvelopeCipher,
|
|
27
27
|
resetTestTables,
|
|
28
28
|
} from "@cosmicdrift/kumiko-framework/testing";
|
|
29
|
-
import
|
|
29
|
+
import * as z from "zod";
|
|
30
30
|
import { AuthHandlers } from "../auth-email-password/constants";
|
|
31
31
|
import { createAuthEmailPasswordFeature } from "../auth-email-password/feature";
|
|
32
32
|
import { createConfigFeature } from "../config";
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
// Credential-scoped SSE revoke.
|
|
2
|
+
//
|
|
3
|
+
// Logout/tenant-switch (sessionRevoker, session-callbacks.ts) and PAT revoke
|
|
4
|
+
// (revoke.write.ts / revokeAllPatTokensForUser) used to make no event at
|
|
5
|
+
// all, so the access-invalidation consumer never heard about them and an
|
|
6
|
+
// already-open SSE stream on that exact credential survived until its
|
|
7
|
+
// JWT/token expired on its own. Both now append a scoped session-revoked /
|
|
8
|
+
// pat-revoked event and the consumer closes exactly the matching stream(s),
|
|
9
|
+
// leaving every other credential's stream of the same user open.
|
|
10
|
+
//
|
|
11
|
+
// Real stack throughout: setupTestStack + real HTTP (createLiveDispatcher for
|
|
12
|
+
// the SSE streams, stack.http/h.authedPost for the writes), never
|
|
13
|
+
// createTestDispatcher.
|
|
14
|
+
|
|
15
|
+
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test";
|
|
16
|
+
import { randomBytes } from "node:crypto";
|
|
17
|
+
import {
|
|
18
|
+
authFoundationFeature,
|
|
19
|
+
resolveTokenVerifier,
|
|
20
|
+
} from "@cosmicdrift/kumiko-bundled-features/auth-foundation";
|
|
21
|
+
import { createLiveDispatcher } from "@cosmicdrift/kumiko-dispatcher-live";
|
|
22
|
+
import type { SessionCreator } from "@cosmicdrift/kumiko-framework/api";
|
|
23
|
+
import { createInMemoryLoginRateLimiter, generateToken } from "@cosmicdrift/kumiko-framework/api";
|
|
24
|
+
import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
|
|
25
|
+
import { eventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
26
|
+
import {
|
|
27
|
+
setupTestStack,
|
|
28
|
+
type TestStack,
|
|
29
|
+
testTenantId,
|
|
30
|
+
unsafeCreateEntityTable,
|
|
31
|
+
unsafePushTables,
|
|
32
|
+
} from "@cosmicdrift/kumiko-framework/stack";
|
|
33
|
+
import {
|
|
34
|
+
createLateBoundHolder,
|
|
35
|
+
createTestEnvelopeCipher,
|
|
36
|
+
resetTestTables,
|
|
37
|
+
} from "@cosmicdrift/kumiko-framework/testing";
|
|
38
|
+
import * as z from "zod";
|
|
39
|
+
import { AuthHandlers } from "../auth-email-password/constants";
|
|
40
|
+
import { createAuthEmailPasswordFeature } from "../auth-email-password/feature";
|
|
41
|
+
import { createConfigFeature } from "../config";
|
|
42
|
+
import { createConfigResolver } from "../config/resolver";
|
|
43
|
+
import { configValuesTable } from "../config/table";
|
|
44
|
+
import { PatHandlers } from "../personal-access-tokens/constants";
|
|
45
|
+
import { createPersonalAccessTokensFeature } from "../personal-access-tokens/feature";
|
|
46
|
+
import { revokeAllPatTokensForUser } from "../personal-access-tokens/revoke-for-user";
|
|
47
|
+
import { apiTokenEntity, apiTokenTable } from "../personal-access-tokens/schema/api-token";
|
|
48
|
+
import type { PatScopeConfig } from "../personal-access-tokens/scopes";
|
|
49
|
+
import { makeSessionHelpers } from "../sessions/__tests__/test-helpers";
|
|
50
|
+
import { createSessionsFeature } from "../sessions/feature";
|
|
51
|
+
import { userSessionEntity, userSessionTable } from "../sessions/schema/user-session";
|
|
52
|
+
import { createSessionCallbacks, type SessionCallbacks } from "../sessions/session-callbacks";
|
|
53
|
+
import { sessionCallbacksFromLateBound } from "../sessions/testing";
|
|
54
|
+
import { createTenantFeature } from "../tenant";
|
|
55
|
+
import { tenantMembershipsTable } from "../tenant/membership-table";
|
|
56
|
+
import { tenantEntity } from "../tenant/schema/tenant";
|
|
57
|
+
import { createUserFeature } from "../user/feature";
|
|
58
|
+
import { userEntity, userTable } from "../user/schema/user";
|
|
59
|
+
|
|
60
|
+
let stack: TestStack;
|
|
61
|
+
let h: ReturnType<typeof makeSessionHelpers>;
|
|
62
|
+
const callbacks = createLateBoundHolder<SessionCallbacks>("session-callbacks");
|
|
63
|
+
|
|
64
|
+
const encryptionKey = randomBytes(32).toString("base64");
|
|
65
|
+
const TENANT = testTenantId(1);
|
|
66
|
+
|
|
67
|
+
const SCOPES: PatScopeConfig = {
|
|
68
|
+
probe: { label: "Probe stream", read: ["stream-probe:stream:probe:tail"] },
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const chunkGates = new Map<string, { promise: Promise<void>; release: () => void }>();
|
|
72
|
+
|
|
73
|
+
function createGate(gateId: string): () => void {
|
|
74
|
+
let release!: () => void;
|
|
75
|
+
const promise = new Promise<void>((resolve) => {
|
|
76
|
+
release = resolve;
|
|
77
|
+
});
|
|
78
|
+
chunkGates.set(gateId, { promise, release });
|
|
79
|
+
return release;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const streamProbeFeature = defineFeature("stream-probe", (r) => {
|
|
83
|
+
r.streamHandler(
|
|
84
|
+
"probe:tail",
|
|
85
|
+
z.object({ gateId: z.string().min(1) }),
|
|
86
|
+
async function* (event) {
|
|
87
|
+
yield { phase: "open" as const };
|
|
88
|
+
const gate = chunkGates.get(event.payload.gateId);
|
|
89
|
+
if (!gate) throw new Error(`missing gate ${event.payload.gateId}`);
|
|
90
|
+
await gate.promise;
|
|
91
|
+
yield { phase: "survived" as const };
|
|
92
|
+
},
|
|
93
|
+
{ access: { roles: ["User"] } },
|
|
94
|
+
);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
function buildLiveFetch(bearerToken: string): {
|
|
98
|
+
readonly fetch: typeof fetch;
|
|
99
|
+
readonly csrfToken: string;
|
|
100
|
+
} {
|
|
101
|
+
const csrfToken = generateToken();
|
|
102
|
+
const fetchImpl = (async (url: unknown, init: RequestInit | undefined) => {
|
|
103
|
+
const reqInit: RequestInit = {
|
|
104
|
+
...(init ?? {}),
|
|
105
|
+
headers: {
|
|
106
|
+
...(init?.headers ?? {}),
|
|
107
|
+
Authorization: `Bearer ${bearerToken}`,
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
return stack.app.request(String(url), reqInit);
|
|
111
|
+
}) as unknown as typeof fetch;
|
|
112
|
+
return { fetch: fetchImpl, csrfToken };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async function openProbeStream(bearerToken: string): Promise<{
|
|
116
|
+
iter: AsyncIterator<{ phase: string }>;
|
|
117
|
+
release: () => void;
|
|
118
|
+
}> {
|
|
119
|
+
const gateId = generateToken();
|
|
120
|
+
const release = createGate(gateId);
|
|
121
|
+
const { fetch, csrfToken } = buildLiveFetch(bearerToken);
|
|
122
|
+
const dispatcher = createLiveDispatcher({ fetch, readCsrf: () => csrfToken });
|
|
123
|
+
const iter = dispatcher
|
|
124
|
+
.stream<{ phase: string }>("stream-probe:stream:probe:tail", { gateId })
|
|
125
|
+
[Symbol.asyncIterator]();
|
|
126
|
+
const first = await iter.next();
|
|
127
|
+
expect(first.done).toBe(false);
|
|
128
|
+
expect(first.value).toEqual({ phase: "open" });
|
|
129
|
+
return { iter, release };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// The append's NOTIFY can wake a dispatcher pass before the test's own
|
|
133
|
+
// runOnce(), and runOnce() skips a consumer that pass is still busy with.
|
|
134
|
+
// Draining first makes the invalidation land before the stream assertions.
|
|
135
|
+
async function deliverPendingEvents(): Promise<void> {
|
|
136
|
+
await stack.eventDispatcher?.drain();
|
|
137
|
+
await stack.eventDispatcher?.runOnce();
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async function mintPat(cookieToken: string): Promise<{ id: string; token: string }> {
|
|
141
|
+
const res = await h.authedPost("/api/write", cookieToken, {
|
|
142
|
+
type: PatHandlers.create,
|
|
143
|
+
payload: {
|
|
144
|
+
name: "probe-token",
|
|
145
|
+
scopes: ["probe:read"],
|
|
146
|
+
currentPassword: "pw-long-enough",
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
expect(res.status).toBe(200);
|
|
150
|
+
const body = (await res.json()) as { data: { id: string; token: string } };
|
|
151
|
+
return body.data;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
beforeAll(async () => {
|
|
155
|
+
const encryption = createTestEnvelopeCipher(encryptionKey);
|
|
156
|
+
const resolver = createConfigResolver({ cipher: encryption });
|
|
157
|
+
const bound = sessionCallbacksFromLateBound(callbacks);
|
|
158
|
+
|
|
159
|
+
stack = await setupTestStack({
|
|
160
|
+
features: [
|
|
161
|
+
createConfigFeature(),
|
|
162
|
+
createUserFeature(),
|
|
163
|
+
createTenantFeature(),
|
|
164
|
+
createAuthEmailPasswordFeature(),
|
|
165
|
+
authFoundationFeature,
|
|
166
|
+
createSessionsFeature({ autoRevokeOnPasswordChange: bound.asMassRevoker() }),
|
|
167
|
+
createPersonalAccessTokensFeature({
|
|
168
|
+
scopes: SCOPES,
|
|
169
|
+
autoRevokeOnPasswordChange: (userId) => revokeAllPatTokensForUser(stack.db, userId),
|
|
170
|
+
}),
|
|
171
|
+
streamProbeFeature,
|
|
172
|
+
],
|
|
173
|
+
extraContext: { configResolver: resolver, configEncryption: encryption },
|
|
174
|
+
authConfig: {
|
|
175
|
+
...bound.asAuthConfig(),
|
|
176
|
+
membershipQuery: "tenant:query:memberships",
|
|
177
|
+
loginHandler: AuthHandlers.login,
|
|
178
|
+
tokenVerifier: (raw: string) =>
|
|
179
|
+
resolveTokenVerifier({ db: stack.db, registry: stack.registry }, raw),
|
|
180
|
+
patRateLimiter: createInMemoryLoginRateLimiter(100, 60_000),
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
callbacks.set(createSessionCallbacks({ db: stack.db }));
|
|
184
|
+
h = makeSessionHelpers(stack, TENANT, bound.asAuthConfig().sessionCreator as SessionCreator);
|
|
185
|
+
|
|
186
|
+
await unsafeCreateEntityTable(stack.db, userEntity);
|
|
187
|
+
await unsafeCreateEntityTable(stack.db, tenantEntity);
|
|
188
|
+
await unsafeCreateEntityTable(stack.db, userSessionEntity);
|
|
189
|
+
await unsafeCreateEntityTable(stack.db, apiTokenEntity);
|
|
190
|
+
await unsafePushTables(stack.db, { configValuesTable, tenantMembershipsTable });
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
afterAll(async () => {
|
|
194
|
+
await stack.cleanup();
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
beforeEach(async () => {
|
|
198
|
+
await resetTestTables(stack.db, [
|
|
199
|
+
userTable,
|
|
200
|
+
tenantMembershipsTable,
|
|
201
|
+
userSessionTable,
|
|
202
|
+
apiTokenTable,
|
|
203
|
+
eventsTable,
|
|
204
|
+
]);
|
|
205
|
+
chunkGates.clear();
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
// Tests release a stream's gate BEFORE asserting it closed: the invalidation
|
|
209
|
+
// already fired during runOnce(), so a revoked stream still rejects, while a
|
|
210
|
+
// stream that was wrongly left open yields its next chunk and fails the
|
|
211
|
+
// assertion instead of hanging on a gate nobody releases.
|
|
212
|
+
describe("logout closes only that cookie session's SSE stream", () => {
|
|
213
|
+
test("session 1 logs out, session 1's stream closes, session 2's stream survives", async () => {
|
|
214
|
+
await h.seedUser("logout-scope@example.com", "pw-long-enough");
|
|
215
|
+
const session1 = await h.login("logout-scope@example.com", "pw-long-enough");
|
|
216
|
+
const session2 = await h.login("logout-scope@example.com", "pw-long-enough");
|
|
217
|
+
|
|
218
|
+
const stream1 = await openProbeStream(session1.token);
|
|
219
|
+
const stream2 = await openProbeStream(session2.token);
|
|
220
|
+
|
|
221
|
+
const logoutRes = await h.authedPost("/api/auth/logout", session1.token);
|
|
222
|
+
expect(logoutRes.status).toBe(200);
|
|
223
|
+
|
|
224
|
+
await deliverPendingEvents();
|
|
225
|
+
|
|
226
|
+
stream1.release();
|
|
227
|
+
|
|
228
|
+
await expect(stream1.iter.next()).rejects.toMatchObject({ code: "access_denied" });
|
|
229
|
+
|
|
230
|
+
stream2.release();
|
|
231
|
+
const survivedChunk = await stream2.iter.next();
|
|
232
|
+
expect(survivedChunk.done).toBe(false);
|
|
233
|
+
expect(survivedChunk.value).toEqual({ phase: "survived" });
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
describe("PAT revoke closes only that token's SSE stream", () => {
|
|
238
|
+
test("revoking PAT1 closes PAT1's stream, PAT2's stream and the cookie stream survive", async () => {
|
|
239
|
+
await h.seedUser("pat-scope@example.com", "pw-long-enough");
|
|
240
|
+
const session = await h.login("pat-scope@example.com", "pw-long-enough");
|
|
241
|
+
const pat1 = await mintPat(session.token);
|
|
242
|
+
const pat2 = await mintPat(session.token);
|
|
243
|
+
|
|
244
|
+
const cookieStream = await openProbeStream(session.token);
|
|
245
|
+
const pat1Stream = await openProbeStream(pat1.token);
|
|
246
|
+
const pat2Stream = await openProbeStream(pat2.token);
|
|
247
|
+
|
|
248
|
+
const revokeRes = await h.authedPost("/api/write", session.token, {
|
|
249
|
+
type: PatHandlers.revoke,
|
|
250
|
+
payload: { id: pat1.id },
|
|
251
|
+
});
|
|
252
|
+
expect(revokeRes.status).toBe(200);
|
|
253
|
+
|
|
254
|
+
await deliverPendingEvents();
|
|
255
|
+
|
|
256
|
+
pat1Stream.release();
|
|
257
|
+
|
|
258
|
+
await expect(pat1Stream.iter.next()).rejects.toMatchObject({ code: "access_denied" });
|
|
259
|
+
|
|
260
|
+
cookieStream.release();
|
|
261
|
+
pat2Stream.release();
|
|
262
|
+
const cookieSurvived = await cookieStream.iter.next();
|
|
263
|
+
expect(cookieSurvived.done).toBe(false);
|
|
264
|
+
expect(cookieSurvived.value).toEqual({ phase: "survived" });
|
|
265
|
+
const pat2Survived = await pat2Stream.iter.next();
|
|
266
|
+
expect(pat2Survived.done).toBe(false);
|
|
267
|
+
expect(pat2Survived.value).toEqual({ phase: "survived" });
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
test("revokeAllPatTokensForUser closes every PAT stream of the user, cookie stream survives", async () => {
|
|
271
|
+
const { userId } = await h.seedUser("pat-mass-scope@example.com", "pw-long-enough");
|
|
272
|
+
const session = await h.login("pat-mass-scope@example.com", "pw-long-enough");
|
|
273
|
+
const pat1 = await mintPat(session.token);
|
|
274
|
+
const pat2 = await mintPat(session.token);
|
|
275
|
+
|
|
276
|
+
const cookieStream = await openProbeStream(session.token);
|
|
277
|
+
const pat1Stream = await openProbeStream(pat1.token);
|
|
278
|
+
const pat2Stream = await openProbeStream(pat2.token);
|
|
279
|
+
|
|
280
|
+
const revokedCount = await revokeAllPatTokensForUser(stack.db, userId);
|
|
281
|
+
expect(revokedCount).toBe(2);
|
|
282
|
+
|
|
283
|
+
await deliverPendingEvents();
|
|
284
|
+
|
|
285
|
+
pat1Stream.release();
|
|
286
|
+
|
|
287
|
+
await expect(pat1Stream.iter.next()).rejects.toMatchObject({ code: "access_denied" });
|
|
288
|
+
pat2Stream.release();
|
|
289
|
+
await expect(pat2Stream.iter.next()).rejects.toMatchObject({ code: "access_denied" });
|
|
290
|
+
|
|
291
|
+
cookieStream.release();
|
|
292
|
+
const cookieSurvived = await cookieStream.iter.next();
|
|
293
|
+
expect(cookieSurvived.done).toBe(false);
|
|
294
|
+
expect(cookieSurvived.value).toEqual({ phase: "survived" });
|
|
295
|
+
});
|
|
296
|
+
});
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
defineWriteHandler,
|
|
5
5
|
resolveAgentExposure,
|
|
6
6
|
} from "@cosmicdrift/kumiko-framework/engine";
|
|
7
|
-
import
|
|
7
|
+
import * as z from "zod";
|
|
8
8
|
import { AgentDocGapKinds, findAgentDocGaps, formatAgentDocGap } from "../agent-doc-lint";
|
|
9
9
|
|
|
10
10
|
const OPEN_ACCESS = {
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
defineFeature,
|
|
8
8
|
} from "@cosmicdrift/kumiko-framework/engine";
|
|
9
9
|
import type { ReferenceFieldDef, TextFieldDef } from "@cosmicdrift/kumiko-framework/engine/types";
|
|
10
|
-
import
|
|
10
|
+
import * as z from "zod";
|
|
11
11
|
import { buildAgentManifest } from "../agent-manifest";
|
|
12
12
|
|
|
13
13
|
const gatedEntity = createEntity({
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
defineEntityListHandler,
|
|
8
8
|
defineFeature,
|
|
9
9
|
} from "@cosmicdrift/kumiko-framework/engine";
|
|
10
|
-
import
|
|
10
|
+
import * as z from "zod";
|
|
11
11
|
import { authFoundationFeature } from "../../auth-foundation";
|
|
12
12
|
import { AuthMfaHandlers, AuthMfaQueries, createAuthMfaFeature } from "../../auth-mfa";
|
|
13
13
|
import { createConfigFeature } from "../../config";
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
type TestStack,
|
|
17
17
|
unsafeCreateEntityTable,
|
|
18
18
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
19
|
-
import
|
|
19
|
+
import * as z from "zod";
|
|
20
20
|
import { buildAgentManifest } from "../agent-manifest";
|
|
21
21
|
import { buildToolCatalog, toolNameForQn } from "../tool-catalog";
|
|
22
22
|
import type { ToolDispatcher } from "../tool-dispatch";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, expect, spyOn, test } from "bun:test";
|
|
2
2
|
import { defineFeature, validateBoot } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
|
-
import
|
|
3
|
+
import * as z from "zod";
|
|
4
4
|
import { AGENT_TOOLS_FEATURE_NAME, createAgentToolsFeature } from "../feature";
|
|
5
5
|
|
|
6
6
|
async function noopWriteHandler() {
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
createTextField,
|
|
7
7
|
defineFeature,
|
|
8
8
|
} from "@cosmicdrift/kumiko-framework/engine";
|
|
9
|
-
import
|
|
9
|
+
import * as z from "zod";
|
|
10
10
|
import { buildAgentManifest } from "../agent-manifest";
|
|
11
11
|
import { buildToolCatalog, toolNameForQn } from "../tool-catalog";
|
|
12
12
|
import type { AgentManifest, AgentToolMode, RegistrySearchView } from "../types";
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
type TestStack,
|
|
13
13
|
testTenantId,
|
|
14
14
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
15
|
-
import
|
|
15
|
+
import * as z from "zod";
|
|
16
16
|
import { createConfigFeature } from "../../config";
|
|
17
17
|
import { createTenantFeature } from "../../tenant";
|
|
18
18
|
import { createUserFeature } from "../../user";
|
|
@@ -2,7 +2,7 @@ import type { DbConnection } from "@cosmicdrift/kumiko-framework/db";
|
|
|
2
2
|
import type { EscapeHatchAuditSink, EscapeHatchKind } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
3
|
import { append } from "@cosmicdrift/kumiko-framework/event-store";
|
|
4
4
|
import { generateId } from "@cosmicdrift/kumiko-framework/utils";
|
|
5
|
-
import
|
|
5
|
+
import * as z from "zod";
|
|
6
6
|
|
|
7
7
|
export const ESCAPE_HATCH_USED_EVENT = "audit:event:escape-hatch-used";
|
|
8
8
|
export const ESCAPE_HATCH_USE_AGGREGATE_TYPE = "escapeHatchUse";
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
6
6
|
import { access, defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
|
|
7
7
|
import { eventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
8
|
-
import
|
|
8
|
+
import * as z from "zod";
|
|
9
9
|
|
|
10
10
|
export const detailsQuery = defineQueryHandler({
|
|
11
11
|
name: "details",
|
|
@@ -15,7 +15,7 @@ import { selectMany, type WhereObject } from "@cosmicdrift/kumiko-framework/bun-
|
|
|
15
15
|
import { access, defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
|
|
16
16
|
import { eventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
17
17
|
import { Temporal } from "temporal-polyfill";
|
|
18
|
-
import
|
|
18
|
+
import * as z from "zod";
|
|
19
19
|
|
|
20
20
|
const MAX_LIMIT = 100;
|
|
21
21
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { defineFeature, type FeatureDefinition } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
|
-
import
|
|
2
|
+
import * as z from "zod";
|
|
3
3
|
import { MIN_HMAC_SECRET_LENGTH } from "./constants";
|
|
4
4
|
import type { AuthMailLocale } from "./email-templates";
|
|
5
5
|
import { changePasswordWrite } from "./handlers/change-password.write";
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
defineWriteHandler,
|
|
5
5
|
SYSTEM_TENANT_ID,
|
|
6
6
|
} from "@cosmicdrift/kumiko-framework/engine";
|
|
7
|
-
import
|
|
7
|
+
import * as z from "zod";
|
|
8
8
|
import { hashPassword, verifyPassword } from "../../shared";
|
|
9
9
|
import { UserHandlers, UserQueries } from "../../user";
|
|
10
10
|
import { invalidCredentials } from "../errors";
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
UnprocessableError,
|
|
5
5
|
writeFailure,
|
|
6
6
|
} from "@cosmicdrift/kumiko-framework/errors";
|
|
7
|
-
import
|
|
7
|
+
import * as z from "zod";
|
|
8
8
|
import { AuthErrors } from "../constants";
|
|
9
9
|
import { invalidUnlockToken } from "../errors";
|
|
10
10
|
import { clearLockoutState } from "../lockout-store";
|
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
type TenantId,
|
|
32
32
|
} from "@cosmicdrift/kumiko-framework/engine";
|
|
33
33
|
import { InternalError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
|
|
34
|
-
import
|
|
34
|
+
import * as z from "zod";
|
|
35
35
|
import { decryptStoredPii, sessionLocaleField, sessionTimezoneField } from "../../shared";
|
|
36
36
|
// kumiko-lint-ignore cross-feature-import invite-flow
|
|
37
37
|
import {
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
type TenantId,
|
|
24
24
|
} from "@cosmicdrift/kumiko-framework/engine";
|
|
25
25
|
import { InternalError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
|
|
26
|
-
import
|
|
26
|
+
import * as z from "zod";
|
|
27
27
|
import { decryptStoredPii } from "../../shared";
|
|
28
28
|
// kumiko-lint-ignore cross-feature-import invite-flow lebt in auth-email-password (Magic-Link), DB-row-owner ist tenant-feature
|
|
29
29
|
import {
|