@solvapay/next 1.0.0-preview.10

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 ADDED
@@ -0,0 +1,477 @@
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
+ cancelSubscription: () => cancelSubscription,
34
+ checkSubscription: () => checkSubscription,
35
+ clearAllSubscriptionCache: () => clearAllSubscriptionCache,
36
+ clearSubscriptionCache: () => clearSubscriptionCache,
37
+ createAuthMiddleware: () => createAuthMiddleware,
38
+ createCheckoutSession: () => createCheckoutSession,
39
+ createCustomerSession: () => createCustomerSession,
40
+ createPaymentIntent: () => createPaymentIntent,
41
+ createSupabaseAuthMiddleware: () => createSupabaseAuthMiddleware,
42
+ getAuthenticatedUser: () => getAuthenticatedUser,
43
+ getSubscriptionCacheStats: () => getSubscriptionCacheStats,
44
+ listPlans: () => listPlans,
45
+ processPayment: () => processPayment,
46
+ syncCustomer: () => syncCustomer
47
+ });
48
+ module.exports = __toCommonJS(index_exports);
49
+ var import_server16 = require("next/server");
50
+ var import_server17 = require("@solvapay/server");
51
+ var import_core = require("@solvapay/core");
52
+
53
+ // src/helpers/auth.ts
54
+ var import_server = require("next/server");
55
+ var import_server2 = require("@solvapay/server");
56
+ async function getAuthenticatedUser(request, options = {}) {
57
+ const result = await (0, import_server2.getAuthenticatedUserCore)(request, options);
58
+ if ((0, import_server2.isErrorResult)(result)) {
59
+ return import_server.NextResponse.json(
60
+ { error: result.error, details: result.details },
61
+ { status: result.status }
62
+ );
63
+ }
64
+ return result;
65
+ }
66
+
67
+ // src/helpers/customer.ts
68
+ var import_server3 = require("next/server");
69
+ var import_server4 = require("@solvapay/server");
70
+ async function syncCustomer(request, options = {}) {
71
+ const result = await (0, import_server4.syncCustomerCore)(request, options);
72
+ if ((0, import_server4.isErrorResult)(result)) {
73
+ return import_server3.NextResponse.json(
74
+ { error: result.error, details: result.details },
75
+ { status: result.status }
76
+ );
77
+ }
78
+ return result;
79
+ }
80
+
81
+ // src/helpers/payment.ts
82
+ var import_server5 = require("next/server");
83
+ var import_server6 = require("@solvapay/server");
84
+ var import_server7 = require("@solvapay/server");
85
+ async function createPaymentIntent(request, body, options = {}) {
86
+ const result = await (0, import_server6.createPaymentIntentCore)(request, body, options);
87
+ if ((0, import_server6.isErrorResult)(result)) {
88
+ return import_server5.NextResponse.json(
89
+ { error: result.error, details: result.details },
90
+ { status: result.status }
91
+ );
92
+ }
93
+ try {
94
+ const userResult = await (0, import_server7.getAuthenticatedUserCore)(request);
95
+ if (!(0, import_server6.isErrorResult)(userResult)) {
96
+ clearSubscriptionCache(userResult.userId);
97
+ }
98
+ } catch {
99
+ }
100
+ return result;
101
+ }
102
+ async function processPayment(request, body, options = {}) {
103
+ const result = await (0, import_server6.processPaymentCore)(request, body, options);
104
+ if ((0, import_server6.isErrorResult)(result)) {
105
+ return import_server5.NextResponse.json(
106
+ { error: result.error, details: result.details },
107
+ { status: result.status }
108
+ );
109
+ }
110
+ try {
111
+ const userResult = await (0, import_server7.getAuthenticatedUserCore)(request);
112
+ if (!(0, import_server6.isErrorResult)(userResult)) {
113
+ clearSubscriptionCache(userResult.userId);
114
+ }
115
+ } catch {
116
+ }
117
+ return result;
118
+ }
119
+
120
+ // src/helpers/checkout.ts
121
+ var import_server8 = require("next/server");
122
+ var import_server9 = require("@solvapay/server");
123
+ async function createCheckoutSession(request, body, options = {}) {
124
+ const result = await (0, import_server9.createCheckoutSessionCore)(request, body, options);
125
+ if ((0, import_server9.isErrorResult)(result)) {
126
+ return import_server8.NextResponse.json(
127
+ { error: result.error, details: result.details },
128
+ { status: result.status }
129
+ );
130
+ }
131
+ return result;
132
+ }
133
+ async function createCustomerSession(request, options = {}) {
134
+ const result = await (0, import_server9.createCustomerSessionCore)(request, options);
135
+ if ((0, import_server9.isErrorResult)(result)) {
136
+ return import_server8.NextResponse.json(
137
+ { error: result.error, details: result.details },
138
+ { status: result.status }
139
+ );
140
+ }
141
+ return result;
142
+ }
143
+
144
+ // src/helpers/subscription.ts
145
+ var import_server10 = require("next/server");
146
+ var import_server11 = require("@solvapay/server");
147
+ var import_server12 = require("@solvapay/server");
148
+ async function cancelSubscription(request, body, options = {}) {
149
+ const result = await (0, import_server11.cancelSubscriptionCore)(request, body, options);
150
+ if ((0, import_server11.isErrorResult)(result)) {
151
+ return import_server10.NextResponse.json(
152
+ { error: result.error, details: result.details },
153
+ { status: result.status }
154
+ );
155
+ }
156
+ try {
157
+ const userResult = await (0, import_server12.getAuthenticatedUserCore)(request);
158
+ if (!(0, import_server11.isErrorResult)(userResult)) {
159
+ clearSubscriptionCache(userResult.userId);
160
+ }
161
+ } catch {
162
+ }
163
+ return result;
164
+ }
165
+
166
+ // src/helpers/plans.ts
167
+ var import_server13 = require("next/server");
168
+ var import_server14 = require("@solvapay/server");
169
+ async function listPlans(request) {
170
+ const result = await (0, import_server14.listPlansCore)(request);
171
+ if ((0, import_server14.isErrorResult)(result)) {
172
+ return import_server13.NextResponse.json(
173
+ { error: result.error, details: result.details },
174
+ { status: result.status }
175
+ );
176
+ }
177
+ return result;
178
+ }
179
+
180
+ // src/helpers/middleware.ts
181
+ var import_server15 = require("next/server");
182
+ function createAuthMiddleware(options) {
183
+ const {
184
+ adapter,
185
+ publicRoutes = [],
186
+ userIdHeader = "x-user-id"
187
+ } = options;
188
+ return async function middleware(request) {
189
+ const { pathname } = request.nextUrl;
190
+ if (!pathname.startsWith("/api")) {
191
+ return import_server15.NextResponse.next();
192
+ }
193
+ const isPublicRoute = publicRoutes.some((route) => pathname.startsWith(route));
194
+ const userId = await adapter.getUserIdFromRequest(request);
195
+ if (isPublicRoute) {
196
+ const requestHeaders2 = new Headers(request.headers);
197
+ if (userId) {
198
+ requestHeaders2.set(userIdHeader, userId);
199
+ }
200
+ return import_server15.NextResponse.next({
201
+ request: {
202
+ headers: requestHeaders2
203
+ }
204
+ });
205
+ }
206
+ if (!userId) {
207
+ return import_server15.NextResponse.json(
208
+ { error: "Unauthorized", details: "Valid authentication required" },
209
+ { status: 401 }
210
+ );
211
+ }
212
+ const requestHeaders = new Headers(request.headers);
213
+ requestHeaders.set(userIdHeader, userId);
214
+ return import_server15.NextResponse.next({
215
+ request: {
216
+ headers: requestHeaders
217
+ }
218
+ });
219
+ };
220
+ }
221
+ function createSupabaseAuthMiddleware(options = {}) {
222
+ const {
223
+ jwtSecret,
224
+ publicRoutes = [],
225
+ userIdHeader = "x-user-id"
226
+ } = options;
227
+ let authAdapter = null;
228
+ let adapterPromise = null;
229
+ const lazyAdapter = {
230
+ async getUserIdFromRequest(req) {
231
+ if (!authAdapter) {
232
+ if (!adapterPromise) {
233
+ adapterPromise = (async () => {
234
+ const secret = jwtSecret || process.env.SUPABASE_JWT_SECRET;
235
+ if (!secret) {
236
+ throw new Error(
237
+ "SUPABASE_JWT_SECRET environment variable is required. Please set it in your .env.local file. Get it from: Supabase Dashboard \u2192 Settings \u2192 API \u2192 JWT Secret"
238
+ );
239
+ }
240
+ const { SupabaseAuthAdapter } = await import("@solvapay/auth/supabase");
241
+ authAdapter = new SupabaseAuthAdapter({ jwtSecret: secret });
242
+ return authAdapter;
243
+ })();
244
+ }
245
+ authAdapter = await adapterPromise;
246
+ }
247
+ return authAdapter.getUserIdFromRequest(req);
248
+ }
249
+ };
250
+ return createAuthMiddleware({
251
+ adapter: lazyAdapter,
252
+ publicRoutes,
253
+ userIdHeader
254
+ });
255
+ }
256
+
257
+ // src/index.ts
258
+ function createRequestDeduplicator(options = {}) {
259
+ const {
260
+ cacheTTL = 2e3,
261
+ maxCacheSize = 1e3,
262
+ cacheErrors = true
263
+ } = options;
264
+ const inFlightRequests = /* @__PURE__ */ new Map();
265
+ const resultCache = /* @__PURE__ */ new Map();
266
+ const cacheInvalidatedAt = /* @__PURE__ */ new Map();
267
+ let cleanupInterval = null;
268
+ if (cacheTTL > 0) {
269
+ cleanupInterval = setInterval(() => {
270
+ const now = Date.now();
271
+ const entriesToDelete = [];
272
+ for (const [key, cached] of resultCache.entries()) {
273
+ if (now - cached.timestamp >= cacheTTL) {
274
+ entriesToDelete.push(key);
275
+ }
276
+ }
277
+ for (const key of entriesToDelete) {
278
+ resultCache.delete(key);
279
+ cacheInvalidatedAt.delete(key);
280
+ }
281
+ if (resultCache.size > maxCacheSize) {
282
+ const sortedEntries = Array.from(resultCache.entries()).sort((a, b) => a[1].timestamp - b[1].timestamp);
283
+ const toRemove = sortedEntries.slice(0, resultCache.size - maxCacheSize);
284
+ for (const [key] of toRemove) {
285
+ resultCache.delete(key);
286
+ cacheInvalidatedAt.delete(key);
287
+ }
288
+ }
289
+ }, Math.min(cacheTTL, 1e3));
290
+ }
291
+ const deduplicate = async (key, fn) => {
292
+ if (cacheTTL > 0) {
293
+ const cached = resultCache.get(key);
294
+ if (cached && Date.now() - cached.timestamp < cacheTTL) {
295
+ return cached.data;
296
+ } else if (cached) {
297
+ resultCache.delete(key);
298
+ }
299
+ }
300
+ let requestPromise = inFlightRequests.get(key);
301
+ if (!requestPromise) {
302
+ const requestStartTime = Date.now();
303
+ requestPromise = (async () => {
304
+ try {
305
+ const result = await fn();
306
+ const invalidatedAt = cacheInvalidatedAt.get(key);
307
+ const shouldCache = !invalidatedAt || invalidatedAt < requestStartTime;
308
+ if (cacheTTL > 0 && shouldCache) {
309
+ resultCache.set(key, {
310
+ data: result,
311
+ timestamp: Date.now()
312
+ });
313
+ }
314
+ return result;
315
+ } catch (error) {
316
+ const invalidatedAt = cacheInvalidatedAt.get(key);
317
+ const shouldCache = !invalidatedAt || invalidatedAt < requestStartTime;
318
+ if (cacheTTL > 0 && cacheErrors && shouldCache) {
319
+ resultCache.set(key, {
320
+ data: error,
321
+ timestamp: Date.now()
322
+ });
323
+ }
324
+ throw error;
325
+ } finally {
326
+ inFlightRequests.delete(key);
327
+ }
328
+ })();
329
+ const existingPromise = inFlightRequests.get(key);
330
+ if (existingPromise) {
331
+ requestPromise = existingPromise;
332
+ } else {
333
+ inFlightRequests.set(key, requestPromise);
334
+ }
335
+ }
336
+ return requestPromise;
337
+ };
338
+ const clearCache = (key) => {
339
+ resultCache.delete(key);
340
+ cacheInvalidatedAt.set(key, Date.now());
341
+ inFlightRequests.delete(key);
342
+ };
343
+ const clearAllCache = () => {
344
+ resultCache.clear();
345
+ cacheInvalidatedAt.clear();
346
+ inFlightRequests.clear();
347
+ };
348
+ const getStats = () => ({
349
+ inFlight: inFlightRequests.size,
350
+ cached: resultCache.size
351
+ });
352
+ return {
353
+ deduplicate,
354
+ clearCache,
355
+ clearAllCache,
356
+ getStats
357
+ };
358
+ }
359
+ var sharedSubscriptionDeduplicator = null;
360
+ function getSharedDeduplicator(options) {
361
+ if (!sharedSubscriptionDeduplicator) {
362
+ sharedSubscriptionDeduplicator = createRequestDeduplicator({
363
+ cacheTTL: 2e3,
364
+ // Cache results for 2 seconds
365
+ maxCacheSize: 1e3,
366
+ // Maximum cache entries
367
+ cacheErrors: true,
368
+ // Cache error results too
369
+ ...options
370
+ });
371
+ }
372
+ return sharedSubscriptionDeduplicator;
373
+ }
374
+ async function checkSubscription(request, options = {}) {
375
+ try {
376
+ const { requireUserId, getUserEmailFromRequest, getUserNameFromRequest } = await import("@solvapay/auth");
377
+ const userIdOrError = requireUserId(request);
378
+ if (userIdOrError instanceof Response) {
379
+ const clonedResponse = userIdOrError.clone();
380
+ const body = await clonedResponse.json().catch(() => ({ error: "Unauthorized" }));
381
+ return import_server16.NextResponse.json(body, { status: userIdOrError.status });
382
+ }
383
+ const userId = userIdOrError;
384
+ const email = options.includeEmail !== false ? await getUserEmailFromRequest(request) : null;
385
+ const name = options.includeName !== false ? await getUserNameFromRequest(request) : null;
386
+ const cachedCustomerRef = request.headers.get("x-solvapay-customer-ref");
387
+ const solvaPay = options.solvaPay || (0, import_server17.createSolvaPay)();
388
+ if (cachedCustomerRef) {
389
+ try {
390
+ const customer = await solvaPay.getCustomer({ customerRef: cachedCustomerRef });
391
+ if (customer && customer.customerRef) {
392
+ if (customer.externalRef && customer.externalRef === userId) {
393
+ const filteredSubscriptions = (customer.subscriptions || []).filter(
394
+ (sub) => sub.status === "active"
395
+ );
396
+ return {
397
+ customerRef: customer.customerRef,
398
+ email: customer.email,
399
+ name: customer.name,
400
+ subscriptions: filteredSubscriptions
401
+ };
402
+ }
403
+ }
404
+ } catch (error) {
405
+ }
406
+ }
407
+ const deduplicator = getSharedDeduplicator(options.deduplication);
408
+ const response = await deduplicator.deduplicate(userId, async () => {
409
+ try {
410
+ const ensuredCustomerRef = await solvaPay.ensureCustomer(userId, userId, {
411
+ email: email || void 0,
412
+ name: name || void 0
413
+ });
414
+ const customer = await solvaPay.getCustomer({ customerRef: ensuredCustomerRef });
415
+ const filteredSubscriptions = (customer.subscriptions || []).filter(
416
+ (sub) => sub.status === "active"
417
+ );
418
+ const result = {
419
+ customerRef: customer.customerRef || userId,
420
+ email: customer.email,
421
+ name: customer.name,
422
+ subscriptions: filteredSubscriptions
423
+ };
424
+ return result;
425
+ } catch (error) {
426
+ console.error("[checkSubscription] Error fetching customer:", error);
427
+ return {
428
+ customerRef: userId,
429
+ subscriptions: []
430
+ };
431
+ }
432
+ });
433
+ return response;
434
+ } catch (error) {
435
+ console.error("Check subscription failed:", error);
436
+ if (error instanceof import_core.SolvaPayError) {
437
+ return import_server16.NextResponse.json(
438
+ { error: error.message },
439
+ { status: 500 }
440
+ );
441
+ }
442
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
443
+ return import_server16.NextResponse.json(
444
+ { error: "Failed to check subscription", details: errorMessage },
445
+ { status: 500 }
446
+ );
447
+ }
448
+ }
449
+ function clearSubscriptionCache(userId) {
450
+ const deduplicator = getSharedDeduplicator();
451
+ deduplicator.clearCache(userId);
452
+ }
453
+ function clearAllSubscriptionCache() {
454
+ const deduplicator = getSharedDeduplicator();
455
+ deduplicator.clearAllCache();
456
+ }
457
+ function getSubscriptionCacheStats() {
458
+ const deduplicator = getSharedDeduplicator();
459
+ return deduplicator.getStats();
460
+ }
461
+ // Annotate the CommonJS export names for ESM import in node:
462
+ 0 && (module.exports = {
463
+ cancelSubscription,
464
+ checkSubscription,
465
+ clearAllSubscriptionCache,
466
+ clearSubscriptionCache,
467
+ createAuthMiddleware,
468
+ createCheckoutSession,
469
+ createCustomerSession,
470
+ createPaymentIntent,
471
+ createSupabaseAuthMiddleware,
472
+ getAuthenticatedUser,
473
+ getSubscriptionCacheStats,
474
+ listPlans,
475
+ processPayment,
476
+ syncCustomer
477
+ });