@misiki/gocommerce-connector 0.3.0 → 0.3.1
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/{index-BfbB3jQb.d.cts → index-D8lNRhqJ.d.cts} +11 -1
- package/dist/{index-BfbB3jQb.d.ts → index-D8lNRhqJ.d.ts} +11 -1
- package/dist/index.cjs +337 -329
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +337 -330
- package/dist/index.js.map +1 -1
- package/dist/services/index.cjs +19 -11
- package/dist/services/index.cjs.map +1 -1
- package/dist/services/index.d.cts +1 -1
- package/dist/services/index.d.ts +1 -1
- package/dist/services/index.js +19 -12
- package/dist/services/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -136,6 +136,313 @@ function forgetAll() {
|
|
|
136
136
|
entries.clear();
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
+
// src/browser.ts
|
|
140
|
+
var inBrowser = () => typeof window !== "undefined" && typeof document !== "undefined";
|
|
141
|
+
function readLocal(key) {
|
|
142
|
+
if (!inBrowser()) return null;
|
|
143
|
+
try {
|
|
144
|
+
return window.localStorage.getItem(key);
|
|
145
|
+
} catch {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
function writeLocal(key, value) {
|
|
150
|
+
if (!inBrowser()) return;
|
|
151
|
+
try {
|
|
152
|
+
window.localStorage.setItem(key, value);
|
|
153
|
+
} catch {
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
function removeLocal(key) {
|
|
157
|
+
if (!inBrowser()) return;
|
|
158
|
+
try {
|
|
159
|
+
window.localStorage.removeItem(key);
|
|
160
|
+
} catch {
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
function readJSON(key) {
|
|
164
|
+
const raw = readLocal(key);
|
|
165
|
+
if (!raw) return null;
|
|
166
|
+
try {
|
|
167
|
+
return JSON.parse(raw);
|
|
168
|
+
} catch {
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
var YEAR = 60 * 60 * 24 * 365;
|
|
173
|
+
function setCookie(name, value, maxAge = YEAR) {
|
|
174
|
+
if (!inBrowser()) return;
|
|
175
|
+
document.cookie = `${name}=${value}; path=/; max-age=${maxAge}; samesite=lax`;
|
|
176
|
+
}
|
|
177
|
+
function clearCookie(name) {
|
|
178
|
+
if (!inBrowser()) return;
|
|
179
|
+
document.cookie = `${name}=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT`;
|
|
180
|
+
}
|
|
181
|
+
function readCookie(name) {
|
|
182
|
+
if (!inBrowser()) return null;
|
|
183
|
+
for (const pair of document.cookie.split(";")) {
|
|
184
|
+
const at = pair.indexOf("=");
|
|
185
|
+
if (at < 0) continue;
|
|
186
|
+
if (pair.slice(0, at).trim() === name) return pair.slice(at + 1).trim();
|
|
187
|
+
}
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
var TOKEN = "gocommerce_token";
|
|
191
|
+
var sessionToken = () => readLocal(TOKEN);
|
|
192
|
+
function toMe(c) {
|
|
193
|
+
const [firstName, ...rest] = (c.name ?? "").trim().split(/\s+/);
|
|
194
|
+
return {
|
|
195
|
+
id: String(c.id),
|
|
196
|
+
userId: String(c.id),
|
|
197
|
+
email: c.email,
|
|
198
|
+
phone: c.phone || null,
|
|
199
|
+
firstName: firstName || "",
|
|
200
|
+
lastName: rest.join(" "),
|
|
201
|
+
name: c.name ?? "",
|
|
202
|
+
fullName: c.name ?? "",
|
|
203
|
+
avatar: null,
|
|
204
|
+
role: "USER",
|
|
205
|
+
emailVerified: c.email_verified,
|
|
206
|
+
storeId: null
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
function startSession(auth) {
|
|
210
|
+
writeLocal(TOKEN, auth.token);
|
|
211
|
+
const me = toMe(auth.record);
|
|
212
|
+
const expires = Math.max(60, Math.floor((Date.parse(auth.expires_at) - Date.now()) / 1e3)) || YEAR;
|
|
213
|
+
setCookie("me", encodeURIComponent(JSON.stringify(me)), expires);
|
|
214
|
+
setCookie("connect.sid", "gocommerce", expires);
|
|
215
|
+
return me;
|
|
216
|
+
}
|
|
217
|
+
function updateMe(c) {
|
|
218
|
+
const me = toMe(c);
|
|
219
|
+
setCookie("me", encodeURIComponent(JSON.stringify(me)));
|
|
220
|
+
return me;
|
|
221
|
+
}
|
|
222
|
+
function endSession() {
|
|
223
|
+
removeLocal(TOKEN);
|
|
224
|
+
clearCookie("me");
|
|
225
|
+
clearCookie("connect.sid");
|
|
226
|
+
}
|
|
227
|
+
function currentMe() {
|
|
228
|
+
const raw = readCookie("me");
|
|
229
|
+
if (!raw) return null;
|
|
230
|
+
try {
|
|
231
|
+
return JSON.parse(decodeURIComponent(raw));
|
|
232
|
+
} catch {
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
function storedCartId() {
|
|
237
|
+
const v = readLocal("cart_id");
|
|
238
|
+
if (!v || v === "undefined" || v === "null") return null;
|
|
239
|
+
return v;
|
|
240
|
+
}
|
|
241
|
+
var rememberCartId = (id2) => writeLocal("cart_id", id2);
|
|
242
|
+
var extrasKey = (cartId) => `gocommerce_cart_${cartId}`;
|
|
243
|
+
var cartExtras = (cartId) => readJSON(extrasKey(cartId)) ?? {};
|
|
244
|
+
function saveCartExtras(cartId, patch) {
|
|
245
|
+
const next = { ...cartExtras(cartId), ...patch };
|
|
246
|
+
writeLocal(extrasKey(cartId), JSON.stringify(next));
|
|
247
|
+
return next;
|
|
248
|
+
}
|
|
249
|
+
var forgetCartExtras = (cartId) => removeLocal(extrasKey(cartId));
|
|
250
|
+
var ORDERS = "gocommerce_orders";
|
|
251
|
+
var placedOrders = () => readJSON(ORDERS) ?? [];
|
|
252
|
+
function rememberOrder(o) {
|
|
253
|
+
const kept = placedOrders().filter((p) => p.number !== o.number);
|
|
254
|
+
writeLocal(ORDERS, JSON.stringify([o, ...kept].slice(0, 50)));
|
|
255
|
+
}
|
|
256
|
+
var placedOrder = (number) => placedOrders().find((p) => p.number === number);
|
|
257
|
+
var placedOrderForCart = (cartId) => placedOrders().find((p) => p.cartId === cartId);
|
|
258
|
+
var placedOrderByReference = (reference) => placedOrders().find((p) => p.reference === reference);
|
|
259
|
+
var WISHLIST = "gocommerce_wishlist";
|
|
260
|
+
var wishlistToken = () => readLocal(WISHLIST);
|
|
261
|
+
var rememberWishlistToken = (token) => writeLocal(WISHLIST, token);
|
|
262
|
+
var forgetWishlistToken = () => removeLocal(WISHLIST);
|
|
263
|
+
|
|
264
|
+
// src/services/base.service.ts
|
|
265
|
+
function mediaUrl(url) {
|
|
266
|
+
if (!url) return null;
|
|
267
|
+
if (!url.startsWith("/") || url.startsWith("//")) return url;
|
|
268
|
+
const { apiUrl, proxyPath } = BaseService.getCredentials();
|
|
269
|
+
return (proxyPath || apiUrl || "").trim().replace(/\/+$/, "") + url;
|
|
270
|
+
}
|
|
271
|
+
var BaseService = class _BaseService {
|
|
272
|
+
static _credentials = { apiUrl: "" };
|
|
273
|
+
_fetch;
|
|
274
|
+
constructor(fetchFn) {
|
|
275
|
+
this._fetch = fetchFn ?? ((input, init) => globalThis.fetch(input, init));
|
|
276
|
+
}
|
|
277
|
+
static setCredentials(creds) {
|
|
278
|
+
_BaseService._credentials = { ..._BaseService._credentials, ...creds };
|
|
279
|
+
}
|
|
280
|
+
static getCredentials() {
|
|
281
|
+
return _BaseService._credentials;
|
|
282
|
+
}
|
|
283
|
+
get creds() {
|
|
284
|
+
return _BaseService._credentials;
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* The engine's base URL from wherever this code runs. In the browser a
|
|
288
|
+
* configured proxy path wins, because the engine answers no CORS preflight.
|
|
289
|
+
*/
|
|
290
|
+
engineBase() {
|
|
291
|
+
const { apiUrl, proxyPath } = this.creds;
|
|
292
|
+
if (proxyPath && typeof window !== "undefined" && window.location) {
|
|
293
|
+
return new URL(proxyPath, window.location.origin).href.replace(/\/+$/, "");
|
|
294
|
+
}
|
|
295
|
+
const url = (apiUrl ?? "").trim();
|
|
296
|
+
if (!url) {
|
|
297
|
+
throw new GoCommerceError(
|
|
298
|
+
"PUBLIC_GOCOMMERCE_API_URL is not set, so this storefront does not know where its commerce engine is. Point it at a running GoCommerce, e.g. http://127.0.0.1:8080.",
|
|
299
|
+
0
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
return url.replace(/\/+$/, "");
|
|
303
|
+
}
|
|
304
|
+
/** An absolute engine URL for a path and query, without sending anything. */
|
|
305
|
+
engineURL(path, query) {
|
|
306
|
+
return this.engineBase() + path + qs(query);
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* One request to the engine, envelope and all.
|
|
310
|
+
*
|
|
311
|
+
* The body is read as text first, so a proxy's HTML error page is reported
|
|
312
|
+
* as what it is rather than as a JSON parse error three frames away.
|
|
313
|
+
*/
|
|
314
|
+
async engine(path, req = {}) {
|
|
315
|
+
const lang = (req.method ?? "GET") === "GET" ? this.creds.language : void 0;
|
|
316
|
+
const url = this.engineURL(path, lang ? { lang, ...req.query } : req.query);
|
|
317
|
+
const headers = { Accept: "application/json", ...req.headers };
|
|
318
|
+
if (req.body !== void 0) headers["Content-Type"] = "application/json";
|
|
319
|
+
if (this.creds.store) headers["X-Store"] = this.creds.store;
|
|
320
|
+
if (req.auth) {
|
|
321
|
+
const token = sessionToken();
|
|
322
|
+
if (!token) throw new GoCommerceError("Please sign in to continue.", 401, "unauthorized");
|
|
323
|
+
headers.Authorization = `Bearer ${token}`;
|
|
324
|
+
}
|
|
325
|
+
const init = {
|
|
326
|
+
method: req.method ?? "GET",
|
|
327
|
+
headers,
|
|
328
|
+
body: req.body === void 0 ? void 0 : JSON.stringify(req.body)
|
|
329
|
+
};
|
|
330
|
+
let res;
|
|
331
|
+
try {
|
|
332
|
+
res = await this._fetch.call(globalThis, url, init);
|
|
333
|
+
} catch (cause) {
|
|
334
|
+
if (typeof window === "undefined" && /CORS/i.test(String(cause?.message))) {
|
|
335
|
+
try {
|
|
336
|
+
res = await globalThis.fetch(url, init);
|
|
337
|
+
} catch (again) {
|
|
338
|
+
throw unreachable(this.engineBase(), again);
|
|
339
|
+
}
|
|
340
|
+
} else {
|
|
341
|
+
throw unreachable(this.engineBase(), cause);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return this.unwrap(res);
|
|
345
|
+
}
|
|
346
|
+
/** The envelope opened: the payload, or the engine's error as a GoCommerceError. */
|
|
347
|
+
async unwrap(res) {
|
|
348
|
+
const text = await res.text();
|
|
349
|
+
let parsed = null;
|
|
350
|
+
if (text) {
|
|
351
|
+
try {
|
|
352
|
+
parsed = JSON.parse(text);
|
|
353
|
+
} catch {
|
|
354
|
+
throw new GoCommerceError(
|
|
355
|
+
`The commerce engine answered ${res.status} with something that is not JSON: ${text.slice(0, 120)}`,
|
|
356
|
+
res.status
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
if (!res.ok) {
|
|
361
|
+
const err = parsed?.error ?? {};
|
|
362
|
+
throw new GoCommerceError(
|
|
363
|
+
err.message ?? `The commerce engine answered ${res.status}.`,
|
|
364
|
+
res.status,
|
|
365
|
+
err.code,
|
|
366
|
+
err.details
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
return parsed ?? { data: null };
|
|
370
|
+
}
|
|
371
|
+
/** The bare payload, for the many callers that never look at `meta`. */
|
|
372
|
+
async data(path, req = {}) {
|
|
373
|
+
return (await this.engine(path, req)).data;
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* Prices a cart at the signed-in shopper's customer-group prices. The
|
|
377
|
+
* engine does this only for an account whose email is confirmed (403
|
|
378
|
+
* otherwise), and the cart stays the shopper's either way — so a refusal
|
|
379
|
+
* is not an error, and neither is a build without ext/identity.
|
|
380
|
+
*/
|
|
381
|
+
async claimCartForAccount(cartId) {
|
|
382
|
+
try {
|
|
383
|
+
await this.engine("/x/identity/me/carts", { method: "POST", body: { cart_id: cartId }, auth: true });
|
|
384
|
+
} catch {
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
// ------------------------------------------------------------ Litekart verbs
|
|
388
|
+
/**
|
|
389
|
+
* The family's path-addressed verbs. An absolute URL is fetched as-is; a
|
|
390
|
+
* relative one is a Litekart REST path, answered from the storefront's own
|
|
391
|
+
* data where it has some and refused otherwise (rest-guard.ts).
|
|
392
|
+
*/
|
|
393
|
+
get(path) {
|
|
394
|
+
return this.raw("get", path);
|
|
395
|
+
}
|
|
396
|
+
post(path, data) {
|
|
397
|
+
return this.raw("post", path, data);
|
|
398
|
+
}
|
|
399
|
+
put(path, data) {
|
|
400
|
+
return this.raw("put", path, data);
|
|
401
|
+
}
|
|
402
|
+
patch(path, data) {
|
|
403
|
+
return this.raw("patch", path, data);
|
|
404
|
+
}
|
|
405
|
+
delete(path) {
|
|
406
|
+
return this.raw("delete", path);
|
|
407
|
+
}
|
|
408
|
+
async raw(method, path, data) {
|
|
409
|
+
if (!/^https?:\/\//i.test(path)) return await resolveRestLocally(method, path);
|
|
410
|
+
const res = await this._fetch.call(globalThis, path, {
|
|
411
|
+
method: method.toUpperCase(),
|
|
412
|
+
headers: { Accept: "application/json", ...data === void 0 ? {} : { "Content-Type": "application/json" } },
|
|
413
|
+
body: data === void 0 ? void 0 : JSON.stringify(data)
|
|
414
|
+
});
|
|
415
|
+
const body = await res.json().catch(() => ({}));
|
|
416
|
+
if (!res.ok)
|
|
417
|
+
throw new GoCommerceError(body?.error?.message ?? `Request failed with status ${res.status}`, res.status);
|
|
418
|
+
return body;
|
|
419
|
+
}
|
|
420
|
+
};
|
|
421
|
+
var unreachable = (base, cause) => new GoCommerceError(`Could not reach the commerce engine at ${base}: ${cause?.message ?? cause}`, 0);
|
|
422
|
+
function qs(query) {
|
|
423
|
+
if (!query) return "";
|
|
424
|
+
const sp = new URLSearchParams();
|
|
425
|
+
for (const [key, value] of Object.entries(query)) {
|
|
426
|
+
if (value === void 0 || value === null || value === "") continue;
|
|
427
|
+
if (Array.isArray(value)) for (const v of value) sp.append(key, String(v));
|
|
428
|
+
else sp.append(key, String(value));
|
|
429
|
+
}
|
|
430
|
+
const s = sp.toString();
|
|
431
|
+
return s ? `?${s}` : "";
|
|
432
|
+
}
|
|
433
|
+
function toPage(env, map) {
|
|
434
|
+
const rows = env.data ?? [];
|
|
435
|
+
const meta = env.meta;
|
|
436
|
+
return {
|
|
437
|
+
data: rows.map(map),
|
|
438
|
+
count: meta?.total ?? rows.length,
|
|
439
|
+
pageSize: meta?.limit ?? rows.length,
|
|
440
|
+
noOfPage: meta?.total_pages ?? 1,
|
|
441
|
+
page: meta?.page ?? 1
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
var emptyPage = () => ({ data: [], count: 0, pageSize: 0, noOfPage: 0, page: 1 });
|
|
445
|
+
|
|
139
446
|
// src/map.ts
|
|
140
447
|
var str = (v) => v === null || v === void 0 ? "" : String(v);
|
|
141
448
|
var arr = (v) => v ?? [];
|
|
@@ -143,7 +450,8 @@ var liveVariants = (p) => arr(p.variants).filter((v) => v.active);
|
|
|
143
450
|
function variantImages(v) {
|
|
144
451
|
const out = [];
|
|
145
452
|
for (const img of [v.image, ...arr(v.images)]) {
|
|
146
|
-
|
|
453
|
+
const url = mediaUrl(img?.url);
|
|
454
|
+
if (url && (img?.kind ?? "image") === "image" && !out.includes(url)) out.push(url);
|
|
147
455
|
}
|
|
148
456
|
return out;
|
|
149
457
|
}
|
|
@@ -152,7 +460,7 @@ function productImages(p) {
|
|
|
152
460
|
const push = (url) => {
|
|
153
461
|
if (url && !out.includes(url)) out.push(url);
|
|
154
462
|
};
|
|
155
|
-
push(p.image_url);
|
|
463
|
+
push(mediaUrl(p.image_url));
|
|
156
464
|
for (const v of arr(p.variants)) for (const url of variantImages(v)) push(url);
|
|
157
465
|
return out;
|
|
158
466
|
}
|
|
@@ -282,9 +590,9 @@ function fromSearchDoc(d) {
|
|
|
282
590
|
mrp: price,
|
|
283
591
|
minPrice: price,
|
|
284
592
|
maxPrice: minorToMajor(d.price_max_minor, d.currency),
|
|
285
|
-
thumbnail: d.image
|
|
286
|
-
image_url: d.image
|
|
287
|
-
images: d.image ?? "",
|
|
593
|
+
thumbnail: mediaUrl(d.image),
|
|
594
|
+
image_url: mediaUrl(d.image),
|
|
595
|
+
images: mediaUrl(d.image) ?? "",
|
|
288
596
|
stock: d.in_stock ? 1 : 0,
|
|
289
597
|
hasStock: d.in_stock,
|
|
290
598
|
// The index cannot say how much is left, only whether any is; a card
|
|
@@ -313,7 +621,7 @@ function toCategory(c) {
|
|
|
313
621
|
level: c.depth,
|
|
314
622
|
rank: c.position,
|
|
315
623
|
childCount: c.child_count,
|
|
316
|
-
thumbnail: c.metadata?.image
|
|
624
|
+
thumbnail: mediaUrl(c.metadata?.image),
|
|
317
625
|
description: c.metadata?.description ?? null,
|
|
318
626
|
isActive: true,
|
|
319
627
|
isFeatured: false,
|
|
@@ -333,7 +641,7 @@ function toCollection(c) {
|
|
|
333
641
|
description: c.description || null,
|
|
334
642
|
subTitle: null,
|
|
335
643
|
rank: str(c.position),
|
|
336
|
-
thumbnail: c.metadata?.image
|
|
644
|
+
thumbnail: mediaUrl(c.metadata?.image),
|
|
337
645
|
isActive: true,
|
|
338
646
|
metaTitle: c.title,
|
|
339
647
|
metaDescription: c.description || null,
|
|
@@ -416,7 +724,7 @@ function toCartLine(l, extra = {}) {
|
|
|
416
724
|
title: l.title,
|
|
417
725
|
name: l.title,
|
|
418
726
|
slug: extra.slug ?? "",
|
|
419
|
-
thumbnail: extra.thumbnail
|
|
727
|
+
thumbnail: mediaUrl(extra.thumbnail),
|
|
420
728
|
variantTitle: l.variant_label ?? "",
|
|
421
729
|
qty: l.quantity,
|
|
422
730
|
price: toMajor(l.unit_price),
|
|
@@ -524,8 +832,8 @@ function toOrderLine(l, currency) {
|
|
|
524
832
|
title: l.title,
|
|
525
833
|
name: l.title,
|
|
526
834
|
slug: "",
|
|
527
|
-
thumbnail: l.image_url
|
|
528
|
-
img: l.image_url
|
|
835
|
+
thumbnail: mediaUrl(l.image_url),
|
|
836
|
+
img: mediaUrl(l.image_url),
|
|
529
837
|
variantTitle: l.variant_label ?? "",
|
|
530
838
|
qty: l.quantity,
|
|
531
839
|
shippedQty: l.shipped_quantity,
|
|
@@ -625,335 +933,34 @@ function toVendor(v) {
|
|
|
625
933
|
id: str(v.id),
|
|
626
934
|
slug: v.slug,
|
|
627
935
|
name: v.name,
|
|
628
|
-
businessName: v.name,
|
|
629
|
-
about: v.about,
|
|
630
|
-
description: v.about,
|
|
631
|
-
website: v.website,
|
|
632
|
-
address: v.address,
|
|
633
|
-
banners: [],
|
|
634
|
-
rating: null
|
|
635
|
-
};
|
|
636
|
-
}
|
|
637
|
-
function toUser(c) {
|
|
638
|
-
const [firstName, ...rest] = (c.name ?? "").trim().split(/\s+/);
|
|
639
|
-
return {
|
|
640
|
-
id: str(c.id),
|
|
641
|
-
userId: str(c.id),
|
|
642
|
-
email: c.email,
|
|
643
|
-
emailVerified: c.email_verified,
|
|
644
|
-
phone: c.phone || null,
|
|
645
|
-
firstName: firstName || "",
|
|
646
|
-
lastName: rest.join(" "),
|
|
647
|
-
name: c.name,
|
|
648
|
-
fullName: c.name,
|
|
649
|
-
avatar: null,
|
|
650
|
-
role: "USER",
|
|
651
|
-
createdAt: c.created_at,
|
|
652
|
-
updatedAt: c.updated_at
|
|
653
|
-
};
|
|
654
|
-
}
|
|
655
|
-
var priceOf = (m) => m ? toMajor(m) : 0;
|
|
656
|
-
|
|
657
|
-
// src/browser.ts
|
|
658
|
-
var inBrowser = () => typeof window !== "undefined" && typeof document !== "undefined";
|
|
659
|
-
function readLocal(key) {
|
|
660
|
-
if (!inBrowser()) return null;
|
|
661
|
-
try {
|
|
662
|
-
return window.localStorage.getItem(key);
|
|
663
|
-
} catch {
|
|
664
|
-
return null;
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
function writeLocal(key, value) {
|
|
668
|
-
if (!inBrowser()) return;
|
|
669
|
-
try {
|
|
670
|
-
window.localStorage.setItem(key, value);
|
|
671
|
-
} catch {
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
function removeLocal(key) {
|
|
675
|
-
if (!inBrowser()) return;
|
|
676
|
-
try {
|
|
677
|
-
window.localStorage.removeItem(key);
|
|
678
|
-
} catch {
|
|
679
|
-
}
|
|
680
|
-
}
|
|
681
|
-
function readJSON(key) {
|
|
682
|
-
const raw = readLocal(key);
|
|
683
|
-
if (!raw) return null;
|
|
684
|
-
try {
|
|
685
|
-
return JSON.parse(raw);
|
|
686
|
-
} catch {
|
|
687
|
-
return null;
|
|
688
|
-
}
|
|
689
|
-
}
|
|
690
|
-
var YEAR = 60 * 60 * 24 * 365;
|
|
691
|
-
function setCookie(name, value, maxAge = YEAR) {
|
|
692
|
-
if (!inBrowser()) return;
|
|
693
|
-
document.cookie = `${name}=${value}; path=/; max-age=${maxAge}; samesite=lax`;
|
|
694
|
-
}
|
|
695
|
-
function clearCookie(name) {
|
|
696
|
-
if (!inBrowser()) return;
|
|
697
|
-
document.cookie = `${name}=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT`;
|
|
698
|
-
}
|
|
699
|
-
function readCookie(name) {
|
|
700
|
-
if (!inBrowser()) return null;
|
|
701
|
-
for (const pair of document.cookie.split(";")) {
|
|
702
|
-
const at = pair.indexOf("=");
|
|
703
|
-
if (at < 0) continue;
|
|
704
|
-
if (pair.slice(0, at).trim() === name) return pair.slice(at + 1).trim();
|
|
705
|
-
}
|
|
706
|
-
return null;
|
|
936
|
+
businessName: v.name,
|
|
937
|
+
about: v.about,
|
|
938
|
+
description: v.about,
|
|
939
|
+
website: v.website,
|
|
940
|
+
address: v.address,
|
|
941
|
+
banners: [],
|
|
942
|
+
rating: null
|
|
943
|
+
};
|
|
707
944
|
}
|
|
708
|
-
|
|
709
|
-
var sessionToken = () => readLocal(TOKEN);
|
|
710
|
-
function toMe(c) {
|
|
945
|
+
function toUser(c) {
|
|
711
946
|
const [firstName, ...rest] = (c.name ?? "").trim().split(/\s+/);
|
|
712
947
|
return {
|
|
713
|
-
id:
|
|
714
|
-
userId:
|
|
948
|
+
id: str(c.id),
|
|
949
|
+
userId: str(c.id),
|
|
715
950
|
email: c.email,
|
|
951
|
+
emailVerified: c.email_verified,
|
|
716
952
|
phone: c.phone || null,
|
|
717
953
|
firstName: firstName || "",
|
|
718
954
|
lastName: rest.join(" "),
|
|
719
|
-
name: c.name
|
|
720
|
-
fullName: c.name
|
|
955
|
+
name: c.name,
|
|
956
|
+
fullName: c.name,
|
|
721
957
|
avatar: null,
|
|
722
958
|
role: "USER",
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
};
|
|
726
|
-
}
|
|
727
|
-
function startSession(auth) {
|
|
728
|
-
writeLocal(TOKEN, auth.token);
|
|
729
|
-
const me = toMe(auth.record);
|
|
730
|
-
const expires = Math.max(60, Math.floor((Date.parse(auth.expires_at) - Date.now()) / 1e3)) || YEAR;
|
|
731
|
-
setCookie("me", encodeURIComponent(JSON.stringify(me)), expires);
|
|
732
|
-
setCookie("connect.sid", "gocommerce", expires);
|
|
733
|
-
return me;
|
|
734
|
-
}
|
|
735
|
-
function updateMe(c) {
|
|
736
|
-
const me = toMe(c);
|
|
737
|
-
setCookie("me", encodeURIComponent(JSON.stringify(me)));
|
|
738
|
-
return me;
|
|
739
|
-
}
|
|
740
|
-
function endSession() {
|
|
741
|
-
removeLocal(TOKEN);
|
|
742
|
-
clearCookie("me");
|
|
743
|
-
clearCookie("connect.sid");
|
|
744
|
-
}
|
|
745
|
-
function currentMe() {
|
|
746
|
-
const raw = readCookie("me");
|
|
747
|
-
if (!raw) return null;
|
|
748
|
-
try {
|
|
749
|
-
return JSON.parse(decodeURIComponent(raw));
|
|
750
|
-
} catch {
|
|
751
|
-
return null;
|
|
752
|
-
}
|
|
753
|
-
}
|
|
754
|
-
function storedCartId() {
|
|
755
|
-
const v = readLocal("cart_id");
|
|
756
|
-
if (!v || v === "undefined" || v === "null") return null;
|
|
757
|
-
return v;
|
|
758
|
-
}
|
|
759
|
-
var rememberCartId = (id2) => writeLocal("cart_id", id2);
|
|
760
|
-
var extrasKey = (cartId) => `gocommerce_cart_${cartId}`;
|
|
761
|
-
var cartExtras = (cartId) => readJSON(extrasKey(cartId)) ?? {};
|
|
762
|
-
function saveCartExtras(cartId, patch) {
|
|
763
|
-
const next = { ...cartExtras(cartId), ...patch };
|
|
764
|
-
writeLocal(extrasKey(cartId), JSON.stringify(next));
|
|
765
|
-
return next;
|
|
766
|
-
}
|
|
767
|
-
var forgetCartExtras = (cartId) => removeLocal(extrasKey(cartId));
|
|
768
|
-
var ORDERS = "gocommerce_orders";
|
|
769
|
-
var placedOrders = () => readJSON(ORDERS) ?? [];
|
|
770
|
-
function rememberOrder(o) {
|
|
771
|
-
const kept = placedOrders().filter((p) => p.number !== o.number);
|
|
772
|
-
writeLocal(ORDERS, JSON.stringify([o, ...kept].slice(0, 50)));
|
|
773
|
-
}
|
|
774
|
-
var placedOrder = (number) => placedOrders().find((p) => p.number === number);
|
|
775
|
-
var placedOrderForCart = (cartId) => placedOrders().find((p) => p.cartId === cartId);
|
|
776
|
-
var placedOrderByReference = (reference) => placedOrders().find((p) => p.reference === reference);
|
|
777
|
-
var WISHLIST = "gocommerce_wishlist";
|
|
778
|
-
var wishlistToken = () => readLocal(WISHLIST);
|
|
779
|
-
var rememberWishlistToken = (token) => writeLocal(WISHLIST, token);
|
|
780
|
-
var forgetWishlistToken = () => removeLocal(WISHLIST);
|
|
781
|
-
|
|
782
|
-
// src/services/base.service.ts
|
|
783
|
-
var BaseService = class _BaseService {
|
|
784
|
-
static _credentials = { apiUrl: "" };
|
|
785
|
-
_fetch;
|
|
786
|
-
constructor(fetchFn) {
|
|
787
|
-
this._fetch = fetchFn ?? ((input, init) => globalThis.fetch(input, init));
|
|
788
|
-
}
|
|
789
|
-
static setCredentials(creds) {
|
|
790
|
-
_BaseService._credentials = { ..._BaseService._credentials, ...creds };
|
|
791
|
-
}
|
|
792
|
-
static getCredentials() {
|
|
793
|
-
return _BaseService._credentials;
|
|
794
|
-
}
|
|
795
|
-
get creds() {
|
|
796
|
-
return _BaseService._credentials;
|
|
797
|
-
}
|
|
798
|
-
/**
|
|
799
|
-
* The engine's base URL from wherever this code runs. In the browser a
|
|
800
|
-
* configured proxy path wins, because the engine answers no CORS preflight.
|
|
801
|
-
*/
|
|
802
|
-
engineBase() {
|
|
803
|
-
const { apiUrl, proxyPath } = this.creds;
|
|
804
|
-
if (proxyPath && typeof window !== "undefined" && window.location) {
|
|
805
|
-
return new URL(proxyPath, window.location.origin).href.replace(/\/+$/, "");
|
|
806
|
-
}
|
|
807
|
-
const url = (apiUrl ?? "").trim();
|
|
808
|
-
if (!url) {
|
|
809
|
-
throw new GoCommerceError(
|
|
810
|
-
"PUBLIC_GOCOMMERCE_API_URL is not set, so this storefront does not know where its commerce engine is. Point it at a running GoCommerce, e.g. http://127.0.0.1:8080.",
|
|
811
|
-
0
|
|
812
|
-
);
|
|
813
|
-
}
|
|
814
|
-
return url.replace(/\/+$/, "");
|
|
815
|
-
}
|
|
816
|
-
/** An absolute engine URL for a path and query, without sending anything. */
|
|
817
|
-
engineURL(path, query) {
|
|
818
|
-
return this.engineBase() + path + qs(query);
|
|
819
|
-
}
|
|
820
|
-
/**
|
|
821
|
-
* One request to the engine, envelope and all.
|
|
822
|
-
*
|
|
823
|
-
* The body is read as text first, so a proxy's HTML error page is reported
|
|
824
|
-
* as what it is rather than as a JSON parse error three frames away.
|
|
825
|
-
*/
|
|
826
|
-
async engine(path, req = {}) {
|
|
827
|
-
const lang = (req.method ?? "GET") === "GET" ? this.creds.language : void 0;
|
|
828
|
-
const url = this.engineURL(path, lang ? { lang, ...req.query } : req.query);
|
|
829
|
-
const headers = { Accept: "application/json", ...req.headers };
|
|
830
|
-
if (req.body !== void 0) headers["Content-Type"] = "application/json";
|
|
831
|
-
if (this.creds.store) headers["X-Store"] = this.creds.store;
|
|
832
|
-
if (req.auth) {
|
|
833
|
-
const token = sessionToken();
|
|
834
|
-
if (!token) throw new GoCommerceError("Please sign in to continue.", 401, "unauthorized");
|
|
835
|
-
headers.Authorization = `Bearer ${token}`;
|
|
836
|
-
}
|
|
837
|
-
const init = {
|
|
838
|
-
method: req.method ?? "GET",
|
|
839
|
-
headers,
|
|
840
|
-
body: req.body === void 0 ? void 0 : JSON.stringify(req.body)
|
|
841
|
-
};
|
|
842
|
-
let res;
|
|
843
|
-
try {
|
|
844
|
-
res = await this._fetch.call(globalThis, url, init);
|
|
845
|
-
} catch (cause) {
|
|
846
|
-
if (typeof window === "undefined" && /CORS/i.test(String(cause?.message))) {
|
|
847
|
-
try {
|
|
848
|
-
res = await globalThis.fetch(url, init);
|
|
849
|
-
} catch (again) {
|
|
850
|
-
throw unreachable(this.engineBase(), again);
|
|
851
|
-
}
|
|
852
|
-
} else {
|
|
853
|
-
throw unreachable(this.engineBase(), cause);
|
|
854
|
-
}
|
|
855
|
-
}
|
|
856
|
-
return this.unwrap(res);
|
|
857
|
-
}
|
|
858
|
-
/** The envelope opened: the payload, or the engine's error as a GoCommerceError. */
|
|
859
|
-
async unwrap(res) {
|
|
860
|
-
const text = await res.text();
|
|
861
|
-
let parsed = null;
|
|
862
|
-
if (text) {
|
|
863
|
-
try {
|
|
864
|
-
parsed = JSON.parse(text);
|
|
865
|
-
} catch {
|
|
866
|
-
throw new GoCommerceError(
|
|
867
|
-
`The commerce engine answered ${res.status} with something that is not JSON: ${text.slice(0, 120)}`,
|
|
868
|
-
res.status
|
|
869
|
-
);
|
|
870
|
-
}
|
|
871
|
-
}
|
|
872
|
-
if (!res.ok) {
|
|
873
|
-
const err = parsed?.error ?? {};
|
|
874
|
-
throw new GoCommerceError(
|
|
875
|
-
err.message ?? `The commerce engine answered ${res.status}.`,
|
|
876
|
-
res.status,
|
|
877
|
-
err.code,
|
|
878
|
-
err.details
|
|
879
|
-
);
|
|
880
|
-
}
|
|
881
|
-
return parsed ?? { data: null };
|
|
882
|
-
}
|
|
883
|
-
/** The bare payload, for the many callers that never look at `meta`. */
|
|
884
|
-
async data(path, req = {}) {
|
|
885
|
-
return (await this.engine(path, req)).data;
|
|
886
|
-
}
|
|
887
|
-
/**
|
|
888
|
-
* Prices a cart at the signed-in shopper's customer-group prices. The
|
|
889
|
-
* engine does this only for an account whose email is confirmed (403
|
|
890
|
-
* otherwise), and the cart stays the shopper's either way — so a refusal
|
|
891
|
-
* is not an error, and neither is a build without ext/identity.
|
|
892
|
-
*/
|
|
893
|
-
async claimCartForAccount(cartId) {
|
|
894
|
-
try {
|
|
895
|
-
await this.engine("/x/identity/me/carts", { method: "POST", body: { cart_id: cartId }, auth: true });
|
|
896
|
-
} catch {
|
|
897
|
-
}
|
|
898
|
-
}
|
|
899
|
-
// ------------------------------------------------------------ Litekart verbs
|
|
900
|
-
/**
|
|
901
|
-
* The family's path-addressed verbs. An absolute URL is fetched as-is; a
|
|
902
|
-
* relative one is a Litekart REST path, answered from the storefront's own
|
|
903
|
-
* data where it has some and refused otherwise (rest-guard.ts).
|
|
904
|
-
*/
|
|
905
|
-
get(path) {
|
|
906
|
-
return this.raw("get", path);
|
|
907
|
-
}
|
|
908
|
-
post(path, data) {
|
|
909
|
-
return this.raw("post", path, data);
|
|
910
|
-
}
|
|
911
|
-
put(path, data) {
|
|
912
|
-
return this.raw("put", path, data);
|
|
913
|
-
}
|
|
914
|
-
patch(path, data) {
|
|
915
|
-
return this.raw("patch", path, data);
|
|
916
|
-
}
|
|
917
|
-
delete(path) {
|
|
918
|
-
return this.raw("delete", path);
|
|
919
|
-
}
|
|
920
|
-
async raw(method, path, data) {
|
|
921
|
-
if (!/^https?:\/\//i.test(path)) return await resolveRestLocally(method, path);
|
|
922
|
-
const res = await this._fetch.call(globalThis, path, {
|
|
923
|
-
method: method.toUpperCase(),
|
|
924
|
-
headers: { Accept: "application/json", ...data === void 0 ? {} : { "Content-Type": "application/json" } },
|
|
925
|
-
body: data === void 0 ? void 0 : JSON.stringify(data)
|
|
926
|
-
});
|
|
927
|
-
const body = await res.json().catch(() => ({}));
|
|
928
|
-
if (!res.ok)
|
|
929
|
-
throw new GoCommerceError(body?.error?.message ?? `Request failed with status ${res.status}`, res.status);
|
|
930
|
-
return body;
|
|
931
|
-
}
|
|
932
|
-
};
|
|
933
|
-
var unreachable = (base, cause) => new GoCommerceError(`Could not reach the commerce engine at ${base}: ${cause?.message ?? cause}`, 0);
|
|
934
|
-
function qs(query) {
|
|
935
|
-
if (!query) return "";
|
|
936
|
-
const sp = new URLSearchParams();
|
|
937
|
-
for (const [key, value] of Object.entries(query)) {
|
|
938
|
-
if (value === void 0 || value === null || value === "") continue;
|
|
939
|
-
if (Array.isArray(value)) for (const v of value) sp.append(key, String(v));
|
|
940
|
-
else sp.append(key, String(value));
|
|
941
|
-
}
|
|
942
|
-
const s = sp.toString();
|
|
943
|
-
return s ? `?${s}` : "";
|
|
944
|
-
}
|
|
945
|
-
function toPage(env, map) {
|
|
946
|
-
const rows = env.data ?? [];
|
|
947
|
-
const meta = env.meta;
|
|
948
|
-
return {
|
|
949
|
-
data: rows.map(map),
|
|
950
|
-
count: meta?.total ?? rows.length,
|
|
951
|
-
pageSize: meta?.limit ?? rows.length,
|
|
952
|
-
noOfPage: meta?.total_pages ?? 1,
|
|
953
|
-
page: meta?.page ?? 1
|
|
959
|
+
createdAt: c.created_at,
|
|
960
|
+
updatedAt: c.updated_at
|
|
954
961
|
};
|
|
955
962
|
}
|
|
956
|
-
var
|
|
963
|
+
var priceOf = (m) => m ? toMajor(m) : 0;
|
|
957
964
|
|
|
958
965
|
// src/services/facts.ts
|
|
959
966
|
var StoreFacts = class extends BaseService {
|
|
@@ -1971,7 +1978,7 @@ var OrderService = class extends BaseService {
|
|
|
1971
1978
|
productId: l.product_id,
|
|
1972
1979
|
variantId: l.variant_id,
|
|
1973
1980
|
title: l.title,
|
|
1974
|
-
img: l.image_url
|
|
1981
|
+
img: mediaUrl(l.image_url),
|
|
1975
1982
|
price: toMajor(l.unit_price),
|
|
1976
1983
|
qty: l.quantity
|
|
1977
1984
|
});
|
|
@@ -3069,6 +3076,6 @@ function attemptKey(request) {
|
|
|
3069
3076
|
}
|
|
3070
3077
|
var b2bService = new B2bService();
|
|
3071
3078
|
|
|
3072
|
-
export { AddressService, AuthService, AutocompleteService, B2bService, BannerService, BaseService, BlogService, CartService, CatalogService, CategoryService, ChatService, CheckoutService, CollectionService, ContactService, CountryService, CouponService, CurrencyService, DealService, DemoRequestService, EnquiryService, FaqService, FeedbackService, GalleryService, GoCommerceError, HomeService, InitService, MeilisearchService, MenuService, NewsletterService, NotSupportedError, OrderService, PageService, PaymentMethodService, PluginService, PluginService as PluginsService, PopularSearchService, PopularityService, ProductService, ProfileService, REDIRECT_GATEWAYS, ReelsService, RegionService, ReviewService, SearchService, SettingService, SettingService as SettingsService, StateService, StoreService, UploadService, UserService, VariantService, VarniCustomDesignService, VarniCustomProductService, VendorService, WarrantyService, WishlistService, addressService, authService, autocompleteService, b2bService, bannerService, blogService, cartService, categoryService, chatService, checkoutService, forgetAll as clearStoreCache, collectionService, connectorName, contactService, countryService, couponService, currencyExponent, currencyService, dealService, demoRequestService, emptyCart, emptyPage, enquiryService, faqService, feedbackService, fromEngineAddress, fromIdentityAddress, fromSearchDoc, galleryService, hasStaticStore, homeService, initService, meilisearchService, menuService, minorToMajor, newsletterService, orderService, pageService, paymentMethodService, pluginService, pluginsService, popularSearchService, popularityService, priceOf, productImages, productService, profileService, qs, readStaticStore, reelsService, regionService, reviewService, searchService, serveRestLocally, setStaticStore, settingService, settingsService, stateService, staticStore, storeService, toCart, toCartLine, toCategory, toCmsPage, toCollection, toEngineAddress, toIdentityAddress, toMajor, toMinor, toOrder, toPage, toProduct, toRating, toUser, toVariant, toVendor, uploadService, userService, variantService, varniCustomDesignService, varniCustomProductService, vendorService, warrantyService, wishlistService };
|
|
3079
|
+
export { AddressService, AuthService, AutocompleteService, B2bService, BannerService, BaseService, BlogService, CartService, CatalogService, CategoryService, ChatService, CheckoutService, CollectionService, ContactService, CountryService, CouponService, CurrencyService, DealService, DemoRequestService, EnquiryService, FaqService, FeedbackService, GalleryService, GoCommerceError, HomeService, InitService, MeilisearchService, MenuService, NewsletterService, NotSupportedError, OrderService, PageService, PaymentMethodService, PluginService, PluginService as PluginsService, PopularSearchService, PopularityService, ProductService, ProfileService, REDIRECT_GATEWAYS, ReelsService, RegionService, ReviewService, SearchService, SettingService, SettingService as SettingsService, StateService, StoreService, UploadService, UserService, VariantService, VarniCustomDesignService, VarniCustomProductService, VendorService, WarrantyService, WishlistService, addressService, authService, autocompleteService, b2bService, bannerService, blogService, cartService, categoryService, chatService, checkoutService, forgetAll as clearStoreCache, collectionService, connectorName, contactService, countryService, couponService, currencyExponent, currencyService, dealService, demoRequestService, emptyCart, emptyPage, enquiryService, faqService, feedbackService, fromEngineAddress, fromIdentityAddress, fromSearchDoc, galleryService, hasStaticStore, homeService, initService, mediaUrl, meilisearchService, menuService, minorToMajor, newsletterService, orderService, pageService, paymentMethodService, pluginService, pluginsService, popularSearchService, popularityService, priceOf, productImages, productService, profileService, qs, readStaticStore, reelsService, regionService, reviewService, searchService, serveRestLocally, setStaticStore, settingService, settingsService, stateService, staticStore, storeService, toCart, toCartLine, toCategory, toCmsPage, toCollection, toEngineAddress, toIdentityAddress, toMajor, toMinor, toOrder, toPage, toProduct, toRating, toUser, toVariant, toVendor, uploadService, userService, variantService, varniCustomDesignService, varniCustomProductService, vendorService, warrantyService, wishlistService };
|
|
3073
3080
|
//# sourceMappingURL=index.js.map
|
|
3074
3081
|
//# sourceMappingURL=index.js.map
|