@jytextiles/medusa-plugin-faire-store-sync 0.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.
Files changed (104) hide show
  1. package/.medusa/server/src/__tests__/ingest-faire-order-support.spec.js +74 -0
  2. package/.medusa/server/src/__tests__/webhook.spec.js +77 -0
  3. package/.medusa/server/src/admin/index.js +960 -0
  4. package/.medusa/server/src/admin/index.mjs +959 -0
  5. package/.medusa/server/src/api/admin/faire/auth/authorize/route.js +12 -0
  6. package/.medusa/server/src/api/admin/faire/auth/callback/route.js +25 -0
  7. package/.medusa/server/src/api/admin/faire/auth/disconnect/route.js +12 -0
  8. package/.medusa/server/src/api/admin/faire/brand/route.js +14 -0
  9. package/.medusa/server/src/api/admin/faire/ingest/orders/[batchId]/route.js +27 -0
  10. package/.medusa/server/src/api/admin/faire/ingest/orders/route.js +20 -0
  11. package/.medusa/server/src/api/admin/faire/products/route.js +16 -0
  12. package/.medusa/server/src/api/admin/faire/settings/route.js +19 -0
  13. package/.medusa/server/src/api/admin/faire/status/product/[id]/route.js +30 -0
  14. package/.medusa/server/src/api/admin/faire/status/route.js +46 -0
  15. package/.medusa/server/src/api/admin/faire/sync/bulk/[batchId]/route.js +29 -0
  16. package/.medusa/server/src/api/admin/faire/sync/bulk/route.js +20 -0
  17. package/.medusa/server/src/api/admin/faire/sync/product/[id]/route.js +14 -0
  18. package/.medusa/server/src/api/admin/faire/syncs/[id]/route.js +32 -0
  19. package/.medusa/server/src/api/admin/faire/syncs/route.js +18 -0
  20. package/.medusa/server/src/api/webhooks/faire/route.js +125 -0
  21. package/.medusa/server/src/jobs/pull-faire-orders.js +32 -0
  22. package/.medusa/server/src/jobs/refresh-faire-token.js +25 -0
  23. package/.medusa/server/src/lib/faire-client.js +321 -0
  24. package/.medusa/server/src/lib/types.js +10 -0
  25. package/.medusa/server/src/lib/webhook.js +58 -0
  26. package/.medusa/server/src/links/product-faire-sync-link.js +57 -0
  27. package/.medusa/server/src/modules/faire-sync/index.js +15 -0
  28. package/.medusa/server/src/modules/faire-sync/migrations/Migration20260707211346.js +34 -0
  29. package/.medusa/server/src/modules/faire-sync/models/faire-order.js +21 -0
  30. package/.medusa/server/src/modules/faire-sync/models/faire-sync-account.js +17 -0
  31. package/.medusa/server/src/modules/faire-sync/models/faire-sync-batch.js +18 -0
  32. package/.medusa/server/src/modules/faire-sync/models/faire-sync-record.js +22 -0
  33. package/.medusa/server/src/modules/faire-sync/models/faire-sync-settings.js +26 -0
  34. package/.medusa/server/src/modules/faire-sync/models/faire-webhook-event.js +21 -0
  35. package/.medusa/server/src/modules/faire-sync/service.js +222 -0
  36. package/.medusa/server/src/subscribers/faire-inventory-sync.js +87 -0
  37. package/.medusa/server/src/subscribers/faire-listing-events.js +46 -0
  38. package/.medusa/server/src/subscribers/faire-order-ingest.js +54 -0
  39. package/.medusa/server/src/subscribers/faire-order-lifecycle.js +71 -0
  40. package/.medusa/server/src/subscribers/faire-product-status-sync.js +71 -0
  41. package/.medusa/server/src/workflows/index.js +21 -0
  42. package/.medusa/server/src/workflows/ingest-faire-order-support.js +76 -0
  43. package/.medusa/server/src/workflows/ingest-faire-order.js +148 -0
  44. package/.medusa/server/src/workflows/ingest-faire-orders-bulk.js +124 -0
  45. package/.medusa/server/src/workflows/refresh-faire-token.js +20 -0
  46. package/.medusa/server/src/workflows/sync-product-to-faire.js +262 -0
  47. package/.medusa/server/src/workflows/sync-products-to-faire.js +90 -0
  48. package/LICENSE +21 -0
  49. package/README.md +180 -0
  50. package/package.json +84 -0
  51. package/scripts/postbuild.js +36 -0
  52. package/src/__tests__/ingest-faire-order-support.spec.ts +77 -0
  53. package/src/__tests__/webhook.spec.ts +81 -0
  54. package/src/admin/lib/api.ts +88 -0
  55. package/src/admin/routes/settings/faire/[id]/page.tsx +184 -0
  56. package/src/admin/routes/settings/faire/hooks/use-faire-sync-columns.tsx +80 -0
  57. package/src/admin/routes/settings/faire/page.tsx +445 -0
  58. package/src/admin/routes/settings/faire/settings/page.tsx +286 -0
  59. package/src/admin/routes/settings/oauth/faire/callback/page.tsx +67 -0
  60. package/src/admin/widgets/faire-product-widget.tsx +180 -0
  61. package/src/api/admin/faire/auth/authorize/route.ts +10 -0
  62. package/src/api/admin/faire/auth/callback/route.ts +29 -0
  63. package/src/api/admin/faire/auth/disconnect/route.ts +10 -0
  64. package/src/api/admin/faire/brand/route.ts +12 -0
  65. package/src/api/admin/faire/ingest/orders/[batchId]/route.ts +31 -0
  66. package/src/api/admin/faire/ingest/orders/route.ts +29 -0
  67. package/src/api/admin/faire/products/route.ts +14 -0
  68. package/src/api/admin/faire/settings/route.ts +17 -0
  69. package/src/api/admin/faire/status/product/[id]/route.ts +30 -0
  70. package/src/api/admin/faire/status/route.ts +47 -0
  71. package/src/api/admin/faire/sync/bulk/[batchId]/route.ts +33 -0
  72. package/src/api/admin/faire/sync/bulk/route.ts +27 -0
  73. package/src/api/admin/faire/sync/product/[id]/route.ts +13 -0
  74. package/src/api/admin/faire/syncs/[id]/route.ts +32 -0
  75. package/src/api/admin/faire/syncs/route.ts +17 -0
  76. package/src/api/webhooks/faire/route.ts +133 -0
  77. package/src/jobs/pull-faire-orders.ts +30 -0
  78. package/src/jobs/refresh-faire-token.ts +23 -0
  79. package/src/lib/faire-client.ts +436 -0
  80. package/src/lib/types.ts +117 -0
  81. package/src/lib/webhook.ts +85 -0
  82. package/src/links/product-faire-sync-link.ts +56 -0
  83. package/src/modules/faire-sync/index.ts +11 -0
  84. package/src/modules/faire-sync/migrations/.snapshot-medusa-faire-sync.json +1486 -0
  85. package/src/modules/faire-sync/migrations/Migration20260707211346.ts +43 -0
  86. package/src/modules/faire-sync/models/faire-order.ts +20 -0
  87. package/src/modules/faire-sync/models/faire-sync-account.ts +16 -0
  88. package/src/modules/faire-sync/models/faire-sync-batch.ts +17 -0
  89. package/src/modules/faire-sync/models/faire-sync-record.ts +21 -0
  90. package/src/modules/faire-sync/models/faire-sync-settings.ts +25 -0
  91. package/src/modules/faire-sync/models/faire-webhook-event.ts +20 -0
  92. package/src/modules/faire-sync/service.ts +252 -0
  93. package/src/subscribers/faire-inventory-sync.ts +97 -0
  94. package/src/subscribers/faire-listing-events.ts +48 -0
  95. package/src/subscribers/faire-order-ingest.ts +61 -0
  96. package/src/subscribers/faire-order-lifecycle.ts +81 -0
  97. package/src/subscribers/faire-product-status-sync.ts +76 -0
  98. package/src/workflows/index.ts +4 -0
  99. package/src/workflows/ingest-faire-order-support.ts +96 -0
  100. package/src/workflows/ingest-faire-order.ts +212 -0
  101. package/src/workflows/ingest-faire-orders-bulk.ts +168 -0
  102. package/src/workflows/refresh-faire-token.ts +28 -0
  103. package/src/workflows/sync-product-to-faire.ts +375 -0
  104. package/src/workflows/sync-products-to-faire.ts +133 -0
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./sync-product-to-faire"), exports);
18
+ __exportStar(require("./sync-products-to-faire"), exports);
19
+ __exportStar(require("./refresh-faire-token"), exports);
20
+ __exportStar(require("./ingest-faire-orders-bulk"), exports);
21
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvd29ya2Zsb3dzL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSwwREFBdUM7QUFDdkMsMkRBQXdDO0FBQ3hDLHdEQUFxQztBQUNyQyw2REFBMEMifQ==
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ // Pure mapping from a Faire order → the pieces createOrderWorkflow needs.
3
+ // Kept side-effect-free so it can be unit-tested without a container.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.faireMoney = void 0;
6
+ exports.mapFaireOrderToOrder = mapFaireOrderToOrder;
7
+ // Faire sends money as integer minor units in *_cents fields (2-decimal
8
+ // currencies). Medusa v2 order line-item unit_price and payment-collection
9
+ // amounts are decimal MAJOR units (e.g. 49.99, not 4999) — same contract the
10
+ // sibling Etsy plugin honours via etsyMoney(). Divide by 100 so orders are not
11
+ // created at 100× the real total.
12
+ const faireMoney = (cents) => {
13
+ const n = Number(cents);
14
+ return Number.isFinite(n) ? n / 100 : 0;
15
+ };
16
+ exports.faireMoney = faireMoney;
17
+ const splitName = (name) => {
18
+ const parts = String(name || "").trim().split(/\s+/).filter(Boolean);
19
+ if (!parts.length)
20
+ return { first: "Faire", last: "Buyer" };
21
+ if (parts.length === 1)
22
+ return { first: parts[0], last: "" };
23
+ return { first: parts[0], last: parts.slice(1).join(" ") };
24
+ };
25
+ function mapFaireOrderToOrder(order) {
26
+ const orderToken = String(order?.order_token ?? order?.id ?? order?.token ?? "");
27
+ const address = order?.address ?? order?.shipping_address ?? {};
28
+ const currency = String(order?.currency ?? order?.currency_code ?? "usd").toLowerCase();
29
+ const buyerName = order?.buyer_name ??
30
+ order?.customer_name ??
31
+ [address?.first_name, address?.last_name].filter(Boolean).join(" ");
32
+ const { first, last } = splitName(buyerName);
33
+ // Faire usually does NOT expose the retailer's email via API — fall back to a
34
+ // synthetic, non-deliverable address keyed by order token so the guest
35
+ // customer is stable and we never accidentally email a real inbox.
36
+ const email = (typeof order?.buyer_email === "string" && order.buyer_email) ||
37
+ (typeof order?.email === "string" && order.email) ||
38
+ `faire+${orderToken}@marketplace.invalid`;
39
+ const items = Array.isArray(order?.items) ? order.items : [];
40
+ const mappedItems = items.map((it) => {
41
+ const unitCents = Number(it?.wholesale_price_cents ?? it?.unit_price_cents ?? 0);
42
+ return {
43
+ title: String(it?.product_name ?? it?.name ?? it?.title ?? "Faire item").slice(0, 250),
44
+ quantity: Math.max(1, Number(it?.quantity ?? it?.qty) || 1),
45
+ unit_price: (0, exports.faireMoney)(unitCents),
46
+ metadata: {
47
+ faire_order_token: orderToken,
48
+ faire_item_id: it?.id != null ? String(it.id) : null,
49
+ faire_product_token: it?.product_token != null ? String(it.product_token) : null,
50
+ faire_sku: it?.sku ?? null,
51
+ faire_variant_id: it?.variant_id != null ? String(it.variant_id) : null,
52
+ },
53
+ };
54
+ });
55
+ const shipping_address = {
56
+ first_name: address?.first_name ?? first,
57
+ last_name: address?.last_name ?? last,
58
+ address_1: address?.street1 ?? address?.address1 ?? address?.address_1 ?? "",
59
+ address_2: address?.street2 ?? address?.address2 ?? address?.address_2 ?? "",
60
+ city: address?.city ?? "",
61
+ province: address?.state ?? address?.province ?? "",
62
+ postal_code: address?.zip ?? address?.postal_code ?? "",
63
+ country_code: String(address?.country ?? address?.country_code ?? "").toLowerCase() || undefined,
64
+ phone: address?.phone ?? undefined,
65
+ };
66
+ return {
67
+ order_token: orderToken,
68
+ email,
69
+ buyer_name: buyerName || null,
70
+ currency_code: currency,
71
+ total: (0, exports.faireMoney)(order?.total_cents ?? order?.grand_total_cents),
72
+ shipping_address,
73
+ items: mappedItems,
74
+ };
75
+ }
76
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5nZXN0LWZhaXJlLW9yZGVyLXN1cHBvcnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvd29ya2Zsb3dzL2luZ2VzdC1mYWlyZS1vcmRlci1zdXBwb3J0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSwwRUFBMEU7QUFDMUUsc0VBQXNFOzs7QUFrQ3RFLG9EQTREQztBQTVGRCx3RUFBd0U7QUFDeEUsMkVBQTJFO0FBQzNFLDZFQUE2RTtBQUM3RSwrRUFBK0U7QUFDL0Usa0NBQWtDO0FBQzNCLE1BQU0sVUFBVSxHQUFHLENBQUMsS0FBYyxFQUFVLEVBQUU7SUFDbkQsTUFBTSxDQUFDLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFBO0lBQ3ZCLE9BQU8sTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFBO0FBQ3pDLENBQUMsQ0FBQTtBQUhZLFFBQUEsVUFBVSxjQUd0QjtBQUVELE1BQU0sU0FBUyxHQUFHLENBQUMsSUFBYSxFQUFtQyxFQUFFO0lBQ25FLE1BQU0sS0FBSyxHQUFHLE1BQU0sQ0FBQyxJQUFJLElBQUksRUFBRSxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQTtJQUNwRSxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU07UUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLENBQUE7SUFDM0QsSUFBSSxLQUFLLENBQUMsTUFBTSxLQUFLLENBQUM7UUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRSxJQUFJLEVBQUUsRUFBRSxFQUFFLENBQUE7SUFDNUQsT0FBTyxFQUFFLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFDLEVB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
@@ -0,0 +1,148 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ingestFaireOrderWorkflow = exports.INGEST_FAIRE_ORDER = void 0;
4
+ const workflows_sdk_1 = require("@medusajs/framework/workflows-sdk");
5
+ const utils_1 = require("@medusajs/framework/utils");
6
+ const core_flows_1 = require("@medusajs/medusa/core-flows");
7
+ const faire_sync_1 = require("../modules/faire-sync");
8
+ const ingest_faire_order_support_1 = require("./ingest-faire-order-support");
9
+ exports.INGEST_FAIRE_ORDER = "faire-ingest-order";
10
+ /**
11
+ * Best-effort inventory decrement for a sold Faire order. Off by default — set
12
+ * FAIRE_DECREMENT_INVENTORY=true to enable. Resolves product → variant →
13
+ * inventory item from the product token (via sync records) and adjusts the
14
+ * level with the most stock down by the sold quantity.
15
+ */
16
+ async function decrementInventory(container, items, service, logger) {
17
+ const query = container.resolve(utils_1.ContainerRegistrationKeys.QUERY);
18
+ const inventory = container.resolve(utils_1.Modules.INVENTORY);
19
+ for (const item of items) {
20
+ const productToken = item.metadata?.faire_product_token;
21
+ if (!productToken)
22
+ continue;
23
+ try {
24
+ const [records] = await service.listSyncRecords({ product_token: String(productToken) }, 1, 0);
25
+ const productId = records?.[0]?.product_id;
26
+ if (!productId)
27
+ continue;
28
+ const { data: products } = await query.graph({
29
+ entity: "product",
30
+ fields: [
31
+ "id",
32
+ "variants.inventory_items.inventory_item_id",
33
+ "variants.inventory_items.inventory.location_levels.location_id",
34
+ "variants.inventory_items.inventory.location_levels.stocked_quantity",
35
+ ],
36
+ filters: { id: productId },
37
+ });
38
+ const invItem = (products?.[0]?.variants || [])
39
+ .flatMap((v) => v.inventory_items || [])
40
+ .find((ii) => ii?.inventory_item_id);
41
+ const levels = invItem?.inventory?.location_levels || [];
42
+ const level = [...levels].sort((a, b) => Number(b.stocked_quantity) - Number(a.stocked_quantity))[0];
43
+ if (!invItem?.inventory_item_id || !level?.location_id)
44
+ continue;
45
+ await inventory.adjustInventory(invItem.inventory_item_id, level.location_id, -Math.abs(item.quantity));
46
+ logger?.info?.(`[faire-order] decremented inventory ${invItem.inventory_item_id} by ${item.quantity}`);
47
+ }
48
+ catch (err) {
49
+ logger?.warn?.(`[faire-order] inventory decrement skipped for product ${productToken}: ${err?.message}`);
50
+ }
51
+ }
52
+ }
53
+ const ingestStep = (0, workflows_sdk_1.createStep)("faire-ingest-order-step", async (input, { container }) => {
54
+ const logger = container.resolve(utils_1.ContainerRegistrationKeys.LOGGER);
55
+ const query = container.resolve(utils_1.ContainerRegistrationKeys.QUERY);
56
+ const service = container.resolve(faire_sync_1.FAIRE_SYNC_MODULE);
57
+ const mapped = (0, ingest_faire_order_support_1.mapFaireOrderToOrder)(input.order);
58
+ if (!mapped.order_token) {
59
+ return new workflows_sdk_1.StepResponse({ order_id: null, skipped: "no_order_token" });
60
+ }
61
+ if (!mapped.items.length) {
62
+ return new workflows_sdk_1.StepResponse({ order_id: null, skipped: "no_items" });
63
+ }
64
+ // Idempotency — never create a second order for the same Faire order token.
65
+ const existing = await service
66
+ .listFaireOrders({ order_token: mapped.order_token })
67
+ .catch(() => []);
68
+ const priorWithOrder = existing?.find((e) => e.order_id);
69
+ if (priorWithOrder) {
70
+ return new workflows_sdk_1.StepResponse({ order_id: priorWithOrder.order_id, skipped: "duplicate" });
71
+ }
72
+ const { data: regions } = await query.graph({
73
+ entity: "region",
74
+ fields: ["id", "currency_code"],
75
+ });
76
+ const region = regions.find((r) => String(r.currency_code).toLowerCase() === mapped.currency_code) || regions[0];
77
+ if (!region) {
78
+ throw new Error("No Medusa region configured to place the Faire order");
79
+ }
80
+ let salesChannelId;
81
+ const { data: stores } = await query.graph({
82
+ entity: "store",
83
+ fields: ["id", "default_sales_channel_id"],
84
+ });
85
+ salesChannelId = stores?.[0]?.default_sales_channel_id;
86
+ if (!salesChannelId) {
87
+ const { data: channels } = await query.graph({
88
+ entity: "sales_channel",
89
+ fields: ["id"],
90
+ });
91
+ salesChannelId = channels?.[0]?.id;
92
+ }
93
+ const orderMetadata = {
94
+ source: "faire",
95
+ faire_order_token: mapped.order_token,
96
+ faire_buyer_name: mapped.buyer_name,
97
+ };
98
+ const { result: order } = await (0, core_flows_1.createOrderWorkflow)(container).run({
99
+ input: {
100
+ region_id: region.id,
101
+ currency_code: mapped.currency_code,
102
+ sales_channel_id: salesChannelId,
103
+ email: mapped.email,
104
+ items: mapped.items,
105
+ shipping_address: mapped.shipping_address,
106
+ metadata: orderMetadata,
107
+ },
108
+ });
109
+ const orderId = order.id;
110
+ // Payment: Faire already collected it → record the collection and mark paid
111
+ // so the Medusa order shows payment_status = captured.
112
+ try {
113
+ const { result: pcRes } = await (0, core_flows_1.createOrderPaymentCollectionWorkflow)(container).run({ input: { order_id: orderId, amount: mapped.total } });
114
+ const paymentCollectionId = Array.isArray(pcRes) ? pcRes[0]?.id : pcRes?.id;
115
+ if (paymentCollectionId) {
116
+ await (0, core_flows_1.markPaymentCollectionAsPaid)(container).run({
117
+ input: {
118
+ payment_collection_id: paymentCollectionId,
119
+ order_id: orderId,
120
+ captured_by: "faire-webhook",
121
+ },
122
+ });
123
+ }
124
+ }
125
+ catch (err) {
126
+ logger?.warn?.(`[faire-order] order ${orderId} created but marking payment paid failed: ${err?.message}`);
127
+ }
128
+ if (process.env.FAIRE_DECREMENT_INVENTORY === "true") {
129
+ await decrementInventory(container, mapped.items, service, logger);
130
+ }
131
+ await service
132
+ .createFaireOrders({
133
+ order_token: mapped.order_token,
134
+ order_id: orderId,
135
+ status: "created",
136
+ currency: mapped.currency_code,
137
+ total: String(mapped.total),
138
+ buyer_name: mapped.buyer_name,
139
+ raw: input.order,
140
+ })
141
+ .catch(() => { });
142
+ logger?.info?.(`[faire-order] created Medusa order ${orderId} from Faire order ${mapped.order_token}`);
143
+ return new workflows_sdk_1.StepResponse({ order_id: orderId });
144
+ });
145
+ exports.ingestFaireOrderWorkflow = (0, workflows_sdk_1.createWorkflow)(exports.INGEST_FAIRE_ORDER, (input) => {
146
+ return new workflows_sdk_1.WorkflowResponse(ingestStep(input));
147
+ });
148
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5nZXN0LWZhaXJlLW9yZGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3dvcmtmbG93cy9pbmdlc3QtZmFpcmUtb3JkZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEscUVBTTBDO0FBQzFDLHFEQUE4RTtBQUM5RSw0REFJb0M7QUFDcEMsc0RBQXlEO0FBRXpELDZFQUFtRTtBQUV0RCxRQUFBLGtCQUFrQixHQUFHLG9CQUFvQixDQUFBO0FBT3REOzs7OztHQUtHO0FBQ0gsS0FBSyxVQUFVLGtCQUFrQixDQUMvQixTQUFjLEVBQ2QsS0FBaUUsRUFDakUsT0FBeUIsRUFDekIsTUFBVztJQUVYLE1BQU0sS0FBSyxHQUFRLFNBQVMsQ0FBQyxPQUFPLENBQUMsaUNBQXlCLENBQUMsS0FBSyxDQUFDLENBQUE7SUFDckUsTUFBTSxTQUFTLEdBQVEsU0FBUyxDQUFDLE9BQU8sQ0FBQyxlQUFPLENBQUMsU0FBUyxDQUFDLENBQUE7SUFFM0QsS0FBSyxNQUFNLElBQUksSUFBSSxLQUFLLEVBQUUsQ0FBQztRQUN6QixNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsUUFBUSxFQUFFLG1CQUFtQixDQUFBO1FBQ3ZELElBQUksQ0FBQyxZQUFZO1lBQUUsU0FBUTtRQUMzQixJQUFJLENBQUM7WUFDSCxNQUFNLENBQUMsT0FBTyxDQUFDLEdBQUcsTUFBTSxPQUFPLENBQUMsZUFBZSxDQUM3QyxFQUFFLGFBQWEsRUFBRSxNQUFNLENBQUMsWUFBWSxDQUFDLEVBQUUsRUFDdkMsQ0FBQyxFQUNELENBQUMsQ0FDRixDQUFBO1lBQ0QsTUFBTSxTQUFTLEdBQUksT0FBaUIsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLFVBQVUsQ0FBQTtZQUNyRCxJQUFJLENBQUMsU0FBUztnQkFBRSxTQUFRO1lBRXhCLE1BQU0sRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLEdBQUcsTUFBTSxLQUFLLENBQUMsS0FBSyxDQUFDO2dCQUMzQyxNQUFN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
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ingestFaireOrdersBulkWorkflow = exports.INGEST_FAIRE_ORDERS_BULK = void 0;
4
+ const workflows_sdk_1 = require("@medusajs/framework/workflows-sdk");
5
+ const faire_sync_1 = require("../modules/faire-sync");
6
+ const ingest_faire_order_1 = require("./ingest-faire-order");
7
+ exports.INGEST_FAIRE_ORDERS_BULK = "faire-ingest-orders-bulk";
8
+ // Faire enforces a modest per-second request budget. Each order ingest fans
9
+ // out to several Medusa calls (create order + payment + optional inventory),
10
+ // so we pace *orders* conservatively and let the client's 429 retry-after
11
+ // backoff absorb bursts.
12
+ const BASE_DELAY_MS = 600;
13
+ const MAX_DELAY_MS = 10_000;
14
+ const PROGRESS_EVERY = 5;
15
+ const PAGE_SIZE = 50;
16
+ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
17
+ // ── Step 1 (inline): open the batch so the HTTP caller gets an id to poll ──
18
+ const openBatchStep = (0, workflows_sdk_1.createStep)("faire-ingest-orders-open-batch-step", async (_input, { container, context }) => {
19
+ const service = container.resolve(faire_sync_1.FAIRE_SYNC_MODULE);
20
+ const account = await service.getActiveAccount();
21
+ if (!account) {
22
+ throw new Error("Faire account is not connected");
23
+ }
24
+ const batch = await service.createFaireSyncBatches({
25
+ transaction_id: context.transactionId,
26
+ status: "processing",
27
+ total_products: 0, // populated as we discover orders (generic counter)
28
+ synced_count: 0,
29
+ failed_count: 0,
30
+ error_log: {},
31
+ started_at: new Date(),
32
+ });
33
+ return new workflows_sdk_1.StepResponse({ batch_id: batch.id });
34
+ });
35
+ // ── Step 2 (async, background): page through Faire orders + ingest each ─────
36
+ const processBatchStep = (0, workflows_sdk_1.createStep)("faire-ingest-orders-process-batch-step", async (input, { container }) => {
37
+ const service = container.resolve(faire_sync_1.FAIRE_SYNC_MODULE);
38
+ const account = await service.ensureFreshToken();
39
+ const client = service.getClient();
40
+ let synced = 0;
41
+ let failed = 0;
42
+ let total = 0;
43
+ let delay = BASE_DELAY_MS;
44
+ const errors = {};
45
+ const persistProgress = async () => {
46
+ await service
47
+ .updateFaireSyncBatches({
48
+ id: input.batch_id,
49
+ total_products: total,
50
+ synced_count: synced,
51
+ failed_count: failed,
52
+ error_log: errors,
53
+ })
54
+ .catch(() => { });
55
+ };
56
+ try {
57
+ let page = 1;
58
+ let stop = false;
59
+ while (!stop) {
60
+ const { results } = await client.listOrders(account.access_token, {
61
+ limit: PAGE_SIZE,
62
+ page,
63
+ });
64
+ if (!results.length)
65
+ break;
66
+ total += results.length;
67
+ for (const order of results) {
68
+ const token = order.order_token;
69
+ try {
70
+ await (0, ingest_faire_order_1.ingestFaireOrderWorkflow)(container).run({
71
+ input: { order: order.raw, order_token: token },
72
+ });
73
+ // Skip === duplicate is still a successful no-op.
74
+ synced++;
75
+ delay = Math.max(BASE_DELAY_MS, Math.floor(delay / 2));
76
+ }
77
+ catch (err) {
78
+ failed++;
79
+ errors[token] = err?.message || "Unknown error";
80
+ if (/429|rate limit/i.test(errors[token])) {
81
+ delay = Math.min(delay * 2, MAX_DELAY_MS);
82
+ }
83
+ }
84
+ if ((synced + failed) % PROGRESS_EVERY === 0) {
85
+ await persistProgress();
86
+ }
87
+ await sleep(delay);
88
+ }
89
+ // Honor an explicit limit on total orders processed.
90
+ if (input.limit != null && total >= input.limit) {
91
+ stop = true;
92
+ }
93
+ // Stop if the last page was short (no more pages).
94
+ if (results.length < PAGE_SIZE) {
95
+ stop = true;
96
+ }
97
+ page++;
98
+ }
99
+ }
100
+ catch (err) {
101
+ errors["__fetch__"] = err?.message || "Failed to list Faire orders";
102
+ }
103
+ await service.updateFaireSyncBatches({
104
+ id: input.batch_id,
105
+ total_products: total,
106
+ status: failed === total && total > 0 ? "failed" : "completed",
107
+ synced_count: synced,
108
+ failed_count: failed,
109
+ error_log: errors,
110
+ completed_at: new Date(),
111
+ });
112
+ return new workflows_sdk_1.StepResponse({ synced, failed });
113
+ });
114
+ exports.ingestFaireOrdersBulkWorkflow = (0, workflows_sdk_1.createWorkflow)(exports.INGEST_FAIRE_ORDERS_BULK, (input) => {
115
+ const opened = openBatchStep(input);
116
+ // Long-running: the HTTP request returns as soon as the batch is opened;
117
+ // the actual per-order ingest runs in the background workflow engine.
118
+ processBatchStep((0, workflows_sdk_1.transform)({ input, opened }, (data) => ({
119
+ batch_id: data.opened.batch_id,
120
+ limit: data.input.limit,
121
+ }))).config({ async: true, backgroundExecution: true });
122
+ return new workflows_sdk_1.WorkflowResponse({ batch_id: opened.batch_id });
123
+ });
124
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5nZXN0LWZhaXJlLW9yZGVycy1idWxrLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3dvcmtmbG93cy9pbmdlc3QtZmFpcmUtb3JkZXJzLWJ1bGsudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEscUVBTzBDO0FBQzFDLHNEQUF5RDtBQUV6RCw2REFBK0Q7QUFFbEQsUUFBQSx3QkFBd0IsR0FBRywwQkFBMEIsQ0FBQTtBQU9sRSw0RUFBNEU7QUFDNUUsNkVBQTZFO0FBQzdFLDBFQUEwRTtBQUMxRSx5QkFBeUI7QUFDekIsTUFBTSxhQUFhLEdBQUcsR0FBRyxDQUFBO0FBQ3pCLE1BQU0sWUFBWSxHQUFHLE1BQU0sQ0FBQTtBQUMzQixNQUFNLGNBQWMsR0FBRyxDQUFDLENBQUE7QUFDeEIsTUFBTSxTQUFTLEdBQUcsRUFBRSxDQUFBO0FBRXBCLE1BQU0sS0FBSyxHQUFHLENBQUMsRUFBVSxFQUFFLEVBQUUsQ0FBQyxJQUFJLE9BQU8sQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsVUFBVSxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFBO0FBRW5FLDhFQUE4RTtBQUU5RSxNQUFNLGFBQWEsR0FBRyxJQUFBLDBCQUFVLEVBQzlCLHFDQUFxQyxFQUNyQyxLQUFLLEVBQ0gsTUFBa0MsRUFDbEMsRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLEVBQ3VCLEVBQUU7SUFDL0MsTUFBTSxPQUFPLEdBQXFCLFNBQVMsQ0FBQyxPQUFPLENBQUMsOEJBQWlCLENBQUMsQ0FBQTtJQUV0RSxNQUFNLE9BQU8sR0FBRyxNQUFNLE9BQU8sQ0FBQyxnQkFBZ0IsRUFBRSxDQUFBO0lBQ2hELElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUNiLE1BQU0sSUFBSSxLQUFLLENBQUMsZ0NBQWdDLENBQUMsQ0FBQTtJQUNuRCxDQUFDO0lBRUQsTUFBTSxLQUFLLEdBQUcsTUFBTSxPQUFPLENBQUMsc0JBQXNCLENBQUM7UUFDakQsY0FBYyxFQUFFLE9BQU8sQ0FBQyxhQUFhO1FBQ3JDLE1BQU0sRUFBRSxZQUFZO1FBQ3BCLGNBQWMsRUFBRSxDQUFDLEVBQUUsb0RBQW9EO1FBQ3ZFLFlBQVksRUFBRSxDQUFDO1FBQ2YsWUFBWSxFQUFFLENBQUM7UUFDZixTQUFTLEVBQUUsRUFBRTtRQUNiLFVBQVUsRUFBRSxJQUFJLElBQUksRUFBRTtLQUNoQixDQUFDLENBQUE7SUFFVCxPQUFPLElBQUksNEJBQVksQ0FBQyxFQUFFLFFBQVEsRUFBRyxLQUFhLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQTtBQUMxRCxDQUFDLENBQ0YsQ0FBQTtBQUVELCtFQUErRTtBQUUvRSxNQUFNLGdCQUFnQixHQUFHLElBQUEsMEJBQVUsRUFDakMsd0NBQXdDLEVBQ3hDLEtBQUssRUFDSCxLQUEyQyxFQUMzQyxFQUFFLFNBQVMsRUFBRSxFQUM4QyxFQUFFO0lBQzdELE1BQU0sT0FBTyxHQUFxQixTQUFTLENBQUMsT0FBTyxDQUFDLDhCQUFpQixDQUFDLENBQUE7SUFDdEUsTUFBTSxPQUFPLEdBQUcsTUFBTSxPQUFPLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQTtJQUNoRCxNQUFNLE1BQU0sR0FBRyxPQUFPLENBQUMsU0FBUyxFQUFFLENBQUE7SUFFbEMsSUFBSSxNQUFNLEdBQUcsQ0FBQyxDQUFBO0lBQ2QsSUFBSSxNQUFNLEdBQUcsQ0FBQyxDQUFBO0lBQ2QsSUFBSSxLQUFLLEdBQUcsQ0FBQyxDQUFBO0lBQ2IsSUFBSSxLQUFLLEdBQUcsYUFBYSxDQUFBO0lBQ3pCLE1BQU0sTUFBTSxHQUEyQixFQUFFLENBQUE7SUFFekMsTUFBTSxlQUFlLEdBQUcsS0FBSyxJQUFJLEVBQUU7UUFDakMsTUFBTSxPQUFPO2FBQ1Ysc0JBQXNCLENBQUM7WUFDdEIsRUFBRSxFQUFFLEtBQUssQ0FBQyxRQUFRO1lBQ2xCLGNBQWMsRUFBRSxLQUFLO1lBQ3JCLFlBQVksRUFBRSxNQUFNO1lBQ3BCLFlBQVksRUFBRSxNQUFNO1lBQ3BCLFNBQVMsRUFBRSxNQUFNO1NBQ1gsQ0FBQzthQUNSLEtBQUssQ0FBQyxHQUFHLEVBQUUsR0FBRSxDQUFDLENBQUMsQ0FBQTtJQUNwQixDQUFDLENBQUE7SUFFRCxJQUFJLENBQUM7UUFDSCxJQUFJLElBQUksR0FBRyxDQUFDLENBQUE7UUFDWixJQUFJLElBQUksR0FBRyxLQUFLLENBQUE7UUFDaEIsT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDO1lBQ2IsTUFBTSxFQUFFLE9BQU8sRUFBRSxHQUFHLE1BQU0sTUFBTSxDQUFDLFVBQVUsQ0FBQyxPQUFPLENBQUMsWUFBWSxFQUFFO2dCQUNoRSxLQUFLLEVBQUUsU0FBUztnQkFDaEIsSUFBSTthQUNMLENBQUMsQ0FBQTtZQUNGLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTTtnQkFBRSxNQUFLO1lBQzFCLEtBQUssSUFBSSxPQUFPLENBQUMsTUFBTSxDQUFBO1lBRXZCLEtBQUssTUFBTSxLQUFLLElBQUksT0FBTyxFQUFFLENBQUM7Z0JBQzVCLE1BQU0sS0FBSyxHQUFHLEtBQUssQ0FBQyxXQUFXLENBQUE7Z0JBQy9CLElBQUksQ0FBQztvQkFDSCxNQUFNLElBQUEsNkNBQXdCLEVBQUMsU0FBUyxDQUFDLENBQUMsR0FBRyxDQUFDO3dCQUM1QyxLQUFLLEVBQUUsRUFBRSxLQUFLLEVBQUUsS0FBSyxDQUFDLEdBQUcsRUFBRSxXQUFXLEVBQUUsS0FBSyxFQUFFO3FCQUNoRCxDQUFDLENBQUE7b0JBQ0Ysa0RBQWtEO29CQUNsRCxNQUFNLEVBQUUsQ0FBQTtvQkFDUixLQUFLLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxhQUFhLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQTtnQkFDeEQsQ0FBQztnQkFBQyxPQUFPLEdBQVEsRUFBRSxDQUFDO29CQUNsQixNQUFNLEVBQUUsQ0FBQTtvQkFDUixNQUFNLENBQUMsS0FBSyxDQUFDLEdBQUcsR0FBRyxFQUFFLE9BQU8sSUFBSSxlQUFlLENBQUE7b0JBQy9DLElBQUksaUJBQWlCLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLENBQUM7d0JBQzFDLEtBQUssR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEtBQUssR0FBRyxDQUFDLEVBQUUsWUFBWSxDQUFDLENBQUE7b0JBQzNDLENBQUM7Z0JBQ0gsQ0FBQztnQkFFRCxJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQyxHQUFHLGNBQWMsS0FBSyxDQUFDLEVBQUUsQ0FBQztvQkFDN0MsTUFBTSxlQUFlLEVBQUUsQ0FBQTtnQkFDekIsQ0FBQztnQkFDRCxNQUFNLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQTtZQUNwQixDQUFDO1lBRUQscURBQXFEO1lBQ3JELElBQUksS0FBSyxDQUFDLEtBQUssSUFBSSxJQUFJLElBQUksS0FBSyxJQUFJLEtBQUssQ0FBQyxLQUFLLEVBQUUsQ0FBQztnQkFDaEQsSUFBSSxHQUFHLElBQUksQ0FBQTtZQUNiLENBQUM7WUFDRCxtREFBbUQ7WUFDbkQsSUFBSSxPQUFPLENBQUMsTUFBTSxHQUFHLFNBQVMsRUFBRSxDQUFDO2dCQUMvQixJQUFJLEdBQUcsSUFBSSxDQUFBO1lBQ2IsQ0FBQztZQUNELElBQUksRUFBRSxDQUFBO1FBQ1IsQ0FBQztJQUNILENBQUM7SUFBQyxPQUFPLEdBQVEsRUFBRSxDQUFDO1FBQ2xCLE1BQU0sQ0FBQyxXQUFXLENBQUMsR0FBRyxHQUFHLEVBQUUsT0FBTyxJQUFJLDZCQUE2QixDQUFBO0lBQ3JFLENBQUM7SUFFRCxNQUFNLE9BQU8sQ0FBQyxzQkFBc0IsQ0FBQztRQUNuQyxFQUFFLEVBQUUsS0FBSyxDQUFDLFFBQVE7UUFDbEIsY0FBYyxFQUFFLEtBQUs7UUFDckIsTUFBTSxFQUFFLE1BQU0sS0FBSyxLQUFLLElBQUksS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxXQUFXO1FBQzlELFlBQVksRUFBRSxNQUFNO1FBQ3BCLFlBQVksRUFBRSxNQUFNO1FBQ3BCLFNBQVMsRUFBRSxNQUFNO1FBQ2pCLFlBQVksRUFBRSxJQUFJLElBQUksRUFBRTtLQUNsQixDQUFDLENBQUE7SUFFVCxPQUFPLElBQUksNEJBQVksQ0FBQyxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsQ0FBQyxDQUFBO0FBQzdDLENBQUMsQ0FDRixDQUFBO0FBRVksUUFBQSw2QkFBNkIsR0FBRyxJQUFBLDhCQUFjLEVBQ3pELGdDQUF3QixFQUN4QixDQUFDLEtBQStDLEVBQUUsRUFBRTtJQUNsRCxNQUFNLE1BQU0sR0FBRyxhQUFhLENBQUMsS0FBSyxDQUFDLENBQUE7SUFFbkMseUVBQXlFO0lBQ3pFLHNFQUFzRTtJQUN0RSxnQkFBZ0IsQ0FDZCxJQUFBLHlCQUFTLEVBQUMsRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLEVBQUUsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFDdEMsUUFBUSxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUTtRQUM5QixLQUFLLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLO0tBQ3hCLENBQUMsQ0FBQyxDQUNKLENBQUMsTUFBTSxDQUFDLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxtQkFBbUIsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFBO0lBRXBELE9BQU8sSUFBSSxnQ0FBZ0IsQ0FBQyxFQUFFLFFBQVEsRUFBRSxNQUFNLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQTtBQUM1RCxDQUFDLENBQ0YsQ0FBQSJ9
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.refreshFaireTokenWorkflow = exports.REFRESH_FAIRE_TOKEN = void 0;
4
+ const workflows_sdk_1 = require("@medusajs/framework/workflows-sdk");
5
+ const faire_sync_1 = require("../modules/faire-sync");
6
+ exports.REFRESH_FAIRE_TOKEN = "faire-refresh-token";
7
+ const refreshFaireTokenStep = (0, workflows_sdk_1.createStep)("faire-refresh-token-step", async (_, { container }) => {
8
+ const service = container.resolve(faire_sync_1.FAIRE_SYNC_MODULE);
9
+ const account = await service.getActiveAccount();
10
+ if (!account) {
11
+ return new workflows_sdk_1.StepResponse({ refreshed: false });
12
+ }
13
+ await service.ensureFreshToken(account);
14
+ return new workflows_sdk_1.StepResponse({ refreshed: true });
15
+ });
16
+ exports.refreshFaireTokenWorkflow = (0, workflows_sdk_1.createWorkflow)(exports.REFRESH_FAIRE_TOKEN, () => {
17
+ const result = refreshFaireTokenStep();
18
+ return new workflows_sdk_1.WorkflowResponse(result);
19
+ });
20
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVmcmVzaC1mYWlyZS10b2tlbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy93b3JrZmxvd3MvcmVmcmVzaC1mYWlyZS10b2tlbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxxRUFLMEM7QUFDMUMsc0RBQXlEO0FBRzVDLFFBQUEsbUJBQW1CLEdBQUcscUJBQXFCLENBQUE7QUFFeEQsTUFBTSxxQkFBcUIsR0FBRyxJQUFBLDBCQUFVLEVBQ3RDLDBCQUEwQixFQUMxQixLQUFLLEVBQUUsQ0FBQyxFQUFFLEVBQUUsU0FBUyxFQUFFLEVBQWlELEVBQUU7SUFDeEUsTUFBTSxPQUFPLEdBQXFCLFNBQVMsQ0FBQyxPQUFPLENBQUMsOEJBQWlCLENBQUMsQ0FBQTtJQUN0RSxNQUFNLE9BQU8sR0FBRyxNQUFNLE9BQU8sQ0FBQyxnQkFBZ0IsRUFBRSxDQUFBO0lBQ2hELElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUNiLE9BQU8sSUFBSSw0QkFBWSxDQUFDLEVBQUUsU0FBUyxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUE7SUFDL0MsQ0FBQztJQUNELE1BQU0sT0FBTyxDQUFDLGdCQUFnQixDQUFDLE9BQU8sQ0FBQyxDQUFBO0lBQ3ZDLE9BQU8sSUFBSSw0QkFBWSxDQUFDLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUE7QUFDOUMsQ0FBQyxDQUNGLENBQUE7QUFFWSxRQUFBLHlCQUF5QixHQUFHLElBQUEsOEJBQWMsRUFBQywyQkFBbUIsRUFBRSxHQUFHLEVBQUU7SUFDaEYsTUFBTSxNQUFNLEdBQUcscUJBQXFCLEVBQUUsQ0FBQTtJQUN0QyxPQUFPLElBQUksZ0NBQWdCLENBQUMsTUFBTSxDQUFDLENBQUE7QUFDckMsQ0FBQyxDQUFDLENBQUEifQ==