@growupsell/commerce 1.0.0-alpha.1 → 1.0.0-alpha.3
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-DDNMdKbR.d.ts +584 -0
- package/dist/{chunk-YZJTPFCH.js → chunk-BORVKACK.js} +160 -59
- package/dist/chunk-BORVKACK.js.map +1 -0
- package/dist/chunk-HGCKDE7D.js +2988 -0
- package/dist/chunk-HGCKDE7D.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-RzekAHeO.d.ts} +73 -287
- 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-ViHXTvEw.d.ts +168 -0
- package/dist/stores/index.d.ts +843 -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) => {
|
|
@@ -137,8 +197,6 @@ function toBusiness(wire) {
|
|
|
137
197
|
name: wire.name ?? null,
|
|
138
198
|
description: wire.description ?? null,
|
|
139
199
|
legalName: wire.legal_name ?? null,
|
|
140
|
-
gstNumber: wire.gst_number ?? null,
|
|
141
|
-
panNumber: wire.pan_number ?? null,
|
|
142
200
|
isTemplate: wire.is_template ?? false,
|
|
143
201
|
category: wire.category ? { id: wire.category.id, name: wire.category.name, type: wire.category.type } : null,
|
|
144
202
|
legalForm: wire.legal_forms ? { id: wire.legal_forms.id, name: wire.legal_forms.name } : null,
|
|
@@ -334,7 +392,9 @@ function toCartLine(wire) {
|
|
|
334
392
|
isDigital: wire.is_digital_product,
|
|
335
393
|
fulfillmentMode: text(wire.fulfillment_mode) ?? "none",
|
|
336
394
|
customData: wire.custom_data ?? null,
|
|
337
|
-
|
|
395
|
+
// The cart serialises the SKU at depth 2, so `selected_variants` are variant rows, not ids
|
|
396
|
+
// (local backend, 2026-11-01): take each row's id.
|
|
397
|
+
variantIds: (sku?.selected_variants ?? []).map((variant) => variant.id)
|
|
338
398
|
};
|
|
339
399
|
}
|
|
340
400
|
function toAppliedPromoCode(wire) {
|
|
@@ -569,6 +629,49 @@ function required(value, name) {
|
|
|
569
629
|
return trimmed;
|
|
570
630
|
}
|
|
571
631
|
|
|
632
|
+
// src/http/push.ts
|
|
633
|
+
var KEY = { anonymous: true };
|
|
634
|
+
var SUBSCRIBE = { business: "required" };
|
|
635
|
+
var UNSUBSCRIBE = { anonymous: true, business: "required" };
|
|
636
|
+
function createPushApi(request) {
|
|
637
|
+
return {
|
|
638
|
+
async vapidPublicKey() {
|
|
639
|
+
const wire = await request(
|
|
640
|
+
"GET",
|
|
641
|
+
"/subscribers/push/vapid-public-key",
|
|
642
|
+
KEY
|
|
643
|
+
);
|
|
644
|
+
return text(wire.public_key);
|
|
645
|
+
},
|
|
646
|
+
async subscribe(subscription) {
|
|
647
|
+
const json = { subscription: toWire(subscription, "subscribe") };
|
|
648
|
+
await request("POST", "/subscribers/create/push", {
|
|
649
|
+
...SUBSCRIBE,
|
|
650
|
+
json
|
|
651
|
+
});
|
|
652
|
+
},
|
|
653
|
+
async unsubscribe(subscription) {
|
|
654
|
+
const json = { subscription: toWire(subscription, "unsubscribe") };
|
|
655
|
+
await request("POST", "/subscribers/push/unsubscribe", {
|
|
656
|
+
...UNSUBSCRIBE,
|
|
657
|
+
json
|
|
658
|
+
});
|
|
659
|
+
}
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
function toWire(subscription, method) {
|
|
663
|
+
const { endpoint, keys } = subscription;
|
|
664
|
+
const missing = [
|
|
665
|
+
endpoint ? null : "endpoint",
|
|
666
|
+
keys?.p256dh ? null : "keys.p256dh",
|
|
667
|
+
keys?.auth ? null : "keys.auth"
|
|
668
|
+
].filter((name) => name !== null);
|
|
669
|
+
if (missing.length > 0) {
|
|
670
|
+
throw new TypeError(`push.${method}: the subscription needs ${missing.join(", ")}.`);
|
|
671
|
+
}
|
|
672
|
+
return { endpoint, keys: { p256dh: keys.p256dh, auth: keys.auth } };
|
|
673
|
+
}
|
|
674
|
+
|
|
572
675
|
// src/http/live-support.ts
|
|
573
676
|
var PUBLIC7 = { anonymous: true, business: "required" };
|
|
574
677
|
function createLiveSupportApi(request) {
|
|
@@ -808,6 +911,12 @@ var SORT = {
|
|
|
808
911
|
popularity: "popularity",
|
|
809
912
|
category: "category"
|
|
810
913
|
};
|
|
914
|
+
var LIST_ORDERING = {
|
|
915
|
+
newest: "-id",
|
|
916
|
+
oldest: "id",
|
|
917
|
+
"name-a-z": "name",
|
|
918
|
+
"name-z-a": "-name"
|
|
919
|
+
};
|
|
811
920
|
var PUBLIC10 = { business: "required", anonymous: true };
|
|
812
921
|
function createProductsApi(request) {
|
|
813
922
|
return {
|
|
@@ -849,6 +958,7 @@ function createProductsApi(request) {
|
|
|
849
958
|
status: "available",
|
|
850
959
|
ids: options.ids,
|
|
851
960
|
category_ids: options.categoryIds,
|
|
961
|
+
ordering: options.sort ? LIST_ORDERING[options.sort] : void 0,
|
|
852
962
|
limit,
|
|
853
963
|
offset
|
|
854
964
|
}
|
|
@@ -932,6 +1042,8 @@ function toImage(wire) {
|
|
|
932
1042
|
url: wire.photo,
|
|
933
1043
|
originalUrl: text(wire.original_photo),
|
|
934
1044
|
variantId: wire.variant ?? null,
|
|
1045
|
+
skuId: wire.sku ?? null,
|
|
1046
|
+
videoUrl: text(wire.link)?.trim() ?? null,
|
|
935
1047
|
order: wire.display_order
|
|
936
1048
|
};
|
|
937
1049
|
}
|
|
@@ -953,7 +1065,8 @@ function toProductListItem(wire) {
|
|
|
953
1065
|
unit: text(wire.unit),
|
|
954
1066
|
variantGroups: (wire.variant ?? []).map(toVariantGroup),
|
|
955
1067
|
selectedVariantIds: wire.selected_variants,
|
|
956
|
-
|
|
1068
|
+
description: text(wire.description),
|
|
1069
|
+
fulfillmentMode: text(wire.fulfillment_mode) ?? "none",
|
|
957
1070
|
hasDigitalDelivery: wire.has_digital_delivery,
|
|
958
1071
|
advanceAmount: amount(wire.advance_amount)
|
|
959
1072
|
};
|
|
@@ -1006,6 +1119,8 @@ function toProductOverview(wire) {
|
|
|
1006
1119
|
id: wire.id,
|
|
1007
1120
|
name: wire.name,
|
|
1008
1121
|
slug: wire.url_slug,
|
|
1122
|
+
description: text(wire.description),
|
|
1123
|
+
fulfillmentMode: wire.fulfillment_mode ?? "none",
|
|
1009
1124
|
categoryName: text(wire.category_name),
|
|
1010
1125
|
images: liveImages(wire.images).map(toImage),
|
|
1011
1126
|
variantGroups: (wire.variant ?? []).map(toVariantGroup),
|
|
@@ -1015,56 +1130,6 @@ function toProductOverview(wire) {
|
|
|
1015
1130
|
};
|
|
1016
1131
|
}
|
|
1017
1132
|
|
|
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
1133
|
// src/http/promotions.ts
|
|
1069
1134
|
var DEFAULT_LIMIT2 = 20;
|
|
1070
1135
|
var PUBLIC_BUSINESS = { anonymous: true, business: "required" };
|
|
@@ -1573,7 +1638,15 @@ function createSessionApi(request) {
|
|
|
1573
1638
|
};
|
|
1574
1639
|
}
|
|
1575
1640
|
function toGuestSession(wire) {
|
|
1576
|
-
|
|
1641
|
+
const raw = wire && typeof wire === "object" ? wire : null;
|
|
1642
|
+
if (typeof raw?.id !== "number" || typeof raw.session_token !== "string" || !raw.session_token) {
|
|
1643
|
+
throw new GrowupsellApiError({
|
|
1644
|
+
kind: "parse",
|
|
1645
|
+
message: "The new guest session has no token.",
|
|
1646
|
+
body: wire
|
|
1647
|
+
});
|
|
1648
|
+
}
|
|
1649
|
+
return { id: raw.id, token: raw.session_token };
|
|
1577
1650
|
}
|
|
1578
1651
|
|
|
1579
1652
|
// src/http/lookup.ts
|
|
@@ -2510,6 +2583,14 @@ function createExchangesApi(request) {
|
|
|
2510
2583
|
CUSTOMER8
|
|
2511
2584
|
)
|
|
2512
2585
|
);
|
|
2586
|
+
},
|
|
2587
|
+
async targetSkus(skuId) {
|
|
2588
|
+
const wire = await request(
|
|
2589
|
+
"GET",
|
|
2590
|
+
`/product/sku/avail/for/exchange/${skuId}`,
|
|
2591
|
+
CUSTOMER8
|
|
2592
|
+
);
|
|
2593
|
+
return wire.map(toExchangeTargetSku);
|
|
2513
2594
|
}
|
|
2514
2595
|
};
|
|
2515
2596
|
}
|
|
@@ -2550,6 +2631,16 @@ function toExchangeResult(wire) {
|
|
|
2550
2631
|
}
|
|
2551
2632
|
return { status: "submitted", id: wire.id, message: text(wire.message) };
|
|
2552
2633
|
}
|
|
2634
|
+
function toExchangeTargetSku(wire) {
|
|
2635
|
+
return {
|
|
2636
|
+
skuId: wire.id,
|
|
2637
|
+
skuCode: wire.sku,
|
|
2638
|
+
name: wire.product_name,
|
|
2639
|
+
photo: text(wire.product_photo),
|
|
2640
|
+
price: amount(wire.price) ?? 0,
|
|
2641
|
+
stockQty: wire.stock_qty
|
|
2642
|
+
};
|
|
2643
|
+
}
|
|
2553
2644
|
function toExchangeListItem(wire) {
|
|
2554
2645
|
return {
|
|
2555
2646
|
id: wire.id,
|
|
@@ -2642,7 +2733,11 @@ function createClient(options) {
|
|
|
2642
2733
|
init.body = JSON.stringify(opts.json);
|
|
2643
2734
|
}
|
|
2644
2735
|
const url = `${baseURL}/${path3.replace(/^\/+/, "")}${buildQuery(opts.query)}`;
|
|
2645
|
-
const
|
|
2736
|
+
const res = await send(url, init, opts.timeoutMs ?? timeoutMs, binary);
|
|
2737
|
+
const { status: status2, ok, text: text2, data } = res;
|
|
2738
|
+
if (headers["x-session-token"] && sessionMarkedInvalid(res.headers)) {
|
|
2739
|
+
report("session", headers["x-session-token"]);
|
|
2740
|
+
}
|
|
2646
2741
|
if (data) return data;
|
|
2647
2742
|
const body = parseBody(text2, ok, status2);
|
|
2648
2743
|
if (ok) return body;
|
|
@@ -2653,7 +2748,8 @@ function createClient(options) {
|
|
|
2653
2748
|
status: status2,
|
|
2654
2749
|
message: messageFromBody(body) ?? `Request failed with status ${status2}`,
|
|
2655
2750
|
fieldErrors: fieldErrorsFromBody(body),
|
|
2656
|
-
body
|
|
2751
|
+
body,
|
|
2752
|
+
retryAfterSeconds: status2 === 429 ? parseRetryAfter(res.headers?.get("retry-after")) : null
|
|
2657
2753
|
});
|
|
2658
2754
|
}
|
|
2659
2755
|
async function send(url, init, ms, binary) {
|
|
@@ -2673,6 +2769,7 @@ function createClient(options) {
|
|
|
2673
2769
|
doFetch(url, init).then(async (res) => ({
|
|
2674
2770
|
status: res.status,
|
|
2675
2771
|
ok: res.ok,
|
|
2772
|
+
headers: res.headers,
|
|
2676
2773
|
// Error responses are read as text even for binary requests: they carry the message.
|
|
2677
2774
|
text: binary && res.ok ? "" : await res.text(),
|
|
2678
2775
|
data: binary && res.ok ? await readBinary(res) : void 0
|
|
@@ -2700,7 +2797,7 @@ function createClient(options) {
|
|
|
2700
2797
|
function report(kind, token) {
|
|
2701
2798
|
if (reported[kind] === token) return;
|
|
2702
2799
|
reported[kind] = token;
|
|
2703
|
-
options.onUnauthorized?.({ kind });
|
|
2800
|
+
options.onUnauthorized?.({ kind, token });
|
|
2704
2801
|
}
|
|
2705
2802
|
return {
|
|
2706
2803
|
request,
|
|
@@ -2725,6 +2822,7 @@ function createClient(options) {
|
|
|
2725
2822
|
forms: createFormsApi(request),
|
|
2726
2823
|
helpdesk: createHelpdeskApi(request),
|
|
2727
2824
|
newsletter: createNewsletterApi(request),
|
|
2825
|
+
push: createPushApi(request),
|
|
2728
2826
|
liveSupport: createLiveSupportApi(request),
|
|
2729
2827
|
customManufacturing: createCustomManufacturingApi(request),
|
|
2730
2828
|
subscriptions: createSubscriptionsApi(request),
|
|
@@ -2754,6 +2852,9 @@ function buildHeaders(credentials, opts) {
|
|
|
2754
2852
|
function isDeadSession(status2, body, headers) {
|
|
2755
2853
|
return status2 === 404 && typeof body === "string" && !!headers["x-session-token"];
|
|
2756
2854
|
}
|
|
2855
|
+
function sessionMarkedInvalid(headers) {
|
|
2856
|
+
return headers?.get("x-session-status")?.trim().toLowerCase() === "invalid";
|
|
2857
|
+
}
|
|
2757
2858
|
function parseBody(text2, ok, status2) {
|
|
2758
2859
|
if (text2 === "") return void 0;
|
|
2759
2860
|
try {
|
|
@@ -2786,4 +2887,4 @@ export {
|
|
|
2786
2887
|
GrowupsellApiError,
|
|
2787
2888
|
createClient
|
|
2788
2889
|
};
|
|
2789
|
-
//# sourceMappingURL=chunk-
|
|
2890
|
+
//# sourceMappingURL=chunk-BORVKACK.js.map
|