@kodice.one/stripefirebase-client 1.0.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,204 @@
1
+ # Firebase + Stripe Payments — Monorepo
2
+
3
+ End-to-end payment integration using **Firebase Functions v2**, **Firestore**, and **Stripe Checkout**, structured as an npm workspaces monorepo.
4
+
5
+ ---
6
+
7
+ ## Project structure
8
+
9
+ ```
10
+ firebase-stripe-payments/
11
+ ├── package.json ← workspace root
12
+ ├── tsconfig.base.json ← shared TS compiler base
13
+ ├── firebase.json ← Firebase project config
14
+ ├── firebase/
15
+ │ ├── firestore.rules ← Firestore security rules
16
+ │ └── firestore.indexes.json
17
+ └── packages/
18
+ ├── shared/ ← @kodice.one/stripefirebase-shared
19
+ │ ├── package.json
20
+ │ ├── tsconfig.json
21
+ │ └── src/index.ts ← all shared TypeScript types
22
+
23
+ ├── functions/ ← @kodice.one/stripefirebase-functions
24
+ │ ├── package.json
25
+ │ ├── tsconfig.json
26
+ │ └── src/index.ts ← createCheckout + stripeWebhook (Functions v2)
27
+
28
+ └── client/ ← @kodice.one/stripefirebase-client (publishable npm lib)
29
+ ├── package.json
30
+ ├── tsconfig.json
31
+ ├── tsconfig.esm.json
32
+ └── src/
33
+ ├── index.ts ← createCheckoutUrl, onPaymentStatusChange, onUserCheckouts
34
+ ├── react.ts ← useStripeCheckout, usePaymentStatus, useUserCheckouts
35
+ └── example.tsx ← reference React components
36
+ ```
37
+
38
+ ---
39
+
40
+ ## Architecture
41
+
42
+ ```
43
+ React App
44
+
45
+ ├─ @kodice.one/stripefirebase-client
46
+ │ ├─ createCheckoutUrl() → calls Firebase Function (onCall v2)
47
+ │ ├─ onPaymentStatusChange() → real-time Firestore listener
48
+ │ └─ /react hooks
49
+
50
+ Firebase Functions (v2)
51
+ ├─ createCheckout (onCall)
52
+ │ ├─ Validates auth + input
53
+ │ ├─ Creates Stripe Checkout Session
54
+ │ └─ Writes checkouts/{uid}/sessions/{sid} status: "pending"
55
+
56
+ └─ stripeWebhook (onRequest)
57
+ ├─ Verifies Stripe signature
58
+ └─ Updates Firestore status on each event:
59
+ checkout.session.completed → "succeeded"
60
+ checkout.session.expired → "expired"
61
+ payment_intent.payment_failed → "failed"
62
+ customer.subscription.deleted → "canceled"
63
+
64
+ Firestore
65
+ └─ checkouts/{userId}/sessions/{sessionId}
66
+ ```
67
+
68
+ ---
69
+
70
+ ## Getting started
71
+
72
+ ### 1. Install dependencies
73
+
74
+ ```bash
75
+ npm install
76
+ ```
77
+
78
+ This installs all workspace packages in one shot.
79
+
80
+ ### 2. Set Stripe secrets (stored in Google Cloud Secret Manager)
81
+
82
+ ```bash
83
+ firebase functions:secrets:set STRIPE_SECRET_KEY
84
+ # paste sk_live_... or sk_test_...
85
+
86
+ firebase functions:secrets:set STRIPE_WEBHOOK_SECRET
87
+ # paste whsec_... (from the Stripe Dashboard after step 4)
88
+ ```
89
+
90
+ ### 3. Build & deploy
91
+
92
+ ```bash
93
+ # Build everything (shared → functions → client)
94
+ npm run build
95
+
96
+ # Deploy Functions + Firestore rules/indexes
97
+ firebase deploy
98
+ ```
99
+
100
+ ### 4. Register the Stripe webhook
101
+
102
+ In [Stripe Dashboard → Webhooks](https://dashboard.stripe.com/webhooks) add:
103
+
104
+ - **URL:** `https://<region>-<project-id>.cloudfunctions.net/stripeWebhook`
105
+ - **Events:**
106
+ - `checkout.session.completed`
107
+ - `checkout.session.expired`
108
+ - `payment_intent.payment_failed`
109
+ - `customer.subscription.deleted`
110
+
111
+ Copy the **Signing secret** and save it: `firebase functions:secrets:set STRIPE_WEBHOOK_SECRET`.
112
+
113
+ ### 5. Use the client in your React app
114
+
115
+ ```bash
116
+ npm install @kodice.one/stripefirebase-client
117
+ ```
118
+
119
+ ```tsx
120
+ // main.tsx
121
+ import { initializeApp } from "firebase/app";
122
+ import { getFunctions } from "firebase/functions";
123
+ import { getFirestore } from "firebase/firestore";
124
+ import { initStripeFirebase } from "@kodice.one/stripefirebase-client";
125
+
126
+ const app = initializeApp({ /* your firebase config */ });
127
+
128
+ initStripeFirebase({
129
+ functions: getFunctions(app),
130
+ firestore: getFirestore(app),
131
+ });
132
+ ```
133
+
134
+ ```tsx
135
+ // PricingPage.tsx
136
+ import { useStripeCheckout } from "@kodice.one/stripefirebase-client/react";
137
+
138
+ export function SubscribeButton({ priceId }: { priceId: string }) {
139
+ const { startCheckout, loading, error } = useStripeCheckout();
140
+
141
+ return (
142
+ <button
143
+ disabled={loading}
144
+ onClick={() => startCheckout({
145
+ lineItems: [{ priceId, quantity: 1 }],
146
+ mode: "subscription",
147
+ successUrl: `${location.origin}/welcome?session_id={CHECKOUT_SESSION_ID}`,
148
+ cancelUrl: `${location.origin}/pricing`,
149
+ })}
150
+ >
151
+ {loading ? "Loading…" : "Subscribe"}
152
+ </button>
153
+ );
154
+ }
155
+ ```
156
+
157
+ ```tsx
158
+ // SuccessPage.tsx — mounted at your successUrl route
159
+ import { usePaymentStatus } from "@kodice.one/stripefirebase-client/react";
160
+
161
+ export function SuccessPage({ userId }: { userId: string }) {
162
+ const sessionId = new URLSearchParams(location.search).get("session_id");
163
+ const { status, session } = usePaymentStatus({ userId, sessionId });
164
+
165
+ if (status === "succeeded") return <h1>Welcome! 🎉</h1>;
166
+ if (status === "failed") return <p>Payment failed — please retry.</p>;
167
+ return <p>Confirming payment…</p>;
168
+ }
169
+ ```
170
+
171
+ ---
172
+
173
+ ## Local development
174
+
175
+ ```bash
176
+ # Start Firebase emulators (Functions + Firestore)
177
+ npm run emulate
178
+
179
+ # In a separate terminal — forward live Stripe events to the local webhook
180
+ stripe listen --forward-to http://localhost:5001/<project-id>/us-central1/stripeWebhook
181
+ ```
182
+
183
+ ---
184
+
185
+ ## Functions v2 highlights
186
+
187
+ | Feature | v1 | v2 (this project) |
188
+ |---|---|---|
189
+ | Import path | `firebase-functions` | `firebase-functions/v2/https` |
190
+ | Secrets | `functions.config()` | `defineSecret()` → Secret Manager |
191
+ | Config | `functions.config().stripe.key` | `process.env` / `secret.value()` |
192
+ | Logging | `functions.logger` | `import { logger } from "firebase-functions/v2"` |
193
+ | onCall data | `(data, context)` | `(request)` → `request.data`, `request.auth` |
194
+ | Concurrency | 1 req / instance | Up to 1000 req / instance |
195
+
196
+ ---
197
+
198
+ ## Security notes
199
+
200
+ - **Firestore rules** deny all client writes; only the Admin SDK (Functions) may write.
201
+ - **Auth guard** in `createCheckout` blocks unauthenticated callers.
202
+ - **Webhook signature** verification prevents spoofed Stripe events.
203
+ - `client_reference_id` and `metadata.userId` are set server-side — clients cannot impersonate another user's session.
204
+ - Stripe secrets are stored in **Google Cloud Secret Manager**, never in source code or `firebase.json`.
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Example React components — illustrates the full client integration.
3
+ * This file is for reference only; do not ship it in production.
4
+ */
5
+ import React from "react";
6
+ export declare function BuyButton({ priceId }: {
7
+ priceId: string;
8
+ }): React.JSX.Element;
9
+ export declare function SubscribeButton({ priceId }: {
10
+ priceId: string;
11
+ }): React.JSX.Element;
12
+ export declare function SuccessPage({ userId }: {
13
+ userId: string;
14
+ }): React.JSX.Element | null;
15
+ export declare function OrderHistory({ userId }: {
16
+ userId: string;
17
+ }): React.JSX.Element;
18
+ //# sourceMappingURL=example.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"example.d.ts","sourceRoot":"","sources":["../src/example.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAU1B,wBAAgB,SAAS,CAAC,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,qBAqBzD;AAID,wBAAgB,eAAe,CAAC,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,qBAsB/D;AAMD,wBAAgB,WAAW,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,4BAuBzD;AAID,wBAAgB,YAAY,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,qBAiB1D"}
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ /**
3
+ * Example React components — illustrates the full client integration.
4
+ * This file is for reference only; do not ship it in production.
5
+ */
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.BuyButton = BuyButton;
11
+ exports.SubscribeButton = SubscribeButton;
12
+ exports.SuccessPage = SuccessPage;
13
+ exports.OrderHistory = OrderHistory;
14
+ const react_1 = __importDefault(require("react"));
15
+ const react_2 = require("./react");
16
+ // ── One-time payment button ──────────────────────────────────────────────────
17
+ function BuyButton({ priceId }) {
18
+ const { startCheckout, loading, error } = (0, react_2.useStripeCheckout)();
19
+ return (react_1.default.createElement("div", null,
20
+ react_1.default.createElement("button", { disabled: loading, onClick: () => startCheckout({
21
+ lineItems: [{ priceId, quantity: 1 }],
22
+ mode: "payment",
23
+ successUrl: `${window.location.origin}/success?session_id={CHECKOUT_SESSION_ID}`,
24
+ cancelUrl: `${window.location.origin}/pricing`,
25
+ }) }, loading ? "Redirecting…" : "Buy now"),
26
+ error && react_1.default.createElement("p", { style: { color: "red" } }, error.message)));
27
+ }
28
+ // ── Subscription button ──────────────────────────────────────────────────────
29
+ function SubscribeButton({ priceId }) {
30
+ const { startCheckout, loading, error } = (0, react_2.useStripeCheckout)();
31
+ return (react_1.default.createElement("div", null,
32
+ react_1.default.createElement("button", { disabled: loading, onClick: () => startCheckout({
33
+ lineItems: [{ priceId, quantity: 1 }],
34
+ mode: "subscription",
35
+ successUrl: `${window.location.origin}/welcome?session_id={CHECKOUT_SESSION_ID}`,
36
+ cancelUrl: `${window.location.origin}/pricing`,
37
+ metadata: { plan: "pro" },
38
+ }) }, loading ? "Loading…" : "Subscribe"),
39
+ error && react_1.default.createElement("p", { style: { color: "red" } }, error.message)));
40
+ }
41
+ // ── Success page ─────────────────────────────────────────────────────────────
42
+ // Mount at whatever URL you pass as successUrl (e.g. /success).
43
+ // Stripe appends ?session_id=cs_... automatically.
44
+ function SuccessPage({ userId }) {
45
+ const sessionId = new URLSearchParams(window.location.search).get("session_id");
46
+ const { status, session, loading, error } = (0, react_2.usePaymentStatus)({ userId, sessionId });
47
+ if (loading)
48
+ return react_1.default.createElement("p", null, "Confirming payment\u2026");
49
+ if (error)
50
+ return react_1.default.createElement("p", null,
51
+ "Error: ",
52
+ error.message);
53
+ if (status === "succeeded") {
54
+ return (react_1.default.createElement("div", null,
55
+ react_1.default.createElement("h1", null, "Payment confirmed!"),
56
+ react_1.default.createElement("p", null,
57
+ "Mode: ", session === null || session === void 0 ? void 0 :
58
+ session.mode),
59
+ (session === null || session === void 0 ? void 0 : session.mode) === "subscription" && (react_1.default.createElement("p", null,
60
+ "Subscription ID: ",
61
+ session.subscriptionId))));
62
+ }
63
+ if (status === "failed")
64
+ return react_1.default.createElement("p", null, "Payment failed. Please try again.");
65
+ if (status === "pending")
66
+ return react_1.default.createElement("p", null, "Waiting for confirmation\u2026");
67
+ return null;
68
+ }
69
+ // ── Order history ─────────────────────────────────────────────────────────────
70
+ function OrderHistory({ userId }) {
71
+ const { sessions, loading, error } = (0, react_2.useUserCheckouts)({ userId });
72
+ if (loading)
73
+ return react_1.default.createElement("p", null, "Loading orders\u2026");
74
+ if (error)
75
+ return react_1.default.createElement("p", null,
76
+ "Error: ",
77
+ error.message);
78
+ if (!sessions.length)
79
+ return react_1.default.createElement("p", null, "No orders yet.");
80
+ return (react_1.default.createElement("ul", null, sessions.map((s) => (react_1.default.createElement("li", { key: s.sessionId },
81
+ react_1.default.createElement("strong", null, s.mode),
82
+ " \u2014 ",
83
+ s.status,
84
+ " \u2014",
85
+ " ",
86
+ new Date(s.createdAt).toLocaleDateString())))));
87
+ }
88
+ //# sourceMappingURL=example.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"example.js","sourceRoot":"","sources":["../src/example.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * @kodice.one/stripefirebase-client — core
3
+ *
4
+ * Framework-agnostic helpers for creating Stripe Checkout sessions and
5
+ * listening to payment status updates via Firestore.
6
+ *
7
+ * Initialize once at app startup, then call createCheckoutUrl() and
8
+ * onPaymentStatusChange() anywhere in your application.
9
+ */
10
+ import { Functions } from "firebase/functions";
11
+ import { Firestore, Unsubscribe } from "firebase/firestore";
12
+ export type { PaymentMode, CheckoutStatus, LineItem, CreateCheckoutRequest, CreateCheckoutResponse, CheckoutDocument, } from "@kodice.one/stripefirebase-shared";
13
+ import type { CreateCheckoutRequest, CreateCheckoutResponse, CheckoutDocument, CheckoutStatus } from "@kodice.one/stripefirebase-shared";
14
+ /**
15
+ * Initialise the client library. Call once after `initializeApp()`.
16
+ *
17
+ * @example
18
+ * import { initializeApp } from "firebase/app";
19
+ * import { getFunctions } from "firebase/functions";
20
+ * import { getFirestore } from "firebase/firestore";
21
+ * import { initStripeFirebase } from "@kodice.one/stripefirebase-client";
22
+ *
23
+ * const app = initializeApp({ ...firebaseConfig });
24
+ * initStripeFirebase({
25
+ * functions: getFunctions(app),
26
+ * firestore: getFirestore(app),
27
+ * });
28
+ */
29
+ export declare function initStripeFirebase(opts: {
30
+ functions: Functions;
31
+ firestore: Firestore;
32
+ }): void;
33
+ /**
34
+ * Calls the `createCheckout` Firebase Function and returns the Stripe
35
+ * Checkout URL along with the session ID.
36
+ *
37
+ * @example
38
+ * const { sessionId, checkoutUrl } = await createCheckoutUrl({
39
+ * lineItems: [{ priceId: "price_abc123", quantity: 1 }],
40
+ * mode: "subscription",
41
+ * successUrl: `${location.origin}/success?session_id={CHECKOUT_SESSION_ID}`,
42
+ * cancelUrl: `${location.origin}/pricing`,
43
+ * });
44
+ * window.location.href = checkoutUrl;
45
+ */
46
+ export declare function createCheckoutUrl(request: CreateCheckoutRequest): Promise<CreateCheckoutResponse>;
47
+ export interface PaymentStatusChangeOptions {
48
+ /** Firebase Auth UID of the current user. */
49
+ userId: string;
50
+ /** Stripe Checkout Session ID returned by createCheckoutUrl. */
51
+ sessionId: string;
52
+ /** Invoked on every document change (including the initial read). */
53
+ onStatusChange: (status: CheckoutStatus, document: CheckoutDocument) => void;
54
+ /** Invoked on Firestore errors. Defaults to console.error. */
55
+ onError?: (error: Error) => void;
56
+ }
57
+ /**
58
+ * Subscribes to real-time Firestore updates for a single Checkout session.
59
+ * Returns an unsubscribe function — call it in cleanup / useEffect teardown.
60
+ *
61
+ * @example
62
+ * const unsub = onPaymentStatusChange({
63
+ * userId,
64
+ * sessionId,
65
+ * onStatusChange: (status, doc) => {
66
+ * if (status === "succeeded") showSuccessBanner(doc);
67
+ * if (status === "failed") showErrorBanner();
68
+ * },
69
+ * });
70
+ * return () => unsub(); // cleanup
71
+ */
72
+ export declare function onPaymentStatusChange(opts: PaymentStatusChangeOptions): Unsubscribe;
73
+ /**
74
+ * Subscribes to all Checkout sessions for a user, newest first.
75
+ * Useful for building an order history page.
76
+ */
77
+ export declare function onUserCheckouts(opts: {
78
+ userId: string;
79
+ maxSessions?: number;
80
+ onCheckouts: (sessions: CheckoutDocument[]) => void;
81
+ onError?: (error: Error) => void;
82
+ }): Unsubscribe;
83
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACL,SAAS,EAGV,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,SAAS,EAOT,WAAW,EACZ,MAAM,oBAAoB,CAAC;AAE5B,YAAY,EACV,WAAW,EACX,cAAc,EACd,QAAQ,EACR,qBAAqB,EACrB,sBAAsB,EACtB,gBAAgB,GACjB,MAAM,mCAAmC,CAAC;AAE3C,OAAO,KAAK,EACV,qBAAqB,EACrB,sBAAsB,EACtB,gBAAgB,EAChB,cAAc,EACf,MAAM,mCAAmC,CAAC;AAS3C;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACvC,SAAS,EAAE,SAAS,CAAC;IACrB,SAAS,EAAE,SAAS,CAAC;CACtB,GAAG,IAAI,CAGP;AAgBD;;;;;;;;;;;;GAYG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,sBAAsB,CAAC,CAejC;AAMD,MAAM,WAAW,0BAA0B;IACzC,6CAA6C;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,SAAS,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,cAAc,EAAE,CAAC,MAAM,EAAE,cAAc,EAAE,QAAQ,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC7E,8DAA8D;IAC9D,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,0BAA0B,GAC/B,WAAW,CAqBb;AAMD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,CAAC,QAAQ,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IACpD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC,GAAG,WAAW,CAed"}
package/dist/index.js ADDED
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+ /**
3
+ * @kodice.one/stripefirebase-client — core
4
+ *
5
+ * Framework-agnostic helpers for creating Stripe Checkout sessions and
6
+ * listening to payment status updates via Firestore.
7
+ *
8
+ * Initialize once at app startup, then call createCheckoutUrl() and
9
+ * onPaymentStatusChange() anywhere in your application.
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.initStripeFirebase = initStripeFirebase;
13
+ exports.createCheckoutUrl = createCheckoutUrl;
14
+ exports.onPaymentStatusChange = onPaymentStatusChange;
15
+ exports.onUserCheckouts = onUserCheckouts;
16
+ const functions_1 = require("firebase/functions");
17
+ const firestore_1 = require("firebase/firestore");
18
+ // ─────────────────────────────────────────────────────────────────────────────
19
+ // Singleton state
20
+ // ─────────────────────────────────────────────────────────────────────────────
21
+ let _functions = null;
22
+ let _firestore = null;
23
+ /**
24
+ * Initialise the client library. Call once after `initializeApp()`.
25
+ *
26
+ * @example
27
+ * import { initializeApp } from "firebase/app";
28
+ * import { getFunctions } from "firebase/functions";
29
+ * import { getFirestore } from "firebase/firestore";
30
+ * import { initStripeFirebase } from "@kodice.one/stripefirebase-client";
31
+ *
32
+ * const app = initializeApp({ ...firebaseConfig });
33
+ * initStripeFirebase({
34
+ * functions: getFunctions(app),
35
+ * firestore: getFirestore(app),
36
+ * });
37
+ */
38
+ function initStripeFirebase(opts) {
39
+ _functions = opts.functions;
40
+ _firestore = opts.firestore;
41
+ }
42
+ function requireFunctions() {
43
+ if (!_functions)
44
+ throw new Error("[kodice.one/stripefirebase-client] Call initStripeFirebase() first.");
45
+ return _functions;
46
+ }
47
+ function requireFirestore() {
48
+ if (!_firestore)
49
+ throw new Error("[kodice.one/stripefirebase-client] Call initStripeFirebase() first.");
50
+ return _firestore;
51
+ }
52
+ // ─────────────────────────────────────────────────────────────────────────────
53
+ // createCheckoutUrl
54
+ // ─────────────────────────────────────────────────────────────────────────────
55
+ /**
56
+ * Calls the `createCheckout` Firebase Function and returns the Stripe
57
+ * Checkout URL along with the session ID.
58
+ *
59
+ * @example
60
+ * const { sessionId, checkoutUrl } = await createCheckoutUrl({
61
+ * lineItems: [{ priceId: "price_abc123", quantity: 1 }],
62
+ * mode: "subscription",
63
+ * successUrl: `${location.origin}/success?session_id={CHECKOUT_SESSION_ID}`,
64
+ * cancelUrl: `${location.origin}/pricing`,
65
+ * });
66
+ * window.location.href = checkoutUrl;
67
+ */
68
+ async function createCheckoutUrl(request) {
69
+ const fn = (0, functions_1.httpsCallable)(requireFunctions(), "createCheckout");
70
+ let result;
71
+ try {
72
+ result = await fn(request);
73
+ }
74
+ catch (err) {
75
+ const msg = err instanceof Error ? err.message : "Failed to create checkout";
76
+ throw new Error(`[kodice.one/stripefirebase-client] ${msg}`);
77
+ }
78
+ return result.data;
79
+ }
80
+ /**
81
+ * Subscribes to real-time Firestore updates for a single Checkout session.
82
+ * Returns an unsubscribe function — call it in cleanup / useEffect teardown.
83
+ *
84
+ * @example
85
+ * const unsub = onPaymentStatusChange({
86
+ * userId,
87
+ * sessionId,
88
+ * onStatusChange: (status, doc) => {
89
+ * if (status === "succeeded") showSuccessBanner(doc);
90
+ * if (status === "failed") showErrorBanner();
91
+ * },
92
+ * });
93
+ * return () => unsub(); // cleanup
94
+ */
95
+ function onPaymentStatusChange(opts) {
96
+ const ref = (0, firestore_1.doc)(requireFirestore(), "checkouts", opts.userId, "sessions", opts.sessionId);
97
+ return (0, firestore_1.onSnapshot)(ref, (snap) => {
98
+ if (!snap.exists())
99
+ return;
100
+ const data = snap.data();
101
+ opts.onStatusChange(data.status, data);
102
+ }, (err) => {
103
+ if (opts.onError)
104
+ opts.onError(err);
105
+ else
106
+ console.error("[kodice.one/stripefirebase-client] Firestore error:", err);
107
+ });
108
+ }
109
+ // ─────────────────────────────────────────────────────────────────────────────
110
+ // onUserCheckouts
111
+ // ─────────────────────────────────────────────────────────────────────────────
112
+ /**
113
+ * Subscribes to all Checkout sessions for a user, newest first.
114
+ * Useful for building an order history page.
115
+ */
116
+ function onUserCheckouts(opts) {
117
+ var _a;
118
+ const q = (0, firestore_1.query)((0, firestore_1.collection)(requireFirestore(), "checkouts", opts.userId, "sessions"), (0, firestore_1.orderBy)("createdAt", "desc"), (0, firestore_1.limit)((_a = opts.maxSessions) !== null && _a !== void 0 ? _a : 20));
119
+ return (0, firestore_1.onSnapshot)(q, (snap) => opts.onCheckouts(snap.docs.map((d) => d.data())), (err) => {
120
+ if (opts.onError)
121
+ opts.onError(err);
122
+ else
123
+ console.error("[kodice.one/stripefirebase-client] Firestore error:", err);
124
+ });
125
+ }
126
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * @kodice.one/stripefirebase-client/react
3
+ *
4
+ * React hooks built on top of the core library.
5
+ * Import: `import { useStripeCheckout } from "@kodice.one/stripefirebase-client/react"`
6
+ */
7
+ import type { CreateCheckoutRequest, CreateCheckoutResponse, CheckoutDocument, CheckoutStatus } from "@kodice.one/stripefirebase-shared";
8
+ export interface UseStripeCheckoutOptions {
9
+ /**
10
+ * When true (default), the hook automatically redirects to the Stripe
11
+ * Checkout page after a session is created.
12
+ */
13
+ autoRedirect?: boolean;
14
+ }
15
+ export interface UseStripeCheckoutReturn {
16
+ /** Initiates the checkout flow. Resolves with the session data or null on error. */
17
+ startCheckout: (req: CreateCheckoutRequest) => Promise<CreateCheckoutResponse | null>;
18
+ loading: boolean;
19
+ error: Error | null;
20
+ /** Session ID of the most recently created checkout — use with usePaymentStatus. */
21
+ sessionId: string | null;
22
+ checkoutUrl: string | null;
23
+ }
24
+ /**
25
+ * Hook that wraps createCheckoutUrl with loading/error state and optional
26
+ * auto-redirect to the Stripe Checkout page.
27
+ *
28
+ * @example
29
+ * const { startCheckout, loading, error } = useStripeCheckout();
30
+ *
31
+ * <button onClick={() => startCheckout({
32
+ * lineItems: [{ priceId: "price_abc", quantity: 1 }],
33
+ * mode: "subscription",
34
+ * successUrl: `${location.origin}/success?session_id={CHECKOUT_SESSION_ID}`,
35
+ * cancelUrl: `${location.origin}/pricing`,
36
+ * })}>
37
+ * Subscribe
38
+ * </button>
39
+ */
40
+ export declare function useStripeCheckout(options?: UseStripeCheckoutOptions): UseStripeCheckoutReturn;
41
+ export interface UsePaymentStatusReturn {
42
+ status: CheckoutStatus | null;
43
+ session: CheckoutDocument | null;
44
+ loading: boolean;
45
+ error: Error | null;
46
+ }
47
+ /**
48
+ * Subscribes to real-time status updates for a specific Checkout session.
49
+ * Mount this on your `/success` page to confirm payment before showing
50
+ * the confirmation UI.
51
+ *
52
+ * @example
53
+ * // /success page — Stripe appends ?session_id=... to your successUrl
54
+ * const sessionId = new URLSearchParams(location.search).get("session_id");
55
+ * const { status, session } = usePaymentStatus({ userId: user.uid, sessionId });
56
+ *
57
+ * if (status === "succeeded") return <SuccessBanner plan={session?.metadata.plan} />;
58
+ * if (status === "failed") return <RetryButton />;
59
+ */
60
+ export declare function usePaymentStatus(opts: {
61
+ userId: string | null | undefined;
62
+ sessionId: string | null | undefined;
63
+ }): UsePaymentStatusReturn;
64
+ export interface UseUserCheckoutsReturn {
65
+ sessions: CheckoutDocument[];
66
+ loading: boolean;
67
+ error: Error | null;
68
+ }
69
+ /**
70
+ * Subscribes to all Checkout sessions for the current user, newest first.
71
+ *
72
+ * @example
73
+ * const { sessions } = useUserCheckouts({ userId: user.uid });
74
+ * return <OrderList orders={sessions} />;
75
+ */
76
+ export declare function useUserCheckouts(opts: {
77
+ userId: string | null | undefined;
78
+ maxSessions?: number;
79
+ }): UseUserCheckoutsReturn;
80
+ //# sourceMappingURL=react.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,OAAO,KAAK,EACV,qBAAqB,EACrB,sBAAsB,EACtB,gBAAgB,EAChB,cAAc,EACf,MAAM,mCAAmC,CAAC;AAM3C,MAAM,WAAW,wBAAwB;IACvC;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,uBAAuB;IACtC,oFAAoF;IACpF,aAAa,EAAE,CAAC,GAAG,EAAE,qBAAqB,KAAK,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC,CAAC;IACtF,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,oFAAoF;IACpF,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,GAAE,wBAA6B,GACrC,uBAAuB,CA+BzB;AAMD,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,cAAc,GAAG,IAAI,CAAC;IAC9B,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACrB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IACrC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAClC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;CACtC,GAAG,sBAAsB,CAgCzB;AAMD,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACrB;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IACrC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAClC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GAAG,sBAAsB,CA4BzB"}
package/dist/react.js ADDED
@@ -0,0 +1,131 @@
1
+ "use strict";
2
+ /**
3
+ * @kodice.one/stripefirebase-client/react
4
+ *
5
+ * React hooks built on top of the core library.
6
+ * Import: `import { useStripeCheckout } from "@kodice.one/stripefirebase-client/react"`
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.useStripeCheckout = useStripeCheckout;
10
+ exports.usePaymentStatus = usePaymentStatus;
11
+ exports.useUserCheckouts = useUserCheckouts;
12
+ const react_1 = require("react");
13
+ const index_1 = require("./index");
14
+ /**
15
+ * Hook that wraps createCheckoutUrl with loading/error state and optional
16
+ * auto-redirect to the Stripe Checkout page.
17
+ *
18
+ * @example
19
+ * const { startCheckout, loading, error } = useStripeCheckout();
20
+ *
21
+ * <button onClick={() => startCheckout({
22
+ * lineItems: [{ priceId: "price_abc", quantity: 1 }],
23
+ * mode: "subscription",
24
+ * successUrl: `${location.origin}/success?session_id={CHECKOUT_SESSION_ID}`,
25
+ * cancelUrl: `${location.origin}/pricing`,
26
+ * })}>
27
+ * Subscribe
28
+ * </button>
29
+ */
30
+ function useStripeCheckout(options = {}) {
31
+ const { autoRedirect = true } = options;
32
+ const [loading, setLoading] = (0, react_1.useState)(false);
33
+ const [error, setError] = (0, react_1.useState)(null);
34
+ const [sessionId, setSessionId] = (0, react_1.useState)(null);
35
+ const [checkoutUrl, setCheckoutUrl] = (0, react_1.useState)(null);
36
+ const startCheckout = (0, react_1.useCallback)(async (req) => {
37
+ setLoading(true);
38
+ setError(null);
39
+ try {
40
+ const response = await (0, index_1.createCheckoutUrl)(req);
41
+ setSessionId(response.sessionId);
42
+ setCheckoutUrl(response.checkoutUrl);
43
+ if (autoRedirect)
44
+ window.location.href = response.checkoutUrl;
45
+ return response;
46
+ }
47
+ catch (err) {
48
+ const e = err instanceof Error ? err : new Error(String(err));
49
+ setError(e);
50
+ return null;
51
+ }
52
+ finally {
53
+ setLoading(false);
54
+ }
55
+ }, [autoRedirect]);
56
+ return { startCheckout, loading, error, sessionId, checkoutUrl };
57
+ }
58
+ /**
59
+ * Subscribes to real-time status updates for a specific Checkout session.
60
+ * Mount this on your `/success` page to confirm payment before showing
61
+ * the confirmation UI.
62
+ *
63
+ * @example
64
+ * // /success page — Stripe appends ?session_id=... to your successUrl
65
+ * const sessionId = new URLSearchParams(location.search).get("session_id");
66
+ * const { status, session } = usePaymentStatus({ userId: user.uid, sessionId });
67
+ *
68
+ * if (status === "succeeded") return <SuccessBanner plan={session?.metadata.plan} />;
69
+ * if (status === "failed") return <RetryButton />;
70
+ */
71
+ function usePaymentStatus(opts) {
72
+ const [status, setStatus] = (0, react_1.useState)(null);
73
+ const [session, setSession] = (0, react_1.useState)(null);
74
+ const [loading, setLoading] = (0, react_1.useState)(true);
75
+ const [error, setError] = (0, react_1.useState)(null);
76
+ (0, react_1.useEffect)(() => {
77
+ if (!opts.userId || !opts.sessionId) {
78
+ setLoading(false);
79
+ return;
80
+ }
81
+ setLoading(true);
82
+ const unsub = (0, index_1.onPaymentStatusChange)({
83
+ userId: opts.userId,
84
+ sessionId: opts.sessionId,
85
+ onStatusChange: (newStatus, doc) => {
86
+ setStatus(newStatus);
87
+ setSession(doc);
88
+ setLoading(false);
89
+ },
90
+ onError: (err) => {
91
+ setError(err);
92
+ setLoading(false);
93
+ },
94
+ });
95
+ return () => unsub();
96
+ }, [opts.userId, opts.sessionId]);
97
+ return { status, session, loading, error };
98
+ }
99
+ /**
100
+ * Subscribes to all Checkout sessions for the current user, newest first.
101
+ *
102
+ * @example
103
+ * const { sessions } = useUserCheckouts({ userId: user.uid });
104
+ * return <OrderList orders={sessions} />;
105
+ */
106
+ function useUserCheckouts(opts) {
107
+ const [sessions, setSessions] = (0, react_1.useState)([]);
108
+ const [loading, setLoading] = (0, react_1.useState)(true);
109
+ const [error, setError] = (0, react_1.useState)(null);
110
+ (0, react_1.useEffect)(() => {
111
+ if (!opts.userId) {
112
+ setLoading(false);
113
+ return;
114
+ }
115
+ const unsub = (0, index_1.onUserCheckouts)({
116
+ userId: opts.userId,
117
+ maxSessions: opts.maxSessions,
118
+ onCheckouts: (docs) => {
119
+ setSessions(docs);
120
+ setLoading(false);
121
+ },
122
+ onError: (err) => {
123
+ setError(err);
124
+ setLoading(false);
125
+ },
126
+ });
127
+ return () => unsub();
128
+ }, [opts.userId, opts.maxSessions]);
129
+ return { sessions, loading, error };
130
+ }
131
+ //# sourceMappingURL=react.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.js","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@kodice.one/stripefirebase-client",
3
+ "version": "1.0.0",
4
+ "private": false,
5
+ "description": "React client library for Firebase + Stripe payment integration",
6
+ "main": "dist/index.js",
7
+ "module": "dist/index.esm.js",
8
+ "types": "dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/index.esm.js",
12
+ "require": "./dist/index.js",
13
+ "types": "./dist/index.d.ts"
14
+ },
15
+ "./react": {
16
+ "import": "./dist/react.esm.js",
17
+ "require": "./dist/react.js",
18
+ "types": "./dist/react.d.ts"
19
+ }
20
+ },
21
+ "scripts": {
22
+ "build": "tsc -p tsconfig.json && tsc -p tsconfig.esm.json",
23
+ "build:watch": "tsc --watch",
24
+ "clean": "rm -rf dist"
25
+ },
26
+ "engines": {
27
+ "node": ">=24.0.0"
28
+ },
29
+ "dependencies": {
30
+ "@kodice.one/stripefirebase-shared": "^1.0.0"
31
+ },
32
+ "peerDependencies": {
33
+ "firebase": ">=10.0.0",
34
+ "react": ">=17.0.0"
35
+ },
36
+ "devDependencies": {
37
+ "@types/node": "^24.0.0",
38
+ "@types/react": "^18.0.0",
39
+ "typescript": "^5.4.0"
40
+ },
41
+ "files": [
42
+ "dist"
43
+ ],
44
+ "license": "MIT"
45
+ }