@growupsell/commerce 1.0.0-alpha.1 → 1.0.0-alpha.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/dist/checkout-CwpFl6qt.d.ts +560 -0
- package/dist/{chunk-YZJTPFCH.js → chunk-AI2CWQ22.js} +149 -56
- package/dist/chunk-AI2CWQ22.js.map +1 -0
- package/dist/chunk-DHBRITDW.js +2980 -0
- package/dist/chunk-DHBRITDW.js.map +1 -0
- package/dist/chunk-JBOZQJ4X.js +472 -0
- package/dist/chunk-JBOZQJ4X.js.map +1 -0
- package/dist/chunk-NNKXIBK4.js +1 -0
- package/dist/chunk-NNKXIBK4.js.map +1 -0
- package/dist/chunk-W2CJSBV4.js +329 -0
- package/dist/chunk-W2CJSBV4.js.map +1 -0
- package/dist/{index-tlJ3s67B.d.ts → client-D4JNDM6j.d.ts} +72 -279
- package/dist/http/index.d.ts +32 -2
- package/dist/http/index.js +2 -1
- package/dist/index.d.ts +6 -3
- package/dist/index.js +123 -4
- package/dist/rules/index.d.ts +462 -78
- package/dist/rules/index.js +103 -3
- package/dist/sku-C3SGyRqT.d.ts +168 -0
- package/dist/stores/index.d.ts +836 -1
- package/dist/stores/index.js +22 -0
- package/package.json +1 -1
- package/dist/chunk-4PHF3WVQ.js +0 -76
- package/dist/chunk-4PHF3WVQ.js.map +0 -1
- package/dist/chunk-YZJTPFCH.js.map +0 -1
- package/dist/promotions-Ck9FZD7h.d.ts +0 -298
|
@@ -1,3 +1,63 @@
|
|
|
1
|
+
// src/http/errors.ts
|
|
2
|
+
var GrowupsellApiError = class extends Error {
|
|
3
|
+
kind;
|
|
4
|
+
/** HTTP status; undefined when no response arrived (network, timeout). */
|
|
5
|
+
status;
|
|
6
|
+
/** Validation messages per field, as returned by the backend (`non_field_errors` included). */
|
|
7
|
+
fieldErrors;
|
|
8
|
+
/** The parsed response body, for anything the fields above don't cover. */
|
|
9
|
+
body;
|
|
10
|
+
/**
|
|
11
|
+
* For a 429 (throttled OTP checks and sends, backend S14): the seconds from `Retry-After`.
|
|
12
|
+
* Null otherwise, and when the header is missing or not a whole number of seconds.
|
|
13
|
+
*/
|
|
14
|
+
retryAfterSeconds;
|
|
15
|
+
constructor(init) {
|
|
16
|
+
super(init.message);
|
|
17
|
+
this.name = "GrowupsellApiError";
|
|
18
|
+
this.kind = init.kind;
|
|
19
|
+
this.status = init.status;
|
|
20
|
+
this.fieldErrors = init.fieldErrors ?? {};
|
|
21
|
+
this.body = init.body;
|
|
22
|
+
this.retryAfterSeconds = init.retryAfterSeconds ?? null;
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
function parseRetryAfter(value) {
|
|
26
|
+
const text2 = value?.trim();
|
|
27
|
+
return text2 && /^\d+$/.test(text2) ? Number(text2) : null;
|
|
28
|
+
}
|
|
29
|
+
function messageFromBody(body) {
|
|
30
|
+
if (typeof body === "string") {
|
|
31
|
+
const text2 = body.trim();
|
|
32
|
+
return text2 && !text2.startsWith("<") ? text2 : void 0;
|
|
33
|
+
}
|
|
34
|
+
if (Array.isArray(body)) return body.length > 0 ? messageFromBody(body[0]) : void 0;
|
|
35
|
+
if (body && typeof body === "object") {
|
|
36
|
+
const record = body;
|
|
37
|
+
for (const key of ["detail", "message"]) {
|
|
38
|
+
if (typeof record[key] === "string" && record[key]) return record[key];
|
|
39
|
+
}
|
|
40
|
+
for (const value of Object.values(record)) {
|
|
41
|
+
if (typeof value === "boolean" || typeof value === "number" || value == null) continue;
|
|
42
|
+
const found = messageFromBody(value);
|
|
43
|
+
if (found) return found;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return void 0;
|
|
47
|
+
}
|
|
48
|
+
function fieldErrorsFromBody(body) {
|
|
49
|
+
if (!body || typeof body !== "object" || Array.isArray(body)) return {};
|
|
50
|
+
const errors = {};
|
|
51
|
+
for (const [field, value] of Object.entries(body)) {
|
|
52
|
+
if (field === "detail" || field === "message") continue;
|
|
53
|
+
if (typeof value === "string") errors[field] = [value];
|
|
54
|
+
else if (Array.isArray(value) && value.length > 0 && value.every((v) => typeof v === "string")) {
|
|
55
|
+
errors[field] = value;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return errors;
|
|
59
|
+
}
|
|
60
|
+
|
|
1
61
|
// src/http/convert.ts
|
|
2
62
|
var text = (value) => value == null || value.trim() === "" ? null : value;
|
|
3
63
|
var amount = (value) => {
|
|
@@ -334,7 +394,9 @@ function toCartLine(wire) {
|
|
|
334
394
|
isDigital: wire.is_digital_product,
|
|
335
395
|
fulfillmentMode: text(wire.fulfillment_mode) ?? "none",
|
|
336
396
|
customData: wire.custom_data ?? null,
|
|
337
|
-
|
|
397
|
+
// The cart serialises the SKU at depth 2, so `selected_variants` are variant rows, not ids
|
|
398
|
+
// (local backend, 2026-11-01): take each row's id.
|
|
399
|
+
variantIds: (sku?.selected_variants ?? []).map((variant) => variant.id)
|
|
338
400
|
};
|
|
339
401
|
}
|
|
340
402
|
function toAppliedPromoCode(wire) {
|
|
@@ -569,6 +631,49 @@ function required(value, name) {
|
|
|
569
631
|
return trimmed;
|
|
570
632
|
}
|
|
571
633
|
|
|
634
|
+
// src/http/push.ts
|
|
635
|
+
var KEY = { anonymous: true };
|
|
636
|
+
var SUBSCRIBE = { business: "required" };
|
|
637
|
+
var UNSUBSCRIBE = { anonymous: true, business: "required" };
|
|
638
|
+
function createPushApi(request) {
|
|
639
|
+
return {
|
|
640
|
+
async vapidPublicKey() {
|
|
641
|
+
const wire = await request(
|
|
642
|
+
"GET",
|
|
643
|
+
"/subscribers/push/vapid-public-key",
|
|
644
|
+
KEY
|
|
645
|
+
);
|
|
646
|
+
return text(wire.public_key);
|
|
647
|
+
},
|
|
648
|
+
async subscribe(subscription) {
|
|
649
|
+
const json = { subscription: toWire(subscription, "subscribe") };
|
|
650
|
+
await request("POST", "/subscribers/create/push", {
|
|
651
|
+
...SUBSCRIBE,
|
|
652
|
+
json
|
|
653
|
+
});
|
|
654
|
+
},
|
|
655
|
+
async unsubscribe(subscription) {
|
|
656
|
+
const json = { subscription: toWire(subscription, "unsubscribe") };
|
|
657
|
+
await request("POST", "/subscribers/push/unsubscribe", {
|
|
658
|
+
...UNSUBSCRIBE,
|
|
659
|
+
json
|
|
660
|
+
});
|
|
661
|
+
}
|
|
662
|
+
};
|
|
663
|
+
}
|
|
664
|
+
function toWire(subscription, method) {
|
|
665
|
+
const { endpoint, keys } = subscription;
|
|
666
|
+
const missing = [
|
|
667
|
+
endpoint ? null : "endpoint",
|
|
668
|
+
keys?.p256dh ? null : "keys.p256dh",
|
|
669
|
+
keys?.auth ? null : "keys.auth"
|
|
670
|
+
].filter((name) => name !== null);
|
|
671
|
+
if (missing.length > 0) {
|
|
672
|
+
throw new TypeError(`push.${method}: the subscription needs ${missing.join(", ")}.`);
|
|
673
|
+
}
|
|
674
|
+
return { endpoint, keys: { p256dh: keys.p256dh, auth: keys.auth } };
|
|
675
|
+
}
|
|
676
|
+
|
|
572
677
|
// src/http/live-support.ts
|
|
573
678
|
var PUBLIC7 = { anonymous: true, business: "required" };
|
|
574
679
|
function createLiveSupportApi(request) {
|
|
@@ -932,6 +1037,8 @@ function toImage(wire) {
|
|
|
932
1037
|
url: wire.photo,
|
|
933
1038
|
originalUrl: text(wire.original_photo),
|
|
934
1039
|
variantId: wire.variant ?? null,
|
|
1040
|
+
skuId: wire.sku ?? null,
|
|
1041
|
+
videoUrl: text(wire.link)?.trim() ?? null,
|
|
935
1042
|
order: wire.display_order
|
|
936
1043
|
};
|
|
937
1044
|
}
|
|
@@ -1015,56 +1122,6 @@ function toProductOverview(wire) {
|
|
|
1015
1122
|
};
|
|
1016
1123
|
}
|
|
1017
1124
|
|
|
1018
|
-
// src/http/errors.ts
|
|
1019
|
-
var GrowupsellApiError = class extends Error {
|
|
1020
|
-
kind;
|
|
1021
|
-
/** HTTP status; undefined when no response arrived (network, timeout). */
|
|
1022
|
-
status;
|
|
1023
|
-
/** Validation messages per field, as returned by the backend (`non_field_errors` included). */
|
|
1024
|
-
fieldErrors;
|
|
1025
|
-
/** The parsed response body, for anything the fields above don't cover. */
|
|
1026
|
-
body;
|
|
1027
|
-
constructor(init) {
|
|
1028
|
-
super(init.message);
|
|
1029
|
-
this.name = "GrowupsellApiError";
|
|
1030
|
-
this.kind = init.kind;
|
|
1031
|
-
this.status = init.status;
|
|
1032
|
-
this.fieldErrors = init.fieldErrors ?? {};
|
|
1033
|
-
this.body = init.body;
|
|
1034
|
-
}
|
|
1035
|
-
};
|
|
1036
|
-
function messageFromBody(body) {
|
|
1037
|
-
if (typeof body === "string") {
|
|
1038
|
-
const text2 = body.trim();
|
|
1039
|
-
return text2 && !text2.startsWith("<") ? text2 : void 0;
|
|
1040
|
-
}
|
|
1041
|
-
if (Array.isArray(body)) return body.length > 0 ? messageFromBody(body[0]) : void 0;
|
|
1042
|
-
if (body && typeof body === "object") {
|
|
1043
|
-
const record = body;
|
|
1044
|
-
for (const key of ["detail", "message"]) {
|
|
1045
|
-
if (typeof record[key] === "string" && record[key]) return record[key];
|
|
1046
|
-
}
|
|
1047
|
-
for (const value of Object.values(record)) {
|
|
1048
|
-
if (typeof value === "boolean" || typeof value === "number" || value == null) continue;
|
|
1049
|
-
const found = messageFromBody(value);
|
|
1050
|
-
if (found) return found;
|
|
1051
|
-
}
|
|
1052
|
-
}
|
|
1053
|
-
return void 0;
|
|
1054
|
-
}
|
|
1055
|
-
function fieldErrorsFromBody(body) {
|
|
1056
|
-
if (!body || typeof body !== "object" || Array.isArray(body)) return {};
|
|
1057
|
-
const errors = {};
|
|
1058
|
-
for (const [field, value] of Object.entries(body)) {
|
|
1059
|
-
if (field === "detail" || field === "message") continue;
|
|
1060
|
-
if (typeof value === "string") errors[field] = [value];
|
|
1061
|
-
else if (Array.isArray(value) && value.length > 0 && value.every((v) => typeof v === "string")) {
|
|
1062
|
-
errors[field] = value;
|
|
1063
|
-
}
|
|
1064
|
-
}
|
|
1065
|
-
return errors;
|
|
1066
|
-
}
|
|
1067
|
-
|
|
1068
1125
|
// src/http/promotions.ts
|
|
1069
1126
|
var DEFAULT_LIMIT2 = 20;
|
|
1070
1127
|
var PUBLIC_BUSINESS = { anonymous: true, business: "required" };
|
|
@@ -1573,7 +1630,15 @@ function createSessionApi(request) {
|
|
|
1573
1630
|
};
|
|
1574
1631
|
}
|
|
1575
1632
|
function toGuestSession(wire) {
|
|
1576
|
-
|
|
1633
|
+
const raw = wire && typeof wire === "object" ? wire : null;
|
|
1634
|
+
if (typeof raw?.id !== "number" || typeof raw.session_token !== "string" || !raw.session_token) {
|
|
1635
|
+
throw new GrowupsellApiError({
|
|
1636
|
+
kind: "parse",
|
|
1637
|
+
message: "The new guest session has no token.",
|
|
1638
|
+
body: wire
|
|
1639
|
+
});
|
|
1640
|
+
}
|
|
1641
|
+
return { id: raw.id, token: raw.session_token };
|
|
1577
1642
|
}
|
|
1578
1643
|
|
|
1579
1644
|
// src/http/lookup.ts
|
|
@@ -2510,6 +2575,14 @@ function createExchangesApi(request) {
|
|
|
2510
2575
|
CUSTOMER8
|
|
2511
2576
|
)
|
|
2512
2577
|
);
|
|
2578
|
+
},
|
|
2579
|
+
async targetSkus(skuId) {
|
|
2580
|
+
const wire = await request(
|
|
2581
|
+
"GET",
|
|
2582
|
+
`/product/sku/avail/for/exchange/${skuId}`,
|
|
2583
|
+
CUSTOMER8
|
|
2584
|
+
);
|
|
2585
|
+
return wire.map(toExchangeTargetSku);
|
|
2513
2586
|
}
|
|
2514
2587
|
};
|
|
2515
2588
|
}
|
|
@@ -2550,6 +2623,16 @@ function toExchangeResult(wire) {
|
|
|
2550
2623
|
}
|
|
2551
2624
|
return { status: "submitted", id: wire.id, message: text(wire.message) };
|
|
2552
2625
|
}
|
|
2626
|
+
function toExchangeTargetSku(wire) {
|
|
2627
|
+
return {
|
|
2628
|
+
skuId: wire.id,
|
|
2629
|
+
skuCode: wire.sku,
|
|
2630
|
+
name: wire.product_name,
|
|
2631
|
+
photo: text(wire.product_photo),
|
|
2632
|
+
price: amount(wire.price) ?? 0,
|
|
2633
|
+
stockQty: wire.stock_qty
|
|
2634
|
+
};
|
|
2635
|
+
}
|
|
2553
2636
|
function toExchangeListItem(wire) {
|
|
2554
2637
|
return {
|
|
2555
2638
|
id: wire.id,
|
|
@@ -2642,7 +2725,11 @@ function createClient(options) {
|
|
|
2642
2725
|
init.body = JSON.stringify(opts.json);
|
|
2643
2726
|
}
|
|
2644
2727
|
const url = `${baseURL}/${path3.replace(/^\/+/, "")}${buildQuery(opts.query)}`;
|
|
2645
|
-
const
|
|
2728
|
+
const res = await send(url, init, opts.timeoutMs ?? timeoutMs, binary);
|
|
2729
|
+
const { status: status2, ok, text: text2, data } = res;
|
|
2730
|
+
if (headers["x-session-token"] && sessionMarkedInvalid(res.headers)) {
|
|
2731
|
+
report("session", headers["x-session-token"]);
|
|
2732
|
+
}
|
|
2646
2733
|
if (data) return data;
|
|
2647
2734
|
const body = parseBody(text2, ok, status2);
|
|
2648
2735
|
if (ok) return body;
|
|
@@ -2653,7 +2740,8 @@ function createClient(options) {
|
|
|
2653
2740
|
status: status2,
|
|
2654
2741
|
message: messageFromBody(body) ?? `Request failed with status ${status2}`,
|
|
2655
2742
|
fieldErrors: fieldErrorsFromBody(body),
|
|
2656
|
-
body
|
|
2743
|
+
body,
|
|
2744
|
+
retryAfterSeconds: status2 === 429 ? parseRetryAfter(res.headers?.get("retry-after")) : null
|
|
2657
2745
|
});
|
|
2658
2746
|
}
|
|
2659
2747
|
async function send(url, init, ms, binary) {
|
|
@@ -2673,6 +2761,7 @@ function createClient(options) {
|
|
|
2673
2761
|
doFetch(url, init).then(async (res) => ({
|
|
2674
2762
|
status: res.status,
|
|
2675
2763
|
ok: res.ok,
|
|
2764
|
+
headers: res.headers,
|
|
2676
2765
|
// Error responses are read as text even for binary requests: they carry the message.
|
|
2677
2766
|
text: binary && res.ok ? "" : await res.text(),
|
|
2678
2767
|
data: binary && res.ok ? await readBinary(res) : void 0
|
|
@@ -2700,7 +2789,7 @@ function createClient(options) {
|
|
|
2700
2789
|
function report(kind, token) {
|
|
2701
2790
|
if (reported[kind] === token) return;
|
|
2702
2791
|
reported[kind] = token;
|
|
2703
|
-
options.onUnauthorized?.({ kind });
|
|
2792
|
+
options.onUnauthorized?.({ kind, token });
|
|
2704
2793
|
}
|
|
2705
2794
|
return {
|
|
2706
2795
|
request,
|
|
@@ -2725,6 +2814,7 @@ function createClient(options) {
|
|
|
2725
2814
|
forms: createFormsApi(request),
|
|
2726
2815
|
helpdesk: createHelpdeskApi(request),
|
|
2727
2816
|
newsletter: createNewsletterApi(request),
|
|
2817
|
+
push: createPushApi(request),
|
|
2728
2818
|
liveSupport: createLiveSupportApi(request),
|
|
2729
2819
|
customManufacturing: createCustomManufacturingApi(request),
|
|
2730
2820
|
subscriptions: createSubscriptionsApi(request),
|
|
@@ -2754,6 +2844,9 @@ function buildHeaders(credentials, opts) {
|
|
|
2754
2844
|
function isDeadSession(status2, body, headers) {
|
|
2755
2845
|
return status2 === 404 && typeof body === "string" && !!headers["x-session-token"];
|
|
2756
2846
|
}
|
|
2847
|
+
function sessionMarkedInvalid(headers) {
|
|
2848
|
+
return headers?.get("x-session-status")?.trim().toLowerCase() === "invalid";
|
|
2849
|
+
}
|
|
2757
2850
|
function parseBody(text2, ok, status2) {
|
|
2758
2851
|
if (text2 === "") return void 0;
|
|
2759
2852
|
try {
|
|
@@ -2786,4 +2879,4 @@ export {
|
|
|
2786
2879
|
GrowupsellApiError,
|
|
2787
2880
|
createClient
|
|
2788
2881
|
};
|
|
2789
|
-
//# sourceMappingURL=chunk-
|
|
2882
|
+
//# sourceMappingURL=chunk-AI2CWQ22.js.map
|