@decocms/apps-shopify 8.1.0-next.0 → 8.1.0-next.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/dist/client.d.ts +36 -0
  2. package/dist/client.d.ts.map +1 -0
  3. package/dist/client.js +82 -0
  4. package/dist/client.js.map +1 -0
  5. package/dist/graphqlOperationName.d.ts +36 -0
  6. package/dist/graphqlOperationName.d.ts.map +1 -0
  7. package/dist/graphqlOperationName.js +59 -0
  8. package/dist/graphqlOperationName.js.map +1 -0
  9. package/dist/index.d.ts +6 -0
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +6 -0
  12. package/dist/index.js.map +1 -0
  13. package/package.json +16 -29
  14. package/src/client.ts +113 -47
  15. package/src/index.ts +9 -51
  16. package/src/actions/cart/addItems.ts +0 -36
  17. package/src/actions/cart/updateCoupons.ts +0 -31
  18. package/src/actions/cart/updateItems.ts +0 -31
  19. package/src/actions/user/signIn.ts +0 -40
  20. package/src/actions/user/signUp.ts +0 -31
  21. package/src/init.ts +0 -39
  22. package/src/loaders/ProductDetailsPage.ts +0 -31
  23. package/src/loaders/ProductList.ts +0 -102
  24. package/src/loaders/ProductListingPage.ts +0 -172
  25. package/src/loaders/RelatedProducts.ts +0 -42
  26. package/src/loaders/cart.ts +0 -74
  27. package/src/loaders/shop.ts +0 -35
  28. package/src/loaders/user.ts +0 -39
  29. package/src/manifest.gen.ts +0 -39
  30. package/src/mod.ts +0 -67
  31. package/src/registry.ts +0 -9
  32. package/src/utils/__tests__/instrumentedFetch.test.ts +0 -84
  33. package/src/utils/__tests__/operationRouter.test.ts +0 -56
  34. package/src/utils/__tests__/transform.test.ts +0 -216
  35. package/src/utils/admin/admin.ts +0 -57
  36. package/src/utils/admin/queries.ts +0 -29
  37. package/src/utils/cart.ts +0 -32
  38. package/src/utils/cookies.ts +0 -82
  39. package/src/utils/enums.ts +0 -438
  40. package/src/utils/graphql.ts +0 -70
  41. package/src/utils/graphqlOperationName.ts +0 -2
  42. package/src/utils/instrumentedFetch.ts +0 -56
  43. package/src/utils/operationRouter.ts +0 -70
  44. package/src/utils/storefront/queries.ts +0 -525
  45. package/src/utils/storefront/storefront.graphql.gen.ts +0 -129
  46. package/src/utils/transform.ts +0 -430
  47. package/src/utils/types.ts +0 -191
  48. package/src/utils/user.ts +0 -23
  49. package/src/utils/utils.ts +0 -159
  50. package/src/v8/client.test.ts +0 -136
  51. package/src/v8/client.ts +0 -125
  52. package/src/v8/graphqlOperationName.test.ts +0 -80
  53. package/tsconfig.json +0 -7
  54. /package/src/{v8/graphqlOperationName.ts → graphqlOperationName.ts} +0 -0
@@ -1,430 +0,0 @@
1
- import type {
2
- BreadcrumbList,
3
- Filter,
4
- ListItem,
5
- Product,
6
- ProductDetailsPage,
7
- PropertyValue,
8
- UnitPriceSpecification,
9
- } from "@decocms/apps-commerce/types";
10
- import { DEFAULT_IMAGE } from "@decocms/apps-commerce/utils/constants";
11
-
12
- type MoneyV2 = { amount: string; currencyCode: string };
13
- type ImageShopify = { url: string; altText?: string | null };
14
- type VideoSource = { url: string };
15
-
16
- interface MediaNode {
17
- alt?: string | null;
18
- previewImage?: ImageShopify | null;
19
- mediaContentType: string;
20
- sources?: VideoSource[];
21
- }
22
-
23
- export type SkuShopify = {
24
- id: string;
25
- title: string;
26
- availableForSale: boolean;
27
- quantityAvailable?: number;
28
- barcode?: string | null;
29
- sku?: string | null;
30
- image?: ImageShopify | null;
31
- price: MoneyV2;
32
- compareAtPrice?: MoneyV2 | null;
33
- selectedOptions: Array<{ name: string; value: string }>;
34
- };
35
-
36
- export type CollectionNode = {
37
- handle: string;
38
- title: string;
39
- id?: string;
40
- description?: string;
41
- descriptionHtml?: string;
42
- image?: ImageShopify | null;
43
- };
44
-
45
- export type ProductShopify = {
46
- id: string;
47
- handle: string;
48
- title: string;
49
- description: string;
50
- descriptionHtml?: string;
51
- createdAt?: string;
52
- tags: string[];
53
- vendor: string;
54
- productType: string;
55
- seo?: { title?: string | null; description?: string | null };
56
- images: { nodes: ImageShopify[] };
57
- media: { nodes: MediaNode[] };
58
- variants: { nodes: SkuShopify[] };
59
- collections?: { nodes: CollectionNode[] };
60
- metafields?: Array<{
61
- key: string;
62
- value: string;
63
- namespace: string;
64
- type: string;
65
- description?: string | null;
66
- reference?: { image?: { url: string } } | null;
67
- references?: {
68
- edges: Array<{ node: { image?: { url: string } } }>;
69
- } | null;
70
- } | null>;
71
- };
72
-
73
- type FilterValue = { id: string; label: string; count: number; input: string };
74
- type FilterShopify = { id: string; label: string; type: string; values: FilterValue[] };
75
-
76
- const getPath = ({ handle }: ProductShopify, sku?: SkuShopify) =>
77
- sku ? `/products/${handle}-${getIdFromVariantId(sku.id)}` : `/products/${handle}`;
78
-
79
- const getIdFromVariantId = (x: string) => {
80
- const splitted = x.split("/");
81
- return Number(splitted[splitted.length - 1]);
82
- };
83
-
84
- const getVariantIdFromId = (id: number) => `gid://shopify/ProductVariant/${id}`;
85
-
86
- const nonEmptyArray = <T>(array: T[] | null | undefined) =>
87
- Array.isArray(array) && array.length > 0 ? array : null;
88
-
89
- export const toProductPage = (
90
- product: ProductShopify,
91
- url: URL,
92
- maybeSkuId?: number,
93
- ): ProductDetailsPage => {
94
- const skuId = maybeSkuId ? getVariantIdFromId(maybeSkuId) : product.variants.nodes[0]?.id;
95
- let sku = product.variants.nodes.find((node) => node.id === skuId);
96
-
97
- if (!sku) {
98
- sku = product.variants.nodes[0];
99
- }
100
-
101
- return {
102
- "@type": "ProductDetailsPage",
103
- breadcrumbList: toBreadcrumbList(product, sku),
104
- product: toProduct(product, sku, url),
105
- seo: {
106
- title: product.seo?.title ?? product.title,
107
- description: product.seo?.description ?? product.description,
108
- canonical: `${url.origin}${getPath(product, sku)}`,
109
- },
110
- };
111
- };
112
-
113
- export const toBreadcrumbItem = ({
114
- name,
115
- position,
116
- item,
117
- }: {
118
- name: string;
119
- position: number;
120
- item: string;
121
- }): ListItem => ({
122
- "@type": "ListItem",
123
- name: decodeURI(name),
124
- position,
125
- item,
126
- });
127
-
128
- export const toBreadcrumbList = (product: ProductShopify, sku: SkuShopify): BreadcrumbList => {
129
- let list: ListItem[] = [];
130
- const collection = product.collections?.nodes[0];
131
-
132
- if (collection) {
133
- list = [
134
- toBreadcrumbItem({
135
- name: collection.title,
136
- position: 1,
137
- item: `/${collection.handle}`,
138
- }),
139
- toBreadcrumbItem({
140
- name: product.title,
141
- position: 2,
142
- item: getPath(product, sku),
143
- }),
144
- ];
145
- } else {
146
- list = [
147
- toBreadcrumbItem({
148
- name: product.title,
149
- position: 2,
150
- item: getPath(product, sku),
151
- }),
152
- ];
153
- }
154
-
155
- return {
156
- "@type": "BreadcrumbList",
157
- numberOfItems: list.length,
158
- itemListElement: list,
159
- };
160
- };
161
-
162
- export const toProduct = (
163
- product: ProductShopify,
164
- sku: SkuShopify,
165
- url: URL,
166
- level = 0,
167
- ): Product => {
168
- const {
169
- createdAt,
170
- description,
171
- images,
172
- media,
173
- id: productGroupID,
174
- variants,
175
- vendor,
176
- productType,
177
- } = product;
178
- const {
179
- id: productID,
180
- barcode,
181
- selectedOptions,
182
- image,
183
- price,
184
- availableForSale,
185
- quantityAvailable,
186
- compareAtPrice,
187
- } = sku;
188
-
189
- const descriptionHtml: PropertyValue = {
190
- "@type": "PropertyValue",
191
- name: "descriptionHtml",
192
- value: product.descriptionHtml,
193
- };
194
-
195
- const productTypeValue: PropertyValue = {
196
- "@type": "PropertyValue",
197
- name: "productType",
198
- value: productType,
199
- };
200
-
201
- const metafields = (product.metafields ?? [])
202
- .filter(
203
- (metafield): metafield is NonNullable<typeof metafield> =>
204
- metafield != null && metafield.key != null && metafield.value != null,
205
- )
206
- .map((metafield): PropertyValue => {
207
- const { key, value, reference, references } = metafield;
208
- const hasReferenceImage = reference && "image" in reference;
209
- const referenceImageUrl = hasReferenceImage ? reference.image?.url : null;
210
-
211
- const hasEdges = references?.edges && references.edges.length > 0;
212
- const edgeImages = hasEdges
213
- ? references!.edges.map((edge) =>
214
- edge.node && "image" in edge.node ? edge.node.image?.url : null,
215
- )
216
- : null;
217
-
218
- const rawValue = referenceImageUrl || edgeImages || value;
219
- const valueToReturn = Array.isArray(rawValue)
220
- ? JSON.stringify(rawValue)
221
- : (rawValue ?? undefined);
222
-
223
- return {
224
- "@type": "PropertyValue",
225
- name: key,
226
- value: valueToReturn,
227
- };
228
- });
229
-
230
- const additionalProperty: PropertyValue[] = selectedOptions
231
- .map(toPropertyValue)
232
- .concat(descriptionHtml)
233
- .concat(productTypeValue)
234
- .concat(metafields);
235
-
236
- const skuImages = nonEmptyArray([image]);
237
- const hasVariant =
238
- level < 1 && variants.nodes.map((variant) => toProduct(product, variant, url, 1));
239
- const priceSpec: UnitPriceSpecification[] = [
240
- {
241
- "@type": "UnitPriceSpecification",
242
- priceType: "https://schema.org/SalePrice",
243
- price: Number(price.amount),
244
- },
245
- ];
246
-
247
- if (compareAtPrice) {
248
- priceSpec.push({
249
- "@type": "UnitPriceSpecification",
250
- priceType: "https://schema.org/ListPrice",
251
- price: Number(compareAtPrice.amount),
252
- });
253
- }
254
-
255
- const collectionNodes = product.collections?.nodes ?? [];
256
-
257
- return {
258
- "@type": "Product",
259
- productID,
260
- url: `${url.origin}${getPath(product, sku)}`,
261
- name: sku.title,
262
- description,
263
- sku: productID,
264
- gtin: barcode ?? undefined,
265
- brand: { "@type": "Brand", name: vendor },
266
- releaseDate: createdAt,
267
- additionalProperty,
268
- isVariantOf: {
269
- "@type": "ProductGroup",
270
- productGroupID,
271
- hasVariant: hasVariant || [],
272
- url: `${url.origin}${getPath(product)}`,
273
- name: product.title,
274
- additionalProperty: [
275
- ...(product.tags ?? []).map((value) => toPropertyValue({ name: "TAG", value })),
276
- ...collectionNodes.map((col) =>
277
- toPropertyValue({
278
- "@id": col.id,
279
- name: "COLLECTION",
280
- value: col.title,
281
- valueReference: col.handle,
282
- description: col.description,
283
- disambiguatingDescription: col.descriptionHtml,
284
- ...(col.image && {
285
- image: [
286
- {
287
- "@type": "ImageObject" as const,
288
- encodingFormat: "image",
289
- alternateName: col.image.altText ?? "",
290
- url: col.image.url,
291
- },
292
- ],
293
- }),
294
- }),
295
- ),
296
- ],
297
- image: nonEmptyArray(images.nodes)?.map((img) => ({
298
- "@type": "ImageObject" as const,
299
- encodingFormat: "image",
300
- alternateName: img.altText ?? "",
301
- url: img.url,
302
- })),
303
- },
304
- image: skuImages?.map((img) => ({
305
- "@type": "ImageObject" as const,
306
- encodingFormat: "image",
307
- alternateName: img?.altText ?? "",
308
- url: img?.url ?? "",
309
- })) ?? [DEFAULT_IMAGE],
310
- video: media.nodes
311
- .filter((m) => m.mediaContentType === "VIDEO")
312
- .map((video) => ({
313
- "@type": "VideoObject" as const,
314
- contentUrl: video.sources?.[0]?.url,
315
- description: video.alt ?? undefined,
316
- thumbnailUrl: video.previewImage?.url,
317
- })),
318
- offers: {
319
- "@type": "AggregateOffer",
320
- priceCurrency: price.currencyCode,
321
- highPrice: compareAtPrice ? Number(compareAtPrice.amount) : Number(price.amount),
322
- lowPrice: Number(price.amount),
323
- offerCount: 1,
324
- offers: [
325
- {
326
- "@type": "Offer",
327
- price: Number(price.amount),
328
- availability: availableForSale
329
- ? "https://schema.org/InStock"
330
- : "https://schema.org/OutOfStock",
331
- inventoryLevel: { value: quantityAvailable ?? 0 },
332
- priceSpecification: priceSpec,
333
- },
334
- ],
335
- },
336
- };
337
- };
338
-
339
- const toPropertyValue = (option: Omit<PropertyValue, "@type">): PropertyValue => ({
340
- "@type": "PropertyValue",
341
- ...option,
342
- });
343
-
344
- const isSelectedFilter = (filterValue: FilterValue, url: URL) => {
345
- let isSelected = false;
346
- const label = getFilterValue(filterValue);
347
-
348
- url.searchParams.forEach((value, key) => {
349
- if (!key?.startsWith("filter")) return;
350
- if (value === label) isSelected = true;
351
- });
352
- return isSelected;
353
- };
354
-
355
- export const toFilter = (filter: FilterShopify, url: URL): Filter => {
356
- if (!filter.type.includes("RANGE")) {
357
- return {
358
- "@type": "FilterToggle",
359
- label: filter.label,
360
- key: filter.id,
361
- values: filter.values.map((value) => ({
362
- quantity: value.count,
363
- label: value.label,
364
- value: value.label,
365
- selected: isSelectedFilter(value, url),
366
- url: filtersURL(filter, value, url),
367
- })),
368
- quantity: filter.values.length,
369
- };
370
- } else {
371
- const min = JSON.parse(filter.values[0].input).min;
372
- const max = JSON.parse(filter.values[0].input).max;
373
- return {
374
- "@type": "FilterRange",
375
- label: filter.label,
376
- key: filter.id,
377
- values: { min, max },
378
- };
379
- }
380
- };
381
-
382
- const filtersURL = (filter: FilterShopify, value: FilterValue, _url: URL) => {
383
- const url = new URL(_url.href);
384
- const params = new URLSearchParams(url.search);
385
- params.delete("page");
386
- params.delete("startCursor");
387
- params.delete("endCursor");
388
-
389
- const label = getFilterValue(value);
390
-
391
- if (params.has(filter.id, label)) {
392
- params.delete(filter.id, label);
393
- } else {
394
- params.append(filter.id, label);
395
- }
396
-
397
- url.search = params.toString();
398
- return url.toString();
399
- };
400
-
401
- const getFilterValue = (value: FilterValue) => {
402
- try {
403
- const parsed = JSON.parse(value.input);
404
-
405
- const fieldsToCheck = [
406
- ["productMetafield", "value"],
407
- ["taxonomyMetafield", "value"],
408
- ["productVendor"],
409
- ["productType"],
410
- ["category", "id"],
411
- ];
412
-
413
- for (const path of fieldsToCheck) {
414
- let current: any = parsed;
415
- for (const key of path) {
416
- if (current && typeof current === "object" && key in current) {
417
- current = current[key];
418
- } else {
419
- current = null;
420
- break;
421
- }
422
- }
423
- if (current != null) return current;
424
- }
425
- } catch (error) {
426
- console.error("Error parsing input JSON:", error);
427
- }
428
-
429
- return value.label;
430
- };
@@ -1,191 +0,0 @@
1
- import type {
2
- CountryCode,
3
- CurrencyCode,
4
- OrderCancelReason,
5
- OrderFinancialStatus,
6
- OrderFulfillmentStatus,
7
- } from "./enums";
8
-
9
- type Attribute = {
10
- key: string;
11
- value?: string;
12
- };
13
-
14
- type MailingAddress = {
15
- address1?: string;
16
- address2?: string;
17
- city?: string;
18
- company?: string;
19
- country?: string;
20
- countryCodeV2?: CountryCode;
21
- firstName?: string;
22
- formattedArea?: string;
23
- id: string;
24
- lastName?: string;
25
- latitude?: number;
26
- longitude?: number;
27
- name?: string;
28
- phone?: string;
29
- province?: string;
30
- provinceCode?: string;
31
- zip?: string;
32
- };
33
-
34
- type MoneyV2 = {
35
- amount: number;
36
- currencyCode: CurrencyCode;
37
- };
38
-
39
- type AppliedGiftCard = {
40
- amountUsed: MoneyV2;
41
- balance: MoneyV2;
42
- id: string;
43
- lastCharacters: string;
44
- presentmentAmountUsed: MoneyV2;
45
- };
46
-
47
- type ShippingRate = {
48
- handle: string;
49
- price: MoneyV2;
50
- title: string;
51
- };
52
-
53
- type AvailableShippingRates = {
54
- ready: boolean;
55
- shippingRates?: ShippingRate[];
56
- };
57
-
58
- type CheckoutBuyerIdentity = {
59
- countryCode: CountryCode;
60
- };
61
-
62
- type Order = {
63
- billingAddress?: MailingAddress;
64
- cancelReason?: OrderCancelReason;
65
- canceledAt?: Date;
66
- currencyCode: CurrencyCode;
67
- currentSubtotalPrice: MoneyV2;
68
- currentTotalDuties?: MoneyV2;
69
- currentTotalPrice: MoneyV2;
70
- currentTotalTax: MoneyV2;
71
- customAttributes: Attribute[];
72
- customerLocale?: string;
73
- customerUrl?: string;
74
- edited: boolean;
75
- email?: string;
76
- financialStatus?: OrderFinancialStatus;
77
- fulfillmentStatus: OrderFulfillmentStatus;
78
- id: string;
79
- name: string;
80
- orderNumber: number;
81
- originalTotalDuties?: MoneyV2;
82
- originalTotalPrice: MoneyV2;
83
- phone?: string;
84
- processedAt: Date;
85
- shippingAddress?: MailingAddress;
86
- };
87
-
88
- type Checkout = {
89
- appliedGiftCards: AppliedGiftCard[];
90
- availableShippingRates?: AvailableShippingRates;
91
- buyerIdentity: CheckoutBuyerIdentity;
92
- completedAt?: Date;
93
- createdAt: Date;
94
- currencyCode: CurrencyCode;
95
- customAttributes: Attribute[];
96
- email?: string;
97
- id: string;
98
- lineItemsSubtotalPrice: MoneyV2;
99
- note: string;
100
- order: Order;
101
- orderStatusUrl: string;
102
- paymentDue: MoneyV2;
103
- ready: boolean;
104
- requireShipping: boolean;
105
- shippingAddress: MailingAddress;
106
- };
107
-
108
- type Customer = {
109
- acceptsMarketing: boolean;
110
- createdAt: Date;
111
- defaultAddress: MailingAddress;
112
- displayName: string;
113
- email: string;
114
- firstName: string;
115
- id: string;
116
- checkout: Checkout;
117
- };
118
-
119
- type CartBuyerIdentity = {
120
- countryCode: string;
121
- customer: Customer;
122
- };
123
-
124
- export type OldCart = {
125
- attribute?: Attribute;
126
- attributes?: Attribute[];
127
- buyerIdentity?: CartBuyerIdentity;
128
- id: string;
129
- };
130
-
131
- export interface Money {
132
- amount: number;
133
- currencyCode: string;
134
- }
135
-
136
- export interface Image {
137
- url: string;
138
- width: number;
139
- height: number;
140
- altText: string;
141
- }
142
-
143
- export interface Media {
144
- nodes: Media[];
145
- }
146
-
147
- export interface Media {
148
- alt: string;
149
- previewImage: Image;
150
- mediaContentType: string;
151
- }
152
-
153
- export interface Option {
154
- name: string;
155
- values: string[];
156
- }
157
-
158
- export interface PriceRange {
159
- minVariantPrice: Price;
160
- maxVariantPrice: Price;
161
- }
162
-
163
- export interface Price {
164
- amount: string;
165
- currencyCode: string;
166
- }
167
-
168
- export interface SEO {
169
- title: string;
170
- description: string;
171
- }
172
-
173
- export interface SelectedOption {
174
- name: string;
175
- value: string;
176
- }
177
-
178
- export interface UnitPriceMeasurement {
179
- measuredType: null;
180
- quantityValue: number;
181
- referenceUnit: null;
182
- quantityUnit: null;
183
- }
184
-
185
- /**
186
- * @title {{{key}}}
187
- */
188
- export interface Metafield {
189
- namespace: string;
190
- key: string;
191
- }
package/src/utils/user.ts DELETED
@@ -1,23 +0,0 @@
1
- import { getCookies, setCookie } from "./cookies";
2
-
3
- const CUSTOMER_COOKIE = "secure_customer_sig";
4
-
5
- const ONE_WEEK_MS = 7 * 24 * 3600 * 1_000;
6
-
7
- export const getUserCookie = (headers: Headers): string | undefined => {
8
- const cookies = getCookies(headers);
9
-
10
- return cookies[CUSTOMER_COOKIE];
11
- };
12
-
13
- export const setUserCookie = (headers: Headers, accessToken: string) => {
14
- setCookie(headers, {
15
- name: CUSTOMER_COOKIE,
16
- value: accessToken,
17
- path: "/",
18
- expires: new Date(Date.now() + ONE_WEEK_MS),
19
- httpOnly: true,
20
- secure: true,
21
- sameSite: "Lax",
22
- });
23
- };