@sixtyninecommerce/admin 0.10.0 → 0.12.0

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.
Files changed (302) hide show
  1. package/README.md +5772 -118
  2. package/dist/auth/index.d.ts +7 -1
  3. package/dist/auth/index.js +8 -1
  4. package/dist/catalog/assets.d.ts +120 -8
  5. package/dist/catalog/assets.js +98 -12
  6. package/dist/catalog/collections.d.ts +279 -14
  7. package/dist/catalog/collections.js +246 -15
  8. package/dist/catalog/documents.d.ts +142 -0
  9. package/dist/catalog/documents.js +114 -0
  10. package/dist/catalog/index.d.ts +54 -6
  11. package/dist/catalog/index.js +10 -1
  12. package/dist/catalog/metadata.d.ts +244 -0
  13. package/dist/catalog/metadata.js +220 -0
  14. package/dist/catalog/products.d.ts +159 -19
  15. package/dist/catalog/products.js +88 -13
  16. package/dist/catalog/properties.d.ts +140 -14
  17. package/dist/catalog/properties.js +65 -1
  18. package/dist/catalog/recommendations.d.ts +288 -0
  19. package/dist/catalog/recommendations.js +237 -0
  20. package/dist/catalog/reviews.d.ts +381 -0
  21. package/dist/catalog/reviews.js +325 -0
  22. package/dist/catalog/types.d.ts +17 -1
  23. package/dist/catalog/types.js +10 -0
  24. package/dist/catalog/variant-find.d.ts +136 -0
  25. package/dist/catalog/variant-find.js +239 -0
  26. package/dist/catalog/variants.d.ts +293 -26
  27. package/dist/catalog/variants.js +164 -7
  28. package/dist/catalog/visibility.d.ts +38 -7
  29. package/dist/catalog/visibility.js +19 -1
  30. package/dist/client.d.ts +121 -9
  31. package/dist/client.js +53 -14
  32. package/dist/content/assets.d.ts +285 -0
  33. package/dist/content/assets.js +181 -0
  34. package/dist/content/forms.d.ts +332 -1
  35. package/dist/content/forms.js +140 -4
  36. package/dist/content/items.d.ts +292 -0
  37. package/dist/content/items.js +170 -0
  38. package/dist/content/menus.d.ts +254 -0
  39. package/dist/content/menus.js +70 -0
  40. package/dist/content/strings.d.ts +137 -0
  41. package/dist/content/strings.js +82 -0
  42. package/dist/content/types.d.ts +282 -0
  43. package/dist/content/types.js +100 -0
  44. package/dist/customers/age-verification.d.ts +66 -0
  45. package/dist/customers/age-verification.js +79 -0
  46. package/dist/customers/credit.d.ts +263 -0
  47. package/dist/customers/credit.js +244 -0
  48. package/dist/customers/delivery-preferences.d.ts +120 -0
  49. package/dist/customers/delivery-preferences.js +97 -0
  50. package/dist/customers/delivery-terms.d.ts +44 -0
  51. package/dist/customers/delivery-terms.js +32 -0
  52. package/dist/customers/groups.d.ts +207 -0
  53. package/dist/customers/groups.js +438 -0
  54. package/dist/customers/index.d.ts +462 -37
  55. package/dist/customers/index.js +317 -40
  56. package/dist/customers/invitation-status.d.ts +57 -0
  57. package/dist/customers/invitation-status.js +21 -0
  58. package/dist/customers/notes.d.ts +67 -0
  59. package/dist/customers/notes.js +51 -0
  60. package/dist/customers/notification-recipients.d.ts +97 -0
  61. package/dist/customers/notification-recipients.js +84 -0
  62. package/dist/customers/saved-lists.d.ts +42 -0
  63. package/dist/customers/saved-lists.js +61 -0
  64. package/dist/customers/vat.d.ts +83 -0
  65. package/dist/customers/vat.js +46 -0
  66. package/dist/customers/wire.d.ts +20 -0
  67. package/dist/customers/wire.js +35 -0
  68. package/dist/documents/ar.d.ts +307 -0
  69. package/dist/documents/ar.js +254 -0
  70. package/dist/documents/emails.d.ts +150 -0
  71. package/dist/documents/emails.js +220 -0
  72. package/dist/documents/index.d.ts +744 -21
  73. package/dist/documents/index.js +438 -24
  74. package/dist/documents/pdf.d.ts +2 -0
  75. package/dist/documents/pdf.js +11 -0
  76. package/dist/fulfillments/create.d.ts +167 -0
  77. package/dist/fulfillments/create.js +216 -0
  78. package/dist/fulfillments/index.d.ts +163 -11
  79. package/dist/fulfillments/index.js +135 -6
  80. package/dist/fulfillments/payment-policy.d.ts +64 -0
  81. package/dist/fulfillments/payment-policy.js +140 -0
  82. package/dist/fulfillments/warehouse.d.ts +724 -0
  83. package/dist/fulfillments/warehouse.js +914 -0
  84. package/dist/geo/index.d.ts +119 -0
  85. package/dist/geo/index.js +107 -0
  86. package/dist/index.d.ts +147 -39
  87. package/dist/index.js +51 -12
  88. package/dist/integrations/afas-actions.d.ts +234 -0
  89. package/dist/integrations/afas-actions.js +310 -0
  90. package/dist/integrations/afas-types.d.ts +483 -0
  91. package/dist/integrations/afas-types.js +5 -0
  92. package/dist/integrations/afas.d.ts +234 -0
  93. package/dist/integrations/afas.js +290 -0
  94. package/dist/integrations/connections.d.ts +103 -0
  95. package/dist/integrations/connections.js +55 -0
  96. package/dist/integrations/esp.d.ts +313 -0
  97. package/dist/integrations/esp.js +169 -0
  98. package/dist/integrations/exact-online-types.d.ts +965 -0
  99. package/dist/integrations/exact-online-types.js +6 -0
  100. package/dist/integrations/exact-online.d.ts +784 -0
  101. package/dist/integrations/exact-online.js +1089 -0
  102. package/dist/integrations/index.d.ts +44 -3
  103. package/dist/integrations/index.js +23 -3
  104. package/dist/integrations/pipeline-discoveries.d.ts +65 -0
  105. package/dist/integrations/pipeline-discoveries.js +65 -0
  106. package/dist/integrations/pipeline-keys.d.ts +13 -0
  107. package/dist/integrations/pipeline-keys.js +22 -0
  108. package/dist/integrations/pipeline-runs.d.ts +119 -0
  109. package/dist/integrations/pipeline-runs.js +87 -0
  110. package/dist/integrations/pipelines.d.ts +87 -15
  111. package/dist/integrations/pipelines.js +41 -22
  112. package/dist/integrations/price-import.d.ts +223 -0
  113. package/dist/integrations/price-import.js +124 -0
  114. package/dist/integrations/types.d.ts +367 -3
  115. package/dist/integrations/types.js +4 -3
  116. package/dist/locations/index.d.ts +66 -0
  117. package/dist/locations/index.js +31 -0
  118. package/dist/meta/index.d.ts +172 -0
  119. package/dist/metafields/index.d.ts +8 -1
  120. package/dist/metafields/index.js +10 -0
  121. package/dist/orders/cancel-with-money.d.ts +237 -0
  122. package/dist/orders/cancel-with-money.js +155 -0
  123. package/dist/orders/commit-edit.d.ts +23 -1
  124. package/dist/orders/commit-edit.js +19 -2
  125. package/dist/orders/deposit-policy.d.ts +3 -1
  126. package/dist/orders/drafts.d.ts +800 -0
  127. package/dist/orders/drafts.js +771 -0
  128. package/dist/orders/fields.d.ts +245 -0
  129. package/dist/orders/fields.js +188 -0
  130. package/dist/orders/get.d.ts +29 -19
  131. package/dist/orders/get.js +17 -8
  132. package/dist/orders/index.d.ts +66 -15
  133. package/dist/orders/index.js +25 -2
  134. package/dist/orders/lifecycle.d.ts +128 -0
  135. package/dist/orders/lifecycle.js +158 -0
  136. package/dist/orders/line-price-preview.d.ts +7 -2
  137. package/dist/orders/list.d.ts +243 -0
  138. package/dist/orders/list.js +487 -0
  139. package/dist/orders/manual-discounts.d.ts +13 -5
  140. package/dist/orders/manual-pricing.d.ts +5 -0
  141. package/dist/orders/money-view.d.ts +149 -0
  142. package/dist/orders/money-view.js +99 -0
  143. package/dist/orders/order-entry.d.ts +20 -7
  144. package/dist/orders/plan-edit.d.ts +34 -2
  145. package/dist/orders/plan-edit.js +112 -11
  146. package/dist/orders/settings.d.ts +201 -0
  147. package/dist/orders/settings.js +325 -0
  148. package/dist/orders/status.d.ts +159 -13
  149. package/dist/orders/status.js +21 -0
  150. package/dist/orders/surcharges.d.ts +20 -1
  151. package/dist/orders/surcharges.js +37 -11
  152. package/dist/payments/account-credit.d.ts +46 -0
  153. package/dist/payments/account-credit.js +42 -0
  154. package/dist/payments/ar.d.ts +292 -0
  155. package/dist/payments/ar.js +223 -0
  156. package/dist/payments/connected-account.d.ts +47 -0
  157. package/dist/payments/connected-account.js +61 -0
  158. package/dist/payments/credit-noted-fields.d.ts +19 -0
  159. package/dist/payments/credit-noted-fields.js +69 -0
  160. package/dist/payments/customer-consent.d.ts +30 -0
  161. package/dist/payments/customer-consent.js +49 -0
  162. package/dist/payments/index.d.ts +340 -19
  163. package/dist/payments/index.js +151 -1
  164. package/dist/payments/methods.d.ts +303 -8
  165. package/dist/payments/methods.js +337 -7
  166. package/dist/payments/mollie-methods.d.ts +159 -0
  167. package/dist/payments/mollie-methods.js +141 -0
  168. package/dist/payments/payment-links.d.ts +180 -0
  169. package/dist/payments/payment-links.js +97 -0
  170. package/dist/payments/provider-keys.d.ts +150 -0
  171. package/dist/payments/provider-keys.js +118 -0
  172. package/dist/payments/providers.d.ts +86 -11
  173. package/dist/payments/providers.js +29 -0
  174. package/dist/payments/requests.d.ts +147 -0
  175. package/dist/payments/requests.js +93 -0
  176. package/dist/payments/store-credit-fields.d.ts +15 -0
  177. package/dist/payments/store-credit-fields.js +51 -0
  178. package/dist/pickups/index.d.ts +106 -0
  179. package/dist/pickups/index.js +108 -0
  180. package/dist/platform/channels.d.ts +132 -0
  181. package/dist/platform/channels.js +128 -0
  182. package/dist/platform/email-gateways.d.ts +165 -0
  183. package/dist/platform/email-gateways.js +78 -0
  184. package/dist/platform/geo.d.ts +123 -0
  185. package/dist/platform/geo.js +144 -0
  186. package/dist/platform/tax.d.ts +162 -0
  187. package/dist/platform/tax.js +169 -0
  188. package/dist/pos/anomalies.d.ts +158 -0
  189. package/dist/pos/anomalies.js +64 -0
  190. package/dist/pos/assisted-selling.d.ts +79 -0
  191. package/dist/pos/assisted-selling.js +38 -0
  192. package/dist/pos/exchanges.d.ts +108 -0
  193. package/dist/pos/exchanges.js +22 -0
  194. package/dist/pos/gift-cards.d.ts +135 -0
  195. package/dist/pos/gift-cards.js +47 -0
  196. package/dist/pos/index.d.ts +2370 -58
  197. package/dist/pos/index.js +854 -7
  198. package/dist/pos/no-receipt.d.ts +94 -0
  199. package/dist/pos/no-receipt.js +25 -0
  200. package/dist/pos/offline-sales.d.ts +228 -0
  201. package/dist/pos/offline-sales.js +170 -0
  202. package/dist/pos/pay-by-link.d.ts +143 -0
  203. package/dist/pos/pay-by-link.js +57 -0
  204. package/dist/pos/quick-keys.d.ts +103 -0
  205. package/dist/pos/quick-keys.js +45 -0
  206. package/dist/pos/reports.d.ts +360 -0
  207. package/dist/pos/reports.js +62 -0
  208. package/dist/pos/returns.d.ts +244 -0
  209. package/dist/pos/returns.js +83 -0
  210. package/dist/pricing/bulk-coupons.d.ts +139 -0
  211. package/dist/pricing/bulk-coupons.js +112 -0
  212. package/dist/pricing/index.d.ts +174 -4
  213. package/dist/pricing/index.js +174 -1
  214. package/dist/pricing/price-lists.d.ts +606 -0
  215. package/dist/pricing/price-lists.js +600 -0
  216. package/dist/purchasing/alerts.d.ts +104 -0
  217. package/dist/purchasing/alerts.js +88 -0
  218. package/dist/purchasing/backorders.d.ts +61 -0
  219. package/dist/purchasing/backorders.js +92 -0
  220. package/dist/purchasing/cost.d.ts +110 -0
  221. package/dist/purchasing/cost.js +86 -0
  222. package/dist/purchasing/index.d.ts +54 -0
  223. package/dist/purchasing/index.js +24 -0
  224. package/dist/purchasing/links.d.ts +263 -0
  225. package/dist/purchasing/links.js +192 -0
  226. package/dist/purchasing/purchase-orders.d.ts +551 -0
  227. package/dist/purchasing/purchase-orders.js +491 -0
  228. package/dist/purchasing/receipts.d.ts +396 -0
  229. package/dist/purchasing/receipts.js +287 -0
  230. package/dist/purchasing/replenishment.d.ts +281 -0
  231. package/dist/purchasing/replenishment.js +240 -0
  232. package/dist/purchasing/returns.d.ts +273 -0
  233. package/dist/purchasing/returns.js +229 -0
  234. package/dist/purchasing/settings.d.ts +152 -0
  235. package/dist/purchasing/settings.js +181 -0
  236. package/dist/purchasing/suppliers.d.ts +476 -0
  237. package/dist/purchasing/suppliers.js +438 -0
  238. package/dist/quotes/index.d.ts +518 -0
  239. package/dist/quotes/index.js +439 -0
  240. package/dist/reports/index.d.ts +71 -8
  241. package/dist/reports/index.js +74 -11
  242. package/dist/returns/index.d.ts +675 -21
  243. package/dist/returns/index.js +756 -11
  244. package/dist/search/index.d.ts +76 -1
  245. package/dist/search/index.js +63 -0
  246. package/dist/seo/config.d.ts +128 -0
  247. package/dist/seo/config.js +95 -0
  248. package/dist/seo/redirects.d.ts +125 -0
  249. package/dist/seo/redirects.js +60 -1
  250. package/dist/seo/settings.d.ts +147 -0
  251. package/dist/seo/settings.js +209 -0
  252. package/dist/shipping/definitions.d.ts +29 -0
  253. package/dist/shipping/definitions.js +47 -0
  254. package/dist/shipping/fulfillment-profiles.d.ts +174 -0
  255. package/dist/shipping/fulfillment-profiles.js +104 -0
  256. package/dist/shipping/hendriks.d.ts +97 -0
  257. package/dist/shipping/hendriks.js +50 -0
  258. package/dist/shipping/index.d.ts +54 -0
  259. package/dist/shipping/index.js +27 -0
  260. package/dist/shipping/methods.d.ts +205 -0
  261. package/dist/shipping/methods.js +240 -0
  262. package/dist/shipping/myparcel.d.ts +668 -0
  263. package/dist/shipping/myparcel.js +466 -0
  264. package/dist/shipping/parcel-count-suggestion.d.ts +2 -0
  265. package/dist/shipping/parcel-rule.d.ts +6 -5
  266. package/dist/shipping/parcel-rule.js +21 -23
  267. package/dist/shipping/rate-tables.d.ts +324 -0
  268. package/dist/shipping/rate-tables.js +390 -0
  269. package/dist/shipping/ship-to-countries.d.ts +75 -0
  270. package/dist/shipping/ship-to-countries.js +47 -0
  271. package/dist/stock/by-location.d.ts +86 -0
  272. package/dist/stock/by-location.js +94 -0
  273. package/dist/stock/index.d.ts +18 -4
  274. package/dist/stock/index.js +7 -0
  275. package/dist/stock/locations.d.ts +144 -0
  276. package/dist/stock/locations.js +168 -0
  277. package/dist/stock/settings.d.ts +106 -0
  278. package/dist/stock/settings.js +103 -0
  279. package/dist/stock/transfers.d.ts +386 -52
  280. package/dist/stock/transfers.js +222 -17
  281. package/dist/stored-value/index.d.ts +312 -11
  282. package/dist/stored-value/index.js +223 -4
  283. package/dist/subscriptions/index.d.ts +682 -0
  284. package/dist/subscriptions/index.js +815 -0
  285. package/dist/tax/display-policy.d.ts +105 -0
  286. package/dist/tax/display-policy.js +84 -0
  287. package/dist/tax/index.d.ts +79 -1
  288. package/dist/tax/index.js +52 -0
  289. package/dist/tenant/email-style.d.ts +102 -0
  290. package/dist/tenant/email-style.js +72 -0
  291. package/dist/tenant/email-templates.d.ts +287 -0
  292. package/dist/tenant/email-templates.js +271 -0
  293. package/dist/tenant/notifications.d.ts +23 -17
  294. package/dist/tenant/settings-sources.d.ts +1 -1
  295. package/dist/tenant/time-zone.d.ts +17 -0
  296. package/dist/tenant/time-zone.js +11 -0
  297. package/dist/types.d.ts +50 -3
  298. package/dist/users/index.d.ts +3 -0
  299. package/dist/users/index.js +2 -0
  300. package/dist/users/warehouses.d.ts +50 -0
  301. package/dist/users/warehouses.js +51 -0
  302. package/package.json +2 -2
@@ -0,0 +1,239 @@
1
+ import { ValidationError } from '@sixtyninecommerce/core';
2
+ import { createSearchModule, escapeSearchFilterValue } from '../search/index.js';
3
+ import { fieldOf } from './types.js';
4
+ /** The most variants one `variants.find` answers. */
5
+ export const MAX_VARIANT_FIND_TAKE = 500;
6
+ /** The most products one `variants.find` search reads (`take / perProduct`, rounded up). */
7
+ export const MAX_VARIANT_FIND_PRODUCTS = 100;
8
+ const FOUND_VARIANT_PRODUCT_FIELDS = /* GraphQL */ `
9
+ id
10
+ name
11
+ slug
12
+ featuredAsset {
13
+ id
14
+ preview
15
+ }
16
+ `;
17
+ /**
18
+ * What a picker reads of a variant. `storePrice`, never core's `price` / `priceWithTax`: those
19
+ * throw for a variant the store has no price for, and one such variant would empty the answer.
20
+ */
21
+ export const FOUND_VARIANT_FIELDS = /* GraphQL */ `
22
+ id
23
+ name
24
+ sku
25
+ enabled
26
+ storePrice {
27
+ price
28
+ priceWithTax
29
+ currencyCode
30
+ }
31
+ trackInventory
32
+ outOfStockThreshold
33
+ useGlobalOutOfStockThreshold
34
+ stockOnHand
35
+ stockAllocated
36
+ stockLevels {
37
+ stockLocationId
38
+ stockOnHand
39
+ stockAllocated
40
+ stockLocation {
41
+ id
42
+ name
43
+ }
44
+ }
45
+ `;
46
+ /** A found variant with its product: the selection of every list that answers variants flat. */
47
+ export const FOUND_VARIANT_WITH_PRODUCT_FIELDS = /* GraphQL */ `
48
+ ${FOUND_VARIANT_FIELDS}
49
+ product {
50
+ ${FOUND_VARIANT_PRODUCT_FIELDS}
51
+ }
52
+ `;
53
+ export const FIND_VARIANTS_BY_IDS_QUERY = /* GraphQL */ `
54
+ query CatalogFindVariantsByIds($options: ProductVariantListOptions) {
55
+ productVariants(options: $options) {
56
+ items {
57
+ ${FOUND_VARIANT_WITH_PRODUCT_FIELDS}
58
+ }
59
+ totalItems
60
+ }
61
+ }
62
+ `;
63
+ /**
64
+ * The variants of some products, bounded PER PRODUCT (`variantList`, never `variants`, which the
65
+ * engine answers whole and then cuts at 1,000 without saying so).
66
+ */
67
+ export const FIND_VARIANTS_OF_PRODUCTS_QUERY = /* GraphQL */ `
68
+ query CatalogFindVariantsOfProducts(
69
+ $options: ProductListOptions
70
+ $variantOptions: ProductVariantListOptions
71
+ ) {
72
+ products(options: $options) {
73
+ items {
74
+ ${FOUND_VARIANT_PRODUCT_FIELDS}
75
+ variantList(options: $variantOptions) {
76
+ items {
77
+ ${FOUND_VARIANT_FIELDS}
78
+ }
79
+ totalItems
80
+ }
81
+ }
82
+ totalItems
83
+ }
84
+ }
85
+ `;
86
+ export function toFoundVariant(wire) {
87
+ const { stockLevels, product, ...rest } = wire;
88
+ return {
89
+ ...rest,
90
+ stockLevels: stockLevels.map((level) => ({
91
+ stockLocationId: level.stockLocationId,
92
+ stockLocationName: level.stockLocation?.name ?? '',
93
+ stockOnHand: level.stockOnHand,
94
+ stockAllocated: level.stockAllocated,
95
+ })),
96
+ product: {
97
+ id: product.id,
98
+ name: product.name,
99
+ slug: product.slug,
100
+ featuredAsset: product.featuredAsset,
101
+ },
102
+ };
103
+ }
104
+ function invalid(message) {
105
+ return new ValidationError({
106
+ code: 'VARIANT_FIND_INPUT_INVALID',
107
+ message,
108
+ status: 400,
109
+ service: 'vendure',
110
+ });
111
+ }
112
+ function wholeNumber(value, low, high) {
113
+ return typeof value === 'number' && Number.isInteger(value) && value >= low && value <= high;
114
+ }
115
+ /** A literal inside a regular expression the engine evaluates (Postgres `~*`). */
116
+ function escapeRegex(value) {
117
+ return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
118
+ }
119
+ function criterionOf(input) {
120
+ const given = ['ids', 'term', 'skuPrefix'].filter((key) => input[key] !== undefined);
121
+ if (given.length !== 1) {
122
+ throw invalid(`Say which variants with exactly one of ids, term and skuPrefix; got ${given.length === 0 ? 'none' : given.join(' and ')}.`);
123
+ }
124
+ if (input.ids !== undefined) {
125
+ if (!Array.isArray(input.ids) || input.ids.some((id) => typeof id !== 'string' || id === '')) {
126
+ throw invalid('ids must be a list of variant ids.');
127
+ }
128
+ return { kind: 'ids', ids: [...new Set(input.ids)] };
129
+ }
130
+ const key = input.term !== undefined ? 'term' : 'skuPrefix';
131
+ const text = input[key];
132
+ if (typeof text !== 'string' || text.trim() === '') {
133
+ throw invalid(`${key} must be text to search for; an empty one finds nothing.`);
134
+ }
135
+ return key === 'term'
136
+ ? { kind: 'term', term: text.trim() }
137
+ : { kind: 'skuPrefix', prefix: text.trim() };
138
+ }
139
+ /** The call's options with the currency the prices are asked in. */
140
+ function pricedIn(options, currencyCode) {
141
+ if (currencyCode === undefined)
142
+ return options;
143
+ if (typeof currencyCode !== 'string' || currencyCode.trim() === '') {
144
+ throw invalid('currencyCode must be an ISO 4217 code, or left out for the store default.');
145
+ }
146
+ return { ...options, tenant: { ...options?.tenant, currency: currencyCode } };
147
+ }
148
+ async function findByIds(transport, ids, take, options) {
149
+ if (ids.length > take) {
150
+ throw invalid(`ids names ${String(ids.length)} variants and take is ${String(take)}. Raise take, or ask for fewer.`);
151
+ }
152
+ if (ids.length === 0)
153
+ return { items: [], products: [] };
154
+ const list = await fieldOf(transport, FIND_VARIANTS_BY_IDS_QUERY, 'productVariants',
155
+ // Sorted so the engine's page is one total order; the answer is re-ordered below.
156
+ { options: { filter: { id: { in: ids } }, take: ids.length, sort: { id: 'ASC' } } }, options);
157
+ const found = new Map(list.items.map((row) => [row.id, row]));
158
+ return {
159
+ items: ids.flatMap((id) => {
160
+ const row = found.get(id);
161
+ return row ? [toFoundVariant(row)] : [];
162
+ }),
163
+ products: [],
164
+ };
165
+ }
166
+ async function findBySearch(transport, criterion, take, perProduct, options, pricedOptions) {
167
+ const productCount = Math.ceil(take / perProduct);
168
+ if (productCount > MAX_VARIANT_FIND_PRODUCTS) {
169
+ throw invalid(`take ${String(take)} at ${String(perProduct)} per product reads ${String(productCount)} products; at most ${String(MAX_VARIANT_FIND_PRODUCTS)}. Raise perProduct or lower take.`);
170
+ }
171
+ // Which products, and in what order, is the index's answer (`search.index`, never a copy of
172
+ // it): relevance for a term, the product's name for a SKU prefix.
173
+ const hits = await createSearchModule(transport).index('products', criterion.kind === 'term'
174
+ ? { term: criterion.term, take: productCount }
175
+ : {
176
+ term: '',
177
+ filters: [`skus STARTS WITH "${escapeSearchFilterValue(criterion.prefix)}"`],
178
+ sort: 'name',
179
+ take: productCount,
180
+ }, options);
181
+ const productIds = hits.items.map((hit) => hit.id);
182
+ if (productIds.length === 0)
183
+ return { items: [], products: [] };
184
+ const list = await fieldOf(transport, FIND_VARIANTS_OF_PRODUCTS_QUERY, 'products', {
185
+ options: { filter: { id: { in: productIds } }, take: productIds.length, sort: { id: 'ASC' } },
186
+ variantOptions: {
187
+ take: perProduct,
188
+ // A total order, so a bounded page is the same page on every read. By id alone: the
189
+ // engine applies the keys of a sort in the order its schema declares them, where `id`
190
+ // precedes `position`, so the `position, id` the pickers used to send was this order.
191
+ sort: { id: 'ASC' },
192
+ // Only a SKU search narrows the variants. A term matches the PRODUCT (its name, its
193
+ // description), and a variant's name is its options, so filtering variants by it would
194
+ // answer a product with nothing to pick.
195
+ ...(criterion.kind === 'skuPrefix'
196
+ ? { filter: { sku: { regex: `^${escapeRegex(criterion.prefix)}` } } }
197
+ : {}),
198
+ },
199
+ }, pricedOptions);
200
+ const read = new Map(list.items.map((product) => [product.id, product]));
201
+ const items = [];
202
+ const products = [];
203
+ for (const id of productIds) {
204
+ const room = take - items.length;
205
+ if (room <= 0)
206
+ break;
207
+ // The index can name a product the store no longer holds: it is updated after each change.
208
+ const product = read.get(id);
209
+ if (!product)
210
+ continue;
211
+ const rows = product.variantList.items.slice(0, room);
212
+ if (rows.length === 0)
213
+ continue;
214
+ for (const row of rows)
215
+ items.push(toFoundVariant({ ...row, product }));
216
+ products.push({ id: product.id, shown: rows.length, total: product.variantList.totalItems });
217
+ }
218
+ return { items, products };
219
+ }
220
+ /** `catalog.variants.find`; its contract is on `VariantsModule.find`. */
221
+ export async function findVariants(transport, input, options) {
222
+ if (typeof input !== 'object' || input === null)
223
+ throw invalid('find takes an input object.');
224
+ const criterion = criterionOf(input);
225
+ const { take, perProduct } = input;
226
+ if (!wholeNumber(take, 1, MAX_VARIANT_FIND_TAKE)) {
227
+ throw invalid(`take must be a whole number from 1 to ${String(MAX_VARIANT_FIND_TAKE)}.`);
228
+ }
229
+ const pricedOptions = pricedIn(options, input.currencyCode);
230
+ if (criterion.kind === 'ids') {
231
+ if (perProduct !== undefined)
232
+ throw invalid('perProduct bounds a search; ids takes none.');
233
+ return findByIds(transport, criterion.ids, take, pricedOptions);
234
+ }
235
+ if (perProduct !== undefined && !wholeNumber(perProduct, 1, take)) {
236
+ throw invalid(`perProduct must be a whole number from 1 to take (${String(take)}).`);
237
+ }
238
+ return findBySearch(transport, criterion, take, perProduct ?? Math.ceil(take / 10), options, pricedOptions);
239
+ }