bodega-checkout 0.1.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 ADDED
@@ -0,0 +1,84 @@
1
+ # bodega-checkout
2
+
3
+ TypeScript SDK for [Bodega](https://bodega.dev) — crypto commerce checkout.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install bodega-checkout
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```ts
14
+ import { createClient } from "bodega-checkout";
15
+
16
+ const bodega = createClient({ apiKey: "sk_live_..." });
17
+
18
+ // Create a checkout session
19
+ const session = await bodega.checkout.create({
20
+ productId: "prod_abc",
21
+ successUrl: "https://myapp.com/success",
22
+ cancelUrl: "https://myapp.com/cancel",
23
+ });
24
+
25
+ // Check access
26
+ const access = await bodega.access.check("0x123...", "prod_abc");
27
+ console.log(access.hasAccess);
28
+
29
+ // List products
30
+ const products = await bodega.products.list();
31
+ ```
32
+
33
+ ## Popup Checkout (Browser)
34
+
35
+ ```ts
36
+ import { createClient, openPopup } from "bodega-checkout";
37
+
38
+ const bodega = createClient({ apiKey: "sk_live_..." });
39
+ const session = await bodega.checkout.create({ ... });
40
+
41
+ openPopup(session.url, {
42
+ onSuccess: (orderId, txHash) => console.log("Paid!", txHash),
43
+ onError: (error) => console.error(error),
44
+ onClose: () => console.log("Closed"),
45
+ });
46
+ ```
47
+
48
+ ## React Hook
49
+
50
+ ```tsx
51
+ import { useBodegaCheckout } from "bodega-checkout/react";
52
+
53
+ function BuyButton({ productId }: { productId: string }) {
54
+ const { checkout, isLoading, error } = useBodegaCheckout({
55
+ apiKey: "sk_live_...",
56
+ });
57
+
58
+ return (
59
+ <button
60
+ disabled={isLoading}
61
+ onClick={() =>
62
+ checkout(productId, {
63
+ onSuccess: (e) => console.log("Paid!", e.txHash),
64
+ onError: (err) => console.error(err),
65
+ onClose: () => console.log("Closed"),
66
+ })
67
+ }
68
+ >
69
+ {isLoading ? "Loading..." : "Buy Now"}
70
+ </button>
71
+ );
72
+ }
73
+ ```
74
+
75
+ ## Configuration
76
+
77
+ | Option | Default | Description |
78
+ | --------- | -------------------- | ------------------- |
79
+ | `apiKey` | — | Your Bodega API key |
80
+ | `baseUrl` | `https://bodega.dev` | API base URL |
81
+
82
+ ## License
83
+
84
+ MIT
@@ -0,0 +1,150 @@
1
+ // src/react/use-bodega.ts
2
+ import { useState, useCallback, useRef } from "react";
3
+
4
+ // src/client.ts
5
+ var DEFAULT_BASE_URL = "https://bodega.dev";
6
+ var BodegaClient = class {
7
+ constructor(config) {
8
+ this.checkout = {
9
+ create: (opts) => this.request("/api/v1/checkout/sessions", {
10
+ method: "POST",
11
+ body: JSON.stringify(opts)
12
+ })
13
+ };
14
+ this.access = {
15
+ check: (wallet, productId) => this.request(
16
+ `/api/v1/access/check?wallet=${encodeURIComponent(wallet)}&productId=${encodeURIComponent(productId)}`
17
+ )
18
+ };
19
+ this.products = {
20
+ list: () => this.request("/api/v1/products")
21
+ };
22
+ this.apiKey = config.apiKey;
23
+ this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
24
+ }
25
+ async request(path, init) {
26
+ const res = await fetch(`${this.baseUrl}${path}`, {
27
+ ...init,
28
+ headers: {
29
+ "Content-Type": "application/json",
30
+ Authorization: `Bearer ${this.apiKey}`,
31
+ ...init?.headers
32
+ }
33
+ });
34
+ if (!res.ok) {
35
+ const body = await res.text().catch(() => "");
36
+ throw new Error(`Bodega API error ${res.status}: ${body}`);
37
+ }
38
+ return res.json();
39
+ }
40
+ };
41
+
42
+ // src/popup.ts
43
+ var checkoutWindow = null;
44
+ function openPopup(checkoutUrl, callbacks = {}) {
45
+ closePopup();
46
+ checkoutWindow = window.open(checkoutUrl, "_blank");
47
+ if (!checkoutWindow) {
48
+ callbacks.onError?.("Popup blocked. Please allow popups for this site.");
49
+ return () => {
50
+ };
51
+ }
52
+ callbacks.onReady?.();
53
+ const pollTimer = setInterval(() => {
54
+ if (checkoutWindow?.closed) {
55
+ clearInterval(pollTimer);
56
+ window.removeEventListener("message", handleMessage);
57
+ checkoutWindow = null;
58
+ callbacks.onClose?.();
59
+ }
60
+ }, 500);
61
+ function handleMessage(e) {
62
+ const data = e.data;
63
+ if (!data || typeof data.type !== "string" || !data.type.startsWith("bodega:"))
64
+ return;
65
+ switch (data.type) {
66
+ case "bodega:ready":
67
+ callbacks.onReady?.();
68
+ break;
69
+ case "bodega:success":
70
+ callbacks.onSuccess?.(data.orderId, data.txHash);
71
+ cleanup();
72
+ break;
73
+ case "bodega:error":
74
+ callbacks.onError?.(data.error);
75
+ break;
76
+ case "bodega:close":
77
+ cleanup();
78
+ callbacks.onClose?.();
79
+ break;
80
+ }
81
+ }
82
+ window.addEventListener("message", handleMessage);
83
+ function cleanup() {
84
+ clearInterval(pollTimer);
85
+ window.removeEventListener("message", handleMessage);
86
+ closePopup();
87
+ }
88
+ return cleanup;
89
+ }
90
+ function closePopup() {
91
+ if (checkoutWindow && !checkoutWindow.closed) {
92
+ checkoutWindow.close();
93
+ }
94
+ checkoutWindow = null;
95
+ }
96
+
97
+ // src/react/use-bodega.ts
98
+ function useBodegaCheckout(config) {
99
+ const [isLoading, setIsLoading] = useState(false);
100
+ const [error, setError] = useState(null);
101
+ const cleanupRef = useRef(null);
102
+ const clientRef = useRef(null);
103
+ if (!clientRef.current) {
104
+ clientRef.current = new BodegaClient(config);
105
+ }
106
+ const checkout = useCallback(
107
+ async (productId, opts = {}) => {
108
+ setIsLoading(true);
109
+ setError(null);
110
+ try {
111
+ const session = await clientRef.current.checkout.create({
112
+ productId,
113
+ successUrl: opts.successUrl ?? window.location.href,
114
+ cancelUrl: opts.cancelUrl ?? window.location.href,
115
+ metadata: opts.metadata
116
+ });
117
+ cleanupRef.current?.();
118
+ cleanupRef.current = openPopup(session.url, {
119
+ onSuccess: (orderId, txHash) => {
120
+ setIsLoading(false);
121
+ opts.onSuccess?.({ type: "bodega:success", orderId, txHash });
122
+ },
123
+ onError: (err) => {
124
+ setError(err);
125
+ setIsLoading(false);
126
+ opts.onError?.(err);
127
+ },
128
+ onClose: () => {
129
+ setIsLoading(false);
130
+ opts.onClose?.();
131
+ }
132
+ });
133
+ } catch (err) {
134
+ const msg = err instanceof Error ? err.message : "Checkout failed";
135
+ setError(msg);
136
+ setIsLoading(false);
137
+ opts.onError?.(msg);
138
+ }
139
+ },
140
+ []
141
+ );
142
+ return { checkout, isLoading, error };
143
+ }
144
+
145
+ export {
146
+ BodegaClient,
147
+ openPopup,
148
+ closePopup,
149
+ useBodegaCheckout
150
+ };
@@ -0,0 +1,31 @@
1
+ import { B as BodegaConfig, C as CheckoutOptions, a as CheckoutSession, A as AccessRecord, P as Product } from './use-bodega-DMW30INZ.js';
2
+ export { b as BodegaCloseEvent, c as BodegaErrorEvent, d as BodegaEvent, e as BodegaReadyEvent, f as BodegaSuccessEvent, O as Order, U as UseCheckoutOptions, g as UseCheckoutReturn, u as useBodegaCheckout } from './use-bodega-DMW30INZ.js';
3
+
4
+ declare class BodegaClient {
5
+ private apiKey;
6
+ private baseUrl;
7
+ constructor(config: BodegaConfig);
8
+ private request;
9
+ checkout: {
10
+ create: (opts: CheckoutOptions) => Promise<CheckoutSession>;
11
+ };
12
+ access: {
13
+ check: (wallet: string, productId: string) => Promise<AccessRecord>;
14
+ };
15
+ products: {
16
+ list: () => Promise<Product[]>;
17
+ };
18
+ }
19
+
20
+ interface PopupCallbacks {
21
+ onReady?: () => void;
22
+ onSuccess?: (orderId: string, txHash: string) => void;
23
+ onError?: (error: string) => void;
24
+ onClose?: () => void;
25
+ }
26
+ declare function openPopup(checkoutUrl: string, callbacks?: PopupCallbacks): () => void;
27
+ declare function closePopup(): void;
28
+
29
+ declare function createClient(config: BodegaConfig): BodegaClient;
30
+
31
+ export { AccessRecord, BodegaClient, BodegaConfig, CheckoutOptions, CheckoutSession, Product, closePopup, createClient, openPopup };
package/dist/index.js ADDED
@@ -0,0 +1,18 @@
1
+ import {
2
+ BodegaClient,
3
+ closePopup,
4
+ openPopup,
5
+ useBodegaCheckout
6
+ } from "./chunk-RLJQ62ON.js";
7
+
8
+ // src/index.ts
9
+ function createClient(config) {
10
+ return new BodegaClient(config);
11
+ }
12
+ export {
13
+ BodegaClient,
14
+ closePopup,
15
+ createClient,
16
+ openPopup,
17
+ useBodegaCheckout
18
+ };
@@ -0,0 +1 @@
1
+ export { u as useBodegaCheckout } from '../use-bodega-DMW30INZ.js';
@@ -0,0 +1,6 @@
1
+ import {
2
+ useBodegaCheckout
3
+ } from "../chunk-RLJQ62ON.js";
4
+ export {
5
+ useBodegaCheckout
6
+ };
@@ -0,0 +1,76 @@
1
+ interface Product {
2
+ id: string;
3
+ name: string;
4
+ description?: string;
5
+ price: number;
6
+ currency: string;
7
+ imageUrl?: string;
8
+ createdAt: string;
9
+ }
10
+ interface Order {
11
+ id: string;
12
+ productId: string;
13
+ wallet: string;
14
+ txHash: string;
15
+ status: "pending" | "completed" | "failed";
16
+ createdAt: string;
17
+ }
18
+ interface CheckoutSession {
19
+ id: string;
20
+ url: string;
21
+ productId: string;
22
+ successUrl: string;
23
+ cancelUrl: string;
24
+ metadata?: Record<string, string>;
25
+ expiresAt: string;
26
+ }
27
+ interface AccessRecord {
28
+ hasAccess: boolean;
29
+ wallet: string;
30
+ productId: string;
31
+ orderId?: string;
32
+ grantedAt?: string;
33
+ }
34
+ interface BodegaConfig {
35
+ apiKey: string;
36
+ baseUrl?: string;
37
+ }
38
+ interface CheckoutOptions {
39
+ productId: string;
40
+ successUrl: string;
41
+ cancelUrl: string;
42
+ metadata?: Record<string, string>;
43
+ }
44
+ interface BodegaReadyEvent {
45
+ type: "bodega:ready";
46
+ }
47
+ interface BodegaSuccessEvent {
48
+ type: "bodega:success";
49
+ orderId: string;
50
+ txHash: string;
51
+ }
52
+ interface BodegaErrorEvent {
53
+ type: "bodega:error";
54
+ error: string;
55
+ }
56
+ interface BodegaCloseEvent {
57
+ type: "bodega:close";
58
+ }
59
+ type BodegaEvent = BodegaReadyEvent | BodegaSuccessEvent | BodegaErrorEvent | BodegaCloseEvent;
60
+ interface UseCheckoutOptions {
61
+ onSuccess?: (event: BodegaSuccessEvent) => void;
62
+ onError?: (error: string) => void;
63
+ onClose?: () => void;
64
+ successUrl?: string;
65
+ cancelUrl?: string;
66
+ metadata?: Record<string, string>;
67
+ }
68
+ interface UseCheckoutReturn {
69
+ checkout: (productId: string, opts?: UseCheckoutOptions) => Promise<void>;
70
+ isLoading: boolean;
71
+ error: string | null;
72
+ }
73
+
74
+ declare function useBodegaCheckout(config: BodegaConfig): UseCheckoutReturn;
75
+
76
+ export { type AccessRecord as A, type BodegaConfig as B, type CheckoutOptions as C, type Order as O, type Product as P, type UseCheckoutOptions as U, type CheckoutSession as a, type BodegaCloseEvent as b, type BodegaErrorEvent as c, type BodegaEvent as d, type BodegaReadyEvent as e, type BodegaSuccessEvent as f, type UseCheckoutReturn as g, useBodegaCheckout as u };
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "bodega-checkout",
3
+ "version": "0.1.0",
4
+ "description": "TypeScript SDK for Bodega — crypto commerce checkout. USDC payments on Base.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "main": "./dist/index.js",
8
+ "module": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "import": "./dist/index.js",
13
+ "types": "./dist/index.d.ts"
14
+ },
15
+ "./react": {
16
+ "import": "./dist/react/use-bodega.js",
17
+ "types": "./dist/react/use-bodega.d.ts"
18
+ }
19
+ },
20
+ "files": [
21
+ "dist"
22
+ ],
23
+ "keywords": [
24
+ "bodega",
25
+ "crypto",
26
+ "payments",
27
+ "usdc",
28
+ "base",
29
+ "checkout",
30
+ "web3"
31
+ ],
32
+ "scripts": {
33
+ "build": "tsup",
34
+ "dev": "tsup --watch",
35
+ "prepublishOnly": "tsup"
36
+ },
37
+ "peerDependencies": {
38
+ "react": ">=18.0.0"
39
+ },
40
+ "peerDependenciesMeta": {
41
+ "react": {
42
+ "optional": true
43
+ }
44
+ },
45
+ "devDependencies": {
46
+ "tsup": "^8.0.0",
47
+ "typescript": "^5.3.0",
48
+ "@types/react": "^18.0.0"
49
+ }
50
+ }