@flopay/node 1.4.3 → 1.4.4
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/dist/index.cjs +1 -269
- package/dist/index.mjs +1 -237
- package/package.json +2 -2
- package/dist/index.cjs.map +0 -1
- package/dist/index.mjs.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,269 +1 @@
|
|
|
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
|
-
STRIPE_API_VERSION: () => STRIPE_API_VERSION
|
|
35
|
-
});
|
|
36
|
-
module.exports = __toCommonJS(index_exports);
|
|
37
|
-
|
|
38
|
-
// src/flopay-node.ts
|
|
39
|
-
var import_stripe = __toESM(require("stripe"), 1);
|
|
40
|
-
var import_shared = require("@flopay/shared");
|
|
41
|
-
var STRIPE_API_VERSION = "2026-04-22.dahlia";
|
|
42
|
-
var FloPay = class {
|
|
43
|
-
constructor(secretKey, options) {
|
|
44
|
-
if (!secretKey) {
|
|
45
|
-
throw new import_shared.FloPayError(
|
|
46
|
-
"A secret key is required to initialize the FloPay server SDK.",
|
|
47
|
-
"authentication_error"
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
this.stripe = new import_stripe.default(options?.stripeSecretKey ?? secretKey, {
|
|
51
|
-
apiVersion: options?.apiVersion ?? STRIPE_API_VERSION,
|
|
52
|
-
appInfo: {
|
|
53
|
-
name: "flopay-node",
|
|
54
|
-
version: import_shared.SDK_VERSION
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
|
-
this.checkout = {
|
|
58
|
-
sessions: {
|
|
59
|
-
create: this.createSession.bind(this),
|
|
60
|
-
retrieve: this.retrieveSession.bind(this),
|
|
61
|
-
expire: this.expireSession.bind(this),
|
|
62
|
-
listLineItems: this.listLineItems.bind(this)
|
|
63
|
-
}
|
|
64
|
-
};
|
|
65
|
-
this.webhooks = {
|
|
66
|
-
constructEvent: this.constructWebhookEvent.bind(this)
|
|
67
|
-
};
|
|
68
|
-
this.customers = {
|
|
69
|
-
create: this.createCustomer.bind(this),
|
|
70
|
-
retrieve: this.retrieveCustomer.bind(this),
|
|
71
|
-
update: this.updateCustomer.bind(this)
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* Create a checkout session via the billing API.
|
|
76
|
-
*
|
|
77
|
-
* Mirrors `createCheckoutSession` from `clicktech-core-ui/modules`.
|
|
78
|
-
* Posts to `{billingApiUrl}/v1/checkouts/sessions` and returns
|
|
79
|
-
* the session UUID for redirect.
|
|
80
|
-
*/
|
|
81
|
-
async createSession(params) {
|
|
82
|
-
const {
|
|
83
|
-
billingApiUrl,
|
|
84
|
-
checkoutBaseUrl,
|
|
85
|
-
items = [],
|
|
86
|
-
subscriptions = [],
|
|
87
|
-
products,
|
|
88
|
-
account,
|
|
89
|
-
successUrl,
|
|
90
|
-
cancelUrl,
|
|
91
|
-
checkoutMode = "confirm",
|
|
92
|
-
couponCodes = [],
|
|
93
|
-
tagsData,
|
|
94
|
-
redirectParams = {},
|
|
95
|
-
timeoutMs = 12e3,
|
|
96
|
-
clientId,
|
|
97
|
-
currency,
|
|
98
|
-
utmMetadata
|
|
99
|
-
} = params;
|
|
100
|
-
const wireProducts = products ?? (0, import_shared.foldIntoProducts)(items, subscriptions);
|
|
101
|
-
const sessionCurrency = (0, import_shared.resolveSessionCurrency)(currency, items, subscriptions, wireProducts);
|
|
102
|
-
if (!sessionCurrency) {
|
|
103
|
-
throw new import_shared.FloPayError(
|
|
104
|
-
"currency is required: pass `currency` on the session, or include a `currency` on the first item/subscription/product.",
|
|
105
|
-
"validation_error",
|
|
106
|
-
{ code: "CurrencyRequired", param: "currency" }
|
|
107
|
-
);
|
|
108
|
-
}
|
|
109
|
-
const payload = {
|
|
110
|
-
clientId,
|
|
111
|
-
checkoutVersion: import_shared.SDK_VERSION,
|
|
112
|
-
successUrl,
|
|
113
|
-
cancelUrl,
|
|
114
|
-
currency: sessionCurrency,
|
|
115
|
-
checkoutMode,
|
|
116
|
-
products: wireProducts.map((product) => (0, import_shared.buildProductPayload)(product, sessionCurrency)),
|
|
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
|
-
const nonce = body?.data?.nonce;
|
|
159
|
-
if (!uuid) {
|
|
160
|
-
throw new Error("Checkout session created but no UUID was returned by the billing API");
|
|
161
|
-
}
|
|
162
|
-
if (!nonce) {
|
|
163
|
-
throw new import_shared.FloPayError(
|
|
164
|
-
"Checkout session created but no `nonce` was returned by the billing API. Upgrade the billing service to TeamFloPay/backend#640 or later.",
|
|
165
|
-
"api_error",
|
|
166
|
-
{ code: "MissingCheckoutSessionToken" }
|
|
167
|
-
);
|
|
168
|
-
}
|
|
169
|
-
const redirectUrl = new URL(`${checkoutBaseUrl.replace(/\/+$/, "")}/secure`);
|
|
170
|
-
redirectUrl.searchParams.set("id", uuid);
|
|
171
|
-
for (const [key, value] of Object.entries(redirectParams)) {
|
|
172
|
-
redirectUrl.searchParams.set(key, value);
|
|
173
|
-
}
|
|
174
|
-
return { status: 201, redirectUrl: redirectUrl.toString(), nonce };
|
|
175
|
-
}
|
|
176
|
-
if (status === 204) {
|
|
177
|
-
return { status: 204 };
|
|
178
|
-
}
|
|
179
|
-
return { status };
|
|
180
|
-
}
|
|
181
|
-
normalizeStripeSession(session) {
|
|
182
|
-
const statusMap = {
|
|
183
|
-
open: "open",
|
|
184
|
-
complete: "complete",
|
|
185
|
-
expired: "expired"
|
|
186
|
-
};
|
|
187
|
-
return {
|
|
188
|
-
id: session.id,
|
|
189
|
-
clientSecret: session.client_secret ?? "",
|
|
190
|
-
mode: session.mode,
|
|
191
|
-
status: statusMap[session.status ?? "open"] ?? "open",
|
|
192
|
-
amount: session.amount_total ?? 0,
|
|
193
|
-
currency: session.currency ?? "usd",
|
|
194
|
-
metadata: session.metadata ?? {}
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
async retrieveSession(id) {
|
|
198
|
-
const session = await this.stripe.checkout.sessions.retrieve(id);
|
|
199
|
-
return this.normalizeStripeSession(session);
|
|
200
|
-
}
|
|
201
|
-
async expireSession(id) {
|
|
202
|
-
const session = await this.stripe.checkout.sessions.expire(id);
|
|
203
|
-
return this.normalizeStripeSession(session);
|
|
204
|
-
}
|
|
205
|
-
async listLineItems(id) {
|
|
206
|
-
const items = await this.stripe.checkout.sessions.listLineItems(id);
|
|
207
|
-
return items.data.map((item) => ({
|
|
208
|
-
price: item.price?.id,
|
|
209
|
-
quantity: item.quantity ?? 1
|
|
210
|
-
}));
|
|
211
|
-
}
|
|
212
|
-
constructWebhookEvent(payload, signature, secret) {
|
|
213
|
-
const event = this.stripe.webhooks.constructEvent(payload, signature, secret);
|
|
214
|
-
return {
|
|
215
|
-
id: event.id,
|
|
216
|
-
type: event.type,
|
|
217
|
-
data: event.data,
|
|
218
|
-
created: event.created
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
|
-
async createCustomer(params) {
|
|
222
|
-
const customer = await this.stripe.customers.create({
|
|
223
|
-
email: params.email,
|
|
224
|
-
name: params.name,
|
|
225
|
-
metadata: params.metadata
|
|
226
|
-
});
|
|
227
|
-
return {
|
|
228
|
-
id: customer.id,
|
|
229
|
-
email: customer.email ?? params.email,
|
|
230
|
-
firstName: params.name?.split(" ")[0],
|
|
231
|
-
lastName: params.name?.split(" ").slice(1).join(" ")
|
|
232
|
-
};
|
|
233
|
-
}
|
|
234
|
-
async retrieveCustomer(id) {
|
|
235
|
-
const customer = await this.stripe.customers.retrieve(id);
|
|
236
|
-
if (customer.deleted) {
|
|
237
|
-
throw new import_shared.FloPayError(
|
|
238
|
-
`Customer ${id} has been deleted`,
|
|
239
|
-
"api_error",
|
|
240
|
-
{ code: "resource_missing" }
|
|
241
|
-
);
|
|
242
|
-
}
|
|
243
|
-
return {
|
|
244
|
-
id: customer.id,
|
|
245
|
-
email: customer.email ?? "",
|
|
246
|
-
firstName: customer.name?.split(" ")[0],
|
|
247
|
-
lastName: customer.name?.split(" ").slice(1).join(" ")
|
|
248
|
-
};
|
|
249
|
-
}
|
|
250
|
-
async updateCustomer(id, params) {
|
|
251
|
-
const customer = await this.stripe.customers.update(id, {
|
|
252
|
-
email: params.email,
|
|
253
|
-
name: params.name,
|
|
254
|
-
metadata: params.metadata
|
|
255
|
-
});
|
|
256
|
-
return {
|
|
257
|
-
id: customer.id,
|
|
258
|
-
email: customer.email ?? "",
|
|
259
|
-
firstName: customer.name?.split(" ")[0],
|
|
260
|
-
lastName: customer.name?.split(" ").slice(1).join(" ")
|
|
261
|
-
};
|
|
262
|
-
}
|
|
263
|
-
};
|
|
264
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
265
|
-
0 && (module.exports = {
|
|
266
|
-
FloPay,
|
|
267
|
-
STRIPE_API_VERSION
|
|
268
|
-
});
|
|
269
|
-
//# sourceMappingURL=index.cjs.map
|
|
1
|
+
"use strict";var A=Object.create;var u=Object.defineProperty;var z=Object.getOwnPropertyDescriptor;var D=Object.getOwnPropertyNames;var F=Object.getPrototypeOf,M=Object.prototype.hasOwnProperty;var q=(s,e)=>{for(var t in e)u(s,t,{get:e[t],enumerable:!0})},b=(s,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of D(e))!M.call(s,o)&&o!==t&&u(s,o,{get:()=>e[o],enumerable:!(r=z(e,o))||r.enumerable});return s};var W=(s,e,t)=>(t=s!=null?A(F(s)):{},b(e||!s||!s.__esModule?u(t,"default",{value:s,enumerable:!0}):t,s)),$=s=>b(u({},"__esModule",{value:!0}),s);var B={};q(B,{FloPay:()=>m,STRIPE_API_VERSION:()=>y});module.exports=$(B);var v=W(require("stripe"),1),i=require("@flopay/shared"),y="2026-04-22.dahlia",m=class{constructor(e,t){if(!e)throw new i.FloPayError("A secret key is required to initialize the FloPay server SDK.","authentication_error");this.stripe=new v.default(t?.stripeSecretKey??e,{apiVersion:t?.apiVersion??y,appInfo:{name:"flopay-node",version:i.SDK_VERSION}}),this.checkout={sessions:{create:this.createSession.bind(this),retrieve:this.retrieveSession.bind(this),expire:this.expireSession.bind(this),listLineItems:this.listLineItems.bind(this)}},this.webhooks={constructEvent:this.constructWebhookEvent.bind(this)},this.customers={create:this.createCustomer.bind(this),retrieve:this.retrieveCustomer.bind(this),update:this.updateCustomer.bind(this)}}async createSession(e){let{billingApiUrl:t,checkoutBaseUrl:r,items:o=[],subscriptions:C=[],products:w,account:n,successUrl:I,cancelUrl:N,checkoutMode:E="confirm",couponCodes:R=[],tagsData:S,redirectParams:U={},timeoutMs:x=12e3,clientId:_,currency:L,utmMetadata:g}=e,P=w??(0,i.foldIntoProducts)(o,C),l=(0,i.resolveSessionCurrency)(L,o,C,P);if(!l)throw new i.FloPayError("currency is required: pass `currency` on the session, or include a `currency` on the first item/subscription/product.","validation_error",{code:"CurrencyRequired",param:"currency"});let d={clientId:_,checkoutVersion:i.SDK_VERSION,successUrl:I,cancelUrl:N,currency:l,checkoutMode:E,products:P.map(a=>(0,i.buildProductPayload)(a,l)),accountData:{userId:n.userId,firstName:n.firstName??null,lastName:n.lastName??null,email:n.email,country:n.country??null,gender:n.gender??null,city:n.city??null,state:n.state??null,zip:n.zip??null},couponCodes:R};S&&(d.tagsData=S),g?.length&&(d.utmMetadata=g);let O=`${t.replace(/\/+$/,"")}/v1/checkouts/sessions`,f=new AbortController,T=setTimeout(()=>f.abort(),x),c,p;try{let a=await fetch(O,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(d),signal:f.signal});c=a.status;try{p=await a.json()}catch{}}finally{clearTimeout(T)}if(c===201){let a=p?.data?.uuid,k=p?.data?.nonce;if(!a)throw new Error("Checkout session created but no UUID was returned by the billing API");if(!k)throw new i.FloPayError("Checkout session created but no `nonce` was returned by the billing API. Upgrade the billing service to TeamFloPay/backend#640 or later.","api_error",{code:"MissingCheckoutSessionToken"});let h=new URL(`${r.replace(/\/+$/,"")}/secure`);h.searchParams.set("id",a);for(let[V,j]of Object.entries(U))h.searchParams.set(V,j);return{status:201,redirectUrl:h.toString(),nonce:k}}return c===204?{status:204}:{status:c}}normalizeStripeSession(e){let t={open:"open",complete:"complete",expired:"expired"};return{id:e.id,clientSecret:e.client_secret??"",mode:e.mode,status:t[e.status??"open"]??"open",amount:e.amount_total??0,currency:e.currency??"usd",metadata:e.metadata??{}}}async retrieveSession(e){let t=await this.stripe.checkout.sessions.retrieve(e);return this.normalizeStripeSession(t)}async expireSession(e){let t=await this.stripe.checkout.sessions.expire(e);return this.normalizeStripeSession(t)}async listLineItems(e){return(await this.stripe.checkout.sessions.listLineItems(e)).data.map(r=>({price:r.price?.id,quantity:r.quantity??1}))}constructWebhookEvent(e,t,r){let o=this.stripe.webhooks.constructEvent(e,t,r);return{id:o.id,type:o.type,data:o.data,created:o.created}}async createCustomer(e){let t=await this.stripe.customers.create({email:e.email,name:e.name,metadata:e.metadata});return{id:t.id,email:t.email??e.email,firstName:e.name?.split(" ")[0],lastName:e.name?.split(" ").slice(1).join(" ")}}async retrieveCustomer(e){let t=await this.stripe.customers.retrieve(e);if(t.deleted)throw new i.FloPayError(`Customer ${e} has been deleted`,"api_error",{code:"resource_missing"});return{id:t.id,email:t.email??"",firstName:t.name?.split(" ")[0],lastName:t.name?.split(" ").slice(1).join(" ")}}async updateCustomer(e,t){let r=await this.stripe.customers.update(e,{email:t.email,name:t.name,metadata:t.metadata});return{id:r.id,email:r.email??"",firstName:r.name?.split(" ")[0],lastName:r.name?.split(" ").slice(1).join(" ")}}};0&&(module.exports={FloPay,STRIPE_API_VERSION});
|
package/dist/index.mjs
CHANGED
|
@@ -1,237 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import Stripe from "stripe";
|
|
3
|
-
import {
|
|
4
|
-
FloPayError,
|
|
5
|
-
SDK_VERSION,
|
|
6
|
-
buildProductPayload,
|
|
7
|
-
foldIntoProducts,
|
|
8
|
-
resolveSessionCurrency
|
|
9
|
-
} from "@flopay/shared";
|
|
10
|
-
var STRIPE_API_VERSION = "2026-04-22.dahlia";
|
|
11
|
-
var FloPay = class {
|
|
12
|
-
constructor(secretKey, options) {
|
|
13
|
-
if (!secretKey) {
|
|
14
|
-
throw new FloPayError(
|
|
15
|
-
"A secret key is required to initialize the FloPay server SDK.",
|
|
16
|
-
"authentication_error"
|
|
17
|
-
);
|
|
18
|
-
}
|
|
19
|
-
this.stripe = new Stripe(options?.stripeSecretKey ?? secretKey, {
|
|
20
|
-
apiVersion: options?.apiVersion ?? STRIPE_API_VERSION,
|
|
21
|
-
appInfo: {
|
|
22
|
-
name: "flopay-node",
|
|
23
|
-
version: SDK_VERSION
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
this.checkout = {
|
|
27
|
-
sessions: {
|
|
28
|
-
create: this.createSession.bind(this),
|
|
29
|
-
retrieve: this.retrieveSession.bind(this),
|
|
30
|
-
expire: this.expireSession.bind(this),
|
|
31
|
-
listLineItems: this.listLineItems.bind(this)
|
|
32
|
-
}
|
|
33
|
-
};
|
|
34
|
-
this.webhooks = {
|
|
35
|
-
constructEvent: this.constructWebhookEvent.bind(this)
|
|
36
|
-
};
|
|
37
|
-
this.customers = {
|
|
38
|
-
create: this.createCustomer.bind(this),
|
|
39
|
-
retrieve: this.retrieveCustomer.bind(this),
|
|
40
|
-
update: this.updateCustomer.bind(this)
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Create a checkout session via the billing API.
|
|
45
|
-
*
|
|
46
|
-
* Mirrors `createCheckoutSession` from `clicktech-core-ui/modules`.
|
|
47
|
-
* Posts to `{billingApiUrl}/v1/checkouts/sessions` and returns
|
|
48
|
-
* the session UUID for redirect.
|
|
49
|
-
*/
|
|
50
|
-
async createSession(params) {
|
|
51
|
-
const {
|
|
52
|
-
billingApiUrl,
|
|
53
|
-
checkoutBaseUrl,
|
|
54
|
-
items = [],
|
|
55
|
-
subscriptions = [],
|
|
56
|
-
products,
|
|
57
|
-
account,
|
|
58
|
-
successUrl,
|
|
59
|
-
cancelUrl,
|
|
60
|
-
checkoutMode = "confirm",
|
|
61
|
-
couponCodes = [],
|
|
62
|
-
tagsData,
|
|
63
|
-
redirectParams = {},
|
|
64
|
-
timeoutMs = 12e3,
|
|
65
|
-
clientId,
|
|
66
|
-
currency,
|
|
67
|
-
utmMetadata
|
|
68
|
-
} = params;
|
|
69
|
-
const wireProducts = products ?? foldIntoProducts(items, subscriptions);
|
|
70
|
-
const sessionCurrency = resolveSessionCurrency(currency, items, subscriptions, wireProducts);
|
|
71
|
-
if (!sessionCurrency) {
|
|
72
|
-
throw new FloPayError(
|
|
73
|
-
"currency is required: pass `currency` on the session, or include a `currency` on the first item/subscription/product.",
|
|
74
|
-
"validation_error",
|
|
75
|
-
{ code: "CurrencyRequired", param: "currency" }
|
|
76
|
-
);
|
|
77
|
-
}
|
|
78
|
-
const payload = {
|
|
79
|
-
clientId,
|
|
80
|
-
checkoutVersion: SDK_VERSION,
|
|
81
|
-
successUrl,
|
|
82
|
-
cancelUrl,
|
|
83
|
-
currency: sessionCurrency,
|
|
84
|
-
checkoutMode,
|
|
85
|
-
products: wireProducts.map((product) => buildProductPayload(product, sessionCurrency)),
|
|
86
|
-
accountData: {
|
|
87
|
-
userId: account.userId,
|
|
88
|
-
firstName: account.firstName ?? null,
|
|
89
|
-
lastName: account.lastName ?? null,
|
|
90
|
-
email: account.email,
|
|
91
|
-
country: account.country ?? null,
|
|
92
|
-
gender: account.gender ?? null,
|
|
93
|
-
city: account.city ?? null,
|
|
94
|
-
state: account.state ?? null,
|
|
95
|
-
zip: account.zip ?? null
|
|
96
|
-
},
|
|
97
|
-
couponCodes
|
|
98
|
-
};
|
|
99
|
-
if (tagsData) {
|
|
100
|
-
payload["tagsData"] = tagsData;
|
|
101
|
-
}
|
|
102
|
-
if (utmMetadata?.length) {
|
|
103
|
-
payload["utmMetadata"] = utmMetadata;
|
|
104
|
-
}
|
|
105
|
-
const url = `${billingApiUrl.replace(/\/+$/, "")}/v1/checkouts/sessions`;
|
|
106
|
-
const controller = new AbortController();
|
|
107
|
-
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
108
|
-
let status;
|
|
109
|
-
let body;
|
|
110
|
-
try {
|
|
111
|
-
const response = await fetch(url, {
|
|
112
|
-
method: "POST",
|
|
113
|
-
headers: { "Content-Type": "application/json" },
|
|
114
|
-
body: JSON.stringify(payload),
|
|
115
|
-
signal: controller.signal
|
|
116
|
-
});
|
|
117
|
-
status = response.status;
|
|
118
|
-
try {
|
|
119
|
-
body = await response.json();
|
|
120
|
-
} catch {
|
|
121
|
-
}
|
|
122
|
-
} finally {
|
|
123
|
-
clearTimeout(timer);
|
|
124
|
-
}
|
|
125
|
-
if (status === 201) {
|
|
126
|
-
const uuid = body?.data?.uuid;
|
|
127
|
-
const nonce = body?.data?.nonce;
|
|
128
|
-
if (!uuid) {
|
|
129
|
-
throw new Error("Checkout session created but no UUID was returned by the billing API");
|
|
130
|
-
}
|
|
131
|
-
if (!nonce) {
|
|
132
|
-
throw new FloPayError(
|
|
133
|
-
"Checkout session created but no `nonce` was returned by the billing API. Upgrade the billing service to TeamFloPay/backend#640 or later.",
|
|
134
|
-
"api_error",
|
|
135
|
-
{ code: "MissingCheckoutSessionToken" }
|
|
136
|
-
);
|
|
137
|
-
}
|
|
138
|
-
const redirectUrl = new URL(`${checkoutBaseUrl.replace(/\/+$/, "")}/secure`);
|
|
139
|
-
redirectUrl.searchParams.set("id", uuid);
|
|
140
|
-
for (const [key, value] of Object.entries(redirectParams)) {
|
|
141
|
-
redirectUrl.searchParams.set(key, value);
|
|
142
|
-
}
|
|
143
|
-
return { status: 201, redirectUrl: redirectUrl.toString(), nonce };
|
|
144
|
-
}
|
|
145
|
-
if (status === 204) {
|
|
146
|
-
return { status: 204 };
|
|
147
|
-
}
|
|
148
|
-
return { status };
|
|
149
|
-
}
|
|
150
|
-
normalizeStripeSession(session) {
|
|
151
|
-
const statusMap = {
|
|
152
|
-
open: "open",
|
|
153
|
-
complete: "complete",
|
|
154
|
-
expired: "expired"
|
|
155
|
-
};
|
|
156
|
-
return {
|
|
157
|
-
id: session.id,
|
|
158
|
-
clientSecret: session.client_secret ?? "",
|
|
159
|
-
mode: session.mode,
|
|
160
|
-
status: statusMap[session.status ?? "open"] ?? "open",
|
|
161
|
-
amount: session.amount_total ?? 0,
|
|
162
|
-
currency: session.currency ?? "usd",
|
|
163
|
-
metadata: session.metadata ?? {}
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
-
async retrieveSession(id) {
|
|
167
|
-
const session = await this.stripe.checkout.sessions.retrieve(id);
|
|
168
|
-
return this.normalizeStripeSession(session);
|
|
169
|
-
}
|
|
170
|
-
async expireSession(id) {
|
|
171
|
-
const session = await this.stripe.checkout.sessions.expire(id);
|
|
172
|
-
return this.normalizeStripeSession(session);
|
|
173
|
-
}
|
|
174
|
-
async listLineItems(id) {
|
|
175
|
-
const items = await this.stripe.checkout.sessions.listLineItems(id);
|
|
176
|
-
return items.data.map((item) => ({
|
|
177
|
-
price: item.price?.id,
|
|
178
|
-
quantity: item.quantity ?? 1
|
|
179
|
-
}));
|
|
180
|
-
}
|
|
181
|
-
constructWebhookEvent(payload, signature, secret) {
|
|
182
|
-
const event = this.stripe.webhooks.constructEvent(payload, signature, secret);
|
|
183
|
-
return {
|
|
184
|
-
id: event.id,
|
|
185
|
-
type: event.type,
|
|
186
|
-
data: event.data,
|
|
187
|
-
created: event.created
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
async createCustomer(params) {
|
|
191
|
-
const customer = await this.stripe.customers.create({
|
|
192
|
-
email: params.email,
|
|
193
|
-
name: params.name,
|
|
194
|
-
metadata: params.metadata
|
|
195
|
-
});
|
|
196
|
-
return {
|
|
197
|
-
id: customer.id,
|
|
198
|
-
email: customer.email ?? params.email,
|
|
199
|
-
firstName: params.name?.split(" ")[0],
|
|
200
|
-
lastName: params.name?.split(" ").slice(1).join(" ")
|
|
201
|
-
};
|
|
202
|
-
}
|
|
203
|
-
async retrieveCustomer(id) {
|
|
204
|
-
const customer = await this.stripe.customers.retrieve(id);
|
|
205
|
-
if (customer.deleted) {
|
|
206
|
-
throw new FloPayError(
|
|
207
|
-
`Customer ${id} has been deleted`,
|
|
208
|
-
"api_error",
|
|
209
|
-
{ code: "resource_missing" }
|
|
210
|
-
);
|
|
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
|
-
async updateCustomer(id, params) {
|
|
220
|
-
const customer = await this.stripe.customers.update(id, {
|
|
221
|
-
email: params.email,
|
|
222
|
-
name: params.name,
|
|
223
|
-
metadata: params.metadata
|
|
224
|
-
});
|
|
225
|
-
return {
|
|
226
|
-
id: customer.id,
|
|
227
|
-
email: customer.email ?? "",
|
|
228
|
-
firstName: customer.name?.split(" ")[0],
|
|
229
|
-
lastName: customer.name?.split(" ").slice(1).join(" ")
|
|
230
|
-
};
|
|
231
|
-
}
|
|
232
|
-
};
|
|
233
|
-
export {
|
|
234
|
-
FloPay,
|
|
235
|
-
STRIPE_API_VERSION
|
|
236
|
-
};
|
|
237
|
-
//# sourceMappingURL=index.mjs.map
|
|
1
|
+
import T from"stripe";import{FloPayError as a,SDK_VERSION as P,buildProductPayload as V,foldIntoProducts as j,resolveSessionCurrency as A}from"@flopay/shared";var f="2026-04-22.dahlia",d=class{constructor(e,t){if(!e)throw new a("A secret key is required to initialize the FloPay server SDK.","authentication_error");this.stripe=new T(t?.stripeSecretKey??e,{apiVersion:t?.apiVersion??f,appInfo:{name:"flopay-node",version:P}}),this.checkout={sessions:{create:this.createSession.bind(this),retrieve:this.retrieveSession.bind(this),expire:this.expireSession.bind(this),listLineItems:this.listLineItems.bind(this)}},this.webhooks={constructEvent:this.constructWebhookEvent.bind(this)},this.customers={create:this.createCustomer.bind(this),retrieve:this.retrieveCustomer.bind(this),update:this.updateCustomer.bind(this)}}async createSession(e){let{billingApiUrl:t,checkoutBaseUrl:s,items:i=[],subscriptions:p=[],products:k,account:r,successUrl:b,cancelUrl:v,checkoutMode:w="confirm",couponCodes:I=[],tagsData:h,redirectParams:N={},timeoutMs:E=12e3,clientId:R,currency:U,utmMetadata:y}=e,C=k??j(i,p),c=A(U,i,p,C);if(!c)throw new a("currency is required: pass `currency` on the session, or include a `currency` on the first item/subscription/product.","validation_error",{code:"CurrencyRequired",param:"currency"});let u={clientId:R,checkoutVersion:P,successUrl:b,cancelUrl:v,currency:c,checkoutMode:w,products:C.map(o=>V(o,c)),accountData:{userId:r.userId,firstName:r.firstName??null,lastName:r.lastName??null,email:r.email,country:r.country??null,gender:r.gender??null,city:r.city??null,state:r.state??null,zip:r.zip??null},couponCodes:I};h&&(u.tagsData=h),y?.length&&(u.utmMetadata=y);let x=`${t.replace(/\/+$/,"")}/v1/checkouts/sessions`,S=new AbortController,_=setTimeout(()=>S.abort(),E),n,m;try{let o=await fetch(x,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(u),signal:S.signal});n=o.status;try{m=await o.json()}catch{}}finally{clearTimeout(_)}if(n===201){let o=m?.data?.uuid,g=m?.data?.nonce;if(!o)throw new Error("Checkout session created but no UUID was returned by the billing API");if(!g)throw new a("Checkout session created but no `nonce` was returned by the billing API. Upgrade the billing service to TeamFloPay/backend#640 or later.","api_error",{code:"MissingCheckoutSessionToken"});let l=new URL(`${s.replace(/\/+$/,"")}/secure`);l.searchParams.set("id",o);for(let[L,O]of Object.entries(N))l.searchParams.set(L,O);return{status:201,redirectUrl:l.toString(),nonce:g}}return n===204?{status:204}:{status:n}}normalizeStripeSession(e){let t={open:"open",complete:"complete",expired:"expired"};return{id:e.id,clientSecret:e.client_secret??"",mode:e.mode,status:t[e.status??"open"]??"open",amount:e.amount_total??0,currency:e.currency??"usd",metadata:e.metadata??{}}}async retrieveSession(e){let t=await this.stripe.checkout.sessions.retrieve(e);return this.normalizeStripeSession(t)}async expireSession(e){let t=await this.stripe.checkout.sessions.expire(e);return this.normalizeStripeSession(t)}async listLineItems(e){return(await this.stripe.checkout.sessions.listLineItems(e)).data.map(s=>({price:s.price?.id,quantity:s.quantity??1}))}constructWebhookEvent(e,t,s){let i=this.stripe.webhooks.constructEvent(e,t,s);return{id:i.id,type:i.type,data:i.data,created:i.created}}async createCustomer(e){let t=await this.stripe.customers.create({email:e.email,name:e.name,metadata:e.metadata});return{id:t.id,email:t.email??e.email,firstName:e.name?.split(" ")[0],lastName:e.name?.split(" ").slice(1).join(" ")}}async retrieveCustomer(e){let t=await this.stripe.customers.retrieve(e);if(t.deleted)throw new a(`Customer ${e} has been deleted`,"api_error",{code:"resource_missing"});return{id:t.id,email:t.email??"",firstName:t.name?.split(" ")[0],lastName:t.name?.split(" ").slice(1).join(" ")}}async updateCustomer(e,t){let s=await this.stripe.customers.update(e,{email:t.email,name:t.name,metadata:t.metadata});return{id:s.id,email:s.email??"",firstName:s.name?.split(" ")[0],lastName:s.name?.split(" ").slice(1).join(" ")}}};export{d as FloPay,f as STRIPE_API_VERSION};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flopay/node",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"publishConfig": {
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
],
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"stripe": "^22.2.1",
|
|
30
|
-
"@flopay/shared": "1.4.
|
|
30
|
+
"@flopay/shared": "1.4.4"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"tsup": "^8.3.0",
|
package/dist/index.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/flopay-node.ts"],"sourcesContent":["export { FloPay, STRIPE_API_VERSION } 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 {\n FloPayError,\n SDK_VERSION,\n buildProductPayload,\n foldIntoProducts,\n resolveSessionCurrency,\n} from '@flopay/shared';\n\nexport const STRIPE_API_VERSION = '2026-04-22.dahlia';\n\ntype StripeConfig = NonNullable<ConstructorParameters<typeof Stripe>[1]>;\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 * currency: 'USD',\n * items: [{ code: 'prod_abc' }],\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(options?.stripeSecretKey ?? secretKey, {\n apiVersion: (options?.apiVersion ?? STRIPE_API_VERSION) as StripeConfig['apiVersion'],\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 products,\n account,\n successUrl,\n cancelUrl,\n checkoutMode = 'confirm',\n couponCodes = [],\n tagsData,\n redirectParams = {},\n timeoutMs = 12000,\n clientId,\n currency,\n utmMetadata,\n } = params;\n\n const wireProducts = products ?? foldIntoProducts(items, subscriptions);\n const sessionCurrency = resolveSessionCurrency(currency, items, subscriptions, wireProducts);\n if (!sessionCurrency) {\n throw new FloPayError(\n 'currency is required: pass `currency` on the session, or include a `currency` on the first item/subscription/product.',\n 'validation_error',\n { code: 'CurrencyRequired', param: 'currency' },\n );\n }\n\n const payload: Record<string, unknown> = {\n clientId,\n checkoutVersion: SDK_VERSION,\n successUrl,\n cancelUrl,\n currency: sessionCurrency,\n checkoutMode,\n products: wireProducts.map((product) => buildProductPayload(product, sessionCurrency)),\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; nonce?: 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; nonce?: 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 const nonce = body?.data?.nonce;\n\n if (!uuid) {\n throw new Error('Checkout session created but no UUID was returned by the billing API');\n }\n\n if (!nonce) {\n throw new FloPayError(\n 'Checkout session created but no `nonce` was returned by the billing API. Upgrade the billing service to TeamFloPay/backend#640 or later.',\n 'api_error',\n { code: 'MissingCheckoutSessionToken' },\n );\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(), nonce };\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"]}
|
package/dist/index.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
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 {\n FloPayError,\n SDK_VERSION,\n buildProductPayload,\n foldIntoProducts,\n resolveSessionCurrency,\n} from '@flopay/shared';\n\nexport const STRIPE_API_VERSION = '2026-04-22.dahlia';\n\ntype StripeConfig = NonNullable<ConstructorParameters<typeof Stripe>[1]>;\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 * currency: 'USD',\n * items: [{ code: 'prod_abc' }],\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(options?.stripeSecretKey ?? secretKey, {\n apiVersion: (options?.apiVersion ?? STRIPE_API_VERSION) as StripeConfig['apiVersion'],\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 products,\n account,\n successUrl,\n cancelUrl,\n checkoutMode = 'confirm',\n couponCodes = [],\n tagsData,\n redirectParams = {},\n timeoutMs = 12000,\n clientId,\n currency,\n utmMetadata,\n } = params;\n\n const wireProducts = products ?? foldIntoProducts(items, subscriptions);\n const sessionCurrency = resolveSessionCurrency(currency, items, subscriptions, wireProducts);\n if (!sessionCurrency) {\n throw new FloPayError(\n 'currency is required: pass `currency` on the session, or include a `currency` on the first item/subscription/product.',\n 'validation_error',\n { code: 'CurrencyRequired', param: 'currency' },\n );\n }\n\n const payload: Record<string, unknown> = {\n clientId,\n checkoutVersion: SDK_VERSION,\n successUrl,\n cancelUrl,\n currency: sessionCurrency,\n checkoutMode,\n products: wireProducts.map((product) => buildProductPayload(product, sessionCurrency)),\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; nonce?: 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; nonce?: 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 const nonce = body?.data?.nonce;\n\n if (!uuid) {\n throw new Error('Checkout session created but no UUID was returned by the billing API');\n }\n\n if (!nonce) {\n throw new FloPayError(\n 'Checkout session created but no `nonce` was returned by the billing API. Upgrade the billing service to TeamFloPay/backend#640 or later.',\n 'api_error',\n { code: 'MissingCheckoutSessionToken' },\n );\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(), nonce };\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":[]}
|