@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.
Files changed (98) hide show
  1. package/dist/audit/handlers/list.query.js +1 -1
  2. package/dist/auth-email-password/email-templates.js +1 -1
  3. package/dist/auth-email-password/handlers/invite-create.write.js +1 -1
  4. package/dist/auth-email-password/handlers/signup-request.write.js +1 -1
  5. package/dist/auth-email-password/handlers/token-request-handler.d.ts +1 -1
  6. package/dist/auth-email-password/reset-token.d.ts +1 -1
  7. package/dist/auth-email-password/unlock-token.d.ts +1 -1
  8. package/dist/auth-email-password/verification-token.d.ts +1 -1
  9. package/dist/auth-mfa/handlers/enable-confirm-preauth.write.js +1 -1
  10. package/dist/auth-mfa/handlers/enable-confirm.write.js +1 -1
  11. package/dist/auth-mfa/hmac-token-codec.d.ts +1 -1
  12. package/dist/auth-mfa/hmac-token-codec.js +1 -1
  13. package/dist/auth-mfa/mfa-challenge-token.d.ts +1 -1
  14. package/dist/auth-mfa/mfa-challenge-token.js +1 -1
  15. package/dist/auth-mfa/mfa-preauth-setup-token.d.ts +1 -1
  16. package/dist/auth-mfa/mfa-preauth-setup-token.js +1 -1
  17. package/dist/auth-mfa/mfa-setup-token.d.ts +1 -1
  18. package/dist/auth-mfa/mfa-setup-token.js +1 -1
  19. package/dist/billing-foundation/constants.d.ts +2 -2
  20. package/dist/billing-foundation/constants.js +3 -12
  21. package/dist/billing-foundation/consumer-protection/confirmation-mail.js +1 -1
  22. package/dist/billing-foundation/consumer-protection/termination-mail.js +1 -1
  23. package/dist/billing-foundation/feature.js +2 -9
  24. package/dist/billing-foundation/handlers/sync-subscription.write.js +3 -6
  25. package/dist/cap-counter/book-cap-usage.js +1 -1
  26. package/dist/cap-counter/enforce-cap.d.ts +1 -1
  27. package/dist/cap-counter/enforce-cap.js +1 -8
  28. package/dist/channel-email/email-channel.js +13 -5
  29. package/dist/channel-email/pii-guard.js +6 -1
  30. package/dist/channel-email/smtp-transport.js +1 -0
  31. package/dist/channel-email/types.d.ts +1 -0
  32. package/dist/delivery/handlers/log.query.d.ts +1 -2
  33. package/dist/delivery/handlers/log.query.js +1 -1
  34. package/dist/delivery/jobs.js +3 -1
  35. package/dist/delivery/types.d.ts +3 -0
  36. package/dist/feature-toggles/handlers/set.write.js +1 -1
  37. package/dist/form-draft/db/queries/cleanup.d.ts +1 -1
  38. package/dist/form-draft/db/queries/cleanup.js +1 -1
  39. package/dist/form-draft/db/queries/owned-file-refs.d.ts +1 -1
  40. package/dist/form-draft/lookup.d.ts +1 -1
  41. package/dist/inbound-mail-foundation/handlers/ingest-message.write.js +1 -1
  42. package/dist/inbound-mail-foundation/oauth-access-token.d.ts +1 -1
  43. package/dist/inbound-mail-foundation/oauth-access-token.js +1 -1
  44. package/dist/inbound-mail-foundation/oauth-state.d.ts +1 -1
  45. package/dist/inbound-mail-foundation/oauth-state.js +1 -1
  46. package/dist/inbound-mail-foundation/watch-supervisor.js +1 -1
  47. package/dist/inbound-provider-imap/feature.js +1 -1
  48. package/dist/inbound-provider-imap/imap-client.js +1 -1
  49. package/dist/jobs/job-instant.d.ts +1 -1
  50. package/dist/jobs/job-instant.js +1 -1
  51. package/dist/metrics/compute.d.ts +1 -1
  52. package/dist/metrics/feature.js +1 -1
  53. package/dist/metrics/types.d.ts +1 -1
  54. package/dist/metrics/window.d.ts +1 -1
  55. package/dist/metrics/window.js +1 -1
  56. package/dist/personal-access-tokens/expiry.js +1 -1
  57. package/dist/personal-access-tokens/handlers/create.write.js +1 -1
  58. package/dist/personal-access-tokens/handlers/revoke.write.js +1 -1
  59. package/dist/personal-access-tokens/revoke-for-user.js +1 -1
  60. package/dist/renderer-simple/simple-renderer.js +49 -13
  61. package/dist/sessions/handlers/revoke-all-for-user.write.js +1 -1
  62. package/dist/sessions/handlers/revoke-all-others.write.js +1 -1
  63. package/dist/sessions/handlers/revoke.write.js +1 -1
  64. package/dist/sessions/session-callbacks.js +1 -1
  65. package/dist/shared/grace-period.d.ts +2 -1
  66. package/dist/shared/grace-period.js +3 -7
  67. package/dist/shared/row-bound-grant.d.ts +1 -1
  68. package/dist/shared/signed-token.d.ts +1 -1
  69. package/dist/shared/signed-token.js +1 -1
  70. package/dist/subscription-mollie/verify-webhook.js +1 -1
  71. package/dist/subscription-stripe/verify-webhook.js +1 -1
  72. package/dist/template-resolver/api.d.ts +1 -1
  73. package/dist/template-resolver/handlers/by-slug.query.d.ts +1 -1
  74. package/dist/template-resolver/handlers/by-tenant.query.d.ts +2 -2
  75. package/dist/template-resolver/handlers/collection-item.query.d.ts +1 -1
  76. package/dist/template-resolver/handlers/collection-list.query.d.ts +1 -1
  77. package/dist/template-resolver/handlers/collection-shared.d.ts +2 -2
  78. package/dist/template-resolver/handlers/find-by-id.query.d.ts +1 -1
  79. package/dist/template-resolver/handlers/list.query.d.ts +1 -1
  80. package/dist/template-resolver/table.d.ts +1 -1
  81. package/dist/tenant/handlers/team-list.query.d.ts +1 -1
  82. package/dist/tenant/handlers/team-list.query.js +1 -1
  83. package/dist/tenant/invited-membership.d.ts +1 -1
  84. package/dist/tenant/invited-membership.js +1 -1
  85. package/dist/tenant-handover/grant.d.ts +1 -1
  86. package/dist/user-data-rights/db/queries/export-jobs.d.ts +1 -1
  87. package/dist/user-data-rights/db/queries/forget-cleanup.d.ts +2 -2
  88. package/dist/user-data-rights/db/queries/forget-cleanup.js +2 -8
  89. package/dist/user-data-rights/deletion-token.d.ts +1 -1
  90. package/dist/user-data-rights/email-templates.d.ts +1 -0
  91. package/dist/user-data-rights/email-templates.js +27 -5
  92. package/dist/user-data-rights/handlers/list-download-attempts.query.js +1 -1
  93. package/dist/user-data-rights/handlers/my-audit-log.query.js +1 -1
  94. package/dist/user-data-rights/lib/default-mailers.js +8 -8
  95. package/dist/waitlist/handlers/invite.write.js +1 -1
  96. package/dist/waitlist/handlers/submit.write.js +1 -1
  97. package/package.json +9 -9
  98. 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-polyfill";
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-polyfill";
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-polyfill";
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-polyfill";
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-polyfill";
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";
@@ -1,4 +1,4 @@
1
- import type { Temporal } from "temporal-polyfill";
1
+ import type { Temporal } from "@cosmicdrift/kumiko-types/temporal";
2
2
  export type VerifyResult = {
3
3
  readonly ok: true;
4
4
  readonly userId: string;
@@ -1,4 +1,4 @@
1
- import type { Temporal } from "temporal-polyfill";
1
+ import type { Temporal } from "@cosmicdrift/kumiko-types/temporal";
2
2
  export type VerifyResult = {
3
3
  readonly ok: true;
4
4
  readonly userId: string;
@@ -1,4 +1,4 @@
1
- import type { Temporal } from "temporal-polyfill";
1
+ import type { Temporal } from "@cosmicdrift/kumiko-types/temporal";
2
2
  export type VerifyResult = {
3
3
  readonly ok: true;
4
4
  readonly userId: string;
@@ -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-polyfill";
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-polyfill";
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,4 +1,4 @@
1
- import { Temporal } from "temporal-polyfill";
1
+ import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
2
2
  export type HmacTokenVerifyResult<TPayload> = {
3
3
  readonly ok: true;
4
4
  readonly payload: TPayload;
@@ -1,5 +1,5 @@
1
1
  import { createHmac, timingSafeEqual } from "node:crypto";
2
- import { Temporal } from "temporal-polyfill";
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-polyfill";
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,4 +1,4 @@
1
- import { Temporal } from "temporal-polyfill";
1
+ import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
2
2
  import { createHmacTokenCodec } from "./hmac-token-codec.js";
3
3
  function isPayload(value) {
4
4
  if (typeof value !== "object" || value === null)
@@ -1,5 +1,5 @@
1
1
  import type { TenantId } from "@cosmicdrift/kumiko-framework/engine";
2
- import { Temporal } from "temporal-polyfill";
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;
@@ -1,4 +1,4 @@
1
- import { Temporal } from "temporal-polyfill";
1
+ import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
2
2
  import { createHmacTokenCodec } from "./hmac-token-codec.js";
3
3
  function isPayload(value) {
4
4
  if (typeof value !== "object" || value === null)
@@ -1,4 +1,4 @@
1
- import { Temporal } from "temporal-polyfill";
1
+ import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
2
2
  export type MfaSetupPayload = {
3
3
  readonly userId: string;
4
4
  readonly totpSecretBase32: 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-polyfill";
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 as TemporalPolyfill } from "temporal-polyfill";
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: TemporalPolyfill.Duration;
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
- // temporal-polyfill is a plain npm dependency (not a framework runtime
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 = TemporalPolyfill.Duration.from({ hours: 24 });
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
- // @cast-boundary temporal-polyfill-vs-ambient: same TC39 Temporal.Instant
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
@@ -1,4 +1,4 @@
1
- import { Temporal } from "temporal-polyfill";
1
+ import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
2
2
  import { CONSENT_TEXTS, resolveConsentLocale } from "./consent-text.js";
3
3
  const LABELS = {
4
4
  de: {
@@ -1,4 +1,4 @@
1
- import { Temporal } from "temporal-polyfill";
1
+ import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
2
2
  import { TERMINATION_TEXTS } from "./termination-texts.js";
3
3
  const TIME_ZONE_BY_LOCALE = {
4
4
  de: "Europe/Berlin",
@@ -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
- // Aliased — an un-aliased `Temporal` would shadow the ambient global
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
- // @cast-boundary temporal-polyfill-vs-ambient: same TC39 Temporal.Instant
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
- // Aliased — an un-aliased `Temporal` would shadow the ambient global
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 the polyfill before comparing — tolerant of a
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 (TemporalPolyfill.Instant.compare(TemporalPolyfill.Instant.from(a), TemporalPolyfill.Instant.from(b)) === 0);
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-polyfill";
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 html = await renderer.render({
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({ to: address, subject, html, ...envelope }));
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) || message.html.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
  });
@@ -2,6 +2,7 @@ export type EmailMessage = {
2
2
  readonly to: string;
3
3
  readonly subject: string;
4
4
  readonly html: string;
5
+ readonly text?: string;
5
6
  readonly from?: string;
6
7
  readonly fromName?: string;
7
8
  readonly replyTo?: string;
@@ -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-polyfill";
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";
@@ -28,7 +28,9 @@ const renderJobPayloadSchema = z.object({
28
28
  message: channelMessageSchema,
29
29
  });
30
30
  const sendJobPayloadSchema = renderJobPayloadSchema.extend({
31
- rendered: z.object({ html: z.string(), subject: z.string() }).optional(),
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;
@@ -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-polyfill";
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-polyfill";
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-polyfill";
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-polyfill";
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-polyfill";
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-polyfill";
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-polyfill";
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-polyfill";
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.
@@ -1,4 +1,4 @@
1
- import { Temporal } from "temporal-polyfill";
1
+ import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
2
2
  export type OAuthStatePayload = {
3
3
  readonly tenantId: string;
4
4
  /** null = shared-Postfach, sonst persönliches Postfach dieses Users. */
@@ -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-polyfill";
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-polyfill";
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-polyfill";
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-polyfill";
1
+ import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
2
2
  export declare function parseJobInstant(iso: string): Temporal.Instant;
@@ -1,4 +1,4 @@
1
- import { Temporal } from "temporal-polyfill";
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 = {
@@ -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-polyfill";
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";