react-shopwave-connect 0.4.2 → 0.4.4

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.
@@ -274,6 +274,74 @@ function safeEqual(a, b) {
274
274
  return diff === 0;
275
275
  }
276
276
 
277
+ //#endregion
278
+ //#region src/core/resources.ts
279
+ /**
280
+ * - merchant: `GET /merchant`; `POST /merchant` with `{ merchant: { id, … } }`
281
+ * updates it (without an `id` the API would create a second merchant, so the
282
+ * route requires one).
283
+ * - user: `GET /user` (read-only here; the API's `POST /user` invites users and
284
+ * needs the admin scope).
285
+ */
286
+ const SHOPWAVE_RESOURCES = Object.freeze({
287
+ merchant: {
288
+ route: "merchant",
289
+ key: "merchant",
290
+ upstream: "merchant",
291
+ writable: true
292
+ },
293
+ user: {
294
+ route: "user",
295
+ key: "user",
296
+ upstream: "user",
297
+ writable: false
298
+ }
299
+ });
300
+ /** `UploadKind` → the API's `contentType` value. */
301
+ const UPLOAD_KINDS = Object.freeze({
302
+ merchant: "merchant",
303
+ merchantFeature: "merchantFeature",
304
+ product: "product",
305
+ user: "user",
306
+ applicationLogo: "applicaionLogo",
307
+ applicationImages: "applicaionImages"
308
+ });
309
+ /** Every `UploadPrefix`, longest first so a name check never takes `product` for `product_thumbnail`. */
310
+ const UPLOAD_PREFIXES = Object.freeze([
311
+ "product_thumbnail",
312
+ "variant_thumbnail",
313
+ "product",
314
+ "variant"
315
+ ]);
316
+ /** How uploads are addressed (app route and Shopwave uploader). */
317
+ const SHOPWAVE_UPLOAD = Object.freeze({
318
+ route: "upload",
319
+ upstream: "uploader",
320
+ kindHeader: "contentType",
321
+ prefixHeader: "prefix",
322
+ fileField: "file",
323
+ kindField: "kind",
324
+ prefixField: "prefix"
325
+ });
326
+ function isUploadKind(value) {
327
+ return typeof value === "string" && Object.prototype.hasOwnProperty.call(UPLOAD_KINDS, value);
328
+ }
329
+ function isUploadPrefix(value) {
330
+ return typeof value === "string" && UPLOAD_PREFIXES.includes(value);
331
+ }
332
+ const SHOPWAVE_LOOKUPS = Object.freeze({
333
+ productTags: {
334
+ route: "products/tags",
335
+ key: "tags",
336
+ upstream: "product/tags"
337
+ },
338
+ productInstanceTags: {
339
+ route: "products/instance-tags",
340
+ key: "tags",
341
+ upstream: "product/instance/tags"
342
+ }
343
+ });
344
+
277
345
  //#endregion
278
346
  //#region src/core/entities.ts
279
347
  /**
@@ -350,50 +418,6 @@ const SHOPWAVE_ENTITIES = Object.freeze({
350
418
  }
351
419
  });
352
420
 
353
- //#endregion
354
- //#region src/core/resources.ts
355
- /**
356
- * - merchant: `GET /merchant`; `POST /merchant` with `{ merchant: { id, … } }`
357
- * updates it (without an `id` the API would create a second merchant, so the
358
- * route requires one).
359
- * - user: `GET /user` (read-only here; the API's `POST /user` invites users and
360
- * needs the admin scope).
361
- */
362
- const SHOPWAVE_RESOURCES = Object.freeze({
363
- merchant: {
364
- route: "merchant",
365
- key: "merchant",
366
- upstream: "merchant",
367
- writable: true
368
- },
369
- user: {
370
- route: "user",
371
- key: "user",
372
- upstream: "user",
373
- writable: false
374
- }
375
- });
376
- /** `UploadKind` → the API's `contentType` value. */
377
- const UPLOAD_KINDS = Object.freeze({
378
- merchant: "merchant",
379
- merchantFeature: "merchantFeature",
380
- product: "product",
381
- user: "user",
382
- applicationLogo: "applicaionLogo",
383
- applicationImages: "applicaionImages"
384
- });
385
- /** How uploads are addressed (app route and Shopwave uploader). */
386
- const SHOPWAVE_UPLOAD = Object.freeze({
387
- route: "upload",
388
- upstream: "uploader",
389
- kindHeader: "contentType",
390
- fileField: "file",
391
- kindField: "kind"
392
- });
393
- function isUploadKind(value) {
394
- return typeof value === "string" && Object.prototype.hasOwnProperty.call(UPLOAD_KINDS, value);
395
- }
396
-
397
421
  //#endregion
398
422
  //#region src/server/api.ts
399
423
  /**
@@ -722,6 +746,8 @@ function createShopwaveApiHandlers(config) {
722
746
  if (!file || typeof file === "string" || file.size === 0) return jsonError(400, "invalid_body", `Missing "${SHOPWAVE_UPLOAD.fileField}"`);
723
747
  const kind = form.get(SHOPWAVE_UPLOAD.kindField);
724
748
  if (!isUploadKind(kind)) return jsonError(400, "invalid_body", `"${SHOPWAVE_UPLOAD.kindField}" must be one of ${Object.keys(UPLOAD_KINDS).join(", ")}`);
749
+ const prefix = form.get(SHOPWAVE_UPLOAD.prefixField);
750
+ if (prefix !== null && !isUploadPrefix(prefix)) return jsonError(400, "invalid_body", `"${SHOPWAVE_UPLOAD.prefixField}" must be one of ${UPLOAD_PREFIXES.join(", ")}`);
725
751
  if (file.size > maxBytes) return jsonError(413, "too_large", `The file is larger than ${maxBytes} bytes`);
726
752
  if (!acceptsType(file.type || "", accept)) return jsonError(415, "unsupported_type", `Files of type "${file.type || "unknown"}" aren't accepted`);
727
753
  const upstreamForm = new FormData();
@@ -729,7 +755,10 @@ function createShopwaveApiHandlers(config) {
729
755
  return forward(request, {
730
756
  method: "PUT",
731
757
  path: SHOPWAVE_UPLOAD.upstream,
732
- headers: { [SHOPWAVE_UPLOAD.kindHeader]: UPLOAD_KINDS[kind] },
758
+ headers: {
759
+ [SHOPWAVE_UPLOAD.kindHeader]: UPLOAD_KINDS[kind],
760
+ ...prefix !== null ? { [SHOPWAVE_UPLOAD.prefixHeader]: prefix } : {}
761
+ },
733
762
  formData: upstreamForm,
734
763
  forwardExtras: false
735
764
  });
@@ -834,6 +863,14 @@ function createShopwaveApiHandlers(config) {
834
863
  passthrough(path) {
835
864
  return { GET: (request) => forward(request, { path }) };
836
865
  },
866
+ lookup(kind) {
867
+ const def = SHOPWAVE_LOOKUPS[kind];
868
+ if (!def) throw new Error(`Unknown Shopwave lookup "${kind}"`);
869
+ return { GET: (request) => forward(request, {
870
+ path: def.upstream,
871
+ forwardExtras: false
872
+ }) };
873
+ },
837
874
  resource(kind) {
838
875
  const def = resourceDef(kind);
839
876
  const save = (request) => writeResource(request, def);
@@ -1176,6 +1213,9 @@ function createShopwaveAuth(config) {
1176
1213
  * export const { GET } = shopwave.resource("user");
1177
1214
  * // app/api/upload/route.ts
1178
1215
  * export const { POST } = shopwave.upload();
1216
+ * // app/api/products/tags/route.ts, app/api/products/instance-tags/route.ts
1217
+ * export const { GET } = shopwave.lookup("productTags");
1218
+ * export const { GET } = shopwave.lookup("productInstanceTags");
1179
1219
  * ```
1180
1220
  */
1181
1221
  function createShopwaveApi(config) {
@@ -1189,9 +1229,11 @@ function createShopwaveApi(config) {
1189
1229
 
1190
1230
  //#endregion
1191
1231
  exports.SHOPWAVE_ENTITIES = SHOPWAVE_ENTITIES;
1232
+ exports.SHOPWAVE_LOOKUPS = SHOPWAVE_LOOKUPS;
1192
1233
  exports.SHOPWAVE_RESOURCES = SHOPWAVE_RESOURCES;
1193
1234
  exports.ShopwaveAuthError = ShopwaveAuthError;
1194
1235
  exports.UPLOAD_KINDS = UPLOAD_KINDS;
1236
+ exports.UPLOAD_PREFIXES = UPLOAD_PREFIXES;
1195
1237
  exports.authorizationHeader = authorizationHeader;
1196
1238
  exports.createShopwaveApi = createShopwaveApi;
1197
1239
  exports.createShopwaveAuth = createShopwaveAuth;