@viu/emporix-sdk 1.0.0 → 2.0.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 +38 -0
- package/README.md +13 -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-WSXRUYBE.js +248 -0
- package/dist/chunk-WSXRUYBE.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-mMTqsW1Z.d.cts} +15 -0
- package/dist/{context-vKgzZ-5f.d.ts → context-mMTqsW1Z.d.ts} +15 -0
- 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 +186 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +53 -2
- 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.d.cts +1 -1
- package/dist/price.d.ts +1 -1
- package/dist/product.d.cts +1 -1
- package/dist/product.d.ts +1 -1
- package/dist/segment.d.cts +1 -1
- package/dist/segment.d.ts +1 -1
- package/package.json +2 -2
- package/dist/chunk-F3WAQH2E.js +0 -120
- package/dist/chunk-F3WAQH2E.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
|
|
@@ -1346,14 +1397,29 @@ var MediaService = class {
|
|
|
1346
1397
|
body: input.body
|
|
1347
1398
|
});
|
|
1348
1399
|
}
|
|
1349
|
-
/**
|
|
1350
|
-
|
|
1351
|
-
|
|
1400
|
+
/**
|
|
1401
|
+
* List assets, wrapped in the shared {@link PaginatedItems} envelope so
|
|
1402
|
+
* callers can iterate over pages consistently with the rest of the SDK.
|
|
1403
|
+
* `hasNextPage` is the standard SDK heuristic: `true` when the returned
|
|
1404
|
+
* page is full (`items.length === requested pageSize`). Pagination
|
|
1405
|
+
* defaults match Emporix's server defaults (`pageNumber: 1`,
|
|
1406
|
+
* `pageSize: 60`) so an empty `query` produces stable expectations.
|
|
1407
|
+
*/
|
|
1408
|
+
async list(query = {}, auth2 = SERVICE2) {
|
|
1409
|
+
const pageNumber = query.pageNumber ?? 1;
|
|
1410
|
+
const pageSize = query.pageSize ?? 60;
|
|
1411
|
+
const items = await this.ctx.http.request({
|
|
1352
1412
|
method: "GET",
|
|
1353
1413
|
path: this.base(),
|
|
1354
1414
|
auth: auth2,
|
|
1355
|
-
|
|
1415
|
+
query: { ...query, pageNumber, pageSize }
|
|
1356
1416
|
});
|
|
1417
|
+
return {
|
|
1418
|
+
items,
|
|
1419
|
+
pageNumber,
|
|
1420
|
+
pageSize,
|
|
1421
|
+
hasNextPage: items.length === pageSize
|
|
1422
|
+
};
|
|
1357
1423
|
}
|
|
1358
1424
|
/** Fetch an asset by id. */
|
|
1359
1425
|
async get(assetId, auth2 = SERVICE2) {
|
|
@@ -1363,13 +1429,37 @@ var MediaService = class {
|
|
|
1363
1429
|
auth: auth2
|
|
1364
1430
|
});
|
|
1365
1431
|
}
|
|
1366
|
-
/**
|
|
1367
|
-
|
|
1432
|
+
/**
|
|
1433
|
+
* Update an asset. The input is a discriminated union mirroring
|
|
1434
|
+
* {@link create}:
|
|
1435
|
+
* - `{ kind: "json", body }` — metadata-only patch (BLOB or LINK).
|
|
1436
|
+
* Sends `application/json`. Used for `refIds`, `details`, `metadata`,
|
|
1437
|
+
* or `url` changes.
|
|
1438
|
+
* - `{ kind: "blob", file, body }` — replaces the BLOB file content
|
|
1439
|
+
* (max 10MB) AND patches metadata in the same request. Sends
|
|
1440
|
+
* `multipart/form-data`.
|
|
1441
|
+
*
|
|
1442
|
+
* `type` and `access` are immutable per Emporix — they must match the
|
|
1443
|
+
* existing asset's values. Optimistic-locking is via `body.metadata.version`;
|
|
1444
|
+
* the server returns 409 Conflict on a stale version.
|
|
1445
|
+
*/
|
|
1446
|
+
async update(assetId, input, auth2 = SERVICE2) {
|
|
1447
|
+
if (input.kind === "blob") {
|
|
1448
|
+
const fd = new FormData();
|
|
1449
|
+
fd.set("file", input.file);
|
|
1450
|
+
fd.set("body", JSON.stringify(input.body));
|
|
1451
|
+
return this.ctx.http.request({
|
|
1452
|
+
method: "PUT",
|
|
1453
|
+
path: `${this.base()}/${assetId}`,
|
|
1454
|
+
auth: auth2,
|
|
1455
|
+
body: fd
|
|
1456
|
+
});
|
|
1457
|
+
}
|
|
1368
1458
|
return this.ctx.http.request({
|
|
1369
1459
|
method: "PUT",
|
|
1370
1460
|
path: `${this.base()}/${assetId}`,
|
|
1371
1461
|
auth: auth2,
|
|
1372
|
-
body:
|
|
1462
|
+
body: input.body
|
|
1373
1463
|
});
|
|
1374
1464
|
}
|
|
1375
1465
|
/** Remove an asset. */
|
|
@@ -1380,6 +1470,72 @@ var MediaService = class {
|
|
|
1380
1470
|
auth: auth2
|
|
1381
1471
|
});
|
|
1382
1472
|
}
|
|
1473
|
+
/**
|
|
1474
|
+
* Download an asset by id. Returns a discriminated union:
|
|
1475
|
+
* - `{ kind: "redirect", url }` for `PUBLIC` assets (server-side 30x with
|
|
1476
|
+
* the storage URL in `Location`).
|
|
1477
|
+
* - `{ kind: "bytes", data }` for `PRIVATE` assets (server-side 200 with
|
|
1478
|
+
* the asset bytes; `etag` + `contentType` headers are exposed for
|
|
1479
|
+
* caching). When the server reports `text/plain` Content-Type (the
|
|
1480
|
+
* OpenAPI-documented format), the SDK decodes the base64 stream into
|
|
1481
|
+
* an `ArrayBuffer` transparently; binary Content-Types are passed
|
|
1482
|
+
* through verbatim.
|
|
1483
|
+
*
|
|
1484
|
+
* Implementation note: uses `redirect: "manual"` so the redirect-location
|
|
1485
|
+
* is observable. In Node.js this works; in a browser the redirect Location
|
|
1486
|
+
* is intentionally hidden by fetch — there, `PUBLIC` downloads will
|
|
1487
|
+
* surface as an opaque-redirect and the SDK throws. Browser code should
|
|
1488
|
+
* use the asset's `url` field from `get()` for `LINK` assets, or the
|
|
1489
|
+
* direct storage URL for `PUBLIC` `BLOB` assets (typically delivered via
|
|
1490
|
+
* an `<img>` tag rather than `download()`).
|
|
1491
|
+
*/
|
|
1492
|
+
async download(assetId, auth2 = SERVICE2) {
|
|
1493
|
+
const path = `${this.base()}/${assetId}/download`;
|
|
1494
|
+
const res = await this.ctx.http.requestRaw(
|
|
1495
|
+
{ method: "GET", path, auth: auth2 },
|
|
1496
|
+
{ redirect: "manual" }
|
|
1497
|
+
);
|
|
1498
|
+
if (res.status >= 300 && res.status < 400) {
|
|
1499
|
+
const url = res.headers.get("location");
|
|
1500
|
+
if (!url) {
|
|
1501
|
+
throw new EmporixError(
|
|
1502
|
+
`media.download: ${res.status} response without a Location header`,
|
|
1503
|
+
res.status
|
|
1504
|
+
);
|
|
1505
|
+
}
|
|
1506
|
+
return { kind: "redirect", url };
|
|
1507
|
+
}
|
|
1508
|
+
if (res.ok) {
|
|
1509
|
+
const etag = res.headers.get("etag") ?? void 0;
|
|
1510
|
+
const contentType = res.headers.get("content-type") ?? void 0;
|
|
1511
|
+
let data;
|
|
1512
|
+
if (contentType?.startsWith("text/plain")) {
|
|
1513
|
+
const text2 = await res.text();
|
|
1514
|
+
const bin = atob(text2);
|
|
1515
|
+
const arr = new Uint8Array(bin.length);
|
|
1516
|
+
for (let i = 0; i < bin.length; i++) arr[i] = bin.charCodeAt(i);
|
|
1517
|
+
data = arr.buffer;
|
|
1518
|
+
} else {
|
|
1519
|
+
data = await res.arrayBuffer();
|
|
1520
|
+
}
|
|
1521
|
+
return {
|
|
1522
|
+
kind: "bytes",
|
|
1523
|
+
data,
|
|
1524
|
+
...etag !== void 0 ? { etag } : {},
|
|
1525
|
+
...contentType !== void 0 ? { contentType } : {}
|
|
1526
|
+
};
|
|
1527
|
+
}
|
|
1528
|
+
const text = await res.text();
|
|
1529
|
+
let parsed = void 0;
|
|
1530
|
+
if (text) {
|
|
1531
|
+
try {
|
|
1532
|
+
parsed = JSON.parse(text);
|
|
1533
|
+
} catch {
|
|
1534
|
+
parsed = text;
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
throw errorFromResponse(res.status, `GET ${path} \u2192 ${res.status}`, parsed);
|
|
1538
|
+
}
|
|
1383
1539
|
/** Multipart upload sugar: builds `AssetCreateBlob` from input. */
|
|
1384
1540
|
async uploadFile(input, auth2 = SERVICE2) {
|
|
1385
1541
|
const body = {
|
|
@@ -1395,6 +1551,27 @@ var MediaService = class {
|
|
|
1395
1551
|
};
|
|
1396
1552
|
return this.create({ kind: "blob", file: input.file, body }, auth2);
|
|
1397
1553
|
}
|
|
1554
|
+
/**
|
|
1555
|
+
* Replace the file content of an existing BLOB asset. Sugar over
|
|
1556
|
+
* {@link update} with `kind: "blob"`. `access` is required because the
|
|
1557
|
+
* field is immutable and the server validates that the patch matches.
|
|
1558
|
+
* Pass `version` from `asset.metadata.version` if you want optimistic
|
|
1559
|
+
* locking (recommended when concurrent writers are possible).
|
|
1560
|
+
*/
|
|
1561
|
+
async replaceFile(assetId, input, auth2 = SERVICE2) {
|
|
1562
|
+
const body = {
|
|
1563
|
+
type: "BLOB",
|
|
1564
|
+
access: input.access,
|
|
1565
|
+
...input.filename || input.mimeType ? {
|
|
1566
|
+
details: {
|
|
1567
|
+
...input.filename ? { filename: input.filename } : {},
|
|
1568
|
+
...input.mimeType ? { mimeType: input.mimeType } : {}
|
|
1569
|
+
}
|
|
1570
|
+
} : {},
|
|
1571
|
+
...input.version !== void 0 ? { metadata: { version: input.version } } : {}
|
|
1572
|
+
};
|
|
1573
|
+
return this.update(assetId, { kind: "blob", file: input.file, body }, auth2);
|
|
1574
|
+
}
|
|
1398
1575
|
/** External-URL sugar: builds `AssetCreateLink`. */
|
|
1399
1576
|
async link(input, auth2 = SERVICE2) {
|
|
1400
1577
|
const body = {
|
|
@@ -1412,7 +1589,7 @@ var MediaService = class {
|
|
|
1412
1589
|
if (refIds.some((r) => isProductRef(r, productId))) return a;
|
|
1413
1590
|
const next = [...refIds, { type: "PRODUCT", id: productId }];
|
|
1414
1591
|
const patch = { type: a.type, refIds: next };
|
|
1415
|
-
return this.update(assetId, patch, auth2);
|
|
1592
|
+
return this.update(assetId, { kind: "json", body: patch }, auth2);
|
|
1416
1593
|
}
|
|
1417
1594
|
/** Remove a PRODUCT refId from an asset (no-op if absent). */
|
|
1418
1595
|
async detachFromProduct(assetId, productId, auth2 = SERVICE2) {
|
|
@@ -1421,7 +1598,7 @@ var MediaService = class {
|
|
|
1421
1598
|
const next = refIds.filter((r) => !isProductRef(r, productId));
|
|
1422
1599
|
if (next.length === refIds.length) return a;
|
|
1423
1600
|
const patch = { type: a.type, refIds: next };
|
|
1424
|
-
return this.update(assetId, patch, auth2);
|
|
1601
|
+
return this.update(assetId, { kind: "json", body: patch }, auth2);
|
|
1425
1602
|
}
|
|
1426
1603
|
/** Convenience: list assets attached to a product (server-side filter). */
|
|
1427
1604
|
async listForProduct(productId, auth2 = SERVICE2) {
|