@uptrademedia/site-kit 1.1.4 → 1.1.5

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.
@@ -106,7 +106,14 @@ async function apiPost(endpoint, body = {}) {
106
106
  body: JSON.stringify(body)
107
107
  });
108
108
  if (!response.ok) {
109
- console.error(`[Commerce] API error: ${response.statusText}`);
109
+ const text = await response.text();
110
+ let body2 = null;
111
+ try {
112
+ body2 = text ? JSON.parse(text) : null;
113
+ } catch {
114
+ body2 = text;
115
+ }
116
+ console.error(`[Commerce] API error:`, response.status, response.statusText || "Unknown", body2);
110
117
  return null;
111
118
  }
112
119
  return await response.json();
@@ -135,9 +142,20 @@ async function fetchOffering(slug) {
135
142
  "/api/public/commerce/offering",
136
143
  { slug }
137
144
  );
138
- return result?.offering || null;
145
+ if (!result) return null;
146
+ const offering = result.offering ?? result;
147
+ return offering?.id ? offering : null;
139
148
  }
140
149
  async function fetchLatestOffering(type, category) {
150
+ if (type === "product") {
151
+ const { products } = await fetchProductsPublic({
152
+ category,
153
+ limit: 1,
154
+ orderBy: "created_at",
155
+ order: "desc"
156
+ });
157
+ return products[0] || null;
158
+ }
141
159
  const result = await apiPost(
142
160
  "/api/public/commerce/offerings",
143
161
  {
@@ -168,7 +186,15 @@ async function fetchNextEvent(category) {
168
186
  return events[0] || null;
169
187
  }
170
188
  async function fetchProducts(options = {}) {
171
- return fetchOfferings({ ...options, type: "product" });
189
+ const { products } = await fetchProductsPublic({
190
+ category: options.category,
191
+ limit: options.limit,
192
+ offset: options.offset,
193
+ orderBy: options.orderBy || "sort_order",
194
+ order: options.order || "asc",
195
+ search: options.search
196
+ });
197
+ return products;
172
198
  }
173
199
  async function fetchServices(options = {}) {
174
200
  return fetchOfferings({ ...options, type: "service" });
@@ -197,6 +223,37 @@ async function fetchCategories() {
197
223
  );
198
224
  return result?.categories || [];
199
225
  }
226
+ async function fetchShippingRates(shippingAddress, offerings) {
227
+ const result = await apiPost(
228
+ "/api/public/commerce/shipping-rates",
229
+ {
230
+ shippingAddress: {
231
+ street1: shippingAddress.street1,
232
+ street2: shippingAddress.street2,
233
+ city: shippingAddress.city,
234
+ state: shippingAddress.state,
235
+ zip: shippingAddress.zip,
236
+ country: shippingAddress.country || "US"
237
+ },
238
+ offerings
239
+ }
240
+ );
241
+ return Array.isArray(result) ? result : [];
242
+ }
243
+ async function validateAddress(address) {
244
+ const result = await apiPost(
245
+ "/api/public/commerce/validate-address",
246
+ {
247
+ street1: address.street1,
248
+ street2: address.street2,
249
+ city: address.city,
250
+ state: address.state,
251
+ zip: address.zip,
252
+ country: address.country || "US"
253
+ }
254
+ );
255
+ return result || { isValid: true, messages: [] };
256
+ }
200
257
  async function fetchActiveProcessor() {
201
258
  const { apiUrl, apiKey } = getApiConfig();
202
259
  if (!apiKey) return null;
@@ -565,8 +622,9 @@ function OfferingList({
565
622
  setError(null);
566
623
  try {
567
624
  let data;
568
- if (type === "product") {
569
- data = await fetchProducts({ category, limit, status });
625
+ if (type === "product" || Array.isArray(type) && type.includes("product")) {
626
+ const { products } = await fetchProductsPublic({ category, limit, orderBy: "sort_order", order: "asc" });
627
+ data = products;
570
628
  } else if (type === "event") {
571
629
  data = await fetchUpcomingEvents({ category, limit });
572
630
  } else {
@@ -1052,7 +1110,7 @@ function ProductEmbed({
1052
1110
  try {
1053
1111
  let data = null;
1054
1112
  if (mode === "specific" && slug) {
1055
- data = await fetchOffering(slug);
1113
+ data = await fetchProductBySlug(slug);
1056
1114
  } else if (mode === "latest" || mode === "featured") {
1057
1115
  data = await fetchLatestOffering("product", category);
1058
1116
  }
@@ -1141,7 +1199,7 @@ function ProductDetail({
1141
1199
  async function load() {
1142
1200
  setLoading(true);
1143
1201
  try {
1144
- const data = await fetchOffering(slug);
1202
+ const data = await fetchProductBySlug(slug);
1145
1203
  setProduct(data);
1146
1204
  if (data?.variants?.length) {
1147
1205
  const defaultVariant = data.variants.find((v) => v.is_default) || data.variants[0];
@@ -1556,6 +1614,7 @@ function ProductGrid({
1556
1614
  style
1557
1615
  }) {
1558
1616
  const [products, setProducts] = useState(propProducts || []);
1617
+ const [total, setTotal] = useState(0);
1559
1618
  const [loading, setLoading] = useState(!propProducts);
1560
1619
  const [searchQuery, setSearchQuery] = useState("");
1561
1620
  const [selectedCategory, setSelectedCategory] = useState(propCategory);
@@ -1572,19 +1631,20 @@ function ProductGrid({
1572
1631
  useEffect(() => {
1573
1632
  if (propProducts) {
1574
1633
  setProducts(propProducts);
1634
+ setTotal(propProducts.length);
1575
1635
  return;
1576
1636
  }
1577
1637
  async function load() {
1578
1638
  setLoading(true);
1579
1639
  try {
1580
- const data = await fetchOfferings({
1581
- type: "product",
1640
+ const { products: data, total: count } = await fetchProductsPublic({
1582
1641
  category: selectedCategory,
1583
1642
  limit,
1584
1643
  orderBy: "created_at",
1585
1644
  order: "desc"
1586
1645
  });
1587
1646
  setProducts(data);
1647
+ setTotal(count);
1588
1648
  } catch (e) {
1589
1649
  console.error("Failed to load products:", e);
1590
1650
  } finally {
@@ -1710,9 +1770,9 @@ function ProductGrid({
1710
1770
  fontSize: "0.875rem",
1711
1771
  color: "#6b7280"
1712
1772
  }, children: [
1713
- filteredProducts.length,
1773
+ searchQuery ? filteredProducts.length : total,
1714
1774
  " product",
1715
- filteredProducts.length !== 1 ? "s" : ""
1775
+ (searchQuery ? filteredProducts.length : total) !== 1 ? "s" : ""
1716
1776
  ] })
1717
1777
  ] }),
1718
1778
  loading && /* @__PURE__ */ jsxs("div", { className: "site-kit-product-grid__grid", style: {
@@ -1811,7 +1871,7 @@ function ProductPage({
1811
1871
  async function load() {
1812
1872
  setLoading(true);
1813
1873
  try {
1814
- const data = await fetchOffering(slug);
1874
+ const data = await fetchProductBySlug(slug);
1815
1875
  setProduct(data);
1816
1876
  } catch (e) {
1817
1877
  console.error("Failed to load product:", e);
@@ -1825,13 +1885,12 @@ function ProductPage({
1825
1885
  if (!product || !showRelatedProducts) return;
1826
1886
  async function loadRelated() {
1827
1887
  try {
1828
- const data = await fetchOfferings({
1829
- type: "product",
1888
+ const { products } = await fetchProductsPublic({
1830
1889
  category: product?.category_id,
1831
1890
  limit: relatedProductsLimit + 1
1832
1891
  // Fetch one extra to exclude current
1833
1892
  });
1834
- const filtered = data.filter((p) => p.id !== product?.id).slice(0, relatedProductsLimit);
1893
+ const filtered = products.filter((p) => p.id !== product?.id).slice(0, relatedProductsLimit);
1835
1894
  setRelatedProducts(filtered);
1836
1895
  } catch (e) {
1837
1896
  console.error("Failed to load related products:", e);
@@ -2087,21 +2146,62 @@ function CheckoutForm({
2087
2146
  const [success, setSuccess] = useState(false);
2088
2147
  const [quantity, setQuantity] = useState(initialQuantity);
2089
2148
  const [processor, setProcessor] = useState(null);
2149
+ const [shippingEnabled, setShippingEnabled] = useState(false);
2150
+ const [shippingStep, setShippingStep] = useState("address");
2151
+ const [shippingAddress, setShippingAddress] = useState({
2152
+ street1: "",
2153
+ street2: "",
2154
+ city: "",
2155
+ state: "",
2156
+ zip: "",
2157
+ country: "US"
2158
+ });
2159
+ const [shippingRates, setShippingRates] = useState([]);
2160
+ const [selectedRate, setSelectedRate] = useState(null);
2161
+ const [loadingRates, setLoadingRates] = useState(false);
2090
2162
  const [customer, setCustomer] = useState({
2091
2163
  email: "",
2092
2164
  name: "",
2093
2165
  phone: ""
2094
2166
  });
2167
+ const isProduct = offering.type === "product";
2095
2168
  useEffect(() => {
2096
- fetchActiveProcessor().then((p) => {
2097
- if (p) setProcessor(p);
2169
+ fetchProcessorConfig().then((config) => {
2170
+ if (config?.processor) setProcessor(config.processor);
2171
+ if (config?.shipping_enabled && isProduct) setShippingEnabled(true);
2098
2172
  });
2099
- }, []);
2173
+ }, [isProduct]);
2100
2174
  const isEvent = offering.type === "event" || offering.type === "class";
2101
2175
  const isFree = !offering.price || offering.price === 0;
2102
2176
  const actualMode = isEvent && isFree ? "register" : mode;
2103
2177
  const defaultSubmitText = actualMode === "register" ? "Register" : isFree ? "Complete Order" : "Continue to Payment";
2104
- const total = offering.price ? offering.price * quantity : 0;
2178
+ const subtotal = offering.price ? offering.price * quantity : 0;
2179
+ const shippingCost = selectedRate ? parseFloat(selectedRate.amount) : 0;
2180
+ const total = subtotal + shippingCost;
2181
+ const updateShippingAddress = (field, value) => {
2182
+ setShippingAddress((prev) => ({ ...prev, [field]: value }));
2183
+ };
2184
+ const handleGetShippingRates = async () => {
2185
+ if (!shippingAddress.street1 || !shippingAddress.city || !shippingAddress.state || !shippingAddress.zip) {
2186
+ setError("Please fill in all required address fields.");
2187
+ return;
2188
+ }
2189
+ setLoadingRates(true);
2190
+ setError(null);
2191
+ try {
2192
+ const rates = await fetchShippingRates(
2193
+ { ...shippingAddress, name: customer.name, phone: customer.phone },
2194
+ [{ offering_id: offering.id, quantity }]
2195
+ );
2196
+ setShippingRates(rates);
2197
+ if (rates.length > 0) setSelectedRate(rates[0]);
2198
+ setShippingStep("rates");
2199
+ } catch (e) {
2200
+ setError("Failed to get shipping rates. Please check your address.");
2201
+ } finally {
2202
+ setLoadingRates(false);
2203
+ }
2204
+ };
2105
2205
  const handleSubmit = async (e) => {
2106
2206
  e.preventDefault();
2107
2207
  setLoading(true);
@@ -2117,12 +2217,23 @@ function CheckoutForm({
2117
2217
  onError?.(result.error || "Registration failed");
2118
2218
  }
2119
2219
  } else {
2120
- const result = await createCheckoutSession(offering.id, {
2220
+ const checkoutOptions = {
2121
2221
  variantId,
2122
2222
  scheduleId,
2123
2223
  quantity,
2124
2224
  customer
2125
- });
2225
+ };
2226
+ if (shippingEnabled && shippingAddress.street1 && selectedRate) {
2227
+ checkoutOptions.shippingAddress = {
2228
+ ...shippingAddress,
2229
+ name: customer.name,
2230
+ phone: customer.phone
2231
+ };
2232
+ checkoutOptions.shippingCarrier = selectedRate.carrier;
2233
+ checkoutOptions.shippingService = selectedRate.service;
2234
+ checkoutOptions.shippingCost = parseFloat(selectedRate.amount);
2235
+ }
2236
+ const result = await createCheckoutSession(offering.id, checkoutOptions);
2126
2237
  if (result.success && result.payment_url) {
2127
2238
  window.location.href = result.payment_url;
2128
2239
  } else {
@@ -2141,6 +2252,7 @@ function CheckoutForm({
2141
2252
  const updateCustomer = (field, value) => {
2142
2253
  setCustomer((prev) => ({ ...prev, [field]: value }));
2143
2254
  };
2255
+ const canProceedToPayment = !shippingEnabled || shippingStep === "rates" && selectedRate;
2144
2256
  if (success) {
2145
2257
  return /* @__PURE__ */ jsxs("div", { className: `site-kit-checkout-success ${className}`, style: {
2146
2258
  padding: "2rem",
@@ -2185,10 +2297,7 @@ function CheckoutForm({
2185
2297
  children: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((n) => /* @__PURE__ */ jsx("option", { value: n, children: n }, n))
2186
2298
  }
2187
2299
  ),
2188
- /* @__PURE__ */ jsxs("span", { style: { marginLeft: "auto", fontWeight: 600 }, children: [
2189
- "Total: ",
2190
- formatPrice(total, offering.currency)
2191
- ] })
2300
+ /* @__PURE__ */ jsx("span", { style: { marginLeft: "auto", fontWeight: 600 }, children: shippingEnabled && selectedRate ? `Subtotal: ${formatPrice(subtotal, offering.currency)}` : `Total: ${formatPrice(total, offering.currency)}` })
2192
2301
  ] })
2193
2302
  ] }),
2194
2303
  /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "1rem" }, children: [
@@ -2252,6 +2361,161 @@ function CheckoutForm({
2252
2361
  )
2253
2362
  ] })
2254
2363
  ] }),
2364
+ shippingEnabled && !isEvent && /* @__PURE__ */ jsxs("div", { style: { marginTop: "1.5rem", paddingTop: "1.5rem", borderTop: "1px solid #e5e7eb" }, children: [
2365
+ /* @__PURE__ */ jsx("h4", { style: { margin: "0 0 1rem", fontSize: "1rem" }, children: "Shipping Address" }),
2366
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "1rem" }, children: [
2367
+ /* @__PURE__ */ jsxs("div", { children: [
2368
+ /* @__PURE__ */ jsx("label", { style: { display: "block", fontSize: "0.875rem", fontWeight: 500, marginBottom: "0.25rem" }, children: "Street Address *" }),
2369
+ /* @__PURE__ */ jsx(
2370
+ "input",
2371
+ {
2372
+ type: "text",
2373
+ required: shippingEnabled,
2374
+ value: shippingAddress.street1,
2375
+ onChange: (e) => updateShippingAddress("street1", e.target.value),
2376
+ className: inputClassName,
2377
+ placeholder: "123 Main St",
2378
+ style: { width: "100%", padding: "0.625rem 0.75rem", borderRadius: "6px", border: "1px solid #d1d5db", fontSize: "1rem" }
2379
+ }
2380
+ )
2381
+ ] }),
2382
+ /* @__PURE__ */ jsxs("div", { children: [
2383
+ /* @__PURE__ */ jsx("label", { style: { display: "block", fontSize: "0.875rem", fontWeight: 500, marginBottom: "0.25rem" }, children: "Apartment, suite, etc." }),
2384
+ /* @__PURE__ */ jsx(
2385
+ "input",
2386
+ {
2387
+ type: "text",
2388
+ value: shippingAddress.street2 || "",
2389
+ onChange: (e) => updateShippingAddress("street2", e.target.value),
2390
+ className: inputClassName,
2391
+ style: { width: "100%", padding: "0.625rem 0.75rem", borderRadius: "6px", border: "1px solid #d1d5db", fontSize: "1rem" }
2392
+ }
2393
+ )
2394
+ ] }),
2395
+ /* @__PURE__ */ jsxs("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "1rem" }, children: [
2396
+ /* @__PURE__ */ jsxs("div", { children: [
2397
+ /* @__PURE__ */ jsx("label", { style: { display: "block", fontSize: "0.875rem", fontWeight: 500, marginBottom: "0.25rem" }, children: "City *" }),
2398
+ /* @__PURE__ */ jsx(
2399
+ "input",
2400
+ {
2401
+ type: "text",
2402
+ required: shippingEnabled,
2403
+ value: shippingAddress.city,
2404
+ onChange: (e) => updateShippingAddress("city", e.target.value),
2405
+ className: inputClassName,
2406
+ style: { width: "100%", padding: "0.625rem 0.75rem", borderRadius: "6px", border: "1px solid #d1d5db", fontSize: "1rem" }
2407
+ }
2408
+ )
2409
+ ] }),
2410
+ /* @__PURE__ */ jsxs("div", { children: [
2411
+ /* @__PURE__ */ jsx("label", { style: { display: "block", fontSize: "0.875rem", fontWeight: 500, marginBottom: "0.25rem" }, children: "State *" }),
2412
+ /* @__PURE__ */ jsx(
2413
+ "input",
2414
+ {
2415
+ type: "text",
2416
+ required: shippingEnabled,
2417
+ value: shippingAddress.state,
2418
+ onChange: (e) => updateShippingAddress("state", e.target.value),
2419
+ className: inputClassName,
2420
+ style: { width: "100%", padding: "0.625rem 0.75rem", borderRadius: "6px", border: "1px solid #d1d5db", fontSize: "1rem" }
2421
+ }
2422
+ )
2423
+ ] })
2424
+ ] }),
2425
+ /* @__PURE__ */ jsxs("div", { children: [
2426
+ /* @__PURE__ */ jsx("label", { style: { display: "block", fontSize: "0.875rem", fontWeight: 500, marginBottom: "0.25rem" }, children: "ZIP Code *" }),
2427
+ /* @__PURE__ */ jsx(
2428
+ "input",
2429
+ {
2430
+ type: "text",
2431
+ required: shippingEnabled,
2432
+ value: shippingAddress.zip,
2433
+ onChange: (e) => updateShippingAddress("zip", e.target.value),
2434
+ className: inputClassName,
2435
+ style: { width: "100%", maxWidth: "120px", padding: "0.625rem 0.75rem", borderRadius: "6px", border: "1px solid #d1d5db", fontSize: "1rem" }
2436
+ }
2437
+ )
2438
+ ] })
2439
+ ] }),
2440
+ shippingStep === "address" && /* @__PURE__ */ jsx(
2441
+ "button",
2442
+ {
2443
+ type: "button",
2444
+ onClick: handleGetShippingRates,
2445
+ disabled: loadingRates || !shippingAddress.street1 || !shippingAddress.city || !shippingAddress.state || !shippingAddress.zip,
2446
+ style: {
2447
+ marginTop: "1rem",
2448
+ padding: "0.625rem 1.25rem",
2449
+ borderRadius: "6px",
2450
+ border: "1px solid #2563eb",
2451
+ background: "white",
2452
+ color: "#2563eb",
2453
+ fontSize: "0.875rem",
2454
+ fontWeight: 500,
2455
+ cursor: loadingRates ? "not-allowed" : "pointer"
2456
+ },
2457
+ children: loadingRates ? "Getting rates..." : "Get shipping options"
2458
+ }
2459
+ ),
2460
+ shippingStep === "rates" && shippingRates.length > 0 && /* @__PURE__ */ jsxs("div", { style: { marginTop: "1rem" }, children: [
2461
+ /* @__PURE__ */ jsx("label", { style: { display: "block", fontSize: "0.875rem", fontWeight: 500, marginBottom: "0.5rem" }, children: "Select shipping method" }),
2462
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: shippingRates.map((rate) => /* @__PURE__ */ jsxs(
2463
+ "label",
2464
+ {
2465
+ style: {
2466
+ display: "flex",
2467
+ alignItems: "center",
2468
+ gap: "0.75rem",
2469
+ padding: "0.75rem",
2470
+ borderRadius: "6px",
2471
+ border: `2px solid ${selectedRate === rate ? "#2563eb" : "#e5e7eb"}`,
2472
+ background: selectedRate === rate ? "#eff6ff" : "white",
2473
+ cursor: "pointer"
2474
+ },
2475
+ children: [
2476
+ /* @__PURE__ */ jsx(
2477
+ "input",
2478
+ {
2479
+ type: "radio",
2480
+ name: "shipping-rate",
2481
+ checked: selectedRate === rate,
2482
+ onChange: () => setSelectedRate(rate)
2483
+ }
2484
+ ),
2485
+ /* @__PURE__ */ jsxs("span", { style: { flex: 1 }, children: [
2486
+ rate.carrier,
2487
+ " - ",
2488
+ rate.service
2489
+ ] }),
2490
+ /* @__PURE__ */ jsx("span", { style: { fontWeight: 600 }, children: formatPrice(parseFloat(rate.amount), rate.currency || "USD") }),
2491
+ rate.estimatedDays && /* @__PURE__ */ jsxs("span", { style: { fontSize: "0.75rem", color: "#666" }, children: [
2492
+ "(",
2493
+ rate.estimatedDays,
2494
+ " days)"
2495
+ ] })
2496
+ ]
2497
+ },
2498
+ rate.objectId || `${rate.carrier}-${rate.service}`
2499
+ )) }),
2500
+ /* @__PURE__ */ jsx(
2501
+ "button",
2502
+ {
2503
+ type: "button",
2504
+ onClick: () => setShippingStep("address"),
2505
+ style: {
2506
+ marginTop: "0.75rem",
2507
+ fontSize: "0.875rem",
2508
+ color: "#6b7280",
2509
+ background: "none",
2510
+ border: "none",
2511
+ cursor: "pointer",
2512
+ textDecoration: "underline"
2513
+ },
2514
+ children: "Change address"
2515
+ }
2516
+ )
2517
+ ] })
2518
+ ] }),
2255
2519
  error && /* @__PURE__ */ jsx("div", { style: {
2256
2520
  marginTop: "1rem",
2257
2521
  padding: "0.75rem",
@@ -2265,7 +2529,7 @@ function CheckoutForm({
2265
2529
  "button",
2266
2530
  {
2267
2531
  type: "submit",
2268
- disabled: loading,
2532
+ disabled: loading || !isEvent && !isFree && !canProceedToPayment,
2269
2533
  className: buttonClassName,
2270
2534
  style: {
2271
2535
  width: "100%",
@@ -4144,6 +4408,6 @@ function getApiKey() {
4144
4408
  return "";
4145
4409
  }
4146
4410
 
4147
- export { CalendarView, CheckoutForm, EventCalendar, EventEmbed, EventModal, EventTile, EventsWidget, OfferingCard, OfferingList, ProductDetail, ProductEmbed, ProductGrid, ProductPage, RegistrationForm, UpcomingEvents, createCheckoutSession, fetchActiveProcessor, fetchCategories, fetchLatestOffering, fetchNextEvent, fetchOffering, fetchOfferings, fetchProcessorConfig, fetchProductBySlug, fetchProducts, fetchProductsPublic, fetchServices, fetchUpcomingEvents, formatDate, formatDateRange, formatDateTime, formatPrice, formatTime, getOfferingUrl, getRelativeTimeUntil, getSpotsRemaining, isEventSoldOut, registerForEvent, useEventModal };
4148
- //# sourceMappingURL=chunk-TI5CH4WT.mjs.map
4149
- //# sourceMappingURL=chunk-TI5CH4WT.mjs.map
4411
+ export { CalendarView, CheckoutForm, EventCalendar, EventEmbed, EventModal, EventTile, EventsWidget, OfferingCard, OfferingList, ProductDetail, ProductEmbed, ProductGrid, ProductPage, RegistrationForm, UpcomingEvents, createCheckoutSession, fetchActiveProcessor, fetchCategories, fetchLatestOffering, fetchNextEvent, fetchOffering, fetchOfferings, fetchProcessorConfig, fetchProductBySlug, fetchProducts, fetchProductsPublic, fetchServices, fetchShippingRates, fetchUpcomingEvents, formatDate, formatDateRange, formatDateTime, formatPrice, formatTime, getOfferingUrl, getRelativeTimeUntil, getSpotsRemaining, isEventSoldOut, registerForEvent, useEventModal, validateAddress };
4412
+ //# sourceMappingURL=chunk-NNKC3X7O.mjs.map
4413
+ //# sourceMappingURL=chunk-NNKC3X7O.mjs.map