@cosmicdrift/kumiko-bundled-features 0.236.0 → 0.237.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/admin-shell/feature.ts +4 -0
- package/src/agent-tools/__tests__/agent-doc-lint.test.ts +53 -1
- package/src/audit/feature.ts +4 -0
- package/src/audit/handlers/details.query.ts +2 -0
- package/src/audit/handlers/list.query.ts +2 -0
- package/src/auth-email-password/handlers/change-password.write.ts +2 -0
- package/src/auth-email-password/handlers/confirm-account-unlock.write.ts +1 -0
- package/src/auth-email-password/handlers/invite-accept-with-login.write.ts +1 -0
- package/src/auth-email-password/handlers/invite-accept.write.ts +1 -0
- package/src/auth-email-password/handlers/invite-create.write.ts +2 -0
- package/src/auth-email-password/handlers/invite-signup-complete.write.ts +1 -0
- package/src/auth-email-password/handlers/login.write.ts +2 -0
- package/src/auth-email-password/handlers/logout.write.ts +2 -0
- package/src/auth-email-password/handlers/request-account-unlock.write.ts +2 -0
- package/src/auth-email-password/handlers/request-email-verification.write.ts +2 -0
- package/src/auth-email-password/handlers/request-password-reset.write.ts +2 -0
- package/src/auth-email-password/handlers/reset-password.write.ts +1 -0
- package/src/auth-email-password/handlers/self-registration-status.query.ts +2 -0
- package/src/auth-email-password/handlers/signup-confirm.write.ts +1 -0
- package/src/auth-email-password/handlers/signup-request.write.ts +2 -0
- package/src/auth-email-password/handlers/token-request-handler.ts +4 -0
- package/src/auth-email-password/handlers/verify-email.write.ts +1 -0
- package/src/auth-mfa/feature.ts +2 -0
- package/src/auth-mfa/handlers/disable.write.ts +3 -0
- package/src/auth-mfa/handlers/enable-confirm-preauth.write.ts +2 -0
- package/src/auth-mfa/handlers/enable-confirm.write.ts +2 -0
- package/src/auth-mfa/handlers/enable-start-preauth.write.ts +2 -0
- package/src/auth-mfa/handlers/enable-start.write.ts +2 -0
- package/src/auth-mfa/handlers/regenerate-recovery.write.ts +3 -0
- package/src/auth-mfa/handlers/status.query.ts +2 -0
- package/src/auth-mfa/handlers/verify.write.ts +2 -0
- package/src/auth-mfa/schema/user-mfa.ts +2 -0
- package/src/billing-foundation/handlers/create-checkout-session.write.ts +2 -0
- package/src/billing-foundation/handlers/create-portal-session.write.ts +2 -0
- package/src/billing-foundation/handlers/list-subscriptions.query.ts +2 -0
- package/src/billing-foundation/handlers/process-event.write.ts +1 -0
- package/src/cap-counter/entity.ts +2 -0
- package/src/cap-counter/feature.ts +7 -1
- package/src/cap-counter/handlers/get-counter.query.ts +2 -0
- package/src/cap-counter/handlers/increment-rolling.write.ts +1 -0
- package/src/cap-counter/handlers/increment.write.ts +1 -0
- package/src/cap-counter/handlers/mark-soft-warned.write.ts +1 -0
- package/src/cap-overview/handlers/caps-usage.query.ts +2 -0
- package/src/cap-overview/handlers/tenant-caps-list.query.ts +2 -0
- package/src/cap-overview/handlers/tenant-options.query.ts +2 -0
- package/src/channel-in-app/handlers/inbox.query.ts +2 -0
- package/src/channel-in-app/handlers/mark-all-read.write.ts +2 -0
- package/src/channel-in-app/handlers/mark-read.write.ts +2 -0
- package/src/channel-in-app/handlers/unread-count.query.ts +2 -0
- package/src/compliance-profiles/handlers/for-tenant.query.ts +2 -0
- package/src/compliance-profiles/handlers/list-profiles.query.ts +2 -0
- package/src/compliance-profiles/handlers/needs-profile.query.ts +2 -0
- package/src/compliance-profiles/handlers/set-profile.write.ts +2 -0
- package/src/compliance-profiles/handlers/sub-processors.query.ts +2 -0
- package/src/compliance-profiles-ops/handlers/tenants-missing-profile.query.ts +2 -0
- package/src/config/handlers/cascade.query.ts +2 -0
- package/src/config/handlers/readiness.query.ts +2 -0
- package/src/config/handlers/reset.write.ts +3 -0
- package/src/config/handlers/schema.query.ts +2 -0
- package/src/config/handlers/set.write.ts +2 -0
- package/src/config/handlers/values.query.ts +2 -0
- package/src/crypto-shredding/handlers/forget-subject.write.ts +3 -0
- package/src/custom-fields/entity.ts +2 -0
- package/src/custom-fields/feature.ts +2 -0
- package/src/custom-fields/handlers/clear-custom-field.write.ts +2 -0
- package/src/custom-fields/handlers/define-system-field.write.ts +2 -0
- package/src/custom-fields/handlers/define-tenant-field.write.ts +2 -0
- package/src/custom-fields/handlers/delete-system-field.write.ts +3 -0
- package/src/custom-fields/handlers/delete-tenant-field.write.ts +3 -0
- package/src/custom-fields/handlers/set-custom-field.write.ts +2 -0
- package/src/custom-fields/handlers/update-tenant-field.write.ts +2 -0
- package/src/data-retention/handlers/policy-for.query.ts +2 -0
- package/src/delivery/handlers/log.query.ts +2 -0
- package/src/delivery/handlers/preferences.query.ts +2 -0
- package/src/delivery/handlers/set-preference.write.ts +2 -0
- package/src/feature-toggles/handlers/list.query.ts +2 -0
- package/src/feature-toggles/handlers/registered.query.ts +2 -0
- package/src/feature-toggles/handlers/set.write.ts +2 -0
- package/src/file-derivatives/handlers/public-variant.query.ts +1 -0
- package/src/folders/entity.ts +4 -0
- package/src/folders/feature.ts +35 -5
- package/src/folders/handlers/clear-folder.write.ts +2 -0
- package/src/folders/handlers/delete-folder.write.ts +3 -0
- package/src/folders/handlers/set-folder.write.ts +2 -0
- package/src/form-draft/handlers/discard.write.ts +3 -0
- package/src/form-draft/handlers/get.query.ts +2 -0
- package/src/form-draft/handlers/list.query.ts +2 -0
- package/src/form-draft/handlers/save.write.ts +2 -0
- package/src/inbound-mail-foundation/handlers/connect-account.write.ts +2 -0
- package/src/inbound-mail-foundation/handlers/disconnect-account.write.ts +3 -0
- package/src/inbound-mail-foundation/handlers/ingest-message.write.ts +1 -0
- package/src/inbound-mail-foundation/handlers/list-accounts.query.ts +2 -0
- package/src/inbound-mail-foundation/handlers/list-messages.query.ts +2 -0
- package/src/inbound-mail-foundation/handlers/update-account.write.ts +2 -0
- package/src/jobs/feature.ts +4 -0
- package/src/jobs/handlers/catalog.query.ts +2 -0
- package/src/jobs/handlers/detail.query.ts +2 -0
- package/src/jobs/handlers/list.query.ts +2 -0
- package/src/jobs/handlers/retry.write.ts +2 -0
- package/src/jobs/handlers/trigger.write.ts +2 -0
- package/src/ledger/entity.ts +6 -0
- package/src/ledger/feature.ts +70 -10
- package/src/ledger/handlers/confirm-schedule-period.write.ts +2 -0
- package/src/ledger/handlers/create-transaction.write.ts +2 -0
- package/src/ledger/handlers/reports.query.ts +6 -0
- package/src/ledger/handlers/reverse-transaction.write.ts +2 -0
- package/src/managed-pages/feature.ts +4 -23
- package/src/managed-pages/handlers/branding.query.ts +2 -0
- package/src/managed-pages/handlers/by-slug.query.ts +2 -0
- package/src/managed-pages/handlers/by-tenant-published.query.ts +2 -0
- package/src/managed-pages/handlers/page-crud.ts +49 -0
- package/src/managed-pages/handlers/set.write.ts +2 -0
- package/src/managed-pages/table.ts +2 -0
- package/src/notes-history/entity.ts +2 -0
- package/src/notes-history/feature.ts +7 -1
- package/src/notes-history/handlers/add-note.write.ts +2 -0
- package/src/personal-access-tokens/feature.ts +2 -0
- package/src/personal-access-tokens/handlers/available-scopes.query.ts +2 -0
- package/src/personal-access-tokens/handlers/create.write.ts +2 -0
- package/src/personal-access-tokens/handlers/list.query.ts +2 -0
- package/src/personal-access-tokens/handlers/revoke.write.ts +3 -0
- package/src/rate-limiting/handlers/status.query.ts +2 -0
- package/src/readiness/handlers/status.query.ts +2 -0
- package/src/secrets/handlers/delete.write.ts +3 -0
- package/src/secrets/handlers/list.query.ts +2 -0
- package/src/secrets/handlers/set.write.ts +2 -0
- package/src/secrets/table.ts +2 -0
- package/src/seo/handlers/seo-config.query.ts +2 -0
- package/src/sessions/handlers/detail.query.ts +2 -0
- package/src/sessions/handlers/list.query.ts +2 -0
- package/src/sessions/handlers/mine.query.ts +2 -0
- package/src/sessions/handlers/revoke-all-for-user.write.ts +3 -0
- package/src/sessions/handlers/revoke-all-others.write.ts +3 -0
- package/src/sessions/handlers/revoke.write.ts +3 -0
- package/src/tags/entity.ts +4 -0
- package/src/tags/feature.ts +39 -6
- package/src/tags/handlers/assign-tag.write.ts +2 -0
- package/src/tags/handlers/create-tag.write.ts +2 -0
- package/src/tags/handlers/delete-tag.write.ts +3 -0
- package/src/tags/handlers/remove-tag.write.ts +2 -0
- package/src/tags/handlers/update-tag.write.ts +2 -0
- package/src/template-resolver/handlers/by-slug.query.ts +2 -0
- package/src/template-resolver/handlers/by-tenant.query.ts +2 -0
- package/src/template-resolver/handlers/collection-item.query.ts +4 -0
- package/src/template-resolver/handlers/collection-list.query.ts +4 -0
- package/src/template-resolver/handlers/collection-set.write.ts +4 -0
- package/src/template-resolver/handlers/find-by-id.query.ts +2 -0
- package/src/template-resolver/handlers/list.query.ts +2 -0
- package/src/template-resolver/handlers/set.write.ts +2 -0
- package/src/template-resolver/handlers/toggle-status.write.ts +12 -3
- package/src/template-resolver/handlers/upsert-system.write.ts +2 -0
- package/src/template-resolver/handlers/upsert-tenant.write.ts +2 -0
- package/src/tenant/feature.ts +15 -3
- package/src/tenant/handlers/active-tenant-ids.query.ts +2 -0
- package/src/tenant/handlers/add-member.write.ts +2 -0
- package/src/tenant/handlers/cancel-invitation.write.ts +2 -0
- package/src/tenant/handlers/create.write.ts +2 -0
- package/src/tenant/handlers/invitations.query.ts +2 -0
- package/src/tenant/handlers/list.query.ts +2 -0
- package/src/tenant/handlers/me.query.ts +2 -0
- package/src/tenant/handlers/members.query.ts +2 -0
- package/src/tenant/handlers/memberships.query.ts +2 -0
- package/src/tenant/handlers/remove-member.write.ts +3 -0
- package/src/tenant/handlers/resolve-user-ids.query.ts +1 -0
- package/src/tenant/handlers/team-list.query.ts +2 -0
- package/src/tenant/handlers/toggle-enabled.write.ts +3 -0
- package/src/tenant/handlers/update-member-roles.write.ts +2 -0
- package/src/tenant/handlers/update.write.ts +2 -0
- package/src/tenant/schema/tenant.ts +2 -0
- package/src/tenant-lifecycle/handlers/cancel-destruction.write.ts +2 -0
- package/src/tenant-lifecycle/handlers/request-destruction.write.ts +3 -0
- package/src/tier-engine/entity.ts +2 -0
- package/src/tier-engine/feature.ts +25 -3
- package/src/tier-engine/handlers/active-tier.query.ts +2 -0
- package/src/tier-engine/handlers/get-tenant-tier.query.ts +2 -0
- package/src/tier-engine/handlers/set-tenant-tier.write.ts +2 -0
- package/src/user/handlers/create.write.ts +2 -0
- package/src/user/handlers/detail.query.ts +2 -0
- package/src/user/handlers/find-for-auth.query.ts +1 -0
- package/src/user/handlers/list.query.ts +2 -0
- package/src/user/handlers/me.query.ts +2 -0
- package/src/user/handlers/update.write.ts +2 -0
- package/src/user/schema/user.ts +2 -0
- package/src/user-data-rights/feature.ts +2 -0
- package/src/user-data-rights/handlers/cancel-deletion.write.ts +2 -0
- package/src/user-data-rights/handlers/confirm-deletion-by-token.write.ts +1 -0
- package/src/user-data-rights/handlers/download-attempt-list.query.ts +6 -1
- package/src/user-data-rights/handlers/download-by-job.query.ts +2 -0
- package/src/user-data-rights/handlers/download-by-token.query.ts +1 -0
- package/src/user-data-rights/handlers/export-job-detail.query.ts +2 -0
- package/src/user-data-rights/handlers/export-job-list.query.ts +2 -0
- package/src/user-data-rights/handlers/export-status.query.ts +2 -0
- package/src/user-data-rights/handlers/lift-restriction.write.ts +2 -0
- package/src/user-data-rights/handlers/list-download-attempts.query.ts +2 -0
- package/src/user-data-rights/handlers/my-audit-log.query.ts +2 -0
- package/src/user-data-rights/handlers/request-deletion-by-email.write.ts +2 -0
- package/src/user-data-rights/handlers/request-deletion.write.ts +3 -0
- package/src/user-data-rights/handlers/request-export.write.ts +2 -0
- package/src/user-data-rights/handlers/restrict-account.write.ts +3 -0
- package/src/user-data-rights/handlers/run-forget-cleanup.write.ts +1 -0
- package/src/user-data-rights/schema/download-attempt.ts +2 -0
- package/src/user-data-rights/schema/export-job.ts +2 -0
- package/src/user-profile/handlers/change-email.write.ts +2 -0
- package/src/workflow-runner/handlers/resume-run.write.ts +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosmicdrift/kumiko-bundled-features",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.237.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>",
|
|
@@ -130,12 +130,12 @@
|
|
|
130
130
|
"./workflow-runner": "./src/workflow-runner/index.ts"
|
|
131
131
|
},
|
|
132
132
|
"dependencies": {
|
|
133
|
-
"@cosmicdrift/kumiko-dispatcher-live": "0.
|
|
134
|
-
"@cosmicdrift/kumiko-framework": "0.
|
|
135
|
-
"@cosmicdrift/kumiko-headless": "0.
|
|
136
|
-
"@cosmicdrift/kumiko-renderer": "0.
|
|
137
|
-
"@cosmicdrift/kumiko-renderer-web": "0.
|
|
138
|
-
"@cosmicdrift/kumiko-types": "0.
|
|
133
|
+
"@cosmicdrift/kumiko-dispatcher-live": "0.237.0",
|
|
134
|
+
"@cosmicdrift/kumiko-framework": "0.237.0",
|
|
135
|
+
"@cosmicdrift/kumiko-headless": "0.237.0",
|
|
136
|
+
"@cosmicdrift/kumiko-renderer": "0.237.0",
|
|
137
|
+
"@cosmicdrift/kumiko-renderer-web": "0.237.0",
|
|
138
|
+
"@cosmicdrift/kumiko-types": "0.237.0",
|
|
139
139
|
"@mollie/api-client": "^4.5.0",
|
|
140
140
|
"@node-rs/argon2": "^2.0.2",
|
|
141
141
|
"@types/mailparser": "^3.4.6",
|
|
@@ -164,7 +164,7 @@
|
|
|
164
164
|
"devDependencies": {
|
|
165
165
|
"@testing-library/user-event": "^14.6.1",
|
|
166
166
|
"@types/qrcode": "^1.5.5",
|
|
167
|
-
"@cosmicdrift/kumiko-locale-de": "0.
|
|
168
|
-
"@cosmicdrift/kumiko-locale-es": "0.
|
|
167
|
+
"@cosmicdrift/kumiko-locale-de": "0.237.0",
|
|
168
|
+
"@cosmicdrift/kumiko-locale-es": "0.237.0"
|
|
169
169
|
}
|
|
170
170
|
}
|
|
@@ -77,6 +77,8 @@ export function createAdminShellFeature(options: CreateAdminShellOptions = {}):
|
|
|
77
77
|
type: "custom",
|
|
78
78
|
renderer: { react: { __component: "TenantOverviewScreen" } },
|
|
79
79
|
access: { roles: access.admin },
|
|
80
|
+
description:
|
|
81
|
+
"Landing page of the tenant-admin workspace, showing pending invitation, member and missing-config counts for the caller's own tenant so an operator sees what needs attention there.",
|
|
80
82
|
});
|
|
81
83
|
r.nav({
|
|
82
84
|
id: "tenant-overview",
|
|
@@ -92,6 +94,8 @@ export function createAdminShellFeature(options: CreateAdminShellOptions = {}):
|
|
|
92
94
|
type: "custom",
|
|
93
95
|
renderer: { react: { __component: "PlatformOverviewScreen" } },
|
|
94
96
|
access: { roles: access.systemAdmin },
|
|
97
|
+
description:
|
|
98
|
+
"Landing page of the platform-admin workspace, showing installation-wide tenant, user and failed-job counts so a system admin sees the health of the whole deployment at a glance.",
|
|
95
99
|
});
|
|
96
100
|
r.nav({
|
|
97
101
|
id: "platform-overview",
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { describe, expect, test } from "bun:test";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
defineFeature,
|
|
4
|
+
defineWriteHandler,
|
|
5
|
+
resolveAgentExposure,
|
|
6
|
+
} from "@cosmicdrift/kumiko-framework/engine";
|
|
3
7
|
import { z } from "zod";
|
|
4
8
|
import { AgentDocGapKinds, findAgentDocGaps, formatAgentDocGap } from "../agent-doc-lint";
|
|
5
9
|
|
|
@@ -53,6 +57,54 @@ describe("findAgentDocGaps", () => {
|
|
|
53
57
|
expect(findAgentDocGaps([feature])).toHaveLength(0);
|
|
54
58
|
});
|
|
55
59
|
|
|
60
|
+
// defineWriteHandler rebuilds its return value from an explicit field
|
|
61
|
+
// whitelist, so a slot it forgets to copy is invisible here even though the
|
|
62
|
+
// author wrote it — that regression hid 37 bundled descriptions.
|
|
63
|
+
test("R1: description authored through defineWriteHandler survives the def rebuild", () => {
|
|
64
|
+
const feature = defineFeature("doc-gap-demo", (r) => {
|
|
65
|
+
r.writeHandler(
|
|
66
|
+
defineWriteHandler({
|
|
67
|
+
name: "do-a",
|
|
68
|
+
schema: z.object({}),
|
|
69
|
+
access: OPEN_ACCESS,
|
|
70
|
+
description: "Does A.",
|
|
71
|
+
handler: noopWriteHandler,
|
|
72
|
+
}),
|
|
73
|
+
);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
expect(findAgentDocGaps([feature])).toHaveLength(0);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("R1: agent hints authored through defineWriteHandler reach the resolved exposure", () => {
|
|
80
|
+
const optedOut = defineWriteHandler({
|
|
81
|
+
name: "do-internal",
|
|
82
|
+
schema: z.object({}),
|
|
83
|
+
access: OPEN_ACCESS,
|
|
84
|
+
agent: { expose: false },
|
|
85
|
+
handler: noopWriteHandler,
|
|
86
|
+
});
|
|
87
|
+
const destructive = defineWriteHandler({
|
|
88
|
+
name: "do-destroy",
|
|
89
|
+
schema: z.object({}),
|
|
90
|
+
access: OPEN_ACCESS,
|
|
91
|
+
description: "Destroys the thing.",
|
|
92
|
+
agent: { risk: "high" },
|
|
93
|
+
handler: noopWriteHandler,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
expect(resolveAgentExposure(optedOut, "write").expose).toBe(false);
|
|
97
|
+
expect(resolveAgentExposure(destructive, "write").risk).toBe("high");
|
|
98
|
+
expect(
|
|
99
|
+
findAgentDocGaps([
|
|
100
|
+
defineFeature("doc-gap-demo", (r) => {
|
|
101
|
+
r.writeHandler(optedOut);
|
|
102
|
+
r.writeHandler(destructive);
|
|
103
|
+
}),
|
|
104
|
+
]),
|
|
105
|
+
).toHaveLength(0);
|
|
106
|
+
});
|
|
107
|
+
|
|
56
108
|
test("R2: custom screen without description -> exactly one gap with the correct QN", () => {
|
|
57
109
|
const feature = defineFeature("doc-gap-demo", (r) => {
|
|
58
110
|
r.screen({ id: "widget-editor", type: "custom", renderer: { react: "stub" } });
|
package/src/audit/feature.ts
CHANGED
|
@@ -44,6 +44,8 @@ export function createAuditFeature(): FeatureDefinition {
|
|
|
44
44
|
id: AUDIT_LOG_SCREEN_ID,
|
|
45
45
|
type: "custom",
|
|
46
46
|
renderer: { react: { __component: "AuditLogScreen" } },
|
|
47
|
+
description:
|
|
48
|
+
"Admin table of the tenant's audit-trail events with actor names and event-type/date filters; open it to browse recent changes and drill into a single event.",
|
|
47
49
|
access: { roles: access.admin },
|
|
48
50
|
});
|
|
49
51
|
// kumiko-lint-ignore app-feature-structure Phase-3 conversion tracked in #2312
|
|
@@ -51,6 +53,8 @@ export function createAuditFeature(): FeatureDefinition {
|
|
|
51
53
|
id: AUDIT_LOG_DETAIL_SCREEN_ID,
|
|
52
54
|
type: "custom",
|
|
53
55
|
renderer: { react: { __component: "AuditLogDetailScreen" } },
|
|
56
|
+
description:
|
|
57
|
+
"Read-only detail view of one audit event showing actor, timestamp, aggregate and the raw event payload and metadata; reached from a row of the audit log.",
|
|
54
58
|
listScreenId: AUDIT_LOG_SCREEN_ID,
|
|
55
59
|
access: { roles: access.admin },
|
|
56
60
|
});
|
|
@@ -9,6 +9,8 @@ import { z } from "zod";
|
|
|
9
9
|
|
|
10
10
|
export const detailsQuery = defineQueryHandler({
|
|
11
11
|
name: "details",
|
|
12
|
+
description:
|
|
13
|
+
"Returns one audit-trail event of the caller's tenant by its event-store id, with full payload and metadata; use it to inspect the exact change behind a row of the audit log list.",
|
|
12
14
|
schema: z.object({
|
|
13
15
|
id: z.string().regex(/^[1-9]\d*$/, "id must be a positive integer"),
|
|
14
16
|
}),
|
|
@@ -21,6 +21,8 @@ const MAX_LIMIT = 100;
|
|
|
21
21
|
|
|
22
22
|
export const listQuery = defineQueryHandler({
|
|
23
23
|
name: "list",
|
|
24
|
+
description:
|
|
25
|
+
"Lists the tenant's audit-trail events newest-first with cursor paging, filterable by aggregate type, aggregate id, event type, actor and time range; use it to answer who changed what and when.",
|
|
24
26
|
schema: z
|
|
25
27
|
.object({
|
|
26
28
|
before: z.string().regex(/^\d+$/, "cursor must be a positive integer").optional(),
|
|
@@ -21,6 +21,8 @@ export const changePasswordWrite = defineWriteHandler({
|
|
|
21
21
|
newPassword: passwordSchema,
|
|
22
22
|
}),
|
|
23
23
|
access: { roles: access.authenticated },
|
|
24
|
+
description:
|
|
25
|
+
"Replaces the signed-in caller's own password after re-checking the current one; use it for a self-service password change rather than the emailed reset flow.",
|
|
24
26
|
handler: async (event, ctx) => {
|
|
25
27
|
const systemUser = createSystemUser(event.user.tenantId);
|
|
26
28
|
|
|
@@ -30,6 +30,7 @@ export function createConfirmAccountUnlockHandler(opts: ConfirmAccountUnlockOpti
|
|
|
30
30
|
token: z.string().min(1),
|
|
31
31
|
}),
|
|
32
32
|
access: { roles: ["all"] },
|
|
33
|
+
agent: { expose: false },
|
|
33
34
|
handler: async (event, ctx) => {
|
|
34
35
|
if (!opts.hmacSecret) {
|
|
35
36
|
return writeFailure(
|
|
@@ -116,6 +116,7 @@ export function createInviteAcceptWithLoginHandler(opts: InviteAcceptWithLoginOp
|
|
|
116
116
|
name: "invite-accept-with-login",
|
|
117
117
|
schema: InviteAcceptWithLoginSchema,
|
|
118
118
|
access: { roles: ["all"] },
|
|
119
|
+
agent: { expose: false },
|
|
119
120
|
// kumiko-lint-ignore complexity-budget reuses login.write.ts's gate chain (lockout/password/email/status/membership/mfa) plus invite-specific branches (email match, already-member check, invitation update, unburn-on-failure) — splitting would scatter gate order across functions without reducing risk
|
|
120
121
|
handler: async (event, ctx) => {
|
|
121
122
|
if (!ctx.redis) {
|
|
@@ -75,6 +75,7 @@ export function createInviteAcceptHandler() {
|
|
|
75
75
|
// nutzen `roles: ["all"]` weil dort GUEST_USER mit ["all"]-role
|
|
76
76
|
// dispatched wird.
|
|
77
77
|
access: { openToAll: true },
|
|
78
|
+
agent: { expose: false },
|
|
78
79
|
// kumiko-lint-ignore complexity-budget invite branches (auth/anon/burn) stay in one handler
|
|
79
80
|
handler: async (event, ctx) => {
|
|
80
81
|
if (!ctx.redis) {
|
|
@@ -94,6 +94,8 @@ export function createInviteCreateHandler(opts: InviteCreateOptions) {
|
|
|
94
94
|
name: "invite-create",
|
|
95
95
|
schema: InviteCreateSchema,
|
|
96
96
|
access: { roles: access.admin },
|
|
97
|
+
description:
|
|
98
|
+
"Invites an email address into the caller's tenant with a chosen membership role, creating or reusing the invitation and mailing the invitee a fresh accept link; re-inviting the same address invalidates the previous link.",
|
|
97
99
|
handler: async (event, ctx) => {
|
|
98
100
|
if (!ctx.redis) {
|
|
99
101
|
return writeFailure(
|
|
@@ -86,6 +86,7 @@ export function createInviteSignupCompleteHandler() {
|
|
|
86
86
|
name: "invite-signup-complete",
|
|
87
87
|
schema: InviteSignupCompleteSchema,
|
|
88
88
|
access: { roles: ["all"] },
|
|
89
|
+
agent: { expose: false },
|
|
89
90
|
handler: async (event, ctx) => {
|
|
90
91
|
if (!ctx.redis) {
|
|
91
92
|
return writeFailure(
|
|
@@ -263,6 +263,8 @@ export function createLoginHandler(opts: LoginHandlerOptions = {}) {
|
|
|
263
263
|
password: z.string().min(1),
|
|
264
264
|
}),
|
|
265
265
|
access: { roles: ["all"] },
|
|
266
|
+
description:
|
|
267
|
+
"Signs a user in with email and password, running the lockout, email-verification, account-status, tenant-membership and MFA gates, and answering with a session or with an MFA challenge or setup requirement.",
|
|
266
268
|
handler: async (event, ctx): Promise<WriteResult<LoginResult>> => {
|
|
267
269
|
const systemUser = createSystemUser(SYSTEM_USER_ID);
|
|
268
270
|
|
|
@@ -8,6 +8,8 @@ export const logoutWrite = defineWriteHandler({
|
|
|
8
8
|
name: "logout",
|
|
9
9
|
schema: z.object({}),
|
|
10
10
|
access: { roles: access.authenticated },
|
|
11
|
+
description:
|
|
12
|
+
"Acknowledges a sign-out for the authenticated caller so the client can discard its token; the JWT is stateless, so no server-side session state changes here.",
|
|
11
13
|
perform: stepsPipeline(({ r }) => [
|
|
12
14
|
r.step.return({ isSuccess: true, data: { kind: "logged-out" } }),
|
|
13
15
|
]),
|
|
@@ -21,6 +21,8 @@ export function createRequestAccountUnlockHandler(opts: RequestAccountUnlockOpti
|
|
|
21
21
|
{
|
|
22
22
|
handlerName: "request-account-unlock",
|
|
23
23
|
successKind: "unlock-requested",
|
|
24
|
+
description:
|
|
25
|
+
"Mails an address a signed, time-limited link that lets a user clear a failed-login lockout without an operator; it applies whether or not the account is locked right now, and answers identically for unknown addresses.",
|
|
24
26
|
defaultTtlMinutes: AUTH_UNLOCK_DEFAULT_TTL_MINUTES,
|
|
25
27
|
sign: signUnlockToken,
|
|
26
28
|
notConfiguredError: AuthErrors.unlockNotConfigured,
|
|
@@ -19,6 +19,8 @@ export function createRequestEmailVerificationHandler(opts: RequestEmailVerifica
|
|
|
19
19
|
{
|
|
20
20
|
handlerName: "request-email-verification",
|
|
21
21
|
successKind: "verification-requested",
|
|
22
|
+
description:
|
|
23
|
+
"Mails an address a signed, time-limited link to confirm it owns the mailbox; an already-verified address is skipped silently, and the answer looks the same for unknown addresses either way.",
|
|
22
24
|
defaultTtlMinutes: AUTH_VERIFY_DEFAULT_TTL_MINUTES,
|
|
23
25
|
sign: signVerificationToken,
|
|
24
26
|
notConfiguredError: AuthErrors.verificationNotConfigured,
|
|
@@ -21,6 +21,8 @@ export function createRequestPasswordResetHandler(opts: RequestPasswordResetOpti
|
|
|
21
21
|
{
|
|
22
22
|
handlerName: "request-password-reset",
|
|
23
23
|
successKind: "reset-requested",
|
|
24
|
+
description:
|
|
25
|
+
"Starts the emailed password-reset flow for an address by minting a signed, time-limited reset token and mailing the reset link, for any existing non-deleted account regardless of its verification state; the answer is identical for unknown addresses, so it never reveals whether an account exists.",
|
|
24
26
|
defaultTtlMinutes: AUTH_RESET_DEFAULT_TTL_MINUTES,
|
|
25
27
|
sign: signResetToken,
|
|
26
28
|
notConfiguredError: AuthErrors.resetNotConfigured,
|
|
@@ -14,6 +14,8 @@ export const selfRegistrationStatusQuery = defineQueryHandler({
|
|
|
14
14
|
name: "signup-registration-status",
|
|
15
15
|
schema: z.object({}),
|
|
16
16
|
access: { roles: ["anonymous", "User", "TenantAdmin", "SystemAdmin"] },
|
|
17
|
+
description:
|
|
18
|
+
"Reports whether self-registration is currently switched on, readable without signing in, so a signup page can hide its own form instead of collecting an address that would be silently ignored.",
|
|
17
19
|
handler: async (_query, ctx) => {
|
|
18
20
|
// Same fail-open reasoning as signup-request.write.ts (#1468): only
|
|
19
21
|
// report disabled when the toggle feature is actually composed.
|
|
@@ -76,6 +76,8 @@ export function createSignupRequestHandler(opts: SignupRequestOptions) {
|
|
|
76
76
|
name: "signup-request",
|
|
77
77
|
schema: SignupRequestSchema,
|
|
78
78
|
access: { roles: ["all"] },
|
|
79
|
+
description:
|
|
80
|
+
"Starts magic-link self-registration by mailing a fresh activation link to an address and invalidating any link still outstanding for it; the answer looks the same whether or not the address is already registered.",
|
|
79
81
|
handler: async (event, ctx) => {
|
|
80
82
|
// Silent no-op when off, matching the route's own always-200
|
|
81
83
|
// anti-enumeration contract (registerTokenRequestRoute swallows every
|
|
@@ -42,6 +42,9 @@ export type TokenRequestData<K extends string> = TokenRequestSuccess<K> | TokenR
|
|
|
42
42
|
export type TokenRequestSpec<TName extends string, TSuccessKind extends string> = {
|
|
43
43
|
readonly handlerName: TName;
|
|
44
44
|
readonly successKind: TSuccessKind;
|
|
45
|
+
// Per-flow, never derived here — a shared sentence would describe the
|
|
46
|
+
// mechanism instead of the flow the agent is picking between.
|
|
47
|
+
readonly description: string;
|
|
45
48
|
readonly defaultTtlMinutes: number;
|
|
46
49
|
// Feature-specific sign function. Signature matches both signResetToken
|
|
47
50
|
// and signVerificationToken (thin wrappers over signed-token.ts).
|
|
@@ -92,6 +95,7 @@ export function createTokenRequestHandler<TName extends string, TSuccessKind ext
|
|
|
92
95
|
name: spec.handlerName,
|
|
93
96
|
schema: RequestTokenSchema,
|
|
94
97
|
access: { roles: ["all"] },
|
|
98
|
+
description: spec.description,
|
|
95
99
|
handler: async (event, ctx) => {
|
|
96
100
|
if (!opts.hmacSecret) {
|
|
97
101
|
// Feature-factory guards this at boot; defensive here for lazy-
|
|
@@ -27,6 +27,7 @@ export function createVerifyEmailHandler(opts: VerifyEmailOptions) {
|
|
|
27
27
|
name: "verify-email",
|
|
28
28
|
schema: VerifyEmailSchema,
|
|
29
29
|
access: { roles: ["all"] },
|
|
30
|
+
agent: { expose: false },
|
|
30
31
|
handler: async (event, ctx) => {
|
|
31
32
|
if (!opts.hmacSecret) {
|
|
32
33
|
return writeFailure(
|
package/src/auth-mfa/feature.ts
CHANGED
|
@@ -137,6 +137,8 @@ export function createAuthMfaFeature(opts: AuthMfaFeatureOptions): FeatureDefini
|
|
|
137
137
|
renderer: { react: { __component: "MfaEnableScreen" } },
|
|
138
138
|
access: { openToAll: true },
|
|
139
139
|
dormant: true,
|
|
140
|
+
description:
|
|
141
|
+
"Self-service screen where a signed-in user enrolls in TOTP two-factor authentication: it shows the QR code and manual secret, reveals the recovery codes once, and confirms enrollment with a code from their authenticator app.",
|
|
140
142
|
});
|
|
141
143
|
r.translations({ keys: AUTH_MFA_FEATURE_I18N });
|
|
142
144
|
|
|
@@ -31,6 +31,9 @@ export function createDisableHandler(opts: DisableOptions) {
|
|
|
31
31
|
name: "disable",
|
|
32
32
|
schema: z.object({ code: z.string().min(6).max(9) }),
|
|
33
33
|
access: { openToAll: true },
|
|
34
|
+
description:
|
|
35
|
+
"Removes the caller's TOTP enrollment for good after they prove possession with a TOTP or recovery code, and signs their other sessions and access tokens out; use it when a user wants two-factor authentication turned off.",
|
|
36
|
+
agent: { risk: "high" },
|
|
34
37
|
handler: async (event, ctx) => {
|
|
35
38
|
const row = await findUserMfaRow(ctx.db, event.user);
|
|
36
39
|
if (!row) return mfaNotEnabled();
|
|
@@ -64,6 +64,8 @@ export function createEnableConfirmPreauthHandler(opts: EnableConfirmPreauthOpti
|
|
|
64
64
|
code: z.string().length(6),
|
|
65
65
|
}),
|
|
66
66
|
access: { roles: ["all"] },
|
|
67
|
+
description:
|
|
68
|
+
"Completes the enrollment that unblocks a sign-in forced into two-factor setup: verifies the code against the pre-auth setup token, stores the factor and derives the session the blocked login never got.",
|
|
67
69
|
handler: async (event, ctx) => {
|
|
68
70
|
const verify = verifyMfaSetupToken(event.payload.setupToken, opts.setupTokenSecret);
|
|
69
71
|
if (!verify.ok) return invalidSetupToken();
|
|
@@ -38,6 +38,8 @@ export function createEnableConfirmHandler(opts: EnableConfirmOptions) {
|
|
|
38
38
|
code: z.string().length(6),
|
|
39
39
|
}),
|
|
40
40
|
access: { openToAll: true },
|
|
41
|
+
description:
|
|
42
|
+
"Completes TOTP enrollment for the signed-in user by checking a code against the secret carried in the setup token from enable-start, then storing the factor and signing every other session and access token out.",
|
|
41
43
|
handler: async (event, ctx) => {
|
|
42
44
|
const verify = verifyMfaSetupToken(event.payload.setupToken, opts.setupTokenSecret);
|
|
43
45
|
if (!verify.ok) return invalidSetupToken();
|
|
@@ -35,6 +35,8 @@ export function createEnableStartPreauthHandler(opts: EnableStartPreauthOptions)
|
|
|
35
35
|
accountLabel: z.string().min(1).max(200),
|
|
36
36
|
}),
|
|
37
37
|
access: { roles: ["all"] },
|
|
38
|
+
description:
|
|
39
|
+
"Begins TOTP enrollment for a user whose sign-in was blocked because the tenant requires two-factor authentication, taking identity from the pre-auth token login issued instead of from a session.",
|
|
38
40
|
handler: async (event, ctx) => {
|
|
39
41
|
const verified = verifyMfaPreauthSetupToken(
|
|
40
42
|
event.payload.preauthSetupToken,
|
|
@@ -30,6 +30,8 @@ export function createEnableStartHandler(opts: EnableStartOptions) {
|
|
|
30
30
|
accountLabel: z.string().min(1).max(200),
|
|
31
31
|
}),
|
|
32
32
|
access: { openToAll: true },
|
|
33
|
+
description:
|
|
34
|
+
"Begins TOTP enrollment for the signed-in user by generating a secret plus recovery codes and returning them as a short-lived setup token, an otpauth:// URI and the one-time plaintext recovery codes; nothing is persisted until enable-confirm.",
|
|
33
35
|
handler: async (event, ctx) => {
|
|
34
36
|
const existing = await findUserMfaRow(ctx.db, event.user);
|
|
35
37
|
if (existing) return mfaAlreadyEnabled();
|
|
@@ -27,6 +27,9 @@ export function createRegenerateRecoveryHandler(opts: RegenerateRecoveryOptions)
|
|
|
27
27
|
name: "regenerate-recovery",
|
|
28
28
|
schema: z.object({ code: z.string().min(6).max(9) }),
|
|
29
29
|
access: { openToAll: true },
|
|
30
|
+
description:
|
|
31
|
+
"Destroys every existing recovery code of the caller, including unused ones, and returns a fresh set once in plaintext; use it when recovery codes may have leaked but TOTP itself should stay enrolled.",
|
|
32
|
+
agent: { risk: "high" },
|
|
30
33
|
handler: async (event, ctx) => {
|
|
31
34
|
const row = await findUserMfaRow(ctx.db, event.user);
|
|
32
35
|
if (!row) return mfaNotEnabled();
|
|
@@ -14,6 +14,8 @@ export const mfaStatusQuery = defineQueryHandler({
|
|
|
14
14
|
name: "user-mfa:status",
|
|
15
15
|
schema: z.object({}),
|
|
16
16
|
access: { openToAll: true },
|
|
17
|
+
description:
|
|
18
|
+
"Reports whether the calling user has TOTP two-factor authentication enrolled; use it before offering either the enrollment flow or the disable and recovery-code actions.",
|
|
17
19
|
handler: async (query, ctx) => {
|
|
18
20
|
const row = await fetchOne<{ id: string }>(ctx.db, userMfaTable, {
|
|
19
21
|
userId: query.user.id,
|
|
@@ -46,6 +46,8 @@ export function createMfaVerifyHandler(opts: MfaVerifyOptions) {
|
|
|
46
46
|
name: "verify",
|
|
47
47
|
schema: z.object({ challengeToken: z.string().min(1), code: z.string().min(6).max(9) }),
|
|
48
48
|
access: { roles: ["all"] },
|
|
49
|
+
description:
|
|
50
|
+
"Finishes a two-step sign-in by checking a TOTP or recovery code against the challenge token that login handed back, under a per-account attempt cap, and derives the resulting session.",
|
|
49
51
|
handler: async (event, ctx) => {
|
|
50
52
|
const verified = verifyMfaChallengeToken(
|
|
51
53
|
event.payload.challengeToken,
|
|
@@ -11,6 +11,8 @@ import {
|
|
|
11
11
|
// mfa.enabled/disabled fall out of the event stream instead of being
|
|
12
12
|
// manually emitted.
|
|
13
13
|
export const userMfaEntity = createEntity({
|
|
14
|
+
description:
|
|
15
|
+
"One user's TOTP two-factor enrollment: the encrypted shared secret, the hashed recovery codes and when the factor was enabled and last used; the row exists only while the user has MFA on.",
|
|
14
16
|
table: "read_user_mfa",
|
|
15
17
|
fields: {
|
|
16
18
|
// FK to the user row, not content — PII-naming heuristic would flag
|
|
@@ -37,6 +37,8 @@ type CreateCheckoutSessionPayload = z.infer<typeof createCheckoutSessionSchema>;
|
|
|
37
37
|
|
|
38
38
|
export const createCheckoutSessionHandler: WriteHandlerDef = {
|
|
39
39
|
name: "create-checkout-session",
|
|
40
|
+
description:
|
|
41
|
+
"Opens a hosted checkout page at the named subscription provider for the caller's tenant and returns its URL; use it when a tenant admin wants to subscribe or switch to a paid plan.",
|
|
40
42
|
schema: createCheckoutSessionSchema,
|
|
41
43
|
// Tenant-Admin-only — der Tenant muss bewusst seine Subscription
|
|
42
44
|
// konfigurieren. SystemAdmin als Fallback für Operator-Initiated-Flows.
|
|
@@ -30,6 +30,8 @@ type CreatePortalSessionPayload = z.infer<typeof createPortalSessionSchema>;
|
|
|
30
30
|
|
|
31
31
|
export const createPortalSessionHandler: WriteHandlerDef = {
|
|
32
32
|
name: "create-portal-session",
|
|
33
|
+
description:
|
|
34
|
+
"Returns a hosted billing-portal URL at the provider that already holds the tenant's subscription; use it when a tenant admin wants to change payment method, see invoices or cancel.",
|
|
33
35
|
schema: createPortalSessionSchema,
|
|
34
36
|
access: { roles: ["TenantAdmin", "SystemAdmin"] },
|
|
35
37
|
handler: async (event, ctx) => {
|
|
@@ -17,6 +17,8 @@ const listSchema = z.object({}).strict();
|
|
|
17
17
|
|
|
18
18
|
export const listSubscriptionsQuery: QueryHandlerDef = {
|
|
19
19
|
name: "subscription:list",
|
|
20
|
+
description:
|
|
21
|
+
"Returns the tenant's subscription rows with provider, status, tier and current period end (provider ids decrypted); use it to answer what plan a tenant is on and until when.",
|
|
20
22
|
schema: listSchema,
|
|
21
23
|
access: { roles: ["SystemAdmin", "TenantAdmin"] },
|
|
22
24
|
handler: async (_query, ctx) => {
|
|
@@ -85,6 +85,7 @@ const NORMALIZED_TO_ES_EVENT: Readonly<Record<string, string>> = {
|
|
|
85
85
|
// Tenant-Admin direkt.
|
|
86
86
|
export const processEventHandler: WriteHandlerDef = {
|
|
87
87
|
name: "process-event",
|
|
88
|
+
agent: { expose: false },
|
|
88
89
|
schema: processEventSchema,
|
|
89
90
|
access: { roles: ["SystemAdmin"] },
|
|
90
91
|
handler: async (event, ctx) => {
|
|
@@ -39,6 +39,8 @@ import {
|
|
|
39
39
|
// auslöst).
|
|
40
40
|
export const capCounterEntity = createEntity({
|
|
41
41
|
table: "read_cap_counters",
|
|
42
|
+
description:
|
|
43
|
+
"One usage counter per tenant, cap name and calendar period, holding the accumulated value and the timestamp of the last soft-limit warning.",
|
|
42
44
|
fields: {
|
|
43
45
|
capName: createTextField({ required: true, maxLength: 100, sortable: true, searchable: true }),
|
|
44
46
|
value: createBigIntField({ required: true, default: 0 }),
|
|
@@ -98,7 +98,13 @@ export const capCounterFeature = defineFeature(CAP_COUNTER_FEATURE, (r) => {
|
|
|
98
98
|
// single-row via get-counter. Detail-by-id-handler bewusst weggelassen
|
|
99
99
|
// (kein Use-Case; der natürliche Lookup ist über capName + period, nicht
|
|
100
100
|
// über aggregate-id).
|
|
101
|
-
r.queryHandler(
|
|
101
|
+
r.queryHandler(
|
|
102
|
+
defineEntityListHandler("cap-counter", capCounterEntity, {
|
|
103
|
+
...sysadminAccess,
|
|
104
|
+
description:
|
|
105
|
+
"Lists usage-counter rows across all tenants with cap name, current value, period start and soft-warn timestamp; use it as the operator view of who is consuming which quota.",
|
|
106
|
+
}),
|
|
107
|
+
);
|
|
102
108
|
r.queryHandler(getCounterQuery);
|
|
103
109
|
|
|
104
110
|
r.screen({
|
|
@@ -18,6 +18,8 @@ const getCounterSchema = z.object({
|
|
|
18
18
|
|
|
19
19
|
export const getCounterQuery: QueryHandlerDef = {
|
|
20
20
|
name: "get-counter",
|
|
21
|
+
description:
|
|
22
|
+
"Returns the calendar-period usage counter row of the caller's tenant for one cap name and period start, or null when nothing was counted yet; use it to show remaining quota.",
|
|
21
23
|
schema: getCounterSchema,
|
|
22
24
|
access: { roles: ["TenantAdmin", "SystemAdmin"] },
|
|
23
25
|
handler: async (query, ctx) => {
|
|
@@ -47,6 +47,7 @@ export const rollingIncrementedSchema = incrementRollingSchema;
|
|
|
47
47
|
// store atomar ermittelt.
|
|
48
48
|
export const incrementRollingCapHandler: WriteHandlerDef = {
|
|
49
49
|
name: "increment-rolling",
|
|
50
|
+
agent: { expose: false },
|
|
50
51
|
schema: incrementRollingSchema,
|
|
51
52
|
// Internal handler — System-Caller (Plattform-foundations nach
|
|
52
53
|
// erfolgreichem Side-Effect) ruft das auf. Tenant-end-users niemals
|
|
@@ -38,6 +38,7 @@ type IncrementPayload = z.infer<typeof incrementSchema>;
|
|
|
38
38
|
// not this handler.
|
|
39
39
|
export const incrementCapHandler: WriteHandlerDef = {
|
|
40
40
|
name: "increment",
|
|
41
|
+
agent: { expose: false },
|
|
41
42
|
schema: incrementSchema,
|
|
42
43
|
// Internal handler — only system-callers (Plattform-foundations after
|
|
43
44
|
// a successful side-effect) drive this. Tenant-end-users never call
|
|
@@ -21,6 +21,7 @@ const markSoftWarnedSchema = z.object({
|
|
|
21
21
|
|
|
22
22
|
export const markSoftWarnedHandler: WriteHandlerDef = {
|
|
23
23
|
name: "mark-soft-warned",
|
|
24
|
+
agent: { expose: false },
|
|
24
25
|
schema: markSoftWarnedSchema,
|
|
25
26
|
access: { roles: ["SystemAdmin"] },
|
|
26
27
|
handler: async (event, ctx) => {
|
|
@@ -19,6 +19,8 @@ const tierAssignmentTable = buildEntityTable("tier-assignment", tierAssignmentEn
|
|
|
19
19
|
export function createCapsUsageQuery(caps: readonly CapSpec[]): QueryHandlerDefinition {
|
|
20
20
|
return defineQueryHandler({
|
|
21
21
|
name: "caps:usage",
|
|
22
|
+
description:
|
|
23
|
+
"Returns one tenant's configured caps with used amount, tier limit and utilisation fraction; use it to answer how close a tenant is to its quota (SystemAdmin may target another tenant via tenantId).",
|
|
22
24
|
schema: z.object({ tenantId: z.string().min(1).optional() }),
|
|
23
25
|
access: { roles: access.admin },
|
|
24
26
|
handler: async (query, ctx) => {
|
|
@@ -95,6 +95,8 @@ export function createTenantCapsListQuery(caps: readonly CapSpec[], listCaps: re
|
|
|
95
95
|
|
|
96
96
|
return definePagedQueryHandler({
|
|
97
97
|
name: "tenant-caps:list",
|
|
98
|
+
description:
|
|
99
|
+
"Lists every tenant on the platform with its tier, billing provider/status and per-cap usage, paged, searchable by name and filterable by tier; use it as the operator-wide capacity overview.",
|
|
98
100
|
schema: z.object({
|
|
99
101
|
cursor: z.string().optional(),
|
|
100
102
|
limit: z.number().int().min(1).max(MAX_LIST_LIMIT).default(50),
|
|
@@ -8,6 +8,8 @@ type TenantRow = { readonly id: string; readonly name: string };
|
|
|
8
8
|
|
|
9
9
|
export const tenantOptionsQuery = defineQueryHandler({
|
|
10
10
|
name: "tenant-options",
|
|
11
|
+
description:
|
|
12
|
+
"Returns all tenants as id/name option pairs sorted by name; use it to populate the tenant picker of a platform-wide overview.",
|
|
11
13
|
schema: z.object({}),
|
|
12
14
|
access: { roles: ["SystemAdmin"] },
|
|
13
15
|
handler: async (_query, ctx) => {
|
|
@@ -10,6 +10,8 @@ export const inboxQuery = defineQueryHandler({
|
|
|
10
10
|
unreadOnly: z.boolean().default(false),
|
|
11
11
|
}),
|
|
12
12
|
access: { openToAll: true },
|
|
13
|
+
description:
|
|
14
|
+
"Lists the calling user's own in-app notification messages newest-first, optionally only the unread ones; use it to show or inspect a user's notification inbox.",
|
|
13
15
|
handler: async (query, ctx) => {
|
|
14
16
|
const where: Record<string, unknown> = { userId: query.user.id };
|
|
15
17
|
if (query.payload.unreadOnly) where["isRead"] = false;
|
|
@@ -7,6 +7,8 @@ export const markAllReadWrite = defineWriteHandler({
|
|
|
7
7
|
name: "markAllRead",
|
|
8
8
|
schema: z.object({}),
|
|
9
9
|
access: { openToAll: true },
|
|
10
|
+
description:
|
|
11
|
+
"Marks every unread in-app message of the calling user as read and returns how many rows were touched; use it for a mark-all-as-read action.",
|
|
10
12
|
handler: async (event, ctx) => {
|
|
11
13
|
const rows = await updateMany(
|
|
12
14
|
ctx.db,
|
|
@@ -11,6 +11,8 @@ export const markReadWrite = defineWriteHandler({
|
|
|
11
11
|
id: z.number().int(),
|
|
12
12
|
}),
|
|
13
13
|
access: { openToAll: true },
|
|
14
|
+
description:
|
|
15
|
+
"Marks one in-app message of the calling user as read by its numeric id, failing with not-found when no such message belongs to the caller; use it when a user opens a single notification.",
|
|
14
16
|
handler: async (event, ctx) => {
|
|
15
17
|
const rows = await updateMany(
|
|
16
18
|
ctx.db,
|
|
@@ -7,6 +7,8 @@ export const unreadCountQuery = defineQueryHandler({
|
|
|
7
7
|
name: "unreadCount",
|
|
8
8
|
schema: z.object({}),
|
|
9
9
|
access: { openToAll: true },
|
|
10
|
+
description:
|
|
11
|
+
"Counts the calling user's unread in-app notification messages; use it for an inbox badge or to check whether a user has pending notifications.",
|
|
10
12
|
handler: async (query, ctx) => {
|
|
11
13
|
// bun-db hat keinen aggregate-helper — selectMany alle matching rows,
|
|
12
14
|
// count() in JS. Pragma: unread-counts sind low-cardinality (user-
|