react-shopwave-connect 0.4.1 → 0.4.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/README.md +17 -5
- package/dist/core/index.cjs +119 -48
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +80 -9
- package/dist/core/index.d.ts +80 -9
- package/dist/core/index.js +116 -49
- package/dist/core/index.js.map +1 -1
- package/dist/hooks/index.cjs +129 -44
- package/dist/hooks/index.cjs.map +1 -1
- package/dist/hooks/index.d.cts +21 -1
- package/dist/hooks/index.d.ts +21 -1
- package/dist/hooks/index.js +128 -45
- package/dist/hooks/index.js.map +1 -1
- package/dist/index.cjs +148 -48
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +100 -9
- package/dist/index.d.ts +100 -9
- package/dist/index.js +143 -49
- package/dist/index.js.map +1 -1
- package/dist/next/index.cjs +83 -2
- package/dist/next/index.cjs.map +1 -1
- package/dist/next/index.d.cts +63 -7
- package/dist/next/index.d.ts +63 -7
- package/dist/next/index.js +83 -3
- package/dist/next/index.js.map +1 -1
- package/dist/server/index.cjs +80 -2
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +60 -7
- package/dist/server/index.d.ts +60 -7
- package/dist/server/index.js +80 -3
- package/dist/server/index.js.map +1 -1
- package/package.json +1 -1
package/dist/next/index.cjs
CHANGED
|
@@ -281,7 +281,10 @@ function safeEqual(a, b) {
|
|
|
281
281
|
* (https://developer.merchantstack.com/api-reference.html) and checked against
|
|
282
282
|
* the live API where noted:
|
|
283
283
|
* - category/product/store: GET filtered by `<x>Ids`, POST upsert, DELETE with `<x>Id` → 205.
|
|
284
|
-
* - promotion: no DELETE;
|
|
284
|
+
* - promotion: no DELETE; promotions are never deleted, only expired. Expiring
|
|
285
|
+
* reads the promotion and saves the whole record back with `endDate` = now (and
|
|
286
|
+
* `startDate` = now too if it hadn't started); the live API rejects a partial
|
|
287
|
+
* `{ id, endDate }` save with error 899. Dates are UTC `YYYY-MM-DD HH:mm:ss`.
|
|
285
288
|
* - employee: POST updates `roleId`, `joinedDate`, `exitDate` (names can't be
|
|
286
289
|
* changed); no DELETE (live API: "Cannot DELETE /employee") → retired via `exitDate`.
|
|
287
290
|
* - consumer: read-only (`GET` with `ids`, comma-separated); live POST → 404.
|
|
@@ -322,7 +325,9 @@ const SHOPWAVE_ENTITIES = Object.freeze({
|
|
|
322
325
|
idHeader: "promotionId",
|
|
323
326
|
writable: true,
|
|
324
327
|
deleteMode: "retire",
|
|
325
|
-
retireField: "endDate"
|
|
328
|
+
retireField: "endDate",
|
|
329
|
+
retireWithRecord: true,
|
|
330
|
+
retireStartField: "startDate"
|
|
326
331
|
},
|
|
327
332
|
employee: {
|
|
328
333
|
route: "employees",
|
|
@@ -388,6 +393,18 @@ const SHOPWAVE_UPLOAD = Object.freeze({
|
|
|
388
393
|
function isUploadKind(value) {
|
|
389
394
|
return typeof value === "string" && Object.prototype.hasOwnProperty.call(UPLOAD_KINDS, value);
|
|
390
395
|
}
|
|
396
|
+
const SHOPWAVE_LOOKUPS = Object.freeze({
|
|
397
|
+
productTags: {
|
|
398
|
+
route: "products/tags",
|
|
399
|
+
key: "tags",
|
|
400
|
+
upstream: "product/tags"
|
|
401
|
+
},
|
|
402
|
+
productInstanceTags: {
|
|
403
|
+
route: "products/instance-tags",
|
|
404
|
+
key: "tags",
|
|
405
|
+
upstream: "product/instance/tags"
|
|
406
|
+
}
|
|
407
|
+
});
|
|
391
408
|
|
|
392
409
|
//#endregion
|
|
393
410
|
//#region src/server/api.ts
|
|
@@ -521,6 +538,18 @@ function jsonError(status, error, message) {
|
|
|
521
538
|
function shopwaveDateTime(date = /* @__PURE__ */ new Date()) {
|
|
522
539
|
return date.toISOString().slice(0, 19).replace("T", " ");
|
|
523
540
|
}
|
|
541
|
+
/**
|
|
542
|
+
* Reads a Shopwave datetime: ISO with a zone (what reads return, e.g.
|
|
543
|
+
* `2026-10-20T16:00:00.000Z`) or a zoneless `YYYY-MM-DD HH:mm:ss`, which is UTC.
|
|
544
|
+
* `null` when the value isn't a date.
|
|
545
|
+
*/
|
|
546
|
+
function parseShopwaveDateTime(value) {
|
|
547
|
+
if (typeof value !== "string" || !value.trim()) return null;
|
|
548
|
+
const text = value.trim();
|
|
549
|
+
const zoneless = /^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}(:\d{2}(\.\d+)?)?$/.test(text);
|
|
550
|
+
const date = new Date(zoneless ? `${text.replace(" ", "T")}Z` : text);
|
|
551
|
+
return Number.isNaN(date.getTime()) ? null : date;
|
|
552
|
+
}
|
|
524
553
|
const NULL_BODY_STATUS = new Set([
|
|
525
554
|
101,
|
|
526
555
|
103,
|
|
@@ -720,6 +749,45 @@ function createShopwaveApiHandlers(config) {
|
|
|
720
749
|
function badId() {
|
|
721
750
|
return jsonError(400, "invalid_id", "Missing or invalid id");
|
|
722
751
|
}
|
|
752
|
+
/**
|
|
753
|
+
* Retires a record the API won't take a partial save for (promotions): reads it,
|
|
754
|
+
* sets `field` to now (and `def.retireStartField` to now too when the record
|
|
755
|
+
* hasn't started yet), and POSTs the whole record back. Both dates are sent as
|
|
756
|
+
* UTC `YYYY-MM-DD HH:mm:ss`; reads return them as ISO with `Z`.
|
|
757
|
+
*/
|
|
758
|
+
async function retireWithRecord(request, def, id, field) {
|
|
759
|
+
const read = await forward(request, {
|
|
760
|
+
path: def.upstream,
|
|
761
|
+
headers: { [def.idsHeader]: id },
|
|
762
|
+
forwardExtras: false
|
|
763
|
+
});
|
|
764
|
+
if (!read.ok) return read;
|
|
765
|
+
let body;
|
|
766
|
+
try {
|
|
767
|
+
body = await read.json();
|
|
768
|
+
} catch {
|
|
769
|
+
return jsonError(502, "invalid_upstream", `The Shopwave API's ${def.upstream} read wasn't JSON`);
|
|
770
|
+
}
|
|
771
|
+
const map = isPlainObject(body) && isPlainObject(body[def.collection]) ? body[def.collection] : {};
|
|
772
|
+
const record = Object.values(map).find((entry) => isPlainObject(entry) && String(entry.id) === id);
|
|
773
|
+
if (!record) return jsonError(404, "not_found", `No ${def.upstream} with id ${id}`);
|
|
774
|
+
const now = /* @__PURE__ */ new Date();
|
|
775
|
+
const retired = {
|
|
776
|
+
...record,
|
|
777
|
+
[field]: shopwaveDateTime(now)
|
|
778
|
+
};
|
|
779
|
+
const startField = def.retireStartField;
|
|
780
|
+
if (startField) {
|
|
781
|
+
const start = parseShopwaveDateTime(record[startField]);
|
|
782
|
+
if (start) retired[startField] = shopwaveDateTime(start > now ? now : start);
|
|
783
|
+
}
|
|
784
|
+
return forward(request, {
|
|
785
|
+
method: "POST",
|
|
786
|
+
path: def.upstream,
|
|
787
|
+
postBody: { [def.collection]: { 0: retired } },
|
|
788
|
+
forwardExtras: false
|
|
789
|
+
});
|
|
790
|
+
}
|
|
723
791
|
return {
|
|
724
792
|
forward,
|
|
725
793
|
entity,
|
|
@@ -755,6 +823,7 @@ function createShopwaveApiHandlers(config) {
|
|
|
755
823
|
if (def.deleteMode === "none") return notSupported(def, "deletes");
|
|
756
824
|
if (def.deleteMode === "retire") {
|
|
757
825
|
const field = def.retireField ?? "exitDate";
|
|
826
|
+
if (def.retireWithRecord) return retireWithRecord(request, def, id, field);
|
|
758
827
|
return forward(request, {
|
|
759
828
|
method: "POST",
|
|
760
829
|
path: def.upstream,
|
|
@@ -777,6 +846,14 @@ function createShopwaveApiHandlers(config) {
|
|
|
777
846
|
passthrough(path) {
|
|
778
847
|
return { GET: (request) => forward(request, { path }) };
|
|
779
848
|
},
|
|
849
|
+
lookup(kind) {
|
|
850
|
+
const def = SHOPWAVE_LOOKUPS[kind];
|
|
851
|
+
if (!def) throw new Error(`Unknown Shopwave lookup "${kind}"`);
|
|
852
|
+
return { GET: (request) => forward(request, {
|
|
853
|
+
path: def.upstream,
|
|
854
|
+
forwardExtras: false
|
|
855
|
+
}) };
|
|
856
|
+
},
|
|
780
857
|
resource(kind) {
|
|
781
858
|
const def = resourceDef(kind);
|
|
782
859
|
const save = (request) => writeResource(request, def);
|
|
@@ -1119,6 +1196,9 @@ function createShopwaveAuth(config) {
|
|
|
1119
1196
|
* export const { GET } = shopwave.resource("user");
|
|
1120
1197
|
* // app/api/upload/route.ts
|
|
1121
1198
|
* export const { POST } = shopwave.upload();
|
|
1199
|
+
* // app/api/products/tags/route.ts, app/api/products/instance-tags/route.ts
|
|
1200
|
+
* export const { GET } = shopwave.lookup("productTags");
|
|
1201
|
+
* export const { GET } = shopwave.lookup("productInstanceTags");
|
|
1122
1202
|
* ```
|
|
1123
1203
|
*/
|
|
1124
1204
|
function createShopwaveApi(config) {
|
|
@@ -1132,6 +1212,7 @@ function createShopwaveApi(config) {
|
|
|
1132
1212
|
|
|
1133
1213
|
//#endregion
|
|
1134
1214
|
exports.SHOPWAVE_ENTITIES = SHOPWAVE_ENTITIES;
|
|
1215
|
+
exports.SHOPWAVE_LOOKUPS = SHOPWAVE_LOOKUPS;
|
|
1135
1216
|
exports.SHOPWAVE_RESOURCES = SHOPWAVE_RESOURCES;
|
|
1136
1217
|
exports.ShopwaveAuthError = ShopwaveAuthError;
|
|
1137
1218
|
exports.UPLOAD_KINDS = UPLOAD_KINDS;
|