@kotao/storefront 0.2.5 → 0.2.6
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 +50 -2
- package/dist/bridge-ZKbKqgFd.d.ts +239 -0
- package/dist/cart-documents-BLavRDiu.d.ts +89 -0
- package/dist/cart-documents.d.ts +1 -2
- package/dist/cart-documents.js +1 -1
- package/dist/{chunk-M7BPQ54D.js → chunk-2MRB6SMP.js} +4 -3
- package/dist/chunk-2MRB6SMP.js.map +1 -0
- package/dist/chunk-CKGI3Y7L.js +19 -0
- package/dist/chunk-CKGI3Y7L.js.map +1 -0
- package/dist/{chunk-GGOZELAA.js → chunk-EG34HLSX.js} +209 -162
- package/dist/chunk-EG34HLSX.js.map +1 -0
- package/dist/chunk-O6YZEY7X.js +1382 -0
- package/dist/chunk-O6YZEY7X.js.map +1 -0
- package/dist/{chunk-MCIFKJQK.js → chunk-R4N565GX.js} +5 -2
- package/dist/chunk-R4N565GX.js.map +1 -0
- package/dist/{chunk-XMTWFJCZ.js → chunk-RFM27BKZ.js} +31 -7
- package/dist/chunk-RFM27BKZ.js.map +1 -0
- package/dist/{chunk-MYDKIJRH.js → chunk-SVMYFYIA.js} +2 -2
- package/dist/{chunk-MYDKIJRH.js.map → chunk-SVMYFYIA.js.map} +1 -1
- package/dist/{chunk-H3D7BAOL.js → chunk-VOTBNOWH.js} +21 -3
- package/dist/chunk-VOTBNOWH.js.map +1 -0
- package/dist/{chunk-PXVDVUFX.js → chunk-W74FGUZH.js} +10 -3
- package/dist/chunk-W74FGUZH.js.map +1 -0
- package/dist/{chunk-2IWNUDSZ.js → chunk-WNXI3MPM.js} +2 -2
- package/dist/chunk-WNXI3MPM.js.map +1 -0
- package/dist/chunk-XXNCFWXT.js +2118 -0
- package/dist/chunk-XXNCFWXT.js.map +1 -0
- package/dist/{client-bsiNPHBi.d.ts → client-CwOPPpFF.d.ts} +11 -1
- package/dist/{createCartHandler-C4RrPwSG.d.ts → createCartHandler-7DdKB-GF.d.ts} +1 -1
- package/dist/custom-css-Bl7Ur3-H.d.ts +6 -0
- package/dist/editor.d.ts +57 -104
- package/dist/editor.js +270 -1
- package/dist/editor.js.map +1 -1
- package/dist/events-react.d.ts +1 -1
- package/dist/events-react.js +1 -1
- package/dist/events.d.ts +3 -3
- package/dist/events.js +1 -1
- package/dist/{fetch-M3Y-fQrW.d.ts → fetch-Bq_cc8_G.d.ts} +5 -0
- package/dist/hydrogen-Bu7k0kE4.d.ts +259 -0
- package/dist/index.d.ts +74 -51
- package/dist/index.js +19 -15
- package/dist/index.js.map +1 -1
- package/dist/react-router.d.ts +30 -9
- package/dist/react-router.js +16 -7
- package/dist/react-router.js.map +1 -1
- package/dist/react.d.ts +79 -11
- package/dist/react.js +279 -10
- package/dist/react.js.map +1 -1
- package/dist/{routing-sEonP93J.d.ts → routing-Bz3Cg0BW.d.ts} +36 -6
- package/dist/seo.d.ts +7 -4
- package/dist/seo.js +2 -2
- package/dist/settings.d.ts +14 -4
- package/dist/settings.js +2 -2
- package/dist/{shop-BJSvtmnV.d.ts → shop-CnrnSAJw.d.ts} +33 -6
- package/dist/{store-CtCWHI8H.d.ts → store-DO08fzJi.d.ts} +1 -1
- package/dist/storefront-api-types.d.ts +12 -0
- package/dist/{types-BDhHWZsP.d.ts → types-BkY0yET-.d.ts} +3 -3
- package/dist/{types-bcbQzx87.d.ts → types-DZX8ScsJ.d.ts} +2 -0
- package/package.json +4 -4
- package/dist/cart-documents-CwwRTvm8.d.ts +0 -21
- package/dist/chunk-2IWNUDSZ.js.map +0 -1
- package/dist/chunk-GGOZELAA.js.map +0 -1
- package/dist/chunk-H3D7BAOL.js.map +0 -1
- package/dist/chunk-M7BPQ54D.js.map +0 -1
- package/dist/chunk-MCIFKJQK.js.map +0 -1
- package/dist/chunk-PXVDVUFX.js.map +0 -1
- package/dist/chunk-PXZ737N3.js +0 -439
- package/dist/chunk-PXZ737N3.js.map +0 -1
- package/dist/chunk-XMTWFJCZ.js.map +0 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { S as StoredThemeSettings } from './fetch-
|
|
1
|
+
import { S as StoredThemeSettings } from './fetch-Bq_cc8_G.js';
|
|
2
2
|
import { C as CacheStrategy, K as KotaoCache, S as StorefrontClient, b as StorefrontCacheInput } from './client-D51WdvYR.js';
|
|
3
|
-
import { C as CartHandler } from './createCartHandler-
|
|
4
|
-
import { E as EventsClient } from './client-
|
|
5
|
-
import { H as HydrogenSession } from './types-
|
|
3
|
+
import { C as CartHandler } from './createCartHandler-7DdKB-GF.js';
|
|
4
|
+
import { E as EventsClient } from './client-CwOPPpFF.js';
|
|
5
|
+
import { H as HydrogenSession } from './types-DZX8ScsJ.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Typed customer-account shapes for the `@kotao/storefront` SDK surface (#91). The names/signatures
|
|
@@ -123,7 +123,7 @@ interface CustomerAccountClient {
|
|
|
123
123
|
requestLoginCode(input: RequestLoginCodeInput): Promise<RequestLoginCodeResult>;
|
|
124
124
|
/**
|
|
125
125
|
* POST to the proxy `/account/verify` endpoint with the OTP code. Returns the raw proxy `Response`
|
|
126
|
-
* so its `Set-Cookie` and 302 redirect headers propagate to the theme's
|
|
126
|
+
* so its `Set-Cookie` and 302 redirect headers propagate to the theme's RR8 action unchanged —
|
|
127
127
|
* do NOT swallow or re-create this Response.
|
|
128
128
|
*/
|
|
129
129
|
verifyLoginCode(input: VerifyLoginCodeInput): Promise<Response>;
|
|
@@ -217,12 +217,22 @@ interface KotaoSession extends HydrogenSession {
|
|
|
217
217
|
}
|
|
218
218
|
interface KotaoContext {
|
|
219
219
|
readonly storefront: StorefrontClient;
|
|
220
|
+
/**
|
|
221
|
+
* Authenticated fetch for REST resources below `STOREFRONT_API_ENDPOINT`.
|
|
222
|
+
*
|
|
223
|
+
* This is deliberately not a general-purpose fetch: theme code is untrusted, so requests outside
|
|
224
|
+
* the configured storefront API origin + base path fail closed before Gateway-signed shop headers
|
|
225
|
+
* are attached.
|
|
226
|
+
*/
|
|
227
|
+
readonly fetch: typeof fetch;
|
|
220
228
|
readonly events: EventsClient;
|
|
221
229
|
readonly cart: CartHandler;
|
|
222
230
|
readonly customerAccount: CustomerAccountClient;
|
|
223
231
|
readonly geo: Geo | null;
|
|
224
232
|
readonly withCache: WithCache;
|
|
225
233
|
readonly locale: string | null;
|
|
234
|
+
/** Gateway-selected Market context. Informational in theme code; API authorization uses HMAC. */
|
|
235
|
+
readonly market?: StorefrontMarketContext | null;
|
|
226
236
|
/** Cookie-presence hint. `isLoggedIn` is true when the session cookie is present in the request.
|
|
227
237
|
* The authoritative check (HMAC verification) happens server-side in the proxy. */
|
|
228
238
|
readonly session: KotaoSession;
|
|
@@ -236,8 +246,26 @@ interface KotaoContext {
|
|
|
236
246
|
*/
|
|
237
247
|
readonly loadThemeSettings: (opts?: {
|
|
238
248
|
readonly fetch?: typeof fetch;
|
|
249
|
+
readonly templateHandle?: string;
|
|
239
250
|
}) => Promise<StoredThemeSettings>;
|
|
240
251
|
}
|
|
252
|
+
interface StorefrontMarketContext {
|
|
253
|
+
readonly id: string;
|
|
254
|
+
readonly pathPrefix: string | null;
|
|
255
|
+
readonly defaultLocale: string;
|
|
256
|
+
readonly alternateLocales: readonly string[];
|
|
257
|
+
readonly rootUrls: readonly {
|
|
258
|
+
readonly locale: string;
|
|
259
|
+
readonly url: string;
|
|
260
|
+
}[];
|
|
261
|
+
readonly canonicalUrl: string;
|
|
262
|
+
readonly themeId: string | null;
|
|
263
|
+
readonly settingsEnvironmentHandle: string | null;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
declare function marketContextFromHeaders(headers: {
|
|
267
|
+
get(name: string): string | null;
|
|
268
|
+
}): StorefrontMarketContext | null;
|
|
241
269
|
declare function trustedShopOriginFromHeaders(headers: Headers): string | undefined;
|
|
242
270
|
/**
|
|
243
271
|
* Framework-agnostic per-request context, mirroring Hydrogen's `createHydrogenContext`:
|
|
@@ -256,6 +284,8 @@ interface StrippedLocalePath {
|
|
|
256
284
|
}
|
|
257
285
|
interface LocalizePathOptions {
|
|
258
286
|
readonly primaryLocale?: string | null;
|
|
287
|
+
/** Trusted Market subfolder prefix that must survive locale switching. */
|
|
288
|
+
readonly marketPathPrefix?: string | null;
|
|
259
289
|
}
|
|
260
290
|
declare function isLocalePathSegment(segment: string): boolean;
|
|
261
291
|
declare function localeFromAcceptLanguage(header: string | null | undefined, availableLocales?: readonly string[]): string | null;
|
|
@@ -266,4 +296,4 @@ declare function stripLocalePrefixFromPathname(pathname: string): StrippedLocale
|
|
|
266
296
|
declare function stripLocalePrefixFromRequest(request: Request): Request;
|
|
267
297
|
declare function localizePath(path: string, locale: string | null | undefined, options?: LocalizePathOptions): string;
|
|
268
298
|
|
|
269
|
-
export { type Address as A,
|
|
299
|
+
export { type Address as A, signGeo as B, type CustomerAccountClient as C, stripLocalePrefixFromPathname as D, trustedShopOriginFromHeaders as E, verifyGeo as F, GEO_HEADER as G, type KotaoContext as K, type LocalizePathOptions as L, type Money as M, type Order as O, ROUTING_LOCALE_HEADER as R, type StorefrontExecutionContext as S, type VerifyLoginCodeInput as V, type WithCache as W, type KotaoEnv as a, type KotaoSession as b, type AddressConnection as c, type CustomerAccount as d, CustomerAccountError as e, type CustomerAccountErrorCode as f, GEO_SIGNATURE_HEADER as g, type Geo as h, type OrderConnection as i, type OrderPageInfo as j, type OrdersOptions as k, ROUTING_ORIGINAL_PATHNAME_HEADER as l, type RequestLoginCodeInput as m, type RequestLoginCodeResult as n, type StorefrontMarketContext as o, type StrippedLocalePath as p, createKotaoContext as q, createWithCache as r, stripLocalePrefixFromRequest as s, isLocalePathSegment as t, localeFromAcceptLanguage as u, localeFromPathname as v, localeFromRequest as w, localizePath as x, marketContextFromHeaders as y, originalPathnameFromRequest as z };
|
package/dist/seo.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { S as SeoConfig, b as SeoDescriptor, J as JsonLd } from './types-
|
|
2
|
-
export {
|
|
1
|
+
import { S as SeoConfig, b as SeoDescriptor, J as JsonLd, A as Alternate } from './types-BkY0yET-.js';
|
|
2
|
+
export { O as OpenGraph, a as OpenGraphImage, T as TwitterCard } from './types-BkY0yET-.js';
|
|
3
3
|
import { S as StorefrontClient } from './client-D51WdvYR.js';
|
|
4
4
|
import './http-types-CGh8WGHB.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* Merge SEO config across levels and emit a flat, deduplicated descriptor list (
|
|
7
|
+
* Merge SEO config across levels and emit a flat, deduplicated descriptor list (RR8 `meta`-compatible):
|
|
8
8
|
* title, description, canonical, robots, Open Graph, Twitter Card, hreflang alternates, and JSON-LD.
|
|
9
9
|
* Open Graph / Twitter titles + descriptions fall back to the page title/description (Hydrogen-shaped).
|
|
10
10
|
*/
|
|
@@ -95,6 +95,7 @@ declare function restaurantJsonLd(input: Omit<LocalBusinessInput, 'type'>): Json
|
|
|
95
95
|
* Storefront API or a search index — an open question, NOT decided here): build the entry list, then call
|
|
96
96
|
* these. The index shape exists so large catalogs split into child sitemaps rather than one document.
|
|
97
97
|
*/
|
|
98
|
+
|
|
98
99
|
type ChangeFreq = 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';
|
|
99
100
|
interface SitemapEntry {
|
|
100
101
|
readonly loc: string;
|
|
@@ -102,6 +103,8 @@ interface SitemapEntry {
|
|
|
102
103
|
readonly changefreq?: ChangeFreq;
|
|
103
104
|
/** 0.0–1.0 (clamped). */
|
|
104
105
|
readonly priority?: number;
|
|
106
|
+
/** Reciprocal language variants for this URL, including x-default when applicable. */
|
|
107
|
+
readonly alternates?: readonly Alternate[];
|
|
105
108
|
}
|
|
106
109
|
interface SitemapIndexEntry {
|
|
107
110
|
readonly loc: string;
|
|
@@ -155,4 +158,4 @@ declare function resolveStorefrontRedirect(storefront: StorefrontClient, path: s
|
|
|
155
158
|
*/
|
|
156
159
|
declare function storefrontRedirect(options: StorefrontRedirectOptions): Promise<Response>;
|
|
157
160
|
|
|
158
|
-
export { type AddressInput, type BreadcrumbItem, type ChangeFreq, type GeoInput, JsonLd, type LocalBusinessInput, type OfferInput, type OrganizationInput, type ProductJsonLdInput, type RedirectLookup, type RedirectOptions, type RobotsOptions, SeoConfig, SeoDescriptor, type SitemapEntry, type SitemapIndexEntry, type StorefrontRedirectOptions, URL_REDIRECT_QUERY, type WebSiteInput, breadcrumbListJsonLd, buildRobotsTxt, buildSitemapIndexXml, buildSitemapXml, getSeoMeta, localBusinessJsonLd, organizationJsonLd, productJsonLd, resolveRedirect, resolveStorefrontRedirect, restaurantJsonLd, robotsResponse, serializeJsonLd, sitemapIndexResponse, sitemapResponse, storefrontRedirect, websiteJsonLd };
|
|
161
|
+
export { type AddressInput, Alternate, type BreadcrumbItem, type ChangeFreq, type GeoInput, JsonLd, type LocalBusinessInput, type OfferInput, type OrganizationInput, type ProductJsonLdInput, type RedirectLookup, type RedirectOptions, type RobotsOptions, SeoConfig, SeoDescriptor, type SitemapEntry, type SitemapIndexEntry, type StorefrontRedirectOptions, URL_REDIRECT_QUERY, type WebSiteInput, breadcrumbListJsonLd, buildRobotsTxt, buildSitemapIndexXml, buildSitemapXml, getSeoMeta, localBusinessJsonLd, organizationJsonLd, productJsonLd, resolveRedirect, resolveStorefrontRedirect, restaurantJsonLd, robotsResponse, serializeJsonLd, sitemapIndexResponse, sitemapResponse, storefrontRedirect, websiteJsonLd };
|
package/dist/seo.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { URL_REDIRECT_QUERY, breadcrumbListJsonLd, buildRobotsTxt, buildSitemapIndexXml, buildSitemapXml, localBusinessJsonLd, organizationJsonLd, productJsonLd, resolveRedirect, resolveStorefrontRedirect, restaurantJsonLd, robotsResponse, sitemapIndexResponse, sitemapResponse, storefrontRedirect, websiteJsonLd } from './chunk-
|
|
2
|
-
export { getSeoMeta, serializeJsonLd } from './chunk-
|
|
1
|
+
export { URL_REDIRECT_QUERY, breadcrumbListJsonLd, buildRobotsTxt, buildSitemapIndexXml, buildSitemapXml, localBusinessJsonLd, organizationJsonLd, productJsonLd, resolveRedirect, resolveStorefrontRedirect, restaurantJsonLd, robotsResponse, sitemapIndexResponse, sitemapResponse, storefrontRedirect, websiteJsonLd } from './chunk-W74FGUZH.js';
|
|
2
|
+
export { getSeoMeta, serializeJsonLd } from './chunk-SVMYFYIA.js';
|
|
3
3
|
//# sourceMappingURL=seo.js.map
|
|
4
4
|
//# sourceMappingURL=seo.js.map
|
package/dist/settings.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SectionSchema, Preset, ValuesDocument, SettingInput, SectionInstance } from '@kotao/storefront-contracts/theme';
|
|
2
|
-
import {
|
|
3
|
-
export { b as ResolvedBlock, T as ThemeSettingsStore, d as createThemeSettingsStore } from './store-
|
|
4
|
-
export { F as FetchThemeSettingsOptions, S as StoredThemeSettings, f as fetchThemeSettings } from './fetch-
|
|
2
|
+
import { a as ResolvedSection, R as ResolvedSettings, c as ThemeSettingsSnapshot } from './store-DO08fzJi.js';
|
|
3
|
+
export { b as ResolvedBlock, T as ThemeSettingsStore, d as createThemeSettingsStore } from './store-DO08fzJi.js';
|
|
4
|
+
export { F as FetchThemeSettingsOptions, S as StoredThemeSettings, f as fetchThemeSettings } from './fetch-Bq_cc8_G.js';
|
|
5
5
|
import './client-D51WdvYR.js';
|
|
6
6
|
import './http-types-CGh8WGHB.js';
|
|
7
7
|
|
|
@@ -51,4 +51,14 @@ interface ResolveThemeSettingsArgs {
|
|
|
51
51
|
/** Compose the merge over an entire values document → the snapshot a theme renders from. */
|
|
52
52
|
declare function resolveThemeSettings(args: ResolveThemeSettingsArgs): ThemeSettingsSnapshot;
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
/**
|
|
55
|
+
* Reconcile a platform-derived layout group with previously published merchant values.
|
|
56
|
+
*
|
|
57
|
+
* Synthetic groups such as `layout-static` are rebuilt from layout/theme.liquid and are not
|
|
58
|
+
* merchant-editable section groups. The current document therefore owns membership and order.
|
|
59
|
+
* Stored values only enrich matching instances, so removed/guarded sections cannot return after a
|
|
60
|
+
* runtime rebuild while saved settings for drawers and other surviving furniture remain intact.
|
|
61
|
+
*/
|
|
62
|
+
declare function reconcileSyntheticSectionGroup(current: ValuesDocument, stored: ValuesDocument | null | undefined): ValuesDocument;
|
|
63
|
+
|
|
64
|
+
export { type ResolveThemeSettingsArgs, ResolvedSection, ResolvedSettings, ThemeSettingsSnapshot, mergeSection, mergeSettings, reconcileSyntheticSectionGroup, resolveThemeSettings };
|
package/dist/settings.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { createThemeSettingsStore, mergeSection, mergeSettings, resolveThemeSettings } from './chunk-
|
|
2
|
-
export { fetchThemeSettings } from './chunk-
|
|
1
|
+
export { createThemeSettingsStore, mergeSection, mergeSettings, reconcileSyntheticSectionGroup, resolveThemeSettings } from './chunk-VOTBNOWH.js';
|
|
2
|
+
export { fetchThemeSettings } from './chunk-2MRB6SMP.js';
|
|
3
3
|
//# sourceMappingURL=settings.js.map
|
|
4
4
|
//# sourceMappingURL=settings.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { j as CartFormAction } from './types-
|
|
1
|
+
import { j as CartFormAction } from './types-DZX8ScsJ.js';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
3
|
|
|
4
4
|
interface CartFormProps {
|
|
@@ -79,18 +79,34 @@ declare const ANALYTICS_EVENTS: {
|
|
|
79
79
|
readonly productAddedToCart: "product_added_to_cart";
|
|
80
80
|
};
|
|
81
81
|
type AnalyticsEventName = (typeof ANALYTICS_EVENTS)[keyof typeof ANALYTICS_EVENTS];
|
|
82
|
+
type AnalyticsDeviceClass = 'mobile' | 'tablet' | 'desktop';
|
|
82
83
|
/** Ambient context the provider attaches to every event before it reaches the pixel. */
|
|
83
84
|
interface AnalyticsContext {
|
|
84
85
|
readonly shopId?: string;
|
|
85
86
|
readonly url?: string;
|
|
86
87
|
readonly geo?: AnalyticsGeo;
|
|
88
|
+
readonly referrer?: string;
|
|
89
|
+
readonly utmSource?: string;
|
|
90
|
+
readonly utmMedium?: string;
|
|
91
|
+
readonly utmCampaign?: string;
|
|
92
|
+
readonly deviceClass?: AnalyticsDeviceClass;
|
|
87
93
|
}
|
|
88
94
|
interface PageViewedPayload {
|
|
89
95
|
readonly title?: string;
|
|
90
96
|
}
|
|
91
97
|
interface ProductViewedPayload {
|
|
92
98
|
readonly productId: string;
|
|
99
|
+
/** Stable offer id; Google Merchant Center and Google ecommerce events use this as item_id. */
|
|
100
|
+
readonly variantId?: string;
|
|
93
101
|
readonly handle?: string;
|
|
102
|
+
readonly title?: string;
|
|
103
|
+
readonly variantTitle?: string;
|
|
104
|
+
readonly vendor?: string;
|
|
105
|
+
readonly sku?: string;
|
|
106
|
+
/** Major-unit price, e.g. 24.95. */
|
|
107
|
+
readonly price?: number;
|
|
108
|
+
readonly currency?: string;
|
|
109
|
+
readonly quantity?: number;
|
|
94
110
|
}
|
|
95
111
|
interface CollectionViewedPayload {
|
|
96
112
|
readonly collectionId: string;
|
|
@@ -107,6 +123,13 @@ interface ProductAddedToCartPayload {
|
|
|
107
123
|
readonly productId: string;
|
|
108
124
|
readonly variantId: string;
|
|
109
125
|
readonly quantity: number;
|
|
126
|
+
readonly title?: string;
|
|
127
|
+
readonly variantTitle?: string;
|
|
128
|
+
readonly vendor?: string;
|
|
129
|
+
readonly sku?: string;
|
|
130
|
+
/** Major-unit price, e.g. 24.95. */
|
|
131
|
+
readonly price?: number;
|
|
132
|
+
readonly currency?: string;
|
|
110
133
|
}
|
|
111
134
|
/** Event name → payload (the typed pub/sub surface). */
|
|
112
135
|
interface AnalyticsEventMap {
|
|
@@ -135,6 +158,8 @@ interface AnalyticsEmitter {
|
|
|
135
158
|
}
|
|
136
159
|
declare function createAnalyticsEmitter(): AnalyticsEmitter;
|
|
137
160
|
|
|
161
|
+
type AnonymousAnalyticsContext = Pick<AnalyticsContext, 'url'>;
|
|
162
|
+
|
|
138
163
|
/** The actual network send. Injectable so tests don't touch the network. */
|
|
139
164
|
type PixelSend = (endpoint: string, body: string) => void;
|
|
140
165
|
interface PixelTransportOptions {
|
|
@@ -163,8 +188,10 @@ interface AnalyticsBusOptions {
|
|
|
163
188
|
readonly transport: PixelTransport;
|
|
164
189
|
/** Legacy consent seam retained for API compatibility while Storefront consent UI is disabled. */
|
|
165
190
|
readonly getConsent: () => ConsentState;
|
|
166
|
-
/** Ambient context (
|
|
191
|
+
/** Ambient context (including attribution and device class) attached to consented events. */
|
|
167
192
|
readonly getContext?: () => AnalyticsContext;
|
|
193
|
+
/** Sanitized same-origin page URL used only for the anonymous page-view fallback. */
|
|
194
|
+
readonly getAnonymousContext?: () => AnonymousAnalyticsContext;
|
|
168
195
|
/** Clock seam for deterministic timestamps in tests. */
|
|
169
196
|
readonly now?: () => string;
|
|
170
197
|
}
|
|
@@ -174,9 +201,9 @@ interface AnalyticsBus {
|
|
|
174
201
|
flush(): void;
|
|
175
202
|
}
|
|
176
203
|
/**
|
|
177
|
-
* Wire the emitter to the pixel. Every published event reaches theme subscribers (via the emitter)
|
|
178
|
-
*
|
|
179
|
-
*
|
|
204
|
+
* Wire the emitter to the pixel. Every published event reaches theme subscribers (via the emitter).
|
|
205
|
+
* First-party recording is consent-strict: denied visits get only an anonymous page_viewed row and
|
|
206
|
+
* never evaluate ambient context, which may read attribution or device-class signals.
|
|
180
207
|
*/
|
|
181
208
|
declare function createAnalyticsBus(options: AnalyticsBusOptions): AnalyticsBus;
|
|
182
209
|
|
|
@@ -199,4 +226,4 @@ interface GetShopAnalyticsOptions {
|
|
|
199
226
|
}
|
|
200
227
|
declare function getShopAnalytics(options: GetShopAnalyticsOptions): ShopAnalytics;
|
|
201
228
|
|
|
202
|
-
export { type AnalyticsContext as A, type BoundNonceProvider as B, type ConsentState as C, DENIED_CONSENT as D, type EventHandler as E,
|
|
229
|
+
export { type AnalyticsContext as A, type BoundNonceProvider as B, type ConsentState as C, DENIED_CONSENT as D, type EventHandler as E, createAnalyticsBus as F, GRANTED_CONSENT as G, createAnalyticsEmitter as H, createPixelTransport as I, getShopAnalytics as J, isGranted as K, mergeConsent as L, parseConsent as M, readConsentCookie as N, serializeConsent as O, type PageViewedPayload as P, type ShopAnalytics as S, type AnalyticsEmitter as a, type AnalyticsBus as b, type ConsentBucket as c, ANALYTICS_EVENTS as d, type AnalyticsBusOptions as e, type AnalyticsDeviceClass as f, getCartFormInput as g, type AnalyticsEventMap as h, type AnalyticsEventName as i, type AnalyticsGeo as j, CONSENT_BUCKETS as k, CONSENT_COOKIE as l, CartForm as m, type CartFormProps as n, type CartViewedPayload as o, type CollectionViewedPayload as p, type GetShopAnalyticsOptions as q, type PixelEvent as r, type PixelSend as s, type PixelTransport as t, useNonce as u, type PixelTransportOptions as v, type ProductAddedToCartPayload as w, type ProductViewedPayload as x, type SearchViewedPayload as y, buildConsentCookie as z };
|
|
@@ -64,4 +64,4 @@ interface ThemeSettingsStore {
|
|
|
64
64
|
}
|
|
65
65
|
declare function createThemeSettingsStore(initial: ThemeSettingsSnapshot): ThemeSettingsStore;
|
|
66
66
|
|
|
67
|
-
export { type ResolvedSettings as R, type ThemeSettingsStore as T, type
|
|
67
|
+
export { type ResolvedSettings as R, type ThemeSettingsStore as T, type ResolvedSection as a, type ResolvedBlock as b, type ThemeSettingsSnapshot as c, createThemeSettingsStore as d };
|
|
@@ -201,6 +201,17 @@ interface ProductVariant extends LooseObject {
|
|
|
201
201
|
readonly id: string;
|
|
202
202
|
readonly image?: Image | null;
|
|
203
203
|
readonly price: MoneyV2;
|
|
204
|
+
readonly quantityRule?: {
|
|
205
|
+
readonly minimum: number;
|
|
206
|
+
readonly maximum: number | null;
|
|
207
|
+
readonly increment: number;
|
|
208
|
+
} | null;
|
|
209
|
+
readonly quantityPriceBreaks?: {
|
|
210
|
+
readonly nodes?: Array<{
|
|
211
|
+
readonly minimumQuantity: number;
|
|
212
|
+
readonly price: MoneyV2;
|
|
213
|
+
}>;
|
|
214
|
+
};
|
|
204
215
|
readonly product: Pick<Product, 'id' | 'handle' | 'title'>;
|
|
205
216
|
readonly selectedOptions: SelectedOption[];
|
|
206
217
|
readonly sku?: string | null;
|
|
@@ -289,6 +300,7 @@ interface CartBuyerIdentityInput extends LooseObject {
|
|
|
289
300
|
readonly customerAccessToken?: string | null;
|
|
290
301
|
readonly email?: string | null;
|
|
291
302
|
readonly phone?: string | null;
|
|
303
|
+
readonly companyLocationId?: string | null;
|
|
292
304
|
}
|
|
293
305
|
interface CartDiscountCode extends LooseObject {
|
|
294
306
|
readonly applicable?: boolean;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* SEO surface types for `@kotao/storefront` (ADR-0003 §SDK), Hydrogen-shaped. Framework-agnostic:
|
|
3
|
-
* `getSeoMeta` emits a flat descriptor list a theme can return from a React Router
|
|
3
|
+
* `getSeoMeta` emits a flat descriptor list a theme can return from a React Router 8 `meta` export or
|
|
4
4
|
* feed to the `<Seo/>` component.
|
|
5
5
|
*/
|
|
6
6
|
interface OpenGraphImage {
|
|
@@ -27,7 +27,7 @@ interface TwitterCard {
|
|
|
27
27
|
readonly description?: string;
|
|
28
28
|
readonly image?: string;
|
|
29
29
|
}
|
|
30
|
-
/** An hreflang alternate
|
|
30
|
+
/** An hreflang alternate emitted only when supplied. */
|
|
31
31
|
interface Alternate {
|
|
32
32
|
readonly hreflang: string;
|
|
33
33
|
readonly href: string;
|
|
@@ -56,7 +56,7 @@ interface SeoConfig {
|
|
|
56
56
|
/** schema.org JSON-LD object(s); accumulated (not overridden) across levels. */
|
|
57
57
|
readonly jsonLd?: JsonLd | readonly JsonLd[];
|
|
58
58
|
}
|
|
59
|
-
/** A head descriptor, shaped to be React Router
|
|
59
|
+
/** A head descriptor, shaped to be React Router 8 `meta`-export compatible. */
|
|
60
60
|
type SeoDescriptor = {
|
|
61
61
|
readonly title: string;
|
|
62
62
|
} | {
|
|
@@ -35,6 +35,7 @@ interface CartBuyerIdentityInput {
|
|
|
35
35
|
readonly phone?: string | null;
|
|
36
36
|
readonly countryCode?: string | null;
|
|
37
37
|
readonly customerAccessToken?: string | null;
|
|
38
|
+
readonly companyLocationId?: string | null;
|
|
38
39
|
}
|
|
39
40
|
interface CartMetafield {
|
|
40
41
|
readonly namespace: string;
|
|
@@ -104,6 +105,7 @@ interface CartBuyerIdentity {
|
|
|
104
105
|
readonly email: string | null;
|
|
105
106
|
readonly phone: string | null;
|
|
106
107
|
readonly countryCode: string | null;
|
|
108
|
+
readonly companyLocationId: string | null;
|
|
107
109
|
}
|
|
108
110
|
interface Cart {
|
|
109
111
|
readonly id: string;
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kotao/storefront",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
|
-
"description": "Kotao Storefronts theme SDK — framework-agnostic server runtime
|
|
6
|
+
"description": "Kotao Storefronts theme SDK — framework-agnostic server runtime, React Router 8 binding, and authenticated source-authoritative React/Hydrogen editor bridge (ADR-0003/ADR-0047). Leaf package (ADR-0006).",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
9
|
"url": "git+https://github.com/kotao-org/monorepo.git",
|
|
@@ -72,11 +72,11 @@
|
|
|
72
72
|
"LICENSE"
|
|
73
73
|
],
|
|
74
74
|
"dependencies": {
|
|
75
|
-
"@kotao/storefront-contracts": "^0.2.
|
|
75
|
+
"@kotao/storefront-contracts": "^0.2.3"
|
|
76
76
|
},
|
|
77
77
|
"peerDependencies": {
|
|
78
78
|
"react": "^18.2.0 || ^19.0.0",
|
|
79
|
-
"react-router": "^
|
|
79
|
+
"react-router": "^8.3.0"
|
|
80
80
|
},
|
|
81
81
|
"peerDependenciesMeta": {
|
|
82
82
|
"react": {
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { CartAdapter } from '@kotao/smart-cart';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* All fully-resolved cart GraphQL document strings from the react seam adapter.
|
|
5
|
-
* Exported for schema-validation tests (apps/storefront-api/test/cart-graphql-documents.test.ts)
|
|
6
|
-
* that submit each document to a real graphql-yoga instance and assert zero validation errors,
|
|
7
|
-
* catching invalid field selections (e.g. subfields on a scalar) at test time rather than runtime.
|
|
8
|
-
*/
|
|
9
|
-
declare const REACT_SEAM_CART_DOCUMENTS: readonly string[];
|
|
10
|
-
/**
|
|
11
|
-
* A CartAdapter that drives the storefront-api cart over the same-origin /api/storefront GraphQL proxy
|
|
12
|
-
* (the proxy injects the read token + resolves the shop server-side). The theme supplies the cart id
|
|
13
|
-
* (from its loader's cart cookie/session) and renders <CartDrawerOverlay adapter={this} />.
|
|
14
|
-
*/
|
|
15
|
-
declare function createStorefrontApiCartAdapter(opts: {
|
|
16
|
-
readonly cartId: string;
|
|
17
|
-
readonly apiPath?: string;
|
|
18
|
-
readonly fetchImpl?: typeof fetch;
|
|
19
|
-
}): CartAdapter;
|
|
20
|
-
|
|
21
|
-
export { REACT_SEAM_CART_DOCUMENTS as R, createStorefrontApiCartAdapter as c };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/react/storefront-cart-adapter.ts"],"names":[],"mappings":"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","file":"chunk-2IWNUDSZ.js","sourcesContent":["import type { CartAdapter, SmartCartLine, SmartCartState } from '@kotao/smart-cart'\n\ninterface GqlMoney {\n amount: string\n currencyCode: string\n}\ninterface GqlCartLine {\n id: string\n quantity: number\n attributes: { key: string; value: string | null }[] | null\n cost: { totalAmount: GqlMoney }\n merchandise: {\n id: string\n title: string | null\n image: { url: string } | null\n product: { title: string }\n }\n}\ninterface GqlCart {\n checkoutUrl: string\n cost: { subtotalAmount: GqlMoney; discountTotal?: GqlMoney }\n discountCodes?: string[]\n lines: { nodes: GqlCartLine[] }\n}\n\n// GraphQL Money is a decimal string (\"216.00\"); SmartCartState money is integer minor units.\nconst toMinorUnits = (m: GqlMoney): number => Math.round(parseFloat(m.amount) * 100)\n\nconst CART_FIELDS = `\n checkoutUrl\n cost { subtotalAmount { amount currencyCode } discountTotal { amount currencyCode } }\n discountCodes\n lines(first: 250) { nodes {\n id quantity\n attributes { key value }\n cost { totalAmount { amount currencyCode } }\n merchandise { ... on ProductVariant { id title image { url } product { title } } }\n } }`\nconst CART_QUERY = `query KotaoSmartCart($cartId: ID!) { cart(id: $cartId) { ${CART_FIELDS} } }`\nconst LINES_ADD = `mutation KotaoSmartCartAdd($cartId: ID!, $lines: [CartLineInput!]!) { cartLinesAdd(cartId: $cartId, lines: $lines) { cart { ${CART_FIELDS} } } }`\nconst LINES_UPDATE = `mutation KotaoSmartCartUpdate($cartId: ID!, $lines: [CartLineUpdateInput!]!) { cartLinesUpdate(cartId: $cartId, lines: $lines) { cart { ${CART_FIELDS} } } }`\nconst LINES_REMOVE = `mutation KotaoSmartCartRemove($cartId: ID!, $lineIds: [ID!]!) { cartLinesRemove(cartId: $cartId, lineIds: $lineIds) { cart { ${CART_FIELDS} } } }`\nconst DISCOUNT_CODES_UPDATE = `mutation KotaoSmartCartDiscountCodes($cartId: ID!, $discountCodes: [String!]!) { cartDiscountCodesUpdate(cartId: $cartId, discountCodes: $discountCodes) { cart { ${CART_FIELDS} } } }`\n\n/**\n * All fully-resolved cart GraphQL document strings from the react seam adapter.\n * Exported for schema-validation tests (apps/storefront-api/test/cart-graphql-documents.test.ts)\n * that submit each document to a real graphql-yoga instance and assert zero validation errors,\n * catching invalid field selections (e.g. subfields on a scalar) at test time rather than runtime.\n */\nexport const REACT_SEAM_CART_DOCUMENTS: readonly string[] = [\n CART_QUERY,\n LINES_ADD,\n LINES_UPDATE,\n LINES_REMOVE,\n DISCOUNT_CODES_UPDATE,\n]\n\nfunction mapCart(c: GqlCart): SmartCartState {\n const currency = c.cost.subtotalAmount.currencyCode\n const lines: SmartCartLine[] = c.lines.nodes.map((l) => {\n const attributes: Record<string, string> = {}\n for (const a of l.attributes ?? []) {\n if (a.value !== null) attributes[a.key] = a.value\n }\n const hasAttributes = Object.keys(attributes).length > 0\n return {\n id: l.id,\n title: l.merchandise.product.title,\n variantTitle: l.merchandise.title,\n variantId: l.merchandise.id ?? null,\n quantity: l.quantity,\n imageUrl: l.merchandise.image?.url ?? null,\n linePrice: { amount: toMinorUnits(l.cost.totalAmount), currency },\n ...(hasAttributes && { attributes }),\n }\n })\n const discountMinorUnits = c.cost.discountTotal != null ? toMinorUnits(c.cost.discountTotal) : 0\n const appliedCodes = c.discountCodes?.filter((code) => code.length > 0)\n return {\n lines,\n subtotal: { amount: toMinorUnits(c.cost.subtotalAmount), currency },\n checkoutUrl: c.checkoutUrl,\n currency,\n ...(discountMinorUnits > 0 && {\n discountTotal: { amount: discountMinorUnits, currency },\n }),\n ...(appliedCodes != null && appliedCodes.length > 0 && { appliedCodes }),\n }\n}\n\n/**\n * A CartAdapter that drives the storefront-api cart over the same-origin /api/storefront GraphQL proxy\n * (the proxy injects the read token + resolves the shop server-side). The theme supplies the cart id\n * (from its loader's cart cookie/session) and renders <CartDrawerOverlay adapter={this} />.\n */\nexport function createStorefrontApiCartAdapter(opts: {\n readonly cartId: string\n readonly apiPath?: string\n readonly fetchImpl?: typeof fetch\n}): CartAdapter {\n const fetchImpl = opts.fetchImpl ?? fetch\n const apiPath = opts.apiPath ?? '/api/storefront'\n const run = async (\n query: string,\n variables: Record<string, unknown>,\n key: string,\n ): Promise<SmartCartState> => {\n const res = await fetchImpl(apiPath, {\n method: 'POST',\n headers: { 'content-type': 'application/json', accept: 'application/json' },\n body: JSON.stringify({ query, variables }),\n })\n if (!res.ok) {\n throw new Error(`storefront cart request failed: ${res.status} ${res.statusText}`)\n }\n const json = (await res.json()) as { data?: Record<string, unknown> }\n const payload = json.data?.[key] as GqlCart | { cart: GqlCart } | undefined\n const cart = payload && 'cart' in payload ? payload.cart : (payload as GqlCart)\n return mapCart(cart)\n }\n return {\n getCart: () => run(CART_QUERY, { cartId: opts.cartId }, 'cart'),\n addLine: (merchandiseId, quantity, attributes) =>\n run(\n LINES_ADD,\n {\n cartId: opts.cartId,\n lines: [\n {\n merchandiseId,\n quantity,\n ...(attributes !== undefined && {\n attributes: Object.entries(attributes).map(([key, value]) => ({ key, value })),\n }),\n },\n ],\n },\n 'cartLinesAdd',\n ),\n updateLine: (id, quantity) =>\n run(LINES_UPDATE, { cartId: opts.cartId, lines: [{ id, quantity }] }, 'cartLinesUpdate'),\n removeLine: (id) =>\n run(LINES_REMOVE, { cartId: opts.cartId, lineIds: [id] }, 'cartLinesRemove'),\n updateDiscountCodes: (codes) =>\n run(\n DISCOUNT_CODES_UPDATE,\n { cartId: opts.cartId, discountCodes: codes },\n 'cartDiscountCodesUpdate',\n ),\n }\n}\n"]}
|