@windrun-huaiin/backend-core 10.0.1

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.
Files changed (198) hide show
  1. package/LICENSE +21 -0
  2. package/dist/app/api/stripe/checkout/route.d.ts +19 -0
  3. package/dist/app/api/stripe/checkout/route.d.ts.map +1 -0
  4. package/dist/app/api/stripe/checkout/route.js +120 -0
  5. package/dist/app/api/stripe/checkout/route.mjs +118 -0
  6. package/dist/app/api/stripe/customer-portal/route.d.ts +11 -0
  7. package/dist/app/api/stripe/customer-portal/route.d.ts.map +1 -0
  8. package/dist/app/api/stripe/customer-portal/route.js +73 -0
  9. package/dist/app/api/stripe/customer-portal/route.mjs +71 -0
  10. package/dist/app/api/user/anonymous/init/route.d.ts +7 -0
  11. package/dist/app/api/user/anonymous/init/route.d.ts.map +1 -0
  12. package/dist/app/api/user/anonymous/init/route.js +210 -0
  13. package/dist/app/api/user/anonymous/init/route.mjs +208 -0
  14. package/dist/app/api/webhook/clerk/user/route.d.ts +7 -0
  15. package/dist/app/api/webhook/clerk/user/route.d.ts.map +1 -0
  16. package/dist/app/api/webhook/clerk/user/route.js +202 -0
  17. package/dist/app/api/webhook/clerk/user/route.mjs +200 -0
  18. package/dist/app/api/webhook/stripe/route.d.ts +8 -0
  19. package/dist/app/api/webhook/stripe/route.d.ts.map +1 -0
  20. package/dist/app/api/webhook/stripe/route.js +70 -0
  21. package/dist/app/api/webhook/stripe/route.mjs +67 -0
  22. package/dist/index.d.ts +7 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +83 -0
  25. package/dist/index.mjs +18 -0
  26. package/dist/lib/auth-utils.d.ts +46 -0
  27. package/dist/lib/auth-utils.d.ts.map +1 -0
  28. package/dist/lib/auth-utils.js +107 -0
  29. package/dist/lib/auth-utils.mjs +102 -0
  30. package/dist/lib/credit-init.d.ts +8 -0
  31. package/dist/lib/credit-init.d.ts.map +1 -0
  32. package/dist/lib/credit-init.js +16 -0
  33. package/dist/lib/credit-init.mjs +10 -0
  34. package/dist/lib/index.d.ts +5 -0
  35. package/dist/lib/index.d.ts.map +1 -0
  36. package/dist/lib/index.js +31 -0
  37. package/dist/lib/index.mjs +4 -0
  38. package/dist/lib/money-price-config.d.ts +51 -0
  39. package/dist/lib/money-price-config.d.ts.map +1 -0
  40. package/dist/lib/money-price-config.js +156 -0
  41. package/dist/lib/money-price-config.mjs +151 -0
  42. package/dist/lib/stripe-config.d.ts +31 -0
  43. package/dist/lib/stripe-config.d.ts.map +1 -0
  44. package/dist/lib/stripe-config.js +278 -0
  45. package/dist/lib/stripe-config.mjs +268 -0
  46. package/dist/node_modules/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.46.2_tslib@2.8.1_typescript@5.9.3/node_modules/tslib/tslib.es6.js +48 -0
  47. package/dist/node_modules/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.46.2_tslib@2.8.1_typescript@5.9.3/node_modules/tslib/tslib.es6.mjs +45 -0
  48. package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/classic/errors.js +54 -0
  49. package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/classic/errors.mjs +51 -0
  50. package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/classic/iso.js +44 -0
  51. package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/classic/iso.mjs +35 -0
  52. package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/classic/parse.js +31 -0
  53. package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/classic/parse.mjs +18 -0
  54. package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/classic/schemas.js +587 -0
  55. package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/classic/schemas.mjs +527 -0
  56. package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/api.js +447 -0
  57. package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/api.mjs +399 -0
  58. package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/checks.js +245 -0
  59. package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/checks.mjs +232 -0
  60. package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/core.js +68 -0
  61. package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/core.mjs +62 -0
  62. package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/doc.js +39 -0
  63. package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/doc.mjs +37 -0
  64. package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/errors.js +80 -0
  65. package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/errors.mjs +75 -0
  66. package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/parse.js +101 -0
  67. package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/parse.mjs +86 -0
  68. package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/regexes.js +102 -0
  69. package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/regexes.mjs +76 -0
  70. package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/registries.js +56 -0
  71. package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/registries.mjs +52 -0
  72. package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/schemas.js +1205 -0
  73. package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/schemas.mjs +1157 -0
  74. package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/util.js +407 -0
  75. package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/util.mjs +374 -0
  76. package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/versions.js +9 -0
  77. package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/versions.mjs +7 -0
  78. package/dist/prisma/client.d.ts +2 -0
  79. package/dist/prisma/client.d.ts.map +1 -0
  80. package/dist/prisma/client.js +12 -0
  81. package/dist/prisma/client.mjs +1 -0
  82. package/dist/prisma/index.d.ts +4 -0
  83. package/dist/prisma/index.d.ts.map +1 -0
  84. package/dist/prisma/index.js +10 -0
  85. package/dist/prisma/index.mjs +2 -0
  86. package/dist/prisma/prisma-transaction-util.d.ts +3 -0
  87. package/dist/prisma/prisma-transaction-util.d.ts.map +1 -0
  88. package/dist/prisma/prisma-transaction-util.js +29 -0
  89. package/dist/prisma/prisma-transaction-util.mjs +27 -0
  90. package/dist/prisma/prisma.d.ts +4 -0
  91. package/dist/prisma/prisma.d.ts.map +1 -0
  92. package/dist/prisma/prisma.js +109 -0
  93. package/dist/prisma/prisma.mjs +106 -0
  94. package/dist/services/aggregate/billing.aggregate.service.d.ts +83 -0
  95. package/dist/services/aggregate/billing.aggregate.service.d.ts.map +1 -0
  96. package/dist/services/aggregate/billing.aggregate.service.js +308 -0
  97. package/dist/services/aggregate/billing.aggregate.service.mjs +306 -0
  98. package/dist/services/aggregate/index.d.ts +3 -0
  99. package/dist/services/aggregate/index.d.ts.map +1 -0
  100. package/dist/services/aggregate/index.js +9 -0
  101. package/dist/services/aggregate/index.mjs +2 -0
  102. package/dist/services/aggregate/user.aggregate.service.d.ts +34 -0
  103. package/dist/services/aggregate/user.aggregate.service.d.ts.map +1 -0
  104. package/dist/services/aggregate/user.aggregate.service.js +136 -0
  105. package/dist/services/aggregate/user.aggregate.service.mjs +133 -0
  106. package/dist/services/context/index.d.ts +2 -0
  107. package/dist/services/context/index.d.ts.map +1 -0
  108. package/dist/services/context/index.js +13 -0
  109. package/dist/services/context/index.mjs +1 -0
  110. package/dist/services/context/user-context-service.d.ts +30 -0
  111. package/dist/services/context/user-context-service.d.ts.map +1 -0
  112. package/dist/services/context/user-context-service.js +170 -0
  113. package/dist/services/context/user-context-service.mjs +162 -0
  114. package/dist/services/database/apilog.service.d.ts +39 -0
  115. package/dist/services/database/apilog.service.d.ts.map +1 -0
  116. package/dist/services/database/apilog.service.js +174 -0
  117. package/dist/services/database/apilog.service.mjs +170 -0
  118. package/dist/services/database/constants.d.ts +73 -0
  119. package/dist/services/database/constants.d.ts.map +1 -0
  120. package/dist/services/database/constants.js +135 -0
  121. package/dist/services/database/constants.mjs +117 -0
  122. package/dist/services/database/credit.service.d.ts +107 -0
  123. package/dist/services/database/credit.service.d.ts.map +1 -0
  124. package/dist/services/database/credit.service.js +515 -0
  125. package/dist/services/database/credit.service.mjs +512 -0
  126. package/dist/services/database/creditAuditLog.service.d.ts +73 -0
  127. package/dist/services/database/creditAuditLog.service.d.ts.map +1 -0
  128. package/dist/services/database/creditAuditLog.service.js +305 -0
  129. package/dist/services/database/creditAuditLog.service.mjs +302 -0
  130. package/dist/services/database/index.d.ts +10 -0
  131. package/dist/services/database/index.d.ts.map +1 -0
  132. package/dist/services/database/index.js +38 -0
  133. package/dist/services/database/index.mjs +8 -0
  134. package/dist/services/database/prisma-model-type.d.ts +3 -0
  135. package/dist/services/database/prisma-model-type.d.ts.map +1 -0
  136. package/dist/services/database/subscription.service.d.ts +48 -0
  137. package/dist/services/database/subscription.service.d.ts.map +1 -0
  138. package/dist/services/database/subscription.service.js +267 -0
  139. package/dist/services/database/subscription.service.mjs +264 -0
  140. package/dist/services/database/transaction.service.d.ts +92 -0
  141. package/dist/services/database/transaction.service.d.ts.map +1 -0
  142. package/dist/services/database/transaction.service.js +326 -0
  143. package/dist/services/database/transaction.service.mjs +323 -0
  144. package/dist/services/database/user.service.d.ts +45 -0
  145. package/dist/services/database/user.service.d.ts.map +1 -0
  146. package/dist/services/database/user.service.js +180 -0
  147. package/dist/services/database/user.service.mjs +177 -0
  148. package/dist/services/database/userBackup.service.d.ts +45 -0
  149. package/dist/services/database/userBackup.service.d.ts.map +1 -0
  150. package/dist/services/database/userBackup.service.js +249 -0
  151. package/dist/services/database/userBackup.service.mjs +246 -0
  152. package/dist/services/stripe/index.d.ts +2 -0
  153. package/dist/services/stripe/index.d.ts.map +1 -0
  154. package/dist/services/stripe/index.js +7 -0
  155. package/dist/services/stripe/index.mjs +1 -0
  156. package/dist/services/stripe/webhook-handler.d.ts +6 -0
  157. package/dist/services/stripe/webhook-handler.d.ts.map +1 -0
  158. package/dist/services/stripe/webhook-handler.js +537 -0
  159. package/dist/services/stripe/webhook-handler.mjs +535 -0
  160. package/migrations/create.sql +176 -0
  161. package/migrations/db.init.sql +13 -0
  162. package/migrations/init-schema.sql +19 -0
  163. package/migrations/purge.sql +27 -0
  164. package/migrations/test-check.sql +167 -0
  165. package/package.json +123 -0
  166. package/prisma/schema.prisma +191 -0
  167. package/src/app/api/stripe/checkout/route.ts +145 -0
  168. package/src/app/api/stripe/customer-portal/route.ts +83 -0
  169. package/src/app/api/user/anonymous/init/route.ts +284 -0
  170. package/src/app/api/webhook/clerk/user/route.ts +249 -0
  171. package/src/app/api/webhook/stripe/route.ts +93 -0
  172. package/src/index.ts +6 -0
  173. package/src/lib/auth-utils.ts +101 -0
  174. package/src/lib/credit-init.ts +9 -0
  175. package/src/lib/index.ts +4 -0
  176. package/src/lib/money-price-config.ts +168 -0
  177. package/src/lib/stripe-config.ts +333 -0
  178. package/src/prisma/client.ts +2 -0
  179. package/src/prisma/index.ts +3 -0
  180. package/src/prisma/prisma-transaction-util.ts +24 -0
  181. package/src/prisma/prisma.ts +122 -0
  182. package/src/services/aggregate/billing.aggregate.service.ts +498 -0
  183. package/src/services/aggregate/index.ts +2 -0
  184. package/src/services/aggregate/user.aggregate.service.ts +168 -0
  185. package/src/services/context/index.ts +1 -0
  186. package/src/services/context/user-context-service.ts +200 -0
  187. package/src/services/database/apilog.service.ts +185 -0
  188. package/src/services/database/constants.ts +148 -0
  189. package/src/services/database/credit.service.ts +747 -0
  190. package/src/services/database/creditAuditLog.service.ts +402 -0
  191. package/src/services/database/index.ts +41 -0
  192. package/src/services/database/prisma-model-type.ts +13 -0
  193. package/src/services/database/subscription.service.ts +319 -0
  194. package/src/services/database/transaction.service.ts +447 -0
  195. package/src/services/database/user.service.ts +218 -0
  196. package/src/services/database/userBackup.service.ts +290 -0
  197. package/src/services/stripe/index.ts +1 -0
  198. package/src/services/stripe/webhook-handler.ts +648 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 D8ger
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,19 @@
1
+ import { NextRequest, NextResponse } from 'next/server';
2
+ export declare function POST(request: NextRequest): Promise<NextResponse<{
3
+ error: string;
4
+ }> | NextResponse<{
5
+ success: boolean;
6
+ data: {
7
+ sessionId: string;
8
+ sessionUrl: string | null;
9
+ orderId: string;
10
+ priceConfig: {
11
+ priceName: string;
12
+ amount: number;
13
+ currency: string;
14
+ credits: number | undefined;
15
+ description: string;
16
+ };
17
+ };
18
+ }>>;
19
+ //# sourceMappingURL=route.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../src/app/api/stripe/checkout/route.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAyBxD,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW;;;;;;;;;;;;;;;;IAuH9C"}
@@ -0,0 +1,120 @@
1
+ 'use strict';
2
+
3
+ var tslib_es6 = require('../../../../node_modules/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.46.2_tslib@2.8.1_typescript@5.9.3/node_modules/tslib/tslib.es6.js');
4
+ var server = require('next/server');
5
+ var zod = require('zod');
6
+ var stripeConfig = require('../../../../lib/stripe-config.js');
7
+ var constants = require('../../../../services/database/constants.js');
8
+ require('../../../../prisma/prisma.js');
9
+ require('../../../../services/database/credit.service.js');
10
+ var transaction_service = require('../../../../services/database/transaction.service.js');
11
+ require('@prisma/client');
12
+ var authUtils = require('../../../../lib/auth-utils.js');
13
+ var moneyPriceConfig = require('../../../../lib/money-price-config.js');
14
+
15
+ // Request validation schema
16
+ const createCheckoutSchema = zod.z.object({
17
+ priceId: zod.z.string().min(1, 'PriceID is required'),
18
+ plan: zod.z.string().min(1, 'Plan is required'),
19
+ billingType: zod.z.string().min(1, 'BillingType is required'),
20
+ provider: zod.z.string().min(1, 'Provider is required'),
21
+ });
22
+ function POST(request) {
23
+ return tslib_es6.__awaiter(this, void 0, void 0, function* () {
24
+ var _a;
25
+ try {
26
+ // Parse request body
27
+ const body = yield request.json();
28
+ const { priceId, plan, billingType, provider } = createCheckoutSchema.parse(body);
29
+ console.log(`Create Checkout: ${priceId} | ${plan} | ${billingType} | ${provider}`);
30
+ // Use unified authentication to get user info
31
+ const authUtils$1 = new authUtils.ApiAuthUtils(request);
32
+ const { user } = yield authUtils$1.requireAuthWithUser();
33
+ // Validate price configuration
34
+ const priceConfig = moneyPriceConfig.getPriceConfig(priceId, plan, billingType, provider);
35
+ if (!priceConfig) {
36
+ return server.NextResponse.json({ error: 'Invalid price configuration' }, { status: 400 });
37
+ }
38
+ // Create or get Stripe customer
39
+ const customerId = yield stripeConfig.createOrGetCustomer({
40
+ userId: user.userId,
41
+ });
42
+ // Generate order ID
43
+ const orderId = `order_${Date.now()}_${Math.random().toString(36).substring(2)}`;
44
+ // Default URLs if not provided
45
+ const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || 'http://localhost:3000';
46
+ const defaultSuccessUrl = `${baseUrl}`;
47
+ const defaultCancelUrl = `${baseUrl}`;
48
+ // Create Stripe checkout session with interval for dynamic mode
49
+ const basciParams = {
50
+ priceId,
51
+ customerId,
52
+ clientReferenceId: user.userId,
53
+ successUrl: defaultSuccessUrl,
54
+ cancelUrl: defaultCancelUrl,
55
+ interval: priceConfig.interval, // ✅ Pass interval to auto-determine mode
56
+ metadata: {
57
+ order_id: orderId,
58
+ user_id: user.userId,
59
+ price_name: priceConfig.priceName,
60
+ credits_granted: ((_a = priceConfig.credits) === null || _a === void 0 ? void 0 : _a.toString()) || '',
61
+ }
62
+ };
63
+ const subscriptionData = {
64
+ metadata: {
65
+ order_id: orderId,
66
+ user_id: user.userId,
67
+ },
68
+ };
69
+ const session = yield stripeConfig.createCheckoutSession(basciParams, subscriptionData);
70
+ // Create transaction record with session info
71
+ const orderType = priceConfig.interval && priceConfig.interval !== 'onetime' ? constants.TransactionType.SUBSCRIPTION : constants.TransactionType.ONE_TIME;
72
+ yield transaction_service.transactionService.createTransaction({
73
+ userId: user.userId,
74
+ orderId,
75
+ orderStatus: constants.OrderStatus.CREATED,
76
+ paymentStatus: constants.PaymentStatus.UN_PAID,
77
+ paySupplier: constants.PaySupplier.STRIPE,
78
+ paySessionId: session.id,
79
+ priceId,
80
+ priceName: priceConfig.priceName,
81
+ amount: priceConfig.amount,
82
+ currency: priceConfig.currency,
83
+ type: orderType,
84
+ creditsGranted: priceConfig.credits,
85
+ orderDetail: priceConfig.description,
86
+ paidEmail: null
87
+ });
88
+ return server.NextResponse.json({
89
+ success: true,
90
+ data: {
91
+ sessionId: session.id,
92
+ sessionUrl: session.url,
93
+ orderId,
94
+ priceConfig: {
95
+ priceName: priceConfig.priceName,
96
+ amount: priceConfig.amount,
97
+ currency: priceConfig.currency,
98
+ credits: priceConfig.credits,
99
+ description: priceConfig.description,
100
+ },
101
+ },
102
+ });
103
+ }
104
+ catch (error) {
105
+ console.error('Create checkout error:', error);
106
+ if (error instanceof stripeConfig.ActiveSubscriptionExistsError) {
107
+ return server.NextResponse.json({
108
+ error: 'Active subscription exists',
109
+ detail: 'Please use the customer portal to manage your existing subscription.',
110
+ }, { status: 409 });
111
+ }
112
+ if (error instanceof zod.z.ZodError) {
113
+ return server.NextResponse.json({ error: 'Validation error', details: error.issues }, { status: 400 });
114
+ }
115
+ return server.NextResponse.json({ error: 'Failed to create checkout session' }, { status: 500 });
116
+ }
117
+ });
118
+ }
119
+
120
+ exports.POST = POST;
@@ -0,0 +1,118 @@
1
+ import { __awaiter } from '../../../../node_modules/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.46.2_tslib@2.8.1_typescript@5.9.3/node_modules/tslib/tslib.es6.mjs';
2
+ import { NextResponse } from 'next/server';
3
+ import { z } from 'zod';
4
+ import { createOrGetCustomer, createCheckoutSession, ActiveSubscriptionExistsError } from '../../../../lib/stripe-config.mjs';
5
+ import { TransactionType, PaySupplier, PaymentStatus, OrderStatus } from '../../../../services/database/constants.mjs';
6
+ import '../../../../prisma/prisma.mjs';
7
+ import '../../../../services/database/credit.service.mjs';
8
+ import { transactionService } from '../../../../services/database/transaction.service.mjs';
9
+ import '@prisma/client';
10
+ import { ApiAuthUtils } from '../../../../lib/auth-utils.mjs';
11
+ import { getPriceConfig } from '../../../../lib/money-price-config.mjs';
12
+
13
+ // Request validation schema
14
+ const createCheckoutSchema = z.object({
15
+ priceId: z.string().min(1, 'PriceID is required'),
16
+ plan: z.string().min(1, 'Plan is required'),
17
+ billingType: z.string().min(1, 'BillingType is required'),
18
+ provider: z.string().min(1, 'Provider is required'),
19
+ });
20
+ function POST(request) {
21
+ return __awaiter(this, void 0, void 0, function* () {
22
+ var _a;
23
+ try {
24
+ // Parse request body
25
+ const body = yield request.json();
26
+ const { priceId, plan, billingType, provider } = createCheckoutSchema.parse(body);
27
+ console.log(`Create Checkout: ${priceId} | ${plan} | ${billingType} | ${provider}`);
28
+ // Use unified authentication to get user info
29
+ const authUtils = new ApiAuthUtils(request);
30
+ const { user } = yield authUtils.requireAuthWithUser();
31
+ // Validate price configuration
32
+ const priceConfig = getPriceConfig(priceId, plan, billingType, provider);
33
+ if (!priceConfig) {
34
+ return NextResponse.json({ error: 'Invalid price configuration' }, { status: 400 });
35
+ }
36
+ // Create or get Stripe customer
37
+ const customerId = yield createOrGetCustomer({
38
+ userId: user.userId,
39
+ });
40
+ // Generate order ID
41
+ const orderId = `order_${Date.now()}_${Math.random().toString(36).substring(2)}`;
42
+ // Default URLs if not provided
43
+ const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || 'http://localhost:3000';
44
+ const defaultSuccessUrl = `${baseUrl}`;
45
+ const defaultCancelUrl = `${baseUrl}`;
46
+ // Create Stripe checkout session with interval for dynamic mode
47
+ const basciParams = {
48
+ priceId,
49
+ customerId,
50
+ clientReferenceId: user.userId,
51
+ successUrl: defaultSuccessUrl,
52
+ cancelUrl: defaultCancelUrl,
53
+ interval: priceConfig.interval, // ✅ Pass interval to auto-determine mode
54
+ metadata: {
55
+ order_id: orderId,
56
+ user_id: user.userId,
57
+ price_name: priceConfig.priceName,
58
+ credits_granted: ((_a = priceConfig.credits) === null || _a === void 0 ? void 0 : _a.toString()) || '',
59
+ }
60
+ };
61
+ const subscriptionData = {
62
+ metadata: {
63
+ order_id: orderId,
64
+ user_id: user.userId,
65
+ },
66
+ };
67
+ const session = yield createCheckoutSession(basciParams, subscriptionData);
68
+ // Create transaction record with session info
69
+ const orderType = priceConfig.interval && priceConfig.interval !== 'onetime' ? TransactionType.SUBSCRIPTION : TransactionType.ONE_TIME;
70
+ yield transactionService.createTransaction({
71
+ userId: user.userId,
72
+ orderId,
73
+ orderStatus: OrderStatus.CREATED,
74
+ paymentStatus: PaymentStatus.UN_PAID,
75
+ paySupplier: PaySupplier.STRIPE,
76
+ paySessionId: session.id,
77
+ priceId,
78
+ priceName: priceConfig.priceName,
79
+ amount: priceConfig.amount,
80
+ currency: priceConfig.currency,
81
+ type: orderType,
82
+ creditsGranted: priceConfig.credits,
83
+ orderDetail: priceConfig.description,
84
+ paidEmail: null
85
+ });
86
+ return NextResponse.json({
87
+ success: true,
88
+ data: {
89
+ sessionId: session.id,
90
+ sessionUrl: session.url,
91
+ orderId,
92
+ priceConfig: {
93
+ priceName: priceConfig.priceName,
94
+ amount: priceConfig.amount,
95
+ currency: priceConfig.currency,
96
+ credits: priceConfig.credits,
97
+ description: priceConfig.description,
98
+ },
99
+ },
100
+ });
101
+ }
102
+ catch (error) {
103
+ console.error('Create checkout error:', error);
104
+ if (error instanceof ActiveSubscriptionExistsError) {
105
+ return NextResponse.json({
106
+ error: 'Active subscription exists',
107
+ detail: 'Please use the customer portal to manage your existing subscription.',
108
+ }, { status: 409 });
109
+ }
110
+ if (error instanceof z.ZodError) {
111
+ return NextResponse.json({ error: 'Validation error', details: error.issues }, { status: 400 });
112
+ }
113
+ return NextResponse.json({ error: 'Failed to create checkout session' }, { status: 500 });
114
+ }
115
+ });
116
+ }
117
+
118
+ export { POST };
@@ -0,0 +1,11 @@
1
+ import { NextRequest, NextResponse } from 'next/server';
2
+ export declare function POST(request: NextRequest): Promise<NextResponse<{
3
+ error: string;
4
+ }> | NextResponse<{
5
+ success: boolean;
6
+ data: {
7
+ sessionId: string;
8
+ sessionUrl: string;
9
+ };
10
+ }>>;
11
+ //# sourceMappingURL=route.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../src/app/api/stripe/customer-portal/route.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAexD,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW;;;;;;;;IAmD9C"}
@@ -0,0 +1,73 @@
1
+ 'use strict';
2
+
3
+ var tslib_es6 = require('../../../../node_modules/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.46.2_tslib@2.8.1_typescript@5.9.3/node_modules/tslib/tslib.es6.js');
4
+ var server = require('next/server');
5
+ var zod = require('zod');
6
+ var stripeConfig = require('../../../../lib/stripe-config.js');
7
+ var authUtils = require('../../../../lib/auth-utils.js');
8
+ require('../../../../prisma/prisma.js');
9
+ var subscription_service = require('../../../../services/database/subscription.service.js');
10
+ require('../../../../services/database/credit.service.js');
11
+ require('@prisma/client');
12
+
13
+ const createCustomerPortalSchema = zod.z
14
+ .object({
15
+ returnUrl: zod.z.string().min(1).optional(),
16
+ })
17
+ .optional();
18
+ function POST(request) {
19
+ return tslib_es6.__awaiter(this, void 0, void 0, function* () {
20
+ try {
21
+ const body = yield request.json().catch(() => ({}));
22
+ const parsed = createCustomerPortalSchema.parse(body);
23
+ const returnUrlInput = parsed === null || parsed === void 0 ? void 0 : parsed.returnUrl;
24
+ const authUtils$1 = new authUtils.ApiAuthUtils(request);
25
+ const { user } = yield authUtils$1.requireAuthWithUser();
26
+ const activeSubscription = yield subscription_service.subscriptionService.getActiveSubscription(user.userId);
27
+ if (!activeSubscription) {
28
+ return server.NextResponse.json({ error: 'No active subscription' }, { status: 403 });
29
+ }
30
+ const customerId = yield stripeConfig.createOrGetCustomer({
31
+ userId: user.userId,
32
+ });
33
+ const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || 'http://localhost:3000';
34
+ const resolvedReturnUrl = resolveReturnUrl(returnUrlInput, baseUrl);
35
+ const session = yield stripeConfig.createCustomerPortalSession({
36
+ customerId,
37
+ returnUrl: resolvedReturnUrl,
38
+ });
39
+ return server.NextResponse.json({
40
+ success: true,
41
+ data: {
42
+ sessionId: session.id,
43
+ sessionUrl: session.url,
44
+ },
45
+ });
46
+ }
47
+ catch (error) {
48
+ console.error('Create customer portal error:', error);
49
+ if (error instanceof zod.z.ZodError) {
50
+ return server.NextResponse.json({ error: 'Validation error', details: error.issues }, { status: 400 });
51
+ }
52
+ return server.NextResponse.json({ error: 'Failed to create customer portal session' }, { status: 500 });
53
+ }
54
+ });
55
+ }
56
+ function resolveReturnUrl(returnUrl, baseUrl) {
57
+ if (!returnUrl) {
58
+ return baseUrl;
59
+ }
60
+ try {
61
+ return new URL(returnUrl).toString();
62
+ }
63
+ catch (_a) {
64
+ try {
65
+ return new URL(returnUrl, baseUrl).toString();
66
+ }
67
+ catch (_b) {
68
+ return baseUrl;
69
+ }
70
+ }
71
+ }
72
+
73
+ exports.POST = POST;
@@ -0,0 +1,71 @@
1
+ import { __awaiter } from '../../../../node_modules/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.46.2_tslib@2.8.1_typescript@5.9.3/node_modules/tslib/tslib.es6.mjs';
2
+ import { NextResponse } from 'next/server';
3
+ import { z } from 'zod';
4
+ import { createOrGetCustomer, createCustomerPortalSession } from '../../../../lib/stripe-config.mjs';
5
+ import { ApiAuthUtils } from '../../../../lib/auth-utils.mjs';
6
+ import '../../../../prisma/prisma.mjs';
7
+ import { subscriptionService } from '../../../../services/database/subscription.service.mjs';
8
+ import '../../../../services/database/credit.service.mjs';
9
+ import '@prisma/client';
10
+
11
+ const createCustomerPortalSchema = z
12
+ .object({
13
+ returnUrl: z.string().min(1).optional(),
14
+ })
15
+ .optional();
16
+ function POST(request) {
17
+ return __awaiter(this, void 0, void 0, function* () {
18
+ try {
19
+ const body = yield request.json().catch(() => ({}));
20
+ const parsed = createCustomerPortalSchema.parse(body);
21
+ const returnUrlInput = parsed === null || parsed === void 0 ? void 0 : parsed.returnUrl;
22
+ const authUtils = new ApiAuthUtils(request);
23
+ const { user } = yield authUtils.requireAuthWithUser();
24
+ const activeSubscription = yield subscriptionService.getActiveSubscription(user.userId);
25
+ if (!activeSubscription) {
26
+ return NextResponse.json({ error: 'No active subscription' }, { status: 403 });
27
+ }
28
+ const customerId = yield createOrGetCustomer({
29
+ userId: user.userId,
30
+ });
31
+ const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || 'http://localhost:3000';
32
+ const resolvedReturnUrl = resolveReturnUrl(returnUrlInput, baseUrl);
33
+ const session = yield createCustomerPortalSession({
34
+ customerId,
35
+ returnUrl: resolvedReturnUrl,
36
+ });
37
+ return NextResponse.json({
38
+ success: true,
39
+ data: {
40
+ sessionId: session.id,
41
+ sessionUrl: session.url,
42
+ },
43
+ });
44
+ }
45
+ catch (error) {
46
+ console.error('Create customer portal error:', error);
47
+ if (error instanceof z.ZodError) {
48
+ return NextResponse.json({ error: 'Validation error', details: error.issues }, { status: 400 });
49
+ }
50
+ return NextResponse.json({ error: 'Failed to create customer portal session' }, { status: 500 });
51
+ }
52
+ });
53
+ }
54
+ function resolveReturnUrl(returnUrl, baseUrl) {
55
+ if (!returnUrl) {
56
+ return baseUrl;
57
+ }
58
+ try {
59
+ return new URL(returnUrl).toString();
60
+ }
61
+ catch (_a) {
62
+ try {
63
+ return new URL(returnUrl, baseUrl).toString();
64
+ }
65
+ catch (_b) {
66
+ return baseUrl;
67
+ }
68
+ }
69
+ }
70
+
71
+ export { POST };
@@ -0,0 +1,7 @@
1
+ import { NextRequest, NextResponse } from 'next/server';
2
+ /**
3
+ * 匿名用户初始化API
4
+ * POST /api/user/anonymous/init
5
+ */
6
+ export declare function POST(request: NextRequest): Promise<NextResponse<unknown>>;
7
+ //# sourceMappingURL=route.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../../src/app/api/user/anonymous/init/route.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AA0QxD;;;GAGG;AACH,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW,kCAE9C"}
@@ -0,0 +1,210 @@
1
+ 'use strict';
2
+
3
+ var tslib_es6 = require('../../../../../node_modules/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.46.2_tslib@2.8.1_typescript@5.9.3/node_modules/tslib/tslib.es6.js');
4
+ var user_aggregate_service = require('../../../../../services/aggregate/user.aggregate.service.js');
5
+ require('../../../../../prisma/prisma.js');
6
+ require('../../../../../services/database/credit.service.js');
7
+ require('@prisma/client');
8
+ var server = require('@windrun-huaiin/third-ui/fingerprint/server');
9
+ var server$1 = require('@clerk/nextjs/server');
10
+ var server$2 = require('next/server');
11
+ var userContextService = require('../../../../../services/context/user-context-service.js');
12
+
13
+ /* eslint-disable @typescript-eslint/no-explicit-any */
14
+ // Fix BigInt serialization issue
15
+ BigInt.prototype.toJSON = function () {
16
+ return this.toString();
17
+ };
18
+ // ==================== 工具函数 ====================
19
+ /** 创建成功响应对象 */
20
+ function createSuccessResponse(params) {
21
+ const response = Object.assign({ success: true, xUser: userContextService.mapUserToXUser(params.entities.user), xCredit: params.entities.credit ? userContextService.mapCreditToXCredit(params.entities.credit) : null, xSubscription: userContextService.mapSubscriptionToXSubscription(params.entities.subscription), isNewUser: params.isNewUser }, params.options);
22
+ return userContextService.applyUserMockContext(response);
23
+ }
24
+ /** 创建错误响应 */
25
+ function createErrorResponse(message, status = 400) {
26
+ const errorResponse = { error: message };
27
+ return server$2.NextResponse.json(errorResponse, { status });
28
+ }
29
+ const SOURCE_REF_MAX_LENGTH = 2048;
30
+ const QUERY_PARAM_MAX_LENGTH = 512;
31
+ function normalizeSourceRef(ref) {
32
+ if (!ref) {
33
+ return null;
34
+ }
35
+ const trimmed = ref.trim();
36
+ if (!trimmed) {
37
+ return null;
38
+ }
39
+ return trimmed.length > SOURCE_REF_MAX_LENGTH
40
+ ? trimmed.slice(0, SOURCE_REF_MAX_LENGTH)
41
+ : trimmed;
42
+ }
43
+ function normalizeQueryParam(value) {
44
+ if (!value) {
45
+ return null;
46
+ }
47
+ const trimmed = value.trim();
48
+ if (!trimmed) {
49
+ return null;
50
+ }
51
+ return trimmed.length > QUERY_PARAM_MAX_LENGTH
52
+ ? trimmed.slice(0, QUERY_PARAM_MAX_LENGTH)
53
+ : trimmed;
54
+ }
55
+ function applySearchParams(sourceRef, params) {
56
+ const setIfEmpty = (key, value) => {
57
+ if (sourceRef[key] !== undefined) {
58
+ return;
59
+ }
60
+ const normalized = normalizeQueryParam(value);
61
+ if (normalized) {
62
+ sourceRef[key] = normalized;
63
+ }
64
+ };
65
+ setIfEmpty('utmSource', params.get('utm_source'));
66
+ setIfEmpty('utmMedium', params.get('utm_medium'));
67
+ setIfEmpty('utmCampaign', params.get('utm_campaign'));
68
+ setIfEmpty('utmTerm', params.get('utm_term'));
69
+ setIfEmpty('utmContent', params.get('utm_content'));
70
+ setIfEmpty('ref', params.get('ref'));
71
+ }
72
+ // 提取用户首次访问来源
73
+ function extractSourceRef(request) {
74
+ const headerRef = request.headers.get('referer') || request.headers.get('referrer');
75
+ const customRef = request.headers.get('x-source-ref');
76
+ const queryRef = request.nextUrl.searchParams.get('ref');
77
+ console.log({
78
+ headerRef,
79
+ customRef,
80
+ queryRef
81
+ });
82
+ const sourceRef = {};
83
+ let normalizedHttpRef = null;
84
+ const candidates = [headerRef, customRef, queryRef];
85
+ for (const candidate of candidates) {
86
+ const normalized = normalizeSourceRef(candidate);
87
+ if (normalized) {
88
+ normalizedHttpRef = normalized;
89
+ sourceRef.httpRefer = normalized;
90
+ break;
91
+ }
92
+ }
93
+ const searchParams = request.nextUrl.searchParams;
94
+ applySearchParams(sourceRef, searchParams);
95
+ if (normalizedHttpRef) {
96
+ try {
97
+ const refererUrl = new URL(normalizedHttpRef);
98
+ applySearchParams(sourceRef, refererUrl.searchParams);
99
+ }
100
+ catch (error) {
101
+ console.warn('Failed to parse referer url for utm/ref:', error);
102
+ }
103
+ }
104
+ return Object.keys(sourceRef).length > 0 ? sourceRef : null;
105
+ }
106
+ /**
107
+ * 根据fingerprint_id查询用户并返回响应数据
108
+ */
109
+ function getUserByClerkId(clerkUserId) {
110
+ return tslib_es6.__awaiter(this, void 0, void 0, function* () {
111
+ const entities = yield userContextService.fetchUserContextByClerkUserId(clerkUserId);
112
+ if (!entities) {
113
+ return null;
114
+ }
115
+ return createSuccessResponse({
116
+ entities,
117
+ isNewUser: false,
118
+ });
119
+ });
120
+ }
121
+ /**
122
+ * 根据fingerprint_id查询用户并返回响应数据
123
+ */
124
+ function getUserByFingerprintId(fingerprintId) {
125
+ return tslib_es6.__awaiter(this, void 0, void 0, function* () {
126
+ const result = yield userContextService.fetchLatestUserContextByFingerprintId(fingerprintId);
127
+ if (!result) {
128
+ return null;
129
+ }
130
+ const { totalUsersOnDevice, hasAnonymousUser } = result, entities = tslib_es6.__rest(result, ["totalUsersOnDevice", "hasAnonymousUser"]);
131
+ return createSuccessResponse({
132
+ entities,
133
+ isNewUser: false,
134
+ options: {
135
+ totalUsersOnDevice,
136
+ hasAnonymousUser,
137
+ },
138
+ });
139
+ });
140
+ }
141
+ /**
142
+ * 通用的fingerprint处理逻辑
143
+ */
144
+ function handleFingerprintRequest(request_1) {
145
+ return tslib_es6.__awaiter(this, arguments, void 0, function* (request, options = {}) {
146
+ // 从请求中提取fingerprint ID
147
+ const fingerprintId = server.extractFingerprintFromNextRequest(request);
148
+ // 验证fingerprint ID
149
+ if (!fingerprintId) {
150
+ return createErrorResponse('Invalid or missing fingerprint ID');
151
+ }
152
+ console.log('Received fingerprintId:', fingerprintId);
153
+ const { userId: clerkUserId } = yield server$1.auth();
154
+ try {
155
+ // 优先根据 Clerk ID 查询(如果已登录)
156
+ let existingUserResult = null;
157
+ if (clerkUserId) {
158
+ // 已登录一律按照clerkUserId去查
159
+ existingUserResult = yield getUserByClerkId(clerkUserId);
160
+ if (existingUserResult && existingUserResult.xUser.fingerprintId !== fingerprintId) {
161
+ // 说明当前用户的指纹ID发生了改变,为什么呢?因为它使用同一账号去注册Clerk,Clerk判定是同一用户!
162
+ // 这个时候一定以登录用户clerkUserId为准
163
+ // 但是考虑到同一指纹ID本身可以绑定多个账号,所以这里什么都不做
164
+ // 就是以当前登录用户去查他自己的数据就行!
165
+ console.warn(`Current login user used diff fp_ids: ${clerkUserId}, db_fp_id=${existingUserResult.xUser.fingerprintId}, req_fp_id=${fingerprintId}`);
166
+ }
167
+ }
168
+ else {
169
+ // 其次才是检查是否已存在该fingerprint的用户
170
+ existingUserResult = yield getUserByFingerprintId(fingerprintId);
171
+ }
172
+ if (existingUserResult) {
173
+ return server$2.NextResponse.json(existingUserResult);
174
+ }
175
+ // 如果不存在用户且不允许创建,返回404
176
+ if (!options.createIfNotExists) {
177
+ return createErrorResponse('User not found', 404);
178
+ }
179
+ const sourceRef = extractSourceRef(request);
180
+ // 创建新的匿名用户
181
+ const { newUser, credit } = yield user_aggregate_service.userAggregateService.initAnonymousUser(fingerprintId, { sourceRef: sourceRef !== null && sourceRef !== void 0 ? sourceRef : undefined });
182
+ console.log(`Created new anonymous user ${newUser.userId} with fingerprint ${fingerprintId}`);
183
+ // 返回创建结果
184
+ const response = createSuccessResponse({
185
+ entities: {
186
+ user: newUser,
187
+ credit,
188
+ subscription: null,
189
+ },
190
+ isNewUser: true,
191
+ });
192
+ return server$2.NextResponse.json(response);
193
+ }
194
+ catch (error) {
195
+ console.error('Fingerprint request error:', error);
196
+ return createErrorResponse('Internal server error', 500);
197
+ }
198
+ });
199
+ }
200
+ /**
201
+ * 匿名用户初始化API
202
+ * POST /api/user/anonymous/init
203
+ */
204
+ function POST(request) {
205
+ return tslib_es6.__awaiter(this, void 0, void 0, function* () {
206
+ return handleFingerprintRequest(request, { createIfNotExists: true });
207
+ });
208
+ }
209
+
210
+ exports.POST = POST;