From db85f3263d0e6dd59054da3721f19600cc018847 Mon Sep 17 00:00:00 2001 From: metatroncubeswdev Date: Thu, 15 Oct 2026 00:47:08 -0400 Subject: [PATCH] fix(build): make every extension build for shopify app deploy - functions: add codegen config and the downloaded schema.graphql (generated/ ignored) - order-reschedule: add the @preact/signals peer dependency - widget: source moved to widget-src/, minified build in assets (npm run build:widget, also run by predeploy); e2e passes on the minified file Co-Authored-By: Claude Opus 5.5 --- .gitignore | 1 + extensions/checkout-guard/package.json | 15 + extensions/checkout-guard/schema.graphql | 5132 ++++++++++++++++ extensions/datewise-widget/assets/datewise.js | 447 +- extensions/delivery-label/package.json | 15 + extensions/delivery-label/schema.graphql | 4992 ++++++++++++++++ extensions/order-reschedule/manifest.json | 3 + extensions/order-reschedule/package-lock.json | 27 + extensions/order-reschedule/package.json | 1 + extensions/payment-rules/package.json | 15 + extensions/payment-rules/schema.graphql | 5259 +++++++++++++++++ package.json | 6 +- shopify.app.toml | 1 - widget-src/datewise.js | 447 ++ 14 files changed, 15912 insertions(+), 449 deletions(-) create mode 100644 extensions/checkout-guard/schema.graphql create mode 100644 extensions/delivery-label/schema.graphql create mode 100644 extensions/order-reschedule/manifest.json create mode 100644 extensions/payment-rules/schema.graphql create mode 100644 widget-src/datewise.js diff --git a/.gitignore b/.gitignore index 5add5fb..5fcaac5 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ extensions/*/dist extensions/*/node_modules *.log .DS_Store +extensions/*/generated diff --git a/extensions/checkout-guard/package.json b/extensions/checkout-guard/package.json index 7c24469..2550b41 100644 --- a/extensions/checkout-guard/package.json +++ b/extensions/checkout-guard/package.json @@ -12,5 +12,20 @@ }, "dependencies": { "@shopify/shopify_function": "^2.0.1" + }, + "codegen": { + "schema": "schema.graphql", + "documents": "src/*.graphql", + "generates": { + "./generated/api.ts": { + "plugins": [ + "typescript", + "typescript-operations" + ] + } + }, + "config": { + "omitOperationSuffix": true + } } } diff --git a/extensions/checkout-guard/schema.graphql b/extensions/checkout-guard/schema.graphql new file mode 100644 index 0000000..1a45b59 --- /dev/null +++ b/extensions/checkout-guard/schema.graphql @@ -0,0 +1,5132 @@ +# api_version: 2026-01 + +schema { + query: Input + mutation: MutationRoot +} + +""" +Only allow the field to be queried when targeting one of the specified targets. +""" +directive @restrictTarget(only: [String!]!) on FIELD_DEFINITION + +""" +Scale the Functions resource limits based on the field's length. +""" +directive @scaleLimits(rate: Float!) on FIELD_DEFINITION + +""" +Requires that exactly one field must be supplied and that field must not be `null`. +""" +directive @oneOf on INPUT_OBJECT + +""" +A custom property. Attributes are used to store additional information about a Shopify resource, such as +products, customers, or orders. Attributes are stored as key-value pairs. + +For example, a list of attributes might include whether a customer is a first-time buyer (`"customer_first_order": "true"`), +whether an order is gift-wrapped (`"gift_wrapped": "true"`), a preferred delivery date +(`"preferred_delivery_date": "2025-10-01"`), the discount applied (`"loyalty_discount_applied": "10%"`), and any +notes provided by the customer (`"customer_notes": "Please leave at the front door"`). +""" +type Attribute { + """ + The key or name of the attribute. For example, `"customer_first_order"`. + """ + key: String! + + """ + The value of the attribute. For example, `"true"`. + """ + value: String +} + +""" +Information about the customer that's interacting with the cart. It includes details such as the +customer's email and phone number, and the total amount of money the customer has spent in the store. +This information helps personalize the checkout experience and ensures that accurate pricing and delivery options +are displayed to customers. +""" +type BuyerIdentity { + """ + The [customer](https://help.shopify.com/manual/customers/manage-customers) that's interacting with the cart. + """ + customer: Customer + + """ + The email address of the customer that's interacting with the cart. + """ + email: String + + """ + Whether the customer is authenticated through their + [customer account](https://help.shopify.com/manual/customers/customer-accounts). + """ + isAuthenticated: Boolean! + + """ + The phone number of the customer that's interacting with the cart. + """ + phone: String + + """ + The company of a B2B customer that's interacting with the cart. + Used to manage and track purchases made by businesses rather than individual customers. + """ + purchasingCompany: PurchasingCompany +} + +type BuyerJourney { + step: BuyerJourneyStep +} + +""" +A specific stage in the customer's purchasing journey that indicates where the customer is in the checkout +process. +""" +enum BuyerJourneyStep { + """ + The customer is interacting with the cart. For example, the customer is adding items to the cart + or removing items from the cart. + """ + CART_INTERACTION + + """ + The customer is completing checkout. For example, the customer is reviewing their order before + finalizing the purchase. + """ + CHECKOUT_COMPLETION + + """ + The customer is interacting with checkout. For example, the customer is adding their shipping + address or payment information. + """ + CHECKOUT_INTERACTION +} + +""" +The cart where the Function is running. A cart contains the merchandise that a customer intends to purchase +and information about the customer, such as the customer's email address and phone number. +""" +type Cart implements HasMetafields { + """ + The custom attributes associated with a cart to store additional information. Cart attributes + allow you to collect specific information from customers on the **Cart** page, such as order notes, + gift wrapping requests, or custom product details. Attributes are stored as key-value pairs. + """ + attribute( + """ + The key of the cart attribute to retrieve. For example, `"gift_wrapping"`. + """ + key: String + ): Attribute + + """ + Information about the customer that's interacting with the cart. It includes details such as the + customer's email and phone number, and the total amount of money the customer has spent in the store. + This information helps personalize the checkout experience and ensures that accurate pricing and delivery options + are displayed to customers. + """ + buyerIdentity: BuyerIdentity + + """ + A breakdown of the costs that the customer will pay at checkout. It includes the total amount, + the subtotal before taxes and duties, the tax amount, and duty charges. + """ + cost: CartCost! + + """ + The items in a cart that are eligible for fulfillment and can be delivered to the customer. + """ + deliverableLines: [DeliverableCartLine!]! + + """ + A collection of items that are grouped by shared delivery characteristics. Delivery groups streamline + fulfillment by organizing items that can be shipped together, based on the customer's + shipping address. For example, if a customer orders a t-shirt and a pair of shoes that can be shipped + together, then the items are included in the same delivery group. + + In the [Order Discount](https://shopify.dev/docs/api/functions/reference/order-discounts) and + [Product Discount](https://shopify.dev/docs/api/functions/reference/product-discounts) legacy APIs, + the `cart.deliveryGroups` input is always an empty array. This means you can't access delivery groups when + creating Order Discount or Product Discount Functions. If you need to apply discounts to shipping costs, + then use the [Discount Function API](https://shopify.dev/docs/api/functions/reference/discount) + instead. + """ + deliveryGroups: [CartDeliveryGroup!]! + + """ + The items in a cart that the customer intends to purchase. A cart line is an entry in the + customer's cart that represents a single unit of a product variant. For example, if a customer adds two + different sizes of the same t-shirt to their cart, then each size is represented as a separate cart line. + """ + lines: [CartLine!]! @scaleLimits(rate: 0.005) + + """ + The additional fields on the **Cart** page that are required for international orders in specific countries, + such as customs information or tax identification numbers. + """ + localizedFields( + """ + The keys of the localized fields to retrieve. + """ + keys: [LocalizedFieldKey!]! = [] + ): [LocalizedField!]! + + """ + A [custom field](https://shopify.dev/docs/apps/build/custom-data) that stores additional information + about a Shopify resource, such as products, orders, and + [many more](https://shopify.dev/docs/api/admin-graphql/latest/enums/MetafieldOwnerType). + Using [metafields with Shopify Functions](https://shopify.dev/docs/apps/build/functions/input-output/metafields-for-input-queries) + enables you to customize the checkout experience. + """ + metafield( + """ + The unique identifier for the metafield within its namespace. A metafield is composed of a + namespace and a key, in the format `namespace.key`. + """ + key: String! + + """ + A category that organizes a group of metafields. Namespaces are used to prevent naming conflicts + between different apps or different parts of the same app. If omitted, then the + [app-reserved namespace](https://shopify.dev/docs/apps/build/custom-data/ownership) + is used. + """ + namespace: String + ): Metafield + + """ + The physical location where a retail order is created or completed. + """ + retailLocation: Location +} + +""" +A breakdown of the costs that the customer will pay at checkout. It includes the total amount, +the subtotal before taxes and duties, the tax amount, and duty charges. +""" +type CartCost { + """ + The amount, before taxes and cart-level discounts, for the customer to pay. + """ + subtotalAmount: MoneyV2! + + """ + The total amount for the customer to pay at checkout. + """ + totalAmount: MoneyV2! + + """ + The duty charges for a customer to pay at checkout. + """ + totalDutyAmount: MoneyV2 + + """ + The total tax amount for the customer to pay at checkout. + """ + totalTaxAmount: MoneyV2 +} + +""" +Information about items in a cart that are grouped by shared delivery characteristics. +Delivery groups streamline fulfillment by organizing items that can be shipped together, based on the customer's +shipping address. For example, if a customer orders a t-shirt and a pair of shoes that can be shipped +together, then the items are included in the same delivery group. +""" +type CartDeliveryGroup { + """ + Information about items in a cart that a customer intends to purchase. A cart line is an entry in the + customer's cart that represents a single unit of a product variant. For example, if a customer adds two + different sizes of the same t-shirt to their cart, then each size is represented as a separate cart line. + """ + cartLines: [CartLine!]! @scaleLimits(rate: 0.005) + + """ + The shipping or destination address associated with the delivery group. + """ + deliveryAddress: MailingAddress + + """ + The delivery options available for the delivery group. Delivery options are the different ways that customers + can choose to have their orders shipped. Examples include express shipping or standard shipping. + """ + deliveryOptions: [CartDeliveryOption!]! + + """ + The type of merchandise in the delivery group. + """ + groupType: CartDeliveryGroupType! + + """ + A [globally-unique ID](https://shopify.dev/docs/api/usage/gids) + for the delivery group. + """ + id: ID! + + """ + Information about the delivery option that the customer has selected. + """ + selectedDeliveryOption: CartDeliveryOption +} + +""" +Defines what type of merchandise is in the delivery group. +""" +enum CartDeliveryGroupType { + """ + The delivery group only contains merchandise that is either a one time purchase or a first delivery of + subscription merchandise. + """ + ONE_TIME_PURCHASE + + """ + The delivery group only contains subscription merchandise. + """ + SUBSCRIPTION +} + +""" +Information about a delivery option that's available for an item in a cart. Delivery options are the different +ways that customers can choose to have their orders shipped. Examples include express shipping or standard +shipping. +""" +type CartDeliveryOption { + """ + A unique identifier that represents the delivery option offered to customers. + For example, `Canada Post Expedited`. + """ + code: String + + """ + The amount that the customer pays if they select the delivery option. + """ + cost: MoneyV2! + + """ + The delivery method associated with the delivery option. A delivery method is a way that merchants can + fulfill orders from their online stores. Delivery methods include shipping to an address, + [local pickup](https://help.shopify.com/manual/fulfillment/setup/delivery-methods/pickup-in-store), + and shipping to a [pickup point](https://help.shopify.com/manual/fulfillment/shopify-shipping/pickup-points), + all of which are natively supported by Shopify checkout. + """ + deliveryMethodType: DeliveryMethod! + + """ + A single-line description of the delivery option, with HTML tags removed. + """ + description: String + + """ + A unique, human-readable identifier of the delivery option's title. + A handle can contain letters, hyphens (`-`), and numbers, but not spaces. + For example, `standard-shipping`. + """ + handle: Handle! + + """ + The name of the delivery option that displays to customers. The title is used to construct the delivery + option's handle. For example, if a delivery option is titled "Standard Shipping", then the handle is + `standard-shipping`. + """ + title: String +} + +""" +Information about an item in a cart that a customer intends to purchase. A cart line is an entry in the +customer's cart that represents a single unit of a product variant. For example, if a customer adds two +different sizes of the same t-shirt to their cart, then each size is represented as a separate cart line. +""" +type CartLine { + """ + The custom attributes associated with a cart to store additional information. Cart attributes + allow you to collect specific information from customers on the **Cart** page, such as order notes, + gift wrapping requests, or custom product details. Attributes are stored as key-value pairs. + + Cart line attributes are equivalent to the + [`line_item`](https://shopify.dev/docs/api/liquid/objects/line_item) + object in Liquid. + """ + attribute( + """ + The key of the cart attribute to retrieve. For example, `"gift_wrapping"`. + """ + key: String + ): Attribute + + """ + The cost of an item in a cart that the customer intends to purchase. Cart lines are entries in the customer's + cart that represent a single unit of a product variant. For example, if a customer adds two different sizes of + the same t-shirt to their cart, then each size is represented as a separate cart line. + """ + cost: CartLineCost! + + """ + The ID of the cart line. + """ + id: ID! + + """ + The item that the customer intends to purchase. + """ + merchandise: Merchandise! + + """ + The [nested relationship](https://shopify.dev/docs/apps/build/product-merchandising/nested-cart-lines) + between this line and its parent line, if any. + """ + parentRelationship: CartLineParentRelationship + + """ + The quantity of the item that the customer intends to purchase. + """ + quantity: Int! + + """ + The [selling plan](https://shopify.dev/docs/apps/build/purchase-options/subscriptions/selling-plans) + associated with the cart line, including information about how a product variant can be sold and purchased. + """ + sellingPlanAllocation: SellingPlanAllocation +} + +""" +The cost of an item in a cart that the customer intends to purchase. Cart lines are entries in the customer's +cart that represent a single unit of a product variant. For example, if a customer adds two different sizes of +the same t-shirt to their cart, then each size is represented as a separate cart line. +""" +type CartLineCost { + """ + The cost of a single unit. For example, if a customer purchases three units of a product + that are priced at $10 each, then the `amountPerQuantity` is $10. + """ + amountPerQuantity: MoneyV2! + + """ + The `compareAt` price of a single unit before any discounts are applied. This field is used to calculate and display + savings for customers. For example, if a product's `compareAtAmountPerQuantity` is $25 and its current price + is $20, then the customer sees a $5 discount. This value can change based on the buyer's identity and is + `null` when the value is hidden from buyers. + """ + compareAtAmountPerQuantity: MoneyV2 + + """ + The cost of items in the cart before applying any discounts to certain items. + This amount serves as the starting point for calculating any potential savings customers + might receive through promotions or discounts. + """ + subtotalAmount: MoneyV2! + + """ + The total cost of items in a cart. + """ + totalAmount: MoneyV2! +} + +""" +Represents the relationship between a cart line and its parent line. +""" +type CartLineParentRelationship { + """ + The parent line in the relationship. + """ + parent: CartLine! +} + +""" +The fetch target result. Your Function must return this data structure when generating the request. +""" +input CartValidationsGenerateFetchResult { + """ + The attributes associated with an HTTP request. + """ + request: HttpRequest +} + +""" +The output of the Function run target. The object contains the validation errors +that display to customers and prevent them from proceeding through checkout. +""" +input CartValidationsGenerateRunResult { + """ + An ordered list of operations to be executed for the validations associated with the + cart and checkout processes. + """ + operations: [Operation!]! +} + +""" +Whether the product is in the specified collection. + +A collection is a group of products that can be displayed in online stores and other sales channels in +categories, which makes it easy for customers to find them. For example, an athletics store might create +different collections for running attire and accessories. +""" +type CollectionMembership { + """ + A [globally-unique ID](https://shopify.dev/docs/api/usage/gids) + for the collection. + """ + collectionId: ID! + + """ + Whether the product is in the specified collection. + """ + isMember: Boolean! +} + +""" +Represents information about a company which is also a customer of the shop. +""" +type Company implements HasMetafields { + """ + The date and time ([ISO 8601 format](http://en.wikipedia.org/wiki/ISO_8601)) at which the company was created in Shopify. + """ + createdAt: DateTime! + + """ + A unique externally-supplied ID for the company. + """ + externalId: String + + """ + The ID of the company. + """ + id: ID! + + """ + A [custom field](https://shopify.dev/docs/apps/build/custom-data) that stores additional information + about a Shopify resource, such as products, orders, and + [many more](https://shopify.dev/docs/api/admin-graphql/latest/enums/MetafieldOwnerType). + Using [metafields with Shopify Functions](https://shopify.dev/docs/apps/build/functions/input-output/metafields-for-input-queries) + enables you to customize the checkout experience. + """ + metafield( + """ + The unique identifier for the metafield within its namespace. A metafield is composed of a + namespace and a key, in the format `namespace.key`. + """ + key: String! + + """ + A category that organizes a group of metafields. Namespaces are used to prevent naming conflicts + between different apps or different parts of the same app. If omitted, then the + [app-reserved namespace](https://shopify.dev/docs/apps/build/custom-data/ownership) + is used. + """ + namespace: String + ): Metafield + + """ + The name of the company. + """ + name: String! + + """ + The date and time ([ISO 8601 format](http://en.wikipedia.org/wiki/ISO_8601)) at which the company was last modified. + """ + updatedAt: DateTime! +} + +""" +A company's main point of contact. +""" +type CompanyContact { + """ + The date and time ([ISO 8601 format](http://en.wikipedia.org/wiki/ISO_8601)) + at which the company contact was created in Shopify. + """ + createdAt: DateTime! + + """ + The ID of the company. + """ + id: ID! + + """ + The company contact's locale (language). + """ + locale: String + + """ + The company contact's job title. + """ + title: String + + """ + The date and time ([ISO 8601 format](http://en.wikipedia.org/wiki/ISO_8601)) + at which the company contact was last modified. + """ + updatedAt: DateTime! +} + +""" +A company's location. +""" +type CompanyLocation implements HasMetafields { + """ + The date and time ([ISO 8601 format](http://en.wikipedia.org/wiki/ISO_8601)) + at which the company location was created in Shopify. + """ + createdAt: DateTime! + + """ + A unique externally-supplied ID for the company. + """ + externalId: String + + """ + The ID of the company. + """ + id: ID! + + """ + The preferred locale of the company location. + """ + locale: String + + """ + A [custom field](https://shopify.dev/docs/apps/build/custom-data) that stores additional information + about a Shopify resource, such as products, orders, and + [many more](https://shopify.dev/docs/api/admin-graphql/latest/enums/MetafieldOwnerType). + Using [metafields with Shopify Functions](https://shopify.dev/docs/apps/build/functions/input-output/metafields-for-input-queries) + enables you to customize the checkout experience. + """ + metafield( + """ + The unique identifier for the metafield within its namespace. A metafield is composed of a + namespace and a key, in the format `namespace.key`. + """ + key: String! + + """ + A category that organizes a group of metafields. Namespaces are used to prevent naming conflicts + between different apps or different parts of the same app. If omitted, then the + [app-reserved namespace](https://shopify.dev/docs/apps/build/custom-data/ownership) + is used. + """ + namespace: String + ): Metafield + + """ + The name of the company location. + """ + name: String! + + """ + The number of orders placed at this company location. + """ + ordersCount: Int! + + """ + The total amount spent at this company location. + """ + totalSpent: MoneyV2! + + """ + The date and time ([ISO 8601 format](http://en.wikipedia.org/wiki/ISO_8601)) + at which the company location was last modified. + """ + updatedAt: DateTime! +} + +""" +The country for which the store is customized, reflecting local preferences and regulations. +Localization might influence the language, currency, and product offerings available in a store to enhance +the shopping experience for customers in that region. +""" +type Country { + """ + The ISO code of the country. + """ + isoCode: CountryCode! +} + +""" +The code designating a country/region, which generally follows ISO 3166-1 alpha-2 guidelines. +If a territory doesn't have a country code value in the `CountryCode` enum, then it might be considered a subdivision +of another country. For example, the territories associated with Spain are represented by the country code `ES`, +and the territories associated with the United States of America are represented by the country code `US`. +""" +enum CountryCode { + """ + Ascension Island. + """ + AC + + """ + Andorra. + """ + AD + + """ + United Arab Emirates. + """ + AE + + """ + Afghanistan. + """ + AF + + """ + Antigua & Barbuda. + """ + AG + + """ + Anguilla. + """ + AI + + """ + Albania. + """ + AL + + """ + Armenia. + """ + AM + + """ + Netherlands Antilles. + """ + AN + + """ + Angola. + """ + AO + + """ + Argentina. + """ + AR + + """ + Austria. + """ + AT + + """ + Australia. + """ + AU + + """ + Aruba. + """ + AW + + """ + Åland Islands. + """ + AX + + """ + Azerbaijan. + """ + AZ + + """ + Bosnia & Herzegovina. + """ + BA + + """ + Barbados. + """ + BB + + """ + Bangladesh. + """ + BD + + """ + Belgium. + """ + BE + + """ + Burkina Faso. + """ + BF + + """ + Bulgaria. + """ + BG + + """ + Bahrain. + """ + BH + + """ + Burundi. + """ + BI + + """ + Benin. + """ + BJ + + """ + St. Barthélemy. + """ + BL + + """ + Bermuda. + """ + BM + + """ + Brunei. + """ + BN + + """ + Bolivia. + """ + BO + + """ + Caribbean Netherlands. + """ + BQ + + """ + Brazil. + """ + BR + + """ + Bahamas. + """ + BS + + """ + Bhutan. + """ + BT + + """ + Bouvet Island. + """ + BV + + """ + Botswana. + """ + BW + + """ + Belarus. + """ + BY + + """ + Belize. + """ + BZ + + """ + Canada. + """ + CA + + """ + Cocos (Keeling) Islands. + """ + CC + + """ + Congo - Kinshasa. + """ + CD + + """ + Central African Republic. + """ + CF + + """ + Congo - Brazzaville. + """ + CG + + """ + Switzerland. + """ + CH + + """ + Côte d’Ivoire. + """ + CI + + """ + Cook Islands. + """ + CK + + """ + Chile. + """ + CL + + """ + Cameroon. + """ + CM + + """ + China. + """ + CN + + """ + Colombia. + """ + CO + + """ + Costa Rica. + """ + CR + + """ + Cuba. + """ + CU + + """ + Cape Verde. + """ + CV + + """ + Curaçao. + """ + CW + + """ + Christmas Island. + """ + CX + + """ + Cyprus. + """ + CY + + """ + Czechia. + """ + CZ + + """ + Germany. + """ + DE + + """ + Djibouti. + """ + DJ + + """ + Denmark. + """ + DK + + """ + Dominica. + """ + DM + + """ + Dominican Republic. + """ + DO + + """ + Algeria. + """ + DZ + + """ + Ecuador. + """ + EC + + """ + Estonia. + """ + EE + + """ + Egypt. + """ + EG + + """ + Western Sahara. + """ + EH + + """ + Eritrea. + """ + ER + + """ + Spain. + """ + ES + + """ + Ethiopia. + """ + ET + + """ + Finland. + """ + FI + + """ + Fiji. + """ + FJ + + """ + Falkland Islands. + """ + FK + + """ + Faroe Islands. + """ + FO + + """ + France. + """ + FR + + """ + Gabon. + """ + GA + + """ + United Kingdom. + """ + GB + + """ + Grenada. + """ + GD + + """ + Georgia. + """ + GE + + """ + French Guiana. + """ + GF + + """ + Guernsey. + """ + GG + + """ + Ghana. + """ + GH + + """ + Gibraltar. + """ + GI + + """ + Greenland. + """ + GL + + """ + Gambia. + """ + GM + + """ + Guinea. + """ + GN + + """ + Guadeloupe. + """ + GP + + """ + Equatorial Guinea. + """ + GQ + + """ + Greece. + """ + GR + + """ + South Georgia & South Sandwich Islands. + """ + GS + + """ + Guatemala. + """ + GT + + """ + Guinea-Bissau. + """ + GW + + """ + Guyana. + """ + GY + + """ + Hong Kong SAR. + """ + HK + + """ + Heard & McDonald Islands. + """ + HM + + """ + Honduras. + """ + HN + + """ + Croatia. + """ + HR + + """ + Haiti. + """ + HT + + """ + Hungary. + """ + HU + + """ + Indonesia. + """ + ID + + """ + Ireland. + """ + IE + + """ + Israel. + """ + IL + + """ + Isle of Man. + """ + IM + + """ + India. + """ + IN + + """ + British Indian Ocean Territory. + """ + IO + + """ + Iraq. + """ + IQ + + """ + Iran. + """ + IR + + """ + Iceland. + """ + IS + + """ + Italy. + """ + IT + + """ + Jersey. + """ + JE + + """ + Jamaica. + """ + JM + + """ + Jordan. + """ + JO + + """ + Japan. + """ + JP + + """ + Kenya. + """ + KE + + """ + Kyrgyzstan. + """ + KG + + """ + Cambodia. + """ + KH + + """ + Kiribati. + """ + KI + + """ + Comoros. + """ + KM + + """ + St. Kitts & Nevis. + """ + KN + + """ + North Korea. + """ + KP + + """ + South Korea. + """ + KR + + """ + Kuwait. + """ + KW + + """ + Cayman Islands. + """ + KY + + """ + Kazakhstan. + """ + KZ + + """ + Laos. + """ + LA + + """ + Lebanon. + """ + LB + + """ + St. Lucia. + """ + LC + + """ + Liechtenstein. + """ + LI + + """ + Sri Lanka. + """ + LK + + """ + Liberia. + """ + LR + + """ + Lesotho. + """ + LS + + """ + Lithuania. + """ + LT + + """ + Luxembourg. + """ + LU + + """ + Latvia. + """ + LV + + """ + Libya. + """ + LY + + """ + Morocco. + """ + MA + + """ + Monaco. + """ + MC + + """ + Moldova. + """ + MD + + """ + Montenegro. + """ + ME + + """ + St. Martin. + """ + MF + + """ + Madagascar. + """ + MG + + """ + North Macedonia. + """ + MK + + """ + Mali. + """ + ML + + """ + Myanmar (Burma). + """ + MM + + """ + Mongolia. + """ + MN + + """ + Macao SAR. + """ + MO + + """ + Martinique. + """ + MQ + + """ + Mauritania. + """ + MR + + """ + Montserrat. + """ + MS + + """ + Malta. + """ + MT + + """ + Mauritius. + """ + MU + + """ + Maldives. + """ + MV + + """ + Malawi. + """ + MW + + """ + Mexico. + """ + MX + + """ + Malaysia. + """ + MY + + """ + Mozambique. + """ + MZ + + """ + Namibia. + """ + NA + + """ + New Caledonia. + """ + NC + + """ + Niger. + """ + NE + + """ + Norfolk Island. + """ + NF + + """ + Nigeria. + """ + NG + + """ + Nicaragua. + """ + NI + + """ + Netherlands. + """ + NL + + """ + Norway. + """ + NO + + """ + Nepal. + """ + NP + + """ + Nauru. + """ + NR + + """ + Niue. + """ + NU + + """ + New Zealand. + """ + NZ + + """ + Oman. + """ + OM + + """ + Panama. + """ + PA + + """ + Peru. + """ + PE + + """ + French Polynesia. + """ + PF + + """ + Papua New Guinea. + """ + PG + + """ + Philippines. + """ + PH + + """ + Pakistan. + """ + PK + + """ + Poland. + """ + PL + + """ + St. Pierre & Miquelon. + """ + PM + + """ + Pitcairn Islands. + """ + PN + + """ + Palestinian Territories. + """ + PS + + """ + Portugal. + """ + PT + + """ + Paraguay. + """ + PY + + """ + Qatar. + """ + QA + + """ + Réunion. + """ + RE + + """ + Romania. + """ + RO + + """ + Serbia. + """ + RS + + """ + Russia. + """ + RU + + """ + Rwanda. + """ + RW + + """ + Saudi Arabia. + """ + SA + + """ + Solomon Islands. + """ + SB + + """ + Seychelles. + """ + SC + + """ + Sudan. + """ + SD + + """ + Sweden. + """ + SE + + """ + Singapore. + """ + SG + + """ + St. Helena. + """ + SH + + """ + Slovenia. + """ + SI + + """ + Svalbard & Jan Mayen. + """ + SJ + + """ + Slovakia. + """ + SK + + """ + Sierra Leone. + """ + SL + + """ + San Marino. + """ + SM + + """ + Senegal. + """ + SN + + """ + Somalia. + """ + SO + + """ + Suriname. + """ + SR + + """ + South Sudan. + """ + SS + + """ + São Tomé & Príncipe. + """ + ST + + """ + El Salvador. + """ + SV + + """ + Sint Maarten. + """ + SX + + """ + Syria. + """ + SY + + """ + Eswatini. + """ + SZ + + """ + Tristan da Cunha. + """ + TA + + """ + Turks & Caicos Islands. + """ + TC + + """ + Chad. + """ + TD + + """ + French Southern Territories. + """ + TF + + """ + Togo. + """ + TG + + """ + Thailand. + """ + TH + + """ + Tajikistan. + """ + TJ + + """ + Tokelau. + """ + TK + + """ + Timor-Leste. + """ + TL + + """ + Turkmenistan. + """ + TM + + """ + Tunisia. + """ + TN + + """ + Tonga. + """ + TO + + """ + Türkiye. + """ + TR + + """ + Trinidad & Tobago. + """ + TT + + """ + Tuvalu. + """ + TV + + """ + Taiwan. + """ + TW + + """ + Tanzania. + """ + TZ + + """ + Ukraine. + """ + UA + + """ + Uganda. + """ + UG + + """ + U.S. Outlying Islands. + """ + UM + + """ + United States. + """ + US + + """ + Uruguay. + """ + UY + + """ + Uzbekistan. + """ + UZ + + """ + Vatican City. + """ + VA + + """ + St. Vincent & Grenadines. + """ + VC + + """ + Venezuela. + """ + VE + + """ + British Virgin Islands. + """ + VG + + """ + Vietnam. + """ + VN + + """ + Vanuatu. + """ + VU + + """ + Wallis & Futuna. + """ + WF + + """ + Samoa. + """ + WS + + """ + Kosovo. + """ + XK + + """ + Yemen. + """ + YE + + """ + Mayotte. + """ + YT + + """ + South Africa. + """ + ZA + + """ + Zambia. + """ + ZM + + """ + Zimbabwe. + """ + ZW + + """ + Unknown Region. + """ + ZZ +} + +""" +The currency codes that represent the world currencies throughout the Admin API. Currency codes include +[standard ISO 4217 codes](https://en.wikipedia.org/wiki/ISO_4217), legacy codes, non-standard codes, +digital currency codes. +""" +enum CurrencyCode { + """ + United Arab Emirates Dirham (AED). + """ + AED + + """ + Afghan Afghani (AFN). + """ + AFN + + """ + Albanian Lek (ALL). + """ + ALL + + """ + Armenian Dram (AMD). + """ + AMD + + """ + Netherlands Antillean Guilder. + """ + ANG @deprecated(reason: "Use `XCG` instead.") + + """ + Angolan Kwanza (AOA). + """ + AOA + + """ + Argentine Pesos (ARS). + """ + ARS + + """ + Australian Dollars (AUD). + """ + AUD + + """ + Aruban Florin (AWG). + """ + AWG + + """ + Azerbaijani Manat (AZN). + """ + AZN + + """ + Bosnia and Herzegovina Convertible Mark (BAM). + """ + BAM + + """ + Barbadian Dollar (BBD). + """ + BBD + + """ + Bangladesh Taka (BDT). + """ + BDT + + """ + Bulgarian Lev (BGN). + """ + BGN + + """ + Bahraini Dinar (BHD). + """ + BHD + + """ + Burundian Franc (BIF). + """ + BIF + + """ + Bermudian Dollar (BMD). + """ + BMD + + """ + Brunei Dollar (BND). + """ + BND + + """ + Bolivian Boliviano (BOB). + """ + BOB + + """ + Brazilian Real (BRL). + """ + BRL + + """ + Bahamian Dollar (BSD). + """ + BSD + + """ + Bhutanese Ngultrum (BTN). + """ + BTN + + """ + Botswana Pula (BWP). + """ + BWP + + """ + Belarusian Ruble (BYN). + """ + BYN + + """ + Belarusian Ruble (BYR). + """ + BYR @deprecated(reason: "Use `BYN` instead.") + + """ + Belize Dollar (BZD). + """ + BZD + + """ + Canadian Dollars (CAD). + """ + CAD + + """ + Congolese franc (CDF). + """ + CDF + + """ + Swiss Francs (CHF). + """ + CHF + + """ + Chilean Peso (CLP). + """ + CLP + + """ + Chinese Yuan Renminbi (CNY). + """ + CNY + + """ + Colombian Peso (COP). + """ + COP + + """ + Costa Rican Colones (CRC). + """ + CRC + + """ + Cape Verdean escudo (CVE). + """ + CVE + + """ + Czech Koruny (CZK). + """ + CZK + + """ + Djiboutian Franc (DJF). + """ + DJF + + """ + Danish Kroner (DKK). + """ + DKK + + """ + Dominican Peso (DOP). + """ + DOP + + """ + Algerian Dinar (DZD). + """ + DZD + + """ + Egyptian Pound (EGP). + """ + EGP + + """ + Eritrean Nakfa (ERN). + """ + ERN + + """ + Ethiopian Birr (ETB). + """ + ETB + + """ + Euro (EUR). + """ + EUR + + """ + Fijian Dollars (FJD). + """ + FJD + + """ + Falkland Islands Pounds (FKP). + """ + FKP + + """ + United Kingdom Pounds (GBP). + """ + GBP + + """ + Georgian Lari (GEL). + """ + GEL + + """ + Ghanaian Cedi (GHS). + """ + GHS + + """ + Gibraltar Pounds (GIP). + """ + GIP + + """ + Gambian Dalasi (GMD). + """ + GMD + + """ + Guinean Franc (GNF). + """ + GNF + + """ + Guatemalan Quetzal (GTQ). + """ + GTQ + + """ + Guyanese Dollar (GYD). + """ + GYD + + """ + Hong Kong Dollars (HKD). + """ + HKD + + """ + Honduran Lempira (HNL). + """ + HNL + + """ + Croatian Kuna (HRK). + """ + HRK + + """ + Haitian Gourde (HTG). + """ + HTG + + """ + Hungarian Forint (HUF). + """ + HUF + + """ + Indonesian Rupiah (IDR). + """ + IDR + + """ + Israeli New Shekel (NIS). + """ + ILS + + """ + Indian Rupees (INR). + """ + INR + + """ + Iraqi Dinar (IQD). + """ + IQD + + """ + Iranian Rial (IRR). + """ + IRR + + """ + Icelandic Kronur (ISK). + """ + ISK + + """ + Jersey Pound. + """ + JEP + + """ + Jamaican Dollars (JMD). + """ + JMD + + """ + Jordanian Dinar (JOD). + """ + JOD + + """ + Japanese Yen (JPY). + """ + JPY + + """ + Kenyan Shilling (KES). + """ + KES + + """ + Kyrgyzstani Som (KGS). + """ + KGS + + """ + Cambodian Riel. + """ + KHR + + """ + Kiribati Dollar (KID). + """ + KID + + """ + Comorian Franc (KMF). + """ + KMF + + """ + South Korean Won (KRW). + """ + KRW + + """ + Kuwaiti Dinar (KWD). + """ + KWD + + """ + Cayman Dollars (KYD). + """ + KYD + + """ + Kazakhstani Tenge (KZT). + """ + KZT + + """ + Laotian Kip (LAK). + """ + LAK + + """ + Lebanese Pounds (LBP). + """ + LBP + + """ + Sri Lankan Rupees (LKR). + """ + LKR + + """ + Liberian Dollar (LRD). + """ + LRD + + """ + Lesotho Loti (LSL). + """ + LSL + + """ + Lithuanian Litai (LTL). + """ + LTL + + """ + Latvian Lati (LVL). + """ + LVL + + """ + Libyan Dinar (LYD). + """ + LYD + + """ + Moroccan Dirham. + """ + MAD + + """ + Moldovan Leu (MDL). + """ + MDL + + """ + Malagasy Ariary (MGA). + """ + MGA + + """ + Macedonia Denar (MKD). + """ + MKD + + """ + Burmese Kyat (MMK). + """ + MMK + + """ + Mongolian Tugrik. + """ + MNT + + """ + Macanese Pataca (MOP). + """ + MOP + + """ + Mauritanian Ouguiya (MRU). + """ + MRU + + """ + Mauritian Rupee (MUR). + """ + MUR + + """ + Maldivian Rufiyaa (MVR). + """ + MVR + + """ + Malawian Kwacha (MWK). + """ + MWK + + """ + Mexican Pesos (MXN). + """ + MXN + + """ + Malaysian Ringgits (MYR). + """ + MYR + + """ + Mozambican Metical. + """ + MZN + + """ + Namibian Dollar. + """ + NAD + + """ + Nigerian Naira (NGN). + """ + NGN + + """ + Nicaraguan Córdoba (NIO). + """ + NIO + + """ + Norwegian Kroner (NOK). + """ + NOK + + """ + Nepalese Rupee (NPR). + """ + NPR + + """ + New Zealand Dollars (NZD). + """ + NZD + + """ + Omani Rial (OMR). + """ + OMR + + """ + Panamian Balboa (PAB). + """ + PAB + + """ + Peruvian Nuevo Sol (PEN). + """ + PEN + + """ + Papua New Guinean Kina (PGK). + """ + PGK + + """ + Philippine Peso (PHP). + """ + PHP + + """ + Pakistani Rupee (PKR). + """ + PKR + + """ + Polish Zlotych (PLN). + """ + PLN + + """ + Paraguayan Guarani (PYG). + """ + PYG + + """ + Qatari Rial (QAR). + """ + QAR + + """ + Romanian Lei (RON). + """ + RON + + """ + Serbian dinar (RSD). + """ + RSD + + """ + Russian Rubles (RUB). + """ + RUB + + """ + Rwandan Franc (RWF). + """ + RWF + + """ + Saudi Riyal (SAR). + """ + SAR + + """ + Solomon Islands Dollar (SBD). + """ + SBD + + """ + Seychellois Rupee (SCR). + """ + SCR + + """ + Sudanese Pound (SDG). + """ + SDG + + """ + Swedish Kronor (SEK). + """ + SEK + + """ + Singapore Dollars (SGD). + """ + SGD + + """ + Saint Helena Pounds (SHP). + """ + SHP + + """ + Sierra Leonean Leone (SLL). + """ + SLL + + """ + Somali Shilling (SOS). + """ + SOS + + """ + Surinamese Dollar (SRD). + """ + SRD + + """ + South Sudanese Pound (SSP). + """ + SSP + + """ + Sao Tome And Principe Dobra (STD). + """ + STD @deprecated(reason: "Use `STN` instead.") + + """ + Sao Tome And Principe Dobra (STN). + """ + STN + + """ + Syrian Pound (SYP). + """ + SYP + + """ + Swazi Lilangeni (SZL). + """ + SZL + + """ + Thai baht (THB). + """ + THB + + """ + Tajikistani Somoni (TJS). + """ + TJS + + """ + Turkmenistani Manat (TMT). + """ + TMT + + """ + Tunisian Dinar (TND). + """ + TND + + """ + Tongan Pa'anga (TOP). + """ + TOP + + """ + Turkish Lira (TRY). + """ + TRY + + """ + Trinidad and Tobago Dollars (TTD). + """ + TTD + + """ + Taiwan Dollars (TWD). + """ + TWD + + """ + Tanzanian Shilling (TZS). + """ + TZS + + """ + Ukrainian Hryvnia (UAH). + """ + UAH + + """ + Ugandan Shilling (UGX). + """ + UGX + + """ + United States Dollars (USD). + """ + USD + + """ + United States Dollars Coin (USDC). + """ + USDC + + """ + Uruguayan Pesos (UYU). + """ + UYU + + """ + Uzbekistan som (UZS). + """ + UZS + + """ + Venezuelan Bolivares (VED). + """ + VED + + """ + Venezuelan Bolivares (VEF). + """ + VEF @deprecated(reason: "Use `VES` instead.") + + """ + Venezuelan Bolivares Soberanos (VES). + """ + VES + + """ + Vietnamese đồng (VND). + """ + VND + + """ + Vanuatu Vatu (VUV). + """ + VUV + + """ + Samoan Tala (WST). + """ + WST + + """ + Central African CFA Franc (XAF). + """ + XAF + + """ + East Caribbean Dollar (XCD). + """ + XCD + + """ + Caribbean Guilder (XCG). + """ + XCG + + """ + West African CFA franc (XOF). + """ + XOF + + """ + CFP Franc (XPF). + """ + XPF + + """ + Unrecognized currency. + """ + XXX + + """ + Yemeni Rial (YER). + """ + YER + + """ + South African Rand (ZAR). + """ + ZAR + + """ + Zambian Kwacha (ZMW). + """ + ZMW +} + +""" +A custom product represents a product that doesn't map to Shopify's +[standard product categories](https://help.shopify.com/manual/products/details/product-type). +For example, you can use a custom product to manage gift cards, shipping requirements, localized product +information, or weight measurements and conversions. +""" +type CustomProduct { + """ + Whether the merchandise is a gift card. + """ + isGiftCard: Boolean! + + """ + Whether the item needs to be shipped to the customer. For example, a + digital gift card doesn't need to be shipped, but a t-shirt does + need to be shipped. + """ + requiresShipping: Boolean! + + """ + The localized name for the product that displays to customers. The title is used to construct the product's + handle, which is a unique, human-readable string of the product's title. For example, if a product is titled + "Black Sunglasses", then the handle is `black-sunglasses`. + """ + title: String! + + """ + The product variant's weight, in the system of measurement set in the `weightUnit` field. + """ + weight: Float + + """ + The unit of measurement for weight. + """ + weightUnit: WeightUnit! +} + +""" +Represents a [customer](https://help.shopify.com/manual/customers/manage-customers). +`Customer` returns data including the customer's contact information and order history. +""" +type Customer implements HasMetafields { + """ + The total amount that the customer has spent on orders. + The amount is converted from the shop's currency to the currency of the cart using a market rate. + """ + amountSpent: MoneyV2! + + """ + The full name of the customer, based on the values for `firstName` and `lastName`. + If `firstName` and `lastName` aren't specified, then the value is the customer's email address. + If the email address isn't specified, then the value is the customer's phone number. + """ + displayName: String! + + """ + The customer's email address. + """ + email: String + + """ + The customer's first name. + """ + firstName: String + + """ + Whether the customer is associated with any of the specified tags. The customer must have at least one tag + from the list to return `true`. + """ + hasAnyTag( + """ + A comma-separated list of searchable keywords that are associated with the customer. For example, + `"VIP, Gold"` returns customers with either the `VIP` or `Gold` tag. + """ + tags: [String!]! = [] + ): Boolean! + + """ + Whether the customer is associated with the specified tags. + """ + hasTags( + """ + A comma-separated list of searchable keywords that are associated with the customer. For example, + `"VIP, Gold"` returns customers with both the `VIP` and `Gold` tags. + """ + tags: [String!]! = [] + ): [HasTagResponse!]! + + """ + A [globally-unique ID](https://shopify.dev/docs/api/usage/gids) + for the customer. + """ + id: ID! + + """ + The customer's last name. + """ + lastName: String + + """ + A [custom field](https://shopify.dev/docs/apps/build/custom-data) that stores additional information + about a Shopify resource, such as products, orders, and + [many more](https://shopify.dev/docs/api/admin-graphql/latest/enums/MetafieldOwnerType). + Using [metafields with Shopify Functions](https://shopify.dev/docs/apps/build/functions/input-output/metafields-for-input-queries) + enables you to customize the checkout experience. + """ + metafield( + """ + The unique identifier for the metafield within its namespace. A metafield is composed of a + namespace and a key, in the format `namespace.key`. + """ + key: String! + + """ + A category that organizes a group of metafields. Namespaces are used to prevent naming conflicts + between different apps or different parts of the same app. If omitted, then the + [app-reserved namespace](https://shopify.dev/docs/apps/build/custom-data/ownership) + is used. + """ + namespace: String + ): Metafield + + """ + The total number of orders that the customer has made at the store. + """ + numberOfOrders: Int! +} + +""" +Represents an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601)-encoded date string. +For example, September 7, 2019 is represented as `"2019-07-16"`. +""" +scalar Date + +""" +Represents an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601)-encoded date and time string. +For example, 3:50 pm on September 7, 2019 in the time zone of UTC (Coordinated Universal Time) is +represented as `"2019-09-07T15:50:00Z`". +""" +scalar DateTime + +""" +A subset of the [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) format that +includes the date and time but not the timezone which is determined from context. + +For example, "2018-01-01T00:00:00". +""" +scalar DateTimeWithoutTimezone + +""" +A signed decimal number, which supports arbitrary precision and is serialized as a string. + +Example values: `"29.99"`, `"29.999"`. +""" +scalar Decimal + +""" +Represents information about the merchandise in the cart. +""" +type DeliverableCartLine { + """ + The custom attributes associated with a cart to store additional information. Cart attributes + allow you to collect specific information from customers on the **Cart** page, such as order notes, + gift wrapping requests, or custom product details. Attributes are stored as key-value pairs. + + Cart line attributes are equivalent to the + [`line_item`](https://shopify.dev/docs/api/liquid/objects/line_item) + object in Liquid. + """ + attribute( + """ + The key of the cart attribute to retrieve. For example, `"gift_wrapping"`. + """ + key: String + ): Attribute + + """ + The ID of the cart line. + """ + id: ID! + + """ + The item that the customer intends to purchase. + """ + merchandise: Merchandise! + + """ + The quantity of the item that the customer intends to purchase. + """ + quantity: Int! +} + +""" +List of different delivery method types. +""" +enum DeliveryMethod { + """ + Local Delivery. + """ + LOCAL + + """ + None. + """ + NONE + + """ + Shipping to a Pickup Point. + """ + PICKUP_POINT + + """ + Local Pickup. + """ + PICK_UP + + """ + Retail. + """ + RETAIL + + """ + Shipping. + """ + SHIPPING +} + +""" +A Function error for a path. +""" +input FunctionError { + """ + A description of the validation error. For example, "The product is out of stock" or + "The product isn't available for purchase in your region". The message is localized for the customer. + """ + localizedMessage: String! + + """ + The [identifier](https://shopify.dev/docs/api/functions/reference/cart-checkout-validation/graphql#supported-checkout-field-targets) + in `shopify.extension.toml` that specifies where you're injecting code in the checkout process. + """ + target: String! +} + +""" +The fetch target result. Your Function must return this data structure when generating the request. +""" +input FunctionFetchResult { + """ + The attributes associated with an HTTP request. + """ + request: HttpRequest +} + +""" +The output of the Function run target. The object contains the validation errors +that display to customers and prevent them from proceeding through checkout. In +API versions 2023-10 and beyond, this type is deprecated in favor of +`FunctionRunResult`. +""" +input FunctionResult { + """ + The validation errors that block a customer from proceeding through checkout. + """ + errors: [FunctionError!]! +} + +""" +The output of the Function run target. The object contains the validation errors +that display to customers and prevent them from proceeding through checkout. +""" +input FunctionRunResult { + """ + The validation errors that block a customer from proceeding through checkout. + """ + errors: [FunctionError!]! +} + +""" +A function-scoped handle to a refer a resource. +The Handle type appears in a JSON response as a String, but it is not intended to be human-readable. +Example value: `"10079785100"` +""" +scalar Handle + +""" +Represents information about the metafields associated to the specified resource. +""" +interface HasMetafields { + """ + A [custom field](https://shopify.dev/docs/apps/build/custom-data) that stores additional information + about a Shopify resource, such as products, orders, and + [many more](https://shopify.dev/docs/api/admin-graphql/latest/enums/MetafieldOwnerType). + Using [metafields with Shopify Functions](https://shopify.dev/docs/apps/build/functions/input-output/metafields-for-input-queries) + enables you to customize the checkout experience. + """ + metafield( + """ + The unique identifier for the metafield within its namespace. A metafield is composed of a + namespace and a key, in the format `namespace.key`. + """ + key: String! + + """ + A category that organizes a group of metafields. Namespaces are used to prevent naming conflicts + between different apps or different parts of the same app. If omitted, then the + [app-reserved namespace](https://shopify.dev/docs/apps/build/custom-data/ownership) + is used. + """ + namespace: String + ): Metafield +} + +""" +Whether a Shopify resource, such as a product or customer, has a specified tag. +""" +type HasTagResponse { + """ + Whether the Shopify resource has the tag. + """ + hasTag: Boolean! + + """ + A searchable keyword that's associated with a Shopify resource, such as a product or customer. For example, + a merchant might apply the `sports` and `summer` tags to products that are associated with sportswear for + summer. + """ + tag: String! +} + +""" +The attributes associated with an HTTP request. +""" +input HttpRequest { + """ + The HTTP request body as a plain string. + Use this field when the body isn't in JSON format. + """ + body: String + + """ + The HTTP headers. + """ + headers: [HttpRequestHeader!]! + + """ + The HTTP request body as a JSON object. + Use this field when the body's in JSON format, to reduce function instruction consumption + and to ensure the body's formatted in logs. + Don't use this field together with the `body` field. If both are provided, then the `body` field + will take precedence. + If this field is specified and no `Content-Type` header is included, then the header will + automatically be set to `application/json`. + """ + jsonBody: JSON + + """ + The HTTP method. + """ + method: HttpRequestMethod! + + """ + Policy attached to the HTTP request. + """ + policy: HttpRequestPolicy! + + """ + The HTTP url (eg.: https://example.com). The scheme needs to be HTTPS. + """ + url: URL! +} + +""" +The attributes associated with an HTTP request header. +""" +input HttpRequestHeader { + """ + Header name. + """ + name: String! + + """ + Header value. + """ + value: String! +} + +""" +The HTTP request available methods. +""" +enum HttpRequestMethod { + """ + Http GET. + """ + GET + + """ + Http POST. + """ + POST +} + +""" +The attributes associated with an HTTP request policy. +""" +input HttpRequestPolicy { + """ + Read timeout in milliseconds. + """ + readTimeoutMs: Int! +} + +""" +The attributes associated with an HTTP response. +""" +type HttpResponse { + """ + The HTTP response body as a plain string. + Use this field when the body is not in JSON format. + """ + body: String + + """ + An HTTP header. + """ + header( + """ + A case-insensitive header name. + """ + name: String! + ): HttpResponseHeader + + """ + The HTTP headers. + """ + headers: [HttpResponseHeader!]! @deprecated(reason: "Use `header` instead.") + + """ + The HTTP response body parsed as JSON. + If the body is valid JSON, it will be parsed and returned as a JSON object. + If parsing fails, then raw body is returned as a string. + Use this field when you expect the response to be JSON, or when you're dealing + with mixed response types, meaning both JSON and non-JSON. + Using this field reduces function instruction consumption and ensures that the data is formatted in logs. + To prevent increasing the function target input size unnecessarily, avoid querying + both `body` and `jsonBody` simultaneously. + """ + jsonBody: JSON + + """ + The HTTP status code. + """ + status: Int! +} + +""" +The attributes associated with an HTTP response header. +""" +type HttpResponseHeader { + """ + Header name. + """ + name: String! + + """ + Header value. + """ + value: String! +} + +""" +Represents a unique identifier, often used to refetch an object. +The ID type appears in a JSON response as a String, but it is not intended to be human-readable. + +Example value: `"gid://shopify/Product/10079785100"` +""" +scalar ID + +""" +The `Input` object is the complete GraphQL schema that your Function can receive +as input to validate cart and checkout. Your Function receives only the fields +that you request in the input query. To optimize performance, we highly +recommend that you request only the fields that your Function requires. +""" +type Input { + """ + Information about the current step in the buyer's purchasing process. The + buyer journey helps you determine where the customer is in their shopping + experience (for example, cart interaction, checkout interaction, or completing + a checkout). You can use this information to apply appropriate validation + rules based on the customer's current context and create a more tailored and + performant shopping experience. + """ + buyerJourney: BuyerJourney! + + """ + The cart where the Function is running. A cart contains the merchandise that a customer intends to purchase + and information about the customer, such as the customer's email address and phone number. + """ + cart: Cart! + + """ + The `FunctionFetchResult` object is the result of the fetch target. This is + the response that Shopify returns after executing the HTTP request defined in + your fetch target, and that is passed as input to the run target. For more + information, refer to [network access for Shopify Functions](https://shopify.dev/docs/apps/build/functions/input-output/network-access). + """ + fetchResult: HttpResponse @restrictTarget(only: ["purchase.validation.run", "cart.validations.generate.run"]) + + """ + The regional and language settings that determine how the Function + handles currency, numbers, dates, and other locale-specific values + during discount calculations. These settings are based on the store's configured + [localization practices](https://shopify.dev/docs/apps/build/functions/localization-practices-shopify-functions). + """ + localization: Localization! + + """ + The exchange rate used to convert discounts between the shop's default + currency and the currency that displays to the customer during checkout. + For example, if a store operates in USD but a customer is viewing discounts in EUR, + then the presentment currency rate handles this conversion for accurate pricing. + """ + presentmentCurrencyRate: Decimal! + + """ + Information about the shop where the Function is running, including the shop's timezone + setting and associated [metafields](https://shopify.dev/docs/apps/build/custom-data). + """ + shop: Shop! + + """ + The configuration of the app that owns the Function. This configuration + controls how merchants can define validation rules for carts and checkout, + such as inventory checks, price validations, or custom purchase restrictions. + """ + validation: Validation! +} + +""" +A [JSON](https://www.json.org/json-en.html) object. + +Example value: +`{ + "product": { + "id": "gid://shopify/Product/1346443542550", + "title": "White T-shirt", + "options": [{ + "name": "Size", + "values": ["M", "L"] + }] + } +}` +""" +scalar JSON + +""" +The language for which the store is customized, ensuring content is tailored to local customers. +This includes product descriptions and customer communications that resonate with the target audience. +""" +type Language { + """ + The ISO code. + """ + isoCode: LanguageCode! +} + +""" +Language codes supported by Shopify. +""" +enum LanguageCode { + """ + Afrikaans. + """ + AF + + """ + Akan. + """ + AK + + """ + Amharic. + """ + AM + + """ + Arabic. + """ + AR + + """ + Assamese. + """ + AS + + """ + Azerbaijani. + """ + AZ + + """ + Belarusian. + """ + BE + + """ + Bulgarian. + """ + BG + + """ + Bambara. + """ + BM + + """ + Bangla. + """ + BN + + """ + Tibetan. + """ + BO + + """ + Breton. + """ + BR + + """ + Bosnian. + """ + BS + + """ + Catalan. + """ + CA + + """ + Chechen. + """ + CE + + """ + Central Kurdish. + """ + CKB + + """ + Czech. + """ + CS + + """ + Church Slavic. + """ + CU + + """ + Welsh. + """ + CY + + """ + Danish. + """ + DA + + """ + German. + """ + DE + + """ + Dzongkha. + """ + DZ + + """ + Ewe. + """ + EE + + """ + Greek. + """ + EL + + """ + English. + """ + EN + + """ + Esperanto. + """ + EO + + """ + Spanish. + """ + ES + + """ + Estonian. + """ + ET + + """ + Basque. + """ + EU + + """ + Persian. + """ + FA + + """ + Fulah. + """ + FF + + """ + Finnish. + """ + FI + + """ + Filipino. + """ + FIL + + """ + Faroese. + """ + FO + + """ + French. + """ + FR + + """ + Western Frisian. + """ + FY + + """ + Irish. + """ + GA + + """ + Scottish Gaelic. + """ + GD + + """ + Galician. + """ + GL + + """ + Gujarati. + """ + GU + + """ + Manx. + """ + GV + + """ + Hausa. + """ + HA + + """ + Hebrew. + """ + HE + + """ + Hindi. + """ + HI + + """ + Croatian. + """ + HR + + """ + Hungarian. + """ + HU + + """ + Armenian. + """ + HY + + """ + Interlingua. + """ + IA + + """ + Indonesian. + """ + ID + + """ + Igbo. + """ + IG + + """ + Sichuan Yi. + """ + II + + """ + Icelandic. + """ + IS + + """ + Italian. + """ + IT + + """ + Japanese. + """ + JA + + """ + Javanese. + """ + JV + + """ + Georgian. + """ + KA + + """ + Kikuyu. + """ + KI + + """ + Kazakh. + """ + KK + + """ + Kalaallisut. + """ + KL + + """ + Khmer. + """ + KM + + """ + Kannada. + """ + KN + + """ + Korean. + """ + KO + + """ + Kashmiri. + """ + KS + + """ + Kurdish. + """ + KU + + """ + Cornish. + """ + KW + + """ + Kyrgyz. + """ + KY + + """ + Luxembourgish. + """ + LB + + """ + Ganda. + """ + LG + + """ + Lingala. + """ + LN + + """ + Lao. + """ + LO + + """ + Lithuanian. + """ + LT + + """ + Luba-Katanga. + """ + LU + + """ + Latvian. + """ + LV + + """ + Malagasy. + """ + MG + + """ + Māori. + """ + MI + + """ + Macedonian. + """ + MK + + """ + Malayalam. + """ + ML + + """ + Mongolian. + """ + MN + + """ + Marathi. + """ + MR + + """ + Malay. + """ + MS + + """ + Maltese. + """ + MT + + """ + Burmese. + """ + MY + + """ + Norwegian (Bokmål). + """ + NB + + """ + North Ndebele. + """ + ND + + """ + Nepali. + """ + NE + + """ + Dutch. + """ + NL + + """ + Norwegian Nynorsk. + """ + NN + + """ + Norwegian. + """ + NO + + """ + Oromo. + """ + OM + + """ + Odia. + """ + OR + + """ + Ossetic. + """ + OS + + """ + Punjabi. + """ + PA + + """ + Polish. + """ + PL + + """ + Pashto. + """ + PS + + """ + Portuguese. + """ + PT + + """ + Portuguese (Brazil). + """ + PT_BR + + """ + Portuguese (Portugal). + """ + PT_PT + + """ + Quechua. + """ + QU + + """ + Romansh. + """ + RM + + """ + Rundi. + """ + RN + + """ + Romanian. + """ + RO + + """ + Russian. + """ + RU + + """ + Kinyarwanda. + """ + RW + + """ + Sanskrit. + """ + SA + + """ + Sardinian. + """ + SC + + """ + Sindhi. + """ + SD + + """ + Northern Sami. + """ + SE + + """ + Sango. + """ + SG + + """ + Sinhala. + """ + SI + + """ + Slovak. + """ + SK + + """ + Slovenian. + """ + SL + + """ + Shona. + """ + SN + + """ + Somali. + """ + SO + + """ + Albanian. + """ + SQ + + """ + Serbian. + """ + SR + + """ + Sundanese. + """ + SU + + """ + Swedish. + """ + SV + + """ + Swahili. + """ + SW + + """ + Tamil. + """ + TA + + """ + Telugu. + """ + TE + + """ + Tajik. + """ + TG + + """ + Thai. + """ + TH + + """ + Tigrinya. + """ + TI + + """ + Turkmen. + """ + TK + + """ + Tongan. + """ + TO + + """ + Turkish. + """ + TR + + """ + Tatar. + """ + TT + + """ + Uyghur. + """ + UG + + """ + Ukrainian. + """ + UK + + """ + Urdu. + """ + UR + + """ + Uzbek. + """ + UZ + + """ + Vietnamese. + """ + VI + + """ + Volapük. + """ + VO + + """ + Wolof. + """ + WO + + """ + Xhosa. + """ + XH + + """ + Yiddish. + """ + YI + + """ + Yoruba. + """ + YO + + """ + Chinese. + """ + ZH + + """ + Chinese (Simplified). + """ + ZH_CN + + """ + Chinese (Traditional). + """ + ZH_TW + + """ + Zulu. + """ + ZU +} + +""" +The current time based on the +[store's timezone setting](https://help.shopify.com/manual/intro-to-shopify/initial-setup/setup-business-settings). +""" +type LocalTime { + """ + The current date relative to the parent object. + """ + date: Date! + + """ + Returns true if the current date and time is at or past the given date and time, and false otherwise. + """ + dateTimeAfter( + """ + The date and time to compare against, assumed to be in the timezone of the parent object. + """ + dateTime: DateTimeWithoutTimezone! + ): Boolean! + + """ + Returns true if the current date and time is before the given date and time, and false otherwise. + """ + dateTimeBefore( + """ + The date and time to compare against, assumed to be in the timezone of the parent timezone. + """ + dateTime: DateTimeWithoutTimezone! + ): Boolean! + + """ + Returns true if the current date and time is between the two given date and times, and false otherwise. + """ + dateTimeBetween( + """ + The upper bound time to compare against, assumed to be in the timezone of the parent timezone. + """ + endDateTime: DateTimeWithoutTimezone! + + """ + The lower bound time to compare against, assumed to be in the timezone of the parent timezone. + """ + startDateTime: DateTimeWithoutTimezone! + ): Boolean! + + """ + Returns true if the current time is at or past the given time, and false otherwise. + """ + timeAfter( + """ + The time to compare against, assumed to be in the timezone of the parent timezone. + """ + time: TimeWithoutTimezone! + ): Boolean! + + """ + Returns true if the current time is at or past the given time, and false otherwise. + """ + timeBefore( + """ + The time to compare against, assumed to be in the timezone of the parent timezone. + """ + time: TimeWithoutTimezone! + ): Boolean! + + """ + Returns true if the current time is between the two given times, and false otherwise. + """ + timeBetween( + """ + The upper bound time to compare against, assumed to be in the timezone of the parent timezone. + """ + endTime: TimeWithoutTimezone! + + """ + The lower bound time to compare against, assumed to be in the timezone of the parent timezone. + """ + startTime: TimeWithoutTimezone! + ): Boolean! +} + +""" +Details about the localized experience for the store in a specific region, including country and language +settings. The localized experience is determined by the store's settings and the customer's location. +Localization ensures that customers can access relevant content and options while browsing or purchasing +products in a store. +""" +type Localization { + """ + The country for which the store is customized, reflecting local preferences and regulations. + Localization might influence the language, currency, and product offerings available in a store to enhance + the shopping experience for customers in that region. + """ + country: Country! + + """ + The language for which the store is customized, ensuring content is tailored to local customers. + This includes product descriptions and customer communications that resonate with the target audience. + """ + language: Language! + + """ + The market that applies to the buyer's country. In cases where multiple + markets match, this returns the most-specific country region market. + """ + market: Market! @deprecated(reason: "This `market` field will be removed in a future version of the API.") +} + +""" +Represents the value captured by a localized field. Localized fields are +additional fields required by certain countries on international orders. For +example, some countries require additional fields for customs information or tax +identification numbers. +""" +type LocalizedField { + """ + The key of the localized field. + """ + key: LocalizedFieldKey! + + """ + The title of the localized field. + """ + title: String! + + """ + The value of the localized field. + """ + value: String +} + +""" +Unique key identifying localized fields. +""" +enum LocalizedFieldKey { + """ + Localized field key 'shipping_credential_br' for country Brazil. + """ + SHIPPING_CREDENTIAL_BR + + """ + Localized field key 'shipping_credential_cl' for country Chile. + """ + SHIPPING_CREDENTIAL_CL + + """ + Localized field key 'shipping_credential_cn' for country China. + """ + SHIPPING_CREDENTIAL_CN + + """ + Localized field key 'shipping_credential_co' for country Colombia. + """ + SHIPPING_CREDENTIAL_CO + + """ + Localized field key 'shipping_credential_cr' for country Costa Rica. + """ + SHIPPING_CREDENTIAL_CR + + """ + Localized field key 'shipping_credential_ec' for country Ecuador. + """ + SHIPPING_CREDENTIAL_EC + + """ + Localized field key 'shipping_credential_es' for country Spain. + """ + SHIPPING_CREDENTIAL_ES + + """ + Localized field key 'shipping_credential_gt' for country Guatemala. + """ + SHIPPING_CREDENTIAL_GT + + """ + Localized field key 'shipping_credential_id' for country Indonesia. + """ + SHIPPING_CREDENTIAL_ID + + """ + Localized field key 'shipping_credential_kr' for country South Korea. + """ + SHIPPING_CREDENTIAL_KR + + """ + Localized field key 'shipping_credential_mx' for country Mexico. + """ + SHIPPING_CREDENTIAL_MX + + """ + Localized field key 'shipping_credential_my' for country Malaysia. + """ + SHIPPING_CREDENTIAL_MY + + """ + Localized field key 'shipping_credential_pe' for country Peru. + """ + SHIPPING_CREDENTIAL_PE + + """ + Localized field key 'shipping_credential_pt' for country Portugal. + """ + SHIPPING_CREDENTIAL_PT + + """ + Localized field key 'shipping_credential_py' for country Paraguay. + """ + SHIPPING_CREDENTIAL_PY + + """ + Localized field key 'shipping_credential_tr' for country Turkey. + """ + SHIPPING_CREDENTIAL_TR + + """ + Localized field key 'shipping_credential_tw' for country Taiwan. + """ + SHIPPING_CREDENTIAL_TW + + """ + Localized field key 'shipping_credential_type_co' for country Colombia. + """ + SHIPPING_CREDENTIAL_TYPE_CO + + """ + Localized field key 'tax_credential_br' for country Brazil. + """ + TAX_CREDENTIAL_BR + + """ + Localized field key 'tax_credential_cl' for country Chile. + """ + TAX_CREDENTIAL_CL + + """ + Localized field key 'tax_credential_co' for country Colombia. + """ + TAX_CREDENTIAL_CO + + """ + Localized field key 'tax_credential_cr' for country Costa Rica. + """ + TAX_CREDENTIAL_CR + + """ + Localized field key 'tax_credential_ec' for country Ecuador. + """ + TAX_CREDENTIAL_EC + + """ + Localized field key 'tax_credential_es' for country Spain. + """ + TAX_CREDENTIAL_ES + + """ + Localized field key 'tax_credential_gt' for country Guatemala. + """ + TAX_CREDENTIAL_GT + + """ + Localized field key 'tax_credential_id' for country Indonesia. + """ + TAX_CREDENTIAL_ID + + """ + Localized field key 'tax_credential_it' for country Italy. + """ + TAX_CREDENTIAL_IT + + """ + Localized field key 'tax_credential_mx' for country Mexico. + """ + TAX_CREDENTIAL_MX + + """ + Localized field key 'tax_credential_my' for country Malaysia. + """ + TAX_CREDENTIAL_MY + + """ + Localized field key 'tax_credential_pe' for country Peru. + """ + TAX_CREDENTIAL_PE + + """ + Localized field key 'tax_credential_pt' for country Portugal. + """ + TAX_CREDENTIAL_PT + + """ + Localized field key 'tax_credential_py' for country Paraguay. + """ + TAX_CREDENTIAL_PY + + """ + Localized field key 'tax_credential_tr' for country Turkey. + """ + TAX_CREDENTIAL_TR + + """ + Localized field key 'tax_credential_type_co' for country Colombia. + """ + TAX_CREDENTIAL_TYPE_CO + + """ + Localized field key 'tax_credential_type_mx' for country Mexico. + """ + TAX_CREDENTIAL_TYPE_MX + + """ + Localized field key 'tax_credential_use_mx' for country Mexico. + """ + TAX_CREDENTIAL_USE_MX + + """ + Localized field key 'tax_email_it' for country Italy. + """ + TAX_EMAIL_IT +} + +""" +Represents the location where the inventory resides. +""" +type Location implements HasMetafields { + """ + The address of this location. + """ + address: LocationAddress! + + """ + The location handle. + """ + handle: Handle! + + """ + The location id. + """ + id: ID! + + """ + A [custom field](https://shopify.dev/docs/apps/build/custom-data) that stores additional information + about a Shopify resource, such as products, orders, and + [many more](https://shopify.dev/docs/api/admin-graphql/latest/enums/MetafieldOwnerType). + Using [metafields with Shopify Functions](https://shopify.dev/docs/apps/build/functions/input-output/metafields-for-input-queries) + enables you to customize the checkout experience. + """ + metafield( + """ + The unique identifier for the metafield within its namespace. A metafield is composed of a + namespace and a key, in the format `namespace.key`. + """ + key: String! + + """ + A category that organizes a group of metafields. Namespaces are used to prevent naming conflicts + between different apps or different parts of the same app. If omitted, then the + [app-reserved namespace](https://shopify.dev/docs/apps/build/custom-data/ownership) + is used. + """ + namespace: String + ): Metafield + + """ + The name of the location. + """ + name: String! +} + +""" +Represents the address of a location. +""" +type LocationAddress { + """ + The first line of the address for the location. + """ + address1: String + + """ + The second line of the address for the location. + """ + address2: String + + """ + The city of the location. + """ + city: String + + """ + The country of the location. + """ + country: String + + """ + The country code of the location. + """ + countryCode: String + + """ + A formatted version of the address for the location. + """ + formatted: [String!]! + + """ + The approximate latitude coordinates of the location. + """ + latitude: Float + + """ + The approximate longitude coordinates of the location. + """ + longitude: Float + + """ + The phone number of the location. + """ + phone: String + + """ + The province of the location. + """ + province: String + + """ + The code for the province, state, or district of the address of the location. + """ + provinceCode: String + + """ + The ZIP code of the location. + """ + zip: String +} + +""" +Represents a mailing address. +""" +type MailingAddress { + """ + The first line of the address. Typically the street address or PO Box number. + """ + address1: String + + """ + The second line of the address. Typically the number of the apartment, suite, or unit. + """ + address2: String + + """ + The name of the city, district, village, or town. + """ + city: String + + """ + The name of the customer's company or organization. + """ + company: String + + """ + The two-letter code for the country of the address. For example, US. + """ + countryCode: CountryCode + + """ + The first name of the customer. + """ + firstName: String + + """ + The last name of the customer. + """ + lastName: String + + """ + The approximate latitude of the address. + """ + latitude: Float + + """ + The approximate longitude of the address. + """ + longitude: Float + + """ + The market that applies to the address's country. In cases where multiple + markets match, this returns the most-specific country region market. + """ + market: Market @deprecated(reason: "This `market` field will be removed in a future version of the API.") + + """ + The full name of the customer, based on firstName and lastName. + """ + name: String + + """ + A unique phone number for the customer. Formatted using E.164 standard. For example, +16135551111. + """ + phone: String + + """ + The alphanumeric code for the region. For example, ON. + """ + provinceCode: String + + """ + The zip or postal code of the address. + """ + zip: String +} + +""" +A market is a group of one or more regions that you want to target for international sales. +By creating a market, you can configure a distinct, localized shopping experience for +customers from a specific area of the world. For example, you can +[change currency](https://shopify.dev/api/admin-graphql/current/mutations/marketCurrencySettingsUpdate), +[configure international pricing](https://shopify.dev/api/examples/product-price-lists), +or [add market-specific domains or subfolders](https://shopify.dev/api/admin-graphql/current/objects/MarketWebPresence). +""" +type Market implements HasMetafields { + """ + A human-readable unique string for the market automatically generated from its title. + """ + handle: Handle! + + """ + A globally-unique identifier. + """ + id: ID! + + """ + A [custom field](https://shopify.dev/docs/apps/build/custom-data) that stores additional information + about a Shopify resource, such as products, orders, and + [many more](https://shopify.dev/docs/api/admin-graphql/latest/enums/MetafieldOwnerType). + Using [metafields with Shopify Functions](https://shopify.dev/docs/apps/build/functions/input-output/metafields-for-input-queries) + enables you to customize the checkout experience. + """ + metafield( + """ + The unique identifier for the metafield within its namespace. A metafield is composed of a + namespace and a key, in the format `namespace.key`. + """ + key: String! + + """ + A category that organizes a group of metafields. Namespaces are used to prevent naming conflicts + between different apps or different parts of the same app. If omitted, then the + [app-reserved namespace](https://shopify.dev/docs/apps/build/custom-data/ownership) + is used. + """ + namespace: String + ): Metafield + + """ + A geographic region which comprises a market. + """ + regions: [MarketRegion!]! +} + +""" +Represents a region. +""" +interface MarketRegion { + """ + The name of the region in the language of the current localization. + """ + name: String +} + +""" +A country which comprises a market. +""" +type MarketRegionCountry implements MarketRegion { + """ + The two-letter code for the country. + """ + code: CountryCode! + + """ + The country name in the language of the current localization. + """ + name: String! +} + +""" +The item that a customer intends to purchase. Merchandise can be a product variant or a custom +product. + +A product variant is a specific version of a product that comes in more than one option, such as size or color. +For example, if a merchant sells t-shirts with options for size and color, then a small, blue t-shirt would be +one product variant and a large, blue t-shirt would be another. + +A custom product represents a product that doesn't map to Shopify's +[standard product categories](https://help.shopify.com/manual/products/details/product-type). +For example, you can use a custom product to manage gift cards, shipping requirements, localized product +information, or weight measurements and conversions. +""" +union Merchandise = CustomProduct | ProductVariant + +""" +[Custom fields](https://shopify.dev/docs/apps/build/custom-data) that store additional information +about a Shopify resource, such as products, orders, and +[many more](https://shopify.dev/docs/api/admin-graphql/latest/enums/MetafieldOwnerType). +Using [metafields with Shopify Functions](https://shopify.dev/docs/apps/build/functions/input-output/metafields-for-input-queries) +enables you to customize the checkout experience. +""" +type Metafield { + """ + The data that's stored in the metafield, using JSON format. + """ + jsonValue: JSON! + + """ + The [type of data](https://shopify.dev/apps/metafields/types) that the metafield stores in + the `value` field. + """ + type: String! + + """ + The data that's stored in the metafield. The data is always stored as a string, + regardless of the [metafield's type](https://shopify.dev/apps/metafields/types). + """ + value: String! +} + +""" +A precise monetary value and its associated currency. Combines a decimal amount +with a three-letter currency code to express prices, costs, and other financial +values throughout the API. For example, 12.99 USD. +""" +type MoneyV2 { + """ + A monetary value in decimal format, allowing for precise representation of cents or fractional + currency. For example, 12.99. + """ + amount: Decimal! + + """ + The three-letter currency code that represents a world currency used in a store. Currency codes + include standard [standard ISO 4217 codes](https://en.wikipedia.org/wiki/ISO_4217), legacy codes, + and non-standard codes. For example, USD. + """ + currencyCode: CurrencyCode! +} + +""" +The root mutation for the API. +""" +type MutationRoot { + """ + Handles the Function result for the cart.validations.generate.fetch target. + """ + cartValidationsGenerateFetch( + """ + The result of the Function. + """ + result: CartValidationsGenerateFetchResult! + ): Void! + + """ + Handles the Function result for the cart.validations.generate.run target. + """ + cartValidationsGenerateRun( + """ + The result of the Function. + """ + result: CartValidationsGenerateRunResult! + ): Void! + + """ + Handles the Function result for the purchase.validation.fetch target. + """ + fetch( + """ + The result of the Function. + """ + result: FunctionFetchResult! + ): Void! + + """ + Handles the Function result. + """ + handleResult( + """ + The result of the Function. + """ + result: FunctionResult! + ): Void! @deprecated(reason: "Use the target-specific field instead.") + + """ + Handles the Function result for the purchase.validation.run target. + """ + run( + """ + The result of the Function. + """ + result: FunctionRunResult! + ): Void! +} + +""" +An operation to apply. +""" +input Operation @oneOf { + """ + An operation that adds validations to the cart and checkout. For example, you might add a validation + that, at checkout, confirms a customer's age meets the legal requirement to purchase a product in their cart. + """ + validationAdd: ValidationAddOperation +} + +""" +The goods and services that merchants offer to customers. Products can include details such as +title, vendor, and custom data stored in [metafields](https://shopify.dev/docs/apps/build/custom-data). +Products can be organized by grouping them into a collection. + +Learn more about [managing products in a merchant's store](https://help.shopify.com/manual/products). +""" +type Product implements HasMetafields { + """ + A unique, human-readable string of the product's title. A handle can contain letters, hyphens (`-`), and + numbers, but not spaces. The handle is used in the online store URL for the product. For example, if a product + is titled "Black Sunglasses", then the handle is `black-sunglasses`. + """ + handle: Handle! + + """ + Whether the product is associated with any of the specified tags. The product must have at least one tag + from the list to return `true`. + """ + hasAnyTag( + """ + A comma-separated list of searchable keywords that are associated with the product. For example, + `"sports, summer"` returns products with either the `sports` or `summer` tag. + """ + tags: [String!]! = [] + ): Boolean! + + """ + Whether the product is associated with the specified tags. + """ + hasTags( + """ + A comma-separated list of searchable keywords that are associated with the product. For example, + `"sports, summer"` returns products with both the `sports` and `summer` tags. + """ + tags: [String!]! = [] + ): [HasTagResponse!]! + + """ + A [globally-unique ID](https://shopify.dev/docs/api/usage/gids) + for the product. + """ + id: ID! + + """ + Whether the product is in any of the specified collections. The product must be in at least one collection + from the list to return `true`. + + A collection is a group of products that can be displayed in online stores and other sales channels in + categories, which makes it easy for customers to find them. For example, an athletics store might create + different collections for running attire and accessories. + """ + inAnyCollection( + """ + A comma-separated list of [globally-unique collection IDs](https://shopify.dev/docs/api/usage/gids) + that are associated with the product. For example, `gid://shopify/Collection/123`, `gid://shopify/Collection/456`. + """ + ids: [ID!]! = [] + ): Boolean! + + """ + Whether the product is in the specified collections. The product must be in all of the collections in the + list to return `true`. + + A collection is a group of products that can be displayed in online stores and other sales channels in + categories, which makes it easy for customers to find them. For example, an athletics store might create + different collections for running attire and accessories. + """ + inCollections( + """ + A comma-separated list of [globally-unique collection IDs](https://shopify.dev/docs/api/usage/gids) + that are associated with the product. For example, `gid://shopify/Collection/123`, `gid://shopify/Collection/456`. + """ + ids: [ID!]! = [] + ): [CollectionMembership!]! + + """ + Whether the product is a gift card. + """ + isGiftCard: Boolean! + + """ + A [custom field](https://shopify.dev/docs/apps/build/custom-data) that stores additional information + about a Shopify resource, such as products, orders, and + [many more](https://shopify.dev/docs/api/admin-graphql/latest/enums/MetafieldOwnerType). + Using [metafields with Shopify Functions](https://shopify.dev/docs/apps/build/functions/input-output/metafields-for-input-queries) + enables you to customize the checkout experience. + """ + metafield( + """ + The unique identifier for the metafield within its namespace. A metafield is composed of a + namespace and a key, in the format `namespace.key`. + """ + key: String! + + """ + A category that organizes a group of metafields. Namespaces are used to prevent naming conflicts + between different apps or different parts of the same app. If omitted, then the + [app-reserved namespace](https://shopify.dev/docs/apps/build/custom-data/ownership) + is used. + """ + namespace: String + ): Metafield + + """ + A custom category for a product. Product types allow merchants to define categories other than the + ones available in Shopify's + [standard product categories](https://help.shopify.com/manual/products/details/product-type). + """ + productType: String + + """ + The localized name for the product that displays to customers. The title is used to construct the product's + handle, which is a unique, human-readable string of the product's title. For example, if a product is titled + "Black Sunglasses", then the handle is `black-sunglasses`. + """ + title: String! + + """ + The name of the product's vendor. + """ + vendor: String +} + +""" +A specific version of a product that comes in more than one option, such as size or color. For example, +if a merchant sells t-shirts with options for size and color, then a small, blue t-shirt would be one +product variant and a large, blue t-shirt would be another. +""" +type ProductVariant implements HasMetafields { + """ + A [globally-unique ID](https://shopify.dev/docs/api/usage/gids) + for the product variant. + """ + id: ID! + + """ + A [custom field](https://shopify.dev/docs/apps/build/custom-data) that stores additional information + about a Shopify resource, such as products, orders, and + [many more](https://shopify.dev/docs/api/admin-graphql/latest/enums/MetafieldOwnerType). + Using [metafields with Shopify Functions](https://shopify.dev/docs/apps/build/functions/input-output/metafields-for-input-queries) + enables you to customize the checkout experience. + """ + metafield( + """ + The unique identifier for the metafield within its namespace. A metafield is composed of a + namespace and a key, in the format `namespace.key`. + """ + key: String! + + """ + A category that organizes a group of metafields. Namespaces are used to prevent naming conflicts + between different apps or different parts of the same app. If omitted, then the + [app-reserved namespace](https://shopify.dev/docs/apps/build/custom-data/ownership) + is used. + """ + namespace: String + ): Metafield + + """ + The product associated with the product variant. For example, if a + merchant sells t-shirts with options for size and color, then a small, + blue t-shirt would be one product variant and a large, blue t-shirt would be another. + The product associated with the product variant would be the t-shirt itself. + """ + product: Product! + + """ + Whether the item needs to be shipped to the customer. For example, a + digital gift card doesn't need to be shipped, but a t-shirt does + need to be shipped. + """ + requiresShipping: Boolean! + + """ + A case-sensitive identifier for the product variant in the merchant's store. For example, `"BBC-1"`. + A product variant must have a SKU to be connected to a + [fulfillment service](https://shopify.dev/docs/apps/build/orders-fulfillment/fulfillment-service-apps/build-for-fulfillment-services). + """ + sku: String + + """ + The localized name for the product variant that displays to customers. + """ + title: String + + """ + The product variant's weight, in the system of measurement set in the `weightUnit` field. + """ + weight: Float + + """ + The unit of measurement for weight. + """ + weightUnit: WeightUnit! +} + +""" +The company of a B2B customer that's interacting with the cart. +Used to manage and track purchases made by businesses rather than individual customers. +""" +type PurchasingCompany { + """ + The company associated to the order or draft order. + """ + company: Company! + + """ + The company contact associated to the order or draft order. + """ + contact: CompanyContact + + """ + The company location associated to the order or draft order. + """ + location: CompanyLocation! +} + +""" +Represents how products and variants can be sold and purchased. +""" +type SellingPlan implements HasMetafields { + """ + The description of the selling plan. + """ + description: String + + """ + A globally-unique identifier. + """ + id: ID! + + """ + A [custom field](https://shopify.dev/docs/apps/build/custom-data) that stores additional information + about a Shopify resource, such as products, orders, and + [many more](https://shopify.dev/docs/api/admin-graphql/latest/enums/MetafieldOwnerType). + Using [metafields with Shopify Functions](https://shopify.dev/docs/apps/build/functions/input-output/metafields-for-input-queries) + enables you to customize the checkout experience. + """ + metafield( + """ + The unique identifier for the metafield within its namespace. A metafield is composed of a + namespace and a key, in the format `namespace.key`. + """ + key: String! + + """ + A category that organizes a group of metafields. Namespaces are used to prevent naming conflicts + between different apps or different parts of the same app. If omitted, then the + [app-reserved namespace](https://shopify.dev/docs/apps/build/custom-data/ownership) + is used. + """ + namespace: String + ): Metafield + + """ + The name of the selling plan. For example, '6 weeks of prepaid granola, delivered weekly'. + """ + name: String! + + """ + Whether purchasing the selling plan will result in multiple deliveries. + """ + recurringDeliveries: Boolean! +} + +""" +Represents an association between a variant and a selling plan. Selling plan +allocations describe the options offered for each variant, and the price of the +variant when purchased with a selling plan. +""" +type SellingPlanAllocation { + """ + A list of price adjustments, with a maximum of two. When there are two, the + first price adjustment goes into effect at the time of purchase, while the + second one starts after a certain number of orders. A price adjustment + represents how a selling plan affects pricing when a variant is purchased with + a selling plan. Prices display in the customer's currency if the shop is + configured for it. + """ + priceAdjustments: [SellingPlanAllocationPriceAdjustment!]! + + """ + A representation of how products and variants can be sold and purchased. For + example, an individual selling plan could be '6 weeks of prepaid granola, + delivered weekly'. + """ + sellingPlan: SellingPlan! +} + +""" +The resulting prices for variants when they're purchased with a specific selling plan. +""" +type SellingPlanAllocationPriceAdjustment { + """ + The effective price for a single delivery. For example, for a prepaid + subscription plan that includes 6 deliveries at the price of $48.00, the per + delivery price is $8.00. + """ + perDeliveryPrice: MoneyV2! + + """ + The price of the variant when it's purchased with a selling plan For example, + for a prepaid subscription plan that includes 6 deliveries of $10.00 granola, + where the customer gets 20% off, the price is 6 x $10.00 x 0.80 = $48.00. + """ + price: MoneyV2! +} + +""" +Information about the store, including the store's timezone setting +and custom data stored in [metafields](https://shopify.dev/docs/apps/build/custom-data). +""" +type Shop implements HasMetafields { + """ + The current time based on the + [store's timezone setting](https://help.shopify.com/manual/intro-to-shopify/initial-setup/setup-business-settings). + """ + localTime: LocalTime! + + """ + A [custom field](https://shopify.dev/docs/apps/build/custom-data) that stores additional information + about a Shopify resource, such as products, orders, and + [many more](https://shopify.dev/docs/api/admin-graphql/latest/enums/MetafieldOwnerType). + Using [metafields with Shopify Functions](https://shopify.dev/docs/apps/build/functions/input-output/metafields-for-input-queries) + enables you to customize the checkout experience. + """ + metafield( + """ + The unique identifier for the metafield within its namespace. A metafield is composed of a + namespace and a key, in the format `namespace.key`. + """ + key: String! + + """ + A category that organizes a group of metafields. Namespaces are used to prevent naming conflicts + between different apps or different parts of the same app. If omitted, then the + [app-reserved namespace](https://shopify.dev/docs/apps/build/custom-data/ownership) + is used. + """ + namespace: String + ): Metafield +} + +""" +A subset of the [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) format that +includes the time but not the date or timezone which is determined from context. +For example, "05:43:21". +""" +scalar TimeWithoutTimezone + +""" +Represents an [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986) and +[RFC 3987](https://datatracker.ietf.org/doc/html/rfc3987)-compliant URI string. + +For example, `"https://example.myshopify.com"` is a valid URL. It includes a scheme (`https`) and a host +(`example.myshopify.com`). +""" +scalar URL + +""" +A customization that validates a cart and/or checkout. +""" +type Validation implements HasMetafields { + """ + A [custom field](https://shopify.dev/docs/apps/build/custom-data) that stores additional information + about a Shopify resource, such as products, orders, and + [many more](https://shopify.dev/docs/api/admin-graphql/latest/enums/MetafieldOwnerType). + Using [metafields with Shopify Functions](https://shopify.dev/docs/apps/build/functions/input-output/metafields-for-input-queries) + enables you to customize the checkout experience. + """ + metafield( + """ + The unique identifier for the metafield within its namespace. A metafield is composed of a + namespace and a key, in the format `namespace.key`. + """ + key: String! + + """ + A category that organizes a group of metafields. Namespaces are used to prevent naming conflicts + between different apps or different parts of the same app. If omitted, then the + [app-reserved namespace](https://shopify.dev/docs/apps/build/custom-data/ownership) + is used. + """ + namespace: String + ): Metafield +} + +""" +An operation that adds validations to the cart and checkout. For example, you might add a validation +that, at checkout, confirms a customer's age meets the legal requirement to purchase a product in their cart. +""" +input ValidationAddOperation { + """ + The validation errors that block a customer from proceeding through checkout. + The errors are grouped by + [target](https://shopify.dev/docs/api/functions/reference/cart-checkout-validation/graphql#supported-checkout-field-targets). + """ + errors: [ValidationError!]! +} + +""" +A Function error for a path. +""" +input ValidationError { + """ + A description of the validation error. For example, "The product is out of stock" or + "The product isn't available for purchase in your region". + """ + message: String! + + """ + The [identifier](https://shopify.dev/docs/api/functions/reference/cart-checkout-validation/graphql#supported-checkout-field-targets) + in `shopify.extension.toml` that specifies where you're injecting code in the checkout process. + """ + target: String! +} + +""" +A void type that can be used to return a null value from a mutation. +""" +scalar Void + +""" +Units of measurement for weight. +""" +enum WeightUnit { + """ + Metric system unit of mass. + """ + GRAMS + + """ + 1 kilogram equals 1000 grams. + """ + KILOGRAMS + + """ + Imperial system unit of mass. + """ + OUNCES + + """ + 1 pound equals 16 ounces. + """ + POUNDS +} diff --git a/extensions/datewise-widget/assets/datewise.js b/extensions/datewise-widget/assets/datewise.js index d21d095..a508558 100644 --- a/extensions/datewise-widget/assets/datewise.js +++ b/extensions/datewise-widget/assets/datewise.js @@ -1,446 +1 @@ -/* Datewise storefront widget. Vanilla JS, no dependencies, safe to load twice. - * Talks to the app through the shop's app proxy (/apps/datewise/*), so it works on any theme. - * - * Lifecycle - * cart change ─▶ refresh(): read /cart.js ─▶ POST availability ─▶ revalidate selection ─▶ render - * slot click ─▶ POST hold (capacity reserved for N minutes) ─▶ write cart attributes + fee line - * checkout ─▶ (optional) block click until a time is chosen; the checkout function enforces it server-side - */ -(function () { - "use strict"; - if (window.__datewiseLoaded) return; - window.__datewiseLoaded = true; - - // ---------- config ---------- - var cfgEl = document.querySelector("[data-datewise-config]"); - var CFG = {}; - try { CFG = cfgEl ? JSON.parse(cfgEl.textContent) : {}; } catch (e) { CFG = {}; } - var T = Object.assign({ - choose: "Pick a highlighted date", needTime: "Please choose a delivery or pickup time before checking out.", - held: "Held for you for", expired: "Your hold expired. Tap the time again to check it's still free.", left: "left", full: "Full", - postal: "Postal / ZIP code", check: "Check", waitlist: "Join the waitlist", joined: "You're on the waitlist. We'll message you if a place opens.", - dispatch: "Ships this day (not an arrival date)", change: "Change", prep: "Earliest times include preparation for", free: "Free", fee: "fee", - nextAvailable: "Next available", offer: "A place opened up and we're holding it for you", error: "Something went wrong. Please try again." - }, CFG.text || {}); - var ROOT = ((window.Shopify && Shopify.routes && Shopify.routes.root) || "/").replace(/\/?$/, "/"); - var API = ROOT + "apps/datewise"; - var LOCALE = CFG.locale || document.documentElement.lang || "en"; - var CURRENCY = CFG.currency || (window.Shopify && Shopify.currency && Shopify.currency.active) || "CAD"; - var ATTR = "_datewise"; - - // ---------- storage (best effort) ---------- - function lsGet(k) { try { return localStorage.getItem("datewise_" + k); } catch (e) { return null; } } - function lsSet(k, v) { try { v == null ? localStorage.removeItem("datewise_" + k) : localStorage.setItem("datewise_" + k, v); } catch (e) {} } - - // ---------- state ---------- - var S = { - data: null, cart: null, lines: [], loading: false, message: null, messageTone: "info", - method: lsGet("method"), locationId: lsGet("location"), postal: lsGet("postal") || "", - date: null, sel: null, token: lsGet("token"), expiresAt: null, heldAt: null, monthOffset: 0, waitlistDone: false, mutating: 0 - }; - - // ---------- helpers ---------- - function esc(s) { return String(s == null ? "" : s).replace(/[&<>"']/g, function (c) { return { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[c]; }); } - function money(c) { try { return new Intl.NumberFormat(LOCALE, { style: "currency", currency: CURRENCY }).format(c / 100); } catch (e) { return "$" + (c / 100).toFixed(2); } } - function dateLabel(d, long) { return new Intl.DateTimeFormat(LOCALE, { weekday: long ? "long" : "short", month: long ? "long" : "short", day: "numeric", timeZone: "UTC" }).format(new Date(d + "T12:00:00Z")); } - function timeLabel(hhmm) { var p = hhmm.split(":"); return new Intl.DateTimeFormat(LOCALE, { hour: "numeric", minute: p[1] === "00" ? undefined : "2-digit", timeZone: "UTC" }).format(new Date(Date.UTC(2000, 0, 1, +p[0], +p[1]))); } - function slotText(s) { return timeLabel(s.start) + " – " + timeLabel(s.end); } - function addMonths(ym, n) { var y = +ym.slice(0, 4), m = +ym.slice(5, 7) - 1 + n; y += Math.floor(m / 12); m = ((m % 12) + 12) % 12; return y + "-" + String(m + 1).padStart(2, "0"); } - function daysIn(ym) { return new Date(Date.UTC(+ym.slice(0, 4), +ym.slice(5, 7), 0)).getUTCDate(); } - var ICON = { - pickup: '', - delivery: '', - shipping: '' - }; - function icon(m) { return '"; } - function weekday(d) { return new Date(d + "T12:00:00Z").getUTCDay(); } - - function api(path, body, method) { - var url = API + path; - var init = { method: method || "POST", headers: { "Content-Type": "application/json", Accept: "application/json" }, credentials: "same-origin" }; - if (body && init.method !== "GET") init.body = JSON.stringify(body); - return realFetch(url, init).then(function (r) { return r.json().catch(function () { return { ok: false, message: T.error }; }); }); - } - function cartReq(path, body) { - S.mutating++; - return realFetch(ROOT + path, { method: body ? "POST" : "GET", headers: { "Content-Type": "application/json", Accept: "application/json" }, body: body ? JSON.stringify(body) : undefined, credentials: "same-origin" }) - .then(function (r) { return r.json(); }) - .finally(function () { setTimeout(function () { S.mutating--; }, 50); }); - } - - // ---------- cart ---------- - function readCart() { - return cartReq("cart.js").then(function (cart) { - S.cart = cart; - S.lines = cart.items.filter(function (i) { return !(i.properties && i.properties._datewise_fee); }) - .map(function (i) { return { variantId: i.variant_id, quantity: i.quantity, price: i.final_price, title: i.product_title }; }); - var raw = cart.attributes && cart.attributes[ATTR]; - if (raw) { - try { - var a = JSON.parse(raw); - S.sel = { method: a.m, locationId: a.l, date: a.d, slot: a.s, fee: a.f }; - S.token = a.t; lsSet("token", a.t); - S.method = S.method || a.m; S.locationId = S.locationId || a.l; S.date = S.date || a.d; - } catch (e) { S.sel = null; } - } else S.sel = null; - return cart; - }); - } - - function feeLines() { return (S.cart ? S.cart.items : []).filter(function (i) { return i.properties && i.properties._datewise_fee; }); } - - function syncFee(variantId) { - var current = feeLines(); - var chain = Promise.resolve(); - var keep = null; - current.forEach(function (line) { - if (!keep && variantId && String(line.variant_id) === String(variantId) && line.quantity === 1) keep = line; - else chain = chain.then(function () { return cartReq("cart/change.js", { id: line.key, quantity: 0 }); }); - }); - if (variantId && !keep) chain = chain.then(function () { return cartReq("cart/add.js", { items: [{ id: Number(variantId), quantity: 1, properties: { _datewise_fee: "1" } }] }); }); - var changed = current.length !== (keep ? 1 : 0) || (variantId && !keep); - return chain.then(function () { return changed; }); - } - - function writeAttributes(attrs) { - var prev = []; - try { prev = JSON.parse(lsGet("keys") || "[]"); } catch (e) {} - var out = {}; - prev.forEach(function (k) { out[k] = ""; }); - Object.keys(attrs).forEach(function (k) { out[k] = attrs[k]; }); - lsSet("keys", JSON.stringify(Object.keys(attrs))); - return cartReq("cart/update.js", { attributes: out }); - } - - function notifyTheme(feeChanged) { - var detail = { source: "datewise" }; - ["cart:refresh", "cart:updated", "cart:change", "theme:cart:change"].forEach(function (n) { document.dispatchEvent(new CustomEvent(n, { detail: detail, bubbles: true })); }); - if (typeof window.publish === "function" && window.PUB_SUB_EVENTS) { - readCart().then(function (cart) { window.publish(window.PUB_SUB_EVENTS.cartUpdate, { source: "datewise", cartData: cart }); }); - } else if (feeChanged && /\/cart\/?$/.test(location.pathname)) { - setTimeout(function () { location.reload(); }, 300); // totals must show the fee line - } - } - - function clearSelection(reason) { - var token = S.token; - S.sel = null; S.expiresAt = null; - if (reason) setMessage(reason, "critical"); - if (token) api("/release", { token: token }).catch(function () {}); - return writeAttributes({ [ATTR]: "" }).then(function () { return syncFee(null); }).then(function (changed) { lsSet("keys", "[]"); if (changed) notifyTheme(true); }); - } - - // ---------- data ---------- - var timer = null; - function refresh(soon) { - clearTimeout(timer); - timer = setTimeout(load, soon ? 0 : 300); - } - function load() { - if (!roots().length && !CFG.checkoutGuard) return Promise.resolve(); - S.loading = true; renderAll(); - return readCart().then(function () { - if (!S.lines.length) { S.data = null; S.loading = false; if (S.sel) clearSelection(null); renderAll(); return; } - return api("/availability", { lines: S.lines, method: S.method || undefined, locationId: S.locationId || undefined, postal: S.postal || undefined, token: S.token || undefined, locale: LOCALE }) - .then(function (data) { - S.loading = false; - if (!data || data.ok === false) { setMessage((data && data.message) || T.error, "critical"); renderAll(); return; } - S.data = data; - S.method = data.method; S.locationId = data.locationId; - revalidate(); - renderAll(); - }); - }).catch(function () { S.loading = false; setMessage(T.error, "critical"); renderAll(); }); - } - - function findSlot(date, slot) { - var d = S.data && S.data.dates.filter(function (x) { return x.date === date; })[0]; - return { d: d, s: d && d.slots.filter(function (x) { return x.id === slot; })[0] }; - } - - /** The cart, method or location changed: drop a selection the rules no longer allow, with a reason. */ - function revalidate() { - if (!S.sel) return; - var d = S.data; - if (!d || d.method !== S.sel.method || d.locationId !== S.sel.locationId) return clearSelection(null); - var f = findSlot(S.sel.date, S.sel.slot); - if (!f.s || !f.s.available) { - var why = (f.s && f.s.reason) || (f.d && f.d.reasons[0]) || ""; - clearSelection(why ? why + ". " + T.choose + "." : T.choose); - } - } - - function hold(date, slot) { - if (!S.data) return; - setMessage(null); - S.loading = true; renderAll(); - return api("/hold", { lines: S.lines, method: S.data.method, locationId: S.data.locationId, date: date, slot: slot, token: S.token || undefined, postal: S.postal || undefined, locale: LOCALE }) - .then(function (res) { - if (!res.ok) { S.loading = false; setMessage(res.message || T.error, "critical"); refresh(true); return; } - S.token = res.token; lsSet("token", res.token); - S.expiresAt = Date.parse(res.expiresAt); - S.heldAt = Date.now(); - S.sel = { method: S.data.method, locationId: S.data.locationId, date: date, slot: slot, fee: res.fee ? res.fee.fee : 0 }; - return writeAttributes(res.attributes) - .then(function () { return syncFee(res.feeVariantId); }) - .then(function (changed) { S.loading = false; renderAll(); notifyTheme(changed); }); - }) - .catch(function () { S.loading = false; setMessage(T.error, "critical"); renderAll(); }); - } - - function setMessage(text, tone) { S.message = text; S.messageTone = tone || "info"; } - - // ---------- rendering ---------- - function roots() { return Array.prototype.slice.call(document.querySelectorAll("[data-datewise-root]")); } - function renderAll() { roots().forEach(render); } - - function render(root) { - if (!root.classList.contains("datewise")) root.classList.add("datewise"); // custom mounts get styles too - var d = S.data; - var heading = root.getAttribute("data-heading") || (d && d.text && d.text.heading) || ""; - if (d && d.text && d.text.accent) root.style.setProperty("--dw-accent", d.text.accent); - var h = ""; - if (heading) h += '

' + esc(heading) + "

"; - h += '
' + (S.message ? '

' + esc(S.message) + "

" : "") + "
"; - if (!d) { root.innerHTML = h + (S.loading ? '' : ""); root.setAttribute("aria-busy", S.loading); return; } - - // methods - h += '
'; - d.methods.forEach(function (m) { - var on = m.method === d.method; - h += '"; - }); - h += "
"; - if (!d.method) { root.innerHTML = h; return; } - - if (d.method === "delivery") { - h += '
"; - } - if (d.split) h += '

' + esc(d.split) + "

"; - - if (d.method !== "shipping" && d.locations.length > 1) { - h += '
'; - d.locations.forEach(function (l) { - var on = l.id === d.locationId; - var right = l.fee ? (l.fee.waived ? T.free : money(l.fee.fee)) : l.distanceKm != null ? l.distanceKm + " km" : ""; - h += '"; - }); - h += "
"; - } else if (d.locationId) { - var only = d.locations.filter(function (l) { return l.id === d.locationId; })[0]; - if (only && d.method !== "shipping") h += '

' + esc(only.name) + (only.fee ? " · " + (only.fee.waived ? T.free : money(only.fee.fee) + " " + T.fee) : "") + "

"; - } - if (!d.locationId) { - if (d.needsAddress) { root.innerHTML = h; return; } - var why = d.locations[0] && d.locations[0].reason; - root.innerHTML = h + (why ? '

' + esc(why) + "

" : ""); - return; - } - if (d.prepNote && d.prepNote.minutes >= 60) h += '

' + esc(T.prep + " " + d.prepNote.item) + " (" + Math.round(d.prepNote.minutes / 6) / 10 + " h)

"; - var peak = d.dates.filter(function (x) { return x.peak && x.peak.message; })[0]; - if (peak) h += '

' + esc(peak.peak.message) + "

"; - - h += calendar(d); - h += slots(d, root); - root.innerHTML = h; - root.setAttribute("aria-busy", S.loading); - tickTimer(); - } - - var ridSeq = 0; - function rid(root) { if (!root.__dwid) root.__dwid = ++ridSeq; return root.__dwid; } - - function calendar(d) { - var map = {}; - d.dates.forEach(function (x) { map[x.date] = x; }); - var firstAvail = (d.dates.filter(function (x) { return x.available; })[0] || d.dates[0] || {}).date; - if (!firstAvail) return ""; - var ym = addMonths(firstAvail.slice(0, 7), S.monthOffset); - var start = d.text.weekStartsOn || 0; - var first = ym + "-01"; - var lead = (weekday(first) - start + 7) % 7; - var h = '
' + - esc(new Intl.DateTimeFormat(LOCALE, { month: "long", year: "numeric", timeZone: "UTC" }).format(new Date(first + "T12:00:00Z"))) + - '
'; - for (var w = 0; w < 7; w++) { - var wd = (start + w) % 7; - h += '"; - } - for (var i = 0; i < lead; i++) h += ""; - for (var day = 1; day <= daysIn(ym); day++) { - var date = ym + "-" + String(day).padStart(2, "0"); - var x = map[date]; - var cls = "dw-day", label = dateLabel(date, true), extra = ""; - if (!x) cls += " dw-out"; - else if (x.available) { cls += " dw-avail"; if (d.text.showRemaining && x.remaining != null && x.remaining <= 5) extra = '' + x.remaining + ""; } - else if (x.waitlist || /full|booked/i.test(x.reasons[0] || "")) { cls += " dw-full"; label += ", " + T.full; } - else { cls += " dw-closed"; label += ", " + (x.reasons[0] || ""); } - if (S.date === date) cls += " dw-sel"; - if (x && x.peak) { cls += " dw-peakday"; label += ", " + x.peak.name; } - h += '"; - } - return h + "
"; - } - - function slots(d, root) { - if (!S.date) return '

' + esc(T.choose) + "

"; - var x = d.dates.filter(function (y) { return y.date === S.date; })[0]; - if (!x) return ""; - var h = '

' + esc(dateLabel(x.date, true)) + (x.peak ? ' ' + esc(x.peak.name) + "" : "") + "

"; - if (d.dateOnly) h += '

' + esc(T.dispatch) + "

"; - if (!x.available) { - h += '

' + esc(x.reasons.join(". ")) + "

"; - if (x.waitlist && !S.waitlistDone) - h += '
"; - if (S.waitlistDone) h += '

' + esc(T.joined) + "

"; - return h + "
"; - } - h += '
'; - x.slots.forEach(function (s) { - var on = S.sel && S.sel.date === x.date && S.sel.slot === s.id; - var sub = s.available ? (d.text.showRemaining && s.remaining != null ? s.remaining + " " + T.left : "") + (s.surcharge ? (s.remaining != null && d.text.showRemaining ? " · " : "") + "+" + money(s.surcharge) : "") : s.reason || ""; - h += '"; - }); - h += "
"; - if (S.sel && S.sel.date === x.date) h += stub(d, x); - return h + ""; - } - - /** The "ticket" confirming what the customer chose, with the hold countdown. */ - function stub(d, x) { - var loc = d.locations.filter(function (l) { return l.id === d.locationId; })[0]; - var s = x.slots.filter(function (y) { return y.id === S.sel.slot; })[0]; - var live = S.expiresAt && S.expiresAt > Date.now(); - var expired = S.expiresAt && !live; - var h = '
' + - '' + icon(d.method) + esc(d.text.labels[d.method]) + (loc && d.method !== "shipping" ? ", " + esc(loc.name) : "") + "" + - '' + esc(dateLabel(x.date, true)) + "" + - (s && !d.dateOnly ? '' + esc(slotText(s)) + "" : "") + - (S.sel.fee ? '+' + esc(money(S.sel.fee)) + " " + esc(T.fee) + "" : "") + - '
'; - if (live) h += '' + esc(T.held) + ' '; - else if (expired) h += '' + esc(T.expired) + ""; - else h += ''; - h += "
"; - if (loc && loc.pickupInstructions && d.method === "pickup") h += '

' + esc(loc.pickupInstructions) + "

"; - return h; - } - - function tickTimer() { - var left = S.expiresAt ? S.expiresAt - Date.now() : 0; - var els = document.querySelectorAll("[data-dw-timer]"); - if (left <= 0 && els.length) return renderAll(); - var s = Math.max(0, Math.round(left / 1000)); - for (var i = 0; i < els.length; i++) els[i].textContent = Math.floor(s / 60) + ":" + String(s % 60).padStart(2, "0"); - var total = S.expiresAt && S.heldAt ? S.expiresAt - S.heldAt : 0; - var rings = document.querySelectorAll("[data-dw-ring]"); - for (var j = 0; j < rings.length; j++) rings[j].style.strokeDashoffset = total > 0 ? String(100 - Math.max(0, Math.min(100, (left / total) * 100))) : "0"; - } - setInterval(tickTimer, 1000); - - // ---------- events ---------- - document.addEventListener("click", function (e) { - var t = e.target.closest && e.target.closest("[data-datewise-root] [data-dw]"); - if (!t || t.tagName === "FORM") return; - if (t.getAttribute("aria-disabled") === "true" && t.getAttribute("data-dw") !== "date") return; - var a = t.getAttribute("data-dw"), v = t.getAttribute("data-v"); - if (a === "method" && v !== S.method) { S.method = v; lsSet("method", v); S.date = null; S.monthOffset = 0; refresh(true); } - else if (a === "loc" && v !== S.locationId) { S.locationId = v; lsSet("location", v); S.date = null; refresh(true); } - else if (a === "month") { S.monthOffset += +v; renderAll(); } - else if (a === "date") { S.date = v; S.waitlistDone = false; setMessage(null); renderAll(); focusFirst(".dw-slot:not([aria-disabled])"); } - else if (a === "slot") hold(S.date, v); - }); - - document.addEventListener("submit", function (e) { - var f = e.target; - if (!f.closest || !f.closest("[data-datewise-root]")) return; - var a = f.getAttribute("data-dw"); - if (!a) return; - e.preventDefault(); - if (a === "postal") { S.postal = f.postal.value.trim(); lsSet("postal", S.postal); S.date = null; refresh(true); } - if (a === "waitlist" && S.data) { - api("/waitlist", { method: S.data.method, locationId: S.data.locationId, date: S.date, slot: "*", email: f.email.value.trim() }).then(function (r) { - if (r.ok) S.waitlistDone = true; else setMessage(r.message || T.error, "critical"); - renderAll(); - }); - } - }); - - // Arrow-key navigation in the calendar grid. - document.addEventListener("keydown", function (e) { - var t = e.target; - if (!t.classList || !t.classList.contains("dw-day")) return; - var step = { ArrowLeft: -1, ArrowRight: 1, ArrowUp: -7, ArrowDown: 7 }[e.key]; - if (!step) return; - var days = Array.prototype.slice.call(t.parentNode.querySelectorAll(".dw-day")); - var next = days[days.indexOf(t) + step]; - if (next) { e.preventDefault(); t.tabIndex = -1; next.tabIndex = 0; next.focus(); } - }); - function focusFirst(sel) { setTimeout(function () { var el = document.querySelector("[data-datewise-root] " + sel); if (el) el.focus(); }, 0); } - - // Checkout guard (convenience; the checkout function is the real enforcement). - function needsTime() { return S.data && S.data.requireScheduling && S.lines.length > 0 && !S.sel; } - function guard(e) { - if (!CFG.checkoutGuard || !needsTime()) return; - var t = e.target.closest && e.target.closest('[name="checkout"], a[href$="/checkout"], form[action$="/checkout"] [type="submit"]'); - if (!t) return; - e.preventDefault(); e.stopPropagation(); - setMessage(T.needTime, "critical"); - renderAll(); - var r = roots()[0]; - if (r) { r.scrollIntoView({ behavior: "smooth", block: "center" }); } - } - document.addEventListener("click", guard, true); - - // React to cart changes made by the theme (add, quantity, remove) — revalidate the selection. - var realFetch = window.fetch.bind(window); - window.fetch = function (input, init) { - var url = typeof input === "string" ? input : input && input.url; - var p = realFetch(input, init); - if (url && /\/cart\/(add|change|update|clear)(\.js)?/.test(url) && !S.mutating) p.then(function () { refresh(); }); - return p; - }; - ["cart:updated", "cart:change", "cart-drawer:open", "ajaxCart:updated"].forEach(function (n) { - document.addEventListener(n, function (e) { if (!(e.detail && e.detail.source === "datewise")) refresh(); }); - }); - if (typeof window.subscribe === "function" && window.PUB_SUB_EVENTS) - window.subscribe(window.PUB_SUB_EVENTS.cartUpdate, function (ev) { if (!ev || ev.source !== "datewise") refresh(); }); - - // ---------- cart drawer mounting ---------- - var DRAWER_SELECTORS = [CFG.drawerSelector, "cart-drawer .drawer__footer", "#CartDrawer .drawer__footer", "#CartDrawer-Footer", ".cart-drawer__footer", "#cart-drawer .cart__footer", ".js-cart-drawer .cart-drawer__footer", "[data-cart-drawer] footer"].filter(Boolean); - function mountDrawer() { - for (var i = 0; i < DRAWER_SELECTORS.length; i++) { - var foot = document.querySelector(DRAWER_SELECTORS[i]); - if (foot && !foot.querySelector("[data-datewise-root]")) { - var el = document.createElement("div"); - el.className = "datewise datewise--drawer"; - el.setAttribute("data-datewise-root", ""); - el.setAttribute("data-drawer", ""); - foot.insertBefore(el, foot.firstChild); - if (S.data) render(el); else refresh(true); - return; - } - } - } - if (cfgEl) { - mountDrawer(); - new MutationObserver(function () { mountDrawer(); }).observe(document.body, { childList: true, subtree: true }); - } - - // ---------- waitlist offer links (?datewise_offer=…) ---------- - function adoptOffer() { - var m = location.search.match(/[?&]datewise_offer=([^&]+)/); - if (!m) return Promise.resolve(); - return api("/offer?token=" + encodeURIComponent(m[1]), null, "GET").then(function (o) { - if (!o.ok) { setMessage(o.message, "critical"); return; } - S.token = o.token; lsSet("token", o.token); - S.method = o.method; S.locationId = o.locationId; S.date = o.date; - setMessage(T.offer + ": " + dateLabel(o.date, true) + ".", "success"); - return load().then(function () { if (S.data && S.data.locationId === o.locationId) return hold(o.date, o.slot); }); - }); - } - - adoptOffer().then(function () { if (!S.data) refresh(true); }); -})(); +"use strict";(function(){"use strict";if(window.__datewiseLoaded)return;window.__datewiseLoaded=!0;var x=document.querySelector("[data-datewise-config]"),m={};try{m=x?JSON.parse(x.textContent):{}}catch{m={}}var l=Object.assign({choose:"Pick a highlighted date",needTime:"Please choose a delivery or pickup time before checking out.",held:"Held for you for",expired:"Your hold expired. Tap the time again to check it's still free.",left:"left",full:"Full",postal:"Postal / ZIP code",check:"Check",waitlist:"Join the waitlist",joined:"You're on the waitlist. We'll message you if a place opens.",dispatch:"Ships this day (not an arrival date)",change:"Change",prep:"Earliest times include preparation for",free:"Free",fee:"fee",nextAvailable:"Next available",offer:"A place opened up and we're holding it for you",error:"Something went wrong. Please try again."},m.text||{}),N=(window.Shopify&&Shopify.routes&&Shopify.routes.root||"/").replace(/\/?$/,"/"),X=N+"apps/datewise",g=m.locale||document.documentElement.lang||"en",ee=m.currency||window.Shopify&&Shopify.currency&&Shopify.currency.active||"CAD",U="_datewise";function _(e){try{return localStorage.getItem("datewise_"+e)}catch{return null}}function w(e,t){try{t==null?localStorage.removeItem("datewise_"+e):localStorage.setItem("datewise_"+e,t)}catch{}}var a={data:null,cart:null,lines:[],loading:!1,message:null,messageTone:"info",method:_("method"),locationId:_("location"),postal:_("postal")||"",date:null,sel:null,token:_("token"),expiresAt:null,heldAt:null,monthOffset:0,waitlistDone:!1,mutating:0};function i(e){return String(e==null?"":e).replace(/[&<>"']/g,function(t){return{"&":"&","<":"<",">":">",'"':""","'":"'"}[t]})}function T(e){try{return new Intl.NumberFormat(g,{style:"currency",currency:ee}).format(e/100)}catch{return"$"+(e/100).toFixed(2)}}function b(e,t){return new Intl.DateTimeFormat(g,{weekday:t?"long":"short",month:t?"long":"short",day:"numeric",timeZone:"UTC"}).format(new Date(e+"T12:00:00Z"))}function j(e){var t=e.split(":");return new Intl.DateTimeFormat(g,{hour:"numeric",minute:t[1]==="00"?void 0:"2-digit",timeZone:"UTC"}).format(new Date(Date.UTC(2e3,0,1,+t[0],+t[1])))}function q(e){return j(e.start)+" \u2013 "+j(e.end)}function te(e,t){var n=+e.slice(0,4),r=+e.slice(5,7)-1+t;return n+=Math.floor(r/12),r=(r%12+12)%12,n+"-"+String(r+1).padStart(2,"0")}function ae(e){return new Date(Date.UTC(+e.slice(0,4),+e.slice(5,7),0)).getUTCDate()}var ne={pickup:'',delivery:'',shipping:''};function P(e){return'"}function re(e){return new Date(e+"T12:00:00Z").getUTCDay()}function S(e,t,n){var r=X+e,o={method:n||"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},credentials:"same-origin"};return t&&o.method!=="GET"&&(o.body=JSON.stringify(t)),L(r,o).then(function(d){return d.json().catch(function(){return{ok:!1,message:l.error}})})}function A(e,t){return a.mutating++,L(N+e,{method:t?"POST":"GET",headers:{"Content-Type":"application/json",Accept:"application/json"},body:t?JSON.stringify(t):void 0,credentials:"same-origin"}).then(function(n){return n.json()}).finally(function(){setTimeout(function(){a.mutating--},50)})}function F(){return A("cart.js").then(function(e){a.cart=e,a.lines=e.items.filter(function(r){return!(r.properties&&r.properties._datewise_fee)}).map(function(r){return{variantId:r.variant_id,quantity:r.quantity,price:r.final_price,title:r.product_title}});var t=e.attributes&&e.attributes[U];if(t)try{var n=JSON.parse(t);a.sel={method:n.m,locationId:n.l,date:n.d,slot:n.s,fee:n.f},a.token=n.t,w("token",n.t),a.method=a.method||n.m,a.locationId=a.locationId||n.l,a.date=a.date||n.d}catch{a.sel=null}else a.sel=null;return e})}function ie(){return(a.cart?a.cart.items:[]).filter(function(e){return e.properties&&e.properties._datewise_fee})}function R(e){var t=ie(),n=Promise.resolve(),r=null;t.forEach(function(d){!r&&e&&String(d.variant_id)===String(e)&&d.quantity===1?r=d:n=n.then(function(){return A("cart/change.js",{id:d.key,quantity:0})})}),e&&!r&&(n=n.then(function(){return A("cart/add.js",{items:[{id:Number(e),quantity:1,properties:{_datewise_fee:"1"}}]})}));var o=t.length!==(r?1:0)||e&&!r;return n.then(function(){return o})}function B(e){var t=[];try{t=JSON.parse(_("keys")||"[]")}catch{}var n={};return t.forEach(function(r){n[r]=""}),Object.keys(e).forEach(function(r){n[r]=e[r]}),w("keys",JSON.stringify(Object.keys(e))),A("cart/update.js",{attributes:n})}function Z(e){var t={source:"datewise"};["cart:refresh","cart:updated","cart:change","theme:cart:change"].forEach(function(n){document.dispatchEvent(new CustomEvent(n,{detail:t,bubbles:!0}))}),typeof window.publish=="function"&&window.PUB_SUB_EVENTS?F().then(function(n){window.publish(window.PUB_SUB_EVENTS.cartUpdate,{source:"datewise",cartData:n})}):e&&/\/cart\/?$/.test(location.pathname)&&setTimeout(function(){location.reload()},300)}function C(e){var t=a.token;return a.sel=null,a.expiresAt=null,e&&p(e,"critical"),t&&S("/release",{token:t}).catch(function(){}),B({[U]:""}).then(function(){return R(null)}).then(function(n){w("keys","[]"),n&&Z(!0)})}var G=null;function h(e){clearTimeout(G),G=setTimeout(H,e?0:300)}function H(){return!M().length&&!m.checkoutGuard?Promise.resolve():(a.loading=!0,f(),F().then(function(){if(!a.lines.length){a.data=null,a.loading=!1,a.sel&&C(null),f();return}return S("/availability",{lines:a.lines,method:a.method||void 0,locationId:a.locationId||void 0,postal:a.postal||void 0,token:a.token||void 0,locale:g}).then(function(e){if(a.loading=!1,!e||e.ok===!1){p(e&&e.message||l.error,"critical"),f();return}a.data=e,a.method=e.method,a.locationId=e.locationId,se(),f()})}).catch(function(){a.loading=!1,p(l.error,"critical"),f()}))}function oe(e,t){var n=a.data&&a.data.dates.filter(function(r){return r.date===e})[0];return{d:n,s:n&&n.slots.filter(function(r){return r.id===t})[0]}}function se(){if(a.sel){var e=a.data;if(!e||e.method!==a.sel.method||e.locationId!==a.sel.locationId)return C(null);var t=oe(a.sel.date,a.sel.slot);if(!t.s||!t.s.available){var n=t.s&&t.s.reason||t.d&&t.d.reasons[0]||"";C(n?n+". "+l.choose+".":l.choose)}}}function J(e,t){if(a.data)return p(null),a.loading=!0,f(),S("/hold",{lines:a.lines,method:a.data.method,locationId:a.data.locationId,date:e,slot:t,token:a.token||void 0,postal:a.postal||void 0,locale:g}).then(function(n){if(!n.ok){a.loading=!1,p(n.message||l.error,"critical"),h(!0);return}return a.token=n.token,w("token",n.token),a.expiresAt=Date.parse(n.expiresAt),a.heldAt=Date.now(),a.sel={method:a.data.method,locationId:a.data.locationId,date:e,slot:t,fee:n.fee?n.fee.fee:0},B(n.attributes).then(function(){return R(n.feeVariantId)}).then(function(r){a.loading=!1,f(),Z(r)})}).catch(function(){a.loading=!1,p(l.error,"critical"),f()})}function p(e,t){a.message=e,a.messageTone=t||"info"}function M(){return Array.prototype.slice.call(document.querySelectorAll("[data-datewise-root]"))}function f(){M().forEach(V)}function V(e){e.classList.contains("datewise")||e.classList.add("datewise");var t=a.data,n=e.getAttribute("data-heading")||t&&t.text&&t.text.heading||"";t&&t.text&&t.text.accent&&e.style.setProperty("--dw-accent",t.text.accent);var r="";if(n&&(r+='

'+i(n)+"

"),r+='
'+(a.message?'

'+i(a.message)+"

":"")+"
",!t){e.innerHTML=r+(a.loading?'':""),e.setAttribute("aria-busy",a.loading);return}if(r+='
',t.methods.forEach(function(s){var v=s.method===t.method;r+='"}),r+="
",!t.method){e.innerHTML=r;return}if(t.method==="delivery"&&(r+='
"),t.split&&(r+='

'+i(t.split)+"

"),t.method!=="shipping"&&t.locations.length>1)r+='
',t.locations.forEach(function(s){var v=s.id===t.locationId,O=s.fee?s.fee.waived?l.free:T(s.fee.fee):s.distanceKm!=null?s.distanceKm+" km":"";r+='"}),r+="
";else if(t.locationId){var o=t.locations.filter(function(s){return s.id===t.locationId})[0];o&&t.method!=="shipping"&&(r+='

'+i(o.name)+(o.fee?" \xB7 "+(o.fee.waived?l.free:T(o.fee.fee)+" "+l.fee):"")+"

")}if(!t.locationId){if(t.needsAddress){e.innerHTML=r;return}var d=t.locations[0]&&t.locations[0].reason;e.innerHTML=r+(d?'

'+i(d)+"

":"");return}t.prepNote&&t.prepNote.minutes>=60&&(r+='

'+i(l.prep+" "+t.prepNote.item)+" ("+Math.round(t.prepNote.minutes/6)/10+" h)

");var c=t.dates.filter(function(s){return s.peak&&s.peak.message})[0];c&&(r+='

'+i(c.peak.message)+"

"),r+=de(t),r+=ce(t,e),e.innerHTML=r,e.setAttribute("aria-busy",a.loading),z()}var le=0;function $(e){return e.__dwid||(e.__dwid=++le),e.__dwid}function de(e){var t={};e.dates.forEach(function(D){t[D.date]=D});var n=(e.dates.filter(function(D){return D.available})[0]||e.dates[0]||{}).date;if(!n)return"";for(var r=te(n.slice(0,7),a.monthOffset),o=e.text.weekStartsOn||0,d=r+"-01",c=(re(d)-o+7)%7,s='
'+i(new Intl.DateTimeFormat(g,{month:"long",year:"numeric",timeZone:"UTC"}).format(new Date(d+"T12:00:00Z")))+'
',v=0;v<7;v++){var O=(o+v)%7;s+='"}for(var W=0;W";for(var I=1;I<=ae(r);I++){var k=r+"-"+String(I).padStart(2,"0"),u=t[k],y="dw-day",E=b(k,!0),Q="";u?u.available?(y+=" dw-avail",e.text.showRemaining&&u.remaining!=null&&u.remaining<=5&&(Q=''+u.remaining+"")):u.waitlist||/full|booked/i.test(u.reasons[0]||"")?(y+=" dw-full",E+=", "+l.full):(y+=" dw-closed",E+=", "+(u.reasons[0]||"")):y+=" dw-out",a.date===k&&(y+=" dw-sel"),u&&u.peak&&(y+=" dw-peakday",E+=", "+u.peak.name),s+='"}return s+"
"}function ce(e,t){if(!a.date)return'

'+i(l.choose)+"

";var n=e.dates.filter(function(o){return o.date===a.date})[0];if(!n)return"";var r='

'+i(b(n.date,!0))+(n.peak?' '+i(n.peak.name)+"":"")+"

";return e.dateOnly&&(r+='

'+i(l.dispatch)+"

"),n.available?(r+='
',n.slots.forEach(function(o){var d=a.sel&&a.sel.date===n.date&&a.sel.slot===o.id,c=o.available?(e.text.showRemaining&&o.remaining!=null?o.remaining+" "+l.left:"")+(o.surcharge?(o.remaining!=null&&e.text.showRemaining?" \xB7 ":"")+"+"+T(o.surcharge):""):o.reason||"";r+='"}),r+="
",a.sel&&a.sel.date===n.date&&(r+=ue(e,n)),r+"
"):(r+='

'+i(n.reasons.join(". "))+"

",n.waitlist&&!a.waitlistDone&&(r+='
"),a.waitlistDone&&(r+='

'+i(l.joined)+"

"),r+"")}function ue(e,t){var n=e.locations.filter(function(s){return s.id===e.locationId})[0],r=t.slots.filter(function(s){return s.id===a.sel.slot})[0],o=a.expiresAt&&a.expiresAt>Date.now(),d=a.expiresAt&&!o,c='
'+P(e.method)+i(e.text.labels[e.method])+(n&&e.method!=="shipping"?", "+i(n.name):"")+''+i(b(t.date,!0))+""+(r&&!e.dateOnly?''+i(q(r))+"":"")+(a.sel.fee?'+'+i(T(a.sel.fee))+" "+i(l.fee)+"":"")+'
';return o?c+=''+i(l.held)+" ":d?c+=''+i(l.expired)+"":c+='',c+="
",n&&n.pickupInstructions&&e.method==="pickup"&&(c+='

'+i(n.pickupInstructions)+"

"),c}function z(){var e=a.expiresAt?a.expiresAt-Date.now():0,t=document.querySelectorAll("[data-dw-timer]");if(e<=0&&t.length)return f();for(var n=Math.max(0,Math.round(e/1e3)),r=0;r0?String(100-Math.max(0,Math.min(100,e/o*100))):"0"}setInterval(z,1e3),document.addEventListener("click",function(e){var t=e.target.closest&&e.target.closest("[data-datewise-root] [data-dw]");if(!(!t||t.tagName==="FORM")&&!(t.getAttribute("aria-disabled")==="true"&&t.getAttribute("data-dw")!=="date")){var n=t.getAttribute("data-dw"),r=t.getAttribute("data-v");n==="method"&&r!==a.method?(a.method=r,w("method",r),a.date=null,a.monthOffset=0,h(!0)):n==="loc"&&r!==a.locationId?(a.locationId=r,w("location",r),a.date=null,h(!0)):n==="month"?(a.monthOffset+=+r,f()):n==="date"?(a.date=r,a.waitlistDone=!1,p(null),f(),fe(".dw-slot:not([aria-disabled])")):n==="slot"&&J(a.date,r)}}),document.addEventListener("submit",function(e){var t=e.target;if(!(!t.closest||!t.closest("[data-datewise-root]"))){var n=t.getAttribute("data-dw");n&&(e.preventDefault(),n==="postal"&&(a.postal=t.postal.value.trim(),w("postal",a.postal),a.date=null,h(!0)),n==="waitlist"&&a.data&&S("/waitlist",{method:a.data.method,locationId:a.data.locationId,date:a.date,slot:"*",email:t.email.value.trim()}).then(function(r){r.ok?a.waitlistDone=!0:p(r.message||l.error,"critical"),f()}))}}),document.addEventListener("keydown",function(e){var t=e.target;if(!(!t.classList||!t.classList.contains("dw-day"))){var n={ArrowLeft:-1,ArrowRight:1,ArrowUp:-7,ArrowDown:7}[e.key];if(n){var r=Array.prototype.slice.call(t.parentNode.querySelectorAll(".dw-day")),o=r[r.indexOf(t)+n];o&&(e.preventDefault(),t.tabIndex=-1,o.tabIndex=0,o.focus())}}});function fe(e){setTimeout(function(){var t=document.querySelector("[data-datewise-root] "+e);t&&t.focus()},0)}function pe(){return a.data&&a.data.requireScheduling&&a.lines.length>0&&!a.sel}function he(e){if(!(!m.checkoutGuard||!pe())){var t=e.target.closest&&e.target.closest('[name="checkout"], a[href$="/checkout"], form[action$="/checkout"] [type="submit"]');if(t){e.preventDefault(),e.stopPropagation(),p(l.needTime,"critical"),f();var n=M()[0];n&&n.scrollIntoView({behavior:"smooth",block:"center"})}}}document.addEventListener("click",he,!0);var L=window.fetch.bind(window);window.fetch=function(e,t){var n=typeof e=="string"?e:e&&e.url,r=L(e,t);return n&&/\/cart\/(add|change|update|clear)(\.js)?/.test(n)&&!a.mutating&&r.then(function(){h()}),r},["cart:updated","cart:change","cart-drawer:open","ajaxCart:updated"].forEach(function(e){document.addEventListener(e,function(t){t.detail&&t.detail.source==="datewise"||h()})}),typeof window.subscribe=="function"&&window.PUB_SUB_EVENTS&&window.subscribe(window.PUB_SUB_EVENTS.cartUpdate,function(e){(!e||e.source!=="datewise")&&h()});var Y=[m.drawerSelector,"cart-drawer .drawer__footer","#CartDrawer .drawer__footer","#CartDrawer-Footer",".cart-drawer__footer","#cart-drawer .cart__footer",".js-cart-drawer .cart-drawer__footer","[data-cart-drawer] footer"].filter(Boolean);function K(){for(var e=0;e