@lonca/trendyol 0.10.0 → 0.11.1
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/README.md +18 -33
- package/dist/{client-0omWgpd_.d.cts → client-CCA1P7sb.d.cts} +117 -18
- package/dist/{client-0omWgpd_.d.ts → client-CCA1P7sb.d.ts} +117 -18
- package/dist/index.cjs +104 -107
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +105 -108
- package/dist/index.js.map +1 -1
- package/dist/testing.cjs +104 -107
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +105 -108
- package/dist/testing.js.map +1 -1
- package/package.json +2 -2
package/dist/testing.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { f as BatchRequestStatus, b3 as TrendyolClient } from './client-CCA1P7sb.cjs';
|
|
2
2
|
import '@lonca/core';
|
|
3
3
|
|
|
4
4
|
/** A request the fake client received, normalized for matching in a `handler`. */
|
package/dist/testing.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { f as BatchRequestStatus, b3 as TrendyolClient } from './client-CCA1P7sb.js';
|
|
2
2
|
import '@lonca/core';
|
|
3
3
|
|
|
4
4
|
/** A request the fake client received, normalized for matching in a `handler`. */
|
package/dist/testing.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { randomUUID } from 'crypto';
|
|
1
|
+
import { createRequester, LoncaError, ServerError, RateLimitError, NotFoundError, ValidationError, AuthError, TokenBucketRateLimiter, TimeoutError } from '@lonca/core';
|
|
3
2
|
|
|
4
3
|
// src/resources/brands.ts
|
|
5
4
|
var DEFAULT_PAGE_SIZE = 1e3;
|
|
@@ -39,7 +38,7 @@ var BrandsResource = class {
|
|
|
39
38
|
* `createProducts` and don't want to page through the full `list()`
|
|
40
39
|
* (1000 brands per page).
|
|
41
40
|
*
|
|
42
|
-
* **
|
|
41
|
+
* **Wire fact (verified STAGE 2026-05-25):** Trendyol's
|
|
43
42
|
* doc claims this is a case-sensitive *exact* match, but live behaviour
|
|
44
43
|
* is **substring + case-insensitive** — `search('Trendyol')` returns
|
|
45
44
|
* 17 hits including `TRENDYOLMILLA`, `trendyol vavist`, `Trendyol Üyelik`.
|
|
@@ -1064,6 +1063,7 @@ var LocationsResource = class {
|
|
|
1064
1063
|
};
|
|
1065
1064
|
var MAX_PAGE_SIZE = 200;
|
|
1066
1065
|
var DEFAULT_PAGE_SIZE2 = 50;
|
|
1066
|
+
var MAX_OFFSET_RECORDS = 1e4;
|
|
1067
1067
|
function toIso3(epochMs) {
|
|
1068
1068
|
if (typeof epochMs !== "number" || !Number.isFinite(epochMs) || epochMs === 0) {
|
|
1069
1069
|
return void 0;
|
|
@@ -1237,6 +1237,11 @@ var OrdersResource = class {
|
|
|
1237
1237
|
async list(params = {}) {
|
|
1238
1238
|
const size = Math.min(params.limit ?? DEFAULT_PAGE_SIZE2, MAX_PAGE_SIZE);
|
|
1239
1239
|
const page = params.cursor ? Number.parseInt(params.cursor, 10) : 0;
|
|
1240
|
+
if ((page + 1) * size > MAX_OFFSET_RECORDS) {
|
|
1241
|
+
throw new ValidationError({
|
|
1242
|
+
message: `getShipmentPackages can reach at most ${MAX_OFFSET_RECORDS} records (page ${page} \xD7 size ${size} exceeds it); use listStream() for full scans`
|
|
1243
|
+
});
|
|
1244
|
+
}
|
|
1240
1245
|
const query = { page, size };
|
|
1241
1246
|
if (params.status) query.status = params.status;
|
|
1242
1247
|
if (params.orderNumber) query.orderNumber = params.orderNumber;
|
|
@@ -1251,7 +1256,8 @@ var OrdersResource = class {
|
|
|
1251
1256
|
const items = (data.content ?? []).map(normalizePackage2);
|
|
1252
1257
|
const totalPages = typeof data.totalPages === "number" ? data.totalPages : 0;
|
|
1253
1258
|
const result = { items };
|
|
1254
|
-
|
|
1259
|
+
const nextPageWithinCap = (page + 2) * size <= MAX_OFFSET_RECORDS;
|
|
1260
|
+
if (page + 1 < totalPages && nextPageWithinCap) {
|
|
1255
1261
|
result.nextCursor = String(page + 1);
|
|
1256
1262
|
}
|
|
1257
1263
|
return result;
|
|
@@ -1690,6 +1696,7 @@ var OrdersResource = class {
|
|
|
1690
1696
|
};
|
|
1691
1697
|
var DEFAULT_PAGE_SIZE3 = 50;
|
|
1692
1698
|
var MAX_PAGE_SIZE2 = 1e3;
|
|
1699
|
+
var MAX_INVENTORY_PAGE_SIZE = 100;
|
|
1693
1700
|
var MAX_BUYBOX_BARCODES = 10;
|
|
1694
1701
|
function normalizeRef(ref) {
|
|
1695
1702
|
return {
|
|
@@ -1755,6 +1762,30 @@ function normalizeProduct(node) {
|
|
|
1755
1762
|
if (node.lastModifiedBy !== void 0) out.lastModifiedBy = node.lastModifiedBy;
|
|
1756
1763
|
return out;
|
|
1757
1764
|
}
|
|
1765
|
+
function normalizeStockPriceVariant(node) {
|
|
1766
|
+
const out = {
|
|
1767
|
+
variantId: node.variantId !== void 0 ? String(node.variantId) : "",
|
|
1768
|
+
barcode: node.barcode ?? "",
|
|
1769
|
+
raw: node
|
|
1770
|
+
};
|
|
1771
|
+
if (typeof node.salePrice === "number") out.salePrice = node.salePrice;
|
|
1772
|
+
if (typeof node.listPrice === "number") out.listPrice = node.listPrice;
|
|
1773
|
+
if (typeof node.quantity === "number") out.quantity = node.quantity;
|
|
1774
|
+
if (node.stockCode !== void 0) out.stockCode = node.stockCode;
|
|
1775
|
+
if (node.stockLastModifiedDate !== void 0 && node.stockLastModifiedDate !== null) {
|
|
1776
|
+
const iso = toIso4(node.stockLastModifiedDate);
|
|
1777
|
+
if (iso) out.stockLastModifiedAt = iso;
|
|
1778
|
+
}
|
|
1779
|
+
return out;
|
|
1780
|
+
}
|
|
1781
|
+
function normalizeStockPrice(node) {
|
|
1782
|
+
return {
|
|
1783
|
+
contentId: node.contentId !== void 0 ? String(node.contentId) : "",
|
|
1784
|
+
productMainId: node.productMainId ?? "",
|
|
1785
|
+
variants: (node.variants ?? []).map(normalizeStockPriceVariant),
|
|
1786
|
+
raw: node
|
|
1787
|
+
};
|
|
1788
|
+
}
|
|
1758
1789
|
function normalizeUnapprovedRejectReason(r) {
|
|
1759
1790
|
const out = {};
|
|
1760
1791
|
if (r.rejectReason !== void 0) out.rejectReason = r.rejectReason;
|
|
@@ -1945,6 +1976,63 @@ var ProductsResource = class {
|
|
|
1945
1976
|
}
|
|
1946
1977
|
return page;
|
|
1947
1978
|
}
|
|
1979
|
+
/**
|
|
1980
|
+
* List **stock and price** for approved products — Trendyol's lightweight
|
|
1981
|
+
* `inventory-and-price` filter. A slim alternative to {@link list} when you
|
|
1982
|
+
* only need pricing + stock: the response carries `contentId`,
|
|
1983
|
+
* `productMainId`, and a `variants[]` array with `barcode`, `salePrice`,
|
|
1984
|
+
* `listPrice`, `quantity`, `stockCode`, and `stockLastModifiedAt` — nothing
|
|
1985
|
+
* else.
|
|
1986
|
+
*
|
|
1987
|
+
* Filter by `barcode`, `contentId`, `stockCode`, `productMainId`, or listing
|
|
1988
|
+
* `status`. Sort with `orderByDirection` (`SellerCreatedDate`). `size` caps
|
|
1989
|
+
* at **100** here (tighter than `list`'s 1000).
|
|
1990
|
+
*
|
|
1991
|
+
* Pagination follows the same convention as {@link list}: pass our opaque
|
|
1992
|
+
* `cursor` from the previous response and we forward it as `nextPageToken`
|
|
1993
|
+
* (required once the dataset exceeds 10,000 items).
|
|
1994
|
+
*
|
|
1995
|
+
* @example
|
|
1996
|
+
* ```ts
|
|
1997
|
+
* import { paginate } from '@lonca/core';
|
|
1998
|
+
* for await (const p of paginate((q) =>
|
|
1999
|
+
* client.products.listInventoryAndPrice({ ...q, status: 'onSale' }),
|
|
2000
|
+
* )) {
|
|
2001
|
+
* for (const v of p.variants) {
|
|
2002
|
+
* console.log(v.barcode, v.quantity, v.salePrice);
|
|
2003
|
+
* }
|
|
2004
|
+
* }
|
|
2005
|
+
* ```
|
|
2006
|
+
*/
|
|
2007
|
+
async listInventoryAndPrice(params = {}) {
|
|
2008
|
+
const size = Math.min(params.limit ?? DEFAULT_PAGE_SIZE3, MAX_INVENTORY_PAGE_SIZE);
|
|
2009
|
+
const query = { size };
|
|
2010
|
+
if (params.cursor) {
|
|
2011
|
+
query.nextPageToken = params.cursor;
|
|
2012
|
+
} else {
|
|
2013
|
+
query.page = 0;
|
|
2014
|
+
}
|
|
2015
|
+
if (params.barcode) query.barcode = params.barcode;
|
|
2016
|
+
if (params.contentId) query.contentId = params.contentId;
|
|
2017
|
+
if (params.stockCode) query.stockCode = params.stockCode;
|
|
2018
|
+
if (params.productMainId) query.productMainId = params.productMainId;
|
|
2019
|
+
if (params.status) query.status = params.status;
|
|
2020
|
+
if (params.orderByDirection) query.orderByDirection = params.orderByDirection;
|
|
2021
|
+
const headers = params.storeFrontCode ? { storeFrontCode: params.storeFrontCode } : void 0;
|
|
2022
|
+
const data = await this.transport.request({
|
|
2023
|
+
method: "GET",
|
|
2024
|
+
path: `/integration/product/sellers/${this.transport.sellerId}/products/approved/inventory-and-price`,
|
|
2025
|
+
query,
|
|
2026
|
+
headers,
|
|
2027
|
+
rateLimiter: this.filterLimiter
|
|
2028
|
+
});
|
|
2029
|
+
const items = (data.content ?? []).map(normalizeStockPrice);
|
|
2030
|
+
const page = { items };
|
|
2031
|
+
if (data.nextPageToken) {
|
|
2032
|
+
page.nextCursor = data.nextPageToken;
|
|
2033
|
+
}
|
|
2034
|
+
return page;
|
|
2035
|
+
}
|
|
1948
2036
|
/**
|
|
1949
2037
|
* Poll a batch request returned by an async write (e.g. `createProducts`,
|
|
1950
2038
|
* `updatePriceAndInventory`).
|
|
@@ -2691,14 +2779,6 @@ function extractErrorsArray(body) {
|
|
|
2691
2779
|
}
|
|
2692
2780
|
return void 0;
|
|
2693
2781
|
}
|
|
2694
|
-
function parseRetryAfter(header) {
|
|
2695
|
-
if (!header) return void 0;
|
|
2696
|
-
const seconds = Number(header);
|
|
2697
|
-
if (!Number.isNaN(seconds)) return Math.max(0, seconds * 1e3);
|
|
2698
|
-
const epoch = Date.parse(header);
|
|
2699
|
-
if (!Number.isNaN(epoch)) return Math.max(0, epoch - Date.now());
|
|
2700
|
-
return void 0;
|
|
2701
|
-
}
|
|
2702
2782
|
|
|
2703
2783
|
// src/transport.ts
|
|
2704
2784
|
var BASE_URLS = {
|
|
@@ -2709,95 +2789,26 @@ var TrendyolTransport = class {
|
|
|
2709
2789
|
constructor(config) {
|
|
2710
2790
|
this.config = config;
|
|
2711
2791
|
this.baseUrl = BASE_URLS[config.env];
|
|
2712
|
-
this.
|
|
2713
|
-
|
|
2714
|
-
|
|
2792
|
+
this.requester = createRequester({
|
|
2793
|
+
fetch: config.fetch ?? fetch,
|
|
2794
|
+
logger: config.logger,
|
|
2795
|
+
timeoutMs: config.timeoutMs ?? 3e4,
|
|
2796
|
+
label: "Trendyol",
|
|
2797
|
+
logPrefix: "trendyol",
|
|
2798
|
+
buildUrl: (opts) => this.buildUrl(opts.path, opts.query),
|
|
2799
|
+
buildHeaders: (correlationId) => this.buildHeaders(correlationId),
|
|
2800
|
+
mapHttpError
|
|
2801
|
+
});
|
|
2715
2802
|
}
|
|
2716
2803
|
config;
|
|
2717
2804
|
baseUrl;
|
|
2718
|
-
|
|
2719
|
-
timeoutMs;
|
|
2720
|
-
fetchImpl;
|
|
2805
|
+
requester;
|
|
2721
2806
|
/** Seller ID this transport is configured with. Resources read it for path-building. */
|
|
2722
2807
|
get sellerId() {
|
|
2723
2808
|
return this.config.sellerId;
|
|
2724
2809
|
}
|
|
2725
|
-
|
|
2726
|
-
return
|
|
2727
|
-
async (attempt) => {
|
|
2728
|
-
if (opts.rateLimiter) await opts.rateLimiter.acquire(opts.signal);
|
|
2729
|
-
const url = this.buildUrl(opts.path, opts.query);
|
|
2730
|
-
const correlationId = randomUUID();
|
|
2731
|
-
const headers = this.buildHeaders(correlationId);
|
|
2732
|
-
const init = {
|
|
2733
|
-
method: opts.method,
|
|
2734
|
-
headers,
|
|
2735
|
-
signal: this.composeSignal(opts.signal)
|
|
2736
|
-
};
|
|
2737
|
-
if (opts.body !== void 0 && opts.method !== "GET") {
|
|
2738
|
-
if (opts.body instanceof FormData) {
|
|
2739
|
-
init.body = opts.body;
|
|
2740
|
-
delete headers["Content-Type"];
|
|
2741
|
-
} else {
|
|
2742
|
-
init.body = JSON.stringify(opts.body);
|
|
2743
|
-
}
|
|
2744
|
-
}
|
|
2745
|
-
this.logger.debug("trendyol.request", {
|
|
2746
|
-
method: opts.method,
|
|
2747
|
-
url,
|
|
2748
|
-
correlationId,
|
|
2749
|
-
attempt
|
|
2750
|
-
});
|
|
2751
|
-
let response;
|
|
2752
|
-
try {
|
|
2753
|
-
response = await this.fetchImpl(url, init);
|
|
2754
|
-
} catch (err) {
|
|
2755
|
-
if (err instanceof Error && err.name === "AbortError") {
|
|
2756
|
-
throw new TimeoutError({
|
|
2757
|
-
message: `Trendyol request timed out after ${this.timeoutMs}ms`,
|
|
2758
|
-
cause: err
|
|
2759
|
-
});
|
|
2760
|
-
}
|
|
2761
|
-
throw new NetworkError({
|
|
2762
|
-
message: "Trendyol network failure",
|
|
2763
|
-
cause: err
|
|
2764
|
-
});
|
|
2765
|
-
}
|
|
2766
|
-
if (!response.ok) {
|
|
2767
|
-
const body = await safeJson(response);
|
|
2768
|
-
const retryAfterMs = parseRetryAfter(response.headers.get("retry-after"));
|
|
2769
|
-
const error = mapHttpError(response.status, body, retryAfterMs);
|
|
2770
|
-
this.logger.warn("trendyol.error", {
|
|
2771
|
-
method: opts.method,
|
|
2772
|
-
url,
|
|
2773
|
-
correlationId,
|
|
2774
|
-
status: response.status,
|
|
2775
|
-
code: error.code,
|
|
2776
|
-
retryable: error.retryable
|
|
2777
|
-
});
|
|
2778
|
-
throw error;
|
|
2779
|
-
}
|
|
2780
|
-
this.logger.debug("trendyol.response", {
|
|
2781
|
-
correlationId,
|
|
2782
|
-
status: response.status
|
|
2783
|
-
});
|
|
2784
|
-
if (response.status === 204) return void 0;
|
|
2785
|
-
return await safeJson(response);
|
|
2786
|
-
},
|
|
2787
|
-
{
|
|
2788
|
-
signal: opts.signal,
|
|
2789
|
-
onRetry: (err, attempt, delay2) => {
|
|
2790
|
-
if (err instanceof LoncaError) {
|
|
2791
|
-
this.logger.warn("trendyol.retry", {
|
|
2792
|
-
attempt,
|
|
2793
|
-
delayMs: delay2,
|
|
2794
|
-
code: err.code,
|
|
2795
|
-
status: err.status
|
|
2796
|
-
});
|
|
2797
|
-
}
|
|
2798
|
-
}
|
|
2799
|
-
}
|
|
2800
|
-
);
|
|
2810
|
+
request(opts) {
|
|
2811
|
+
return this.requester(opts);
|
|
2801
2812
|
}
|
|
2802
2813
|
buildUrl(path, query) {
|
|
2803
2814
|
const url = new URL(path, this.baseUrl);
|
|
@@ -2820,21 +2831,7 @@ var TrendyolTransport = class {
|
|
|
2820
2831
|
Accept: "application/json"
|
|
2821
2832
|
};
|
|
2822
2833
|
}
|
|
2823
|
-
composeSignal(external) {
|
|
2824
|
-
const timeoutSignal = AbortSignal.timeout(this.timeoutMs);
|
|
2825
|
-
if (!external) return timeoutSignal;
|
|
2826
|
-
return AbortSignal.any([external, timeoutSignal]);
|
|
2827
|
-
}
|
|
2828
2834
|
};
|
|
2829
|
-
async function safeJson(response) {
|
|
2830
|
-
const text = await response.text();
|
|
2831
|
-
if (!text) return void 0;
|
|
2832
|
-
try {
|
|
2833
|
-
return JSON.parse(text);
|
|
2834
|
-
} catch {
|
|
2835
|
-
return text;
|
|
2836
|
-
}
|
|
2837
|
-
}
|
|
2838
2835
|
|
|
2839
2836
|
// src/client.ts
|
|
2840
2837
|
function buildClient(transport) {
|