@spindlecommerce/storefront-client 0.0.0-stage → 0.1.0
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/LICENSE +21 -0
- package/README.md +27 -2
- package/dist/builder.d.ts +6 -0
- package/dist/builder.js +5 -0
- package/dist/cart.d.ts +105 -0
- package/dist/cart.js +230 -0
- package/dist/client.d.ts +102 -0
- package/dist/client.js +108 -0
- package/dist/documents.d.ts +39 -0
- package/dist/documents.js +217 -0
- package/dist/errors.d.ts +12 -0
- package/dist/errors.js +20 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +11 -0
- package/dist/media.d.ts +2 -0
- package/dist/media.js +2 -0
- package/dist/paths.d.ts +10 -0
- package/dist/paths.js +25 -0
- package/dist/prices.d.ts +4 -0
- package/dist/prices.js +3 -0
- package/dist/types.d.ts +455 -0
- package/dist/types.js +2 -0
- package/dist/variants.d.ts +29 -0
- package/dist/variants.js +26 -0
- package/dist/visual-editing.d.ts +47 -0
- package/dist/visual-editing.js +23 -0
- package/dist/webhooks.d.ts +52 -0
- package/dist/webhooks.js +80 -0
- package/package.json +37 -3
- package/schema.graphql +1453 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/** The GraphQL documents behind the client's methods. */
|
|
2
|
+
/** For your own documents: spread `...ProductSummary` and append the fragment. */
|
|
3
|
+
export declare const fragments: {
|
|
4
|
+
money: string;
|
|
5
|
+
address: string;
|
|
6
|
+
productSummary: string;
|
|
7
|
+
builderPage: string;
|
|
8
|
+
cart: string;
|
|
9
|
+
};
|
|
10
|
+
export declare const ROUTE = "\n query Route($path: String!) {\n route(path: $path) {\n __typename\n ... on Page { ...BuilderPage }\n ... on Product {\n ...ProductSummary\n description\n seo { title description }\n categories { id name path }\n media { id url alt kind position variant { id } }\n variants {\n id sku name isAvailable quantityAvailable\n price { ...Money } compareAtPrice { ...Money }\n selectedOptions { attribute value label name swatch }\n media { url alt }\n }\n attributes { attribute { code label } value }\n }\n ... on Category { id name slug path description ancestors { id name path } children { id name path } }\n ... on Redirect { location statusCode }\n }\n }\n \n fragment BuilderPage on Page {\n id type path title isPreview publishedAt updatedAt\n seo { title description noIndex image { url alt width height } }\n content\n references {\n products { ...ProductSummary }\n categories { id name path }\n pages { id path title }\n }\n }\n \n fragment ProductSummary on Product {\n id name slug isAvailable\n priceRange { minVariantPrice { ...Money } maxVariantPrice { ...Money } compareAtMinVariantPrice { ...Money } }\n media { url alt kind variant { id } }\n options { attribute { code label } values { code label swatch } }\n variants { id isAvailable selectedOptions { attribute value } }\n }\n fragment Money on Money { amount currencyCode formatted }";
|
|
11
|
+
export declare const TEMPLATE = "\n query Template($path: String!) {\n route(path: $path) {\n ... on Product { template { ...BuilderPage templateFor } }\n ... on Category { template { ...BuilderPage templateFor } }\n }\n }\n \n fragment BuilderPage on Page {\n id type path title isPreview publishedAt updatedAt\n seo { title description noIndex image { url alt width height } }\n content\n references {\n products { ...ProductSummary }\n categories { id name path }\n pages { id path title }\n }\n }\n \n fragment ProductSummary on Product {\n id name slug isAvailable\n priceRange { minVariantPrice { ...Money } maxVariantPrice { ...Money } compareAtMinVariantPrice { ...Money } }\n media { url alt kind variant { id } }\n options { attribute { code label } values { code label swatch } }\n variants { id isAvailable selectedOptions { attribute value } }\n }\n fragment Money on Money { amount currencyCode formatted }";
|
|
12
|
+
export declare const SECTIONS = "\n query Sections($path: String!) {\n route(path: $path) {\n ... on Product { sections { ...BuilderPage } }\n ... on Category { sections { ...BuilderPage } }\n }\n }\n \n fragment BuilderPage on Page {\n id type path title isPreview publishedAt updatedAt\n seo { title description noIndex image { url alt width height } }\n content\n references {\n products { ...ProductSummary }\n categories { id name path }\n pages { id path title }\n }\n }\n \n fragment ProductSummary on Product {\n id name slug isAvailable\n priceRange { minVariantPrice { ...Money } maxVariantPrice { ...Money } compareAtMinVariantPrice { ...Money } }\n media { url alt kind variant { id } }\n options { attribute { code label } values { code label swatch } }\n variants { id isAvailable selectedOptions { attribute value } }\n }\n fragment Money on Money { amount currencyCode formatted }";
|
|
13
|
+
export declare const SITE = "\n query Site($header: String!, $footer: String!) {\n header: singletonPage(type: $header) { ...BuilderPage }\n footer: singletonPage(type: $footer) { ...BuilderPage }\n localization { locale currencyCode channel { code name } }\n }\n \n fragment BuilderPage on Page {\n id type path title isPreview publishedAt updatedAt\n seo { title description noIndex image { url alt width height } }\n content\n references {\n products { ...ProductSummary }\n categories { id name path }\n pages { id path title }\n }\n }\n \n fragment ProductSummary on Product {\n id name slug isAvailable\n priceRange { minVariantPrice { ...Money } maxVariantPrice { ...Money } compareAtMinVariantPrice { ...Money } }\n media { url alt kind variant { id } }\n options { attribute { code label } values { code label swatch } }\n variants { id isAvailable selectedOptions { attribute value } }\n }\n fragment Money on Money { amount currencyCode formatted }";
|
|
14
|
+
export declare const NEWEST_PRODUCTS = "\n query NewestProducts($first: Int!) {\n products(first: $first, sort: { field: NEWEST, direction: DESC }) { edges { node { ...ProductSummary } } }\n }\n \n fragment ProductSummary on Product {\n id name slug isAvailable\n priceRange { minVariantPrice { ...Money } maxVariantPrice { ...Money } compareAtMinVariantPrice { ...Money } }\n media { url alt kind variant { id } }\n options { attribute { code label } values { code label swatch } }\n variants { id isAvailable selectedOptions { attribute value } }\n }\n fragment Money on Money { amount currencyCode formatted }";
|
|
15
|
+
export declare const CATEGORY_PRODUCTS = "\n query CategoryProducts($id: ID!, $first: Int!, $after: String, $sort: ProductSortInput) {\n category(id: $id) {\n id name path\n products(first: $first, after: $after, sort: $sort) {\n totalCount\n pageInfo { hasNextPage endCursor }\n edges { node { ...ProductSummary } }\n }\n }\n }\n \n fragment ProductSummary on Product {\n id name slug isAvailable\n priceRange { minVariantPrice { ...Money } maxVariantPrice { ...Money } compareAtMinVariantPrice { ...Money } }\n media { url alt kind variant { id } }\n options { attribute { code label } values { code label swatch } }\n variants { id isAvailable selectedOptions { attribute value } }\n }\n fragment Money on Money { amount currencyCode formatted }";
|
|
16
|
+
export declare const PAGES = "\n query Pages($type: String, $first: Int!, $after: String) {\n pages(type: $type, first: $first, after: $after) {\n pageInfo { hasNextPage endCursor }\n edges { node { path updatedAt seo { noIndex } } }\n }\n }";
|
|
17
|
+
export declare const PRODUCT_SLUGS = "\n query ProductSlugs($after: String) {\n products(first: 100, after: $after) { pageInfo { hasNextPage endCursor } edges { node { slug } } }\n }";
|
|
18
|
+
export declare const CATEGORY_TREE = "\n query CategoryTree { categoryTree { path children { path children { path children { path } } } } }";
|
|
19
|
+
export declare const LOCALIZED_PATH = "\n query LocalizedPath($id: ID!) {\n node(id: $id) { ... on Product { slug } ... on Category { path } }\n }";
|
|
20
|
+
export declare const PREVIEW_SESSION = "query PreviewSession { previewSession { expiresAt adminOrigin at } }";
|
|
21
|
+
export declare const COUNTRIES = "query Countries { localization { locale channel { countries { code name } } } }";
|
|
22
|
+
export declare const CART_QUERY = "query Cart($id: ID!) { cart(id: $id) { ...Cart } } \n fragment Cart on Cart {\n id isOpen totalQuantity currencyCode\n cost { subtotal { ...Money } total { ...Money } tax { ...Money } shipping { ...Money } discountTotal { ...Money } pricesIncludeTax }\n lines {\n id name quantity quantityAvailable\n unitPrice { ...Money } compareAtUnitPrice { ...Money } total { ...Money }\n issue { code message }\n product { name slug media { url alt kind } }\n variant { id name selectedOptions { name label } media { url alt } }\n }\n }\n fragment Money on Money { amount currencyCode formatted }";
|
|
23
|
+
export declare const CART_CREATE: string;
|
|
24
|
+
export declare const CART_LINES_ADD: string;
|
|
25
|
+
export declare const CART_LINES_UPDATE: string;
|
|
26
|
+
export declare const CART_LINES_REMOVE: string;
|
|
27
|
+
export declare const CART_MOVE: string;
|
|
28
|
+
/** PaymentMethodOption.provider and sessionRequired are newer than the rest of the API. */
|
|
29
|
+
export declare const PAYMENT_FIELDS = "code name instructions provider sessionRequired";
|
|
30
|
+
export declare const LEGACY_PAYMENT_FIELDS = "code name instructions";
|
|
31
|
+
export declare const checkoutCart: (paymentFields: string) => string;
|
|
32
|
+
export declare const CART_UPDATE = "mutation CheckoutUpdate($cartId: ID!, $input: CartUpdateInput!) { result: cartUpdate(cartId: $cartId, input: $input) { __typename ... on Error { code message } ... on ValidationError { fieldErrors { path message } } } }";
|
|
33
|
+
export declare const COUPON_APPLY = "mutation CheckoutCouponApply($cartId: ID!, $code: String!) { result: cartCouponApply(cartId: $cartId, code: $code) { __typename ... on Error { code message } ... on ValidationError { fieldErrors { path message } } ... on CouponNotApplicableError { reason } } }";
|
|
34
|
+
export declare const COUPON_REMOVE = "mutation CheckoutCouponRemove($cartId: ID!, $code: String!) { result: cartCouponRemove(cartId: $cartId, code: $code) { __typename ... on Error { code message } ... on ValidationError { fieldErrors { path message } } } }";
|
|
35
|
+
export declare const PAYMENT_SESSION_CREATE = "\n mutation CheckoutPaymentSession($cartId: ID!) {\n result: cartPaymentSessionCreate(cartId: $cartId) {\n __typename\n ... on CartPaymentSessionPayload { session { provider methodCode amount { ...Money } clientData } }\n ... on Error { code message }\n }\n }\n fragment Money on Money { amount currencyCode formatted }";
|
|
36
|
+
export declare const PLACE_ORDER = "\n mutation CheckoutPlaceOrder($cartId: ID!, $idempotencyKey: String!, $input: CartUpdateInput, $payment: PaymentDataInput) {\n result: checkoutPlaceOrder(cartId: $cartId, idempotencyKey: $idempotencyKey, input: $input, payment: $payment) {\n __typename\n ... on CheckoutPayload { order { number email billingAddress { postalCode } } }\n ... on Error { code message }\n ... on ValidationError { fieldErrors { path message } }\n ... on CartNotReadyError { missing fieldErrors { path message } }\n ... on InsufficientStockError { sku available }\n }\n }";
|
|
37
|
+
/** A cart that became an order elsewhere: a payment webhook, or another tab. */
|
|
38
|
+
export declare const CONVERTED_CART = "query CheckoutConvertedCart($id: ID!) { cart(id: $id) { isOpen order { number email billingAddress { postalCode } } } }";
|
|
39
|
+
export declare const GUEST_ORDER = "\n query GuestOrder($email: EmailAddress!, $number: String!, $postalCode: String!, $cartId: ID!) {\n order: guestOrder(email: $email, number: $number, postalCode: $postalCode) {\n number email locale status paymentStatus placedAt currencyCode\n lines {\n id name sku quantity\n unitPrice { ...Money } subtotal { ...Money } total { ...Money }\n product { name slug media { url alt kind } }\n variant { selectedOptions { name label } media { url alt } }\n }\n totals { subtotal { ...Money } shipping { ...Money } tax { ...Money } total { ...Money } pricesIncludeTax discounts { name couponCode amount { ...Money } } }\n shippingAddress { ...Address }\n billingAddress { ...Address }\n shippingMethod { name }\n }\n cart(id: $cartId) { selectedPaymentMethod { code name instructions } }\n }\n fragment Money on Money { amount currencyCode formatted }\n fragment Address on Address { firstName lastName company line1 line2 city region regionCode postalCode countryCode phone }";
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/** The GraphQL documents behind the client's methods. */
|
|
2
|
+
const MONEY = `fragment Money on Money { amount currencyCode formatted }`;
|
|
3
|
+
const ADDRESS = `fragment Address on Address { firstName lastName company line1 line2 city region regionCode postalCode countryCode phone }`;
|
|
4
|
+
const PRODUCT_SUMMARY = `
|
|
5
|
+
fragment ProductSummary on Product {
|
|
6
|
+
id name slug isAvailable
|
|
7
|
+
priceRange { minVariantPrice { ...Money } maxVariantPrice { ...Money } compareAtMinVariantPrice { ...Money } }
|
|
8
|
+
media { url alt kind variant { id } }
|
|
9
|
+
options { attribute { code label } values { code label swatch } }
|
|
10
|
+
variants { id isAvailable selectedOptions { attribute value } }
|
|
11
|
+
}
|
|
12
|
+
${MONEY}`;
|
|
13
|
+
const BUILDER_PAGE = `
|
|
14
|
+
fragment BuilderPage on Page {
|
|
15
|
+
id type path title isPreview publishedAt updatedAt
|
|
16
|
+
seo { title description noIndex image { url alt width height } }
|
|
17
|
+
content
|
|
18
|
+
references {
|
|
19
|
+
products { ...ProductSummary }
|
|
20
|
+
categories { id name path }
|
|
21
|
+
pages { id path title }
|
|
22
|
+
}
|
|
23
|
+
}`;
|
|
24
|
+
const CART = `
|
|
25
|
+
fragment Cart on Cart {
|
|
26
|
+
id isOpen totalQuantity currencyCode
|
|
27
|
+
cost { subtotal { ...Money } total { ...Money } tax { ...Money } shipping { ...Money } discountTotal { ...Money } pricesIncludeTax }
|
|
28
|
+
lines {
|
|
29
|
+
id name quantity quantityAvailable
|
|
30
|
+
unitPrice { ...Money } compareAtUnitPrice { ...Money } total { ...Money }
|
|
31
|
+
issue { code message }
|
|
32
|
+
product { name slug media { url alt kind } }
|
|
33
|
+
variant { id name selectedOptions { name label } media { url alt } }
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
${MONEY}`;
|
|
37
|
+
/** For your own documents: spread `...ProductSummary` and append the fragment. */
|
|
38
|
+
export const fragments = { money: MONEY, address: ADDRESS, productSummary: PRODUCT_SUMMARY, builderPage: `${BUILDER_PAGE}${PRODUCT_SUMMARY}`, cart: CART };
|
|
39
|
+
// ---------------------------------------------------------------- catalog and pages
|
|
40
|
+
export const ROUTE = `
|
|
41
|
+
query Route($path: String!) {
|
|
42
|
+
route(path: $path) {
|
|
43
|
+
__typename
|
|
44
|
+
... on Page { ...BuilderPage }
|
|
45
|
+
... on Product {
|
|
46
|
+
...ProductSummary
|
|
47
|
+
description
|
|
48
|
+
seo { title description }
|
|
49
|
+
categories { id name path }
|
|
50
|
+
media { id url alt kind position variant { id } }
|
|
51
|
+
variants {
|
|
52
|
+
id sku name isAvailable quantityAvailable
|
|
53
|
+
price { ...Money } compareAtPrice { ...Money }
|
|
54
|
+
selectedOptions { attribute value label name swatch }
|
|
55
|
+
media { url alt }
|
|
56
|
+
}
|
|
57
|
+
attributes { attribute { code label } value }
|
|
58
|
+
}
|
|
59
|
+
... on Category { id name slug path description ancestors { id name path } children { id name path } }
|
|
60
|
+
... on Redirect { location statusCode }
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
${BUILDER_PAGE}
|
|
64
|
+
${PRODUCT_SUMMARY}`;
|
|
65
|
+
// Not part of the route query, which would then select more than the API's limit of 250 fields
|
|
66
|
+
// (counting the __typename and id fields its response cache adds).
|
|
67
|
+
export const TEMPLATE = `
|
|
68
|
+
query Template($path: String!) {
|
|
69
|
+
route(path: $path) {
|
|
70
|
+
... on Product { template { ...BuilderPage templateFor } }
|
|
71
|
+
... on Category { template { ...BuilderPage templateFor } }
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
${BUILDER_PAGE}
|
|
75
|
+
${PRODUCT_SUMMARY}`;
|
|
76
|
+
// Not part of the route query either, for the same reason.
|
|
77
|
+
export const SECTIONS = `
|
|
78
|
+
query Sections($path: String!) {
|
|
79
|
+
route(path: $path) {
|
|
80
|
+
... on Product { sections { ...BuilderPage } }
|
|
81
|
+
... on Category { sections { ...BuilderPage } }
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
${BUILDER_PAGE}
|
|
85
|
+
${PRODUCT_SUMMARY}`;
|
|
86
|
+
export const SITE = `
|
|
87
|
+
query Site($header: String!, $footer: String!) {
|
|
88
|
+
header: singletonPage(type: $header) { ...BuilderPage }
|
|
89
|
+
footer: singletonPage(type: $footer) { ...BuilderPage }
|
|
90
|
+
localization { locale currencyCode channel { code name } }
|
|
91
|
+
}
|
|
92
|
+
${BUILDER_PAGE}
|
|
93
|
+
${PRODUCT_SUMMARY}`;
|
|
94
|
+
export const NEWEST_PRODUCTS = `
|
|
95
|
+
query NewestProducts($first: Int!) {
|
|
96
|
+
products(first: $first, sort: { field: NEWEST, direction: DESC }) { edges { node { ...ProductSummary } } }
|
|
97
|
+
}
|
|
98
|
+
${PRODUCT_SUMMARY}`;
|
|
99
|
+
export const CATEGORY_PRODUCTS = `
|
|
100
|
+
query CategoryProducts($id: ID!, $first: Int!, $after: String, $sort: ProductSortInput) {
|
|
101
|
+
category(id: $id) {
|
|
102
|
+
id name path
|
|
103
|
+
products(first: $first, after: $after, sort: $sort) {
|
|
104
|
+
totalCount
|
|
105
|
+
pageInfo { hasNextPage endCursor }
|
|
106
|
+
edges { node { ...ProductSummary } }
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
${PRODUCT_SUMMARY}`;
|
|
111
|
+
export const PAGES = `
|
|
112
|
+
query Pages($type: String, $first: Int!, $after: String) {
|
|
113
|
+
pages(type: $type, first: $first, after: $after) {
|
|
114
|
+
pageInfo { hasNextPage endCursor }
|
|
115
|
+
edges { node { path updatedAt seo { noIndex } } }
|
|
116
|
+
}
|
|
117
|
+
}`;
|
|
118
|
+
export const PRODUCT_SLUGS = `
|
|
119
|
+
query ProductSlugs($after: String) {
|
|
120
|
+
products(first: 100, after: $after) { pageInfo { hasNextPage endCursor } edges { node { slug } } }
|
|
121
|
+
}`;
|
|
122
|
+
export const CATEGORY_TREE = `
|
|
123
|
+
query CategoryTree { categoryTree { path children { path children { path children { path } } } } }`;
|
|
124
|
+
export const LOCALIZED_PATH = `
|
|
125
|
+
query LocalizedPath($id: ID!) {
|
|
126
|
+
node(id: $id) { ... on Product { slug } ... on Category { path } }
|
|
127
|
+
}`;
|
|
128
|
+
export const PREVIEW_SESSION = `query PreviewSession { previewSession { expiresAt adminOrigin at } }`;
|
|
129
|
+
export const COUNTRIES = `query Countries { localization { locale channel { countries { code name } } } }`;
|
|
130
|
+
// ---------------------------------------------------------------- carts
|
|
131
|
+
/** Only adding and changing quantities can return InsufficientStockError. */
|
|
132
|
+
const cartResult = (canRunOutOfStock) => `
|
|
133
|
+
__typename
|
|
134
|
+
... on CartPayload { cart { ...Cart } }
|
|
135
|
+
... on Error { code message }
|
|
136
|
+
${canRunOutOfStock ? "... on InsufficientStockError { available }" : ""}`;
|
|
137
|
+
export const CART_QUERY = `query Cart($id: ID!) { cart(id: $id) { ...Cart } } ${CART}`;
|
|
138
|
+
export const CART_CREATE = `mutation CartCreate($lines: [CartLineInput!]) { result: cartCreate(input: { lines: $lines }) { ${cartResult(true)} } } ${CART}`;
|
|
139
|
+
export const CART_LINES_ADD = `mutation CartLinesAdd($id: ID!, $lines: [CartLineInput!]!) { result: cartLinesAdd(cartId: $id, lines: $lines) { ${cartResult(true)} } } ${CART}`;
|
|
140
|
+
export const CART_LINES_UPDATE = `mutation CartLinesUpdate($id: ID!, $lines: [CartLineUpdateInput!]!) { result: cartLinesUpdate(cartId: $id, lines: $lines) { ${cartResult(true)} } } ${CART}`;
|
|
141
|
+
export const CART_LINES_REMOVE = `mutation CartLinesRemove($id: ID!, $lineIds: [ID!]!) { result: cartLinesRemove(cartId: $id, lineIds: $lineIds) { ${cartResult(false)} } } ${CART}`;
|
|
142
|
+
export const CART_MOVE = `mutation CartMove($id: ID!, $input: CartUpdateInput!) { result: cartUpdate(cartId: $id, input: $input) { ${cartResult(false)} } } ${CART}`;
|
|
143
|
+
// ---------------------------------------------------------------- checkout
|
|
144
|
+
/** PaymentMethodOption.provider and sessionRequired are newer than the rest of the API. */
|
|
145
|
+
export const PAYMENT_FIELDS = "code name instructions provider sessionRequired";
|
|
146
|
+
export const LEGACY_PAYMENT_FIELDS = "code name instructions";
|
|
147
|
+
export const checkoutCart = (paymentFields) => `
|
|
148
|
+
query CheckoutCart($id: ID!) {
|
|
149
|
+
cart(id: $id) {
|
|
150
|
+
id isOpen currencyCode version email requiresShipping missing billingSameAsShipping
|
|
151
|
+
shippingAddress { ...Address }
|
|
152
|
+
billingAddress { ...Address }
|
|
153
|
+
availableShippingMethods { code name description price { ...Money } minDeliveryDays maxDeliveryDays }
|
|
154
|
+
selectedShippingMethod { code name price { ...Money } }
|
|
155
|
+
availablePaymentMethods { ${paymentFields} }
|
|
156
|
+
selectedPaymentMethod { code }
|
|
157
|
+
coupons { code applied reason }
|
|
158
|
+
discounts { name couponCode amount { ...Money } }
|
|
159
|
+
cost { subtotal { ...Money } total { ...Money } tax { ...Money } pricesIncludeTax }
|
|
160
|
+
lines {
|
|
161
|
+
id name quantity quantityAvailable
|
|
162
|
+
unitPrice { ...Money } compareAtUnitPrice { ...Money } subtotal { ...Money } total { ...Money }
|
|
163
|
+
issue { code message }
|
|
164
|
+
product { name slug media { url alt kind } }
|
|
165
|
+
variant { id name selectedOptions { name label } media { url alt } }
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
${MONEY}
|
|
170
|
+
${ADDRESS}`;
|
|
171
|
+
/** What checkout reads of a cart mutation's result. */
|
|
172
|
+
const CHANGE_RESULT = `__typename ... on Error { code message } ... on ValidationError { fieldErrors { path message } }`;
|
|
173
|
+
export const CART_UPDATE = `mutation CheckoutUpdate($cartId: ID!, $input: CartUpdateInput!) { result: cartUpdate(cartId: $cartId, input: $input) { ${CHANGE_RESULT} } }`;
|
|
174
|
+
export const COUPON_APPLY = `mutation CheckoutCouponApply($cartId: ID!, $code: String!) { result: cartCouponApply(cartId: $cartId, code: $code) { ${CHANGE_RESULT} ... on CouponNotApplicableError { reason } } }`;
|
|
175
|
+
export const COUPON_REMOVE = `mutation CheckoutCouponRemove($cartId: ID!, $code: String!) { result: cartCouponRemove(cartId: $cartId, code: $code) { ${CHANGE_RESULT} } }`;
|
|
176
|
+
export const PAYMENT_SESSION_CREATE = `
|
|
177
|
+
mutation CheckoutPaymentSession($cartId: ID!) {
|
|
178
|
+
result: cartPaymentSessionCreate(cartId: $cartId) {
|
|
179
|
+
__typename
|
|
180
|
+
... on CartPaymentSessionPayload { session { provider methodCode amount { ...Money } clientData } }
|
|
181
|
+
... on Error { code message }
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
${MONEY}`;
|
|
185
|
+
const PLACED = `number email billingAddress { postalCode }`;
|
|
186
|
+
export const PLACE_ORDER = `
|
|
187
|
+
mutation CheckoutPlaceOrder($cartId: ID!, $idempotencyKey: String!, $input: CartUpdateInput, $payment: PaymentDataInput) {
|
|
188
|
+
result: checkoutPlaceOrder(cartId: $cartId, idempotencyKey: $idempotencyKey, input: $input, payment: $payment) {
|
|
189
|
+
__typename
|
|
190
|
+
... on CheckoutPayload { order { ${PLACED} } }
|
|
191
|
+
... on Error { code message }
|
|
192
|
+
... on ValidationError { fieldErrors { path message } }
|
|
193
|
+
... on CartNotReadyError { missing fieldErrors { path message } }
|
|
194
|
+
... on InsufficientStockError { sku available }
|
|
195
|
+
}
|
|
196
|
+
}`;
|
|
197
|
+
/** A cart that became an order elsewhere: a payment webhook, or another tab. */
|
|
198
|
+
export const CONVERTED_CART = `query CheckoutConvertedCart($id: ID!) { cart(id: $id) { isOpen order { ${PLACED} } } }`;
|
|
199
|
+
export const GUEST_ORDER = `
|
|
200
|
+
query GuestOrder($email: EmailAddress!, $number: String!, $postalCode: String!, $cartId: ID!) {
|
|
201
|
+
order: guestOrder(email: $email, number: $number, postalCode: $postalCode) {
|
|
202
|
+
number email locale status paymentStatus placedAt currencyCode
|
|
203
|
+
lines {
|
|
204
|
+
id name sku quantity
|
|
205
|
+
unitPrice { ...Money } subtotal { ...Money } total { ...Money }
|
|
206
|
+
product { name slug media { url alt kind } }
|
|
207
|
+
variant { selectedOptions { name label } media { url alt } }
|
|
208
|
+
}
|
|
209
|
+
totals { subtotal { ...Money } shipping { ...Money } tax { ...Money } total { ...Money } pricesIncludeTax discounts { name couponCode amount { ...Money } } }
|
|
210
|
+
shippingAddress { ...Address }
|
|
211
|
+
billingAddress { ...Address }
|
|
212
|
+
shippingMethod { name }
|
|
213
|
+
}
|
|
214
|
+
cart(id: $cartId) { selectedPaymentMethod { code name instructions } }
|
|
215
|
+
}
|
|
216
|
+
${MONEY}
|
|
217
|
+
${ADDRESS}`;
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** The API answered with GraphQL errors or an unexpected status. Status 0: it could not be reached. */
|
|
2
|
+
export declare class StorefrontApiError extends Error {
|
|
3
|
+
readonly status: number;
|
|
4
|
+
readonly codes: string[];
|
|
5
|
+
constructor(message: string, status: number, codes?: string[], options?: ErrorOptions);
|
|
6
|
+
}
|
|
7
|
+
/** A request with a preview token the API no longer accepts. */
|
|
8
|
+
export declare class PreviewExpiredError extends Error {
|
|
9
|
+
constructor();
|
|
10
|
+
}
|
|
11
|
+
/** Checked by name as well, since server bundles may hold more than one copy of this module. */
|
|
12
|
+
export declare const isPreviewExpired: (error: unknown) => error is PreviewExpiredError;
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** The API answered with GraphQL errors or an unexpected status. Status 0: it could not be reached. */
|
|
2
|
+
export class StorefrontApiError extends Error {
|
|
3
|
+
status;
|
|
4
|
+
codes;
|
|
5
|
+
constructor(message, status, codes = [], options) {
|
|
6
|
+
super(message, options);
|
|
7
|
+
this.name = "StorefrontApiError";
|
|
8
|
+
this.status = status;
|
|
9
|
+
this.codes = codes;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
/** A request with a preview token the API no longer accepts. */
|
|
13
|
+
export class PreviewExpiredError extends Error {
|
|
14
|
+
constructor() {
|
|
15
|
+
super("The preview has expired; open it again from the admin");
|
|
16
|
+
this.name = "PreviewExpiredError";
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/** Checked by name as well, since server bundles may hold more than one copy of this module. */
|
|
20
|
+
export const isPreviewExpired = (error) => error instanceof PreviewExpiredError || (error instanceof Error && error.name === "PreviewExpiredError");
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { blockNodes, containsComponent, isContentNode } from "./builder.ts";
|
|
2
|
+
export { CartError, createCartSession, type CartChange, type CartSession, type CartSessionOptions, type CartStore, type PaymentSession, type PaymentSessionResult, type PlaceOrderFailure, type PlaceOrderResult, } from "./cart.ts";
|
|
3
|
+
export { allNodes, createStorefrontClient, type RequestOptions, type StorefrontClient, type StorefrontClientOptions, type StorefrontScope } from "./client.ts";
|
|
4
|
+
export { fragments } from "./documents.ts";
|
|
5
|
+
export { isPreviewExpired, PreviewExpiredError, StorefrontApiError } from "./errors.ts";
|
|
6
|
+
export { mediaUrl } from "./media.ts";
|
|
7
|
+
export { categoryPath, normalizePath, productPath, safeLocalPath } from "./paths.ts";
|
|
8
|
+
export { isLower, isOnSale } from "./prices.ts";
|
|
9
|
+
export type * from "./types.ts";
|
|
10
|
+
export { chooseValue, firstValue, hasValues, inStock, matches, selectionOf, valuesWith, variantFor, type Selection } from "./variants.ts";
|
|
11
|
+
export { editable, visualEditingBridge, visualEditingBridgeUrl, type EditAttributes, type Editable, type VisualEditingBridge } from "./visual-editing.ts";
|
|
12
|
+
export { changesFor, parseWebhookEvent, SIGNATURE_TOLERANCE_SECONDS, verifyWebhookSignature, type ContentChange, type ContentChanges, type WebhookEvent } from "./webhooks.ts";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { blockNodes, containsComponent, isContentNode } from "./builder.js";
|
|
2
|
+
export { CartError, createCartSession, } from "./cart.js";
|
|
3
|
+
export { allNodes, createStorefrontClient } from "./client.js";
|
|
4
|
+
export { fragments } from "./documents.js";
|
|
5
|
+
export { isPreviewExpired, PreviewExpiredError, StorefrontApiError } from "./errors.js";
|
|
6
|
+
export { mediaUrl } from "./media.js";
|
|
7
|
+
export { categoryPath, normalizePath, productPath, safeLocalPath } from "./paths.js";
|
|
8
|
+
export { isLower, isOnSale } from "./prices.js";
|
|
9
|
+
export { chooseValue, firstValue, hasValues, inStock, matches, selectionOf, valuesWith, variantFor } from "./variants.js";
|
|
10
|
+
export { editable, visualEditingBridge, visualEditingBridgeUrl } from "./visual-editing.js";
|
|
11
|
+
export { changesFor, parseWebhookEvent, SIGNATURE_TOLERANCE_SECONDS, verifyWebhookSignature } from "./webhooks.js";
|
package/dist/media.d.ts
ADDED
package/dist/media.js
ADDED
package/dist/paths.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** The API's path rules: lowercase, single slashes, no trailing slash ("/" for the home page). */
|
|
2
|
+
export declare const normalizePath: (input: string) => string;
|
|
3
|
+
/** The API builds content links the same way. */
|
|
4
|
+
export declare const productPath: (slug: string) => string;
|
|
5
|
+
export declare const categoryPath: (path: string) => string;
|
|
6
|
+
/**
|
|
7
|
+
* A same-origin path to redirect to, or null for anything that could leave the site: absolute
|
|
8
|
+
* URLs, "//host" and backslash tricks.
|
|
9
|
+
*/
|
|
10
|
+
export declare const safeLocalPath: (value: string | null | undefined) => string | null;
|
package/dist/paths.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** The API's path rules: lowercase, single slashes, no trailing slash ("/" for the home page). */
|
|
2
|
+
export const normalizePath = (input) => {
|
|
3
|
+
const trimmed = input.trim().toLowerCase().replace(/\/{2,}/g, "/");
|
|
4
|
+
const withSlash = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
|
|
5
|
+
return withSlash.length > 1 ? withSlash.replace(/\/+$/, "") : withSlash;
|
|
6
|
+
};
|
|
7
|
+
/** The API builds content links the same way. */
|
|
8
|
+
export const productPath = (slug) => `/products/${slug}`;
|
|
9
|
+
export const categoryPath = (path) => `/categories/${path}`;
|
|
10
|
+
/**
|
|
11
|
+
* A same-origin path to redirect to, or null for anything that could leave the site: absolute
|
|
12
|
+
* URLs, "//host" and backslash tricks.
|
|
13
|
+
*/
|
|
14
|
+
export const safeLocalPath = (value) => {
|
|
15
|
+
if (!value || !value.startsWith("/") || value.startsWith("//") || value.startsWith("/\\") || value.length > 2000)
|
|
16
|
+
return null;
|
|
17
|
+
try {
|
|
18
|
+
const base = "http://storefront.invalid";
|
|
19
|
+
const url = new URL(value, base);
|
|
20
|
+
return url.origin === base ? `${url.pathname}${url.search}${url.hash}` : null;
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
};
|
package/dist/prices.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Money, PriceRange } from "./types.ts";
|
|
2
|
+
/** Whether a compare-at price is above the price, so the item shows as on sale. */
|
|
3
|
+
export declare const isLower: (price: Money, compareAt: Money | null | undefined) => compareAt is Money;
|
|
4
|
+
export declare const isOnSale: (range: PriceRange | null | undefined) => boolean;
|
package/dist/prices.js
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
/** Whether a compare-at price is above the price, so the item shows as on sale. */
|
|
2
|
+
export const isLower = (price, compareAt) => !!compareAt && Number(compareAt.amount) > Number(price.amount);
|
|
3
|
+
export const isOnSale = (range) => !!range?.minVariantPrice && isLower(range.minVariantPrice, range.compareAtMinVariantPrice);
|