@cosmicdrift/kumiko-bundled-features 0.349.0 → 0.351.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.js +1 -1
- package/dist/cap-counter/enforce-cap.d.ts +1 -1
- package/dist/cap-counter/enforce-cap.js +1 -8
- package/dist/channel-email/email-channel.js +13 -5
- package/dist/channel-email/pii-guard.js +6 -1
- package/dist/channel-email/smtp-transport.js +1 -0
- package/dist/channel-email/types.d.ts +1 -0
- package/dist/delivery/handlers/log.query.d.ts +1 -2
- package/dist/delivery/handlers/log.query.js +1 -1
- package/dist/delivery/jobs.js +3 -1
- package/dist/delivery/types.d.ts +3 -0
- 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/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-simple/simple-renderer.js +49 -13
- 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 +1 -1
- package/dist/tenant/handlers/team-list.query.d.ts +1 -1
- package/dist/tenant/handlers/team-list.query.js +1 -1
- package/dist/tenant/invited-membership.d.ts +1 -1
- package/dist/tenant/invited-membership.js +1 -1
- package/dist/tenant-handover/grant.d.ts +1 -1
- 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.d.ts +1 -0
- package/dist/user-data-rights/email-templates.js +27 -5
- 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/lib/default-mailers.js +8 -8
- package/dist/waitlist/handlers/invite.write.js +1 -1
- package/dist/waitlist/handlers/submit.write.js +1 -1
- package/package.json +9 -9
- package/src/channel-email/changes.json +6 -0
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
17
17
|
import { access, defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
|
|
18
18
|
import { eventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
19
|
-
import { Temporal } from "temporal
|
|
19
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
20
20
|
import * as z from "zod";
|
|
21
21
|
import { AUDIT_SCOPE_VALUES } from "../constants.js";
|
|
22
22
|
import { resolveAuditScopeFilter } from "./resolve-audit-tenant.js";
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// English ships here. Other languages register via @cosmicdrift/kumiko-locale-*
|
|
9
9
|
// (localeDe() / localeEs() call registerMailTranslations).
|
|
10
10
|
import { mailT, registerMailTranslations } from "@cosmicdrift/kumiko-framework/i18n";
|
|
11
|
-
import { Temporal } from "temporal
|
|
11
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
12
12
|
export const AUTH_MAIL_EN = {
|
|
13
13
|
"auth.mail.appNameDefault": "Account",
|
|
14
14
|
"auth.mail.reset.subject": "{app} — Reset your password",
|
|
@@ -20,7 +20,7 @@ import { generateToken } from "@cosmicdrift/kumiko-framework/api";
|
|
|
20
20
|
import { createEventStoreExecutor } from "@cosmicdrift/kumiko-framework/db";
|
|
21
21
|
import { access, assignableAppRolesOf, defineWriteHandler, } from "@cosmicdrift/kumiko-framework/engine";
|
|
22
22
|
import { InternalError, writeFailure, } from "@cosmicdrift/kumiko-framework/errors";
|
|
23
|
-
import { Temporal } from "temporal
|
|
23
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
24
24
|
import * as z from "zod";
|
|
25
25
|
// kumiko-lint-ignore cross-feature-import invite-flow lebt in auth-email-password (Magic-Link-Pattern), DB-row-owner ist tenant-feature
|
|
26
26
|
import { INVITATION_STATUS, tenantInvitationEntity, tenantInvitationsTable, } from "../../tenant/invitation-table.js";
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
import { generateToken } from "@cosmicdrift/kumiko-framework/api";
|
|
24
24
|
import { defineWriteHandler } from "@cosmicdrift/kumiko-framework/engine";
|
|
25
25
|
import { InternalError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
|
|
26
|
-
import { Temporal } from "temporal
|
|
26
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
27
27
|
import * as z from "zod";
|
|
28
28
|
import { findSignupHandoverProvider } from "../../shared/index.js";
|
|
29
29
|
import { AUTH_SIGNUP_DEFAULT_TTL_MINUTES } from "../constants.js";
|
|
@@ -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
|
import { type AuthUserRow } from "../auth-user-row.js";
|
|
4
4
|
import type { AuthMailContent, AuthMailLocale, RenderTokenContentArgs } from "../email-templates.js";
|
|
@@ -2,7 +2,7 @@ import { createEventStoreExecutor, createTenantDb } from "@cosmicdrift/kumiko-fr
|
|
|
2
2
|
import { buildSessionRoles, createSystemUser, defineWriteHandler, } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
3
|
import { InternalError, writeFailure } 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 { burnToken, sessionLocaleField, sessionTimezoneField } from "../../shared/index.js";
|
|
8
8
|
import { USER_STATUS, UserQueries } from "../../user/index.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createEventStoreExecutor } from "@cosmicdrift/kumiko-framework/db";
|
|
2
2
|
import { defineWriteHandler } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
3
|
import { InternalError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
|
|
4
|
-
import { Temporal } from "temporal
|
|
4
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
5
5
|
import * as z from "zod";
|
|
6
6
|
import { burnToken } from "../../shared/index.js";
|
|
7
7
|
import { base32Decode } from "../base32.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
2
|
-
import { Temporal } from "temporal
|
|
2
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
3
3
|
function hmacSign(input, secret) {
|
|
4
4
|
return createHmac("sha256", secret).update(input).digest("base64url");
|
|
5
5
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { TenantId } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
|
-
import { Temporal } from "temporal
|
|
2
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
3
3
|
import { type HmacTokenVerifyResult } from "./hmac-token-codec.js";
|
|
4
4
|
export type MfaChallengePayload = {
|
|
5
5
|
readonly userId: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { TenantId } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
|
-
import { Temporal } from "temporal
|
|
2
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
3
3
|
import { type HmacTokenVerifyResult } from "./hmac-token-codec.js";
|
|
4
4
|
export type MfaPreauthSetupPayload = {
|
|
5
5
|
readonly userId: string;
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
// signed-token.ts (userId-only payload) because setup needs to carry
|
|
11
11
|
// generated secret material, not just re-derive it from a lookup.
|
|
12
12
|
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
13
|
-
import { Temporal } from "temporal
|
|
13
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
14
14
|
function sign(input, secret) {
|
|
15
15
|
return createHmac("sha256", secret).update(input).digest("base64url");
|
|
16
16
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference types="temporal-polyfill/global" preserve="true" />
|
|
2
|
-
import { Temporal
|
|
2
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
3
3
|
export declare const BILLING_FOUNDATION_FEATURE: "billing-foundation";
|
|
4
4
|
export declare const SUBSCRIPTION_PROVIDER_EXTENSION: "subscriptionProvider";
|
|
5
5
|
/** delivery notification type of the § 312f contract confirmation mail. */
|
|
@@ -119,7 +119,7 @@ export declare const BillingPlanActions: {
|
|
|
119
119
|
export type BillingPlanAction = (typeof BillingPlanActions)[keyof typeof BillingPlanActions];
|
|
120
120
|
export declare const TERMINAL_SUBSCRIPTION_STATUSES: ReadonlySet<string>;
|
|
121
121
|
export declare function isTerminalSubscriptionStatus(status: string): boolean;
|
|
122
|
-
export declare const STALE_INCOMPLETE_AFTER:
|
|
122
|
+
export declare const STALE_INCOMPLETE_AFTER: globalThis.Temporal.Duration;
|
|
123
123
|
/** Time-aware terminal check for the checkout gate: a canceled subscription
|
|
124
124
|
* is terminal (see `isTerminalSubscriptionStatus`), and so is an
|
|
125
125
|
* `incomplete` one once it's older than `STALE_INCOMPLETE_AFTER` — every
|
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
/// <reference types="temporal-polyfill/global" preserve="true" />
|
|
2
2
|
// @runtime client
|
|
3
|
-
|
|
4
|
-
// module), so importing it here doesn't break browser bundles. Aliased —
|
|
5
|
-
// same reason as event-store.ts's own import: the un-aliased name would
|
|
6
|
-
// shadow the ambient global `Temporal` TYPE every `Temporal.Instant`
|
|
7
|
-
// annotation in this file (and its callers, e.g. StoredEvent.createdAt)
|
|
8
|
-
// resolves against, see #1438.
|
|
9
|
-
import { Temporal as TemporalPolyfill } from "temporal-polyfill";
|
|
3
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
10
4
|
// Feature name
|
|
11
5
|
export const BILLING_FOUNDATION_FEATURE = "billing-foundation";
|
|
12
6
|
// Extension-point name fuer Provider-Plugins (subscription-stripe,
|
|
@@ -158,7 +152,7 @@ export function isTerminalSubscriptionStatus(status) {
|
|
|
158
152
|
// after roughly 23 hours; without a matching staleness cutoff on our side, a
|
|
159
153
|
// stale incomplete row would block that tenant from ever starting a new
|
|
160
154
|
// checkout, since the projection has no expiry-triggered event of its own.
|
|
161
|
-
export const STALE_INCOMPLETE_AFTER =
|
|
155
|
+
export const STALE_INCOMPLETE_AFTER = Temporal.Duration.from({ hours: 24 });
|
|
162
156
|
/** Time-aware terminal check for the checkout gate: a canceled subscription
|
|
163
157
|
* is terminal (see `isTerminalSubscriptionStatus`), and so is an
|
|
164
158
|
* `incomplete` one once it's older than `STALE_INCOMPLETE_AFTER` — every
|
|
@@ -170,10 +164,7 @@ export function isSubscriptionBlockingCheckout(sub, now) {
|
|
|
170
164
|
if (sub.status !== SubscriptionStatuses.incomplete)
|
|
171
165
|
return true;
|
|
172
166
|
const staleAt = sub.lastChangedAt.add(STALE_INCOMPLETE_AFTER);
|
|
173
|
-
|
|
174
|
-
// at runtime — row types resolve against ambient Temporal; polyfill Instant
|
|
175
|
-
// is a separate nominal type across the two .d.ts sources.
|
|
176
|
-
return (TemporalPolyfill.Instant.compare(now, staleAt) < 0);
|
|
167
|
+
return Temporal.Instant.compare(now, staleAt) < 0;
|
|
177
168
|
}
|
|
178
169
|
// A subscription in one of these statuses can be switched to a different
|
|
179
170
|
// plan tier via the provider's confirmation page (Stripe portal
|
|
@@ -50,10 +50,7 @@
|
|
|
50
50
|
// (z.B. für analytics: "wie viele Wechsel im Monat?"), kommt ein
|
|
51
51
|
// `subscription-provider-changed`-event-type später.
|
|
52
52
|
import { defineFeature, EXT_TENANT_DATA, } from "@cosmicdrift/kumiko-framework/engine";
|
|
53
|
-
|
|
54
|
-
// `Temporal` TYPE `ResolvedBillingFoundationOptions.now`'s return type
|
|
55
|
-
// resolves against, see event-store.ts's own import comment (#1438).
|
|
56
|
-
import { Temporal as TemporalPolyfill } from "temporal-polyfill";
|
|
53
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
57
54
|
import { BILLING_FOUNDATION_FEATURE, SUBSCRIPTION_PROVIDER_EXTENSION, SubscriptionFoundationHandlers, } from "./constants.js";
|
|
58
55
|
import { registerConsumerProtection } from "./consumer-protection/register-consent.js";
|
|
59
56
|
import { paymentEntity, subscriptionEntity } from "./entities.js";
|
|
@@ -87,11 +84,7 @@ export function createBillingFoundationFeature(options = {}) {
|
|
|
87
84
|
// ever calls `Temporal.Now.instant` itself.
|
|
88
85
|
const widened = {
|
|
89
86
|
...options,
|
|
90
|
-
|
|
91
|
-
// at runtime — `now` is typed against the ambient Temporal global;
|
|
92
|
-
// TemporalPolyfill.Now.instant() returns the polyfill's own nominal
|
|
93
|
-
// Instant type across the two .d.ts sources.
|
|
94
|
-
now: options.now ?? (() => TemporalPolyfill.Now.instant()),
|
|
87
|
+
now: options.now ?? (() => Temporal.Now.instant()),
|
|
95
88
|
...(options.baseUrl !== undefined && {
|
|
96
89
|
baseUrl: options.baseUrl.endsWith("/") ? options.baseUrl.slice(0, -1) : options.baseUrl,
|
|
97
90
|
}),
|
|
@@ -14,23 +14,20 @@
|
|
|
14
14
|
// the same reason. A human SystemAdmin can still dispatch this directly.
|
|
15
15
|
import { createHash } from "node:crypto";
|
|
16
16
|
import { SYSTEM_ROLE } from "@cosmicdrift/kumiko-framework/engine";
|
|
17
|
-
|
|
18
|
-
// `Temporal` TYPE `SubscriptionView.currentPeriodEnd`/`.cancelAt` resolve
|
|
19
|
-
// against, same reasoning as constants.ts's own import.
|
|
20
|
-
import { Temporal as TemporalPolyfill } from "temporal-polyfill";
|
|
17
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
21
18
|
import * as z from "zod";
|
|
22
19
|
import { findProviderPlugin } from "../checkout-core.js";
|
|
23
20
|
import { isTerminalSubscriptionStatus, SubscriptionEventTypes } from "../constants.js";
|
|
24
21
|
import { getSubscriptionForTenant } from "../get-subscription-for-tenant.js";
|
|
25
22
|
import { appendSubscriptionEvent } from "./process-event.write.js";
|
|
26
23
|
export const syncSubscriptionSchema = z.object({}).strict();
|
|
27
|
-
// Parses both sides fresh via
|
|
24
|
+
// Parses both sides fresh via Temporal before comparing — tolerant of a
|
|
28
25
|
// provider snapshot's ISO string using a different (but equivalent)
|
|
29
26
|
// representation than `Temporal.Instant#toString()`'s canonical form
|
|
30
27
|
// (offset spelling, sub-second precision, ...), unlike a plain `===` on the
|
|
31
28
|
// raw strings.
|
|
32
29
|
function isoInstantsEqual(a, b) {
|
|
33
|
-
return
|
|
30
|
+
return Temporal.Instant.compare(Temporal.Instant.from(a), Temporal.Instant.from(b)) === 0;
|
|
34
31
|
}
|
|
35
32
|
// Deterministic per (snapshot-content, current stream head) — not per-call.
|
|
36
33
|
// Folding in `lastChangedAt` (not just the snapshot's own fields) closes a
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { runInOwnTransaction } from "@cosmicdrift/kumiko-framework/db";
|
|
3
3
|
import { createEntityExecutor, } from "@cosmicdrift/kumiko-framework/engine";
|
|
4
4
|
import { eventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
5
|
-
import { Temporal } from "temporal
|
|
5
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
6
6
|
import * as z from "zod";
|
|
7
7
|
import { capCounterAggregateId, rollingCapAggregateId } from "./aggregate-id.js";
|
|
8
8
|
import { CAP_COUNTER_ROLLING_AGGREGATE_TYPE, ROLLING_INCREMENTED_EVENT_QN } from "./constants.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
/// <reference types="temporal-polyfill/global" preserve="true" />
|
|
2
1
|
import { type HandlerContext } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
2
|
import { KumikoError } from "@cosmicdrift/kumiko-framework/errors";
|
|
3
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
4
4
|
/**
|
|
5
5
|
* Cap-Toleranz-Profile — pro Cap-Typ asymmetrisch. Quelle: Memory
|
|
6
6
|
* `project_pricing_byok_caps` §3 + `docs/plans/marketing/produkt/
|
|
@@ -1,15 +1,8 @@
|
|
|
1
|
-
/// <reference types="temporal-polyfill/global" preserve="true" />
|
|
2
1
|
import { createEntityExecutor } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
2
|
import { KumikoError, reraiseAsKumikoError } from "@cosmicdrift/kumiko-framework/errors";
|
|
3
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
4
4
|
import { markCapSoftWarned, readRollingCapUsage } from "./book-cap-usage.js";
|
|
5
5
|
import { capCounterEntity } from "./entity.js";
|
|
6
|
-
// Temporal globally provided by the framework's polyfill init
|
|
7
|
-
// (ensureTemporalPolyfill() in time/polyfill.ts, called from
|
|
8
|
-
// setupTestStack/boot). Importing from "temporal-polyfill" gives us
|
|
9
|
-
// the polyfill-package types which don't quite match drizzle's
|
|
10
|
-
// `instant()`-customType (temporal-spec narrowing of `until(...).sign`).
|
|
11
|
-
// Mirror the audit-handler pattern: rely on the global ambient
|
|
12
|
-
// declaration from temporal-spec.
|
|
13
6
|
const { table } = createEntityExecutor("cap-counter", capCounterEntity);
|
|
14
7
|
export const CAP_TOLERANCES = {
|
|
15
8
|
/** Mails / Tokens — billig, BYOK ab Pro. Burst-Buffer großzügig. */
|
|
@@ -78,13 +78,15 @@ export function createEmailChannel(options) {
|
|
|
78
78
|
title: message.title,
|
|
79
79
|
body: message.body,
|
|
80
80
|
};
|
|
81
|
-
const
|
|
81
|
+
const rendererInput = {
|
|
82
82
|
template: message.notificationType,
|
|
83
83
|
variables,
|
|
84
84
|
locale: message.locale,
|
|
85
|
-
}
|
|
85
|
+
};
|
|
86
|
+
const html = await renderer.render(rendererInput);
|
|
87
|
+
const text = renderer.renderText ? await renderer.renderText(rendererInput) : undefined;
|
|
86
88
|
const subject = variables["subject"] ?? message.title; // @cast-boundary dynamic-key
|
|
87
|
-
return { html, subject };
|
|
89
|
+
return { html, subject, ...(text !== undefined && { text }) };
|
|
88
90
|
}
|
|
89
91
|
return {
|
|
90
92
|
name: "email",
|
|
@@ -101,9 +103,15 @@ export function createEmailChannel(options) {
|
|
|
101
103
|
return renderMessage(message);
|
|
102
104
|
},
|
|
103
105
|
async send(address, message, _ctx, rendered) {
|
|
104
|
-
const { html, subject } = rendered ?? (await renderMessage(message));
|
|
106
|
+
const { html, subject, text } = rendered ?? (await renderMessage(message));
|
|
105
107
|
const envelope = emailEnvelopeFrom(message.data);
|
|
106
|
-
await transport.send(guardEmailMessage({
|
|
108
|
+
await transport.send(guardEmailMessage({
|
|
109
|
+
to: address,
|
|
110
|
+
subject,
|
|
111
|
+
html,
|
|
112
|
+
...(text !== undefined && { text }),
|
|
113
|
+
...envelope,
|
|
114
|
+
}));
|
|
107
115
|
return { status: "sent", address };
|
|
108
116
|
},
|
|
109
117
|
};
|
|
@@ -28,7 +28,9 @@ export function guardEmailMessage(message) {
|
|
|
28
28
|
`("${PII_CIPHERTEXT_PREFIX}…") — decrypt the stored value before mailing (decryptStoredPii).`);
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
|
-
const leaking = message.subject.includes(CIPHERTEXT_MARKER) ||
|
|
31
|
+
const leaking = message.subject.includes(CIPHERTEXT_MARKER) ||
|
|
32
|
+
message.html.includes(CIPHERTEXT_MARKER) ||
|
|
33
|
+
message.text?.includes(CIPHERTEXT_MARKER) === true;
|
|
32
34
|
if (!leaking)
|
|
33
35
|
return message;
|
|
34
36
|
const detail = "[channel-email] mail subject/body contains a PII ciphertext " +
|
|
@@ -41,6 +43,9 @@ export function guardEmailMessage(message) {
|
|
|
41
43
|
...message,
|
|
42
44
|
subject: message.subject.replace(CIPHERTEXT_RE, "[pii-redacted]"),
|
|
43
45
|
html: message.html.replace(CIPHERTEXT_RE, "[pii-redacted]"),
|
|
46
|
+
...(message.text !== undefined && {
|
|
47
|
+
text: message.text.replace(CIPHERTEXT_RE, "[pii-redacted]"),
|
|
48
|
+
}),
|
|
44
49
|
};
|
|
45
50
|
}
|
|
46
51
|
export function withPiiCiphertextGuard(transport) {
|
|
@@ -54,6 +54,7 @@ export function createSmtpTransport(options) {
|
|
|
54
54
|
to: message.to,
|
|
55
55
|
subject: message.subject,
|
|
56
56
|
html: message.html,
|
|
57
|
+
...(message.text !== undefined && { text: message.text }),
|
|
57
58
|
...(message.replyTo && { replyTo: message.replyTo }),
|
|
58
59
|
...(message.headers && { headers: message.headers }),
|
|
59
60
|
});
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { type DeliveryErrorCode, type NotifyPriority } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
|
-
import { Temporal } from "temporal-polyfill";
|
|
3
2
|
import * as z from "zod";
|
|
4
3
|
import type { DeliveryStatusValue } from "../constants.js";
|
|
5
4
|
export declare const logQuery: import("@cosmicdrift/kumiko-framework/engine").PagedQueryHandlerDefinition<"log", z.ZodObject<{
|
|
@@ -22,5 +21,5 @@ export declare const logQuery: import("@cosmicdrift/kumiko-framework/engine").Pa
|
|
|
22
21
|
error: DeliveryErrorCode | null;
|
|
23
22
|
priority: NotifyPriority;
|
|
24
23
|
confirmed: boolean | null;
|
|
25
|
-
createdAt: Temporal.Instant;
|
|
24
|
+
createdAt: globalThis.Temporal.Instant;
|
|
26
25
|
}, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap>;
|
|
@@ -2,7 +2,7 @@ import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
|
2
2
|
import { decodeKeysetCursor, encodeKeysetCursor, } from "@cosmicdrift/kumiko-framework/db";
|
|
3
3
|
import { access, definePagedQueryHandler, isDeliveryErrorCode, isUuid, MAX_LIST_LIMIT, SYSTEM_USER_ID, } from "@cosmicdrift/kumiko-framework/engine";
|
|
4
4
|
import { InternalError } from "@cosmicdrift/kumiko-framework/errors";
|
|
5
|
-
import { Temporal } from "temporal
|
|
5
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
6
6
|
import * as z from "zod";
|
|
7
7
|
import { decryptStoredPii } from "../../shared/index.js";
|
|
8
8
|
import { resolveUserDisplayNames, USER_FEATURE } from "../../user/index.js";
|
package/dist/delivery/jobs.js
CHANGED
|
@@ -28,7 +28,9 @@ const renderJobPayloadSchema = z.object({
|
|
|
28
28
|
message: channelMessageSchema,
|
|
29
29
|
});
|
|
30
30
|
const sendJobPayloadSchema = renderJobPayloadSchema.extend({
|
|
31
|
-
rendered: z
|
|
31
|
+
rendered: z
|
|
32
|
+
.object({ html: z.string(), subject: z.string(), text: z.string().optional() })
|
|
33
|
+
.optional(),
|
|
32
34
|
});
|
|
33
35
|
function requireTenantScopedDeps(ctx, tenantId) {
|
|
34
36
|
const registry = ctx.registry;
|
package/dist/delivery/types.d.ts
CHANGED
|
@@ -26,6 +26,7 @@ export type ChannelResult = {
|
|
|
26
26
|
export type RenderedMessage = {
|
|
27
27
|
readonly html: string;
|
|
28
28
|
readonly subject: string;
|
|
29
|
+
readonly text?: string;
|
|
29
30
|
};
|
|
30
31
|
export declare const DELIVERY_CHANNEL_MODES: readonly ["inline", "queued"];
|
|
31
32
|
export type DeliveryChannelMode = (typeof DELIVERY_CHANNEL_MODES)[number];
|
|
@@ -44,6 +45,8 @@ export type RendererInput = {
|
|
|
44
45
|
export type NotificationRenderer = {
|
|
45
46
|
readonly name: string;
|
|
46
47
|
render(input: RendererInput): Promise<string>;
|
|
48
|
+
/** Plain-text version of the same mail; the email channel sends it as the text part of a multipart/alternative mail. */
|
|
49
|
+
renderText?(input: RendererInput): Promise<string>;
|
|
47
50
|
};
|
|
48
51
|
export type DeliveryLogEntry = {
|
|
49
52
|
readonly tenantId: TenantId;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { insertOne, selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
2
2
|
import { defineWriteHandler, SYSTEM_TENANT_ID } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
3
|
import { UnprocessableError, VersionConflictError, writeFailure, } from "@cosmicdrift/kumiko-framework/errors";
|
|
4
|
-
import { Temporal } from "temporal
|
|
4
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
5
5
|
import * as z from "zod";
|
|
6
6
|
import { FEATURE_TOGGLE_AGGREGATE_TYPE, FEATURE_TOGGLE_CROSS_TENANT_REASON, FEATURE_TOGGLE_SET_EVENT_NAME, FeatureToggleErrors, } from "../constants.js";
|
|
7
7
|
import { globalFeatureStateTable } from "../global-feature-state-table.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { DbConnection } 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
|
import type { FormDraftBlob } from "../../schemas.js";
|
|
5
5
|
export type StaleDraftRow = {
|
|
6
6
|
readonly id: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { unsafeReadRetrying } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
2
|
-
import { Temporal } from "temporal
|
|
2
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
3
3
|
// COALESCE(modified_at, inserted_at) — a draft's "last touched" timestamp is
|
|
4
4
|
// modified_at once the upsert path (save.write.ts) has updated it at least
|
|
5
5
|
// once; a draft saved exactly once (create, never updated) has no
|
|
@@ -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 type { Temporal } from "temporal
|
|
3
|
+
import type { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
4
4
|
export declare function filterOwnedStorageKeys(db: DbRunner, tenantId: TenantId, ownerId: string, candidateKeys: readonly string[], draftInsertedAt: Temporal.Instant, isCreateMode: boolean): Promise<readonly string[]>;
|
|
5
5
|
export type OwnedFileRef = {
|
|
6
6
|
readonly id: string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { TenantDb } from "@cosmicdrift/kumiko-framework/db";
|
|
2
2
|
import type { 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 { FormDraftBlob } from "./schemas.js";
|
|
5
5
|
export type FormDraftRow = {
|
|
6
6
|
readonly id: string;
|
|
@@ -23,7 +23,7 @@ import { countWhere } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
|
23
23
|
import { configuredPiiSubjectKms, encryptPiiFieldValues, } from "@cosmicdrift/kumiko-framework/crypto";
|
|
24
24
|
import { acquireNamespacedAdvisoryLock } from "@cosmicdrift/kumiko-framework/db";
|
|
25
25
|
import { InternalError } from "@cosmicdrift/kumiko-framework/errors";
|
|
26
|
-
import { Temporal } from "temporal
|
|
26
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
27
27
|
import * as z from "zod";
|
|
28
28
|
import { inboundMessageAggregateId, mailThreadAggregateId } from "../aggregate-id.js";
|
|
29
29
|
import { INBOUND_MESSAGE_PII_FIELDS, inboundMessageEntity, MAIL_THREAD_PII_FIELDS, mailThreadEntity, seenMessageTable, } from "../entities.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type DbConnection } from "@cosmicdrift/kumiko-framework/db";
|
|
2
2
|
import type { SecretsContext } from "@cosmicdrift/kumiko-framework/secrets";
|
|
3
|
-
import { Temporal } from "temporal
|
|
3
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
4
4
|
import { type InboundMailContext, type InboundMailProviderPlugin, type MailAccountRecord, type OAuthTokenSet } from "./types.js";
|
|
5
5
|
/** Shared by the OAuth callback and the refresh path so both write the slot identically. */
|
|
6
6
|
export declare function inboundRefreshTokenSecretOptions(accountId: string): {
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
// so the read always reflects the latest committed write.
|
|
18
18
|
import { transaction } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
19
19
|
import { acquireNamespacedAdvisoryLock } from "@cosmicdrift/kumiko-framework/db";
|
|
20
|
-
import { Temporal } from "temporal
|
|
20
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
21
21
|
import { InboundMailAuthMethods, inboundCredentialSecretKey } from "./constants.js";
|
|
22
22
|
import { InboundAuthError, } from "./types.js";
|
|
23
23
|
// 'inoa' as ASCII — disjoint from the other fixed advisory-lock namespaces.
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
// Muster: auth-email-password/signed-token.ts (HMAC-SHA256, purpose im
|
|
11
11
|
// HMAC-Input, timing-safe compare, Expiry im Klartext-Segment).
|
|
12
12
|
import { createHmac, randomUUID, timingSafeEqual } from "node:crypto";
|
|
13
|
-
import { Temporal } from "temporal
|
|
13
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
14
14
|
const STATE_PURPOSE = "inbound-mail-oauth-connect";
|
|
15
15
|
function sign(input, secret) {
|
|
16
16
|
return createHmac("sha256", secret).update(input).digest("base64url");
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
// exceeded) tears down the local watcher instead of racing a new holder.
|
|
46
46
|
import { fetchOne, insertOne, selectMany, updateMany } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
47
47
|
import { configuredPiiSubjectKms, decryptPiiFieldValues, } from "@cosmicdrift/kumiko-framework/crypto";
|
|
48
|
-
import { Temporal } from "temporal
|
|
48
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
49
49
|
import { InboundMailAccountStatuses, InboundMailFoundationHandlers } from "./constants.js";
|
|
50
50
|
import { MAIL_ACCOUNT_PII_FIELDS, syncCursorTable } from "./entities.js";
|
|
51
51
|
import { createOAuthAccessTokenManager, usesFoundationManagedOAuth, } from "./oauth-access-token.js";
|
|
@@ -26,7 +26,7 @@ import { INBOUND_MAIL_PROVIDER_EXTENSION, InboundAuthError, inboundCredentialSec
|
|
|
26
26
|
import { requireSecretsContext } from "@cosmicdrift/kumiko-bundled-features/secrets";
|
|
27
27
|
import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
|
|
28
28
|
import { instantToLegacyDate } from "@cosmicdrift/kumiko-framework/time";
|
|
29
|
-
import { Temporal } from "temporal
|
|
29
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
30
30
|
import { parseImapCredentialDocument } from "./credential-document.js";
|
|
31
31
|
import { assertUidValidity, coerceDate, createImapClient, IMAP_MAILBOX, imapMailHostGuard, mapImapError, parseImapCursor, toRawInboundMessage, } from "./imap-client.js";
|
|
32
32
|
const FEATURE_NAME = "inbound-provider-imap";
|
|
@@ -5,9 +5,9 @@ import { BlockedHostError, readAllowedPrivateMailHostsFromEnv, resolveMailConnec
|
|
|
5
5
|
import { InboundAuthError, InboundCursorInvalidError, InboundTransientError, } from "@cosmicdrift/kumiko-bundled-features/inbound-mail-foundation";
|
|
6
6
|
import { createFallbackLogger } from "@cosmicdrift/kumiko-framework/logging";
|
|
7
7
|
import { legacyDateToInstant } from "@cosmicdrift/kumiko-framework/time";
|
|
8
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
8
9
|
import { ImapFlow } from "imapflow";
|
|
9
10
|
import { simpleParser } from "mailparser";
|
|
10
|
-
import { Temporal } from "temporal-polyfill";
|
|
11
11
|
export const IMAP_MAILBOX = "INBOX";
|
|
12
12
|
const SNIPPET_MAX = 300;
|
|
13
13
|
const log = createFallbackLogger("inbound-provider-imap");
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Temporal } from "temporal
|
|
1
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
2
2
|
export declare function parseJobInstant(iso: string): Temporal.Instant;
|
package/dist/jobs/job-instant.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Temporal } from "temporal
|
|
1
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
2
2
|
// kumiko-framework#1525: the five value-position Temporal.Instant.from
|
|
3
3
|
// call sites in feature.ts live inside defineApply callbacks with no
|
|
4
4
|
// exported seam, so this thin wrapper gives the ambient-global-independence
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { WhereObject } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
2
|
+
import type { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
2
3
|
import type { TenantDb } from "@cosmicdrift/kumiko-types/tenant-db-types";
|
|
3
|
-
import type { Temporal } from "temporal-polyfill";
|
|
4
4
|
import { type MetricRange } from "./constants.js";
|
|
5
5
|
import type { MetricDefinition, MetricResult } from "./types.js";
|
|
6
6
|
export type MetricRunParams = {
|
package/dist/metrics/feature.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { access, defineFeature, defineQueryHandler, } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
2
|
import { InternalError, ValidationError } from "@cosmicdrift/kumiko-framework/errors";
|
|
3
|
-
import { Temporal } from "temporal
|
|
3
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
4
4
|
import * as z from "zod";
|
|
5
5
|
import { runMetric } from "./compute.js";
|
|
6
6
|
import { METRIC_RANGES, METRICS_FEATURE, METRICS_SYSTEM_FEATURE, } from "./constants.js";
|