@cosmicdrift/kumiko-bundled-features 0.350.0 → 0.352.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/dist/audit/handlers/list.query.js +1 -1
- package/dist/auth-email-password/email-templates.js +1 -1
- package/dist/auth-email-password/handlers/invite-create.write.js +1 -1
- package/dist/auth-email-password/handlers/signup-request.write.js +1 -1
- package/dist/auth-email-password/handlers/token-request-handler.d.ts +1 -1
- package/dist/auth-email-password/reset-token.d.ts +1 -1
- package/dist/auth-email-password/unlock-token.d.ts +1 -1
- package/dist/auth-email-password/verification-token.d.ts +1 -1
- package/dist/auth-mfa/handlers/enable-confirm-preauth.write.js +1 -1
- package/dist/auth-mfa/handlers/enable-confirm.write.js +1 -1
- package/dist/auth-mfa/hmac-token-codec.d.ts +1 -1
- package/dist/auth-mfa/hmac-token-codec.js +1 -1
- package/dist/auth-mfa/mfa-challenge-token.d.ts +1 -1
- package/dist/auth-mfa/mfa-challenge-token.js +1 -1
- package/dist/auth-mfa/mfa-preauth-setup-token.d.ts +1 -1
- package/dist/auth-mfa/mfa-preauth-setup-token.js +1 -1
- package/dist/auth-mfa/mfa-setup-token.d.ts +1 -1
- package/dist/auth-mfa/mfa-setup-token.js +1 -1
- package/dist/billing-foundation/constants.d.ts +2 -2
- package/dist/billing-foundation/constants.js +3 -12
- package/dist/billing-foundation/consumer-protection/confirmation-mail.js +1 -1
- package/dist/billing-foundation/consumer-protection/termination-mail.js +1 -1
- package/dist/billing-foundation/feature.js +2 -9
- package/dist/billing-foundation/handlers/sync-subscription.write.js +3 -6
- package/dist/cap-counter/book-cap-usage.d.ts +5 -1
- package/dist/cap-counter/book-cap-usage.js +66 -45
- package/dist/cap-counter/cap-reservation.d.ts +12 -0
- package/dist/cap-counter/cap-reservation.js +135 -0
- package/dist/cap-counter/constants.d.ts +3 -0
- package/dist/cap-counter/constants.js +6 -0
- package/dist/cap-counter/enforce-cap.d.ts +1 -1
- package/dist/cap-counter/enforce-cap.js +1 -8
- package/dist/cap-counter/feature.js +7 -2
- package/dist/cap-counter/handlers/increment-rolling.write.d.ts +5 -0
- package/dist/cap-counter/handlers/increment-rolling.write.js +4 -0
- package/dist/cap-counter/index.d.ts +4 -2
- package/dist/cap-counter/index.js +3 -1
- package/dist/cap-counter/payload-field.d.ts +1 -0
- package/dist/cap-counter/payload-field.js +11 -0
- package/dist/cap-counter/reservation-chain.d.ts +2 -0
- package/dist/cap-counter/reservation-chain.js +44 -0
- package/dist/cap-counter/stock-cap-guard.d.ts +3 -0
- package/dist/cap-counter/tables.d.ts +3 -0
- package/dist/cap-counter/tables.js +36 -0
- package/dist/cap-counter/value-cap-guard.d.ts +18 -0
- package/dist/cap-counter/value-cap-guard.js +33 -0
- package/dist/cap-counter/with-cap-enforcement.d.ts +5 -7
- package/dist/cap-counter/with-cap-enforcement.js +35 -51
- package/dist/channel-discord/feature.js +1 -0
- package/dist/channel-slack/feature.js +1 -0
- package/dist/channel-teams/feature.js +1 -0
- package/dist/compliance-profiles/schema/profile-selection.d.ts +2 -0
- package/dist/delivery/attempt-log-retention.d.ts +9 -0
- package/dist/delivery/attempt-log-retention.js +23 -0
- package/dist/delivery/attempt-log.d.ts +1 -1
- package/dist/delivery/attempt-log.js +21 -2
- package/dist/delivery/constants.d.ts +1 -1
- package/dist/delivery/constants.js +1 -1
- package/dist/delivery/events.d.ts +1 -0
- package/dist/delivery/events.js +2 -0
- package/dist/delivery/feature.d.ts +1 -0
- package/dist/delivery/feature.js +39 -3
- package/dist/delivery/handlers/log.query.d.ts +1 -2
- package/dist/delivery/handlers/log.query.js +1 -1
- package/dist/delivery/index.d.ts +2 -1
- package/dist/delivery/index.js +2 -1
- package/dist/delivery/mask-recipient-address.d.ts +1 -0
- package/dist/delivery/mask-recipient-address.js +41 -0
- package/dist/delivery/public-names.d.ts +2 -0
- package/dist/delivery/public-names.js +3 -0
- package/dist/delivery/types.d.ts +1 -0
- package/dist/delivery/types.js +6 -2
- package/dist/feature-toggles/handlers/set.write.js +1 -1
- package/dist/form-draft/db/queries/cleanup.d.ts +1 -1
- package/dist/form-draft/db/queries/cleanup.js +1 -1
- package/dist/form-draft/db/queries/owned-file-refs.d.ts +1 -1
- package/dist/form-draft/lookup.d.ts +1 -1
- package/dist/inbound-mail-foundation/handlers/ingest-message.write.js +1 -1
- package/dist/inbound-mail-foundation/oauth-access-token.d.ts +1 -1
- package/dist/inbound-mail-foundation/oauth-access-token.js +1 -1
- package/dist/inbound-mail-foundation/oauth-state.d.ts +1 -1
- package/dist/inbound-mail-foundation/oauth-state.js +1 -1
- package/dist/inbound-mail-foundation/watch-supervisor.js +1 -1
- package/dist/inbound-provider-imap/feature.js +1 -1
- package/dist/inbound-provider-imap/imap-client.js +1 -1
- package/dist/jobs/job-instant.d.ts +1 -1
- package/dist/jobs/job-instant.js +1 -1
- package/dist/ledger/entity.d.ts +3 -0
- package/dist/metrics/compute.d.ts +1 -1
- package/dist/metrics/feature.js +1 -1
- package/dist/metrics/types.d.ts +1 -1
- package/dist/metrics/window.d.ts +1 -1
- package/dist/metrics/window.js +1 -1
- package/dist/personal-access-tokens/expiry.js +1 -1
- package/dist/personal-access-tokens/handlers/create.write.js +1 -1
- package/dist/personal-access-tokens/handlers/revoke.write.js +1 -1
- package/dist/personal-access-tokens/revoke-for-user.js +1 -1
- package/dist/renderer-foundation/types.d.ts +1 -0
- package/dist/renderer-simple/feature.js +4 -6
- package/dist/renderer-simple/index.d.ts +1 -0
- package/dist/renderer-simple/mail-blocks.d.ts +21 -0
- package/dist/renderer-simple/mail-blocks.js +107 -0
- package/dist/renderer-simple/simple-renderer.js +21 -3
- package/dist/sessions/handlers/revoke-all-for-user.write.js +1 -1
- package/dist/sessions/handlers/revoke-all-others.write.js +1 -1
- package/dist/sessions/handlers/revoke.write.js +1 -1
- package/dist/sessions/session-callbacks.js +1 -1
- package/dist/shared/grace-period.d.ts +2 -1
- package/dist/shared/grace-period.js +3 -7
- package/dist/shared/row-bound-grant.d.ts +1 -1
- package/dist/shared/signed-token.d.ts +1 -1
- package/dist/shared/signed-token.js +1 -1
- package/dist/subscription-mollie/verify-webhook.js +1 -1
- package/dist/subscription-stripe/verify-webhook.js +1 -1
- package/dist/template-resolver/api.d.ts +1 -1
- package/dist/template-resolver/handlers/by-slug.query.d.ts +1 -1
- package/dist/template-resolver/handlers/by-tenant.query.d.ts +2 -2
- package/dist/template-resolver/handlers/collection-item.query.d.ts +1 -1
- package/dist/template-resolver/handlers/collection-list.query.d.ts +1 -1
- package/dist/template-resolver/handlers/collection-shared.d.ts +2 -2
- package/dist/template-resolver/handlers/find-by-id.query.d.ts +1 -1
- package/dist/template-resolver/handlers/list.query.d.ts +1 -1
- package/dist/template-resolver/table.d.ts +9 -1
- package/dist/template-resolver/user-content-table.d.ts +4 -0
- package/dist/tenant/handlers/team-list.query.d.ts +1 -1
- package/dist/tenant/handlers/team-list.query.js +1 -1
- package/dist/tenant/invitation-table.d.ts +2 -0
- package/dist/tenant/invited-membership.d.ts +1 -1
- package/dist/tenant/invited-membership.js +1 -1
- package/dist/tenant/schema/tenant.d.ts +2 -0
- package/dist/tenant-handover/grant.d.ts +1 -1
- package/dist/tier-engine/index.d.ts +1 -0
- package/dist/tier-engine/index.js +1 -0
- package/dist/tier-engine/tier-option-gate.d.ts +32 -0
- package/dist/tier-engine/tier-option-gate.js +62 -0
- package/dist/user/schema/user.d.ts +2 -0
- package/dist/user-data-rights/db/queries/export-jobs.d.ts +1 -1
- package/dist/user-data-rights/db/queries/forget-cleanup.d.ts +2 -2
- package/dist/user-data-rights/db/queries/forget-cleanup.js +2 -8
- package/dist/user-data-rights/deletion-token.d.ts +1 -1
- package/dist/user-data-rights/email-templates.js +1 -1
- package/dist/user-data-rights/handlers/list-download-attempts.query.js +1 -1
- package/dist/user-data-rights/handlers/my-audit-log.query.js +1 -1
- package/dist/user-data-rights/schema/export-job.d.ts +2 -0
- package/dist/user-data-rights-defaults/hooks/delivery-attempt.userdata-hook.js +25 -6
- package/dist/waitlist/entity.d.ts +2 -0
- package/dist/waitlist/handlers/invite.write.js +1 -1
- package/dist/waitlist/handlers/submit.write.js +1 -1
- package/package.json +10 -10
- package/src/cap-counter/changes.json +28 -0
- package/src/delivery/changes.json +12 -0
- package/src/derivatives-sharp/changes.json +6 -0
- package/src/legal-pages/changes.json +6 -0
- package/src/renderer-simple/changes.json +6 -0
- package/src/tier-engine/changes.json +6 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { escapeHtml, escapeHtmlAttr } from "@cosmicdrift/kumiko-headless";
|
|
2
|
+
// Literal types (as const) keep the colors compile-time known, so they can go into style
|
|
3
|
+
// attributes without escaping.
|
|
4
|
+
const TONE_COLORS = {
|
|
5
|
+
neutral: { bg: "#f3f4f6", fg: "#374151" },
|
|
6
|
+
info: { bg: "#dbeafe", fg: "#1e40af" },
|
|
7
|
+
success: { bg: "#dcfce7", fg: "#166534" },
|
|
8
|
+
warning: { bg: "#fef3c7", fg: "#92400e" },
|
|
9
|
+
danger: { bg: "#fee2e2", fg: "#991b1b" },
|
|
10
|
+
};
|
|
11
|
+
const STAGE_STATES = ["done", "current", "upcoming"];
|
|
12
|
+
const STAGE_DONE_COLOR = "#16a34a";
|
|
13
|
+
const STAGE_UPCOMING_BG = "#e5e7eb";
|
|
14
|
+
const STAGE_UPCOMING_FG = "#9ca3af";
|
|
15
|
+
function isRecord(value) {
|
|
16
|
+
return typeof value === "object" && value !== null;
|
|
17
|
+
}
|
|
18
|
+
function isMailTone(value) {
|
|
19
|
+
return typeof value === "string" && Object.hasOwn(TONE_COLORS, value);
|
|
20
|
+
}
|
|
21
|
+
function toneColors(tone) {
|
|
22
|
+
return TONE_COLORS[isMailTone(tone) ? tone : "neutral"];
|
|
23
|
+
}
|
|
24
|
+
function isStageState(value) {
|
|
25
|
+
return STAGE_STATES.some((state) => state === value);
|
|
26
|
+
}
|
|
27
|
+
// Template data is runtime data (variables of a stored template): entries that do not match are
|
|
28
|
+
// skipped instead of failing the whole mail.
|
|
29
|
+
function isStage(value) {
|
|
30
|
+
return isRecord(value) && typeof value["label"] === "string" && isStageState(value["state"]);
|
|
31
|
+
}
|
|
32
|
+
function isChip(value) {
|
|
33
|
+
return isRecord(value) && typeof value["label"] === "string";
|
|
34
|
+
}
|
|
35
|
+
export function parseBadge(value) {
|
|
36
|
+
return isChip(value) && value.label !== "" ? value : undefined;
|
|
37
|
+
}
|
|
38
|
+
function validStages(value) {
|
|
39
|
+
return Array.isArray(value) ? value.filter(isStage) : [];
|
|
40
|
+
}
|
|
41
|
+
function validChips(value) {
|
|
42
|
+
return Array.isArray(value) ? value.filter(isChip) : [];
|
|
43
|
+
}
|
|
44
|
+
function pill(chip, margin) {
|
|
45
|
+
const { bg, fg } = toneColors(chip.tone);
|
|
46
|
+
return `<span style="display:inline-block;margin:${margin};padding:2px 10px;border-radius:999px;background:${bg};color:${fg};font-size:12px;font-weight:600;line-height:18px">${escapeHtml(chip.label)}</span>`;
|
|
47
|
+
}
|
|
48
|
+
export function renderBadge(badge) {
|
|
49
|
+
return `<p style="margin:0 0 12px">${pill(badge, "0")}</p>`;
|
|
50
|
+
}
|
|
51
|
+
export function renderChips(chips) {
|
|
52
|
+
const valid = validChips(chips);
|
|
53
|
+
if (valid.length === 0)
|
|
54
|
+
return "";
|
|
55
|
+
return `<p style="margin:0 0 16px">${valid.map((chip) => pill(chip, "0 6px 6px 0")).join("")}</p>`;
|
|
56
|
+
}
|
|
57
|
+
function stageMarker(stage, position, primaryColor) {
|
|
58
|
+
const base = "display:inline-block;width:24px;height:24px;line-height:24px;border-radius:12px;text-align:center;font-size:12px;font-weight:700";
|
|
59
|
+
const primary = escapeHtmlAttr(primaryColor);
|
|
60
|
+
if (stage.state === "done") {
|
|
61
|
+
return `<span style="${base};background:${STAGE_DONE_COLOR};color:#fff">✓</span>`;
|
|
62
|
+
}
|
|
63
|
+
if (stage.state === "current") {
|
|
64
|
+
return `<span style="${base};background:#fff;border:2px solid ${primary};line-height:20px;width:20px;height:20px;color:${primary}">${position}</span>`;
|
|
65
|
+
}
|
|
66
|
+
return `<span style="${base};background:${STAGE_UPCOMING_BG};color:${STAGE_UPCOMING_FG}">${position}</span>`;
|
|
67
|
+
}
|
|
68
|
+
function stageCell(stage, position, primaryColor) {
|
|
69
|
+
const labelColor = stage.state === "upcoming" ? STAGE_UPCOMING_FG : "#111";
|
|
70
|
+
const weight = stage.state === "current" ? 700 : 400;
|
|
71
|
+
return `<td align="center" valign="top" style="padding:0 4px;font-family:sans-serif">${stageMarker(stage, position, primaryColor)}<div style="margin:4px 0 0;font-size:12px;font-weight:${weight};color:${labelColor}">${escapeHtml(stage.label)}</div></td>`;
|
|
72
|
+
}
|
|
73
|
+
function stageConnector(previous) {
|
|
74
|
+
const color = previous.state === "done" ? STAGE_DONE_COLOR : STAGE_UPCOMING_BG;
|
|
75
|
+
return `<td valign="top" style="padding:11px 0 0"><div style="width:24px;height:2px;line-height:2px;font-size:2px;background:${color}"> </div></td>`;
|
|
76
|
+
}
|
|
77
|
+
export function renderStages(stages, primaryColor) {
|
|
78
|
+
const valid = validStages(stages);
|
|
79
|
+
if (valid.length === 0)
|
|
80
|
+
return "";
|
|
81
|
+
const cellsHtml = valid
|
|
82
|
+
.map((stage, index) => {
|
|
83
|
+
const previous = valid[index - 1];
|
|
84
|
+
const connector = previous ? stageConnector(previous) : "";
|
|
85
|
+
return `${connector}${stageCell(stage, index + 1, primaryColor)}`;
|
|
86
|
+
})
|
|
87
|
+
.join("");
|
|
88
|
+
return `<table role="presentation" cellpadding="0" cellspacing="0" border="0" style="margin:0 0 16px"><tr>${cellsHtml}</tr></table>`;
|
|
89
|
+
}
|
|
90
|
+
const STAGE_TEXT_MARKER = {
|
|
91
|
+
done: "✓",
|
|
92
|
+
current: "▶",
|
|
93
|
+
upcoming: "○",
|
|
94
|
+
};
|
|
95
|
+
export function badgeText(badge) {
|
|
96
|
+
return `[${badge.label}]`;
|
|
97
|
+
}
|
|
98
|
+
export function stagesText(stages) {
|
|
99
|
+
return validStages(stages)
|
|
100
|
+
.map((stage) => `${STAGE_TEXT_MARKER[stage.state]} ${stage.label}`)
|
|
101
|
+
.join(" → ");
|
|
102
|
+
}
|
|
103
|
+
export function chipsText(chips) {
|
|
104
|
+
return validChips(chips)
|
|
105
|
+
.map((chip) => chip.label)
|
|
106
|
+
.join(" · ");
|
|
107
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { escapeHtml, escapeHtmlAttr } from "@cosmicdrift/kumiko-headless";
|
|
2
2
|
import { renderSafeMarkdown } from "../page-render/index.js";
|
|
3
|
+
import { badgeText, chipsText, parseBadge, renderBadge, renderChips, renderStages, stagesText, } from "./mail-blocks.js";
|
|
3
4
|
const DEFAULT_PRIMARY_COLOR = "#2563eb";
|
|
4
5
|
const HEX_COLOR_PATTERN = /^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
|
|
5
6
|
function isHttpUrl(value) {
|
|
@@ -107,6 +108,7 @@ function templateContent(variables) {
|
|
|
107
108
|
const data = variables; // @cast-boundary render-helper
|
|
108
109
|
// Without structured fields, title + body become the header and a single text section.
|
|
109
110
|
return {
|
|
111
|
+
badge: parseBadge(data.badge),
|
|
110
112
|
header: data.header ?? data.title,
|
|
111
113
|
sections: data.sections ?? (data.body ? [{ text: data.body }] : undefined),
|
|
112
114
|
footer: data.footer,
|
|
@@ -122,6 +124,10 @@ function sectionText(section) {
|
|
|
122
124
|
return section.markdown;
|
|
123
125
|
if ("button" in section)
|
|
124
126
|
return `${section.button.label}: ${section.button.url}`;
|
|
127
|
+
if ("stages" in section)
|
|
128
|
+
return stagesText(section.stages);
|
|
129
|
+
if ("chips" in section)
|
|
130
|
+
return chipsText(section.chips);
|
|
125
131
|
return "";
|
|
126
132
|
}
|
|
127
133
|
function renderSection(section, primaryColor) {
|
|
@@ -138,6 +144,10 @@ function renderSection(section, primaryColor) {
|
|
|
138
144
|
if ("button" in section) {
|
|
139
145
|
return `<p style="margin:0 0 16px"><a href="${escapeHtml(section.button.url)}" style="display:inline-block;padding:10px 24px;background:${escapeHtmlAttr(primaryColor)};color:#fff;text-decoration:none;border-radius:4px;font-size:14px">${escapeHtml(section.button.label)}</a></p>`;
|
|
140
146
|
}
|
|
147
|
+
if ("stages" in section)
|
|
148
|
+
return renderStages(section.stages, primaryColor);
|
|
149
|
+
if ("chips" in section)
|
|
150
|
+
return renderChips(section.chips);
|
|
141
151
|
return "";
|
|
142
152
|
}
|
|
143
153
|
// Simple Renderer: turns structured email template data into HTML with inline CSS.
|
|
@@ -150,11 +160,13 @@ export function createSimpleRenderer(branding) {
|
|
|
150
160
|
return {
|
|
151
161
|
name: "simple",
|
|
152
162
|
async render(input) {
|
|
153
|
-
const { header, sections, footer } = templateContent(input.variables);
|
|
163
|
+
const { badge, header, sections, footer } = templateContent(input.variables);
|
|
154
164
|
const parts = [];
|
|
155
165
|
parts.push('<!DOCTYPE html><html><body style="margin:0;padding:0;font-family:sans-serif">');
|
|
156
166
|
parts.push('<div style="max-width:600px;margin:0 auto;padding:24px">');
|
|
157
167
|
parts.push(renderBrandingHeader(branding, primaryColor, logoUrl));
|
|
168
|
+
if (badge)
|
|
169
|
+
parts.push(renderBadge(badge));
|
|
158
170
|
if (header) {
|
|
159
171
|
parts.push(`<h1 style="margin:0 0 24px;color:#111;font-size:20px;font-weight:600">${escapeHtml(header)}</h1>`);
|
|
160
172
|
}
|
|
@@ -171,9 +183,15 @@ export function createSimpleRenderer(branding) {
|
|
|
171
183
|
return parts.join("");
|
|
172
184
|
},
|
|
173
185
|
async renderText(input) {
|
|
174
|
-
const { header, sections, footer } = templateContent(input.variables);
|
|
186
|
+
const { badge, header, sections, footer } = templateContent(input.variables);
|
|
175
187
|
const brandingFooter = brandingFooterLines(branding, input.locale).join("\n");
|
|
176
|
-
return [
|
|
188
|
+
return [
|
|
189
|
+
badge ? badgeText(badge) : undefined,
|
|
190
|
+
header,
|
|
191
|
+
...(sections ?? []).map(sectionText),
|
|
192
|
+
footer,
|
|
193
|
+
brandingFooter,
|
|
194
|
+
]
|
|
177
195
|
.filter((block) => block !== undefined && block !== "")
|
|
178
196
|
.join("\n\n");
|
|
179
197
|
},
|
|
@@ -4,7 +4,7 @@ import { access, defineWriteHandler, SYSTEM_TENANT_ID } from "@cosmicdrift/kumik
|
|
|
4
4
|
import { UnprocessableError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
|
|
5
5
|
import { append } from "@cosmicdrift/kumiko-framework/event-store";
|
|
6
6
|
import { generateId } from "@cosmicdrift/kumiko-framework/utils";
|
|
7
|
-
import { Temporal } from "temporal
|
|
7
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
8
8
|
import * as z from "zod";
|
|
9
9
|
import { userSessionTable } from "../schema/user-session.js";
|
|
10
10
|
import { SESSION_REVOKED_AGGREGATE_TYPE, SESSION_REVOKED_EVENT_QN, sessionRevokedSchema, } from "../session-revoked-event.js";
|
|
@@ -2,7 +2,7 @@ import { updateMany } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
|
2
2
|
import { defineWriteHandler } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
3
|
import { UnprocessableError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
|
|
4
4
|
import { generateId } from "@cosmicdrift/kumiko-framework/utils";
|
|
5
|
-
import { Temporal } from "temporal
|
|
5
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
6
6
|
import * as z from "zod";
|
|
7
7
|
import { SessionErrors } from "../constants.js";
|
|
8
8
|
import { userSessionTable } from "../schema/user-session.js";
|
|
@@ -2,7 +2,7 @@ import { fetchOne, updateMany } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
|
2
2
|
import { defineWriteHandler } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
3
|
import { UnprocessableError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
|
|
4
4
|
import { generateId } from "@cosmicdrift/kumiko-framework/utils";
|
|
5
|
-
import { Temporal } from "temporal
|
|
5
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
6
6
|
import * as z from "zod";
|
|
7
7
|
import { SessionErrors, USER_SESSION_ENTITY_NAME } from "../constants.js";
|
|
8
8
|
import { userSessionTable } from "../schema/user-session.js";
|
|
@@ -2,7 +2,7 @@ import { fetchOne, insertOne, transaction, updateMany } from "@cosmicdrift/kumik
|
|
|
2
2
|
import { buildSessionRoles, SYSTEM_TENANT_ID } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
3
|
import { append } from "@cosmicdrift/kumiko-framework/event-store";
|
|
4
4
|
import { generateId, parseRoles } from "@cosmicdrift/kumiko-framework/utils";
|
|
5
|
-
import { Temporal } from "temporal
|
|
5
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
6
6
|
import { encryptForDirectWrite } from "../shared/index.js";
|
|
7
7
|
import { tenantMembershipsTable } from "../tenant/index.js";
|
|
8
8
|
import { isPrincipalBlocked, userTable } from "../user/index.js";
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/** Shared grace-period check for user-data-rights + tenant-lifecycle cancel flows. */
|
|
2
2
|
/// <reference types="temporal-polyfill/global" preserve="true" />
|
|
3
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
3
4
|
/**
|
|
4
5
|
* True when `gracePeriodEnd` is still in the future.
|
|
5
|
-
* Uses the
|
|
6
|
+
* Uses the module's Temporal so callers don't depend on `globalThis.Temporal`.
|
|
6
7
|
*/
|
|
7
8
|
export declare function isWithinGracePeriod(gracePeriodEnd: Temporal.Instant | null): boolean;
|
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
/// <reference types="temporal-polyfill/global" preserve="true" />
|
|
2
2
|
/** Shared grace-period check for user-data-rights + tenant-lifecycle cancel flows. */
|
|
3
|
-
import { Temporal
|
|
3
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
4
4
|
/**
|
|
5
5
|
* True when `gracePeriodEnd` is still in the future.
|
|
6
|
-
* Uses the
|
|
6
|
+
* Uses the module's Temporal so callers don't depend on `globalThis.Temporal`.
|
|
7
7
|
*/
|
|
8
8
|
export function isWithinGracePeriod(gracePeriodEnd) {
|
|
9
|
-
|
|
10
|
-
// at runtime — row types resolve against ambient Temporal; polyfill Instant
|
|
11
|
-
// is a separate nominal type across the two .d.ts sources.
|
|
12
|
-
return (gracePeriodEnd != null &&
|
|
13
|
-
TemporalPolyfill.Instant.compare(gracePeriodEnd, TemporalPolyfill.Now.instant()) > 0);
|
|
9
|
+
return (gracePeriodEnd != null && Temporal.Instant.compare(gracePeriodEnd, Temporal.Now.instant()) > 0);
|
|
14
10
|
}
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
// Timing-safe comparison on verify so a valid-length forgery can't leak
|
|
13
13
|
// signal through a short-circuit.
|
|
14
14
|
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
15
|
-
import { Temporal } from "temporal
|
|
15
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
16
16
|
function sign(input, secret) {
|
|
17
17
|
return createHmac("sha256", secret).update(input).digest("base64url");
|
|
18
18
|
}
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
// Created-Event mit subscription-id bekommt.
|
|
16
16
|
import { parseProviderConsentId, SubscriptionEventTypes, SubscriptionStatuses, } from "@cosmicdrift/kumiko-bundled-features/billing-foundation";
|
|
17
17
|
import { createFallbackLogger } from "@cosmicdrift/kumiko-framework/logging";
|
|
18
|
-
import { Temporal } from "temporal
|
|
18
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
19
19
|
import { MOLLIE_PROVIDER_NAME } from "./constants.js";
|
|
20
20
|
const log = createFallbackLogger("subscription-mollie");
|
|
21
21
|
export function verifyAndParseMollieWebhook(client, options) {
|
|
@@ -34,8 +34,8 @@
|
|
|
34
34
|
import { BillingEventKinds, parseProviderConsentId, SubscriptionEventTypes, SubscriptionStatuses, } from "@cosmicdrift/kumiko-bundled-features/billing-foundation";
|
|
35
35
|
import { ExtraRouteRejection } from "@cosmicdrift/kumiko-framework/api";
|
|
36
36
|
import { createFallbackLogger } from "@cosmicdrift/kumiko-framework/logging";
|
|
37
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
37
38
|
import Stripe from "stripe";
|
|
38
|
-
import { Temporal } from "temporal-polyfill";
|
|
39
39
|
import { STRIPE_PROVIDER_NAME, StripeEventTypes } from "./constants.js";
|
|
40
40
|
const log = createFallbackLogger("subscription-stripe");
|
|
41
41
|
export function isResourceMissingStripeError(error) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { DbConnection } from "@cosmicdrift/kumiko-framework/db";
|
|
2
2
|
import type { SessionUser, TenantId } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
|
-
import type { Temporal } from "temporal
|
|
3
|
+
import type { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
4
4
|
import type { ContentFormat, TemplateKind } from "./constants.js";
|
|
5
5
|
export type TemplateResource = {
|
|
6
6
|
readonly id: string;
|
|
@@ -10,5 +10,5 @@ export declare const bySlugQuery: import("@cosmicdrift/kumiko-types/define-handl
|
|
|
10
10
|
content: string | null;
|
|
11
11
|
contentFormat: string;
|
|
12
12
|
folder: string | null;
|
|
13
|
-
modifiedAt:
|
|
13
|
+
modifiedAt: Temporal.Instant | null;
|
|
14
14
|
} | null, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Temporal } from "temporal
|
|
1
|
+
import type { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
2
2
|
import * as z from "zod";
|
|
3
3
|
export type TextBlockSummary = {
|
|
4
4
|
readonly slug: string;
|
|
@@ -17,6 +17,6 @@ export declare const byTenantQuery: import("@cosmicdrift/kumiko-types/define-han
|
|
|
17
17
|
title: string | null;
|
|
18
18
|
content: string | null;
|
|
19
19
|
folder: string | null;
|
|
20
|
-
modifiedAt: Temporal.Instant | null;
|
|
20
|
+
modifiedAt: globalThis.Temporal.Instant | null;
|
|
21
21
|
}[];
|
|
22
22
|
}, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap>;
|
|
@@ -11,5 +11,5 @@ export declare function makeCollectionItemQuery(collection: ContentCollectionDef
|
|
|
11
11
|
content: string | null;
|
|
12
12
|
contentFormat: string;
|
|
13
13
|
folder: string | null;
|
|
14
|
-
modifiedAt:
|
|
14
|
+
modifiedAt: Temporal.Instant | null;
|
|
15
15
|
} | null, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap>;
|
|
@@ -10,6 +10,6 @@ export declare function makeCollectionListQuery(collection: ContentCollectionDef
|
|
|
10
10
|
content: string | null;
|
|
11
11
|
contentFormat: string;
|
|
12
12
|
folder: string | null;
|
|
13
|
-
modifiedAt:
|
|
13
|
+
modifiedAt: Temporal.Instant | null;
|
|
14
14
|
}[];
|
|
15
15
|
}, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { EventStoreExecutor } from "@cosmicdrift/kumiko-framework/db";
|
|
2
2
|
import type { AccessRule, ContentCollectionDefinition, SessionUser, TenantId } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
|
-
import type { Temporal } from "temporal
|
|
3
|
+
import type { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
4
4
|
import { templateResourcesTable } from "../table.js";
|
|
5
5
|
import { userContentEntriesTable } from "../user-content-table.js";
|
|
6
6
|
export declare const DEFAULT_COLLECTION_ACCESS: AccessRule;
|
|
@@ -31,5 +31,5 @@ export declare function toCollectionEntry(row: CollectionEntryRow): {
|
|
|
31
31
|
content: string | null;
|
|
32
32
|
contentFormat: string;
|
|
33
33
|
folder: string | null;
|
|
34
|
-
modifiedAt: Temporal.Instant | null;
|
|
34
|
+
modifiedAt: globalThis.Temporal.Instant | null;
|
|
35
35
|
};
|
|
@@ -15,5 +15,5 @@ export declare const findByIdQuery: import("@cosmicdrift/kumiko-types/define-han
|
|
|
15
15
|
scope: string;
|
|
16
16
|
parentTemplateId: string | null;
|
|
17
17
|
status: string;
|
|
18
|
-
modifiedAt:
|
|
18
|
+
modifiedAt: Temporal.Instant | null;
|
|
19
19
|
} | null, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap>;
|
|
@@ -22,5 +22,5 @@ export declare const listQuery: import("@cosmicdrift/kumiko-types/define-handler
|
|
|
22
22
|
scope: string;
|
|
23
23
|
status: string;
|
|
24
24
|
contentFormat: string;
|
|
25
|
-
modifiedAt:
|
|
25
|
+
modifiedAt: Temporal.Instant | null;
|
|
26
26
|
}[], import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Temporal } from "temporal
|
|
1
|
+
import type { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
2
2
|
export declare const templateResourceEntity: import("@cosmicdrift/kumiko-types/fields").EntityDefinition<{
|
|
3
3
|
slug: {
|
|
4
4
|
readonly type: "text";
|
|
@@ -42,6 +42,7 @@ export declare const templateResourceEntity: import("@cosmicdrift/kumiko-types/f
|
|
|
42
42
|
} | undefined;
|
|
43
43
|
readonly optionsQuery?: string;
|
|
44
44
|
readonly optionsQueryPayload?: import("@cosmicdrift/kumiko-types/fields").OptionsQueryPayload;
|
|
45
|
+
readonly optionsAvailabilityQuery?: string;
|
|
45
46
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
46
47
|
required: true;
|
|
47
48
|
};
|
|
@@ -143,6 +144,7 @@ export declare const templateResourceEntity: import("@cosmicdrift/kumiko-types/f
|
|
|
143
144
|
} | undefined;
|
|
144
145
|
readonly optionsQuery?: string;
|
|
145
146
|
readonly optionsQueryPayload?: import("@cosmicdrift/kumiko-types/fields").OptionsQueryPayload;
|
|
147
|
+
readonly optionsAvailabilityQuery?: string;
|
|
146
148
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
147
149
|
required: true;
|
|
148
150
|
};
|
|
@@ -195,6 +197,7 @@ export declare const templateResourceEntity: import("@cosmicdrift/kumiko-types/f
|
|
|
195
197
|
} | undefined;
|
|
196
198
|
readonly optionsQuery?: string;
|
|
197
199
|
readonly optionsQueryPayload?: import("@cosmicdrift/kumiko-types/fields").OptionsQueryPayload;
|
|
200
|
+
readonly optionsAvailabilityQuery?: string;
|
|
198
201
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
199
202
|
required: true;
|
|
200
203
|
};
|
|
@@ -237,6 +240,7 @@ export declare const templateResourceEntity: import("@cosmicdrift/kumiko-types/f
|
|
|
237
240
|
} | undefined;
|
|
238
241
|
readonly optionsQuery?: string;
|
|
239
242
|
readonly optionsQueryPayload?: import("@cosmicdrift/kumiko-types/fields").OptionsQueryPayload;
|
|
243
|
+
readonly optionsAvailabilityQuery?: string;
|
|
240
244
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
241
245
|
required: true;
|
|
242
246
|
};
|
|
@@ -284,6 +288,7 @@ export declare const templateResourcesTable: import("@cosmicdrift/kumiko-framewo
|
|
|
284
288
|
} | undefined;
|
|
285
289
|
readonly optionsQuery?: string;
|
|
286
290
|
readonly optionsQueryPayload?: import("@cosmicdrift/kumiko-types/fields").OptionsQueryPayload;
|
|
291
|
+
readonly optionsAvailabilityQuery?: string;
|
|
287
292
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
288
293
|
required: true;
|
|
289
294
|
};
|
|
@@ -385,6 +390,7 @@ export declare const templateResourcesTable: import("@cosmicdrift/kumiko-framewo
|
|
|
385
390
|
} | undefined;
|
|
386
391
|
readonly optionsQuery?: string;
|
|
387
392
|
readonly optionsQueryPayload?: import("@cosmicdrift/kumiko-types/fields").OptionsQueryPayload;
|
|
393
|
+
readonly optionsAvailabilityQuery?: string;
|
|
388
394
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
389
395
|
required: true;
|
|
390
396
|
};
|
|
@@ -437,6 +443,7 @@ export declare const templateResourcesTable: import("@cosmicdrift/kumiko-framewo
|
|
|
437
443
|
} | undefined;
|
|
438
444
|
readonly optionsQuery?: string;
|
|
439
445
|
readonly optionsQueryPayload?: import("@cosmicdrift/kumiko-types/fields").OptionsQueryPayload;
|
|
446
|
+
readonly optionsAvailabilityQuery?: string;
|
|
440
447
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
441
448
|
required: true;
|
|
442
449
|
};
|
|
@@ -479,6 +486,7 @@ export declare const templateResourcesTable: import("@cosmicdrift/kumiko-framewo
|
|
|
479
486
|
} | undefined;
|
|
480
487
|
readonly optionsQuery?: string;
|
|
481
488
|
readonly optionsQueryPayload?: import("@cosmicdrift/kumiko-types/fields").OptionsQueryPayload;
|
|
489
|
+
readonly optionsAvailabilityQuery?: string;
|
|
482
490
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
483
491
|
required: true;
|
|
484
492
|
};
|
|
@@ -63,6 +63,7 @@ export declare const userContentEntryEntity: import("@cosmicdrift/kumiko-types/f
|
|
|
63
63
|
} | undefined;
|
|
64
64
|
readonly optionsQuery?: string;
|
|
65
65
|
readonly optionsQueryPayload?: import("@cosmicdrift/kumiko-types/fields").OptionsQueryPayload;
|
|
66
|
+
readonly optionsAvailabilityQuery?: string;
|
|
66
67
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
67
68
|
required: true;
|
|
68
69
|
};
|
|
@@ -164,6 +165,7 @@ export declare const userContentEntryEntity: import("@cosmicdrift/kumiko-types/f
|
|
|
164
165
|
} | undefined;
|
|
165
166
|
readonly optionsQuery?: string;
|
|
166
167
|
readonly optionsQueryPayload?: import("@cosmicdrift/kumiko-types/fields").OptionsQueryPayload;
|
|
168
|
+
readonly optionsAvailabilityQuery?: string;
|
|
167
169
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
168
170
|
required: true;
|
|
169
171
|
};
|
|
@@ -232,6 +234,7 @@ export declare const userContentEntriesTable: import("@cosmicdrift/kumiko-framew
|
|
|
232
234
|
} | undefined;
|
|
233
235
|
readonly optionsQuery?: string;
|
|
234
236
|
readonly optionsQueryPayload?: import("@cosmicdrift/kumiko-types/fields").OptionsQueryPayload;
|
|
237
|
+
readonly optionsAvailabilityQuery?: string;
|
|
235
238
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
236
239
|
required: true;
|
|
237
240
|
};
|
|
@@ -333,6 +336,7 @@ export declare const userContentEntriesTable: import("@cosmicdrift/kumiko-framew
|
|
|
333
336
|
} | undefined;
|
|
334
337
|
readonly optionsQuery?: string;
|
|
335
338
|
readonly optionsQueryPayload?: import("@cosmicdrift/kumiko-types/fields").OptionsQueryPayload;
|
|
339
|
+
readonly optionsAvailabilityQuery?: string;
|
|
336
340
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
337
341
|
required: true;
|
|
338
342
|
};
|
|
@@ -2,7 +2,7 @@ import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
|
2
2
|
import { access, definePagedQueryHandler, MAX_LIST_LIMIT, } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
3
|
import { InternalError } from "@cosmicdrift/kumiko-framework/errors";
|
|
4
4
|
import { parseRoles } from "@cosmicdrift/kumiko-framework/utils";
|
|
5
|
-
import { Temporal } from "temporal
|
|
5
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
6
6
|
import * as z from "zod";
|
|
7
7
|
import { userSessionTable } from "../../sessions/index.js";
|
|
8
8
|
import { decryptStoredPii, mapWithConcurrency } from "../../shared/index.js";
|
|
@@ -69,6 +69,7 @@ export declare const tenantInvitationEntity: import("@cosmicdrift/kumiko-types/f
|
|
|
69
69
|
} | undefined;
|
|
70
70
|
readonly optionsQuery?: string;
|
|
71
71
|
readonly optionsQueryPayload?: import("@cosmicdrift/kumiko-types/fields").OptionsQueryPayload;
|
|
72
|
+
readonly optionsAvailabilityQuery?: string;
|
|
72
73
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
73
74
|
required: true;
|
|
74
75
|
};
|
|
@@ -172,6 +173,7 @@ export declare const tenantInvitationsTable: import("@cosmicdrift/kumiko-framewo
|
|
|
172
173
|
} | undefined;
|
|
173
174
|
readonly optionsQuery?: string;
|
|
174
175
|
readonly optionsQueryPayload?: import("@cosmicdrift/kumiko-types/fields").OptionsQueryPayload;
|
|
176
|
+
readonly optionsAvailabilityQuery?: string;
|
|
175
177
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
176
178
|
required: true;
|
|
177
179
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type DbRunner } from "@cosmicdrift/kumiko-framework/db";
|
|
2
2
|
import { type TenantId } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
|
-
import { Temporal } from "temporal
|
|
3
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
4
4
|
export type InvitedMembershipOptions = {
|
|
5
5
|
readonly userId: string;
|
|
6
6
|
readonly tenantId: TenantId;
|
|
@@ -3,7 +3,7 @@ import { createEventStoreExecutor, createTenantDb, } from "@cosmicdrift/kumiko-f
|
|
|
3
3
|
import { createSystemUser } from "@cosmicdrift/kumiko-framework/engine";
|
|
4
4
|
import { ConflictError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
|
|
5
5
|
import { parseRoles } from "@cosmicdrift/kumiko-framework/utils";
|
|
6
|
-
import { Temporal } from "temporal
|
|
6
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
7
7
|
import { TenantErrors } from "./constants.js";
|
|
8
8
|
import { findForbiddenMembershipRole, reservedMembershipRoleError } from "./membership-roles.js";
|
|
9
9
|
import { tenantMembershipEntity, tenantMembershipsTable } from "./membership-table.js";
|
|
@@ -66,6 +66,7 @@ export declare const tenantEntity: import("@cosmicdrift/kumiko-types/fields").En
|
|
|
66
66
|
} | undefined;
|
|
67
67
|
readonly optionsQuery?: string;
|
|
68
68
|
readonly optionsQueryPayload?: import("@cosmicdrift/kumiko-types/fields").OptionsQueryPayload;
|
|
69
|
+
readonly optionsAvailabilityQuery?: string;
|
|
69
70
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
70
71
|
required: true;
|
|
71
72
|
};
|
|
@@ -217,6 +218,7 @@ export declare const tenantTable: import("@cosmicdrift/kumiko-framework/db").Ent
|
|
|
217
218
|
} | undefined;
|
|
218
219
|
readonly optionsQuery?: string;
|
|
219
220
|
readonly optionsQueryPayload?: import("@cosmicdrift/kumiko-types/fields").OptionsQueryPayload;
|
|
221
|
+
readonly optionsAvailabilityQuery?: string;
|
|
220
222
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
221
223
|
required: true;
|
|
222
224
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Temporal } from "temporal
|
|
1
|
+
import type { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
2
2
|
export declare function tenantHandoverPurpose(entityType: string): string;
|
|
3
3
|
export declare function signTenantHandoverGrant(args: {
|
|
4
4
|
readonly entityType: string;
|
|
@@ -3,5 +3,6 @@ export { type AddOnDefinition, type AddOnMap, type ComposeAppInput, type Compose
|
|
|
3
3
|
export { TIER_ENGINE_FEATURE, TierAssignmentSources, TierEngineHandlers, TierEngineQueries, } from "./constants.js";
|
|
4
4
|
export { tierAssignmentEntity } from "./entity.js";
|
|
5
5
|
export { type CreateTierEngineOptions, createTierEngineFeature, tierEngineFeature, } from "./feature.js";
|
|
6
|
+
export { createTierOptionGate, type TierOptionAvailability, type TierOptionGate, type TierOptionGateDeps, type TierOptionSpec, } from "./tier-option-gate.js";
|
|
6
7
|
export { createTierResolver, type TierResolver, type TierResolverDeps, } from "./tier-resolver.js";
|
|
7
8
|
export { isTrialActive, type TrialPolicy } from "./trial.js";
|
|
@@ -11,5 +11,6 @@ export { composeApp, } from "./compose-app.js";
|
|
|
11
11
|
export { TIER_ENGINE_FEATURE, TierAssignmentSources, TierEngineHandlers, TierEngineQueries, } from "./constants.js";
|
|
12
12
|
export { tierAssignmentEntity } from "./entity.js";
|
|
13
13
|
export { createTierEngineFeature, tierEngineFeature, } from "./feature.js";
|
|
14
|
+
export { createTierOptionGate, } from "./tier-option-gate.js";
|
|
14
15
|
export { createTierResolver, } from "./tier-resolver.js";
|
|
15
16
|
export { isTrialActive } from "./trial.js";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { EntityTableMeta, SchemaTable, TenantDb } from "@cosmicdrift/kumiko-framework/db";
|
|
2
|
+
import type { WriteHandlerDef } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
|
+
import { type WriteFailure } from "@cosmicdrift/kumiko-framework/errors";
|
|
4
|
+
import { type CapGuardContext, type CapLimitContext } from "../cap-counter/index.js";
|
|
5
|
+
export type TierOptionSpec<TCaps> = {
|
|
6
|
+
readonly field: string;
|
|
7
|
+
readonly options: readonly string[];
|
|
8
|
+
readonly isOptionAllowed: (option: string, caps: TCaps) => boolean;
|
|
9
|
+
readonly code: string;
|
|
10
|
+
readonly i18nKey: string;
|
|
11
|
+
/** Lets an update that resends the unchanged stored value of a no longer allowed
|
|
12
|
+
* option pass (edit forms submit the whole row). Without it the stored value is not looked up. */
|
|
13
|
+
readonly table?: SchemaTable | EntityTableMeta;
|
|
14
|
+
};
|
|
15
|
+
export type TierOptionAvailability = {
|
|
16
|
+
readonly value: string;
|
|
17
|
+
readonly disabled: boolean;
|
|
18
|
+
readonly hint?: string;
|
|
19
|
+
};
|
|
20
|
+
export type TierOptionGateDeps<TTier extends string, TCaps> = {
|
|
21
|
+
/** Ascending: the first tier that allows an option is the one named as required. */
|
|
22
|
+
readonly tierOrder: readonly TTier[];
|
|
23
|
+
readonly capsForTier: (tier: TTier, context: CapLimitContext) => TCaps | Promise<TCaps>;
|
|
24
|
+
readonly resolveTier: (db: TenantDb) => Promise<TTier>;
|
|
25
|
+
};
|
|
26
|
+
export type TierOptionGate<TTier extends string, TCaps> = {
|
|
27
|
+
readonly optionAvailability: (db: TenantDb, context: CapLimitContext, spec: Pick<TierOptionSpec<TCaps>, "options" | "isOptionAllowed">, hintFor: (requiredTier: TTier) => string) => Promise<readonly TierOptionAvailability[]>;
|
|
28
|
+
/** `recordId` is the id of the edited row; with `spec.table` it enables the unchanged-value pass. */
|
|
29
|
+
readonly checkTierOption: (ctx: CapGuardContext, value: unknown, spec: TierOptionSpec<TCaps>, recordId?: string) => Promise<WriteFailure | null>;
|
|
30
|
+
readonly withTierOptionGate: (handler: WriteHandlerDef, spec: TierOptionSpec<TCaps>) => WriteHandlerDef;
|
|
31
|
+
};
|
|
32
|
+
export declare function createTierOptionGate<TTier extends string, TCaps>(deps: TierOptionGateDeps<TTier, TCaps>): TierOptionGate<TTier, TCaps>;
|