react-shopwave-connect 0.4.5 → 0.4.7
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 +19 -11
- package/dist/core/index.cjs +281 -137
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +307 -160
- package/dist/core/index.d.ts +307 -160
- package/dist/core/index.js +276 -138
- package/dist/core/index.js.map +1 -1
- package/dist/hooks/index.cjs +268 -115
- package/dist/hooks/index.cjs.map +1 -1
- package/dist/hooks/index.d.cts +96 -29
- package/dist/hooks/index.d.ts +96 -29
- package/dist/hooks/index.js +268 -116
- package/dist/hooks/index.js.map +1 -1
- package/dist/index.cjs +301 -137
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +316 -160
- package/dist/index.d.ts +316 -160
- package/dist/index.js +295 -138
- package/dist/index.js.map +1 -1
- package/dist/next/index.cjs +69 -2
- package/dist/next/index.cjs.map +1 -1
- package/dist/next/index.d.cts +36 -5
- package/dist/next/index.d.ts +36 -5
- package/dist/next/index.js +69 -2
- package/dist/next/index.js.map +1 -1
- package/dist/server/index.cjs +70 -2
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +45 -8
- package/dist/server/index.d.ts +45 -8
- package/dist/server/index.js +70 -3
- package/dist/server/index.js.map +1 -1
- package/package.json +5 -1
package/dist/server/index.d.cts
CHANGED
|
@@ -37,7 +37,7 @@ declare const SHOPWAVE_TOKEN_EXPIRED_ERROR_ID = 908;
|
|
|
37
37
|
declare function tokenFromResponse(response: ShopwaveTokenResponse, previous?: ShopwaveToken, now?: number): ShopwaveToken | null;
|
|
38
38
|
/**
|
|
39
39
|
* Reads a token from session storage. Accepts both the current shape and the
|
|
40
|
-
* legacy raw response that older apps
|
|
40
|
+
* legacy raw response that older apps stored directly in
|
|
41
41
|
* the session, so existing sessions survive an upgrade.
|
|
42
42
|
*/
|
|
43
43
|
declare function normalizeStoredToken(raw: unknown): ShopwaveToken | null;
|
|
@@ -215,8 +215,15 @@ interface EntityDefinition {
|
|
|
215
215
|
* start = end and the record is expired without ever running.
|
|
216
216
|
*/
|
|
217
217
|
retireStartField?: string;
|
|
218
|
+
/**
|
|
219
|
+
* Header naming child records to delete instead of the whole record
|
|
220
|
+
* (`productComponentInstanceIds: 1,2`). Only `item()` DELETE uses it, and only when
|
|
221
|
+
* the caller's `extras` carry this one key (a non-empty list of ids); every other
|
|
222
|
+
* `extras` key is still dropped. Only for `deleteMode: "delete"`.
|
|
223
|
+
*/
|
|
224
|
+
childIdsHeader?: string;
|
|
218
225
|
}
|
|
219
|
-
type EntityKind = "product" | "category" | "store" | "promotion" | "employee" | "consumer";
|
|
226
|
+
type EntityKind = "product" | "category" | "store" | "promotion" | "employee" | "consumer" | "productComponent";
|
|
220
227
|
/** Entities that can be created/updated through the API. */
|
|
221
228
|
type WritableEntityKind = Exclude<EntityKind, "consumer">;
|
|
222
229
|
/** Entities that can be deleted (or retired) through the API. */
|
|
@@ -233,6 +240,27 @@ type DeletableEntityKind = Exclude<EntityKind, "consumer">;
|
|
|
233
240
|
* - employee: POST updates `roleId`, `joinedDate`, `exitDate` (names can't be
|
|
234
241
|
* changed); no DELETE (live API: "Cannot DELETE /employee") → retired via `exitDate`.
|
|
235
242
|
* - consumer: read-only (`GET` with `ids`, comma-separated); live POST → 404.
|
|
243
|
+
* - productComponent: modifier groups, `/product/component` (live, staging, 11 Nov 2026). The
|
|
244
|
+
* API reference lists no read filters; these are what the live API does:
|
|
245
|
+
* - Reads filter by `componentIds` (group ids) or `productIds` (the parent product; option
|
|
246
|
+
* products don't match). `productComponentIds` is ignored on reads: every group comes back.
|
|
247
|
+
* `deleted: false` gives live groups only, `true` deleted groups only, no header both.
|
|
248
|
+
* No match → 204 with an empty body. No order, sort, priority or position field anywhere.
|
|
249
|
+
* - Groups are keyed by id; `products` (option products) by product id; `productInstances`
|
|
250
|
+
* (option rows) by row id. Reads reformat values: price `"100"` → `"100.0"`,
|
|
251
|
+
* vatPercentage `"0.2000"` → `"0.200"`. `tags` and `name` are stored as sent (no trimming;
|
|
252
|
+
* a `tags` array is joined with commas; `tags` null or left out → null).
|
|
253
|
+
* - POST upserts (201, echoed under the ref). For each option product in `products`, its rows
|
|
254
|
+
* are replaced: every row sent is created afresh with a new id (a row `id` is ignored, also
|
|
255
|
+
* on a price change) and rows left out are removed. Option products left out of the save
|
|
256
|
+
* are untouched, and an empty `productInstances` removes nothing. A save without `products`
|
|
257
|
+
* updates only the group's own fields. The echo isn't proof of what was stored: renames of
|
|
258
|
+
* groups created moments earlier by a test run echoed the new name but never stuck (re-read
|
|
259
|
+
* for 90 s), while older groups, and groups created in Shopwave's own admin, renamed at
|
|
260
|
+
* once. Cause not yet known.
|
|
261
|
+
* - DELETE with `productComponentIds` (plural, comma list) → 205, soft delete. Adding
|
|
262
|
+
* `productComponentInstanceIds` deletes just those rows (205); they stay in live reads with
|
|
263
|
+
* `deleteDate` set. The singular `productComponentId` hangs (504 after 60 s).
|
|
236
264
|
*/
|
|
237
265
|
declare const SHOPWAVE_ENTITIES: Readonly<Record<EntityKind, EntityDefinition>>;
|
|
238
266
|
//#endregion
|
|
@@ -278,8 +306,8 @@ declare const UPLOAD_KINDS: Readonly<Record<UploadKind, string>>;
|
|
|
278
306
|
/**
|
|
279
307
|
* The role an image plays, sent to Shopwave as the uploader's `prefix` header.
|
|
280
308
|
* The uploader names the file `<prefix>_<hash>.<ext>`, so the role travels with
|
|
281
|
-
* the file wherever a record stores it (a product's `images`). Live,
|
|
282
|
-
*
|
|
309
|
+
* the file wherever a record stores it (a product's `images`). Live, test
|
|
310
|
+
* merchant, 4 Nov 2026: all four values answered 201.
|
|
283
311
|
* - `product`: a product gallery image;
|
|
284
312
|
* - `product_thumbnail`: the product's lead image, shown in lists;
|
|
285
313
|
* - `variant` / `variant_thumbnail`: a variant's own image and its lead image
|
|
@@ -318,7 +346,7 @@ declare const SHOPWAVE_UPLOAD: Readonly<{
|
|
|
318
346
|
* on the merchant's products. No parameters. The API reference says
|
|
319
347
|
* "internal SKU tags are excluded", but the live API includes system tags
|
|
320
348
|
* written by imports and syncs (`PID-133`, `VID-137`, `#Hash:…`, `upc-…`;
|
|
321
|
-
* test merchant
|
|
349
|
+
* a test merchant, 29 Oct 2026). Apps that offer the list as suggestions
|
|
322
350
|
* filter those themselves. Tags of deleted products drop out of the list.
|
|
323
351
|
* - productInstanceTags: `GET /product/instance/tags` → `{ tags: string[] }`,
|
|
324
352
|
* the same for price instances (channels such as "Eat In", "Takeout").
|
|
@@ -364,7 +392,7 @@ declare class RequestBodyError extends Error {}
|
|
|
364
392
|
*
|
|
365
393
|
* Accepts:
|
|
366
394
|
* - the SDK ≥ 0.3 shape `{ <collection>: { "0": {...}, "1": {...} } }` (refs kept),
|
|
367
|
-
* - the older
|
|
395
|
+
* - the older app shapes `{ <collection>: { new: {...} } }` / `{ updated: {...} }`,
|
|
368
396
|
* - a bare entity object `{ title: … }`.
|
|
369
397
|
*
|
|
370
398
|
* With `forcedId` (item routes) exactly one entity is allowed and its `id` is
|
|
@@ -438,7 +466,10 @@ interface ItemHandlers {
|
|
|
438
466
|
GET: RouteHandler;
|
|
439
467
|
/** Update the record at `[id]` (the id in the URL wins). */
|
|
440
468
|
PUT: RouteHandler;
|
|
441
|
-
/**
|
|
469
|
+
/**
|
|
470
|
+
* Delete the record at `[id]`. Shopwave answers 205 with an empty body. For an entity with
|
|
471
|
+
* `childIdsHeader`, `extras` carrying that key deletes just those child rows instead.
|
|
472
|
+
*/
|
|
442
473
|
DELETE: RouteHandler;
|
|
443
474
|
}
|
|
444
475
|
interface ResourceHandlers {
|
|
@@ -502,7 +533,13 @@ interface ShopwaveApiHandlers {
|
|
|
502
533
|
}
|
|
503
534
|
/** `YYYY-MM-DD HH:mm:ss` in UTC, the datetime format Shopwave writes use (e.g. promotions). */
|
|
504
535
|
declare function shopwaveDateTime(date?: Date): string;
|
|
536
|
+
/**
|
|
537
|
+
* The child ids a DELETE names in `extras` under `header` (case-insensitive), as one comma
|
|
538
|
+
* list: `undefined` when the key is absent, `null` when `extras` or the value is invalid (not a
|
|
539
|
+
* JSON object, or not a non-empty list of ids). The key may hold an array or a comma string.
|
|
540
|
+
*/
|
|
541
|
+
declare function readChildIds(raw: string | null, header: string): string | undefined | null;
|
|
505
542
|
declare function createShopwaveApiHandlers(config: ShopwaveApiConfig): ShopwaveApiHandlers;
|
|
506
543
|
//#endregion
|
|
507
|
-
export { BLOCKED_EXTRAS, type CollectionHandlers, type DeletableEntityKind, type EntityDefinition, type EntityKind, type ForwardInit, type ItemHandlers, type LookupDefinition, type LookupKind, RequestBodyError, type ResourceDefinition, type ResourceHandlers, type ResourceKind, type RouteContext, type RouteHandler, SHOPWAVE_ENTITIES, SHOPWAVE_LOOKUPS, SHOPWAVE_RESOURCES, SHOPWAVE_TOKEN_EXPIRED_ERROR_ID, SHOPWAVE_UPLOAD, type ShopwaveApiConfig, type ShopwaveApiHandlers, ShopwaveAuthError, type ShopwaveAuthErrorCode, type ShopwaveOAuthClient, type ShopwaveOAuthConfig, type ShopwaveToken, type ShopwaveTokenResponse, UPLOAD_KINDS, UPLOAD_PREFIXES, type UploadHandlers, type UploadKind, type UploadOptions, type UploadPrefix, type WritableEntityKind, assertOAuthConfig, authorizationHeader, createShopwaveApiHandlers, createShopwaveOAuth, createState, isExpiredTokenResponse, isTokenExpired, normalizeStoredToken, normalizeWriteBody, parseExtras, readRequestToken, safeEqual, sanitizeReturnTo, shopwaveDateTime, tokenFromResponse };
|
|
544
|
+
export { BLOCKED_EXTRAS, type CollectionHandlers, type DeletableEntityKind, type EntityDefinition, type EntityKind, type ForwardInit, type ItemHandlers, type LookupDefinition, type LookupKind, RequestBodyError, type ResourceDefinition, type ResourceHandlers, type ResourceKind, type RouteContext, type RouteHandler, SHOPWAVE_ENTITIES, SHOPWAVE_LOOKUPS, SHOPWAVE_RESOURCES, SHOPWAVE_TOKEN_EXPIRED_ERROR_ID, SHOPWAVE_UPLOAD, type ShopwaveApiConfig, type ShopwaveApiHandlers, ShopwaveAuthError, type ShopwaveAuthErrorCode, type ShopwaveOAuthClient, type ShopwaveOAuthConfig, type ShopwaveToken, type ShopwaveTokenResponse, UPLOAD_KINDS, UPLOAD_PREFIXES, type UploadHandlers, type UploadKind, type UploadOptions, type UploadPrefix, type WritableEntityKind, assertOAuthConfig, authorizationHeader, createShopwaveApiHandlers, createShopwaveOAuth, createState, isExpiredTokenResponse, isTokenExpired, normalizeStoredToken, normalizeWriteBody, parseExtras, readChildIds, readRequestToken, safeEqual, sanitizeReturnTo, shopwaveDateTime, tokenFromResponse };
|
|
508
545
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/server/index.d.ts
CHANGED
|
@@ -37,7 +37,7 @@ declare const SHOPWAVE_TOKEN_EXPIRED_ERROR_ID = 908;
|
|
|
37
37
|
declare function tokenFromResponse(response: ShopwaveTokenResponse, previous?: ShopwaveToken, now?: number): ShopwaveToken | null;
|
|
38
38
|
/**
|
|
39
39
|
* Reads a token from session storage. Accepts both the current shape and the
|
|
40
|
-
* legacy raw response that older apps
|
|
40
|
+
* legacy raw response that older apps stored directly in
|
|
41
41
|
* the session, so existing sessions survive an upgrade.
|
|
42
42
|
*/
|
|
43
43
|
declare function normalizeStoredToken(raw: unknown): ShopwaveToken | null;
|
|
@@ -215,8 +215,15 @@ interface EntityDefinition {
|
|
|
215
215
|
* start = end and the record is expired without ever running.
|
|
216
216
|
*/
|
|
217
217
|
retireStartField?: string;
|
|
218
|
+
/**
|
|
219
|
+
* Header naming child records to delete instead of the whole record
|
|
220
|
+
* (`productComponentInstanceIds: 1,2`). Only `item()` DELETE uses it, and only when
|
|
221
|
+
* the caller's `extras` carry this one key (a non-empty list of ids); every other
|
|
222
|
+
* `extras` key is still dropped. Only for `deleteMode: "delete"`.
|
|
223
|
+
*/
|
|
224
|
+
childIdsHeader?: string;
|
|
218
225
|
}
|
|
219
|
-
type EntityKind = "product" | "category" | "store" | "promotion" | "employee" | "consumer";
|
|
226
|
+
type EntityKind = "product" | "category" | "store" | "promotion" | "employee" | "consumer" | "productComponent";
|
|
220
227
|
/** Entities that can be created/updated through the API. */
|
|
221
228
|
type WritableEntityKind = Exclude<EntityKind, "consumer">;
|
|
222
229
|
/** Entities that can be deleted (or retired) through the API. */
|
|
@@ -233,6 +240,27 @@ type DeletableEntityKind = Exclude<EntityKind, "consumer">;
|
|
|
233
240
|
* - employee: POST updates `roleId`, `joinedDate`, `exitDate` (names can't be
|
|
234
241
|
* changed); no DELETE (live API: "Cannot DELETE /employee") → retired via `exitDate`.
|
|
235
242
|
* - consumer: read-only (`GET` with `ids`, comma-separated); live POST → 404.
|
|
243
|
+
* - productComponent: modifier groups, `/product/component` (live, staging, 11 Nov 2026). The
|
|
244
|
+
* API reference lists no read filters; these are what the live API does:
|
|
245
|
+
* - Reads filter by `componentIds` (group ids) or `productIds` (the parent product; option
|
|
246
|
+
* products don't match). `productComponentIds` is ignored on reads: every group comes back.
|
|
247
|
+
* `deleted: false` gives live groups only, `true` deleted groups only, no header both.
|
|
248
|
+
* No match → 204 with an empty body. No order, sort, priority or position field anywhere.
|
|
249
|
+
* - Groups are keyed by id; `products` (option products) by product id; `productInstances`
|
|
250
|
+
* (option rows) by row id. Reads reformat values: price `"100"` → `"100.0"`,
|
|
251
|
+
* vatPercentage `"0.2000"` → `"0.200"`. `tags` and `name` are stored as sent (no trimming;
|
|
252
|
+
* a `tags` array is joined with commas; `tags` null or left out → null).
|
|
253
|
+
* - POST upserts (201, echoed under the ref). For each option product in `products`, its rows
|
|
254
|
+
* are replaced: every row sent is created afresh with a new id (a row `id` is ignored, also
|
|
255
|
+
* on a price change) and rows left out are removed. Option products left out of the save
|
|
256
|
+
* are untouched, and an empty `productInstances` removes nothing. A save without `products`
|
|
257
|
+
* updates only the group's own fields. The echo isn't proof of what was stored: renames of
|
|
258
|
+
* groups created moments earlier by a test run echoed the new name but never stuck (re-read
|
|
259
|
+
* for 90 s), while older groups, and groups created in Shopwave's own admin, renamed at
|
|
260
|
+
* once. Cause not yet known.
|
|
261
|
+
* - DELETE with `productComponentIds` (plural, comma list) → 205, soft delete. Adding
|
|
262
|
+
* `productComponentInstanceIds` deletes just those rows (205); they stay in live reads with
|
|
263
|
+
* `deleteDate` set. The singular `productComponentId` hangs (504 after 60 s).
|
|
236
264
|
*/
|
|
237
265
|
declare const SHOPWAVE_ENTITIES: Readonly<Record<EntityKind, EntityDefinition>>;
|
|
238
266
|
//#endregion
|
|
@@ -278,8 +306,8 @@ declare const UPLOAD_KINDS: Readonly<Record<UploadKind, string>>;
|
|
|
278
306
|
/**
|
|
279
307
|
* The role an image plays, sent to Shopwave as the uploader's `prefix` header.
|
|
280
308
|
* The uploader names the file `<prefix>_<hash>.<ext>`, so the role travels with
|
|
281
|
-
* the file wherever a record stores it (a product's `images`). Live,
|
|
282
|
-
*
|
|
309
|
+
* the file wherever a record stores it (a product's `images`). Live, test
|
|
310
|
+
* merchant, 4 Nov 2026: all four values answered 201.
|
|
283
311
|
* - `product`: a product gallery image;
|
|
284
312
|
* - `product_thumbnail`: the product's lead image, shown in lists;
|
|
285
313
|
* - `variant` / `variant_thumbnail`: a variant's own image and its lead image
|
|
@@ -318,7 +346,7 @@ declare const SHOPWAVE_UPLOAD: Readonly<{
|
|
|
318
346
|
* on the merchant's products. No parameters. The API reference says
|
|
319
347
|
* "internal SKU tags are excluded", but the live API includes system tags
|
|
320
348
|
* written by imports and syncs (`PID-133`, `VID-137`, `#Hash:…`, `upc-…`;
|
|
321
|
-
* test merchant
|
|
349
|
+
* a test merchant, 29 Oct 2026). Apps that offer the list as suggestions
|
|
322
350
|
* filter those themselves. Tags of deleted products drop out of the list.
|
|
323
351
|
* - productInstanceTags: `GET /product/instance/tags` → `{ tags: string[] }`,
|
|
324
352
|
* the same for price instances (channels such as "Eat In", "Takeout").
|
|
@@ -364,7 +392,7 @@ declare class RequestBodyError extends Error {}
|
|
|
364
392
|
*
|
|
365
393
|
* Accepts:
|
|
366
394
|
* - the SDK ≥ 0.3 shape `{ <collection>: { "0": {...}, "1": {...} } }` (refs kept),
|
|
367
|
-
* - the older
|
|
395
|
+
* - the older app shapes `{ <collection>: { new: {...} } }` / `{ updated: {...} }`,
|
|
368
396
|
* - a bare entity object `{ title: … }`.
|
|
369
397
|
*
|
|
370
398
|
* With `forcedId` (item routes) exactly one entity is allowed and its `id` is
|
|
@@ -438,7 +466,10 @@ interface ItemHandlers {
|
|
|
438
466
|
GET: RouteHandler;
|
|
439
467
|
/** Update the record at `[id]` (the id in the URL wins). */
|
|
440
468
|
PUT: RouteHandler;
|
|
441
|
-
/**
|
|
469
|
+
/**
|
|
470
|
+
* Delete the record at `[id]`. Shopwave answers 205 with an empty body. For an entity with
|
|
471
|
+
* `childIdsHeader`, `extras` carrying that key deletes just those child rows instead.
|
|
472
|
+
*/
|
|
442
473
|
DELETE: RouteHandler;
|
|
443
474
|
}
|
|
444
475
|
interface ResourceHandlers {
|
|
@@ -502,7 +533,13 @@ interface ShopwaveApiHandlers {
|
|
|
502
533
|
}
|
|
503
534
|
/** `YYYY-MM-DD HH:mm:ss` in UTC, the datetime format Shopwave writes use (e.g. promotions). */
|
|
504
535
|
declare function shopwaveDateTime(date?: Date): string;
|
|
536
|
+
/**
|
|
537
|
+
* The child ids a DELETE names in `extras` under `header` (case-insensitive), as one comma
|
|
538
|
+
* list: `undefined` when the key is absent, `null` when `extras` or the value is invalid (not a
|
|
539
|
+
* JSON object, or not a non-empty list of ids). The key may hold an array or a comma string.
|
|
540
|
+
*/
|
|
541
|
+
declare function readChildIds(raw: string | null, header: string): string | undefined | null;
|
|
505
542
|
declare function createShopwaveApiHandlers(config: ShopwaveApiConfig): ShopwaveApiHandlers;
|
|
506
543
|
//#endregion
|
|
507
|
-
export { BLOCKED_EXTRAS, type CollectionHandlers, type DeletableEntityKind, type EntityDefinition, type EntityKind, type ForwardInit, type ItemHandlers, type LookupDefinition, type LookupKind, RequestBodyError, type ResourceDefinition, type ResourceHandlers, type ResourceKind, type RouteContext, type RouteHandler, SHOPWAVE_ENTITIES, SHOPWAVE_LOOKUPS, SHOPWAVE_RESOURCES, SHOPWAVE_TOKEN_EXPIRED_ERROR_ID, SHOPWAVE_UPLOAD, type ShopwaveApiConfig, type ShopwaveApiHandlers, ShopwaveAuthError, type ShopwaveAuthErrorCode, type ShopwaveOAuthClient, type ShopwaveOAuthConfig, type ShopwaveToken, type ShopwaveTokenResponse, UPLOAD_KINDS, UPLOAD_PREFIXES, type UploadHandlers, type UploadKind, type UploadOptions, type UploadPrefix, type WritableEntityKind, assertOAuthConfig, authorizationHeader, createShopwaveApiHandlers, createShopwaveOAuth, createState, isExpiredTokenResponse, isTokenExpired, normalizeStoredToken, normalizeWriteBody, parseExtras, readRequestToken, safeEqual, sanitizeReturnTo, shopwaveDateTime, tokenFromResponse };
|
|
544
|
+
export { BLOCKED_EXTRAS, type CollectionHandlers, type DeletableEntityKind, type EntityDefinition, type EntityKind, type ForwardInit, type ItemHandlers, type LookupDefinition, type LookupKind, RequestBodyError, type ResourceDefinition, type ResourceHandlers, type ResourceKind, type RouteContext, type RouteHandler, SHOPWAVE_ENTITIES, SHOPWAVE_LOOKUPS, SHOPWAVE_RESOURCES, SHOPWAVE_TOKEN_EXPIRED_ERROR_ID, SHOPWAVE_UPLOAD, type ShopwaveApiConfig, type ShopwaveApiHandlers, ShopwaveAuthError, type ShopwaveAuthErrorCode, type ShopwaveOAuthClient, type ShopwaveOAuthConfig, type ShopwaveToken, type ShopwaveTokenResponse, UPLOAD_KINDS, UPLOAD_PREFIXES, type UploadHandlers, type UploadKind, type UploadOptions, type UploadPrefix, type WritableEntityKind, assertOAuthConfig, authorizationHeader, createShopwaveApiHandlers, createShopwaveOAuth, createState, isExpiredTokenResponse, isTokenExpired, normalizeStoredToken, normalizeWriteBody, parseExtras, readChildIds, readRequestToken, safeEqual, sanitizeReturnTo, shopwaveDateTime, tokenFromResponse };
|
|
508
545
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/server/index.js
CHANGED
|
@@ -44,7 +44,7 @@ function tokenFromResponse(response, previous, now = Date.now()) {
|
|
|
44
44
|
}
|
|
45
45
|
/**
|
|
46
46
|
* Reads a token from session storage. Accepts both the current shape and the
|
|
47
|
-
* legacy raw response that older apps
|
|
47
|
+
* legacy raw response that older apps stored directly in
|
|
48
48
|
* the session, so existing sessions survive an upgrade.
|
|
49
49
|
*/
|
|
50
50
|
function normalizeStoredToken(raw) {
|
|
@@ -326,6 +326,27 @@ const SHOPWAVE_LOOKUPS = Object.freeze({
|
|
|
326
326
|
* - employee: POST updates `roleId`, `joinedDate`, `exitDate` (names can't be
|
|
327
327
|
* changed); no DELETE (live API: "Cannot DELETE /employee") → retired via `exitDate`.
|
|
328
328
|
* - consumer: read-only (`GET` with `ids`, comma-separated); live POST → 404.
|
|
329
|
+
* - productComponent: modifier groups, `/product/component` (live, staging, 11 Nov 2026). The
|
|
330
|
+
* API reference lists no read filters; these are what the live API does:
|
|
331
|
+
* - Reads filter by `componentIds` (group ids) or `productIds` (the parent product; option
|
|
332
|
+
* products don't match). `productComponentIds` is ignored on reads: every group comes back.
|
|
333
|
+
* `deleted: false` gives live groups only, `true` deleted groups only, no header both.
|
|
334
|
+
* No match → 204 with an empty body. No order, sort, priority or position field anywhere.
|
|
335
|
+
* - Groups are keyed by id; `products` (option products) by product id; `productInstances`
|
|
336
|
+
* (option rows) by row id. Reads reformat values: price `"100"` → `"100.0"`,
|
|
337
|
+
* vatPercentage `"0.2000"` → `"0.200"`. `tags` and `name` are stored as sent (no trimming;
|
|
338
|
+
* a `tags` array is joined with commas; `tags` null or left out → null).
|
|
339
|
+
* - POST upserts (201, echoed under the ref). For each option product in `products`, its rows
|
|
340
|
+
* are replaced: every row sent is created afresh with a new id (a row `id` is ignored, also
|
|
341
|
+
* on a price change) and rows left out are removed. Option products left out of the save
|
|
342
|
+
* are untouched, and an empty `productInstances` removes nothing. A save without `products`
|
|
343
|
+
* updates only the group's own fields. The echo isn't proof of what was stored: renames of
|
|
344
|
+
* groups created moments earlier by a test run echoed the new name but never stuck (re-read
|
|
345
|
+
* for 90 s), while older groups, and groups created in Shopwave's own admin, renamed at
|
|
346
|
+
* once. Cause not yet known.
|
|
347
|
+
* - DELETE with `productComponentIds` (plural, comma list) → 205, soft delete. Adding
|
|
348
|
+
* `productComponentInstanceIds` deletes just those rows (205); they stay in live reads with
|
|
349
|
+
* `deleteDate` set. The singular `productComponentId` hangs (504 after 60 s).
|
|
329
350
|
*/
|
|
330
351
|
const SHOPWAVE_ENTITIES = Object.freeze({
|
|
331
352
|
product: {
|
|
@@ -385,6 +406,16 @@ const SHOPWAVE_ENTITIES = Object.freeze({
|
|
|
385
406
|
idHeader: "consumerId",
|
|
386
407
|
writable: false,
|
|
387
408
|
deleteMode: "none"
|
|
409
|
+
},
|
|
410
|
+
productComponent: {
|
|
411
|
+
route: "product-components",
|
|
412
|
+
collection: "productComponents",
|
|
413
|
+
upstream: "product/component",
|
|
414
|
+
idsHeader: "componentIds",
|
|
415
|
+
idHeader: "productComponentIds",
|
|
416
|
+
writable: true,
|
|
417
|
+
deleteMode: "delete",
|
|
418
|
+
childIdsHeader: "productComponentInstanceIds"
|
|
388
419
|
}
|
|
389
420
|
});
|
|
390
421
|
|
|
@@ -474,7 +505,7 @@ function isPlainObject(value) {
|
|
|
474
505
|
*
|
|
475
506
|
* Accepts:
|
|
476
507
|
* - the SDK ≥ 0.3 shape `{ <collection>: { "0": {...}, "1": {...} } }` (refs kept),
|
|
477
|
-
* - the older
|
|
508
|
+
* - the older app shapes `{ <collection>: { new: {...} } }` / `{ updated: {...} }`,
|
|
478
509
|
* - a bare entity object `{ title: … }`.
|
|
479
510
|
*
|
|
480
511
|
* With `forcedId` (item routes) exactly one entity is allowed and its `id` is
|
|
@@ -558,6 +589,29 @@ async function readUpstream(response) {
|
|
|
558
589
|
};
|
|
559
590
|
}
|
|
560
591
|
}
|
|
592
|
+
/**
|
|
593
|
+
* The child ids a DELETE names in `extras` under `header` (case-insensitive), as one comma
|
|
594
|
+
* list: `undefined` when the key is absent, `null` when `extras` or the value is invalid (not a
|
|
595
|
+
* JSON object, or not a non-empty list of ids). The key may hold an array or a comma string.
|
|
596
|
+
*/
|
|
597
|
+
function readChildIds(raw, header) {
|
|
598
|
+
if (!raw) return void 0;
|
|
599
|
+
let parsed;
|
|
600
|
+
try {
|
|
601
|
+
parsed = JSON.parse(raw);
|
|
602
|
+
} catch {
|
|
603
|
+
return null;
|
|
604
|
+
}
|
|
605
|
+
if (!isPlainObject(parsed)) return null;
|
|
606
|
+
const key = Object.keys(parsed).find((k) => k.toLowerCase() === header.toLowerCase());
|
|
607
|
+
if (key === void 0) return void 0;
|
|
608
|
+
const value = parsed[key];
|
|
609
|
+
const list = Array.isArray(value) ? value : typeof value === "string" || typeof value === "number" ? String(value).split(",") : null;
|
|
610
|
+
if (!list) return null;
|
|
611
|
+
const ids = list.map((v) => typeof v === "string" || typeof v === "number" ? String(v).trim() : "");
|
|
612
|
+
if (ids.length === 0 || ids.some((id) => !ID_PATTERN.test(id))) return null;
|
|
613
|
+
return ids.join(",");
|
|
614
|
+
}
|
|
561
615
|
async function routeParam(context, name) {
|
|
562
616
|
const value = (await context?.params)?.[name];
|
|
563
617
|
const id = Array.isArray(value) ? value[0] : value;
|
|
@@ -808,6 +862,19 @@ function createShopwaveApiHandlers(config) {
|
|
|
808
862
|
const id = await routeParam(context, param);
|
|
809
863
|
if (!id) return badId();
|
|
810
864
|
if (def.deleteMode === "none") return notSupported(def, "deletes");
|
|
865
|
+
if (def.deleteMode === "delete" && def.childIdsHeader) {
|
|
866
|
+
const childIds = readChildIds(request.headers.get("extras"), def.childIdsHeader);
|
|
867
|
+
if (childIds === null) return jsonError(400, "invalid_extras", `"${def.childIdsHeader}" must be a non-empty list of ids`);
|
|
868
|
+
if (childIds !== void 0) return forward(request, {
|
|
869
|
+
method: "DELETE",
|
|
870
|
+
path: def.upstream,
|
|
871
|
+
headers: {
|
|
872
|
+
[def.idHeader]: id,
|
|
873
|
+
[def.childIdsHeader]: childIds
|
|
874
|
+
},
|
|
875
|
+
forwardExtras: false
|
|
876
|
+
});
|
|
877
|
+
}
|
|
811
878
|
if (def.deleteMode === "retire") {
|
|
812
879
|
const field = def.retireField ?? "exitDate";
|
|
813
880
|
if (def.retireWithRecord) return retireWithRecord(request, def, id, field);
|
|
@@ -857,5 +924,5 @@ function createShopwaveApiHandlers(config) {
|
|
|
857
924
|
}
|
|
858
925
|
|
|
859
926
|
//#endregion
|
|
860
|
-
export { BLOCKED_EXTRAS, RequestBodyError, SHOPWAVE_ENTITIES, SHOPWAVE_LOOKUPS, SHOPWAVE_RESOURCES, SHOPWAVE_TOKEN_EXPIRED_ERROR_ID, SHOPWAVE_UPLOAD, ShopwaveAuthError, UPLOAD_KINDS, UPLOAD_PREFIXES, assertOAuthConfig, authorizationHeader, createShopwaveApiHandlers, createShopwaveOAuth, createState, isExpiredTokenResponse, isTokenExpired, normalizeStoredToken, normalizeWriteBody, parseExtras, readRequestToken, safeEqual, sanitizeReturnTo, shopwaveDateTime, tokenFromResponse };
|
|
927
|
+
export { BLOCKED_EXTRAS, RequestBodyError, SHOPWAVE_ENTITIES, SHOPWAVE_LOOKUPS, SHOPWAVE_RESOURCES, SHOPWAVE_TOKEN_EXPIRED_ERROR_ID, SHOPWAVE_UPLOAD, ShopwaveAuthError, UPLOAD_KINDS, UPLOAD_PREFIXES, assertOAuthConfig, authorizationHeader, createShopwaveApiHandlers, createShopwaveOAuth, createState, isExpiredTokenResponse, isTokenExpired, normalizeStoredToken, normalizeWriteBody, parseExtras, readChildIds, readRequestToken, safeEqual, sanitizeReturnTo, shopwaveDateTime, tokenFromResponse };
|
|
861
928
|
//# sourceMappingURL=index.js.map
|