sanity-plugin-stripe 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +130 -53
- package/dist/{guards-CAcETsf7.js → countries-Csjmv4lY.js} +3 -3
- package/dist/countries-Csjmv4lY.js.map +1 -0
- package/dist/index.d.ts +20 -4
- package/dist/index.js +135 -34
- package/dist/index.js.map +1 -1
- package/dist/money-XMQaHsbV.d.ts +5 -0
- package/dist/react.d.ts +21 -10
- package/dist/react.js +13 -7
- package/dist/react.js.map +1 -1
- package/dist/regions-Bfhg4QDs.d.ts +157 -0
- package/dist/regions-CFDYMokP.js +207 -0
- package/dist/regions-CFDYMokP.js.map +1 -0
- package/dist/server.d.ts +97 -19
- package/dist/server.js +330 -107
- package/dist/server.js.map +1 -1
- package/dist/{countries-BuqQF1AW.js → stock-DAsSGayt.js} +4 -10
- package/dist/stock-DAsSGayt.js.map +1 -0
- package/package.json +15 -34
- package/dist/cart-CSjxtjq-.js +0 -111
- package/dist/cart-CSjxtjq-.js.map +0 -1
- package/dist/cart-D2KxuwQz.d.ts +0 -74
- package/dist/countries-BuqQF1AW.js.map +0 -1
- package/dist/guards-CAcETsf7.js.map +0 -1
- package/dist/regions-DbCIM0I1.d.ts +0 -32
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cart-CSjxtjq-.js","names":[],"sources":["../src/core/cart.ts"],"sourcesContent":["import {asArray, isObject} from './guards'\n\n/** The cart's types and rules. Used by the Studio, the browser and the server alike. */\n\nexport type Availability = 'onSale' | 'soldOut'\n\n/** What the browser keeps in the cart: references only, never prices. */\nexport interface CartLine {\n /** Sanity document id of the product. */\n productId: string\n /** `_key` of the chosen variant, when the product has variants. */\n variantKey?: string\n quantity: number\n}\n\nexport interface CartVariant {\n _key: string\n label?: string | null\n availability?: Availability | null\n}\n\n/**\n * A product as the cart and the checkout read it from Sanity: see `cartProductProjection`. It\n * says whether the product is on sale, never how many are left: counts are private.\n */\nexport interface CartProduct {\n _id: string\n title?: string | null\n slug?: string | null\n imageUrl?: string | null\n commerce?: {\n availability?: Availability | null\n /** In currency units (25 means €25). */\n price?: number | null\n taxClass?: string | null\n variants?: CartVariant[] | null\n } | null\n}\n\n/**\n * Products as a query with `cartProductProjection` returns them. Anything that isn't a document\n * is dropped; the fields are checked where they are used, in `lineStatus`.\n */\nexport function readCartProducts(value: unknown): CartProduct[] {\n return asArray(value).filter(\n (item): item is CartProduct => isObject(item) && typeof item._id === 'string',\n )\n}\n\n/** Most of one item a buyer can order at once. */\nexport const MAX_QUANTITY = 10\n\n/** One cart line per product and variant. */\nexport function lineKey(line: Pick<CartLine, 'productId' | 'variantKey'>): string {\n return `${line.productId}:${line.variantKey ?? ''}`\n}\n\n/**\n * Turns anything (stored JSON, a request body) into valid cart lines: drops what doesn't parse,\n * merges duplicates and keeps quantities between 1 and `max`.\n *\n * A product id with a dot is dropped: a published document's id has none, so a draft or a copy\n * inside a release can never be put in a cart, whatever the site's Sanity client is able to read.\n */\nexport function sanitizeLines(input: unknown, max = MAX_QUANTITY): CartLine[] {\n const merged = new Map<string, CartLine>()\n for (const item of asArray(input).slice(0, 100)) {\n if (!isObject(item)) continue\n const {productId, variantKey, quantity} = item\n if (typeof productId !== 'string' || !productId || productId.length > 200) continue\n if (productId.includes('.')) continue\n if (variantKey !== undefined && (typeof variantKey !== 'string' || variantKey.length > 200))\n continue\n if (typeof quantity !== 'number' || !Number.isFinite(quantity)) continue\n const line: CartLine = {productId, quantity: 0, ...(variantKey ? {variantKey} : {})}\n const key = lineKey(line)\n const existing = merged.get(key)\n const total = (existing?.quantity ?? 0) + Math.floor(quantity)\n if (total < 1) continue\n merged.set(key, {...line, quantity: Math.min(total, max)})\n }\n return [...merged.values()]\n}\n\nexport type Unavailable = 'missing' | 'soldOut' | 'noPrice' | 'chooseVariant' | 'variantMissing'\n\nexport type LineStatus =\n | {available: true; maxQuantity: number; price: number; variant?: CartVariant}\n | {available: false; reason: Unavailable}\n\n/**\n * Whether a product (and variant) is on sale, as far as anyone can see. Stock counts are private,\n * so they are checked by the checkout route, on the server.\n */\nexport function lineStatus(\n product: CartProduct | undefined,\n variantKey?: string,\n max = MAX_QUANTITY,\n): LineStatus {\n const commerce = product?.commerce\n if (!product || !commerce) return {available: false, reason: 'missing'}\n if (commerce.availability === 'soldOut') return {available: false, reason: 'soldOut'}\n if (typeof commerce.price !== 'number') return {available: false, reason: 'noPrice'}\n\n const variants = commerce.variants ?? []\n let variant: CartVariant | undefined\n if (variants.length) {\n if (!variantKey) return {available: false, reason: 'chooseVariant'}\n variant = variants.find((candidate) => candidate._key === variantKey)\n if (!variant) return {available: false, reason: 'variantMissing'}\n if (variant.availability === 'soldOut') return {available: false, reason: 'soldOut'}\n } else if (variantKey) {\n return {available: false, reason: 'variantMissing'}\n }\n\n return {available: true, maxQuantity: max, price: commerce.price, variant}\n}\n\n/** Display name for a line: the product title, plus the variant label when there is one. */\nexport function lineName(\n product: Pick<CartProduct, 'title'>,\n variant?: Pick<CartVariant, 'label'>,\n): string {\n const title = product.title ?? 'Product'\n return variant?.label ? `${title} – ${variant.label}` : title\n}\n\n/** Why the checkout turned a cart line down. */\nexport interface CheckoutProblem {\n productId: string\n variantKey?: string\n name?: string\n reason: Unavailable | 'tooMany'\n /** For `tooMany`: how many can be ordered. Left out when the shop hides what is left. */\n maxQuantity?: number\n}\n\n/** The problems in a checkout route's reply, as the browser reads them. */\nexport function readCheckoutProblems(value: unknown): CheckoutProblem[] {\n return asArray(value).filter(\n (item): item is CheckoutProblem =>\n isObject(item) && typeof item.productId === 'string' && typeof item.reason === 'string',\n )\n}\n\n/** A cart line with everything a cart page shows for it. */\nexport interface CartRow {\n line: CartLine\n product: CartProduct | undefined\n status: LineStatus\n name: string\n /** The line's quantity, capped at what can be ordered. 0 when the line can't be bought. */\n quantity: number\n /** Price times quantity, in currency units. 0 when the line can't be bought. */\n total: number\n}\n\n/** Joins the cart's lines with their products, as read from Sanity for the cart page. */\nexport function cartRows(\n lines: readonly CartLine[],\n products: readonly CartProduct[],\n max = MAX_QUANTITY,\n): CartRow[] {\n const byId = new Map(products.map((product) => [product._id, product]))\n return lines.map((line) => {\n const product = byId.get(line.productId)\n const status = lineStatus(product, line.variantKey, max)\n const name = product ? lineName(product, status.available ? status.variant : undefined) : 'Item'\n const quantity = status.available ? Math.min(line.quantity, status.maxQuantity) : 0\n const total = status.available ? status.price * quantity : 0\n return {line, product, status, name, quantity, total}\n })\n}\n\n/** What the cart's lines add up to, in currency units, before shipping. */\nexport function cartSubtotal(rows: readonly CartRow[]): number {\n return rows.reduce((sum, row) => sum + row.total, 0)\n}\n"],"mappings":"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"}
|
package/dist/cart-D2KxuwQz.d.ts
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
/** The cart's types and rules. Used by the Studio, the browser and the server alike. */
|
|
2
|
-
type Availability = 'onSale' | 'soldOut';
|
|
3
|
-
/** What the browser keeps in the cart: references only, never prices. */
|
|
4
|
-
interface CartLine {
|
|
5
|
-
/** Sanity document id of the product. */
|
|
6
|
-
productId: string;
|
|
7
|
-
/** `_key` of the chosen variant, when the product has variants. */
|
|
8
|
-
variantKey?: string;
|
|
9
|
-
quantity: number;
|
|
10
|
-
}
|
|
11
|
-
interface CartVariant {
|
|
12
|
-
_key: string;
|
|
13
|
-
label?: string | null;
|
|
14
|
-
availability?: Availability | null;
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* A product as the cart and the checkout read it from Sanity: see `cartProductProjection`. It
|
|
18
|
-
* says whether the product is on sale, never how many are left: counts are private.
|
|
19
|
-
*/
|
|
20
|
-
interface CartProduct {
|
|
21
|
-
_id: string;
|
|
22
|
-
title?: string | null;
|
|
23
|
-
slug?: string | null;
|
|
24
|
-
imageUrl?: string | null;
|
|
25
|
-
commerce?: {
|
|
26
|
-
availability?: Availability | null;
|
|
27
|
-
/** In currency units (25 means €25). */
|
|
28
|
-
price?: number | null;
|
|
29
|
-
taxClass?: string | null;
|
|
30
|
-
variants?: CartVariant[] | null;
|
|
31
|
-
} | null;
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Products as a query with `cartProductProjection` returns them. Anything that isn't a document
|
|
35
|
-
* is dropped; the fields are checked where they are used, in `lineStatus`.
|
|
36
|
-
*/
|
|
37
|
-
declare function readCartProducts(value: unknown): CartProduct[];
|
|
38
|
-
/** One cart line per product and variant. */
|
|
39
|
-
declare function lineKey(line: Pick<CartLine, 'productId' | 'variantKey'>): string;
|
|
40
|
-
type Unavailable = 'missing' | 'soldOut' | 'noPrice' | 'chooseVariant' | 'variantMissing';
|
|
41
|
-
type LineStatus = {
|
|
42
|
-
available: true;
|
|
43
|
-
maxQuantity: number;
|
|
44
|
-
price: number;
|
|
45
|
-
variant?: CartVariant;
|
|
46
|
-
} | {
|
|
47
|
-
available: false;
|
|
48
|
-
reason: Unavailable;
|
|
49
|
-
};
|
|
50
|
-
/** Why the checkout turned a cart line down. */
|
|
51
|
-
interface CheckoutProblem {
|
|
52
|
-
productId: string;
|
|
53
|
-
variantKey?: string;
|
|
54
|
-
name?: string;
|
|
55
|
-
reason: Unavailable | 'tooMany';
|
|
56
|
-
/** For `tooMany`: how many can be ordered. Left out when the shop hides what is left. */
|
|
57
|
-
maxQuantity?: number;
|
|
58
|
-
}
|
|
59
|
-
/** A cart line with everything a cart page shows for it. */
|
|
60
|
-
interface CartRow {
|
|
61
|
-
line: CartLine;
|
|
62
|
-
product: CartProduct | undefined;
|
|
63
|
-
status: LineStatus;
|
|
64
|
-
name: string;
|
|
65
|
-
/** The line's quantity, capped at what can be ordered. 0 when the line can't be bought. */
|
|
66
|
-
quantity: number;
|
|
67
|
-
/** Price times quantity, in currency units. 0 when the line can't be bought. */
|
|
68
|
-
total: number;
|
|
69
|
-
}
|
|
70
|
-
/** Joins the cart's lines with their products, as read from Sanity for the cart page. */
|
|
71
|
-
declare function cartRows(lines: readonly CartLine[], products: readonly CartProduct[], max?: number): CartRow[];
|
|
72
|
-
/** What the cart's lines add up to, in currency units, before shipping. */
|
|
73
|
-
declare function cartSubtotal(rows: readonly CartRow[]): number;
|
|
74
|
-
export { CartVariant as a, Unavailable as c, lineKey as d, readCartProducts as f, CartRow as i, cartRows as l, CartLine as n, CheckoutProblem as o, CartProduct as r, LineStatus as s, Availability as t, cartSubtotal as u };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"countries-BuqQF1AW.js","names":[],"sources":["../src/core/ids.ts","../src/core/stock.ts","../src/core/countries.ts"],"sourcesContent":["/** Schema type names. They are saved in content, so they never change. */\nexport const COMMERCE_TYPE = 'stripeCommerce'\nexport const VARIANT_TYPE = 'stripeVariant'\nexport const SHIPPING_REGION_TYPE = 'stripeShippingRegion'\nexport const SHOP_SETTINGS_TYPE = 'stripeShopSettings'\n\n/**\n * The one shop settings document, named after its type. Its id has no dot, so the site reads it\n * without a token: it holds what the cart shows anyway.\n */\nexport const SHOP_SETTINGS_ID = 'stripeShopSettings'\n\n/**\n * A product's stock counts. They are kept out of the product document, which anyone can read\n * from a public dataset: a dot in an id means Sanity serves the document to members and tokens\n * only.\n */\nexport const STOCK_TYPE = 'stripe.stock'\n\nexport function stockId(productId: string): string {\n return `stripe.stock.${productId}`\n}\n\n/**\n * What one paid Checkout Session did to stock, written in the same transaction as the change, so\n * the same payment never lowers stock twice. It holds product ids and counts, nothing about the\n * buyer, and is deleted after a month.\n */\nexport const STOCK_CHANGE_TYPE = 'stripe.stockChange'\n\nexport function stockChangeId(sessionId: string): string {\n return `stripe.stockChange.${sessionId.replaceAll(/[^\\w-]/g, '-')}`\n}\n\n/** The id a product is published under, whichever version of it a form is editing. */\nexport function publishedId(documentId: string): string {\n if (documentId.startsWith('drafts.')) return documentId.slice('drafts.'.length)\n if (documentId.startsWith('versions.')) return documentId.split('.').slice(2).join('.')\n return documentId\n}\n","import {asArray, asNumber, isObject} from './guards'\nimport {STOCK_TYPE, stockId} from './ids'\n\n/** A product's stock, as its private stock document holds it. */\nexport interface ProductStock {\n /** For a product without variants. Null when it isn't counted. */\n stockCount: number | null\n /** One entry per counted variant, under the variant's `_key`. */\n variants: Array<{_key: string; stockCount: number | null}>\n}\n\n/** The stock documents with the ids in `$ids`. Only a client with a token gets an answer. */\nexport const STOCK_QUERY = `*[_type == \"${STOCK_TYPE}\" && _id in $ids]{_id, stockCount, variants[]{_key, stockCount}}`\n\n/** Stock documents as Sanity returned them, by product id. */\nexport function readStockDocuments(value: unknown): Map<string, ProductStock> {\n const prefix = stockId('')\n const stock = new Map<string, ProductStock>()\n for (const item of asArray(value)) {\n if (!isObject(item) || typeof item._id !== 'string' || !item._id.startsWith(prefix)) continue\n stock.set(item._id.slice(prefix.length), {\n stockCount: asNumber(item.stockCount),\n variants: asArray(item.variants).flatMap((variant) =>\n isObject(variant) && typeof variant._key === 'string'\n ? [{_key: variant._key, stockCount: asNumber(variant.stockCount)}]\n : [],\n ),\n })\n }\n return stock\n}\n\n/** How many are left of a product or one of its variants. Null when it isn't counted. */\nexport function stockLeft(stock: ProductStock | undefined, variantKey?: string): number | null {\n if (!stock) return null\n if (!variantKey) return stock.stockCount\n return stock.variants.find((variant) => variant._key === variantKey)?.stockCount ?? null\n}\n","/**\n * Every country Stripe Checkout accepts in `shipping_address_collection.allowed_countries`\n * (stripe-node 23, API version 2026-10-28.endive). A region set to \"everywhere else\" ships to\n * these, minus the countries the other regions list.\n */\nexport const STRIPE_SHIPPING_COUNTRIES = [\n 'AC',\n 'AD',\n 'AE',\n 'AF',\n 'AG',\n 'AI',\n 'AL',\n 'AM',\n 'AO',\n 'AQ',\n 'AR',\n 'AT',\n 'AU',\n 'AW',\n 'AX',\n 'AZ',\n 'BA',\n 'BB',\n 'BD',\n 'BE',\n 'BF',\n 'BG',\n 'BH',\n 'BI',\n 'BJ',\n 'BL',\n 'BM',\n 'BN',\n 'BO',\n 'BQ',\n 'BR',\n 'BS',\n 'BT',\n 'BV',\n 'BW',\n 'BY',\n 'BZ',\n 'CA',\n 'CD',\n 'CF',\n 'CG',\n 'CH',\n 'CI',\n 'CK',\n 'CL',\n 'CM',\n 'CN',\n 'CO',\n 'CR',\n 'CV',\n 'CW',\n 'CY',\n 'CZ',\n 'DE',\n 'DJ',\n 'DK',\n 'DM',\n 'DO',\n 'DZ',\n 'EC',\n 'EE',\n 'EG',\n 'EH',\n 'ER',\n 'ES',\n 'ET',\n 'FI',\n 'FJ',\n 'FK',\n 'FO',\n 'FR',\n 'GA',\n 'GB',\n 'GD',\n 'GE',\n 'GF',\n 'GG',\n 'GH',\n 'GI',\n 'GL',\n 'GM',\n 'GN',\n 'GP',\n 'GQ',\n 'GR',\n 'GS',\n 'GT',\n 'GU',\n 'GW',\n 'GY',\n 'HK',\n 'HN',\n 'HR',\n 'HT',\n 'HU',\n 'ID',\n 'IE',\n 'IL',\n 'IM',\n 'IN',\n 'IO',\n 'IQ',\n 'IS',\n 'IT',\n 'JE',\n 'JM',\n 'JO',\n 'JP',\n 'KE',\n 'KG',\n 'KH',\n 'KI',\n 'KM',\n 'KN',\n 'KR',\n 'KW',\n 'KY',\n 'KZ',\n 'LA',\n 'LB',\n 'LC',\n 'LI',\n 'LK',\n 'LR',\n 'LS',\n 'LT',\n 'LU',\n 'LV',\n 'LY',\n 'MA',\n 'MC',\n 'MD',\n 'ME',\n 'MF',\n 'MG',\n 'MK',\n 'ML',\n 'MM',\n 'MN',\n 'MO',\n 'MQ',\n 'MR',\n 'MS',\n 'MT',\n 'MU',\n 'MV',\n 'MW',\n 'MX',\n 'MY',\n 'MZ',\n 'NA',\n 'NC',\n 'NE',\n 'NG',\n 'NI',\n 'NL',\n 'NO',\n 'NP',\n 'NR',\n 'NU',\n 'NZ',\n 'OM',\n 'PA',\n 'PE',\n 'PF',\n 'PG',\n 'PH',\n 'PK',\n 'PL',\n 'PM',\n 'PN',\n 'PR',\n 'PS',\n 'PT',\n 'PY',\n 'QA',\n 'RE',\n 'RO',\n 'RS',\n 'RU',\n 'RW',\n 'SA',\n 'SB',\n 'SC',\n 'SD',\n 'SE',\n 'SG',\n 'SH',\n 'SI',\n 'SJ',\n 'SK',\n 'SL',\n 'SM',\n 'SN',\n 'SO',\n 'SR',\n 'SS',\n 'ST',\n 'SV',\n 'SX',\n 'SZ',\n 'TA',\n 'TC',\n 'TD',\n 'TF',\n 'TG',\n 'TH',\n 'TJ',\n 'TK',\n 'TL',\n 'TM',\n 'TN',\n 'TO',\n 'TR',\n 'TT',\n 'TV',\n 'TW',\n 'TZ',\n 'UA',\n 'UG',\n 'US',\n 'UY',\n 'UZ',\n 'VA',\n 'VC',\n 'VE',\n 'VG',\n 'VN',\n 'VU',\n 'WF',\n 'WS',\n 'XK',\n 'YE',\n 'YT',\n 'ZA',\n 'ZM',\n 'ZW',\n] as const\n\n/** The European Union's member states, for a shipping region: `countries: [...EU_COUNTRIES]`. */\nexport const EU_COUNTRIES = [\n 'AT',\n 'BE',\n 'BG',\n 'CY',\n 'CZ',\n 'DE',\n 'DK',\n 'EE',\n 'ES',\n 'FI',\n 'FR',\n 'GR',\n 'HR',\n 'HU',\n 'IE',\n 'IT',\n 'LT',\n 'LU',\n 'LV',\n 'MT',\n 'NL',\n 'PL',\n 'PT',\n 'RO',\n 'SE',\n 'SI',\n 'SK',\n] as const\n"],"mappings":";;AACA,MAAa,gBAAgB,kBAChB,eAAe,iBACf,uBAAuB,wBACvB,qBAAqB,sBAMrB,mBAAmB,sBAOnB,aAAa;AAE1B,SAAgB,QAAQ,WAA2B;CACjD,OAAO,gBAAgB;AACzB;;;;;;AAOA,MAAa,oBAAoB;AAEjC,SAAgB,cAAc,WAA2B;CACvD,OAAO,sBAAsB,UAAU,WAAW,WAAW,GAAG;AAClE;;AAGA,SAAgB,YAAY,YAA4B;CAGtD,OAFI,WAAW,WAAW,SAAS,IAAU,WAAW,MAAM,CAAgB,IAC1E,WAAW,WAAW,WAAW,IAAU,WAAW,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,GAAG,IAC/E;AACT;;AC3BA,MAAa,cAAc,eAAe,WAAW;;AAGrD,SAAgB,mBAAmB,OAA2C;CAC5E,IAAM,SAAS,QAAQ,EAAE,GACnB,wBAAQ,IAAI,IAA0B;CAC5C,KAAK,IAAM,QAAQ,QAAQ,KAAK,GAC9B,AAAK,SAAS,IAAI,KAAK,OAAO,KAAK,OAAQ,YAAa,KAAK,IAAI,WAAW,MAAM,KAClF,MAAM,IAAI,KAAK,IAAI,MAAM,OAAO,MAAM,GAAG;EACvC,YAAY,SAAS,KAAK,UAAU;EACpC,UAAU,QAAQ,KAAK,QAAQ,CAAC,CAAC,SAAS,YACxC,SAAS,OAAO,KAAK,OAAO,QAAQ,QAAS,WACzC,CAAC;GAAC,MAAM,QAAQ;GAAM,YAAY,SAAS,QAAQ,UAAU;EAAC,CAAC,IAC/D,CAAC,CACP;CACF,CAAC;CAEH,OAAO;AACT;;AAGA,SAAgB,UAAU,OAAiC,YAAoC;CAG7F,OAFK,QACA,aACE,MAAM,SAAS,MAAM,YAAY,QAAQ,SAAS,UAAU,CAAC,EAAE,cAAc,OAD5D,MAAM,aADX;AAGrB;;;;;;AChCA,MAAa,4BAA4B,kuBA8OzC,GAGa,eAAe,4GA4B5B"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"guards-CAcETsf7.js","names":[],"sources":["../src/core/money.ts","../src/core/guards.ts"],"sourcesContent":["/**\n * Prices are entered in the Studio in currency units (25 means €25) and sent to Stripe in the\n * currency's minor unit (2500). Which is which follows https://docs.stripe.com/currencies.\n */\n\nconst ZERO_DECIMAL = new Set([\n 'bif',\n 'clp',\n 'djf',\n 'gnf',\n 'jpy',\n 'kmf',\n 'krw',\n 'mga',\n 'pyg',\n 'rwf',\n 'vnd',\n 'vuv',\n 'xaf',\n 'xof',\n 'xpf',\n])\n\nconst THREE_DECIMAL = new Set(['bhd', 'jod', 'kwd', 'omr', 'tnd'])\n\n/** Whole amounts only, which Stripe still takes as if they had two decimals: 5 ISK is `500`. */\nconst WHOLE_AS_TWO_DECIMAL = new Set(['isk', 'ugx'])\n\n/** How many decimals Stripe's amounts carry: `1099` is 10.99 USD, `10` is 10 JPY. */\nexport function minorUnitDigits(currency: string): 0 | 2 | 3 {\n const code = currency.toLowerCase()\n if (ZERO_DECIMAL.has(code)) return 0\n if (THREE_DECIMAL.has(code)) return 3\n return 2\n}\n\n/** How many decimals a price in this currency can have: 0 for yen, 2 for euros. */\nexport function priceDecimals(currency: string): 0 | 2 {\n const code = currency.toLowerCase()\n return ZERO_DECIMAL.has(code) || WHOLE_AS_TWO_DECIMAL.has(code) ? 0 : 2\n}\n\n/** Converts a price entered in the Studio (25, 29.5) into the amount Stripe expects. */\nexport function toMinorUnits(amount: number, currency: string): number {\n const code = currency.toLowerCase()\n if (WHOLE_AS_TWO_DECIMAL.has(code)) return Math.round(amount) * 100\n const digits = minorUnitDigits(code)\n const minor = Math.round(amount * 10 ** digits)\n // Stripe refuses three-decimal amounts that don't end in 0.\n return digits === 3 ? Math.round(minor / 10) * 10 : minor\n}\n\n/** The other way: Stripe's amount back into currency units. */\nexport function fromMinorUnits(minor: number, currency: string): number {\n return minor / 10 ** minorUnitDigits(currency)\n}\n\n/** Formats one of Stripe's amounts, such as `2500` and `eur`, for people: \"€25.00\". */\nexport function formatMoney(minor: number, currency: string, locale = 'en'): string {\n return new Intl.NumberFormat(locale, {\n style: 'currency',\n currency: currency.toUpperCase(),\n }).format(fromMinorUnits(minor, currency))\n}\n\n/** Formats a price as entered in the Studio. */\nexport function formatPrice(amount: number, currency: string, locale = 'en'): string {\n return new Intl.NumberFormat(locale, {\n style: 'currency',\n currency: currency.toUpperCase(),\n }).format(amount)\n}\n","/** For reading what arrives as `unknown`: a request body, stored JSON, a reply from Sanity. */\nexport const isObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\nexport const asArray = (value: unknown): unknown[] => (Array.isArray(value) ? value : [])\n\nexport const asString = (value: unknown): string | null =>\n typeof value === 'string' ? value : null\n\nexport const asNumber = (value: unknown): number | null =>\n typeof value === 'number' && Number.isFinite(value) ? value : null\n"],"mappings":";;;;AAKA,MAAM,+BAAe,IAAI,IAAI;CAC3B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC,GAEK,gCAAgB,IAAI,IAAI;CAAC;CAAO;CAAO;CAAO;CAAO;AAAK,CAAC,GAG3D,uCAAuB,IAAI,IAAI,CAAC,OAAO,KAAK,CAAC;;AAGnD,SAAgB,gBAAgB,UAA6B;CAC3D,IAAM,OAAO,SAAS,YAAY;CAGlC,OAFI,aAAa,IAAI,IAAI,IAAU,IAC/B,cAAc,IAAI,IAAI,IAAU,IAC7B;AACT;;AAGA,SAAgB,cAAc,UAAyB;CACrD,IAAM,OAAO,SAAS,YAAY;CAClC,OAAO,aAAa,IAAI,IAAI,KAAK,qBAAqB,IAAI,IAAI,IAAI,IAAI;AACxE;;AAGA,SAAgB,aAAa,QAAgB,UAA0B;CACrE,IAAM,OAAO,SAAS,YAAY;CAClC,IAAI,qBAAqB,IAAI,IAAI,GAAG,OAAO,KAAK,MAAM,MAAM,IAAI;CAChE,IAAM,SAAS,gBAAgB,IAAI,GAC7B,QAAQ,KAAK,MAAM,SAAS,MAAM,MAAM;CAE9C,OAAO,WAAW,IAAI,KAAK,MAAM,QAAQ,EAAE,IAAI,KAAK;AACtD;;AAGA,SAAgB,eAAe,OAAe,UAA0B;CACtE,OAAO,QAAQ,MAAM,gBAAgB,QAAQ;AAC/C;;AAGA,SAAgB,YAAY,OAAe,UAAkB,SAAS,MAAc;CAClF,OAAO,IAAI,KAAK,aAAa,QAAQ;EACnC,OAAO;EACP,UAAU,SAAS,YAAY;CACjC,CAAC,CAAC,CAAC,OAAO,eAAe,OAAO,QAAQ,CAAC;AAC3C;;AAGA,SAAgB,YAAY,QAAgB,UAAkB,SAAS,MAAc;CACnF,OAAO,IAAI,KAAK,aAAa,QAAQ;EACnC,OAAO;EACP,UAAU,SAAS,YAAY;CACjC,CAAC,CAAC,CAAC,OAAO,MAAM;AAClB;;ACtEA,MAAa,YAAY,UACvB,OAAO,SAAU,cAAY,SAAkB,CAAC,MAAM,QAAQ,KAAK,GAExD,WAAW,UAA+B,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,GAE1E,YAAY,UACvB,OAAO,SAAU,WAAW,QAAQ,MAEzB,YAAY,UACvB,OAAO,SAAU,YAAY,OAAO,SAAS,KAAK,IAAI,QAAQ"}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
/** Formats one of Stripe's amounts, such as `2500` and `eur`, for people: "€25.00". */
|
|
2
|
-
declare function formatMoney(minor: number, currency: string, locale?: string): string;
|
|
3
|
-
/** Formats a price as entered in the Studio. */
|
|
4
|
-
declare function formatPrice(amount: number, currency: string, locale?: string): string;
|
|
5
|
-
/** A shipping region with one flat rate per order. */
|
|
6
|
-
interface ShippingRegion {
|
|
7
|
-
id: string;
|
|
8
|
-
title: string;
|
|
9
|
-
/** ISO 3166-1 alpha-2 codes. Empty for the "everywhere else" region until resolved. */
|
|
10
|
-
countries: string[];
|
|
11
|
-
everywhereElse: boolean;
|
|
12
|
-
/** In currency units. */
|
|
13
|
-
rate: number;
|
|
14
|
-
}
|
|
15
|
-
/** The shop settings document, as `SHOP_SETTINGS_QUERY` returns it. */
|
|
16
|
-
interface ShopSettings {
|
|
17
|
-
shippingRegions?: Array<{
|
|
18
|
-
_key: string;
|
|
19
|
-
title?: string | null;
|
|
20
|
-
everywhereElse?: boolean | null;
|
|
21
|
-
countries?: string[] | null;
|
|
22
|
-
rate?: number | null;
|
|
23
|
-
}> | null;
|
|
24
|
-
autoSoldOut?: boolean | null;
|
|
25
|
-
}
|
|
26
|
-
/** The shop settings as Sanity returned them, or null when they aren't published yet. */
|
|
27
|
-
declare function readShopSettings(value: unknown): ShopSettings | null;
|
|
28
|
-
/** What a cart page needs of each region: no country lists. */
|
|
29
|
-
type RegionOption = Pick<ShippingRegion, 'id' | 'title' | 'rate'>;
|
|
30
|
-
/** The regions a buyer can choose from, the same ones the checkout accepts. */
|
|
31
|
-
declare function regionOptions(settings: ShopSettings | null | undefined): RegionOption[];
|
|
32
|
-
export { regionOptions as a, readShopSettings as i, ShippingRegion as n, formatMoney as o, ShopSettings as r, formatPrice as s, RegionOption as t };
|