@sixtyninecommerce/admin 0.10.0 → 0.11.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 (247) hide show
  1. package/README.md +4347 -171
  2. package/dist/catalog/assets.d.ts +120 -8
  3. package/dist/catalog/assets.js +98 -12
  4. package/dist/catalog/collections.d.ts +279 -14
  5. package/dist/catalog/collections.js +246 -15
  6. package/dist/catalog/index.d.ts +9 -2
  7. package/dist/catalog/index.js +4 -0
  8. package/dist/catalog/products.d.ts +159 -19
  9. package/dist/catalog/products.js +88 -13
  10. package/dist/catalog/properties.d.ts +102 -14
  11. package/dist/catalog/properties.js +13 -0
  12. package/dist/catalog/recommendations.d.ts +261 -0
  13. package/dist/catalog/recommendations.js +145 -0
  14. package/dist/catalog/reviews.d.ts +368 -0
  15. package/dist/catalog/reviews.js +318 -0
  16. package/dist/catalog/types.d.ts +17 -1
  17. package/dist/catalog/types.js +10 -0
  18. package/dist/catalog/variant-find.d.ts +136 -0
  19. package/dist/catalog/variant-find.js +239 -0
  20. package/dist/catalog/variants.d.ts +233 -26
  21. package/dist/catalog/variants.js +125 -7
  22. package/dist/catalog/visibility.d.ts +20 -5
  23. package/dist/catalog/visibility.js +19 -1
  24. package/dist/client.d.ts +95 -9
  25. package/dist/client.js +35 -7
  26. package/dist/content/assets.d.ts +286 -0
  27. package/dist/content/assets.js +181 -0
  28. package/dist/content/items.d.ts +269 -0
  29. package/dist/content/items.js +170 -0
  30. package/dist/content/types.d.ts +282 -0
  31. package/dist/content/types.js +100 -0
  32. package/dist/customers/age-verification.d.ts +66 -0
  33. package/dist/customers/age-verification.js +79 -0
  34. package/dist/customers/credit.d.ts +263 -0
  35. package/dist/customers/credit.js +244 -0
  36. package/dist/customers/delivery-preferences.d.ts +120 -0
  37. package/dist/customers/delivery-preferences.js +97 -0
  38. package/dist/customers/groups.d.ts +207 -0
  39. package/dist/customers/groups.js +438 -0
  40. package/dist/customers/index.d.ts +447 -37
  41. package/dist/customers/index.js +313 -40
  42. package/dist/customers/invitation-status.d.ts +57 -0
  43. package/dist/customers/invitation-status.js +21 -0
  44. package/dist/customers/notes.d.ts +67 -0
  45. package/dist/customers/notes.js +51 -0
  46. package/dist/customers/notification-recipients.d.ts +97 -0
  47. package/dist/customers/notification-recipients.js +84 -0
  48. package/dist/customers/saved-lists.d.ts +42 -0
  49. package/dist/customers/saved-lists.js +61 -0
  50. package/dist/customers/vat.d.ts +83 -0
  51. package/dist/customers/vat.js +46 -0
  52. package/dist/customers/wire.d.ts +20 -0
  53. package/dist/customers/wire.js +35 -0
  54. package/dist/documents/ar.d.ts +307 -0
  55. package/dist/documents/ar.js +254 -0
  56. package/dist/documents/index.d.ts +731 -21
  57. package/dist/documents/index.js +436 -24
  58. package/dist/documents/pdf.d.ts +2 -0
  59. package/dist/documents/pdf.js +11 -0
  60. package/dist/fulfillments/create.d.ts +167 -0
  61. package/dist/fulfillments/create.js +216 -0
  62. package/dist/fulfillments/index.d.ts +44 -10
  63. package/dist/fulfillments/index.js +11 -2
  64. package/dist/fulfillments/payment-policy.d.ts +64 -0
  65. package/dist/fulfillments/payment-policy.js +140 -0
  66. package/dist/fulfillments/warehouse.d.ts +724 -0
  67. package/dist/fulfillments/warehouse.js +914 -0
  68. package/dist/geo/index.d.ts +119 -0
  69. package/dist/geo/index.js +107 -0
  70. package/dist/index.d.ts +123 -35
  71. package/dist/index.js +45 -12
  72. package/dist/integrations/afas-actions.d.ts +234 -0
  73. package/dist/integrations/afas-actions.js +310 -0
  74. package/dist/integrations/afas-types.d.ts +483 -0
  75. package/dist/integrations/afas-types.js +5 -0
  76. package/dist/integrations/afas.d.ts +234 -0
  77. package/dist/integrations/afas.js +290 -0
  78. package/dist/integrations/connections.d.ts +103 -0
  79. package/dist/integrations/connections.js +55 -0
  80. package/dist/integrations/esp.d.ts +313 -0
  81. package/dist/integrations/esp.js +169 -0
  82. package/dist/integrations/exact-online-types.d.ts +423 -0
  83. package/dist/integrations/exact-online-types.js +6 -0
  84. package/dist/integrations/exact-online.d.ts +248 -0
  85. package/dist/integrations/exact-online.js +376 -0
  86. package/dist/integrations/index.d.ts +29 -3
  87. package/dist/integrations/index.js +18 -3
  88. package/dist/integrations/pipeline-keys.d.ts +13 -0
  89. package/dist/integrations/pipeline-keys.js +22 -0
  90. package/dist/integrations/pipelines.d.ts +15 -14
  91. package/dist/integrations/pipelines.js +6 -22
  92. package/dist/integrations/types.d.ts +146 -0
  93. package/dist/locations/index.d.ts +66 -0
  94. package/dist/locations/index.js +31 -0
  95. package/dist/meta/index.d.ts +162 -0
  96. package/dist/orders/cancel-with-money.d.ts +227 -0
  97. package/dist/orders/cancel-with-money.js +153 -0
  98. package/dist/orders/commit-edit.d.ts +7 -1
  99. package/dist/orders/commit-edit.js +5 -1
  100. package/dist/orders/drafts.d.ts +800 -0
  101. package/dist/orders/drafts.js +771 -0
  102. package/dist/orders/fields.d.ts +245 -0
  103. package/dist/orders/fields.js +188 -0
  104. package/dist/orders/get.d.ts +29 -19
  105. package/dist/orders/get.js +17 -8
  106. package/dist/orders/index.d.ts +49 -9
  107. package/dist/orders/index.js +22 -2
  108. package/dist/orders/lifecycle.d.ts +128 -0
  109. package/dist/orders/lifecycle.js +158 -0
  110. package/dist/orders/line-price-preview.d.ts +7 -2
  111. package/dist/orders/list.d.ts +222 -0
  112. package/dist/orders/list.js +377 -0
  113. package/dist/orders/manual-pricing.d.ts +5 -0
  114. package/dist/orders/order-entry.d.ts +20 -7
  115. package/dist/orders/plan-edit.d.ts +1 -1
  116. package/dist/orders/plan-edit.js +4 -1
  117. package/dist/orders/settings.d.ts +201 -0
  118. package/dist/orders/settings.js +325 -0
  119. package/dist/orders/status.d.ts +159 -13
  120. package/dist/orders/status.js +21 -0
  121. package/dist/orders/surcharges.d.ts +8 -1
  122. package/dist/orders/surcharges.js +3 -2
  123. package/dist/payments/account-credit.d.ts +30 -0
  124. package/dist/payments/account-credit.js +19 -0
  125. package/dist/payments/ar.d.ts +292 -0
  126. package/dist/payments/ar.js +223 -0
  127. package/dist/payments/connected-account.d.ts +47 -0
  128. package/dist/payments/connected-account.js +61 -0
  129. package/dist/payments/credit-noted-fields.d.ts +12 -0
  130. package/dist/payments/credit-noted-fields.js +37 -0
  131. package/dist/payments/index.d.ts +257 -11
  132. package/dist/payments/index.js +131 -1
  133. package/dist/payments/methods.d.ts +303 -8
  134. package/dist/payments/methods.js +337 -7
  135. package/dist/payments/mollie-methods.d.ts +159 -0
  136. package/dist/payments/mollie-methods.js +141 -0
  137. package/dist/payments/payment-links.d.ts +180 -0
  138. package/dist/payments/payment-links.js +97 -0
  139. package/dist/payments/provider-keys.d.ts +150 -0
  140. package/dist/payments/provider-keys.js +118 -0
  141. package/dist/payments/providers.d.ts +86 -11
  142. package/dist/payments/providers.js +29 -0
  143. package/dist/payments/requests.d.ts +144 -0
  144. package/dist/payments/requests.js +92 -0
  145. package/dist/payments/store-credit-fields.d.ts +15 -0
  146. package/dist/payments/store-credit-fields.js +51 -0
  147. package/dist/pickups/index.d.ts +104 -0
  148. package/dist/pickups/index.js +105 -0
  149. package/dist/platform/channels.d.ts +132 -0
  150. package/dist/platform/channels.js +128 -0
  151. package/dist/platform/geo.d.ts +123 -0
  152. package/dist/platform/geo.js +144 -0
  153. package/dist/platform/tax.d.ts +154 -0
  154. package/dist/platform/tax.js +139 -0
  155. package/dist/pos/anomalies.d.ts +158 -0
  156. package/dist/pos/anomalies.js +64 -0
  157. package/dist/pos/assisted-selling.d.ts +79 -0
  158. package/dist/pos/assisted-selling.js +38 -0
  159. package/dist/pos/exchanges.d.ts +103 -0
  160. package/dist/pos/exchanges.js +22 -0
  161. package/dist/pos/gift-cards.d.ts +135 -0
  162. package/dist/pos/gift-cards.js +47 -0
  163. package/dist/pos/index.d.ts +2125 -32
  164. package/dist/pos/index.js +742 -4
  165. package/dist/pos/no-receipt.d.ts +94 -0
  166. package/dist/pos/no-receipt.js +25 -0
  167. package/dist/pos/offline-sales.d.ts +187 -0
  168. package/dist/pos/offline-sales.js +116 -0
  169. package/dist/pos/pay-by-link.d.ts +143 -0
  170. package/dist/pos/pay-by-link.js +57 -0
  171. package/dist/pos/quick-keys.d.ts +103 -0
  172. package/dist/pos/quick-keys.js +45 -0
  173. package/dist/pos/reports.d.ts +360 -0
  174. package/dist/pos/reports.js +62 -0
  175. package/dist/pos/returns.d.ts +217 -0
  176. package/dist/pos/returns.js +53 -0
  177. package/dist/pricing/bulk-coupons.d.ts +139 -0
  178. package/dist/pricing/bulk-coupons.js +112 -0
  179. package/dist/pricing/index.d.ts +174 -4
  180. package/dist/pricing/index.js +174 -1
  181. package/dist/pricing/price-lists.d.ts +604 -0
  182. package/dist/pricing/price-lists.js +600 -0
  183. package/dist/purchasing/alerts.d.ts +89 -0
  184. package/dist/purchasing/alerts.js +62 -0
  185. package/dist/purchasing/cost.d.ts +110 -0
  186. package/dist/purchasing/cost.js +86 -0
  187. package/dist/purchasing/index.d.ts +36 -0
  188. package/dist/purchasing/index.js +16 -0
  189. package/dist/purchasing/purchase-orders.d.ts +548 -0
  190. package/dist/purchasing/purchase-orders.js +491 -0
  191. package/dist/purchasing/replenishment.d.ts +281 -0
  192. package/dist/purchasing/replenishment.js +240 -0
  193. package/dist/purchasing/settings.d.ts +152 -0
  194. package/dist/purchasing/settings.js +181 -0
  195. package/dist/purchasing/suppliers.d.ts +476 -0
  196. package/dist/purchasing/suppliers.js +438 -0
  197. package/dist/quotes/index.d.ts +501 -0
  198. package/dist/quotes/index.js +439 -0
  199. package/dist/reports/index.d.ts +71 -8
  200. package/dist/reports/index.js +74 -11
  201. package/dist/returns/index.d.ts +614 -21
  202. package/dist/returns/index.js +695 -11
  203. package/dist/search/index.d.ts +76 -1
  204. package/dist/search/index.js +63 -0
  205. package/dist/shipping/definitions.d.ts +29 -0
  206. package/dist/shipping/definitions.js +47 -0
  207. package/dist/shipping/fulfillment-profiles.d.ts +174 -0
  208. package/dist/shipping/fulfillment-profiles.js +104 -0
  209. package/dist/shipping/hendriks.d.ts +97 -0
  210. package/dist/shipping/hendriks.js +50 -0
  211. package/dist/shipping/index.d.ts +48 -0
  212. package/dist/shipping/index.js +25 -0
  213. package/dist/shipping/methods.d.ts +198 -0
  214. package/dist/shipping/methods.js +240 -0
  215. package/dist/shipping/myparcel.d.ts +254 -0
  216. package/dist/shipping/myparcel.js +178 -0
  217. package/dist/shipping/parcel-count-suggestion.d.ts +2 -0
  218. package/dist/shipping/parcel-rule.d.ts +6 -5
  219. package/dist/shipping/parcel-rule.js +21 -23
  220. package/dist/shipping/rate-tables.d.ts +179 -0
  221. package/dist/shipping/rate-tables.js +184 -0
  222. package/dist/stock/index.d.ts +10 -3
  223. package/dist/stock/index.js +3 -0
  224. package/dist/stock/locations.d.ts +144 -0
  225. package/dist/stock/locations.js +168 -0
  226. package/dist/stock/transfers.d.ts +216 -43
  227. package/dist/stock/transfers.js +140 -13
  228. package/dist/stored-value/index.d.ts +214 -4
  229. package/dist/stored-value/index.js +152 -0
  230. package/dist/subscriptions/index.d.ts +682 -0
  231. package/dist/subscriptions/index.js +815 -0
  232. package/dist/tax/index.d.ts +76 -1
  233. package/dist/tax/index.js +50 -0
  234. package/dist/tenant/email-style.d.ts +102 -0
  235. package/dist/tenant/email-style.js +72 -0
  236. package/dist/tenant/email-templates.d.ts +66 -0
  237. package/dist/tenant/email-templates.js +54 -0
  238. package/dist/tenant/notifications.d.ts +23 -17
  239. package/dist/tenant/settings-sources.d.ts +1 -1
  240. package/dist/tenant/time-zone.d.ts +17 -0
  241. package/dist/tenant/time-zone.js +11 -0
  242. package/dist/types.d.ts +50 -3
  243. package/dist/users/index.d.ts +3 -0
  244. package/dist/users/index.js +2 -0
  245. package/dist/users/warehouses.d.ts +50 -0
  246. package/dist/users/warehouses.js +51 -0
  247. package/package.json +2 -2
@@ -0,0 +1,269 @@
1
+ import { type Page, type Transport } from '@sixtyninecommerce/core';
2
+ import type { Call, ListOptions } from '../types.js';
3
+ /** The statuses the CMS gives an item; a read types `status` open, as {@link ContentItem} says. */
4
+ export type ContentItemStatus = 'draft' | 'published' | 'archived';
5
+ /**
6
+ * An item's own row: what every item answer carries, the write answers included.
7
+ *
8
+ * `collectionId` is the id of the item's content type (what the CMS calls a collection).
9
+ */
10
+ export interface ContentItemRecord {
11
+ id: string;
12
+ channelId: string;
13
+ collectionId: string;
14
+ /** Unique within the type; null for an item that has none (it then has no URL either). */
15
+ slug: string | null;
16
+ /** One of {@link ContentItemStatus}, typed open so a newer CMS's status still reads. */
17
+ status: string;
18
+ publishedAt: string | null;
19
+ /** The parent item in a hierarchical type; null at the top level. */
20
+ parentId: string | null;
21
+ /**
22
+ * The storefront URL path; null when the type has no `basePath` or the item has no slug.
23
+ */
24
+ path: string | null;
25
+ /** Order among its siblings. */
26
+ position: number;
27
+ createdAt: string;
28
+ updatedAt: string;
29
+ [extra: string]: unknown;
30
+ }
31
+ /** An item with its field values, as `items.list` answers it. */
32
+ export interface ContentItem extends ContentItemRecord {
33
+ /**
34
+ * Field slug → value, stored verbatim: the keys are the merchant's own field slugs and a
35
+ * value's inner keys are whatever was written, so neither is ever case-converted. With a
36
+ * `languageCode`, a localizable field's value in that language where one is stored, else its
37
+ * base value; without one, base values only.
38
+ */
39
+ values: Record<string, unknown>;
40
+ }
41
+ /** An item's slug and URL path in one language other than the store's default. */
42
+ export interface ContentItemSlugTranslation {
43
+ slug: string;
44
+ path: string | null;
45
+ }
46
+ /** One item as `items.get` answers it. */
47
+ export interface ContentItemDetail extends ContentItem {
48
+ /** Language code → the item's translated slug and path, for each language that has one. */
49
+ slugTranslations: Record<string, ContentItemSlugTranslation>;
50
+ }
51
+ /** One item as `items.lookup` resolves it: enough to label a reference to it. */
52
+ export interface ContentItemSummary {
53
+ id: string;
54
+ slug: string | null;
55
+ /** One of {@link ContentItemStatus}. */
56
+ status: string;
57
+ /** The item's content type. */
58
+ collectionId: string;
59
+ collectionName: string;
60
+ collectionTitleFieldSlug: string | null;
61
+ /** The item's base title-field value when it is a string, else null. */
62
+ title: string | null;
63
+ [extra: string]: unknown;
64
+ }
65
+ /** One item as `items.lookupWithFields` resolves it. */
66
+ export interface ContentItemWithFields {
67
+ id: string;
68
+ title: string | null;
69
+ /**
70
+ * Base (unlocalized) values of the requested field slugs, stored verbatim; a slug with no
71
+ * stored value is absent.
72
+ */
73
+ fieldValues: Record<string, unknown>;
74
+ [extra: string]: unknown;
75
+ }
76
+ export interface ContentItemListOptions extends ListOptions {
77
+ /**
78
+ * Only items in this status. Honoured for a credential holding `ReadCmsContent` on the
79
+ * store; any other caller is served published items only, whatever it asks for.
80
+ */
81
+ status?: ContentItemStatus;
82
+ /** Only the children of this item; `null` for the top-level items. Ignored with `search`. */
83
+ parentId?: string | null;
84
+ /** Only the item with this exact slug. Ignored with `search`. */
85
+ slug?: string;
86
+ /**
87
+ * Full-text search over the items' values; its results come in relevance order. The CMS's
88
+ * search applies `status` but not `parentId`, `slug` or `sort`, which it then ignores.
89
+ */
90
+ search?: string;
91
+ /**
92
+ * `position` (or `-position`) orders by the items' own order; without it, newest first.
93
+ * Ignored with `search`.
94
+ */
95
+ sort?: 'position' | '-position';
96
+ /**
97
+ * Each localizable value in this language where one is stored, else the base value. Without
98
+ * one, base values only: the client's tenant `language` is NOT applied here, so a list read
99
+ * and an `update` that writes it back name the same rows.
100
+ */
101
+ languageCode?: string;
102
+ }
103
+ export interface GetContentItemOptions extends Call {
104
+ /** As on {@link ContentItemListOptions.languageCode}: base values when omitted. */
105
+ languageCode?: string;
106
+ }
107
+ /**
108
+ * Exactly what `CreateItemDto` whitelists (the CMS runs `forbidNonWhitelisted`, so a fetched
109
+ * item handed back is a 400). No index signature, so excess-property checking fires.
110
+ */
111
+ export interface CreateContentItemInput {
112
+ /**
113
+ * Lowercase letters, digits and hyphens. Without one, the slug is made from the type's title
114
+ * field value when the type has one.
115
+ */
116
+ slug?: string;
117
+ /** A parent item of the same type; only a hierarchical type takes one. */
118
+ parentId?: string | null;
119
+ position?: number;
120
+ /**
121
+ * Field slug → value for the type's top-level `item` fields, sent verbatim. A slug that is
122
+ * not one of them is refused and nothing is written.
123
+ */
124
+ values?: Record<string, unknown>;
125
+ /**
126
+ * The language `values` are written in: a localizable field's value goes to that language,
127
+ * every other field's to the base. Omit it for the base values (the store's default
128
+ * language); naming the default language explicitly writes a separate language row.
129
+ */
130
+ languageCode?: string;
131
+ }
132
+ /**
133
+ * The members `items.update` acts on, the same DTO as create. An absent key leaves the stored
134
+ * value alone, and `values` writes only the slugs it names.
135
+ */
136
+ export interface UpdateContentItemInput {
137
+ /**
138
+ * The base slug; moves the item's path and every descendant's. With a non-default
139
+ * `languageCode`, the slug of that language instead. `null` clears the base slug (the item
140
+ * then has no URL).
141
+ */
142
+ slug?: string | null;
143
+ /** Moves the item under another parent of the same type; `null` to the top level. */
144
+ parentId?: string | null;
145
+ position?: number;
146
+ values?: Record<string, unknown>;
147
+ languageCode?: string;
148
+ }
149
+ /**
150
+ * The entries of a content type, read and written through the CMS.
151
+ *
152
+ * Reads need no permission, but what they answer depends on the credential: drafts and archived
153
+ * items are served only to a holder of `ReadCmsContent` on the store, and everyone else reads
154
+ * published items alone (`items.get` of an unpublished item is then `NotFoundError`). Writes
155
+ * need the permission each method names (`@permission`).
156
+ *
157
+ * Refusals are the CMS's problem+json, mapped by status:
158
+ * - `NotFoundError` (404, `NOT_FOUND`): no such type or item in this store.
159
+ * - `ConflictError` (409, `CONFLICT`): the slug or the URL path is taken, or a singleton type
160
+ * already has its item.
161
+ * - `ValidationError` (400): `VALIDATION_FAILED` with one `details[]` entry per refused input
162
+ * member; `VALIDATION_ERROR` for what the CMS refuses on its own (a value for no field, a
163
+ * parent on a type that is not hierarchical, a slug reserved by the storefront, publishing an
164
+ * item with a required field empty, deleting an item that has children).
165
+ * - `PermissionDeniedError` (403): the credential lacks the write's permission.
166
+ *
167
+ * The CMS records the platform events (`content.published`, `content.updated`,
168
+ * `content.unpublished`) itself; nothing here emits one. No write here is deduplicated: an
169
+ * `idempotencyKey` is sent and acts on nothing, so a repeated `create` is a second item.
170
+ */
171
+ export interface ContentItemsModule {
172
+ /**
173
+ * The type's items, a page at a time, newest first unless `sort` says otherwise. Pages are
174
+ * offset-based (`Page.total` counts the matches), so `after: offsetCursor((n - 1) * size)`
175
+ * opens page `n`, and an item written while a walk runs can be seen twice or not at all.
176
+ *
177
+ * @effect read
178
+ */
179
+ list(typeId: string, options?: ContentItemListOptions): Promise<Page<ContentItem>>;
180
+ /**
181
+ * One item with its values and its translated slugs.
182
+ *
183
+ * @effect read
184
+ */
185
+ get(typeId: string, itemId: string, options?: GetContentItemOptions): Promise<ContentItemDetail>;
186
+ /**
187
+ * Adds an item as a draft. Answers its row; read its values back with `get`.
188
+ *
189
+ * @effect write
190
+ * @permission CreateCmsContent
191
+ */
192
+ create(typeId: string, input: CreateContentItemInput, options?: Call): Promise<ContentItemRecord>;
193
+ /**
194
+ * Writes what the input names in one transaction. Answers the item's row; read its values
195
+ * back with `get`.
196
+ *
197
+ * @effect write
198
+ * @permission UpdateCmsContent
199
+ */
200
+ update(typeId: string, itemId: string, input: UpdateContentItemInput, options?: Call): Promise<ContentItemRecord>;
201
+ /**
202
+ * Removes the item: it leaves the storefront and its URL is freed, and nothing in the SDK
203
+ * brings it back. An item that still has children is refused (`ValidationError`).
204
+ *
205
+ * @effect destructive
206
+ * @permission DeleteCmsContent
207
+ */
208
+ delete(typeId: string, itemId: string, options?: Call): Promise<void>;
209
+ /**
210
+ * Puts the item on the storefront. Refused (`ValidationError`, naming the fields) while a
211
+ * required field is empty.
212
+ *
213
+ * @effect write
214
+ * @permission UpdateCmsContent
215
+ */
216
+ publish(typeId: string, itemId: string, options?: Call): Promise<ContentItemRecord>;
217
+ /**
218
+ * Takes the item off the storefront; it becomes a draft.
219
+ *
220
+ * @effect write
221
+ * @permission UpdateCmsContent
222
+ */
223
+ unpublish(typeId: string, itemId: string, options?: Call): Promise<ContentItemRecord>;
224
+ /**
225
+ * Sets one status on several items of the type in one transaction, and answers how many it
226
+ * changed. An id that is not a live item of this type in this store is skipped, not refused.
227
+ * Unlike `publish`, it does not check required fields.
228
+ *
229
+ * @effect write
230
+ * @permission UpdateCmsContent
231
+ */
232
+ bulkSetStatus(typeId: string, itemIds: readonly string[], status: ContentItemStatus, options?: Call): Promise<{
233
+ updated: number;
234
+ }>;
235
+ /**
236
+ * Removes several items of the type in one transaction, and answers how many it removed. An
237
+ * id that is not a live item of this type is skipped; a selected item whose child is not
238
+ * selected too refuses the whole call (`ValidationError`) and removes nothing.
239
+ *
240
+ * @effect destructive
241
+ * @permission DeleteCmsContent
242
+ */
243
+ bulkDelete(typeId: string, itemIds: readonly string[], options?: Call): Promise<{
244
+ deleted: number;
245
+ }>;
246
+ /**
247
+ * Resolves item ids of ANY content type of the store to a label: what a content reference
248
+ * field, a menu entry or a product property stores. Any number of ids; the SDK splits them
249
+ * into the CMS's batches of 50. Answers the ids that resolved, in the order given, each once:
250
+ * an unknown id, another store's, or one the credential may not see is absent, never an
251
+ * error. An id that is not a UUID is refused instead (`ValidationError`, `INVALID_DATA`), and
252
+ * the whole call fails with it: no other id is resolved.
253
+ *
254
+ * Every status for a holder of `ReadCmsContent`, `UpdateCatalog` or `UpdateProduct` on the
255
+ * store (a catalog writer resolves a draft its product references); published items only for
256
+ * everyone else.
257
+ *
258
+ * @effect read
259
+ */
260
+ lookup(ids: readonly string[], options?: Call): Promise<ContentItemSummary[]>;
261
+ /**
262
+ * As `lookup`, with the base values of the named field slugs. With no ids or no slugs it
263
+ * answers `[]` without a request.
264
+ *
265
+ * @effect read
266
+ */
267
+ lookupWithFields(ids: readonly string[], fieldSlugs: readonly string[], options?: Call): Promise<ContentItemWithFields[]>;
268
+ }
269
+ export declare function createContentItemsModule(transport: Transport): ContentItemsModule;
@@ -0,0 +1,170 @@
1
+ import { createPage, offsetCursor, PLATFORM_PASSTHROUGH_KEYS, readOffsetCursor, } from '@sixtyninecommerce/core';
2
+ const DEFAULT_PAGE_SIZE = 50;
3
+ /**
4
+ * `GET /items/lookup*` refuses more ids than this (`ITEM_LOOKUP_MAX_IDS` in the CMS's
5
+ * `collections.controller.ts`): it once sliced to 50 and dropped the rest without a word.
6
+ */
7
+ const LOOKUP_BATCH_SIZE = 50;
8
+ /**
9
+ * Item `values` are keyed by the merchant's field slugs (`hero_2_image` camelised is
10
+ * `hero2Image`, and back is `hero2_image`), in both directions. `slug_translations` is keyed by
11
+ * language code. `values` cannot join the platform set: content strings use the name for a DTO
12
+ * array.
13
+ */
14
+ const ITEM_PASSTHROUGH = new Set([
15
+ ...PLATFORM_PASSTHROUGH_KEYS,
16
+ 'values',
17
+ 'slug_translations',
18
+ ]);
19
+ function itemsPath(typeId) {
20
+ return `/collections/${encodeURIComponent(typeId)}/items`;
21
+ }
22
+ function itemPath(typeId, itemId) {
23
+ return `${itemsPath(typeId)}/${encodeURIComponent(itemId)}`;
24
+ }
25
+ function isRecord(value) {
26
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
27
+ }
28
+ /**
29
+ * A write answers the item ENTITY: `values` there is the stored value rows (with each row's
30
+ * field), not the slug-keyed map a read answers, and `slugTranslations` the translation rows.
31
+ * Neither is the read shape, so neither is passed on.
32
+ */
33
+ function toRecord(item) {
34
+ const { values: _rows, slugTranslations: _translations, ...record } = item;
35
+ return record;
36
+ }
37
+ /**
38
+ * The item read sends both the translation rows (`slugTranslations`) and the same data keyed by
39
+ * language (`slug_translations`); camelised, the two land on ONE key and the later one wins.
40
+ * Today that is the map; a row array (the CMS reordering its answer) is folded into one.
41
+ */
42
+ function slugTranslationMap(value) {
43
+ if (!Array.isArray(value))
44
+ return isRecord(value) ? value : {};
45
+ const map = {};
46
+ for (const row of value) {
47
+ if (isRecord(row) && typeof row.languageCode === 'string' && typeof row.slug === 'string') {
48
+ map[row.languageCode] = {
49
+ slug: row.slug,
50
+ path: typeof row.path === 'string' ? row.path : null,
51
+ };
52
+ }
53
+ }
54
+ return map;
55
+ }
56
+ function batched(items, size) {
57
+ const out = [];
58
+ for (let i = 0; i < items.length; i += size)
59
+ out.push(items.slice(i, i + size));
60
+ return out;
61
+ }
62
+ /** The CMS answers a lookup in no guaranteed order; give it back in the caller's. */
63
+ function inOrderOf(ids, found) {
64
+ const byId = new Map(found.map((item) => [item.id, item]));
65
+ return ids.flatMap((id) => {
66
+ const item = byId.get(id);
67
+ return item === undefined ? [] : [item];
68
+ });
69
+ }
70
+ export function createContentItemsModule(transport) {
71
+ async function listPage(typeId, offset, limit, options) {
72
+ const body = await transport.rest('cms', {
73
+ method: 'GET',
74
+ path: itemsPath(typeId),
75
+ query: {
76
+ // `offset` is always sent: it keeps the CMS out of its keyset mode, which can resume
77
+ // neither `sort` nor `search` and cannot open page n. Without `limit` an offset read
78
+ // answers the WHOLE list.
79
+ limit,
80
+ offset,
81
+ status: options?.status,
82
+ parent_id: options?.parentId === null ? 'root' : options?.parentId,
83
+ slug: options?.slug,
84
+ search: options?.search,
85
+ sort: options?.sort,
86
+ // Always sent, empty for the base values: the transport adds the tenant's `language`
87
+ // to any read that names none, and a write never gets it.
88
+ language_code: options?.languageCode ?? '',
89
+ },
90
+ }, { ...options, preserveKeys: ITEM_PASSTHROUGH });
91
+ const items = body.data ?? [];
92
+ // An offset read echoes neither the offset nor a cursor, so the page is built from what
93
+ // THIS call asked for.
94
+ const total = body.pagination?.total ?? items.length;
95
+ const advanced = offset + (items.length > 0 ? items.length : limit);
96
+ const hasNext = advanced < total;
97
+ return createPage(items, { nextCursor: hasNext ? offsetCursor(advanced) : null, hasNext, total }, (cursor) => listPage(typeId, readOffsetCursor(cursor), limit, options));
98
+ }
99
+ async function writeItem(method, path, body, options) {
100
+ const answer = await transport.rest('cms', { method, path, ...(body === undefined ? {} : { body }) }, { ...options, preserveKeys: ITEM_PASSTHROUGH });
101
+ return toRecord(answer.data);
102
+ }
103
+ return {
104
+ list(typeId, options) {
105
+ const limit = options?.limit ?? DEFAULT_PAGE_SIZE;
106
+ const offset = options?.after === undefined ? 0 : readOffsetCursor(options.after);
107
+ return listPage(typeId, offset, limit, options);
108
+ },
109
+ async get(typeId, itemId, options) {
110
+ const body = await transport.rest('cms', {
111
+ method: 'GET',
112
+ path: itemPath(typeId, itemId),
113
+ query: { language_code: options?.languageCode ?? '' },
114
+ }, { ...options, preserveKeys: ITEM_PASSTHROUGH });
115
+ return {
116
+ ...body.data,
117
+ slugTranslations: slugTranslationMap(body.data.slugTranslations),
118
+ };
119
+ },
120
+ create(typeId, input, options) {
121
+ return writeItem('POST', itemsPath(typeId), input, options);
122
+ },
123
+ update(typeId, itemId, input, options) {
124
+ return writeItem('PATCH', itemPath(typeId, itemId), input, options);
125
+ },
126
+ async delete(typeId, itemId, options) {
127
+ await transport.rest('cms', { method: 'DELETE', path: itemPath(typeId, itemId), expect: 'void' }, options);
128
+ },
129
+ publish(typeId, itemId, options) {
130
+ return writeItem('POST', `${itemPath(typeId, itemId)}/publish`, undefined, options);
131
+ },
132
+ unpublish(typeId, itemId, options) {
133
+ return writeItem('POST', `${itemPath(typeId, itemId)}/unpublish`, undefined, options);
134
+ },
135
+ async bulkSetStatus(typeId, itemIds, status, options) {
136
+ const body = await transport.rest('cms', {
137
+ method: 'POST',
138
+ path: `${itemsPath(typeId)}/bulk-status`,
139
+ body: { itemIds: [...itemIds], status },
140
+ }, options);
141
+ return { updated: body.data.updated };
142
+ },
143
+ async bulkDelete(typeId, itemIds, options) {
144
+ const body = await transport.rest('cms', {
145
+ method: 'POST',
146
+ path: `${itemsPath(typeId)}/bulk-delete`,
147
+ body: { itemIds: [...itemIds] },
148
+ }, options);
149
+ return { deleted: body.data.deleted };
150
+ },
151
+ async lookup(ids, options) {
152
+ const unique = [...new Set(ids)];
153
+ if (unique.length === 0)
154
+ return [];
155
+ const pages = await Promise.all(batched(unique, LOOKUP_BATCH_SIZE).map((batch) => transport.rest('cms', { method: 'GET', path: '/items/lookup', query: { ids: batch.join(',') } }, options)));
156
+ return inOrderOf(unique, pages.flatMap((page) => page.data));
157
+ },
158
+ async lookupWithFields(ids, fieldSlugs, options) {
159
+ const unique = [...new Set(ids)];
160
+ if (unique.length === 0 || fieldSlugs.length === 0)
161
+ return [];
162
+ const pages = await Promise.all(batched(unique, LOOKUP_BATCH_SIZE).map((batch) => transport.rest('cms', {
163
+ method: 'GET',
164
+ path: '/items/lookup-with-fields',
165
+ query: { ids: batch.join(','), field_slugs: fieldSlugs.join(',') },
166
+ }, { ...options, preserveKeys: PLATFORM_PASSTHROUGH_KEYS })));
167
+ return inOrderOf(unique, pages.flatMap((page) => page.data));
168
+ },
169
+ };
170
+ }