react-shopwave-connect 0.4.2 → 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.
@@ -340,6 +340,26 @@ declare function fetchProductsMap(productIds: number[] | null | undefined, optio
340
340
  [id: number]: Product;
341
341
  }>;
342
342
  //#endregion
343
+ //#region src/core/productTags.d.ts
344
+ /**
345
+ * Turns a tag list from the API into clean strings: trims each tag, drops
346
+ * blanks and anything that isn't text, and removes exact duplicates (first one
347
+ * wins). The API's own order is kept. A map is accepted too (its values are
348
+ * used), in case the API ever answers keyed by id.
349
+ */
350
+ declare function normalizeTagList(value: unknown): string[];
351
+ /**
352
+ * Every distinct tag used on the merchant's products (`GET /product/tags`),
353
+ * for a tag field's suggestions. Returns `[]` when there are none.
354
+ */
355
+ declare function fetchProductTags(options?: RequestOptions): Promise<string[]>;
356
+ /**
357
+ * Every distinct tag used on the merchant's price instances
358
+ * (`GET /product/instance/tags`): the channel names (Eat In, Takeout, …).
359
+ * Returns `[]` when there are none.
360
+ */
361
+ declare function fetchProductInstanceTags(options?: RequestOptions): Promise<string[]>;
362
+ //#endregion
343
363
  //#region src/core/promotion.d.ts
344
364
  /** Promotion rule identifiers as stored by the Shopwave API. */
345
365
  declare enum PromotionRuleSet {
@@ -537,8 +557,9 @@ declare function submitEntity<R = any>({
537
557
  //#region src/core/entities.d.ts
538
558
  /**
539
559
  * How each Shopwave entity is addressed, shared by the client functions below
540
- * and the server route handlers in `react-shopwave-connect/next`, so the two
541
- * halves of the contract can't drift apart.
560
+ * and the server route handlers in `react-shopwave-connect/server` (wrapped with
561
+ * the session by `react-shopwave-connect/next`), so the two halves of the
562
+ * contract can't drift apart.
542
563
  */
543
564
  interface EntityDefinition {
544
565
  /** App route segment: `/api/<route>` and `/api/<route>/<id>`. */
@@ -790,7 +811,7 @@ declare function buildConsumerMap(consumers: Consumer[] | null | undefined): {
790
811
  *
791
812
  * Like `SHOPWAVE_ENTITIES`, this table is shared by the client functions
792
813
  * (`fetchMerchant`, `fetchUser`, `uploadImage`, …) and the server route
793
- * handlers in `react-shopwave-connect/next`, so the two halves of the contract
814
+ * handlers in `react-shopwave-connect/server`, so the two halves of the contract
794
815
  * can't drift apart. These aren't in `SHOPWAVE_ENTITIES` because they aren't
795
816
  * keyed collections: `GET /merchant` answers `{ merchant: {…} }`, not a map by id.
796
817
  */
@@ -837,6 +858,35 @@ declare const SHOPWAVE_UPLOAD: Readonly<{
837
858
  kindField: "kind";
838
859
  }>;
839
860
  declare function isUploadKind(value: unknown): value is UploadKind;
861
+ /**
862
+ * Read-only lists that aren't records: the merchant's distinct tags.
863
+ *
864
+ * Like `SHOPWAVE_RESOURCES`, shared by the client functions
865
+ * (`fetchProductTags`, `fetchProductInstanceTags`) and the server route
866
+ * handlers (`shopwave.lookup(kind)`), so the two halves can't drift apart.
867
+ *
868
+ * - productTags: `GET /product/tags` → `{ tags: string[] }`, every distinct tag
869
+ * on the merchant's products. No parameters. The API reference says
870
+ * "internal SKU tags are excluded", but the live API includes system tags
871
+ * written by imports and syncs (`PID-133`, `VID-137`, `#Hash:…`, `upc-…`;
872
+ * test merchant 5644, 29 Oct 2026). Apps that offer the list as suggestions
873
+ * filter those themselves. Tags of deleted products drop out of the list.
874
+ * - productInstanceTags: `GET /product/instance/tags` → `{ tags: string[] }`,
875
+ * the same for price instances (channels such as "Eat In", "Takeout").
876
+ *
877
+ * The app route for instance tags is `products/instance-tags`, one segment
878
+ * under `products`, so it sits beside `products/[id]` without nesting deeper.
879
+ */
880
+ interface LookupDefinition {
881
+ /** App route: `/api/<route>`. */
882
+ route: string;
883
+ /** Key of the list in the response (`{ tags: [...] }`). */
884
+ key: string;
885
+ /** Shopwave API path. */
886
+ upstream: string;
887
+ }
888
+ type LookupKind = "productTags" | "productInstanceTags";
889
+ declare const SHOPWAVE_LOOKUPS: Readonly<Record<LookupKind, LookupDefinition>>;
840
890
  //#endregion
841
891
  //#region src/core/imageFit.d.ts
842
892
  /**
@@ -1174,5 +1224,5 @@ interface UserResponse {
1174
1224
  /** Reads the logged-in user, or `null` when the API returns none. */
1175
1225
  declare function fetchUser(options?: RequestOptions): Promise<User | null>;
1176
1226
  //#endregion
1177
- export { Basket, BasketFilters, BasketItem, BasketPagination, BasketReportRow, BasketSummary, Category, CategoryResponse, CombineBasketRowsParams, Consumer, ConsumerResponse, CropRect, DEFAULT_BASKET_FILTERS, DEFAULT_PAGINATION, DeletableEntityKind, Employee, EmployeeResponse, EntityDefinition, EntityId, EntityInput, EntityKind, EntityTypes, ErrorMessage, Extras, FetchByIdParams, FetchCategoriesParams, FetchEmployeesParams, FetchProductsParams, FetchPromotionsParams, FetchStoresParams, FitImageOptions, ImageSize, MERCHANT_COLOUR_KEYS, MERCHANT_FIELD_MAX_LENGTH, MERCHANT_IMAGE_SLOTS, MERCHANT_IMAGE_SLOT_KEYS, MERCHANT_LINK_KEYS, MERCHANT_LINK_PATHS, MERCHANT_OBJECT_FIELDS, MERCHANT_READ_ONLY_FIELDS, Merchant, MerchantColourKey, MerchantColourSet, MerchantColours, MerchantImageIds, MerchantImageSlot, MerchantImageSlotDefinition, MerchantLinkKey, MerchantLinks, MerchantPatch, MerchantResponse, MessageInfo, ParsedBasket, Product, ProductInstance, ProductInstanceInput, ProductInstances, ProductResponse, ProductSaveInput, Promotion, PromotionResponse, PromotionRuleSet, ReportData, ReportKey, ReportQuery, ReportQueryMap, ReportResponse, RepricedInstance, RequestOptions, ResourceDefinition, ResourceKind, SHOPWAVE_ENTITIES, SHOPWAVE_IMAGE_BASE_URL, SHOPWAVE_RESOURCES, SHOPWAVE_UPLOAD, Saved, SessionStatus, ShopwaveApiError, ShopwaveErrorMap, Store, StoreResponse, SubmitEntityArgs, SubmitEntityResponse, SuccessMessage, UPLOAD_KINDS, UpdateMerchantOptions, UploadImageParams, UploadKind, UploadMerchantImageOptions, UploadedImage, User, UserEmployee, UserResponse, WritableEntityKind, apiDelete, apiGet, apiRequest, apiResponse, apiSend, assertNoApiErrors, authorizationFor, buildBasketReportQuery, buildConsumerMap, collectConsumerIds, collectProductIds, combineBasketRows, computeBasketSummary, coverCrop, deleteCategory, deleteEmployee, deleteEntity, deleteEntityById, deleteProduct, deletePromotion, deleteStore, fetchCategories, fetchCategory, fetchConsumer, fetchConsumers, fetchEmployee, fetchEmployees, fetchEntityById, fetchMerchant, fetchProduct, fetchProducts, fetchProductsMap, fetchPromotion, fetchPromotions, fetchReport, fetchSession, fetchStore, fetchStores, fetchUser, findRepricedInstances, fitImageToSize, formatDateForQuery, getApiErrorMap, getApiErrors, getImageUrl, getMerchantImage, getMerchantImageUrl, imageFileName, isSameInstancePrice, isUploadKind, loginPath, logout, logoutPath, merchantLinksFromForm, merchantLinksToForm, normalizeMerchantLinks, parseBasketReportData, readImageSize, rolesById, saveCategory, saveEmployee, saveEntities, saveEntity, saveProduct, savePromotion, saveStore, setMerchantImage, submitEntity, toProductInstancesForSave, toShopwaveApiError, toStoredImageIds, updateMerchant, uploadImage, uploadMerchantImage, validateMerchant, withToken };
1227
+ export { Basket, BasketFilters, BasketItem, BasketPagination, BasketReportRow, BasketSummary, Category, CategoryResponse, CombineBasketRowsParams, Consumer, ConsumerResponse, CropRect, DEFAULT_BASKET_FILTERS, DEFAULT_PAGINATION, DeletableEntityKind, Employee, EmployeeResponse, EntityDefinition, EntityId, EntityInput, EntityKind, EntityTypes, ErrorMessage, Extras, FetchByIdParams, FetchCategoriesParams, FetchEmployeesParams, FetchProductsParams, FetchPromotionsParams, FetchStoresParams, FitImageOptions, ImageSize, LookupDefinition, LookupKind, MERCHANT_COLOUR_KEYS, MERCHANT_FIELD_MAX_LENGTH, MERCHANT_IMAGE_SLOTS, MERCHANT_IMAGE_SLOT_KEYS, MERCHANT_LINK_KEYS, MERCHANT_LINK_PATHS, MERCHANT_OBJECT_FIELDS, MERCHANT_READ_ONLY_FIELDS, Merchant, MerchantColourKey, MerchantColourSet, MerchantColours, MerchantImageIds, MerchantImageSlot, MerchantImageSlotDefinition, MerchantLinkKey, MerchantLinks, MerchantPatch, MerchantResponse, MessageInfo, ParsedBasket, Product, ProductInstance, ProductInstanceInput, ProductInstances, ProductResponse, ProductSaveInput, Promotion, PromotionResponse, PromotionRuleSet, ReportData, ReportKey, ReportQuery, ReportQueryMap, ReportResponse, RepricedInstance, RequestOptions, ResourceDefinition, ResourceKind, SHOPWAVE_ENTITIES, SHOPWAVE_IMAGE_BASE_URL, SHOPWAVE_LOOKUPS, SHOPWAVE_RESOURCES, SHOPWAVE_UPLOAD, Saved, SessionStatus, ShopwaveApiError, ShopwaveErrorMap, Store, StoreResponse, SubmitEntityArgs, SubmitEntityResponse, SuccessMessage, UPLOAD_KINDS, UpdateMerchantOptions, UploadImageParams, UploadKind, UploadMerchantImageOptions, UploadedImage, User, UserEmployee, UserResponse, WritableEntityKind, apiDelete, apiGet, apiRequest, apiResponse, apiSend, assertNoApiErrors, authorizationFor, buildBasketReportQuery, buildConsumerMap, collectConsumerIds, collectProductIds, combineBasketRows, computeBasketSummary, coverCrop, deleteCategory, deleteEmployee, deleteEntity, deleteEntityById, deleteProduct, deletePromotion, deleteStore, fetchCategories, fetchCategory, fetchConsumer, fetchConsumers, fetchEmployee, fetchEmployees, fetchEntityById, fetchMerchant, fetchProduct, fetchProductInstanceTags, fetchProductTags, fetchProducts, fetchProductsMap, fetchPromotion, fetchPromotions, fetchReport, fetchSession, fetchStore, fetchStores, fetchUser, findRepricedInstances, fitImageToSize, formatDateForQuery, getApiErrorMap, getApiErrors, getImageUrl, getMerchantImage, getMerchantImageUrl, imageFileName, isSameInstancePrice, isUploadKind, loginPath, logout, logoutPath, merchantLinksFromForm, merchantLinksToForm, normalizeMerchantLinks, normalizeTagList, parseBasketReportData, readImageSize, rolesById, saveCategory, saveEmployee, saveEntities, saveEntity, saveProduct, savePromotion, saveStore, setMerchantImage, submitEntity, toProductInstancesForSave, toShopwaveApiError, toStoredImageIds, updateMerchant, uploadImage, uploadMerchantImage, validateMerchant, withToken };
1178
1228
  //# sourceMappingURL=index.d.cts.map
@@ -340,6 +340,26 @@ declare function fetchProductsMap(productIds: number[] | null | undefined, optio
340
340
  [id: number]: Product;
341
341
  }>;
342
342
  //#endregion
343
+ //#region src/core/productTags.d.ts
344
+ /**
345
+ * Turns a tag list from the API into clean strings: trims each tag, drops
346
+ * blanks and anything that isn't text, and removes exact duplicates (first one
347
+ * wins). The API's own order is kept. A map is accepted too (its values are
348
+ * used), in case the API ever answers keyed by id.
349
+ */
350
+ declare function normalizeTagList(value: unknown): string[];
351
+ /**
352
+ * Every distinct tag used on the merchant's products (`GET /product/tags`),
353
+ * for a tag field's suggestions. Returns `[]` when there are none.
354
+ */
355
+ declare function fetchProductTags(options?: RequestOptions): Promise<string[]>;
356
+ /**
357
+ * Every distinct tag used on the merchant's price instances
358
+ * (`GET /product/instance/tags`): the channel names (Eat In, Takeout, …).
359
+ * Returns `[]` when there are none.
360
+ */
361
+ declare function fetchProductInstanceTags(options?: RequestOptions): Promise<string[]>;
362
+ //#endregion
343
363
  //#region src/core/promotion.d.ts
344
364
  /** Promotion rule identifiers as stored by the Shopwave API. */
345
365
  declare enum PromotionRuleSet {
@@ -537,8 +557,9 @@ declare function submitEntity<R = any>({
537
557
  //#region src/core/entities.d.ts
538
558
  /**
539
559
  * How each Shopwave entity is addressed, shared by the client functions below
540
- * and the server route handlers in `react-shopwave-connect/next`, so the two
541
- * halves of the contract can't drift apart.
560
+ * and the server route handlers in `react-shopwave-connect/server` (wrapped with
561
+ * the session by `react-shopwave-connect/next`), so the two halves of the
562
+ * contract can't drift apart.
542
563
  */
543
564
  interface EntityDefinition {
544
565
  /** App route segment: `/api/<route>` and `/api/<route>/<id>`. */
@@ -790,7 +811,7 @@ declare function buildConsumerMap(consumers: Consumer[] | null | undefined): {
790
811
  *
791
812
  * Like `SHOPWAVE_ENTITIES`, this table is shared by the client functions
792
813
  * (`fetchMerchant`, `fetchUser`, `uploadImage`, …) and the server route
793
- * handlers in `react-shopwave-connect/next`, so the two halves of the contract
814
+ * handlers in `react-shopwave-connect/server`, so the two halves of the contract
794
815
  * can't drift apart. These aren't in `SHOPWAVE_ENTITIES` because they aren't
795
816
  * keyed collections: `GET /merchant` answers `{ merchant: {…} }`, not a map by id.
796
817
  */
@@ -837,6 +858,35 @@ declare const SHOPWAVE_UPLOAD: Readonly<{
837
858
  kindField: "kind";
838
859
  }>;
839
860
  declare function isUploadKind(value: unknown): value is UploadKind;
861
+ /**
862
+ * Read-only lists that aren't records: the merchant's distinct tags.
863
+ *
864
+ * Like `SHOPWAVE_RESOURCES`, shared by the client functions
865
+ * (`fetchProductTags`, `fetchProductInstanceTags`) and the server route
866
+ * handlers (`shopwave.lookup(kind)`), so the two halves can't drift apart.
867
+ *
868
+ * - productTags: `GET /product/tags` → `{ tags: string[] }`, every distinct tag
869
+ * on the merchant's products. No parameters. The API reference says
870
+ * "internal SKU tags are excluded", but the live API includes system tags
871
+ * written by imports and syncs (`PID-133`, `VID-137`, `#Hash:…`, `upc-…`;
872
+ * test merchant 5644, 29 Oct 2026). Apps that offer the list as suggestions
873
+ * filter those themselves. Tags of deleted products drop out of the list.
874
+ * - productInstanceTags: `GET /product/instance/tags` → `{ tags: string[] }`,
875
+ * the same for price instances (channels such as "Eat In", "Takeout").
876
+ *
877
+ * The app route for instance tags is `products/instance-tags`, one segment
878
+ * under `products`, so it sits beside `products/[id]` without nesting deeper.
879
+ */
880
+ interface LookupDefinition {
881
+ /** App route: `/api/<route>`. */
882
+ route: string;
883
+ /** Key of the list in the response (`{ tags: [...] }`). */
884
+ key: string;
885
+ /** Shopwave API path. */
886
+ upstream: string;
887
+ }
888
+ type LookupKind = "productTags" | "productInstanceTags";
889
+ declare const SHOPWAVE_LOOKUPS: Readonly<Record<LookupKind, LookupDefinition>>;
840
890
  //#endregion
841
891
  //#region src/core/imageFit.d.ts
842
892
  /**
@@ -1174,5 +1224,5 @@ interface UserResponse {
1174
1224
  /** Reads the logged-in user, or `null` when the API returns none. */
1175
1225
  declare function fetchUser(options?: RequestOptions): Promise<User | null>;
1176
1226
  //#endregion
1177
- export { Basket, BasketFilters, BasketItem, BasketPagination, BasketReportRow, BasketSummary, Category, CategoryResponse, CombineBasketRowsParams, Consumer, ConsumerResponse, CropRect, DEFAULT_BASKET_FILTERS, DEFAULT_PAGINATION, DeletableEntityKind, Employee, EmployeeResponse, EntityDefinition, EntityId, EntityInput, EntityKind, EntityTypes, ErrorMessage, Extras, FetchByIdParams, FetchCategoriesParams, FetchEmployeesParams, FetchProductsParams, FetchPromotionsParams, FetchStoresParams, FitImageOptions, ImageSize, MERCHANT_COLOUR_KEYS, MERCHANT_FIELD_MAX_LENGTH, MERCHANT_IMAGE_SLOTS, MERCHANT_IMAGE_SLOT_KEYS, MERCHANT_LINK_KEYS, MERCHANT_LINK_PATHS, MERCHANT_OBJECT_FIELDS, MERCHANT_READ_ONLY_FIELDS, Merchant, MerchantColourKey, MerchantColourSet, MerchantColours, MerchantImageIds, MerchantImageSlot, MerchantImageSlotDefinition, MerchantLinkKey, MerchantLinks, MerchantPatch, MerchantResponse, MessageInfo, ParsedBasket, Product, ProductInstance, ProductInstanceInput, ProductInstances, ProductResponse, ProductSaveInput, Promotion, PromotionResponse, PromotionRuleSet, ReportData, ReportKey, ReportQuery, ReportQueryMap, ReportResponse, RepricedInstance, RequestOptions, ResourceDefinition, ResourceKind, SHOPWAVE_ENTITIES, SHOPWAVE_IMAGE_BASE_URL, SHOPWAVE_RESOURCES, SHOPWAVE_UPLOAD, Saved, SessionStatus, ShopwaveApiError, ShopwaveErrorMap, Store, StoreResponse, SubmitEntityArgs, SubmitEntityResponse, SuccessMessage, UPLOAD_KINDS, UpdateMerchantOptions, UploadImageParams, UploadKind, UploadMerchantImageOptions, UploadedImage, User, UserEmployee, UserResponse, WritableEntityKind, apiDelete, apiGet, apiRequest, apiResponse, apiSend, assertNoApiErrors, authorizationFor, buildBasketReportQuery, buildConsumerMap, collectConsumerIds, collectProductIds, combineBasketRows, computeBasketSummary, coverCrop, deleteCategory, deleteEmployee, deleteEntity, deleteEntityById, deleteProduct, deletePromotion, deleteStore, fetchCategories, fetchCategory, fetchConsumer, fetchConsumers, fetchEmployee, fetchEmployees, fetchEntityById, fetchMerchant, fetchProduct, fetchProducts, fetchProductsMap, fetchPromotion, fetchPromotions, fetchReport, fetchSession, fetchStore, fetchStores, fetchUser, findRepricedInstances, fitImageToSize, formatDateForQuery, getApiErrorMap, getApiErrors, getImageUrl, getMerchantImage, getMerchantImageUrl, imageFileName, isSameInstancePrice, isUploadKind, loginPath, logout, logoutPath, merchantLinksFromForm, merchantLinksToForm, normalizeMerchantLinks, parseBasketReportData, readImageSize, rolesById, saveCategory, saveEmployee, saveEntities, saveEntity, saveProduct, savePromotion, saveStore, setMerchantImage, submitEntity, toProductInstancesForSave, toShopwaveApiError, toStoredImageIds, updateMerchant, uploadImage, uploadMerchantImage, validateMerchant, withToken };
1227
+ export { Basket, BasketFilters, BasketItem, BasketPagination, BasketReportRow, BasketSummary, Category, CategoryResponse, CombineBasketRowsParams, Consumer, ConsumerResponse, CropRect, DEFAULT_BASKET_FILTERS, DEFAULT_PAGINATION, DeletableEntityKind, Employee, EmployeeResponse, EntityDefinition, EntityId, EntityInput, EntityKind, EntityTypes, ErrorMessage, Extras, FetchByIdParams, FetchCategoriesParams, FetchEmployeesParams, FetchProductsParams, FetchPromotionsParams, FetchStoresParams, FitImageOptions, ImageSize, LookupDefinition, LookupKind, MERCHANT_COLOUR_KEYS, MERCHANT_FIELD_MAX_LENGTH, MERCHANT_IMAGE_SLOTS, MERCHANT_IMAGE_SLOT_KEYS, MERCHANT_LINK_KEYS, MERCHANT_LINK_PATHS, MERCHANT_OBJECT_FIELDS, MERCHANT_READ_ONLY_FIELDS, Merchant, MerchantColourKey, MerchantColourSet, MerchantColours, MerchantImageIds, MerchantImageSlot, MerchantImageSlotDefinition, MerchantLinkKey, MerchantLinks, MerchantPatch, MerchantResponse, MessageInfo, ParsedBasket, Product, ProductInstance, ProductInstanceInput, ProductInstances, ProductResponse, ProductSaveInput, Promotion, PromotionResponse, PromotionRuleSet, ReportData, ReportKey, ReportQuery, ReportQueryMap, ReportResponse, RepricedInstance, RequestOptions, ResourceDefinition, ResourceKind, SHOPWAVE_ENTITIES, SHOPWAVE_IMAGE_BASE_URL, SHOPWAVE_LOOKUPS, SHOPWAVE_RESOURCES, SHOPWAVE_UPLOAD, Saved, SessionStatus, ShopwaveApiError, ShopwaveErrorMap, Store, StoreResponse, SubmitEntityArgs, SubmitEntityResponse, SuccessMessage, UPLOAD_KINDS, UpdateMerchantOptions, UploadImageParams, UploadKind, UploadMerchantImageOptions, UploadedImage, User, UserEmployee, UserResponse, WritableEntityKind, apiDelete, apiGet, apiRequest, apiResponse, apiSend, assertNoApiErrors, authorizationFor, buildBasketReportQuery, buildConsumerMap, collectConsumerIds, collectProductIds, combineBasketRows, computeBasketSummary, coverCrop, deleteCategory, deleteEmployee, deleteEntity, deleteEntityById, deleteProduct, deletePromotion, deleteStore, fetchCategories, fetchCategory, fetchConsumer, fetchConsumers, fetchEmployee, fetchEmployees, fetchEntityById, fetchMerchant, fetchProduct, fetchProductInstanceTags, fetchProductTags, fetchProducts, fetchProductsMap, fetchPromotion, fetchPromotions, fetchReport, fetchSession, fetchStore, fetchStores, fetchUser, findRepricedInstances, fitImageToSize, formatDateForQuery, getApiErrorMap, getApiErrors, getImageUrl, getMerchantImage, getMerchantImageUrl, imageFileName, isSameInstancePrice, isUploadKind, loginPath, logout, logoutPath, merchantLinksFromForm, merchantLinksToForm, normalizeMerchantLinks, normalizeTagList, parseBasketReportData, readImageSize, rolesById, saveCategory, saveEmployee, saveEntities, saveEntity, saveProduct, savePromotion, saveStore, setMerchantImage, submitEntity, toProductInstancesForSave, toShopwaveApiError, toStoredImageIds, updateMerchant, uploadImage, uploadMerchantImage, validateMerchant, withToken };
1178
1228
  //# sourceMappingURL=index.d.ts.map
@@ -349,6 +349,106 @@ async function fetchProductsMap(productIds, options = {}, batchSize = 200) {
349
349
  return result;
350
350
  }
351
351
 
352
+ //#endregion
353
+ //#region src/core/resources.ts
354
+ /**
355
+ * - merchant: `GET /merchant`; `POST /merchant` with `{ merchant: { id, … } }`
356
+ * updates it (without an `id` the API would create a second merchant, so the
357
+ * route requires one).
358
+ * - user: `GET /user` (read-only here; the API's `POST /user` invites users and
359
+ * needs the admin scope).
360
+ */
361
+ const SHOPWAVE_RESOURCES = Object.freeze({
362
+ merchant: {
363
+ route: "merchant",
364
+ key: "merchant",
365
+ upstream: "merchant",
366
+ writable: true
367
+ },
368
+ user: {
369
+ route: "user",
370
+ key: "user",
371
+ upstream: "user",
372
+ writable: false
373
+ }
374
+ });
375
+ /** `UploadKind` → the API's `contentType` value. */
376
+ const UPLOAD_KINDS = Object.freeze({
377
+ merchant: "merchant",
378
+ merchantFeature: "merchantFeature",
379
+ product: "product",
380
+ user: "user",
381
+ applicationLogo: "applicaionLogo",
382
+ applicationImages: "applicaionImages"
383
+ });
384
+ /** How uploads are addressed (app route and Shopwave uploader). */
385
+ const SHOPWAVE_UPLOAD = Object.freeze({
386
+ route: "upload",
387
+ upstream: "uploader",
388
+ kindHeader: "contentType",
389
+ fileField: "file",
390
+ kindField: "kind"
391
+ });
392
+ function isUploadKind(value) {
393
+ return typeof value === "string" && Object.prototype.hasOwnProperty.call(UPLOAD_KINDS, value);
394
+ }
395
+ const SHOPWAVE_LOOKUPS = Object.freeze({
396
+ productTags: {
397
+ route: "products/tags",
398
+ key: "tags",
399
+ upstream: "product/tags"
400
+ },
401
+ productInstanceTags: {
402
+ route: "products/instance-tags",
403
+ key: "tags",
404
+ upstream: "product/instance/tags"
405
+ }
406
+ });
407
+
408
+ //#endregion
409
+ //#region src/core/productTags.ts
410
+ /**
411
+ * Turns a tag list from the API into clean strings: trims each tag, drops
412
+ * blanks and anything that isn't text, and removes exact duplicates (first one
413
+ * wins). The API's own order is kept. A map is accepted too (its values are
414
+ * used), in case the API ever answers keyed by id.
415
+ */
416
+ function normalizeTagList(value) {
417
+ const list = Array.isArray(value) ? value : value && typeof value === "object" ? Object.values(value) : [];
418
+ const seen = /* @__PURE__ */ new Set();
419
+ const out = [];
420
+ for (const item of list) {
421
+ if (typeof item !== "string" && typeof item !== "number") continue;
422
+ const tag = String(item).trim();
423
+ if (!tag || seen.has(tag)) continue;
424
+ seen.add(tag);
425
+ out.push(tag);
426
+ }
427
+ return out;
428
+ }
429
+ async function fetchLookup(kind, options) {
430
+ const def = SHOPWAVE_LOOKUPS[kind];
431
+ if (!def) throw new Error(`Unknown Shopwave lookup "${kind}"`);
432
+ const json = await apiGet(`/api/${def.route}`, {}, options);
433
+ assertNoApiErrors(json, 200);
434
+ return normalizeTagList(json?.[def.key]);
435
+ }
436
+ /**
437
+ * Every distinct tag used on the merchant's products (`GET /product/tags`),
438
+ * for a tag field's suggestions. Returns `[]` when there are none.
439
+ */
440
+ function fetchProductTags(options = {}) {
441
+ return fetchLookup("productTags", options);
442
+ }
443
+ /**
444
+ * Every distinct tag used on the merchant's price instances
445
+ * (`GET /product/instance/tags`): the channel names (Eat In, Takeout, …).
446
+ * Returns `[]` when there are none.
447
+ */
448
+ function fetchProductInstanceTags(options = {}) {
449
+ return fetchLookup("productInstanceTags", options);
450
+ }
451
+
352
452
  //#endregion
353
453
  //#region src/core/promotion.ts
354
454
  /** Promotion rule identifiers as stored by the Shopwave API. */
@@ -810,50 +910,6 @@ function buildConsumerMap(consumers) {
810
910
  return map;
811
911
  }
812
912
 
813
- //#endregion
814
- //#region src/core/resources.ts
815
- /**
816
- * - merchant: `GET /merchant`; `POST /merchant` with `{ merchant: { id, … } }`
817
- * updates it (without an `id` the API would create a second merchant, so the
818
- * route requires one).
819
- * - user: `GET /user` (read-only here; the API's `POST /user` invites users and
820
- * needs the admin scope).
821
- */
822
- const SHOPWAVE_RESOURCES = Object.freeze({
823
- merchant: {
824
- route: "merchant",
825
- key: "merchant",
826
- upstream: "merchant",
827
- writable: true
828
- },
829
- user: {
830
- route: "user",
831
- key: "user",
832
- upstream: "user",
833
- writable: false
834
- }
835
- });
836
- /** `UploadKind` → the API's `contentType` value. */
837
- const UPLOAD_KINDS = Object.freeze({
838
- merchant: "merchant",
839
- merchantFeature: "merchantFeature",
840
- product: "product",
841
- user: "user",
842
- applicationLogo: "applicaionLogo",
843
- applicationImages: "applicaionImages"
844
- });
845
- /** How uploads are addressed (app route and Shopwave uploader). */
846
- const SHOPWAVE_UPLOAD = Object.freeze({
847
- route: "upload",
848
- upstream: "uploader",
849
- kindHeader: "contentType",
850
- fileField: "file",
851
- kindField: "kind"
852
- });
853
- function isUploadKind(value) {
854
- return typeof value === "string" && Object.prototype.hasOwnProperty.call(UPLOAD_KINDS, value);
855
- }
856
-
857
913
  //#endregion
858
914
  //#region src/core/imageFit.ts
859
915
  /**
@@ -1291,5 +1347,5 @@ async function fetchUser(options = {}) {
1291
1347
  }
1292
1348
 
1293
1349
  //#endregion
1294
- export { DEFAULT_BASKET_FILTERS, DEFAULT_PAGINATION, MERCHANT_COLOUR_KEYS, MERCHANT_FIELD_MAX_LENGTH, MERCHANT_IMAGE_SLOTS, MERCHANT_IMAGE_SLOT_KEYS, MERCHANT_LINK_KEYS, MERCHANT_LINK_PATHS, MERCHANT_OBJECT_FIELDS, MERCHANT_READ_ONLY_FIELDS, PromotionRuleSet, SHOPWAVE_ENTITIES, SHOPWAVE_IMAGE_BASE_URL, SHOPWAVE_RESOURCES, SHOPWAVE_UPLOAD, ShopwaveApiError, UPLOAD_KINDS, apiDelete, apiGet, apiRequest, apiSend, assertNoApiErrors, authorizationFor, buildBasketReportQuery, buildConsumerMap, collectConsumerIds, collectProductIds, combineBasketRows, computeBasketSummary, coverCrop, deleteCategory, deleteEmployee, deleteEntity, deleteEntityById, deleteProduct, deletePromotion, deleteStore, fetchCategories, fetchCategory, fetchConsumer, fetchConsumers, fetchEmployee, fetchEmployees, fetchEntityById, fetchMerchant, fetchProduct, fetchProducts, fetchProductsMap, fetchPromotion, fetchPromotions, fetchReport, fetchSession, fetchStore, fetchStores, fetchUser, findRepricedInstances, fitImageToSize, formatDateForQuery, getApiErrorMap, getApiErrors, getImageUrl, getMerchantImage, getMerchantImageUrl, imageFileName, isSameInstancePrice, isUploadKind, loginPath, logout, logoutPath, merchantLinksFromForm, merchantLinksToForm, normalizeMerchantLinks, parseBasketReportData, readImageSize, rolesById, saveCategory, saveEmployee, saveEntities, saveEntity, saveProduct, savePromotion, saveStore, setMerchantImage, submitEntity, toProductInstancesForSave, toShopwaveApiError, toStoredImageIds, updateMerchant, uploadImage, uploadMerchantImage, validateMerchant, withToken };
1350
+ export { DEFAULT_BASKET_FILTERS, DEFAULT_PAGINATION, MERCHANT_COLOUR_KEYS, MERCHANT_FIELD_MAX_LENGTH, MERCHANT_IMAGE_SLOTS, MERCHANT_IMAGE_SLOT_KEYS, MERCHANT_LINK_KEYS, MERCHANT_LINK_PATHS, MERCHANT_OBJECT_FIELDS, MERCHANT_READ_ONLY_FIELDS, PromotionRuleSet, SHOPWAVE_ENTITIES, SHOPWAVE_IMAGE_BASE_URL, SHOPWAVE_LOOKUPS, SHOPWAVE_RESOURCES, SHOPWAVE_UPLOAD, ShopwaveApiError, UPLOAD_KINDS, apiDelete, apiGet, apiRequest, apiSend, assertNoApiErrors, authorizationFor, buildBasketReportQuery, buildConsumerMap, collectConsumerIds, collectProductIds, combineBasketRows, computeBasketSummary, coverCrop, deleteCategory, deleteEmployee, deleteEntity, deleteEntityById, deleteProduct, deletePromotion, deleteStore, fetchCategories, fetchCategory, fetchConsumer, fetchConsumers, fetchEmployee, fetchEmployees, fetchEntityById, fetchMerchant, fetchProduct, fetchProductInstanceTags, fetchProductTags, fetchProducts, fetchProductsMap, fetchPromotion, fetchPromotions, fetchReport, fetchSession, fetchStore, fetchStores, fetchUser, findRepricedInstances, fitImageToSize, formatDateForQuery, getApiErrorMap, getApiErrors, getImageUrl, getMerchantImage, getMerchantImageUrl, imageFileName, isSameInstancePrice, isUploadKind, loginPath, logout, logoutPath, merchantLinksFromForm, merchantLinksToForm, normalizeMerchantLinks, normalizeTagList, parseBasketReportData, readImageSize, rolesById, saveCategory, saveEmployee, saveEntities, saveEntity, saveProduct, savePromotion, saveStore, setMerchantImage, submitEntity, toProductInstancesForSave, toShopwaveApiError, toStoredImageIds, updateMerchant, uploadImage, uploadMerchantImage, validateMerchant, withToken };
1295
1351
  //# sourceMappingURL=index.js.map