@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,248 @@
|
|
|
1
|
+
import * as Schema from "effect/Schema";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
RestAddressSchema,
|
|
5
|
+
RestAttributeSchema,
|
|
6
|
+
RestDiscountAllocationSchema,
|
|
7
|
+
RestMoneyBagSchema,
|
|
8
|
+
RestTaxLineSchema,
|
|
9
|
+
emptyText,
|
|
10
|
+
fromRest,
|
|
11
|
+
gid,
|
|
12
|
+
normalizeAmount,
|
|
13
|
+
splitTags,
|
|
14
|
+
upper,
|
|
15
|
+
} from "../shared";
|
|
16
|
+
import {
|
|
17
|
+
DiscountAllocationMethodSchema,
|
|
18
|
+
type DiscountApplication,
|
|
19
|
+
DiscountApplicationTypeSchema,
|
|
20
|
+
DiscountTargetSelectionSchema,
|
|
21
|
+
DiscountTargetTypeSchema,
|
|
22
|
+
DiscountValueTypeSchema,
|
|
23
|
+
OrderCancelReasonSchema,
|
|
24
|
+
OrderFinancialStatusSchema,
|
|
25
|
+
type Order,
|
|
26
|
+
} from "./row";
|
|
27
|
+
|
|
28
|
+
const nullableMoney = Schema.NullOr(RestMoneyBagSchema);
|
|
29
|
+
|
|
30
|
+
const RestShippingLineSchema = Schema.Struct({
|
|
31
|
+
id: Schema.NullOr(Schema.Number),
|
|
32
|
+
title: Schema.String,
|
|
33
|
+
code: Schema.NullOr(Schema.String),
|
|
34
|
+
source: Schema.NullOr(Schema.String),
|
|
35
|
+
carrier_identifier: Schema.NullOr(Schema.String),
|
|
36
|
+
phone: Schema.NullOr(Schema.String),
|
|
37
|
+
is_removed: Schema.Boolean,
|
|
38
|
+
price_set: RestMoneyBagSchema,
|
|
39
|
+
discounted_price_set: RestMoneyBagSchema,
|
|
40
|
+
current_discounted_price_set: RestMoneyBagSchema,
|
|
41
|
+
tax_lines: Schema.Array(RestTaxLineSchema),
|
|
42
|
+
discount_allocations: Schema.Array(RestDiscountAllocationSchema),
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const RestLineItemSchema = Schema.Struct({
|
|
46
|
+
admin_graphql_api_id: Schema.String,
|
|
47
|
+
name: Schema.String,
|
|
48
|
+
title: Schema.String,
|
|
49
|
+
variant_title: Schema.NullOr(Schema.String),
|
|
50
|
+
sku: Schema.NullOr(Schema.String),
|
|
51
|
+
vendor: Schema.NullOr(Schema.String),
|
|
52
|
+
product_id: Schema.NullOr(Schema.Number),
|
|
53
|
+
variant_id: Schema.NullOr(Schema.Number),
|
|
54
|
+
quantity: Schema.Int,
|
|
55
|
+
current_quantity: Schema.Int,
|
|
56
|
+
taxable: Schema.Boolean,
|
|
57
|
+
requires_shipping: Schema.Boolean,
|
|
58
|
+
gift_card: Schema.Boolean,
|
|
59
|
+
price_set: RestMoneyBagSchema,
|
|
60
|
+
total_discount_set: RestMoneyBagSchema,
|
|
61
|
+
tax_lines: Schema.Array(RestTaxLineSchema),
|
|
62
|
+
discount_allocations: Schema.Array(RestDiscountAllocationSchema),
|
|
63
|
+
properties: Schema.Array(RestAttributeSchema),
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const RestDiscountApplicationSchema = Schema.Struct({
|
|
67
|
+
type: upper(DiscountApplicationTypeSchema),
|
|
68
|
+
code: Schema.optional(Schema.NullOr(Schema.String)),
|
|
69
|
+
title: Schema.optional(Schema.NullOr(Schema.String)),
|
|
70
|
+
description: Schema.optional(Schema.NullOr(Schema.String)),
|
|
71
|
+
allocation_method: upper(DiscountAllocationMethodSchema),
|
|
72
|
+
target_selection: upper(DiscountTargetSelectionSchema),
|
|
73
|
+
target_type: upper(DiscountTargetTypeSchema),
|
|
74
|
+
value_type: upper(DiscountValueTypeSchema),
|
|
75
|
+
value: Schema.String,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
export const OrderWebhookPayloadSchema = Schema.Struct({
|
|
79
|
+
id: Schema.Number,
|
|
80
|
+
admin_graphql_api_id: Schema.String,
|
|
81
|
+
name: Schema.String,
|
|
82
|
+
email: Schema.NullOr(Schema.String),
|
|
83
|
+
phone: Schema.NullOr(Schema.String),
|
|
84
|
+
customer: Schema.NullOr(Schema.Struct({ admin_graphql_api_id: Schema.String })),
|
|
85
|
+
customer_locale: Schema.NullOr(Schema.String),
|
|
86
|
+
buyer_accepts_marketing: Schema.Boolean,
|
|
87
|
+
billing_address: Schema.NullOr(RestAddressSchema),
|
|
88
|
+
shipping_address: Schema.NullOr(RestAddressSchema),
|
|
89
|
+
note: Schema.NullOr(Schema.String),
|
|
90
|
+
note_attributes: Schema.Array(RestAttributeSchema),
|
|
91
|
+
tags: Schema.String,
|
|
92
|
+
confirmation_number: Schema.NullOr(Schema.String),
|
|
93
|
+
po_number: Schema.NullOr(Schema.String),
|
|
94
|
+
source_name: Schema.NullOr(Schema.String),
|
|
95
|
+
source_identifier: Schema.NullOr(Schema.String),
|
|
96
|
+
app_id: Schema.NullOr(Schema.Number),
|
|
97
|
+
payment_gateway_names: Schema.Array(Schema.String),
|
|
98
|
+
test: Schema.Boolean,
|
|
99
|
+
taxes_included: Schema.Boolean,
|
|
100
|
+
tax_exempt: Schema.Boolean,
|
|
101
|
+
duties_included: Schema.Boolean,
|
|
102
|
+
estimated_taxes: Schema.Boolean,
|
|
103
|
+
total_weight: Schema.NullOr(Schema.Int),
|
|
104
|
+
financial_status: Schema.NullOr(upper(OrderFinancialStatusSchema)),
|
|
105
|
+
cancel_reason: Schema.NullOr(upper(OrderCancelReasonSchema)),
|
|
106
|
+
cancelled_at: Schema.NullOr(Schema.DateFromString),
|
|
107
|
+
closed_at: Schema.NullOr(Schema.DateFromString),
|
|
108
|
+
processed_at: Schema.DateFromString,
|
|
109
|
+
created_at: Schema.DateFromString,
|
|
110
|
+
updated_at: Schema.DateFromString,
|
|
111
|
+
currency: Schema.String,
|
|
112
|
+
presentment_currency: Schema.String,
|
|
113
|
+
discount_codes: Schema.Array(Schema.Struct({ code: Schema.String })),
|
|
114
|
+
discount_applications: Schema.Array(RestDiscountApplicationSchema),
|
|
115
|
+
subtotal_price_set: nullableMoney,
|
|
116
|
+
current_subtotal_price_set: RestMoneyBagSchema,
|
|
117
|
+
total_discounts_set: nullableMoney,
|
|
118
|
+
current_total_discounts_set: RestMoneyBagSchema,
|
|
119
|
+
total_shipping_price_set: RestMoneyBagSchema,
|
|
120
|
+
current_shipping_price_set: RestMoneyBagSchema,
|
|
121
|
+
total_tax_set: nullableMoney,
|
|
122
|
+
current_total_tax_set: RestMoneyBagSchema,
|
|
123
|
+
original_total_duties_set: nullableMoney,
|
|
124
|
+
current_total_duties_set: nullableMoney,
|
|
125
|
+
total_price_set: RestMoneyBagSchema,
|
|
126
|
+
current_total_price_set: RestMoneyBagSchema,
|
|
127
|
+
tax_lines: Schema.Array(RestTaxLineSchema),
|
|
128
|
+
shipping_lines: Schema.Array(RestShippingLineSchema),
|
|
129
|
+
line_items: Schema.Array(RestLineItemSchema),
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
export const OrderDeleteWebhookPayloadSchema = Schema.Struct({ id: Schema.Number });
|
|
133
|
+
|
|
134
|
+
export const OrderEventSchema = Schema.Union([
|
|
135
|
+
Schema.Struct({
|
|
136
|
+
_tag: Schema.Literal("upsert"),
|
|
137
|
+
payload: Schema.toType(OrderWebhookPayloadSchema),
|
|
138
|
+
}),
|
|
139
|
+
Schema.Struct({
|
|
140
|
+
_tag: Schema.Literal("delete"),
|
|
141
|
+
id: Schema.String,
|
|
142
|
+
version: Schema.Date,
|
|
143
|
+
}),
|
|
144
|
+
]);
|
|
145
|
+
|
|
146
|
+
export type OrderWebhookPayload = Schema.Schema.Type<typeof OrderWebhookPayloadSchema>;
|
|
147
|
+
|
|
148
|
+
const orMoney = (bag: Schema.Schema.Type<typeof RestMoneyBagSchema> | null) =>
|
|
149
|
+
bag === null ? null : fromRest.money(bag);
|
|
150
|
+
|
|
151
|
+
export const fromOrderWebhook = (payload: OrderWebhookPayload): Order => ({
|
|
152
|
+
id: payload.admin_graphql_api_id,
|
|
153
|
+
legacyResourceId: String(payload.id),
|
|
154
|
+
name: payload.name,
|
|
155
|
+
email: emptyText(payload.email),
|
|
156
|
+
phone: emptyText(payload.phone),
|
|
157
|
+
customerId: payload.customer?.admin_graphql_api_id ?? "",
|
|
158
|
+
customerLocale: emptyText(payload.customer_locale),
|
|
159
|
+
customerAcceptsMarketing: payload.buyer_accepts_marketing,
|
|
160
|
+
billingAddress: payload.billing_address ? fromRest.address(payload.billing_address) : null,
|
|
161
|
+
shippingAddress: payload.shipping_address ? fromRest.address(payload.shipping_address) : null,
|
|
162
|
+
note: emptyText(payload.note),
|
|
163
|
+
customAttributes: payload.note_attributes.map(fromRest.attribute),
|
|
164
|
+
tags: splitTags(payload.tags),
|
|
165
|
+
confirmationNumber: emptyText(payload.confirmation_number),
|
|
166
|
+
poNumber: emptyText(payload.po_number),
|
|
167
|
+
sourceName: emptyText(payload.source_name),
|
|
168
|
+
sourceIdentifier: emptyText(payload.source_identifier),
|
|
169
|
+
appId: payload.app_id === null ? "" : gid("App", payload.app_id),
|
|
170
|
+
paymentGatewayNames: payload.payment_gateway_names,
|
|
171
|
+
test: payload.test,
|
|
172
|
+
taxesIncluded: payload.taxes_included,
|
|
173
|
+
taxExempt: payload.tax_exempt,
|
|
174
|
+
dutiesIncluded: payload.duties_included,
|
|
175
|
+
estimatedTaxes: payload.estimated_taxes,
|
|
176
|
+
totalWeight: payload.total_weight,
|
|
177
|
+
displayFinancialStatus: payload.financial_status,
|
|
178
|
+
cancelReason: payload.cancel_reason,
|
|
179
|
+
cancelledAt: payload.cancelled_at,
|
|
180
|
+
closedAt: payload.closed_at,
|
|
181
|
+
processedAt: payload.processed_at,
|
|
182
|
+
createdAt: payload.created_at,
|
|
183
|
+
updatedAt: payload.updated_at,
|
|
184
|
+
currencyCode: payload.currency,
|
|
185
|
+
presentmentCurrencyCode: payload.presentment_currency,
|
|
186
|
+
discountCodes: payload.discount_codes.map((discount) => discount.code),
|
|
187
|
+
discountApplications: payload.discount_applications.map(
|
|
188
|
+
(application, index): DiscountApplication => ({
|
|
189
|
+
index,
|
|
190
|
+
type: application.type,
|
|
191
|
+
code: application.type === "DISCOUNT_CODE" ? (application.code ?? null) : null,
|
|
192
|
+
title: application.type === "DISCOUNT_CODE" ? null : (application.title ?? null),
|
|
193
|
+
description: application.type === "MANUAL" ? (application.description ?? null) : null,
|
|
194
|
+
allocationMethod: application.allocation_method,
|
|
195
|
+
targetSelection: application.target_selection,
|
|
196
|
+
targetType: application.target_type,
|
|
197
|
+
valueType: application.value_type,
|
|
198
|
+
value: normalizeAmount(application.value),
|
|
199
|
+
}),
|
|
200
|
+
),
|
|
201
|
+
subtotalPriceSet: orMoney(payload.subtotal_price_set),
|
|
202
|
+
currentSubtotalPriceSet: fromRest.money(payload.current_subtotal_price_set),
|
|
203
|
+
totalDiscountsSet: orMoney(payload.total_discounts_set),
|
|
204
|
+
currentTotalDiscountsSet: fromRest.money(payload.current_total_discounts_set),
|
|
205
|
+
totalShippingPriceSet: fromRest.money(payload.total_shipping_price_set),
|
|
206
|
+
currentShippingPriceSet: fromRest.money(payload.current_shipping_price_set),
|
|
207
|
+
totalTaxSet: orMoney(payload.total_tax_set),
|
|
208
|
+
currentTotalTaxSet: fromRest.money(payload.current_total_tax_set),
|
|
209
|
+
originalTotalDutiesSet: orMoney(payload.original_total_duties_set),
|
|
210
|
+
currentTotalDutiesSet: orMoney(payload.current_total_duties_set),
|
|
211
|
+
totalPriceSet: fromRest.money(payload.total_price_set),
|
|
212
|
+
currentTotalPriceSet: fromRest.money(payload.current_total_price_set),
|
|
213
|
+
taxLines: payload.tax_lines.map(fromRest.taxLine),
|
|
214
|
+
shippingLines: payload.shipping_lines.map((line) => ({
|
|
215
|
+
id: line.id === null ? null : gid("ShippingLine", line.id),
|
|
216
|
+
title: line.title,
|
|
217
|
+
code: line.code,
|
|
218
|
+
source: line.source,
|
|
219
|
+
carrierIdentifier: line.carrier_identifier,
|
|
220
|
+
phone: line.phone,
|
|
221
|
+
isRemoved: line.is_removed,
|
|
222
|
+
originalPriceSet: fromRest.money(line.price_set),
|
|
223
|
+
discountedPriceSet: fromRest.money(line.discounted_price_set),
|
|
224
|
+
currentDiscountedPriceSet: fromRest.money(line.current_discounted_price_set),
|
|
225
|
+
taxLines: line.tax_lines.map(fromRest.taxLine),
|
|
226
|
+
discountAllocations: line.discount_allocations.map(fromRest.discountAllocation),
|
|
227
|
+
})),
|
|
228
|
+
lineItems: payload.line_items.map((item) => ({
|
|
229
|
+
id: item.admin_graphql_api_id,
|
|
230
|
+
name: item.name,
|
|
231
|
+
title: item.title,
|
|
232
|
+
variantTitle: item.variant_title,
|
|
233
|
+
sku: item.sku,
|
|
234
|
+
vendor: item.vendor,
|
|
235
|
+
productId: item.product_id === null ? null : gid("Product", item.product_id),
|
|
236
|
+
variantId: item.variant_id === null ? null : gid("ProductVariant", item.variant_id),
|
|
237
|
+
quantity: item.quantity,
|
|
238
|
+
currentQuantity: item.current_quantity,
|
|
239
|
+
taxable: item.taxable,
|
|
240
|
+
requiresShipping: item.requires_shipping,
|
|
241
|
+
isGiftCard: item.gift_card,
|
|
242
|
+
originalUnitPriceSet: fromRest.money(item.price_set),
|
|
243
|
+
totalDiscountSet: fromRest.money(item.total_discount_set),
|
|
244
|
+
taxLines: item.tax_lines.map(fromRest.taxLine),
|
|
245
|
+
discountAllocations: item.discount_allocations.map(fromRest.discountAllocation),
|
|
246
|
+
customAttributes: item.properties.map(fromRest.attribute),
|
|
247
|
+
})),
|
|
248
|
+
});
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import * as Schema from "effect/Schema";
|
|
2
|
+
|
|
3
|
+
import { connection, pageQuery } from "../shared";
|
|
4
|
+
import {
|
|
5
|
+
type Product,
|
|
6
|
+
ProductOptionSchema,
|
|
7
|
+
ProductStatusSchema,
|
|
8
|
+
ProductVariantInventoryPolicySchema,
|
|
9
|
+
} from "./row";
|
|
10
|
+
|
|
11
|
+
const ProductVariantFields = `
|
|
12
|
+
id
|
|
13
|
+
legacyResourceId
|
|
14
|
+
title
|
|
15
|
+
sku
|
|
16
|
+
barcode
|
|
17
|
+
price
|
|
18
|
+
compareAtPrice
|
|
19
|
+
inventoryPolicy
|
|
20
|
+
taxable
|
|
21
|
+
createdAt
|
|
22
|
+
updatedAt
|
|
23
|
+
`;
|
|
24
|
+
|
|
25
|
+
const ProductFields = `
|
|
26
|
+
id
|
|
27
|
+
legacyResourceId
|
|
28
|
+
title
|
|
29
|
+
handle
|
|
30
|
+
descriptionHtml
|
|
31
|
+
productType
|
|
32
|
+
vendor
|
|
33
|
+
status
|
|
34
|
+
tags
|
|
35
|
+
createdAt
|
|
36
|
+
updatedAt
|
|
37
|
+
publishedAt
|
|
38
|
+
templateSuffix
|
|
39
|
+
featuredMedia { ... on MediaImage { image { url altText } } }
|
|
40
|
+
options(first: 100) { id name position values }
|
|
41
|
+
variants(first: 25) { nodes { ${ProductVariantFields} } pageInfo { hasNextPage endCursor } }
|
|
42
|
+
`;
|
|
43
|
+
|
|
44
|
+
export const ProductByIdQuery = `#graphql
|
|
45
|
+
query AirfoilProductById($id: ID!) {
|
|
46
|
+
product(id: $id) { ${ProductFields} }
|
|
47
|
+
}
|
|
48
|
+
`;
|
|
49
|
+
|
|
50
|
+
export const ProductVariantsQuery = `#graphql
|
|
51
|
+
query AirfoilProductVariants($id: ID!, $first: Int!, $after: String) {
|
|
52
|
+
node: product(id: $id) {
|
|
53
|
+
connection: variants(first: $first, after: $after) {
|
|
54
|
+
nodes { ${ProductVariantFields} }
|
|
55
|
+
pageInfo { hasNextPage endCursor }
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
`;
|
|
60
|
+
|
|
61
|
+
export const ProductsQuery = pageQuery("AirfoilProducts", "products", ProductFields);
|
|
62
|
+
|
|
63
|
+
export const GraphQLProductVariantNodeSchema = Schema.Struct({
|
|
64
|
+
id: Schema.String,
|
|
65
|
+
legacyResourceId: Schema.String,
|
|
66
|
+
title: Schema.String,
|
|
67
|
+
sku: Schema.NullOr(Schema.String),
|
|
68
|
+
barcode: Schema.NullOr(Schema.String),
|
|
69
|
+
price: Schema.String,
|
|
70
|
+
compareAtPrice: Schema.NullOr(Schema.String),
|
|
71
|
+
inventoryPolicy: ProductVariantInventoryPolicySchema,
|
|
72
|
+
taxable: Schema.Boolean,
|
|
73
|
+
createdAt: Schema.DateFromString,
|
|
74
|
+
updatedAt: Schema.DateFromString,
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
const GraphQLFeaturedMediaSchema = Schema.Struct({
|
|
78
|
+
image: Schema.optional(
|
|
79
|
+
Schema.NullOr(
|
|
80
|
+
Schema.Struct({
|
|
81
|
+
url: Schema.String,
|
|
82
|
+
altText: Schema.NullOr(Schema.String),
|
|
83
|
+
}),
|
|
84
|
+
),
|
|
85
|
+
),
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const GraphQLProductNodeSchema = Schema.Struct({
|
|
89
|
+
id: Schema.String,
|
|
90
|
+
legacyResourceId: Schema.String,
|
|
91
|
+
title: Schema.String,
|
|
92
|
+
handle: Schema.String,
|
|
93
|
+
descriptionHtml: Schema.String,
|
|
94
|
+
productType: Schema.String,
|
|
95
|
+
vendor: Schema.String,
|
|
96
|
+
status: ProductStatusSchema,
|
|
97
|
+
tags: Schema.Array(Schema.String),
|
|
98
|
+
createdAt: Schema.DateFromString,
|
|
99
|
+
updatedAt: Schema.DateFromString,
|
|
100
|
+
publishedAt: Schema.NullOr(Schema.DateFromString),
|
|
101
|
+
templateSuffix: Schema.NullOr(Schema.String),
|
|
102
|
+
featuredMedia: Schema.NullOr(GraphQLFeaturedMediaSchema),
|
|
103
|
+
options: Schema.Array(ProductOptionSchema),
|
|
104
|
+
variants: connection(GraphQLProductVariantNodeSchema),
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
export const GraphQLProductsDataSchema = Schema.Struct({
|
|
108
|
+
products: connection(GraphQLProductNodeSchema),
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
export const GraphQLProductByIdDataSchema = Schema.Struct({
|
|
112
|
+
product: Schema.NullOr(GraphQLProductNodeSchema),
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
export type GraphQLProductNode = Schema.Schema.Type<typeof GraphQLProductNodeSchema>;
|
|
116
|
+
|
|
117
|
+
type GraphQLProductVariantNode = Schema.Schema.Type<typeof GraphQLProductVariantNodeSchema>;
|
|
118
|
+
|
|
119
|
+
export const normalizeProductNode = (
|
|
120
|
+
node: GraphQLProductNode,
|
|
121
|
+
variants: ReadonlyArray<GraphQLProductVariantNode>,
|
|
122
|
+
): Product => ({
|
|
123
|
+
id: node.id,
|
|
124
|
+
legacyResourceId: node.legacyResourceId,
|
|
125
|
+
title: node.title,
|
|
126
|
+
handle: node.handle,
|
|
127
|
+
descriptionHtml: node.descriptionHtml,
|
|
128
|
+
productType: node.productType,
|
|
129
|
+
vendor: node.vendor,
|
|
130
|
+
status: node.status,
|
|
131
|
+
tags: node.tags,
|
|
132
|
+
createdAt: node.createdAt,
|
|
133
|
+
updatedAt: node.updatedAt,
|
|
134
|
+
publishedAt: node.publishedAt,
|
|
135
|
+
templateSuffix: node.templateSuffix ?? "",
|
|
136
|
+
featuredMedia:
|
|
137
|
+
node.featuredMedia === null || node.featuredMedia.image === undefined
|
|
138
|
+
? null
|
|
139
|
+
: { image: node.featuredMedia.image },
|
|
140
|
+
options: node.options,
|
|
141
|
+
variants,
|
|
142
|
+
});
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { Iceberg } from "@useairfoil/connector-kit";
|
|
2
|
+
import * as Schema from "effect/Schema";
|
|
3
|
+
|
|
4
|
+
import { field } from "../shared";
|
|
5
|
+
|
|
6
|
+
export const ProductStatusSchema = Schema.Literals(["ACTIVE", "ARCHIVED", "DRAFT", "UNLISTED"]);
|
|
7
|
+
|
|
8
|
+
export const ProductVariantInventoryPolicySchema = Schema.Literals(["CONTINUE", "DENY"]);
|
|
9
|
+
|
|
10
|
+
const ProductImageSchema = Schema.Struct({
|
|
11
|
+
url: Schema.String.pipe(field(202, "URL of the image.")),
|
|
12
|
+
altText: Schema.NullOr(Schema.String).pipe(field(203, "Alternative text for the image.")),
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export const ProductFeaturedMediaSchema = Schema.Struct({
|
|
16
|
+
image: Schema.NullOr(ProductImageSchema).pipe(field(201, "Image for the featured media.")),
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export const ProductOptionSchema = Schema.Struct({
|
|
20
|
+
id: Schema.String.pipe(field(302, "Unique product option identifier.")),
|
|
21
|
+
name: Schema.String.pipe(field(303, "Name of the product option.")),
|
|
22
|
+
position: Schema.Int.pipe(field(304, "Position of the option on the product.")),
|
|
23
|
+
values: Schema.Array(Schema.String.annotate({ fieldId: 306 })).pipe(
|
|
24
|
+
field(305, "Values available for the option."),
|
|
25
|
+
),
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
export const ProductVariantSchema = Schema.Struct({
|
|
29
|
+
id: Schema.String.pipe(field(402, "Unique product variant identifier.")),
|
|
30
|
+
legacyResourceId: Schema.String.pipe(field(403, "Numeric variant identifier stored as text.")),
|
|
31
|
+
title: Schema.String.pipe(field(404, "Display title of the variant.")),
|
|
32
|
+
sku: Schema.NullOr(Schema.String).pipe(field(405, "Stock keeping unit for the variant.")),
|
|
33
|
+
barcode: Schema.NullOr(Schema.String).pipe(field(406, "Barcode for the variant.")),
|
|
34
|
+
price: Schema.String.pipe(field(407, "Price of the variant.")),
|
|
35
|
+
compareAtPrice: Schema.NullOr(Schema.String).pipe(
|
|
36
|
+
field(408, "Original price used for comparison."),
|
|
37
|
+
),
|
|
38
|
+
inventoryPolicy: ProductVariantInventoryPolicySchema.pipe(
|
|
39
|
+
field(409, "Behavior when the variant is out of stock."),
|
|
40
|
+
),
|
|
41
|
+
taxable: Schema.Boolean.pipe(field(410, "Whether the variant is taxable.")),
|
|
42
|
+
createdAt: Schema.Date.pipe(field(411, "Time when the variant was created.")),
|
|
43
|
+
updatedAt: Schema.Date.pipe(field(412, "Time when the variant was last changed.")),
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
export const ProductSchema = Schema.Struct({
|
|
47
|
+
id: Schema.String.pipe(field(1, "Unique product identifier.")),
|
|
48
|
+
legacyResourceId: Schema.String.pipe(field(2, "Numeric product identifier stored as text.")),
|
|
49
|
+
title: Schema.String.pipe(field(3, "Title of the product.")),
|
|
50
|
+
handle: Schema.String.pipe(field(4, "URL handle for the product.")),
|
|
51
|
+
descriptionHtml: Schema.String.pipe(field(5, "Product description as HTML.")),
|
|
52
|
+
productType: Schema.String.pipe(field(6, "Merchant-defined product type.")),
|
|
53
|
+
vendor: Schema.String.pipe(field(7, "Vendor of the product.")),
|
|
54
|
+
status: ProductStatusSchema.pipe(field(8, "Current product status.")),
|
|
55
|
+
tags: Schema.Array(Schema.String.annotate({ fieldId: 101 })).pipe(
|
|
56
|
+
field(9, "Tags added to the product."),
|
|
57
|
+
),
|
|
58
|
+
createdAt: Schema.Date.pipe(field(10, "Time when the product was created.")),
|
|
59
|
+
updatedAt: Schema.Date.pipe(field(11, "Time when the product was last changed.")),
|
|
60
|
+
publishedAt: Schema.NullOr(Schema.Date).pipe(field(12, "Time when the product was published.")),
|
|
61
|
+
templateSuffix: Schema.NullOr(Schema.String).pipe(
|
|
62
|
+
field(13, "Theme template suffix used by the product."),
|
|
63
|
+
),
|
|
64
|
+
featuredMedia: Schema.NullOr(ProductFeaturedMediaSchema).pipe(
|
|
65
|
+
field(14, "Featured media for the product."),
|
|
66
|
+
),
|
|
67
|
+
options: Schema.Array(ProductOptionSchema.annotate({ fieldId: 301 })).pipe(
|
|
68
|
+
field(15, "Options for the product."),
|
|
69
|
+
),
|
|
70
|
+
variants: Schema.Array(ProductVariantSchema.annotate({ fieldId: 401 })).pipe(
|
|
71
|
+
field(16, "Variants of the product."),
|
|
72
|
+
),
|
|
73
|
+
_deleted: Schema.optional(Schema.Boolean).pipe(field(17, "Whether the product was deleted.")),
|
|
74
|
+
})
|
|
75
|
+
.annotate({
|
|
76
|
+
description: "Products in a Shopify store.",
|
|
77
|
+
})
|
|
78
|
+
.pipe(Iceberg.identifier("id"));
|
|
79
|
+
|
|
80
|
+
export type ProductStatus = Schema.Schema.Type<typeof ProductStatusSchema>;
|
|
81
|
+
|
|
82
|
+
export type ProductVariantInventoryPolicy = Schema.Schema.Type<
|
|
83
|
+
typeof ProductVariantInventoryPolicySchema
|
|
84
|
+
>;
|
|
85
|
+
|
|
86
|
+
export type ProductFeaturedMedia = Schema.Schema.Type<typeof ProductFeaturedMediaSchema>;
|
|
87
|
+
|
|
88
|
+
export type ProductOption = Schema.Schema.Type<typeof ProductOptionSchema>;
|
|
89
|
+
|
|
90
|
+
export type ProductVariant = Schema.Schema.Type<typeof ProductVariantSchema>;
|
|
91
|
+
|
|
92
|
+
export type Product = Schema.Schema.Type<typeof ProductSchema>;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import * as Schema from "effect/Schema";
|
|
2
|
+
|
|
3
|
+
import { gid, splitTags, upper } from "../shared";
|
|
4
|
+
import {
|
|
5
|
+
type Product,
|
|
6
|
+
type ProductFeaturedMedia,
|
|
7
|
+
type ProductOption,
|
|
8
|
+
ProductStatusSchema,
|
|
9
|
+
type ProductVariant,
|
|
10
|
+
ProductVariantInventoryPolicySchema,
|
|
11
|
+
} from "./row";
|
|
12
|
+
|
|
13
|
+
export const ProductWebhookImageSchema = Schema.Struct({
|
|
14
|
+
src: Schema.String,
|
|
15
|
+
alt: Schema.NullOr(Schema.String),
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export const ProductWebhookOptionSchema = Schema.Struct({
|
|
19
|
+
id: Schema.Number,
|
|
20
|
+
name: Schema.String,
|
|
21
|
+
position: Schema.Int,
|
|
22
|
+
values: Schema.Array(Schema.String),
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
export const ProductWebhookVariantSchema = Schema.Struct({
|
|
26
|
+
admin_graphql_api_id: Schema.String,
|
|
27
|
+
id: Schema.Number,
|
|
28
|
+
title: Schema.String,
|
|
29
|
+
price: Schema.String,
|
|
30
|
+
inventory_policy: upper(ProductVariantInventoryPolicySchema),
|
|
31
|
+
compare_at_price: Schema.NullOr(Schema.String),
|
|
32
|
+
created_at: Schema.DateFromString,
|
|
33
|
+
updated_at: Schema.DateFromString,
|
|
34
|
+
taxable: Schema.Boolean,
|
|
35
|
+
barcode: Schema.NullOr(Schema.String),
|
|
36
|
+
sku: Schema.NullOr(Schema.String),
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
export const ProductWebhookVariantGidSchema = Schema.Struct({
|
|
40
|
+
admin_graphql_api_id: Schema.String,
|
|
41
|
+
updated_at: Schema.DateFromString,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
export const ProductWebhookPayloadSchema = Schema.Struct({
|
|
45
|
+
id: Schema.Number,
|
|
46
|
+
admin_graphql_api_id: Schema.String,
|
|
47
|
+
body_html: Schema.NullOr(Schema.String),
|
|
48
|
+
created_at: Schema.DateFromString,
|
|
49
|
+
handle: Schema.String,
|
|
50
|
+
image: Schema.optional(Schema.NullOr(ProductWebhookImageSchema)),
|
|
51
|
+
options: Schema.Array(ProductWebhookOptionSchema),
|
|
52
|
+
product_type: Schema.String,
|
|
53
|
+
published_at: Schema.NullOr(Schema.DateFromString),
|
|
54
|
+
status: upper(ProductStatusSchema),
|
|
55
|
+
tags: Schema.String,
|
|
56
|
+
template_suffix: Schema.NullOr(Schema.String),
|
|
57
|
+
title: Schema.String,
|
|
58
|
+
updated_at: Schema.DateFromString,
|
|
59
|
+
variants: Schema.Array(ProductWebhookVariantSchema),
|
|
60
|
+
variant_gids: Schema.Array(ProductWebhookVariantGidSchema),
|
|
61
|
+
vendor: Schema.String,
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
export const ProductDeleteWebhookPayloadSchema = Schema.Struct({ id: Schema.Number });
|
|
65
|
+
|
|
66
|
+
export const ProductEventSchema = Schema.Union([
|
|
67
|
+
Schema.Struct({
|
|
68
|
+
_tag: Schema.Literal("upsert"),
|
|
69
|
+
payload: Schema.toType(ProductWebhookPayloadSchema),
|
|
70
|
+
triggeredAt: Schema.Date,
|
|
71
|
+
}),
|
|
72
|
+
Schema.Struct({
|
|
73
|
+
_tag: Schema.Literal("delete"),
|
|
74
|
+
id: Schema.String,
|
|
75
|
+
version: Schema.Date,
|
|
76
|
+
}),
|
|
77
|
+
]);
|
|
78
|
+
|
|
79
|
+
export type ProductWebhookImage = Schema.Schema.Type<typeof ProductWebhookImageSchema>;
|
|
80
|
+
|
|
81
|
+
export type ProductWebhookOption = Schema.Schema.Type<typeof ProductWebhookOptionSchema>;
|
|
82
|
+
|
|
83
|
+
export type ProductWebhookVariant = Schema.Schema.Type<typeof ProductWebhookVariantSchema>;
|
|
84
|
+
|
|
85
|
+
export type ProductWebhookPayload = Schema.Schema.Type<typeof ProductWebhookPayloadSchema>;
|
|
86
|
+
|
|
87
|
+
const normalizeProductOption = (option: ProductWebhookOption): ProductOption => ({
|
|
88
|
+
id: gid("ProductOption", option.id),
|
|
89
|
+
name: option.name,
|
|
90
|
+
position: option.position,
|
|
91
|
+
values: option.values,
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
const normalizeProductVariant = (variant: ProductWebhookVariant): ProductVariant => ({
|
|
95
|
+
id: variant.admin_graphql_api_id,
|
|
96
|
+
legacyResourceId: String(variant.id),
|
|
97
|
+
title: variant.title,
|
|
98
|
+
sku: variant.sku,
|
|
99
|
+
barcode: variant.barcode,
|
|
100
|
+
price: variant.price,
|
|
101
|
+
compareAtPrice: variant.compare_at_price,
|
|
102
|
+
inventoryPolicy: variant.inventory_policy,
|
|
103
|
+
taxable: variant.taxable,
|
|
104
|
+
createdAt: variant.created_at,
|
|
105
|
+
updatedAt: variant.updated_at,
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const normalizeProductFeaturedMedia = (
|
|
109
|
+
image: ProductWebhookImage | null | undefined,
|
|
110
|
+
): ProductFeaturedMedia | null =>
|
|
111
|
+
image === null || image === undefined ? null : { image: { url: image.src, altText: image.alt } };
|
|
112
|
+
|
|
113
|
+
export const fromProductWebhook = (payload: ProductWebhookPayload): Product => ({
|
|
114
|
+
id: payload.admin_graphql_api_id,
|
|
115
|
+
legacyResourceId: String(payload.id),
|
|
116
|
+
title: payload.title,
|
|
117
|
+
handle: payload.handle,
|
|
118
|
+
descriptionHtml: payload.body_html ?? "",
|
|
119
|
+
productType: payload.product_type,
|
|
120
|
+
vendor: payload.vendor,
|
|
121
|
+
status: payload.status,
|
|
122
|
+
tags: splitTags(payload.tags),
|
|
123
|
+
createdAt: payload.created_at,
|
|
124
|
+
updatedAt: payload.updated_at,
|
|
125
|
+
publishedAt: payload.published_at,
|
|
126
|
+
templateSuffix: payload.template_suffix ?? "",
|
|
127
|
+
featuredMedia: normalizeProductFeaturedMedia(payload.image),
|
|
128
|
+
options: payload.options.map(normalizeProductOption),
|
|
129
|
+
variants: payload.variants.map(normalizeProductVariant),
|
|
130
|
+
});
|