platform-types 1.10.678 → 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.
- package/dist/cjs/emailSuppression.js +12 -0
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/storefrontAssets.js +3 -1
- package/dist/cjs/storefrontDesign.js +26 -2
- package/dist/cjs/storefrontTheme.js +7 -0
- package/dist/emailSuppression.d.ts +125 -0
- package/dist/emailSuppression.js +11 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/storefrontAssets.d.ts +41 -12
- package/dist/storefrontAssets.js +3 -1
- package/dist/storefrontDesign.d.ts +39 -2
- package/dist/storefrontDesign.js +25 -1
- package/dist/storefrontTheme.d.ts +7 -0
- package/dist/storefrontTheme.js +7 -0
- package/package.json +1 -1
|
@@ -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);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.MAX_STOREFRONT_ASSETS = exports.STOREFRONT_ASSET_VARIANTS = void 0;
|
|
4
|
+
const storefrontDesign_ts_1 = require("./storefrontDesign.js");
|
|
4
5
|
exports.STOREFRONT_ASSET_VARIANTS = [
|
|
5
6
|
'original',
|
|
6
7
|
'200x200',
|
|
@@ -9,4 +10,5 @@ exports.STOREFRONT_ASSET_VARIANTS = [
|
|
|
9
10
|
'1200x1200',
|
|
10
11
|
'1600x1600',
|
|
11
12
|
];
|
|
12
|
-
|
|
13
|
+
/** The active-asset cap, the same value as `STOREFRONT_DESIGN_LIMITS.activeImages` by construction. */
|
|
14
|
+
exports.MAX_STOREFRONT_ASSETS = storefrontDesign_ts_1.STOREFRONT_DESIGN_LIMITS.activeImages;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.STOREFRONT_SOCIAL_HOSTS = exports.STOREFRONT_BENEFIT_ICONS = exports.STOREFRONT_RESERVED_SLUGS = exports.STOREFRONT_CONTACT_FIELDS = exports.STOREFRONT_BUILTIN_DESTINATIONS = exports.STOREFRONT_SECTION_TYPES = exports.STOREFRONT_DESIGN_LIMITS = void 0;
|
|
3
|
+
exports.STOREFRONT_SOCIAL_HOSTS = exports.STOREFRONT_BENEFIT_ICONS = exports.STOREFRONT_RESERVED_SLUGS = exports.STOREFRONT_CONTACT_FIELDS = exports.STOREFRONT_PROTECTED_BUILTIN_DESTINATIONS = exports.STOREFRONT_BUILTIN_DESTINATIONS = exports.STOREFRONT_SECTION_TYPES = exports.STOREFRONT_DESIGN_LIMITS = void 0;
|
|
4
4
|
exports.createStorefrontDesignV1 = createStorefrontDesignV1;
|
|
5
5
|
exports.STOREFRONT_DESIGN_LIMITS = {
|
|
6
6
|
customPages: 20,
|
|
@@ -24,6 +24,8 @@ exports.STOREFRONT_DESIGN_LIMITS = {
|
|
|
24
24
|
seoTitle: 120,
|
|
25
25
|
seoDescription: 320,
|
|
26
26
|
imageAlt: 250,
|
|
27
|
+
assetFilename: 255,
|
|
28
|
+
assetSearch: 80,
|
|
27
29
|
activeImages: 200,
|
|
28
30
|
imageDecodedBytes: 4 * 1024 * 1024,
|
|
29
31
|
imagePixels: 32_000_000,
|
|
@@ -58,7 +60,21 @@ exports.STOREFRONT_BUILTIN_DESTINATIONS = [
|
|
|
58
60
|
'cart',
|
|
59
61
|
'account',
|
|
60
62
|
'privacy',
|
|
61
|
-
|
|
63
|
+
];
|
|
64
|
+
/**
|
|
65
|
+
* The built-in destinations that must stay reachable whatever a design does with
|
|
66
|
+
* its menus: search, cart, account and the required legal page. Reachability is
|
|
67
|
+
* owned by the storefront's platform chrome, not by the design: the storefront
|
|
68
|
+
* always renders these outside merchant menus and footer groups, so no design can
|
|
69
|
+
* remove or repoint them. A design may still link to them. Editors show them as
|
|
70
|
+
* fixed, non-editable entries. `parseStorefrontDesign` therefore does not refuse
|
|
71
|
+
* a document whose menus omit them.
|
|
72
|
+
*/
|
|
73
|
+
exports.STOREFRONT_PROTECTED_BUILTIN_DESTINATIONS = [
|
|
74
|
+
'search',
|
|
75
|
+
'cart',
|
|
76
|
+
'account',
|
|
77
|
+
'privacy',
|
|
62
78
|
];
|
|
63
79
|
exports.STOREFRONT_CONTACT_FIELDS = ['email', 'phone', 'whatsapp', 'address', 'hours', 'socials'];
|
|
64
80
|
exports.STOREFRONT_RESERVED_SLUGS = [
|
|
@@ -91,6 +107,14 @@ exports.STOREFRONT_RESERVED_SLUGS = [
|
|
|
91
107
|
'admin',
|
|
92
108
|
'storefront',
|
|
93
109
|
'pagina',
|
|
110
|
+
'basket',
|
|
111
|
+
'profile',
|
|
112
|
+
'favorites',
|
|
113
|
+
'invoices',
|
|
114
|
+
'payments',
|
|
115
|
+
'payment-methods',
|
|
116
|
+
'user',
|
|
117
|
+
'mantenimiento',
|
|
94
118
|
];
|
|
95
119
|
exports.STOREFRONT_BENEFIT_ICONS = ['truck', 'shield', 'credit-card', 'store', 'heart', 'check'];
|
|
96
120
|
exports.STOREFRONT_SOCIAL_HOSTS = {
|
|
@@ -65,6 +65,13 @@ const surfaceTokens = (background, settings, mode, surface, warnings) => {
|
|
|
65
65
|
disabled: { background: disabledBackground, text: readableText(disabledBackground) },
|
|
66
66
|
};
|
|
67
67
|
};
|
|
68
|
+
/**
|
|
69
|
+
* The storefront theme for a design's settings overrides.
|
|
70
|
+
*
|
|
71
|
+
* Settings resolve from the registry defaults plus the store's own design
|
|
72
|
+
* overrides ONLY — no GLOBAL or WEB layer takes part — so a consumer uses this
|
|
73
|
+
* as shipped rather than merging layers of its own first.
|
|
74
|
+
*/
|
|
68
75
|
const resolveStorefrontTheme = (overrides = {}) => {
|
|
69
76
|
const settings = (0, storefrontDesignRegistry_ts_1.resolveStorefrontDesignSettings)(overrides);
|
|
70
77
|
const warnings = [];
|
|
@@ -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";
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export declare const STOREFRONT_ASSET_VARIANTS: readonly ["original", "200x200", "400x400", "800x800", "1200x1200", "1600x1600"];
|
|
2
|
-
|
|
2
|
+
/** The active-asset cap, the same value as `STOREFRONT_DESIGN_LIMITS.activeImages` by construction. */
|
|
3
|
+
export declare const MAX_STOREFRONT_ASSETS: 200;
|
|
3
4
|
declare global {
|
|
4
|
-
type StorefrontAssetErrorCode = 'ROLE_FORBIDDEN' | 'PLAN_UPGRADE_REQUIRED' | 'SUBSCRIPTION_READONLY' | 'STOREFRONT_ASSET_ENTITLEMENT_UNAVAILABLE' | 'STOREFRONT_ASSET_REQUEST_TOO_LARGE' | 'STOREFRONT_ASSET_TIMEOUT' | 'VALIDATION_FAILED' | 'ASSET_ARCHIVE_UNCERTAIN' | 'ASSET_CAPACITY_EXCEEDED' | 'ASSET_NOT_FOUND' | 'ASSET_REQUEST_CONFLICT' | 'ASSET_STORAGE_CONFLICT' | 'ASSET_TOO_LARGE' | 'ASSET_UPLOAD_FAILED' | 'ASSET_UPLOAD_PENDING' | 'ASSET_UPLOAD_UNCERTAIN' | 'INVALID_ACTOR' | 'INVALID_ASSET_CURSOR' | 'INVALID_ASSET_ID' | 'INVALID_ASSET_IMAGE' | 'INVALID_ASSET_LIMIT' | 'INVALID_ASSET_PLACEMENT' | 'INVALID_ASSET_STAGE' | 'INVALID_ASSET_VARIANT' | 'INVALID_REQUEST_ID' | 'INVALID_STORE_CONTEXT' | 'LEGACY_LOGO_MAPPING_CONFLICT';
|
|
5
|
+
type StorefrontAssetErrorCode = 'ROLE_FORBIDDEN' | 'PLAN_UPGRADE_REQUIRED' | 'SUBSCRIPTION_READONLY' | 'STOREFRONT_ASSET_ENTITLEMENT_UNAVAILABLE' | 'STOREFRONT_ASSET_REQUEST_TOO_LARGE' | 'STOREFRONT_ASSET_TIMEOUT' | 'VALIDATION_FAILED' | 'ASSET_ARCHIVE_UNCERTAIN' | 'ASSET_ARCHIVED' | 'ASSET_CAPACITY_EXCEEDED' | 'ASSET_NOT_FOUND' | 'ASSET_REQUEST_CONFLICT' | 'ASSET_STORAGE_CONFLICT' | 'ASSET_TOO_LARGE' | 'ASSET_UPDATE_UNCERTAIN' | 'ASSET_UPLOAD_FAILED' | 'ASSET_UPLOAD_PENDING' | 'ASSET_UPLOAD_UNCERTAIN' | 'INVALID_ACTOR' | 'INVALID_ASSET_CURSOR' | 'INVALID_ASSET_ID' | 'INVALID_ASSET_IMAGE' | 'INVALID_ASSET_LIMIT' | 'INVALID_ASSET_PLACEMENT' | 'INVALID_ASSET_SEARCH' | 'INVALID_ASSET_STAGE' | 'INVALID_ASSET_VARIANT' | 'INVALID_REQUEST_ID' | 'INVALID_STORE_CONTEXT' | 'LEGACY_LOGO_MAPPING_CONFLICT';
|
|
5
6
|
interface StorefrontAssetResponse {
|
|
6
7
|
message: string;
|
|
7
8
|
data: StorefrontAsset;
|
|
@@ -21,18 +22,51 @@ declare global {
|
|
|
21
22
|
source?: EntitlementSource;
|
|
22
23
|
requiredPlan?: PlanTier | null;
|
|
23
24
|
currentPlan?: PlanTier | null;
|
|
25
|
+
currentStatus?: SubscriptionStatus;
|
|
24
26
|
}
|
|
25
27
|
type StorefrontAssetVariant = (typeof STOREFRONT_ASSET_VARIANTS)[number];
|
|
28
|
+
/**
|
|
29
|
+
* `filename` is the picked file's name, kept as a basename (any directory
|
|
30
|
+
* part dropped) for the library's search; `label` and `defaultAlt` seed the
|
|
31
|
+
* editor's picker and a NEW placement's alt — a placement carries its own
|
|
32
|
+
* `alt`, so neither is ever read at render time. Each is bounded in code
|
|
33
|
+
* points, and a blank, ill-formed or control-character value is refused
|
|
34
|
+
* 400 `VALIDATION_FAILED`, never cleaned up.
|
|
35
|
+
*/
|
|
26
36
|
interface StorefrontAssetUploadRequest {
|
|
27
37
|
requestId: string;
|
|
28
38
|
base64: string;
|
|
39
|
+
filename?: string;
|
|
40
|
+
label?: string;
|
|
41
|
+
defaultAlt?: string;
|
|
29
42
|
}
|
|
30
43
|
interface StorefrontAssetArchiveRequest {
|
|
31
44
|
requestId: string;
|
|
32
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* `PATCH /store/design/assets/{assetId}`. An omitted key is left as stored,
|
|
48
|
+
* `null` clears it. Idempotent by `requestId` like archive: the same body
|
|
49
|
+
* replays the first answer, a different body under the same `requestId`
|
|
50
|
+
* answers 409 `ASSET_REQUEST_CONFLICT`. An archived asset answers 409
|
|
51
|
+
* `ASSET_ARCHIVED`. Editing metadata never touches a draft, published or
|
|
52
|
+
* historical placement.
|
|
53
|
+
*/
|
|
54
|
+
interface StorefrontAssetMetadataUpdateRequest {
|
|
55
|
+
requestId: string;
|
|
56
|
+
label?: string | null;
|
|
57
|
+
defaultAlt?: string | null;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* `search` matches `filename` and `label` case- and accent-insensitively, as
|
|
61
|
+
* a substring. ⚠️ The filter applies AFTER `limit` rows of the active list are
|
|
62
|
+
* read, so a filtered page can hold fewer than `limit` items — even none —
|
|
63
|
+
* and still carry a `cursor`; follow the cursor until it is absent. A cursor
|
|
64
|
+
* is bound to the `search` it was minted under.
|
|
65
|
+
*/
|
|
33
66
|
interface StorefrontAssetListQuery {
|
|
34
67
|
limit?: number;
|
|
35
68
|
cursor?: string;
|
|
69
|
+
search?: string;
|
|
36
70
|
}
|
|
37
71
|
interface StorefrontAssetFieldError {
|
|
38
72
|
path: string;
|
|
@@ -48,15 +82,10 @@ declare global {
|
|
|
48
82
|
height: number;
|
|
49
83
|
contentType: 'image/jpeg' | 'image/png' | 'image/webp';
|
|
50
84
|
createdAt: number;
|
|
85
|
+
filename?: string;
|
|
86
|
+
label?: string;
|
|
87
|
+
defaultAlt?: string;
|
|
51
88
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
mobileAssetId?: string;
|
|
55
|
-
alt?: string;
|
|
56
|
-
decorative: boolean;
|
|
57
|
-
focalPoint?: {
|
|
58
|
-
x: number;
|
|
59
|
-
y: number;
|
|
60
|
-
};
|
|
61
|
-
}
|
|
89
|
+
/** @deprecated Use `StorefrontDesignImagePlacement`; this is the same shape. */
|
|
90
|
+
type StorefrontAssetPlacement = StorefrontDesignImagePlacement;
|
|
62
91
|
}
|
package/dist/storefrontAssets.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { STOREFRONT_DESIGN_LIMITS } from "./storefrontDesign.js";
|
|
1
2
|
export const STOREFRONT_ASSET_VARIANTS = [
|
|
2
3
|
'original',
|
|
3
4
|
'200x200',
|
|
@@ -6,4 +7,5 @@ export const STOREFRONT_ASSET_VARIANTS = [
|
|
|
6
7
|
'1200x1200',
|
|
7
8
|
'1600x1600',
|
|
8
9
|
];
|
|
9
|
-
|
|
10
|
+
/** The active-asset cap, the same value as `STOREFRONT_DESIGN_LIMITS.activeImages` by construction. */
|
|
11
|
+
export const MAX_STOREFRONT_ASSETS = STOREFRONT_DESIGN_LIMITS.activeImages;
|
|
@@ -20,6 +20,8 @@ export declare const STOREFRONT_DESIGN_LIMITS: {
|
|
|
20
20
|
readonly seoTitle: 120;
|
|
21
21
|
readonly seoDescription: 320;
|
|
22
22
|
readonly imageAlt: 250;
|
|
23
|
+
readonly assetFilename: 255;
|
|
24
|
+
readonly assetSearch: 80;
|
|
23
25
|
readonly activeImages: 200;
|
|
24
26
|
readonly imageDecodedBytes: number;
|
|
25
27
|
readonly imagePixels: 32000000;
|
|
@@ -34,9 +36,19 @@ export declare const STOREFRONT_DESIGN_LIMITS: {
|
|
|
34
36
|
readonly contactEmail: 254;
|
|
35
37
|
};
|
|
36
38
|
export declare const STOREFRONT_SECTION_TYPES: readonly ["banner", "imageText", "products", "categories", "brands", "text", "faq", "benefits", "contact", "paymentDelivery"];
|
|
37
|
-
export declare const STOREFRONT_BUILTIN_DESTINATIONS: readonly ["home", "catalogue", "offers", "new", "search", "cart", "account", "privacy"
|
|
39
|
+
export declare const STOREFRONT_BUILTIN_DESTINATIONS: readonly ["home", "catalogue", "offers", "new", "search", "cart", "account", "privacy"];
|
|
40
|
+
/**
|
|
41
|
+
* The built-in destinations that must stay reachable whatever a design does with
|
|
42
|
+
* its menus: search, cart, account and the required legal page. Reachability is
|
|
43
|
+
* owned by the storefront's platform chrome, not by the design: the storefront
|
|
44
|
+
* always renders these outside merchant menus and footer groups, so no design can
|
|
45
|
+
* remove or repoint them. A design may still link to them. Editors show them as
|
|
46
|
+
* fixed, non-editable entries. `parseStorefrontDesign` therefore does not refuse
|
|
47
|
+
* a document whose menus omit them.
|
|
48
|
+
*/
|
|
49
|
+
export declare const STOREFRONT_PROTECTED_BUILTIN_DESTINATIONS: readonly ["search", "cart", "account", "privacy"];
|
|
38
50
|
export declare const STOREFRONT_CONTACT_FIELDS: readonly ["email", "phone", "whatsapp", "address", "hours", "socials"];
|
|
39
|
-
export declare const STOREFRONT_RESERVED_SLUGS: readonly ["home", "index", "api", "auth", "login", "logout", "account", "cart", "checkout", "orders", "search", "products", "product", "producto", "coleccion", "categories", "brands", "sale", "new", "privacy", "terms", "sitemap", "robots", "manifest", "assets", "preview", "admin", "storefront", "pagina"];
|
|
51
|
+
export declare const STOREFRONT_RESERVED_SLUGS: readonly ["home", "index", "api", "auth", "login", "logout", "account", "cart", "checkout", "orders", "search", "products", "product", "producto", "coleccion", "categories", "brands", "sale", "new", "privacy", "terms", "sitemap", "robots", "manifest", "assets", "preview", "admin", "storefront", "pagina", "basket", "profile", "favorites", "invoices", "payments", "payment-methods", "user", "mantenimiento"];
|
|
40
52
|
export declare const STOREFRONT_BENEFIT_ICONS: readonly ["truck", "shield", "credit-card", "store", "heart", "check"];
|
|
41
53
|
export declare const STOREFRONT_SOCIAL_HOSTS: {
|
|
42
54
|
readonly instagram: readonly ["instagram.com", "www.instagram.com"];
|
|
@@ -305,6 +317,17 @@ declare global {
|
|
|
305
317
|
expiresAt: string;
|
|
306
318
|
protocolVersion: 1;
|
|
307
319
|
}
|
|
320
|
+
/**
|
|
321
|
+
* The editor access refusals, answered by the shared editor gate
|
|
322
|
+
* (`stacks/helpers/storefrontEditorGate.ts`) before any editor route reads or
|
|
323
|
+
* writes: 403 `ROLE_FORBIDDEN` (anything but an exact single-role tenant
|
|
324
|
+
* ADMIN), 403 `PLAN_UPGRADE_REQUIRED` (storefront entitlement off), 402
|
|
325
|
+
* `SUBSCRIPTION_READONLY` (a mutating call on a status other than active,
|
|
326
|
+
* trialing or past_due) and 503 `STOREFRONT_ASSET_ENTITLEMENT_UNAVAILABLE`
|
|
327
|
+
* (the entitlement could not be read). The 503 keeps the asset library's name
|
|
328
|
+
* so one gate answers one code on every editor route.
|
|
329
|
+
*/
|
|
330
|
+
type StorefrontDesignAccessErrorCode = 'ROLE_FORBIDDEN' | 'PLAN_UPGRADE_REQUIRED' | 'SUBSCRIPTION_READONLY' | 'STOREFRONT_ASSET_ENTITLEMENT_UNAVAILABLE';
|
|
308
331
|
type StorefrontDesignFailure = {
|
|
309
332
|
message: string;
|
|
310
333
|
error: 'STOREFRONT_REVISION_CONFLICT';
|
|
@@ -314,6 +337,20 @@ declare global {
|
|
|
314
337
|
message: string;
|
|
315
338
|
error: Exclude<StorefrontDesignErrorCode, 'STOREFRONT_REVISION_CONFLICT'>;
|
|
316
339
|
fieldErrors?: StorefrontDesignFieldError[];
|
|
340
|
+
} | {
|
|
341
|
+
message: string;
|
|
342
|
+
error: 'PLAN_UPGRADE_REQUIRED';
|
|
343
|
+
feature: 'storefront';
|
|
344
|
+
currentPlan: PlanTier | null;
|
|
345
|
+
source?: EntitlementSource;
|
|
346
|
+
requiredPlan?: PlanTier | null;
|
|
347
|
+
} | {
|
|
348
|
+
message: string;
|
|
349
|
+
error: 'SUBSCRIPTION_READONLY';
|
|
350
|
+
currentStatus: SubscriptionStatus;
|
|
351
|
+
} | {
|
|
352
|
+
message: string;
|
|
353
|
+
error: 'ROLE_FORBIDDEN' | 'STOREFRONT_ASSET_ENTITLEMENT_UNAVAILABLE';
|
|
317
354
|
};
|
|
318
355
|
type StorefrontDesignDraftResponse = {
|
|
319
356
|
message: string;
|
package/dist/storefrontDesign.js
CHANGED
|
@@ -20,6 +20,8 @@ export const STOREFRONT_DESIGN_LIMITS = {
|
|
|
20
20
|
seoTitle: 120,
|
|
21
21
|
seoDescription: 320,
|
|
22
22
|
imageAlt: 250,
|
|
23
|
+
assetFilename: 255,
|
|
24
|
+
assetSearch: 80,
|
|
23
25
|
activeImages: 200,
|
|
24
26
|
imageDecodedBytes: 4 * 1024 * 1024,
|
|
25
27
|
imagePixels: 32_000_000,
|
|
@@ -54,7 +56,21 @@ export const STOREFRONT_BUILTIN_DESTINATIONS = [
|
|
|
54
56
|
'cart',
|
|
55
57
|
'account',
|
|
56
58
|
'privacy',
|
|
57
|
-
|
|
59
|
+
];
|
|
60
|
+
/**
|
|
61
|
+
* The built-in destinations that must stay reachable whatever a design does with
|
|
62
|
+
* its menus: search, cart, account and the required legal page. Reachability is
|
|
63
|
+
* owned by the storefront's platform chrome, not by the design: the storefront
|
|
64
|
+
* always renders these outside merchant menus and footer groups, so no design can
|
|
65
|
+
* remove or repoint them. A design may still link to them. Editors show them as
|
|
66
|
+
* fixed, non-editable entries. `parseStorefrontDesign` therefore does not refuse
|
|
67
|
+
* a document whose menus omit them.
|
|
68
|
+
*/
|
|
69
|
+
export const STOREFRONT_PROTECTED_BUILTIN_DESTINATIONS = [
|
|
70
|
+
'search',
|
|
71
|
+
'cart',
|
|
72
|
+
'account',
|
|
73
|
+
'privacy',
|
|
58
74
|
];
|
|
59
75
|
export const STOREFRONT_CONTACT_FIELDS = ['email', 'phone', 'whatsapp', 'address', 'hours', 'socials'];
|
|
60
76
|
export const STOREFRONT_RESERVED_SLUGS = [
|
|
@@ -87,6 +103,14 @@ export const STOREFRONT_RESERVED_SLUGS = [
|
|
|
87
103
|
'admin',
|
|
88
104
|
'storefront',
|
|
89
105
|
'pagina',
|
|
106
|
+
'basket',
|
|
107
|
+
'profile',
|
|
108
|
+
'favorites',
|
|
109
|
+
'invoices',
|
|
110
|
+
'payments',
|
|
111
|
+
'payment-methods',
|
|
112
|
+
'user',
|
|
113
|
+
'mantenimiento',
|
|
90
114
|
];
|
|
91
115
|
export const STOREFRONT_BENEFIT_ICONS = ['truck', 'shield', 'credit-card', 'store', 'heart', 'check'];
|
|
92
116
|
export const STOREFRONT_SOCIAL_HOSTS = {
|
|
@@ -50,5 +50,12 @@ export interface StorefrontResolvedTheme {
|
|
|
50
50
|
warnings: StorefrontThemeWarning[];
|
|
51
51
|
}
|
|
52
52
|
export declare const storefrontContrastRatio: (foreground: string, background: string) => number;
|
|
53
|
+
/**
|
|
54
|
+
* The storefront theme for a design's settings overrides.
|
|
55
|
+
*
|
|
56
|
+
* Settings resolve from the registry defaults plus the store's own design
|
|
57
|
+
* overrides ONLY — no GLOBAL or WEB layer takes part — so a consumer uses this
|
|
58
|
+
* as shipped rather than merging layers of its own first.
|
|
59
|
+
*/
|
|
53
60
|
export declare const resolveStorefrontTheme: (overrides?: Partial<StorefrontDesignSettings>) => StorefrontResolvedTheme;
|
|
54
61
|
export {};
|
package/dist/storefrontTheme.js
CHANGED
|
@@ -61,6 +61,13 @@ const surfaceTokens = (background, settings, mode, surface, warnings) => {
|
|
|
61
61
|
disabled: { background: disabledBackground, text: readableText(disabledBackground) },
|
|
62
62
|
};
|
|
63
63
|
};
|
|
64
|
+
/**
|
|
65
|
+
* The storefront theme for a design's settings overrides.
|
|
66
|
+
*
|
|
67
|
+
* Settings resolve from the registry defaults plus the store's own design
|
|
68
|
+
* overrides ONLY — no GLOBAL or WEB layer takes part — so a consumer uses this
|
|
69
|
+
* as shipped rather than merging layers of its own first.
|
|
70
|
+
*/
|
|
64
71
|
export const resolveStorefrontTheme = (overrides = {}) => {
|
|
65
72
|
const settings = resolveStorefrontDesignSettings(overrides);
|
|
66
73
|
const warnings = [];
|