food402 1.0.3 → 1.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.
@@ -1,30 +1,65 @@
1
- // src/api.ts - TGO Yemek API Functions
2
- import { getToken } from "./auth.js";
3
- import { randomUUID } from "crypto";
1
+ // shared/api.ts - TGO Yemek API Functions (token-parameterized for multi-user support)
4
2
  const USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36";
5
3
  const API_BASE = "https://api.tgoapis.com";
6
4
  const PAYMENT_API_BASE = "https://payment.tgoapps.com";
7
- export async function getAddresses() {
8
- const token = await getToken();
5
+ // UUID generator that works in both Node.js and Cloudflare Workers
6
+ function generateUUID() {
7
+ if (typeof crypto !== "undefined" && crypto.randomUUID) {
8
+ return crypto.randomUUID();
9
+ }
10
+ // Fallback for environments without crypto.randomUUID
11
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
12
+ const r = (Math.random() * 16) | 0;
13
+ const v = c === "x" ? r : (r & 0x3) | 0x8;
14
+ return v.toString(16);
15
+ });
16
+ }
17
+ // Helper to create common headers
18
+ function createHeaders(token, contentType) {
19
+ const headers = {
20
+ "Accept": "application/json, text/plain, */*",
21
+ "Authorization": `Bearer ${token}`,
22
+ "User-Agent": USER_AGENT,
23
+ "Origin": "https://tgoyemek.com",
24
+ "x-correlationid": generateUUID(),
25
+ "pid": generateUUID(),
26
+ "sid": generateUUID(),
27
+ };
28
+ if (contentType) {
29
+ headers["Content-Type"] = contentType;
30
+ }
31
+ return headers;
32
+ }
33
+ // Helper to create payment headers
34
+ function createPaymentHeaders(token, correlationId, pid, sid) {
35
+ return {
36
+ "Accept": "application/json, text/plain, */*",
37
+ "Authorization": `Bearer ${token}`,
38
+ "Content-Type": "application/json",
39
+ "User-Agent": USER_AGENT,
40
+ "Origin": "https://tgoyemek.com",
41
+ "app-name": "TrendyolGo",
42
+ "x-applicationid": "1",
43
+ "x-channelid": "4",
44
+ "x-storefrontid": "1",
45
+ "x-features": "OPTIONAL_REBATE;MEAL_CART_ENABLED",
46
+ "x-supported-payment-options": "MULTINET;SODEXO;EDENRED;ON_DELIVERY;SETCARD",
47
+ "x-correlationid": correlationId || generateUUID(),
48
+ "pid": pid || generateUUID(),
49
+ "sid": sid || generateUUID(),
50
+ };
51
+ }
52
+ export async function getAddresses(token) {
9
53
  const response = await fetch(`${API_BASE}/web-user-apimemberaddress-santral/addresses`, {
10
54
  method: "GET",
11
- headers: {
12
- "Accept": "application/json, text/plain, */*",
13
- "Authorization": `Bearer ${token}`,
14
- "User-Agent": USER_AGENT,
15
- "Origin": "https://tgoyemek.com",
16
- "x-correlationid": randomUUID(),
17
- "pid": randomUUID(),
18
- "sid": randomUUID()
19
- }
55
+ headers: createHeaders(token),
20
56
  });
21
57
  if (!response.ok) {
22
58
  throw new Error(`Failed to fetch addresses: ${response.status} ${response.statusText}`);
23
59
  }
24
60
  return response.json();
25
61
  }
26
- export async function getRestaurants(latitude, longitude, page = 1) {
27
- const token = await getToken();
62
+ export async function getRestaurants(token, latitude, longitude, page = 1) {
28
63
  const pageSize = 50;
29
64
  const params = new URLSearchParams({
30
65
  sortType: "RESTAURANT_SCORE",
@@ -33,25 +68,16 @@ export async function getRestaurants(latitude, longitude, page = 1) {
33
68
  latitude,
34
69
  longitude,
35
70
  pageSize: pageSize.toString(),
36
- page: page.toString()
71
+ page: page.toString(),
37
72
  });
38
73
  const response = await fetch(`${API_BASE}/web-discovery-apidiscovery-santral/restaurants/filters?${params}`, {
39
74
  method: "GET",
40
- headers: {
41
- "Accept": "application/json, text/plain, */*",
42
- "Authorization": `Bearer ${token}`,
43
- "User-Agent": USER_AGENT,
44
- "Origin": "https://tgoyemek.com",
45
- "x-correlationid": randomUUID(),
46
- "pid": randomUUID(),
47
- "sid": randomUUID()
48
- }
75
+ headers: createHeaders(token),
49
76
  });
50
77
  if (!response.ok) {
51
78
  throw new Error(`Failed to fetch restaurants: ${response.status} ${response.statusText}`);
52
79
  }
53
80
  const data = await response.json();
54
- // Transform to simplified format for AI context efficiency
55
81
  const restaurants = data.restaurants.map((r) => ({
56
82
  id: r.id,
57
83
  name: r.name,
@@ -63,37 +89,27 @@ export async function getRestaurants(latitude, longitude, page = 1) {
63
89
  distance: r.location?.distance ?? 0,
64
90
  neighborhoodName: r.location?.neighborhoodName ?? "",
65
91
  isClosed: r.isClosed,
66
- campaignText: r.campaignText
92
+ campaignText: r.campaignText,
67
93
  }));
68
94
  return {
69
95
  restaurants,
70
96
  totalCount: data.restaurantCount,
71
97
  currentPage: page,
72
98
  pageSize,
73
- hasNextPage: !!data.links?.next?.href
99
+ hasNextPage: !!data.links?.next?.href,
74
100
  };
75
101
  }
76
- export async function getRestaurantMenu(restaurantId, latitude, longitude) {
77
- const token = await getToken();
102
+ export async function getRestaurantMenu(token, restaurantId, latitude, longitude) {
78
103
  const params = new URLSearchParams({ latitude, longitude });
79
104
  const response = await fetch(`${API_BASE}/web-restaurant-apirestaurant-santral/restaurants/${restaurantId}?${params}`, {
80
105
  method: "GET",
81
- headers: {
82
- "Accept": "application/json, text/plain, */*",
83
- "Authorization": `Bearer ${token}`,
84
- "User-Agent": USER_AGENT,
85
- "Origin": "https://tgoyemek.com",
86
- "x-correlationid": randomUUID(),
87
- "pid": randomUUID(),
88
- "sid": randomUUID()
89
- }
106
+ headers: createHeaders(token),
90
107
  });
91
108
  if (!response.ok) {
92
109
  throw new Error(`Failed to fetch restaurant menu: ${response.status} ${response.statusText}`);
93
110
  }
94
111
  const data = await response.json();
95
112
  const restaurant = data.restaurant;
96
- // Transform restaurant info
97
113
  const info = {
98
114
  id: restaurant.info.id,
99
115
  name: restaurant.info.name,
@@ -102,9 +118,8 @@ export async function getRestaurantMenu(restaurantId, latitude, longitude) {
102
118
  ratingText: restaurant.info.score?.ratingText ?? "",
103
119
  workingHours: restaurant.info.workingHours,
104
120
  deliveryTime: restaurant.info.deliveryInfo?.eta ?? "",
105
- minOrderPrice: restaurant.info.deliveryInfo?.minPrice ?? 0
121
+ minOrderPrice: restaurant.info.deliveryInfo?.minPrice ?? 0,
106
122
  };
107
- // Transform categories and products
108
123
  let totalItems = 0;
109
124
  const categories = restaurant.sections.map((section) => {
110
125
  const items = section.products.map((product) => ({
@@ -112,46 +127,35 @@ export async function getRestaurantMenu(restaurantId, latitude, longitude) {
112
127
  name: product.name,
113
128
  description: product.description ?? "",
114
129
  price: product.price?.salePrice ?? 0,
115
- likePercentage: product.productScore?.likePercentageInfo
130
+ likePercentage: product.productScore?.likePercentageInfo,
116
131
  }));
117
132
  totalItems += items.length;
118
133
  return {
119
134
  name: section.name,
120
135
  slug: section.slug,
121
- items
136
+ items,
122
137
  };
123
138
  });
124
139
  return {
125
140
  info,
126
141
  categories,
127
- totalItems
142
+ totalItems,
128
143
  };
129
144
  }
130
- export async function getProductRecommendations(restaurantId, productIds) {
131
- const token = await getToken();
145
+ export async function getProductRecommendations(token, restaurantId, productIds) {
132
146
  const response = await fetch(`${API_BASE}/web-discovery-apidiscovery-santral/recommendation/product`, {
133
147
  method: "POST",
134
- headers: {
135
- "Accept": "application/json, text/plain, */*",
136
- "Authorization": `Bearer ${token}`,
137
- "Content-Type": "application/json",
138
- "User-Agent": USER_AGENT,
139
- "Origin": "https://tgoyemek.com",
140
- "x-correlationid": randomUUID(),
141
- "pid": randomUUID(),
142
- "sid": randomUUID()
143
- },
148
+ headers: createHeaders(token, "application/json"),
144
149
  body: JSON.stringify({
145
150
  restaurantId: restaurantId.toString(),
146
- productIds: productIds.map(id => id.toString()),
147
- page: "PDP"
148
- })
151
+ productIds: productIds.map((id) => id.toString()),
152
+ page: "PDP",
153
+ }),
149
154
  });
150
155
  if (!response.ok) {
151
156
  throw new Error(`Failed to fetch product recommendations: ${response.status} ${response.statusText}`);
152
157
  }
153
158
  const data = await response.json();
154
- // Transform to simplified format
155
159
  let totalItems = 0;
156
160
  const collections = (data.collections || []).map((collection) => {
157
161
  const items = (collection.items || []).map((item) => ({
@@ -159,56 +163,45 @@ export async function getProductRecommendations(restaurantId, productIds) {
159
163
  name: item.name,
160
164
  description: item.description,
161
165
  price: item.sellingPrice ?? 0,
162
- imageUrl: item.imageUrl ?? ""
166
+ imageUrl: item.imageUrl ?? "",
163
167
  }));
164
168
  totalItems += items.length;
165
169
  return {
166
170
  name: collection.name,
167
- items
171
+ items,
168
172
  };
169
173
  });
170
174
  return {
171
175
  collections,
172
- totalItems
176
+ totalItems,
173
177
  };
174
178
  }
175
- export async function getProductDetails(restaurantId, productId, latitude, longitude) {
176
- const token = await getToken();
179
+ export async function getProductDetails(token, restaurantId, productId, latitude, longitude) {
177
180
  const params = new URLSearchParams({ latitude, longitude });
178
181
  const response = await fetch(`${API_BASE}/web-restaurant-apirestaurant-santral/restaurants/${restaurantId}/products/${productId}?${params}`, {
179
182
  method: "POST",
180
- headers: {
181
- "Accept": "application/json, text/plain, */*",
182
- "Authorization": `Bearer ${token}`,
183
- "Content-Type": "application/json",
184
- "User-Agent": USER_AGENT,
185
- "Origin": "https://tgoyemek.com",
186
- "x-correlationid": randomUUID(),
187
- "pid": randomUUID(),
188
- "sid": randomUUID()
189
- },
190
- body: JSON.stringify({})
183
+ headers: createHeaders(token, "application/json"),
184
+ body: JSON.stringify({}),
191
185
  });
192
186
  if (!response.ok) {
193
187
  throw new Error(`Failed to fetch product details: ${response.status} ${response.statusText}`);
194
188
  }
195
189
  const data = await response.json();
196
- // Transform components to simplified format
197
190
  const components = (data.components || []).map((comp) => ({
198
191
  type: comp.type,
199
192
  title: comp.title,
200
193
  description: comp.description,
201
- modifierGroupId: comp.modifierGroupId, // Include for MODIFIER_GROUP types
194
+ modifierGroupId: comp.modifierGroupId,
202
195
  options: (comp.options || []).map((opt) => ({
203
196
  id: opt.optionId,
204
197
  name: opt.title,
205
198
  price: opt.price?.salePrice ?? 0,
206
199
  selected: opt.selected ?? false,
207
- isPopular: opt.badges?.some((b) => b.type === "POPULAR_OPTION") ?? false
200
+ isPopular: opt.badges?.some((b) => b.type === "POPULAR_OPTION") ?? false,
208
201
  })),
209
202
  isSingleChoice: comp.isSingleChoice ?? false,
210
203
  minSelections: comp.min ?? 0,
211
- maxSelections: comp.max ?? 0
204
+ maxSelections: comp.max ?? 0,
212
205
  }));
213
206
  return {
214
207
  restaurantId: data.restaurantId,
@@ -219,57 +212,36 @@ export async function getProductDetails(restaurantId, productId, latitude, longi
219
212
  imageUrl: data.productImage ?? "",
220
213
  price: data.price?.salePrice ?? 0,
221
214
  maxQuantity: data.maxQuantity ?? 50,
222
- components
215
+ components,
223
216
  };
224
217
  }
225
- export async function setShippingAddress(request) {
226
- const token = await getToken();
218
+ export async function setShippingAddress(token, request) {
227
219
  const response = await fetch(`${API_BASE}/web-checkout-apicheckout-santral/shipping`, {
228
220
  method: "POST",
229
- headers: {
230
- "Accept": "application/json, text/plain, */*",
231
- "Authorization": `Bearer ${token}`,
232
- "Content-Type": "application/json",
233
- "User-Agent": USER_AGENT,
234
- "Origin": "https://tgoyemek.com",
235
- "x-correlationid": randomUUID(),
236
- "pid": randomUUID(),
237
- "sid": randomUUID()
238
- },
239
- body: JSON.stringify(request)
221
+ headers: createHeaders(token, "application/json"),
222
+ body: JSON.stringify(request),
240
223
  });
241
224
  if (!response.ok) {
242
225
  throw new Error(`Failed to set shipping address: ${response.status} ${response.statusText}`);
243
226
  }
244
227
  }
245
- export async function addToBasket(request) {
246
- const token = await getToken();
228
+ export async function addToBasket(token, request) {
247
229
  const response = await fetch(`${API_BASE}/web-checkout-apicheckout-santral/carts/items`, {
248
230
  method: "POST",
249
- headers: {
250
- "Accept": "application/json, text/plain, */*",
251
- "Authorization": `Bearer ${token}`,
252
- "Content-Type": "application/json",
253
- "User-Agent": USER_AGENT,
254
- "Origin": "https://tgoyemek.com",
255
- "x-correlationid": randomUUID(),
256
- "pid": randomUUID(),
257
- "sid": randomUUID()
258
- },
231
+ headers: createHeaders(token, "application/json"),
259
232
  body: JSON.stringify({
260
233
  storeId: request.storeId,
261
234
  items: request.items,
262
- isFlashSale: false, // Always false
263
- storePickup: false, // Always false (delivery mode)
235
+ isFlashSale: false,
236
+ storePickup: false,
264
237
  latitude: request.latitude,
265
- longitude: request.longitude
266
- })
238
+ longitude: request.longitude,
239
+ }),
267
240
  });
268
241
  if (!response.ok) {
269
242
  throw new Error(`Failed to add to basket: ${response.status} ${response.statusText}`);
270
243
  }
271
244
  const data = await response.json();
272
- // Extract store info from first grouped product
273
245
  const storeData = data.groupedProducts?.[0]?.store;
274
246
  const store = {
275
247
  id: storeData?.id ?? request.storeId,
@@ -277,22 +249,20 @@ export async function addToBasket(request) {
277
249
  imageUrl: storeData?.imageUrl ?? "",
278
250
  rating: storeData?.rating ?? 0,
279
251
  averageDeliveryInterval: storeData?.averageDeliveryInterval ?? "",
280
- minAmount: storeData?.minAmount ?? 0
252
+ minAmount: storeData?.minAmount ?? 0,
281
253
  };
282
- // Extract products from grouped products
283
254
  const products = (data.groupedProducts?.[0]?.products || []).map((p) => ({
284
255
  productId: p.productId,
285
256
  itemId: p.itemId,
286
257
  name: p.name,
287
258
  quantity: p.quantity,
288
259
  salePrice: p.salePrice,
289
- description: p.description ?? ""
260
+ description: p.description ?? "",
290
261
  }));
291
- // Transform summary
292
262
  const summary = (data.summary || []).map((s) => ({
293
263
  title: s.title,
294
264
  amount: s.amount,
295
- isPromotion: s.isPromotion ?? false
265
+ isPromotion: s.isPromotion ?? false,
296
266
  }));
297
267
  return {
298
268
  store,
@@ -302,28 +272,18 @@ export async function addToBasket(request) {
302
272
  totalProductPrice: data.totalProductPrice ?? 0,
303
273
  totalProductPriceDiscounted: data.totalProductPriceDiscounted ?? 0,
304
274
  totalPrice: data.totalPrice ?? 0,
305
- deliveryPrice: data.deliveryPrice ?? 0
275
+ deliveryPrice: data.deliveryPrice ?? 0,
306
276
  };
307
277
  }
308
- export async function getBasket() {
309
- const token = await getToken();
278
+ export async function getBasket(token) {
310
279
  const response = await fetch(`${API_BASE}/web-checkout-apicheckout-santral/carts`, {
311
280
  method: "GET",
312
- headers: {
313
- "Accept": "application/json, text/plain, */*",
314
- "Authorization": `Bearer ${token}`,
315
- "User-Agent": USER_AGENT,
316
- "Origin": "https://tgoyemek.com",
317
- "x-correlationid": randomUUID(),
318
- "pid": randomUUID(),
319
- "sid": randomUUID()
320
- }
281
+ headers: createHeaders(token),
321
282
  });
322
283
  if (!response.ok) {
323
284
  throw new Error(`Failed to get basket: ${response.status} ${response.statusText}`);
324
285
  }
325
286
  const data = await response.json();
326
- // Transform grouped products to store groups
327
287
  const storeGroups = (data.groupedProducts || []).map((group) => ({
328
288
  store: {
329
289
  id: group.store?.id ?? 0,
@@ -331,7 +291,7 @@ export async function getBasket() {
331
291
  imageUrl: group.store?.imageUrl ?? "",
332
292
  rating: group.store?.rating ?? 0,
333
293
  averageDeliveryInterval: group.store?.averageDeliveryInterval ?? "",
334
- minAmount: group.store?.minAmount ?? 0
294
+ minAmount: group.store?.minAmount ?? 0,
335
295
  },
336
296
  products: (group.products || []).map((p) => ({
337
297
  productId: p.productId,
@@ -345,19 +305,18 @@ export async function getBasket() {
345
305
  productId: m.productId,
346
306
  modifierGroupId: m.modifierGroupId,
347
307
  name: m.name,
348
- price: m.price
308
+ price: m.price,
349
309
  })),
350
310
  ingredientExcludes: (p.ingredientOption?.excludes || []).map((e) => ({
351
311
  id: e.id,
352
- name: e.name
353
- }))
354
- }))
312
+ name: e.name,
313
+ })),
314
+ })),
355
315
  }));
356
- // Transform summary
357
316
  const summary = (data.summary || []).map((s) => ({
358
317
  title: s.title,
359
318
  amount: s.amount,
360
- isPromotion: s.isPromotion ?? false
319
+ isPromotion: s.isPromotion ?? false,
361
320
  }));
362
321
  return {
363
322
  storeGroups,
@@ -367,28 +326,18 @@ export async function getBasket() {
367
326
  totalProductPriceDiscounted: data.totalProductPriceDiscounted ?? 0,
368
327
  totalPrice: data.totalPrice ?? 0,
369
328
  deliveryPrice: data.deliveryPrice ?? 0,
370
- isEmpty: (data.totalProductCount ?? 0) === 0
329
+ isEmpty: (data.totalProductCount ?? 0) === 0,
371
330
  };
372
331
  }
373
- export async function removeFromBasket(itemId) {
374
- const token = await getToken();
332
+ export async function removeFromBasket(token, itemId) {
375
333
  const response = await fetch(`${API_BASE}/web-checkout-apicheckout-santral/carts/items/${itemId}`, {
376
334
  method: "DELETE",
377
- headers: {
378
- "Accept": "application/json, text/plain, */*",
379
- "Authorization": `Bearer ${token}`,
380
- "User-Agent": USER_AGENT,
381
- "Origin": "https://tgoyemek.com",
382
- "x-correlationid": randomUUID(),
383
- "pid": randomUUID(),
384
- "sid": randomUUID()
385
- }
335
+ headers: createHeaders(token),
386
336
  });
387
337
  if (!response.ok) {
388
338
  throw new Error(`Failed to remove from basket: ${response.status} ${response.statusText}`);
389
339
  }
390
340
  const data = await response.json();
391
- // Transform using same logic as getBasket
392
341
  const storeGroups = (data.groupedProducts || []).map((group) => ({
393
342
  store: {
394
343
  id: group.store?.id ?? 0,
@@ -396,7 +345,7 @@ export async function removeFromBasket(itemId) {
396
345
  imageUrl: group.store?.imageUrl ?? "",
397
346
  rating: group.store?.rating ?? 0,
398
347
  averageDeliveryInterval: group.store?.averageDeliveryInterval ?? "",
399
- minAmount: group.store?.minAmount ?? 0
348
+ minAmount: group.store?.minAmount ?? 0,
400
349
  },
401
350
  products: (group.products || []).map((p) => ({
402
351
  productId: p.productId,
@@ -410,18 +359,18 @@ export async function removeFromBasket(itemId) {
410
359
  productId: m.productId,
411
360
  modifierGroupId: m.modifierGroupId,
412
361
  name: m.name,
413
- price: m.price
362
+ price: m.price,
414
363
  })),
415
364
  ingredientExcludes: (p.ingredientOption?.excludes || []).map((e) => ({
416
365
  id: e.id,
417
- name: e.name
418
- }))
419
- }))
366
+ name: e.name,
367
+ })),
368
+ })),
420
369
  }));
421
370
  const summary = (data.summary || []).map((s) => ({
422
371
  title: s.title,
423
372
  amount: s.amount,
424
- isPromotion: s.isPromotion ?? false
373
+ isPromotion: s.isPromotion ?? false,
425
374
  }));
426
375
  return {
427
376
  storeGroups,
@@ -431,40 +380,22 @@ export async function removeFromBasket(itemId) {
431
380
  totalProductPriceDiscounted: data.totalProductPriceDiscounted ?? 0,
432
381
  totalPrice: data.totalPrice ?? 0,
433
382
  deliveryPrice: data.deliveryPrice ?? 0,
434
- isEmpty: (data.totalProductCount ?? 0) === 0
383
+ isEmpty: (data.totalProductCount ?? 0) === 0,
435
384
  };
436
385
  }
437
- export async function clearBasket() {
438
- const token = await getToken();
386
+ export async function clearBasket(token) {
439
387
  const response = await fetch(`${API_BASE}/web-checkout-apicheckout-santral/carts`, {
440
388
  method: "DELETE",
441
- headers: {
442
- "Accept": "application/json, text/plain, */*",
443
- "Authorization": `Bearer ${token}`,
444
- "User-Agent": USER_AGENT,
445
- "Origin": "https://tgoyemek.com",
446
- "x-correlationid": randomUUID(),
447
- "pid": randomUUID(),
448
- "sid": randomUUID()
449
- }
389
+ headers: createHeaders(token),
450
390
  });
451
391
  if (!response.ok) {
452
392
  throw new Error(`Failed to clear basket: ${response.status} ${response.statusText}`);
453
393
  }
454
394
  }
455
- export async function getCities() {
456
- const token = await getToken();
395
+ export async function getCities(token) {
457
396
  const response = await fetch(`${API_BASE}/web-user-apimemberaddress-santral/cities`, {
458
397
  method: "GET",
459
- headers: {
460
- "Accept": "application/json, text/plain, */*",
461
- "Authorization": `Bearer ${token}`,
462
- "User-Agent": USER_AGENT,
463
- "Origin": "https://tgoyemek.com",
464
- "x-correlationid": randomUUID(),
465
- "pid": randomUUID(),
466
- "sid": randomUUID()
467
- }
398
+ headers: createHeaders(token),
468
399
  });
469
400
  if (!response.ok) {
470
401
  throw new Error(`Failed to fetch cities: ${response.status} ${response.statusText}`);
@@ -473,26 +404,17 @@ export async function getCities() {
473
404
  const cities = (data.cities || []).map((c) => ({
474
405
  id: c.id,
475
406
  code: c.code,
476
- name: c.name
407
+ name: c.name,
477
408
  }));
478
409
  return {
479
410
  cities,
480
- count: cities.length
411
+ count: cities.length,
481
412
  };
482
413
  }
483
- export async function getDistricts(cityId) {
484
- const token = await getToken();
414
+ export async function getDistricts(token, cityId) {
485
415
  const response = await fetch(`${API_BASE}/web-user-apimemberaddress-santral/cities/${cityId}/districts`, {
486
416
  method: "GET",
487
- headers: {
488
- "Accept": "application/json, text/plain, */*",
489
- "Authorization": `Bearer ${token}`,
490
- "User-Agent": USER_AGENT,
491
- "Origin": "https://tgoyemek.com",
492
- "x-correlationid": randomUUID(),
493
- "pid": randomUUID(),
494
- "sid": randomUUID()
495
- }
417
+ headers: createHeaders(token),
496
418
  });
497
419
  if (!response.ok) {
498
420
  throw new Error(`Failed to fetch districts: ${response.status} ${response.statusText}`);
@@ -500,27 +422,18 @@ export async function getDistricts(cityId) {
500
422
  const data = await response.json();
501
423
  const districts = (data.districts || []).map((d) => ({
502
424
  id: d.id,
503
- name: d.name
425
+ name: d.name,
504
426
  }));
505
427
  return {
506
428
  districts,
507
429
  count: districts.length,
508
- cityId
430
+ cityId,
509
431
  };
510
432
  }
511
- export async function getNeighborhoods(districtId) {
512
- const token = await getToken();
433
+ export async function getNeighborhoods(token, districtId) {
513
434
  const response = await fetch(`${API_BASE}/web-user-apimemberaddress-santral/districts/${districtId}/neighborhoods`, {
514
435
  method: "GET",
515
- headers: {
516
- "Accept": "application/json, text/plain, */*",
517
- "Authorization": `Bearer ${token}`,
518
- "User-Agent": USER_AGENT,
519
- "Origin": "https://tgoyemek.com",
520
- "x-correlationid": randomUUID(),
521
- "pid": randomUUID(),
522
- "sid": randomUUID()
523
- }
436
+ headers: createHeaders(token),
524
437
  });
525
438
  if (!response.ok) {
526
439
  throw new Error(`Failed to fetch neighborhoods: ${response.status} ${response.statusText}`);
@@ -528,16 +441,15 @@ export async function getNeighborhoods(districtId) {
528
441
  const data = await response.json();
529
442
  const neighborhoods = (data.neighborhoods || []).map((n) => ({
530
443
  id: n.id,
531
- name: n.name
444
+ name: n.name,
532
445
  }));
533
446
  return {
534
447
  neighborhoods,
535
448
  count: neighborhoods.length,
536
- districtId
449
+ districtId,
537
450
  };
538
451
  }
539
- export async function addAddress(request) {
540
- const token = await getToken();
452
+ export async function addAddress(token, request) {
541
453
  const payload = {
542
454
  name: request.name,
543
455
  surname: request.surname,
@@ -554,35 +466,24 @@ export async function addAddress(request) {
554
466
  latitude: request.latitude,
555
467
  longitude: request.longitude,
556
468
  countryCode: request.countryCode ?? "TR",
557
- elevatorAvailable: request.elevatorAvailable ?? false
469
+ elevatorAvailable: request.elevatorAvailable ?? false,
558
470
  };
559
471
  const response = await fetch(`${API_BASE}/web-user-apimemberaddress-santral/addresses`, {
560
472
  method: "POST",
561
- headers: {
562
- "Accept": "application/json, text/plain, */*",
563
- "Authorization": `Bearer ${token}`,
564
- "Content-Type": "application/json",
565
- "User-Agent": USER_AGENT,
566
- "Origin": "https://tgoyemek.com",
567
- "x-correlationid": randomUUID(),
568
- "pid": randomUUID(),
569
- "sid": randomUUID()
570
- },
571
- body: JSON.stringify(payload)
473
+ headers: createHeaders(token, "application/json"),
474
+ body: JSON.stringify(payload),
572
475
  });
573
- // Handle OTP required case (429 Too Many Requests)
574
476
  if (response.status === 429) {
575
477
  return {
576
478
  success: false,
577
479
  requiresOtp: true,
578
- message: "OTP verification required. Please add this address through the TGO Yemek website."
480
+ message: "OTP verification required. Please add this address through the TGO Yemek website.",
579
481
  };
580
482
  }
581
483
  if (!response.ok) {
582
484
  throw new Error(`Failed to add address: ${response.status} ${response.statusText}`);
583
485
  }
584
486
  const data = await response.json();
585
- // Transform the returned address
586
487
  const address = {
587
488
  id: data.id,
588
489
  name: data.name,
@@ -605,58 +506,33 @@ export async function addAddress(request) {
605
506
  floor: data.floor ?? "",
606
507
  doorNumber: data.doorNumber ?? "",
607
508
  addressType: data.addressType ?? "HOME",
608
- elevatorAvailable: data.elevatorAvailable ?? false
509
+ elevatorAvailable: data.elevatorAvailable ?? false,
609
510
  };
610
511
  return {
611
512
  success: true,
612
513
  address,
613
- message: "Address added successfully"
514
+ message: "Address added successfully",
614
515
  };
615
516
  }
616
- export async function updateCustomerNote(request) {
617
- const token = await getToken();
517
+ export async function updateCustomerNote(token, request) {
618
518
  const response = await fetch(`${API_BASE}/web-checkout-apicheckout-santral/carts/customerNote`, {
619
519
  method: "PUT",
620
- headers: {
621
- "Accept": "application/json, text/plain, */*",
622
- "Authorization": `Bearer ${token}`,
623
- "Content-Type": "application/json",
624
- "User-Agent": USER_AGENT,
625
- "Origin": "https://tgoyemek.com",
626
- "x-correlationid": randomUUID(),
627
- "pid": randomUUID(),
628
- "sid": randomUUID()
629
- },
520
+ headers: createHeaders(token, "application/json"),
630
521
  body: JSON.stringify({
631
522
  customerNote: request.customerNote,
632
523
  noServiceWare: request.noServiceWare,
633
524
  contactlessDelivery: request.contactlessDelivery,
634
- dontRingBell: request.dontRingBell
635
- })
525
+ dontRingBell: request.dontRingBell,
526
+ }),
636
527
  });
637
528
  if (!response.ok) {
638
529
  throw new Error(`Failed to update customer note: ${response.status} ${response.statusText}`);
639
530
  }
640
531
  }
641
- export async function getSavedCards() {
642
- const token = await getToken();
532
+ export async function getSavedCards(token) {
643
533
  const response = await fetch(`${PAYMENT_API_BASE}/v2/cards/`, {
644
534
  method: "GET",
645
- headers: {
646
- "Accept": "application/json, text/plain, */*",
647
- "Authorization": `Bearer ${token}`,
648
- "User-Agent": USER_AGENT,
649
- "Origin": "https://tgoyemek.com",
650
- "app-name": "TrendyolGo",
651
- "x-applicationid": "1",
652
- "x-channelid": "4",
653
- "x-storefrontid": "1",
654
- "x-features": "OPTIONAL_REBATE;MEAL_CART_ENABLED",
655
- "x-supported-payment-options": "MULTINET;SODEXO;EDENRED;ON_DELIVERY;SETCARD",
656
- "x-correlationid": randomUUID(),
657
- "pid": randomUUID(),
658
- "sid": randomUUID()
659
- }
535
+ headers: createPaymentHeaders(token),
660
536
  });
661
537
  if (!response.ok) {
662
538
  throw new Error(`Failed to fetch saved cards: ${response.status} ${response.statusText}`);
@@ -671,35 +547,25 @@ export async function getSavedCards() {
671
547
  bankName: c.bankName ?? "",
672
548
  isDebitCard: c.isDebitCard ?? false,
673
549
  cvvRequired: c.cvvRequired ?? false,
674
- cardNetwork: c.cardNetwork ?? ""
550
+ cardNetwork: c.cardNetwork ?? "",
675
551
  }));
676
552
  if (cards.length === 0) {
677
553
  return {
678
554
  cards: [],
679
555
  hasCards: false,
680
- message: "No saved cards. Please add a payment method at tgoyemek.com"
556
+ message: "No saved cards. Please add a payment method at tgoyemek.com",
681
557
  };
682
558
  }
683
559
  return {
684
560
  cards,
685
- hasCards: true
561
+ hasCards: true,
686
562
  };
687
563
  }
688
- export async function getCheckoutReady() {
689
- const token = await getToken();
564
+ export async function getCheckoutReady(token) {
690
565
  const response = await fetch(`${API_BASE}/web-checkout-apicheckout-santral/carts?cartContext=payment&limitPromoMbs=false`, {
691
566
  method: "GET",
692
- headers: {
693
- "Accept": "application/json, text/plain, */*",
694
- "Authorization": `Bearer ${token}`,
695
- "User-Agent": USER_AGENT,
696
- "Origin": "https://tgoyemek.com",
697
- "x-correlationid": randomUUID(),
698
- "pid": randomUUID(),
699
- "sid": randomUUID()
700
- }
567
+ headers: createHeaders(token),
701
568
  });
702
- // Handle 400 error (typically means empty cart)
703
569
  if (response.status === 400) {
704
570
  return {
705
571
  ready: false,
@@ -709,25 +575,23 @@ export async function getCheckoutReady() {
709
575
  imageUrl: "",
710
576
  rating: 0,
711
577
  averageDeliveryInterval: "",
712
- minAmount: 0
578
+ minAmount: 0,
713
579
  },
714
580
  products: [],
715
581
  summary: [],
716
582
  totalPrice: 0,
717
583
  deliveryPrice: 0,
718
- warnings: ["Cart is empty. Add items before checkout."]
584
+ warnings: ["Cart is empty. Add items before checkout."],
719
585
  };
720
586
  }
721
587
  if (!response.ok) {
722
588
  throw new Error(`Failed to get checkout ready: ${response.status} ${response.statusText}`);
723
589
  }
724
590
  const data = await response.json();
725
- // Extract warnings from response
726
591
  const warnings = [];
727
592
  if (data.warnings) {
728
593
  warnings.push(...data.warnings.map((w) => w.message || String(w)));
729
594
  }
730
- // Check if cart is empty
731
595
  if ((data.totalProductCount ?? 0) === 0) {
732
596
  return {
733
597
  ready: false,
@@ -737,16 +601,15 @@ export async function getCheckoutReady() {
737
601
  imageUrl: "",
738
602
  rating: 0,
739
603
  averageDeliveryInterval: "",
740
- minAmount: 0
604
+ minAmount: 0,
741
605
  },
742
606
  products: [],
743
607
  summary: [],
744
608
  totalPrice: 0,
745
609
  deliveryPrice: 0,
746
- warnings: ["Cart is empty. Add items before checkout."]
610
+ warnings: ["Cart is empty. Add items before checkout."],
747
611
  };
748
612
  }
749
- // Extract store and products from first group
750
613
  const group = data.groupedProducts?.[0];
751
614
  const store = {
752
615
  id: group?.store?.id ?? 0,
@@ -754,7 +617,7 @@ export async function getCheckoutReady() {
754
617
  imageUrl: group?.store?.imageUrl ?? "",
755
618
  rating: group?.store?.rating ?? 0,
756
619
  averageDeliveryInterval: group?.store?.averageDeliveryInterval ?? "",
757
- minAmount: group?.store?.minAmount ?? 0
620
+ minAmount: group?.store?.minAmount ?? 0,
758
621
  };
759
622
  const products = (group?.products || []).map((p) => ({
760
623
  productId: p.productId,
@@ -768,19 +631,18 @@ export async function getCheckoutReady() {
768
631
  productId: m.productId,
769
632
  modifierGroupId: m.modifierGroupId,
770
633
  name: m.name,
771
- price: m.price
634
+ price: m.price,
772
635
  })),
773
636
  ingredientExcludes: (p.ingredientOption?.excludes || []).map((e) => ({
774
637
  id: e.id,
775
- name: e.name
776
- }))
638
+ name: e.name,
639
+ })),
777
640
  }));
778
641
  const summary = (data.summary || []).map((s) => ({
779
642
  title: s.title,
780
643
  amount: s.amount,
781
- isPromotion: s.isPromotion ?? false
644
+ isPromotion: s.isPromotion ?? false,
782
645
  }));
783
- // Check minimum order amount
784
646
  const minAmount = store.minAmount || 0;
785
647
  const totalPrice = data.totalPrice ?? 0;
786
648
  if (minAmount > 0 && totalPrice < minAmount) {
@@ -793,84 +655,32 @@ export async function getCheckoutReady() {
793
655
  summary,
794
656
  totalPrice: data.totalPrice ?? 0,
795
657
  deliveryPrice: data.deliveryPrice ?? 0,
796
- warnings
658
+ warnings,
797
659
  };
798
660
  }
799
- async function selectPaymentMethod(cardId, binCode) {
800
- const token = await getToken();
801
- const response = await fetch(`${PAYMENT_API_BASE}/v3/payment/options`, {
802
- method: "POST",
803
- headers: {
804
- "Accept": "application/json, text/plain, */*",
805
- "Authorization": `Bearer ${token}`,
806
- "Content-Type": "application/json",
807
- "User-Agent": USER_AGENT,
808
- "Origin": "https://tgoyemek.com",
809
- "app-name": "TrendyolGo",
810
- "x-applicationid": "1",
811
- "x-channelid": "4",
812
- "x-storefrontid": "1",
813
- "x-features": "OPTIONAL_REBATE;MEAL_CART_ENABLED",
814
- "x-supported-payment-options": "MULTINET;SODEXO;EDENRED;ON_DELIVERY;SETCARD",
815
- "x-correlationid": randomUUID(),
816
- "pid": randomUUID(),
817
- "sid": randomUUID()
818
- },
819
- body: JSON.stringify({
820
- paymentType: "payWithCard",
821
- data: {
822
- savedCardId: cardId,
823
- binCode: binCode,
824
- installmentId: 0,
825
- reward: null,
826
- installmentPostponingSelected: false
827
- }
828
- })
829
- });
830
- if (!response.ok) {
831
- throw new Error(`Failed to select payment method: ${response.status} ${response.statusText}`);
832
- }
833
- }
834
- export async function placeOrder(cardId) {
835
- const token = await getToken();
661
+ export async function placeOrder(token, cardId) {
836
662
  // First, get the saved cards to find the bin code for this card
837
- const cardsResponse = await getSavedCards();
838
- const card = cardsResponse.cards.find(c => c.cardId === cardId);
663
+ const cardsResponse = await getSavedCards(token);
664
+ const card = cardsResponse.cards.find((c) => c.cardId === cardId);
839
665
  if (!card) {
840
666
  return {
841
667
  success: false,
842
- message: `Card with ID ${cardId} not found. Use get_saved_cards to see available cards.`
668
+ message: `Card with ID ${cardId} not found. Use get_saved_cards to see available cards.`,
843
669
  };
844
670
  }
845
671
  // Extract bin code from masked card number (first 6 digits + **)
846
672
  const binCode = card.maskedCardNumber.substring(0, 6) + "**";
847
- // IMPORTANT: Use the same session IDs across all payment-related calls
848
- // This is required for the payment system to track the transaction properly
849
- const correlationId = randomUUID();
850
- const pid = randomUUID();
851
- const sid = randomUUID();
852
- const paymentHeaders = {
853
- "Accept": "application/json, text/plain, */*",
854
- "Authorization": `Bearer ${token}`,
855
- "Content-Type": "application/json",
856
- "User-Agent": USER_AGENT,
857
- "Origin": "https://tgoyemek.com",
858
- "app-name": "TrendyolGo",
859
- "x-applicationid": "1",
860
- "x-channelid": "4",
861
- "x-storefrontid": "1",
862
- "x-features": "OPTIONAL_REBATE;MEAL_CART_ENABLED",
863
- "x-supported-payment-options": "MULTINET;SODEXO;EDENRED;ON_DELIVERY;SETCARD",
864
- "x-correlationid": correlationId,
865
- "pid": pid,
866
- "sid": sid
867
- };
673
+ // Use the same session IDs across all payment-related calls
674
+ const correlationId = generateUUID();
675
+ const pid = generateUUID();
676
+ const sid = generateUUID();
677
+ const paymentHeaders = createPaymentHeaders(token, correlationId, pid, sid);
868
678
  // Step 1: Initialize cart state in payment system
869
679
  const checkoutResponse = await fetch(`${API_BASE}/web-checkout-apicheckout-santral/carts?cartContext=payment&limitPromoMbs=false`, { method: "GET", headers: paymentHeaders });
870
680
  if (!checkoutResponse.ok) {
871
681
  return {
872
682
  success: false,
873
- message: `Failed to initialize checkout: ${checkoutResponse.status} ${checkoutResponse.statusText}`
683
+ message: `Failed to initialize checkout: ${checkoutResponse.status} ${checkoutResponse.statusText}`,
874
684
  };
875
685
  }
876
686
  // Step 2: Select payment method
@@ -884,14 +694,14 @@ export async function placeOrder(cardId) {
884
694
  binCode: binCode,
885
695
  installmentId: 0,
886
696
  reward: null,
887
- installmentPostponingSelected: false
888
- }
889
- })
697
+ installmentPostponingSelected: false,
698
+ },
699
+ }),
890
700
  });
891
701
  if (!optionsResponse.ok) {
892
702
  return {
893
703
  success: false,
894
- message: `Failed to select payment method: ${optionsResponse.status} ${optionsResponse.statusText}`
704
+ message: `Failed to select payment method: ${optionsResponse.status} ${optionsResponse.statusText}`,
895
705
  };
896
706
  }
897
707
  // Step 3: Place the order with 3D Secure
@@ -904,25 +714,28 @@ export async function placeOrder(cardId) {
904
714
  {
905
715
  name: "payWithCard",
906
716
  cardNo: "",
907
- customerSelectedThreeD: false
908
- }
717
+ customerSelectedThreeD: false,
718
+ },
909
719
  ],
910
- callbackUrl: "https://tgoyemek.com/odeme"
911
- })
720
+ callbackUrl: "https://tgoyemek.com/odeme",
721
+ }),
912
722
  });
913
723
  if (!response.ok) {
914
724
  const errorText = await response.text();
915
- // Check for 3D Secure requirement in error response
916
725
  if (response.status === 400 || response.status === 403) {
917
726
  try {
918
727
  const errorData = JSON.parse(errorText);
919
- if (errorData.redirectUrl || errorData.requires3DSecure || errorData.threeDSecureUrl || errorData.htmlContent || errorData.json?.content) {
728
+ if (errorData.redirectUrl ||
729
+ errorData.requires3DSecure ||
730
+ errorData.threeDSecureUrl ||
731
+ errorData.htmlContent ||
732
+ errorData.json?.content) {
920
733
  return {
921
734
  success: false,
922
735
  requires3DSecure: true,
923
736
  redirectUrl: errorData.redirectUrl || errorData.threeDSecureUrl,
924
737
  htmlContent: errorData.htmlContent || errorData.json?.content,
925
- message: "3D Secure verification required. Complete payment in browser."
738
+ message: "3D Secure verification required. Complete payment in browser.",
926
739
  };
927
740
  }
928
741
  }
@@ -933,9 +746,8 @@ export async function placeOrder(cardId) {
933
746
  throw new Error(`Failed to place order: ${response.status} ${response.statusText}`);
934
747
  }
935
748
  const data = await response.json();
936
- // Check if 3D Secure HTML content is returned (successful 3D Secure initiation)
749
+ // Check if 3D Secure HTML content is returned
937
750
  if (data.json?.content) {
938
- // Extract redirect URL from HTML form if present
939
751
  const formMatch = data.json.content.match(/action="([^"]+)"/);
940
752
  const redirectUrl = formMatch ? formMatch[1] : undefined;
941
753
  return {
@@ -943,60 +755,49 @@ export async function placeOrder(cardId) {
943
755
  requires3DSecure: true,
944
756
  redirectUrl,
945
757
  htmlContent: data.json.content,
946
- message: "3D Secure verification required. Complete payment in browser."
758
+ message: "3D Secure verification required. Complete payment in browser.",
947
759
  };
948
760
  }
949
- // Check other 3D Secure indicators
950
761
  if (data.requires3DSecure || data.redirectUrl || data.threeDSecureUrl || data.htmlContent) {
951
762
  return {
952
763
  success: false,
953
764
  requires3DSecure: true,
954
765
  redirectUrl: data.redirectUrl || data.threeDSecureUrl,
955
766
  htmlContent: data.htmlContent,
956
- message: "3D Secure verification required. Complete payment in browser."
767
+ message: "3D Secure verification required. Complete payment in browser.",
957
768
  };
958
769
  }
959
770
  return {
960
771
  success: true,
961
772
  orderId: data.orderId || data.orderNumber || data.id,
962
- message: "Order placed successfully!"
773
+ message: "Order placed successfully!",
963
774
  };
964
775
  }
965
- export async function getOrders(page = 1) {
966
- const token = await getToken();
776
+ export async function getOrders(token, page = 1) {
967
777
  const pageSize = 50;
968
778
  const params = new URLSearchParams({
969
779
  page: page.toString(),
970
- pageSize: pageSize.toString()
780
+ pageSize: pageSize.toString(),
971
781
  });
972
782
  const response = await fetch(`${API_BASE}/web-checkout-apicheckout-santral/orders?${params}`, {
973
783
  method: "GET",
974
- headers: {
975
- "Accept": "application/json, text/plain, */*",
976
- "Authorization": `Bearer ${token}`,
977
- "User-Agent": USER_AGENT,
978
- "Origin": "https://tgoyemek.com",
979
- "x-correlationid": randomUUID(),
980
- "pid": randomUUID(),
981
- "sid": randomUUID()
982
- }
784
+ headers: createHeaders(token),
983
785
  });
984
786
  if (!response.ok) {
985
787
  throw new Error(`Failed to fetch orders: ${response.status} ${response.statusText}`);
986
788
  }
987
789
  const data = await response.json();
988
- // Transform orders to simplified format
989
790
  const orders = (data.orders || []).map((o) => ({
990
791
  id: o.id,
991
792
  orderDate: o.orderDate ?? "",
992
793
  store: {
993
794
  id: o.store?.id ?? 0,
994
- name: o.store?.name ?? ""
795
+ name: o.store?.name ?? "",
995
796
  },
996
797
  status: {
997
798
  status: o.status?.status ?? "",
998
799
  statusText: o.status?.statusText ?? "",
999
- statusColor: o.status?.statusColor ?? ""
800
+ statusColor: o.status?.statusColor ?? "",
1000
801
  },
1001
802
  price: {
1002
803
  totalPrice: o.price?.totalPrice ?? 0,
@@ -1004,15 +805,15 @@ export async function getOrders(page = 1) {
1004
805
  refundedPrice: o.price?.refundedPrice ?? 0,
1005
806
  cancelledPrice: o.price?.cancelledPrice ?? 0,
1006
807
  totalDeliveryPrice: o.price?.totalDeliveryPrice ?? 0,
1007
- totalServicePrice: o.price?.totalServicePrice ?? 0
808
+ totalServicePrice: o.price?.totalServicePrice ?? 0,
1008
809
  },
1009
810
  productSummary: o.product?.name ?? "",
1010
811
  products: (o.productList || []).map((p) => ({
1011
812
  productId: p.productId,
1012
813
  name: p.name,
1013
- imageUrl: p.imageUrl ?? ""
814
+ imageUrl: p.imageUrl ?? "",
1014
815
  })),
1015
- isReady: o.isReady ?? false
816
+ isReady: o.isReady ?? false,
1016
817
  }));
1017
818
  return {
1018
819
  orders,
@@ -1020,52 +821,38 @@ export async function getOrders(page = 1) {
1020
821
  currentPage: data.pagination?.currentPage ?? page,
1021
822
  pageSize: data.pagination?.pageSize ?? pageSize,
1022
823
  totalCount: data.pagination?.totalCount ?? 0,
1023
- hasNext: data.pagination?.hasNext ?? false
1024
- }
824
+ hasNext: data.pagination?.hasNext ?? false,
825
+ },
1025
826
  };
1026
827
  }
1027
- export async function getOrderDetail(orderId) {
1028
- const token = await getToken();
828
+ export async function getOrderDetail(token, orderId) {
1029
829
  const params = new URLSearchParams({
1030
- orderId
830
+ orderId,
1031
831
  });
1032
832
  const response = await fetch(`${API_BASE}/web-checkout-apicheckout-santral/orders/detail?${params}`, {
1033
833
  method: "GET",
1034
- headers: {
1035
- "Accept": "application/json, text/plain, */*",
1036
- "Authorization": `Bearer ${token}`,
1037
- "User-Agent": USER_AGENT,
1038
- "Origin": "https://tgoyemek.com",
1039
- "x-correlationid": randomUUID(),
1040
- "pid": randomUUID(),
1041
- "sid": randomUUID()
1042
- }
834
+ headers: createHeaders(token),
1043
835
  });
1044
836
  if (!response.ok) {
1045
837
  throw new Error(`Failed to fetch order detail: ${response.status} ${response.statusText}`);
1046
838
  }
1047
839
  const data = await response.json();
1048
- // Extract shipment info
1049
840
  const shipment = data.shipment;
1050
841
  const shipmentSummary = shipment?.summary;
1051
842
  const shipmentItem = shipment?.items?.[0];
1052
- // Extract status steps from shipment item state
1053
843
  const statusSteps = (shipmentItem?.state?.statuses || []).map((s) => ({
1054
844
  status: s.status ?? "",
1055
- statusText: s.statusText ?? ""
845
+ statusText: s.statusText ?? "",
1056
846
  }));
1057
- // Extract products from shipment item
1058
847
  const products = (shipmentItem?.products || []).map((p) => ({
1059
848
  name: p.name ?? "",
1060
849
  imageUrl: p.imageUrl ?? "",
1061
850
  salePrice: p.salePrice ?? 0,
1062
851
  salePriceText: p.salePriceText ?? "",
1063
852
  quantity: p.quantity ?? 1,
1064
- description: p.description ?? ""
853
+ description: p.description ?? "",
1065
854
  }));
1066
- // Extract delivery address
1067
855
  const addr = data.deliveryAddress;
1068
- // Extract price from summary
1069
856
  const summaryPrice = data.summary?.price;
1070
857
  return {
1071
858
  orderId: data.summary?.orderId ?? orderId,
@@ -1074,14 +861,14 @@ export async function getOrderDetail(orderId) {
1074
861
  customerNote: data.summary?.customerNote ?? "",
1075
862
  store: {
1076
863
  id: parseInt(shipmentSummary?.store?.id, 10) || 0,
1077
- name: shipmentSummary?.store?.name ?? ""
864
+ name: shipmentSummary?.store?.name ?? "",
1078
865
  },
1079
866
  eta: shipmentSummary?.eta ?? "",
1080
867
  deliveredDate: shipmentSummary?.deliveredDate ?? "",
1081
868
  status: {
1082
869
  status: shipmentItem?.status?.status ?? "",
1083
870
  statusText: shipmentItem?.status?.statusText ?? "",
1084
- statusColor: shipmentItem?.status?.statusColor ?? ""
871
+ statusColor: shipmentItem?.status?.statusColor ?? "",
1085
872
  },
1086
873
  statusSteps,
1087
874
  products,
@@ -1091,44 +878,34 @@ export async function getOrderDetail(orderId) {
1091
878
  refundedPrice: summaryPrice?.refundedPrice ?? 0,
1092
879
  cancelledPrice: summaryPrice?.cancelledPrice ?? 0,
1093
880
  totalDeliveryPrice: summaryPrice?.totalDeliveryPrice ?? 0,
1094
- totalServicePrice: summaryPrice?.totalServicePrice ?? 0
881
+ totalServicePrice: summaryPrice?.totalServicePrice ?? 0,
1095
882
  },
1096
883
  paymentDescription: data.paymentInfo?.paymentDescription ?? "",
1097
884
  deliveryAddress: {
1098
885
  name: addr?.name ?? "",
1099
886
  address: addr?.address ?? "",
1100
887
  districtCity: addr?.districtCity ?? "",
1101
- phoneNumber: addr?.phoneNumber ?? ""
1102
- }
888
+ phoneNumber: addr?.phoneNumber ?? "",
889
+ },
1103
890
  };
1104
891
  }
1105
- export async function searchRestaurants(searchQuery, latitude, longitude, page = 1) {
1106
- const token = await getToken();
892
+ export async function searchRestaurants(token, searchQuery, latitude, longitude, page = 1) {
1107
893
  const pageSize = 50;
1108
894
  const params = new URLSearchParams({
1109
895
  searchQuery,
1110
896
  latitude,
1111
897
  longitude,
1112
898
  pageSize: pageSize.toString(),
1113
- page: page.toString()
899
+ page: page.toString(),
1114
900
  });
1115
901
  const response = await fetch(`${API_BASE}/web-restaurant-apirestaurant-santral/restaurants/in/search?${params}`, {
1116
902
  method: "GET",
1117
- headers: {
1118
- "Accept": "application/json, text/plain, */*",
1119
- "Authorization": `Bearer ${token}`,
1120
- "User-Agent": USER_AGENT,
1121
- "Origin": "https://tgoyemek.com",
1122
- "x-correlationid": randomUUID(),
1123
- "pid": randomUUID(),
1124
- "sid": randomUUID()
1125
- }
903
+ headers: createHeaders(token),
1126
904
  });
1127
905
  if (!response.ok) {
1128
906
  throw new Error(`Failed to search restaurants: ${response.status} ${response.statusText}`);
1129
907
  }
1130
908
  const data = await response.json();
1131
- // Transform to simplified format for AI context efficiency
1132
909
  const restaurants = (data.restaurants || []).map((r) => {
1133
910
  const isClosed = r.isClosed ?? false;
1134
911
  return {
@@ -1148,9 +925,11 @@ export async function searchRestaurants(searchQuery, latitude, longitude, page =
1148
925
  name: p.name,
1149
926
  description: p.description,
1150
927
  price: p.price?.salePrice ?? p.price ?? 0,
1151
- imageUrl: p.imageUrl
928
+ imageUrl: p.imageUrl,
1152
929
  })),
1153
- ...(isClosed && { warning: "This restaurant is currently closed. Do not proceed with ordering from this restaurant." })
930
+ ...(isClosed && {
931
+ warning: "This restaurant is currently closed. Do not proceed with ordering from this restaurant.",
932
+ }),
1154
933
  };
1155
934
  });
1156
935
  return {
@@ -1159,6 +938,8 @@ export async function searchRestaurants(searchQuery, latitude, longitude, page =
1159
938
  currentPage: page,
1160
939
  pageSize,
1161
940
  hasNextPage: !!data.links?.next?.href,
1162
- searchQuery: data.searchQuery ?? searchQuery
941
+ searchQuery: data.searchQuery ?? searchQuery,
1163
942
  };
1164
943
  }
944
+ // Re-export types for convenience
945
+ export * from "./types.js";