@wix/himalaya-cli 0.1536.0 → 0.1538.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 (31) hide show
  1. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/bookings-v2/src/extensions.d.ts +16 -0
  2. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/data-collections-v1/src/extensions.d.ts +4 -0
  3. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/wix-data/src/index.d.ts +497 -4
  4. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-bookings.mjs +5 -0
  5. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-data-collections.mjs +1 -5
  6. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-data.mjs +315 -7
  7. package/dist/cli.mjs +852 -538
  8. package/dist/preview-assets.generated.bin +0 -0
  9. package/fixtures/wix-canned.json +1 -0
  10. package/guides/cms-collections.md +31 -0
  11. package/guides/himi-json-output.md +13 -2
  12. package/guides/iap-products.md +13 -5
  13. package/guides/release-notes.md +12 -0
  14. package/guides/wix-api-usage.md +53 -6
  15. package/package.json +2 -2
  16. package/templates/beauty-salon/dev/index.ts +1109 -2310
  17. package/templates/beauty-salon/tier5-src/_shared/himi-bookings.ts +121 -1
  18. package/templates/beauty-salon/tier5-src/himi-booking-service/index.ts +9 -55
  19. package/templates/beauty-salon/tier5-src/himi-booking-services/index.ts +264 -18
  20. package/templates/branded-lite/dev/index.ts +1075 -2276
  21. package/templates/branded-lite/tier5-src/_shared/himi-bookings.ts +121 -1
  22. package/templates/branded-lite/tier5-src/himi-booking-service/index.ts +9 -55
  23. package/templates/branded-lite/tier5-src/himi-booking-services/index.ts +264 -18
  24. package/templates/gym-fitness/dev/index.ts +1075 -2276
  25. package/templates/gym-fitness/tier5-src/_shared/himi-bookings.ts +121 -1
  26. package/templates/gym-fitness/tier5-src/himi-booking-service/index.ts +9 -55
  27. package/templates/gym-fitness/tier5-src/himi-booking-services/index.ts +264 -18
  28. package/templates/yoga-studio/dev/index.ts +1137 -2338
  29. package/templates/yoga-studio/tier5-src/_shared/himi-bookings.ts +121 -1
  30. package/templates/yoga-studio/tier5-src/himi-booking-service/index.ts +9 -55
  31. package/templates/yoga-studio/tier5-src/himi-booking-services/index.ts +264 -18
@@ -126,6 +126,22 @@ export interface WixQueryServicesResponse {
126
126
  * read it — NOT the owner/BO `_api/` gateway (which fails for visitors, #463). Takes
127
127
  * the standard query envelope (filter/sort/paging). */
128
128
  export declare function queryServices(req?: WixQueryServicesRequest): Promise<WixQueryServicesResponse>;
129
+ /** One service category, as the categories query returns it. `sortOrder` is the business's
130
+ * own order; the response is already in it. */
131
+ export interface WixServiceCategory {
132
+ id?: string;
133
+ name?: string;
134
+ sortOrder?: number;
135
+ }
136
+ export interface WixQueryServiceCategoriesResponse {
137
+ categories: WixServiceCategory[];
138
+ }
139
+ /** List the site's service categories — POST /bookings/v2/services/categories/query with an
140
+ * empty body. Returns only the categories that have services, in the business's own order
141
+ * (the order of the site's Book Online page). Verified live 2026-11-01 with an anonymous
142
+ * visitor token: 200.
143
+ * @scope visitor — an anonymous visitor session is enough. */
144
+ export declare function queryServiceCategories(): Promise<WixQueryServiceCategoriesResponse>;
129
145
  export interface WixGetServiceResponse {
130
146
  service: WixService;
131
147
  }
@@ -4,5 +4,9 @@ export declare function createDataCollection(collection: WixDataCollection): Pro
4
4
  /**
5
5
  * Replace a data collection's schema. Wix uses optimistic concurrency: pass the
6
6
  * `revision` read from getDataCollection, or the call is rejected as stale.
7
+ *
8
+ * The id travels in the body — `PUT /data/v2/collections` with `{ collection }`, as Wix
9
+ * documents it; the path form `PUT /data/v2/collections/{id}` is not a route. Needs an owner
10
+ * identity, and the call replaces the schema, so send every field you want to keep.
7
11
  */
8
12
  export declare function updateDataCollection(collection: WixDataCollection): Promise<WixUpdateDataCollectionResponse>;
@@ -20,15 +20,50 @@ export interface WixDataSort {
20
20
  fieldName: string;
21
21
  order?: "ASC" | "DESC";
22
22
  }
23
+ /** Cursor paging: pass `cursor` from the previous page's `pagingMetadata.cursors.next`. */
24
+ export interface WixDataCursorPaging {
25
+ limit?: number;
26
+ cursor?: string;
27
+ }
28
+ /** Inline the items a reference or multi-reference field points at. */
29
+ export interface WixIncludeReference {
30
+ field: string;
31
+ /** Per-item cap on inlined references. Wix defaults to 50 and allows up to 1000. */
32
+ limit?: number;
33
+ }
34
+ /** The rarely-needed read parameters of `queryDataItems`. Every field is omitted from the wire
35
+ * body unless set, so a caller that passes none sends the exact body it always sent. */
36
+ export interface WixQueryOptions {
37
+ /** Read from the primary database instance instead of the nearest mirror. Slower, but a read
38
+ * right after your own write sees it — the default is eventually consistent. */
39
+ consistentRead?: boolean;
40
+ /** Page by cursor instead of `offset`. Mutually exclusive with `offset`. */
41
+ cursorPaging?: WixDataCursorPaging;
42
+ /** Return only these fields (`_id` always comes back). */
43
+ fields?: string[];
44
+ includeReferences?: WixIncludeReference[];
45
+ /** IETF BCP 47 tag; needs Wix Multilingual enabled for the collection. */
46
+ language?: string;
47
+ /** Also read pending drafts (collections with the draft-items plugin). */
48
+ includeDraftItems?: boolean;
49
+ }
23
50
  export interface WixQueryDataItemsRequest {
24
51
  dataCollectionId: string;
25
52
  query?: {
26
53
  filter?: Record<string, unknown>;
27
54
  paging?: WixDataPaging;
55
+ cursorPaging?: WixDataCursorPaging;
28
56
  sort?: WixDataSort[];
57
+ fields?: string[];
29
58
  };
30
59
  /** When true, `pagingMetadata.total` is filled (offset paging only). Default omitted. */
31
60
  returnTotalCount?: boolean;
61
+ consistentRead?: boolean;
62
+ includeReferences?: WixIncludeReference[];
63
+ language?: string;
64
+ publishPluginOptions?: {
65
+ includeDraftItems: boolean;
66
+ };
32
67
  }
33
68
  export interface WixQueryDataItemsResponse {
34
69
  dataItems?: WixDataItem[];
@@ -39,14 +74,27 @@ export interface WixQueryDataItemsResponse {
39
74
  total?: number;
40
75
  totalCount?: number;
41
76
  tooManyToCount?: boolean;
77
+ /** Present under cursor paging. `next` is absent on the last page. */
78
+ cursors?: {
79
+ next?: string;
80
+ prev?: string;
81
+ };
42
82
  };
43
83
  }
44
84
  export interface WixInsertDataItemRequest {
45
85
  dataCollectionId: string;
46
86
  dataItem: {
87
+ id?: string;
47
88
  data: Record<string, unknown>;
48
89
  };
49
90
  }
91
+ /** Optional `insertDataItem` parameters. */
92
+ export interface WixInsertDataItemOptions {
93
+ /** A client-chosen item id (max 128 chars). Wix keeps it verbatim and answers a second insert
94
+ * of the same id with 409 `WDE0074` rather than a duplicate — which is what makes a retry
95
+ * after a lost response safe, and what the offline outbox relies on. */
96
+ id?: string;
97
+ }
50
98
  export interface WixUpdateDataItemRequest {
51
99
  dataCollectionId: string;
52
100
  dataItem: {
@@ -85,8 +133,34 @@ export interface WixUpdateDataItemRequest {
85
133
  * ```
86
134
  *
87
135
  * To read ONE row, use `getDataItem` rather than a page plus a client-side
88
- * `.find()` — that pattern breaks silently once the collection outgrows `limit`. */
89
- export declare function queryDataItems(dataCollectionId: string, limit?: number, filter?: Record<string, unknown>, returnTotalCount?: boolean, offset?: number, sort?: WixDataSort[]): Promise<WixQueryDataItemsResponse>;
136
+ * `.find()` — that pattern breaks silently once the collection outgrows `limit`.
137
+ *
138
+ * The seventh argument carries the rarer read options. `consistentRead` is the one that
139
+ * matters after your own write — the default read may come from a mirror that has not caught
140
+ * up yet, so "insert, then query" can miss the row you just wrote:
141
+ *
142
+ * ```ts
143
+ * await insertDataItem("Messages", { text });
144
+ * await queryDataItems("Messages", 50, undefined, false, 0, undefined, { consistentRead: true });
145
+ * ```
146
+ *
147
+ * `cursorPaging` pages by an opaque cursor instead of `offset` (up to 1000 per page, and it
148
+ * stays correct while rows are inserted between pages). Define `filter`, `sort` and
149
+ * `returnTotalCount` on the first request: the cursor carries them, and Wix refuses a follow-up
150
+ * that sends them again (`400 WDE0080`, checked against a live site), so this drops them
151
+ * whenever a cursor is passed and the same arguments can be reused for every page. `fields` projects, and
152
+ * `includeReferences` inlines referenced items (a multi-reference field is absent from a
153
+ * result unless it is named here).
154
+ *
155
+ * ```ts
156
+ * let cursor: string | undefined;
157
+ * do {
158
+ * const page = await queryDataItems("Posts", 50, { status: "live" }, false, 0, undefined, { cursorPaging: { cursor } });
159
+ * render(page.dataItems);
160
+ * cursor = page.pagingMetadata?.cursors?.next; // absent on the last page: stop there
161
+ * } while (cursor);
162
+ * ``` */
163
+ export declare function queryDataItems(dataCollectionId: string, limit?: number, filter?: Record<string, unknown>, returnTotalCount?: boolean, offset?: number, sort?: WixDataSort[], options?: WixQueryOptions): Promise<WixQueryDataItemsResponse>;
90
164
  /** Read ONE item by id — GET /wix-data/v2/items/{dataItemId}?dataCollectionId=…
91
165
  *
92
166
  * Reach for this on a detail screen. Before it existed the only read this package
@@ -112,8 +186,15 @@ export declare function queryDataItems(dataCollectionId: string, limit?: number,
112
186
  export declare function getDataItem(dataCollectionId: string, dataItemId: string): Promise<{
113
187
  dataItem?: WixDataItem;
114
188
  }>;
115
- /** Insert an item — POST /wix-data/v2/items. */
116
- export declare function insertDataItem(dataCollectionId: string, data: Record<string, unknown>): Promise<{
189
+ /** Insert an item — POST /wix-data/v2/items.
190
+ *
191
+ * Insert is create-only: a second insert of an existing id fails with 409 `WDE0074` instead of
192
+ * overwriting. Pass `{ id }` to choose the id yourself — mint it once before the first attempt
193
+ * and a retry after a lost response cannot create a duplicate (the 409 means "already there").
194
+ * Wix reads the id from the item envelope and refuses `data._id` on its own (`400 WDE0080`), so an
195
+ * `_id` given only inside `data` is moved onto the envelope for you. To insert-or-replace by id,
196
+ * use `saveDataItem`. */
197
+ export declare function insertDataItem(dataCollectionId: string, data: Record<string, unknown>, options?: WixInsertDataItemOptions): Promise<{
117
198
  dataItem?: WixDataItem;
118
199
  }>;
119
200
  /** Update an item — PUT /wix-data/v2/items/{id}. */
@@ -122,4 +203,416 @@ export declare function updateDataItem(dataCollectionId: string, id: string, dat
122
203
  }>;
123
204
  /** Remove an item — DELETE /wix-data/v2/items/{id}?dataCollectionId=…. */
124
205
  export declare function removeDataItem(dataCollectionId: string, id: string): Promise<unknown>;
206
+ /** One edit inside a patch. Build them with `setField`, `removeField`, `incrementField`,
207
+ * `appendToArray` and `removeFromArray` rather than by hand. */
208
+ export type WixFieldModification = {
209
+ fieldPath: string;
210
+ action: "SET_FIELD";
211
+ setFieldOptions: {
212
+ value: unknown;
213
+ };
214
+ } | {
215
+ fieldPath: string;
216
+ action: "REMOVE_FIELD";
217
+ } | {
218
+ fieldPath: string;
219
+ action: "INCREMENT_FIELD";
220
+ incrementFieldOptions: {
221
+ value: number;
222
+ };
223
+ } | {
224
+ fieldPath: string;
225
+ action: "APPEND_TO_ARRAY";
226
+ appendToArrayOptions: {
227
+ value: unknown;
228
+ };
229
+ } | {
230
+ fieldPath: string;
231
+ action: "REMOVE_FROM_ARRAY";
232
+ removeFromArrayOptions: {
233
+ value: unknown;
234
+ };
235
+ };
236
+ /** Set one field to `value`, leaving every other field alone. `fieldPath` may be dotted
237
+ * (`"address.city"`). For a MULTI_REFERENCE field `value` is an array of item ids and the
238
+ * call REPLACES the whole link set. */
239
+ export declare function setField(fieldPath: string, value: unknown): WixFieldModification;
240
+ /** Clear one field. */
241
+ export declare function removeField(fieldPath: string): WixFieldModification;
242
+ /** Add `by` to a numeric field atomically on the server (negative to subtract). Two devices that
243
+ * each increment a counter both land; a read-then-`updateDataItem` would lose one. */
244
+ export declare function incrementField(fieldPath: string, by?: number): WixFieldModification;
245
+ /** Append `value` to an array field. Not for MULTI_REFERENCE fields — Wix fails that per item
246
+ * with `WDE0303`; use `insertDataItemReferences` or `setField` with an array of ids. */
247
+ export declare function appendToArray(fieldPath: string, value: unknown): WixFieldModification;
248
+ /** Remove the first occurrence of `value` from an array field. */
249
+ export declare function removeFromArray(fieldPath: string, value: unknown): WixFieldModification;
250
+ /** Change only the named fields of one item — PATCH /wix-data/v2/items/{id}.
251
+ *
252
+ * Prefer this to `updateDataItem` for any partial change. `updateDataItem` REPLACES the whole
253
+ * item, so sending two fields deletes every other field — including the one you look the row up
254
+ * by. A patch touches only what you name, can increment a number atomically, and takes 1 to 100
255
+ * modifications.
256
+ *
257
+ * ```ts
258
+ * await patchDataItem("Posts", id, [setField("title", "New"), incrementField("views")]);
259
+ * ```
260
+ *
261
+ * Works on collections created in the CMS or through the API; Wix does not support it on Wix
262
+ * app collections (Stores products and the like). Needs write permission on the collection
263
+ * for the calling identity.
264
+ *
265
+ * @scope visitor — enough when the collection's update role is ANYONE; a stricter role answers `403 WDE0027` (checked against a live site).
266
+ */
267
+ export declare function patchDataItem(dataCollectionId: string, dataItemId: string, fieldModifications: WixFieldModification[]): Promise<{
268
+ dataItem?: WixDataItem;
269
+ }>;
270
+ /** Optional `saveDataItem` parameters. */
271
+ export interface WixSaveDataItemOptions {
272
+ /** The item's id (max 128 chars). If an item with this id exists it is replaced, otherwise it is
273
+ * created with exactly this id. Omit it to let Wix generate one. */
274
+ id?: string;
275
+ }
276
+ /** Insert the item, or replace it if the id already exists — POST /wix-data/v2/items/save.
277
+ *
278
+ * With an explicit `{ id }` this is the idempotent write: saving the same id twice leaves one row
279
+ * holding the second write, so it is safe to retry and it is one of the two item writes the
280
+ * offline write queue may hold (last write wins — there is no revision check). On an existing id
281
+ * it REPLACES the whole item like `updateDataItem` — use `patchDataItem` to change only some fields.
282
+ *
283
+ * Without an id Wix generates one and the call is an insert, so a retry after a lost response adds
284
+ * a second row: mint the id once and pass it if you may retry. An `_id` given only inside `data` is
285
+ * moved onto the envelope. `action` in the result says which happened (`INSERT` or `UPDATE`).
286
+ *
287
+ * @scope visitor — enough when the collection's insert and update roles are ANYONE; a stricter role answers `403 WDE0027` (checked against a live site).
288
+ */
289
+ export declare function saveDataItem(dataCollectionId: string, data: Record<string, unknown>, options?: WixSaveDataItemOptions): Promise<{
290
+ action?: string;
291
+ dataItem?: WixDataItem;
292
+ }>;
293
+ /** Optional read parameters shared by the count, aggregate and reference reads. */
294
+ export interface WixReadOptions {
295
+ /** Read from the primary instance; see `WixQueryOptions.consistentRead`. */
296
+ consistentRead?: boolean;
297
+ language?: string;
298
+ includeDraftItems?: boolean;
299
+ }
300
+ /** How many items match — POST /wix-data/v2/items/count.
301
+ *
302
+ * One read, and cheaper than `queryDataItems(..., returnTotalCount)` when you do not need the
303
+ * rows. `filter` is the same Wix filter object `queryDataItems` takes. Returns `{ totalCount }`.
304
+ *
305
+ * @scope visitor — enough when the collection's read role is ANYONE; a stricter role answers `403 WDE0027` (checked against a live site).
306
+ */
307
+ export declare function countDataItems(dataCollectionId: string, filter?: Record<string, unknown>, options?: WixReadOptions): Promise<{
308
+ totalCount?: number;
309
+ }>;
310
+ export interface WixBulkItemError {
311
+ code?: string;
312
+ description?: string;
313
+ data?: Record<string, unknown>;
314
+ }
315
+ export interface WixBulkItemMetadata {
316
+ id?: string;
317
+ /** Index of this item in the array you sent — how a result is matched back to its input. */
318
+ originalIndex?: number;
319
+ success?: boolean;
320
+ error?: WixBulkItemError;
321
+ }
322
+ export interface WixBulkDataItemResult {
323
+ action?: string;
324
+ itemMetadata?: WixBulkItemMetadata;
325
+ /** Present only when the request set `returnEntity: true`. */
326
+ dataItem?: WixDataItem;
327
+ }
328
+ export interface WixBulkActionMetadata {
329
+ totalSuccesses?: number;
330
+ totalFailures?: number;
331
+ }
332
+ export interface WixBulkDataItemsResponse {
333
+ results?: WixBulkDataItemResult[];
334
+ bulkActionMetadata?: WixBulkActionMetadata;
335
+ }
336
+ export interface WixBulkWriteOptions {
337
+ /** Return each written item in `results[].dataItem`. Off by default to keep the response small. */
338
+ returnEntity?: boolean;
339
+ }
340
+ export interface WixBulkConditionalWriteOptions extends WixBulkWriteOptions {
341
+ /** Apply the write only to items that also match this filter (an optimistic-concurrency guard). */
342
+ condition?: {
343
+ filter: Record<string, unknown>;
344
+ };
345
+ }
346
+ /** The items of a bulk response that failed — an empty array means every item was written.
347
+ * An item counts as failed when its result says `success: false`, or carries a non-null `error`
348
+ * without `success: true`, so a response that leaves `success` off a failed item is still caught.
349
+ * Wix sends `originalIndex` on every result, `0` included (checked against a live site).
350
+ *
351
+ * ```ts
352
+ * const res = await bulkInsertDataItems("Menu", rows);
353
+ * for (const f of bulkFailures(res)) console.warn(rows[f.itemMetadata!.originalIndex!], f.itemMetadata!.error);
354
+ * ``` */
355
+ export declare function bulkFailures<T extends {
356
+ itemMetadata?: WixBulkItemMetadata;
357
+ referenceMetadata?: WixBulkItemMetadata;
358
+ }>(res: {
359
+ results?: T[];
360
+ } | undefined): T[];
361
+ /** Insert up to 1000 items in one call — POST /wix-data/v2/bulk/items/insert.
362
+ *
363
+ * Create-only: an item whose `id` already exists is rejected (Wix reports it per item, not as a
364
+ * failed call). CHECK THE RESULT — the HTTP status is 200 even when items failed; use `bulkFailures(res)` or
365
+ * `res.bulkActionMetadata.totalFailures`. A retry of the whole call after a lost response re-sends
366
+ * rows that landed, so give rows an `id` (it goes beside `data`, not inside it) if a duplicate
367
+ * would matter. Multi-reference values in `data` are silently dropped by Wix; write those with
368
+ * `insertDataItemReferences`. The payload is capped at about 4 MB.
369
+ *
370
+ * @scope visitor — enough when the collection's insert role is ANYONE; a stricter role fails every item with `WDE0027` inside a 200 (checked against a live site).
371
+ */
372
+ export declare function bulkInsertDataItems(dataCollectionId: string, dataItems: {
373
+ id?: string;
374
+ data: Record<string, unknown>;
375
+ }[], options?: WixBulkWriteOptions): Promise<WixBulkDataItemsResponse>;
376
+ /** Insert-or-replace up to 1000 items in one call — POST /wix-data/v2/bulk/items/save.
377
+ *
378
+ * The idempotent bulk write for items that carry an `id`: rerunning the same call converges on the
379
+ * same rows, so it is the right one for imports and syncs. An item without an id is inserted again
380
+ * on every run. Each item with an existing `id` is REPLACED whole. As with
381
+ * every bulk call the HTTP status is 200 whatever happened — read `bulkFailures(res)`.
382
+ *
383
+ * @scope visitor — enough when the collection's insert and update roles are ANYONE; a stricter role fails the items with `WDE0027` inside a 200.
384
+ */
385
+ export declare function bulkSaveDataItems(dataCollectionId: string, dataItems: {
386
+ id?: string;
387
+ data: Record<string, unknown>;
388
+ }[], options?: WixBulkWriteOptions): Promise<WixBulkDataItemsResponse>;
389
+ /** Replace up to 1000 existing items — POST /wix-data/v2/bulk/items/update.
390
+ *
391
+ * Every item needs its `id` on the envelope. `data._id` may stay when it equals that id (so an item
392
+ * read back from a query can be sent as is) but must not differ — Wix answers a mismatch with
393
+ * `400 WDE0080` (both checked against a live site). An id that does not exist fails that item. Like
394
+ * `updateDataItem` this REPLACES each item whole, so fields you leave out are deleted — prefer
395
+ * `bulkPatchDataItems` for partial changes. The status is 200 whatever happened; read
396
+ * `bulkFailures(res)`.
397
+ *
398
+ * @scope visitor — enough when the collection's update role is ANYONE; a stricter role fails every item with `WDE0027` inside a 200 (checked against a live site).
399
+ */
400
+ export declare function bulkUpdateDataItems(dataCollectionId: string, dataItems: {
401
+ id: string;
402
+ data: Record<string, unknown>;
403
+ }[], options?: WixBulkConditionalWriteOptions): Promise<WixBulkDataItemsResponse>;
404
+ /** Patch up to 100 items in one call — POST /wix-data/v2/bulk/items/patch.
405
+ *
406
+ * Each patch names an item and 1 to 100 modifications (`setField`, `incrementField`, …); fields
407
+ * not named are untouched, and increments are atomic. The body key is `patches`, not `dataItems`
408
+ * — sending the latter fails with `WDE0080`. Not for Wix app collections. The status is 200
409
+ * whatever happened; read `bulkFailures(res)`.
410
+ *
411
+ * @scope visitor — enough when the collection's update role is ANYONE; a stricter role fails every item with `WDE0027` inside a 200 (checked against a live site).
412
+ */
413
+ export declare function bulkPatchDataItems(dataCollectionId: string, patches: {
414
+ dataItemId: string;
415
+ fieldModifications: WixFieldModification[];
416
+ }[], options?: WixBulkConditionalWriteOptions): Promise<WixBulkDataItemsResponse>;
417
+ /** Remove up to 1000 items by id in one call — POST /wix-data/v2/bulk/items/remove.
418
+ *
419
+ * Irreversible, and it clears references to the removed items. Results are per item, and the
420
+ * status is 200 even when some items fail (an id that does not exist is `WDE0073` per item);
421
+ * read `bulkFailures(res)`. A remove the caller may not make at all is a 403 instead.
422
+ *
423
+ * @scope visitor — enough when the collection's remove role is ANYONE; a stricter role answers `403 WDE0027` for the whole request (checked against a live site).
424
+ */
425
+ export declare function bulkRemoveDataItems(dataCollectionId: string, dataItemIds: string[], options?: {
426
+ condition?: {
427
+ filter: Record<string, unknown>;
428
+ };
429
+ }): Promise<WixBulkDataItemsResponse>;
430
+ /** Paging block of the reads below, as Wix returns it. */
431
+ export interface WixPagingMetadata {
432
+ count?: number;
433
+ offset?: number;
434
+ /** Filled for offset paging when `returnTotalCount` was set and the server could count. */
435
+ total?: number;
436
+ tooManyToCount?: boolean;
437
+ cursors?: {
438
+ next?: string;
439
+ prev?: string;
440
+ };
441
+ hasNext?: boolean;
442
+ }
443
+ /** One aggregation stage: an object with exactly one key — `group`, `filter`, `sort`, `projection`,
444
+ * `unwindArray`, `objectToArray`, `skip` or `limit`. Wix's pipeline reference documents each. */
445
+ export type WixPipelineStage = Record<string, unknown>;
446
+ export interface WixAggregationPipeline {
447
+ /** Up to 100 stages, run in order, each on the previous stage's output. */
448
+ stages: WixPipelineStage[];
449
+ /** Page the pipeline's results. Offset and cursor paging are mutually exclusive. */
450
+ paging?: WixDataPaging;
451
+ cursorPaging?: WixDataCursorPaging;
452
+ }
453
+ export interface WixAggregateOptions extends WixReadOptions {
454
+ returnTotalCount?: boolean;
455
+ }
456
+ /** Run an aggregation pipeline — POST /wix-data/v2/items/aggregate-pipeline.
457
+ *
458
+ * Counts, sums, averages and group-bys computed by Wix instead of by downloading every row and
459
+ * folding it on the device — one read, however large the collection.
460
+ *
461
+ * ```ts
462
+ * const { results } = await aggregateDataItemsPipeline("Products", {
463
+ * stages: [{ group: {
464
+ * groupIds: [{ key: "category", expression: { fieldPath: "category" } }],
465
+ * accumulators: [{ resultFieldName: "count", sum: { expression: { numeric: 1 } } }],
466
+ * } }],
467
+ * });
468
+ * ```
469
+ *
470
+ * Each result is a group: its group keys sit under `_id`, accumulators under their
471
+ * `resultFieldName`. Not supported on Wix app collections. Up to 10000 results per response.
472
+ *
473
+ * A follow-up page (`pipeline.cursorPaging.cursor` set) sends only the cursor: it already carries
474
+ * the stages, and Wix refuses stages or `returnTotalCount` beside it (`400 WDE0080`, checked
475
+ * against a live site). So pass the same pipeline for every page, with the next cursor.
476
+ *
477
+ * @scope visitor — enough when the collection's read role is ANYONE; a stricter role answers `403 WDE0027` (checked against a live site).
478
+ */
479
+ export declare function aggregateDataItemsPipeline(dataCollectionId: string, pipeline: WixAggregationPipeline | {
480
+ cursorPaging: WixDataCursorPaging & {
481
+ cursor: string;
482
+ };
483
+ stages?: undefined;
484
+ paging?: undefined;
485
+ }, options?: WixAggregateOptions): Promise<{
486
+ results?: Record<string, unknown>[];
487
+ pagingMetadata?: WixPagingMetadata;
488
+ }>;
489
+ export interface WixDistinctOptions extends WixReadOptions {
490
+ filter?: Record<string, unknown>;
491
+ order?: "ASC" | "DESC";
492
+ paging?: WixDataPaging;
493
+ cursorPaging?: WixDataCursorPaging;
494
+ returnTotalCount?: boolean;
495
+ }
496
+ /** The unique values of one field, across the items matching `filter` — POST
497
+ * /wix-data/v2/items/query-distinct-values.
498
+ *
499
+ * What a filter chip or a category picker needs: the list of cities in use, without fetching every
500
+ * row to build it. Returns `{ distinctValues, pagingMetadata }`. Wix's reference types each entry
501
+ * as a value union (string, number, boolean, list, struct or null); inspect one live response
502
+ * before depending on the exact serialisation of non-string fields.
503
+ *
504
+ * @scope visitor — enough when the collection's read role is ANYONE; a stricter role answers `403 WDE0027` (checked against a live site).
505
+ */
506
+ export declare function queryDistinctValues(dataCollectionId: string, fieldName: string, options?: WixDistinctOptions): Promise<{
507
+ distinctValues?: unknown[];
508
+ pagingMetadata?: WixPagingMetadata;
509
+ }>;
510
+ export interface WixSearchOptions {
511
+ /** `OR` (default): any term matches. `AND`: every term must. */
512
+ mode?: "OR" | "AND";
513
+ /** Tolerate typos and partial matches. */
514
+ fuzzy?: boolean;
515
+ filter?: Record<string, unknown>;
516
+ sort?: WixDataSort[];
517
+ /** Fields to return (`_id` always comes back). */
518
+ fields?: string[];
519
+ /** Offset paging only: Wix answers cursor paging on search with `400 WDE0080` ("Cursor paging is
520
+ * not supported for search"), checked against a live site. */
521
+ paging?: WixDataPaging;
522
+ includeReferences?: WixIncludeReference[];
523
+ includeDraftItems?: boolean;
524
+ }
525
+ /** Full-text search a collection — POST /wix-data/v2/items/search.
526
+ *
527
+ * `expression` is up to 100 characters; terms are split on whitespace and combined by `mode`.
528
+ * Only collections created in the CMS or through the Data Collections API can be searched — not
529
+ * Wix app collections, external collections or Blocks. Filtering is limited to fields defined in
530
+ * the collection's structure, each field type accepts only some operators, and search results are
531
+ * ALWAYS eventually consistent (there is no `consistentRead`), so a row written a moment ago may
532
+ * not be found yet. Returns the same shape as `queryDataItems`.
533
+ *
534
+ * @scope visitor — enough when the collection's read role is ANYONE; a stricter role answers `403 WDE0027` (checked against a live site).
535
+ */
536
+ export declare function searchDataItems(dataCollectionId: string, expression: string, options?: WixSearchOptions): Promise<WixQueryDataItemsResponse>;
537
+ export interface WixDataItemReference {
538
+ referringItemId: string;
539
+ referringItemFieldName: string;
540
+ referencedItemId: string;
541
+ }
542
+ export interface WixBulkReferenceResult {
543
+ action?: string;
544
+ referenceMetadata?: WixBulkItemMetadata;
545
+ dataItemReference?: WixDataItemReference;
546
+ }
547
+ export interface WixBulkReferencesResponse {
548
+ results?: WixBulkReferenceResult[];
549
+ bulkActionMetadata?: WixBulkActionMetadata;
550
+ }
551
+ /** What `queryReferencedDataItems` returns for one link: the item, or why it could not be read. */
552
+ export interface WixReferencedResult {
553
+ referringItemId?: string;
554
+ dataItem?: WixDataItem;
555
+ /** The link points at an id that is missing, still a draft, or not readable by this identity
556
+ * (`unauthorized: true`). */
557
+ unresolvedReference?: {
558
+ referencedItemId?: string;
559
+ unauthorized?: boolean;
560
+ };
561
+ }
562
+ export interface WixQueryReferencedOptions extends WixReadOptions {
563
+ order?: "ASC" | "DESC";
564
+ paging?: WixDataPaging;
565
+ cursorPaging?: WixDataCursorPaging;
566
+ fields?: string[];
567
+ returnTotalCount?: boolean;
568
+ }
569
+ /** Read the items one item links to, page by page — POST /wix-data/v2/items/query-referenced.
570
+ *
571
+ * Use this when a multi-reference field can hold more items than `includeReferences` should
572
+ * inline (that caps at 1000 per item, 50 by default). Results come in the order the links were
573
+ * made (`order: "DESC"` for newest first). A link that cannot be resolved comes back as
574
+ * `unresolvedReference` instead of being dropped.
575
+ *
576
+ * @scope visitor — enough when the collection's read role is ANYONE; a stricter role answers `403 WDE0027` (checked against a live site).
577
+ */
578
+ export declare function queryReferencedDataItems(dataCollectionId: string, referringItemId: string, referringItemFieldName: string, options?: WixQueryReferencedOptions): Promise<{
579
+ results?: WixReferencedResult[];
580
+ pagingMetadata?: WixPagingMetadata;
581
+ }>;
582
+ /** Does `referringItemId`'s field link to `referencedItemId`? — POST /wix-data/v2/items/is-referenced.
583
+ * Returns `{ isReferenced }`.
584
+ *
585
+ * @scope visitor — enough when the collection's read role is ANYONE; a stricter role answers `403 WDE0027` (checked against a live site).
586
+ */
587
+ export declare function isReferencedDataItem(dataCollectionId: string, referringItemId: string, referringItemFieldName: string, referencedItemId: string, options?: {
588
+ consistentRead?: boolean;
589
+ }): Promise<{
590
+ isReferenced?: boolean;
591
+ }>;
592
+ /** Add links to a reference or multi-reference field, keeping the links already there — POST
593
+ * /wix-data/v2/bulk/items/insert-references. Up to 1000 per call.
594
+ *
595
+ * The safe way to write a multi-reference field: Wix silently drops multi-reference values written
596
+ * through insert, save, update or any bulk item write, and answers 200. After writing, read the item
597
+ * back with `queryDataItems(..., { includeReferences })` to confirm. This call's own status is 200
598
+ * whatever happened; read `bulkFailures(res)`.
599
+ *
600
+ * @scope visitor — enough when the referring collection's update role is ANYONE; a stricter role is refused with `WDE0027` (checked against a live site).
601
+ */
602
+ export declare function insertDataItemReferences(dataCollectionId: string, references: WixDataItemReference[], options?: WixBulkWriteOptions): Promise<WixBulkReferencesResponse>;
603
+ /** Remove specific links without touching the others — POST /wix-data/v2/bulk/items/remove-references.
604
+ * Up to 1000 per call; the status is 200 whatever happened, so read `bulkFailures(res)`.
605
+ *
606
+ * @scope visitor — enough when the referring collection's update role is ANYONE; a stricter role is refused with `WDE0027` (checked against a live site).
607
+ */
608
+ export declare function removeDataItemReferences(dataCollectionId: string, references: WixDataItemReference[]): Promise<WixBulkReferencesResponse>;
609
+ /** Make a field's links exactly `newReferencedItemIds`, dropping any others — POST
610
+ * /wix-data/v2/items/replace-references. An empty array removes every link. Up to 1000 ids.
611
+ * Returns the resulting `{ dataItemReferences }`.
612
+ *
613
+ * @scope visitor — enough when the referring collection's update role is ANYONE; a stricter role is refused with `WDE0027` (checked against a live site).
614
+ */
615
+ export declare function replaceDataItemReferences(dataCollectionId: string, referringItemId: string, referringItemFieldName: string, newReferencedItemIds: string[]): Promise<{
616
+ dataItemReferences?: WixDataItemReference[];
617
+ }>;
125
618
  export { wixCall };
@@ -19,6 +19,10 @@ async function queryServices(req = {}) {
19
19
  const res = await wixCall("POST", "/bookings/v2/services/query", req);
20
20
  return { ...res, services: (res.services ?? []).map(decodeService) };
21
21
  }
22
+ async function queryServiceCategories() {
23
+ const res = await wixCall("POST", "/bookings/v2/services/categories/query", {});
24
+ return { ...res, categories: Array.isArray(res?.categories) ? res.categories : [] };
25
+ }
22
26
  async function getService(serviceId, options) {
23
27
  const path = `/bookings/v2/services/${serviceId}`;
24
28
  const conditionalFields = options?.conditionalFields ?? [];
@@ -323,6 +327,7 @@ export {
323
327
  queryBookings,
324
328
  queryResources,
325
329
  queryServiceAvailability,
330
+ queryServiceCategories,
326
331
  queryServices,
327
332
  queryStaff,
328
333
  registerToWaitlist,
@@ -5,11 +5,7 @@ function createDataCollection(collection) {
5
5
  }
6
6
  function updateDataCollection(collection) {
7
7
  if (!collection?.id) throw new Error("updateDataCollection: collection.id is required");
8
- return wixCall(
9
- "PUT",
10
- `/data/v2/collections/${encodeURIComponent(collection.id)}`,
11
- { collection }
12
- );
8
+ return wixCall("PUT", "/data/v2/collections", { collection });
13
9
  }
14
10
 
15
11
  // ../../stdlib/wix-sdk/data-collections-v1/src/index.ts