@flopay/node 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,157 @@
1
+ # @flopay/node
2
+
3
+ Server-side FloPay SDK for Node.js. Creates checkout sessions via the billing API, manages Stripe customers, and verifies webhooks.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pnpm add @flopay/node
9
+ ```
10
+
11
+ Depends on `stripe` (^17.0.0) and `@flopay/shared`.
12
+
13
+ ## Quick Start
14
+
15
+ ### Initialize
16
+
17
+ ```ts
18
+ import { FloPay } from '@flopay/node';
19
+
20
+ const flopay = new FloPay('sk_test_...');
21
+ ```
22
+
23
+ ### Create a Checkout Session (Billing API)
24
+
25
+ ```ts
26
+ const result = await flopay.checkout.sessions.create({
27
+ billingApiUrl: 'https://billing.example.com',
28
+ checkoutBaseUrl: 'https://checkout.example.com',
29
+ clientId: 'client_123',
30
+ items: [{
31
+ providerItemId: 'prod_abc',
32
+ providerItemName: 'Pro Plan',
33
+ totalAmount: 49.99,
34
+ overrideAmount: 24.99,
35
+ currency: 'USD',
36
+ }],
37
+ subscriptions: [{
38
+ providerPlanId: 'plan_xyz',
39
+ providerPlanName: 'Monthly Plan',
40
+ totalAmount: 9.99,
41
+ currency: 'USD',
42
+ }],
43
+ account: {
44
+ userId: 'user_1',
45
+ email: 'user@example.com',
46
+ firstName: 'John',
47
+ lastName: 'Doe',
48
+ },
49
+ successUrl: 'https://example.com/success',
50
+ cancelUrl: 'https://example.com/cancel',
51
+ checkoutMode: 'confirm', // 'confirm' | 'auto' | 'full'
52
+ couponCodes: ['SAVE10'],
53
+ tagsData: { googleContainerId: 'GTM-XXXX' },
54
+ redirectParams: { email: 'user@example.com', mode: 'confirm' },
55
+ timeoutMs: 12000,
56
+ });
57
+
58
+ // result = { status: 201, redirectUrl: 'https://checkout.example.com/secure?id=uuid&...' }
59
+ // result = { status: 204 } (payment method already on file)
60
+ ```
61
+
62
+ ### Retrieve / Expire a Checkout Session (Stripe Direct)
63
+
64
+ ```ts
65
+ const session = await flopay.checkout.sessions.retrieve('cs_test_...');
66
+ // { id, clientSecret, mode, status, amount, currency, metadata }
67
+
68
+ const expired = await flopay.checkout.sessions.expire('cs_test_...');
69
+
70
+ const lineItems = await flopay.checkout.sessions.listLineItems('cs_test_...');
71
+ // [{ price: 'price_xxx', quantity: 1 }]
72
+ ```
73
+
74
+ ### Manage Customers
75
+
76
+ ```ts
77
+ const customer = await flopay.customers.create({
78
+ email: 'user@example.com',
79
+ name: 'John Doe',
80
+ metadata: { plan: 'pro' },
81
+ });
82
+ // { id: 'cus_xxx', email: '...', firstName: 'John', lastName: 'Doe' }
83
+
84
+ const retrieved = await flopay.customers.retrieve('cus_xxx');
85
+
86
+ const updated = await flopay.customers.update('cus_xxx', {
87
+ name: 'Jane Doe',
88
+ metadata: { plan: 'enterprise' },
89
+ });
90
+ ```
91
+
92
+ ### Verify Webhooks
93
+
94
+ ```ts
95
+ import { FloPay } from '@flopay/node';
96
+
97
+ const flopay = new FloPay('sk_test_...');
98
+
99
+ // In your webhook handler (e.g. Express, Next.js API route):
100
+ const event = flopay.webhooks.constructEvent(
101
+ requestBody, // raw body string or Buffer
102
+ signatureHeader, // Stripe-Signature header
103
+ 'whsec_...', // webhook signing secret
104
+ );
105
+
106
+ console.log(event.type); // e.g. 'checkout.session.completed'
107
+ console.log(event.data); // event payload
108
+ console.log(event.created); // unix timestamp
109
+ ```
110
+
111
+ ## API Reference
112
+
113
+ ### Constructor
114
+
115
+ ```ts
116
+ new FloPay(secretKey: string, options?: FloPayNodeOptions)
117
+ ```
118
+
119
+ | Parameter | Type | Description |
120
+ |-----------|------|-------------|
121
+ | `secretKey` | `string` | Stripe secret key (`sk_test_...` or `sk_live_...`). Required. |
122
+ | `options.apiVersion` | `string?` | API version override |
123
+ | `options.stripeSecretKey` | `string?` | Explicit Stripe key (for future multi-provider support) |
124
+
125
+ ### `flopay.checkout.sessions`
126
+
127
+ | Method | Returns | Description |
128
+ |--------|---------|-------------|
129
+ | `create(params)` | `Promise<CheckoutSessionResult>` | Creates a session via billing API (`POST /v1/checkouts/sessions`). Returns `{ status: 201, redirectUrl }` or `{ status: 204 }`. |
130
+ | `retrieve(id)` | `Promise<CheckoutSession>` | Retrieves a Stripe checkout session and normalizes it |
131
+ | `expire(id)` | `Promise<CheckoutSession>` | Expires a Stripe checkout session |
132
+ | `listLineItems(id)` | `Promise<LineItem[]>` | Lists line items for a Stripe checkout session |
133
+
134
+ ### `flopay.customers`
135
+
136
+ | Method | Returns | Description |
137
+ |--------|---------|-------------|
138
+ | `create(params)` | `Promise<Customer>` | Creates a Stripe customer |
139
+ | `retrieve(id)` | `Promise<Customer>` | Retrieves a Stripe customer. Throws if deleted. |
140
+ | `update(id, params)` | `Promise<Customer>` | Updates a Stripe customer |
141
+
142
+ ### `flopay.webhooks`
143
+
144
+ | Method | Returns | Description |
145
+ |--------|---------|-------------|
146
+ | `constructEvent(payload, signature, secret)` | `WebhookEvent` | Verifies and parses a Stripe webhook event |
147
+
148
+ ### Types
149
+
150
+ | Type | Description |
151
+ |------|-------------|
152
+ | `FloPayNodeOptions` | Constructor options |
153
+ | `CreateSessionParams` | Full session creation parameters (from `@flopay/shared`) |
154
+ | `CheckoutSessionResult` | `{ status: 201, redirectUrl }` / `{ status: 204 }` / `{ status: number }` |
155
+ | `CheckoutSession` | Normalized session: `id`, `clientSecret`, `mode`, `status`, `amount`, `currency`, `metadata` |
156
+ | `Customer` | `id`, `email`, `firstName?`, `lastName?` |
157
+ | `WebhookEvent` | `id`, `type`, `data`, `created` |
package/dist/index.cjs ADDED
@@ -0,0 +1,260 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ FloPay: () => FloPay
34
+ });
35
+ module.exports = __toCommonJS(index_exports);
36
+
37
+ // src/flopay-node.ts
38
+ var import_stripe = __toESM(require("stripe"), 1);
39
+ var import_shared = require("@flopay/shared");
40
+ var FloPay = class {
41
+ constructor(secretKey, options) {
42
+ if (!secretKey) {
43
+ throw new import_shared.FloPayError(
44
+ "A secret key is required to initialize the FloPay server SDK.",
45
+ "authentication_error"
46
+ );
47
+ }
48
+ this.stripe = new import_stripe.default(secretKey, {
49
+ apiVersion: "2025-04-30.basil",
50
+ appInfo: {
51
+ name: "flopay-node",
52
+ version: import_shared.SDK_VERSION
53
+ }
54
+ });
55
+ this.checkout = {
56
+ sessions: {
57
+ create: this.createSession.bind(this),
58
+ retrieve: this.retrieveSession.bind(this),
59
+ expire: this.expireSession.bind(this),
60
+ listLineItems: this.listLineItems.bind(this)
61
+ }
62
+ };
63
+ this.webhooks = {
64
+ constructEvent: this.constructWebhookEvent.bind(this)
65
+ };
66
+ this.customers = {
67
+ create: this.createCustomer.bind(this),
68
+ retrieve: this.retrieveCustomer.bind(this),
69
+ update: this.updateCustomer.bind(this)
70
+ };
71
+ }
72
+ /**
73
+ * Create a checkout session via the billing API.
74
+ *
75
+ * Mirrors `createCheckoutSession` from `clicktech-core-ui/modules`.
76
+ * Posts to `{billingApiUrl}/v1/checkouts/sessions` and returns
77
+ * the session UUID for redirect.
78
+ */
79
+ async createSession(params) {
80
+ const {
81
+ billingApiUrl,
82
+ checkoutBaseUrl,
83
+ items = [],
84
+ subscriptions = [],
85
+ account,
86
+ successUrl,
87
+ cancelUrl,
88
+ checkoutMode = "confirm",
89
+ couponCodes = [],
90
+ tagsData,
91
+ redirectParams = {},
92
+ timeoutMs = 12e3,
93
+ clientId,
94
+ utmMetadata
95
+ } = params;
96
+ const payload = {
97
+ clientId,
98
+ successUrl,
99
+ cancelUrl,
100
+ checkoutMode,
101
+ items: items.map((item) => ({
102
+ providerItemId: item.providerItemId,
103
+ providerItemName: item.providerItemName ?? null,
104
+ quantity: item.quantity ?? 1,
105
+ totalAmount: item.totalAmount,
106
+ overrideAmount: item.overrideAmount ?? null,
107
+ currency: item.currency ?? "USD"
108
+ })),
109
+ subscriptions: subscriptions.map((sub) => ({
110
+ providerPlanId: sub.providerPlanId,
111
+ providerPlanName: sub.providerPlanName ?? null,
112
+ quantity: sub.quantity ?? 1,
113
+ totalAmount: sub.totalAmount,
114
+ overrideAmount: sub.overrideAmount ?? null,
115
+ currency: sub.currency ?? "USD"
116
+ })),
117
+ accountData: {
118
+ userId: account.userId,
119
+ firstName: account.firstName ?? null,
120
+ lastName: account.lastName ?? null,
121
+ email: account.email,
122
+ country: account.country ?? null,
123
+ gender: account.gender ?? null,
124
+ city: account.city ?? null,
125
+ state: account.state ?? null,
126
+ zip: account.zip ?? null
127
+ },
128
+ couponCodes
129
+ };
130
+ if (tagsData) {
131
+ payload["tagsData"] = tagsData;
132
+ }
133
+ if (utmMetadata?.length) {
134
+ payload["utmMetadata"] = utmMetadata;
135
+ }
136
+ const url = `${billingApiUrl.replace(/\/+$/, "")}/v1/checkouts/sessions`;
137
+ const controller = new AbortController();
138
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
139
+ let status;
140
+ let body;
141
+ try {
142
+ const response = await fetch(url, {
143
+ method: "POST",
144
+ headers: { "Content-Type": "application/json" },
145
+ body: JSON.stringify(payload),
146
+ signal: controller.signal
147
+ });
148
+ status = response.status;
149
+ try {
150
+ body = await response.json();
151
+ } catch {
152
+ }
153
+ } finally {
154
+ clearTimeout(timer);
155
+ }
156
+ if (status === 201) {
157
+ const uuid = body?.data?.uuid;
158
+ if (!uuid) {
159
+ throw new Error("Checkout session created but no UUID was returned by the billing API");
160
+ }
161
+ const redirectUrl = new URL(`${checkoutBaseUrl.replace(/\/+$/, "")}/secure`);
162
+ redirectUrl.searchParams.set("id", uuid);
163
+ for (const [key, value] of Object.entries(redirectParams)) {
164
+ redirectUrl.searchParams.set(key, value);
165
+ }
166
+ return { status: 201, redirectUrl: redirectUrl.toString() };
167
+ }
168
+ if (status === 204) {
169
+ return { status: 204 };
170
+ }
171
+ return { status };
172
+ }
173
+ normalizeStripeSession(session) {
174
+ const statusMap = {
175
+ open: "open",
176
+ complete: "complete",
177
+ expired: "expired"
178
+ };
179
+ return {
180
+ id: session.id,
181
+ clientSecret: session.client_secret ?? "",
182
+ mode: session.mode,
183
+ status: statusMap[session.status ?? "open"] ?? "open",
184
+ amount: session.amount_total ?? 0,
185
+ currency: session.currency ?? "usd",
186
+ metadata: session.metadata ?? {}
187
+ };
188
+ }
189
+ async retrieveSession(id) {
190
+ const session = await this.stripe.checkout.sessions.retrieve(id);
191
+ return this.normalizeStripeSession(session);
192
+ }
193
+ async expireSession(id) {
194
+ const session = await this.stripe.checkout.sessions.expire(id);
195
+ return this.normalizeStripeSession(session);
196
+ }
197
+ async listLineItems(id) {
198
+ const items = await this.stripe.checkout.sessions.listLineItems(id);
199
+ return items.data.map((item) => ({
200
+ price: item.price?.id,
201
+ quantity: item.quantity ?? 1
202
+ }));
203
+ }
204
+ constructWebhookEvent(payload, signature, secret) {
205
+ const event = this.stripe.webhooks.constructEvent(payload, signature, secret);
206
+ return {
207
+ id: event.id,
208
+ type: event.type,
209
+ data: event.data,
210
+ created: event.created
211
+ };
212
+ }
213
+ async createCustomer(params) {
214
+ const customer = await this.stripe.customers.create({
215
+ email: params.email,
216
+ name: params.name,
217
+ metadata: params.metadata
218
+ });
219
+ return {
220
+ id: customer.id,
221
+ email: customer.email ?? params.email,
222
+ firstName: params.name?.split(" ")[0],
223
+ lastName: params.name?.split(" ").slice(1).join(" ")
224
+ };
225
+ }
226
+ async retrieveCustomer(id) {
227
+ const customer = await this.stripe.customers.retrieve(id);
228
+ if (customer.deleted) {
229
+ throw new import_shared.FloPayError(
230
+ `Customer ${id} has been deleted`,
231
+ "api_error",
232
+ { code: "resource_missing" }
233
+ );
234
+ }
235
+ return {
236
+ id: customer.id,
237
+ email: customer.email ?? "",
238
+ firstName: customer.name?.split(" ")[0],
239
+ lastName: customer.name?.split(" ").slice(1).join(" ")
240
+ };
241
+ }
242
+ async updateCustomer(id, params) {
243
+ const customer = await this.stripe.customers.update(id, {
244
+ email: params.email,
245
+ name: params.name,
246
+ metadata: params.metadata
247
+ });
248
+ return {
249
+ id: customer.id,
250
+ email: customer.email ?? "",
251
+ firstName: customer.name?.split(" ")[0],
252
+ lastName: customer.name?.split(" ").slice(1).join(" ")
253
+ };
254
+ }
255
+ };
256
+ // Annotate the CommonJS export names for ESM import in node:
257
+ 0 && (module.exports = {
258
+ FloPay
259
+ });
260
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/flopay-node.ts"],"sourcesContent":["export { FloPay } from './flopay-node.js';\nexport type { FloPayNodeOptions } from './flopay-node.js';\n","import Stripe from 'stripe';\nimport type {\n CheckoutSession,\n LineItem,\n CreateSessionParams,\n CheckoutSessionResult,\n CreateCustomerParams,\n UpdateCustomerParams,\n WebhookEvent,\n Customer,\n} from '@flopay/shared';\nimport { FloPayError, SDK_VERSION } from '@flopay/shared';\n\n/** Options for the FloPay Node SDK constructor. */\nexport interface FloPayNodeOptions {\n apiVersion?: string;\n /** Stripe secret key, required when using Stripe-specific operations. */\n stripeSecretKey?: string;\n}\n\n/**\n * Server-side FloPay SDK.\n *\n * Supports two modes of operation:\n *\n * 1. **Billing API mode** — Creates checkout sessions via the FloPay/ClickTech\n * billing API (`POST /v1/checkouts/sessions`). This mirrors the\n * `createCheckoutSession` function from `clicktech-core-ui`.\n *\n * 2. **Stripe direct mode** — When a `stripeSecretKey` is provided, also\n * exposes direct Stripe operations (customers, webhooks).\n *\n * @example\n * ```ts\n * import { FloPay } from '@flopay/node';\n *\n * const flopay = new FloPay('sk_test_...');\n *\n * // Create session via billing API\n * const result = await flopay.checkout.sessions.create({\n * billingApiUrl: 'https://billing.example.com',\n * checkoutBaseUrl: 'https://checkout.example.com',\n * clientId: 'client_123',\n * items: [{ providerItemId: 'prod_abc', totalAmount: 49.99 }],\n * account: { userId: 'user_1', email: 'user@example.com' },\n * successUrl: '/success',\n * cancelUrl: '/cancel',\n * });\n * ```\n */\nexport class FloPay {\n private readonly stripe: Stripe;\n\n readonly checkout: {\n sessions: {\n /** Create a checkout session via the billing API. */\n create: (params: CreateSessionParams) => Promise<CheckoutSessionResult>;\n /** Retrieve a checkout session from Stripe. */\n retrieve: (id: string) => Promise<CheckoutSession>;\n /** Expire a checkout session on Stripe. */\n expire: (id: string) => Promise<CheckoutSession>;\n /** List line items for a Stripe checkout session. */\n listLineItems: (id: string) => Promise<LineItem[]>;\n };\n };\n\n readonly webhooks: {\n constructEvent: (\n payload: string | Buffer,\n signature: string,\n secret: string,\n ) => WebhookEvent;\n };\n\n readonly customers: {\n create: (params: CreateCustomerParams) => Promise<Customer>;\n retrieve: (id: string) => Promise<Customer>;\n update: (id: string, params: UpdateCustomerParams) => Promise<Customer>;\n };\n\n constructor(secretKey: string, options?: FloPayNodeOptions) {\n if (!secretKey) {\n throw new FloPayError(\n 'A secret key is required to initialize the FloPay server SDK.',\n 'authentication_error',\n );\n }\n\n this.stripe = new Stripe(secretKey, {\n apiVersion: '2025-04-30.basil' as Stripe.LatestApiVersion,\n appInfo: {\n name: 'flopay-node',\n version: SDK_VERSION,\n },\n });\n\n this.checkout = {\n sessions: {\n create: this.createSession.bind(this),\n retrieve: this.retrieveSession.bind(this),\n expire: this.expireSession.bind(this),\n listLineItems: this.listLineItems.bind(this),\n },\n };\n\n this.webhooks = {\n constructEvent: this.constructWebhookEvent.bind(this),\n };\n\n this.customers = {\n create: this.createCustomer.bind(this),\n retrieve: this.retrieveCustomer.bind(this),\n update: this.updateCustomer.bind(this),\n };\n }\n\n /**\n * Create a checkout session via the billing API.\n *\n * Mirrors `createCheckoutSession` from `clicktech-core-ui/modules`.\n * Posts to `{billingApiUrl}/v1/checkouts/sessions` and returns\n * the session UUID for redirect.\n */\n private async createSession(\n params: CreateSessionParams,\n ): Promise<CheckoutSessionResult> {\n const {\n billingApiUrl,\n checkoutBaseUrl,\n items = [],\n subscriptions = [],\n account,\n successUrl,\n cancelUrl,\n checkoutMode = 'confirm',\n couponCodes = [],\n tagsData,\n redirectParams = {},\n timeoutMs = 12000,\n clientId,\n utmMetadata,\n } = params;\n\n const payload: Record<string, unknown> = {\n clientId,\n successUrl,\n cancelUrl,\n checkoutMode,\n items: items.map((item) => ({\n providerItemId: item.providerItemId,\n providerItemName: item.providerItemName ?? null,\n quantity: item.quantity ?? 1,\n totalAmount: item.totalAmount,\n overrideAmount: item.overrideAmount ?? null,\n currency: item.currency ?? 'USD',\n })),\n subscriptions: subscriptions.map((sub) => ({\n providerPlanId: sub.providerPlanId,\n providerPlanName: sub.providerPlanName ?? null,\n quantity: sub.quantity ?? 1,\n totalAmount: sub.totalAmount,\n overrideAmount: sub.overrideAmount ?? null,\n currency: sub.currency ?? 'USD',\n })),\n accountData: {\n userId: account.userId,\n firstName: account.firstName ?? null,\n lastName: account.lastName ?? null,\n email: account.email,\n country: account.country ?? null,\n gender: account.gender ?? null,\n city: account.city ?? null,\n state: account.state ?? null,\n zip: account.zip ?? null,\n },\n couponCodes,\n };\n\n if (tagsData) {\n payload['tagsData'] = tagsData;\n }\n\n if (utmMetadata?.length) {\n payload['utmMetadata'] = utmMetadata;\n }\n\n const url = `${billingApiUrl.replace(/\\/+$/, '')}/v1/checkouts/sessions`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n\n let status: number;\n let body: { data?: { uuid?: string } } | undefined;\n\n try {\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n signal: controller.signal,\n });\n\n status = response.status;\n\n try {\n body = await response.json() as { data?: { uuid?: string } };\n } catch {\n // 204 or empty body\n }\n } finally {\n clearTimeout(timer);\n }\n\n if (status === 201) {\n const uuid = body?.data?.uuid;\n\n if (!uuid) {\n throw new Error('Checkout session created but no UUID was returned by the billing API');\n }\n\n const redirectUrl = new URL(`${checkoutBaseUrl.replace(/\\/+$/, '')}/secure`);\n redirectUrl.searchParams.set('id', uuid);\n\n for (const [key, value] of Object.entries(redirectParams)) {\n redirectUrl.searchParams.set(key, value);\n }\n\n return { status: 201, redirectUrl: redirectUrl.toString() };\n }\n\n if (status === 204) {\n return { status: 204 };\n }\n\n return { status };\n }\n\n private normalizeStripeSession(\n session: Stripe.Checkout.Session,\n ): CheckoutSession {\n const statusMap: Record<string, CheckoutSession['status']> = {\n open: 'open',\n complete: 'complete',\n expired: 'expired',\n };\n\n return {\n id: session.id,\n clientSecret: session.client_secret ?? '',\n mode: session.mode as CheckoutSession['mode'],\n status: statusMap[session.status ?? 'open'] ?? 'open',\n amount: session.amount_total ?? 0,\n currency: session.currency ?? 'usd',\n metadata: (session.metadata as Record<string, string>) ?? {},\n };\n }\n\n private async retrieveSession(id: string): Promise<CheckoutSession> {\n const session = await this.stripe.checkout.sessions.retrieve(id);\n return this.normalizeStripeSession(session);\n }\n\n private async expireSession(id: string): Promise<CheckoutSession> {\n const session = await this.stripe.checkout.sessions.expire(id);\n return this.normalizeStripeSession(session);\n }\n\n private async listLineItems(id: string): Promise<LineItem[]> {\n const items = await this.stripe.checkout.sessions.listLineItems(id);\n return items.data.map((item) => ({\n price: item.price?.id,\n quantity: item.quantity ?? 1,\n }));\n }\n\n private constructWebhookEvent(\n payload: string | Buffer,\n signature: string,\n secret: string,\n ): WebhookEvent {\n const event = this.stripe.webhooks.constructEvent(payload, signature, secret);\n\n return {\n id: event.id,\n type: event.type,\n data: event.data as unknown as Record<string, unknown>,\n created: event.created,\n };\n }\n\n private async createCustomer(params: CreateCustomerParams): Promise<Customer> {\n const customer = await this.stripe.customers.create({\n email: params.email,\n name: params.name,\n metadata: params.metadata,\n });\n\n return {\n id: customer.id,\n email: customer.email ?? params.email,\n firstName: params.name?.split(' ')[0],\n lastName: params.name?.split(' ').slice(1).join(' '),\n };\n }\n\n private async retrieveCustomer(id: string): Promise<Customer> {\n const customer = await this.stripe.customers.retrieve(id);\n\n if (customer.deleted) {\n throw new FloPayError(\n `Customer ${id} has been deleted`,\n 'api_error',\n { code: 'resource_missing' },\n );\n }\n\n return {\n id: customer.id,\n email: customer.email ?? '',\n firstName: customer.name?.split(' ')[0],\n lastName: customer.name?.split(' ').slice(1).join(' '),\n };\n }\n\n private async updateCustomer(\n id: string,\n params: UpdateCustomerParams,\n ): Promise<Customer> {\n const customer = await this.stripe.customers.update(id, {\n email: params.email,\n name: params.name,\n metadata: params.metadata,\n });\n\n return {\n id: customer.id,\n email: customer.email ?? '',\n firstName: customer.name?.split(' ')[0],\n lastName: customer.name?.split(' ').slice(1).join(' '),\n };\n }\n}\n"],"mappings":"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","names":["Stripe"]}
@@ -0,0 +1,80 @@
1
+ import { CreateSessionParams, CheckoutSessionResult, CheckoutSession, LineItem, WebhookEvent, CreateCustomerParams, Customer, UpdateCustomerParams } from '@flopay/shared';
2
+
3
+ /** Options for the FloPay Node SDK constructor. */
4
+ interface FloPayNodeOptions {
5
+ apiVersion?: string;
6
+ /** Stripe secret key, required when using Stripe-specific operations. */
7
+ stripeSecretKey?: string;
8
+ }
9
+ /**
10
+ * Server-side FloPay SDK.
11
+ *
12
+ * Supports two modes of operation:
13
+ *
14
+ * 1. **Billing API mode** — Creates checkout sessions via the FloPay/ClickTech
15
+ * billing API (`POST /v1/checkouts/sessions`). This mirrors the
16
+ * `createCheckoutSession` function from `clicktech-core-ui`.
17
+ *
18
+ * 2. **Stripe direct mode** — When a `stripeSecretKey` is provided, also
19
+ * exposes direct Stripe operations (customers, webhooks).
20
+ *
21
+ * @example
22
+ * ```ts
23
+ * import { FloPay } from '@flopay/node';
24
+ *
25
+ * const flopay = new FloPay('sk_test_...');
26
+ *
27
+ * // Create session via billing API
28
+ * const result = await flopay.checkout.sessions.create({
29
+ * billingApiUrl: 'https://billing.example.com',
30
+ * checkoutBaseUrl: 'https://checkout.example.com',
31
+ * clientId: 'client_123',
32
+ * items: [{ providerItemId: 'prod_abc', totalAmount: 49.99 }],
33
+ * account: { userId: 'user_1', email: 'user@example.com' },
34
+ * successUrl: '/success',
35
+ * cancelUrl: '/cancel',
36
+ * });
37
+ * ```
38
+ */
39
+ declare class FloPay {
40
+ private readonly stripe;
41
+ readonly checkout: {
42
+ sessions: {
43
+ /** Create a checkout session via the billing API. */
44
+ create: (params: CreateSessionParams) => Promise<CheckoutSessionResult>;
45
+ /** Retrieve a checkout session from Stripe. */
46
+ retrieve: (id: string) => Promise<CheckoutSession>;
47
+ /** Expire a checkout session on Stripe. */
48
+ expire: (id: string) => Promise<CheckoutSession>;
49
+ /** List line items for a Stripe checkout session. */
50
+ listLineItems: (id: string) => Promise<LineItem[]>;
51
+ };
52
+ };
53
+ readonly webhooks: {
54
+ constructEvent: (payload: string | Buffer, signature: string, secret: string) => WebhookEvent;
55
+ };
56
+ readonly customers: {
57
+ create: (params: CreateCustomerParams) => Promise<Customer>;
58
+ retrieve: (id: string) => Promise<Customer>;
59
+ update: (id: string, params: UpdateCustomerParams) => Promise<Customer>;
60
+ };
61
+ constructor(secretKey: string, options?: FloPayNodeOptions);
62
+ /**
63
+ * Create a checkout session via the billing API.
64
+ *
65
+ * Mirrors `createCheckoutSession` from `clicktech-core-ui/modules`.
66
+ * Posts to `{billingApiUrl}/v1/checkouts/sessions` and returns
67
+ * the session UUID for redirect.
68
+ */
69
+ private createSession;
70
+ private normalizeStripeSession;
71
+ private retrieveSession;
72
+ private expireSession;
73
+ private listLineItems;
74
+ private constructWebhookEvent;
75
+ private createCustomer;
76
+ private retrieveCustomer;
77
+ private updateCustomer;
78
+ }
79
+
80
+ export { FloPay, type FloPayNodeOptions };
@@ -0,0 +1,80 @@
1
+ import { CreateSessionParams, CheckoutSessionResult, CheckoutSession, LineItem, WebhookEvent, CreateCustomerParams, Customer, UpdateCustomerParams } from '@flopay/shared';
2
+
3
+ /** Options for the FloPay Node SDK constructor. */
4
+ interface FloPayNodeOptions {
5
+ apiVersion?: string;
6
+ /** Stripe secret key, required when using Stripe-specific operations. */
7
+ stripeSecretKey?: string;
8
+ }
9
+ /**
10
+ * Server-side FloPay SDK.
11
+ *
12
+ * Supports two modes of operation:
13
+ *
14
+ * 1. **Billing API mode** — Creates checkout sessions via the FloPay/ClickTech
15
+ * billing API (`POST /v1/checkouts/sessions`). This mirrors the
16
+ * `createCheckoutSession` function from `clicktech-core-ui`.
17
+ *
18
+ * 2. **Stripe direct mode** — When a `stripeSecretKey` is provided, also
19
+ * exposes direct Stripe operations (customers, webhooks).
20
+ *
21
+ * @example
22
+ * ```ts
23
+ * import { FloPay } from '@flopay/node';
24
+ *
25
+ * const flopay = new FloPay('sk_test_...');
26
+ *
27
+ * // Create session via billing API
28
+ * const result = await flopay.checkout.sessions.create({
29
+ * billingApiUrl: 'https://billing.example.com',
30
+ * checkoutBaseUrl: 'https://checkout.example.com',
31
+ * clientId: 'client_123',
32
+ * items: [{ providerItemId: 'prod_abc', totalAmount: 49.99 }],
33
+ * account: { userId: 'user_1', email: 'user@example.com' },
34
+ * successUrl: '/success',
35
+ * cancelUrl: '/cancel',
36
+ * });
37
+ * ```
38
+ */
39
+ declare class FloPay {
40
+ private readonly stripe;
41
+ readonly checkout: {
42
+ sessions: {
43
+ /** Create a checkout session via the billing API. */
44
+ create: (params: CreateSessionParams) => Promise<CheckoutSessionResult>;
45
+ /** Retrieve a checkout session from Stripe. */
46
+ retrieve: (id: string) => Promise<CheckoutSession>;
47
+ /** Expire a checkout session on Stripe. */
48
+ expire: (id: string) => Promise<CheckoutSession>;
49
+ /** List line items for a Stripe checkout session. */
50
+ listLineItems: (id: string) => Promise<LineItem[]>;
51
+ };
52
+ };
53
+ readonly webhooks: {
54
+ constructEvent: (payload: string | Buffer, signature: string, secret: string) => WebhookEvent;
55
+ };
56
+ readonly customers: {
57
+ create: (params: CreateCustomerParams) => Promise<Customer>;
58
+ retrieve: (id: string) => Promise<Customer>;
59
+ update: (id: string, params: UpdateCustomerParams) => Promise<Customer>;
60
+ };
61
+ constructor(secretKey: string, options?: FloPayNodeOptions);
62
+ /**
63
+ * Create a checkout session via the billing API.
64
+ *
65
+ * Mirrors `createCheckoutSession` from `clicktech-core-ui/modules`.
66
+ * Posts to `{billingApiUrl}/v1/checkouts/sessions` and returns
67
+ * the session UUID for redirect.
68
+ */
69
+ private createSession;
70
+ private normalizeStripeSession;
71
+ private retrieveSession;
72
+ private expireSession;
73
+ private listLineItems;
74
+ private constructWebhookEvent;
75
+ private createCustomer;
76
+ private retrieveCustomer;
77
+ private updateCustomer;
78
+ }
79
+
80
+ export { FloPay, type FloPayNodeOptions };
package/dist/index.mjs ADDED
@@ -0,0 +1,223 @@
1
+ // src/flopay-node.ts
2
+ import Stripe from "stripe";
3
+ import { FloPayError, SDK_VERSION } from "@flopay/shared";
4
+ var FloPay = class {
5
+ constructor(secretKey, options) {
6
+ if (!secretKey) {
7
+ throw new FloPayError(
8
+ "A secret key is required to initialize the FloPay server SDK.",
9
+ "authentication_error"
10
+ );
11
+ }
12
+ this.stripe = new Stripe(secretKey, {
13
+ apiVersion: "2025-04-30.basil",
14
+ appInfo: {
15
+ name: "flopay-node",
16
+ version: SDK_VERSION
17
+ }
18
+ });
19
+ this.checkout = {
20
+ sessions: {
21
+ create: this.createSession.bind(this),
22
+ retrieve: this.retrieveSession.bind(this),
23
+ expire: this.expireSession.bind(this),
24
+ listLineItems: this.listLineItems.bind(this)
25
+ }
26
+ };
27
+ this.webhooks = {
28
+ constructEvent: this.constructWebhookEvent.bind(this)
29
+ };
30
+ this.customers = {
31
+ create: this.createCustomer.bind(this),
32
+ retrieve: this.retrieveCustomer.bind(this),
33
+ update: this.updateCustomer.bind(this)
34
+ };
35
+ }
36
+ /**
37
+ * Create a checkout session via the billing API.
38
+ *
39
+ * Mirrors `createCheckoutSession` from `clicktech-core-ui/modules`.
40
+ * Posts to `{billingApiUrl}/v1/checkouts/sessions` and returns
41
+ * the session UUID for redirect.
42
+ */
43
+ async createSession(params) {
44
+ const {
45
+ billingApiUrl,
46
+ checkoutBaseUrl,
47
+ items = [],
48
+ subscriptions = [],
49
+ account,
50
+ successUrl,
51
+ cancelUrl,
52
+ checkoutMode = "confirm",
53
+ couponCodes = [],
54
+ tagsData,
55
+ redirectParams = {},
56
+ timeoutMs = 12e3,
57
+ clientId,
58
+ utmMetadata
59
+ } = params;
60
+ const payload = {
61
+ clientId,
62
+ successUrl,
63
+ cancelUrl,
64
+ checkoutMode,
65
+ items: items.map((item) => ({
66
+ providerItemId: item.providerItemId,
67
+ providerItemName: item.providerItemName ?? null,
68
+ quantity: item.quantity ?? 1,
69
+ totalAmount: item.totalAmount,
70
+ overrideAmount: item.overrideAmount ?? null,
71
+ currency: item.currency ?? "USD"
72
+ })),
73
+ subscriptions: subscriptions.map((sub) => ({
74
+ providerPlanId: sub.providerPlanId,
75
+ providerPlanName: sub.providerPlanName ?? null,
76
+ quantity: sub.quantity ?? 1,
77
+ totalAmount: sub.totalAmount,
78
+ overrideAmount: sub.overrideAmount ?? null,
79
+ currency: sub.currency ?? "USD"
80
+ })),
81
+ accountData: {
82
+ userId: account.userId,
83
+ firstName: account.firstName ?? null,
84
+ lastName: account.lastName ?? null,
85
+ email: account.email,
86
+ country: account.country ?? null,
87
+ gender: account.gender ?? null,
88
+ city: account.city ?? null,
89
+ state: account.state ?? null,
90
+ zip: account.zip ?? null
91
+ },
92
+ couponCodes
93
+ };
94
+ if (tagsData) {
95
+ payload["tagsData"] = tagsData;
96
+ }
97
+ if (utmMetadata?.length) {
98
+ payload["utmMetadata"] = utmMetadata;
99
+ }
100
+ const url = `${billingApiUrl.replace(/\/+$/, "")}/v1/checkouts/sessions`;
101
+ const controller = new AbortController();
102
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
103
+ let status;
104
+ let body;
105
+ try {
106
+ const response = await fetch(url, {
107
+ method: "POST",
108
+ headers: { "Content-Type": "application/json" },
109
+ body: JSON.stringify(payload),
110
+ signal: controller.signal
111
+ });
112
+ status = response.status;
113
+ try {
114
+ body = await response.json();
115
+ } catch {
116
+ }
117
+ } finally {
118
+ clearTimeout(timer);
119
+ }
120
+ if (status === 201) {
121
+ const uuid = body?.data?.uuid;
122
+ if (!uuid) {
123
+ throw new Error("Checkout session created but no UUID was returned by the billing API");
124
+ }
125
+ const redirectUrl = new URL(`${checkoutBaseUrl.replace(/\/+$/, "")}/secure`);
126
+ redirectUrl.searchParams.set("id", uuid);
127
+ for (const [key, value] of Object.entries(redirectParams)) {
128
+ redirectUrl.searchParams.set(key, value);
129
+ }
130
+ return { status: 201, redirectUrl: redirectUrl.toString() };
131
+ }
132
+ if (status === 204) {
133
+ return { status: 204 };
134
+ }
135
+ return { status };
136
+ }
137
+ normalizeStripeSession(session) {
138
+ const statusMap = {
139
+ open: "open",
140
+ complete: "complete",
141
+ expired: "expired"
142
+ };
143
+ return {
144
+ id: session.id,
145
+ clientSecret: session.client_secret ?? "",
146
+ mode: session.mode,
147
+ status: statusMap[session.status ?? "open"] ?? "open",
148
+ amount: session.amount_total ?? 0,
149
+ currency: session.currency ?? "usd",
150
+ metadata: session.metadata ?? {}
151
+ };
152
+ }
153
+ async retrieveSession(id) {
154
+ const session = await this.stripe.checkout.sessions.retrieve(id);
155
+ return this.normalizeStripeSession(session);
156
+ }
157
+ async expireSession(id) {
158
+ const session = await this.stripe.checkout.sessions.expire(id);
159
+ return this.normalizeStripeSession(session);
160
+ }
161
+ async listLineItems(id) {
162
+ const items = await this.stripe.checkout.sessions.listLineItems(id);
163
+ return items.data.map((item) => ({
164
+ price: item.price?.id,
165
+ quantity: item.quantity ?? 1
166
+ }));
167
+ }
168
+ constructWebhookEvent(payload, signature, secret) {
169
+ const event = this.stripe.webhooks.constructEvent(payload, signature, secret);
170
+ return {
171
+ id: event.id,
172
+ type: event.type,
173
+ data: event.data,
174
+ created: event.created
175
+ };
176
+ }
177
+ async createCustomer(params) {
178
+ const customer = await this.stripe.customers.create({
179
+ email: params.email,
180
+ name: params.name,
181
+ metadata: params.metadata
182
+ });
183
+ return {
184
+ id: customer.id,
185
+ email: customer.email ?? params.email,
186
+ firstName: params.name?.split(" ")[0],
187
+ lastName: params.name?.split(" ").slice(1).join(" ")
188
+ };
189
+ }
190
+ async retrieveCustomer(id) {
191
+ const customer = await this.stripe.customers.retrieve(id);
192
+ if (customer.deleted) {
193
+ throw new FloPayError(
194
+ `Customer ${id} has been deleted`,
195
+ "api_error",
196
+ { code: "resource_missing" }
197
+ );
198
+ }
199
+ return {
200
+ id: customer.id,
201
+ email: customer.email ?? "",
202
+ firstName: customer.name?.split(" ")[0],
203
+ lastName: customer.name?.split(" ").slice(1).join(" ")
204
+ };
205
+ }
206
+ async updateCustomer(id, params) {
207
+ const customer = await this.stripe.customers.update(id, {
208
+ email: params.email,
209
+ name: params.name,
210
+ metadata: params.metadata
211
+ });
212
+ return {
213
+ id: customer.id,
214
+ email: customer.email ?? "",
215
+ firstName: customer.name?.split(" ")[0],
216
+ lastName: customer.name?.split(" ").slice(1).join(" ")
217
+ };
218
+ }
219
+ };
220
+ export {
221
+ FloPay
222
+ };
223
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/flopay-node.ts"],"sourcesContent":["import Stripe from 'stripe';\nimport type {\n CheckoutSession,\n LineItem,\n CreateSessionParams,\n CheckoutSessionResult,\n CreateCustomerParams,\n UpdateCustomerParams,\n WebhookEvent,\n Customer,\n} from '@flopay/shared';\nimport { FloPayError, SDK_VERSION } from '@flopay/shared';\n\n/** Options for the FloPay Node SDK constructor. */\nexport interface FloPayNodeOptions {\n apiVersion?: string;\n /** Stripe secret key, required when using Stripe-specific operations. */\n stripeSecretKey?: string;\n}\n\n/**\n * Server-side FloPay SDK.\n *\n * Supports two modes of operation:\n *\n * 1. **Billing API mode** — Creates checkout sessions via the FloPay/ClickTech\n * billing API (`POST /v1/checkouts/sessions`). This mirrors the\n * `createCheckoutSession` function from `clicktech-core-ui`.\n *\n * 2. **Stripe direct mode** — When a `stripeSecretKey` is provided, also\n * exposes direct Stripe operations (customers, webhooks).\n *\n * @example\n * ```ts\n * import { FloPay } from '@flopay/node';\n *\n * const flopay = new FloPay('sk_test_...');\n *\n * // Create session via billing API\n * const result = await flopay.checkout.sessions.create({\n * billingApiUrl: 'https://billing.example.com',\n * checkoutBaseUrl: 'https://checkout.example.com',\n * clientId: 'client_123',\n * items: [{ providerItemId: 'prod_abc', totalAmount: 49.99 }],\n * account: { userId: 'user_1', email: 'user@example.com' },\n * successUrl: '/success',\n * cancelUrl: '/cancel',\n * });\n * ```\n */\nexport class FloPay {\n private readonly stripe: Stripe;\n\n readonly checkout: {\n sessions: {\n /** Create a checkout session via the billing API. */\n create: (params: CreateSessionParams) => Promise<CheckoutSessionResult>;\n /** Retrieve a checkout session from Stripe. */\n retrieve: (id: string) => Promise<CheckoutSession>;\n /** Expire a checkout session on Stripe. */\n expire: (id: string) => Promise<CheckoutSession>;\n /** List line items for a Stripe checkout session. */\n listLineItems: (id: string) => Promise<LineItem[]>;\n };\n };\n\n readonly webhooks: {\n constructEvent: (\n payload: string | Buffer,\n signature: string,\n secret: string,\n ) => WebhookEvent;\n };\n\n readonly customers: {\n create: (params: CreateCustomerParams) => Promise<Customer>;\n retrieve: (id: string) => Promise<Customer>;\n update: (id: string, params: UpdateCustomerParams) => Promise<Customer>;\n };\n\n constructor(secretKey: string, options?: FloPayNodeOptions) {\n if (!secretKey) {\n throw new FloPayError(\n 'A secret key is required to initialize the FloPay server SDK.',\n 'authentication_error',\n );\n }\n\n this.stripe = new Stripe(secretKey, {\n apiVersion: '2025-04-30.basil' as Stripe.LatestApiVersion,\n appInfo: {\n name: 'flopay-node',\n version: SDK_VERSION,\n },\n });\n\n this.checkout = {\n sessions: {\n create: this.createSession.bind(this),\n retrieve: this.retrieveSession.bind(this),\n expire: this.expireSession.bind(this),\n listLineItems: this.listLineItems.bind(this),\n },\n };\n\n this.webhooks = {\n constructEvent: this.constructWebhookEvent.bind(this),\n };\n\n this.customers = {\n create: this.createCustomer.bind(this),\n retrieve: this.retrieveCustomer.bind(this),\n update: this.updateCustomer.bind(this),\n };\n }\n\n /**\n * Create a checkout session via the billing API.\n *\n * Mirrors `createCheckoutSession` from `clicktech-core-ui/modules`.\n * Posts to `{billingApiUrl}/v1/checkouts/sessions` and returns\n * the session UUID for redirect.\n */\n private async createSession(\n params: CreateSessionParams,\n ): Promise<CheckoutSessionResult> {\n const {\n billingApiUrl,\n checkoutBaseUrl,\n items = [],\n subscriptions = [],\n account,\n successUrl,\n cancelUrl,\n checkoutMode = 'confirm',\n couponCodes = [],\n tagsData,\n redirectParams = {},\n timeoutMs = 12000,\n clientId,\n utmMetadata,\n } = params;\n\n const payload: Record<string, unknown> = {\n clientId,\n successUrl,\n cancelUrl,\n checkoutMode,\n items: items.map((item) => ({\n providerItemId: item.providerItemId,\n providerItemName: item.providerItemName ?? null,\n quantity: item.quantity ?? 1,\n totalAmount: item.totalAmount,\n overrideAmount: item.overrideAmount ?? null,\n currency: item.currency ?? 'USD',\n })),\n subscriptions: subscriptions.map((sub) => ({\n providerPlanId: sub.providerPlanId,\n providerPlanName: sub.providerPlanName ?? null,\n quantity: sub.quantity ?? 1,\n totalAmount: sub.totalAmount,\n overrideAmount: sub.overrideAmount ?? null,\n currency: sub.currency ?? 'USD',\n })),\n accountData: {\n userId: account.userId,\n firstName: account.firstName ?? null,\n lastName: account.lastName ?? null,\n email: account.email,\n country: account.country ?? null,\n gender: account.gender ?? null,\n city: account.city ?? null,\n state: account.state ?? null,\n zip: account.zip ?? null,\n },\n couponCodes,\n };\n\n if (tagsData) {\n payload['tagsData'] = tagsData;\n }\n\n if (utmMetadata?.length) {\n payload['utmMetadata'] = utmMetadata;\n }\n\n const url = `${billingApiUrl.replace(/\\/+$/, '')}/v1/checkouts/sessions`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n\n let status: number;\n let body: { data?: { uuid?: string } } | undefined;\n\n try {\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n signal: controller.signal,\n });\n\n status = response.status;\n\n try {\n body = await response.json() as { data?: { uuid?: string } };\n } catch {\n // 204 or empty body\n }\n } finally {\n clearTimeout(timer);\n }\n\n if (status === 201) {\n const uuid = body?.data?.uuid;\n\n if (!uuid) {\n throw new Error('Checkout session created but no UUID was returned by the billing API');\n }\n\n const redirectUrl = new URL(`${checkoutBaseUrl.replace(/\\/+$/, '')}/secure`);\n redirectUrl.searchParams.set('id', uuid);\n\n for (const [key, value] of Object.entries(redirectParams)) {\n redirectUrl.searchParams.set(key, value);\n }\n\n return { status: 201, redirectUrl: redirectUrl.toString() };\n }\n\n if (status === 204) {\n return { status: 204 };\n }\n\n return { status };\n }\n\n private normalizeStripeSession(\n session: Stripe.Checkout.Session,\n ): CheckoutSession {\n const statusMap: Record<string, CheckoutSession['status']> = {\n open: 'open',\n complete: 'complete',\n expired: 'expired',\n };\n\n return {\n id: session.id,\n clientSecret: session.client_secret ?? '',\n mode: session.mode as CheckoutSession['mode'],\n status: statusMap[session.status ?? 'open'] ?? 'open',\n amount: session.amount_total ?? 0,\n currency: session.currency ?? 'usd',\n metadata: (session.metadata as Record<string, string>) ?? {},\n };\n }\n\n private async retrieveSession(id: string): Promise<CheckoutSession> {\n const session = await this.stripe.checkout.sessions.retrieve(id);\n return this.normalizeStripeSession(session);\n }\n\n private async expireSession(id: string): Promise<CheckoutSession> {\n const session = await this.stripe.checkout.sessions.expire(id);\n return this.normalizeStripeSession(session);\n }\n\n private async listLineItems(id: string): Promise<LineItem[]> {\n const items = await this.stripe.checkout.sessions.listLineItems(id);\n return items.data.map((item) => ({\n price: item.price?.id,\n quantity: item.quantity ?? 1,\n }));\n }\n\n private constructWebhookEvent(\n payload: string | Buffer,\n signature: string,\n secret: string,\n ): WebhookEvent {\n const event = this.stripe.webhooks.constructEvent(payload, signature, secret);\n\n return {\n id: event.id,\n type: event.type,\n data: event.data as unknown as Record<string, unknown>,\n created: event.created,\n };\n }\n\n private async createCustomer(params: CreateCustomerParams): Promise<Customer> {\n const customer = await this.stripe.customers.create({\n email: params.email,\n name: params.name,\n metadata: params.metadata,\n });\n\n return {\n id: customer.id,\n email: customer.email ?? params.email,\n firstName: params.name?.split(' ')[0],\n lastName: params.name?.split(' ').slice(1).join(' '),\n };\n }\n\n private async retrieveCustomer(id: string): Promise<Customer> {\n const customer = await this.stripe.customers.retrieve(id);\n\n if (customer.deleted) {\n throw new FloPayError(\n `Customer ${id} has been deleted`,\n 'api_error',\n { code: 'resource_missing' },\n );\n }\n\n return {\n id: customer.id,\n email: customer.email ?? '',\n firstName: customer.name?.split(' ')[0],\n lastName: customer.name?.split(' ').slice(1).join(' '),\n };\n }\n\n private async updateCustomer(\n id: string,\n params: UpdateCustomerParams,\n ): Promise<Customer> {\n const customer = await this.stripe.customers.update(id, {\n email: params.email,\n name: params.name,\n metadata: params.metadata,\n });\n\n return {\n id: customer.id,\n email: customer.email ?? '',\n firstName: customer.name?.split(' ')[0],\n lastName: customer.name?.split(' ').slice(1).join(' '),\n };\n }\n}\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@flopay/node",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "publishConfig": {
6
+ "registry": "https://registry.npmjs.org/",
7
+ "access": "restricted"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "https://github.com/flopay/flopay.git",
12
+ "directory": "packages/node"
13
+ },
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/index.d.ts",
17
+ "import": "./dist/index.mjs",
18
+ "require": "./dist/index.cjs"
19
+ }
20
+ },
21
+ "main": "./dist/index.cjs",
22
+ "module": "./dist/index.mjs",
23
+ "types": "./dist/index.d.ts",
24
+ "files": [
25
+ "dist"
26
+ ],
27
+ "dependencies": {
28
+ "stripe": "^17.0.0",
29
+ "@flopay/shared": "0.1.0"
30
+ },
31
+ "devDependencies": {
32
+ "typescript": "^5.7.0",
33
+ "tsup": "^8.3.0",
34
+ "vitest": "^2.1.0"
35
+ },
36
+ "scripts": {
37
+ "build": "tsup",
38
+ "dev": "tsup --watch",
39
+ "typecheck": "tsc --noEmit",
40
+ "test": "vitest run",
41
+ "clean": "rm -rf dist"
42
+ }
43
+ }