@lonca/trendyol 0.8.0 → 0.10.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/dist/index.cjs CHANGED
@@ -397,6 +397,269 @@ var ClaimsResource = class {
397
397
  return rows.map((row) => ({ raw: row }));
398
398
  }
399
399
  };
400
+ var MAX_BATCH_ITEMS = 5e3;
401
+ var ExportCenterResource = class {
402
+ constructor(transport, limiter) {
403
+ this.transport = transport;
404
+ this.limiter = limiter ?? new core.TokenBucketRateLimiter({ capacity: 1e3, intervalMs: 6e4 });
405
+ }
406
+ transport;
407
+ limiter;
408
+ // ─── Products ────────────────────────────────────────────────────────────
409
+ /**
410
+ * List Export Center-approved products. Uses Trendyol's `pageKey`
411
+ * pagination — the first call leaves `pageKey` empty; subsequent
412
+ * calls pass the `x-paging-key` value from the previous response.
413
+ */
414
+ async listProducts(params = {}) {
415
+ const query = {};
416
+ if (params.barcodes && params.barcodes.length > 0) query.barcodes = params.barcodes.join(",");
417
+ if (params.pageKey) query.pageKey = params.pageKey;
418
+ if (params.size !== void 0) query.size = params.size;
419
+ const data = await this.transport.request({
420
+ method: "GET",
421
+ path: `/integration/ecgw/v2/${this.transport.sellerId}/products`,
422
+ query: Object.keys(query).length ? query : void 0,
423
+ rateLimiter: this.limiter
424
+ });
425
+ const rows = pickArray(data);
426
+ return rows.map((r) => ({ raw: r ?? {} }));
427
+ }
428
+ /**
429
+ * Create Export Center products. Maximum 5000 per call. Returns a
430
+ * `batchId` you can poll via `getBatchStatus(batchId)`.
431
+ *
432
+ * @throws {ValidationError} when `products` is empty / oversized.
433
+ */
434
+ async createProducts(products) {
435
+ this.assertBatch(products, "createProducts");
436
+ const data = await this.transport.request({
437
+ method: "POST",
438
+ path: `/integration/ecgw/v2/${this.transport.sellerId}/products`,
439
+ body: { products },
440
+ rateLimiter: this.limiter
441
+ });
442
+ return normalizeBatchResponse(data);
443
+ }
444
+ /**
445
+ * Update Export Center prices. **Trendyol allows one price update per
446
+ * barcode per day.** Returns a `batchId`.
447
+ *
448
+ * @throws {ValidationError} when `priceInfos` is empty / oversized.
449
+ */
450
+ async updatePrices(priceInfos) {
451
+ this.assertBatch(priceInfos, "updatePrices");
452
+ const data = await this.transport.request({
453
+ method: "POST",
454
+ path: `/integration/ecgw/v1/${this.transport.sellerId}/prices`,
455
+ body: { priceInfos },
456
+ rateLimiter: this.limiter
457
+ });
458
+ return normalizeBatchResponse(data);
459
+ }
460
+ /**
461
+ * Update Export Center stocks. Returns a `batchId`. Sellers using
462
+ * Trendyol's shared inventory cannot use this endpoint (per portal docs).
463
+ *
464
+ * @throws {ValidationError} when `items` is empty / oversized.
465
+ */
466
+ async updateStocks(items) {
467
+ this.assertBatch(items, "updateStocks");
468
+ const data = await this.transport.request({
469
+ method: "POST",
470
+ path: `/integration/ecgw/v1/${this.transport.sellerId}/stocks`,
471
+ body: { items },
472
+ rateLimiter: this.limiter
473
+ });
474
+ return normalizeBatchResponse(data);
475
+ }
476
+ // ─── Batch status ────────────────────────────────────────────────────────
477
+ /**
478
+ * Look up the status of a previously-submitted batch. Trendyol retains
479
+ * batch records for **24 hours** only — older `batchId`s return `404`.
480
+ */
481
+ async getBatchStatus(batchId) {
482
+ if (!batchId) {
483
+ throw new core.ValidationError({ message: "exportCenter.getBatchStatus: batchId is required" });
484
+ }
485
+ const data = await this.transport.request({
486
+ method: "GET",
487
+ path: `/integration/ecgw/v1/${this.transport.sellerId}/check-status`,
488
+ query: { batchId },
489
+ rateLimiter: this.limiter
490
+ });
491
+ return normalizeBatchStatus(data);
492
+ }
493
+ // ─── Packages ────────────────────────────────────────────────────────────
494
+ /** List daily Export Center packages (V2 — query-based filters). */
495
+ async listPackagesV2(params = {}) {
496
+ const data = await this.transport.request({
497
+ method: "GET",
498
+ path: `/integration/ecgw/v2/${this.transport.sellerId}/packages`,
499
+ query: {
500
+ trackingNumber: params.trackingNumber,
501
+ status: params.status,
502
+ creationStartDate: params.creationStartDate,
503
+ creationEndDate: params.creationEndDate,
504
+ size: params.size,
505
+ boutiqueId: params.boutiqueId
506
+ },
507
+ rateLimiter: this.limiter
508
+ });
509
+ return pickArray(data).map(normalizePackage);
510
+ }
511
+ /** List Export Center packages (V3 — consolidated, page-based). */
512
+ async listPackagesV3(params = {}) {
513
+ const data = await this.transport.request({
514
+ method: "GET",
515
+ path: `/integration/ecgw/v3/${this.transport.sellerId}/packages`,
516
+ query: {
517
+ status: params.status,
518
+ page: params.offset !== void 0 ? params.offset : void 0,
519
+ size: params.limit,
520
+ creationStartDate: params.creationStartDate,
521
+ creationEndDate: params.creationEndDate
522
+ },
523
+ rateLimiter: this.limiter
524
+ });
525
+ return pickArray(data).map(normalizePackage);
526
+ }
527
+ /** Get the line items inside an Export Center package. */
528
+ async getPackageItems(params) {
529
+ if (!params || !params.packageId) {
530
+ throw new core.ValidationError({
531
+ message: "exportCenter.getPackageItems: packageId is required"
532
+ });
533
+ }
534
+ const data = await this.transport.request({
535
+ method: "GET",
536
+ path: `/integration/ecgw/v2/${this.transport.sellerId}/packages/items`,
537
+ query: {
538
+ packageId: params.packageId,
539
+ status: params.status,
540
+ page: params.offset,
541
+ size: params.limit
542
+ },
543
+ rateLimiter: this.limiter
544
+ });
545
+ return pickArray(data).map((r) => ({ raw: r ?? {} }));
546
+ }
547
+ // ─── Lookup ──────────────────────────────────────────────────────────────
548
+ /** Get the required attributes for an Export Center category. */
549
+ async getCategoryAttributes(categoryId) {
550
+ if (categoryId === void 0 || categoryId === null || categoryId === "") {
551
+ throw new core.ValidationError({
552
+ message: "exportCenter.getCategoryAttributes: categoryId is required"
553
+ });
554
+ }
555
+ const data = await this.transport.request({
556
+ method: "GET",
557
+ path: `/integration/ecgw/v1/${this.transport.sellerId}/lookup/product-categories/${encodeURIComponent(String(categoryId))}/attributes`,
558
+ rateLimiter: this.limiter
559
+ });
560
+ return pickArray(data).map((r) => {
561
+ const row = r ?? {};
562
+ const out = { raw: row };
563
+ if (typeof row.attributeId === "number" || typeof row.attributeId === "string") {
564
+ out.attributeId = row.attributeId;
565
+ }
566
+ if (typeof row.attributeName === "string") out.attributeName = row.attributeName;
567
+ if (typeof row.required === "boolean") out.required = row.required;
568
+ if (Array.isArray(row.values)) out.values = row.values;
569
+ return out;
570
+ });
571
+ }
572
+ /** Get the care-instruction lookup values used by `createProducts`. */
573
+ async getCareInstructions() {
574
+ const data = await this.transport.request({
575
+ method: "GET",
576
+ path: `/integration/ecgw/v1/${this.transport.sellerId}/lookup/care-instructions`,
577
+ rateLimiter: this.limiter
578
+ });
579
+ return pickArray(data).map(normalizeNamedRef);
580
+ }
581
+ /** Get the material-composition lookup values used by `createProducts`. */
582
+ async getCompositions() {
583
+ const data = await this.transport.request({
584
+ method: "GET",
585
+ path: `/integration/ecgw/v1/${this.transport.sellerId}/lookup/compositions`,
586
+ rateLimiter: this.limiter
587
+ });
588
+ return pickArray(data).map(normalizeNamedRef);
589
+ }
590
+ /** Get the country-of-origin lookup values used by `createProducts`. */
591
+ async getOrigins() {
592
+ const data = await this.transport.request({
593
+ method: "GET",
594
+ path: `/integration/ecgw/v1/${this.transport.sellerId}/lookup/origins`,
595
+ rateLimiter: this.limiter
596
+ });
597
+ return pickArray(data).map((r) => {
598
+ const row = r ?? {};
599
+ const out = { raw: row };
600
+ if (typeof row.id === "number" || typeof row.id === "string") out.id = row.id;
601
+ if (typeof row.name === "string") out.name = row.name;
602
+ if (typeof row.countryCode === "string") out.countryCode = row.countryCode;
603
+ return out;
604
+ });
605
+ }
606
+ // ─── Helpers ─────────────────────────────────────────────────────────────
607
+ assertBatch(items, methodLabel) {
608
+ if (!Array.isArray(items) || items.length === 0) {
609
+ throw new core.ValidationError({
610
+ message: `exportCenter.${methodLabel}: items must not be empty`
611
+ });
612
+ }
613
+ if (items.length > MAX_BATCH_ITEMS) {
614
+ throw new core.ValidationError({
615
+ message: `exportCenter.${methodLabel}: max ${MAX_BATCH_ITEMS} items per call (got ${items.length})`
616
+ });
617
+ }
618
+ }
619
+ };
620
+ function pickArray(data) {
621
+ if (Array.isArray(data)) return data;
622
+ if (data && typeof data === "object") {
623
+ const obj = data;
624
+ if (Array.isArray(obj.content)) return obj.content;
625
+ if (Array.isArray(obj.items)) return obj.items;
626
+ if (Array.isArray(obj.data)) return obj.data;
627
+ if (Array.isArray(obj.products)) return obj.products;
628
+ if (Array.isArray(obj.packages)) return obj.packages;
629
+ }
630
+ return [];
631
+ }
632
+ function normalizeBatchResponse(data) {
633
+ const obj = data && typeof data === "object" ? data : {};
634
+ return {
635
+ batchId: String(obj.batchId ?? obj.batchRequestId ?? obj.id ?? ""),
636
+ raw: obj
637
+ };
638
+ }
639
+ function normalizeBatchStatus(data) {
640
+ const obj = data && typeof data === "object" ? data : {};
641
+ const out = { raw: obj };
642
+ if (typeof obj.batchId === "string") out.batchId = obj.batchId;
643
+ if (typeof obj.status === "string") out.status = obj.status;
644
+ if (typeof obj.itemCount === "number") out.itemCount = obj.itemCount;
645
+ if (typeof obj.failedItemCount === "number") out.failedItemCount = obj.failedItemCount;
646
+ if (Array.isArray(obj.items)) out.items = obj.items;
647
+ return out;
648
+ }
649
+ function normalizePackage(row) {
650
+ const r = row ?? {};
651
+ const out = { raw: r };
652
+ if (typeof r.packageNumber === "string") out.packageNumber = r.packageNumber;
653
+ if (typeof r.status === "string") out.status = r.status;
654
+ return out;
655
+ }
656
+ function normalizeNamedRef(row) {
657
+ const r = row ?? {};
658
+ const out = { raw: r };
659
+ if (typeof r.id === "number" || typeof r.id === "string") out.id = r.id;
660
+ if (typeof r.name === "string") out.name = r.name;
661
+ return out;
662
+ }
400
663
  function toIso2(epochMs) {
401
664
  if (typeof epochMs !== "number" || !Number.isFinite(epochMs) || epochMs === 0) {
402
665
  return void 0;
@@ -442,11 +705,14 @@ var FinanceResource = class {
442
705
  transport;
443
706
  limiter;
444
707
  async getSettlements(params = {}) {
445
- return this.queryPage(`/integration/sellers/${this.transport.sellerId}/settlements`, params);
708
+ return this.queryPage(
709
+ `/integration/finance/che/sellers/${this.transport.sellerId}/settlements`,
710
+ params
711
+ );
446
712
  }
447
713
  async getOtherFinancials(params = {}) {
448
714
  return this.queryPage(
449
- `/integration/sellers/${this.transport.sellerId}/otherfinancials`,
715
+ `/integration/finance/che/sellers/${this.transport.sellerId}/otherfinancials`,
450
716
  params
451
717
  );
452
718
  }
@@ -473,11 +739,37 @@ var FinanceResource = class {
473
739
  }
474
740
  };
475
741
  var MAX_ITEMS_PER_REQUEST = 1e3;
742
+ async function pollBatchStatus(getStatus, batchRequestId, opts = {}) {
743
+ const pollIntervalMs = opts.pollIntervalMs ?? 2e3;
744
+ const timeoutMs = opts.timeoutMs ?? 12e4;
745
+ const deadline = Date.now() + timeoutMs;
746
+ for (; ; ) {
747
+ opts.signal?.throwIfAborted();
748
+ const result = await getStatus(batchRequestId);
749
+ if (result.status === "COMPLETED" || result.status === "FAILED") {
750
+ return result;
751
+ }
752
+ if (Date.now() >= deadline) {
753
+ throw new core.TimeoutError({
754
+ message: `Trendyol batch ${batchRequestId} did not settle within ${timeoutMs}ms (last status: ${result.status})`,
755
+ data: { batchRequestId, lastStatus: result.status, lastResult: result }
756
+ });
757
+ }
758
+ await delay(pollIntervalMs, opts.signal);
759
+ }
760
+ }
476
761
  var InventoryResource = class {
477
- constructor(transport) {
762
+ /**
763
+ * @param transport Trendyol transport.
764
+ * @param getBatchStatus Batch-status poller (wired by `createTrendyolClient`
765
+ * to `products.getBatchStatus`). Required only for `updateAndWait`.
766
+ */
767
+ constructor(transport, getBatchStatus) {
478
768
  this.transport = transport;
769
+ this.getBatchStatus = getBatchStatus;
479
770
  }
480
771
  transport;
772
+ getBatchStatus;
481
773
  /**
482
774
  * Update price and/or stock for one or more SKUs (by barcode).
483
775
  *
@@ -491,6 +783,9 @@ var InventoryResource = class {
491
783
  * ```
492
784
  *
493
785
  * @throws {ValidationError} when `items` is empty or longer than 1000.
786
+ * @throws {ServerError} when Trendyol accepts the request but returns no
787
+ * `batchRequestId` (an unpollable response — surfaced loudly instead of
788
+ * handing back an empty id).
494
789
  */
495
790
  async update(items) {
496
791
  if (items.length === 0) {
@@ -506,9 +801,70 @@ var InventoryResource = class {
506
801
  path: `/integration/inventory/sellers/${this.transport.sellerId}/products/price-and-inventory`,
507
802
  body: { items }
508
803
  });
509
- return { batchRequestId: data.batchRequestId ?? "" };
804
+ if (!data.batchRequestId) {
805
+ throw new core.ServerError({
806
+ message: "Trendyol updatePriceAndInventory returned no batchRequestId",
807
+ data: { response: data }
808
+ });
809
+ }
810
+ return { batchRequestId: data.batchRequestId };
811
+ }
812
+ /**
813
+ * Submit price/stock updates and wait for them to settle.
814
+ *
815
+ * Splits `items` into chunks of ≤1000, submits each via {@link update}, and
816
+ * polls each `batchRequestId` to a terminal state. Returns one
817
+ * `BatchRequestResult` per chunk (read `failedItemCount` / `items[]` for
818
+ * per-barcode outcomes). Compose `@lonca/core`'s `retry` around this for
819
+ * transient-error resilience.
820
+ *
821
+ * @throws {ValidationError} when `items` is empty.
822
+ * @throws {TimeoutError} when any chunk does not settle within `timeoutMs`;
823
+ * `error.data.batchRequestId` identifies the stuck chunk.
824
+ */
825
+ async updateAndWait(items, opts = {}) {
826
+ if (items.length === 0) {
827
+ throw new core.ValidationError({ message: "updateAndWait: items must not be empty" });
828
+ }
829
+ const getStatus = this.getBatchStatus;
830
+ if (!getStatus) {
831
+ throw new Error(
832
+ "updateAndWait requires a batch-status poller; obtain the client via createTrendyolClient()"
833
+ );
834
+ }
835
+ const results = [];
836
+ for (const batch of chunk(items, MAX_ITEMS_PER_REQUEST)) {
837
+ const { batchRequestId } = await this.update(batch);
838
+ results.push(await pollBatchStatus(getStatus, batchRequestId, opts));
839
+ }
840
+ return results;
510
841
  }
511
842
  };
843
+ function chunk(items, size) {
844
+ if (items.length <= size) return [items];
845
+ const chunks = [];
846
+ for (let i = 0; i < items.length; i += size) {
847
+ chunks.push(items.slice(i, i + size));
848
+ }
849
+ return chunks;
850
+ }
851
+ function delay(ms, signal) {
852
+ return new Promise((resolve, reject) => {
853
+ if (signal?.aborted) {
854
+ reject(signal.reason ?? new Error("Aborted"));
855
+ return;
856
+ }
857
+ const onAbort = () => {
858
+ clearTimeout(timer);
859
+ reject(signal?.reason ?? new Error("Aborted"));
860
+ };
861
+ const timer = setTimeout(() => {
862
+ signal?.removeEventListener("abort", onAbort);
863
+ resolve();
864
+ }, ms);
865
+ signal?.addEventListener("abort", onAbort, { once: true });
866
+ });
867
+ }
512
868
  var InvoicesResource = class {
513
869
  constructor(transport, limiter) {
514
870
  this.transport = transport;
@@ -794,9 +1150,9 @@ function normalizeCustomer(node) {
794
1150
  return out;
795
1151
  }
796
1152
  function normalizeShipmentPackage(rawNode) {
797
- return normalizePackage(rawNode ?? {});
1153
+ return normalizePackage2(rawNode ?? {});
798
1154
  }
799
- function normalizePackage(node) {
1155
+ function normalizePackage2(node) {
800
1156
  const pkgId = node.shipmentPackageId ?? node.id;
801
1157
  const out = {
802
1158
  id: pkgId !== void 0 ? String(pkgId) : "",
@@ -897,7 +1253,7 @@ var OrdersResource = class {
897
1253
  query,
898
1254
  rateLimiter: this.limiter
899
1255
  });
900
- const items = (data.content ?? []).map(normalizePackage);
1256
+ const items = (data.content ?? []).map(normalizePackage2);
901
1257
  const totalPages = typeof data.totalPages === "number" ? data.totalPages : 0;
902
1258
  const result = { items };
903
1259
  if (page + 1 < totalPages) {
@@ -1194,7 +1550,7 @@ var OrdersResource = class {
1194
1550
  query,
1195
1551
  rateLimiter: this.limiter
1196
1552
  });
1197
- const items = (data.content ?? []).map(normalizePackage);
1553
+ const items = (data.content ?? []).map(normalizePackage2);
1198
1554
  const result = { items };
1199
1555
  if (data.hasMore && data.nextCursor) {
1200
1556
  result.nextCursor = data.nextCursor;
@@ -2077,6 +2433,55 @@ var TestOrdersResource = class {
2077
2433
  });
2078
2434
  }
2079
2435
  };
2436
+ var VideosResource = class {
2437
+ constructor(transport, options = {}) {
2438
+ this.transport = transport;
2439
+ this.createLimiter = options.createLimiter ?? new core.TokenBucketRateLimiter({ capacity: 200, intervalMs: 6e4 });
2440
+ this.listLimiter = options.listLimiter ?? new core.TokenBucketRateLimiter({ capacity: 1e3, intervalMs: 6e4 });
2441
+ }
2442
+ transport;
2443
+ createLimiter;
2444
+ listLimiter;
2445
+ /**
2446
+ * Queue a video for upload. Trendyol downloads from the URL in the
2447
+ * body asynchronously; poll `list()` (filtered by id) for status.
2448
+ *
2449
+ * @throws {ValidationError} when `input` is empty / not an object.
2450
+ */
2451
+ async create(input) {
2452
+ if (!input || typeof input !== "object") {
2453
+ throw new core.ValidationError({ message: "videos.create: input is required" });
2454
+ }
2455
+ return this.transport.request({
2456
+ method: "POST",
2457
+ path: `/integration/video/sellers/${this.transport.sellerId}/videos`,
2458
+ body: input,
2459
+ rateLimiter: this.createLimiter
2460
+ });
2461
+ }
2462
+ /** List the seller's integration videos (optionally filtered by id / status). */
2463
+ async list(params = {}) {
2464
+ const data = await this.transport.request({
2465
+ method: "GET",
2466
+ path: `/integration/video/sellers/${this.transport.sellerId}/videos`,
2467
+ query: {
2468
+ id: params.id,
2469
+ sellerIntegrationStatus: params.sellerIntegrationStatus,
2470
+ page: params.offset,
2471
+ size: params.limit
2472
+ },
2473
+ rateLimiter: this.listLimiter
2474
+ });
2475
+ const rows = Array.isArray(data) ? data : Array.isArray(data?.content) ? data.content : Array.isArray(data?.items) ? data.items : [];
2476
+ return rows.map((r) => {
2477
+ const row = r ?? {};
2478
+ const out = { raw: row };
2479
+ if (typeof row.id === "string") out.id = row.id;
2480
+ if (typeof row.status === "string") out.status = row.status;
2481
+ return out;
2482
+ });
2483
+ }
2484
+ };
2080
2485
  function normalizeWebhook(node) {
2081
2486
  const out = {
2082
2487
  id: node.id !== void 0 ? String(node.id) : "",
@@ -2193,6 +2598,16 @@ var WebhooksResource = class {
2193
2598
  }
2194
2599
  };
2195
2600
 
2601
+ // src/capabilities.ts
2602
+ var trendyolCapabilities = {
2603
+ /** Trendyol has no time-bounded / scheduled pricing (`pricings[]`). */
2604
+ scheduledPricing: false,
2605
+ /** `inventory.update` accepts stock-only items (`quantity` with no price). */
2606
+ stockOnlyBatch: true,
2607
+ /** Products expose `updatedAt`, so last-write-wins guards are supported. */
2608
+ listingUpdatedAt: true
2609
+ };
2610
+
2196
2611
  // src/auth.ts
2197
2612
  function buildAuthHeader(apiKey, apiSecret) {
2198
2613
  const token = Buffer.from(`${apiKey}:${apiSecret}`, "utf8").toString("base64");
@@ -2203,27 +2618,31 @@ function buildUserAgent(sellerId, integratorName) {
2203
2618
  }
2204
2619
  function mapHttpError(status, body, retryAfterMs) {
2205
2620
  const data = { body };
2621
+ const issues = normalizeErrorIssues(body);
2206
2622
  switch (status) {
2207
2623
  case 401:
2208
2624
  return new core.AuthError({
2209
2625
  message: "Trendyol authentication failed (check apiKey / apiSecret)",
2210
2626
  status,
2211
- data
2627
+ data,
2628
+ issues
2212
2629
  });
2213
2630
  case 403:
2214
2631
  return new core.ValidationError({
2215
2632
  message: "Trendyol forbidden (check User-Agent header or endpoint path)",
2216
2633
  status,
2217
- data
2634
+ data,
2635
+ issues
2218
2636
  });
2219
2637
  case 404:
2220
- return new core.NotFoundError({ message: "Trendyol resource not found", status, data });
2638
+ return new core.NotFoundError({ message: "Trendyol resource not found", status, data, issues });
2221
2639
  case 429:
2222
2640
  return new core.RateLimitError({
2223
2641
  message: "Trendyol rate limit exceeded",
2224
2642
  status,
2225
2643
  retryAfterMs,
2226
- data
2644
+ data,
2645
+ issues
2227
2646
  });
2228
2647
  case 500:
2229
2648
  case 502:
@@ -2232,7 +2651,8 @@ function mapHttpError(status, body, retryAfterMs) {
2232
2651
  return new core.ServerError({
2233
2652
  message: `Trendyol server error (${status})`,
2234
2653
  status,
2235
- data
2654
+ data,
2655
+ issues
2236
2656
  });
2237
2657
  default:
2238
2658
  return new core.LoncaError({
@@ -2240,10 +2660,42 @@ function mapHttpError(status, body, retryAfterMs) {
2240
2660
  message: `Trendyol unexpected response (${status})`,
2241
2661
  status,
2242
2662
  data,
2663
+ issues,
2243
2664
  retryable: false
2244
2665
  });
2245
2666
  }
2246
2667
  }
2668
+ function normalizeErrorIssues(body) {
2669
+ const errors = extractErrorsArray(body);
2670
+ if (!errors) return [];
2671
+ const issues = [];
2672
+ for (const entry of errors) {
2673
+ if (typeof entry === "string") {
2674
+ issues.push({ message: entry });
2675
+ continue;
2676
+ }
2677
+ if (entry && typeof entry === "object") {
2678
+ const e = entry;
2679
+ if (typeof e.message !== "string") continue;
2680
+ const issue = { message: e.message };
2681
+ if (typeof e.field === "string") issue.field = e.field;
2682
+ if (typeof e.code === "string") issue.code = e.code;
2683
+ issues.push(issue);
2684
+ }
2685
+ }
2686
+ return issues;
2687
+ }
2688
+ function extractErrorsArray(body) {
2689
+ if (!body || typeof body !== "object") return void 0;
2690
+ const b = body;
2691
+ if (Array.isArray(b.errors)) return b.errors;
2692
+ const nested = b.body;
2693
+ if (nested && typeof nested === "object") {
2694
+ const n2 = nested;
2695
+ if (Array.isArray(n2.errors)) return n2.errors;
2696
+ }
2697
+ return void 0;
2698
+ }
2247
2699
  function parseRetryAfter(header) {
2248
2700
  if (!header) return void 0;
2249
2701
  const seconds = Number(header);
@@ -2339,11 +2791,11 @@ var TrendyolTransport = class {
2339
2791
  },
2340
2792
  {
2341
2793
  signal: opts.signal,
2342
- onRetry: (err, attempt, delay) => {
2794
+ onRetry: (err, attempt, delay2) => {
2343
2795
  if (err instanceof core.LoncaError) {
2344
2796
  this.logger.warn("trendyol.retry", {
2345
2797
  attempt,
2346
- delayMs: delay,
2798
+ delayMs: delay2,
2347
2799
  code: err.code,
2348
2800
  status: err.status
2349
2801
  });
@@ -2401,12 +2853,16 @@ function createTrendyolClient(opts) {
2401
2853
  logger: opts.logger,
2402
2854
  timeoutMs: opts.timeoutMs
2403
2855
  });
2856
+ return buildClient(transport);
2857
+ }
2858
+ function buildClient(transport) {
2859
+ const products = new ProductsResource(transport);
2404
2860
  return {
2405
2861
  brands: new BrandsResource(transport),
2406
2862
  categories: new CategoriesResource(transport),
2407
2863
  suppliers: new SuppliersResource(transport),
2408
- products: new ProductsResource(transport),
2409
- inventory: new InventoryResource(transport),
2864
+ products,
2865
+ inventory: new InventoryResource(transport, (id) => products.getBatchStatus(id)),
2410
2866
  orders: new OrdersResource(transport),
2411
2867
  claims: new ClaimsResource(transport),
2412
2868
  webhooks: new WebhooksResource(transport),
@@ -2415,7 +2871,10 @@ function createTrendyolClient(opts) {
2415
2871
  finance: new FinanceResource(transport),
2416
2872
  labels: new LabelsResource(transport),
2417
2873
  testOrders: new TestOrdersResource(transport),
2418
- locations: new LocationsResource(transport)
2874
+ locations: new LocationsResource(transport),
2875
+ exportCenter: new ExportCenterResource(transport),
2876
+ videos: new VideosResource(transport),
2877
+ capabilities: trendyolCapabilities
2419
2878
  };
2420
2879
  }
2421
2880
  function parseWebhookEvent(rawBody) {
@@ -2452,10 +2911,33 @@ function parseWebhookEvent(rawBody) {
2452
2911
  raw: body
2453
2912
  };
2454
2913
  }
2914
+ var statusMap = {
2915
+ Created: "created",
2916
+ Awaiting: "created",
2917
+ // new order awaiting seller acceptance
2918
+ Verified: "created",
2919
+ // accepted/verified, before picking
2920
+ Picking: "picking",
2921
+ UnPacked: "picking",
2922
+ // back in fulfillment after being unpacked
2923
+ Invoiced: "invoiced",
2924
+ Shipped: "shipped",
2925
+ AtCollectionPoint: "shipped",
2926
+ // in transit, awaiting pickup
2927
+ UnDelivered: "shipped",
2928
+ // delivery attempt failed; still in carrier's hands
2929
+ Delivered: "delivered",
2930
+ Cancelled: "cancelled",
2931
+ UnSupplied: "cancelled",
2932
+ // seller couldn't supply → effectively cancelled
2933
+ Returned: "returned"
2934
+ };
2935
+ var normalizeStatus = core.createStatusNormalizer(statusMap);
2455
2936
 
2456
2937
  exports.BrandsResource = BrandsResource;
2457
2938
  exports.CategoriesResource = CategoriesResource;
2458
2939
  exports.ClaimsResource = ClaimsResource;
2940
+ exports.ExportCenterResource = ExportCenterResource;
2459
2941
  exports.FinanceResource = FinanceResource;
2460
2942
  exports.InventoryResource = InventoryResource;
2461
2943
  exports.InvoicesResource = InvoicesResource;
@@ -2466,9 +2948,14 @@ exports.ProductsResource = ProductsResource;
2466
2948
  exports.QuestionsResource = QuestionsResource;
2467
2949
  exports.SuppliersResource = SuppliersResource;
2468
2950
  exports.TestOrdersResource = TestOrdersResource;
2951
+ exports.VideosResource = VideosResource;
2469
2952
  exports.WebhooksResource = WebhooksResource;
2470
2953
  exports.createTrendyolClient = createTrendyolClient;
2471
2954
  exports.normalizeShipmentPackage = normalizeShipmentPackage;
2955
+ exports.normalizeStatus = normalizeStatus;
2472
2956
  exports.parseWebhookEvent = parseWebhookEvent;
2957
+ exports.pollBatchStatus = pollBatchStatus;
2958
+ exports.statusMap = statusMap;
2959
+ exports.trendyolCapabilities = trendyolCapabilities;
2473
2960
  //# sourceMappingURL=index.cjs.map
2474
2961
  //# sourceMappingURL=index.cjs.map