@zappie/kit 0.1.6 → 0.1.8
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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @zappie/kit
|
|
2
2
|
|
|
3
|
+
## 0.1.8
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 86f1426: Checkout opens through `redirectToCheckout`, which refuses any URL that isn't Zappie's checkout.
|
|
8
|
+
|
|
9
|
+
## 0.1.7
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 9b25eb7: The packages now live in zappie/storefront-packages, and each package's repository, homepage and issues links point there. This release is the first one published from that repository.
|
|
14
|
+
|
|
3
15
|
## 0.1.6
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"$schema":"https://registry.zappie.ai/v1/schema/item.json","name":"checkout-button","type":"component","version":"1.1.0","title":"Checkout button","description":"Open checkout with quote checks, safe retries and visit attribution.","requires":{"@zappie/sdk":"^0.1.0","@zappie/tokens":"^0.1.0"},"dependencies":{},"registryDependencies":[],"files":[{"path":"checkout-button.tsx","target":"components/zappie/checkout-button.tsx","sha256":"f19d6bfa715f2c325ce779c657726d9b814409cccd66e1c3f5d4da79f865ff09","content":"\"use client\";\n\nimport type { CartModule } from \"@zappie/sdk\";\nimport type { CheckoutClient } from \"@zappie/sdk/checkout\";\nimport { CheckoutError, isContactPhoneValid } from \"@zappie/sdk/checkout\";\nimport { useCart } from \"@zappie/sdk/react\";\nimport { currentSource } from \"@zappie/sdk/visits\";\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { createCheckoutAttempt } from \"./checkout-attempt\";\nimport \"./checkout-button.css\";\nimport { checkoutButtonState } from \"./checkout-state\";\n\nexport type CheckoutButtonProps = {\n checkout: CheckoutClient;\n branchId: string;\n returnUrl?: string;\n cancelUrl?: string;\n contactPhone?: string;\n /** The rider's note for a delivery. It goes with payment and never asks for a new quote. */\n instructions?: string;\n attribution?: () => { source: string; campaign: string };\n onSignIn?: () => void;\n /** Show a recoverable error when opening payment fails. */\n onError?: (failure: unknown) => void;\n onContactPhoneRequired?: () => void;\n redirect?: (url: string) => void;\n};\n\ntype Payload = ReturnType<CartModule[\"toCheckoutPayload\"]>;\n\nfunction withInstructions(payload: Payload, note: string | undefined) {\n const f = payload.fulfilment;\n if (note === undefined || f.type !== \"delivery\") {\n return payload;\n }\n const { instructions: _old, ...address } = f.address;\n const value = note.trim();\n return {\n ...payload,\n fulfilment: {\n ...f,\n address: value ? { ...address, instructions: value } : address,\n },\n };\n}\n\nexport function CheckoutButton({\n checkout,\n branchId,\n returnUrl,\n cancelUrl,\n contactPhone = \"\",\n instructions,\n attribution = currentSource,\n onSignIn,\n onError,\n onContactPhoneRequired,\n redirect = (url) => window.top?.location.assign(url),\n}: CheckoutButtonProps) {\n const cart = useCart();\n const attempt = useMemo(() => createCheckoutAttempt(), []);\n const [busy, setBusy] = useState(false);\n const quoted = useRef(\"\");\n const quoteKey = JSON.stringify([\n cart.lines,\n cart.fulfilment,\n cart.promoCode,\n ]);\n const [forced, setForced] = useState<\"sign_in\" | undefined>();\n useEffect(() => {\n if (\n cart.isHydrated &&\n cart.lines.length > 0 &&\n cart.state.status === \"ready\" &&\n quoted.current !== quoteKey\n ) {\n quoted.current = quoteKey;\n void cart.actions.quote().catch((failure: unknown) => onError?.(failure));\n }\n }, [\n cart.actions,\n cart.isHydrated,\n cart.lines.length,\n cart.state.status,\n quoteKey,\n onError,\n ]);\n const state = checkoutButtonState(\n cart.state,\n cart.fulfilment,\n isContactPhoneValid(contactPhone),\n busy,\n forced,\n );\n const activate = async () => {\n if (state.status === \"sign_in\") {\n onSignIn?.();\n return;\n }\n if (state.status === \"phone\") {\n onContactPhoneRequired?.();\n return;\n }\n if (state.status === \"retry\") {\n try {\n await cart.actions.quote({ force: true });\n } catch (failure) {\n onError?.(failure);\n }\n return;\n }\n if (state.status !== \"pay\") {\n return;\n }\n setBusy(true);\n try {\n const checkoutAttempt = attempt({\n payload: withInstructions(\n cart.actions.toCheckoutPayload(),\n instructions,\n ),\n branchId,\n contactPhone,\n returnUrl: returnUrl ?? `${location.origin}/checkout/return`,\n ...((cancelUrl ?? location.href)\n ? { cancelUrl: cancelUrl ?? location.href }\n : {}),\n attribution: attribution(),\n });\n const session = await checkout.open(\n checkoutAttempt.request,\n checkoutAttempt.key,\n );\n redirect(session.url);\n } catch (failure) {\n if (\n failure instanceof CheckoutError &&\n failure.apiCode === \"customer_required\"\n ) {\n setForced(\"sign_in\");\n onSignIn?.();\n return;\n }\n if (onError) {\n onError(failure);\n return;\n }\n throw failure;\n } finally {\n setBusy(false);\n }\n };\n return (\n <button\n type=\"button\"\n className=\"z-kit-checkout-button\"\n data-state={state.status}\n data-zappie-checkout=\"\"\n disabled={!state.enabled}\n onClick={() => void activate()}\n >\n {state.label}\n </button>\n );\n}\n"},{"path":"checkout-attempt.ts","target":"components/zappie/checkout-attempt.ts","sha256":"cefb578068eac7d86f343d2ae5f7f9e2feda13bced3f05b365b78a71252d1bca","content":"import type { CartModule } from \"@zappie/sdk\";\nimport { checkoutFulfilment, type CheckoutRequest } from \"@zappie/sdk/checkout\";\n\ntype Payload = ReturnType<CartModule[\"toCheckoutPayload\"]>;\ntype Attribution = { source: string; campaign: string };\nexport type CheckoutAttempt = { key: string; request: CheckoutRequest };\n\nfunction fulfilment(payload: Payload) {\n const value = checkoutFulfilment(payload.fulfilment);\n if (value.type === \"pickup\") {\n return {\n type: \"pickup\" as const,\n ...(value.scheduled_for !== undefined\n ? { scheduled_for: value.scheduled_for }\n : {}),\n };\n }\n if (value.type === \"delivery\") {\n return {\n type: \"delivery\" as const,\n ...(value.address !== undefined ? { address: value.address } : {}),\n ...(value.delivery_region_id !== undefined\n ? { delivery_region_id: value.delivery_region_id }\n : {}),\n ...(value.instructions !== undefined\n ? { instructions: value.instructions }\n : {}),\n ...(value.scheduled_for !== undefined\n ? { scheduled_for: value.scheduled_for }\n : {}),\n };\n }\n throw new Error(\"Dine-in checkout is unavailable\");\n}\n\nexport function createCheckoutAttempt() {\n let current: { digest: string; attempt: CheckoutAttempt } | undefined;\n return ({\n payload,\n branchId,\n contactPhone,\n returnUrl,\n cancelUrl,\n attribution,\n }: {\n payload: Payload;\n branchId: string;\n contactPhone: string;\n returnUrl: string;\n cancelUrl?: string;\n attribution: Attribution;\n }) => {\n const normalizedPhone = contactPhone.trim().replace(/\\s+/g, \"\");\n const digest = JSON.stringify({ payload, contactPhone: normalizedPhone });\n if (current?.digest === digest) {\n return current.attempt;\n }\n const request: CheckoutRequest = {\n branch_id: branchId,\n menu_version: payload.menu_version,\n lines: payload.lines,\n fulfilment: fulfilment(payload),\n ...(normalizedPhone ? { contact_phone: normalizedPhone } : {}),\n ...(payload.promo_code ? { promo_code: payload.promo_code } : {}),\n ...(attribution.source ? { source: attribution.source } : {}),\n ...(attribution.campaign ? { campaign: attribution.campaign } : {}),\n return_url: returnUrl,\n ...(cancelUrl ? { cancel_url: cancelUrl } : {}),\n };\n current = { digest, attempt: { key: crypto.randomUUID(), request } };\n return current.attempt;\n };\n}\n"},{"path":"checkout-state.ts","target":"components/zappie/checkout-state.ts","sha256":"e8e2dc8f88d513c124d44516e3d18012d4fd7e2c069e31454d4426dd6c2d4e43","content":"import type { CartFulfilment, CartState } from \"@zappie/sdk\";\nimport {\n payReadiness,\n type PayReadiness,\n type PayReadinessQuoteState,\n} from \"@zappie/sdk/checkout\";\n\nexport type CheckoutButtonStatus = PayReadiness | \"busy\";\nconst labels: Record<CheckoutButtonStatus, string> = {\n address: \"Add a delivery address\",\n quoting: \"Updating total…\",\n retry: \"Update totals to continue\",\n choose_area: \"Choose a delivery area\",\n fix_issues: \"Review your cart\",\n sign_in: \"Sign in to continue\",\n phone: \"Check your phone number\",\n pay: \"Continue to payment\",\n busy: \"Please wait…\",\n};\n\nfunction quoteState(state: CartState): PayReadinessQuoteState {\n if (state.status === \"quoting\") {\n return { status: \"loading\" };\n }\n if (state.status === \"quoted\") {\n return { status: \"ready\", quote: state.quote };\n }\n if (state.status === \"needs_attention\") {\n return state.quote\n ? { status: \"ready\", quote: state.quote }\n : { status: \"error\" };\n }\n return { status: \"idle\" };\n}\n\nexport function checkoutButtonState(\n state: CartState,\n fulfilment: CartFulfilment | null,\n contactPhoneValid: boolean,\n busy: boolean,\n forced?: \"sign_in\",\n) {\n let status: CheckoutButtonStatus;\n if (busy) {\n status = \"busy\";\n } else if (forced) {\n status = forced;\n } else {\n const addressValid =\n fulfilment?.type !== \"delivery\" ||\n Boolean(\n fulfilment.address.line1 ||\n fulfilment.address.placeId ||\n fulfilment.address.coordinates,\n );\n status = payReadiness(quoteState(state), contactPhoneValid, addressValid);\n if (status === \"pay\" && state.status === \"needs_attention\") {\n status = \"fix_issues\";\n }\n }\n return {\n status,\n label: labels[status],\n enabled:\n status === \"pay\" ||\n status === \"sign_in\" ||\n status === \"phone\" ||\n status === \"retry\",\n };\n}\n"},{"path":"checkout-button.css","target":"components/zappie/checkout-button.css","sha256":"9e6bb8afe1bb1e5cd55ed458e435d90b4b3d546fb4276d3fd9432d022844ca22","content":".z-kit-checkout-button {\n width: 100%;\n border: 0;\n border-radius: var(--z-radius-md);\n padding: var(--z-space-3) var(--z-space-5);\n background: var(--z-accent);\n color: var(--z-accent-contrast);\n font-family: var(--z-font-body);\n font-size: var(--z-text-md);\n cursor: pointer;\n}\n\n.z-kit-checkout-button:disabled {\n background: var(--z-border);\n color: var(--z-text-muted);\n cursor: not-allowed;\n}\n\n.z-kit-checkout-button:focus-visible {\n outline: 2px solid var(--z-focus-ring);\n outline-offset: 2px;\n}\n"}],"tokens":["--z-space-3","--z-space-5","--z-border","--z-radius-md","--z-accent","--z-accent-contrast","--z-text-muted","--z-focus-ring","--z-font-body","--z-text-md"],"frameworks":["react-router","next","vite","astro-react"],"docs":"https://docs.zappie.ai/kit/checkout-button"}
|
|
1
|
+
{"$schema":"https://registry.zappie.ai/v1/schema/item.json","name":"checkout-button","type":"component","version":"1.1.0","title":"Checkout button","description":"Open checkout with quote checks, safe retries and visit attribution.","requires":{"@zappie/sdk":"^0.1.0","@zappie/tokens":"^0.1.0"},"dependencies":{},"registryDependencies":[],"files":[{"path":"checkout-button.tsx","target":"components/zappie/checkout-button.tsx","sha256":"779ae1c956b15a9527f45c16422341f157bc33d7f1c5f17733fd20de4c919697","content":"\"use client\";\n\nimport type { CartModule } from \"@zappie/sdk\";\nimport type { CheckoutClient } from \"@zappie/sdk/checkout\";\nimport { CheckoutError, isContactPhoneValid } from \"@zappie/sdk/checkout\";\nimport { useCart } from \"@zappie/sdk/react\";\nimport { redirectToCheckout } from \"@zappie/sdk/redirect\";\nimport { currentSource } from \"@zappie/sdk/visits\";\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { createCheckoutAttempt } from \"./checkout-attempt\";\nimport \"./checkout-button.css\";\nimport { checkoutButtonState } from \"./checkout-state\";\n\nexport type CheckoutButtonProps = {\n checkout: CheckoutClient;\n branchId: string;\n returnUrl?: string;\n cancelUrl?: string;\n contactPhone?: string;\n /** The rider's note for a delivery. It goes with payment and never asks for a new quote. */\n instructions?: string;\n attribution?: () => { source: string; campaign: string };\n onSignIn?: () => void;\n /** Show a recoverable error when opening payment fails. */\n onError?: (failure: unknown) => void;\n onContactPhoneRequired?: () => void;\n redirect?: (url: string) => void;\n};\n\ntype Payload = ReturnType<CartModule[\"toCheckoutPayload\"]>;\n\nfunction withInstructions(payload: Payload, note: string | undefined) {\n const f = payload.fulfilment;\n if (note === undefined || f.type !== \"delivery\") {\n return payload;\n }\n const { instructions: _old, ...address } = f.address;\n const value = note.trim();\n return {\n ...payload,\n fulfilment: {\n ...f,\n address: value ? { ...address, instructions: value } : address,\n },\n };\n}\n\nexport function CheckoutButton({\n checkout,\n branchId,\n returnUrl,\n cancelUrl,\n contactPhone = \"\",\n instructions,\n attribution = currentSource,\n onSignIn,\n onError,\n onContactPhoneRequired,\n redirect = (url) => redirectToCheckout(url, window.top ?? window),\n}: CheckoutButtonProps) {\n const cart = useCart();\n const attempt = useMemo(() => createCheckoutAttempt(), []);\n const [busy, setBusy] = useState(false);\n const quoted = useRef(\"\");\n const quoteKey = JSON.stringify([\n cart.lines,\n cart.fulfilment,\n cart.promoCode,\n ]);\n const [forced, setForced] = useState<\"sign_in\" | undefined>();\n useEffect(() => {\n if (\n cart.isHydrated &&\n cart.lines.length > 0 &&\n cart.state.status === \"ready\" &&\n quoted.current !== quoteKey\n ) {\n quoted.current = quoteKey;\n void cart.actions.quote().catch((failure: unknown) => onError?.(failure));\n }\n }, [\n cart.actions,\n cart.isHydrated,\n cart.lines.length,\n cart.state.status,\n quoteKey,\n onError,\n ]);\n const state = checkoutButtonState(\n cart.state,\n cart.fulfilment,\n isContactPhoneValid(contactPhone),\n busy,\n forced,\n );\n const activate = async () => {\n if (state.status === \"sign_in\") {\n onSignIn?.();\n return;\n }\n if (state.status === \"phone\") {\n onContactPhoneRequired?.();\n return;\n }\n if (state.status === \"retry\") {\n try {\n await cart.actions.quote({ force: true });\n } catch (failure) {\n onError?.(failure);\n }\n return;\n }\n if (state.status !== \"pay\") {\n return;\n }\n setBusy(true);\n try {\n const checkoutAttempt = attempt({\n payload: withInstructions(\n cart.actions.toCheckoutPayload(),\n instructions,\n ),\n branchId,\n contactPhone,\n returnUrl: returnUrl ?? `${location.origin}/checkout/return`,\n ...((cancelUrl ?? location.href)\n ? { cancelUrl: cancelUrl ?? location.href }\n : {}),\n attribution: attribution(),\n });\n const session = await checkout.open(\n checkoutAttempt.request,\n checkoutAttempt.key,\n );\n redirect(session.url);\n } catch (failure) {\n if (\n failure instanceof CheckoutError &&\n failure.apiCode === \"customer_required\"\n ) {\n setForced(\"sign_in\");\n onSignIn?.();\n return;\n }\n if (onError) {\n onError(failure);\n return;\n }\n throw failure;\n } finally {\n setBusy(false);\n }\n };\n return (\n <button\n type=\"button\"\n className=\"z-kit-checkout-button\"\n data-state={state.status}\n data-zappie-checkout=\"\"\n disabled={!state.enabled}\n onClick={() => void activate()}\n >\n {state.label}\n </button>\n );\n}\n"},{"path":"checkout-attempt.ts","target":"components/zappie/checkout-attempt.ts","sha256":"cefb578068eac7d86f343d2ae5f7f9e2feda13bced3f05b365b78a71252d1bca","content":"import type { CartModule } from \"@zappie/sdk\";\nimport { checkoutFulfilment, type CheckoutRequest } from \"@zappie/sdk/checkout\";\n\ntype Payload = ReturnType<CartModule[\"toCheckoutPayload\"]>;\ntype Attribution = { source: string; campaign: string };\nexport type CheckoutAttempt = { key: string; request: CheckoutRequest };\n\nfunction fulfilment(payload: Payload) {\n const value = checkoutFulfilment(payload.fulfilment);\n if (value.type === \"pickup\") {\n return {\n type: \"pickup\" as const,\n ...(value.scheduled_for !== undefined\n ? { scheduled_for: value.scheduled_for }\n : {}),\n };\n }\n if (value.type === \"delivery\") {\n return {\n type: \"delivery\" as const,\n ...(value.address !== undefined ? { address: value.address } : {}),\n ...(value.delivery_region_id !== undefined\n ? { delivery_region_id: value.delivery_region_id }\n : {}),\n ...(value.instructions !== undefined\n ? { instructions: value.instructions }\n : {}),\n ...(value.scheduled_for !== undefined\n ? { scheduled_for: value.scheduled_for }\n : {}),\n };\n }\n throw new Error(\"Dine-in checkout is unavailable\");\n}\n\nexport function createCheckoutAttempt() {\n let current: { digest: string; attempt: CheckoutAttempt } | undefined;\n return ({\n payload,\n branchId,\n contactPhone,\n returnUrl,\n cancelUrl,\n attribution,\n }: {\n payload: Payload;\n branchId: string;\n contactPhone: string;\n returnUrl: string;\n cancelUrl?: string;\n attribution: Attribution;\n }) => {\n const normalizedPhone = contactPhone.trim().replace(/\\s+/g, \"\");\n const digest = JSON.stringify({ payload, contactPhone: normalizedPhone });\n if (current?.digest === digest) {\n return current.attempt;\n }\n const request: CheckoutRequest = {\n branch_id: branchId,\n menu_version: payload.menu_version,\n lines: payload.lines,\n fulfilment: fulfilment(payload),\n ...(normalizedPhone ? { contact_phone: normalizedPhone } : {}),\n ...(payload.promo_code ? { promo_code: payload.promo_code } : {}),\n ...(attribution.source ? { source: attribution.source } : {}),\n ...(attribution.campaign ? { campaign: attribution.campaign } : {}),\n return_url: returnUrl,\n ...(cancelUrl ? { cancel_url: cancelUrl } : {}),\n };\n current = { digest, attempt: { key: crypto.randomUUID(), request } };\n return current.attempt;\n };\n}\n"},{"path":"checkout-state.ts","target":"components/zappie/checkout-state.ts","sha256":"e8e2dc8f88d513c124d44516e3d18012d4fd7e2c069e31454d4426dd6c2d4e43","content":"import type { CartFulfilment, CartState } from \"@zappie/sdk\";\nimport {\n payReadiness,\n type PayReadiness,\n type PayReadinessQuoteState,\n} from \"@zappie/sdk/checkout\";\n\nexport type CheckoutButtonStatus = PayReadiness | \"busy\";\nconst labels: Record<CheckoutButtonStatus, string> = {\n address: \"Add a delivery address\",\n quoting: \"Updating total…\",\n retry: \"Update totals to continue\",\n choose_area: \"Choose a delivery area\",\n fix_issues: \"Review your cart\",\n sign_in: \"Sign in to continue\",\n phone: \"Check your phone number\",\n pay: \"Continue to payment\",\n busy: \"Please wait…\",\n};\n\nfunction quoteState(state: CartState): PayReadinessQuoteState {\n if (state.status === \"quoting\") {\n return { status: \"loading\" };\n }\n if (state.status === \"quoted\") {\n return { status: \"ready\", quote: state.quote };\n }\n if (state.status === \"needs_attention\") {\n return state.quote\n ? { status: \"ready\", quote: state.quote }\n : { status: \"error\" };\n }\n return { status: \"idle\" };\n}\n\nexport function checkoutButtonState(\n state: CartState,\n fulfilment: CartFulfilment | null,\n contactPhoneValid: boolean,\n busy: boolean,\n forced?: \"sign_in\",\n) {\n let status: CheckoutButtonStatus;\n if (busy) {\n status = \"busy\";\n } else if (forced) {\n status = forced;\n } else {\n const addressValid =\n fulfilment?.type !== \"delivery\" ||\n Boolean(\n fulfilment.address.line1 ||\n fulfilment.address.placeId ||\n fulfilment.address.coordinates,\n );\n status = payReadiness(quoteState(state), contactPhoneValid, addressValid);\n if (status === \"pay\" && state.status === \"needs_attention\") {\n status = \"fix_issues\";\n }\n }\n return {\n status,\n label: labels[status],\n enabled:\n status === \"pay\" ||\n status === \"sign_in\" ||\n status === \"phone\" ||\n status === \"retry\",\n };\n}\n"},{"path":"checkout-button.css","target":"components/zappie/checkout-button.css","sha256":"9e6bb8afe1bb1e5cd55ed458e435d90b4b3d546fb4276d3fd9432d022844ca22","content":".z-kit-checkout-button {\n width: 100%;\n border: 0;\n border-radius: var(--z-radius-md);\n padding: var(--z-space-3) var(--z-space-5);\n background: var(--z-accent);\n color: var(--z-accent-contrast);\n font-family: var(--z-font-body);\n font-size: var(--z-text-md);\n cursor: pointer;\n}\n\n.z-kit-checkout-button:disabled {\n background: var(--z-border);\n color: var(--z-text-muted);\n cursor: not-allowed;\n}\n\n.z-kit-checkout-button:focus-visible {\n outline: 2px solid var(--z-focus-ring);\n outline-offset: 2px;\n}\n"}],"tokens":["--z-space-3","--z-space-5","--z-border","--z-radius-md","--z-accent","--z-accent-contrast","--z-text-muted","--z-focus-ring","--z-font-body","--z-text-md"],"frameworks":["react-router","next","vite","astro-react"],"docs":"https://docs.zappie.ai/kit/checkout-button"}
|
package/package.json
CHANGED
|
@@ -1,20 +1,33 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zappie/kit",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "The registry of copy-in Zappie storefront components, installed with the zappie CLI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
|
-
"url": "git+https://github.com/zappie/storefront.git",
|
|
8
|
+
"url": "git+https://github.com/zappie/storefront-packages.git",
|
|
9
9
|
"directory": "packages/kit"
|
|
10
10
|
},
|
|
11
11
|
"devDependencies": {
|
|
12
|
-
"
|
|
12
|
+
"@axe-core/playwright": "4.14.0",
|
|
13
|
+
"@playwright/test": "1.64.1",
|
|
14
|
+
"@testing-library/react": "^16.3.3",
|
|
15
|
+
"@types/google.maps": "^3.66.7",
|
|
16
|
+
"@vitejs/plugin-react": "^6.1.2",
|
|
17
|
+
"lucide-react": "^0.546.0",
|
|
18
|
+
"react": "19.3.1",
|
|
19
|
+
"react-dom": "19.3.1",
|
|
20
|
+
"vite": "8.3.5",
|
|
21
|
+
"vitest": "^4.1.12",
|
|
22
|
+
"zod": "^4.6.7",
|
|
23
|
+
"@zappie/sdk": "^0.2.0",
|
|
24
|
+
"@zappie/foundations": "^0.1.12",
|
|
25
|
+
"@zappie/tokens": "^0.1.3"
|
|
13
26
|
},
|
|
14
27
|
"license": "MIT",
|
|
15
|
-
"homepage": "https://github.com/zappie/storefront#readme",
|
|
28
|
+
"homepage": "https://github.com/zappie/storefront-packages#readme",
|
|
16
29
|
"bugs": {
|
|
17
|
-
"url": "https://github.com/zappie/storefront/issues"
|
|
30
|
+
"url": "https://github.com/zappie/storefront-packages/issues"
|
|
18
31
|
},
|
|
19
32
|
"publishConfig": {
|
|
20
33
|
"access": "public",
|