order-management 0.0.21 → 0.0.22

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.
Files changed (34) hide show
  1. package/.medusa/server/src/admin/index.js +49 -23
  2. package/.medusa/server/src/admin/index.mjs +49 -23
  3. package/.medusa/server/src/api/admin/swaps/[id]/approve/route.js +69 -31
  4. package/.medusa/server/src/api/admin/swaps/health/route.js +150 -0
  5. package/.medusa/server/src/api/admin/swaps/route.js +6 -12
  6. package/.medusa/server/src/api/admin/swaps/validators.js +9 -13
  7. package/.medusa/server/src/api/store/orders/[order_id]/swaps/route.js +47 -2
  8. package/.medusa/server/src/api/store/swaps/[id]/cancel/route.js +8 -1
  9. package/.medusa/server/src/api/store/swaps/[id]/route.js +15 -4
  10. package/.medusa/server/src/api/store/swaps/route.js +53 -10
  11. package/.medusa/server/src/helpers/swaps.js +1 -1
  12. package/.medusa/server/src/modules/swap/migrations/Migration20260123144734.js +29 -0
  13. package/.medusa/server/src/modules/swap/migrations/Migration20260123162423.js +48 -0
  14. package/.medusa/server/src/modules/swap/migrations/Migration20260126114640.js +48 -0
  15. package/.medusa/server/src/modules/swap/models/swap.js +7 -2
  16. package/.medusa/server/src/modules/swap/service.js +259 -32
  17. package/.medusa/server/src/subscribers/exchange-created.js +171 -0
  18. package/.medusa/server/src/workflows/steps/swap/create-medusa-exchange-step.js +153 -19
  19. package/.medusa/server/src/workflows/steps/swap/create-medusa-return-step.js +62 -6
  20. package/.medusa/server/src/workflows/steps/swap/create-swap-step.js +7 -12
  21. package/.medusa/server/src/workflows/steps/swap/index.js +6 -4
  22. package/.medusa/server/src/workflows/steps/swap/rollback-return-step.js +70 -0
  23. package/.medusa/server/src/workflows/steps/swap/sync-medusa-status-step.js +49 -3
  24. package/.medusa/server/src/workflows/steps/swap/update-swap-exchange-details-step.js +27 -0
  25. package/.medusa/server/src/workflows/steps/swap/validate-eligibility-step.js +9 -4
  26. package/.medusa/server/src/workflows/steps/swap/validate-order-step.js +24 -1
  27. package/.medusa/server/src/workflows/swaps/approve-swap-workflow.js +19 -3
  28. package/.medusa/server/src/workflows/swaps/create-swap-workflow.js +3 -1
  29. package/.medusa/server/src/workflows/swaps/execute-swap-workflow.js +26 -4
  30. package/package.json +1 -1
  31. package/.medusa/server/src/api/admin/swaps/[id]/process-payment/route.js +0 -152
  32. package/.medusa/server/src/api/admin/swaps/[id]/status/route.js +0 -45
  33. package/.medusa/server/src/api/admin/swaps/[id]/sync/route.js +0 -148
  34. package/.medusa/server/src/workflows/steps/swap/handle-payment-difference-step.js +0 -102
@@ -8,28 +8,178 @@ class SwapService extends (0, utils_1.MedusaService)({ Swap: swap_1.Swap }) {
8
8
  this.manager_ = container.manager;
9
9
  this.logger_ = container.logger;
10
10
  }
11
+ /**
12
+ * Helper function to parse and normalize swap items arrays
13
+ * Handles both array format and JSONB format from database
14
+ */
15
+ parseSwapItems(items) {
16
+ if (!items)
17
+ return [];
18
+ if (Array.isArray(items)) {
19
+ return items.map((item) => ({
20
+ id: String(item.id || item.item_id || ""),
21
+ quantity: Number(item.quantity || 0),
22
+ reason: item.reason ? String(item.reason) : undefined,
23
+ }));
24
+ }
25
+ // If it's a JSON string, parse it
26
+ if (typeof items === "string") {
27
+ try {
28
+ const parsed = JSON.parse(items);
29
+ return Array.isArray(parsed) ? this.parseSwapItems(parsed) : [];
30
+ }
31
+ catch {
32
+ return [];
33
+ }
34
+ }
35
+ return [];
36
+ }
37
+ /**
38
+ * Helper function to parse and normalize new items arrays
39
+ */
40
+ parseNewItems(items) {
41
+ if (!items)
42
+ return [];
43
+ if (Array.isArray(items)) {
44
+ return items.map((item) => ({
45
+ variant_id: String(item.variant_id || ""),
46
+ quantity: Number(item.quantity || 0),
47
+ }));
48
+ }
49
+ // If it's a JSON string, parse it
50
+ if (typeof items === "string") {
51
+ try {
52
+ const parsed = JSON.parse(items);
53
+ return Array.isArray(parsed) ? this.parseNewItems(parsed) : [];
54
+ }
55
+ catch {
56
+ return [];
57
+ }
58
+ }
59
+ return [];
60
+ }
61
+ /**
62
+ * Helper function to normalize and compare swap items arrays
63
+ */
64
+ normalizeSwapItems(items) {
65
+ return JSON.stringify(items
66
+ .map((item) => ({ id: item.id, quantity: item.quantity }))
67
+ .sort((a, b) => a.id.localeCompare(b.id)));
68
+ }
69
+ /**
70
+ * Helper function to normalize and compare new items arrays
71
+ */
72
+ normalizeNewItems(items) {
73
+ return JSON.stringify(items
74
+ .map((item) => ({ variant_id: item.variant_id, quantity: item.quantity }))
75
+ .sort((a, b) => a.variant_id.localeCompare(b.variant_id)));
76
+ }
77
+ /**
78
+ * Check for duplicate swaps with the same return_items and new_items
79
+ * This is called both in validateEligibility and createSwap to prevent race conditions
80
+ *
81
+ * Note: Uses pagination to handle orders with many swaps.
82
+ * If an order has more than 1000 swaps, we check in batches.
83
+ */
84
+ async checkForDuplicateSwap(orderId, returnItems, newItems) {
85
+ // Check for ALL existing swaps for the same order (not just pending ones)
86
+ // This prevents creating duplicate swap requests regardless of status
87
+ // Use pagination to handle orders with many swaps
88
+ const batchSize = 1000;
89
+ let skip = 0;
90
+ let hasMore = true;
91
+ const allSwapsArray = [];
92
+ while (hasMore) {
93
+ const batch = await this.listSwaps({
94
+ order_id: orderId,
95
+ }, {
96
+ take: batchSize,
97
+ skip,
98
+ });
99
+ const batchArray = Array.isArray(batch) ? batch : batch ? [batch] : [];
100
+ allSwapsArray.push(...batchArray);
101
+ // If we got fewer results than batchSize, we've reached the end
102
+ hasMore = batchArray.length === batchSize;
103
+ skip += batchSize;
104
+ }
105
+ const swapsArray = allSwapsArray;
106
+ // Normalize current swap items for comparison
107
+ const currentReturnItemsNormalized = this.normalizeSwapItems(returnItems);
108
+ const currentNewItemsNormalized = this.normalizeNewItems(newItems);
109
+ this.logger_?.info(`Checking for duplicate swap: order_id=${orderId}, existing_swaps=${swapsArray.length}`);
110
+ // Check each existing swap for exact duplicates
111
+ for (const existingSwap of swapsArray) {
112
+ const swapData = existingSwap;
113
+ // Parse the stored data (might be JSONB format)
114
+ const existingReturnItems = this.parseSwapItems(swapData.return_items);
115
+ const existingNewItems = this.parseNewItems(swapData.new_items);
116
+ // Skip if no items found (shouldn't happen, but defensive)
117
+ if (existingReturnItems.length === 0 || existingNewItems.length === 0) {
118
+ continue;
119
+ }
120
+ // Normalize existing swap items for comparison
121
+ const existingReturnItemsNormalized = this.normalizeSwapItems(existingReturnItems);
122
+ const existingNewItemsNormalized = this.normalizeNewItems(existingNewItems);
123
+ // Check for exact match (both return_items AND new_items must match)
124
+ if (currentReturnItemsNormalized === existingReturnItemsNormalized &&
125
+ currentNewItemsNormalized === existingNewItemsNormalized) {
126
+ const status = swapData.status || "unknown";
127
+ this.logger_?.warn(`Duplicate swap detected: order_id=${orderId}, existing_swap_id=${swapData.id}, status=${status}`);
128
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, `A swap request with the same return items and new items already exists for this order (ID: ${swapData.id}, status: ${status}). Please use the existing swap request instead.`);
129
+ }
130
+ }
131
+ }
11
132
  async createSwap(input) {
12
- const { order_id, return_items, new_items, reason, note } = input;
133
+ const { order_id, customer_id, return_items, new_items, difference_due, reason, note } = input;
134
+ if (!customer_id) {
135
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Customer ID is required");
136
+ }
13
137
  if (!return_items || return_items.length === 0) {
14
138
  throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Return items are required");
15
139
  }
16
140
  if (!new_items || new_items.length === 0) {
17
141
  throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "New items are required");
18
142
  }
143
+ // CRITICAL: Check for duplicates BEFORE creating to prevent race conditions
144
+ // This is called again here even though validateEligibility also checks,
145
+ // because there's a time window between validation and creation where
146
+ // another request could create a duplicate
147
+ //
148
+ // Note: This check reduces but doesn't eliminate race conditions.
149
+ // For complete protection, consider:
150
+ // 1. Database-level unique constraint on (order_id, return_items_hash, new_items_hash)
151
+ // 2. Application-level distributed locking (Redis, etc.)
152
+ // 3. Optimistic locking with version field
153
+ this.logger_?.info(`Creating swap: order_id=${order_id}, customer_id=${customer_id}, checking for duplicates before creation`);
154
+ try {
155
+ await this.checkForDuplicateSwap(order_id, return_items, new_items);
156
+ this.logger_?.info(`No duplicates found, proceeding with swap creation: order_id=${order_id}`);
157
+ }
158
+ catch (duplicateError) {
159
+ // Re-throw duplicate errors with more context
160
+ if (duplicateError instanceof utils_1.MedusaError && duplicateError.type === utils_1.MedusaError.Types.DUPLICATE_ERROR) {
161
+ throw duplicateError;
162
+ }
163
+ // If it's a different error, wrap it
164
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.DUPLICATE_ERROR, `Duplicate swap detected for order ${order_id}. This may be due to concurrent requests.`);
165
+ }
19
166
  const swap = await this.createSwaps({
20
167
  order_id,
168
+ customer_id,
21
169
  status: "requested",
22
170
  return_items: return_items,
23
171
  new_items: new_items,
24
- difference_due: 0, // Will be calculated later
172
+ difference_due: difference_due ?? 0, // Use provided difference_due or default to 0
25
173
  reason: reason || null,
26
174
  note: note || null,
27
175
  metadata: {
28
176
  created_at: new Date().toISOString(),
177
+ customer_id, // Store in metadata for redundancy and audit trail
29
178
  status_history: [
30
179
  {
31
180
  status: "requested",
32
181
  timestamp: new Date().toISOString(),
182
+ customer_id,
33
183
  },
34
184
  ],
35
185
  },
@@ -113,15 +263,9 @@ class SwapService extends (0, utils_1.MedusaService)({ Swap: swap_1.Swap }) {
113
263
  const currentStatus = swapData.status;
114
264
  // Validate status transition
115
265
  const validTransitions = {
116
- requested: ["approved", "rejected", "cancelled"],
117
- approved: ["return_started", "cancelled"],
118
- return_started: ["return_shipped", "cancelled"],
119
- return_shipped: ["return_received", "cancelled"],
120
- return_received: ["new_items_shipped", "cancelled"],
121
- new_items_shipped: ["completed", "cancelled"],
266
+ requested: ["approved", "rejected"],
267
+ approved: [], // Terminal state (exchange created separately)
122
268
  rejected: [], // Terminal state
123
- completed: [], // Terminal state
124
- cancelled: [], // Terminal state
125
269
  };
126
270
  const allowedTransitions = validTransitions[currentStatus] || [];
127
271
  if (!allowedTransitions.includes(status)) {
@@ -159,33 +303,115 @@ class SwapService extends (0, utils_1.MedusaService)({ Swap: swap_1.Swap }) {
159
303
  // For now, return stored value or 0 - this will be implemented in workflow step
160
304
  return swapData.difference_due || 0;
161
305
  }
162
- async validateEligibility(orderId, returnItems) {
163
- // Check for existing pending swaps for the same order
164
- const existingSwaps = await this.listSwaps({
165
- order_id: orderId,
166
- status: ["requested", "approved", "return_started"],
167
- }, {
168
- take: 100,
306
+ /**
307
+ * Rollback orphaned return - removes return_id from swap when exchange creation fails
308
+ * This is used when exchange creation fails after return creation
309
+ */
310
+ async rollbackReturn(swapId, returnId, reason) {
311
+ const swap = await this.retrieveSwap(swapId);
312
+ const swapData = swap;
313
+ // Only rollback if return_id matches
314
+ if (swapData.return_id !== returnId) {
315
+ // Return already changed or doesn't match
316
+ return swap;
317
+ }
318
+ const swapMetadata = swapData.metadata || {};
319
+ const medusaIntegration = swapMetadata.medusa_integration || {};
320
+ const rollbackHistory = swapMetadata.rollback_history || [];
321
+ // Remove return_id from swap and log rollback
322
+ const updatedSwap = await this.updateSwaps({
323
+ selector: { id: swapId },
324
+ data: {
325
+ return_id: null,
326
+ metadata: {
327
+ ...swapMetadata,
328
+ medusa_integration: {
329
+ ...medusaIntegration,
330
+ return_id: null,
331
+ return_rollback_at: new Date().toISOString(),
332
+ return_rollback_reason: reason,
333
+ },
334
+ rollback_history: [
335
+ ...rollbackHistory,
336
+ {
337
+ action: "rollback_return",
338
+ return_id: returnId,
339
+ reason,
340
+ timestamp: new Date().toISOString(),
341
+ },
342
+ ],
343
+ },
344
+ },
169
345
  });
170
- const swapsArray = Array.isArray(existingSwaps) ? existingSwaps : existingSwaps ? [existingSwaps] : [];
171
- // Check if any return items overlap with existing swaps
172
- for (const existingSwap of swapsArray) {
346
+ return Array.isArray(updatedSwap) ? updatedSwap[0] : updatedSwap;
347
+ }
348
+ async validateEligibility(orderId, returnItems, newItems, orderItems) {
349
+ // 1. Check for exact duplicate swaps (same return_items + new_items)
350
+ // This uses the same logic as createSwap to ensure consistency
351
+ await this.checkForDuplicateSwap(orderId, returnItems, newItems);
352
+ // 2. Check quantity overlap for return items in PENDING swaps only
353
+ // Calculate total requested quantity per item across all pending swaps
354
+ // Use pagination to handle orders with many swaps
355
+ const batchSize = 1000;
356
+ let skip = 0;
357
+ let hasMore = true;
358
+ const allSwapsArray = [];
359
+ while (hasMore) {
360
+ const batch = await this.listSwaps({
361
+ order_id: orderId,
362
+ }, {
363
+ take: batchSize,
364
+ skip,
365
+ });
366
+ const batchArray = Array.isArray(batch) ? batch : batch ? [batch] : [];
367
+ allSwapsArray.push(...batchArray);
368
+ // If we got fewer results than batchSize, we've reached the end
369
+ hasMore = batchArray.length === batchSize;
370
+ skip += batchSize;
371
+ }
372
+ const swapsArray = allSwapsArray;
373
+ const pendingSwaps = swapsArray.filter((swap) => {
374
+ const swapData = swap;
375
+ const status = swapData.status || "";
376
+ return ["requested", "approved", "return_started"].includes(status);
377
+ });
378
+ const requestedQuantities = {};
379
+ // Sum quantities from existing pending swaps (parse the data first)
380
+ for (const existingSwap of pendingSwaps) {
173
381
  const swapData = existingSwap;
174
- const existingReturnItems = swapData.return_items;
175
- if (existingReturnItems) {
176
- for (const returnItem of returnItems) {
177
- const hasOverlap = existingReturnItems.some((existing) => existing.id === returnItem.id && existing.quantity > 0);
178
- if (hasOverlap) {
179
- throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, `Item ${returnItem.id} is already part of a pending swap for this order`);
180
- }
382
+ const existingReturnItems = this.parseSwapItems(swapData.return_items);
383
+ for (const existingItem of existingReturnItems) {
384
+ if (existingItem.id && existingItem.quantity > 0) {
385
+ requestedQuantities[existingItem.id] =
386
+ (requestedQuantities[existingItem.id] || 0) + existingItem.quantity;
181
387
  }
182
388
  }
183
389
  }
390
+ // Add current request quantities and validate against order quantities
391
+ for (const returnItem of returnItems) {
392
+ if (!returnItem.id || returnItem.quantity <= 0) {
393
+ continue;
394
+ }
395
+ const orderItem = orderItems.find((item) => item.id === returnItem.id);
396
+ if (!orderItem) {
397
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, `Return item ${returnItem.id} not found in order`);
398
+ }
399
+ // STRICT CHECK: Prevent any item from being in multiple pending swaps
400
+ // This ensures no duplicate swap requests for the same item
401
+ if (requestedQuantities[returnItem.id] > 0) {
402
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, `Item ${returnItem.id} is already part of a pending swap for this order and cannot be included in another swap request`);
403
+ }
404
+ // Also validate quantity doesn't exceed available
405
+ if (returnItem.quantity > orderItem.quantity) {
406
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, `Item ${returnItem.id}: Requested quantity (${returnItem.quantity}) exceeds available quantity (${orderItem.quantity}) in order`);
407
+ }
408
+ }
184
409
  }
185
410
  async checkRateLimit(customerId, orderId) {
186
411
  // Check for existing swaps by this customer for this order
187
412
  const existingSwaps = await this.listSwaps({
188
413
  order_id: orderId,
414
+ customer_id: customerId,
189
415
  }, {
190
416
  take: 100,
191
417
  });
@@ -195,16 +421,17 @@ class SwapService extends (0, utils_1.MedusaService)({ Swap: swap_1.Swap }) {
195
421
  throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, `Maximum ${maxSwapsPerOrder} swaps allowed per order`);
196
422
  }
197
423
  // Check customer's total swap count (across all orders)
198
- const customerSwaps = await this.listSwaps({}, {
199
- take: 1000,
424
+ // Now we can filter directly by customer_id without joining with orders
425
+ const customerSwaps = await this.listSwaps({
426
+ customer_id: customerId,
427
+ }, {
428
+ take: 1000, // Reasonable limit for rate limiting check
200
429
  });
201
430
  const customerSwapsArray = Array.isArray(customerSwaps)
202
431
  ? customerSwaps
203
432
  : customerSwaps
204
433
  ? [customerSwaps]
205
434
  : [];
206
- // Filter by customer (would need to join with order, simplified here)
207
- // In a real implementation, you'd query orders with customer_id and then swaps
208
435
  const maxSwapsPerCustomer = 20; // Configurable limit
209
436
  const customerSwapCount = customerSwapsArray.length;
210
437
  if (customerSwapCount >= maxSwapsPerCustomer) {
@@ -221,4 +448,4 @@ class SwapService extends (0, utils_1.MedusaService)({ Swap: swap_1.Swap }) {
221
448
  }
222
449
  }
223
450
  exports.default = SwapService;
224
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9tb2R1bGVzL3N3YXAvc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLHFEQUFzRTtBQUN0RSx3Q0FBb0M7QUFrQ3BDLE1BQXFCLFdBQVksU0FBUSxJQUFBLHFCQUFhLEVBQUMsRUFBRSxJQUFJLEVBQUosV0FBSSxFQUFFLENBQUM7SUFJOUQsWUFBWSxTQUErQjtRQUN6QyxLQUFLLENBQUMsU0FBUyxDQUFDLENBQUE7UUFDaEIsSUFBSSxDQUFDLFFBQVEsR0FBRyxTQUFTLENBQUMsT0FBTyxDQUFBO1FBQ2pDLElBQUksQ0FBQyxPQUFPLEdBQUcsU0FBUyxDQUFDLE1BQU0sQ0FBQTtJQUNqQyxDQUFDO0lBRUQsS0FBSyxDQUFDLFVBQVUsQ0FBQyxLQUFzQjtRQUNyQyxNQUFNLEVBQUUsUUFBUSxFQUFFLFlBQVksRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxHQUFHLEtBQUssQ0FBQTtRQUVqRSxJQUFJLENBQUMsWUFBWSxJQUFJLFlBQVksQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDL0MsTUFBTSxJQUFJLG1CQUFXLENBQ25CLG1CQUFXLENBQUMsS0FBSyxDQUFDLFlBQVksRUFDOUIsMkJBQTJCLENBQzVCLENBQUE7UUFDSCxDQUFDO1FBRUQsSUFBSSxDQUFDLFNBQVMsSUFBSSxTQUFTLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQ3pDLE1BQU0sSUFBSSxtQkFBVyxDQUNuQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxZQUFZLEVBQzlCLHdCQUF3QixDQUN6QixDQUFBO1FBQ0gsQ0FBQztRQUVELE1BQU0sSUFBSSxHQUFHLE1BQU0sSUFBSSxDQUFDLFdBQVcsQ0FBQztZQUNsQyxRQUFRO1lBQ1IsTUFBTSxFQUFFLFdBQVc7WUFDbkIsWUFBWSxFQUFFLFlBQWtEO1lBQ2hFLFNBQVMsRUFBRSxT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
451
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9tb2R1bGVzL3N3YXAvc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLHFEQUFzRTtBQUN0RSx3Q0FBb0M7QUFvQ3BDLE1BQXFCLFdBQVksU0FBUSxJQUFBLHFCQUFhLEVBQUMsRUFBRSxJQUFJLEVBQUosV0FBSSxFQUFFLENBQUM7SUFJOUQsWUFBWSxTQUErQjtRQUN6QyxLQUFLLENBQUMsU0FBUyxDQUFDLENBQUE7UUFDaEIsSUFBSSxDQUFDLFFBQVEsR0FBRyxTQUFTLENBQUMsT0FBTyxDQUFBO1FBQ2pDLElBQUksQ0FBQyxPQUFPLEdBQUcsU0FBUyxDQUFDLE1BQU0sQ0FBQTtJQUNqQyxDQUFDO0lBRUQ7OztPQUdHO0lBQ0ssY0FBYyxDQUFDLEtBQWM7UUFDbkMsSUFBSSxDQUFDLEtBQUs7WUFBRSxPQUFPLEVBQUUsQ0FBQTtRQUNyQixJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUN6QixPQUFPLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLENBQUM7Z0JBQzFCLEVBQUUsRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLEVBQUUsSUFBSSxJQUFJLENBQUMsT0FBTyxJQUFJLEVBQUUsQ0FBQztnQkFDekMsUUFBUSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsUUFBUSxJQUFJLENBQUMsQ0FBQztnQkFDcEMsTUFBTSxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVM7YUFDdEQsQ0FBQyxDQUFDLENBQUE7UUFDTCxDQUFDO1FBQ0Qsa0NBQWtDO1FBQ2xDLElBQUksT0FBTyxLQUFLLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDOUIsSUFBSSxDQUFDO2dCQUNILE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUE7Z0JBQ2hDLE9BQU8sS0FBSyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFBO1lBQ2pFLENBQUM7WUFBQyxNQUFNLENBQUM7Z0JBQ1AsT0FBTyxFQUFFLENBQUE7WUFDWCxDQUFDO1FBQ0gsQ0FBQztRQUNELE9BQU8sRUFBRSxDQUFBO0lBQ1gsQ0FBQztJQUVEOztPQUVHO0lBQ0ssYUFBYSxDQUFDLEtBQWM7UUFDbEMsSUFBSSxDQUFDLEtBQUs7WUFBRSxPQUFPLEVBQUUsQ0FBQTtRQUNyQixJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUN6QixPQUFPLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLENBQUM7Z0JBQzFCLFVBQVUsRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLFVBQVUsSUFBSSxFQUFFLENBQUM7Z0JBQ3pDLFFBQVEsRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLFFBQVEsSUFBSSxDQUFDLENBQUM7YUFDckMsQ0FBQyxDQUFDLENBQUE7UUFDTCxDQUFDO1FBQ0Qsa0NBQWtDO1FBQ2xDLElBQUksT0FBTyxLQUFLLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDOUIsSUFBSSxDQUFDO2dCQUNILE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUE7Z0JBQ2hDLE9BQU8sS0FBSyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFBO1lBQ2hFLENBQUM7WUFBQyxNQUFNLENBQUM7Z0JBQ1AsT0FBTyxFQUFFLENBQUE7WUFDWCxDQUFDO1FBQ0gsQ0FBQztRQUNELE9BQU8sRUFBRSxDQUFBO0lBQ1gsQ0FBQztJQUVEOztPQUVHO0lBQ0ssa0JBQWtCLENBQUMsS0FBaUI7UUFDMUMsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUNuQixLQUFLO2FBQ0YsR0FBRyxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxDQUFDLEVBQUUsRUFBRSxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUUsUUFBUSxFQUFFLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDO2FBQ3pELElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUM1QyxDQUFBO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ0ssaUJBQWlCLENBQUMsS0FBb0I7UUFDNUMsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUNuQixLQUFLO2FBQ0YsR0FBRyxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxDQUFDLEVBQUUsVUFBVSxFQUFFLElBQUksQ0FBQyxVQUFVLEVBQUUsUUFBUSxFQUFFLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDO2FBQ3pFLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUM1RCxDQUFBO0lBQ0gsQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNLLEtBQUssQ0FBQyxxQkFBcUIsQ0FDakMsT0FBZSxFQUNmLFdBQXVCLEVBQ3ZCLFFBQXVCO1FBRXZCLDBFQUEwRTtRQUMxRSxzRUFBc0U7UUFDdEUsa0RBQWtEO1FBQ2xELE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQTtRQUN0QixJQUFJLElBQUksR0FBRyxDQUFDLENBQUE7UUFDWixJQUFJLE9BQU8sR0FBRyxJQUFJLENBQUE7UUFDbEIsTUFBTSxhQUFhLEdBQWMsRUFBRSxDQUFBO1FBRW5DLE9BQU8sT0FBTyxFQUFFLENBQUM7WUFDZixNQUFNLEtBQUssR0FBRyxNQUFNLElBQUksQ0FBQyxTQUFTLENBQ2hDO2dCQUNFLFFBQVEsRUFBRSxPQUFPO2FBQ2xCLEVBQ0Q7Z0JBQ0UsSUFBSSxFQUFFLFNBQVM7Z0JBQ2YsSUFBSTthQUNMLENBQ0YsQ0FBQTtZQUVELE1BQU0sVUFBVSxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUE7WUFDdEUsYUFBYSxDQUFDLElBQUksQ0FBQyxHQUFHLFVBQVUsQ0FBQyxDQUFBO1lBRWpDLGdFQUFnRTtZQUNoRSxPQUFPLEdBQUcsVUFBVSxDQUFDLE1BQU0sS0FBSyxTQUFTLENBQUE7WUFDekMsSUFBSSxJQUFJLFNBQVMsQ0FBQTtRQUNuQixDQUFDO1FBRUQsTUFBTSxVQUFVLEdBQUcsYUFBYSxDQUFBO1FBRWhDLDhDQUE4QztRQUM5QyxNQUFNLDRCQUE0QixHQUFHLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxXQUFXLENBQUMsQ0FBQTtRQUN6RSxNQUFNLHlCQUF5QixHQUFHLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxRQUFRLENBQUMsQ0FBQTtRQUVsRSxJQUFJLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyx5Q0FBeUMsT0FBTyxvQkFBb0IsVUFBVSxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUE7UUFFM0csZ0RBQWdEO1FBQ2hELEtBQUssTUFBTSxZQUFZLElBQUksVUFBVSxFQUFFLENBQUM7WUFDdEMsTUFBTSxRQUFRLEdBQUcsWUFLaEIsQ0FBQTtZQUVELGdEQUFnRDtZQUNoRCxNQUFNLG1CQUFtQixHQUFHLElBQUksQ0FBQyxjQUFjLENBQUMsUUFBUSxDQUFDLFlBQVksQ0FBQyxDQUFBO1lBQ3RFLE1BQU0sZ0JBQWdCLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLENBQUE7WUFFL0QsMkRBQTJEO1lBQzNELElBQUksbUJBQW1CLENBQUMsTUFBTSxLQUFLLENBQUMsSUFBSSxnQkFBZ0IsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7Z0JBQ3RFLFNBQVE7WUFDVixDQUFDO1lBRUQsK0NBQStDO1lBQy9DLE1BQU0sNkJBQTZCLEdBQUcsSUFBSSxDQUFDLGtCQUFrQixDQUFDLG1CQUFtQixDQUFDLENBQUE7WUFDbEYsTUFBTSwwQkFBMEIsR0FBRyxJQUFJLENBQUMsaUJBQWlCLENBQUMsZ0JBQWdCLENBQUMsQ0FBQTtZQUUzRSxxRUFBcUU7WUFDckUsSUFDRSw0QkFBNEIsS0FBSyw2QkFBNkI7Z0JBQzlELHlCQUF5QixLQUFLLDBCQUEwQixFQUN4RCxDQUFDO2dCQUNELE1BQU0sTUFBTSxHQUFHLFFBQVEsQ0FBQyxNQUFNLElBQUksU0FBUyxDQUFBO2dCQUMzQyxJQUFJLENBQUMsT0FBTyxFQUFFLElBQUksQ0FDaEIscUNBQXFDLE9BQU8sc0JBQXNCLFFBQVEsQ0FBQyxFQUFFLFlBQVksTUFBTSxFQUFFLENBQ2xHLENBQUE7Z0JBQ0QsTUFBTSxJQUFJLG1CQUFXLENBQ25CLG1CQUFXLENBQUMsS0FBSyxDQUFDLFlBQVksRUFDOUIsOEZBQThGLFFBQVEsQ0FBQyxFQUFFLGFBQWEsTUFBTSxrREFBa0QsQ0FDL0ssQ0FBQTtZQUNILENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUVELEtBQUssQ0FBQyxVQUFVLENBQUMsS0FBc0I7UUFDckMsTUFBTSxFQUFFLFFBQVEsRUFBRSxXQUFXLEVBQUUsWUFBWSxFQUFFLFNBQVMsRUFBRSxjQUFjLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxHQUFHLEtBQUssQ0FBQTtRQUU5RixJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7WUFDakIsTUFBTSxJQUFJLG1CQUFXLENBQ25CLG1CQUFXLENBQUMsS0FBSyxDQUFDLFlBQVksRUFDOUIseUJBQXlCLENBQzFCLENBQUE7UUFDSCxDQUFDO1FBRUQsSUFBSSxDQUFDLFlBQVksSUFBSSxZQUFZLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQy9DLE1BQU0sSUFBSSxtQkFBVyxDQUNuQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxZQUFZLEVBQzlCLDJCQUEyQixDQUM1QixDQUFBO1FBQ0gsQ0FBQztRQUVELElBQUksQ0FBQyxTQUFTLElBQUksU0FBUyxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUN6QyxNQUFNLElBQUksbUJBQVcsQ0FDbkIsbUJBQVcsQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUM5Qix3QkFBd0IsQ0FDekIsQ0FBQTtRQUNILENBQUM7UUFFRCw0RUFBNEU7UUFDNUUseUVBQXlFO1FBQ3pFLHNFQUFzRTtRQUN0RSwyQ0FBMkM7UUFDM0MsR0FBRztRQUNILGtFQUFrRTtRQUNsRSxxQ0FBcUM7UUFDckMsdUZBQXVGO1FBQ3ZGLHlEQUF5RDtRQUN6RCwyQ0FBMkM7UUFDM0MsSUFBSSxDQUFDLE9BQU8sRUFBRSxJQUFJLENBQUMsMkJBQTJCLFFBQVEsaUJBQWlCLFdBQVcsMkNBQTJDLENBQUMsQ0FBQTtRQUM5SCxJQUFJLENBQUM7WUFDSCxNQUFNLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxRQUFRLEVBQUUsWUFBWSxFQUFFLFNBQVMsQ0FBQyxDQUFBO1lBQ25FLElBQUksQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLGdFQUFnRSxRQUFRLEVBQUUsQ0FBQyxDQUFBO1FBQ2hHLENBQUM7UUFBQyxPQUFPLGNBQWMsRUFBRSxDQUFDO1lBQ3hCLDhDQUE4QztZQUM5QyxJQUFJLGNBQWMsWUFBWSxtQkFBVyxJQUFJLGNBQWMsQ0FBQyxJQUFJLEtBQUssbUJBQVcsQ0FBQyxLQUFLLENBQUMsZUFBZSxFQUFFLENBQUM7Z0JBQ3ZHLE1BQU0sY0FBYyxDQUFBO1lBQ3RCLENBQUM7WUFDRCxxQ0FBcUM7WUFDckMsTUFBTSxJQUFJLG1CQUFXLENBQ25CLG1CQUFXLENBQUMsS0FBSyxDQUFDLGVBQWUsRUFDakMscUNBQXFDLFFBQVEsMkNBQTJDLENBQ3pGLENBQUE7UUFDSCxDQUFDO1FBRUQsTUFBTSxJQUFJLEdBQUcsTUFBTSxJQUFJLENBQUMsV0FBVyxDQUFDO1lBQ2xDLFFBQVE7WUFDUixXQUFXO1lBQ1gsTUFBTSxFQUFFLFdBQVc7WUFDbkIsWUFBWSxFQUFFLFlBQWtEO1lBQ2hFLFNBQVMsRUFBRSxTQUErQztZQUMxRCxjQUFjLEVBQUUsY0FBYyxJQUFJLENBQUMsRUFBRSw4Q0FBOEM7WUFDbkYsTUFBTSxFQUFFLE1BQU0sSUFBSSxJQUFJO1lBQ3RCLElBQUksRUFBRSxJQUFJLElBQUksSUFBSTtZQUNsQixRQUFRLEVBQUU7Z0JBQ1IsVUFBVSxFQUFFLElBQUksSUFBSSxFQUFFLENBQUMsV0FBVyxFQUFFO2dCQUNwQyxXQUFXLEVBQUUsbURBQW1EO2dCQUNoRSxjQUFjLEVBQUU7b0JBQ2Q7d0JBQ0UsTUFBTSxFQUFFLFdBQVc7d0JBQ25CLFNBQVMsRUFBRSxJQUFJLElBQUksRUFBRSxDQUFDLFdBQVcsRUFBRTt3QkFDbkMsV0FBVztxQkFDWjtpQkFDRjthQUNGO1NBQ0YsQ0FBQyxDQUFBO1FBRUYsT0FBTyxLQUFLLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQTtJQUM3QyxDQUFDO0lBRUQsS0FBSyxDQUFDLFdBQVcsQ0FBQyxNQUFjLEVBQUUsT0FBZTtRQUMvQyxNQUFNLElBQUksR0FBRyxNQUFNLElBQUksQ0FBQyxZQUFZLENBQUMsTUFBTSxDQUFDLENBQUE7UUFDNUMsTUFBTSxRQUFRLEdBQUcsSUFBOEQsQ0FBQTtRQUUvRSxJQUFJLFFBQVEsQ0FBQyxNQUFNLEtBQUssV0FBVyxFQUFFLENBQUM7WUFDcEMsTUFBTSxJQUFJLG1CQUFXLENBQ25CLG1CQUFXLENBQUMsS0FBSyxDQUFDLFlBQVksRUFDOUIsNENBQTRDLFFBQVEsQ0FBQyxNQUFNLEVBQUUsQ0FDOUQsQ0FBQTtRQUNILENBQUM7UUFFRCxNQUFNLFFBQVEsR0FBSSxRQUFRLENBQUMsUUFBb0MsSUFBSSxFQUFFLENBQUE7UUFDckUsTUFBTSxhQUFhLEdBQUksUUFBUSxDQUFDLGNBQWlELElBQUksRUFBRSxDQUFBO1FBQ3ZGLE1BQU0saUJBQWlCLEdBQUksUUFBUSxDQUFDLGtCQUE4QyxJQUFJLEVBQUUsQ0FBQTtRQUN4RixNQUFNLGNBQWMsR0FBSSxRQUFRLENBQUMsZUFBMkMsSUFBSSxFQUFFLENBQUE7UUFFbEYsTUFBTSxJQUFJLENBQUMsV0FBVyxDQUFDO1lBQ3JCLFFBQVEsRUFBRSxFQUFFLEVBQUUsRUFBRSxNQUFNLEVBQUU7WUFDeEIsSUFBSSxFQUFFO2dCQUNKLE1BQU0sRUFBRSxVQUFVO2dCQUNsQixRQUFRLEVBQUU7b0JBQ1IsR0FBRyxRQUFRO29CQUNYLFdBQVcsRUFBRSxJQUFJLElBQUksRUFBRSxDQUFDLFdBQVcsRUFBRTtvQkFDckMsV0FBVyxFQUFFLE9BQU87b0JBQ3BCLGNBQWMsRUFBRTt3QkFDZCxHQUFHLGFBQWE7d0JBQ2hCOzRCQUNFLE1BQU0sRUFBRSxVQUFVOzRCQUNsQixTQUFTLEVBQUUsSUFBSSxJQUFJLEVBQUUsQ0FBQyxXQUFXLEVBQUU7NEJBQ25DLFFBQVEsRUFBRSxPQUFPO3lCQUNsQjtxQkFDRjtvQkFDRCxrQkFBa0IsRUFBRTt3QkFDbEIsR0FBRyxpQkFBaUI7cUJBQ3JCO29CQUNELGVBQWUsRUFBRTt3QkFDZixHQUFHLGNBQWM7d0JBQ2pCLGlCQUFpQixFQUFFLE9BQU87d0JBQzFCLGlCQUFpQixFQUFFLElBQUksSUFBSSxFQUFFLENBQUMsV0FBVyxFQUFFO3FCQUM1QztpQkFDRjthQUNGO1NBQ0YsQ0FBQyxDQUFBO1FBRUYsT0FBTyxNQUFNLElBQUksQ0FBQyxZQUFZLENBQUMsTUFBTSxDQUFDLENBQUE7SUFDeEMsQ0FBQztJQUVELEtBQUssQ0FBQyxVQUFVLENBQUMsTUFBYyxFQUFFLE9BQWUsRUFBRSxNQUFlO1FBQy9ELE1BQU0sSUFBSSxHQUFHLE1BQU0sSUFBSSxDQUFDLFlBQVksQ0FBQyxNQUFNLENBQUMsQ0FBQTtRQUM1QyxNQUFNLFFBQVEsR0FBRyxJQUE4RCxDQUFBO1FBRS9FLElBQUksUUFBUSxDQUFDLE1BQU0sS0FBSyxXQUFXLEVBQUUsQ0FBQztZQUNwQyxNQUFNLElBQUksbUJBQVcsQ0FDbkIsbUJBQVcsQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUM5Qiw0Q0FBNEMsUUFBUSxDQUFDLE1BQU0sRUFBRSxDQUM5RCxDQUFBO1FBQ0gsQ0FBQztRQUVELE1BQU0sUUFBUSxHQUFJLFFBQVEsQ0FBQyxRQUFvQyxJQUFJLEVBQUUsQ0FBQTtRQUNyRSxNQUFNLGFBQWEsR0FBSSxRQUFRLENBQUMsY0FBaUQsSUFBSSxFQUFFLENBQUE7UUFFdkYsTUFBTSxJQUFJLENBQUMsV0FBVyxDQUFDO1lBQ3JCLFFBQVEsRUFBRSxFQUFFLEVBQUUsRUFBRSxNQUFNLEVBQUU7WUFDeEIsSUFBSSxFQUFFO2dCQUNKLE1BQU0sRUFBRSxVQUFVO2dCQUNsQixRQUFRLEVBQUU7b0JBQ1IsR0FBRyxRQUFRO29CQUNYLFdBQVcsRUFBRSxJQUFJLElBQUksRUFBRSxDQUFDLFdBQVcsRUFBRTtvQkFDckMsV0FBVyxFQUFFLE9BQU87b0JBQ3BCLGdCQUFnQixFQUFFLE1BQU0sSUFBSSxJQUFJO29CQUNoQyxjQUFjLEVBQUU7d0JBQ2QsR0FBRyxhQUFhO3dCQUNoQjs0QkFDRSxNQUFNLEVBQUUsVUFBVTs0QkFDbEIsU0FBUyxFQUFFLElBQUksSUFBSSxFQUFFLENBQUMsV0FBVyxFQUFFOzRCQUNuQyxRQUFRLEVBQUUsT0FBTzs0QkFDakIsTUFBTSxFQUFFLE1BQU0sSUFBSSxJQUFJO3lCQUN2QjtxQkFDRjtpQkFDRjthQUNGO1NBQ0YsQ0FBQyxDQUFBO1FBRUYsT0FBTyxNQUFNLElBQUksQ0FBQyxZQUFZLENBQUMsTUFBTSxDQUFDLENBQUE7SUFDeEMsQ0FBQztJQUVELEtBQUssQ0FBQyxnQkFBZ0IsQ0FBQyxLQUE0QjtRQUNqRCxNQUFNLEVBQUUsT0FBTyxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUUsa0JBQWtCLEVBQUUsR0FBRyxLQUFLLENBQUE7UUFFL0QsTUFBTSxJQUFJLEdBQUcsTUFBTSxJQUFJLENBQUMsWUFBWSxDQUFDLE9BQU8sQ0FBQyxDQUFBO1FBQzdDLE1BQU0sUUFBUSxHQUFHLElBQThELENBQUE7UUFDL0UsTUFBTSxhQUFhLEdBQUcsUUFBUSxDQUFDLE1BQU0sQ0FBQTtRQUVyQyw2QkFBNkI7UUFDN0IsTUFBTSxnQkFBZ0IsR0FBNkI7WUFDakQsU0FBUyxFQUFFLENBQUMsVUFBVSxFQUFFLFVBQVUsQ0FBQztZQUNuQyxRQUFRLEVBQUUsRUFBRSxFQUFFLCtDQUErQztZQUM3RCxRQUFRLEVBQUUsRUFBRSxFQUFFLGlCQUFpQjtTQUNoQyxDQUFBO1FBRUQsTUFBTSxrQkFBa0IsR0FBRyxnQkFBZ0IsQ0FBQyxhQUFhLENBQUMsSUFBSSxFQUFFLENBQUE7UUFDaEUsSUFBSSxDQUFDLGtCQUFrQixDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO1lBQ3pDLE1BQU0sSUFBSSxtQkFBVyxDQUNuQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxZQUFZLEVBQzlCLGtDQUFrQyxhQUFhLE9BQU8sTUFBTSwwQkFBMEIsa0JBQWtCLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQ3RILENBQUE7UUFDSCxDQUFDO1FBRUQsTUFBTSxRQUFRLEdBQUksUUFBUSxDQUFDLFFBQW9DLElBQUksRUFBRSxDQUFBO1FBQ3JFLE1BQU0sYUFBYSxHQUFJLFFBQVEsQ0FBQyxjQUFpRCxJQUFJLEVBQUUsQ0FBQTtRQUV2RixNQUFNLElBQUksQ0FBQyxXQUFXLENBQUM7WUFDckIsUUFBUSxFQUFFLEVBQUUsRUFBRSxFQUFFLE9BQU8sRUFBRTtZQUN6QixJQUFJLEVBQUU7Z0JBQ0osTUFBTTtnQkFDTixRQUFRLEVBQUU7b0JBQ1IsR0FBRyxRQUFRO29CQUNYLEdBQUcsa0JBQWtCO29CQUNyQixjQUFjLEVBQUU7d0JBQ2QsR0FBRyxhQUFhO3dCQUNoQjs0QkFDRSxNQUFNOzRCQUNOLFNBQVMsRUFBRSxJQUFJLElBQUksRUFBRSxDQUFDLFdBQVcsRUFBRTt5QkFDcEM7cUJBQ0Y7aUJBQ0Y7YUFDRjtTQUNGLENBQUMsQ0FBQTtRQUVGLE9BQU8sTUFBTSxJQUFJLENBQUMsWUFBWSxDQUFDLE9BQU8sQ0FBQyxDQUFBO0lBQ3pDLENBQUM7SUFFRCxLQUFLLENBQUMsc0JBQXNCLENBQUMsTUFBYztRQUN6QyxNQUFNLElBQUksR0FBRyxNQUFNLElBQUksQ0FBQyxZQUFZLENBQUMsTUFBTSxDQUFDLENBQUE7UUFDNUMsTUFBTSxRQUFRLEdBQUcsSUFBbUMsQ0FBQTtRQUVwRCw0REFBNEQ7UUFDNUQsd0NBQXdDO1FBQ3hDLGtDQUFrQztRQUNsQywrQkFBK0I7UUFDL0IsOERBQThEO1FBRTlELGdGQUFnRjtRQUNoRixPQUFPLFFBQVEsQ0FBQyxjQUFjLElBQUksQ0FBQyxDQUFBO0lBQ3JDLENBQUM7SUFFRDs7O09BR0c7SUFDSCxLQUFLLENBQUMsY0FBYyxDQUFDLE1BQWMsRUFBRSxRQUFnQixFQUFFLE1BQWM7UUFDbkUsTUFBTSxJQUFJLEdBQUcsTUFBTSxJQUFJLENBQUMsWUFBWSxDQUFDLE1BQU0sQ0FBQyxDQUFBO1FBQzVDLE1BQU0sUUFBUSxHQUFHLElBR2hCLENBQUE7UUFFRCxxQ0FBcUM7UUFDckMsSUFBSSxRQUFRLENBQUMsU0FBUyxLQUFLLFFBQVEsRUFBRSxDQUFDO1lBQ3BDLDBDQUEwQztZQUMxQyxPQUFPLElBQUksQ0FBQTtRQUNiLENBQUM7UUFFRCxNQUFNLFlBQVksR0FBRyxRQUFRLENBQUMsUUFBUSxJQUFJLEVBQUUsQ0FBQTtRQUM1QyxNQUFNLGlCQUFpQixHQUFJLFlBQVksQ0FBQyxrQkFBOEMsSUFBSSxFQUFFLENBQUE7UUFDNUYsTUFBTSxlQUFlLEdBQUksWUFBWSxDQUFDLGdCQUFtRCxJQUFJLEVBQUUsQ0FBQTtRQUUvRiw4Q0FBOEM7UUFDOUMsTUFBTSxXQUFXLEdBQUcsTUFBTSxJQUFJLENBQUMsV0FBVyxDQUFDO1lBQ3pDLFFBQVEsRUFBRSxFQUFFLEVBQUUsRUFBRSxNQUFNLEVBQUU7WUFDeEIsSUFBSSxFQUFFO2dCQUNKLFNBQVMsRUFBRSxJQUFJO2dCQUNmLFFBQVEsRUFBRTtvQkFDUixHQUFHLFlBQVk7b0JBQ2Ysa0JBQWtCLEVBQUU7d0JBQ2xCLEdBQUcsaUJBQWlCO3dCQUNwQixTQUFTLEVBQUUsSUFBSTt3QkFDZixrQkFBa0IsRUFBRSxJQUFJLElBQUksRUFBRSxDQUFDLFdBQVcsRUFBRTt3QkFDNUMsc0JBQXNCLEVBQUUsTUFBTTtxQkFDL0I7b0JBQ0QsZ0JBQWdCLEVBQUU7d0JBQ2hCLEdBQUcsZUFBZTt3QkFDbEI7NEJBQ0UsTUFBTSxFQUFFLGlCQUFpQjs0QkFDekIsU0FBUyxFQUFFLFFBQVE7NEJBQ25CLE1BQU07NEJBQ04sU0FBUyxFQUFFLElBQUksSUFBSSxFQUFFLENBQUMsV0FBVyxFQUFFO3lCQUNwQztxQkFDRjtpQkFDRjthQUNGO1NBQ0YsQ0FBQyxDQUFBO1FBRUYsT0FBTyxLQUFLLENBQUMsT0FBTyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLFdBQVcsQ0FBQTtJQUNsRSxDQUFDO0lBRUQsS0FBSyxDQUFDLG1CQUFtQixDQUN2QixPQUFlLEVBQ2YsV0FBdUIsRUFDdkIsUUFBdUIsRUFDdkIsVUFBbUQ7UUFFbkQscUVBQXFFO1FBQ3JFLCtEQUErRDtRQUMvRCxNQUFNLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxPQUFPLEVBQUUsV0FBVyxFQUFFLFFBQVEsQ0FBQyxDQUFBO1FBRWhFLG1FQUFtRTtRQUNuRSx1RUFBdUU7UUFDdkUsa0RBQWtEO1FBQ2xELE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQTtRQUN0QixJQUFJLElBQUksR0FBRyxDQUFDLENBQUE7UUFDWixJQUFJLE9BQU8sR0FBRyxJQUFJLENBQUE7UUFDbEIsTUFBTSxhQUFhLEdBQWMsRUFBRSxDQUFBO1FBRW5DLE9BQU8sT0FBTyxFQUFFLENBQUM7WUFDZixNQUFNLEtBQUssR0FBRyxNQUFNLElBQUksQ0FBQyxTQUFTLENBQ2hDO2dCQUNFLFFBQVEsRUFBRSxPQUFPO2FBQ2xCLEVBQ0Q7Z0JBQ0UsSUFBSSxFQUFFLFNBQVM7Z0JBQ2YsSUFBSTthQUNMLENBQ0YsQ0FBQTtZQUVELE1BQU0sVUFBVSxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUE7WUFDdEUsYUFBYSxDQUFDLElBQUksQ0FBQyxHQUFHLFVBQVUsQ0FBQyxDQUFBO1lBRWpDLGdFQUFnRTtZQUNoRSxPQUFPLEdBQUcsVUFBVSxDQUFDLE1BQU0sS0FBSyxTQUFTLENBQUE7WUFDekMsSUFBSSxJQUFJLFNBQVMsQ0FBQTtRQUNuQixDQUFDO1FBRUQsTUFBTSxVQUFVLEdBQUcsYUFBYSxDQUFBO1FBRWhDLE1BQU0sWUFBWSxHQUFHLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRTtZQUM5QyxNQUFNLFFBQVEsR0FBRyxJQUEyQixDQUFBO1lBQzVDLE1BQU0sTUFBTSxHQUFHLFFBQVEsQ0FBQyxNQUFNLElBQUksRUFBRSxDQUFBO1lBQ3BDLE9BQU8sQ0FBQyxXQUFXLEVBQUUsVUFBVSxFQUFFLGdCQUFnQixDQUFDLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFBO1FBQ3JFLENBQUMsQ0FBQyxDQUFBO1FBRUYsTUFBTSxtQkFBbUIsR0FBMkIsRUFBRSxDQUFBO1FBRXRELG9FQUFvRTtRQUNwRSxLQUFLLE1BQU0sWUFBWSxJQUFJLFlBQVksRUFBRSxDQUFDO1lBQ3hDLE1BQU0sUUFBUSxHQUFHLFlBQTBDLENBQUE7WUFDM0QsTUFBTSxtQkFBbUIsR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDLFFBQVEsQ0FBQyxZQUFZLENBQUMsQ0FBQTtZQUV0RSxLQUFLLE1BQU0sWUFBWSxJQUFJLG1CQUFtQixFQUFFLENBQUM7Z0JBQy9DLElBQUksWUFBWSxDQUFDLEVBQUUsSUFBSSxZQUFZLENBQUMsUUFBUSxHQUFHLENBQUMsRUFBRSxDQUFDO29CQUNqRCxtQkFBbUIsQ0FBQyxZQUFZLENBQUMsRUFBRSxDQUFDO3dCQUNsQyxDQUFDLG1CQUFtQixDQUFDLFlBQVksQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxZQUFZLENBQUMsUUFBUSxDQUFBO2dCQUN2RSxDQUFDO1lBQ0gsQ0FBQztRQUNILENBQUM7UUFFRCx1RUFBdUU7UUFDdkUsS0FBSyxNQUFNLFVBQVUsSUFBSSxXQUFXLEVBQUUsQ0FBQztZQUNyQyxJQUFJLENBQUMsVUFBVSxDQUFDLEVBQUUsSUFBSSxVQUFVLENBQUMsUUFBUSxJQUFJLENBQUMsRUFBRSxDQUFDO2dCQUMvQyxTQUFRO1lBQ1YsQ0FBQztZQUVELE1BQU0sU0FBUyxHQUFHLFVBQVUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxFQUFFLEtBQUssVUFBVSxDQUFDLEVBQUUsQ0FBQyxDQUFBO1lBRXRFLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztnQkFDZixNQUFNLElBQUksbUJBQVcsQ0FDbkIsbUJBQVcsQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUM5QixlQUFlLFVBQVUsQ0FBQyxFQUFFLHFCQUFxQixDQUNsRCxDQUFBO1lBQ0gsQ0FBQztZQUVELHNFQUFzRTtZQUN0RSw0REFBNEQ7WUFDNUQsSUFBSSxtQkFBbUIsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQzNDLE1BQU0sSUFBSSxtQkFBVyxDQUNuQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxZQUFZLEVBQzlCLFFBQVEsVUFBVSxDQUFDLEVBQUUsa0dBQWtHLENBQ3hILENBQUE7WUFDSCxDQUFDO1lBRUQsa0RBQWtEO1lBQ2xELElBQUksVUFBVSxDQUFDLFFBQVEsR0FBRyxTQUFTLENBQUMsUUFBUSxFQUFFLENBQUM7Z0JBQzdDLE1BQU0sSUFBSSxtQkFBVyxDQUNuQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxZQUFZLEVBQzlCLFFBQVEsVUFBVSxDQUFDLEVBQUUseUJBQXlCLFVBQVUsQ0FBQyxRQUFRLGlDQUFpQyxTQUFTLENBQUMsUUFBUSxZQUFZLENBQ2pJLENBQUE7WUFDSCxDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7SUFFRCxLQUFLLENBQUMsY0FBYyxDQUFDLFVBQWtCLEVBQUUsT0FBZTtRQUN0RCwyREFBMkQ7UUFDM0QsTUFBTSxhQUFhLEdBQUcsTUFBTSxJQUFJLENBQUMsU0FBUyxDQUN4QztZQUNFLFFBQVEsRUFBRSxPQUFPO1lBQ2pCLFdBQVcsRUFBRSxVQUFVO1NBQ3hCLEVBQ0Q7WUFDRSxJQUFJLEVBQUUsR0FBRztTQUNWLENBQ0YsQ0FBQTtRQUVELE1BQU0sVUFBVSxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUE7UUFDdEcsTUFBTSxnQkFBZ0IsR0FBRyxDQUFDLENBQUEsQ0FBQyxxQkFBcUI7UUFFaEQsSUFBSSxVQUFVLENBQUMsTUFBTSxJQUFJLGdCQUFnQixFQUFFLENBQUM7WUFDMUMsTUFBTSxJQUFJLG1CQUFXLENBQ25CLG1CQUFXLENBQUMsS0FBSyxDQUFDLFlBQVksRUFDOUIsV0FBVyxnQkFBZ0IsMEJBQTBCLENBQ3RELENBQUE7UUFDSCxDQUFDO1FBRUQsd0RBQXdEO1FBQ3hELHdFQUF3RTtRQUN4RSxNQUFNLGFBQWEsR0FBRyxNQUFNLElBQUksQ0FBQyxTQUFTLENBQ3hDO1lBQ0UsV0FBVyxFQUFFLFVBQVU7U0FDeEIsRUFDRDtZQUNFLElBQUksRUFBRSxJQUFJLEVBQUUsMkNBQTJDO1NBQ3hELENBQ0YsQ0FBQTtRQUVELE1BQU0sa0JBQWtCLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxhQUFhLENBQUM7WUFDckQsQ0FBQyxDQUFDLGFBQWE7WUFDZixDQUFDLENBQUMsYUFBYTtnQkFDZixDQUFDLENBQUMsQ0FBQyxhQUFhLENBQUM7Z0JBQ2pCLENBQUMsQ0FBQyxFQUFFLENBQUE7UUFFTixNQUFNLG1CQUFtQixHQUFHLEVBQUUsQ0FBQSxDQUFDLHFCQUFxQjtRQUNwRCxNQUFNLGlCQUFpQixHQUFHLGtCQUFrQixDQUFDLE1BQU0sQ0FBQTtRQUVuRCxJQUFJLGlCQUFpQixJQUFJLG1CQUFtQixFQUFFLENBQUM7WUFDN0MsTUFBTSxJQUFJLG1CQUFXLENBQ25CLG1CQUFXLENBQUMsS0FBSyxDQUFDLFlBQVksRUFDOUIsV0FBVyxtQkFBbUIsNkJBQTZCLENBQzVELENBQUE7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUVELEtBQUssQ0FBQyx1QkFBdUIsQ0FBQyxNQUFjO1FBQzFDLHVEQUF1RDtRQUN2RCxtREFBbUQ7UUFDbkQseUNBQXlDO1FBQ3pDLDhCQUE4QjtRQUM5QixxQkFBcUI7UUFDckIsT0FBTyxJQUFJLENBQUE7SUFDYixDQUFDO0NBQ0Y7QUE3a0JELDhCQTZrQkMifQ==
@@ -0,0 +1,171 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.config = void 0;
4
+ exports.default = exchangeCreatedHandler;
5
+ const utils_1 = require("@medusajs/framework/utils");
6
+ const swap_1 = require("../modules/swap");
7
+ /**
8
+ * Subscriber handler for exchange created events
9
+ * Automatically links exchanges created by admin to approved swaps
10
+ *
11
+ * When an exchange is created, this subscriber:
12
+ * 1. Finds the swap with matching order_id and status "approved" without exchange_id
13
+ * 2. Links the exchange to the swap by updating exchange_id field
14
+ * 3. Stores linking timestamp in metadata
15
+ */
16
+ async function exchangeCreatedHandler({ event: { data }, container, }) {
17
+ const startTime = Date.now();
18
+ let retryCount = 0;
19
+ const maxRetries = 3;
20
+ const retryDelay = 1000; // 1 second base delay
21
+ // Log event received for verification
22
+ console.log("[Exchange Created Subscriber] Event received:", {
23
+ event_name: "exchange.created",
24
+ exchange_id: data.id,
25
+ order_id: data.order_id,
26
+ timestamp: new Date().toISOString(),
27
+ });
28
+ const executeWithRetry = async () => {
29
+ try {
30
+ const exchangeId = data.id;
31
+ const orderId = data.order_id;
32
+ if (!exchangeId) {
33
+ console.error("[Exchange Created Subscriber] No exchange ID found in event data");
34
+ return;
35
+ }
36
+ if (!orderId) {
37
+ console.debug("[Exchange Created Subscriber] No order_id in exchange, skipping link");
38
+ return;
39
+ }
40
+ const swapService = container.resolve(swap_1.SWAP_MODULE);
41
+ const remoteQuery = container.resolve(utils_1.ContainerRegistrationKeys.REMOTE_QUERY);
42
+ // Validate exchange exists in Medusa before processing
43
+ try {
44
+ const exchangeQuery = (0, utils_1.remoteQueryObjectFromString)({
45
+ entryPoint: "exchange",
46
+ fields: ["id", "order_id"],
47
+ filters: {
48
+ id: [exchangeId],
49
+ },
50
+ });
51
+ const exchanges = await remoteQuery(exchangeQuery);
52
+ const exchangeArray = Array.isArray(exchanges) ? exchanges : exchanges ? [exchanges] : [];
53
+ const exchange = exchangeArray.find((e) => {
54
+ const eData = e;
55
+ return eData?.id === exchangeId;
56
+ });
57
+ if (!exchange) {
58
+ console.warn(`[Exchange Created Subscriber] Exchange ${exchangeId} not found in Medusa, skipping link`);
59
+ return;
60
+ }
61
+ }
62
+ catch (validationError) {
63
+ const validationErrorMessage = validationError instanceof Error ? validationError.message : String(validationError);
64
+ console.warn(`[Exchange Created Subscriber] Failed to validate exchange ${exchangeId}: ${validationErrorMessage}`);
65
+ // Continue processing even if validation fails (might be transient)
66
+ }
67
+ // Find swap by order_id where status is "approved" and exchange_id is null
68
+ let swaps;
69
+ let swap = null;
70
+ try {
71
+ swaps = await swapService.listSwaps({
72
+ order_id: orderId,
73
+ status: "approved",
74
+ }, { take: 10 });
75
+ const swapsArray = Array.isArray(swaps) ? swaps : swaps ? [swaps] : [];
76
+ // Find swap without exchange_id (not yet linked)
77
+ swap = swapsArray.find((s) => {
78
+ const swapData = s;
79
+ return !swapData.exchange_id;
80
+ }) || null;
81
+ }
82
+ catch (filterError) {
83
+ const errorMessage = filterError instanceof Error ? filterError.message : String(filterError);
84
+ console.warn(`[Exchange Created Subscriber] Failed to find swap: ${errorMessage}`);
85
+ return;
86
+ }
87
+ if (!swap) {
88
+ // No unlinked approved swap found for this order
89
+ // This is expected if:
90
+ // - Exchange was created manually without a swap request
91
+ // - Swap is not approved yet
92
+ // - Swap already has an exchange_id
93
+ console.debug(`[Exchange Created Subscriber] No unlinked approved swap found for order ${orderId} and exchange ${exchangeId}`);
94
+ return;
95
+ }
96
+ const swapData = swap;
97
+ if (!swapData.id) {
98
+ console.error("[Exchange Created Subscriber] Swap found but missing ID");
99
+ return;
100
+ }
101
+ // Link exchange to swap
102
+ const swapMetadata = swapData.metadata || {};
103
+ const linkingHistory = swapMetadata.exchange_linking_history || [];
104
+ await swapService.updateSwaps({
105
+ selector: { id: swapData.id },
106
+ data: {
107
+ exchange_id: exchangeId,
108
+ metadata: {
109
+ ...swapMetadata,
110
+ exchange_linking_history: [
111
+ ...linkingHistory,
112
+ {
113
+ exchange_id: exchangeId,
114
+ linked_at: new Date().toISOString(),
115
+ linked_by: "exchange_created_subscriber",
116
+ },
117
+ ],
118
+ exchange_linked_at: new Date().toISOString(),
119
+ },
120
+ },
121
+ });
122
+ const duration = Date.now() - startTime;
123
+ console.log(`[Exchange Created Subscriber] Linked exchange ${exchangeId} to swap ${swapData.id}`, {
124
+ duration_ms: duration,
125
+ retry_count: retryCount,
126
+ order_id: orderId,
127
+ });
128
+ }
129
+ catch (error) {
130
+ const errorMessage = error instanceof Error ? error.message : String(error);
131
+ const errorStack = error instanceof Error ? error.stack : undefined;
132
+ // Retry logic with exponential backoff
133
+ if (retryCount < maxRetries) {
134
+ retryCount++;
135
+ const delay = retryDelay * Math.pow(2, retryCount - 1);
136
+ console.warn(`[Exchange Created Subscriber] Retry ${retryCount}/${maxRetries} after ${delay}ms:`, errorMessage);
137
+ await new Promise((resolve) => setTimeout(resolve, delay));
138
+ return executeWithRetry();
139
+ }
140
+ console.error("[Exchange Created Subscriber] Error linking exchange to swap (max retries exceeded):", {
141
+ error: errorMessage,
142
+ stack: errorStack,
143
+ retry_count: retryCount,
144
+ exchange_id: data.id,
145
+ order_id: data.order_id,
146
+ });
147
+ // Don't throw - subscriber errors shouldn't break the exchange flow
148
+ }
149
+ };
150
+ await executeWithRetry();
151
+ }
152
+ /**
153
+ * Subscriber configuration
154
+ *
155
+ * Event Name: "exchange.created"
156
+ *
157
+ * This subscriber listens for exchange creation events in Medusa.
158
+ * When an exchange is created, it automatically links it to an approved swap
159
+ * if one exists for the same order.
160
+ *
161
+ * Event Data Structure Expected:
162
+ * {
163
+ * id: string (exchange ID)
164
+ * order_id?: string (order ID)
165
+ * [key: string]: unknown (other exchange fields)
166
+ * }
167
+ */
168
+ exports.config = {
169
+ event: "exchange.created",
170
+ };
171
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXhjaGFuZ2UtY3JlYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9zdWJzY3JpYmVycy9leGNoYW5nZS1jcmVhdGVkLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQXFCQSx5Q0FxTEM7QUF6TUQscURBQWtHO0FBRWxHLDBDQUE2QztBQVM3Qzs7Ozs7Ozs7R0FRRztBQUNZLEtBQUssVUFBVSxzQkFBc0IsQ0FBQyxFQUNuRCxLQUFLLEVBQUUsRUFBRSxJQUFJLEVBQUUsRUFDZixTQUFTLEdBQ2dDO0lBQ3pDLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQTtJQUM1QixJQUFJLFVBQVUsR0FBRyxDQUFDLENBQUE7SUFDbEIsTUFBTSxVQUFVLEdBQUcsQ0FBQyxDQUFBO0lBQ3BCLE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQSxDQUFDLHNCQUFzQjtJQUU5QyxzQ0FBc0M7SUFDdEMsT0FBTyxDQUFDLEdBQUcsQ0FBQywrQ0FBK0MsRUFBRTtRQUMzRCxVQUFVLEVBQUUsa0JBQWtCO1FBQzlCLFdBQVcsRUFBRSxJQUFJLENBQUMsRUFBRTtRQUNwQixRQUFRLEVBQUUsSUFBSSxDQUFDLFFBQVE7UUFDdkIsU0FBUyxFQUFFLElBQUksSUFBSSxFQUFFLENBQUMsV0FBVyxFQUFFO0tBQ3BDLENBQUMsQ0FBQTtJQUVGLE1BQU0sZ0JBQWdCLEdBQUcsS0FBSyxJQUFtQixFQUFFO1FBQ2pELElBQUksQ0FBQztZQUNILE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxFQUFFLENBQUE7WUFDMUIsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQTtZQUU3QixJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7Z0JBQ2hCLE9BQU8sQ0FBQyxLQUFLLENBQUMsa0VBQWtFLENBQUMsQ0FBQTtnQkFDakYsT0FBTTtZQUNSLENBQUM7WUFFRCxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7Z0JBQ2IsT0FBTyxD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