@viu/emporix-sdk 1.0.0 → 2.1.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.
- package/CHANGELOG.md +56 -0
- package/README.md +26 -1
- package/dist/availability.cjs +101 -0
- package/dist/availability.cjs.map +1 -0
- package/dist/availability.d.cts +87 -0
- package/dist/availability.d.ts +87 -0
- package/dist/availability.js +4 -0
- package/dist/availability.js.map +1 -0
- package/dist/cart.d.cts +1 -1
- package/dist/cart.d.ts +1 -1
- package/dist/category.d.cts +1 -1
- package/dist/category.d.ts +1 -1
- package/dist/checkout.d.cts +1 -1
- package/dist/checkout.d.ts +1 -1
- package/dist/{chunk-QDABAMVN.js → chunk-JTJV7WUW.js} +25 -2
- package/dist/chunk-JTJV7WUW.js.map +1 -0
- package/dist/chunk-SCI7D74B.js +91 -0
- package/dist/chunk-SCI7D74B.js.map +1 -0
- package/dist/chunk-WSXRUYBE.js +248 -0
- package/dist/chunk-WSXRUYBE.js.map +1 -0
- package/dist/chunk-XMEP74BU.js +60 -0
- package/dist/chunk-XMEP74BU.js.map +1 -0
- package/dist/companies.d.cts +1 -1
- package/dist/companies.d.ts +1 -1
- package/dist/contacts.d.cts +1 -1
- package/dist/contacts.d.ts +1 -1
- package/dist/{context-vKgzZ-5f.d.cts → context-CGuxSb56.d.cts} +16 -1
- package/dist/{context-vKgzZ-5f.d.ts → context-CGuxSb56.d.ts} +16 -1
- package/dist/customer-groups.d.cts +1 -1
- package/dist/customer-groups.d.ts +1 -1
- package/dist/customer.d.cts +1 -1
- package/dist/customer.d.ts +1 -1
- package/dist/index.cjs +311 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -5
- package/dist/index.d.ts +8 -5
- package/dist/index.js +61 -6
- package/dist/index.js.map +1 -1
- package/dist/locations.d.cts +1 -1
- package/dist/locations.d.ts +1 -1
- package/dist/media.cjs +218 -9
- package/dist/media.cjs.map +1 -1
- package/dist/media.d.cts +103 -7
- package/dist/media.d.ts +103 -7
- package/dist/media.js +2 -1
- package/dist/orders.d.cts +1 -1
- package/dist/orders.d.ts +1 -1
- package/dist/payment.d.cts +1 -1
- package/dist/payment.d.ts +1 -1
- package/dist/price.cjs +44 -0
- package/dist/price.cjs.map +1 -1
- package/dist/price.d.cts +27 -2
- package/dist/price.d.ts +27 -2
- package/dist/price.js +1 -1
- package/dist/product.cjs +23 -0
- package/dist/product.cjs.map +1 -1
- package/dist/product.d.cts +18 -1
- package/dist/product.d.ts +18 -1
- package/dist/product.js +1 -1
- package/dist/segment.d.cts +1 -1
- package/dist/segment.d.ts +1 -1
- package/package.json +7 -2
- package/dist/chunk-F3WAQH2E.js +0 -120
- package/dist/chunk-F3WAQH2E.js.map +0 -1
- package/dist/chunk-HEO34WLO.js +0 -47
- package/dist/chunk-HEO34WLO.js.map +0 -1
- package/dist/chunk-QDABAMVN.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -634,6 +634,57 @@ var HttpClient = class {
|
|
|
634
634
|
throw errorFromResponse(res.status, `${o.method} ${o.path} \u2192 ${res.status}`, parsed);
|
|
635
635
|
}
|
|
636
636
|
}
|
|
637
|
+
/**
|
|
638
|
+
* Single-shot fetch that returns the raw {@link Response} unparsed. Used by
|
|
639
|
+
* endpoints whose responses are not JSON (binary downloads, redirect-only
|
|
640
|
+
* endpoints). Skips the retry-on-5xx and 401-reauth-once paths intentionally
|
|
641
|
+
* — those depend on parsing the JSON error body, which a raw consumer must
|
|
642
|
+
* handle itself if needed. Auth resolution + timeout + logging are still
|
|
643
|
+
* applied.
|
|
644
|
+
*
|
|
645
|
+
* `extra.redirect` is forwarded to `fetch` so callers can use `'manual'` to
|
|
646
|
+
* capture 30x responses with their `Location` header (Node fetch exposes
|
|
647
|
+
* the header in this mode; browser fetch returns an opaque response).
|
|
648
|
+
*/
|
|
649
|
+
async requestRaw(o, extra) {
|
|
650
|
+
const requestId = `req-${++requestSeq}`;
|
|
651
|
+
const log = this.opts.logger.child({ requestId });
|
|
652
|
+
const url = new URL(this.opts.host + o.path);
|
|
653
|
+
for (const [k, v] of Object.entries(o.query ?? {})) {
|
|
654
|
+
if (v !== void 0) url.searchParams.set(k, String(v));
|
|
655
|
+
}
|
|
656
|
+
const token = await resolveToken(o.auth, this.opts.provider);
|
|
657
|
+
log.debug("http requestRaw", {
|
|
658
|
+
authKind: o.auth.kind,
|
|
659
|
+
method: o.method,
|
|
660
|
+
url: url.pathname,
|
|
661
|
+
redirect: extra?.redirect ?? "follow"
|
|
662
|
+
});
|
|
663
|
+
const controller = new AbortController();
|
|
664
|
+
const timer = setTimeout(
|
|
665
|
+
() => controller.abort(),
|
|
666
|
+
o.timeoutMs ?? this.opts.timeouts.readMs
|
|
667
|
+
);
|
|
668
|
+
const isFormData = typeof FormData !== "undefined" && o.body instanceof FormData;
|
|
669
|
+
const init = {
|
|
670
|
+
method: o.method,
|
|
671
|
+
headers: {
|
|
672
|
+
...o.headers ?? {},
|
|
673
|
+
Authorization: `Bearer ${token}`,
|
|
674
|
+
...o.body !== void 0 && !isFormData ? { "Content-Type": "application/json" } : {}
|
|
675
|
+
},
|
|
676
|
+
signal: controller.signal,
|
|
677
|
+
...extra?.redirect ? { redirect: extra.redirect } : {}
|
|
678
|
+
};
|
|
679
|
+
if (o.body !== void 0) {
|
|
680
|
+
init.body = isFormData ? o.body : JSON.stringify(o.body);
|
|
681
|
+
}
|
|
682
|
+
try {
|
|
683
|
+
return await fetch(url, init);
|
|
684
|
+
} finally {
|
|
685
|
+
clearTimeout(timer);
|
|
686
|
+
}
|
|
687
|
+
}
|
|
637
688
|
};
|
|
638
689
|
|
|
639
690
|
// src/core/require-customer.ts
|
|
@@ -945,6 +996,29 @@ var ProductService = class {
|
|
|
945
996
|
);
|
|
946
997
|
return pages.flat();
|
|
947
998
|
}
|
|
999
|
+
/**
|
|
1000
|
+
* Streams the VARIANT children of a PARENT_VARIANT product, page by page,
|
|
1001
|
+
* via the search query `productType:VARIANT parentVariantId:<id>`. Default
|
|
1002
|
+
* pageSize 200. The query syntax (space-separated fields = implicit AND) is
|
|
1003
|
+
* encapsulated here so consumers don't build it themselves.
|
|
1004
|
+
*/
|
|
1005
|
+
listVariantChildrenAll(parentVariantId, params = {}, auth2 = ANON) {
|
|
1006
|
+
const pageSize = params.pageSize ?? 200;
|
|
1007
|
+
const q = `productType:VARIANT parentVariantId:${parentVariantId}`;
|
|
1008
|
+
return iterateAll((pageNumber) => this.search(q, { pageNumber, pageSize }, auth2));
|
|
1009
|
+
}
|
|
1010
|
+
/**
|
|
1011
|
+
* Resolves ALL VARIANT children of a PARENT_VARIANT product into a flat
|
|
1012
|
+
* array (loads every page). Default pageSize 200. Returns `[]` when there are
|
|
1013
|
+
* no children — never throws.
|
|
1014
|
+
*/
|
|
1015
|
+
async listVariantChildren(parentVariantId, params = {}, auth2 = ANON) {
|
|
1016
|
+
const out = [];
|
|
1017
|
+
for await (const child of this.listVariantChildrenAll(parentVariantId, params, auth2)) {
|
|
1018
|
+
out.push(child);
|
|
1019
|
+
}
|
|
1020
|
+
return out;
|
|
1021
|
+
}
|
|
948
1022
|
};
|
|
949
1023
|
|
|
950
1024
|
// src/services/category.ts
|
|
@@ -1311,6 +1385,50 @@ var PriceService = class {
|
|
|
1311
1385
|
body: input
|
|
1312
1386
|
});
|
|
1313
1387
|
}
|
|
1388
|
+
/**
|
|
1389
|
+
* Chunked variant of {@link matchByContext} for large `items` arrays. The
|
|
1390
|
+
* Emporix backend handles only a limited number of items per request
|
|
1391
|
+
* (production limit ~50), so this splits `input.items` into chunks and runs
|
|
1392
|
+
* `matchByContext` with bounded concurrency.
|
|
1393
|
+
*
|
|
1394
|
+
* By default a failing chunk is skipped (its items are absent from the
|
|
1395
|
+
* result) and `opts.onChunkError` is called once for it; pass
|
|
1396
|
+
* `throwOnAnyChunkError: true` to reject on the first failure instead.
|
|
1397
|
+
*
|
|
1398
|
+
* **Result order is not guaranteed** — match entries back to your items by
|
|
1399
|
+
* `priceId` / `itemRef.id`.
|
|
1400
|
+
*/
|
|
1401
|
+
async matchByContextChunked(input, opts = {}, auth2) {
|
|
1402
|
+
const chunkSize = opts.chunkSize ?? 50;
|
|
1403
|
+
const concurrency = opts.concurrency ?? 4;
|
|
1404
|
+
if (chunkSize < 1) throw new Error("chunkSize must be >= 1");
|
|
1405
|
+
if (concurrency < 1) throw new Error("concurrency must be >= 1");
|
|
1406
|
+
const items = input.items ?? [];
|
|
1407
|
+
if (items.length === 0) return [];
|
|
1408
|
+
const chunks = [];
|
|
1409
|
+
for (let i = 0; i < items.length; i += chunkSize) {
|
|
1410
|
+
chunks.push({ ...input, items: items.slice(i, i + chunkSize) });
|
|
1411
|
+
}
|
|
1412
|
+
const results = new Array(chunks.length);
|
|
1413
|
+
let cursor = 0;
|
|
1414
|
+
const worker = async () => {
|
|
1415
|
+
for (; ; ) {
|
|
1416
|
+
const idx = cursor++;
|
|
1417
|
+
const chunk = chunks[idx];
|
|
1418
|
+
if (chunk === void 0) return;
|
|
1419
|
+
try {
|
|
1420
|
+
results[idx] = await this.matchByContext(chunk, auth2);
|
|
1421
|
+
} catch (err) {
|
|
1422
|
+
if (opts.throwOnAnyChunkError) throw err;
|
|
1423
|
+
results[idx] = [];
|
|
1424
|
+
opts.onChunkError?.(err, idx);
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
};
|
|
1428
|
+
const workerCount = Math.min(concurrency, chunks.length);
|
|
1429
|
+
await Promise.all(Array.from({ length: workerCount }, () => worker()));
|
|
1430
|
+
return results.flat();
|
|
1431
|
+
}
|
|
1314
1432
|
};
|
|
1315
1433
|
|
|
1316
1434
|
// src/services/media.ts
|
|
@@ -1346,14 +1464,29 @@ var MediaService = class {
|
|
|
1346
1464
|
body: input.body
|
|
1347
1465
|
});
|
|
1348
1466
|
}
|
|
1349
|
-
/**
|
|
1350
|
-
|
|
1351
|
-
|
|
1467
|
+
/**
|
|
1468
|
+
* List assets, wrapped in the shared {@link PaginatedItems} envelope so
|
|
1469
|
+
* callers can iterate over pages consistently with the rest of the SDK.
|
|
1470
|
+
* `hasNextPage` is the standard SDK heuristic: `true` when the returned
|
|
1471
|
+
* page is full (`items.length === requested pageSize`). Pagination
|
|
1472
|
+
* defaults match Emporix's server defaults (`pageNumber: 1`,
|
|
1473
|
+
* `pageSize: 60`) so an empty `query` produces stable expectations.
|
|
1474
|
+
*/
|
|
1475
|
+
async list(query = {}, auth2 = SERVICE2) {
|
|
1476
|
+
const pageNumber = query.pageNumber ?? 1;
|
|
1477
|
+
const pageSize = query.pageSize ?? 60;
|
|
1478
|
+
const items = await this.ctx.http.request({
|
|
1352
1479
|
method: "GET",
|
|
1353
1480
|
path: this.base(),
|
|
1354
1481
|
auth: auth2,
|
|
1355
|
-
|
|
1482
|
+
query: { ...query, pageNumber, pageSize }
|
|
1356
1483
|
});
|
|
1484
|
+
return {
|
|
1485
|
+
items,
|
|
1486
|
+
pageNumber,
|
|
1487
|
+
pageSize,
|
|
1488
|
+
hasNextPage: items.length === pageSize
|
|
1489
|
+
};
|
|
1357
1490
|
}
|
|
1358
1491
|
/** Fetch an asset by id. */
|
|
1359
1492
|
async get(assetId, auth2 = SERVICE2) {
|
|
@@ -1363,13 +1496,37 @@ var MediaService = class {
|
|
|
1363
1496
|
auth: auth2
|
|
1364
1497
|
});
|
|
1365
1498
|
}
|
|
1366
|
-
/**
|
|
1367
|
-
|
|
1499
|
+
/**
|
|
1500
|
+
* Update an asset. The input is a discriminated union mirroring
|
|
1501
|
+
* {@link create}:
|
|
1502
|
+
* - `{ kind: "json", body }` — metadata-only patch (BLOB or LINK).
|
|
1503
|
+
* Sends `application/json`. Used for `refIds`, `details`, `metadata`,
|
|
1504
|
+
* or `url` changes.
|
|
1505
|
+
* - `{ kind: "blob", file, body }` — replaces the BLOB file content
|
|
1506
|
+
* (max 10MB) AND patches metadata in the same request. Sends
|
|
1507
|
+
* `multipart/form-data`.
|
|
1508
|
+
*
|
|
1509
|
+
* `type` and `access` are immutable per Emporix — they must match the
|
|
1510
|
+
* existing asset's values. Optimistic-locking is via `body.metadata.version`;
|
|
1511
|
+
* the server returns 409 Conflict on a stale version.
|
|
1512
|
+
*/
|
|
1513
|
+
async update(assetId, input, auth2 = SERVICE2) {
|
|
1514
|
+
if (input.kind === "blob") {
|
|
1515
|
+
const fd = new FormData();
|
|
1516
|
+
fd.set("file", input.file);
|
|
1517
|
+
fd.set("body", JSON.stringify(input.body));
|
|
1518
|
+
return this.ctx.http.request({
|
|
1519
|
+
method: "PUT",
|
|
1520
|
+
path: `${this.base()}/${assetId}`,
|
|
1521
|
+
auth: auth2,
|
|
1522
|
+
body: fd
|
|
1523
|
+
});
|
|
1524
|
+
}
|
|
1368
1525
|
return this.ctx.http.request({
|
|
1369
1526
|
method: "PUT",
|
|
1370
1527
|
path: `${this.base()}/${assetId}`,
|
|
1371
1528
|
auth: auth2,
|
|
1372
|
-
body:
|
|
1529
|
+
body: input.body
|
|
1373
1530
|
});
|
|
1374
1531
|
}
|
|
1375
1532
|
/** Remove an asset. */
|
|
@@ -1380,6 +1537,72 @@ var MediaService = class {
|
|
|
1380
1537
|
auth: auth2
|
|
1381
1538
|
});
|
|
1382
1539
|
}
|
|
1540
|
+
/**
|
|
1541
|
+
* Download an asset by id. Returns a discriminated union:
|
|
1542
|
+
* - `{ kind: "redirect", url }` for `PUBLIC` assets (server-side 30x with
|
|
1543
|
+
* the storage URL in `Location`).
|
|
1544
|
+
* - `{ kind: "bytes", data }` for `PRIVATE` assets (server-side 200 with
|
|
1545
|
+
* the asset bytes; `etag` + `contentType` headers are exposed for
|
|
1546
|
+
* caching). When the server reports `text/plain` Content-Type (the
|
|
1547
|
+
* OpenAPI-documented format), the SDK decodes the base64 stream into
|
|
1548
|
+
* an `ArrayBuffer` transparently; binary Content-Types are passed
|
|
1549
|
+
* through verbatim.
|
|
1550
|
+
*
|
|
1551
|
+
* Implementation note: uses `redirect: "manual"` so the redirect-location
|
|
1552
|
+
* is observable. In Node.js this works; in a browser the redirect Location
|
|
1553
|
+
* is intentionally hidden by fetch — there, `PUBLIC` downloads will
|
|
1554
|
+
* surface as an opaque-redirect and the SDK throws. Browser code should
|
|
1555
|
+
* use the asset's `url` field from `get()` for `LINK` assets, or the
|
|
1556
|
+
* direct storage URL for `PUBLIC` `BLOB` assets (typically delivered via
|
|
1557
|
+
* an `<img>` tag rather than `download()`).
|
|
1558
|
+
*/
|
|
1559
|
+
async download(assetId, auth2 = SERVICE2) {
|
|
1560
|
+
const path = `${this.base()}/${assetId}/download`;
|
|
1561
|
+
const res = await this.ctx.http.requestRaw(
|
|
1562
|
+
{ method: "GET", path, auth: auth2 },
|
|
1563
|
+
{ redirect: "manual" }
|
|
1564
|
+
);
|
|
1565
|
+
if (res.status >= 300 && res.status < 400) {
|
|
1566
|
+
const url = res.headers.get("location");
|
|
1567
|
+
if (!url) {
|
|
1568
|
+
throw new EmporixError(
|
|
1569
|
+
`media.download: ${res.status} response without a Location header`,
|
|
1570
|
+
res.status
|
|
1571
|
+
);
|
|
1572
|
+
}
|
|
1573
|
+
return { kind: "redirect", url };
|
|
1574
|
+
}
|
|
1575
|
+
if (res.ok) {
|
|
1576
|
+
const etag = res.headers.get("etag") ?? void 0;
|
|
1577
|
+
const contentType = res.headers.get("content-type") ?? void 0;
|
|
1578
|
+
let data;
|
|
1579
|
+
if (contentType?.startsWith("text/plain")) {
|
|
1580
|
+
const text2 = await res.text();
|
|
1581
|
+
const bin = atob(text2);
|
|
1582
|
+
const arr = new Uint8Array(bin.length);
|
|
1583
|
+
for (let i = 0; i < bin.length; i++) arr[i] = bin.charCodeAt(i);
|
|
1584
|
+
data = arr.buffer;
|
|
1585
|
+
} else {
|
|
1586
|
+
data = await res.arrayBuffer();
|
|
1587
|
+
}
|
|
1588
|
+
return {
|
|
1589
|
+
kind: "bytes",
|
|
1590
|
+
data,
|
|
1591
|
+
...etag !== void 0 ? { etag } : {},
|
|
1592
|
+
...contentType !== void 0 ? { contentType } : {}
|
|
1593
|
+
};
|
|
1594
|
+
}
|
|
1595
|
+
const text = await res.text();
|
|
1596
|
+
let parsed = void 0;
|
|
1597
|
+
if (text) {
|
|
1598
|
+
try {
|
|
1599
|
+
parsed = JSON.parse(text);
|
|
1600
|
+
} catch {
|
|
1601
|
+
parsed = text;
|
|
1602
|
+
}
|
|
1603
|
+
}
|
|
1604
|
+
throw errorFromResponse(res.status, `GET ${path} \u2192 ${res.status}`, parsed);
|
|
1605
|
+
}
|
|
1383
1606
|
/** Multipart upload sugar: builds `AssetCreateBlob` from input. */
|
|
1384
1607
|
async uploadFile(input, auth2 = SERVICE2) {
|
|
1385
1608
|
const body = {
|
|
@@ -1395,6 +1618,27 @@ var MediaService = class {
|
|
|
1395
1618
|
};
|
|
1396
1619
|
return this.create({ kind: "blob", file: input.file, body }, auth2);
|
|
1397
1620
|
}
|
|
1621
|
+
/**
|
|
1622
|
+
* Replace the file content of an existing BLOB asset. Sugar over
|
|
1623
|
+
* {@link update} with `kind: "blob"`. `access` is required because the
|
|
1624
|
+
* field is immutable and the server validates that the patch matches.
|
|
1625
|
+
* Pass `version` from `asset.metadata.version` if you want optimistic
|
|
1626
|
+
* locking (recommended when concurrent writers are possible).
|
|
1627
|
+
*/
|
|
1628
|
+
async replaceFile(assetId, input, auth2 = SERVICE2) {
|
|
1629
|
+
const body = {
|
|
1630
|
+
type: "BLOB",
|
|
1631
|
+
access: input.access,
|
|
1632
|
+
...input.filename || input.mimeType ? {
|
|
1633
|
+
details: {
|
|
1634
|
+
...input.filename ? { filename: input.filename } : {},
|
|
1635
|
+
...input.mimeType ? { mimeType: input.mimeType } : {}
|
|
1636
|
+
}
|
|
1637
|
+
} : {},
|
|
1638
|
+
...input.version !== void 0 ? { metadata: { version: input.version } } : {}
|
|
1639
|
+
};
|
|
1640
|
+
return this.update(assetId, { kind: "blob", file: input.file, body }, auth2);
|
|
1641
|
+
}
|
|
1398
1642
|
/** External-URL sugar: builds `AssetCreateLink`. */
|
|
1399
1643
|
async link(input, auth2 = SERVICE2) {
|
|
1400
1644
|
const body = {
|
|
@@ -1412,7 +1656,7 @@ var MediaService = class {
|
|
|
1412
1656
|
if (refIds.some((r) => isProductRef(r, productId))) return a;
|
|
1413
1657
|
const next = [...refIds, { type: "PRODUCT", id: productId }];
|
|
1414
1658
|
const patch = { type: a.type, refIds: next };
|
|
1415
|
-
return this.update(assetId, patch, auth2);
|
|
1659
|
+
return this.update(assetId, { kind: "json", body: patch }, auth2);
|
|
1416
1660
|
}
|
|
1417
1661
|
/** Remove a PRODUCT refId from an asset (no-op if absent). */
|
|
1418
1662
|
async detachFromProduct(assetId, productId, auth2 = SERVICE2) {
|
|
@@ -1421,7 +1665,7 @@ var MediaService = class {
|
|
|
1421
1665
|
const next = refIds.filter((r) => !isProductRef(r, productId));
|
|
1422
1666
|
if (next.length === refIds.length) return a;
|
|
1423
1667
|
const patch = { type: a.type, refIds: next };
|
|
1424
|
-
return this.update(assetId, patch, auth2);
|
|
1668
|
+
return this.update(assetId, { kind: "json", body: patch }, auth2);
|
|
1425
1669
|
}
|
|
1426
1670
|
/** Convenience: list assets attached to a product (server-side filter). */
|
|
1427
1671
|
async listForProduct(productId, auth2 = SERVICE2) {
|
|
@@ -1933,6 +2177,61 @@ var SalesOrdersService = class {
|
|
|
1933
2177
|
}
|
|
1934
2178
|
};
|
|
1935
2179
|
|
|
2180
|
+
// src/services/availability.ts
|
|
2181
|
+
var ANON6 = { kind: "anonymous" };
|
|
2182
|
+
var AvailabilityService = class {
|
|
2183
|
+
constructor(ctx) {
|
|
2184
|
+
this.ctx = ctx;
|
|
2185
|
+
}
|
|
2186
|
+
ctx;
|
|
2187
|
+
/**
|
|
2188
|
+
* Single product. Resolves the availability record, or — when
|
|
2189
|
+
* `opts.defaultAvailableOnNotFound` is set — a default available record on 404.
|
|
2190
|
+
*/
|
|
2191
|
+
async get(productId, siteCode, auth2 = ANON6, opts = {}) {
|
|
2192
|
+
try {
|
|
2193
|
+
return await this.ctx.http.request({
|
|
2194
|
+
method: "GET",
|
|
2195
|
+
path: `/availability/${this.ctx.tenant}/availability/${encodeURIComponent(
|
|
2196
|
+
productId
|
|
2197
|
+
)}/${encodeURIComponent(siteCode)}`,
|
|
2198
|
+
auth: auth2
|
|
2199
|
+
});
|
|
2200
|
+
} catch (err) {
|
|
2201
|
+
if (err instanceof EmporixNotFoundError && opts.defaultAvailableOnNotFound) {
|
|
2202
|
+
return { productId, site: siteCode, available: true };
|
|
2203
|
+
}
|
|
2204
|
+
throw err;
|
|
2205
|
+
}
|
|
2206
|
+
}
|
|
2207
|
+
/**
|
|
2208
|
+
* Batch read via `POST .../availability/search` (one request). Products with
|
|
2209
|
+
* no availability record are absent from the response; each is synthesized as
|
|
2210
|
+
* `{ available: false }` (or `{ available: true }` when
|
|
2211
|
+
* `opts.defaultAvailableOnNotFound` is set). The result preserves input order
|
|
2212
|
+
* and length. An empty `productIds` resolves to `[]` without a request.
|
|
2213
|
+
*/
|
|
2214
|
+
async getMany(productIds, siteCode, auth2 = ANON6, opts = {}) {
|
|
2215
|
+
if (productIds.length === 0) return [];
|
|
2216
|
+
const found = await this.ctx.http.request({
|
|
2217
|
+
method: "POST",
|
|
2218
|
+
path: `/availability/${this.ctx.tenant}/availability/search`,
|
|
2219
|
+
auth: auth2,
|
|
2220
|
+
query: { site: siteCode, pageSize: productIds.length },
|
|
2221
|
+
body: productIds
|
|
2222
|
+
});
|
|
2223
|
+
const byId = /* @__PURE__ */ new Map();
|
|
2224
|
+
for (const a of found) if (a.productId) byId.set(a.productId, a);
|
|
2225
|
+
return productIds.map(
|
|
2226
|
+
(id) => byId.get(id) ?? {
|
|
2227
|
+
productId: id,
|
|
2228
|
+
site: siteCode,
|
|
2229
|
+
available: Boolean(opts.defaultAvailableOnNotFound)
|
|
2230
|
+
}
|
|
2231
|
+
);
|
|
2232
|
+
}
|
|
2233
|
+
};
|
|
2234
|
+
|
|
1936
2235
|
// src/client.ts
|
|
1937
2236
|
var SDK_VERSION = "0.0.0";
|
|
1938
2237
|
var EmporixClient = class {
|
|
@@ -1953,6 +2252,7 @@ var EmporixClient = class {
|
|
|
1953
2252
|
customerGroups;
|
|
1954
2253
|
orders;
|
|
1955
2254
|
salesOrders;
|
|
2255
|
+
availability;
|
|
1956
2256
|
/** The validated tenant this client is bound to. */
|
|
1957
2257
|
tenant;
|
|
1958
2258
|
/**
|
|
@@ -2022,6 +2322,7 @@ var EmporixClient = class {
|
|
|
2022
2322
|
this.customerGroups = new CustomerGroupsService(mk("iam"));
|
|
2023
2323
|
this.orders = new OrdersService(mk("orders"));
|
|
2024
2324
|
this.salesOrders = new SalesOrdersService(mk("sales-orders"));
|
|
2325
|
+
this.availability = new AvailabilityService(mk("availability"));
|
|
2025
2326
|
}
|
|
2026
2327
|
/** Sets the runtime log level globally or for one service. */
|
|
2027
2328
|
setLogLevel(level, opts = {}) {
|
|
@@ -2033,6 +2334,7 @@ var EmporixClient = class {
|
|
|
2033
2334
|
}
|
|
2034
2335
|
};
|
|
2035
2336
|
|
|
2337
|
+
exports.AvailabilityService = AvailabilityService;
|
|
2036
2338
|
exports.CartService = CartService;
|
|
2037
2339
|
exports.CategoryService = CategoryService;
|
|
2038
2340
|
exports.CheckoutService = CheckoutService;
|