platform-types 1.10.679 → 1.10.681

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/dist/store.d.ts CHANGED
@@ -892,6 +892,13 @@ declare global {
892
892
  * value refetches `GET /store` to see those.
893
893
  */
894
894
  publicStorefront?: PublicStorefront | null;
895
+ /**
896
+ * Server-built public contact on web GET /store and customer STORE frames.
897
+ * Absent means an older API; an empty object means no validated public
898
+ * targets. Private fields are omitted. Before design adoption, only the
899
+ * email/phone pair explicitly consented by config.publicContact is used.
900
+ */
901
+ publicContact?: StorefrontPublicContact;
895
902
  /** Read-only legacy editor seed, available only to the entitled tenant ADMIN. */
896
903
  storefrontEditorBaseline?: StorefrontEditorBaseline;
897
904
  photoURL: string;
@@ -229,6 +229,30 @@ declare global {
229
229
  value: StorefrontDesignContactValues[K];
230
230
  };
231
231
  };
232
+ /** Public overrides only. Missing, private, empty and invalid fields are omitted by the server. */
233
+ interface StorefrontPublicContact {
234
+ email?: string;
235
+ /** Explicit +E.164 (8–15 digits); the server never guesses a country code. */
236
+ phone?: {
237
+ number: string;
238
+ url: `tel:${string}`;
239
+ };
240
+ /** Same E.164 number, with a digits-only wa.me path and no platform fallback. */
241
+ whatsapp?: {
242
+ number: string;
243
+ url: `https://wa.me/${string}`;
244
+ };
245
+ /** Plain display text; renderers must escape markup. Independent of fiscal/legal identity. */
246
+ address?: string;
247
+ /** Rows may repeat days or overlap to represent split shifts; overnight hours use separate rows. */
248
+ hours?: StorefrontContactHours;
249
+ /** At most one account per kind (six kinds), with an approved HTTPS destination. */
250
+ socials?: StorefrontContactSocial[];
251
+ }
252
+ /** Published design projection; contact values contain normalized destinations without author visibility wrappers. */
253
+ type StorefrontDesignPublic = Omit<StorefrontDesignV1, 'contact'> & {
254
+ contact: StorefrontPublicContact;
255
+ };
232
256
  interface StorefrontDesignV1 {
233
257
  schemaVersion: 1;
234
258
  templateId: 'standard';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "platform-types",
3
- "version": "1.10.679",
3
+ "version": "1.10.681",
4
4
  "description": "Shared wire and entity contracts for the platform.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",