Checkout functions
Type your checkout functions, and read the schemas and limits Storeware holds them to.
import { ... } from '@storeware/plugin-sdk/functions';defineFunctions
Types an app's functions export, so each handler is checked against its kind.
function defineFunctions<T extends { [handle: string]: { [K in FunctionKind]: { kind: K; run: FunctionTypes[K]; }; }[FunctionKind]; }>(functions: T): { [H in keyof T]: T[H]['run']; }FunctionKind
type FunctionKind = (typeof FUNCTION_KINDS)[number];PaymentMethod
type PaymentMethod = (typeof PAYMENT_METHODS)[number];FunctionLine
type FunctionLine = z.infer<typeof functionLine>;BasketInput
type BasketInput = z.infer<typeof basketInput>;DeliveryOption
type DeliveryOption = z.infer<typeof deliveryOption>;DeliveryRatesInput
type DeliveryRatesInput = z.infer<typeof deliveryRatesInput>;DeliveryRatesOutput
type DeliveryRatesOutput = z.infer<typeof deliveryRatesOutput>;DiscountInput
type DiscountInput = z.infer<typeof discountInput>;DiscountOutput
type DiscountOutput = z.infer<typeof discountOutput>;PaymentMethodsInput
type PaymentMethodsInput = z.infer<typeof paymentMethodsInput>;PaymentMethodsOutput
type PaymentMethodsOutput = z.infer<typeof paymentMethodsOutput>;CartValidationInput
type CartValidationInput = z.infer<typeof cartValidationInput>;CartValidationOutput
type CartValidationOutput = z.infer<typeof cartValidationOutput>;FunctionTypes
| Name | Type | Description |
|---|---|---|
discount | (input: DiscountInput) => DiscountOutput | Promise<DiscountOutput> | |
delivery_rates | (input: DeliveryRatesInput) => DeliveryRatesOutput | Promise<DeliveryRatesOutput> | |
payment_methods | ( input: PaymentMethodsInput, ) => PaymentMethodsOutput | Promise<PaymentMethodsOutput> | |
cart_validation | ( input: CartValidationInput, ) => CartValidationOutput | Promise<CartValidationOutput> |
FUNCTION_KINDS
const FUNCTION_KINDS: readonly ['discount', 'delivery_rates', 'payment_methods', 'cart_validation']PAYMENT_METHODS
The payment methods a function can hide or reorder. Platform level on purpose: card is every card and wallet Stripe offers, on_account is paying later on a business's terms, crypto is stablecoin payment.
const PAYMENT_METHODS: readonly ['card', 'on_account', 'crypto']FUNCTION_CPU_MS
CPU time one call may use, in milliseconds.
const FUNCTION_CPU_MS: 25FUNCTION_WALL_MS
Wall time one call may take, in milliseconds, waiting included.
const FUNCTION_WALL_MS: 250MAX_FUNCTION_OUTPUT_BYTES
The largest answer a function may give, as JSON, in bytes.
const MAX_FUNCTION_OUTPUT_BYTES: numberfunctionLine
One line of the basket, as every kind sees it.
const functionLine: z.ZodObject<{ id: z.ZodString; productId: z.ZodString; variantId: z.ZodString; sku: z.ZodNullable<z.ZodString>; title: z.ZodString; variantTitle: z.ZodNullable<z.ZodString>; quantity: z.ZodNumber; unitPrice: z.ZodNumber; grams: z.ZodNullable<z.ZodNumber>; requiresShipping: z.ZodBoolean; metafields: z.ZodRecord<z.ZodString, z.ZodUnknown>; }, z.core.$strip>basketInput
What every kind is given: the basket, who is buying, and where it goes.
const basketInput: z.ZodObject<{ storeId: z.ZodString; currency: z.ZodString; lines: z.ZodArray<z.ZodObject<{ id: z.ZodString; productId: z.ZodString; variantId: z.ZodString; sku: z.ZodNullable<z.ZodString>; title: z.ZodString; variantTitle: z.ZodNullable<z.ZodString>; quantity: z.ZodNumber; unitPrice: z.ZodNumber; grams: z.ZodNullable<z.ZodNumber>; requiresShipping: z.ZodBoolean; metafields: z.ZodRecord<z.ZodString, z.ZodUnknown>; }, z.core.$strip>>; subtotal: z.ZodNumber; buyer: z.ZodObject<{ customerId: z.ZodNullable<z.ZodString>; companyId: z.ZodNullable<z.ZodString>; email: z.ZodNullable<z.ZodString>; metafields: z.ZodRecord<z.ZodString, z.ZodUnknown>; }, z.core.$strip>; destination: z.ZodNullable<z.ZodObject<{ country: z.ZodString; region: z.ZodNullable<z.ZodString>; postalCode: z.ZodNullable<z.ZodString>; city: z.ZodNullable<z.ZodString>; }, z.core.$strip>>; discountCode: z.ZodNullable<z.ZodString>; delivery: z.ZodNullable<z.ZodObject<{ id: z.ZodString; type: z.ZodString; title: z.ZodString; amount: z.ZodNumber; }, z.core.$strip>>; channel: z.ZodEnum<{ web: 'web'; agent: 'agent'; }>; }, z.core.$strip>deliveryOption
const deliveryOption: z.ZodObject<{ id: z.ZodString; type: z.ZodString; title: z.ZodString; description: z.ZodOptional<z.ZodString>; carrier: z.ZodOptional<z.ZodString>; amount: z.ZodNumber; }, z.core.$strip>deliveryRatesInput
const deliveryRatesInput: z.ZodObject<{ storeId: z.ZodString; currency: z.ZodString; lines: z.ZodArray<z.ZodObject<{ id: z.ZodString; productId: z.ZodString; variantId: z.ZodString; sku: z.ZodNullable<z.ZodString>; title: z.ZodString; variantTitle: z.ZodNullable<z.ZodString>; quantity: z.ZodNumber; unitPrice: z.ZodNumber; grams: z.ZodNullable<z.ZodNumber>; requiresShipping: z.ZodBoolean; metafields: z.ZodRecord<z.ZodString, z.ZodUnknown>; }, z.core.$strip>>; subtotal: z.ZodNumber; buyer: z.ZodObject<{ customerId: z.ZodNullable<z.ZodString>; companyId: z.ZodNullable<z.ZodString>; email: z.ZodNullable<z.ZodString>; metafields: z.ZodRecord<z.ZodString, z.ZodUnknown>; }, z.core.$strip>; destination: z.ZodNullable<z.ZodObject<{ country: z.ZodString; region: z.ZodNullable<z.ZodString>; postalCode: z.ZodNullable<z.ZodString>; city: z.ZodNullable<z.ZodString>; }, z.core.$strip>>; discountCode: z.ZodNullable<z.ZodString>; delivery: z.ZodNullable<z.ZodObject<{ id: z.ZodString; type: z.ZodString; title: z.ZodString; amount: z.ZodNumber; }, z.core.$strip>>; channel: z.ZodEnum<{ web: 'web'; agent: 'agent'; }>; options: z.ZodArray<z.ZodObject<{ id: z.ZodString; type: z.ZodString; title: z.ZodString; description: z.ZodOptional<z.ZodString>; carrier: z.ZodOptional<z.ZodString>; amount: z.ZodNumber; }, z.core.$strip>>; }, z.core.$strip>deliveryRatesOutput
The options to offer, in order. An option left out is hidden. Only options the input named may appear, each once, so an id never changes and nothing is invented; offering new rates is [checkout.delivery_rates]'s job.
const deliveryRatesOutput: z.ZodObject<{ options: z.ZodArray<z.ZodObject<{ id: z.ZodString; title: z.ZodOptional<z.ZodString>; amount: z.ZodOptional<z.ZodNumber>; }, z.core.$strict>>; }, z.core.$strip>discountInput
const discountInput: z.ZodObject<{ storeId: z.ZodString; currency: z.ZodString; lines: z.ZodArray<z.ZodObject<{ id: z.ZodString; productId: z.ZodString; variantId: z.ZodString; sku: z.ZodNullable<z.ZodString>; title: z.ZodString; variantTitle: z.ZodNullable<z.ZodString>; quantity: z.ZodNumber; unitPrice: z.ZodNumber; grams: z.ZodNullable<z.ZodNumber>; requiresShipping: z.ZodBoolean; metafields: z.ZodRecord<z.ZodString, z.ZodUnknown>; }, z.core.$strip>>; subtotal: z.ZodNumber; buyer: z.ZodObject<{ customerId: z.ZodNullable<z.ZodString>; companyId: z.ZodNullable<z.ZodString>; email: z.ZodNullable<z.ZodString>; metafields: z.ZodRecord<z.ZodString, z.ZodUnknown>; }, z.core.$strip>; destination: z.ZodNullable<z.ZodObject<{ country: z.ZodString; region: z.ZodNullable<z.ZodString>; postalCode: z.ZodNullable<z.ZodString>; city: z.ZodNullable<z.ZodString>; }, z.core.$strip>>; discountCode: z.ZodNullable<z.ZodString>; delivery: z.ZodNullable<z.ZodObject<{ id: z.ZodString; type: z.ZodString; title: z.ZodString; amount: z.ZodNumber; }, z.core.$strip>>; channel: z.ZodEnum<{ web: 'web'; agent: 'agent'; }>; }, z.core.$strip>discountOutput
const discountOutput: z.ZodObject<{ discounts: z.ZodArray<z.ZodObject<{ title: z.ZodString; target: z.ZodUnion<readonly [z.ZodLiteral<'order'>, z.ZodLiteral<'delivery'>, z.ZodObject<{ lines: z.ZodArray<z.ZodString>; }, z.core.$strict>]>; value: z.ZodUnion<readonly [z.ZodObject<{ percent: z.ZodNumber; }, z.core.$strict>, z.ZodObject<{ amount: z.ZodNumber; }, z.core.$strict>]>; }, z.core.$strict>>; }, z.core.$strip>paymentMethodsInput
const paymentMethodsInput: z.ZodObject<{ storeId: z.ZodString; currency: z.ZodString; lines: z.ZodArray<z.ZodObject<{ id: z.ZodString; productId: z.ZodString; variantId: z.ZodString; sku: z.ZodNullable<z.ZodString>; title: z.ZodString; variantTitle: z.ZodNullable<z.ZodString>; quantity: z.ZodNumber; unitPrice: z.ZodNumber; grams: z.ZodNullable<z.ZodNumber>; requiresShipping: z.ZodBoolean; metafields: z.ZodRecord<z.ZodString, z.ZodUnknown>; }, z.core.$strip>>; subtotal: z.ZodNumber; buyer: z.ZodObject<{ customerId: z.ZodNullable<z.ZodString>; companyId: z.ZodNullable<z.ZodString>; email: z.ZodNullable<z.ZodString>; metafields: z.ZodRecord<z.ZodString, z.ZodUnknown>; }, z.core.$strip>; destination: z.ZodNullable<z.ZodObject<{ country: z.ZodString; region: z.ZodNullable<z.ZodString>; postalCode: z.ZodNullable<z.ZodString>; city: z.ZodNullable<z.ZodString>; }, z.core.$strip>>; discountCode: z.ZodNullable<z.ZodString>; delivery: z.ZodNullable<z.ZodObject<{ id: z.ZodString; type: z.ZodString; title: z.ZodString; amount: z.ZodNumber; }, z.core.$strip>>; channel: z.ZodEnum<{ web: 'web'; agent: 'agent'; }>; methods: z.ZodArray<z.ZodEnum<{ card: 'card'; on_account: 'on_account'; crypto: 'crypto'; }>>; }, z.core.$strip>paymentMethodsOutput
The methods to offer, in order. A method left out is not offered, and refused if tried.
const paymentMethodsOutput: z.ZodObject<{ methods: z.ZodArray<z.ZodEnum<{ card: 'card'; on_account: 'on_account'; crypto: 'crypto'; }>>; }, z.core.$strip>cartValidationInput
const cartValidationInput: z.ZodObject<{ storeId: z.ZodString; currency: z.ZodString; lines: z.ZodArray<z.ZodObject<{ id: z.ZodString; productId: z.ZodString; variantId: z.ZodString; sku: z.ZodNullable<z.ZodString>; title: z.ZodString; variantTitle: z.ZodNullable<z.ZodString>; quantity: z.ZodNumber; unitPrice: z.ZodNumber; grams: z.ZodNullable<z.ZodNumber>; requiresShipping: z.ZodBoolean; metafields: z.ZodRecord<z.ZodString, z.ZodUnknown>; }, z.core.$strip>>; subtotal: z.ZodNumber; buyer: z.ZodObject<{ customerId: z.ZodNullable<z.ZodString>; companyId: z.ZodNullable<z.ZodString>; email: z.ZodNullable<z.ZodString>; metafields: z.ZodRecord<z.ZodString, z.ZodUnknown>; }, z.core.$strip>; destination: z.ZodNullable<z.ZodObject<{ country: z.ZodString; region: z.ZodNullable<z.ZodString>; postalCode: z.ZodNullable<z.ZodString>; city: z.ZodNullable<z.ZodString>; }, z.core.$strip>>; discountCode: z.ZodNullable<z.ZodString>; delivery: z.ZodNullable<z.ZodObject<{ id: z.ZodString; type: z.ZodString; title: z.ZodString; amount: z.ZodNumber; }, z.core.$strip>>; channel: z.ZodEnum<{ web: 'web'; agent: 'agent'; }>; }, z.core.$strip>cartValidationOutput
const cartValidationOutput: z.ZodObject<{ errors: z.ZodArray<z.ZodObject<{ message: z.ZodString; lineId: z.ZodOptional<z.ZodString>; }, z.core.$strict>>; }, z.core.$strip>FUNCTION_SCHEMAS
Each kind's input and output schema, by kind.
const FUNCTION_SCHEMAS: { readonly discount: { readonly input: z.ZodObject<{ storeId: z.ZodString; currency: z.ZodString; lines: z.ZodArray<z.ZodObject<{ id: z.ZodString; productId: z.ZodString; variantId: z.ZodString; sku: z.ZodNullable<z.ZodString>; title: z.ZodString; variantTitle: z.ZodNullable<z.ZodString>; quantity: z.ZodNumber; unitPrice: z.ZodNumber; grams: z.ZodNullable<z.ZodNumber>; requiresShipping: z.ZodBoolean; metafields: z.ZodRecord<z.ZodString, z.ZodUnknown>; }, z.core.$strip>>; subtotal: z.ZodNumber; buyer: z.ZodObject<{ customerId: z.ZodNullable<z.ZodString>; companyId: z.ZodNullable<z.ZodString>; email: z.ZodNullable<z.ZodString>; metafields: z.ZodRecord<z.ZodString, z.ZodUnknown>; }, z.core.$strip>; destination: z.ZodNullable<z.ZodObject<{ country: z.ZodString; region: z.ZodNullable<z.ZodString>; postalCode: z.ZodNullable<z.ZodString>; city: z.ZodNullable<z.ZodString>; }, z.core.$strip>>; discountCode: z.ZodNullable<z.ZodString>; delivery: z.ZodNullable<z.ZodObject<{ id: z.ZodString; type: z.ZodString; title: z.ZodString; amount: z.ZodNumber; }, z.core.$strip>>; channel: z.ZodEnum<{ web: 'web'; agent: 'agent'; }>; }, z.core.$strip>; readonly output: z.ZodObject<{ discounts: z.ZodArray<z.ZodObject<{ title: z.ZodString; target: z.ZodUnion<readonly [z.ZodLiteral<'order'>, z.ZodLiteral<'delivery'>, z.ZodObject<{ lines: z.ZodArray<z.ZodString>; }, z.core.$strict>]>; value: z.ZodUnion<readonly [z.ZodObject<{ percent: z.ZodNumber; }, z.core.$strict>, z.ZodObject<{ amount: z.ZodNumber; }, z.core.$strict>]>; }, z.core.$strict>>; }, z.core.$strip>; }; readonly delivery_rates: { readonly input: z.ZodObject<{ storeId: z.ZodString; currency: z.ZodString; lines: z.ZodArray<z.ZodObject<{ id: z.ZodString; productId: z.ZodString; variantId: z.ZodString; sku: z.ZodNullable<z.ZodString>; title: z.ZodString; variantTitle: z.ZodNullable<z.ZodString>; quantity: z.ZodNumber; unitPrice: z.ZodNumber; grams: z.ZodNullable<z.ZodNumber>; requiresShipping: z.ZodBoolean; metafields: z.ZodRecord<z.ZodString, z.ZodUnknown>; }, z.core.$strip>>; subtotal: z.ZodNumber; buyer: z.ZodObject<{ customerId: z.ZodNullable<z.ZodString>; companyId: z.ZodNullable<z.ZodString>; email: z.ZodNullable<z.ZodString>; metafields: z.ZodRecord<z.ZodString, z.ZodUnknown>; }, z.core.$strip>; destination: z.ZodNullable<z.ZodObject<{ country: z.ZodString; region: z.ZodNullable<z.ZodString>; postalCode: z.ZodNullable<z.ZodString>; city: z.ZodNullable<z.ZodString>; }, z.core.$strip>>; discountCode: z.ZodNullable<z.ZodString>; delivery: z.ZodNullable<z.ZodObject<{ id: z.ZodString; type: z.ZodString; title: z.ZodString; amount: z.ZodNumber; }, z.core.$strip>>; channel: z.ZodEnum<{ web: 'web'; agent: 'agent'; }>; options: z.ZodArray<z.ZodObject<{ id: z.ZodString; type: z.ZodString; title: z.ZodString; description: z.ZodOptional<z.ZodString>; carrier: z.ZodOptional<z.ZodString>; amount: z.ZodNumber; }, z.core.$strip>>; }, z.core.$strip>; readonly output: z.ZodObject<{ options: z.ZodArray<z.ZodObject<{ id: z.ZodString; title: z.ZodOptional<z.ZodString>; amount: z.ZodOptional<z.ZodNumber>; }, z.core.$strict>>; }, z.core.$strip>; }; readonly payment_methods: { readonly input: z.ZodObject<{ storeId: z.ZodString; currency: z.ZodString; lines: z.ZodArray<z.ZodObject<{ id: z.ZodString; productId: z.ZodString; variantId: z.ZodString; sku: z.ZodNullable<z.ZodString>; title: z.ZodString; variantTitle: z.ZodNullable<z.ZodString>; quantity: z.ZodNumber; unitPrice: z.ZodNumber; grams: z.ZodNullable<z.ZodNumber>; requiresShipping: z.ZodBoolean; metafields: z.ZodRecord<z.ZodString, z.ZodUnknown>; }, z.core.$strip>>; subtotal: z.ZodNumber; buyer: z.ZodObject<{ customerId: z.ZodNullable<z.ZodString>; companyId: z.ZodNullable<z.ZodString>; email: z.ZodNullable<z.ZodString>; metafields: z.ZodRecord<z.ZodString, z.ZodUnknown>; }, z.core.$strip>; destination: z.ZodNullable<z.ZodObject<{ country: z.ZodString; region: z.ZodNullable<z.ZodString>; postalCode: z.ZodNullable<z.ZodString>; city: z.ZodNullable<z.ZodString>; }, z.core.$strip>>; discountCode: z.ZodNullable<z.ZodString>; delivery: z.ZodNullable<z.ZodObject<{ id: z.ZodString; type: z.ZodString; title: z.ZodString; amount: z.ZodNumber; }, z.core.$strip>>; channel: z.ZodEnum<{ web: 'web'; agent: 'agent'; }>; methods: z.ZodArray<z.ZodEnum<{ card: 'card'; on_account: 'on_account'; crypto: 'crypto'; }>>; }, z.core.$strip>; readonly output: z.ZodObject<{ methods: z.ZodArray<z.ZodEnum<{ card: 'card'; on_account: 'on_account'; crypto: 'crypto'; }>>; }, z.core.$strip>; }; readonly cart_validation: { readonly input: z.ZodObject<{ storeId: z.ZodString; currency: z.ZodString; lines: z.ZodArray<z.ZodObject<{ id: z.ZodString; productId: z.ZodString; variantId: z.ZodString; sku: z.ZodNullable<z.ZodString>; title: z.ZodString; variantTitle: z.ZodNullable<z.ZodString>; quantity: z.ZodNumber; unitPrice: z.ZodNumber; grams: z.ZodNullable<z.ZodNumber>; requiresShipping: z.ZodBoolean; metafields: z.ZodRecord<z.ZodString, z.ZodUnknown>; }, z.core.$strip>>; subtotal: z.ZodNumber; buyer: z.ZodObject<{ customerId: z.ZodNullable<z.ZodString>; companyId: z.ZodNullable<z.ZodString>; email: z.ZodNullable<z.ZodString>; metafields: z.ZodRecord<z.ZodString, z.ZodUnknown>; }, z.core.$strip>; destination: z.ZodNullable<z.ZodObject<{ country: z.ZodString; region: z.ZodNullable<z.ZodString>; postalCode: z.ZodNullable<z.ZodString>; city: z.ZodNullable<z.ZodString>; }, z.core.$strip>>; discountCode: z.ZodNullable<z.ZodString>; delivery: z.ZodNullable<z.ZodObject<{ id: z.ZodString; type: z.ZodString; title: z.ZodString; amount: z.ZodNumber; }, z.core.$strip>>; channel: z.ZodEnum<{ web: 'web'; agent: 'agent'; }>; }, z.core.$strip>; readonly output: z.ZodObject<{ errors: z.ZodArray<z.ZodObject<{ message: z.ZodString; lineId: z.ZodOptional<z.ZodString>; }, z.core.$strict>>; }, z.core.$strip>; }; }