@lonca/trendyol 1.0.1 → 1.2.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/README.md CHANGED
@@ -41,7 +41,7 @@ Each entry is a method on the client.
41
41
  | `finance` | `getSettlements({...})`, `getOtherFinancials({...})` — both return typed `FinancialTransaction[]` |
42
42
  | `labels` | `createCommon(trackingNumber, {format: 'ZPL', ...})`, `getCommon(trackingNumber)` |
43
43
  | `testOrders` | `create({...})`, `updateStatus(id, status, { lines?, params? })`, `setClaimsWaitingInAction()` — **STAGE-only utility** |
44
- | `locations` | `getCountries()`, `getTurkeyCities()`, `getTurkeyDistricts(cityCode)`, `getTurkeyNeighborhoods(cityCode, districtCode)`, `getAzerbaijanCities()`, `getAzerbaijanDistricts(...)`, `getCitiesByCountry/getDistrictsByCity(...)` |
44
+ | `locations` | `getCountries()`, `getTurkeyCities()`, `getTurkeyDistricts(cityId)`, `getTurkeyNeighborhoods(cityId, districtId)`, `getAzerbaijanCities()`, `getAzerbaijanDistricts(...)`, `getCitiesByCountry/getDistrictsByCity(...)` |
45
45
  | `exportCenter` | `listProducts({...})`, `createProducts(items)`, `updatePrices(items)`, `updateStocks(items)`, `getBatchStatus(batchId)`, `listPackagesV2/V3({...})`, `getPackageItems({packageId, ...})`, `getCategoryAttributes(id)`, `getCareInstructions()`, `getCompositions()`, `getOrigins()` — **Trendyol Export Center / İhracat Merkezi** |
46
46
  | `videos` | `create({contentId, url, ...})`, `list({id?, sellerIntegrationStatus?, ...})` — product-page video upload + status |
47
47
  | **top-level** | `parseWebhookEvent(rawBody)`, `normalizeShipmentPackage(rawNode)` — for inbound webhook handlers |
@@ -377,8 +377,8 @@ const { videoId } = await client.videos.create({ title, videoUrl, productContent
377
377
  // locations (no sellerId — utility lookup)
378
378
  const countries = await client.locations.getCountries();
379
379
  const cities = await client.locations.getTurkeyCities();
380
- const districts = await client.locations.getTurkeyDistricts(cityCode);
381
- const neighborhoods = await client.locations.getTurkeyNeighborhoods(cityCode, districtCode);
380
+ const districts = await client.locations.getTurkeyDistricts(city.id); // pass ids, not codes
381
+ const neighborhoods = await client.locations.getTurkeyNeighborhoods(city.id, district.id); // Neighborhood: id, name, postCode
382
382
  ```
383
383
 
384
384
  ## Mutation results
@@ -45,6 +45,11 @@ declare class TrendyolTransport {
45
45
  interface Brand {
46
46
  id: string;
47
47
  name: string;
48
+ /**
49
+ * Whether Trendyol flags the brand as a luxury brand. Undocumented by Trendyol but sent on
50
+ * every brand of the prod `brands.list` response; omitted when the response lacks it.
51
+ */
52
+ luxe?: boolean;
48
53
  }
49
54
 
50
55
  /**
@@ -63,6 +68,14 @@ declare class BrandsResource {
63
68
  /**
64
69
  * List Trendyol brands, one page at a time.
65
70
  *
71
+ * **Next-page heuristic.** Trendyol's brand list carries no page count (neither the docs
72
+ * nor the prod wire have `totalPages` / `totalElements` — the response is just
73
+ * `{ brands: [...] }`). So when `totalPages` is absent, a **full page** (at least `limit`
74
+ * brands — Trendyol may send ~1000 even for a smaller `limit`) means "there may be more"
75
+ * and sets `nextCursor`; a short page is the last one. When the
76
+ * total is an exact multiple of the page size, `paginate()` makes one extra request that
77
+ * comes back empty and stops there. If Trendyol ever sends `totalPages`, it wins.
78
+ *
66
79
  * @example
67
80
  * ```ts
68
81
  * import { paginate } from '@lonca/core';
@@ -147,13 +160,13 @@ interface CategoryAttribute {
147
160
  */
148
161
  allowMultipleAttributeValues?: boolean;
149
162
  /**
150
- * Allowed values for this attribute.
163
+ * Allowed values, only if the response inlines them — normally an empty array.
151
164
  *
152
- * NOTE: Trendyol's live API often omits this field on the `getCategoryAttributes`
153
- * response — the endpoint returns attribute metadata + flags, not the full value
154
- * catalog. In that case `values` is an empty array. If `allowCustom` is `true`,
155
- * any custom text is accepted; otherwise use `client.categories.getAttributeValues(categoryId, attributeId)`
156
- * to fetch the catalog from the dedicated V2 endpoint.
165
+ * @deprecated Trendyol's `getCategoryAttributes` response carries no value list — neither the
166
+ * docs nor the prod wire (2026-10-10) have `attributeValues` — so this is normally `[]` (an
167
+ * inline list from an older response format is still mapped). Fetch the catalog with
168
+ * `client.categories.getAttributeValues(categoryId, attributeId)` (with `paginate()`); when
169
+ * `allowCustom` is `true`, any custom text is accepted as well.
157
170
  */
158
171
  values: CategoryAttributeValue[];
159
172
  }
@@ -193,8 +206,8 @@ declare class CategoriesResource {
193
206
  /**
194
207
  * Fetch the allowed values for a single category attribute (paginated).
195
208
  *
196
- * `getCategoryAttributes` returns attribute metadata + flags but typically
197
- * omits the value catalog. Use this method to fetch the catalog for an
209
+ * `getCategoryAttributes` returns attribute metadata + flags only, never the
210
+ * value catalog (docs and prod wire agree). Use this method to fetch the catalog for an
198
211
  * attribute when `allowCustom` is `false` and you need to map your data
199
212
  * onto Trendyol's accepted values.
200
213
  *
@@ -797,22 +810,47 @@ interface City {
797
810
  id?: string;
798
811
  code: string;
799
812
  name?: string;
813
+ /**
814
+ * The country the city belongs to — the country code of the lookup that returned it
815
+ * (`'TR'` for `getTurkeyCities`, `'AZ'` for `getAzerbaijanCities`, the argument of
816
+ * `getCitiesByCountry`). Trendyol's city rows carry no country field (neither the docs nor
817
+ * the prod wire), so the SDK fills it from the request; earlier versions read a wire field
818
+ * that never arrives and always left it `undefined`.
819
+ */
800
820
  countryCode?: string;
801
821
  raw: Record<string, unknown>;
802
822
  }
803
823
  interface District {
804
824
  /** Trendyol's internal district id — pass to `getTurkeyNeighborhoods(cityId, district.id)`. */
805
825
  id?: string;
826
+ /** Trendyol's district code (the prod wire's `code`; falls back to the id when a row has none). */
806
827
  code: string;
807
828
  name?: string;
829
+ /**
830
+ * @deprecated Trendyol's district rows carry no city reference — neither the docs nor the prod
831
+ * wire (2026-10-10) have one — so this is always `undefined`. Keep the city you passed to
832
+ * `getTurkeyDistricts` / `getAzerbaijanDistricts` / `getDistrictsByCity` instead.
833
+ */
808
834
  cityCode?: string;
809
835
  raw: Record<string, unknown>;
810
836
  }
811
837
  interface Neighborhood {
812
838
  /** Trendyol's internal neighborhood id. */
813
839
  id?: string;
840
+ /**
841
+ * @deprecated Trendyol's neighborhood rows have no code (prod wire 2026-10-10: `id`, `name`,
842
+ * `postCode`; the docs list `id` and `name`), so this is always the same value as `id` (`''`
843
+ * when the row has no id). Use `id`.
844
+ */
814
845
  code: string;
815
846
  name?: string;
847
+ /** The neighborhood's postal code (prod wire `postCode`; not in Trendyol's docs). */
848
+ postCode?: string;
849
+ /**
850
+ * @deprecated Trendyol's neighborhood rows carry no district reference — neither the docs nor
851
+ * the prod wire (2026-10-10) have one — so this is always `undefined`. Keep the district you
852
+ * passed to `getTurkeyNeighborhoods` instead.
853
+ */
816
854
  districtCode?: string;
817
855
  raw: Record<string, unknown>;
818
856
  }
@@ -1273,6 +1311,7 @@ declare class LocationsResource {
1273
1311
  getAzerbaijanDistricts(cityId: string | number): Promise<District[]>;
1274
1312
  getCitiesByCountry(countryCode: string): Promise<City[]>;
1275
1313
  getDistrictsByCity(countryCode: string, cityId: string | number): Promise<District[]>;
1314
+ /** `countryCode` is the lookup's country — city rows do not carry one on the wire. */
1276
1315
  private cities;
1277
1316
  private districts;
1278
1317
  private neighborhoods;
@@ -2392,25 +2431,43 @@ type SupplierAddressType = 'SHIPMENT' | 'RETURNING' | 'INVOICE' | 'WAREHOUSE';
2392
2431
  *
2393
2432
  * Used by `createProduct V2` for `shipmentAddressId` / `returningAddressId`.
2394
2433
  *
2395
- * NOTE: The exact field set is best-effort; some optional fields may differ
2396
- * once verified against real STAGE responses. Bumped fields land in a follow-up
2397
- * minor release if needed.
2434
+ * Field set checked against the docs and the prod wire (2026-10-10).
2398
2435
  */
2399
2436
  interface SupplierAddress {
2400
2437
  id: string;
2401
- /** Free-form label set by the seller. */
2438
+ /**
2439
+ * @deprecated Trendyol's address rows carry no name or label — neither the docs nor the prod
2440
+ * wire (2026-10-10) have one — so this is always `undefined`. Identify an address by `id`,
2441
+ * `addressType` and the role flags; use `fullAddress` / `address` for its text.
2442
+ */
2402
2443
  name?: string;
2403
- /** Primary role declared by Trendyol. */
2444
+ /**
2445
+ * Primary role declared by Trendyol. The docs spell it `Shipment` / `Invoice` / `Returning`;
2446
+ * the SDK upper-cases it.
2447
+ */
2404
2448
  addressType: SupplierAddressType;
2405
2449
  isShipmentAddress: boolean;
2406
2450
  isReturningAddress: boolean;
2407
2451
  isInvoiceAddress: boolean;
2408
2452
  isDefault: boolean;
2409
- /** Multi-line address string as registered in the Partner Panel. */
2453
+ /** Street address as registered in the Partner Panel. */
2410
2454
  address?: string;
2455
+ /** The complete address text (Trendyol's `fullAddress`). */
2456
+ fullAddress?: string;
2457
+ /** Country name as Trendyol sends it. */
2458
+ country?: string;
2411
2459
  city?: string;
2460
+ /** Trendyol's city code (stringified from the wire number). */
2461
+ cityCode?: string;
2412
2462
  district?: string;
2463
+ /** Trendyol's district id (stringified from the wire number). */
2464
+ districtId?: string;
2413
2465
  postCode?: string;
2466
+ /**
2467
+ * @deprecated Trendyol's address rows carry no `fullName` — neither the docs nor the prod wire
2468
+ * (2026-10-10) have one — so this is always `undefined`. Use `fullAddress` for the complete
2469
+ * address text.
2470
+ */
2414
2471
  fullName?: string;
2415
2472
  }
2416
2473
 
@@ -2749,6 +2806,11 @@ interface CreateClientOptions {
2749
2806
  logger?: Logger;
2750
2807
  /** Request timeout in ms. Default: 30_000. */
2751
2808
  timeoutMs?: number;
2809
+ /**
2810
+ * Custom `fetch` implementation (e.g. to add a proxy agent, record or mock
2811
+ * traffic). Defaults to the global `fetch`.
2812
+ */
2813
+ fetch?: typeof fetch;
2752
2814
  }
2753
2815
  interface TrendyolClient {
2754
2816
  brands: BrandsResource;
@@ -45,6 +45,11 @@ declare class TrendyolTransport {
45
45
  interface Brand {
46
46
  id: string;
47
47
  name: string;
48
+ /**
49
+ * Whether Trendyol flags the brand as a luxury brand. Undocumented by Trendyol but sent on
50
+ * every brand of the prod `brands.list` response; omitted when the response lacks it.
51
+ */
52
+ luxe?: boolean;
48
53
  }
49
54
 
50
55
  /**
@@ -63,6 +68,14 @@ declare class BrandsResource {
63
68
  /**
64
69
  * List Trendyol brands, one page at a time.
65
70
  *
71
+ * **Next-page heuristic.** Trendyol's brand list carries no page count (neither the docs
72
+ * nor the prod wire have `totalPages` / `totalElements` — the response is just
73
+ * `{ brands: [...] }`). So when `totalPages` is absent, a **full page** (at least `limit`
74
+ * brands — Trendyol may send ~1000 even for a smaller `limit`) means "there may be more"
75
+ * and sets `nextCursor`; a short page is the last one. When the
76
+ * total is an exact multiple of the page size, `paginate()` makes one extra request that
77
+ * comes back empty and stops there. If Trendyol ever sends `totalPages`, it wins.
78
+ *
66
79
  * @example
67
80
  * ```ts
68
81
  * import { paginate } from '@lonca/core';
@@ -147,13 +160,13 @@ interface CategoryAttribute {
147
160
  */
148
161
  allowMultipleAttributeValues?: boolean;
149
162
  /**
150
- * Allowed values for this attribute.
163
+ * Allowed values, only if the response inlines them — normally an empty array.
151
164
  *
152
- * NOTE: Trendyol's live API often omits this field on the `getCategoryAttributes`
153
- * response — the endpoint returns attribute metadata + flags, not the full value
154
- * catalog. In that case `values` is an empty array. If `allowCustom` is `true`,
155
- * any custom text is accepted; otherwise use `client.categories.getAttributeValues(categoryId, attributeId)`
156
- * to fetch the catalog from the dedicated V2 endpoint.
165
+ * @deprecated Trendyol's `getCategoryAttributes` response carries no value list — neither the
166
+ * docs nor the prod wire (2026-10-10) have `attributeValues` — so this is normally `[]` (an
167
+ * inline list from an older response format is still mapped). Fetch the catalog with
168
+ * `client.categories.getAttributeValues(categoryId, attributeId)` (with `paginate()`); when
169
+ * `allowCustom` is `true`, any custom text is accepted as well.
157
170
  */
158
171
  values: CategoryAttributeValue[];
159
172
  }
@@ -193,8 +206,8 @@ declare class CategoriesResource {
193
206
  /**
194
207
  * Fetch the allowed values for a single category attribute (paginated).
195
208
  *
196
- * `getCategoryAttributes` returns attribute metadata + flags but typically
197
- * omits the value catalog. Use this method to fetch the catalog for an
209
+ * `getCategoryAttributes` returns attribute metadata + flags only, never the
210
+ * value catalog (docs and prod wire agree). Use this method to fetch the catalog for an
198
211
  * attribute when `allowCustom` is `false` and you need to map your data
199
212
  * onto Trendyol's accepted values.
200
213
  *
@@ -797,22 +810,47 @@ interface City {
797
810
  id?: string;
798
811
  code: string;
799
812
  name?: string;
813
+ /**
814
+ * The country the city belongs to — the country code of the lookup that returned it
815
+ * (`'TR'` for `getTurkeyCities`, `'AZ'` for `getAzerbaijanCities`, the argument of
816
+ * `getCitiesByCountry`). Trendyol's city rows carry no country field (neither the docs nor
817
+ * the prod wire), so the SDK fills it from the request; earlier versions read a wire field
818
+ * that never arrives and always left it `undefined`.
819
+ */
800
820
  countryCode?: string;
801
821
  raw: Record<string, unknown>;
802
822
  }
803
823
  interface District {
804
824
  /** Trendyol's internal district id — pass to `getTurkeyNeighborhoods(cityId, district.id)`. */
805
825
  id?: string;
826
+ /** Trendyol's district code (the prod wire's `code`; falls back to the id when a row has none). */
806
827
  code: string;
807
828
  name?: string;
829
+ /**
830
+ * @deprecated Trendyol's district rows carry no city reference — neither the docs nor the prod
831
+ * wire (2026-10-10) have one — so this is always `undefined`. Keep the city you passed to
832
+ * `getTurkeyDistricts` / `getAzerbaijanDistricts` / `getDistrictsByCity` instead.
833
+ */
808
834
  cityCode?: string;
809
835
  raw: Record<string, unknown>;
810
836
  }
811
837
  interface Neighborhood {
812
838
  /** Trendyol's internal neighborhood id. */
813
839
  id?: string;
840
+ /**
841
+ * @deprecated Trendyol's neighborhood rows have no code (prod wire 2026-10-10: `id`, `name`,
842
+ * `postCode`; the docs list `id` and `name`), so this is always the same value as `id` (`''`
843
+ * when the row has no id). Use `id`.
844
+ */
814
845
  code: string;
815
846
  name?: string;
847
+ /** The neighborhood's postal code (prod wire `postCode`; not in Trendyol's docs). */
848
+ postCode?: string;
849
+ /**
850
+ * @deprecated Trendyol's neighborhood rows carry no district reference — neither the docs nor
851
+ * the prod wire (2026-10-10) have one — so this is always `undefined`. Keep the district you
852
+ * passed to `getTurkeyNeighborhoods` instead.
853
+ */
816
854
  districtCode?: string;
817
855
  raw: Record<string, unknown>;
818
856
  }
@@ -1273,6 +1311,7 @@ declare class LocationsResource {
1273
1311
  getAzerbaijanDistricts(cityId: string | number): Promise<District[]>;
1274
1312
  getCitiesByCountry(countryCode: string): Promise<City[]>;
1275
1313
  getDistrictsByCity(countryCode: string, cityId: string | number): Promise<District[]>;
1314
+ /** `countryCode` is the lookup's country — city rows do not carry one on the wire. */
1276
1315
  private cities;
1277
1316
  private districts;
1278
1317
  private neighborhoods;
@@ -2392,25 +2431,43 @@ type SupplierAddressType = 'SHIPMENT' | 'RETURNING' | 'INVOICE' | 'WAREHOUSE';
2392
2431
  *
2393
2432
  * Used by `createProduct V2` for `shipmentAddressId` / `returningAddressId`.
2394
2433
  *
2395
- * NOTE: The exact field set is best-effort; some optional fields may differ
2396
- * once verified against real STAGE responses. Bumped fields land in a follow-up
2397
- * minor release if needed.
2434
+ * Field set checked against the docs and the prod wire (2026-10-10).
2398
2435
  */
2399
2436
  interface SupplierAddress {
2400
2437
  id: string;
2401
- /** Free-form label set by the seller. */
2438
+ /**
2439
+ * @deprecated Trendyol's address rows carry no name or label — neither the docs nor the prod
2440
+ * wire (2026-10-10) have one — so this is always `undefined`. Identify an address by `id`,
2441
+ * `addressType` and the role flags; use `fullAddress` / `address` for its text.
2442
+ */
2402
2443
  name?: string;
2403
- /** Primary role declared by Trendyol. */
2444
+ /**
2445
+ * Primary role declared by Trendyol. The docs spell it `Shipment` / `Invoice` / `Returning`;
2446
+ * the SDK upper-cases it.
2447
+ */
2404
2448
  addressType: SupplierAddressType;
2405
2449
  isShipmentAddress: boolean;
2406
2450
  isReturningAddress: boolean;
2407
2451
  isInvoiceAddress: boolean;
2408
2452
  isDefault: boolean;
2409
- /** Multi-line address string as registered in the Partner Panel. */
2453
+ /** Street address as registered in the Partner Panel. */
2410
2454
  address?: string;
2455
+ /** The complete address text (Trendyol's `fullAddress`). */
2456
+ fullAddress?: string;
2457
+ /** Country name as Trendyol sends it. */
2458
+ country?: string;
2411
2459
  city?: string;
2460
+ /** Trendyol's city code (stringified from the wire number). */
2461
+ cityCode?: string;
2412
2462
  district?: string;
2463
+ /** Trendyol's district id (stringified from the wire number). */
2464
+ districtId?: string;
2413
2465
  postCode?: string;
2466
+ /**
2467
+ * @deprecated Trendyol's address rows carry no `fullName` — neither the docs nor the prod wire
2468
+ * (2026-10-10) have one — so this is always `undefined`. Use `fullAddress` for the complete
2469
+ * address text.
2470
+ */
2414
2471
  fullName?: string;
2415
2472
  }
2416
2473
 
@@ -2749,6 +2806,11 @@ interface CreateClientOptions {
2749
2806
  logger?: Logger;
2750
2807
  /** Request timeout in ms. Default: 30_000. */
2751
2808
  timeoutMs?: number;
2809
+ /**
2810
+ * Custom `fetch` implementation (e.g. to add a proxy agent, record or mock
2811
+ * traffic). Defaults to the global `fetch`.
2812
+ */
2813
+ fetch?: typeof fetch;
2752
2814
  }
2753
2815
  interface TrendyolClient {
2754
2816
  brands: BrandsResource;
package/dist/index.cjs CHANGED
@@ -4,6 +4,11 @@ var core = require('@lonca/core');
4
4
 
5
5
  // src/resources/brands.ts
6
6
  var DEFAULT_PAGE_SIZE = 1e3;
7
+ function toBrand(node) {
8
+ const brand = { id: String(node.id), name: node.name };
9
+ if (typeof node.luxe === "boolean") brand.luxe = node.luxe;
10
+ return brand;
11
+ }
7
12
  var BrandsResource = class {
8
13
  constructor(transport, limiter) {
9
14
  this.transport = transport;
@@ -14,6 +19,14 @@ var BrandsResource = class {
14
19
  /**
15
20
  * List Trendyol brands, one page at a time.
16
21
  *
22
+ * **Next-page heuristic.** Trendyol's brand list carries no page count (neither the docs
23
+ * nor the prod wire have `totalPages` / `totalElements` — the response is just
24
+ * `{ brands: [...] }`). So when `totalPages` is absent, a **full page** (at least `limit`
25
+ * brands — Trendyol may send ~1000 even for a smaller `limit`) means "there may be more"
26
+ * and sets `nextCursor`; a short page is the last one. When the
27
+ * total is an exact multiple of the page size, `paginate()` makes one extra request that
28
+ * comes back empty and stops there. If Trendyol ever sends `totalPages`, it wins.
29
+ *
17
30
  * @example
18
31
  * ```ts
19
32
  * import { paginate } from '@lonca/core';
@@ -31,8 +44,10 @@ var BrandsResource = class {
31
44
  query: { page, size },
32
45
  rateLimiter: this.limiter
33
46
  });
34
- const items = data.brands.map((b) => ({ id: String(b.id), name: b.name }));
35
- const nextCursor = page + 1 < data.totalPages ? String(page + 1) : void 0;
47
+ const brands = data?.brands ?? [];
48
+ const items = brands.map(toBrand);
49
+ const hasMore = typeof data?.totalPages === "number" ? page + 1 < data.totalPages : size > 0 && brands.length >= size;
50
+ const nextCursor = hasMore ? String(page + 1) : void 0;
36
51
  return nextCursor !== void 0 ? { items, nextCursor } : { items };
37
52
  }
38
53
  /**
@@ -56,7 +71,7 @@ var BrandsResource = class {
56
71
  query: { name },
57
72
  rateLimiter: this.limiter
58
73
  });
59
- return (data ?? []).map((b) => ({ id: String(b.id), name: b.name }));
74
+ return (data ?? []).map(toBrand);
60
75
  }
61
76
  };
62
77
  function normalizeCategory(node) {
@@ -69,7 +84,6 @@ function normalizeCategory(node) {
69
84
  }
70
85
  function normalizeAttribute(node) {
71
86
  const attr = node.attribute ?? { id: 0, name: "" };
72
- const rawValues = node.attributeValues ?? [];
73
87
  const out = {
74
88
  id: String(attr.id),
75
89
  name: attr.name,
@@ -77,7 +91,8 @@ function normalizeAttribute(node) {
77
91
  allowCustom: !!node.allowCustom,
78
92
  varianter: !!node.varianter,
79
93
  slicer: !!node.slicer,
80
- values: rawValues.map((v) => ({ id: String(v.id), name: v.name }))
94
+ // Deprecated: normally empty — see `attributeValues` on the node above.
95
+ values: (node.attributeValues ?? []).map((v) => ({ id: String(v.id), name: v.name }))
81
96
  };
82
97
  if (node.categoryId !== void 0) {
83
98
  out.categoryId = String(node.categoryId);
@@ -139,8 +154,8 @@ var CategoriesResource = class {
139
154
  /**
140
155
  * Fetch the allowed values for a single category attribute (paginated).
141
156
  *
142
- * `getCategoryAttributes` returns attribute metadata + flags but typically
143
- * omits the value catalog. Use this method to fetch the catalog for an
157
+ * `getCategoryAttributes` returns attribute metadata + flags only, never the
158
+ * value catalog (docs and prod wire agree). Use this method to fetch the catalog for an
144
159
  * attribute when `allowCustom` is `false` and you need to map your data
145
160
  * onto Trendyol's accepted values.
146
161
  *
@@ -1021,7 +1036,7 @@ var LocationsResource = class {
1021
1036
  }
1022
1037
  // ─── Domestic (TR / AZ) ───────────────────────────────────────────────
1023
1038
  async getTurkeyCities() {
1024
- return this.cities(`/integration/member/countries/domestic/TR/cities`);
1039
+ return this.cities(`/integration/member/countries/domestic/TR/cities`, "TR");
1025
1040
  }
1026
1041
  /**
1027
1042
  * List districts for a Turkish city. **Pass the city `id`** (`City.id`) — the
@@ -1043,7 +1058,7 @@ var LocationsResource = class {
1043
1058
  );
1044
1059
  }
1045
1060
  async getAzerbaijanCities() {
1046
- return this.cities(`/integration/member/countries/domestic/AZ/cities`);
1061
+ return this.cities(`/integration/member/countries/domestic/AZ/cities`, "AZ");
1047
1062
  }
1048
1063
  /** List districts for an Azerbaijani city. **Pass the city `id`** (`City.id`), not `code`. */
1049
1064
  async getAzerbaijanDistricts(cityId) {
@@ -1053,7 +1068,10 @@ var LocationsResource = class {
1053
1068
  }
1054
1069
  // ─── International (GULF / CEE) ───────────────────────────────────────
1055
1070
  async getCitiesByCountry(countryCode) {
1056
- return this.cities(`/integration/member/countries/${encodeURIComponent(countryCode)}/cities`);
1071
+ return this.cities(
1072
+ `/integration/member/countries/${encodeURIComponent(countryCode)}/cities`,
1073
+ countryCode
1074
+ );
1057
1075
  }
1058
1076
  async getDistrictsByCity(countryCode, cityId) {
1059
1077
  return this.districts(
@@ -1061,7 +1079,8 @@ var LocationsResource = class {
1061
1079
  );
1062
1080
  }
1063
1081
  // ─── Shared paginators ────────────────────────────────────────────────
1064
- async cities(path) {
1082
+ /** `countryCode` is the lookup's country — city rows do not carry one on the wire. */
1083
+ async cities(path, countryCode) {
1065
1084
  const data = await this.transport.request({
1066
1085
  method: "GET",
1067
1086
  path,
@@ -1071,7 +1090,7 @@ var LocationsResource = class {
1071
1090
  id: node.id !== void 0 ? String(node.id) : void 0,
1072
1091
  code: String(node.code ?? node.id ?? ""),
1073
1092
  name: node.name,
1074
- countryCode: node.countryCode
1093
+ countryCode
1075
1094
  }));
1076
1095
  }
1077
1096
  async districts(path) {
@@ -1083,8 +1102,7 @@ var LocationsResource = class {
1083
1102
  return n(data, (node) => ({
1084
1103
  id: node.id !== void 0 ? String(node.id) : void 0,
1085
1104
  code: String(node.code ?? node.id ?? ""),
1086
- name: node.name,
1087
- cityCode: node.cityCode !== void 0 ? String(node.cityCode) : void 0
1105
+ name: node.name
1088
1106
  }));
1089
1107
  }
1090
1108
  async neighborhoods(path) {
@@ -1093,12 +1111,16 @@ var LocationsResource = class {
1093
1111
  path,
1094
1112
  rateLimiter: this.limiter
1095
1113
  });
1096
- return n(data, (node) => ({
1097
- id: node.id !== void 0 ? String(node.id) : void 0,
1098
- code: String(node.code ?? node.id ?? ""),
1099
- name: node.name,
1100
- districtCode: node.districtCode !== void 0 ? String(node.districtCode) : void 0
1101
- }));
1114
+ return n(data, (node) => {
1115
+ const id = node.id !== void 0 ? String(node.id) : void 0;
1116
+ return {
1117
+ id,
1118
+ // Neighborhood rows have no code; `code` mirrors the id (as it always did in practice).
1119
+ code: id ?? "",
1120
+ name: node.name,
1121
+ postCode: typeof node.postCode === "string" ? node.postCode : void 0
1122
+ };
1123
+ });
1102
1124
  }
1103
1125
  };
1104
1126
  var MAX_PAGE_SIZE = 200;
@@ -2454,29 +2476,35 @@ var VALID_TYPES = /* @__PURE__ */ new Set([
2454
2476
  "WAREHOUSE"
2455
2477
  ]);
2456
2478
  function normalizeAddressType(raw) {
2457
- if (raw && VALID_TYPES.has(raw)) {
2458
- return raw;
2479
+ const upper = typeof raw === "string" ? raw.toUpperCase() : void 0;
2480
+ if (upper && VALID_TYPES.has(upper)) {
2481
+ return upper;
2459
2482
  }
2460
- const stripped = raw?.replace(/_ADDRESS$/, "");
2483
+ const stripped = upper?.replace(/_ADDRESS$/, "");
2461
2484
  if (stripped && VALID_TYPES.has(stripped)) {
2462
2485
  return stripped;
2463
2486
  }
2464
2487
  return "SHIPMENT";
2465
2488
  }
2489
+ function optionalString(value) {
2490
+ return typeof value === "number" || typeof value === "string" ? String(value) : void 0;
2491
+ }
2466
2492
  function normalizeAddress2(node) {
2467
2493
  return {
2468
2494
  id: String(node.id),
2469
- name: node.name,
2470
2495
  addressType: normalizeAddressType(node.addressType),
2471
2496
  isShipmentAddress: node.isShipmentAddress ?? false,
2472
2497
  isReturningAddress: node.isReturningAddress ?? false,
2473
2498
  isInvoiceAddress: node.isInvoiceAddress ?? false,
2474
2499
  isDefault: node.isDefault ?? false,
2475
2500
  address: node.address,
2501
+ fullAddress: node.fullAddress,
2502
+ country: node.country,
2476
2503
  city: node.city,
2504
+ cityCode: optionalString(node.cityCode),
2477
2505
  district: node.district,
2478
- postCode: node.postCode,
2479
- fullName: node.fullName
2506
+ districtId: optionalString(node.districtId),
2507
+ postCode: node.postCode
2480
2508
  };
2481
2509
  }
2482
2510
  var DEFAULT_CACHE_TTL_MS = 60 * 60 * 1e3;
@@ -2943,7 +2971,8 @@ function createTrendyolClient(opts) {
2943
2971
  integratorName: opts.integratorName,
2944
2972
  clientIp: opts.clientIp,
2945
2973
  logger: opts.logger,
2946
- timeoutMs: opts.timeoutMs
2974
+ timeoutMs: opts.timeoutMs,
2975
+ fetch: opts.fetch
2947
2976
  });
2948
2977
  return buildClient(transport);
2949
2978
  }