@useairfoil/producer-shopify 0.2.0 → 0.2.2

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 (61) hide show
  1. package/LICENSE.txt +201 -0
  2. package/README.md +85 -248
  3. package/dist/index.d.mts +6993 -0
  4. package/dist/index.mjs +3 -0
  5. package/dist/main.d.mts +1 -0
  6. package/dist/main.mjs +700 -0
  7. package/dist/main.mjs.map +1 -0
  8. package/dist/manifest.d.mts +32 -0
  9. package/dist/manifest.mjs +51 -0
  10. package/dist/manifest.mjs.map +1 -0
  11. package/dist/{chunk-Bp6m_JJh.js → rolldown-runtime-D7D4PA-g.mjs} +4 -4
  12. package/dist/src-YBU_KSf5.mjs +2472 -0
  13. package/dist/src-YBU_KSf5.mjs.map +1 -0
  14. package/package.json +27 -27
  15. package/src/{auth.ts → api/auth.ts} +15 -35
  16. package/src/api/client.ts +429 -0
  17. package/src/api/graphql.ts +221 -0
  18. package/src/api/http.ts +25 -0
  19. package/src/connector.ts +266 -163
  20. package/src/create-table.ts +10 -0
  21. package/src/demo/customers.ts +412 -0
  22. package/src/demo/index.ts +31 -0
  23. package/src/demo/setup.ts +63 -0
  24. package/src/demo/shared.ts +114 -0
  25. package/src/index.ts +35 -21
  26. package/src/main.ts +14 -8
  27. package/src/manifest.ts +4 -55
  28. package/src/resources/carts/row.ts +82 -0
  29. package/src/resources/carts/webhook.ts +98 -0
  30. package/src/resources/customers/graphql.ts +175 -0
  31. package/src/resources/customers/row.ts +140 -0
  32. package/src/resources/customers/webhook.ts +30 -0
  33. package/src/resources/orders/graphql.ts +419 -0
  34. package/src/resources/orders/row.ts +306 -0
  35. package/src/resources/orders/webhook.ts +248 -0
  36. package/src/resources/products/graphql.ts +142 -0
  37. package/src/resources/products/row.ts +122 -0
  38. package/src/resources/products/webhook.ts +130 -0
  39. package/src/resources/refunds/graphql.ts +196 -0
  40. package/src/resources/refunds/row.ts +137 -0
  41. package/src/resources/refunds/webhook.ts +123 -0
  42. package/src/resources/shared.ts +300 -0
  43. package/src/sandbox.ts +3 -3
  44. package/src/start.ts +4 -6
  45. package/src/tables.ts +15 -0
  46. package/dist/index.d.ts +0 -965
  47. package/dist/index.js +0 -4
  48. package/dist/main.d.ts +0 -1
  49. package/dist/main.js +0 -49
  50. package/dist/main.js.map +0 -1
  51. package/dist/manifest-BFfx2LkS.js +0 -91
  52. package/dist/manifest-BFfx2LkS.js.map +0 -1
  53. package/dist/manifest-CPOEExQU.d.ts +0 -34
  54. package/dist/manifest.d.ts +0 -2
  55. package/dist/manifest.js +0 -3
  56. package/dist/src-DqmiLrYS.js +0 -984
  57. package/dist/src-DqmiLrYS.js.map +0 -1
  58. package/src/api.ts +0 -636
  59. package/src/schemas.ts +0 -319
  60. package/src/throttle.ts +0 -89
  61. package/src/transient-retry.ts +0 -74
package/dist/index.mjs ADDED
@@ -0,0 +1,3 @@
1
+ import { C as CartWebhookPayloadSchema, S as ProductVariantSchema, _ as ProductWebhookPayloadSchema, a as RefundWebhookPayloadSchema, b as ProductStatusSchema, c as OrderWebhookPayloadSchema, d as CartSchema, f as client_exports, g as ProductDeleteWebhookPayloadSchema, h as CustomerSchema, l as fromOrderWebhook, m as OrderSchema, o as fromRefundWebhook, p as RefundSchema, r as connector_exports, s as OrderDeleteWebhookPayloadSchema, t as ShopifyNormalize, u as CartLineItemSchema, v as ProductOptionSchema, w as PageInfoSchema, x as ProductVariantInventoryPolicySchema, y as ProductSchema } from "./src-YBU_KSf5.mjs";
2
+ import { manifest } from "./manifest.mjs";
3
+ export { CartLineItemSchema, CartSchema, CartWebhookPayloadSchema, CustomerSchema, OrderDeleteWebhookPayloadSchema, OrderSchema, OrderWebhookPayloadSchema, PageInfoSchema, ProductDeleteWebhookPayloadSchema, ProductOptionSchema, ProductSchema, ProductStatusSchema, ProductVariantInventoryPolicySchema, ProductVariantSchema, ProductWebhookPayloadSchema, RefundSchema, RefundWebhookPayloadSchema, client_exports as ShopifyApiClient, connector_exports as ShopifyConnector, ShopifyNormalize, fromOrderWebhook, fromRefundWebhook, manifest };
@@ -0,0 +1 @@
1
+ export {}
package/dist/main.mjs ADDED
@@ -0,0 +1,700 @@
1
+ import { E as normalizeAmount, T as gid, d as CartSchema, h as CustomerSchema, i as layerConfig, m as OrderSchema, n as ShopifyConnector, p as RefundSchema, y as ProductSchema } from "./src-YBU_KSf5.mjs";
2
+ import { ShopifyConfigDef } from "./manifest.mjs";
3
+ import "effect/Schema";
4
+ import { Config, Duration, Effect, Layer, Logger, Schema } from "effect";
5
+ import { ConnectorApp, Demo, Ingestor, RuntimeConfig, StateStore, Telemetry } from "@useairfoil/connector-kit";
6
+ import { FetchHttpClient } from "effect/http";
7
+ import { NodeRuntime, NodeServices } from "@effect/platform-node";
8
+ import { Command } from "effect/cli";
9
+ import { PgClient } from "@effect/sql-pg";
10
+ //#region package.json
11
+ var version = "0.2.2";
12
+ //#endregion
13
+ //#region src/tables.ts
14
+ const tableSchemas = {
15
+ products: ProductSchema,
16
+ carts: CartSchema,
17
+ customers: CustomerSchema,
18
+ orders: OrderSchema,
19
+ refunds: RefundSchema
20
+ };
21
+ //#endregion
22
+ //#region src/create-table.ts
23
+ const createTableCommand = ConnectorApp.makeCreateTableCommand(tableSchemas);
24
+ const setupCommand = ConnectorApp.makeSetupCommand(tableSchemas).pipe(Command.provide(RuntimeConfig.layerHosted()));
25
+ //#endregion
26
+ //#region src/demo/shared.ts
27
+ const hour = Duration.toMillis(Duration.hours(1));
28
+ const day = Duration.toMillis(Duration.days(1));
29
+ const vendor = "Northwind Goods";
30
+ const taxRate = .08;
31
+ const welcomeCode = "WELCOME10";
32
+ const catalog = [
33
+ {
34
+ title: "Classic Cotton Tee",
35
+ type: "T-Shirts",
36
+ price: 2800,
37
+ grams: 180,
38
+ option: {
39
+ name: "Size",
40
+ values: [
41
+ "S",
42
+ "M",
43
+ "L",
44
+ "XL"
45
+ ]
46
+ }
47
+ },
48
+ {
49
+ title: "Everyday Hoodie",
50
+ type: "Sweatshirts",
51
+ price: 6400,
52
+ grams: 520,
53
+ option: {
54
+ name: "Size",
55
+ values: [
56
+ "S",
57
+ "M",
58
+ "L",
59
+ "XL"
60
+ ]
61
+ }
62
+ },
63
+ {
64
+ title: "Linen Button Shirt",
65
+ type: "Shirts",
66
+ price: 7200,
67
+ grams: 260,
68
+ option: {
69
+ name: "Size",
70
+ values: [
71
+ "S",
72
+ "M",
73
+ "L"
74
+ ]
75
+ }
76
+ },
77
+ {
78
+ title: "Wool Beanie",
79
+ type: "Hats",
80
+ price: 2600,
81
+ grams: 90,
82
+ option: {
83
+ name: "Color",
84
+ values: [
85
+ "Charcoal",
86
+ "Navy",
87
+ "Rust"
88
+ ]
89
+ }
90
+ },
91
+ {
92
+ title: "Canvas Tote Bag",
93
+ type: "Bags",
94
+ price: 2200,
95
+ grams: 300,
96
+ option: null
97
+ },
98
+ {
99
+ title: "Leather Card Wallet",
100
+ type: "Accessories",
101
+ price: 5400,
102
+ grams: 80,
103
+ option: {
104
+ name: "Color",
105
+ values: ["Black", "Tan"]
106
+ }
107
+ },
108
+ {
109
+ title: "Stoneware Mug",
110
+ type: "Home",
111
+ price: 1800,
112
+ grams: 400,
113
+ option: {
114
+ name: "Color",
115
+ values: ["Cream", "Sage"]
116
+ }
117
+ },
118
+ {
119
+ title: "Insulated Water Bottle",
120
+ type: "Home",
121
+ price: 3200,
122
+ grams: 450,
123
+ option: {
124
+ name: "Color",
125
+ values: [
126
+ "Black",
127
+ "White",
128
+ "Sky"
129
+ ]
130
+ }
131
+ },
132
+ {
133
+ title: "Merino Running Socks",
134
+ type: "Socks",
135
+ price: 1600,
136
+ grams: 60,
137
+ option: {
138
+ name: "Size",
139
+ values: ["S/M", "L/XL"]
140
+ }
141
+ },
142
+ {
143
+ title: "Gift Card",
144
+ type: "Gift Cards",
145
+ price: 5e3,
146
+ grams: 0,
147
+ option: null
148
+ }
149
+ ];
150
+ const productNumber = (p) => 81e11 + p;
151
+ const variantNumber = (p, v) => 44e12 + p * 10 + v;
152
+ const handleOf = (item) => item.title.toLowerCase().replaceAll(" ", "-");
153
+ const isGiftCard = (item) => item.type === "Gift Cards";
154
+ const valuesOf = (item) => item.option?.values ?? ["Default Title"];
155
+ const money = (cents) => {
156
+ const amount = normalizeAmount((cents / 100).toFixed(2));
157
+ return {
158
+ shopMoney: {
159
+ amount,
160
+ currencyCode: "USD"
161
+ },
162
+ presentmentMoney: {
163
+ amount,
164
+ currencyCode: "USD"
165
+ }
166
+ };
167
+ };
168
+ const amount = (cents) => normalizeAmount((cents / 100).toFixed(2));
169
+ /** Date helpers for one run. `at` keeps a time from going past now. */
170
+ const clock = ({ now }) => {
171
+ const at = (time) => new Date(Math.min(time, now.getTime()));
172
+ return { at };
173
+ };
174
+ //#endregion
175
+ //#region src/demo/customers.ts
176
+ /** One group is one customer with their orders, refunds, and sometimes an open cart. */
177
+ const customerRows = (index, context) => {
178
+ const { faker, now } = context;
179
+ const { at } = clock(context);
180
+ const rows = {
181
+ customers: [],
182
+ orders: [],
183
+ refunds: [],
184
+ carts: []
185
+ };
186
+ const customerNumber = 72e11 + index;
187
+ const customerId = gid("Customer", customerNumber);
188
+ const addressId = gid("MailingAddress", 93e11 + index);
189
+ const firstName = faker.person.firstName();
190
+ const lastName = faker.person.lastName();
191
+ const email = faker.internet.exampleEmail({
192
+ firstName,
193
+ lastName
194
+ }).toLowerCase();
195
+ const phone = faker.phone.number({ style: "international" });
196
+ const address = {
197
+ firstName,
198
+ lastName,
199
+ name: `${firstName} ${lastName}`,
200
+ company: null,
201
+ address1: faker.location.streetAddress(),
202
+ address2: null,
203
+ city: faker.location.city(),
204
+ province: faker.location.state(),
205
+ provinceCode: faker.location.state({ abbreviated: true }),
206
+ country: "United States",
207
+ countryCode: "US",
208
+ zip: faker.location.zipCode("#####"),
209
+ phone,
210
+ latitude: faker.location.latitude(),
211
+ longitude: faker.location.longitude()
212
+ };
213
+ const subscribed = faker.datatype.boolean({ probability: .4 });
214
+ const created = at(now.getTime() - faker.number.int({
215
+ min: 10 * day,
216
+ max: 700 * day
217
+ }));
218
+ const orderCount = faker.helpers.weightedArrayElement([
219
+ {
220
+ weight: 20,
221
+ value: 0
222
+ },
223
+ {
224
+ weight: 40,
225
+ value: 1
226
+ },
227
+ {
228
+ weight: 20,
229
+ value: 2
230
+ },
231
+ {
232
+ weight: 10,
233
+ value: 3
234
+ },
235
+ {
236
+ weight: 10,
237
+ value: faker.number.int({
238
+ min: 4,
239
+ max: 6
240
+ })
241
+ }
242
+ ]);
243
+ const orderTimes = Array.from({ length: orderCount }, () => faker.date.between({
244
+ from: created,
245
+ to: now
246
+ })).toSorted((a, b) => a.getTime() - b.getTime());
247
+ let spent = 0;
248
+ let lastChange = created;
249
+ orderTimes.forEach((orderCreated, n) => {
250
+ const orderNumber = 56e11 + index * 10 + n;
251
+ const orderId = gid("Order", orderNumber);
252
+ const saleId = gid("OrderTransaction", 67e11 + (index * 10 + n) * 2);
253
+ const discounted = n === 0 && faker.datatype.boolean({ probability: .25 });
254
+ const lines = faker.helpers.arrayElements(catalog.map((item, p) => ({
255
+ item,
256
+ p
257
+ })), {
258
+ min: 1,
259
+ max: 3
260
+ }).map(({ item, p }, k) => {
261
+ const v = faker.number.int({ max: valuesOf(item).length - 1 });
262
+ const quantity = isGiftCard(item) ? 1 : faker.number.int({
263
+ min: 1,
264
+ max: 2
265
+ });
266
+ const gross = item.price * quantity;
267
+ const discount = discounted ? Math.round(gross * .1) : 0;
268
+ return {
269
+ item,
270
+ p,
271
+ v,
272
+ k,
273
+ quantity,
274
+ gross,
275
+ discount,
276
+ tax: isGiftCard(item) ? 0 : Math.round((gross - discount) * taxRate)
277
+ };
278
+ });
279
+ const discountTotal = lines.reduce((sum, line) => sum + line.discount, 0);
280
+ const subtotal = lines.reduce((sum, line) => sum + line.gross - line.discount, 0);
281
+ const tax = lines.reduce((sum, line) => sum + line.tax, 0);
282
+ const shipping = lines.every((line) => isGiftCard(line.item)) || subtotal >= 7500 ? 0 : 600;
283
+ const total = subtotal + shipping + tax;
284
+ const grams = lines.reduce((sum, line) => sum + line.item.grams * line.quantity, 0);
285
+ const cancelled = faker.datatype.boolean({ probability: .03 });
286
+ const refund = cancelled ? null : faker.helpers.maybe(() => faker.helpers.arrayElement(["full", "partial"]), { probability: .06 });
287
+ const refundedLines = refund === "full" ? lines : refund === "partial" ? lines.slice(0, 1) : [];
288
+ const refundShipping = refund === "full" ? shipping : 0;
289
+ const refundedSubtotal = refundedLines.reduce((sum, line) => sum + line.gross - line.discount, 0);
290
+ const refundedTax = refundedLines.reduce((sum, line) => sum + line.tax, 0);
291
+ const refundedTotal = refundedSubtotal + refundedTax + refundShipping;
292
+ const cancelledAt = cancelled ? at(orderCreated.getTime() + faker.number.int({
293
+ min: 6e4,
294
+ max: day
295
+ })) : null;
296
+ const refundAt = refund ? at(orderCreated.getTime() + faker.number.int({
297
+ min: 3 * day,
298
+ max: 20 * day
299
+ })) : null;
300
+ const fulfilled = orderCreated.getTime() < now.getTime() - 5 * day;
301
+ const closedAt = cancelledAt ?? (fulfilled ? at(orderCreated.getTime() + faker.number.int({
302
+ min: 2 * day,
303
+ max: 5 * day
304
+ })) : null);
305
+ const updatedAt = new Date(Math.max(orderCreated.getTime(), closedAt?.getTime() ?? 0, refundAt?.getTime() ?? 0));
306
+ const current = cancelled ? 0 : 1;
307
+ const currentSubtotal = (subtotal - refundedSubtotal) * current;
308
+ const currentTax = (tax - refundedTax) * current;
309
+ const currentShipping = (shipping - refundShipping) * current;
310
+ const currentTotal = currentSubtotal + currentTax + currentShipping;
311
+ spent += currentTotal;
312
+ lastChange = updatedAt > lastChange ? updatedAt : lastChange;
313
+ const shippingLineId = gid("ShippingLine", 45e11 + index * 10 + n);
314
+ rows.orders.push({
315
+ id: orderId,
316
+ legacyResourceId: String(orderNumber),
317
+ name: `#${1001 + index * 10 + n}`,
318
+ email,
319
+ phone,
320
+ customerId,
321
+ customerLocale: "en",
322
+ customerAcceptsMarketing: subscribed,
323
+ billingAddress: address,
324
+ shippingAddress: lines.every((line) => isGiftCard(line.item)) ? null : address,
325
+ note: "",
326
+ customAttributes: [],
327
+ tags: [],
328
+ confirmationNumber: faker.string.alphanumeric({
329
+ length: 9,
330
+ casing: "upper"
331
+ }),
332
+ poNumber: "",
333
+ sourceName: "web",
334
+ sourceIdentifier: "",
335
+ appId: gid("App", 580111),
336
+ paymentGatewayNames: ["shopify_payments"],
337
+ test: false,
338
+ taxesIncluded: false,
339
+ taxExempt: false,
340
+ dutiesIncluded: false,
341
+ estimatedTaxes: false,
342
+ totalWeight: grams,
343
+ displayFinancialStatus: cancelled ? "VOIDED" : refund === "full" ? "REFUNDED" : refund === "partial" ? "PARTIALLY_REFUNDED" : "PAID",
344
+ cancelReason: cancelled ? "CUSTOMER" : null,
345
+ cancelledAt,
346
+ closedAt,
347
+ processedAt: orderCreated,
348
+ createdAt: orderCreated,
349
+ updatedAt,
350
+ currencyCode: "USD",
351
+ presentmentCurrencyCode: "USD",
352
+ discountCodes: discounted ? [welcomeCode] : [],
353
+ discountApplications: discounted ? [{
354
+ index: 0,
355
+ type: "DISCOUNT_CODE",
356
+ code: welcomeCode,
357
+ title: null,
358
+ description: null,
359
+ allocationMethod: "ACROSS",
360
+ targetSelection: "ALL",
361
+ targetType: "LINE_ITEM",
362
+ valueType: "PERCENTAGE",
363
+ value: "10"
364
+ }] : [],
365
+ subtotalPriceSet: money(subtotal),
366
+ currentSubtotalPriceSet: money(currentSubtotal),
367
+ totalDiscountsSet: money(discountTotal),
368
+ currentTotalDiscountsSet: money(discountTotal * current),
369
+ totalShippingPriceSet: money(shipping),
370
+ currentShippingPriceSet: money(currentShipping),
371
+ totalTaxSet: money(tax),
372
+ currentTotalTaxSet: money(currentTax),
373
+ originalTotalDutiesSet: null,
374
+ currentTotalDutiesSet: null,
375
+ totalPriceSet: money(total),
376
+ currentTotalPriceSet: money(currentTotal),
377
+ taxLines: tax > 0 ? [{
378
+ title: "Sales Tax",
379
+ rate: taxRate,
380
+ priceSet: money(tax)
381
+ }] : [],
382
+ shippingLines: shipping === 0 && lines.every((line) => isGiftCard(line.item)) ? [] : [{
383
+ id: shippingLineId,
384
+ title: shipping === 0 ? "Free Shipping" : "Standard Shipping",
385
+ code: shipping === 0 ? "Free Shipping" : "Standard Shipping",
386
+ source: "shopify",
387
+ carrierIdentifier: null,
388
+ phone: null,
389
+ isRemoved: false,
390
+ originalPriceSet: money(shipping),
391
+ discountedPriceSet: money(shipping),
392
+ currentDiscountedPriceSet: money(currentShipping),
393
+ taxLines: [],
394
+ discountAllocations: []
395
+ }],
396
+ lineItems: lines.map((line) => {
397
+ const value = valuesOf(line.item)[line.v] ?? "Default Title";
398
+ const refundedQuantity = refundedLines.includes(line) ? line.quantity : 0;
399
+ return {
400
+ id: gid("LineItem", 0xcbba106e000 + (index * 10 + n) * 10 + line.k),
401
+ name: line.item.option ? `${line.item.title} - ${value}` : line.item.title,
402
+ title: line.item.title,
403
+ variantTitle: line.item.option ? value : null,
404
+ sku: `NW-${handleOf(line.item).toUpperCase()}-${value.replace("/", "").toUpperCase()}`,
405
+ vendor,
406
+ productId: gid("Product", productNumber(line.p)),
407
+ variantId: gid("ProductVariant", variantNumber(line.p, line.v)),
408
+ quantity: line.quantity,
409
+ currentQuantity: (line.quantity - refundedQuantity) * current,
410
+ taxable: !isGiftCard(line.item),
411
+ requiresShipping: !isGiftCard(line.item),
412
+ isGiftCard: isGiftCard(line.item),
413
+ originalUnitPriceSet: money(line.item.price),
414
+ totalDiscountSet: money(line.discount),
415
+ taxLines: line.tax > 0 ? [{
416
+ title: "Sales Tax",
417
+ rate: taxRate,
418
+ priceSet: money(line.tax)
419
+ }] : [],
420
+ discountAllocations: discounted ? [{
421
+ discountApplicationIndex: 0,
422
+ amountSet: money(line.discount)
423
+ }] : [],
424
+ customAttributes: []
425
+ };
426
+ })
427
+ });
428
+ if (refund && refundAt) {
429
+ const refundNumber = 0xe8d4a51000 + index * 10 + n;
430
+ rows.refunds.push({
431
+ id: gid("Refund", refundNumber),
432
+ legacyResourceId: String(refundNumber),
433
+ orderId,
434
+ note: refund === "full" ? "Returned by customer" : "",
435
+ createdAt: refundAt,
436
+ processedAt: refundAt,
437
+ transactions: [{
438
+ id: gid("OrderTransaction", 67e11 + (index * 10 + n) * 2 + 1),
439
+ kind: "REFUND",
440
+ status: "SUCCESS",
441
+ amount: amount(refundedTotal),
442
+ currencyCode: "USD",
443
+ gateway: "shopify_payments",
444
+ test: false,
445
+ errorCode: null,
446
+ parentTransactionId: saleId,
447
+ createdAt: refundAt,
448
+ processedAt: refundAt
449
+ }],
450
+ refundLineItems: refundedLines.map((line) => ({
451
+ id: gid("RefundLineItem", 2e12 + (index * 10 + n) * 10 + line.k),
452
+ lineItemId: gid("LineItem", 0xcbba106e000 + (index * 10 + n) * 10 + line.k),
453
+ quantity: line.quantity,
454
+ restockType: "RETURN",
455
+ locationId: gid("Location", 64000000001),
456
+ subtotalSet: money(line.gross - line.discount),
457
+ totalTaxSet: money(line.tax)
458
+ })),
459
+ refundShippingLines: refundShipping > 0 ? [{
460
+ id: gid("RefundShippingLine", 3e12 + index * 10 + n),
461
+ shippingLineId,
462
+ subtotalAmountSet: money(refundShipping)
463
+ }] : [],
464
+ orderAdjustments: [],
465
+ duties: []
466
+ });
467
+ }
468
+ });
469
+ if (faker.datatype.boolean({ probability: .25 })) {
470
+ const token = `c1-${index.toString(16).padStart(8, "0")}${faker.string.hexadecimal({
471
+ length: 24,
472
+ casing: "lower",
473
+ prefix: ""
474
+ })}`;
475
+ const cartCreated = at(now.getTime() - faker.number.int({
476
+ min: hour,
477
+ max: 7 * day
478
+ }));
479
+ rows.carts.push({
480
+ id: token,
481
+ token,
482
+ topic: "carts/update",
483
+ lineItems: faker.helpers.arrayElements(catalog.map((item, p) => ({
484
+ item,
485
+ p
486
+ })), {
487
+ min: 1,
488
+ max: 2
489
+ }).map(({ item, p }) => {
490
+ const v = faker.number.int({ max: valuesOf(item).length - 1 });
491
+ const quantity = faker.number.int({
492
+ min: 1,
493
+ max: 2
494
+ });
495
+ const variant = variantNumber(p, v);
496
+ return {
497
+ id: String(variant),
498
+ properties: null,
499
+ quantity,
500
+ variantId: gid("ProductVariant", variant),
501
+ key: `${variant}:${faker.string.hexadecimal({
502
+ length: 32,
503
+ casing: "lower",
504
+ prefix: ""
505
+ })}`,
506
+ discountedPrice: amount(item.price),
507
+ discounts: "[]",
508
+ giftCard: isGiftCard(item),
509
+ grams: item.grams,
510
+ linePrice: amount(item.price * quantity),
511
+ originalLinePrice: amount(item.price * quantity),
512
+ originalPrice: amount(item.price),
513
+ price: amount(item.price),
514
+ productId: gid("Product", productNumber(p)),
515
+ sku: `NW-${handleOf(item).toUpperCase()}-${(valuesOf(item)[v] ?? "").replace("/", "").toUpperCase()}`,
516
+ taxable: !isGiftCard(item),
517
+ title: item.title,
518
+ totalDiscount: "0",
519
+ vendor,
520
+ discountedPriceSet: money(item.price),
521
+ linePriceSet: money(item.price * quantity),
522
+ originalLinePriceSet: money(item.price * quantity),
523
+ priceSet: money(item.price),
524
+ totalDiscountSet: money(0),
525
+ parentRelationship: null
526
+ };
527
+ }),
528
+ note: "",
529
+ updatedAt: at(cartCreated.getTime() + faker.number.int({
530
+ min: 0,
531
+ max: hour
532
+ })),
533
+ createdAt: cartCreated
534
+ });
535
+ }
536
+ const subscribedAt = subscribed ? created : null;
537
+ rows.customers.push({
538
+ id: customerId,
539
+ legacyResourceId: String(customerNumber),
540
+ firstName,
541
+ lastName,
542
+ displayName: `${firstName} ${lastName}`,
543
+ email,
544
+ emailMarketingState: subscribed ? "SUBSCRIBED" : "NOT_SUBSCRIBED",
545
+ emailMarketingOptInLevel: subscribed ? "SINGLE_OPT_IN" : null,
546
+ emailMarketingUpdatedAt: subscribedAt,
547
+ phone,
548
+ smsMarketingState: "NOT_SUBSCRIBED",
549
+ smsMarketingOptInLevel: null,
550
+ smsMarketingUpdatedAt: null,
551
+ smsMarketingCollectedFrom: null,
552
+ note: "",
553
+ state: orderCount > 0 ? "ENABLED" : "DISABLED",
554
+ verifiedEmail: true,
555
+ taxExempt: false,
556
+ taxExemptions: [],
557
+ tags: orderCount >= 3 ? ["repeat"] : [],
558
+ locale: "en",
559
+ numberOfOrders: orderCount,
560
+ amountSpent: {
561
+ amount: amount(spent),
562
+ currencyCode: "USD"
563
+ },
564
+ lastOrderId: orderCount > 0 ? gid("Order", 56e11 + index * 10 + orderCount - 1) : "",
565
+ productSubscriberStatus: "NEVER_SUBSCRIBED",
566
+ dataSaleOptOut: false,
567
+ defaultAddressId: addressId,
568
+ addresses: [{
569
+ id: addressId,
570
+ ...address
571
+ }],
572
+ createdAt: created,
573
+ updatedAt: lastChange
574
+ });
575
+ return rows;
576
+ };
577
+ //#endregion
578
+ //#region src/demo/setup.ts
579
+ /** The product catalog, written once before any customer. */
580
+ const setupRows = ({ now }) => {
581
+ const created = /* @__PURE__ */ new Date(now.getTime() - 800 * day);
582
+ return { products: catalog.map((item, p) => ({
583
+ id: gid("Product", productNumber(p)),
584
+ legacyResourceId: String(productNumber(p)),
585
+ title: item.title,
586
+ handle: handleOf(item),
587
+ descriptionHtml: `<p>The ${item.title.toLowerCase()} from ${vendor}.</p>`,
588
+ productType: item.type,
589
+ vendor,
590
+ status: "ACTIVE",
591
+ tags: [item.type.toLowerCase()],
592
+ createdAt: created,
593
+ updatedAt: created,
594
+ publishedAt: created,
595
+ templateSuffix: "",
596
+ featuredMedia: { image: {
597
+ url: `https://demo.example.com/images/${handleOf(item)}.jpg`,
598
+ altText: item.title
599
+ } },
600
+ options: [{
601
+ id: gid("ProductOption", productNumber(p)),
602
+ name: item.option?.name ?? "Title",
603
+ position: 1,
604
+ values: valuesOf(item)
605
+ }],
606
+ variants: valuesOf(item).map((value, v) => ({
607
+ id: gid("ProductVariant", variantNumber(p, v)),
608
+ legacyResourceId: String(variantNumber(p, v)),
609
+ title: value,
610
+ sku: `NW-${handleOf(item).toUpperCase()}-${value.replace("/", "").toUpperCase()}`,
611
+ barcode: null,
612
+ price: amount(item.price),
613
+ compareAtPrice: null,
614
+ inventoryPolicy: "DENY",
615
+ taxable: !isGiftCard(item),
616
+ createdAt: created,
617
+ updatedAt: created
618
+ }))
619
+ })) };
620
+ };
621
+ //#endregion
622
+ //#region src/demo/index.ts
623
+ const demo = Demo.define({
624
+ name: "producer-shopify",
625
+ setup: {
626
+ tables: [Demo.table({
627
+ name: "products",
628
+ rowSchema: ProductSchema,
629
+ version: "updatedAt"
630
+ })],
631
+ rows: setupRows
632
+ },
633
+ group: {
634
+ tables: [
635
+ Demo.table({
636
+ name: "customers",
637
+ rowSchema: CustomerSchema,
638
+ version: "updatedAt"
639
+ }),
640
+ Demo.table({
641
+ name: "orders",
642
+ rowSchema: OrderSchema,
643
+ version: "updatedAt"
644
+ }),
645
+ Demo.table({
646
+ name: "refunds",
647
+ rowSchema: RefundSchema,
648
+ version: "processedAt"
649
+ }),
650
+ Demo.table({
651
+ name: "carts",
652
+ rowSchema: CartSchema,
653
+ version: "updatedAt"
654
+ })
655
+ ],
656
+ rows: customerRows
657
+ }
658
+ });
659
+ const demoCommand = ConnectorApp.makeDemoCommand(demo).pipe(Command.provide(RuntimeConfig.layerHosted()));
660
+ //#endregion
661
+ //#region src/sandbox.ts
662
+ const ConnectorLayer$1 = layerConfig(ShopifyConfigDef.config);
663
+ const TelemetryLayer$1 = Layer.mergeAll(Telemetry.layerOtlp({ redactedHeaders: ["x-shopify-access-token"] }), Telemetry.layerMetricsConsoleDump());
664
+ const sandboxCommand = Command.make("sandbox", {}, () => Effect.gen(function* () {
665
+ const port = yield* RuntimeConfig.httpPort;
666
+ const entrypoint = yield* ShopifyConnector;
667
+ return yield* ConnectorApp.start(entrypoint, { port });
668
+ }).pipe(Effect.annotateLogs({ component: "producer-shopify" }), Effect.provide(Layer.mergeAll(StateStore.layerMemory, Ingestor.layerConsole, ConnectorLayer$1, Logger.layer([Logger.consolePretty()]), TelemetryLayer$1)))).pipe(Command.withDescription("Run the connector locally and log ingested data"));
669
+ //#endregion
670
+ //#region src/start.ts
671
+ const ConnectorLayer = layerConfig(ShopifyConfigDef.config);
672
+ const TelemetryLayer = Telemetry.layerOtlp({ redactedHeaders: ["x-shopify-access-token"] });
673
+ const PostgresLayer = PgClient.layerConfig({
674
+ url: Config.schema(Schema.Redacted(Schema.NonEmptyString), RuntimeConfig.PlatformRuntimeKey.postgresConnectionString),
675
+ maxConnections: Config.succeed(2),
676
+ connectTimeout: Config.succeed("5 seconds"),
677
+ applicationName: Config.succeed("airfoil-producer-shopify")
678
+ });
679
+ const StateStoreLayer = StateStore.layerSql().pipe(Layer.provide(PostgresLayer));
680
+ const startCommand = Command.make("start", {}, () => Effect.gen(function* () {
681
+ const port = yield* RuntimeConfig.httpPort;
682
+ const entrypoint = yield* ShopifyConnector;
683
+ return yield* ConnectorApp.start(entrypoint, { port }).pipe(Effect.provide(Ingestor.layerArrowFlightConfig(entrypoint)));
684
+ }).pipe(Effect.annotateLogs({ component: "producer-shopify" }), Effect.provide(Layer.mergeAll(StateStoreLayer, ConnectorLayer, Logger.layer([Logger.consolePretty()]), TelemetryLayer)), Effect.provide(RuntimeConfig.layerHosted()))).pipe(Command.withDescription("Run the connector"));
685
+ //#endregion
686
+ //#region src/main.ts
687
+ const BootstrapLayer = Layer.mergeAll(FetchHttpClient.layer, NodeServices.layer);
688
+ const program = Command.make("producer-shopify", {}, () => Effect.void).pipe(Command.withSubcommands([
689
+ setupCommand,
690
+ startCommand,
691
+ sandboxCommand,
692
+ createTableCommand,
693
+ demoCommand
694
+ ]));
695
+ const cli = Command.run(program, { version });
696
+ NodeRuntime.runMain(cli.pipe(Effect.provide(BootstrapLayer), Effect.scoped));
697
+ //#endregion
698
+ export {};
699
+
700
+ //# sourceMappingURL=main.mjs.map