shopgpt 0.2.0 → 0.3.0
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 +95 -94
- package/dist/index.d.ts +7 -11
- package/dist/index.js +15 -11
- package/dist/react.d.ts +6 -9
- package/dist/react.js +12 -18
- package/dist/types.d.ts +11 -4
- package/package.json +28 -23
package/README.md
CHANGED
|
@@ -1,94 +1,95 @@
|
|
|
1
|
-
# shopgpt — Shoppable CTV Ad SDK
|
|
2
|
-
|
|
3
|
-
TV ad plays → viewer presses the CTA → cart converts → TV updates live.
|
|
4
|
-
|
|
5
|
-
Works on any HTML5 CTV (Samsung Tizen, LG webOS, FireTV, AndroidTV, Roku webview). No native code.
|
|
6
|
-
|
|
7
|
-
## Quickstart
|
|
8
|
-
|
|
9
|
-
```ts
|
|
10
|
-
import { ShopGPTCTV } from "shopgpt";
|
|
11
|
-
|
|
12
|
-
const ctv = new ShopGPTCTV({
|
|
13
|
-
|
|
14
|
-
// listen for conversions
|
|
15
|
-
ctv.onEvent((e) => {
|
|
16
|
-
if (e.type === "added_to_cart") showBadge(e.session);
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
// when the ad
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
//
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
cta
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
`
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
|
71
|
-
|
|
|
72
|
-
|
|
|
73
|
-
|
|
|
74
|
-
| GET | `/api/ctv/
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
-
|
|
94
|
-
-
|
|
1
|
+
# shopgpt — Shoppable CTV Ad SDK
|
|
2
|
+
|
|
3
|
+
TV ad plays → viewer presses the CTA → cart converts → TV updates live.
|
|
4
|
+
|
|
5
|
+
Works on any HTML5 CTV (Samsung Tizen, LG webOS, FireTV, AndroidTV, Roku webview). No native code.
|
|
6
|
+
|
|
7
|
+
## Quickstart
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { ShopGPTCTV } from "shopgpt";
|
|
11
|
+
|
|
12
|
+
const ctv = new ShopGPTCTV({ apiBase: "https://app.rankup.diy" });
|
|
13
|
+
|
|
14
|
+
// listen for conversions
|
|
15
|
+
ctv.onEvent((e) => {
|
|
16
|
+
if (e.type === "added_to_cart") showBadge(e.session);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
// when the ad starts — pass the 3 VAST params as-is.
|
|
20
|
+
// The product (title, image, price) is looked up server-side from rankupid.
|
|
21
|
+
const { session } = await ctv.createSession({ shoppable, rankupid, cta });
|
|
22
|
+
if (!session) return; // shoppable: false → plain ad
|
|
23
|
+
|
|
24
|
+
// CTA press → raises the added_to_cart flag
|
|
25
|
+
await ctv.addToCart(session.id);
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## CTA (fully customisable)
|
|
29
|
+
|
|
30
|
+
Two built-in presets, or any custom text:
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
import { ShopGPTAddToCartButton } from "shopgpt/react";
|
|
34
|
+
|
|
35
|
+
// preset 1 (default)
|
|
36
|
+
<ShopGPTAddToCartButton session={session} cta="add_to_cart" />
|
|
37
|
+
|
|
38
|
+
// preset 2
|
|
39
|
+
<ShopGPTAddToCartButton session={session} cta="send_to_phone" />
|
|
40
|
+
|
|
41
|
+
// fully custom — change it as you want
|
|
42
|
+
<ShopGPTAddToCartButton
|
|
43
|
+
session={session}
|
|
44
|
+
label="Buy Now"
|
|
45
|
+
className="my-cta-class"
|
|
46
|
+
onCta={(s) => analytics.track("ctv_cta", { sessionId: s.id })}
|
|
47
|
+
/>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## React
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
import { ShopGPTCTVPlayer, useShopGPTShoppableAd } from "shopgpt/react";
|
|
54
|
+
|
|
55
|
+
<ShopGPTCTVPlayer
|
|
56
|
+
videoSrc="https://…/ad.mp4"
|
|
57
|
+
ad={{ shoppable: true, rankupid: 10403886137619, cta: "Scan to buy" }}
|
|
58
|
+
cta="send_to_phone" // or ctaLabel="Buy Now"
|
|
59
|
+
onConverted={(s) => console.log("sold!", s.cartCount)}
|
|
60
|
+
/>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Hooks: `useShopGPTShoppableAd(ad, opts)` (create + poll automatically),
|
|
64
|
+
`useShopGPTSession(sessionId)` (follow a live session).
|
|
65
|
+
|
|
66
|
+
## Backend (included in this repo)
|
|
67
|
+
|
|
68
|
+
| Method | Route | Purpose |
|
|
69
|
+
|---|---|---|
|
|
70
|
+
| POST | `/api/ctv/session` | create session `{ shoppable, rankupid, cta }` → product resolved server-side (404 if unknown) |
|
|
71
|
+
| GET | `/api/ctv/session/:id` | poll session (no-store) |
|
|
72
|
+
| PATCH | `/api/ctv/session/:id` | `{ status: "scanned" \| "viewing" \| "completed" }` |
|
|
73
|
+
| POST | `/api/ctv/cart` | `{ sessionId, qty }` → marks `added_to_cart` |
|
|
74
|
+
| GET | `/api/ctv/cart?sessionId=` | list cart items |
|
|
75
|
+
| GET | `/api/ctv/products` | catalog products shaped for TV |
|
|
76
|
+
|
|
77
|
+
Demo: `/ctv-demo/tv` (TV) → press the CTA → spot flips to converted live.
|
|
78
|
+
|
|
79
|
+
## ShopGPT handoff (CTV → shopgpt.rankup.diy)
|
|
80
|
+
|
|
81
|
+
Sessions carry a ShopGPT deep link (`session.mobileUrl`):
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
https://shopgpt.rankup.diy/?product_id=<acp_item_id>&ctv=<sessionId>
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
`?product_id=` opens the ShopGPT product dialog (chat + add to cart);
|
|
88
|
+
`&ctv=` lets ShopGPT beacon `scanned` / `added_to_cart` back to
|
|
89
|
+
`/api/ctv/session/:id` and `/api/ctv/cart` (CORS open) so the TV updates live.
|
|
90
|
+
|
|
91
|
+
## Production notes
|
|
92
|
+
|
|
93
|
+
- Current store is in-memory (`lib/ctv/store.ts`). Move to Supabase `ctv_sessions` + `ctv_cart_items` or Upstash Redis for multi-instance.
|
|
94
|
+
- Wire `product` from Shopify / Woo / ACP feed (`lib/acp`, `app/shop/[slug]/[itemId]`).
|
|
95
|
+
- Analytics: `ctv.track("impression", { sessionId })` → POST `/api/ctv/session/track` (stub, add table).
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ShopGPTConfig, ShopGPTEvent, ShopGPTProduct, ShopGPTSession } from "./types";
|
|
1
|
+
import type { ShopGPTAdParams, ShopGPTConfig, ShopGPTEvent, ShopGPTProduct, ShopGPTSession } from "./types";
|
|
2
2
|
export * from "./types";
|
|
3
3
|
type Listener = (e: ShopGPTEvent) => void;
|
|
4
4
|
/**
|
|
@@ -8,8 +8,8 @@ type Listener = (e: ShopGPTEvent) => void;
|
|
|
8
8
|
* Phone side: getSession() → markViewed() → addToCart()
|
|
9
9
|
*
|
|
10
10
|
* @example
|
|
11
|
-
* const ctv = new ShopGPTCTV({
|
|
12
|
-
* const { session } = await ctv.createSession(
|
|
11
|
+
* const ctv = new ShopGPTCTV({ apiBase: "https://app.rankup.diy" });
|
|
12
|
+
* const { session } = await ctv.createSession({ shoppable: true, rankupid: 10403886137619, cta: "Scan to buy" });
|
|
13
13
|
* ctv.onEvent((e) => { if (e.type === "added_to_cart") showBadge(e.session); });
|
|
14
14
|
*/
|
|
15
15
|
export declare class ShopGPTCTV {
|
|
@@ -21,13 +21,9 @@ export declare class ShopGPTCTV {
|
|
|
21
21
|
onEvent(fn: Listener): () => void;
|
|
22
22
|
private emit;
|
|
23
23
|
private f;
|
|
24
|
-
createSession(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
ttlSec?: number;
|
|
28
|
-
}): Promise<{
|
|
29
|
-
session: ShopGPTSession;
|
|
30
|
-
mobileUrl: string;
|
|
24
|
+
createSession(ad: ShopGPTAdParams): Promise<{
|
|
25
|
+
session: ShopGPTSession | null;
|
|
26
|
+
mobileUrl: string | null;
|
|
31
27
|
}>;
|
|
32
28
|
getSession(sessionId: string): Promise<ShopGPTSession>;
|
|
33
29
|
pollSession(sessionId: string, onUpdate?: (s: ShopGPTSession) => void): () => void;
|
|
@@ -42,5 +38,5 @@ export declare class ShopGPTCTV {
|
|
|
42
38
|
}>;
|
|
43
39
|
track(event: string, props?: Record<string, unknown>): void;
|
|
44
40
|
}
|
|
45
|
-
/** Vanilla script-tag helper:
|
|
41
|
+
/** Vanilla script-tag helper: marks [data-shopgpt-ctv] elements ready. */
|
|
46
42
|
export declare function autoInit(selector?: string): ShopGPTCTV;
|
package/dist/index.js
CHANGED
|
@@ -13,8 +13,8 @@ function resolveBase(cfg) {
|
|
|
13
13
|
* Phone side: getSession() → markViewed() → addToCart()
|
|
14
14
|
*
|
|
15
15
|
* @example
|
|
16
|
-
* const ctv = new ShopGPTCTV({
|
|
17
|
-
* const { session } = await ctv.createSession(
|
|
16
|
+
* const ctv = new ShopGPTCTV({ apiBase: "https://app.rankup.diy" });
|
|
17
|
+
* const { session } = await ctv.createSession({ shoppable: true, rankupid: 10403886137619, cta: "Scan to buy" });
|
|
18
18
|
* ctv.onEvent((e) => { if (e.type === "added_to_cart") showBadge(e.session); });
|
|
19
19
|
*/
|
|
20
20
|
export class ShopGPTCTV {
|
|
@@ -43,24 +43,28 @@ export class ShopGPTCTV {
|
|
|
43
43
|
f() {
|
|
44
44
|
return this.cfg.fetchImpl ?? fetch.bind(globalThis);
|
|
45
45
|
}
|
|
46
|
-
// ── TV: create a shoppable session
|
|
47
|
-
|
|
46
|
+
// ── TV: create a shoppable session from the VAST ad params ─────
|
|
47
|
+
// Only { shoppable, rankupid, cta } are needed — the server looks up the
|
|
48
|
+
// product. `session` is null when the ad isn't shoppable.
|
|
49
|
+
async createSession(ad) {
|
|
50
|
+
if (ad.shoppable === false)
|
|
51
|
+
return { session: null, mobileUrl: null };
|
|
48
52
|
const res = await this.f()(`${this.apiBase}/api/ctv/session`, {
|
|
49
53
|
method: "POST",
|
|
50
54
|
headers: { "content-type": "application/json" },
|
|
51
55
|
body: JSON.stringify({
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
ttlSec: opts?.ttlSec ?? 600,
|
|
56
|
+
shoppable: ad.shoppable ?? true,
|
|
57
|
+
rankupid: ad.rankupid,
|
|
58
|
+
cta: ad.cta,
|
|
56
59
|
}),
|
|
57
60
|
});
|
|
58
61
|
if (!res.ok)
|
|
59
62
|
throw new Error(`createSession failed: ${res.status}`);
|
|
60
63
|
const session = (await res.json()).session;
|
|
61
|
-
|
|
64
|
+
if (!session)
|
|
65
|
+
return { session: null, mobileUrl: null };
|
|
62
66
|
this.emit({ type: "session_created", session });
|
|
63
|
-
return { session, mobileUrl };
|
|
67
|
+
return { session, mobileUrl: session.mobileUrl };
|
|
64
68
|
}
|
|
65
69
|
// ── Shared: fetch one session ───────────────────────────────────
|
|
66
70
|
async getSession(sessionId) {
|
|
@@ -142,7 +146,7 @@ export class ShopGPTCTV {
|
|
|
142
146
|
}
|
|
143
147
|
}
|
|
144
148
|
}
|
|
145
|
-
/** Vanilla script-tag helper:
|
|
149
|
+
/** Vanilla script-tag helper: marks [data-shopgpt-ctv] elements ready. */
|
|
146
150
|
export function autoInit(selector = "[data-shopgpt-ctv]") {
|
|
147
151
|
const client = new ShopGPTCTV();
|
|
148
152
|
if (typeof document !== "undefined") {
|
package/dist/react.d.ts
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { ShopGPTCTV } from "./index";
|
|
2
|
-
import type {
|
|
2
|
+
import type { ShopGPTAdParams, ShopGPTSession } from "./types";
|
|
3
3
|
export declare function useShopGPTSession(sessionId: string | null, apiBase?: string): {
|
|
4
4
|
session: ShopGPTSession | null;
|
|
5
5
|
error: string | null;
|
|
6
6
|
};
|
|
7
|
-
export declare function useShopGPTShoppableAd(
|
|
8
|
-
placementId?: string;
|
|
9
|
-
campaignId?: string;
|
|
7
|
+
export declare function useShopGPTShoppableAd(ad: ShopGPTAdParams | null, opts?: {
|
|
10
8
|
apiBase?: string;
|
|
11
9
|
autoCreate?: boolean;
|
|
12
10
|
}): {
|
|
@@ -30,15 +28,14 @@ export declare function ShopGPTAddToCartButton({ session, client, apiBase, qty,
|
|
|
30
28
|
onAdded?: (s: ShopGPTSession) => void;
|
|
31
29
|
className?: string;
|
|
32
30
|
}): import("react/jsx-runtime").JSX.Element | null;
|
|
33
|
-
export declare function ShopGPTCTVPlayer({ videoSrc,
|
|
31
|
+
export declare function ShopGPTCTVPlayer({ videoSrc, ad, apiBase, cta, ctaLabel, onConverted, }: {
|
|
34
32
|
videoSrc: string;
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
campaignId?: string;
|
|
33
|
+
/** VAST ad params: { shoppable, rankupid, cta } */
|
|
34
|
+
ad: ShopGPTAdParams;
|
|
38
35
|
apiBase?: string;
|
|
39
36
|
/** CTA preset passed to the button: "add_to_cart" | "send_to_phone" */
|
|
40
37
|
cta?: ShopGPTCta;
|
|
41
|
-
/** Fully custom CTA text (overrides the preset) */
|
|
38
|
+
/** Fully custom CTA text (overrides the preset and the ad's `cta`) */
|
|
42
39
|
ctaLabel?: string;
|
|
43
40
|
onConverted?: (s: ShopGPTSession) => void;
|
|
44
41
|
}): import("react/jsx-runtime").JSX.Element;
|
package/dist/react.js
CHANGED
|
@@ -22,35 +22,33 @@ export function useShopGPTSession(sessionId, apiBase) {
|
|
|
22
22
|
}, [sessionId, apiBase]);
|
|
23
23
|
return { session, error };
|
|
24
24
|
}
|
|
25
|
-
// ── Hook: create session
|
|
26
|
-
export function useShopGPTShoppableAd(
|
|
25
|
+
// ── Hook: create session from the VAST ad params (TV ad start) ────
|
|
26
|
+
export function useShopGPTShoppableAd(ad, opts) {
|
|
27
27
|
const [session, setSession] = useState(null);
|
|
28
28
|
const [loading, setLoading] = useState(false);
|
|
29
29
|
const clientRef = useRef(null);
|
|
30
30
|
if (!clientRef.current)
|
|
31
31
|
clientRef.current = new ShopGPTCTV(opts?.apiBase ? { apiBase: opts.apiBase } : {});
|
|
32
32
|
const create = useCallback(async () => {
|
|
33
|
-
if (!
|
|
33
|
+
if (!ad)
|
|
34
34
|
return null;
|
|
35
35
|
setLoading(true);
|
|
36
36
|
try {
|
|
37
|
-
const r = await clientRef.current.createSession(
|
|
38
|
-
placementId: opts?.placementId,
|
|
39
|
-
campaignId: opts?.campaignId,
|
|
40
|
-
});
|
|
37
|
+
const r = await clientRef.current.createSession(ad);
|
|
41
38
|
setSession(r.session);
|
|
42
|
-
|
|
39
|
+
if (r.session)
|
|
40
|
+
clientRef.current.pollSession(r.session.id, setSession);
|
|
43
41
|
return r.session;
|
|
44
42
|
}
|
|
45
43
|
finally {
|
|
46
44
|
setLoading(false);
|
|
47
45
|
}
|
|
48
|
-
}, [
|
|
46
|
+
}, [ad]);
|
|
49
47
|
useEffect(() => {
|
|
50
|
-
if (opts?.autoCreate !== false &&
|
|
48
|
+
if (opts?.autoCreate !== false && ad && !session)
|
|
51
49
|
void create();
|
|
52
50
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
53
|
-
}, [
|
|
51
|
+
}, [ad?.rankupid, ad?.shoppable]);
|
|
54
52
|
useEffect(() => () => clientRef.current?.stopPolling(), []);
|
|
55
53
|
return { session, loading, create };
|
|
56
54
|
}
|
|
@@ -86,16 +84,12 @@ export function ShopGPTAddToCartButton({ session, client, apiBase, qty = 1, cta
|
|
|
86
84
|
// ── Component: minimal CTV player wrapper ─────────────────────────
|
|
87
85
|
// Remote CTA button (raises `added_to_cart` flag). Overlay shows the
|
|
88
86
|
// product name only — no other chrome.
|
|
89
|
-
export function ShopGPTCTVPlayer({ videoSrc,
|
|
90
|
-
const { session } = useShopGPTShoppableAd(
|
|
91
|
-
placementId,
|
|
92
|
-
campaignId,
|
|
93
|
-
apiBase,
|
|
94
|
-
});
|
|
87
|
+
export function ShopGPTCTVPlayer({ videoSrc, ad, apiBase, cta = "add_to_cart", ctaLabel, onConverted, }) {
|
|
88
|
+
const { session } = useShopGPTShoppableAd(ad, { apiBase });
|
|
95
89
|
useEffect(() => {
|
|
96
90
|
if (session &&
|
|
97
91
|
(session.status === "added_to_cart" || session.status === "completed"))
|
|
98
92
|
onConverted?.(session);
|
|
99
93
|
}, [session, onConverted]);
|
|
100
|
-
return (_jsxs("div", { className: "relative aspect-video w-full overflow-hidden rounded-2xl bg-black", children: [_jsx("video", { src: videoSrc, controls: true, autoPlay: true, muted: true, loop: true, playsInline: true, className: "h-full w-full object-cover" }), session && (_jsx("div", { className: "absolute bottom-6 right-6 z-20 rounded-2xl bg-black/70 p-4 text-white shadow-2xl backdrop-blur", children: _jsxs("div", { className: "pr-2", children: [_jsx("p", { className: "max-w-[240px] truncate text-sm font-semibold", children: session.product.title }), _jsx("div", { className: "mt-2", children: _jsx(ShopGPTAddToCartButton, { session: session, apiBase: apiBase, cta: cta, label: ctaLabel }) })] }) }))] }));
|
|
94
|
+
return (_jsxs("div", { className: "relative aspect-video w-full overflow-hidden rounded-2xl bg-black", children: [_jsx("video", { src: videoSrc, controls: true, autoPlay: true, muted: true, loop: true, playsInline: true, className: "h-full w-full object-cover" }), session && (_jsx("div", { className: "absolute bottom-6 right-6 z-20 rounded-2xl bg-black/70 p-4 text-white shadow-2xl backdrop-blur", children: _jsxs("div", { className: "pr-2", children: [_jsx("p", { className: "max-w-[240px] truncate text-sm font-semibold", children: session.product.title }), _jsx("div", { className: "mt-2", children: _jsx(ShopGPTAddToCartButton, { session: session, apiBase: apiBase, cta: cta, label: ctaLabel ?? session.cta }) })] }) }))] }));
|
|
101
95
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -8,13 +8,22 @@ export interface ShopGPTProduct {
|
|
|
8
8
|
url?: string;
|
|
9
9
|
description?: string;
|
|
10
10
|
}
|
|
11
|
+
/** The three params a VAST ad carries. The product is resolved server-side from `rankupid`. */
|
|
12
|
+
export interface ShopGPTAdParams {
|
|
13
|
+
/** false → plain ad, no session is created */
|
|
14
|
+
shoppable?: boolean;
|
|
15
|
+
/** Our product id (unique identifier) */
|
|
16
|
+
rankupid: number | string;
|
|
17
|
+
/** CTA label shown on the TV, e.g. "Scan to buy" */
|
|
18
|
+
cta?: string;
|
|
19
|
+
}
|
|
11
20
|
export type ShopGPTSessionStatus = "created" | "scanned" | "viewing" | "added_to_cart" | "completed" | "expired";
|
|
12
21
|
export interface ShopGPTSession {
|
|
13
22
|
id: string;
|
|
14
23
|
product: ShopGPTProduct;
|
|
15
24
|
status: ShopGPTSessionStatus;
|
|
16
|
-
|
|
17
|
-
|
|
25
|
+
rankupid?: string;
|
|
26
|
+
cta?: string;
|
|
18
27
|
mobileUrl: string;
|
|
19
28
|
cartCount: number;
|
|
20
29
|
scanCount: number;
|
|
@@ -24,8 +33,6 @@ export interface ShopGPTSession {
|
|
|
24
33
|
export interface ShopGPTConfig {
|
|
25
34
|
/** e.g. "https://shop.example.com" — base the SDK falls back to for links. Defaults to window.location.origin */
|
|
26
35
|
apiBase?: string;
|
|
27
|
-
placementId?: string;
|
|
28
|
-
campaignId?: string;
|
|
29
36
|
pollIntervalMs?: number;
|
|
30
37
|
fetchImpl?: typeof fetch;
|
|
31
38
|
}
|
package/package.json
CHANGED
|
@@ -1,23 +1,28 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "shopgpt",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "ShopGPT Shoppable CTV Ad SDK — remote CTA to cart with live TV conversion events. Works on any HTML5 CTV player (Tizen, webOS, FireTV, AndroidTV).",
|
|
5
|
-
"main": "./dist/index.js",
|
|
6
|
-
"types": "./dist/index.d.ts",
|
|
7
|
-
"files": [
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
"
|
|
15
|
-
},
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
},
|
|
19
|
-
"
|
|
20
|
-
"react":
|
|
21
|
-
},
|
|
22
|
-
"
|
|
23
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "shopgpt",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "ShopGPT Shoppable CTV Ad SDK — remote CTA to cart with live TV conversion events. Works on any HTML5 CTV player (Tizen, webOS, FireTV, AndroidTV).",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"README.md"
|
|
10
|
+
],
|
|
11
|
+
"type": "module",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": "./dist/index.js",
|
|
14
|
+
"./react": "./dist/react.js"
|
|
15
|
+
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc -p tsconfig.json"
|
|
18
|
+
},
|
|
19
|
+
"peerDependencies": {
|
|
20
|
+
"react": ">=18"
|
|
21
|
+
},
|
|
22
|
+
"peerDependenciesMeta": {
|
|
23
|
+
"react": {
|
|
24
|
+
"optional": true
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"license": "MIT"
|
|
28
|
+
}
|