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