@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
@@ -0,0 +1,2472 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
+ import { ShopifyConfigDef, manifest } from "./manifest.mjs";
3
+ import * as Schema$1 from "effect/Schema";
4
+ import { Config, Context, Data, Duration, Effect, Layer, Option, Predicate, Redacted, Schedule, Schema, SchemaTransformation, Stream } from "effect";
5
+ import { Auth, Connector, ConnectorError, Cursor, Fetch, Iceberg, Metrics, Resource, Telemetry, Webhook } from "@useairfoil/connector-kit";
6
+ import { HttpClient, HttpClientRequest, HttpClientResponse, HttpServerResponse } from "effect/http";
7
+ import { createHmac, timingSafeEqual } from "node:crypto";
8
+ //#region src/resources/shared.ts
9
+ const PageInfoSchema = Schema$1.Struct({
10
+ hasNextPage: Schema$1.Boolean,
11
+ endCursor: Schema$1.NullOr(Schema$1.String)
12
+ });
13
+ const gid = (type, id) => `gid://shopify/${type}/${id}`;
14
+ const normalizeAmount = (amount) => amount.includes(".") ? amount.replace(/0+$/, "").replace(/\.$/, "") : amount;
15
+ const emptyText = (value) => value ?? "";
16
+ const splitTags = (value) => value.split(",").map((tag) => tag.trim()).filter((tag) => tag.length > 0);
17
+ const moneyBag = Schema$1.Struct({
18
+ shopMoney: Schema$1.Struct({
19
+ amount: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Amount in the shop currency." })),
20
+ currencyCode: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Shop currency code." }))
21
+ }).pipe(Schema$1.annotateKey({ description: "Amount in the shop currency." })),
22
+ presentmentMoney: Schema$1.Struct({
23
+ amount: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Amount in the customer currency." })),
24
+ currencyCode: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Customer currency code." }))
25
+ }).pipe(Schema$1.annotateKey({ description: "Amount in the customer currency." }))
26
+ });
27
+ const address = Schema$1.Struct({
28
+ firstName: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "First name." })),
29
+ lastName: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Last name." })),
30
+ name: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Full name." })),
31
+ company: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Company name." })),
32
+ address1: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "First address line." })),
33
+ address2: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Second address line." })),
34
+ city: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "City." })),
35
+ province: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Province or state." })),
36
+ provinceCode: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Province or state code." })),
37
+ country: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Country." })),
38
+ countryCode: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Two-letter country code." })),
39
+ zip: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Postal code." })),
40
+ phone: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Phone number." })),
41
+ latitude: Schema$1.NullOr(Schema$1.Finite).pipe(Schema$1.annotateKey({ description: "Latitude." })),
42
+ longitude: Schema$1.NullOr(Schema$1.Finite).pipe(Schema$1.annotateKey({ description: "Longitude." }))
43
+ });
44
+ const attributes = Schema$1.Array(Schema$1.Struct({
45
+ key: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Attribute name." })),
46
+ value: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Attribute value." }))
47
+ }));
48
+ const taxLines = Schema$1.Array(Schema$1.Struct({
49
+ title: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Tax name." })),
50
+ rate: Schema$1.NullOr(Schema$1.Finite).pipe(Schema$1.annotateKey({ description: "Tax rate as a fraction." })),
51
+ priceSet: moneyBag.pipe(Schema$1.annotateKey({ description: "Tax amount." }))
52
+ }));
53
+ const discountAllocations = Schema$1.Array(Schema$1.Struct({
54
+ discountApplicationIndex: Schema$1.Int.pipe(Schema$1.annotateKey({ description: "Index of the order discount application." })),
55
+ amountSet: moneyBag.pipe(Schema$1.annotateKey({ description: "Allocated discount amount." }))
56
+ }));
57
+ const RestMoneyBagSchema = Schema$1.Struct({
58
+ shop_money: Schema$1.Struct({
59
+ amount: Schema$1.String,
60
+ currency_code: Schema$1.String
61
+ }),
62
+ presentment_money: Schema$1.Struct({
63
+ amount: Schema$1.String,
64
+ currency_code: Schema$1.String
65
+ })
66
+ });
67
+ const nullableText = Schema$1.NullOr(Schema$1.String);
68
+ const RestAddressSchema = Schema$1.Struct({
69
+ first_name: nullableText,
70
+ last_name: nullableText,
71
+ name: nullableText,
72
+ company: nullableText,
73
+ address1: nullableText,
74
+ address2: nullableText,
75
+ city: nullableText,
76
+ province: nullableText,
77
+ province_code: nullableText,
78
+ country: nullableText,
79
+ country_code: nullableText,
80
+ zip: nullableText,
81
+ phone: nullableText,
82
+ latitude: Schema$1.NullOr(Schema$1.Number),
83
+ longitude: Schema$1.NullOr(Schema$1.Number)
84
+ });
85
+ const RestAttributeSchema = Schema$1.Struct({
86
+ name: Schema$1.String,
87
+ value: Schema$1.NullOr(Schema$1.String)
88
+ });
89
+ const RestTaxLineSchema = Schema$1.Struct({
90
+ title: Schema$1.String,
91
+ rate: Schema$1.NullOr(Schema$1.Number),
92
+ price_set: RestMoneyBagSchema
93
+ });
94
+ const RestDiscountAllocationSchema = Schema$1.Struct({
95
+ discount_application_index: Schema$1.Int,
96
+ amount_set: RestMoneyBagSchema
97
+ });
98
+ const fromRest = {
99
+ money: (bag) => ({
100
+ shopMoney: {
101
+ amount: normalizeAmount(bag.shop_money.amount),
102
+ currencyCode: bag.shop_money.currency_code
103
+ },
104
+ presentmentMoney: {
105
+ amount: normalizeAmount(bag.presentment_money.amount),
106
+ currencyCode: bag.presentment_money.currency_code
107
+ }
108
+ }),
109
+ address: (value) => ({
110
+ firstName: value.first_name,
111
+ lastName: value.last_name,
112
+ name: value.name,
113
+ company: value.company,
114
+ address1: value.address1,
115
+ address2: value.address2,
116
+ city: value.city,
117
+ province: value.province,
118
+ provinceCode: value.province_code,
119
+ country: value.country,
120
+ countryCode: value.country_code,
121
+ zip: value.zip,
122
+ phone: value.phone,
123
+ latitude: value.latitude,
124
+ longitude: value.longitude
125
+ }),
126
+ attribute: (value) => ({
127
+ key: value.name,
128
+ value: value.value
129
+ }),
130
+ taxLine: (value) => ({
131
+ title: value.title,
132
+ rate: value.rate,
133
+ priceSet: fromRest.money(value.price_set)
134
+ }),
135
+ discountAllocation: (value) => ({
136
+ discountApplicationIndex: value.discount_application_index,
137
+ amountSet: fromRest.money(value.amount_set)
138
+ })
139
+ };
140
+ const MoneyBagFields = `shopMoney { amount currencyCode } presentmentMoney { amount currencyCode }`;
141
+ const AddressFields = `firstName lastName name company address1 address2 city province provinceCode country countryCodeV2 zip phone latitude longitude`;
142
+ const TaxLineFields = `title rate priceSet { ${MoneyBagFields} }`;
143
+ const DiscountAllocationFields = `allocatedAmountSet { ${MoneyBagFields} } discountApplication { index }`;
144
+ const GraphQLMoneyBagSchema = Schema$1.Struct({
145
+ shopMoney: Schema$1.Struct({
146
+ amount: Schema$1.String,
147
+ currencyCode: Schema$1.String
148
+ }),
149
+ presentmentMoney: Schema$1.Struct({
150
+ amount: Schema$1.String,
151
+ currencyCode: Schema$1.String
152
+ })
153
+ });
154
+ const GraphQLAddressSchema = Schema$1.Struct({
155
+ firstName: Schema$1.NullOr(Schema$1.String),
156
+ lastName: Schema$1.NullOr(Schema$1.String),
157
+ name: Schema$1.NullOr(Schema$1.String),
158
+ company: Schema$1.NullOr(Schema$1.String),
159
+ address1: Schema$1.NullOr(Schema$1.String),
160
+ address2: Schema$1.NullOr(Schema$1.String),
161
+ city: Schema$1.NullOr(Schema$1.String),
162
+ province: Schema$1.NullOr(Schema$1.String),
163
+ provinceCode: Schema$1.NullOr(Schema$1.String),
164
+ country: Schema$1.NullOr(Schema$1.String),
165
+ countryCodeV2: Schema$1.NullOr(Schema$1.String),
166
+ zip: Schema$1.NullOr(Schema$1.String),
167
+ phone: Schema$1.NullOr(Schema$1.String),
168
+ latitude: Schema$1.NullOr(Schema$1.Number),
169
+ longitude: Schema$1.NullOr(Schema$1.Number)
170
+ });
171
+ const GraphQLAttributeSchema = Schema$1.Struct({
172
+ key: Schema$1.String,
173
+ value: Schema$1.NullOr(Schema$1.String)
174
+ });
175
+ const GraphQLTaxLineSchema = Schema$1.Struct({
176
+ title: Schema$1.String,
177
+ rate: Schema$1.NullOr(Schema$1.Number),
178
+ priceSet: GraphQLMoneyBagSchema
179
+ });
180
+ const GraphQLDiscountAllocationSchema = Schema$1.Struct({
181
+ allocatedAmountSet: GraphQLMoneyBagSchema,
182
+ discountApplication: Schema$1.Struct({ index: Schema$1.Int })
183
+ });
184
+ const connection = (node) => Schema$1.Struct({
185
+ nodes: Schema$1.Array(node),
186
+ pageInfo: PageInfoSchema
187
+ });
188
+ const fromGraphQL = {
189
+ money: (bag) => ({
190
+ shopMoney: {
191
+ amount: normalizeAmount(bag.shopMoney.amount),
192
+ currencyCode: bag.shopMoney.currencyCode
193
+ },
194
+ presentmentMoney: {
195
+ amount: normalizeAmount(bag.presentmentMoney.amount),
196
+ currencyCode: bag.presentmentMoney.currencyCode
197
+ }
198
+ }),
199
+ address: ({ countryCodeV2, ...value }) => ({
200
+ ...value,
201
+ countryCode: countryCodeV2
202
+ }),
203
+ taxLine: (value) => ({
204
+ title: value.title,
205
+ rate: value.rate,
206
+ priceSet: fromGraphQL.money(value.priceSet)
207
+ }),
208
+ discountAllocation: (value) => ({
209
+ discountApplicationIndex: value.discountApplication.index,
210
+ amountSet: fromGraphQL.money(value.allocatedAmountSet)
211
+ })
212
+ };
213
+ const upper = (literals) => Schema$1.String.pipe(Schema$1.decode(SchemaTransformation.toUpperCase()), Schema$1.decodeTo(literals));
214
+ const PageInfoFields = `pageInfo { hasNextPage endCursor }`;
215
+ const idRef = Schema$1.NullOr(Schema$1.Struct({ id: Schema$1.String }));
216
+ const pageQuery = (name, connection, fields) => `#graphql
217
+ query ${name}($first: Int!, $after: String) {
218
+ ${connection}(first: $first, after: $after) {
219
+ nodes {
220
+ ${fields}
221
+ }
222
+ pageInfo {
223
+ hasNextPage
224
+ endCursor
225
+ }
226
+ }
227
+ }
228
+ `;
229
+ //#endregion
230
+ //#region src/resources/carts/webhook.ts
231
+ const JsonStringSchema = Schema$1.flip(Schema$1.fromJsonString(Schema$1.Unknown));
232
+ const CartWebhookLineItemSchema = Schema$1.Struct({
233
+ id: Schema$1.Number,
234
+ properties: Schema$1.Union([Schema$1.Null, JsonStringSchema]),
235
+ quantity: Schema$1.Int,
236
+ variant_id: Schema$1.Number,
237
+ key: Schema$1.String,
238
+ discounted_price: Schema$1.String,
239
+ discounts: JsonStringSchema,
240
+ gift_card: Schema$1.Boolean,
241
+ grams: Schema$1.Int,
242
+ line_price: Schema$1.String,
243
+ original_line_price: Schema$1.String,
244
+ original_price: Schema$1.String,
245
+ price: Schema$1.String,
246
+ product_id: Schema$1.Number,
247
+ sku: Schema$1.NullOr(Schema$1.String),
248
+ taxable: Schema$1.Boolean,
249
+ title: Schema$1.String,
250
+ total_discount: Schema$1.String,
251
+ vendor: Schema$1.String,
252
+ discounted_price_set: RestMoneyBagSchema,
253
+ line_price_set: RestMoneyBagSchema,
254
+ original_line_price_set: RestMoneyBagSchema,
255
+ price_set: RestMoneyBagSchema,
256
+ total_discount_set: RestMoneyBagSchema,
257
+ parent_relationship: Schema$1.Union([Schema$1.Null, JsonStringSchema])
258
+ });
259
+ const CartWebhookPayloadSchema = Schema$1.Struct({
260
+ id: Schema$1.String,
261
+ token: Schema$1.String,
262
+ line_items: Schema$1.Array(CartWebhookLineItemSchema),
263
+ note: Schema$1.NullOr(Schema$1.String),
264
+ updated_at: Schema$1.DateFromString,
265
+ created_at: Schema$1.DateFromString
266
+ });
267
+ const CartWebhookEventSchema = Schema$1.Struct({
268
+ id: Schema$1.String,
269
+ token: Schema$1.String,
270
+ line_items: Schema$1.Array(Schema$1.toType(CartWebhookLineItemSchema)),
271
+ note: Schema$1.NullOr(Schema$1.String),
272
+ updated_at: Schema$1.Date,
273
+ created_at: Schema$1.Date,
274
+ topic: Schema$1.Literals(["carts/create", "carts/update"])
275
+ });
276
+ const normalizeCartLineItem = (item) => ({
277
+ id: String(item.id),
278
+ properties: item.properties,
279
+ quantity: item.quantity,
280
+ variantId: gid("ProductVariant", item.variant_id),
281
+ key: item.key,
282
+ discountedPrice: normalizeAmount(item.discounted_price),
283
+ discounts: item.discounts,
284
+ giftCard: item.gift_card,
285
+ grams: item.grams,
286
+ linePrice: normalizeAmount(item.line_price),
287
+ originalLinePrice: normalizeAmount(item.original_line_price),
288
+ originalPrice: normalizeAmount(item.original_price),
289
+ price: normalizeAmount(item.price),
290
+ productId: gid("Product", item.product_id),
291
+ sku: item.sku,
292
+ taxable: item.taxable,
293
+ title: item.title,
294
+ totalDiscount: normalizeAmount(item.total_discount),
295
+ vendor: item.vendor,
296
+ discountedPriceSet: fromRest.money(item.discounted_price_set),
297
+ linePriceSet: fromRest.money(item.line_price_set),
298
+ originalLinePriceSet: fromRest.money(item.original_line_price_set),
299
+ priceSet: fromRest.money(item.price_set),
300
+ totalDiscountSet: fromRest.money(item.total_discount_set),
301
+ parentRelationship: item.parent_relationship
302
+ });
303
+ const fromCartWebhook = (payload) => ({
304
+ id: payload.id,
305
+ token: payload.token,
306
+ topic: payload.topic,
307
+ lineItems: payload.line_items.map(normalizeCartLineItem),
308
+ note: payload.note ?? "",
309
+ updatedAt: payload.updated_at,
310
+ createdAt: payload.created_at
311
+ });
312
+ //#endregion
313
+ //#region src/resources/products/row.ts
314
+ const ProductStatusSchema = Schema$1.Literals([
315
+ "ACTIVE",
316
+ "ARCHIVED",
317
+ "DRAFT",
318
+ "UNLISTED"
319
+ ]);
320
+ const ProductVariantInventoryPolicySchema = Schema$1.Literals(["CONTINUE", "DENY"]);
321
+ const ProductImageSchema = Schema$1.Struct({
322
+ url: Schema$1.String.pipe(Schema$1.annotateKey({ description: "URL of the image." })),
323
+ altText: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Alternative text for the image." }))
324
+ });
325
+ const ProductFeaturedMediaSchema = Schema$1.Struct({ image: Schema$1.NullOr(ProductImageSchema).pipe(Schema$1.annotateKey({ description: "Image for the featured media." })) });
326
+ const ProductOptionSchema = Schema$1.Struct({
327
+ id: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Unique product option identifier." })),
328
+ name: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Name of the product option." })),
329
+ position: Schema$1.Int.pipe(Schema$1.annotateKey({ description: "Position of the option on the product." })),
330
+ values: Schema$1.Array(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Values available for the option." }))
331
+ });
332
+ const ProductVariantSchema = Schema$1.Struct({
333
+ id: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Unique product variant identifier." })),
334
+ legacyResourceId: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Numeric variant identifier stored as text." })),
335
+ title: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Display title of the variant." })),
336
+ sku: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Stock keeping unit for the variant." })),
337
+ barcode: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Barcode for the variant." })),
338
+ price: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Price of the variant." })),
339
+ compareAtPrice: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Original price used for comparison." })),
340
+ inventoryPolicy: ProductVariantInventoryPolicySchema.pipe(Schema$1.annotateKey({ description: "Behavior when the variant is out of stock." })),
341
+ taxable: Schema$1.Boolean.pipe(Schema$1.annotateKey({ description: "Whether the variant is taxable." })),
342
+ createdAt: Schema$1.Date.pipe(Schema$1.annotateKey({ description: "Time when the variant was created." })),
343
+ updatedAt: Schema$1.Date.pipe(Schema$1.annotateKey({ description: "Time when the variant was last changed." }))
344
+ });
345
+ const ProductSchema = Schema$1.Struct({
346
+ id: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Unique product identifier." })),
347
+ legacyResourceId: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Numeric product identifier stored as text." })),
348
+ title: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Title of the product." })),
349
+ handle: Schema$1.String.pipe(Schema$1.annotateKey({ description: "URL handle for the product." })),
350
+ descriptionHtml: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Product description as HTML." })),
351
+ productType: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Merchant-defined product type." })),
352
+ vendor: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Vendor of the product." })),
353
+ status: ProductStatusSchema.pipe(Schema$1.annotateKey({ description: "Current product status." })),
354
+ tags: Schema$1.Array(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Tags added to the product." })),
355
+ createdAt: Schema$1.Date.pipe(Schema$1.annotateKey({ description: "Time when the product was created." })),
356
+ updatedAt: Schema$1.Date.pipe(Schema$1.annotateKey({ description: "Time when the product was last changed." })),
357
+ publishedAt: Schema$1.NullOr(Schema$1.Date).pipe(Schema$1.annotateKey({ description: "Time when the product was published." })),
358
+ templateSuffix: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Theme template suffix used by the product." })),
359
+ featuredMedia: Schema$1.NullOr(ProductFeaturedMediaSchema).pipe(Schema$1.annotateKey({ description: "Featured media for the product." })),
360
+ options: Schema$1.Array(ProductOptionSchema).pipe(Schema$1.annotateKey({ description: "Options for the product." })),
361
+ variants: Schema$1.Array(ProductVariantSchema).pipe(Schema$1.annotateKey({ description: "Variants of the product." })),
362
+ _deleted: Schema$1.optional(Schema$1.Boolean).pipe(Schema$1.annotateKey({ description: "Whether the product was deleted." }))
363
+ }).annotate({ description: "Products in a Shopify store." }).pipe(Iceberg.identifier("id"));
364
+ //#endregion
365
+ //#region src/resources/products/webhook.ts
366
+ const ProductWebhookImageSchema = Schema$1.Struct({
367
+ src: Schema$1.String,
368
+ alt: Schema$1.NullOr(Schema$1.String)
369
+ });
370
+ const ProductWebhookOptionSchema = Schema$1.Struct({
371
+ id: Schema$1.Number,
372
+ name: Schema$1.String,
373
+ position: Schema$1.Int,
374
+ values: Schema$1.Array(Schema$1.String)
375
+ });
376
+ const ProductWebhookVariantSchema = Schema$1.Struct({
377
+ admin_graphql_api_id: Schema$1.String,
378
+ id: Schema$1.Number,
379
+ title: Schema$1.String,
380
+ price: Schema$1.String,
381
+ inventory_policy: upper(ProductVariantInventoryPolicySchema),
382
+ compare_at_price: Schema$1.NullOr(Schema$1.String),
383
+ created_at: Schema$1.DateFromString,
384
+ updated_at: Schema$1.DateFromString,
385
+ taxable: Schema$1.Boolean,
386
+ barcode: Schema$1.NullOr(Schema$1.String),
387
+ sku: Schema$1.NullOr(Schema$1.String)
388
+ });
389
+ const ProductWebhookVariantGidSchema = Schema$1.Struct({
390
+ admin_graphql_api_id: Schema$1.String,
391
+ updated_at: Schema$1.DateFromString
392
+ });
393
+ const ProductWebhookPayloadSchema = Schema$1.Struct({
394
+ id: Schema$1.Number,
395
+ admin_graphql_api_id: Schema$1.String,
396
+ body_html: Schema$1.NullOr(Schema$1.String),
397
+ created_at: Schema$1.DateFromString,
398
+ handle: Schema$1.String,
399
+ image: Schema$1.optional(Schema$1.NullOr(ProductWebhookImageSchema)),
400
+ options: Schema$1.Array(ProductWebhookOptionSchema),
401
+ product_type: Schema$1.String,
402
+ published_at: Schema$1.NullOr(Schema$1.DateFromString),
403
+ status: upper(ProductStatusSchema),
404
+ tags: Schema$1.String,
405
+ template_suffix: Schema$1.NullOr(Schema$1.String),
406
+ title: Schema$1.String,
407
+ updated_at: Schema$1.DateFromString,
408
+ variants: Schema$1.Array(ProductWebhookVariantSchema),
409
+ variant_gids: Schema$1.Array(ProductWebhookVariantGidSchema),
410
+ vendor: Schema$1.String
411
+ });
412
+ const ProductDeleteWebhookPayloadSchema = Schema$1.Struct({ id: Schema$1.Number });
413
+ const ProductEventSchema = Schema$1.Union([Schema$1.Struct({
414
+ _tag: Schema$1.Literal("upsert"),
415
+ payload: Schema$1.toType(ProductWebhookPayloadSchema),
416
+ triggeredAt: Schema$1.Date
417
+ }), Schema$1.Struct({
418
+ _tag: Schema$1.Literal("delete"),
419
+ id: Schema$1.String,
420
+ version: Schema$1.Date
421
+ })]);
422
+ const normalizeProductOption = (option) => ({
423
+ id: gid("ProductOption", option.id),
424
+ name: option.name,
425
+ position: option.position,
426
+ values: option.values
427
+ });
428
+ const normalizeProductVariant = (variant) => ({
429
+ id: variant.admin_graphql_api_id,
430
+ legacyResourceId: String(variant.id),
431
+ title: variant.title,
432
+ sku: variant.sku,
433
+ barcode: variant.barcode,
434
+ price: variant.price,
435
+ compareAtPrice: variant.compare_at_price,
436
+ inventoryPolicy: variant.inventory_policy,
437
+ taxable: variant.taxable,
438
+ createdAt: variant.created_at,
439
+ updatedAt: variant.updated_at
440
+ });
441
+ const normalizeProductFeaturedMedia = (image) => image === null || image === void 0 ? null : { image: {
442
+ url: image.src,
443
+ altText: image.alt
444
+ } };
445
+ const fromProductWebhook = (payload) => ({
446
+ id: payload.admin_graphql_api_id,
447
+ legacyResourceId: String(payload.id),
448
+ title: payload.title,
449
+ handle: payload.handle,
450
+ descriptionHtml: payload.body_html ?? "",
451
+ productType: payload.product_type,
452
+ vendor: payload.vendor,
453
+ status: payload.status,
454
+ tags: splitTags(payload.tags),
455
+ createdAt: payload.created_at,
456
+ updatedAt: payload.updated_at,
457
+ publishedAt: payload.published_at,
458
+ templateSuffix: payload.template_suffix ?? "",
459
+ featuredMedia: normalizeProductFeaturedMedia(payload.image),
460
+ options: payload.options.map(normalizeProductOption),
461
+ variants: payload.variants.map(normalizeProductVariant)
462
+ });
463
+ //#endregion
464
+ //#region src/resources/customers/row.ts
465
+ const CustomerStateSchema = Schema$1.Literals([
466
+ "DECLINED",
467
+ "DISABLED",
468
+ "ENABLED",
469
+ "INVITED"
470
+ ]);
471
+ const EmailMarketingStateSchema = Schema$1.Literals([
472
+ "INVALID",
473
+ "NOT_SUBSCRIBED",
474
+ "PENDING",
475
+ "REDACTED",
476
+ "SUBSCRIBED",
477
+ "UNSUBSCRIBED"
478
+ ]);
479
+ const SmsMarketingStateSchema = Schema$1.Literals([
480
+ "NOT_SUBSCRIBED",
481
+ "PENDING",
482
+ "SUBSCRIBED",
483
+ "UNSUBSCRIBED",
484
+ "REDACTED"
485
+ ]);
486
+ const MarketingOptInLevelSchema = Schema$1.Literals([
487
+ "SINGLE_OPT_IN",
488
+ "CONFIRMED_OPT_IN",
489
+ "UNKNOWN"
490
+ ]);
491
+ const ConsentCollectedFromSchema = Schema$1.Literals(["SHOPIFY", "OTHER"]);
492
+ const ProductSubscriberStatusSchema = Schema$1.Literals([
493
+ "ACTIVE",
494
+ "CANCELLED",
495
+ "EXPIRED",
496
+ "FAILED",
497
+ "NEVER_SUBSCRIBED",
498
+ "PAUSED"
499
+ ]);
500
+ const CustomerAddressSchema = Schema$1.Struct({
501
+ id: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Unique address identifier." })),
502
+ ...address.fields
503
+ });
504
+ const CustomerSchema = Schema$1.Struct({
505
+ id: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Unique customer identifier." })),
506
+ legacyResourceId: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Numeric customer identifier stored as text." })),
507
+ firstName: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "First name." })),
508
+ lastName: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Last name." })),
509
+ displayName: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Full name shown in Shopify." })),
510
+ email: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Default email address." })),
511
+ emailMarketingState: Schema$1.NullOr(EmailMarketingStateSchema).pipe(Schema$1.annotateKey({ description: "Email marketing consent state." })),
512
+ emailMarketingOptInLevel: Schema$1.NullOr(MarketingOptInLevelSchema).pipe(Schema$1.annotateKey({ description: "Email marketing opt-in level." })),
513
+ emailMarketingUpdatedAt: Schema$1.NullOr(Schema$1.Date).pipe(Schema$1.annotateKey({ description: "Time when email marketing consent last changed." })),
514
+ phone: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Default phone number." })),
515
+ smsMarketingState: Schema$1.NullOr(SmsMarketingStateSchema).pipe(Schema$1.annotateKey({ description: "SMS marketing consent state." })),
516
+ smsMarketingOptInLevel: Schema$1.NullOr(MarketingOptInLevelSchema).pipe(Schema$1.annotateKey({ description: "SMS marketing opt-in level." })),
517
+ smsMarketingUpdatedAt: Schema$1.NullOr(Schema$1.Date).pipe(Schema$1.annotateKey({ description: "Time when SMS marketing consent last changed." })),
518
+ smsMarketingCollectedFrom: Schema$1.NullOr(ConsentCollectedFromSchema).pipe(Schema$1.annotateKey({ description: "Where SMS marketing consent was collected." })),
519
+ note: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Merchant note about the customer." })),
520
+ state: CustomerStateSchema.pipe(Schema$1.annotateKey({ description: "Customer account state." })),
521
+ verifiedEmail: Schema$1.Boolean.pipe(Schema$1.annotateKey({ description: "Whether the email address is verified." })),
522
+ taxExempt: Schema$1.Boolean.pipe(Schema$1.annotateKey({ description: "Whether the customer is exempt from tax." })),
523
+ taxExemptions: Schema$1.Array(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Tax exemptions that apply to the customer." })),
524
+ tags: Schema$1.Array(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Tags added to the customer." })),
525
+ locale: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Customer language." })),
526
+ numberOfOrders: Schema$1.Int.pipe(Schema$1.annotateKey({ description: "Number of orders the customer placed." })),
527
+ amountSpent: Schema$1.Struct({
528
+ amount: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Amount spent." })),
529
+ currencyCode: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Shop currency code." }))
530
+ }).pipe(Schema$1.annotateKey({ description: "Total amount spent in the shop currency." })),
531
+ lastOrderId: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Most recent order identifier." })),
532
+ productSubscriberStatus: Schema$1.NullOr(ProductSubscriberStatusSchema).pipe(Schema$1.annotateKey({ description: "Subscription status for products." })),
533
+ dataSaleOptOut: Schema$1.NullOr(Schema$1.Boolean).pipe(Schema$1.annotateKey({ description: "Whether the customer opted out of data sale." })),
534
+ defaultAddressId: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Default address identifier." })),
535
+ addresses: Schema$1.Array(CustomerAddressSchema).pipe(Schema$1.annotateKey({ description: "Saved addresses." })),
536
+ createdAt: Schema$1.Date.pipe(Schema$1.annotateKey({ description: "Time when the customer was created." })),
537
+ updatedAt: Schema$1.Date.pipe(Schema$1.annotateKey({ description: "Time when the customer was last changed." })),
538
+ _deleted: Schema$1.optional(Schema$1.Boolean).pipe(Schema$1.annotateKey({ description: "Whether the customer was deleted." }))
539
+ }).annotate({ description: "Customers in a Shopify store." }).pipe(Iceberg.identifier("id"));
540
+ //#endregion
541
+ //#region src/resources/customers/graphql.ts
542
+ const CustomerAddressNodeFields = `id ${AddressFields}`;
543
+ const CustomerFields = `
544
+ id
545
+ legacyResourceId
546
+ firstName
547
+ lastName
548
+ displayName
549
+ note
550
+ state
551
+ verifiedEmail
552
+ taxExempt
553
+ taxExemptions
554
+ tags
555
+ locale
556
+ numberOfOrders
557
+ amountSpent { amount currencyCode }
558
+ lastOrder { id }
559
+ productSubscriberStatus
560
+ dataSaleOptOut
561
+ defaultEmailAddress { emailAddress marketingState marketingOptInLevel marketingUpdatedAt }
562
+ defaultPhoneNumber { phoneNumber }
563
+ smsMarketingConsent { marketingState marketingOptInLevel consentUpdatedAt consentCollectedFrom }
564
+ defaultAddress { id }
565
+ addressesV2(first: 25) {
566
+ nodes { ${CustomerAddressNodeFields} }
567
+ pageInfo { hasNextPage endCursor }
568
+ }
569
+ createdAt
570
+ updatedAt
571
+ `;
572
+ const CustomerAddressesQuery = `#graphql
573
+ query AirfoilCustomerAddresses($id: ID!, $first: Int!, $after: String) {
574
+ node: customer(id: $id) {
575
+ connection: addressesV2(first: $first, after: $after) {
576
+ nodes { ${CustomerAddressNodeFields} }
577
+ pageInfo { hasNextPage endCursor }
578
+ }
579
+ }
580
+ }
581
+ `;
582
+ const CustomerByIdQuery = `#graphql
583
+ query AirfoilCustomerById($id: ID!) {
584
+ customer(id: $id) { ${CustomerFields} }
585
+ }
586
+ `;
587
+ const GraphQLCustomerAddressesSchema = connection(Schema$1.Struct({
588
+ id: Schema$1.String,
589
+ ...GraphQLAddressSchema.fields
590
+ }));
591
+ const GraphQLCustomerNodeSchema = Schema$1.Struct({
592
+ id: Schema$1.String,
593
+ legacyResourceId: Schema$1.String,
594
+ firstName: Schema$1.NullOr(Schema$1.String),
595
+ lastName: Schema$1.NullOr(Schema$1.String),
596
+ displayName: Schema$1.String,
597
+ note: Schema$1.NullOr(Schema$1.String),
598
+ state: CustomerStateSchema,
599
+ verifiedEmail: Schema$1.Boolean,
600
+ taxExempt: Schema$1.Boolean,
601
+ taxExemptions: Schema$1.Array(Schema$1.String),
602
+ tags: Schema$1.Array(Schema$1.String),
603
+ locale: Schema$1.String,
604
+ numberOfOrders: Schema$1.NumberFromString,
605
+ amountSpent: Schema$1.Struct({
606
+ amount: Schema$1.String,
607
+ currencyCode: Schema$1.String
608
+ }),
609
+ lastOrder: Schema$1.NullOr(Schema$1.Struct({ id: Schema$1.String })),
610
+ productSubscriberStatus: ProductSubscriberStatusSchema,
611
+ dataSaleOptOut: Schema$1.Boolean,
612
+ defaultEmailAddress: Schema$1.NullOr(Schema$1.Struct({
613
+ emailAddress: Schema$1.String,
614
+ marketingState: EmailMarketingStateSchema,
615
+ marketingOptInLevel: Schema$1.NullOr(MarketingOptInLevelSchema),
616
+ marketingUpdatedAt: Schema$1.NullOr(Schema$1.DateFromString)
617
+ })),
618
+ defaultPhoneNumber: Schema$1.NullOr(Schema$1.Struct({ phoneNumber: Schema$1.String })),
619
+ smsMarketingConsent: Schema$1.NullOr(Schema$1.Struct({
620
+ marketingState: SmsMarketingStateSchema,
621
+ marketingOptInLevel: MarketingOptInLevelSchema,
622
+ consentUpdatedAt: Schema$1.NullOr(Schema$1.DateFromString),
623
+ consentCollectedFrom: Schema$1.NullOr(ConsentCollectedFromSchema)
624
+ })),
625
+ defaultAddress: Schema$1.NullOr(Schema$1.Struct({ id: Schema$1.String })),
626
+ addressesV2: GraphQLCustomerAddressesSchema,
627
+ createdAt: Schema$1.DateFromString,
628
+ updatedAt: Schema$1.DateFromString
629
+ });
630
+ const addressId = (value) => value.replace(/\?.*$/, "");
631
+ const normalizeCustomerNode = (node, addresses) => ({
632
+ id: node.id,
633
+ legacyResourceId: node.legacyResourceId,
634
+ firstName: emptyText(node.firstName),
635
+ lastName: emptyText(node.lastName),
636
+ displayName: node.displayName,
637
+ email: node.defaultEmailAddress?.emailAddress ?? "",
638
+ emailMarketingState: node.defaultEmailAddress?.marketingState ?? null,
639
+ emailMarketingOptInLevel: node.defaultEmailAddress?.marketingOptInLevel ?? null,
640
+ emailMarketingUpdatedAt: node.defaultEmailAddress?.marketingUpdatedAt ?? null,
641
+ phone: node.defaultPhoneNumber?.phoneNumber ?? "",
642
+ smsMarketingState: node.smsMarketingConsent?.marketingState ?? null,
643
+ smsMarketingOptInLevel: node.smsMarketingConsent?.marketingOptInLevel ?? null,
644
+ smsMarketingUpdatedAt: node.smsMarketingConsent?.consentUpdatedAt ?? null,
645
+ smsMarketingCollectedFrom: node.smsMarketingConsent?.consentCollectedFrom ?? null,
646
+ note: emptyText(node.note),
647
+ state: node.state,
648
+ verifiedEmail: node.verifiedEmail,
649
+ taxExempt: node.taxExempt,
650
+ taxExemptions: node.taxExemptions,
651
+ tags: node.tags,
652
+ locale: node.locale,
653
+ numberOfOrders: node.numberOfOrders,
654
+ amountSpent: {
655
+ amount: normalizeAmount(node.amountSpent.amount),
656
+ currencyCode: node.amountSpent.currencyCode
657
+ },
658
+ lastOrderId: node.lastOrder?.id ?? "",
659
+ productSubscriberStatus: node.productSubscriberStatus,
660
+ dataSaleOptOut: node.dataSaleOptOut,
661
+ defaultAddressId: node.defaultAddress === null ? "" : addressId(node.defaultAddress.id),
662
+ addresses: addresses.map(({ id, ...value }) => ({
663
+ id: addressId(id),
664
+ ...fromGraphQL.address(value)
665
+ })),
666
+ createdAt: node.createdAt,
667
+ updatedAt: node.updatedAt
668
+ });
669
+ const CustomersQuery = pageQuery("AirfoilCustomers", "customers", CustomerFields);
670
+ const GraphQLCustomersDataSchema = Schema$1.Struct({ customers: connection(GraphQLCustomerNodeSchema) });
671
+ const GraphQLCustomerByIdDataSchema = Schema$1.Struct({ customer: Schema$1.NullOr(GraphQLCustomerNodeSchema) });
672
+ //#endregion
673
+ //#region src/resources/orders/row.ts
674
+ const OrderCancelReasonSchema = Schema$1.Literals([
675
+ "CUSTOMER",
676
+ "DECLINED",
677
+ "FRAUD",
678
+ "INVENTORY",
679
+ "STAFF",
680
+ "OTHER"
681
+ ]);
682
+ const OrderFinancialStatusSchema = Schema$1.Literals([
683
+ "PENDING",
684
+ "AUTHORIZED",
685
+ "PARTIALLY_PAID",
686
+ "PARTIALLY_REFUNDED",
687
+ "VOIDED",
688
+ "PAID",
689
+ "REFUNDED",
690
+ "EXPIRED"
691
+ ]);
692
+ const DiscountApplicationTypeSchema = Schema$1.Literals([
693
+ "DISCOUNT_CODE",
694
+ "MANUAL",
695
+ "AUTOMATIC",
696
+ "SCRIPT"
697
+ ]);
698
+ const DiscountAllocationMethodSchema = Schema$1.Literals([
699
+ "ACROSS",
700
+ "EACH",
701
+ "ONE"
702
+ ]);
703
+ const DiscountTargetSelectionSchema = Schema$1.Literals([
704
+ "ALL",
705
+ "ENTITLED",
706
+ "EXPLICIT"
707
+ ]);
708
+ const DiscountTargetTypeSchema = Schema$1.Literals(["LINE_ITEM", "SHIPPING_LINE"]);
709
+ const DiscountValueTypeSchema = Schema$1.Literals(["PERCENTAGE", "FIXED_AMOUNT"]);
710
+ const DiscountApplicationSchema = Schema$1.Struct({
711
+ index: Schema$1.Int.pipe(Schema$1.annotateKey({ description: "Position used by discount allocations." })),
712
+ type: DiscountApplicationTypeSchema.pipe(Schema$1.annotateKey({ description: "How the discount was applied." })),
713
+ code: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Discount code." })),
714
+ title: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Discount title." })),
715
+ description: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Manual discount description." })),
716
+ allocationMethod: DiscountAllocationMethodSchema.pipe(Schema$1.annotateKey({ description: "How the value is split." })),
717
+ targetSelection: DiscountTargetSelectionSchema.pipe(Schema$1.annotateKey({ description: "Which lines are targeted." })),
718
+ targetType: DiscountTargetTypeSchema.pipe(Schema$1.annotateKey({ description: "Kind of lines targeted." })),
719
+ valueType: DiscountValueTypeSchema.pipe(Schema$1.annotateKey({ description: "Whether the value is a percent." })),
720
+ value: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Percent or amount in the customer currency." }))
721
+ });
722
+ const ShippingLineSchema = Schema$1.Struct({
723
+ id: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Unique shipping line identifier." })),
724
+ title: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Shipping method title." })),
725
+ code: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Shipping rate code." })),
726
+ source: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Source of the shipping rate." })),
727
+ carrierIdentifier: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Carrier service identifier." })),
728
+ phone: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Phone number for the shipping line." })),
729
+ isRemoved: Schema$1.Boolean.pipe(Schema$1.annotateKey({ description: "Whether the line was removed by an edit." })),
730
+ originalPriceSet: moneyBag.pipe(Schema$1.annotateKey({ description: "Price before discounts." })),
731
+ discountedPriceSet: moneyBag.pipe(Schema$1.annotateKey({ description: "Price after discounts." })),
732
+ currentDiscountedPriceSet: moneyBag.pipe(Schema$1.annotateKey({ description: "Price after discounts, edits, and refunds." })),
733
+ taxLines: taxLines.pipe(Schema$1.annotateKey({ description: "Taxes on the shipping line." })),
734
+ discountAllocations: discountAllocations.pipe(Schema$1.annotateKey({ description: "Discounts on the line." }))
735
+ });
736
+ const OrderLineItemSchema = Schema$1.Struct({
737
+ id: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Unique line item identifier." })),
738
+ name: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Product and variant name." })),
739
+ title: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Product title." })),
740
+ variantTitle: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Variant title." })),
741
+ sku: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Stock keeping unit." })),
742
+ vendor: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Product vendor." })),
743
+ productId: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Product identifier." })),
744
+ variantId: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Product variant identifier." })),
745
+ quantity: Schema$1.Int.pipe(Schema$1.annotateKey({ description: "Quantity when the order was placed." })),
746
+ currentQuantity: Schema$1.Int.pipe(Schema$1.annotateKey({ description: "Quantity after removals and refunds." })),
747
+ taxable: Schema$1.Boolean.pipe(Schema$1.annotateKey({ description: "Whether the line item is taxable." })),
748
+ requiresShipping: Schema$1.Boolean.pipe(Schema$1.annotateKey({ description: "Whether the line item needs shipping." })),
749
+ isGiftCard: Schema$1.Boolean.pipe(Schema$1.annotateKey({ description: "Whether the line item is a gift card." })),
750
+ originalUnitPriceSet: moneyBag.pipe(Schema$1.annotateKey({ description: "Unit price before discounts." })),
751
+ totalDiscountSet: moneyBag.pipe(Schema$1.annotateKey({ description: "Total discount on the line." })),
752
+ taxLines: taxLines.pipe(Schema$1.annotateKey({ description: "Taxes on the line." })),
753
+ discountAllocations: discountAllocations.pipe(Schema$1.annotateKey({ description: "Discounts on the line." })),
754
+ customAttributes: attributes.pipe(Schema$1.annotateKey({ description: "Custom line properties." }))
755
+ });
756
+ const OrderSchema = Schema$1.Struct({
757
+ id: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Unique order identifier." })),
758
+ legacyResourceId: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Numeric order identifier stored as text." })),
759
+ name: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Order name shown to the merchant." })),
760
+ email: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Email used for the order." })),
761
+ phone: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Phone used for the order." })),
762
+ customerId: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Customer identifier." })),
763
+ customerLocale: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Customer language." })),
764
+ customerAcceptsMarketing: Schema$1.Boolean.pipe(Schema$1.annotateKey({ description: "Whether the buyer accepts marketing." })),
765
+ billingAddress: Schema$1.NullOr(address).pipe(Schema$1.annotateKey({ description: "Billing address." })),
766
+ shippingAddress: Schema$1.NullOr(address).pipe(Schema$1.annotateKey({ description: "Shipping address." })),
767
+ note: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Order note." })),
768
+ customAttributes: attributes.pipe(Schema$1.annotateKey({ description: "Custom order attributes." })),
769
+ tags: Schema$1.Array(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Tags added to the order." })),
770
+ confirmationNumber: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Confirmation number." })),
771
+ poNumber: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Purchase order number." })),
772
+ sourceName: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Channel that created the order." })),
773
+ sourceIdentifier: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Identifier from the source." })),
774
+ appId: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "App that created the order." })),
775
+ paymentGatewayNames: Schema$1.Array(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Payment gateways used." })),
776
+ test: Schema$1.Boolean.pipe(Schema$1.annotateKey({ description: "Whether the order is a test order." })),
777
+ taxesIncluded: Schema$1.Boolean.pipe(Schema$1.annotateKey({ description: "Whether prices include taxes." })),
778
+ taxExempt: Schema$1.Boolean.pipe(Schema$1.annotateKey({ description: "Whether the order is exempt from tax." })),
779
+ dutiesIncluded: Schema$1.Boolean.pipe(Schema$1.annotateKey({ description: "Whether prices include duties." })),
780
+ estimatedTaxes: Schema$1.Boolean.pipe(Schema$1.annotateKey({ description: "Whether taxes are estimates." })),
781
+ totalWeight: Schema$1.NullOr(Schema$1.Int).pipe(Schema$1.annotateKey({ description: "Total weight in grams." })),
782
+ displayFinancialStatus: Schema$1.NullOr(OrderFinancialStatusSchema).pipe(Schema$1.annotateKey({ description: "Payment status of the order." })),
783
+ cancelReason: Schema$1.NullOr(OrderCancelReasonSchema).pipe(Schema$1.annotateKey({ description: "Reason the order was cancelled." })),
784
+ cancelledAt: Schema$1.NullOr(Schema$1.Date).pipe(Schema$1.annotateKey({ description: "Time when the order was cancelled." })),
785
+ closedAt: Schema$1.NullOr(Schema$1.Date).pipe(Schema$1.annotateKey({ description: "Time when the order was closed." })),
786
+ processedAt: Schema$1.Date.pipe(Schema$1.annotateKey({ description: "Time when the order was processed." })),
787
+ createdAt: Schema$1.Date.pipe(Schema$1.annotateKey({ description: "Time when the order was created." })),
788
+ updatedAt: Schema$1.Date.pipe(Schema$1.annotateKey({ description: "Time when the order was last changed." })),
789
+ currencyCode: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Shop currency code." })),
790
+ presentmentCurrencyCode: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Customer currency code." })),
791
+ discountCodes: Schema$1.Array(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Discount codes used." })),
792
+ discountApplications: Schema$1.Array(DiscountApplicationSchema).pipe(Schema$1.annotateKey({ description: "Discounts applied to the order." })),
793
+ subtotalPriceSet: Schema$1.NullOr(moneyBag).pipe(Schema$1.annotateKey({ description: "Subtotal when the order was placed." })),
794
+ currentSubtotalPriceSet: moneyBag.pipe(Schema$1.annotateKey({ description: "Subtotal after edits and refunds." })),
795
+ totalDiscountsSet: Schema$1.NullOr(moneyBag).pipe(Schema$1.annotateKey({ description: "Discounts when the order was placed." })),
796
+ currentTotalDiscountsSet: moneyBag.pipe(Schema$1.annotateKey({ description: "Discounts after edits and refunds." })),
797
+ totalShippingPriceSet: moneyBag.pipe(Schema$1.annotateKey({ description: "Shipping when the order was placed." })),
798
+ currentShippingPriceSet: moneyBag.pipe(Schema$1.annotateKey({ description: "Shipping after edits and refunds." })),
799
+ totalTaxSet: Schema$1.NullOr(moneyBag).pipe(Schema$1.annotateKey({ description: "Tax when the order was placed." })),
800
+ currentTotalTaxSet: moneyBag.pipe(Schema$1.annotateKey({ description: "Tax after edits and refunds." })),
801
+ originalTotalDutiesSet: Schema$1.NullOr(moneyBag).pipe(Schema$1.annotateKey({ description: "Duties when the order was placed." })),
802
+ currentTotalDutiesSet: Schema$1.NullOr(moneyBag).pipe(Schema$1.annotateKey({ description: "Duties after edits and refunds." })),
803
+ totalPriceSet: moneyBag.pipe(Schema$1.annotateKey({ description: "Total when the order was placed." })),
804
+ currentTotalPriceSet: moneyBag.pipe(Schema$1.annotateKey({ description: "Total after edits and refunds." })),
805
+ taxLines: taxLines.pipe(Schema$1.annotateKey({ description: "Taxes when the order was placed." })),
806
+ shippingLines: Schema$1.Array(ShippingLineSchema).pipe(Schema$1.annotateKey({ description: "Shipping lines, including removed ones." })),
807
+ lineItems: Schema$1.Array(OrderLineItemSchema).pipe(Schema$1.annotateKey({ description: "Line items in the order." })),
808
+ _deleted: Schema$1.optional(Schema$1.Boolean).pipe(Schema$1.annotateKey({ description: "Whether the order was deleted." }))
809
+ }).annotate({ description: "Orders in a Shopify store." }).pipe(Iceberg.identifier("id"));
810
+ //#endregion
811
+ //#region src/resources/orders/graphql.ts
812
+ const LineItemFields = `
813
+ id
814
+ name
815
+ title
816
+ variantTitle
817
+ sku
818
+ vendor
819
+ product { id }
820
+ variant { id }
821
+ quantity
822
+ currentQuantity
823
+ taxable
824
+ requiresShipping
825
+ isGiftCard
826
+ originalUnitPriceSet { ${MoneyBagFields} }
827
+ totalDiscountSet { ${MoneyBagFields} }
828
+ taxLines { ${TaxLineFields} }
829
+ discountAllocations { ${DiscountAllocationFields} }
830
+ customAttributes { key value }
831
+ `;
832
+ const ShippingLineFields = `
833
+ id
834
+ title
835
+ code
836
+ source
837
+ carrierIdentifier
838
+ phone
839
+ isRemoved
840
+ originalPriceSet { ${MoneyBagFields} }
841
+ discountedPriceSet { ${MoneyBagFields} }
842
+ currentDiscountedPriceSet { ${MoneyBagFields} }
843
+ taxLines { ${TaxLineFields} }
844
+ discountAllocations { ${DiscountAllocationFields} }
845
+ `;
846
+ const DiscountApplicationFields = `
847
+ __typename
848
+ index
849
+ allocationMethod
850
+ targetSelection
851
+ targetType
852
+ value {
853
+ __typename
854
+ ... on MoneyV2 { amount }
855
+ ... on PricingPercentageValue { percentage }
856
+ }
857
+ ... on DiscountCodeApplication { code }
858
+ ... on ManualDiscountApplication { title description }
859
+ ... on AutomaticDiscountApplication { title }
860
+ ... on ScriptDiscountApplication { title }
861
+ `;
862
+ const OrderFields = `
863
+ id
864
+ legacyResourceId
865
+ name
866
+ email
867
+ phone
868
+ customer { id }
869
+ customerLocale
870
+ customerAcceptsMarketing
871
+ billingAddress { ${AddressFields} }
872
+ shippingAddress { ${AddressFields} }
873
+ note
874
+ customAttributes { key value }
875
+ tags
876
+ confirmationNumber
877
+ poNumber
878
+ sourceName
879
+ sourceIdentifier
880
+ app { id }
881
+ paymentGatewayNames
882
+ test
883
+ taxesIncluded
884
+ taxExempt
885
+ dutiesIncluded
886
+ estimatedTaxes
887
+ totalWeight
888
+ displayFinancialStatus
889
+ cancelReason
890
+ cancelledAt
891
+ closedAt
892
+ processedAt
893
+ createdAt
894
+ updatedAt
895
+ currencyCode
896
+ presentmentCurrencyCode
897
+ discountCodes
898
+ discountApplications(first: 25) { nodes { ${DiscountApplicationFields} } ${PageInfoFields} }
899
+ subtotalPriceSet { ${MoneyBagFields} }
900
+ currentSubtotalPriceSet { ${MoneyBagFields} }
901
+ totalDiscountsSet { ${MoneyBagFields} }
902
+ currentTotalDiscountsSet { ${MoneyBagFields} }
903
+ totalShippingPriceSet { ${MoneyBagFields} }
904
+ currentShippingPriceSet { ${MoneyBagFields} }
905
+ totalTaxSet { ${MoneyBagFields} }
906
+ currentTotalTaxSet { ${MoneyBagFields} }
907
+ originalTotalDutiesSet { ${MoneyBagFields} }
908
+ currentTotalDutiesSet { ${MoneyBagFields} }
909
+ totalPriceSet { ${MoneyBagFields} }
910
+ currentTotalPriceSet { ${MoneyBagFields} }
911
+ taxLines { ${TaxLineFields} }
912
+ shippingLines(first: 25, includeRemovals: true) { nodes { ${ShippingLineFields} } ${PageInfoFields} }
913
+ lineItems(first: 50) { nodes { ${LineItemFields} } ${PageInfoFields} }
914
+ `;
915
+ const orderConnectionQuery = (name, selection) => `#graphql
916
+ query ${name}($id: ID!, $first: Int!, $after: String) {
917
+ node: order(id: $id) {
918
+ connection: ${selection}
919
+ }
920
+ }
921
+ `;
922
+ const OrderLineItemsQuery = orderConnectionQuery("AirfoilOrderLineItems", `lineItems(first: $first, after: $after) { nodes { ${LineItemFields} } ${PageInfoFields} }`);
923
+ const OrderShippingLinesQuery = orderConnectionQuery("AirfoilOrderShippingLines", `shippingLines(first: $first, after: $after, includeRemovals: true) { nodes { ${ShippingLineFields} } ${PageInfoFields} }`);
924
+ const OrderDiscountApplicationsQuery = orderConnectionQuery("AirfoilOrderDiscountApplications", `discountApplications(first: $first, after: $after) { nodes { ${DiscountApplicationFields} } ${PageInfoFields} }`);
925
+ const GraphQLLineItemsSchema = connection(Schema$1.Struct({
926
+ id: Schema$1.String,
927
+ name: Schema$1.String,
928
+ title: Schema$1.String,
929
+ variantTitle: Schema$1.NullOr(Schema$1.String),
930
+ sku: Schema$1.NullOr(Schema$1.String),
931
+ vendor: Schema$1.NullOr(Schema$1.String),
932
+ product: idRef,
933
+ variant: idRef,
934
+ quantity: Schema$1.Int,
935
+ currentQuantity: Schema$1.Int,
936
+ taxable: Schema$1.Boolean,
937
+ requiresShipping: Schema$1.Boolean,
938
+ isGiftCard: Schema$1.Boolean,
939
+ originalUnitPriceSet: GraphQLMoneyBagSchema,
940
+ totalDiscountSet: GraphQLMoneyBagSchema,
941
+ taxLines: Schema$1.Array(GraphQLTaxLineSchema),
942
+ discountAllocations: Schema$1.Array(GraphQLDiscountAllocationSchema),
943
+ customAttributes: Schema$1.Array(GraphQLAttributeSchema)
944
+ }));
945
+ const GraphQLShippingLinesSchema = connection(Schema$1.Struct({
946
+ id: Schema$1.NullOr(Schema$1.String),
947
+ title: Schema$1.String,
948
+ code: Schema$1.NullOr(Schema$1.String),
949
+ source: Schema$1.NullOr(Schema$1.String),
950
+ carrierIdentifier: Schema$1.NullOr(Schema$1.String),
951
+ phone: Schema$1.NullOr(Schema$1.String),
952
+ isRemoved: Schema$1.Boolean,
953
+ originalPriceSet: GraphQLMoneyBagSchema,
954
+ discountedPriceSet: GraphQLMoneyBagSchema,
955
+ currentDiscountedPriceSet: GraphQLMoneyBagSchema,
956
+ taxLines: Schema$1.Array(GraphQLTaxLineSchema),
957
+ discountAllocations: Schema$1.Array(GraphQLDiscountAllocationSchema)
958
+ }));
959
+ const discountApplicationBase = {
960
+ index: Schema$1.Int,
961
+ allocationMethod: DiscountAllocationMethodSchema,
962
+ targetSelection: DiscountTargetSelectionSchema,
963
+ targetType: DiscountTargetTypeSchema,
964
+ value: Schema$1.Union([Schema$1.Struct({
965
+ __typename: Schema$1.Literal("MoneyV2"),
966
+ amount: Schema$1.String
967
+ }), Schema$1.Struct({
968
+ __typename: Schema$1.Literal("PricingPercentageValue"),
969
+ percentage: Schema$1.Number
970
+ })])
971
+ };
972
+ const GraphQLDiscountApplicationsSchema = connection(Schema$1.Union([
973
+ Schema$1.Struct({
974
+ __typename: Schema$1.Literal("DiscountCodeApplication"),
975
+ code: Schema$1.String,
976
+ ...discountApplicationBase
977
+ }),
978
+ Schema$1.Struct({
979
+ __typename: Schema$1.Literal("ManualDiscountApplication"),
980
+ title: Schema$1.String,
981
+ description: Schema$1.NullOr(Schema$1.String),
982
+ ...discountApplicationBase
983
+ }),
984
+ Schema$1.Struct({
985
+ __typename: Schema$1.Literals(["AutomaticDiscountApplication", "ScriptDiscountApplication"]),
986
+ title: Schema$1.String,
987
+ ...discountApplicationBase
988
+ })
989
+ ]));
990
+ const GraphQLOrderNodeSchema = Schema$1.Struct({
991
+ id: Schema$1.String,
992
+ legacyResourceId: Schema$1.String,
993
+ name: Schema$1.String,
994
+ email: Schema$1.NullOr(Schema$1.String),
995
+ phone: Schema$1.NullOr(Schema$1.String),
996
+ customer: idRef,
997
+ customerLocale: Schema$1.NullOr(Schema$1.String),
998
+ customerAcceptsMarketing: Schema$1.Boolean,
999
+ billingAddress: Schema$1.NullOr(GraphQLAddressSchema),
1000
+ shippingAddress: Schema$1.NullOr(GraphQLAddressSchema),
1001
+ note: Schema$1.NullOr(Schema$1.String),
1002
+ customAttributes: Schema$1.Array(GraphQLAttributeSchema),
1003
+ tags: Schema$1.Array(Schema$1.String),
1004
+ confirmationNumber: Schema$1.NullOr(Schema$1.String),
1005
+ poNumber: Schema$1.NullOr(Schema$1.String),
1006
+ sourceName: Schema$1.NullOr(Schema$1.String),
1007
+ sourceIdentifier: Schema$1.NullOr(Schema$1.String),
1008
+ app: idRef,
1009
+ paymentGatewayNames: Schema$1.Array(Schema$1.String),
1010
+ test: Schema$1.Boolean,
1011
+ taxesIncluded: Schema$1.Boolean,
1012
+ taxExempt: Schema$1.Boolean,
1013
+ dutiesIncluded: Schema$1.Boolean,
1014
+ estimatedTaxes: Schema$1.Boolean,
1015
+ totalWeight: Schema$1.NullOr(Schema$1.NumberFromString),
1016
+ displayFinancialStatus: Schema$1.NullOr(OrderFinancialStatusSchema),
1017
+ cancelReason: Schema$1.NullOr(OrderCancelReasonSchema),
1018
+ cancelledAt: Schema$1.NullOr(Schema$1.DateFromString),
1019
+ closedAt: Schema$1.NullOr(Schema$1.DateFromString),
1020
+ processedAt: Schema$1.DateFromString,
1021
+ createdAt: Schema$1.DateFromString,
1022
+ updatedAt: Schema$1.DateFromString,
1023
+ currencyCode: Schema$1.String,
1024
+ presentmentCurrencyCode: Schema$1.String,
1025
+ discountCodes: Schema$1.Array(Schema$1.String),
1026
+ discountApplications: GraphQLDiscountApplicationsSchema,
1027
+ subtotalPriceSet: Schema$1.NullOr(GraphQLMoneyBagSchema),
1028
+ currentSubtotalPriceSet: GraphQLMoneyBagSchema,
1029
+ totalDiscountsSet: Schema$1.NullOr(GraphQLMoneyBagSchema),
1030
+ currentTotalDiscountsSet: GraphQLMoneyBagSchema,
1031
+ totalShippingPriceSet: GraphQLMoneyBagSchema,
1032
+ currentShippingPriceSet: GraphQLMoneyBagSchema,
1033
+ totalTaxSet: Schema$1.NullOr(GraphQLMoneyBagSchema),
1034
+ currentTotalTaxSet: GraphQLMoneyBagSchema,
1035
+ originalTotalDutiesSet: Schema$1.NullOr(GraphQLMoneyBagSchema),
1036
+ currentTotalDutiesSet: Schema$1.NullOr(GraphQLMoneyBagSchema),
1037
+ totalPriceSet: GraphQLMoneyBagSchema,
1038
+ currentTotalPriceSet: GraphQLMoneyBagSchema,
1039
+ taxLines: Schema$1.Array(GraphQLTaxLineSchema),
1040
+ shippingLines: GraphQLShippingLinesSchema,
1041
+ lineItems: GraphQLLineItemsSchema
1042
+ });
1043
+ const discountApplicationType = {
1044
+ DiscountCodeApplication: "DISCOUNT_CODE",
1045
+ ManualDiscountApplication: "MANUAL",
1046
+ AutomaticDiscountApplication: "AUTOMATIC",
1047
+ ScriptDiscountApplication: "SCRIPT"
1048
+ };
1049
+ const fromOrderNode = (node, nested) => ({
1050
+ id: node.id,
1051
+ legacyResourceId: node.legacyResourceId,
1052
+ name: node.name,
1053
+ email: emptyText(node.email),
1054
+ phone: emptyText(node.phone),
1055
+ customerId: node.customer?.id ?? "",
1056
+ customerLocale: emptyText(node.customerLocale),
1057
+ customerAcceptsMarketing: node.customerAcceptsMarketing,
1058
+ billingAddress: node.billingAddress ? fromGraphQL.address(node.billingAddress) : null,
1059
+ shippingAddress: node.shippingAddress ? fromGraphQL.address(node.shippingAddress) : null,
1060
+ note: emptyText(node.note),
1061
+ customAttributes: node.customAttributes,
1062
+ tags: node.tags,
1063
+ confirmationNumber: emptyText(node.confirmationNumber),
1064
+ poNumber: emptyText(node.poNumber),
1065
+ sourceName: emptyText(node.sourceName),
1066
+ sourceIdentifier: emptyText(node.sourceIdentifier),
1067
+ appId: node.app?.id ?? "",
1068
+ paymentGatewayNames: node.paymentGatewayNames,
1069
+ test: node.test,
1070
+ taxesIncluded: node.taxesIncluded,
1071
+ taxExempt: node.taxExempt,
1072
+ dutiesIncluded: node.dutiesIncluded,
1073
+ estimatedTaxes: node.estimatedTaxes,
1074
+ totalWeight: node.totalWeight,
1075
+ displayFinancialStatus: node.displayFinancialStatus,
1076
+ cancelReason: node.cancelReason,
1077
+ cancelledAt: node.cancelledAt,
1078
+ closedAt: node.closedAt,
1079
+ processedAt: node.processedAt,
1080
+ createdAt: node.createdAt,
1081
+ updatedAt: node.updatedAt,
1082
+ currencyCode: node.currencyCode,
1083
+ presentmentCurrencyCode: node.presentmentCurrencyCode,
1084
+ discountCodes: node.discountCodes,
1085
+ discountApplications: nested.discountApplications.map((application) => ({
1086
+ index: application.index,
1087
+ type: discountApplicationType[application.__typename],
1088
+ code: application.__typename === "DiscountCodeApplication" ? application.code : null,
1089
+ title: application.__typename === "DiscountCodeApplication" ? null : application.title,
1090
+ description: application.__typename === "ManualDiscountApplication" ? application.description : null,
1091
+ allocationMethod: application.allocationMethod,
1092
+ targetSelection: application.targetSelection,
1093
+ targetType: application.targetType,
1094
+ valueType: application.value.__typename === "MoneyV2" ? "FIXED_AMOUNT" : "PERCENTAGE",
1095
+ value: application.value.__typename === "MoneyV2" ? normalizeAmount(application.value.amount) : normalizeAmount(String(application.value.percentage))
1096
+ })),
1097
+ subtotalPriceSet: node.subtotalPriceSet ? fromGraphQL.money(node.subtotalPriceSet) : null,
1098
+ currentSubtotalPriceSet: fromGraphQL.money(node.currentSubtotalPriceSet),
1099
+ totalDiscountsSet: node.totalDiscountsSet ? fromGraphQL.money(node.totalDiscountsSet) : null,
1100
+ currentTotalDiscountsSet: fromGraphQL.money(node.currentTotalDiscountsSet),
1101
+ totalShippingPriceSet: fromGraphQL.money(node.totalShippingPriceSet),
1102
+ currentShippingPriceSet: fromGraphQL.money(node.currentShippingPriceSet),
1103
+ totalTaxSet: node.totalTaxSet ? fromGraphQL.money(node.totalTaxSet) : null,
1104
+ currentTotalTaxSet: fromGraphQL.money(node.currentTotalTaxSet),
1105
+ originalTotalDutiesSet: node.originalTotalDutiesSet ? fromGraphQL.money(node.originalTotalDutiesSet) : null,
1106
+ currentTotalDutiesSet: node.currentTotalDutiesSet ? fromGraphQL.money(node.currentTotalDutiesSet) : null,
1107
+ totalPriceSet: fromGraphQL.money(node.totalPriceSet),
1108
+ currentTotalPriceSet: fromGraphQL.money(node.currentTotalPriceSet),
1109
+ taxLines: node.taxLines.map(fromGraphQL.taxLine),
1110
+ shippingLines: nested.shippingLines.map((line) => ({
1111
+ id: line.id,
1112
+ title: line.title,
1113
+ code: line.code,
1114
+ source: line.source,
1115
+ carrierIdentifier: line.carrierIdentifier,
1116
+ phone: line.phone,
1117
+ isRemoved: line.isRemoved,
1118
+ originalPriceSet: fromGraphQL.money(line.originalPriceSet),
1119
+ discountedPriceSet: fromGraphQL.money(line.discountedPriceSet),
1120
+ currentDiscountedPriceSet: fromGraphQL.money(line.currentDiscountedPriceSet),
1121
+ taxLines: line.taxLines.map(fromGraphQL.taxLine),
1122
+ discountAllocations: line.discountAllocations.map(fromGraphQL.discountAllocation)
1123
+ })),
1124
+ lineItems: nested.lineItems.map((item) => ({
1125
+ id: item.id,
1126
+ name: item.name,
1127
+ title: item.title,
1128
+ variantTitle: item.variantTitle,
1129
+ sku: item.sku,
1130
+ vendor: item.vendor,
1131
+ productId: item.product?.id ?? null,
1132
+ variantId: item.variant?.id ?? null,
1133
+ quantity: item.quantity,
1134
+ currentQuantity: item.currentQuantity,
1135
+ taxable: item.taxable,
1136
+ requiresShipping: item.requiresShipping,
1137
+ isGiftCard: item.isGiftCard,
1138
+ originalUnitPriceSet: fromGraphQL.money(item.originalUnitPriceSet),
1139
+ totalDiscountSet: fromGraphQL.money(item.totalDiscountSet),
1140
+ taxLines: item.taxLines.map(fromGraphQL.taxLine),
1141
+ discountAllocations: item.discountAllocations.map(fromGraphQL.discountAllocation),
1142
+ customAttributes: item.customAttributes
1143
+ }))
1144
+ });
1145
+ const OrdersQuery = pageQuery("AirfoilOrders", "orders", OrderFields);
1146
+ const GraphQLOrdersDataSchema = Schema$1.Struct({ orders: connection(GraphQLOrderNodeSchema) });
1147
+ //#endregion
1148
+ //#region src/resources/products/graphql.ts
1149
+ const ProductVariantFields = `
1150
+ id
1151
+ legacyResourceId
1152
+ title
1153
+ sku
1154
+ barcode
1155
+ price
1156
+ compareAtPrice
1157
+ inventoryPolicy
1158
+ taxable
1159
+ createdAt
1160
+ updatedAt
1161
+ `;
1162
+ const ProductFields = `
1163
+ id
1164
+ legacyResourceId
1165
+ title
1166
+ handle
1167
+ descriptionHtml
1168
+ productType
1169
+ vendor
1170
+ status
1171
+ tags
1172
+ createdAt
1173
+ updatedAt
1174
+ publishedAt
1175
+ templateSuffix
1176
+ featuredMedia { ... on MediaImage { image { url altText } } }
1177
+ options(first: 100) { id name position values }
1178
+ variants(first: 25) { nodes { ${ProductVariantFields} } pageInfo { hasNextPage endCursor } }
1179
+ `;
1180
+ const ProductByIdQuery = `#graphql
1181
+ query AirfoilProductById($id: ID!) {
1182
+ product(id: $id) { ${ProductFields} }
1183
+ }
1184
+ `;
1185
+ const ProductVariantsQuery = `#graphql
1186
+ query AirfoilProductVariants($id: ID!, $first: Int!, $after: String) {
1187
+ node: product(id: $id) {
1188
+ connection: variants(first: $first, after: $after) {
1189
+ nodes { ${ProductVariantFields} }
1190
+ pageInfo { hasNextPage endCursor }
1191
+ }
1192
+ }
1193
+ }
1194
+ `;
1195
+ const ProductsQuery = pageQuery("AirfoilProducts", "products", ProductFields);
1196
+ const GraphQLProductVariantNodeSchema = Schema$1.Struct({
1197
+ id: Schema$1.String,
1198
+ legacyResourceId: Schema$1.String,
1199
+ title: Schema$1.String,
1200
+ sku: Schema$1.NullOr(Schema$1.String),
1201
+ barcode: Schema$1.NullOr(Schema$1.String),
1202
+ price: Schema$1.String,
1203
+ compareAtPrice: Schema$1.NullOr(Schema$1.String),
1204
+ inventoryPolicy: ProductVariantInventoryPolicySchema,
1205
+ taxable: Schema$1.Boolean,
1206
+ createdAt: Schema$1.DateFromString,
1207
+ updatedAt: Schema$1.DateFromString
1208
+ });
1209
+ const GraphQLFeaturedMediaSchema = Schema$1.Struct({ image: Schema$1.optional(Schema$1.NullOr(Schema$1.Struct({
1210
+ url: Schema$1.String,
1211
+ altText: Schema$1.NullOr(Schema$1.String)
1212
+ }))) });
1213
+ const GraphQLProductNodeSchema = Schema$1.Struct({
1214
+ id: Schema$1.String,
1215
+ legacyResourceId: Schema$1.String,
1216
+ title: Schema$1.String,
1217
+ handle: Schema$1.String,
1218
+ descriptionHtml: Schema$1.String,
1219
+ productType: Schema$1.String,
1220
+ vendor: Schema$1.String,
1221
+ status: ProductStatusSchema,
1222
+ tags: Schema$1.Array(Schema$1.String),
1223
+ createdAt: Schema$1.DateFromString,
1224
+ updatedAt: Schema$1.DateFromString,
1225
+ publishedAt: Schema$1.NullOr(Schema$1.DateFromString),
1226
+ templateSuffix: Schema$1.NullOr(Schema$1.String),
1227
+ featuredMedia: Schema$1.NullOr(GraphQLFeaturedMediaSchema),
1228
+ options: Schema$1.Array(ProductOptionSchema),
1229
+ variants: connection(GraphQLProductVariantNodeSchema)
1230
+ });
1231
+ const GraphQLProductsDataSchema = Schema$1.Struct({ products: connection(GraphQLProductNodeSchema) });
1232
+ const GraphQLProductByIdDataSchema = Schema$1.Struct({ product: Schema$1.NullOr(GraphQLProductNodeSchema) });
1233
+ const normalizeProductNode = (node, variants) => ({
1234
+ id: node.id,
1235
+ legacyResourceId: node.legacyResourceId,
1236
+ title: node.title,
1237
+ handle: node.handle,
1238
+ descriptionHtml: node.descriptionHtml,
1239
+ productType: node.productType,
1240
+ vendor: node.vendor,
1241
+ status: node.status,
1242
+ tags: node.tags,
1243
+ createdAt: node.createdAt,
1244
+ updatedAt: node.updatedAt,
1245
+ publishedAt: node.publishedAt,
1246
+ templateSuffix: node.templateSuffix ?? "",
1247
+ featuredMedia: node.featuredMedia === null || node.featuredMedia.image === void 0 ? null : { image: node.featuredMedia.image },
1248
+ options: node.options,
1249
+ variants
1250
+ });
1251
+ //#endregion
1252
+ //#region src/resources/refunds/row.ts
1253
+ const TransactionKindSchema = Schema$1.Literals([
1254
+ "SALE",
1255
+ "CAPTURE",
1256
+ "AUTHORIZATION",
1257
+ "VOID",
1258
+ "REFUND",
1259
+ "CHANGE",
1260
+ "EMV_AUTHORIZATION",
1261
+ "SUGGESTED_REFUND"
1262
+ ]);
1263
+ const TransactionStatusSchema = Schema$1.Literals([
1264
+ "SUCCESS",
1265
+ "FAILURE",
1266
+ "PENDING",
1267
+ "ERROR",
1268
+ "AWAITING_RESPONSE",
1269
+ "UNKNOWN"
1270
+ ]);
1271
+ const RestockTypeSchema = Schema$1.Literals([
1272
+ "RETURN",
1273
+ "CANCEL",
1274
+ "LEGACY_RESTOCK",
1275
+ "NO_RESTOCK"
1276
+ ]);
1277
+ const RefundSchema = Schema$1.Struct({
1278
+ id: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Unique refund identifier." })),
1279
+ legacyResourceId: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Numeric refund identifier stored as text." })),
1280
+ orderId: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Refunded order identifier." })),
1281
+ note: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Refund note." })),
1282
+ createdAt: Schema$1.NullOr(Schema$1.Date).pipe(Schema$1.annotateKey({ description: "Time when the refund was created." })),
1283
+ processedAt: Schema$1.Date.pipe(Schema$1.annotateKey({ description: "Time when the refund was processed." })),
1284
+ transactions: Schema$1.Array(Schema$1.Struct({
1285
+ id: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Unique transaction identifier." })),
1286
+ kind: TransactionKindSchema.pipe(Schema$1.annotateKey({ description: "Kind of transaction." })),
1287
+ status: TransactionStatusSchema.pipe(Schema$1.annotateKey({ description: "Status reported for the transaction." })),
1288
+ amount: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Amount in the customer currency." })),
1289
+ currencyCode: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Customer currency code." })),
1290
+ gateway: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Payment gateway." })),
1291
+ test: Schema$1.Boolean.pipe(Schema$1.annotateKey({ description: "Whether the transaction is a test." })),
1292
+ errorCode: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Gateway error code." })),
1293
+ parentTransactionId: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Transaction this one refunds." })),
1294
+ createdAt: Schema$1.Date.pipe(Schema$1.annotateKey({ description: "Time when the transaction was created." })),
1295
+ processedAt: Schema$1.NullOr(Schema$1.Date).pipe(Schema$1.annotateKey({ description: "Time when the transaction was processed." }))
1296
+ })).pipe(Schema$1.annotateKey({ description: "Transactions that move the refunded money." })),
1297
+ refundLineItems: Schema$1.Array(Schema$1.Struct({
1298
+ id: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Unique refund line item identifier." })),
1299
+ lineItemId: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Refunded order line item identifier." })),
1300
+ quantity: Schema$1.Int.pipe(Schema$1.annotateKey({ description: "Quantity refunded." })),
1301
+ restockType: RestockTypeSchema.pipe(Schema$1.annotateKey({ description: "How the items were restocked." })),
1302
+ locationId: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Restock location identifier." })),
1303
+ subtotalSet: moneyBag.pipe(Schema$1.annotateKey({ description: "Refunded subtotal." })),
1304
+ totalTaxSet: moneyBag.pipe(Schema$1.annotateKey({ description: "Refunded tax." }))
1305
+ })).pipe(Schema$1.annotateKey({ description: "Refunded order line items." })),
1306
+ refundShippingLines: Schema$1.Array(Schema$1.Struct({
1307
+ id: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Unique refund shipping line identifier." })),
1308
+ shippingLineId: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Refunded shipping line." })),
1309
+ subtotalAmountSet: moneyBag.pipe(Schema$1.annotateKey({ description: "Refunded shipping amount." }))
1310
+ })).pipe(Schema$1.annotateKey({ description: "Refunded shipping." })),
1311
+ orderAdjustments: Schema$1.Array(Schema$1.Struct({
1312
+ id: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Unique order adjustment identifier." })),
1313
+ reason: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Reason for the adjustment." })),
1314
+ amountSet: moneyBag.pipe(Schema$1.annotateKey({ description: "Adjustment amount." })),
1315
+ taxAmountSet: moneyBag.pipe(Schema$1.annotateKey({ description: "Tax on the adjustment." }))
1316
+ })).pipe(Schema$1.annotateKey({ description: "Refund discrepancy adjustments." })),
1317
+ duties: Schema$1.Array(Schema$1.Struct({
1318
+ dutyId: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Refunded duty identifier." })),
1319
+ amountSet: moneyBag.pipe(Schema$1.annotateKey({ description: "Refunded duty amount." }))
1320
+ })).pipe(Schema$1.annotateKey({ description: "Refunded duties." }))
1321
+ }).annotate({ description: "Refunds on orders in a Shopify store." }).pipe(Iceberg.identifier("id"));
1322
+ //#endregion
1323
+ //#region src/resources/refunds/graphql.ts
1324
+ const TransactionFields = `id kind status gateway test errorCode parentTransaction { id } createdAt processedAt amountSet { ${MoneyBagFields} }`;
1325
+ const RefundLineItemFields = `id lineItem { id } quantity restockType location { id } subtotalSet { ${MoneyBagFields} } totalTaxSet { ${MoneyBagFields} }`;
1326
+ const RefundShippingLineFields = `id shippingLine { id } subtotalAmountSet { ${MoneyBagFields} }`;
1327
+ const OrderAdjustmentFields = `id reason amountSet { ${MoneyBagFields} } taxAmountSet { ${MoneyBagFields} }`;
1328
+ const RefundFields = `
1329
+ id
1330
+ legacyResourceId
1331
+ note
1332
+ createdAt
1333
+ processedAt
1334
+ duties { originalDuty { id } amountSet { ${MoneyBagFields} } }
1335
+ transactions(first: 10) { nodes { ${TransactionFields} } ${PageInfoFields} }
1336
+ refundLineItems(first: 50) { nodes { ${RefundLineItemFields} } ${PageInfoFields} }
1337
+ refundShippingLines(first: 10) { nodes { ${RefundShippingLineFields} } ${PageInfoFields} }
1338
+ orderAdjustments(first: 10) { nodes { ${OrderAdjustmentFields} } ${PageInfoFields} }
1339
+ `;
1340
+ const refundConnectionQuery = (name, selection) => `#graphql
1341
+ query ${name}($id: ID!, $first: Int!, $after: String) {
1342
+ node: refund(id: $id) {
1343
+ connection: ${selection}
1344
+ }
1345
+ }
1346
+ `;
1347
+ const RefundTransactionsQuery = refundConnectionQuery("AirfoilRefundTransactions", `transactions(first: $first, after: $after) { nodes { ${TransactionFields} } ${PageInfoFields} }`);
1348
+ const RefundLineItemsQuery = refundConnectionQuery("AirfoilRefundLineItems", `refundLineItems(first: $first, after: $after) { nodes { ${RefundLineItemFields} } ${PageInfoFields} }`);
1349
+ const RefundShippingLinesQuery = refundConnectionQuery("AirfoilRefundShippingLines", `refundShippingLines(first: $first, after: $after) { nodes { ${RefundShippingLineFields} } ${PageInfoFields} }`);
1350
+ const RefundOrderAdjustmentsQuery = refundConnectionQuery("AirfoilRefundOrderAdjustments", `orderAdjustments(first: $first, after: $after) { nodes { ${OrderAdjustmentFields} } ${PageInfoFields} }`);
1351
+ const GraphQLRefundTransactionsSchema = connection(Schema$1.Struct({
1352
+ id: Schema$1.String,
1353
+ kind: TransactionKindSchema,
1354
+ status: TransactionStatusSchema,
1355
+ gateway: Schema$1.NullOr(Schema$1.String),
1356
+ test: Schema$1.Boolean,
1357
+ errorCode: Schema$1.NullOr(Schema$1.String),
1358
+ parentTransaction: idRef,
1359
+ createdAt: Schema$1.DateFromString,
1360
+ processedAt: Schema$1.NullOr(Schema$1.DateFromString),
1361
+ amountSet: GraphQLMoneyBagSchema
1362
+ }));
1363
+ const GraphQLRefundLineItemsSchema = connection(Schema$1.Struct({
1364
+ id: Schema$1.NullOr(Schema$1.String),
1365
+ lineItem: Schema$1.Struct({ id: Schema$1.String }),
1366
+ quantity: Schema$1.Int,
1367
+ restockType: RestockTypeSchema,
1368
+ location: idRef,
1369
+ subtotalSet: GraphQLMoneyBagSchema,
1370
+ totalTaxSet: GraphQLMoneyBagSchema
1371
+ }));
1372
+ const GraphQLRefundShippingLinesSchema = connection(Schema$1.Struct({
1373
+ id: Schema$1.String,
1374
+ shippingLine: idRef,
1375
+ subtotalAmountSet: GraphQLMoneyBagSchema
1376
+ }));
1377
+ const GraphQLOrderAdjustmentsSchema = connection(Schema$1.Struct({
1378
+ id: Schema$1.String,
1379
+ reason: Schema$1.NullOr(Schema$1.String),
1380
+ amountSet: GraphQLMoneyBagSchema,
1381
+ taxAmountSet: GraphQLMoneyBagSchema
1382
+ }));
1383
+ const GraphQLRefundNodeSchema = Schema$1.Struct({
1384
+ id: Schema$1.String,
1385
+ legacyResourceId: Schema$1.String,
1386
+ note: Schema$1.NullOr(Schema$1.String),
1387
+ createdAt: Schema$1.NullOr(Schema$1.DateFromString),
1388
+ processedAt: Schema$1.DateFromString,
1389
+ duties: Schema$1.NullOr(Schema$1.Array(Schema$1.Struct({
1390
+ originalDuty: idRef,
1391
+ amountSet: GraphQLMoneyBagSchema
1392
+ }))),
1393
+ transactions: GraphQLRefundTransactionsSchema,
1394
+ refundLineItems: GraphQLRefundLineItemsSchema,
1395
+ refundShippingLines: GraphQLRefundShippingLinesSchema,
1396
+ orderAdjustments: GraphQLOrderAdjustmentsSchema
1397
+ });
1398
+ const fromRefundNode = (orderId, node, nested) => ({
1399
+ id: node.id,
1400
+ legacyResourceId: node.legacyResourceId,
1401
+ orderId,
1402
+ note: node.note ?? "",
1403
+ createdAt: node.createdAt,
1404
+ processedAt: node.processedAt,
1405
+ transactions: nested.transactions.map((transaction) => ({
1406
+ id: transaction.id,
1407
+ kind: transaction.kind,
1408
+ status: transaction.status,
1409
+ amount: normalizeAmount(transaction.amountSet.presentmentMoney.amount),
1410
+ currencyCode: transaction.amountSet.presentmentMoney.currencyCode,
1411
+ gateway: transaction.gateway,
1412
+ test: transaction.test,
1413
+ errorCode: transaction.errorCode,
1414
+ parentTransactionId: transaction.parentTransaction?.id ?? null,
1415
+ createdAt: transaction.createdAt,
1416
+ processedAt: transaction.processedAt
1417
+ })),
1418
+ refundLineItems: nested.refundLineItems.map((item) => ({
1419
+ id: item.id,
1420
+ lineItemId: item.lineItem.id,
1421
+ quantity: item.quantity,
1422
+ restockType: item.restockType,
1423
+ locationId: item.location?.id ?? null,
1424
+ subtotalSet: fromGraphQL.money(item.subtotalSet),
1425
+ totalTaxSet: fromGraphQL.money(item.totalTaxSet)
1426
+ })),
1427
+ refundShippingLines: nested.refundShippingLines.map((line) => ({
1428
+ id: line.id,
1429
+ shippingLineId: line.shippingLine?.id ?? null,
1430
+ subtotalAmountSet: fromGraphQL.money(line.subtotalAmountSet)
1431
+ })),
1432
+ orderAdjustments: nested.orderAdjustments.map((adjustment) => ({
1433
+ id: adjustment.id,
1434
+ reason: adjustment.reason,
1435
+ amountSet: fromGraphQL.money(adjustment.amountSet),
1436
+ taxAmountSet: fromGraphQL.money(adjustment.taxAmountSet)
1437
+ })),
1438
+ duties: (node.duties ?? []).map((duty) => ({
1439
+ dutyId: duty.originalDuty?.id ?? null,
1440
+ amountSet: fromGraphQL.money(duty.amountSet)
1441
+ }))
1442
+ });
1443
+ const OrderRefundsQuery = pageQuery("AirfoilOrderRefunds", "orders", `id refunds { ${RefundFields} }`);
1444
+ const GraphQLOrderRefundsDataSchema = Schema$1.Struct({ orders: connection(Schema$1.Struct({
1445
+ id: Schema$1.String,
1446
+ refunds: Schema$1.Array(GraphQLRefundNodeSchema)
1447
+ })) });
1448
+ //#endregion
1449
+ //#region src/api/auth.ts
1450
+ var ShopifyAuthError = class extends Data.TaggedError("ShopifyAuthError") {};
1451
+ var ShopifyAuth = class extends Context.Service()("@useairfoil/producer-shopify/ShopifyAuth") {};
1452
+ const TokenResponseSchema = Schema.Struct({
1453
+ access_token: Schema.String,
1454
+ expires_in: Schema.Number
1455
+ });
1456
+ const ErrorResponseSchema = Schema.Struct({ error: Schema.Literals(["shop_not_permitted", "invalid_client"]) });
1457
+ const shopUrl = (shopDomain) => `https://${shopDomain.replace(/^https?:\/\//i, "").replace(/\/+$/g, "")}`;
1458
+ const errorMessages = {
1459
+ shop_not_permitted: "The Shopify app and store must belong to the same Shopify organization",
1460
+ invalid_client: "The Shopify client ID or client secret is invalid",
1461
+ exchange_failed: "Shopify authentication failed"
1462
+ };
1463
+ const errorFor = (reason) => new ShopifyAuthError({
1464
+ reason,
1465
+ message: errorMessages[reason]
1466
+ });
1467
+ const decodeRejectedResponse = (response) => HttpClientResponse.schemaBodyJson(ErrorResponseSchema)(response).pipe(Effect.map((body) => body.error), Effect.catch(() => Effect.succeed("exchange_failed")));
1468
+ const make$3 = Effect.fnUntraced(function* (config) {
1469
+ const client = yield* HttpClient.HttpClient;
1470
+ const endpoint = `${shopUrl(config.shopDomain)}/admin/oauth/access_token`;
1471
+ return yield* Auth.makeTokenCache({ acquire: Effect.scoped(Effect.gen(function* () {
1472
+ const request = HttpClientRequest.post(endpoint).pipe(HttpClientRequest.bodyUrlParams({
1473
+ grant_type: "client_credentials",
1474
+ client_id: config.clientId,
1475
+ client_secret: Redacted.value(config.clientSecret)
1476
+ }));
1477
+ const response = yield* client.execute(request).pipe(Effect.mapError(() => errorFor("exchange_failed")));
1478
+ const successfulResponse = yield* HttpClientResponse.filterStatusOk(response).pipe(Effect.catchTag("HttpClientError", () => decodeRejectedResponse(response).pipe(Effect.flatMap((reason) => Effect.fail(errorFor(reason))))));
1479
+ const body = yield* HttpClientResponse.schemaBodyJson(TokenResponseSchema)(successfulResponse).pipe(Effect.mapError(() => errorFor("exchange_failed")));
1480
+ return {
1481
+ value: Redacted.make(body.access_token),
1482
+ expiresIn: Duration.seconds(body.expires_in)
1483
+ };
1484
+ })) });
1485
+ });
1486
+ const layer$2 = (config) => Layer.effect(ShopifyAuth)(make$3(config));
1487
+ //#endregion
1488
+ //#region src/api/http.ts
1489
+ const isResponse = (value) => Predicate.hasProperty(value, HttpClientResponse.TypeId);
1490
+ const retrySchedule = (options) => Metrics.retrySchedule({
1491
+ connector: manifest.name,
1492
+ baseDelay: options.baseDelay,
1493
+ times: options.maxRetries
1494
+ }).pipe(Schedule.modifyDelay(({ input, duration }) => {
1495
+ if (!isResponse(input) || input.status !== 429) return Effect.succeed(duration);
1496
+ const seconds = Number(input.headers["retry-after"]);
1497
+ return Effect.succeed(Number.isFinite(seconds) ? Duration.seconds(seconds) : duration);
1498
+ }));
1499
+ //#endregion
1500
+ //#region src/api/graphql.ts
1501
+ const SHOPIFY_API_VERSION = "2026-07";
1502
+ const maxRetries = 5;
1503
+ const retryBaseDelay = Duration.millis(500);
1504
+ const requestTimeout = Duration.minutes(2);
1505
+ const ThrottleStatusSchema = Schema.Struct({
1506
+ maximumAvailable: Schema.Number,
1507
+ currentlyAvailable: Schema.Number,
1508
+ restoreRate: Schema.Number
1509
+ });
1510
+ const GraphQLResponseSchema = Schema.Struct({
1511
+ data: Schema.optional(Schema.Unknown),
1512
+ errors: Schema.optional(Schema.Array(Schema.Struct({ extensions: Schema.optional(Schema.Struct({ code: Schema.optional(Schema.String) })) }))),
1513
+ extensions: Schema.optional(Schema.Struct({ cost: Schema.optional(Schema.Struct({
1514
+ requestedQueryCost: Schema.optional(Schema.Number),
1515
+ throttleStatus: Schema.optional(ThrottleStatusSchema)
1516
+ })) }))
1517
+ });
1518
+ const retryableCodes = ["THROTTLED", "INTERNAL_SERVER_ERROR"];
1519
+ /** How long Shopify needs to restore the query's cost, when it says so. */
1520
+ const throttleWait = (response) => {
1521
+ const cost = response.extensions?.cost;
1522
+ const status = cost?.throttleStatus;
1523
+ if (cost?.requestedQueryCost === void 0 || status === void 0) return Option.none();
1524
+ const deficit = cost.requestedQueryCost - status.currentlyAvailable;
1525
+ return Option.some(Duration.millis(Math.ceil(deficit / status.restoreRate * 1e3)));
1526
+ };
1527
+ var Retryable = class extends Data.TaggedError("Retryable") {};
1528
+ const make$2 = Effect.fnUntraced(function* (config) {
1529
+ const auth = yield* ShopifyAuth;
1530
+ const client = (yield* HttpClient.HttpClient).pipe(HttpClient.mapRequestEffect((request) => auth.get.pipe(Effect.map((token) => HttpClientRequest.setHeader(request, "X-Shopify-Access-Token", Redacted.value(token))))), HttpClient.mapRequest(HttpClientRequest.acceptJson), HttpClient.retryTransient({ schedule: retrySchedule({
1531
+ maxRetries,
1532
+ baseDelay: retryBaseDelay
1533
+ }) }));
1534
+ const endpoint = `${shopUrl(config.shopDomain)}/admin/api/${SHOPIFY_API_VERSION}/graphql.json`;
1535
+ const graphqlRetrySchedule = Schedule.exponential(retryBaseDelay).pipe(Schedule.jittered, Schedule.upTo({ times: maxRetries }), Schedule.modifyDelay(({ input, duration }) => Effect.succeed(input instanceof Retryable ? Option.match(input.wait, {
1536
+ onNone: () => duration,
1537
+ onSome: (wait) => Duration.max(wait, retryBaseDelay)
1538
+ }) : duration)));
1539
+ const fetchGraphQL = (options) => {
1540
+ const fail = (message, cause, annotation) => Effect.logWarning(message).pipe(Effect.annotateLogs({
1541
+ operationName: options.operationName,
1542
+ body: JSON.stringify(cause)
1543
+ }), Effect.andThen(Telemetry.annotateError(annotation, cause)), Effect.andThen(Effect.fail(new ConnectorError({
1544
+ message,
1545
+ cause
1546
+ }))));
1547
+ const decodeError = (error) => Telemetry.annotateError("api_decode", error).pipe(Effect.andThen(Effect.fail(new ConnectorError({
1548
+ message: "Shopify GraphQL response schema decode failed",
1549
+ cause: error
1550
+ }))));
1551
+ return Effect.gen(function* () {
1552
+ const request = HttpClientRequest.post(endpoint).pipe(HttpClientRequest.bodyJsonUnsafe({
1553
+ query: options.query,
1554
+ variables: options.variables ?? {}
1555
+ }));
1556
+ const response = yield* client.execute(request).pipe(Effect.tapError((error) => Telemetry.annotateError("api_http", error)), Effect.mapError((error) => error._tag === "ShopifyAuthError" ? new ConnectorError({
1557
+ message: error.message,
1558
+ cause: error
1559
+ }) : new ConnectorError({
1560
+ message: "Shopify GraphQL request failed",
1561
+ cause: error
1562
+ })));
1563
+ const body = yield* response.json.pipe(Effect.tapError((error) => Telemetry.annotateError("api_json", error)), Effect.mapError((error) => new ConnectorError({
1564
+ message: "Shopify GraphQL returned invalid JSON",
1565
+ cause: error
1566
+ })));
1567
+ if (response.status < 200 || response.status >= 300) return yield* fail("Shopify GraphQL returned non-2xx status", {
1568
+ status: response.status,
1569
+ body,
1570
+ operationName: options.operationName
1571
+ }, "api_status");
1572
+ const graphql = yield* Schema.decodeUnknownEffect(GraphQLResponseSchema)(body).pipe(Effect.catch(decodeError));
1573
+ if (graphql.errors !== void 0 && graphql.errors.length > 0) {
1574
+ const codes = graphql.errors.map((error) => error.extensions?.code);
1575
+ const code = retryableCodes.find((retryable) => codes.includes(retryable));
1576
+ if (code !== void 0) return yield* new Retryable({
1577
+ code,
1578
+ wait: code === "THROTTLED" ? throttleWait(graphql) : Option.none(),
1579
+ body
1580
+ });
1581
+ return yield* fail("Shopify GraphQL returned errors", body, "api_graphql");
1582
+ }
1583
+ return yield* Schema.decodeUnknownEffect(options.schema)(graphql.data).pipe(Effect.catch(decodeError));
1584
+ }).pipe(Effect.withSpan(Telemetry.SpanName.apiFetch, {
1585
+ kind: "client",
1586
+ attributes: { [Telemetry.Attr.apiPath]: `graphql:${options.operationName}` }
1587
+ })).pipe(Effect.retry({
1588
+ schedule: graphqlRetrySchedule.pipe(Schedule.tap(({ input, duration }) => input instanceof Retryable ? Effect.logWarning("Shopify GraphQL request returned a retryable error, retrying").pipe(Effect.annotateLogs({
1589
+ operationName: options.operationName,
1590
+ code: input.code,
1591
+ waitMillis: Duration.toMillis(duration)
1592
+ }), Effect.andThen(Metrics.recordApiRetry({
1593
+ connector: manifest.name,
1594
+ reason: input.code === "THROTTLED" ? "rate_limit" : "server_error"
1595
+ }))) : Effect.void)),
1596
+ while: (error) => error._tag === "Retryable"
1597
+ }), Effect.catchTag("Retryable", (error) => fail("Shopify GraphQL returned errors", error.body, "api_graphql"))).pipe(Effect.timeoutOrElse({
1598
+ duration: requestTimeout,
1599
+ orElse: () => Effect.fail(new ConnectorError({ message: "Shopify GraphQL request timed out" }))
1600
+ }));
1601
+ };
1602
+ return fetchGraphQL;
1603
+ });
1604
+ //#endregion
1605
+ //#region src/api/client.ts
1606
+ var client_exports = /* @__PURE__ */ __exportAll({
1607
+ ShopifyApiClient: () => ShopifyApiClient,
1608
+ layer: () => layer$1,
1609
+ layerConfig: () => layerConfig$1,
1610
+ make: () => make$1
1611
+ });
1612
+ var ShopifyApiClient = class extends Context.Service()("@useairfoil/producer-shopify/ShopifyApiClient") {};
1613
+ const CustomersAccessQuery = `#graphql
1614
+ query AirfoilCustomersAccess {
1615
+ customers(first: 1) {
1616
+ nodes {
1617
+ id
1618
+ defaultEmailAddress { emailAddress }
1619
+ defaultPhoneNumber { phoneNumber }
1620
+ defaultAddress { address1 }
1621
+ }
1622
+ }
1623
+ }
1624
+ `;
1625
+ const OrdersAccessQuery = `#graphql
1626
+ query AirfoilOrdersAccess {
1627
+ orders(first: 1) {
1628
+ nodes {
1629
+ id
1630
+ email
1631
+ phone
1632
+ shippingAddress { address1 }
1633
+ }
1634
+ }
1635
+ }
1636
+ `;
1637
+ const ProductsAccessQuery = `#graphql
1638
+ query AirfoilProductsAccess {
1639
+ products(first: 1) {
1640
+ nodes {
1641
+ id
1642
+ }
1643
+ }
1644
+ }
1645
+ `;
1646
+ const ShopIdentityQuery = `#graphql
1647
+ query AirfoilShopIdentity {
1648
+ shop {
1649
+ id
1650
+ }
1651
+ }
1652
+ `;
1653
+ const ShopIdentitySchema = Schema.Struct({ shop: Schema.Struct({ id: Schema.String }) });
1654
+ const ProductsAccessSchema = Schema.Struct({ products: Schema.Struct({ nodes: Schema.Array(Schema.Struct({ id: Schema.String })) }) });
1655
+ const OrdersAccessSchema = Schema.Struct({ orders: Schema.Struct({ nodes: Schema.Array(Schema.Struct({ id: Schema.String })) }) });
1656
+ const CustomersAccessSchema = Schema.Struct({ customers: Schema.Struct({ nodes: Schema.Array(Schema.Struct({ id: Schema.String })) }) });
1657
+ const nestedPageSchema = (connection) => Schema.Struct({ node: Schema.NullOr(Schema.Struct({ connection })) });
1658
+ const make$1 = Effect.fnUntraced(function* (config) {
1659
+ const fetchGraphQL = yield* make$2(config);
1660
+ const nextPageCursor = (pageInfo) => pageInfo.hasNextPage ? Option.fromNullishOr(pageInfo.endCursor) : Option.none();
1661
+ const fetchProductById = (id) => fetchGraphQL({
1662
+ operationName: "AirfoilProductById",
1663
+ query: ProductByIdQuery,
1664
+ variables: { id },
1665
+ schema: GraphQLProductByIdDataSchema
1666
+ }).pipe(Effect.flatMap((data) => {
1667
+ const node = data.product;
1668
+ if (node === null) return Effect.succeed(Option.none());
1669
+ return loadProduct(node).pipe(Effect.map(Option.some));
1670
+ }));
1671
+ const followConnection = (first, options) => Option.match(nextPageCursor(first.pageInfo), {
1672
+ onNone: () => Effect.succeed(first.nodes),
1673
+ onSome: (initialCursor) => Stream.paginate(initialCursor, (after) => fetchGraphQL({
1674
+ operationName: options.operationName,
1675
+ query: options.query,
1676
+ variables: {
1677
+ id: options.id,
1678
+ first: 100,
1679
+ after
1680
+ },
1681
+ schema: options.schema
1682
+ }).pipe(Effect.flatMap(({ node }) => node === null ? Effect.fail(new ConnectorError({ message: `Shopify record disappeared during ${options.operationName}` })) : Effect.succeed([node.connection.nodes, nextPageCursor(node.connection.pageInfo)])))).pipe(Stream.runCollect, Effect.map((rest) => [...first.nodes, ...rest]))
1683
+ });
1684
+ const loadOrder = (node) => Effect.all({
1685
+ discountApplications: followConnection(node.discountApplications, {
1686
+ id: node.id,
1687
+ operationName: "AirfoilOrderDiscountApplications",
1688
+ query: OrderDiscountApplicationsQuery,
1689
+ schema: nestedPageSchema(GraphQLDiscountApplicationsSchema)
1690
+ }),
1691
+ shippingLines: followConnection(node.shippingLines, {
1692
+ id: node.id,
1693
+ operationName: "AirfoilOrderShippingLines",
1694
+ query: OrderShippingLinesQuery,
1695
+ schema: nestedPageSchema(GraphQLShippingLinesSchema)
1696
+ }),
1697
+ lineItems: followConnection(node.lineItems, {
1698
+ id: node.id,
1699
+ operationName: "AirfoilOrderLineItems",
1700
+ query: OrderLineItemsQuery,
1701
+ schema: nestedPageSchema(GraphQLLineItemsSchema)
1702
+ })
1703
+ }).pipe(Effect.map((nested) => fromOrderNode(node, nested)));
1704
+ const loadRefund = (orderId, node) => Effect.all({
1705
+ transactions: followConnection(node.transactions, {
1706
+ id: node.id,
1707
+ operationName: "AirfoilRefundTransactions",
1708
+ query: RefundTransactionsQuery,
1709
+ schema: nestedPageSchema(GraphQLRefundTransactionsSchema)
1710
+ }),
1711
+ refundLineItems: followConnection(node.refundLineItems, {
1712
+ id: node.id,
1713
+ operationName: "AirfoilRefundLineItems",
1714
+ query: RefundLineItemsQuery,
1715
+ schema: nestedPageSchema(GraphQLRefundLineItemsSchema)
1716
+ }),
1717
+ refundShippingLines: followConnection(node.refundShippingLines, {
1718
+ id: node.id,
1719
+ operationName: "AirfoilRefundShippingLines",
1720
+ query: RefundShippingLinesQuery,
1721
+ schema: nestedPageSchema(GraphQLRefundShippingLinesSchema)
1722
+ }),
1723
+ orderAdjustments: followConnection(node.orderAdjustments, {
1724
+ id: node.id,
1725
+ operationName: "AirfoilRefundOrderAdjustments",
1726
+ query: RefundOrderAdjustmentsQuery,
1727
+ schema: nestedPageSchema(GraphQLOrderAdjustmentsSchema)
1728
+ })
1729
+ }).pipe(Effect.map((nested) => fromRefundNode(orderId, node, nested)));
1730
+ const loadCustomer = (node) => followConnection(node.addressesV2, {
1731
+ id: node.id,
1732
+ operationName: "AirfoilCustomerAddresses",
1733
+ query: CustomerAddressesQuery,
1734
+ schema: nestedPageSchema(GraphQLCustomerAddressesSchema)
1735
+ }).pipe(Effect.map((addresses) => normalizeCustomerNode(node, addresses)));
1736
+ const loadProduct = (node) => followConnection(node.variants, {
1737
+ id: node.id,
1738
+ operationName: "AirfoilProductVariants",
1739
+ query: ProductVariantsQuery,
1740
+ schema: nestedPageSchema(connection(GraphQLProductVariantNodeSchema))
1741
+ }).pipe(Effect.map((variants) => normalizeProductNode(node, variants)));
1742
+ const toPage = (pageInfo, items) => items.pipe(Effect.map((loaded) => ({
1743
+ items: loaded,
1744
+ endCursor: pageInfo.endCursor,
1745
+ hasMore: pageInfo.hasNextPage
1746
+ })));
1747
+ const fetchProducts = (options) => fetchGraphQL({
1748
+ operationName: "AirfoilProducts",
1749
+ query: ProductsQuery,
1750
+ variables: {
1751
+ first: options.first,
1752
+ after: options.after ?? null
1753
+ },
1754
+ schema: GraphQLProductsDataSchema
1755
+ }).pipe(Effect.flatMap(({ products }) => toPage(products.pageInfo, Effect.forEach(products.nodes, loadProduct))));
1756
+ const fetchOrders = (options) => fetchGraphQL({
1757
+ operationName: "AirfoilOrders",
1758
+ query: OrdersQuery,
1759
+ variables: {
1760
+ first: options.first,
1761
+ after: options.after ?? null
1762
+ },
1763
+ schema: GraphQLOrdersDataSchema
1764
+ }).pipe(Effect.flatMap(({ orders }) => toPage(orders.pageInfo, Effect.forEach(orders.nodes, loadOrder))));
1765
+ const fetchRefunds = (options) => fetchGraphQL({
1766
+ operationName: "AirfoilOrderRefunds",
1767
+ query: OrderRefundsQuery,
1768
+ variables: {
1769
+ first: options.first,
1770
+ after: options.after ?? null
1771
+ },
1772
+ schema: GraphQLOrderRefundsDataSchema
1773
+ }).pipe(Effect.flatMap(({ orders }) => toPage(orders.pageInfo, Effect.forEach(orders.nodes, (order) => Effect.forEach(order.refunds, (refund) => loadRefund(order.id, refund))).pipe(Effect.map((refunds) => refunds.flat())))));
1774
+ const fetchCustomers = (options) => fetchGraphQL({
1775
+ operationName: "AirfoilCustomers",
1776
+ query: CustomersQuery,
1777
+ variables: {
1778
+ first: options.first,
1779
+ after: options.after ?? null
1780
+ },
1781
+ schema: GraphQLCustomersDataSchema
1782
+ }).pipe(Effect.flatMap(({ customers }) => toPage(customers.pageInfo, Effect.forEach(customers.nodes, loadCustomer))));
1783
+ const fetchCustomerById = (id) => fetchGraphQL({
1784
+ operationName: "AirfoilCustomerById",
1785
+ query: CustomerByIdQuery,
1786
+ variables: { id },
1787
+ schema: GraphQLCustomerByIdDataSchema
1788
+ }).pipe(Effect.flatMap(({ customer }) => customer === null ? Effect.succeed(Option.none()) : loadCustomer(customer).pipe(Effect.map(Option.some))));
1789
+ const checkCustomersAccess = fetchGraphQL({
1790
+ operationName: "AirfoilCustomersAccess",
1791
+ query: CustomersAccessQuery,
1792
+ schema: CustomersAccessSchema
1793
+ }).pipe(Effect.asVoid);
1794
+ const checkOrdersAccess = fetchGraphQL({
1795
+ operationName: "AirfoilOrdersAccess",
1796
+ query: OrdersAccessQuery,
1797
+ schema: OrdersAccessSchema
1798
+ }).pipe(Effect.asVoid);
1799
+ return {
1800
+ checkConnection: fetchGraphQL({
1801
+ operationName: "AirfoilShopIdentity",
1802
+ query: ShopIdentityQuery,
1803
+ schema: ShopIdentitySchema
1804
+ }).pipe(Effect.asVoid),
1805
+ checkProductsAccess: fetchGraphQL({
1806
+ operationName: "AirfoilProductsAccess",
1807
+ query: ProductsAccessQuery,
1808
+ schema: ProductsAccessSchema
1809
+ }).pipe(Effect.asVoid),
1810
+ checkOrdersAccess,
1811
+ checkCustomersAccess,
1812
+ fetchGraphQL,
1813
+ fetchProducts,
1814
+ fetchProductById,
1815
+ fetchOrders,
1816
+ fetchRefunds,
1817
+ fetchCustomers,
1818
+ fetchCustomerById
1819
+ };
1820
+ });
1821
+ const layer$1 = (config) => Layer.effect(ShopifyApiClient)(make$1(config));
1822
+ const layerConfig$1 = (config) => Layer.effect(ShopifyApiClient)(Config.unwrap(config).pipe(Effect.flatMap(make$1)));
1823
+ //#endregion
1824
+ //#region src/resources/carts/row.ts
1825
+ const CartLineItemSchema = Schema$1.Struct({
1826
+ id: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Unique cart line identifier." })),
1827
+ properties: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Custom line properties stored as JSON." })),
1828
+ quantity: Schema$1.Int.pipe(Schema$1.annotateKey({ description: "Quantity of the cart line." })),
1829
+ variantId: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Product variant identifier." })),
1830
+ key: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Unique key for the cart line." })),
1831
+ discountedPrice: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Price after discounts." })),
1832
+ discounts: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Line discounts stored as JSON." })),
1833
+ giftCard: Schema$1.Boolean.pipe(Schema$1.annotateKey({ description: "Whether the line is a gift card." })),
1834
+ grams: Schema$1.Int.pipe(Schema$1.annotateKey({ description: "Weight of the line in grams." })),
1835
+ linePrice: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Total price for the line." })),
1836
+ originalLinePrice: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Line price before discounts." })),
1837
+ originalPrice: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Unit price before discounts." })),
1838
+ price: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Current unit price." })),
1839
+ productId: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Product identifier." })),
1840
+ sku: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Stock keeping unit for the line." })),
1841
+ taxable: Schema$1.Boolean.pipe(Schema$1.annotateKey({ description: "Whether the line is taxable." })),
1842
+ title: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Title of the cart line." })),
1843
+ totalDiscount: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Total discount for the line." })),
1844
+ vendor: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Vendor of the product." })),
1845
+ discountedPriceSet: moneyBag.pipe(Schema$1.annotateKey({ description: "Price after discounts." })),
1846
+ linePriceSet: moneyBag.pipe(Schema$1.annotateKey({ description: "Total price for the line." })),
1847
+ originalLinePriceSet: moneyBag.pipe(Schema$1.annotateKey({ description: "Line price before discounts." })),
1848
+ priceSet: moneyBag.pipe(Schema$1.annotateKey({ description: "Current unit price." })),
1849
+ totalDiscountSet: moneyBag.pipe(Schema$1.annotateKey({ description: "Total discount for the line." })),
1850
+ parentRelationship: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Parent relationship stored as JSON." }))
1851
+ });
1852
+ const CartSchema = Schema$1.Struct({
1853
+ id: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Unique cart identifier." })),
1854
+ token: Schema$1.String.pipe(Schema$1.annotateKey({ description: "Token for the cart." })),
1855
+ topic: Schema$1.Literals(["carts/create", "carts/update"]).pipe(Schema$1.annotateKey({ description: "Webhook topic that last changed the cart." })),
1856
+ lineItems: Schema$1.Array(CartLineItemSchema).pipe(Schema$1.annotateKey({ description: "Items in the cart." })),
1857
+ note: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.annotateKey({ description: "Note added to the cart." })),
1858
+ updatedAt: Schema$1.Date.pipe(Schema$1.annotateKey({ description: "Time when the cart was last changed." })),
1859
+ createdAt: Schema$1.Date.pipe(Schema$1.annotateKey({ description: "Time when the cart was created." }))
1860
+ }).annotate({ description: "Latest state of each cart in a Shopify store." }).pipe(Iceberg.identifier("id"));
1861
+ //#endregion
1862
+ //#region src/resources/customers/webhook.ts
1863
+ const CustomerWebhookPayloadSchema = Schema$1.Struct({
1864
+ admin_graphql_api_id: Schema$1.String,
1865
+ updated_at: Schema$1.DateFromString
1866
+ });
1867
+ const CustomerPurchaseSummaryPayloadSchema = Schema$1.Struct({
1868
+ customerId: Schema$1.String,
1869
+ occurredAt: Schema$1.DateFromString
1870
+ });
1871
+ const CustomerEmailConsentPayloadSchema = Schema$1.Struct({ customer_id: Schema$1.Number });
1872
+ const CustomerSmsConsentPayloadSchema = Schema$1.Struct({ id: Schema$1.Number });
1873
+ const CustomerTagsPayloadSchema = Schema$1.Struct({
1874
+ customerId: Schema$1.String,
1875
+ occurredAt: Schema$1.DateFromString
1876
+ });
1877
+ const CustomerDeleteWebhookPayloadSchema = Schema$1.Struct({ id: Schema$1.Number });
1878
+ const CustomerEventSchema = Schema$1.Struct({
1879
+ _tag: Schema$1.Literals(["refresh", "delete"]),
1880
+ id: Schema$1.String,
1881
+ version: Schema$1.Date
1882
+ });
1883
+ //#endregion
1884
+ //#region src/resources/orders/webhook.ts
1885
+ const nullableMoney = Schema$1.NullOr(RestMoneyBagSchema);
1886
+ const RestShippingLineSchema = Schema$1.Struct({
1887
+ id: Schema$1.NullOr(Schema$1.Number),
1888
+ title: Schema$1.String,
1889
+ code: Schema$1.NullOr(Schema$1.String),
1890
+ source: Schema$1.NullOr(Schema$1.String),
1891
+ carrier_identifier: Schema$1.NullOr(Schema$1.String),
1892
+ phone: Schema$1.NullOr(Schema$1.String),
1893
+ is_removed: Schema$1.Boolean,
1894
+ price_set: RestMoneyBagSchema,
1895
+ discounted_price_set: RestMoneyBagSchema,
1896
+ current_discounted_price_set: RestMoneyBagSchema,
1897
+ tax_lines: Schema$1.Array(RestTaxLineSchema),
1898
+ discount_allocations: Schema$1.Array(RestDiscountAllocationSchema)
1899
+ });
1900
+ const RestLineItemSchema = Schema$1.Struct({
1901
+ admin_graphql_api_id: Schema$1.String,
1902
+ name: Schema$1.String,
1903
+ title: Schema$1.String,
1904
+ variant_title: Schema$1.NullOr(Schema$1.String),
1905
+ sku: Schema$1.NullOr(Schema$1.String),
1906
+ vendor: Schema$1.NullOr(Schema$1.String),
1907
+ product_id: Schema$1.NullOr(Schema$1.Number),
1908
+ variant_id: Schema$1.NullOr(Schema$1.Number),
1909
+ quantity: Schema$1.Int,
1910
+ current_quantity: Schema$1.Int,
1911
+ taxable: Schema$1.Boolean,
1912
+ requires_shipping: Schema$1.Boolean,
1913
+ gift_card: Schema$1.Boolean,
1914
+ price_set: RestMoneyBagSchema,
1915
+ total_discount_set: RestMoneyBagSchema,
1916
+ tax_lines: Schema$1.Array(RestTaxLineSchema),
1917
+ discount_allocations: Schema$1.Array(RestDiscountAllocationSchema),
1918
+ properties: Schema$1.Array(RestAttributeSchema)
1919
+ });
1920
+ const RestDiscountApplicationSchema = Schema$1.Struct({
1921
+ type: upper(DiscountApplicationTypeSchema),
1922
+ code: Schema$1.optional(Schema$1.NullOr(Schema$1.String)),
1923
+ title: Schema$1.optional(Schema$1.NullOr(Schema$1.String)),
1924
+ description: Schema$1.optional(Schema$1.NullOr(Schema$1.String)),
1925
+ allocation_method: upper(DiscountAllocationMethodSchema),
1926
+ target_selection: upper(DiscountTargetSelectionSchema),
1927
+ target_type: upper(DiscountTargetTypeSchema),
1928
+ value_type: upper(DiscountValueTypeSchema),
1929
+ value: Schema$1.String
1930
+ });
1931
+ const OrderWebhookPayloadSchema = Schema$1.Struct({
1932
+ id: Schema$1.Number,
1933
+ admin_graphql_api_id: Schema$1.String,
1934
+ name: Schema$1.String,
1935
+ email: Schema$1.NullOr(Schema$1.String),
1936
+ phone: Schema$1.NullOr(Schema$1.String),
1937
+ customer: Schema$1.NullOr(Schema$1.Struct({ admin_graphql_api_id: Schema$1.String })),
1938
+ customer_locale: Schema$1.NullOr(Schema$1.String),
1939
+ buyer_accepts_marketing: Schema$1.Boolean,
1940
+ billing_address: Schema$1.NullOr(RestAddressSchema),
1941
+ shipping_address: Schema$1.NullOr(RestAddressSchema),
1942
+ note: Schema$1.NullOr(Schema$1.String),
1943
+ note_attributes: Schema$1.Array(RestAttributeSchema),
1944
+ tags: Schema$1.String,
1945
+ confirmation_number: Schema$1.NullOr(Schema$1.String),
1946
+ po_number: Schema$1.NullOr(Schema$1.String),
1947
+ source_name: Schema$1.NullOr(Schema$1.String),
1948
+ source_identifier: Schema$1.NullOr(Schema$1.String),
1949
+ app_id: Schema$1.NullOr(Schema$1.Number),
1950
+ payment_gateway_names: Schema$1.Array(Schema$1.String),
1951
+ test: Schema$1.Boolean,
1952
+ taxes_included: Schema$1.Boolean,
1953
+ tax_exempt: Schema$1.Boolean,
1954
+ duties_included: Schema$1.Boolean,
1955
+ estimated_taxes: Schema$1.Boolean,
1956
+ total_weight: Schema$1.NullOr(Schema$1.Int),
1957
+ financial_status: Schema$1.NullOr(upper(OrderFinancialStatusSchema)),
1958
+ cancel_reason: Schema$1.NullOr(upper(OrderCancelReasonSchema)),
1959
+ cancelled_at: Schema$1.NullOr(Schema$1.DateFromString),
1960
+ closed_at: Schema$1.NullOr(Schema$1.DateFromString),
1961
+ processed_at: Schema$1.DateFromString,
1962
+ created_at: Schema$1.DateFromString,
1963
+ updated_at: Schema$1.DateFromString,
1964
+ currency: Schema$1.String,
1965
+ presentment_currency: Schema$1.String,
1966
+ discount_codes: Schema$1.Array(Schema$1.Struct({ code: Schema$1.String })),
1967
+ discount_applications: Schema$1.Array(RestDiscountApplicationSchema),
1968
+ subtotal_price_set: nullableMoney,
1969
+ current_subtotal_price_set: RestMoneyBagSchema,
1970
+ total_discounts_set: nullableMoney,
1971
+ current_total_discounts_set: RestMoneyBagSchema,
1972
+ total_shipping_price_set: RestMoneyBagSchema,
1973
+ current_shipping_price_set: RestMoneyBagSchema,
1974
+ total_tax_set: nullableMoney,
1975
+ current_total_tax_set: RestMoneyBagSchema,
1976
+ original_total_duties_set: nullableMoney,
1977
+ current_total_duties_set: nullableMoney,
1978
+ total_price_set: RestMoneyBagSchema,
1979
+ current_total_price_set: RestMoneyBagSchema,
1980
+ tax_lines: Schema$1.Array(RestTaxLineSchema),
1981
+ shipping_lines: Schema$1.Array(RestShippingLineSchema),
1982
+ line_items: Schema$1.Array(RestLineItemSchema)
1983
+ });
1984
+ const OrderDeleteWebhookPayloadSchema = Schema$1.Struct({ id: Schema$1.Number });
1985
+ const OrderEventSchema = Schema$1.Union([Schema$1.Struct({
1986
+ _tag: Schema$1.Literal("upsert"),
1987
+ payload: Schema$1.toType(OrderWebhookPayloadSchema)
1988
+ }), Schema$1.Struct({
1989
+ _tag: Schema$1.Literal("delete"),
1990
+ id: Schema$1.String,
1991
+ version: Schema$1.Date
1992
+ })]);
1993
+ const orMoney = (bag) => bag === null ? null : fromRest.money(bag);
1994
+ const fromOrderWebhook = (payload) => ({
1995
+ id: payload.admin_graphql_api_id,
1996
+ legacyResourceId: String(payload.id),
1997
+ name: payload.name,
1998
+ email: emptyText(payload.email),
1999
+ phone: emptyText(payload.phone),
2000
+ customerId: payload.customer?.admin_graphql_api_id ?? "",
2001
+ customerLocale: emptyText(payload.customer_locale),
2002
+ customerAcceptsMarketing: payload.buyer_accepts_marketing,
2003
+ billingAddress: payload.billing_address ? fromRest.address(payload.billing_address) : null,
2004
+ shippingAddress: payload.shipping_address ? fromRest.address(payload.shipping_address) : null,
2005
+ note: emptyText(payload.note),
2006
+ customAttributes: payload.note_attributes.map(fromRest.attribute),
2007
+ tags: splitTags(payload.tags),
2008
+ confirmationNumber: emptyText(payload.confirmation_number),
2009
+ poNumber: emptyText(payload.po_number),
2010
+ sourceName: emptyText(payload.source_name),
2011
+ sourceIdentifier: emptyText(payload.source_identifier),
2012
+ appId: payload.app_id === null ? "" : gid("App", payload.app_id),
2013
+ paymentGatewayNames: payload.payment_gateway_names,
2014
+ test: payload.test,
2015
+ taxesIncluded: payload.taxes_included,
2016
+ taxExempt: payload.tax_exempt,
2017
+ dutiesIncluded: payload.duties_included,
2018
+ estimatedTaxes: payload.estimated_taxes,
2019
+ totalWeight: payload.total_weight,
2020
+ displayFinancialStatus: payload.financial_status,
2021
+ cancelReason: payload.cancel_reason,
2022
+ cancelledAt: payload.cancelled_at,
2023
+ closedAt: payload.closed_at,
2024
+ processedAt: payload.processed_at,
2025
+ createdAt: payload.created_at,
2026
+ updatedAt: payload.updated_at,
2027
+ currencyCode: payload.currency,
2028
+ presentmentCurrencyCode: payload.presentment_currency,
2029
+ discountCodes: payload.discount_codes.map((discount) => discount.code),
2030
+ discountApplications: payload.discount_applications.map((application, index) => ({
2031
+ index,
2032
+ type: application.type,
2033
+ code: application.type === "DISCOUNT_CODE" ? application.code ?? null : null,
2034
+ title: application.type === "DISCOUNT_CODE" ? null : application.title ?? null,
2035
+ description: application.type === "MANUAL" ? application.description ?? null : null,
2036
+ allocationMethod: application.allocation_method,
2037
+ targetSelection: application.target_selection,
2038
+ targetType: application.target_type,
2039
+ valueType: application.value_type,
2040
+ value: normalizeAmount(application.value)
2041
+ })),
2042
+ subtotalPriceSet: orMoney(payload.subtotal_price_set),
2043
+ currentSubtotalPriceSet: fromRest.money(payload.current_subtotal_price_set),
2044
+ totalDiscountsSet: orMoney(payload.total_discounts_set),
2045
+ currentTotalDiscountsSet: fromRest.money(payload.current_total_discounts_set),
2046
+ totalShippingPriceSet: fromRest.money(payload.total_shipping_price_set),
2047
+ currentShippingPriceSet: fromRest.money(payload.current_shipping_price_set),
2048
+ totalTaxSet: orMoney(payload.total_tax_set),
2049
+ currentTotalTaxSet: fromRest.money(payload.current_total_tax_set),
2050
+ originalTotalDutiesSet: orMoney(payload.original_total_duties_set),
2051
+ currentTotalDutiesSet: orMoney(payload.current_total_duties_set),
2052
+ totalPriceSet: fromRest.money(payload.total_price_set),
2053
+ currentTotalPriceSet: fromRest.money(payload.current_total_price_set),
2054
+ taxLines: payload.tax_lines.map(fromRest.taxLine),
2055
+ shippingLines: payload.shipping_lines.map((line) => ({
2056
+ id: line.id === null ? null : gid("ShippingLine", line.id),
2057
+ title: line.title,
2058
+ code: line.code,
2059
+ source: line.source,
2060
+ carrierIdentifier: line.carrier_identifier,
2061
+ phone: line.phone,
2062
+ isRemoved: line.is_removed,
2063
+ originalPriceSet: fromRest.money(line.price_set),
2064
+ discountedPriceSet: fromRest.money(line.discounted_price_set),
2065
+ currentDiscountedPriceSet: fromRest.money(line.current_discounted_price_set),
2066
+ taxLines: line.tax_lines.map(fromRest.taxLine),
2067
+ discountAllocations: line.discount_allocations.map(fromRest.discountAllocation)
2068
+ })),
2069
+ lineItems: payload.line_items.map((item) => ({
2070
+ id: item.admin_graphql_api_id,
2071
+ name: item.name,
2072
+ title: item.title,
2073
+ variantTitle: item.variant_title,
2074
+ sku: item.sku,
2075
+ vendor: item.vendor,
2076
+ productId: item.product_id === null ? null : gid("Product", item.product_id),
2077
+ variantId: item.variant_id === null ? null : gid("ProductVariant", item.variant_id),
2078
+ quantity: item.quantity,
2079
+ currentQuantity: item.current_quantity,
2080
+ taxable: item.taxable,
2081
+ requiresShipping: item.requires_shipping,
2082
+ isGiftCard: item.gift_card,
2083
+ originalUnitPriceSet: fromRest.money(item.price_set),
2084
+ totalDiscountSet: fromRest.money(item.total_discount_set),
2085
+ taxLines: item.tax_lines.map(fromRest.taxLine),
2086
+ discountAllocations: item.discount_allocations.map(fromRest.discountAllocation),
2087
+ customAttributes: item.properties.map(fromRest.attribute)
2088
+ }))
2089
+ });
2090
+ //#endregion
2091
+ //#region src/resources/refunds/webhook.ts
2092
+ const RefundWebhookPayloadSchema = Schema$1.Struct({
2093
+ id: Schema$1.Number,
2094
+ admin_graphql_api_id: Schema$1.String,
2095
+ order_id: Schema$1.Number,
2096
+ note: Schema$1.NullOr(Schema$1.String),
2097
+ created_at: Schema$1.NullOr(Schema$1.DateFromString),
2098
+ processed_at: Schema$1.DateFromString,
2099
+ transactions: Schema$1.Array(Schema$1.Struct({
2100
+ admin_graphql_api_id: Schema$1.String,
2101
+ kind: upper(TransactionKindSchema),
2102
+ status: upper(TransactionStatusSchema),
2103
+ amount: Schema$1.String,
2104
+ currency: Schema$1.String,
2105
+ gateway: Schema$1.NullOr(Schema$1.String),
2106
+ test: Schema$1.Boolean,
2107
+ error_code: Schema$1.NullOr(Schema$1.String),
2108
+ parent_id: Schema$1.NullOr(Schema$1.Number),
2109
+ created_at: Schema$1.DateFromString,
2110
+ processed_at: Schema$1.NullOr(Schema$1.DateFromString)
2111
+ })),
2112
+ refund_line_items: Schema$1.Array(Schema$1.Struct({
2113
+ id: Schema$1.Number,
2114
+ line_item_id: Schema$1.Number,
2115
+ quantity: Schema$1.Int,
2116
+ restock_type: upper(RestockTypeSchema),
2117
+ location_id: Schema$1.NullOr(Schema$1.Number),
2118
+ subtotal_set: RestMoneyBagSchema,
2119
+ total_tax_set: RestMoneyBagSchema
2120
+ })),
2121
+ refund_shipping_lines: Schema$1.Array(Schema$1.Struct({
2122
+ id: Schema$1.Number,
2123
+ shipping_line_id: Schema$1.NullOr(Schema$1.Number),
2124
+ subtotal_amount_set: RestMoneyBagSchema
2125
+ })),
2126
+ order_adjustments: Schema$1.Array(Schema$1.Struct({
2127
+ id: Schema$1.Number,
2128
+ kind: Schema$1.NullOr(Schema$1.String),
2129
+ reason: Schema$1.NullOr(Schema$1.String),
2130
+ amount_set: RestMoneyBagSchema,
2131
+ tax_amount_set: RestMoneyBagSchema
2132
+ })),
2133
+ duties: Schema$1.Array(Schema$1.Struct({
2134
+ duty_id: Schema$1.NullOr(Schema$1.Number),
2135
+ amount_set: RestMoneyBagSchema
2136
+ }))
2137
+ });
2138
+ const RefundEventSchema = Schema$1.toType(RefundWebhookPayloadSchema);
2139
+ const fromRefundWebhook = (payload) => ({
2140
+ id: payload.admin_graphql_api_id,
2141
+ legacyResourceId: String(payload.id),
2142
+ orderId: gid("Order", payload.order_id),
2143
+ note: payload.note ?? "",
2144
+ createdAt: payload.created_at,
2145
+ processedAt: payload.processed_at,
2146
+ transactions: payload.transactions.map((transaction) => ({
2147
+ id: transaction.admin_graphql_api_id,
2148
+ kind: transaction.kind,
2149
+ status: transaction.status,
2150
+ amount: normalizeAmount(transaction.amount),
2151
+ currencyCode: transaction.currency,
2152
+ gateway: transaction.gateway,
2153
+ test: transaction.test,
2154
+ errorCode: transaction.error_code?.toUpperCase() ?? null,
2155
+ parentTransactionId: transaction.parent_id === null ? null : gid("OrderTransaction", transaction.parent_id),
2156
+ createdAt: transaction.created_at,
2157
+ processedAt: transaction.processed_at
2158
+ })),
2159
+ refundLineItems: payload.refund_line_items.map((item) => ({
2160
+ id: gid("RefundLineItem", item.id),
2161
+ lineItemId: gid("LineItem", item.line_item_id),
2162
+ quantity: item.quantity,
2163
+ restockType: item.restock_type,
2164
+ locationId: item.location_id === null ? null : gid("Location", item.location_id),
2165
+ subtotalSet: fromRest.money(item.subtotal_set),
2166
+ totalTaxSet: fromRest.money(item.total_tax_set)
2167
+ })),
2168
+ refundShippingLines: payload.refund_shipping_lines.map((line) => ({
2169
+ id: gid("RefundShippingLine", line.id),
2170
+ shippingLineId: line.shipping_line_id === null ? null : gid("ShippingLine", line.shipping_line_id),
2171
+ subtotalAmountSet: fromRest.money(line.subtotal_amount_set)
2172
+ })),
2173
+ orderAdjustments: payload.order_adjustments.filter((adjustment) => adjustment.kind !== "shipping_refund").map((adjustment) => ({
2174
+ id: gid("OrderAdjustment", adjustment.id),
2175
+ reason: adjustment.reason?.toUpperCase().replaceAll(" ", "_") ?? null,
2176
+ amountSet: fromRest.money(adjustment.amount_set),
2177
+ taxAmountSet: fromRest.money(adjustment.tax_amount_set)
2178
+ })),
2179
+ duties: payload.duties.map((duty) => ({
2180
+ dutyId: duty.duty_id === null ? null : gid("Duty", duty.duty_id),
2181
+ amountSet: fromRest.money(duty.amount_set)
2182
+ }))
2183
+ });
2184
+ //#endregion
2185
+ //#region src/connector.ts
2186
+ var connector_exports = /* @__PURE__ */ __exportAll({
2187
+ ShopifyConfigDef: () => ShopifyConfigDef,
2188
+ ShopifyConnector: () => ShopifyConnector,
2189
+ layer: () => layer,
2190
+ layerConfig: () => layerConfig,
2191
+ make: () => make,
2192
+ manifest: () => manifest
2193
+ });
2194
+ const isValidWebhookSignature = (rawBody, signature, secret) => {
2195
+ if (!signature) return false;
2196
+ const digest = createHmac("sha256", secret).update(Buffer.from(rawBody)).digest();
2197
+ const provided = Buffer.from(signature, "base64");
2198
+ return provided.length === digest.length && timingSafeEqual(digest, provided);
2199
+ };
2200
+ const decodeTriggeredAt = (value) => Option.getOrNull(Schema.decodeUnknownOption(Schema.DateFromString)(value));
2201
+ const backfillPages = (fetchPage) => Fetch.page({
2202
+ pageCursor: Cursor.string(),
2203
+ cutoff: Cursor.isoDateTime(),
2204
+ fetch: ({ pageCursor }) => fetchPage({
2205
+ first: 50,
2206
+ after: typeof pageCursor === "string" ? pageCursor : void 0
2207
+ }).pipe(Effect.map((page) => ({
2208
+ rows: page.items,
2209
+ nextPageCursor: page.endCursor ?? void 0,
2210
+ hasMore: page.hasMore
2211
+ })))
2212
+ });
2213
+ const make = Effect.fnUntraced(function* (config) {
2214
+ const api = yield* ShopifyApiClient;
2215
+ const Products = Resource.entity({
2216
+ name: "products",
2217
+ rowSchema: ProductSchema,
2218
+ version: "updatedAt",
2219
+ check: api.checkProductsAccess,
2220
+ backfill: backfillPages(api.fetchProducts),
2221
+ webhook: {
2222
+ schema: ProductEventSchema,
2223
+ handler: ({ payload }) => {
2224
+ if (payload._tag === "delete") return Effect.succeed([{
2225
+ id: payload.id,
2226
+ updatedAt: payload.version,
2227
+ _deleted: true
2228
+ }]);
2229
+ const product = payload.payload;
2230
+ if (product.variants.length === product.variant_gids.length) return Effect.succeed([fromProductWebhook(product)]);
2231
+ const triggeredAt = payload.triggeredAt;
2232
+ return Effect.gen(function* () {
2233
+ const refetched = yield* api.fetchProductById(product.admin_graphql_api_id);
2234
+ if (Option.isSome(refetched)) return [refetched.value];
2235
+ return [{
2236
+ id: product.admin_graphql_api_id,
2237
+ updatedAt: triggeredAt,
2238
+ _deleted: true
2239
+ }];
2240
+ });
2241
+ }
2242
+ }
2243
+ });
2244
+ const Customers = Resource.entity({
2245
+ name: "customers",
2246
+ rowSchema: CustomerSchema,
2247
+ version: "updatedAt",
2248
+ check: api.checkCustomersAccess,
2249
+ backfill: backfillPages(api.fetchCustomers),
2250
+ webhook: {
2251
+ schema: CustomerEventSchema,
2252
+ handler: ({ payload: { _tag, id, version } }) => Effect.gen(function* () {
2253
+ const customer = _tag === "refresh" ? yield* api.fetchCustomerById(id) : Option.none();
2254
+ return Option.isNone(customer) ? [{
2255
+ id,
2256
+ updatedAt: version,
2257
+ _deleted: true
2258
+ }] : [customer.value];
2259
+ })
2260
+ }
2261
+ });
2262
+ const Orders = Resource.entity({
2263
+ name: "orders",
2264
+ rowSchema: OrderSchema,
2265
+ version: "updatedAt",
2266
+ check: api.checkOrdersAccess,
2267
+ backfill: backfillPages(api.fetchOrders),
2268
+ webhook: {
2269
+ schema: OrderEventSchema,
2270
+ handler: ({ payload }) => Effect.succeed(payload._tag === "delete" ? [{
2271
+ id: payload.id,
2272
+ updatedAt: payload.version,
2273
+ _deleted: true
2274
+ }] : [fromOrderWebhook(payload.payload)])
2275
+ }
2276
+ });
2277
+ const Refunds = Resource.entity({
2278
+ name: "refunds",
2279
+ rowSchema: RefundSchema,
2280
+ version: "processedAt",
2281
+ check: api.checkOrdersAccess,
2282
+ backfill: backfillPages(api.fetchRefunds),
2283
+ webhook: {
2284
+ schema: RefundEventSchema,
2285
+ handler: ({ payload }) => Effect.succeed([fromRefundWebhook(payload)])
2286
+ }
2287
+ });
2288
+ const Carts = Resource.entity({
2289
+ name: "carts",
2290
+ rowSchema: CartSchema,
2291
+ version: "updatedAt",
2292
+ check: api.checkConnection,
2293
+ webhook: {
2294
+ schema: CartWebhookEventSchema,
2295
+ handler: ({ payload }) => Effect.succeed([fromCartWebhook(payload)])
2296
+ }
2297
+ });
2298
+ const webhookRoute = Webhook.route({
2299
+ path: "/webhooks/shopify",
2300
+ ackMode: "after-ingest",
2301
+ schema: Schema.Unknown,
2302
+ handler: ({ request, rawBody, payload: json, to }) => Effect.gen(function* () {
2303
+ const signature = request.headers["x-shopify-hmac-sha256"];
2304
+ if (!isValidWebhookSignature(rawBody, signature, Redacted.value(config.webhookSecret))) return HttpServerResponse.jsonUnsafe({
2305
+ ok: false,
2306
+ error: "Shopify webhook verification failed"
2307
+ }, { status: 401 });
2308
+ const topic = request.headers["x-shopify-topic"] ?? "";
2309
+ const decode = (schema) => Schema.decodeUnknownOption(schema)(json);
2310
+ const invalid = HttpServerResponse.jsonUnsafe({
2311
+ ok: false,
2312
+ error: `Invalid Shopify webhook for ${topic}`
2313
+ }, { status: 400 });
2314
+ const triggeredAt = decodeTriggeredAt(request.headers["x-shopify-triggered-at"]);
2315
+ if (triggeredAt === null) return invalid;
2316
+ switch (topic) {
2317
+ case "products/create":
2318
+ case "products/update": {
2319
+ const payload = decode(ProductWebhookPayloadSchema);
2320
+ if (Option.isNone(payload)) return invalid;
2321
+ yield* to(Products, {
2322
+ _tag: "upsert",
2323
+ payload: payload.value,
2324
+ triggeredAt
2325
+ });
2326
+ break;
2327
+ }
2328
+ case "products/delete": {
2329
+ const payload = decode(ProductDeleteWebhookPayloadSchema);
2330
+ if (Option.isNone(payload)) return invalid;
2331
+ yield* to(Products, {
2332
+ _tag: "delete",
2333
+ id: gid("Product", payload.value.id),
2334
+ version: triggeredAt
2335
+ });
2336
+ break;
2337
+ }
2338
+ case "carts/create":
2339
+ case "carts/update": {
2340
+ const payload = decode(CartWebhookPayloadSchema);
2341
+ if (Option.isNone(payload)) return invalid;
2342
+ yield* to(Carts, {
2343
+ ...payload.value,
2344
+ topic
2345
+ });
2346
+ break;
2347
+ }
2348
+ case "customers/create":
2349
+ case "customers/disable":
2350
+ case "customers/enable":
2351
+ case "customers/update": {
2352
+ const payload = decode(CustomerWebhookPayloadSchema);
2353
+ if (Option.isNone(payload)) return invalid;
2354
+ yield* to(Customers, {
2355
+ _tag: "refresh",
2356
+ id: payload.value.admin_graphql_api_id,
2357
+ version: payload.value.updated_at
2358
+ });
2359
+ break;
2360
+ }
2361
+ case "customers/purchasing_summary": {
2362
+ const payload = decode(CustomerPurchaseSummaryPayloadSchema);
2363
+ if (Option.isNone(payload)) return invalid;
2364
+ yield* to(Customers, {
2365
+ _tag: "refresh",
2366
+ id: payload.value.customerId,
2367
+ version: payload.value.occurredAt
2368
+ });
2369
+ break;
2370
+ }
2371
+ case "customers_email_marketing_consent/update": {
2372
+ const payload = decode(CustomerEmailConsentPayloadSchema);
2373
+ if (Option.isNone(payload)) return invalid;
2374
+ yield* to(Customers, {
2375
+ _tag: "refresh",
2376
+ id: gid("Customer", payload.value.customer_id),
2377
+ version: triggeredAt
2378
+ });
2379
+ break;
2380
+ }
2381
+ case "customers_marketing_consent/update": {
2382
+ const payload = decode(CustomerSmsConsentPayloadSchema);
2383
+ if (Option.isNone(payload)) return invalid;
2384
+ yield* to(Customers, {
2385
+ _tag: "refresh",
2386
+ id: gid("Customer", payload.value.id),
2387
+ version: triggeredAt
2388
+ });
2389
+ break;
2390
+ }
2391
+ case "customer.tags_added":
2392
+ case "customer.tags_removed": {
2393
+ const payload = decode(CustomerTagsPayloadSchema);
2394
+ if (Option.isNone(payload)) return invalid;
2395
+ yield* to(Customers, {
2396
+ _tag: "refresh",
2397
+ id: payload.value.customerId,
2398
+ version: payload.value.occurredAt
2399
+ });
2400
+ break;
2401
+ }
2402
+ case "customers/delete": {
2403
+ const payload = decode(CustomerDeleteWebhookPayloadSchema);
2404
+ if (Option.isNone(payload)) return invalid;
2405
+ yield* to(Customers, {
2406
+ _tag: "delete",
2407
+ id: gid("Customer", payload.value.id),
2408
+ version: triggeredAt
2409
+ });
2410
+ break;
2411
+ }
2412
+ case "orders/create":
2413
+ case "orders/updated": {
2414
+ const payload = decode(OrderWebhookPayloadSchema);
2415
+ if (Option.isNone(payload)) return invalid;
2416
+ yield* to(Orders, {
2417
+ _tag: "upsert",
2418
+ payload: payload.value
2419
+ });
2420
+ break;
2421
+ }
2422
+ case "orders/delete": {
2423
+ const payload = decode(OrderDeleteWebhookPayloadSchema);
2424
+ if (Option.isNone(payload)) return invalid;
2425
+ yield* to(Orders, {
2426
+ _tag: "delete",
2427
+ id: gid("Order", payload.value.id),
2428
+ version: triggeredAt
2429
+ });
2430
+ break;
2431
+ }
2432
+ case "refunds/create": {
2433
+ const payload = decode(RefundWebhookPayloadSchema);
2434
+ if (Option.isNone(payload)) return invalid;
2435
+ yield* to(Refunds, payload.value);
2436
+ break;
2437
+ }
2438
+ default: yield* Effect.logWarning("Ignoring unknown Shopify webhook topic").pipe(Effect.annotateLogs({ topic }));
2439
+ }
2440
+ return HttpServerResponse.jsonUnsafe({ ok: true });
2441
+ })
2442
+ });
2443
+ return Connector.define({
2444
+ name: "producer-shopify",
2445
+ title: "Shopify",
2446
+ resources: [
2447
+ Products,
2448
+ Carts,
2449
+ Customers,
2450
+ Orders,
2451
+ Refunds
2452
+ ],
2453
+ webhooks: [webhookRoute]
2454
+ });
2455
+ });
2456
+ var ShopifyConnector = class extends Context.Service()("@useairfoil/producer-shopify/ShopifyConnector") {};
2457
+ const layer = (config) => {
2458
+ const authLayer = layer$2(config);
2459
+ const apiLayer = layer$1(config).pipe(Layer.provide(authLayer));
2460
+ return Layer.effect(ShopifyConnector)(make(config).pipe(Effect.annotateLogs({ component: "producer-shopify" }))).pipe(Layer.provide(apiLayer));
2461
+ };
2462
+ const layerConfig = (config) => Layer.unwrap(Config.unwrap(config).pipe(Effect.map(layer)));
2463
+ //#endregion
2464
+ //#region src/index.ts
2465
+ const ShopifyNormalize = {
2466
+ productWebhook: fromProductWebhook,
2467
+ cartWebhook: fromCartWebhook
2468
+ };
2469
+ //#endregion
2470
+ export { CartWebhookPayloadSchema as C, normalizeAmount as E, ProductVariantSchema as S, gid as T, ProductWebhookPayloadSchema as _, RefundWebhookPayloadSchema as a, ProductStatusSchema as b, OrderWebhookPayloadSchema as c, CartSchema as d, client_exports as f, ProductDeleteWebhookPayloadSchema as g, CustomerSchema as h, layerConfig as i, fromOrderWebhook as l, OrderSchema as m, ShopifyConnector as n, fromRefundWebhook as o, RefundSchema as p, connector_exports as r, OrderDeleteWebhookPayloadSchema as s, ShopifyNormalize as t, CartLineItemSchema as u, ProductOptionSchema as v, PageInfoSchema as w, ProductVariantInventoryPolicySchema as x, ProductSchema as y };
2471
+
2472
+ //# sourceMappingURL=src-YBU_KSf5.mjs.map