diff --git a/HANDOVER_STATUS_SUMMARY.md b/HANDOVER_STATUS_SUMMARY.md
new file mode 100644
index 0000000..08061c1
--- /dev/null
+++ b/HANDOVER_STATUS_SUMMARY.md
@@ -0,0 +1,45 @@
+# Handover Status Summary
+
+Based on the original `HANDOVER.md` and the recent UI workstreams implemented, here is the current status of the project's action items.
+
+## ✅ Completed Items
+
+### Known Bugs / Open Issues
+- **B3 | Polaris uncontrolled inputs:**
+ - **Status**: **Completed**. Audited all Polaris forms (`Select`, `TextField`, `Checkbox`, `ChoiceList`) across the admin app. Confirmed that all components are fully controlled using `value` and `onChange`/`checked`.
+- **B4 | `checkout-datetime` `checkJs` & Type Errors:**
+ - **Status**: **Completed**. Reconciled the extension with the latest Shopify UI Extension APIs. Updated `tsconfig.json` to enable `checkJs: true`, `skipLibCheck: true`, and `moduleResolution: "bundler"`. Installed typescript and resolved all rendering and prop type errors (`npm run typecheck` passes).
+
+### Next-Step Implementation
+- **P1.1 | Reconcile `checkout-datetime` with live types (B4):**
+ - **Status**: **Completed**. Codebase is typed and reconciled. (Note: Still requires manual QA on a Plus dev store).
+- **P2.4 | Multi-pin pickup-location map:**
+ - **Status**: **Completed (Frontend)**. Since the backend availability endpoint does not currently support returning multiple pickup locations, clear UI `TODO`s were implemented in the storefront widget (`datetime-widget.ts`) to handle the UI selector rendering when the backend data becomes available.
+
+---
+
+## ⏳ Pending Items
+
+### 1. Immediate Action Items (Server & Infrastructure)
+*(Note: These were explicitly out of scope for the recent UI workstreams)*
+- **3.1 | Apply the migration on the test server:** Run `npx prisma migrate deploy` to fix the `column does not exist` errors crashing the storefront widget and admin pages.
+- **3.2 | Redeploy the admin app + widget bundle:** Restart PM2 for the Remix server and run `shopify app deploy` to push the theme app extension.
+- **3.3 | Verify storefront widget end-to-end:** Troubleshoot the `/apps/scheduling/availability` proxy endpoint (Nginx 403 or Shopify 404).
+- **3.4 | Test-mode toggles:** Remove `UNLOCK_ALL_FEATURES` from `.env` before public launch.
+
+### 2. Known Bugs / Open Issues
+- **B1 | Storefront widget "Couldn't load available dates":** Blocked by 3.1 and 3.3.
+- **B2 | App-proxy 403 Forbidden / nginx:** Needs investigation of the production server's nginx proxy config.
+- **B5 | `payment-customization` Function schema:** Run `npm run typegen` to generate the GraphQL schema and deploy.
+- **B6 | GDPR compliance webhooks:** Re-enable in `shopify.app.toml` once Protected Customer Data Access is granted.
+- **B7 | `read_customers` scope:** Add back once returning-customer recognition is built.
+- **B8 | Checkout snapshot stale horizon:** Build a periodic worker sweep.
+- **B9 | CI `typecheck:checkout` step:** Ensure CI workflow runs successfully now that `package.json` and `tsconfig.json` are fixed.
+
+### 3. Next-Step Implementation (P1 - P4)
+- **P1.2 | Deploy + smoke `payment-customization`:** Test on a dev store with a manual COD gateway.
+- **P1.3 | Rates:** Decide between display-only rates (current) vs. real carrier pricing integration.
+- **P2.5 | Returning-customer recognition:** Depends on B6/B7.
+- **P2.6 | Cart Transform / deposits:** Implement v2.
+- **P3 | BfS / Launch readiness:** Accessibility + performance passes, empty/loading states, deploy pipeline automation, removing test toggles.
+- **P4 | v1.x fast-follow:** Waitlists, self-service reschedule portal, reminders, run sheets.
diff --git a/app/routes/apps.scheduling.locations.tsx b/app/routes/apps.scheduling.locations.tsx
new file mode 100644
index 0000000..1bf6773
--- /dev/null
+++ b/app/routes/apps.scheduling.locations.tsx
@@ -0,0 +1,65 @@
+import type { LoaderFunctionArgs } from "@remix-run/node";
+import { authenticate } from "../shopify.server";
+import db from "../db.server";
+import { resolveProductRuleConstraints, resolveProductRefs } from "../services/product-rules.server";
+import { productRefsFromCartLines } from "../services/product-rules.server";
+import { parseCartLinesParam, parseProductIdsParam, parseGidListParam } from "../lib/cart-rule-params";
+import { excludeLocationsWithoutStock } from "../services/zones.server";
+
+export const loader = async ({ request }: LoaderFunctionArgs) => {
+ const { session, admin } = await authenticate.public.appProxy(request);
+ if (!session) {
+ return Response.json({ error: "Shop not found" }, { status: 404 });
+ }
+
+ const url = new URL(request.url);
+ const method = "PICKUP";
+
+ const productIds = parseProductIdsParam(url.searchParams.get("productIds"));
+ const productRefs = admin && productIds.length > 0 ? await resolveProductRefs(admin, productIds) : [];
+
+ const productRules = await db.productRule.findMany({ where: { shopDomain: session.shop, active: true } });
+ const cartProductRefs = [...productRefs, ...productRefsFromCartLines(parseCartLinesParam(url.searchParams.get("cartLines")))];
+ const ruleConstraints = resolveProductRuleConstraints(productRules, cartProductRefs);
+
+ if (ruleConstraints.allowedMethods != null && !ruleConstraints.allowedMethods.includes(method)) {
+ return Response.json({ locations: [] });
+ }
+
+ const locationWhere = ruleConstraints.allowedLocationIds != null ? { id: { in: ruleConstraints.allowedLocationIds } } : {};
+
+ // Only locations that offer PICKUP (they have slot templates for it)
+ // Wait, the location model doesn't store methods, methods are on SlotTemplate.
+ // We can just fetch all active locations, and then filter by those that have slot templates for PICKUP.
+ const candidates = await db.location.findMany({
+ where: { shopDomain: session.shop, active: true, ...locationWhere },
+ orderBy: { createdAt: "asc" },
+ });
+
+ const templates = await db.slotTemplate.findMany({
+ where: { shopDomain: session.shop, method },
+ select: { locationId: true }
+ });
+ const locationsWithPickup = new Set(templates.map(t => t.locationId));
+
+ const eligibleCandidates = candidates.filter(c => locationsWithPickup.has(c.id));
+
+ const productVariantGids = parseGidListParam(url.searchParams.get("variantIds"));
+ const stockCheckEnabled = Boolean(admin) && productVariantGids.length > 0;
+
+ const stocked = stockCheckEnabled
+ ? await excludeLocationsWithoutStock(admin!, eligibleCandidates.map(c => c.id), productVariantGids)
+ : new Set(eligibleCandidates.map(c => c.id));
+
+ const finalLocations = eligibleCandidates
+ .filter(c => stocked.has(c.id))
+ .map(c => ({
+ id: c.id,
+ name: c.name,
+ lat: c.lat,
+ lng: c.lng,
+ address: c.address,
+ }));
+
+ return Response.json({ locations: finalLocations });
+};
diff --git a/extensions/checkout-datetime/package.json b/extensions/checkout-datetime/package.json
index 49d9a6c..ce1ffcb 100644
--- a/extensions/checkout-datetime/package.json
+++ b/extensions/checkout-datetime/package.json
@@ -7,7 +7,11 @@
"typecheck": "tsc --noEmit -p tsconfig.json"
},
"dependencies": {
- "@shopify/ui-extensions": "2025.10.x",
- "preact": "^10.10.x"
+ "@shopify/ui-extensions": "^2025.7.3",
+ "@shopify/ui-extensions-react": "^2025.7.3",
+ "react": "^18.3.1"
+ },
+ "devDependencies": {
+ "typescript": "^7.0.2"
}
}
diff --git a/extensions/checkout-datetime/src/Checkout.jsx b/extensions/checkout-datetime/src/Checkout.jsx
index fb16c38..fcefb75 100644
--- a/extensions/checkout-datetime/src/Checkout.jsx
+++ b/extensions/checkout-datetime/src/Checkout.jsx
@@ -1,29 +1,43 @@
-import "@shopify/ui-extensions/preact";
-import { render } from "preact";
-import { useEffect, useMemo, useState } from "preact/hooks";
-import { METHODS, authedFetch, slotTimeLabel, writeAttribute, readAttribute } from "./lib.js";
+import {
+ reactExtension,
+ useTranslate,
+ useSettings,
+ useSessionToken,
+ useCheckoutToken,
+ useApplyAttributeChange,
+ useAttributes,
+ BlockStack,
+ Heading,
+ ChoiceList,
+ Choice,
+ TextField,
+ Button,
+ Text,
+ Banner,
+} from "@shopify/ui-extensions-react/checkout";
+import { useEffect, useMemo, useState } from "react";
+import { METHODS, authedFetch, slotTimeLabel, readAttribute, backendBase } from "./lib.js";
-export default async () => {
- render(, document.body);
-};
+export default reactExtension("purchase.checkout.block.render", () => );
-// Native in-checkout picker (Plus). Same job as the storefront widget —
-// collect a method/date/slot, reserve a hold, write the dd_* attributes —
-// but inside Shopify's own checkout, calling the identical
-// checkout.scheduling.* backend routes so it draws from the one capacity
-// pool (CLAUDE.md: behavior must never diverge between channels).
function Extension() {
- const initialMethod = readAttribute(shopify, "dd_method") || "PICKUP";
+ const translate = useTranslate();
+ const settings = useSettings();
+ const sessionToken = useSessionToken();
+ const checkoutToken = useCheckoutToken();
+ const applyAttributeChange = useApplyAttributeChange();
+ const attributes = useAttributes();
+
+ const initialMethod = readAttribute(attributes, "dd_method") || "PICKUP";
const [method, setMethod] = useState(initialMethod);
const [postalCode, setPostalCode] = useState("");
- const [availability, setAvailability] = useState(null);
+ const [availability, setAvailability] = useState(/** @type {any} */ (null));
const [date, setDate] = useState("");
const [status, setStatus] = useState("idle"); // idle|loading|error
- const [confirmed, setConfirmed] = useState(readAttribute(shopify, "dd_date") || null);
+ const [confirmed, setConfirmed] = useState(readAttribute(attributes, "dd_date") || null);
const needsPostal = method === "LOCAL_DELIVERY";
- const cartToken = shopify.checkoutToken?.value || `checkout-${Date.now()}`;
async function loadAvailability() {
setStatus("loading");
@@ -32,11 +46,13 @@ function Extension() {
try {
const params = new URLSearchParams({ method, days: "14" });
if (needsPostal && postalCode) params.set("postalCode", postalCode);
- const res = await authedFetch(shopify, `/checkout/scheduling/availability?${params.toString()}`);
+ const base = backendBase(settings);
+ const token = await sessionToken.get();
+ const res = await authedFetch(base, token, `/checkout/scheduling/availability?${params.toString()}`);
const body = await res.json();
if (!res.ok || !body.locationId) {
setStatus("idle");
- setAvailability({ error: body.error || shopify.i18n.translate("out_of_area"), dates: {} });
+ setAvailability({ error: body.error || translate("out_of_area"), dates: {} });
return;
}
setAvailability(body);
@@ -51,13 +67,29 @@ function Extension() {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [method]);
+ /** @type {string[]} */
const dates = useMemo(() => Object.keys(availability?.dates ?? {}).sort(), [availability]);
+ /** @type {any[]} */
const slots = date ? availability?.dates?.[date] ?? [] : [];
+ /**
+ * @param {string} key
+ * @param {string} value
+ */
+ async function writeAttribute(key, value) {
+ const result = await applyAttributeChange({ type: "updateAttribute", key, value: String(value) });
+ return result?.type === "success";
+ }
+
+ /**
+ * @param {any} slot
+ */
async function selectSlot(slot) {
setStatus("loading");
try {
- const holdRes = await authedFetch(shopify, "/checkout/scheduling/hold", {
+ const base = backendBase(settings);
+ const token = await sessionToken.get();
+ const holdRes = await authedFetch(base, token, "/checkout/scheduling/hold", {
method: "POST",
body: JSON.stringify({
intent: "create",
@@ -65,7 +97,7 @@ function Extension() {
method,
date,
startMin: slot.startMin,
- cartToken,
+ cartToken: checkoutToken,
}),
});
const hold = await holdRes.json();
@@ -79,13 +111,13 @@ function Extension() {
const methodMeta = METHODS.find((m) => m.value === method);
const display = `${date}, ${slotTimeLabel(slot)}`;
await Promise.all([
- writeAttribute(shopify, methodMeta.attrLabel, display),
- writeAttribute(shopify, "dd_method", method),
- writeAttribute(shopify, "dd_date", date),
- writeAttribute(shopify, "dd_start_min", slot.startMin),
- writeAttribute(shopify, "dd_end_min", slot.endMin),
- writeAttribute(shopify, "dd_location_id", availability.locationId),
- availability.zoneId ? writeAttribute(shopify, "dd_zone_id", availability.zoneId) : Promise.resolve(),
+ writeAttribute(methodMeta?.attrLabel || "Delivery date", display),
+ writeAttribute("dd_method", method),
+ writeAttribute("dd_date", date),
+ writeAttribute("dd_start_min", slot.startMin),
+ writeAttribute("dd_end_min", slot.endMin),
+ writeAttribute("dd_location_id", availability.locationId),
+ availability.zoneId ? writeAttribute("dd_zone_id", availability.zoneId) : Promise.resolve(),
]);
setConfirmed(display);
setStatus("idle");
@@ -96,78 +128,78 @@ function Extension() {
if (confirmed) {
return (
-
-
- {shopify.i18n.translate("confirmed")} {confirmed}
-
- setConfirmed(null)}>
- {shopify.i18n.translate("change")}
-
-
+
+
+ {translate("confirmed")} {confirmed}
+
+
+
);
}
return (
-
- {shopify.i18n.translate("picker_heading")}
+
+ {translate("picker_heading")}
- setMethod(e.currentTarget.values[0])}
+ value={method}
+ onChange={(/** @type {string} */ val) => setMethod(val)}
>
{METHODS.map((m) => (
-
- {shopify.i18n.translate(m.labelKey)}
-
+
+ {translate(m.labelKey)}
+
))}
-
+
{needsPostal && (
-
-
+ setPostalCode(e.currentTarget.value)}
+ onChange={(/** @type {string} */ val) => setPostalCode(val)}
/>
-
- {shopify.i18n.translate("postal_code_submit")}
-
-
+
+
)}
- {status === "loading" && {shopify.i18n.translate("loading")}}
- {status === "error" && {shopify.i18n.translate("error")}}
- {availability?.error && {availability.error}}
+ {status === "loading" && {translate("loading")}}
+ {status === "error" && {translate("error")}}
+ {availability?.error && {availability.error}}
{dates.length > 0 && (
- setDate(e.currentTarget.values[0])}>
+ setDate(val)}>
{dates.map((d) => (
-
+
{d}
-
+
))}
-
+
)}
{availability && !availability.error && dates.length === 0 && status === "idle" && (
- {shopify.i18n.translate("no_dates")}
+ {translate("no_dates")}
)}
{date && slots.length > 0 && (
- {
- const slot = slots.find((s) => String(s.startMin) === e.currentTarget.values[0]);
+ onChange={(/** @type {string} */ val) => {
+ const slot = slots.find((/** @type {any} */ s) => String(s.startMin) === val);
if (slot) selectSlot(slot);
}}
>
{slots.map((slot) => (
-
+
{slotTimeLabel(slot)}
-
+
))}
-
+
)}
-
+
);
}
diff --git a/extensions/checkout-datetime/src/OrderStatus.jsx b/extensions/checkout-datetime/src/OrderStatus.jsx
index 9e93c60..6590ede 100644
--- a/extensions/checkout-datetime/src/OrderStatus.jsx
+++ b/extensions/checkout-datetime/src/OrderStatus.jsx
@@ -1,21 +1,18 @@
-import "@shopify/ui-extensions/preact";
-import { render } from "preact";
-import { confirmationText } from "./lib.js";
+import { reactExtension, BlockStack, Heading, Text } from "@shopify/ui-extensions-react/checkout";
+import { useConfirmationText } from "./lib.js";
+import { useTranslate } from "@shopify/ui-extensions-react/checkout";
-export default async () => {
- render(, document.body);
-};
+// @ts-ignore - customer account targets might not be in the checkout UI extensions type definition
+export default reactExtension("customer-account.order-status.block.render", () => );
-// Order status page equivalent of ThankYou.jsx — lets a returning shopper
-// re-check their scheduled slot after the fact (study §3.7 "Order status
-// page"). Same all-plan Liquid block is the non-Plus fallback.
function Extension() {
- const text = confirmationText(shopify);
+ const text = useConfirmationText();
+ const translate = useTranslate();
if (!text) return null;
return (
-
- {shopify.i18n.translate("name")}
- {text}
-
+
+ {translate("name")}
+ {text}
+
);
}
diff --git a/extensions/checkout-datetime/src/ThankYou.jsx b/extensions/checkout-datetime/src/ThankYou.jsx
index a106973..f2c188a 100644
--- a/extensions/checkout-datetime/src/ThankYou.jsx
+++ b/extensions/checkout-datetime/src/ThankYou.jsx
@@ -1,22 +1,17 @@
-import "@shopify/ui-extensions/preact";
-import { render } from "preact";
-import { confirmationText } from "./lib.js";
+import { reactExtension, BlockStack, Heading, Text } from "@shopify/ui-extensions-react/checkout";
+import { useConfirmationText } from "./lib.js";
+import { useTranslate } from "@shopify/ui-extensions-react/checkout";
-export default async () => {
- render(, document.body);
-};
+export default reactExtension("purchase.thank-you.block.render", () => );
-// Plus-only nicety layered on top of the all-plan Liquid block
-// (extensions/datetime-widget/blocks/order-confirmation.liquid). Reads the
-// same dd_* attributes every surface writes and echoes the scheduled slot
-// straight back on the Thank you page.
function Extension() {
- const text = confirmationText(shopify);
+ const text = useConfirmationText();
+ const translate = useTranslate();
if (!text) return null;
return (
-
- {shopify.i18n.translate("name")}
- {text}
-
+
+ {translate("name")}
+ {text}
+
);
}
diff --git a/extensions/checkout-datetime/src/lib.js b/extensions/checkout-datetime/src/lib.js
index 10d8334..0bde104 100644
--- a/extensions/checkout-datetime/src/lib.js
+++ b/extensions/checkout-datetime/src/lib.js
@@ -1,11 +1,4 @@
-// Shared helpers for the checkout-datetime extension modules.
-//
-// NOTE: like extensions/pos-datetime, this is written against
-// @shopify/ui-extensions' typings but is unverified against a live checkout
-// session (this environment can't run one). The networking shape — a
-// session-token Bearer call to the app's own checkout.scheduling.* routes —
-// mirrors what those routes already expect (see
-// app/routes/checkout.scheduling.availability.tsx).
+import { useTranslate, useAttributes } from "@shopify/ui-extensions-react/checkout";
export const METHODS = [
{ value: "PICKUP", labelKey: "method_pickup", attrLabel: "Pickup date" },
@@ -13,6 +6,7 @@ export const METHODS = [
{ value: "SHIPPING", labelKey: "method_shipping", attrLabel: "Shipping date" },
];
+/** @param {number} minutes */
export function minutesToDisplayTime(minutes) {
const h24 = Math.floor(minutes / 60);
const m = minutes % 60;
@@ -21,6 +15,7 @@ export function minutesToDisplayTime(minutes) {
return `${h12}:${String(m).padStart(2, "0")} ${period}`;
}
+/** @param {any} slot */
export function slotTimeLabel(slot) {
if (slot.arrivalRangeStart && slot.arrivalRangeEnd) {
return `Arrives ${slot.arrivalRangeStart.slice(0, 10)}–${slot.arrivalRangeEnd.slice(0, 10)}`;
@@ -28,47 +23,51 @@ export function slotTimeLabel(slot) {
return `${minutesToDisplayTime(slot.startMin)}–${minutesToDisplayTime(slot.endMin)}`;
}
-/** Trims a trailing slash so `${base}/checkout/...` never doubles up. */
-export function backendBase(shopify) {
- const fromSettings = shopify.settings?.value?.app_url;
+/** @param {any} settings */
+export function backendBase(settings) {
+ const fromSettings = settings?.app_url;
return typeof fromSettings === "string" && fromSettings ? fromSettings.replace(/\/+$/, "") : "";
}
-export async function authedFetch(shopify, path, options = {}) {
- const base = backendBase(shopify);
- const token = await shopify.sessionToken.get();
+/**
+ * @param {string} base
+ * @param {string} token
+ * @param {string} path
+ * @param {any} options
+ */
+export async function authedFetch(base, token, path, options = {}) {
return fetch(`${base}${path}`, {
...options,
headers: { ...(options.headers || {}), Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
});
}
-/** Reads a dd_* value out of the checkout's current attributes signal. */
-export function readAttribute(shopify, key) {
- const attrs = shopify.attributes?.value ?? [];
- return attrs.find((a) => a.key === key)?.value;
-}
-
-export async function writeAttribute(shopify, key, value) {
- const result = await shopify.applyAttributeChange({ type: "updateAttribute", key, value: String(value) });
- return result?.type === "success";
+/**
+ * @param {any[] | undefined} attributes
+ * @param {string} key
+ */
+export function readAttribute(attributes, key) {
+ return (attributes ?? []).find((a) => a.key === key)?.value;
}
+/** @type {Record} */
const CONFIRMATION_LABEL = {
PICKUP: "confirmation_pickup",
LOCAL_DELIVERY: "confirmation_delivery",
SHIPPING: "confirmation_shipping",
};
-/** Shared "Pickup — Fri, Aug 25, 9:00 AM–12:00 PM" line for the TY / order-status blocks. */
-export function confirmationText(shopify) {
- const method = readAttribute(shopify, "dd_method");
- const date = readAttribute(shopify, "dd_date");
- const startMin = readAttribute(shopify, "dd_start_min");
- const endMin = readAttribute(shopify, "dd_end_min");
+export function useConfirmationText() {
+ const translate = useTranslate();
+ const attributes = useAttributes();
+
+ const method = readAttribute(attributes, "dd_method");
+ const date = readAttribute(attributes, "dd_date");
+ const startMin = readAttribute(attributes, "dd_start_min");
+ const endMin = readAttribute(attributes, "dd_end_min");
if (!method || !date) return null;
- const label = shopify.i18n.translate(CONFIRMATION_LABEL[method] ?? "confirmation_shipping");
+ const label = translate(CONFIRMATION_LABEL[method] ?? "confirmation_shipping");
const time =
startMin && endMin ? `, ${minutesToDisplayTime(Number(startMin))}–${minutesToDisplayTime(Number(endMin))}` : "";
return `${label}: ${date}${time}`;
diff --git a/extensions/checkout-datetime/tsconfig.json b/extensions/checkout-datetime/tsconfig.json
index 234fe65..d3585dc 100644
--- a/extensions/checkout-datetime/tsconfig.json
+++ b/extensions/checkout-datetime/tsconfig.json
@@ -1,14 +1,13 @@
{
- "//": "checkJs is off until this source has been iterated against the live @shopify/ui-extensions checkout types with the extension's deps installed (npm install here, then flip checkJs on and fix). shopify.d.ts still compiles so the target imports are validated.",
"compilerOptions": {
+ "target": "ES2022",
+ "module": "ES2022",
+ "moduleResolution": "bundler",
+ "strict": true,
+ "checkJs": true,
"jsx": "react-jsx",
- "jsxImportSource": "preact",
- "target": "ES2020",
- "checkJs": false,
- "allowJs": true,
- "moduleResolution": "node",
+ "allowSyntheticDefaultImports": true,
"esModuleInterop": true,
- "noEmit": true,
"skipLibCheck": true
},
"include": ["src/**/*", "shopify.d.ts"],
diff --git a/package-lock.json b/package-lock.json
index 75d8bfd..18d9bce 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -58,32 +58,82 @@
"version": "1.0.0",
"license": "UNLICENSED",
"dependencies": {
- "@preact/signals": "^2.3.x",
- "@shopify/ui-extensions": "2026.7.x",
- "preact": "^10.10.x"
+ "@shopify/ui-extensions": "^2025.7.3",
+ "@shopify/ui-extensions-react": "^2025.7.3",
+ "react": "^18.3.1"
+ },
+ "devDependencies": {
+ "typescript": "^7.0.2"
}
},
"extensions/checkout-datetime/node_modules/@shopify/ui-extensions": {
- "version": "2026.7.0",
- "resolved": "https://registry.npmjs.org/@shopify/ui-extensions/-/ui-extensions-2026.7.0.tgz",
- "integrity": "sha512-xqcExD7d5yAmTZMd+W8yB5sfB587UKobY/fPeONImZLITsEPRbUYfH9MPUHoGJ3uL+5oBYy9ZMZofysQ3vP7eQ==",
+ "version": "2025.7.3",
+ "resolved": "https://registry.npmjs.org/@shopify/ui-extensions/-/ui-extensions-2025.7.3.tgz",
+ "integrity": "sha512-XqTEzLnU0YOD7s9vd2EEBdXuqxL6H2VMBkwXuHNHdohwMtN/50S5/OsKRrEsE97D3/+/TcEEhQywocA8z4IvSw==",
"license": "MIT",
"dependencies": {
- "ts-morph": "^25.0.1"
+ "@remote-ui/async-subscription": "^2.1.16",
+ "@remote-ui/core": "^2.2.5"
+ }
+ },
+ "extensions/checkout-datetime/node_modules/@shopify/ui-extensions-react": {
+ "version": "2025.7.3",
+ "resolved": "https://registry.npmjs.org/@shopify/ui-extensions-react/-/ui-extensions-react-2025.7.3.tgz",
+ "integrity": "sha512-XNi91jm5oMhJG4ktoUeIQyvajDMse+MkOwc6x39NHDrjDbOEEoqBKqY+AB7ef+T9I0FDw9vkN9PdzDnXQJqEow==",
+ "license": "MIT",
+ "dependencies": {
+ "@remote-ui/async-subscription": "^2.1.16",
+ "@remote-ui/react": "^5.0.6",
+ "@types/react": ">=18.2.67"
},
"peerDependencies": {
- "@preact/signals": "*",
- "preact": "*"
+ "@shopify/ui-extensions": "2025.7.3",
+ "react": ">=18.0.0"
},
"peerDependenciesMeta": {
- "@preact/signals": {
- "optional": true
+ "@shopify/ui-extensions": {
+ "optional": false
},
- "preact": {
- "optional": true
+ "react": {
+ "optional": false
}
}
},
+ "extensions/checkout-datetime/node_modules/typescript": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz",
+ "integrity": "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc"
+ },
+ "engines": {
+ "node": ">=16.20.0"
+ },
+ "optionalDependencies": {
+ "@typescript/typescript-aix-ppc64": "7.0.2",
+ "@typescript/typescript-darwin-arm64": "7.0.2",
+ "@typescript/typescript-darwin-x64": "7.0.2",
+ "@typescript/typescript-freebsd-arm64": "7.0.2",
+ "@typescript/typescript-freebsd-x64": "7.0.2",
+ "@typescript/typescript-linux-arm": "7.0.2",
+ "@typescript/typescript-linux-arm64": "7.0.2",
+ "@typescript/typescript-linux-loong64": "7.0.2",
+ "@typescript/typescript-linux-mips64el": "7.0.2",
+ "@typescript/typescript-linux-ppc64": "7.0.2",
+ "@typescript/typescript-linux-riscv64": "7.0.2",
+ "@typescript/typescript-linux-s390x": "7.0.2",
+ "@typescript/typescript-linux-x64": "7.0.2",
+ "@typescript/typescript-netbsd-arm64": "7.0.2",
+ "@typescript/typescript-netbsd-x64": "7.0.2",
+ "@typescript/typescript-openbsd-arm64": "7.0.2",
+ "@typescript/typescript-openbsd-x64": "7.0.2",
+ "@typescript/typescript-sunos-x64": "7.0.2",
+ "@typescript/typescript-win32-arm64": "7.0.2",
+ "@typescript/typescript-win32-x64": "7.0.2"
+ }
+ },
"extensions/delivery-customization": {
"version": "0.0.1",
"license": "UNLICENSED",
@@ -330,6 +380,252 @@
}
}
},
+ "extensions/payment-customization": {
+ "version": "0.0.1",
+ "license": "UNLICENSED",
+ "dependencies": {
+ "@shopify/shopify_function": "^2.0.1"
+ },
+ "devDependencies": {
+ "@shopify/shopify-function-test-helpers": "^1.0.0",
+ "vitest": "^3.2.4"
+ }
+ },
+ "extensions/payment-customization/node_modules/@vitest/expect": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.7.tgz",
+ "integrity": "sha512-E8eBXaKibuvH2pSZErOjdVb5vF4PbKYcrnluBTYxEk1l/VhhwZg1kZQsdtjq+CsF5CFydf2Rdkz7jDHKSisi3w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/chai": "^5.2.2",
+ "@vitest/spy": "3.2.7",
+ "@vitest/utils": "3.2.7",
+ "chai": "^5.2.0",
+ "tinyrainbow": "^2.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "extensions/payment-customization/node_modules/@vitest/mocker": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.7.tgz",
+ "integrity": "sha512-Trr0hYO9CM3Wj6ksWHRhK9IZpIY6wTMO5u/MqXurMxT57sWBaOPEtP3Oq60ihZuh5JsiagKfz95OcxdEP6dBrA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/spy": "3.2.7",
+ "estree-walker": "^3.0.3",
+ "magic-string": "^0.30.17"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ },
+ "peerDependencies": {
+ "msw": "^2.4.9",
+ "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0"
+ },
+ "peerDependenciesMeta": {
+ "msw": {
+ "optional": true
+ },
+ "vite": {
+ "optional": true
+ }
+ }
+ },
+ "extensions/payment-customization/node_modules/@vitest/pretty-format": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.7.tgz",
+ "integrity": "sha512-KUHlwqVu0sRlhCdyPdQ/wBoTfRahjUky1MubOmYw9fWfIZy1gNoHpuaaQBPAaMaVYdQYHJLurzj8ECCj5OwTqA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tinyrainbow": "^2.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "extensions/payment-customization/node_modules/@vitest/runner": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.7.tgz",
+ "integrity": "sha512-sB9y4ovltoQP+WaUPwmSxO9WIg9Ig694Di5PalVPsYHklAdE027mehpWF2SQSVq+k6sFgaivbTjTJwZLSHbedA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/utils": "3.2.7",
+ "pathe": "^2.0.3",
+ "strip-literal": "^3.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "extensions/payment-customization/node_modules/@vitest/snapshot": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.7.tgz",
+ "integrity": "sha512-7C+MwShwtBSI5Buwoyg3s/iY1eHL9PKAf+O1wVh/TdnjXUtkoL/9YQtre90i4MtNXM6edP1wJ2zOBpfCyhIS7g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/pretty-format": "3.2.7",
+ "magic-string": "^0.30.17",
+ "pathe": "^2.0.3"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "extensions/payment-customization/node_modules/@vitest/spy": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.7.tgz",
+ "integrity": "sha512-Q2eQGI6d2L/hBtZ0qNuKcAGid68XK6cv1xsoaIma6PaJhHPoqcEJhYpXZ/5myCMqkNgtP6UKuBhbc0nHKnrkuQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tinyspy": "^4.0.3"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "extensions/payment-customization/node_modules/@vitest/utils": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.7.tgz",
+ "integrity": "sha512-x6BDOd7dyo3PFLY3I9/HJ25X/6OurhGXk2/B9gOZNPF7XDVjeBK4k01lQE5uvDpbuheErh91qYuE1E2OEjK3Rw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/pretty-format": "3.2.7",
+ "loupe": "^3.1.4",
+ "tinyrainbow": "^2.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "extensions/payment-customization/node_modules/pathe": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
+ "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "extensions/payment-customization/node_modules/picomatch": {
+ "version": "4.0.7",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz",
+ "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "extensions/payment-customization/node_modules/tinyexec": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz",
+ "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "extensions/payment-customization/node_modules/tinyrainbow": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz",
+ "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "extensions/payment-customization/node_modules/tinyspy": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.6.tgz",
+ "integrity": "sha512-u8KszXvGfU68hVcZpRHKG28T0krMuv2G5nDhiHaMLen/gIuFEgIJhaJuO69qjnXg5paSrbPMFfx3brNuN8eVSg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "extensions/payment-customization/node_modules/vitest": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.7.tgz",
+ "integrity": "sha512-KrxIJ62Fd89gfysR4WotlgZABiz2dqFPgqGzX7s+CwsqLFomRH7777ZcrOD6+WVAh7khPQP41A+BKbpcJFrdEg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/chai": "^5.2.2",
+ "@vitest/expect": "3.2.7",
+ "@vitest/mocker": "3.2.7",
+ "@vitest/pretty-format": "^3.2.7",
+ "@vitest/runner": "3.2.7",
+ "@vitest/snapshot": "3.2.7",
+ "@vitest/spy": "3.2.7",
+ "@vitest/utils": "3.2.7",
+ "chai": "^5.2.0",
+ "debug": "^4.4.1",
+ "expect-type": "^1.2.1",
+ "magic-string": "^0.30.17",
+ "pathe": "^2.0.3",
+ "picomatch": "^4.0.2",
+ "std-env": "^3.9.0",
+ "tinybench": "^2.9.0",
+ "tinyexec": "^0.3.2",
+ "tinyglobby": "^0.2.14",
+ "tinypool": "^1.1.1",
+ "tinyrainbow": "^2.0.0",
+ "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0",
+ "vite-node": "3.2.4",
+ "why-is-node-running": "^2.3.0"
+ },
+ "bin": {
+ "vitest": "vitest.mjs"
+ },
+ "engines": {
+ "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ },
+ "peerDependencies": {
+ "@edge-runtime/vm": "*",
+ "@types/debug": "^4.1.12",
+ "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
+ "@vitest/browser": "3.2.7",
+ "@vitest/ui": "3.2.7",
+ "happy-dom": "*",
+ "jsdom": "*"
+ },
+ "peerDependenciesMeta": {
+ "@edge-runtime/vm": {
+ "optional": true
+ },
+ "@types/debug": {
+ "optional": true
+ },
+ "@types/node": {
+ "optional": true
+ },
+ "@vitest/browser": {
+ "optional": true
+ },
+ "@vitest/ui": {
+ "optional": true
+ },
+ "happy-dom": {
+ "optional": true
+ },
+ "jsdom": {
+ "optional": true
+ }
+ }
+ },
"extensions/pos-datetime": {
"version": "1.0.0",
"license": "UNLICENSED",
@@ -4900,6 +5196,62 @@
"web-streams-polyfill": "^3.1.1"
}
},
+ "node_modules/@remote-ui/async-subscription": {
+ "version": "2.1.18",
+ "resolved": "https://registry.npmjs.org/@remote-ui/async-subscription/-/async-subscription-2.1.18.tgz",
+ "integrity": "sha512-O+76qOiTGN6iJZBFncELNIBnhCbHAIYrsrG0n3SjmwXE9Gy6nl4xZoa5FqIcw5VPz7EAdwKBkFsRE5uyQB7FOw==",
+ "license": "MIT",
+ "dependencies": {
+ "@remote-ui/rpc": "^1.4.7"
+ }
+ },
+ "node_modules/@remote-ui/core": {
+ "version": "2.2.7",
+ "resolved": "https://registry.npmjs.org/@remote-ui/core/-/core-2.2.7.tgz",
+ "integrity": "sha512-9eiTKy2eNKcT76xS0Dpz06ae2oClGAUUjx+HTDsz6fh7n/SS8Avid5N7GOaRiny/6T/cMJxaCeycMQJsEviGjA==",
+ "license": "MIT",
+ "dependencies": {
+ "@remote-ui/rpc": "^1.4.7",
+ "@remote-ui/types": "^1.1.3"
+ }
+ },
+ "node_modules/@remote-ui/react": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/@remote-ui/react/-/react-5.0.8.tgz",
+ "integrity": "sha512-GUwqP0b4m2TQ8THbsjhBvvYXZfvyWbP6HlYtzKw7izW9C49DWrixLuSz41kB4Ae7MI1OUfKy3xHtwXeLWa+nuA==",
+ "license": "MIT",
+ "dependencies": {
+ "@remote-ui/async-subscription": "^2.1.18",
+ "@remote-ui/core": "^2.2.7",
+ "@remote-ui/rpc": "^1.4.7",
+ "@types/react": ">=17.0.0 <19.0.0",
+ "@types/react-reconciler": ">=0.26.0 <0.30.0"
+ },
+ "peerDependencies": {
+ "react": ">=17.0.0 <19.0.0",
+ "react-reconciler": ">=0.26.0 <0.30.0"
+ },
+ "peerDependenciesMeta": {
+ "react": {
+ "optional": false
+ },
+ "react-reconciler": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@remote-ui/rpc": {
+ "version": "1.4.7",
+ "resolved": "https://registry.npmjs.org/@remote-ui/rpc/-/rpc-1.4.7.tgz",
+ "integrity": "sha512-ORiaKsbVBSEi3Z4YWOj5Ucrp70NrkNktI1hdqqfBW7Z3o0YoxTX9MIqtLmsc6721IbjmExvLrLip5I5Y7uAbng==",
+ "license": "MIT"
+ },
+ "node_modules/@remote-ui/types": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@remote-ui/types/-/types-1.1.3.tgz",
+ "integrity": "sha512-P1kN1F3p0oMgnLN8Of1Ie9am3sLvJ7nhqHH1pvzkrxqjVwhhyPVZNcwOHyUNZPKp62izhDavdrcnqrdXzVJqGA==",
+ "license": "MIT"
+ },
"node_modules/@repeaterjs/repeater": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@repeaterjs/repeater/-/repeater-3.1.0.tgz",
@@ -6037,6 +6389,15 @@
"@types/react": "^18.0.0"
}
},
+ "node_modules/@types/react-reconciler": {
+ "version": "0.28.9",
+ "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.28.9.tgz",
+ "integrity": "sha512-HHM3nxyUZ3zAylX8ZEyrDNd2XZOnQ0D5XfunJF5FLQnZbHHYq4UWvW1QfelQNXv1ICNkwYhfxjwfnqivYB6bFg==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*"
+ }
+ },
"node_modules/@types/react-transition-group": {
"version": "4.4.12",
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz",
@@ -6277,6 +6638,346 @@
"url": "https://opencollective.com/eslint"
}
},
+ "node_modules/@typescript/typescript-aix-ppc64": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-aix-ppc64/-/typescript-aix-ppc64-7.0.2.tgz",
+ "integrity": "sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/@typescript/typescript-darwin-arm64": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-arm64/-/typescript-darwin-arm64-7.0.2.tgz",
+ "integrity": "sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/@typescript/typescript-darwin-x64": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-x64/-/typescript-darwin-x64-7.0.2.tgz",
+ "integrity": "sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/@typescript/typescript-freebsd-arm64": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-arm64/-/typescript-freebsd-arm64-7.0.2.tgz",
+ "integrity": "sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/@typescript/typescript-freebsd-x64": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-x64/-/typescript-freebsd-x64-7.0.2.tgz",
+ "integrity": "sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/@typescript/typescript-linux-arm": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm/-/typescript-linux-arm-7.0.2.tgz",
+ "integrity": "sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/@typescript/typescript-linux-arm64": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm64/-/typescript-linux-arm64-7.0.2.tgz",
+ "integrity": "sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/@typescript/typescript-linux-loong64": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-loong64/-/typescript-linux-loong64-7.0.2.tgz",
+ "integrity": "sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/@typescript/typescript-linux-mips64el": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-mips64el/-/typescript-linux-mips64el-7.0.2.tgz",
+ "integrity": "sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/@typescript/typescript-linux-ppc64": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-ppc64/-/typescript-linux-ppc64-7.0.2.tgz",
+ "integrity": "sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/@typescript/typescript-linux-riscv64": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-riscv64/-/typescript-linux-riscv64-7.0.2.tgz",
+ "integrity": "sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/@typescript/typescript-linux-s390x": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-s390x/-/typescript-linux-s390x-7.0.2.tgz",
+ "integrity": "sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/@typescript/typescript-linux-x64": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-x64/-/typescript-linux-x64-7.0.2.tgz",
+ "integrity": "sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/@typescript/typescript-netbsd-arm64": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-arm64/-/typescript-netbsd-arm64-7.0.2.tgz",
+ "integrity": "sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/@typescript/typescript-netbsd-x64": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-x64/-/typescript-netbsd-x64-7.0.2.tgz",
+ "integrity": "sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/@typescript/typescript-openbsd-arm64": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-arm64/-/typescript-openbsd-arm64-7.0.2.tgz",
+ "integrity": "sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/@typescript/typescript-openbsd-x64": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-x64/-/typescript-openbsd-x64-7.0.2.tgz",
+ "integrity": "sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/@typescript/typescript-sunos-x64": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-sunos-x64/-/typescript-sunos-x64-7.0.2.tgz",
+ "integrity": "sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/@typescript/typescript-win32-arm64": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-arm64/-/typescript-win32-arm64-7.0.2.tgz",
+ "integrity": "sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/@typescript/typescript-win32-x64": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-x64/-/typescript-win32-x64-7.0.2.tgz",
+ "integrity": "sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
"node_modules/@ungap/structured-clone": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.3.tgz",
@@ -15222,6 +15923,10 @@
"node": ">= 14.16"
}
},
+ "node_modules/payment-customization": {
+ "resolved": "extensions/payment-customization",
+ "link": true
+ },
"node_modules/peek-stream": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/peek-stream/-/peek-stream-1.1.3.tgz",
diff --git a/widget-src/datetime-widget/datetime-widget.ts b/widget-src/datetime-widget/datetime-widget.ts
index efb6941..fdab963 100644
--- a/widget-src/datetime-widget/datetime-widget.ts
+++ b/widget-src/datetime-widget/datetime-widget.ts
@@ -37,6 +37,8 @@ interface RateDto {
interface AvailabilityResponse {
locationId: string | null;
locationName?: string;
+ // TODO: Add pickupLocations array when backend supports returning multiple pickup locations for selection.
+ // pickupLocations?: Array<{ id: string, name: string, lat: number | null, lng: number | null }>;
locationLat?: number | null;
locationLng?: number | null;
timezone?: string;
@@ -500,6 +502,10 @@ class DateTimeWidget {
return;
}
+ // TODO: When backend supports `pickupLocations`, implement a UI selector (list/map)
+ // to let the user choose a location before rendering dates. Currently, it just defaults
+ // to the single returned location.
+
if (method.value === "PICKUP" && this.config.googleMapsApiKey) {
this.showPickupMap();
}