platform-types 1.10.679 → 1.10.680

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.
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ // Suppressed email addresses, as a platform MANAGER sees them through
3
+ // `/platform/email-suppression`. Two lists gate a send, and this surface reads both:
4
+ //
5
+ // - the APP list — one DynamoDB row per (store, address) under
6
+ // `EMAILSUPPRESSION#{storeId}` (or `#PLATFORM`), written by the SES event consumer
7
+ // or by a MANAGER, and enforced by the send path;
8
+ // - the SES ACCOUNT list — maintained by SES itself. ⚠️ Dev and prod share one AWS
9
+ // account, so this list is shared across stages while app rows are per stage.
10
+ //
11
+ // ⚠️ Operator surface only. No tenant-tier route returns these shapes.
12
+ Object.defineProperty(exports, "__esModule", { value: true });
package/dist/cjs/index.js CHANGED
@@ -56,6 +56,7 @@ __exportStar(require("./gating.js"), exports);
56
56
  __exportStar(require("./holdingCost.js"), exports);
57
57
  __exportStar(require("./demo.js"), exports);
58
58
  __exportStar(require("./emailIdentity.js"), exports);
59
+ __exportStar(require("./emailSuppression.js"), exports);
59
60
  __exportStar(require("./impersonation.js"), exports);
60
61
  __exportStar(require("./imports.js"), exports);
61
62
  __exportStar(require("./inventory.js"), exports);
@@ -0,0 +1,125 @@
1
+ /** Why an app row suppresses. `'bounce'` blocks every send; `'complaint'` every send but transactional. */
2
+ export type EmailSuppressionReason = 'bounce' | 'complaint';
3
+ /** Who wrote the app row: the SES event consumer, or a MANAGER by hand. */
4
+ export type EmailSuppressionSource = 'ses-event' | 'manager';
5
+ /** SES's own reason on an account-list entry. */
6
+ export type SesSuppressionReason = 'BOUNCE' | 'COMPLAINT';
7
+ /** The app row's half of an entry. Fields written before the evidence was kept are absent. */
8
+ export interface EmailSuppressionAppRow {
9
+ reason: EmailSuppressionReason;
10
+ source: EmailSuppressionSource;
11
+ firstSuppressedAt?: number;
12
+ lastEventAt?: number;
13
+ bounceType?: 'Permanent' | 'Transient' | 'Undetermined';
14
+ bounceSubType?: string;
15
+ /** Remote SMTP diagnostic text, at most 500 bytes. Never message content. */
16
+ diagnosticCode?: string;
17
+ sesMessageId?: string;
18
+ feedbackId?: string;
19
+ /** Present on a manual add only. */
20
+ actorUserId?: string;
21
+ /** Epoch seconds — the row's TTL. */
22
+ expiresAt: number;
23
+ }
24
+ /** The SES account list's half of an entry. */
25
+ export interface EmailSuppressionSesEntry {
26
+ reason: SesSuppressionReason;
27
+ /** The exact spelling SES holds, when it differs from the lowercased `address`. */
28
+ address?: string;
29
+ /** ISO-8601, as SES reports it. */
30
+ lastUpdateTime: string;
31
+ }
32
+ /**
33
+ * One address in one scope. An address with app rows in two stores is two entries;
34
+ * the SES half (account-wide) rides on each of them. `storeId: null` is an SES-only
35
+ * entry with no app row anywhere.
36
+ */
37
+ export interface EmailSuppressionEntry {
38
+ address: string;
39
+ storeId: string | 'PLATFORM' | null;
40
+ /** The store's display name when `storeId` names a store. */
41
+ storeName?: string;
42
+ app: EmailSuppressionAppRow | null;
43
+ ses: EmailSuppressionSesEntry | null;
44
+ }
45
+ /** `GET /platform/email-suppression` — `data`. Pass `nextCursor` back as `?cursor=`. */
46
+ export interface EmailSuppressionListResponse {
47
+ items: EmailSuppressionEntry[];
48
+ nextCursor?: string;
49
+ /** A source was read up to its cap, so the merged view may be incomplete. */
50
+ truncated?: boolean;
51
+ }
52
+ /** One SES event for the address, from the store's `EMAILEVENT#` history. */
53
+ export interface EmailSuppressionEvent {
54
+ storeId: string;
55
+ sesMessageId: string;
56
+ eventType: 'Bounce' | 'Complaint' | 'Delivery' | 'Reject' | 'Open' | 'Click';
57
+ bounceType?: 'Permanent' | 'Transient' | 'Undetermined';
58
+ createdAt: number;
59
+ }
60
+ /** `GET /platform/email-suppression/{address}` — `data`. */
61
+ export interface EmailSuppressionDetail {
62
+ address: string;
63
+ /** One per app row, or a single SES-only entry; empty when the address is on neither list. */
64
+ entries: EmailSuppressionEntry[];
65
+ /** The newest events first, at most 20. */
66
+ events: EmailSuppressionEvent[];
67
+ /** The event read hit its bound before covering every store. */
68
+ eventsTruncated?: boolean;
69
+ /**
70
+ * `false` — the domain authoritatively accepts no mail (an RFC 7505 null MX, or it
71
+ * does not exist); `null` — unknown: the lookup did not answer, or the domain has no
72
+ * MX record and relies on an implicit MX.
73
+ */
74
+ mxPresent: boolean | null;
75
+ /** SES did not answer (throttle or timeout), so each entry's `ses` half is unknown, not absent. */
76
+ sesUnavailable?: boolean;
77
+ }
78
+ /** A non-blocking caution on a write. */
79
+ export type EmailSuppressionWarning =
80
+ /** The MX lookup did not answer, or the domain relies on an implicit MX (A/AAAA only). */
81
+ 'MX_UNKNOWN'
82
+ /** A permanent NoEmail/General bounce was recorded less than an hour ago. */
83
+ | 'RECENT_PERMANENT_BOUNCE'
84
+ /** The store roster was read up to its cap, so a store's row may have been missed. */
85
+ | 'STORE_ROSTER_TRUNCATED';
86
+ /**
87
+ * What happened to the SES account list. `'skipped'` — this stage does not write the
88
+ * SES list: dev and prod share one AWS account, so only prod may change it.
89
+ */
90
+ export type EmailSuppressionSesWrite = 'removed' | 'absent' | 'skipped';
91
+ /** `DELETE /platform/email-suppression/{address}` — body. Omit `storeId` to clear every store's row. */
92
+ export interface EmailSuppressionDeleteRequest {
93
+ reason: string;
94
+ storeId?: string;
95
+ }
96
+ /** `DELETE /platform/email-suppression/{address}` — `data`. Idempotent: an absent entry is success. */
97
+ export interface EmailSuppressionDeleteResponse {
98
+ app: 'removed' | 'absent';
99
+ ses: EmailSuppressionSesWrite;
100
+ warnings?: EmailSuppressionWarning[];
101
+ }
102
+ /**
103
+ * `POST /platform/email-suppression` — body. `'manual'` and `'bounce'` store an app `'bounce'`
104
+ * row and (prod only) an SES `BOUNCE` entry; `'complaint'` stores an app `'complaint'` row only.
105
+ * Omit `storeId` to suppress on the platform partition.
106
+ */
107
+ export interface EmailSuppressionCreateRequest {
108
+ address: string;
109
+ reason: EmailSuppressionReason | 'manual';
110
+ note: string;
111
+ storeId?: string;
112
+ }
113
+ /** `POST /platform/email-suppression` — `data`. */
114
+ export interface EmailSuppressionCreateResponse {
115
+ entry: EmailSuppressionEntry;
116
+ /**
117
+ * `'skipped'` on a stage that does not write the SES list (see {@link EmailSuppressionSesWrite}),
118
+ * and for a `'complaint'` add on every stage: the SES account list blocks EVERY send whatever
119
+ * its reason, so an SES COMPLAINT entry would also stop the transactional mail an app
120
+ * complaint row lets through.
121
+ */
122
+ ses: 'added' | 'skipped';
123
+ /** SES did not answer the read-back, so `entry.ses` is unknown, not absent. */
124
+ sesUnavailable?: boolean;
125
+ }
@@ -0,0 +1,11 @@
1
+ // Suppressed email addresses, as a platform MANAGER sees them through
2
+ // `/platform/email-suppression`. Two lists gate a send, and this surface reads both:
3
+ //
4
+ // - the APP list — one DynamoDB row per (store, address) under
5
+ // `EMAILSUPPRESSION#{storeId}` (or `#PLATFORM`), written by the SES event consumer
6
+ // or by a MANAGER, and enforced by the send path;
7
+ // - the SES ACCOUNT list — maintained by SES itself. ⚠️ Dev and prod share one AWS
8
+ // account, so this list is shared across stages while app rows are per stage.
9
+ //
10
+ // ⚠️ Operator surface only. No tenant-tier route returns these shapes.
11
+ export {};
package/dist/index.d.ts CHANGED
@@ -32,6 +32,7 @@ export * from './gating.ts';
32
32
  export * from './holdingCost.ts';
33
33
  export * from './demo.ts';
34
34
  export * from './emailIdentity.ts';
35
+ export * from './emailSuppression.ts';
35
36
  export * from './impersonation.ts';
36
37
  export * from './imports.ts';
37
38
  export * from './inventory.ts';
package/dist/index.js CHANGED
@@ -40,6 +40,7 @@ export * from "./gating.js";
40
40
  export * from "./holdingCost.js";
41
41
  export * from "./demo.js";
42
42
  export * from "./emailIdentity.js";
43
+ export * from "./emailSuppression.js";
43
44
  export * from "./impersonation.js";
44
45
  export * from "./imports.js";
45
46
  export * from "./inventory.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "platform-types",
3
- "version": "1.10.679",
3
+ "version": "1.10.680",
4
4
  "description": "Shared wire and entity contracts for the platform.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",