@neowhale/storefront 0.1.2 → 0.2.1
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 +1 -1
- package/dist/chunk-CUVDHOQ4.js +90 -0
- package/dist/chunk-CUVDHOQ4.js.map +1 -0
- package/dist/chunk-DAM7NZCI.cjs +92 -0
- package/dist/chunk-DAM7NZCI.cjs.map +1 -0
- package/dist/chunk-OP4LOUCV.cjs +291 -0
- package/dist/chunk-OP4LOUCV.cjs.map +1 -0
- package/dist/chunk-QIIKQ7DN.js +288 -0
- package/dist/chunk-QIIKQ7DN.js.map +1 -0
- package/dist/client-y0V1x0px.d.cts +305 -0
- package/dist/client-y0V1x0px.d.ts +305 -0
- package/dist/index.cjs +11 -2
- package/dist/index.d.cts +14 -267
- package/dist/index.d.ts +14 -267
- package/dist/index.js +2 -1
- package/dist/next/index.cjs +7 -7
- package/dist/next/index.cjs.map +1 -1
- package/dist/next/index.d.cts +1 -1
- package/dist/next/index.d.ts +1 -1
- package/dist/next/index.js +4 -4
- package/dist/next/index.js.map +1 -1
- package/dist/pixel-manager-CYtRIGo0.d.ts +10 -0
- package/dist/pixel-manager-Db6Czwr2.d.cts +10 -0
- package/dist/react/index.cjs +69 -13
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +25 -3
- package/dist/react/index.d.ts +25 -3
- package/dist/react/index.js +69 -14
- package/dist/react/index.js.map +1 -1
- package/package.json +8 -1
- package/dist/chunk-PR4PUHVN.js +0 -273
- package/dist/chunk-PR4PUHVN.js.map +0 -1
- package/dist/chunk-XMLH3TLA.cjs +0 -275
- package/dist/chunk-XMLH3TLA.cjs.map +0 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
React and Next.js SDK for WhaleTools storefronts. Provides a typed API client, React hooks for cart/auth/analytics, and Next.js server utilities -- everything needed to build a headless storefront against the Whale Gateway API.
|
|
4
4
|
|
|
5
|
-
**v0.1.
|
|
5
|
+
**v0.1.2** | [npm](https://www.npmjs.com/package/@neowhale/storefront)
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// src/pixels/meta-pixel.ts
|
|
2
|
+
var EVENT_MAP = {
|
|
3
|
+
page_view: "PageView",
|
|
4
|
+
product_view: "ViewContent",
|
|
5
|
+
add_to_cart: "AddToCart",
|
|
6
|
+
remove_from_cart: "RemoveFromCart",
|
|
7
|
+
begin_checkout: "InitiateCheckout",
|
|
8
|
+
purchase: "Purchase",
|
|
9
|
+
search: "Search",
|
|
10
|
+
category_view: "ViewContent"
|
|
11
|
+
};
|
|
12
|
+
var MetaPixelProvider = class {
|
|
13
|
+
constructor(pixelId) {
|
|
14
|
+
this.name = "meta";
|
|
15
|
+
this.loaded = false;
|
|
16
|
+
this.pixelId = pixelId;
|
|
17
|
+
}
|
|
18
|
+
async load() {
|
|
19
|
+
if (typeof window === "undefined") return;
|
|
20
|
+
if (this.loaded) return;
|
|
21
|
+
const w = window;
|
|
22
|
+
if (!w.fbq) {
|
|
23
|
+
const n = w.fbq = function(...args) {
|
|
24
|
+
n.callMethod ? n.callMethod.apply(n, args) : n.queue.push(args);
|
|
25
|
+
};
|
|
26
|
+
if (!w._fbq) w._fbq = n;
|
|
27
|
+
n.push = n;
|
|
28
|
+
n.loaded = true;
|
|
29
|
+
n.version = "2.0";
|
|
30
|
+
n.queue = [];
|
|
31
|
+
}
|
|
32
|
+
await new Promise((resolve) => {
|
|
33
|
+
const script = document.createElement("script");
|
|
34
|
+
script.async = true;
|
|
35
|
+
script.src = "https://connect.facebook.net/en_US/fbevents.js";
|
|
36
|
+
script.onload = () => resolve();
|
|
37
|
+
script.onerror = () => resolve();
|
|
38
|
+
const first = document.getElementsByTagName("script")[0];
|
|
39
|
+
first?.parentNode?.insertBefore(script, first);
|
|
40
|
+
});
|
|
41
|
+
w.fbq("init", this.pixelId);
|
|
42
|
+
w.fbq("track", "PageView");
|
|
43
|
+
this.loaded = true;
|
|
44
|
+
}
|
|
45
|
+
track(event, params) {
|
|
46
|
+
if (typeof window === "undefined") return;
|
|
47
|
+
const w = window;
|
|
48
|
+
if (typeof w.fbq !== "function") return;
|
|
49
|
+
const metaEvent = EVENT_MAP[event];
|
|
50
|
+
if (!metaEvent) return;
|
|
51
|
+
if (params && Object.keys(params).length > 0) {
|
|
52
|
+
w.fbq("track", metaEvent, params);
|
|
53
|
+
} else {
|
|
54
|
+
w.fbq("track", metaEvent);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
isLoaded() {
|
|
58
|
+
return this.loaded;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// src/pixels/pixel-manager.ts
|
|
63
|
+
var PROVIDER_REGISTRY = {
|
|
64
|
+
meta: MetaPixelProvider
|
|
65
|
+
};
|
|
66
|
+
var PixelManager = class {
|
|
67
|
+
constructor(configs) {
|
|
68
|
+
this.providers = [];
|
|
69
|
+
for (const config of configs) {
|
|
70
|
+
const Ctor = PROVIDER_REGISTRY[config.provider];
|
|
71
|
+
if (Ctor) {
|
|
72
|
+
this.providers.push(new Ctor(config.pixel_id));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
async initialize() {
|
|
77
|
+
await Promise.all(this.providers.map((p) => p.load()));
|
|
78
|
+
}
|
|
79
|
+
track(event, params) {
|
|
80
|
+
for (const provider of this.providers) {
|
|
81
|
+
if (provider.isLoaded()) {
|
|
82
|
+
provider.track(event, params);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export { PixelManager };
|
|
89
|
+
//# sourceMappingURL=chunk-CUVDHOQ4.js.map
|
|
90
|
+
//# sourceMappingURL=chunk-CUVDHOQ4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/pixels/meta-pixel.ts","../src/pixels/pixel-manager.ts"],"names":[],"mappings":"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","file":"chunk-CUVDHOQ4.js","sourcesContent":["import type { PixelProvider } from './types.js'\n\n/** Map SDK event names → Meta standard event names */\nconst EVENT_MAP: Record<string, string> = {\n page_view: 'PageView',\n product_view: 'ViewContent',\n add_to_cart: 'AddToCart',\n remove_from_cart: 'RemoveFromCart',\n begin_checkout: 'InitiateCheckout',\n purchase: 'Purchase',\n search: 'Search',\n category_view: 'ViewContent',\n}\n\nexport class MetaPixelProvider implements PixelProvider {\n readonly name = 'meta'\n private pixelId: string\n private loaded = false\n\n constructor(pixelId: string) {\n this.pixelId = pixelId\n }\n\n async load(): Promise<void> {\n if (typeof window === 'undefined') return\n if (this.loaded) return\n\n // Initialize fbq queue\n const w = window as any\n if (!w.fbq) {\n const n: any = (w.fbq = function (...args: any[]) {\n n.callMethod ? n.callMethod.apply(n, args) : n.queue.push(args)\n })\n if (!w._fbq) w._fbq = n\n n.push = n\n n.loaded = true\n n.version = '2.0'\n n.queue = []\n }\n\n // Inject script\n await new Promise<void>((resolve) => {\n const script = document.createElement('script')\n script.async = true\n script.src = 'https://connect.facebook.net/en_US/fbevents.js'\n script.onload = () => resolve()\n script.onerror = () => resolve() // don't block on load failure\n const first = document.getElementsByTagName('script')[0]\n first?.parentNode?.insertBefore(script, first)\n })\n\n w.fbq('init', this.pixelId)\n w.fbq('track', 'PageView')\n this.loaded = true\n }\n\n track(event: string, params?: Record<string, unknown>): void {\n if (typeof window === 'undefined') return\n const w = window as any\n if (typeof w.fbq !== 'function') return\n\n const metaEvent = EVENT_MAP[event]\n if (!metaEvent) return\n\n if (params && Object.keys(params).length > 0) {\n w.fbq('track', metaEvent, params)\n } else {\n w.fbq('track', metaEvent)\n }\n }\n\n isLoaded(): boolean {\n return this.loaded\n }\n}\n","import type { PixelConfig, PixelProvider } from './types.js'\nimport { MetaPixelProvider } from './meta-pixel.js'\n\nconst PROVIDER_REGISTRY: Record<string, new (pixelId: string) => PixelProvider> = {\n meta: MetaPixelProvider,\n}\n\nexport class PixelManager {\n private providers: PixelProvider[] = []\n\n constructor(configs: PixelConfig[]) {\n for (const config of configs) {\n const Ctor = PROVIDER_REGISTRY[config.provider]\n if (Ctor) {\n this.providers.push(new Ctor(config.pixel_id))\n }\n }\n }\n\n async initialize(): Promise<void> {\n await Promise.all(this.providers.map((p) => p.load()))\n }\n\n track(event: string, params?: Record<string, unknown>): void {\n for (const provider of this.providers) {\n if (provider.isLoaded()) {\n provider.track(event, params)\n }\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/pixels/meta-pixel.ts
|
|
4
|
+
var EVENT_MAP = {
|
|
5
|
+
page_view: "PageView",
|
|
6
|
+
product_view: "ViewContent",
|
|
7
|
+
add_to_cart: "AddToCart",
|
|
8
|
+
remove_from_cart: "RemoveFromCart",
|
|
9
|
+
begin_checkout: "InitiateCheckout",
|
|
10
|
+
purchase: "Purchase",
|
|
11
|
+
search: "Search",
|
|
12
|
+
category_view: "ViewContent"
|
|
13
|
+
};
|
|
14
|
+
var MetaPixelProvider = class {
|
|
15
|
+
constructor(pixelId) {
|
|
16
|
+
this.name = "meta";
|
|
17
|
+
this.loaded = false;
|
|
18
|
+
this.pixelId = pixelId;
|
|
19
|
+
}
|
|
20
|
+
async load() {
|
|
21
|
+
if (typeof window === "undefined") return;
|
|
22
|
+
if (this.loaded) return;
|
|
23
|
+
const w = window;
|
|
24
|
+
if (!w.fbq) {
|
|
25
|
+
const n = w.fbq = function(...args) {
|
|
26
|
+
n.callMethod ? n.callMethod.apply(n, args) : n.queue.push(args);
|
|
27
|
+
};
|
|
28
|
+
if (!w._fbq) w._fbq = n;
|
|
29
|
+
n.push = n;
|
|
30
|
+
n.loaded = true;
|
|
31
|
+
n.version = "2.0";
|
|
32
|
+
n.queue = [];
|
|
33
|
+
}
|
|
34
|
+
await new Promise((resolve) => {
|
|
35
|
+
const script = document.createElement("script");
|
|
36
|
+
script.async = true;
|
|
37
|
+
script.src = "https://connect.facebook.net/en_US/fbevents.js";
|
|
38
|
+
script.onload = () => resolve();
|
|
39
|
+
script.onerror = () => resolve();
|
|
40
|
+
const first = document.getElementsByTagName("script")[0];
|
|
41
|
+
first?.parentNode?.insertBefore(script, first);
|
|
42
|
+
});
|
|
43
|
+
w.fbq("init", this.pixelId);
|
|
44
|
+
w.fbq("track", "PageView");
|
|
45
|
+
this.loaded = true;
|
|
46
|
+
}
|
|
47
|
+
track(event, params) {
|
|
48
|
+
if (typeof window === "undefined") return;
|
|
49
|
+
const w = window;
|
|
50
|
+
if (typeof w.fbq !== "function") return;
|
|
51
|
+
const metaEvent = EVENT_MAP[event];
|
|
52
|
+
if (!metaEvent) return;
|
|
53
|
+
if (params && Object.keys(params).length > 0) {
|
|
54
|
+
w.fbq("track", metaEvent, params);
|
|
55
|
+
} else {
|
|
56
|
+
w.fbq("track", metaEvent);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
isLoaded() {
|
|
60
|
+
return this.loaded;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// src/pixels/pixel-manager.ts
|
|
65
|
+
var PROVIDER_REGISTRY = {
|
|
66
|
+
meta: MetaPixelProvider
|
|
67
|
+
};
|
|
68
|
+
var PixelManager = class {
|
|
69
|
+
constructor(configs) {
|
|
70
|
+
this.providers = [];
|
|
71
|
+
for (const config of configs) {
|
|
72
|
+
const Ctor = PROVIDER_REGISTRY[config.provider];
|
|
73
|
+
if (Ctor) {
|
|
74
|
+
this.providers.push(new Ctor(config.pixel_id));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async initialize() {
|
|
79
|
+
await Promise.all(this.providers.map((p) => p.load()));
|
|
80
|
+
}
|
|
81
|
+
track(event, params) {
|
|
82
|
+
for (const provider of this.providers) {
|
|
83
|
+
if (provider.isLoaded()) {
|
|
84
|
+
provider.track(event, params);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
exports.PixelManager = PixelManager;
|
|
91
|
+
//# sourceMappingURL=chunk-DAM7NZCI.cjs.map
|
|
92
|
+
//# sourceMappingURL=chunk-DAM7NZCI.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/pixels/meta-pixel.ts","../src/pixels/pixel-manager.ts"],"names":[],"mappings":"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","file":"chunk-DAM7NZCI.cjs","sourcesContent":["import type { PixelProvider } from './types.js'\n\n/** Map SDK event names → Meta standard event names */\nconst EVENT_MAP: Record<string, string> = {\n page_view: 'PageView',\n product_view: 'ViewContent',\n add_to_cart: 'AddToCart',\n remove_from_cart: 'RemoveFromCart',\n begin_checkout: 'InitiateCheckout',\n purchase: 'Purchase',\n search: 'Search',\n category_view: 'ViewContent',\n}\n\nexport class MetaPixelProvider implements PixelProvider {\n readonly name = 'meta'\n private pixelId: string\n private loaded = false\n\n constructor(pixelId: string) {\n this.pixelId = pixelId\n }\n\n async load(): Promise<void> {\n if (typeof window === 'undefined') return\n if (this.loaded) return\n\n // Initialize fbq queue\n const w = window as any\n if (!w.fbq) {\n const n: any = (w.fbq = function (...args: any[]) {\n n.callMethod ? n.callMethod.apply(n, args) : n.queue.push(args)\n })\n if (!w._fbq) w._fbq = n\n n.push = n\n n.loaded = true\n n.version = '2.0'\n n.queue = []\n }\n\n // Inject script\n await new Promise<void>((resolve) => {\n const script = document.createElement('script')\n script.async = true\n script.src = 'https://connect.facebook.net/en_US/fbevents.js'\n script.onload = () => resolve()\n script.onerror = () => resolve() // don't block on load failure\n const first = document.getElementsByTagName('script')[0]\n first?.parentNode?.insertBefore(script, first)\n })\n\n w.fbq('init', this.pixelId)\n w.fbq('track', 'PageView')\n this.loaded = true\n }\n\n track(event: string, params?: Record<string, unknown>): void {\n if (typeof window === 'undefined') return\n const w = window as any\n if (typeof w.fbq !== 'function') return\n\n const metaEvent = EVENT_MAP[event]\n if (!metaEvent) return\n\n if (params && Object.keys(params).length > 0) {\n w.fbq('track', metaEvent, params)\n } else {\n w.fbq('track', metaEvent)\n }\n }\n\n isLoaded(): boolean {\n return this.loaded\n }\n}\n","import type { PixelConfig, PixelProvider } from './types.js'\nimport { MetaPixelProvider } from './meta-pixel.js'\n\nconst PROVIDER_REGISTRY: Record<string, new (pixelId: string) => PixelProvider> = {\n meta: MetaPixelProvider,\n}\n\nexport class PixelManager {\n private providers: PixelProvider[] = []\n\n constructor(configs: PixelConfig[]) {\n for (const config of configs) {\n const Ctor = PROVIDER_REGISTRY[config.provider]\n if (Ctor) {\n this.providers.push(new Ctor(config.pixel_id))\n }\n }\n }\n\n async initialize(): Promise<void> {\n await Promise.all(this.providers.map((p) => p.load()))\n }\n\n track(event: string, params?: Record<string, unknown>): void {\n for (const provider of this.providers) {\n if (provider.isLoaded()) {\n provider.track(event, params)\n }\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/resilient-send.ts
|
|
4
|
+
var MAX_RETRIES = 2;
|
|
5
|
+
var RETRY_DELAY_MS = 1e3;
|
|
6
|
+
async function resilientSend(url, payload, headers) {
|
|
7
|
+
const body = JSON.stringify(payload);
|
|
8
|
+
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
9
|
+
try {
|
|
10
|
+
const res = await fetch(url, {
|
|
11
|
+
method: "POST",
|
|
12
|
+
headers,
|
|
13
|
+
body,
|
|
14
|
+
keepalive: true
|
|
15
|
+
});
|
|
16
|
+
if (res.ok || res.status < 500) return;
|
|
17
|
+
} catch {
|
|
18
|
+
}
|
|
19
|
+
if (attempt < MAX_RETRIES) {
|
|
20
|
+
await new Promise((r) => setTimeout(r, RETRY_DELAY_MS * (attempt + 1)));
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
if (typeof navigator !== "undefined" && navigator.sendBeacon) {
|
|
24
|
+
navigator.sendBeacon(url, body);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// src/client-queries.ts
|
|
29
|
+
async function fetchAllCustomerOrders(requestFn, customerId) {
|
|
30
|
+
const encoded = encodeURIComponent(customerId);
|
|
31
|
+
const all = [];
|
|
32
|
+
let cursor;
|
|
33
|
+
let hasMore = true;
|
|
34
|
+
while (hasMore) {
|
|
35
|
+
const params = new URLSearchParams({ customer_id: encoded, limit: "100" });
|
|
36
|
+
if (cursor) params.set("starting_after", cursor);
|
|
37
|
+
const res = await requestFn(`/orders?${params}`);
|
|
38
|
+
const items = res?.data ?? [];
|
|
39
|
+
if (items.length === 0) break;
|
|
40
|
+
all.push(...items);
|
|
41
|
+
cursor = items[items.length - 1].id;
|
|
42
|
+
hasMore = res.has_more ?? false;
|
|
43
|
+
}
|
|
44
|
+
return all;
|
|
45
|
+
}
|
|
46
|
+
async function findCustomerAnalytics(requestFn, customerId, customerName) {
|
|
47
|
+
try {
|
|
48
|
+
const res = await requestFn(
|
|
49
|
+
"/analytics/customers?limit=200"
|
|
50
|
+
);
|
|
51
|
+
const byId = res.customers?.find((c) => c.customer_id === customerId);
|
|
52
|
+
if (byId) return byId;
|
|
53
|
+
if (customerName) {
|
|
54
|
+
const normalized = customerName.toLowerCase().trim();
|
|
55
|
+
return res.customers?.find(
|
|
56
|
+
(c) => c.customer_name?.toLowerCase().trim() === normalized
|
|
57
|
+
) ?? null;
|
|
58
|
+
}
|
|
59
|
+
return null;
|
|
60
|
+
} catch {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function encodeBase64Url(url) {
|
|
65
|
+
if (typeof Buffer !== "undefined") {
|
|
66
|
+
return Buffer.from(url, "utf-8").toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
67
|
+
}
|
|
68
|
+
return btoa(url).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
69
|
+
}
|
|
70
|
+
function signMedia(signingSecret, encodedUrl, w, q, f) {
|
|
71
|
+
const payload = `${signingSecret}|${encodedUrl}|${w}|${q}|${f}`;
|
|
72
|
+
let h1 = 2166136261, h2 = 3421674724, h3 = 440920331, h4 = 3854870482;
|
|
73
|
+
for (let i = 0; i < payload.length; i++) {
|
|
74
|
+
const c = payload.charCodeAt(i);
|
|
75
|
+
h1 ^= c;
|
|
76
|
+
h1 = Math.imul(h1, 16777619);
|
|
77
|
+
h2 ^= c;
|
|
78
|
+
h2 = Math.imul(h2, 16777629);
|
|
79
|
+
h3 ^= c;
|
|
80
|
+
h3 = Math.imul(h3, 16777637);
|
|
81
|
+
h4 ^= c;
|
|
82
|
+
h4 = Math.imul(h4, 16777679);
|
|
83
|
+
}
|
|
84
|
+
return ((h1 >>> 0).toString(16).padStart(8, "0") + (h2 >>> 0).toString(16).padStart(8, "0") + (h3 >>> 0).toString(16).padStart(8, "0") + (h4 >>> 0).toString(16).padStart(8, "0")).slice(0, 32);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// src/client.ts
|
|
88
|
+
var WhaleClient = class {
|
|
89
|
+
constructor(config) {
|
|
90
|
+
this._sessionToken = null;
|
|
91
|
+
this.storeId = config.storeId;
|
|
92
|
+
this.apiKey = config.apiKey;
|
|
93
|
+
this.gatewayUrl = config.gatewayUrl || "https://whale-gateway.fly.dev";
|
|
94
|
+
this.proxyPath = config.proxyPath || "/api/gw";
|
|
95
|
+
}
|
|
96
|
+
// -- Token Management --
|
|
97
|
+
setSessionToken(token) {
|
|
98
|
+
this._sessionToken = token;
|
|
99
|
+
}
|
|
100
|
+
getSessionToken() {
|
|
101
|
+
return this._sessionToken;
|
|
102
|
+
}
|
|
103
|
+
// -- Base URL --
|
|
104
|
+
get baseUrl() {
|
|
105
|
+
return typeof window === "undefined" ? this.gatewayUrl : this.proxyPath;
|
|
106
|
+
}
|
|
107
|
+
// -- Base Fetcher --
|
|
108
|
+
async request(path, options = {}, opts) {
|
|
109
|
+
const url = `${this.baseUrl}/v1/stores/${this.storeId}${path}`;
|
|
110
|
+
const headers = {
|
|
111
|
+
"Content-Type": "application/json",
|
|
112
|
+
"x-api-key": this.apiKey
|
|
113
|
+
};
|
|
114
|
+
if (this._sessionToken) headers["Authorization"] = `Bearer ${this._sessionToken}`;
|
|
115
|
+
const fetchOptions = {
|
|
116
|
+
...options,
|
|
117
|
+
headers: { ...headers, ...options.headers ?? {} }
|
|
118
|
+
};
|
|
119
|
+
if (opts?.revalidate !== void 0) fetchOptions.next = { revalidate: opts.revalidate };
|
|
120
|
+
const res = await fetch(url, fetchOptions);
|
|
121
|
+
if (!res.ok) {
|
|
122
|
+
let message = `Gateway error ${res.status}: ${res.statusText}`;
|
|
123
|
+
try {
|
|
124
|
+
const body = await res.json();
|
|
125
|
+
if (body?.message) message = body.message;
|
|
126
|
+
else if (body?.error) message = body.error;
|
|
127
|
+
} catch {
|
|
128
|
+
}
|
|
129
|
+
const err = new Error(message);
|
|
130
|
+
err.status = res.status;
|
|
131
|
+
throw err;
|
|
132
|
+
}
|
|
133
|
+
if (res.status === 204) return void 0;
|
|
134
|
+
return res.json();
|
|
135
|
+
}
|
|
136
|
+
// -- Products --
|
|
137
|
+
async listProducts(params) {
|
|
138
|
+
const sp = new URLSearchParams();
|
|
139
|
+
if (params?.limit) sp.set("limit", String(params.limit));
|
|
140
|
+
if (params?.starting_after) sp.set("starting_after", params.starting_after);
|
|
141
|
+
if (params?.status) sp.set("status", params.status);
|
|
142
|
+
const qs = sp.toString();
|
|
143
|
+
return this.request(`/products${qs ? `?${qs}` : ""}`);
|
|
144
|
+
}
|
|
145
|
+
async getProduct(id) {
|
|
146
|
+
return this.request(`/products/${id}`);
|
|
147
|
+
}
|
|
148
|
+
async getAllProducts(options) {
|
|
149
|
+
const all = [];
|
|
150
|
+
let cursor;
|
|
151
|
+
let hasMore = true;
|
|
152
|
+
let pages = 0;
|
|
153
|
+
const maxPages = options?.maxPages ?? 20;
|
|
154
|
+
while (hasMore && pages < maxPages) {
|
|
155
|
+
const params = new URLSearchParams({ limit: "100" });
|
|
156
|
+
if (options?.status) params.set("status", options.status);
|
|
157
|
+
else params.set("status", "published");
|
|
158
|
+
if (cursor) params.set("starting_after", cursor);
|
|
159
|
+
const data = await this.request(
|
|
160
|
+
`/products?${params}`,
|
|
161
|
+
{},
|
|
162
|
+
options?.revalidate !== void 0 ? { revalidate: options.revalidate } : void 0
|
|
163
|
+
);
|
|
164
|
+
if (!data.data || data.data.length === 0) break;
|
|
165
|
+
for (const p of data.data) {
|
|
166
|
+
if (!options?.filter || options.filter(p)) all.push(p);
|
|
167
|
+
cursor = p.id;
|
|
168
|
+
}
|
|
169
|
+
hasMore = data.has_more;
|
|
170
|
+
pages++;
|
|
171
|
+
}
|
|
172
|
+
return all;
|
|
173
|
+
}
|
|
174
|
+
// -- Cart --
|
|
175
|
+
async createCart(customerEmail) {
|
|
176
|
+
return this.request("/cart", {
|
|
177
|
+
method: "POST",
|
|
178
|
+
body: JSON.stringify(customerEmail ? { customer_email: customerEmail } : {})
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
async getCart(cartId) {
|
|
182
|
+
return this.request(`/cart/${cartId}`);
|
|
183
|
+
}
|
|
184
|
+
async addToCart(cartId, productId, quantity, options) {
|
|
185
|
+
return this.request(`/cart/${cartId}/items`, {
|
|
186
|
+
method: "POST",
|
|
187
|
+
body: JSON.stringify({
|
|
188
|
+
product_id: productId,
|
|
189
|
+
quantity,
|
|
190
|
+
...options?.tier !== void 0 && { tier: options.tier },
|
|
191
|
+
...options?.unitPrice !== void 0 && { unit_price: options.unitPrice }
|
|
192
|
+
})
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
async updateCartItem(cartId, itemId, quantity) {
|
|
196
|
+
return this.request(`/cart/${cartId}/items/${itemId}`, { method: "PATCH", body: JSON.stringify({ quantity }) });
|
|
197
|
+
}
|
|
198
|
+
async removeCartItem(cartId, itemId) {
|
|
199
|
+
return this.request(`/cart/${cartId}/items/${itemId}`, { method: "DELETE" });
|
|
200
|
+
}
|
|
201
|
+
// -- Checkout --
|
|
202
|
+
async checkout(cartId, customerEmail, payment) {
|
|
203
|
+
return this.request("/checkout", {
|
|
204
|
+
method: "POST",
|
|
205
|
+
body: JSON.stringify({
|
|
206
|
+
cart_id: cartId,
|
|
207
|
+
...customerEmail && { customer_email: customerEmail },
|
|
208
|
+
...payment && {
|
|
209
|
+
payment_method: payment.payment_method,
|
|
210
|
+
...payment.opaque_data && { opaque_data: payment.opaque_data },
|
|
211
|
+
...payment.billTo && { bill_to: payment.billTo },
|
|
212
|
+
...payment.shipTo && { ship_to: payment.shipTo }
|
|
213
|
+
}
|
|
214
|
+
})
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
// -- Customers --
|
|
218
|
+
async findCustomer(query) {
|
|
219
|
+
const encoded = encodeURIComponent(query);
|
|
220
|
+
const res = await this.request(`/customers?query=${encoded}`);
|
|
221
|
+
return Array.isArray(res) ? res : res?.data ?? [];
|
|
222
|
+
}
|
|
223
|
+
async getCustomer(id) {
|
|
224
|
+
return this.request(`/customers/${id}`);
|
|
225
|
+
}
|
|
226
|
+
async createCustomer(data) {
|
|
227
|
+
return this.request("/customers", { method: "POST", body: JSON.stringify(data) });
|
|
228
|
+
}
|
|
229
|
+
// -- Orders --
|
|
230
|
+
async listOrders(params) {
|
|
231
|
+
const sp = new URLSearchParams();
|
|
232
|
+
if (params?.customer_id) sp.set("customer_id", params.customer_id);
|
|
233
|
+
if (params?.limit) sp.set("limit", String(params.limit));
|
|
234
|
+
if (params?.starting_after) sp.set("starting_after", params.starting_after);
|
|
235
|
+
const qs = sp.toString();
|
|
236
|
+
return this.request(`/orders${qs ? `?${qs}` : ""}`);
|
|
237
|
+
}
|
|
238
|
+
async getOrder(id) {
|
|
239
|
+
return this.request(`/orders/${id}`);
|
|
240
|
+
}
|
|
241
|
+
async getCustomerOrders(customerId) {
|
|
242
|
+
return fetchAllCustomerOrders((path, opts) => this.request(path, opts), customerId);
|
|
243
|
+
}
|
|
244
|
+
// -- Auth (OTP) --
|
|
245
|
+
async sendCode(email) {
|
|
246
|
+
return this.request("/storefront/auth/send-code", { method: "POST", body: JSON.stringify({ email }) });
|
|
247
|
+
}
|
|
248
|
+
async verifyCode(email, code) {
|
|
249
|
+
return this.request("/storefront/auth/verify-code", { method: "POST", body: JSON.stringify({ email, code }) });
|
|
250
|
+
}
|
|
251
|
+
// -- Customer Analytics --
|
|
252
|
+
async getCustomerAnalytics(customerId, customerName) {
|
|
253
|
+
return findCustomerAnalytics((path) => this.request(path), customerId, customerName);
|
|
254
|
+
}
|
|
255
|
+
// -- Locations --
|
|
256
|
+
async listLocations() {
|
|
257
|
+
return this.request("/locations");
|
|
258
|
+
}
|
|
259
|
+
// -- COA --
|
|
260
|
+
getCOAEmbedUrl(productId) {
|
|
261
|
+
return `${this.baseUrl}/v1/stores/${this.storeId}/coa/${productId}/embed`;
|
|
262
|
+
}
|
|
263
|
+
// -- Storefront Config --
|
|
264
|
+
async fetchStorefrontConfig() {
|
|
265
|
+
return this.request("/storefront/config");
|
|
266
|
+
}
|
|
267
|
+
// -- Analytics / Storefront Sessions --
|
|
268
|
+
async createSession(params) {
|
|
269
|
+
return this.request("/storefront/sessions", { method: "POST", body: JSON.stringify(params) });
|
|
270
|
+
}
|
|
271
|
+
async updateSession(sessionId, params) {
|
|
272
|
+
return this.request(`/storefront/sessions/${sessionId}`, { method: "PATCH", body: JSON.stringify(params) });
|
|
273
|
+
}
|
|
274
|
+
async trackEvent(params) {
|
|
275
|
+
const url = `${this.baseUrl}/v1/stores/${this.storeId}/storefront/events`;
|
|
276
|
+
const headers = {
|
|
277
|
+
"Content-Type": "application/json",
|
|
278
|
+
"x-api-key": this.apiKey
|
|
279
|
+
};
|
|
280
|
+
if (this._sessionToken) headers["Authorization"] = `Bearer ${this._sessionToken}`;
|
|
281
|
+
await resilientSend(url, params, headers);
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
// -- Static Media Utilities --
|
|
285
|
+
WhaleClient.encodeBase64Url = encodeBase64Url;
|
|
286
|
+
WhaleClient.signMedia = signMedia;
|
|
287
|
+
|
|
288
|
+
exports.WhaleClient = WhaleClient;
|
|
289
|
+
exports.resilientSend = resilientSend;
|
|
290
|
+
//# sourceMappingURL=chunk-OP4LOUCV.cjs.map
|
|
291
|
+
//# sourceMappingURL=chunk-OP4LOUCV.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/resilient-send.ts","../src/client-queries.ts","../src/client.ts"],"names":[],"mappings":"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","file":"chunk-OP4LOUCV.cjs","sourcesContent":["/**\n * Resilient HTTP sender for analytics/event payloads.\n *\n * Retries transient (5xx / network) failures with linear back-off,\n * then falls back to navigator.sendBeacon so the event still lands\n * even when the tab is being unloaded.\n *\n * 4xx responses are NOT retried — they indicate a client error that\n * won't resolve by resending.\n */\n\nconst MAX_RETRIES = 2\nconst RETRY_DELAY_MS = 1000\n\nexport async function resilientSend(\n url: string,\n payload: object,\n headers: Record<string, string>,\n): Promise<void> {\n const body = JSON.stringify(payload)\n\n for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {\n try {\n const res = await fetch(url, {\n method: 'POST',\n headers,\n body,\n keepalive: true,\n })\n // Success or client-error (4xx) — don't retry\n if (res.ok || res.status < 500) return\n } catch {\n // Network error — retry\n }\n\n if (attempt < MAX_RETRIES) {\n await new Promise<void>((r) => setTimeout(r, RETRY_DELAY_MS * (attempt + 1)))\n }\n }\n\n // All retries exhausted — fire-and-forget via sendBeacon\n if (typeof navigator !== 'undefined' && navigator.sendBeacon) {\n navigator.sendBeacon(url, body)\n }\n}\n","/**\n * Extended query methods and static utilities for WhaleClient.\n * Extracted from client.ts to keep the core under 300 lines.\n */\n\nimport type {\n Customer,\n CustomerAnalytics,\n ListResponse,\n Location,\n Order,\n SendCodeResponse,\n StorefrontSession,\n VerifyCodeResponse,\n EventType,\n} from './types.js'\n\n/**\n * Paginate through all customer orders.\n */\nexport async function fetchAllCustomerOrders(\n requestFn: <T>(path: string, opts?: RequestInit) => Promise<T>,\n customerId: string\n): Promise<Order[]> {\n const encoded = encodeURIComponent(customerId)\n const all: Order[] = []\n let cursor: string | undefined\n let hasMore = true\n\n while (hasMore) {\n const params = new URLSearchParams({ customer_id: encoded, limit: '100' })\n if (cursor) params.set('starting_after', cursor)\n\n const res = await requestFn<ListResponse<Order>>(`/orders?${params}`)\n const items = res?.data ?? []\n if (items.length === 0) break\n\n all.push(...items)\n cursor = items[items.length - 1].id\n hasMore = res.has_more ?? false\n }\n\n return all\n}\n\n/**\n * Find customer analytics by ID or name (fallback).\n */\nexport async function findCustomerAnalytics(\n requestFn: <T>(path: string) => Promise<T>,\n customerId: string,\n customerName?: string\n): Promise<CustomerAnalytics | null> {\n try {\n const res = await requestFn<{ customers: CustomerAnalytics[] }>(\n '/analytics/customers?limit=200'\n )\n const byId = res.customers?.find((c) => c.customer_id === customerId)\n if (byId) return byId\n if (customerName) {\n const normalized = customerName.toLowerCase().trim()\n return (\n res.customers?.find(\n (c) => c.customer_name?.toLowerCase().trim() === normalized\n ) ?? null\n )\n }\n return null\n } catch {\n return null\n }\n}\n\n/**\n * Base64url-encode a URL string (works in both Node and browser).\n */\nexport function encodeBase64Url(url: string): string {\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(url, 'utf-8')\n .toString('base64')\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=+$/, '')\n }\n return btoa(url)\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=+$/, '')\n}\n\n/**\n * Quad-FNV (128-bit) media signing — matches gateway's media-signature.ts.\n */\nexport function signMedia(\n signingSecret: string,\n encodedUrl: string,\n w: string,\n q: string,\n f: string\n): string {\n const payload = `${signingSecret}|${encodedUrl}|${w}|${q}|${f}`\n let h1 = 0x811c9dc5, h2 = 0xcbf29ce4, h3 = 0x1a47e90b, h4 = 0xe5c4a7d2\n for (let i = 0; i < payload.length; i++) {\n const c = payload.charCodeAt(i)\n h1 ^= c; h1 = Math.imul(h1, 0x01000193)\n h2 ^= c; h2 = Math.imul(h2, 0x0100019d)\n h3 ^= c; h3 = Math.imul(h3, 0x010001a5)\n h4 ^= c; h4 = Math.imul(h4, 0x010001cf)\n }\n return (\n (h1 >>> 0).toString(16).padStart(8, '0') +\n (h2 >>> 0).toString(16).padStart(8, '0') +\n (h3 >>> 0).toString(16).padStart(8, '0') +\n (h4 >>> 0).toString(16).padStart(8, '0')\n ).slice(0, 32)\n}\n","import type {\n Cart,\n CartItem,\n Customer,\n CustomerAnalytics,\n ListResponse,\n Location,\n Order,\n PaymentData,\n Product,\n SendCodeResponse,\n StorefrontSession,\n VerifyCodeResponse,\n WhaleStorefrontConfig,\n EventType,\n} from './types.js'\n\nimport type { StorefrontConfig } from './pixels/types.js'\n\nimport {\n fetchAllCustomerOrders,\n findCustomerAnalytics,\n encodeBase64Url,\n signMedia,\n} from './client-queries.js'\n\nimport { resilientSend } from './resilient-send.js'\n\n// -- WhaleClient --\n// Stateless HTTP wrapper around whale-gateway. Works server-side and client-side.\n// No React, no browser APIs (except fetch).\n\nexport class WhaleClient {\n readonly storeId: string\n readonly apiKey: string\n readonly gatewayUrl: string\n readonly proxyPath: string\n\n private _sessionToken: string | null = null\n\n constructor(config: WhaleStorefrontConfig) {\n this.storeId = config.storeId\n this.apiKey = config.apiKey\n this.gatewayUrl = config.gatewayUrl || 'https://whale-gateway.fly.dev'\n this.proxyPath = config.proxyPath || '/api/gw'\n }\n\n // -- Token Management --\n\n setSessionToken(token: string | null): void { this._sessionToken = token }\n getSessionToken(): string | null { return this._sessionToken }\n\n // -- Base URL --\n\n private get baseUrl(): string {\n return typeof window === 'undefined' ? this.gatewayUrl : this.proxyPath\n }\n\n // -- Base Fetcher --\n\n private async request<T = unknown>(\n path: string, options: RequestInit = {}, opts?: { revalidate?: number }\n ): Promise<T> {\n const url = `${this.baseUrl}/v1/stores/${this.storeId}${path}`\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'x-api-key': this.apiKey,\n }\n if (this._sessionToken) headers['Authorization'] = `Bearer ${this._sessionToken}`\n\n const fetchOptions: RequestInit & { next?: { revalidate?: number } } = {\n ...options,\n headers: { ...headers, ...((options.headers as Record<string, string>) ?? {}) },\n }\n if (opts?.revalidate !== undefined) fetchOptions.next = { revalidate: opts.revalidate }\n\n const res = await fetch(url, fetchOptions)\n if (!res.ok) {\n let message = `Gateway error ${res.status}: ${res.statusText}`\n try {\n const body = await res.json()\n if (body?.message) message = body.message\n else if (body?.error) message = body.error\n } catch { /* ignore parse errors */ }\n const err = new Error(message) as Error & { status: number }\n err.status = res.status\n throw err\n }\n if (res.status === 204) return undefined as T\n return res.json() as Promise<T>\n }\n\n // -- Products --\n\n async listProducts(params?: { limit?: number; starting_after?: string; status?: string }): Promise<ListResponse<Product>> {\n const sp = new URLSearchParams()\n if (params?.limit) sp.set('limit', String(params.limit))\n if (params?.starting_after) sp.set('starting_after', params.starting_after)\n if (params?.status) sp.set('status', params.status)\n const qs = sp.toString()\n return this.request<ListResponse<Product>>(`/products${qs ? `?${qs}` : ''}`)\n }\n\n async getProduct(id: string): Promise<Product> {\n return this.request<Product>(`/products/${id}`)\n }\n\n async getAllProducts(options?: {\n status?: string; maxPages?: number; revalidate?: number; filter?: (product: Product) => boolean\n }): Promise<Product[]> {\n const all: Product[] = []\n let cursor: string | undefined\n let hasMore = true\n let pages = 0\n const maxPages = options?.maxPages ?? 20\n\n while (hasMore && pages < maxPages) {\n const params = new URLSearchParams({ limit: '100' })\n if (options?.status) params.set('status', options.status)\n else params.set('status', 'published')\n if (cursor) params.set('starting_after', cursor)\n\n const data = await this.request<ListResponse<Product>>(\n `/products?${params}`, {},\n options?.revalidate !== undefined ? { revalidate: options.revalidate } : undefined\n )\n if (!data.data || data.data.length === 0) break\n for (const p of data.data) {\n if (!options?.filter || options.filter(p)) all.push(p)\n cursor = p.id\n }\n hasMore = data.has_more\n pages++\n }\n return all\n }\n\n // -- Cart --\n\n async createCart(customerEmail?: string): Promise<Cart> {\n return this.request<Cart>('/cart', {\n method: 'POST',\n body: JSON.stringify(customerEmail ? { customer_email: customerEmail } : {}),\n })\n }\n\n async getCart(cartId: string): Promise<Cart> {\n return this.request<Cart>(`/cart/${cartId}`)\n }\n\n async addToCart(cartId: string, productId: string, quantity: number, options?: { tier?: string; unitPrice?: number }): Promise<CartItem> {\n return this.request<CartItem>(`/cart/${cartId}/items`, {\n method: 'POST',\n body: JSON.stringify({\n product_id: productId, quantity,\n ...(options?.tier !== undefined && { tier: options.tier }),\n ...(options?.unitPrice !== undefined && { unit_price: options.unitPrice }),\n }),\n })\n }\n\n async updateCartItem(cartId: string, itemId: string, quantity: number): Promise<Cart> {\n return this.request<Cart>(`/cart/${cartId}/items/${itemId}`, { method: 'PATCH', body: JSON.stringify({ quantity }) })\n }\n\n async removeCartItem(cartId: string, itemId: string): Promise<void> {\n return this.request<void>(`/cart/${cartId}/items/${itemId}`, { method: 'DELETE' })\n }\n\n // -- Checkout --\n\n async checkout(cartId: string, customerEmail?: string, payment?: PaymentData): Promise<Order> {\n return this.request<Order>('/checkout', {\n method: 'POST',\n body: JSON.stringify({\n cart_id: cartId,\n ...(customerEmail && { customer_email: customerEmail }),\n ...(payment && {\n payment_method: payment.payment_method,\n ...(payment.opaque_data && { opaque_data: payment.opaque_data }),\n ...(payment.billTo && { bill_to: payment.billTo }),\n ...(payment.shipTo && { ship_to: payment.shipTo }),\n }),\n }),\n })\n }\n\n // -- Customers --\n\n async findCustomer(query: string): Promise<Customer[]> {\n const encoded = encodeURIComponent(query)\n const res = await this.request<{ data: Customer[] } | Customer[]>(`/customers?query=${encoded}`)\n return Array.isArray(res) ? res : res?.data ?? []\n }\n\n async getCustomer(id: string): Promise<Customer> { return this.request<Customer>(`/customers/${id}`) }\n\n async createCustomer(data: { first_name: string; last_name: string; email: string; phone?: string }): Promise<Customer> {\n return this.request<Customer>('/customers', { method: 'POST', body: JSON.stringify(data) })\n }\n\n // -- Orders --\n\n async listOrders(params?: { customer_id?: string; limit?: number; starting_after?: string }): Promise<ListResponse<Order>> {\n const sp = new URLSearchParams()\n if (params?.customer_id) sp.set('customer_id', params.customer_id)\n if (params?.limit) sp.set('limit', String(params.limit))\n if (params?.starting_after) sp.set('starting_after', params.starting_after)\n const qs = sp.toString()\n return this.request<ListResponse<Order>>(`/orders${qs ? `?${qs}` : ''}`)\n }\n\n async getOrder(id: string): Promise<Order> { return this.request<Order>(`/orders/${id}`) }\n\n async getCustomerOrders(customerId: string): Promise<Order[]> {\n return fetchAllCustomerOrders((path, opts) => this.request(path, opts), customerId)\n }\n\n // -- Auth (OTP) --\n\n async sendCode(email: string): Promise<SendCodeResponse> {\n return this.request<SendCodeResponse>('/storefront/auth/send-code', { method: 'POST', body: JSON.stringify({ email }) })\n }\n\n async verifyCode(email: string, code: string): Promise<VerifyCodeResponse> {\n return this.request<VerifyCodeResponse>('/storefront/auth/verify-code', { method: 'POST', body: JSON.stringify({ email, code }) })\n }\n\n // -- Customer Analytics --\n\n async getCustomerAnalytics(customerId: string, customerName?: string): Promise<CustomerAnalytics | null> {\n return findCustomerAnalytics((path) => this.request(path), customerId, customerName)\n }\n\n // -- Locations --\n\n async listLocations(): Promise<ListResponse<Location>> { return this.request<ListResponse<Location>>('/locations') }\n\n // -- COA --\n\n getCOAEmbedUrl(productId: string): string {\n return `${this.baseUrl}/v1/stores/${this.storeId}/coa/${productId}/embed`\n }\n\n // -- Storefront Config --\n\n async fetchStorefrontConfig(): Promise<StorefrontConfig> {\n return this.request<StorefrontConfig>('/storefront/config')\n }\n\n // -- Analytics / Storefront Sessions --\n\n async createSession(params: { user_agent?: string; referrer?: string }): Promise<StorefrontSession> {\n return this.request<StorefrontSession>('/storefront/sessions', { method: 'POST', body: JSON.stringify(params) })\n }\n\n async updateSession(sessionId: string, params: { last_active_at?: string; customer_id?: string }): Promise<StorefrontSession> {\n return this.request<StorefrontSession>(`/storefront/sessions/${sessionId}`, { method: 'PATCH', body: JSON.stringify(params) })\n }\n\n async trackEvent(params: { session_id: string; event_type: EventType; event_data?: Record<string, unknown> }): Promise<void> {\n const url = `${this.baseUrl}/v1/stores/${this.storeId}/storefront/events`\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'x-api-key': this.apiKey,\n }\n if (this._sessionToken) headers['Authorization'] = `Bearer ${this._sessionToken}`\n await resilientSend(url, params, headers)\n }\n\n // -- Static Media Utilities --\n\n static encodeBase64Url = encodeBase64Url\n static signMedia = signMedia\n}\n"]}
|