@solifyn/core 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,69 @@
1
+ interface CheckoutSessionInput {
2
+ merchantId: string;
3
+ price: number;
4
+ currency: string;
5
+ productId: string;
6
+ productName: string;
7
+ isLive?: boolean;
8
+ options?: {
9
+ applicationFeePercent?: number;
10
+ planType?: 'one_time' | 'renewal' | 'usage_based';
11
+ billingPeriod?: number;
12
+ trialPeriodDays?: number;
13
+ expirationDays?: number;
14
+ sourceUrl?: string;
15
+ customerEmail?: string;
16
+ metadata?: Record<string, any>;
17
+ };
18
+ }
19
+ interface CheckoutSessionOutput {
20
+ id: string;
21
+ checkoutUrl: string;
22
+ rawResponse?: any;
23
+ }
24
+ interface IPaymentProvider {
25
+ createCheckoutSession(input: CheckoutSessionInput): Promise<CheckoutSessionOutput>;
26
+ }
27
+
28
+ declare class CheckoutError extends Error {
29
+ readonly code: string;
30
+ readonly statusCode: number;
31
+ constructor(message: string, code?: string, statusCode?: number);
32
+ }
33
+ declare class UnauthorizedError extends CheckoutError {
34
+ constructor(message?: string);
35
+ }
36
+ declare class ProviderError extends CheckoutError {
37
+ constructor(message: string, statusCode?: number);
38
+ }
39
+ declare class ValidationError extends CheckoutError {
40
+ constructor(message: string);
41
+ }
42
+
43
+ declare class Mapper {
44
+ static toPlanData(input: CheckoutSessionInput): any;
45
+ static toCheckoutSessionOutput(Response: any): CheckoutSessionOutput;
46
+ }
47
+
48
+ declare class PaymentProvider implements IPaymentProvider {
49
+ private client;
50
+ constructor(apiKey: string, baseURL?: string);
51
+ createCheckoutSession(input: CheckoutSessionInput): Promise<CheckoutSessionOutput>;
52
+ }
53
+
54
+ declare class PaymentService {
55
+ private provider;
56
+ constructor(provider: IPaymentProvider);
57
+ createCheckoutSession(input: CheckoutSessionInput): Promise<CheckoutSessionOutput>;
58
+ }
59
+
60
+ interface SolifynConfig {
61
+ apiKey: string;
62
+ baseURL?: string;
63
+ }
64
+ declare class Solifyn {
65
+ readonly checkout: PaymentService;
66
+ constructor(config: SolifynConfig);
67
+ }
68
+
69
+ export { CheckoutError, type CheckoutSessionInput, type CheckoutSessionOutput, type IPaymentProvider, Mapper, PaymentProvider, PaymentService, ProviderError, Solifyn, type SolifynConfig, UnauthorizedError, ValidationError };
@@ -0,0 +1,69 @@
1
+ interface CheckoutSessionInput {
2
+ merchantId: string;
3
+ price: number;
4
+ currency: string;
5
+ productId: string;
6
+ productName: string;
7
+ isLive?: boolean;
8
+ options?: {
9
+ applicationFeePercent?: number;
10
+ planType?: 'one_time' | 'renewal' | 'usage_based';
11
+ billingPeriod?: number;
12
+ trialPeriodDays?: number;
13
+ expirationDays?: number;
14
+ sourceUrl?: string;
15
+ customerEmail?: string;
16
+ metadata?: Record<string, any>;
17
+ };
18
+ }
19
+ interface CheckoutSessionOutput {
20
+ id: string;
21
+ checkoutUrl: string;
22
+ rawResponse?: any;
23
+ }
24
+ interface IPaymentProvider {
25
+ createCheckoutSession(input: CheckoutSessionInput): Promise<CheckoutSessionOutput>;
26
+ }
27
+
28
+ declare class CheckoutError extends Error {
29
+ readonly code: string;
30
+ readonly statusCode: number;
31
+ constructor(message: string, code?: string, statusCode?: number);
32
+ }
33
+ declare class UnauthorizedError extends CheckoutError {
34
+ constructor(message?: string);
35
+ }
36
+ declare class ProviderError extends CheckoutError {
37
+ constructor(message: string, statusCode?: number);
38
+ }
39
+ declare class ValidationError extends CheckoutError {
40
+ constructor(message: string);
41
+ }
42
+
43
+ declare class Mapper {
44
+ static toPlanData(input: CheckoutSessionInput): any;
45
+ static toCheckoutSessionOutput(Response: any): CheckoutSessionOutput;
46
+ }
47
+
48
+ declare class PaymentProvider implements IPaymentProvider {
49
+ private client;
50
+ constructor(apiKey: string, baseURL?: string);
51
+ createCheckoutSession(input: CheckoutSessionInput): Promise<CheckoutSessionOutput>;
52
+ }
53
+
54
+ declare class PaymentService {
55
+ private provider;
56
+ constructor(provider: IPaymentProvider);
57
+ createCheckoutSession(input: CheckoutSessionInput): Promise<CheckoutSessionOutput>;
58
+ }
59
+
60
+ interface SolifynConfig {
61
+ apiKey: string;
62
+ baseURL?: string;
63
+ }
64
+ declare class Solifyn {
65
+ readonly checkout: PaymentService;
66
+ constructor(config: SolifynConfig);
67
+ }
68
+
69
+ export { CheckoutError, type CheckoutSessionInput, type CheckoutSessionOutput, type IPaymentProvider, Mapper, PaymentProvider, PaymentService, ProviderError, Solifyn, type SolifynConfig, UnauthorizedError, ValidationError };
package/dist/index.js ADDED
@@ -0,0 +1,211 @@
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
+ CheckoutError: () => CheckoutError,
34
+ Mapper: () => Mapper,
35
+ PaymentProvider: () => PaymentProvider,
36
+ PaymentService: () => PaymentService,
37
+ ProviderError: () => ProviderError,
38
+ Solifyn: () => Solifyn,
39
+ UnauthorizedError: () => UnauthorizedError,
40
+ ValidationError: () => ValidationError
41
+ });
42
+ module.exports = __toCommonJS(index_exports);
43
+
44
+ // src/errors/index.ts
45
+ var CheckoutError = class extends Error {
46
+ code;
47
+ statusCode;
48
+ constructor(message, code = "CHECKOUT_ERROR", statusCode = 400) {
49
+ super(message);
50
+ this.name = "CheckoutError";
51
+ this.code = code;
52
+ this.statusCode = statusCode;
53
+ Object.setPrototypeOf(this, new.target.prototype);
54
+ }
55
+ };
56
+ var UnauthorizedError = class extends CheckoutError {
57
+ constructor(message = "Unauthorized") {
58
+ super(message, "UNAUTHORIZED", 401);
59
+ }
60
+ };
61
+ var ProviderError = class extends CheckoutError {
62
+ constructor(message, statusCode = 400) {
63
+ super(message, "PROVIDER_ERROR", statusCode);
64
+ }
65
+ };
66
+ var ValidationError = class extends CheckoutError {
67
+ constructor(message) {
68
+ super(message, "VALIDATION_ERROR", 400);
69
+ }
70
+ };
71
+
72
+ // src/mappers/mapper.ts
73
+ var Mapper = class {
74
+ static toPlanData(input) {
75
+ const { price, currency, productId, productName, options } = input;
76
+ const feePercent = options?.applicationFeePercent ?? 0.05;
77
+ const feeAmount = parseFloat((price * feePercent).toFixed(2));
78
+ const planData = {
79
+ company_id: input.merchantId,
80
+ title: productName,
81
+ initial_price: price,
82
+ currency: currency.toLowerCase(),
83
+ plan_type: options?.planType || "one_time",
84
+ product_id: productId,
85
+ application_fee_amount: feeAmount,
86
+ override_tax_type: "exclusive",
87
+ visibility: "visible"
88
+ };
89
+ const effectivePlanType = planData.plan_type === "renewal" || planData.plan_type === "usage_based" ? "renewal" : "one_time";
90
+ const isUsageBased = planData.plan_type === "usage_based";
91
+ planData.plan_type = effectivePlanType;
92
+ if (planData.plan_type === "renewal") {
93
+ planData.initial_price = 0;
94
+ planData.renewal_price = price;
95
+ planData.billing_period = options?.billingPeriod || 30;
96
+ if (isUsageBased) {
97
+ planData.internal_notes = `USAGE_BASED_PLAN:${options?.customerEmail || "guest"}`;
98
+ planData.visibility = "hidden";
99
+ }
100
+ if (options?.trialPeriodDays !== void 0 && options?.trialPeriodDays !== null) {
101
+ planData.trial_period_days = Number(options.trialPeriodDays);
102
+ }
103
+ } else {
104
+ planData.initial_price = price;
105
+ if (options?.expirationDays) {
106
+ planData.expiration_days = options.expirationDays;
107
+ }
108
+ }
109
+ return {
110
+ plan: planData,
111
+ isUsageBased
112
+ };
113
+ }
114
+ static toCheckoutSessionOutput(Response) {
115
+ const checkoutUrl = Response?.checkout_url || Response?.purchase_url;
116
+ if (!Response || !Response.id || !checkoutUrl) {
117
+ throw new Error("Invalid checkout session response from Solifyn");
118
+ }
119
+ if (!Response.checkout_url && Response.purchase_url) {
120
+ Response.checkout_url = Response.purchase_url;
121
+ }
122
+ return {
123
+ id: Response.id,
124
+ checkoutUrl,
125
+ rawResponse: Response
126
+ };
127
+ }
128
+ };
129
+
130
+ // src/services/provider.ts
131
+ var import_sdk = __toESM(require("@whop/sdk"));
132
+ var PaymentProvider = class {
133
+ client;
134
+ constructor(apiKey, baseURL) {
135
+ this.client = new import_sdk.default({
136
+ apiKey,
137
+ baseURL
138
+ });
139
+ }
140
+ async createCheckoutSession(input) {
141
+ const { plan, isUsageBased } = Mapper.toPlanData(input);
142
+ try {
143
+ const Response = await this.client.checkoutConfigurations.create({
144
+ source_url: input.options?.sourceUrl || "https://solifyn.com",
145
+ plan,
146
+ metadata: {
147
+ ...input.options?.metadata,
148
+ is_usage_based: isUsageBased ? "true" : "false"
149
+ }
150
+ });
151
+ return Mapper.toCheckoutSessionOutput(Response);
152
+ } catch (error) {
153
+ console.error("API call failed. Full error details:", error);
154
+ if (error.response) {
155
+ try {
156
+ console.error("Response data:", JSON.stringify(error.response.data || error.response, null, 2));
157
+ } catch (e) {
158
+ }
159
+ }
160
+ const isAuthError = error.message?.includes("401") || error.message?.includes("unauthorized") || error.message?.includes("Authentication failed");
161
+ if (isAuthError) {
162
+ throw new UnauthorizedError("SDK Authentication failed. Check API keys.");
163
+ }
164
+ throw new ProviderError(`Checkout failed: ${error.message}`, error.statusCode || 400);
165
+ }
166
+ }
167
+ };
168
+
169
+ // src/services/payment.service.ts
170
+ var PaymentService = class {
171
+ provider;
172
+ constructor(provider) {
173
+ this.provider = provider;
174
+ }
175
+ async createCheckoutSession(input) {
176
+ if (!input.merchantId) {
177
+ throw new Error("merchantId is required");
178
+ }
179
+ if (!input.productId) {
180
+ throw new Error("productId is required");
181
+ }
182
+ if (input.price < 0) {
183
+ throw new Error("price must be non-negative");
184
+ }
185
+ return this.provider.createCheckoutSession(input);
186
+ }
187
+ };
188
+
189
+ // src/client.ts
190
+ var Solifyn = class {
191
+ checkout;
192
+ constructor(config) {
193
+ if (!config || !config.apiKey) {
194
+ throw new Error("Solifyn API key is required");
195
+ }
196
+ const provider = new PaymentProvider(config.apiKey, config.baseURL);
197
+ this.checkout = new PaymentService(provider);
198
+ }
199
+ };
200
+ // Annotate the CommonJS export names for ESM import in node:
201
+ 0 && (module.exports = {
202
+ CheckoutError,
203
+ Mapper,
204
+ PaymentProvider,
205
+ PaymentService,
206
+ ProviderError,
207
+ Solifyn,
208
+ UnauthorizedError,
209
+ ValidationError
210
+ });
211
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/errors/index.ts","../src/mappers/mapper.ts","../src/services/provider.ts","../src/services/payment.service.ts","../src/client.ts"],"sourcesContent":["export * from './interfaces';\nexport * from './errors';\nexport * from './mappers/mapper';\nexport * from './services/provider';\nexport * from './services/payment.service';\nexport * from './client';\n","export class CheckoutError extends Error {\n public readonly code: string;\n public readonly statusCode: number;\n\n constructor(message: string, code = 'CHECKOUT_ERROR', statusCode = 400) {\n super(message);\n this.name = 'CheckoutError';\n this.code = code;\n this.statusCode = statusCode;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class UnauthorizedError extends CheckoutError {\n constructor(message = 'Unauthorized') {\n super(message, 'UNAUTHORIZED', 401);\n }\n}\n\nexport class ProviderError extends CheckoutError {\n constructor(message: string, statusCode = 400) {\n super(message, 'PROVIDER_ERROR', statusCode);\n }\n}\n\nexport class ValidationError extends CheckoutError {\n constructor(message: string) {\n super(message, 'VALIDATION_ERROR', 400);\n }\n}\n","import { CheckoutSessionInput, CheckoutSessionOutput } from '../interfaces';\n\nexport class Mapper {\n static toPlanData(input: CheckoutSessionInput): any {\n const { price, currency, productId, productName, options } = input;\n const feePercent = options?.applicationFeePercent ?? 0.05;\n const feeAmount = parseFloat((price * feePercent).toFixed(2));\n\n const planData: any = {\n company_id: input.merchantId,\n title: productName,\n initial_price: price,\n currency: currency.toLowerCase(),\n plan_type: options?.planType || 'one_time',\n product_id: productId,\n application_fee_amount: feeAmount,\n override_tax_type: 'exclusive',\n visibility: 'visible',\n };\n\n const effectivePlanType =\n planData.plan_type === 'renewal' || planData.plan_type === 'usage_based'\n ? 'renewal'\n : 'one_time';\n const isUsageBased = planData.plan_type === 'usage_based';\n planData.plan_type = effectivePlanType;\n\n if (planData.plan_type === 'renewal') {\n planData.initial_price = 0;\n planData.renewal_price = price;\n planData.billing_period = options?.billingPeriod || 30;\n\n if (isUsageBased) {\n planData.internal_notes = `USAGE_BASED_PLAN:${options?.customerEmail || 'guest'}`;\n planData.visibility = 'hidden';\n }\n\n if (options?.trialPeriodDays !== undefined && options?.trialPeriodDays !== null) {\n planData.trial_period_days = Number(options.trialPeriodDays);\n }\n } else {\n planData.initial_price = price;\n if (options?.expirationDays) {\n planData.expiration_days = options.expirationDays;\n }\n }\n\n return {\n plan: planData,\n isUsageBased,\n };\n }\n\n static toCheckoutSessionOutput(Response: any): CheckoutSessionOutput {\n const checkoutUrl = Response?.checkout_url || Response?.purchase_url;\n if (!Response || !Response.id || !checkoutUrl) {\n throw new Error('Invalid checkout session response from Solifyn');\n }\n\n if (!Response.checkout_url && Response.purchase_url) {\n Response.checkout_url = Response.purchase_url;\n }\n\n return {\n id: Response.id,\n checkoutUrl: checkoutUrl,\n rawResponse: Response,\n };\n }\n}\n","import Whop from '@whop/sdk';\nimport { IPaymentProvider, CheckoutSessionInput, CheckoutSessionOutput } from '../interfaces';\nimport { ProviderError, UnauthorizedError } from '../errors';\nimport { Mapper } from '../mappers/mapper';\n\nexport class PaymentProvider implements IPaymentProvider {\n private client: Whop;\n\n constructor(apiKey: string, baseURL?: string) {\n this.client = new Whop({\n apiKey,\n baseURL,\n });\n }\n\n async createCheckoutSession(input: CheckoutSessionInput): Promise<CheckoutSessionOutput> {\n const { plan, isUsageBased } = Mapper.toPlanData(input);\n\n try {\n const Response = await (this.client as any).checkoutConfigurations.create({\n source_url: input.options?.sourceUrl || 'https://solifyn.com',\n plan,\n metadata: {\n ...input.options?.metadata,\n is_usage_based: isUsageBased ? 'true' : 'false',\n },\n });\n\n return Mapper.toCheckoutSessionOutput(Response);\n } catch (error: any) {\n console.error(\"API call failed. Full error details:\", error);\n if (error.response) {\n try {\n console.error(\"Response data:\", JSON.stringify(error.response.data || error.response, null, 2));\n } catch (e) { }\n }\n // Map authorization errors\n const isAuthError =\n error.message?.includes('401') ||\n error.message?.includes('unauthorized') ||\n error.message?.includes('Authentication failed');\n\n if (isAuthError) {\n throw new UnauthorizedError('SDK Authentication failed. Check API keys.');\n }\n\n throw new ProviderError(`Checkout failed: ${error.message}`, error.statusCode || 400);\n }\n }\n}\n","import { IPaymentProvider, CheckoutSessionInput, CheckoutSessionOutput } from '../interfaces';\n\nexport class PaymentService {\n private provider: IPaymentProvider;\n\n constructor(provider: IPaymentProvider) {\n this.provider = provider;\n }\n\n async createCheckoutSession(input: CheckoutSessionInput): Promise<CheckoutSessionOutput> {\n if (!input.merchantId) {\n throw new Error('merchantId is required');\n }\n if (!input.productId) {\n throw new Error('productId is required');\n }\n if (input.price < 0) {\n throw new Error('price must be non-negative');\n }\n\n return this.provider.createCheckoutSession(input);\n }\n}\n","import { PaymentProvider } from './services/provider';\nimport { PaymentService } from './services/payment.service';\n\nexport interface SolifynConfig {\n apiKey: string;\n baseURL?: string;\n}\n\nexport class Solifyn {\n public readonly checkout: PaymentService;\n\n constructor(config: SolifynConfig) {\n if (!config || !config.apiKey) {\n throw new Error('Solifyn API key is required');\n }\n const provider = new PaymentProvider(config.apiKey, config.baseURL);\n this.checkout = new PaymentService(provider);\n }\n}\n"],"mappings":"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","names":["Whop"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,167 @@
1
+ // src/errors/index.ts
2
+ var CheckoutError = class extends Error {
3
+ code;
4
+ statusCode;
5
+ constructor(message, code = "CHECKOUT_ERROR", statusCode = 400) {
6
+ super(message);
7
+ this.name = "CheckoutError";
8
+ this.code = code;
9
+ this.statusCode = statusCode;
10
+ Object.setPrototypeOf(this, new.target.prototype);
11
+ }
12
+ };
13
+ var UnauthorizedError = class extends CheckoutError {
14
+ constructor(message = "Unauthorized") {
15
+ super(message, "UNAUTHORIZED", 401);
16
+ }
17
+ };
18
+ var ProviderError = class extends CheckoutError {
19
+ constructor(message, statusCode = 400) {
20
+ super(message, "PROVIDER_ERROR", statusCode);
21
+ }
22
+ };
23
+ var ValidationError = class extends CheckoutError {
24
+ constructor(message) {
25
+ super(message, "VALIDATION_ERROR", 400);
26
+ }
27
+ };
28
+
29
+ // src/mappers/mapper.ts
30
+ var Mapper = class {
31
+ static toPlanData(input) {
32
+ const { price, currency, productId, productName, options } = input;
33
+ const feePercent = options?.applicationFeePercent ?? 0.05;
34
+ const feeAmount = parseFloat((price * feePercent).toFixed(2));
35
+ const planData = {
36
+ company_id: input.merchantId,
37
+ title: productName,
38
+ initial_price: price,
39
+ currency: currency.toLowerCase(),
40
+ plan_type: options?.planType || "one_time",
41
+ product_id: productId,
42
+ application_fee_amount: feeAmount,
43
+ override_tax_type: "exclusive",
44
+ visibility: "visible"
45
+ };
46
+ const effectivePlanType = planData.plan_type === "renewal" || planData.plan_type === "usage_based" ? "renewal" : "one_time";
47
+ const isUsageBased = planData.plan_type === "usage_based";
48
+ planData.plan_type = effectivePlanType;
49
+ if (planData.plan_type === "renewal") {
50
+ planData.initial_price = 0;
51
+ planData.renewal_price = price;
52
+ planData.billing_period = options?.billingPeriod || 30;
53
+ if (isUsageBased) {
54
+ planData.internal_notes = `USAGE_BASED_PLAN:${options?.customerEmail || "guest"}`;
55
+ planData.visibility = "hidden";
56
+ }
57
+ if (options?.trialPeriodDays !== void 0 && options?.trialPeriodDays !== null) {
58
+ planData.trial_period_days = Number(options.trialPeriodDays);
59
+ }
60
+ } else {
61
+ planData.initial_price = price;
62
+ if (options?.expirationDays) {
63
+ planData.expiration_days = options.expirationDays;
64
+ }
65
+ }
66
+ return {
67
+ plan: planData,
68
+ isUsageBased
69
+ };
70
+ }
71
+ static toCheckoutSessionOutput(Response) {
72
+ const checkoutUrl = Response?.checkout_url || Response?.purchase_url;
73
+ if (!Response || !Response.id || !checkoutUrl) {
74
+ throw new Error("Invalid checkout session response from Solifyn");
75
+ }
76
+ if (!Response.checkout_url && Response.purchase_url) {
77
+ Response.checkout_url = Response.purchase_url;
78
+ }
79
+ return {
80
+ id: Response.id,
81
+ checkoutUrl,
82
+ rawResponse: Response
83
+ };
84
+ }
85
+ };
86
+
87
+ // src/services/provider.ts
88
+ import Whop from "@whop/sdk";
89
+ var PaymentProvider = class {
90
+ client;
91
+ constructor(apiKey, baseURL) {
92
+ this.client = new Whop({
93
+ apiKey,
94
+ baseURL
95
+ });
96
+ }
97
+ async createCheckoutSession(input) {
98
+ const { plan, isUsageBased } = Mapper.toPlanData(input);
99
+ try {
100
+ const Response = await this.client.checkoutConfigurations.create({
101
+ source_url: input.options?.sourceUrl || "https://solifyn.com",
102
+ plan,
103
+ metadata: {
104
+ ...input.options?.metadata,
105
+ is_usage_based: isUsageBased ? "true" : "false"
106
+ }
107
+ });
108
+ return Mapper.toCheckoutSessionOutput(Response);
109
+ } catch (error) {
110
+ console.error("API call failed. Full error details:", error);
111
+ if (error.response) {
112
+ try {
113
+ console.error("Response data:", JSON.stringify(error.response.data || error.response, null, 2));
114
+ } catch (e) {
115
+ }
116
+ }
117
+ const isAuthError = error.message?.includes("401") || error.message?.includes("unauthorized") || error.message?.includes("Authentication failed");
118
+ if (isAuthError) {
119
+ throw new UnauthorizedError("SDK Authentication failed. Check API keys.");
120
+ }
121
+ throw new ProviderError(`Checkout failed: ${error.message}`, error.statusCode || 400);
122
+ }
123
+ }
124
+ };
125
+
126
+ // src/services/payment.service.ts
127
+ var PaymentService = class {
128
+ provider;
129
+ constructor(provider) {
130
+ this.provider = provider;
131
+ }
132
+ async createCheckoutSession(input) {
133
+ if (!input.merchantId) {
134
+ throw new Error("merchantId is required");
135
+ }
136
+ if (!input.productId) {
137
+ throw new Error("productId is required");
138
+ }
139
+ if (input.price < 0) {
140
+ throw new Error("price must be non-negative");
141
+ }
142
+ return this.provider.createCheckoutSession(input);
143
+ }
144
+ };
145
+
146
+ // src/client.ts
147
+ var Solifyn = class {
148
+ checkout;
149
+ constructor(config) {
150
+ if (!config || !config.apiKey) {
151
+ throw new Error("Solifyn API key is required");
152
+ }
153
+ const provider = new PaymentProvider(config.apiKey, config.baseURL);
154
+ this.checkout = new PaymentService(provider);
155
+ }
156
+ };
157
+ export {
158
+ CheckoutError,
159
+ Mapper,
160
+ PaymentProvider,
161
+ PaymentService,
162
+ ProviderError,
163
+ Solifyn,
164
+ UnauthorizedError,
165
+ ValidationError
166
+ };
167
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors/index.ts","../src/mappers/mapper.ts","../src/services/provider.ts","../src/services/payment.service.ts","../src/client.ts"],"sourcesContent":["export class CheckoutError extends Error {\n public readonly code: string;\n public readonly statusCode: number;\n\n constructor(message: string, code = 'CHECKOUT_ERROR', statusCode = 400) {\n super(message);\n this.name = 'CheckoutError';\n this.code = code;\n this.statusCode = statusCode;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class UnauthorizedError extends CheckoutError {\n constructor(message = 'Unauthorized') {\n super(message, 'UNAUTHORIZED', 401);\n }\n}\n\nexport class ProviderError extends CheckoutError {\n constructor(message: string, statusCode = 400) {\n super(message, 'PROVIDER_ERROR', statusCode);\n }\n}\n\nexport class ValidationError extends CheckoutError {\n constructor(message: string) {\n super(message, 'VALIDATION_ERROR', 400);\n }\n}\n","import { CheckoutSessionInput, CheckoutSessionOutput } from '../interfaces';\n\nexport class Mapper {\n static toPlanData(input: CheckoutSessionInput): any {\n const { price, currency, productId, productName, options } = input;\n const feePercent = options?.applicationFeePercent ?? 0.05;\n const feeAmount = parseFloat((price * feePercent).toFixed(2));\n\n const planData: any = {\n company_id: input.merchantId,\n title: productName,\n initial_price: price,\n currency: currency.toLowerCase(),\n plan_type: options?.planType || 'one_time',\n product_id: productId,\n application_fee_amount: feeAmount,\n override_tax_type: 'exclusive',\n visibility: 'visible',\n };\n\n const effectivePlanType =\n planData.plan_type === 'renewal' || planData.plan_type === 'usage_based'\n ? 'renewal'\n : 'one_time';\n const isUsageBased = planData.plan_type === 'usage_based';\n planData.plan_type = effectivePlanType;\n\n if (planData.plan_type === 'renewal') {\n planData.initial_price = 0;\n planData.renewal_price = price;\n planData.billing_period = options?.billingPeriod || 30;\n\n if (isUsageBased) {\n planData.internal_notes = `USAGE_BASED_PLAN:${options?.customerEmail || 'guest'}`;\n planData.visibility = 'hidden';\n }\n\n if (options?.trialPeriodDays !== undefined && options?.trialPeriodDays !== null) {\n planData.trial_period_days = Number(options.trialPeriodDays);\n }\n } else {\n planData.initial_price = price;\n if (options?.expirationDays) {\n planData.expiration_days = options.expirationDays;\n }\n }\n\n return {\n plan: planData,\n isUsageBased,\n };\n }\n\n static toCheckoutSessionOutput(Response: any): CheckoutSessionOutput {\n const checkoutUrl = Response?.checkout_url || Response?.purchase_url;\n if (!Response || !Response.id || !checkoutUrl) {\n throw new Error('Invalid checkout session response from Solifyn');\n }\n\n if (!Response.checkout_url && Response.purchase_url) {\n Response.checkout_url = Response.purchase_url;\n }\n\n return {\n id: Response.id,\n checkoutUrl: checkoutUrl,\n rawResponse: Response,\n };\n }\n}\n","import Whop from '@whop/sdk';\nimport { IPaymentProvider, CheckoutSessionInput, CheckoutSessionOutput } from '../interfaces';\nimport { ProviderError, UnauthorizedError } from '../errors';\nimport { Mapper } from '../mappers/mapper';\n\nexport class PaymentProvider implements IPaymentProvider {\n private client: Whop;\n\n constructor(apiKey: string, baseURL?: string) {\n this.client = new Whop({\n apiKey,\n baseURL,\n });\n }\n\n async createCheckoutSession(input: CheckoutSessionInput): Promise<CheckoutSessionOutput> {\n const { plan, isUsageBased } = Mapper.toPlanData(input);\n\n try {\n const Response = await (this.client as any).checkoutConfigurations.create({\n source_url: input.options?.sourceUrl || 'https://solifyn.com',\n plan,\n metadata: {\n ...input.options?.metadata,\n is_usage_based: isUsageBased ? 'true' : 'false',\n },\n });\n\n return Mapper.toCheckoutSessionOutput(Response);\n } catch (error: any) {\n console.error(\"API call failed. Full error details:\", error);\n if (error.response) {\n try {\n console.error(\"Response data:\", JSON.stringify(error.response.data || error.response, null, 2));\n } catch (e) { }\n }\n // Map authorization errors\n const isAuthError =\n error.message?.includes('401') ||\n error.message?.includes('unauthorized') ||\n error.message?.includes('Authentication failed');\n\n if (isAuthError) {\n throw new UnauthorizedError('SDK Authentication failed. Check API keys.');\n }\n\n throw new ProviderError(`Checkout failed: ${error.message}`, error.statusCode || 400);\n }\n }\n}\n","import { IPaymentProvider, CheckoutSessionInput, CheckoutSessionOutput } from '../interfaces';\n\nexport class PaymentService {\n private provider: IPaymentProvider;\n\n constructor(provider: IPaymentProvider) {\n this.provider = provider;\n }\n\n async createCheckoutSession(input: CheckoutSessionInput): Promise<CheckoutSessionOutput> {\n if (!input.merchantId) {\n throw new Error('merchantId is required');\n }\n if (!input.productId) {\n throw new Error('productId is required');\n }\n if (input.price < 0) {\n throw new Error('price must be non-negative');\n }\n\n return this.provider.createCheckoutSession(input);\n }\n}\n","import { PaymentProvider } from './services/provider';\nimport { PaymentService } from './services/payment.service';\n\nexport interface SolifynConfig {\n apiKey: string;\n baseURL?: string;\n}\n\nexport class Solifyn {\n public readonly checkout: PaymentService;\n\n constructor(config: SolifynConfig) {\n if (!config || !config.apiKey) {\n throw new Error('Solifyn API key is required');\n }\n const provider = new PaymentProvider(config.apiKey, config.baseURL);\n this.checkout = new PaymentService(provider);\n }\n}\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@solifyn/core",
3
+ "version": "1.0.0",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "description": "Solifyn Core TypeScript SDK wrapping billing, payments, and checkout flows",
8
+ "main": "./dist/index.js",
9
+ "module": "./dist/index.mjs",
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "require": "./dist/index.js",
15
+ "import": "./dist/index.mjs"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "scripts": {
22
+ "build": "tsup",
23
+ "test": "vitest run",
24
+ "test:watch": "vitest"
25
+ },
26
+ "dependencies": {
27
+ "@whop/sdk": "^0.0.38"
28
+ },
29
+ "devDependencies": {
30
+ "tsup": "^8.0.2",
31
+ "typescript": "^5.3.3",
32
+ "vitest": "^1.3.1"
33
+ }
34
+ }