@proxima-io/storefront-core 0.3.0 → 0.8.2
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/README.md +68 -17
- package/dist/addresses/address-book.d.ts +36 -0
- package/dist/addresses/address-book.d.ts.map +1 -0
- package/dist/addresses/address-book.js +62 -0
- package/dist/addresses/address-book.js.map +1 -0
- package/dist/analytics/analytics.d.ts +28 -0
- package/dist/analytics/analytics.d.ts.map +1 -0
- package/dist/analytics/analytics.js +124 -0
- package/dist/analytics/analytics.js.map +1 -0
- package/dist/analytics/attribution.d.ts +28 -0
- package/dist/analytics/attribution.d.ts.map +1 -0
- package/dist/analytics/attribution.js +116 -0
- package/dist/analytics/attribution.js.map +1 -0
- package/dist/analytics/session.d.ts +12 -0
- package/dist/analytics/session.d.ts.map +1 -0
- package/dist/analytics/session.js +62 -0
- package/dist/analytics/session.js.map +1 -0
- package/dist/analytics/trackers.d.ts +29 -0
- package/dist/analytics/trackers.d.ts.map +1 -0
- package/dist/analytics/trackers.js +30 -0
- package/dist/analytics/trackers.js.map +1 -0
- package/dist/api/endpoints.d.ts +70 -0
- package/dist/api/endpoints.d.ts.map +1 -0
- package/dist/api/endpoints.js +70 -0
- package/dist/api/endpoints.js.map +1 -0
- package/dist/api/index.d.ts +3 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +3 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/storefront-client.d.ts +50 -0
- package/dist/api/storefront-client.d.ts.map +1 -0
- package/dist/api/storefront-client.js +123 -0
- package/dist/api/storefront-client.js.map +1 -0
- package/dist/buyer/auth.d.ts +105 -0
- package/dist/buyer/auth.d.ts.map +1 -0
- package/dist/buyer/auth.js +215 -0
- package/dist/buyer/auth.js.map +1 -0
- package/dist/cache/cache.d.ts +31 -0
- package/dist/cache/cache.d.ts.map +1 -0
- package/dist/cache/cache.js +71 -0
- package/dist/cache/cache.js.map +1 -0
- package/dist/campaign/countdown.d.ts +40 -0
- package/dist/campaign/countdown.d.ts.map +1 -0
- package/dist/campaign/countdown.js +71 -0
- package/dist/campaign/countdown.js.map +1 -0
- package/dist/cart/cart.d.ts +57 -0
- package/dist/cart/cart.d.ts.map +1 -0
- package/dist/cart/cart.js +64 -0
- package/dist/cart/cart.js.map +1 -0
- package/dist/catalog/listings.d.ts +87 -0
- package/dist/catalog/listings.d.ts.map +1 -0
- package/dist/catalog/listings.js +140 -0
- package/dist/catalog/listings.js.map +1 -0
- package/dist/cms/payment-methods.d.ts +13 -0
- package/dist/cms/payment-methods.d.ts.map +1 -0
- package/dist/cms/payment-methods.js +41 -0
- package/dist/cms/payment-methods.js.map +1 -0
- package/dist/cms/website.d.ts +76 -0
- package/dist/cms/website.d.ts.map +1 -0
- package/dist/cms/website.js +146 -0
- package/dist/cms/website.js.map +1 -0
- package/dist/cookie-consent/consent.d.ts +22 -0
- package/dist/cookie-consent/consent.d.ts.map +1 -0
- package/dist/cookie-consent/consent.js +93 -0
- package/dist/cookie-consent/consent.js.map +1 -0
- package/dist/index.d.ts +45 -1310
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +42 -1576
- package/dist/index.js.map +1 -1
- package/dist/internal/http.d.ts +5 -0
- package/dist/internal/http.d.ts.map +1 -0
- package/dist/internal/http.js +27 -0
- package/dist/internal/http.js.map +1 -0
- package/dist/orders/guest.d.ts +9 -0
- package/dist/orders/guest.d.ts.map +1 -0
- package/dist/orders/guest.js +30 -0
- package/dist/orders/guest.js.map +1 -0
- package/dist/orders/orders.d.ts +23 -0
- package/dist/orders/orders.d.ts.map +1 -0
- package/dist/orders/orders.js +33 -0
- package/dist/orders/orders.js.map +1 -0
- package/dist/seo/engine-url.d.ts +26 -0
- package/dist/seo/engine-url.d.ts.map +1 -0
- package/dist/seo/engine-url.js +111 -0
- package/dist/seo/engine-url.js.map +1 -0
- package/dist/seo/hreflang.d.ts +19 -0
- package/dist/seo/hreflang.d.ts.map +1 -0
- package/dist/seo/hreflang.js +52 -0
- package/dist/seo/hreflang.js.map +1 -0
- package/dist/seo/indexnow.d.ts +24 -0
- package/dist/seo/indexnow.d.ts.map +1 -0
- package/dist/seo/indexnow.js +50 -0
- package/dist/seo/indexnow.js.map +1 -0
- package/dist/seo/json-ld.d.ts +57 -0
- package/dist/seo/json-ld.d.ts.map +1 -0
- package/dist/seo/json-ld.js +180 -0
- package/dist/seo/json-ld.js.map +1 -0
- package/dist/seo/page-seo.d.ts +21 -0
- package/dist/seo/page-seo.d.ts.map +1 -0
- package/dist/seo/page-seo.js +68 -0
- package/dist/seo/page-seo.js.map +1 -0
- package/dist/seo/robots.d.ts +23 -0
- package/dist/seo/robots.d.ts.map +1 -0
- package/dist/seo/robots.js +35 -0
- package/dist/seo/robots.js.map +1 -0
- package/dist/seo/sitemap.d.ts +35 -0
- package/dist/seo/sitemap.d.ts.map +1 -0
- package/dist/seo/sitemap.js +186 -0
- package/dist/seo/sitemap.js.map +1 -0
- package/dist/server/process.d.ts +136 -0
- package/dist/server/process.d.ts.map +1 -0
- package/dist/server/process.js +143 -0
- package/dist/server/process.js.map +1 -0
- package/dist/types/address.d.ts +40 -0
- package/dist/types/address.d.ts.map +1 -0
- package/dist/types/address.js +2 -0
- package/dist/types/address.js.map +1 -0
- package/dist/types/analytics.d.ts +79 -0
- package/dist/types/analytics.d.ts.map +1 -0
- package/dist/types/analytics.js +2 -0
- package/dist/types/analytics.js.map +1 -0
- package/dist/types/business.d.ts +95 -0
- package/dist/types/business.d.ts.map +1 -0
- package/dist/types/business.js +2 -0
- package/dist/types/business.js.map +1 -0
- package/dist/types/buyer.d.ts +144 -0
- package/dist/types/buyer.d.ts.map +1 -0
- package/dist/types/buyer.js +45 -0
- package/dist/types/buyer.js.map +1 -0
- package/dist/types/campaign.d.ts +51 -0
- package/dist/types/campaign.d.ts.map +1 -0
- package/dist/types/campaign.js +2 -0
- package/dist/types/campaign.js.map +1 -0
- package/dist/types/cart.d.ts +40 -0
- package/dist/types/cart.d.ts.map +1 -0
- package/dist/types/cart.js +2 -0
- package/dist/types/cart.js.map +1 -0
- package/dist/types/catalog.d.ts +164 -0
- package/dist/types/catalog.d.ts.map +1 -0
- package/dist/types/catalog.js +2 -0
- package/dist/types/catalog.js.map +1 -0
- package/dist/types/cms.d.ts +200 -0
- package/dist/types/cms.d.ts.map +1 -0
- package/dist/types/cms.js +2 -0
- package/dist/types/cms.js.map +1 -0
- package/dist/types/cookie-consent.d.ts +18 -0
- package/dist/types/cookie-consent.d.ts.map +1 -0
- package/dist/types/cookie-consent.js +7 -0
- package/dist/types/cookie-consent.js.map +1 -0
- package/dist/types/guest-order.d.ts +16 -0
- package/dist/types/guest-order.d.ts.map +1 -0
- package/dist/types/guest-order.js +9 -0
- package/dist/types/guest-order.js.map +1 -0
- package/dist/types/listing.d.ts +14 -0
- package/dist/types/listing.d.ts.map +1 -0
- package/dist/types/listing.js +2 -0
- package/dist/types/listing.js.map +1 -0
- package/dist/types/order.d.ts +40 -0
- package/dist/types/order.d.ts.map +1 -0
- package/dist/types/order.js +2 -0
- package/dist/types/order.js.map +1 -0
- package/dist/types/seo.d.ts +96 -0
- package/dist/types/seo.d.ts.map +1 -0
- package/dist/types/seo.js +2 -0
- package/dist/types/seo.js.map +1 -0
- package/dist/types/server-env.d.ts +19 -0
- package/dist/types/server-env.d.ts.map +1 -0
- package/dist/types/server-env.js +10 -0
- package/dist/types/server-env.js.map +1 -0
- package/dist/types/wishlist.d.ts +10 -0
- package/dist/types/wishlist.d.ts.map +1 -0
- package/dist/types/wishlist.js +2 -0
- package/dist/types/wishlist.js.map +1 -0
- package/dist/wishlist/wishlist.d.ts +28 -0
- package/dist/wishlist/wishlist.d.ts.map +1 -0
- package/dist/wishlist/wishlist.js +42 -0
- package/dist/wishlist/wishlist.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { StorefrontEndpoints, createStorefrontClient } from '../api/index.js';
|
|
2
|
+
import { MissingFieldsError, } from '../types/buyer.js';
|
|
3
|
+
function tenant(config, website) {
|
|
4
|
+
return {
|
|
5
|
+
client: createStorefrontClient(config),
|
|
6
|
+
businessId: website.business_id,
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Fetch the merchant-configured registration form schema.
|
|
11
|
+
* Call this server-side in your /register page to know which fields to render
|
|
12
|
+
* and which are required. `email` and `password` are always prepended by the API.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* // src/pages/register.astro
|
|
16
|
+
* const form = await fetchRegistrationForm({ baseUrl: env.apiUrl }, website);
|
|
17
|
+
* // Pass `form` as a prop to a client component that renders the dynamic form
|
|
18
|
+
*/
|
|
19
|
+
export async function fetchRegistrationForm(config, website) {
|
|
20
|
+
const { client, businessId } = tenant(config, website);
|
|
21
|
+
return client.get(StorefrontEndpoints.auth.registrationForm(), { businessId });
|
|
22
|
+
}
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
// Buyer Auth — client-side functions
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
/**
|
|
27
|
+
* Register a new customer. The merchant decides which fields are required —
|
|
28
|
+
* call fetchRegistrationForm() first to know what to collect.
|
|
29
|
+
*
|
|
30
|
+
* Throws MissingFieldsError when the merchant marked fields as required but
|
|
31
|
+
* they were omitted, so you can mark exactly which inputs are invalid.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* try {
|
|
35
|
+
* const session = await registerBuyer(config, website, { email, password, fullName });
|
|
36
|
+
* } catch (e) {
|
|
37
|
+
* if (e instanceof MissingFieldsError) {
|
|
38
|
+
* e.missingFields.forEach(({ field }) => markError(field));
|
|
39
|
+
* }
|
|
40
|
+
* }
|
|
41
|
+
*/
|
|
42
|
+
export async function registerBuyer(config, website, params) {
|
|
43
|
+
const { client, businessId } = tenant(config, website);
|
|
44
|
+
const body = {
|
|
45
|
+
email: params.email,
|
|
46
|
+
password: params.password,
|
|
47
|
+
};
|
|
48
|
+
if (params.fullName !== undefined)
|
|
49
|
+
body.full_name = params.fullName;
|
|
50
|
+
if (params.phone !== undefined)
|
|
51
|
+
body.phone = params.phone;
|
|
52
|
+
if (params.docType !== undefined)
|
|
53
|
+
body.doc_type = params.docType;
|
|
54
|
+
if (params.docNumber !== undefined)
|
|
55
|
+
body.doc_number = params.docNumber;
|
|
56
|
+
if (params.birthDate !== undefined)
|
|
57
|
+
body.birth_date = params.birthDate;
|
|
58
|
+
if (params.newsletterSubscribed !== undefined)
|
|
59
|
+
body.newsletter_subscribed = params.newsletterSubscribed;
|
|
60
|
+
if (params.registrationSource !== undefined)
|
|
61
|
+
body.registration_source = params.registrationSource;
|
|
62
|
+
if (params.metadata !== undefined)
|
|
63
|
+
body.metadata = params.metadata;
|
|
64
|
+
if (params.address !== undefined)
|
|
65
|
+
body.address = params.address;
|
|
66
|
+
if (params.captchaToken)
|
|
67
|
+
body.captcha_token = params.captchaToken;
|
|
68
|
+
try {
|
|
69
|
+
return await client.post(StorefrontEndpoints.auth.register(), body, { businessId });
|
|
70
|
+
}
|
|
71
|
+
catch (e) {
|
|
72
|
+
const err = e;
|
|
73
|
+
if (err.status === 422 && typeof err.data?.detail === "string" && err.data.detail.startsWith("MISSING_REQUIRED_FIELDS:")) {
|
|
74
|
+
try {
|
|
75
|
+
const raw = err.data.detail.replace("MISSING_REQUIRED_FIELDS:", "").trim();
|
|
76
|
+
const normalized = raw.replace(/'/g, '"');
|
|
77
|
+
const missingFields = JSON.parse(normalized);
|
|
78
|
+
throw new MissingFieldsError(missingFields);
|
|
79
|
+
}
|
|
80
|
+
catch (parseErr) {
|
|
81
|
+
if (parseErr instanceof MissingFieldsError)
|
|
82
|
+
throw parseErr;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
throw e;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Authenticate a customer with email and password.
|
|
90
|
+
* Returns a BuyerSession with access_token and refresh_token.
|
|
91
|
+
* Throws { status: 401 } on wrong credentials.
|
|
92
|
+
*/
|
|
93
|
+
export async function loginBuyer(config, website, params) {
|
|
94
|
+
const { client, businessId } = tenant(config, website);
|
|
95
|
+
const body = { email: params.email, password: params.password };
|
|
96
|
+
if (params.captchaToken)
|
|
97
|
+
body.captcha_token = params.captchaToken;
|
|
98
|
+
return client.post(StorefrontEndpoints.auth.login(), body, { businessId });
|
|
99
|
+
}
|
|
100
|
+
/** Invalidate the current session server-side. Best-effort — always clear the cookie too. */
|
|
101
|
+
export async function logoutBuyer(config, website, params) {
|
|
102
|
+
const { client, businessId } = tenant(config, website);
|
|
103
|
+
await client.post(StorefrontEndpoints.auth.logout(), undefined, {
|
|
104
|
+
businessId,
|
|
105
|
+
token: params.token,
|
|
106
|
+
ignoreErrors: true,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Exchange a refresh token for a new access token.
|
|
111
|
+
* Call this when you get a 401 on any authenticated request.
|
|
112
|
+
* Throws { status: 401 } if the refresh token is expired or revoked.
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* // In Astro middleware:
|
|
116
|
+
* try {
|
|
117
|
+
* const session = await refreshBuyerToken(config, website, { refreshToken });
|
|
118
|
+
* // Set new access_token cookie
|
|
119
|
+
* } catch {
|
|
120
|
+
* // Clear both cookies, redirect to login
|
|
121
|
+
* }
|
|
122
|
+
*/
|
|
123
|
+
export async function refreshBuyerToken(config, website, params) {
|
|
124
|
+
const { client, businessId } = tenant(config, website);
|
|
125
|
+
return client.post(StorefrontEndpoints.auth.refresh(), undefined, {
|
|
126
|
+
businessId,
|
|
127
|
+
query: { refresh_token: params.refreshToken },
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
/** Fetch the authenticated customer's full profile. */
|
|
131
|
+
export async function fetchBuyerProfile(config, website, params) {
|
|
132
|
+
const { client, businessId } = tenant(config, website);
|
|
133
|
+
return client.get(StorefrontEndpoints.buyer.me(), {
|
|
134
|
+
businessId,
|
|
135
|
+
token: params.token,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Update the authenticated customer's profile. Only the fields you include
|
|
140
|
+
* in `params` are changed — it's a partial update.
|
|
141
|
+
*/
|
|
142
|
+
export async function updateBuyerProfile(config, website, params) {
|
|
143
|
+
const { client, businessId } = tenant(config, website);
|
|
144
|
+
const body = {};
|
|
145
|
+
if (params.fullName !== undefined)
|
|
146
|
+
body.full_name = params.fullName;
|
|
147
|
+
if (params.phone !== undefined)
|
|
148
|
+
body.phone = params.phone;
|
|
149
|
+
if (params.docType !== undefined)
|
|
150
|
+
body.doc_type = params.docType;
|
|
151
|
+
if (params.docNumber !== undefined)
|
|
152
|
+
body.doc_number = params.docNumber;
|
|
153
|
+
if (params.birthDate !== undefined)
|
|
154
|
+
body.birth_date = params.birthDate;
|
|
155
|
+
if (params.newsletterSubscribed !== undefined)
|
|
156
|
+
body.newsletter_subscribed = params.newsletterSubscribed;
|
|
157
|
+
if (params.avatarUrl !== undefined)
|
|
158
|
+
body.avatar_url = params.avatarUrl;
|
|
159
|
+
if (params.password !== undefined)
|
|
160
|
+
body.password = params.password;
|
|
161
|
+
return client.patch(StorefrontEndpoints.buyer.profile(), body, {
|
|
162
|
+
businessId,
|
|
163
|
+
token: params.token,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
// ---------------------------------------------------------------------------
|
|
167
|
+
// Password recovery & email verification
|
|
168
|
+
// ---------------------------------------------------------------------------
|
|
169
|
+
/**
|
|
170
|
+
* Send a password reset email. Always resolves — even if the email doesn't exist.
|
|
171
|
+
* Always show: "Si el email existe, recibirás un enlace para restablecer tu contraseña."
|
|
172
|
+
*/
|
|
173
|
+
export async function forgotPassword(config, website, params) {
|
|
174
|
+
const { client, businessId } = tenant(config, website);
|
|
175
|
+
const body = { email: params.email };
|
|
176
|
+
if (params.captchaToken)
|
|
177
|
+
body.captcha_token = params.captchaToken;
|
|
178
|
+
await client.post(StorefrontEndpoints.auth.forgotPassword(), body, {
|
|
179
|
+
businessId,
|
|
180
|
+
ignoreErrors: true,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Reset the customer's password using the token from the reset email link.
|
|
185
|
+
* The token is the `?token=` query param in the reset URL.
|
|
186
|
+
* On success, all active sessions are revoked — redirect to login.
|
|
187
|
+
* Throws { status: 400, data.detail: BUYER_AUTH_ERRORS.RESET_TOKEN_INVALID } on bad token.
|
|
188
|
+
*/
|
|
189
|
+
export async function resetPassword(config, params) {
|
|
190
|
+
const client = createStorefrontClient(config);
|
|
191
|
+
await client.post(StorefrontEndpoints.auth.resetPassword(), {
|
|
192
|
+
token: params.token,
|
|
193
|
+
new_password: params.newPassword,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Verify the customer's email using the token from the verification email link.
|
|
198
|
+
* Throws { status: 400, data.detail: BUYER_AUTH_ERRORS.VERIFY_TOKEN_INVALID } on bad token.
|
|
199
|
+
*/
|
|
200
|
+
export async function verifyEmail(config, params) {
|
|
201
|
+
const client = createStorefrontClient(config);
|
|
202
|
+
await client.post(StorefrontEndpoints.auth.verifyEmail(), { token: params.token });
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Re-send the email verification link. Requires the customer to be authenticated.
|
|
206
|
+
* Throws { status: 400, data.detail: BUYER_AUTH_ERRORS.EMAIL_ALREADY_VERIFIED } if already verified.
|
|
207
|
+
*/
|
|
208
|
+
export async function resendVerification(config, website, params) {
|
|
209
|
+
const { client, businessId } = tenant(config, website);
|
|
210
|
+
await client.post(StorefrontEndpoints.auth.resendVerification(), undefined, {
|
|
211
|
+
businessId,
|
|
212
|
+
token: params.token,
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/buyer/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { ProximaCompositionResponse, ProximaWebsiteResponse } from '../types/cms.js';
|
|
2
|
+
declare class _TtlCache<T> {
|
|
3
|
+
private readonly ttlMs;
|
|
4
|
+
private readonly store;
|
|
5
|
+
constructor(ttlMs: number);
|
|
6
|
+
get(key: string): T | null;
|
|
7
|
+
set(key: string, data: T): void;
|
|
8
|
+
delete(key: string): void;
|
|
9
|
+
clear(): void;
|
|
10
|
+
}
|
|
11
|
+
/** In-process cache for website config (shell, theme, capabilities). TTL: 5 min. */
|
|
12
|
+
export declare const websiteCache: _TtlCache<ProximaWebsiteResponse>;
|
|
13
|
+
/** In-process cache for CMS compositions (page sections). TTL: 60 s. */
|
|
14
|
+
export declare const compositionCache: _TtlCache<ProximaCompositionResponse>;
|
|
15
|
+
/**
|
|
16
|
+
* Flush cache entries by scope — mirrors the payload sent by `StorefrontWebhookNotifier`:
|
|
17
|
+
* "composition" + path → flush that page's composition
|
|
18
|
+
* "website" → flush website config + all compositions (they depend on it)
|
|
19
|
+
* "all" → flush everything
|
|
20
|
+
*/
|
|
21
|
+
export declare function invalidateByScope(scope: string, path?: string): void;
|
|
22
|
+
/**
|
|
23
|
+
* Handle the POST /api/cache/invalidate webhook from the Proxima API.
|
|
24
|
+
* Drop this into your Astro route:
|
|
25
|
+
*
|
|
26
|
+
* export const POST: APIRoute = ({ request }) =>
|
|
27
|
+
* handleCacheInvalidateWebhook(request, import.meta.env.PROXIMA_WEBHOOK_SECRET);
|
|
28
|
+
*/
|
|
29
|
+
export declare function handleCacheInvalidateWebhook(request: Request, secret?: string): Promise<Response>;
|
|
30
|
+
export {};
|
|
31
|
+
//# sourceMappingURL=cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/cache/cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAoB1F,cAAM,SAAS,CAAC,CAAC;IAEH,OAAO,CAAC,QAAQ,CAAC,KAAK;IADlC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqC;gBAC9B,KAAK,EAAE,MAAM;IAE1C,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI;IAO1B,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI;IAI/B,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IACzB,KAAK,IAAI,IAAI;CACd;AAED,oFAAoF;AACpF,eAAO,MAAM,YAAY,mCAAoD,CAAC;AAE9E,wEAAwE;AACxE,eAAO,MAAM,gBAAgB,uCAAoD,CAAC;AAElF;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAUpE;AAED;;;;;;GAMG;AACH,wBAAsB,4BAA4B,CAChD,OAAO,EAAE,OAAO,EAChB,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,QAAQ,CAAC,CAiBnB"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
class _TtlCache {
|
|
2
|
+
ttlMs;
|
|
3
|
+
store = new Map();
|
|
4
|
+
constructor(ttlMs) {
|
|
5
|
+
this.ttlMs = ttlMs;
|
|
6
|
+
}
|
|
7
|
+
get(key) {
|
|
8
|
+
const entry = this.store.get(key);
|
|
9
|
+
if (!entry)
|
|
10
|
+
return null;
|
|
11
|
+
if (Date.now() > entry.expiresAt) {
|
|
12
|
+
this.store.delete(key);
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
return entry.data;
|
|
16
|
+
}
|
|
17
|
+
set(key, data) {
|
|
18
|
+
this.store.set(key, { data, expiresAt: Date.now() + this.ttlMs });
|
|
19
|
+
}
|
|
20
|
+
delete(key) { this.store.delete(key); }
|
|
21
|
+
clear() { this.store.clear(); }
|
|
22
|
+
}
|
|
23
|
+
/** In-process cache for website config (shell, theme, capabilities). TTL: 5 min. */
|
|
24
|
+
export const websiteCache = new _TtlCache(5 * 60_000);
|
|
25
|
+
/** In-process cache for CMS compositions (page sections). TTL: 60 s. */
|
|
26
|
+
export const compositionCache = new _TtlCache(60_000);
|
|
27
|
+
/**
|
|
28
|
+
* Flush cache entries by scope — mirrors the payload sent by `StorefrontWebhookNotifier`:
|
|
29
|
+
* "composition" + path → flush that page's composition
|
|
30
|
+
* "website" → flush website config + all compositions (they depend on it)
|
|
31
|
+
* "all" → flush everything
|
|
32
|
+
*/
|
|
33
|
+
export function invalidateByScope(scope, path) {
|
|
34
|
+
if (scope === "composition" && path) {
|
|
35
|
+
compositionCache.delete(path);
|
|
36
|
+
}
|
|
37
|
+
else if (scope === "website") {
|
|
38
|
+
websiteCache.clear();
|
|
39
|
+
compositionCache.clear();
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
websiteCache.clear();
|
|
43
|
+
compositionCache.clear();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Handle the POST /api/cache/invalidate webhook from the Proxima API.
|
|
48
|
+
* Drop this into your Astro route:
|
|
49
|
+
*
|
|
50
|
+
* export const POST: APIRoute = ({ request }) =>
|
|
51
|
+
* handleCacheInvalidateWebhook(request, import.meta.env.PROXIMA_WEBHOOK_SECRET);
|
|
52
|
+
*/
|
|
53
|
+
export async function handleCacheInvalidateWebhook(request, secret) {
|
|
54
|
+
if (secret) {
|
|
55
|
+
const auth = request.headers.get("Authorization") ?? "";
|
|
56
|
+
if (auth !== `Bearer ${secret}`) {
|
|
57
|
+
return new Response("Unauthorized", { status: 401 });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
let body = {};
|
|
61
|
+
try {
|
|
62
|
+
body = await request.json();
|
|
63
|
+
}
|
|
64
|
+
catch { /* empty body → treat as "all" */ }
|
|
65
|
+
invalidateByScope(body.scope ?? "all", body.path);
|
|
66
|
+
return new Response(JSON.stringify({ ok: true }), {
|
|
67
|
+
status: 200,
|
|
68
|
+
headers: { "Content-Type": "application/json" },
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/cache/cache.ts"],"names":[],"mappings":"AAoBA,MAAM,SAAS;IAEgB;IADZ,KAAK,GAAG,IAAI,GAAG,EAA0B,CAAC;IAC3D,YAA6B,KAAa;QAAb,UAAK,GAAL,KAAK,CAAQ;IAAG,CAAC;IAE9C,GAAG,CAAC,GAAW;QACb,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QACxB,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;YAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAAC,OAAO,IAAI,CAAC;QAAC,CAAC;QAC1E,OAAO,KAAK,CAAC,IAAI,CAAC;IACpB,CAAC;IAED,GAAG,CAAC,GAAW,EAAE,IAAO;QACtB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;IACpE,CAAC;IAED,MAAM,CAAC,GAAW,IAAU,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACrD,KAAK,KAAW,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;CACtC;AAED,oFAAoF;AACpF,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,SAAS,CAAyB,CAAC,GAAG,MAAM,CAAC,CAAC;AAE9E,wEAAwE;AACxE,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,SAAS,CAA6B,MAAM,CAAC,CAAC;AAElF;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAa,EAAE,IAAa;IAC5D,IAAI,KAAK,KAAK,aAAa,IAAI,IAAI,EAAE,CAAC;QACpC,gBAAgB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;SAAM,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QAC/B,YAAY,CAAC,KAAK,EAAE,CAAC;QACrB,gBAAgB,CAAC,KAAK,EAAE,CAAC;IAC3B,CAAC;SAAM,CAAC;QACN,YAAY,CAAC,KAAK,EAAE,CAAC;QACrB,gBAAgB,CAAC,KAAK,EAAE,CAAC;IAC3B,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAChD,OAAgB,EAChB,MAAe;IAEf,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC;QACxD,IAAI,IAAI,KAAK,UAAU,MAAM,EAAE,EAAE,CAAC;YAChC,OAAO,IAAI,QAAQ,CAAC,cAAc,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;IAED,IAAI,IAAI,GAAsC,EAAE,CAAC;IACjD,IAAI,CAAC;QAAC,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,iCAAiC,CAAC,CAAC;IAEhF,iBAAiB,CAAC,IAAI,CAAC,KAAK,IAAI,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IAElD,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE;QAChD,MAAM,EAAE,GAAG;QACX,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;KAChD,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { CampaignCountdownState, ResolvedSmartCollectionInfo } from '../types/campaign.js';
|
|
2
|
+
/**
|
|
3
|
+
* Returns a single countdown snapshot for the given ISO UTC target.
|
|
4
|
+
* Safe to call server-side — no timers.
|
|
5
|
+
*/
|
|
6
|
+
export declare function getCampaignCountdown(targetAt: string | null): CampaignCountdownState;
|
|
7
|
+
/**
|
|
8
|
+
* Creates a client-side ticker that calls `onTick` every second until expiry.
|
|
9
|
+
* Fires immediately on creation. Returns a cleanup function that cancels the
|
|
10
|
+
* interval — call it in cleanup / on component unmount.
|
|
11
|
+
*
|
|
12
|
+
* ```ts
|
|
13
|
+
* const stop = createCampaignTicker(targetAt, (state) => {
|
|
14
|
+
* renderCountdown(state);
|
|
15
|
+
* if (state.expired) stop();
|
|
16
|
+
* });
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare function createCampaignTicker(targetAt: string, onTick: (state: CampaignCountdownState) => void): () => void;
|
|
20
|
+
/**
|
|
21
|
+
* Extracts the countdown target from `attributes_meta` for a `datetime`-type
|
|
22
|
+
* attribute. Returns null if the attribute has no schedule metadata.
|
|
23
|
+
*
|
|
24
|
+
* ```ts
|
|
25
|
+
* // In section frontmatter:
|
|
26
|
+
* const targetAt = resolveCampaignTarget(props.attributesMeta, "campaign_end_date");
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare function resolveCampaignTarget(attributesMeta: Record<string, any> | null | undefined, attrName: string): string | null;
|
|
30
|
+
/**
|
|
31
|
+
* Extracts the countdown target from a resolved Smart Collection's `schedule`
|
|
32
|
+
* block. Returns null if the SC is missing or has no countdown target.
|
|
33
|
+
*
|
|
34
|
+
* ```ts
|
|
35
|
+
* // sc comes from section.attributes.products_sc or similar:
|
|
36
|
+
* const targetAt = resolveSmartCollectionTarget(sc);
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare function resolveSmartCollectionTarget(sc: ResolvedSmartCollectionInfo | Record<string, any> | null | undefined): string | null;
|
|
40
|
+
//# sourceMappingURL=countdown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"countdown.d.ts","sourceRoot":"","sources":["../../src/campaign/countdown.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,sBAAsB,EAEtB,2BAA2B,EAC5B,MAAM,sBAAsB,CAAC;AAE9B;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,sBAAsB,CAiBpF;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,GAC9C,MAAM,IAAI,CASZ;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CACnC,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,GAAG,SAAS,EACtD,QAAQ,EAAE,MAAM,GACf,MAAM,GAAG,IAAI,CAGf;AAED;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,CAC1C,EAAE,EAAE,2BAA2B,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,GAAG,SAAS,GACvE,MAAM,GAAG,IAAI,CAEf"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns a single countdown snapshot for the given ISO UTC target.
|
|
3
|
+
* Safe to call server-side — no timers.
|
|
4
|
+
*/
|
|
5
|
+
export function getCampaignCountdown(targetAt) {
|
|
6
|
+
if (!targetAt) {
|
|
7
|
+
return { days: 0, hours: 0, minutes: 0, seconds: 0, expired: true, targetAt };
|
|
8
|
+
}
|
|
9
|
+
const diffMs = new Date(targetAt).getTime() - Date.now();
|
|
10
|
+
if (diffMs <= 0) {
|
|
11
|
+
return { days: 0, hours: 0, minutes: 0, seconds: 0, expired: true, targetAt };
|
|
12
|
+
}
|
|
13
|
+
const s = Math.floor(diffMs / 1000);
|
|
14
|
+
return {
|
|
15
|
+
days: Math.floor(s / 86400),
|
|
16
|
+
hours: Math.floor((s % 86400) / 3600),
|
|
17
|
+
minutes: Math.floor((s % 3600) / 60),
|
|
18
|
+
seconds: s % 60,
|
|
19
|
+
expired: false,
|
|
20
|
+
targetAt,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Creates a client-side ticker that calls `onTick` every second until expiry.
|
|
25
|
+
* Fires immediately on creation. Returns a cleanup function that cancels the
|
|
26
|
+
* interval — call it in cleanup / on component unmount.
|
|
27
|
+
*
|
|
28
|
+
* ```ts
|
|
29
|
+
* const stop = createCampaignTicker(targetAt, (state) => {
|
|
30
|
+
* renderCountdown(state);
|
|
31
|
+
* if (state.expired) stop();
|
|
32
|
+
* });
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export function createCampaignTicker(targetAt, onTick) {
|
|
36
|
+
const tick = () => {
|
|
37
|
+
const state = getCampaignCountdown(targetAt);
|
|
38
|
+
onTick(state);
|
|
39
|
+
if (state.expired)
|
|
40
|
+
clearInterval(handle);
|
|
41
|
+
};
|
|
42
|
+
tick();
|
|
43
|
+
const handle = setInterval(tick, 1000);
|
|
44
|
+
return () => clearInterval(handle);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Extracts the countdown target from `attributes_meta` for a `datetime`-type
|
|
48
|
+
* attribute. Returns null if the attribute has no schedule metadata.
|
|
49
|
+
*
|
|
50
|
+
* ```ts
|
|
51
|
+
* // In section frontmatter:
|
|
52
|
+
* const targetAt = resolveCampaignTarget(props.attributesMeta, "campaign_end_date");
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export function resolveCampaignTarget(attributesMeta, attrName) {
|
|
56
|
+
const schedule = attributesMeta?.[attrName]?.schedule;
|
|
57
|
+
return schedule?.countdown_target_at ?? null;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Extracts the countdown target from a resolved Smart Collection's `schedule`
|
|
61
|
+
* block. Returns null if the SC is missing or has no countdown target.
|
|
62
|
+
*
|
|
63
|
+
* ```ts
|
|
64
|
+
* // sc comes from section.attributes.products_sc or similar:
|
|
65
|
+
* const targetAt = resolveSmartCollectionTarget(sc);
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
export function resolveSmartCollectionTarget(sc) {
|
|
69
|
+
return sc?.schedule?.countdown_target_at ?? null;
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=countdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"countdown.js","sourceRoot":"","sources":["../../src/campaign/countdown.ts"],"names":[],"mappings":"AAMA;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,QAAuB;IAC1D,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IAChF,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACzD,IAAI,MAAM,IAAI,CAAC,EAAE,CAAC;QAChB,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IAChF,CAAC;IACD,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACpC,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC;QAC3B,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,IAAI,CAAC;QACrC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACpC,OAAO,EAAE,CAAC,GAAG,EAAE;QACf,OAAO,EAAE,KAAK;QACd,QAAQ;KACT,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,oBAAoB,CAClC,QAAgB,EAChB,MAA+C;IAE/C,MAAM,IAAI,GAAG,GAAG,EAAE;QAChB,MAAM,KAAK,GAAG,oBAAoB,CAAC,QAAQ,CAAC,CAAC;QAC7C,MAAM,CAAC,KAAK,CAAC,CAAC;QACd,IAAI,KAAK,CAAC,OAAO;YAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC3C,CAAC,CAAC;IACF,IAAI,EAAE,CAAC;IACP,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACvC,OAAO,GAAG,EAAE,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;AACrC,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,qBAAqB,CACnC,cAAsD,EACtD,QAAgB;IAEhB,MAAM,QAAQ,GAAG,cAAc,EAAE,CAAC,QAAQ,CAAC,EAAE,QAAmD,CAAC;IACjG,OAAO,QAAQ,EAAE,mBAAmB,IAAI,IAAI,CAAC;AAC/C,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,4BAA4B,CAC1C,EAAwE;IAExE,OAAQ,EAAkC,EAAE,QAAQ,EAAE,mBAAmB,IAAI,IAAI,CAAC;AACpF,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { ProximaApiConfig, ProximaWebsiteResponse } from '../types/cms.js';
|
|
2
|
+
import type { Cart } from '../types/cart.js';
|
|
3
|
+
import type { CouponValidationResult } from '../types/catalog.js';
|
|
4
|
+
/** Fetch the current cart. Works for both guest sessions and authenticated customers. */
|
|
5
|
+
export declare function fetchCart(config: Pick<ProximaApiConfig, "baseUrl">, website: ProximaWebsiteResponse, params: {
|
|
6
|
+
token?: string | null;
|
|
7
|
+
sessionId?: string | null;
|
|
8
|
+
}): Promise<Cart>;
|
|
9
|
+
/**
|
|
10
|
+
* Add a product variant to the cart. Use `StorefrontProductSummary.default_variant_id`
|
|
11
|
+
* as `variantId` when adding from a listing card.
|
|
12
|
+
*/
|
|
13
|
+
export declare function addToCart(config: Pick<ProximaApiConfig, "baseUrl">, website: ProximaWebsiteResponse, params: {
|
|
14
|
+
token?: string | null;
|
|
15
|
+
sessionId?: string | null;
|
|
16
|
+
variantId: number;
|
|
17
|
+
quantity: number;
|
|
18
|
+
}): Promise<Cart>;
|
|
19
|
+
/** Update the quantity of an existing cart item. Set `quantity` to 0 to remove it. */
|
|
20
|
+
export declare function updateCartItem(config: Pick<ProximaApiConfig, "baseUrl">, website: ProximaWebsiteResponse, params: {
|
|
21
|
+
token?: string | null;
|
|
22
|
+
sessionId?: string | null;
|
|
23
|
+
variantId: number;
|
|
24
|
+
quantity: number;
|
|
25
|
+
}): Promise<Cart>;
|
|
26
|
+
/** Remove a product variant from the cart entirely. */
|
|
27
|
+
export declare function removeCartItem(config: Pick<ProximaApiConfig, "baseUrl">, website: ProximaWebsiteResponse, params: {
|
|
28
|
+
token?: string | null;
|
|
29
|
+
sessionId?: string | null;
|
|
30
|
+
variantId: number;
|
|
31
|
+
}): Promise<Cart>;
|
|
32
|
+
/**
|
|
33
|
+
* Merge a guest cart (identified by session ID) into the authenticated customer's cart.
|
|
34
|
+
* Call this immediately after a successful login if there is an active guest session.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* const sessionId = localStorage.getItem('proxima_session_id');
|
|
38
|
+
* if (sessionId) await mergeGuestCart(config, website, { token, sessionId });
|
|
39
|
+
*/
|
|
40
|
+
export declare function mergeGuestCart(config: Pick<ProximaApiConfig, "baseUrl">, website: ProximaWebsiteResponse, params: {
|
|
41
|
+
token: string;
|
|
42
|
+
sessionId: string;
|
|
43
|
+
}): Promise<Cart>;
|
|
44
|
+
/**
|
|
45
|
+
* Validate a coupon code before checkout. Always resolves — check `result.valid`.
|
|
46
|
+
* Use the `discount_amount` from the result to preview the discount in the UI.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* const result = await validateCoupon(config, website, { code: 'PROMO10', amount: 150.00 });
|
|
50
|
+
* if (result.valid) showDiscount(result.discount_amount);
|
|
51
|
+
* else showError(result.error);
|
|
52
|
+
*/
|
|
53
|
+
export declare function validateCoupon(config: Pick<ProximaApiConfig, "baseUrl">, website: Pick<ProximaWebsiteResponse, "business_id">, params: {
|
|
54
|
+
code: string;
|
|
55
|
+
amount: number;
|
|
56
|
+
}): Promise<CouponValidationResult>;
|
|
57
|
+
//# sourceMappingURL=cart.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cart.d.ts","sourceRoot":"","sources":["../../src/cart/cart.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAChF,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAalE,yFAAyF;AACzF,wBAAsB,SAAS,CAC7B,MAAM,EAAE,IAAI,CAAC,gBAAgB,EAAE,SAAS,CAAC,EACzC,OAAO,EAAE,sBAAsB,EAC/B,MAAM,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAC3D,OAAO,CAAC,IAAI,CAAC,CAGf;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAC7B,MAAM,EAAE,IAAI,CAAC,gBAAgB,EAAE,SAAS,CAAC,EACzC,OAAO,EAAE,sBAAsB,EAC/B,MAAM,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAChG,OAAO,CAAC,IAAI,CAAC,CAOf;AAED,sFAAsF;AACtF,wBAAsB,cAAc,CAClC,MAAM,EAAE,IAAI,CAAC,gBAAgB,EAAE,SAAS,CAAC,EACzC,OAAO,EAAE,sBAAsB,EAC/B,MAAM,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAChG,OAAO,CAAC,IAAI,CAAC,CAOf;AAED,uDAAuD;AACvD,wBAAsB,cAAc,CAClC,MAAM,EAAE,IAAI,CAAC,gBAAgB,EAAE,SAAS,CAAC,EACzC,OAAO,EAAE,sBAAsB,EAC/B,MAAM,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAC9E,OAAO,CAAC,IAAI,CAAC,CAMf;AAED;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,IAAI,CAAC,gBAAgB,EAAE,SAAS,CAAC,EACzC,OAAO,EAAE,sBAAsB,EAC/B,MAAM,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAC3C,OAAO,CAAC,IAAI,CAAC,CAOf;AAED;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,IAAI,CAAC,gBAAgB,EAAE,SAAS,CAAC,EACzC,OAAO,EAAE,IAAI,CAAC,sBAAsB,EAAE,aAAa,CAAC,EACpD,MAAM,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACvC,OAAO,CAAC,sBAAsB,CAAC,CAMjC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { StorefrontEndpoints, createStorefrontClient } from '../api/index.js';
|
|
2
|
+
function cartContext(website, params) {
|
|
3
|
+
return {
|
|
4
|
+
businessId: website.business_id,
|
|
5
|
+
token: params.token,
|
|
6
|
+
sessionId: params.sessionId,
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
/** Fetch the current cart. Works for both guest sessions and authenticated customers. */
|
|
10
|
+
export async function fetchCart(config, website, params) {
|
|
11
|
+
const client = createStorefrontClient(config);
|
|
12
|
+
return client.get(StorefrontEndpoints.cart.root(), cartContext(website, params));
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Add a product variant to the cart. Use `StorefrontProductSummary.default_variant_id`
|
|
16
|
+
* as `variantId` when adding from a listing card.
|
|
17
|
+
*/
|
|
18
|
+
export async function addToCart(config, website, params) {
|
|
19
|
+
const client = createStorefrontClient(config);
|
|
20
|
+
return client.post(StorefrontEndpoints.cart.items(), { product_variant_id: params.variantId, quantity: params.quantity }, cartContext(website, params));
|
|
21
|
+
}
|
|
22
|
+
/** Update the quantity of an existing cart item. Set `quantity` to 0 to remove it. */
|
|
23
|
+
export async function updateCartItem(config, website, params) {
|
|
24
|
+
const client = createStorefrontClient(config);
|
|
25
|
+
return client.patch(StorefrontEndpoints.cart.item(params.variantId), { quantity: params.quantity }, cartContext(website, params));
|
|
26
|
+
}
|
|
27
|
+
/** Remove a product variant from the cart entirely. */
|
|
28
|
+
export async function removeCartItem(config, website, params) {
|
|
29
|
+
const client = createStorefrontClient(config);
|
|
30
|
+
return client.delete(StorefrontEndpoints.cart.item(params.variantId), cartContext(website, params));
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Merge a guest cart (identified by session ID) into the authenticated customer's cart.
|
|
34
|
+
* Call this immediately after a successful login if there is an active guest session.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* const sessionId = localStorage.getItem('proxima_session_id');
|
|
38
|
+
* if (sessionId) await mergeGuestCart(config, website, { token, sessionId });
|
|
39
|
+
*/
|
|
40
|
+
export async function mergeGuestCart(config, website, params) {
|
|
41
|
+
const client = createStorefrontClient(config);
|
|
42
|
+
return client.post(StorefrontEndpoints.cart.merge(), undefined, {
|
|
43
|
+
businessId: website.business_id,
|
|
44
|
+
token: params.token,
|
|
45
|
+
headers: { 'X-Session-ID': params.sessionId },
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Validate a coupon code before checkout. Always resolves — check `result.valid`.
|
|
50
|
+
* Use the `discount_amount` from the result to preview the discount in the UI.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* const result = await validateCoupon(config, website, { code: 'PROMO10', amount: 150.00 });
|
|
54
|
+
* if (result.valid) showDiscount(result.discount_amount);
|
|
55
|
+
* else showError(result.error);
|
|
56
|
+
*/
|
|
57
|
+
export async function validateCoupon(config, website, params) {
|
|
58
|
+
const client = createStorefrontClient(config);
|
|
59
|
+
return client.get(StorefrontEndpoints.commerce.validateCoupon(), {
|
|
60
|
+
businessId: website.business_id,
|
|
61
|
+
query: { code: params.code, amount: params.amount },
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=cart.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cart.js","sourceRoot":"","sources":["../../src/cart/cart.ts"],"names":[],"mappings":"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"}
|