@windrun-huaiin/backend-core 29.0.3 → 31.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.
Files changed (51) hide show
  1. package/README.md +95 -0
  2. package/dist/app/api/user/anonymous/init/route.d.ts +1 -1
  3. package/dist/app/api/user/anonymous/init/route.d.ts.map +1 -1
  4. package/dist/app/api/user/anonymous/init/route.js +18 -19
  5. package/dist/app/api/user/anonymous/init/route.mjs +18 -19
  6. package/dist/app/api/webhook/clerk/user/route.js +16 -16
  7. package/dist/app/api/webhook/clerk/user/route.mjs +16 -16
  8. package/dist/auth/auth-utils.d.ts +8 -23
  9. package/dist/auth/auth-utils.d.ts.map +1 -1
  10. package/dist/auth/auth-utils.js +8 -20
  11. package/dist/auth/auth-utils.mjs +8 -20
  12. package/dist/lib/money-price-config.d.ts +28 -28
  13. package/dist/lib/money-price-config.js +31 -31
  14. package/dist/lib/money-price-config.mjs +31 -31
  15. package/dist/lib/stripe-config.js +3 -3
  16. package/dist/lib/stripe-config.mjs +3 -3
  17. package/dist/prisma/prisma-transaction-util.js +1 -1
  18. package/dist/prisma/prisma-transaction-util.mjs +1 -1
  19. package/dist/prisma/prisma.d.ts.map +1 -1
  20. package/dist/prisma/prisma.js +18 -19
  21. package/dist/prisma/prisma.mjs +18 -19
  22. package/dist/services/aggregate/billing.aggregate.service.js +6 -6
  23. package/dist/services/aggregate/billing.aggregate.service.mjs +6 -6
  24. package/dist/services/aggregate/user.aggregate.service.d.ts +9 -9
  25. package/dist/services/aggregate/user.aggregate.service.js +16 -16
  26. package/dist/services/aggregate/user.aggregate.service.mjs +16 -16
  27. package/dist/services/database/constants.js +34 -34
  28. package/dist/services/database/constants.mjs +34 -34
  29. package/dist/services/database/credit.service.js +2 -2
  30. package/dist/services/database/credit.service.mjs +2 -2
  31. package/dist/services/database/transaction.service.js +1 -1
  32. package/dist/services/database/transaction.service.mjs +1 -1
  33. package/dist/services/database/user.service.js +2 -2
  34. package/dist/services/database/user.service.mjs +2 -2
  35. package/dist/services/stripe/webhook-handler.js +5 -5
  36. package/dist/services/stripe/webhook-handler.mjs +5 -5
  37. package/package.json +13 -6
  38. package/src/app/api/user/anonymous/init/route.ts +21 -22
  39. package/src/app/api/webhook/clerk/user/route.ts +17 -17
  40. package/src/auth/auth-utils.ts +8 -23
  41. package/src/lib/money-price-config.ts +31 -32
  42. package/src/lib/stripe-config.ts +3 -3
  43. package/src/prisma/prisma-transaction-util.ts +1 -1
  44. package/src/prisma/prisma.ts +18 -19
  45. package/src/services/aggregate/billing.aggregate.service.ts +7 -7
  46. package/src/services/aggregate/user.aggregate.service.ts +16 -16
  47. package/src/services/database/constants.ts +34 -34
  48. package/src/services/database/credit.service.ts +2 -2
  49. package/src/services/database/transaction.service.ts +1 -1
  50. package/src/services/database/user.service.ts +2 -2
  51. package/src/services/stripe/webhook-handler.ts +5 -5
@@ -1,5 +1,5 @@
1
1
  const globalForPrisma = globalThis;
2
- // ==================== 日志配置 ====================
2
+ // ==================== Logging Configuration ====================
3
3
  const getLogConfig = () => {
4
4
  if (process.env.PRISMA_DEBUG === 'true') {
5
5
  return [
@@ -65,41 +65,40 @@ function registerDevelopmentQueryLogger(prismaClient, instanceId) {
65
65
  const listenerId = `listener_${Date.now()}_${Math.random().toString(36).substr(2, 5)}`;
66
66
  globalForPrisma[ID_KEY] = listenerId;
67
67
  console.log(`Prisma Query Logger Registered | Listener ID: ${listenerId} | Instance ID: ${instanceId}`);
68
- // --- 自定义SQL拼接 ---
68
+ // --- Custom SQL interpolation ---
69
69
  const interpolate = (query, params) => {
70
- // 1. 【核心修改】:安全检查和参数解析
70
+ // 1. Validate and parse parameters safely.
71
71
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
72
72
  let parameters = [];
73
73
  try {
74
- // 尝试解析 params 字符串
75
- // 如果 params 是空字符串 "",或者不是有效的 JSON,这里会捕获错误
74
+ // Parse the params string. Empty strings or invalid JSON are handled by the catch block.
76
75
  parameters = params && params.length > 0 ? JSON.parse(params) : [];
77
76
  // eslint-disable-next-line unused-imports/no-unused-vars
78
77
  }
79
78
  catch (e) {
80
- // 如果无法解析,则直接返回原始查询,跳过替换
79
+ // If parsing fails, return the original query without interpolation.
81
80
  return query;
82
81
  }
83
- // 确保 parameters 是一个数组
82
+ // Ensure parameters is an array.
84
83
  if (!Array.isArray(parameters)) {
85
- console.warn('Prisma params解析结果不是数组,跳过参数替换。Result:', parameters);
84
+ console.warn('Prisma params did not parse to an array; skipping parameter interpolation. Result:', parameters);
86
85
  return query;
87
86
  }
88
- // 如果没有参数,直接返回查询
87
+ // If there are no parameters, return the query as-is.
89
88
  if (parameters.length === 0) {
90
89
  return query;
91
90
  }
92
- // 2. 将参数列表的值进行安全的字符串化处理
91
+ // 2. Safely stringify parameter values.
93
92
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
94
93
  const safeValues = parameters.map((p) => {
95
94
  if (p === null)
96
95
  return 'NULL';
97
- // 对字符串类型的值加上单引号并转义(这是SQL安全的关键)
96
+ // Quote and escape string values for readable SQL logging.
98
97
  if (typeof p === 'string')
99
98
  return `'${p.replace(/'/g, "''")}'`;
100
- return p; // 数字、布尔值等直接返回
99
+ return p; // Numbers, booleans, and similar values can be returned directly.
101
100
  });
102
- // 3. 循环替换 $1, $2, ...
101
+ // 3. Replace $1, $2, ... placeholders.
103
102
  let sql = query;
104
103
  for (let i = 0; i < safeValues.length; i++) {
105
104
  const placeholder = new RegExp('\\$' + (i + 1) + '(?!\\d)', 'g');
@@ -112,20 +111,20 @@ function registerDevelopmentQueryLogger(prismaClient, instanceId) {
112
111
  const slow = ms >= 200 ? '🐌 SLOW SQL ' : '🚀 SQL';
113
112
  const interpolatedSql = interpolate(event.query, event.params);
114
113
  const clean = interpolatedSql
115
- .replace(/"[^"]+"\./g, '') // "".
116
- .replace(/= '([^']+)'/g, `= '$1'`) // 已经替换成单引号,此处可以优化
117
- .replace(/"/g, ''); // 彻底灭双引号
114
+ .replace(/"[^"]+"\./g, '') // Remove "table". prefixes.
115
+ .replace(/= '([^']+)'/g, `= '$1'`) // Keep normalized quoted values.
116
+ .replace(/"/g, ''); // Remove remaining double quotes.
118
117
  console.log('─'.repeat(60));
119
118
  console.log(`Prisma Instance ID: ${instanceId} | Listener ID: ${listenerId}`);
120
119
  console.log(`${clean};`);
121
- console.log(`⏰ 耗时: ${ms}ms, ${slow}`);
120
+ console.log(`Duration: ${ms}ms, ${slow}`);
122
121
  };
123
- // 注册包装后的 handler
122
+ // Register the wrapped handler.
124
123
  (_a = prismaClient.$on) === null || _a === void 0 ? void 0 : _a.call(prismaClient, 'query', wrappedHandler);
125
124
  globalForPrisma[REGISTERED_KEY] = true;
126
125
  }
127
126
  }
128
- // ==================== 便捷方法, 入参事务客户端不存在或者不传, 就返回全局非事务客户端 ====================
127
+ // ==================== Client Helper: fall back to the global non-transaction client when no transaction client is provided ====================
129
128
  function checkAndFallbackWithNonTCClient(tx) {
130
129
  return tx !== null && tx !== void 0 ? tx : getBackendCorePrisma();
131
130
  }
@@ -14,7 +14,7 @@ class BillingAggregateService {
14
14
  yield prismaTransactionUtil.runInTransaction((tx) => tslib.__awaiter(this, void 0, void 0, function* () {
15
15
  var _a, _b, _c, _d, _e, _f, _g, _h;
16
16
  const now = new Date();
17
- // 订阅截止时间统一为到期日最后1s
17
+ // Set subscription expiry to the last second of the expiration date
18
18
  const originSubPeriodEnd = context.periodEnd;
19
19
  const specialEnd = originSubPeriodEnd ? new Date(originSubPeriodEnd.setHours(23, 59, 59, 999)) : originSubPeriodEnd;
20
20
  const updatedSubscription = yield subscription_service.subscriptionService.updateSubscription(context.subIdKey, {
@@ -132,7 +132,7 @@ class BillingAggregateService {
132
132
  paidEmail: context.paidEmail,
133
133
  payUpdatedAt: new Date(),
134
134
  }, tx);
135
- // 订阅截止时间统一为到期日最后1s
135
+ // Set subscription expiry to the last second of the expiration date
136
136
  const originSubPeriodEnd = context.periodEnd;
137
137
  const specialEnd = originSubPeriodEnd ? new Date(originSubPeriodEnd.setHours(23, 59, 59, 999)) : originSubPeriodEnd;
138
138
  yield subscription_service.subscriptionService.updateSubscription(context.subIdKey, {
@@ -218,7 +218,7 @@ class BillingAggregateService {
218
218
  return tslib.__awaiter(this, void 0, void 0, function* () {
219
219
  yield prismaTransactionUtil.runInTransaction((tx) => tslib.__awaiter(this, void 0, void 0, function* () {
220
220
  if (params.isUserCancel) {
221
- // 记录用户取消订阅的时间信息
221
+ // Record the time when the user unsubscribes
222
222
  yield transaction_service.transactionService.update(params.orderId, {
223
223
  subLastTryCancelAt: new Date(),
224
224
  }, tx);
@@ -236,14 +236,14 @@ class BillingAggregateService {
236
236
  return tslib.__awaiter(this, void 0, void 0, function* () {
237
237
  yield prismaTransactionUtil.runInTransaction((tx) => tslib.__awaiter(this, void 0, void 0, function* () {
238
238
  var _a;
239
- // 更新订单, 记录取消信息
239
+ // Update the order and log cancellation details
240
240
  yield transaction_service.transactionService.update(context.orderId, {
241
241
  subPeriodCanceledAt: context.canceledAt,
242
242
  subCancellationDetail: (_a = context.cancellationDetail) !== null && _a !== void 0 ? _a : undefined
243
243
  }, tx);
244
- // 更新订阅信息
244
+ // Update subscription information
245
245
  yield subscription_service.subscriptionService.updateStatus(context.subIdKey, constants.SubscriptionStatus.CANCELED, tx);
246
- // 清理积分并留痕
246
+ // Clear credits and keep audit trail
247
247
  yield credit_service.creditService.purgePaidCredit(context.userId, 'cancel_subscription_purge', context.orderId, tx);
248
248
  }));
249
249
  });
@@ -12,7 +12,7 @@ class BillingAggregateService {
12
12
  yield runInTransaction((tx) => __awaiter(this, void 0, void 0, function* () {
13
13
  var _a, _b, _c, _d, _e, _f, _g, _h;
14
14
  const now = new Date();
15
- // 订阅截止时间统一为到期日最后1s
15
+ // Set subscription expiry to the last second of the expiration date
16
16
  const originSubPeriodEnd = context.periodEnd;
17
17
  const specialEnd = originSubPeriodEnd ? new Date(originSubPeriodEnd.setHours(23, 59, 59, 999)) : originSubPeriodEnd;
18
18
  const updatedSubscription = yield subscriptionService.updateSubscription(context.subIdKey, {
@@ -130,7 +130,7 @@ class BillingAggregateService {
130
130
  paidEmail: context.paidEmail,
131
131
  payUpdatedAt: new Date(),
132
132
  }, tx);
133
- // 订阅截止时间统一为到期日最后1s
133
+ // Set subscription expiry to the last second of the expiration date
134
134
  const originSubPeriodEnd = context.periodEnd;
135
135
  const specialEnd = originSubPeriodEnd ? new Date(originSubPeriodEnd.setHours(23, 59, 59, 999)) : originSubPeriodEnd;
136
136
  yield subscriptionService.updateSubscription(context.subIdKey, {
@@ -216,7 +216,7 @@ class BillingAggregateService {
216
216
  return __awaiter(this, void 0, void 0, function* () {
217
217
  yield runInTransaction((tx) => __awaiter(this, void 0, void 0, function* () {
218
218
  if (params.isUserCancel) {
219
- // 记录用户取消订阅的时间信息
219
+ // Record the time when the user unsubscribes
220
220
  yield transactionService.update(params.orderId, {
221
221
  subLastTryCancelAt: new Date(),
222
222
  }, tx);
@@ -234,14 +234,14 @@ class BillingAggregateService {
234
234
  return __awaiter(this, void 0, void 0, function* () {
235
235
  yield runInTransaction((tx) => __awaiter(this, void 0, void 0, function* () {
236
236
  var _a;
237
- // 更新订单, 记录取消信息
237
+ // Update the order and log cancellation details
238
238
  yield transactionService.update(context.orderId, {
239
239
  subPeriodCanceledAt: context.canceledAt,
240
240
  subCancellationDetail: (_a = context.cancellationDetail) !== null && _a !== void 0 ? _a : undefined
241
241
  }, tx);
242
- // 更新订阅信息
242
+ // Update subscription information
243
243
  yield subscriptionService.updateStatus(context.subIdKey, SubscriptionStatus.CANCELED, tx);
244
- // 清理积分并留痕
244
+ // Clear credits and keep audit trail
245
245
  yield creditService.purgePaidCredit(context.userId, 'cancel_subscription_purge', context.orderId, tx);
246
246
  }));
247
247
  });
@@ -7,17 +7,17 @@ export declare class UserAggregateService {
7
7
  credit: Credit;
8
8
  }>;
9
9
  /**
10
- * 创建新的注册用户
10
+ * Create a new registered user
11
11
  *
12
- * 初始化步骤(与 credit 平行):
13
- * 1. 创建 User 记录
14
- * 2. 初始化 Credit 记录(免费积分)
15
- * 3. 初始化 Subscription 记录(占位符,status=INCOMPLETE
16
- * 4. 记录 CreditUsage(审计)
12
+ * Initialization steps (parallel to credit):
13
+ * 1. Create User record
14
+ * 2. Initialize Credit record (free credits)
15
+ * 3. Initialize Subscription record (placeholder, status=INCOMPLETE)
16
+ * 4. Record CreditUsage (audit)
17
17
  *
18
- * 后续当用户通过 Stripe 订阅时:
19
- * - session.completed invoice.paid UPDATE subscription 记录
20
- * - 不需要 CREATE,只需 UPDATE 确保逻辑一致
18
+ * When the user subscribes via Stripe later:
19
+ * - session.completed or invoice.paid will UPDATE the subscription record
20
+ * - No CREATE needed, only UPDATE to ensure logical consistency
21
21
  */
22
22
  createNewRegisteredUser(clerkUserId: string, email?: string, fingerprintId?: string, userName?: string, sourceRef?: CoreJsonValue): Promise<{
23
23
  newUser: User;
@@ -32,17 +32,17 @@ class UserAggregateService {
32
32
  });
33
33
  }
34
34
  /**
35
- * 创建新的注册用户
35
+ * Create a new registered user
36
36
  *
37
- * 初始化步骤(与 credit 平行):
38
- * 1. 创建 User 记录
39
- * 2. 初始化 Credit 记录(免费积分)
40
- * 3. 初始化 Subscription 记录(占位符,status=INCOMPLETE
41
- * 4. 记录 CreditUsage(审计)
37
+ * Initialization steps (parallel to credit):
38
+ * 1. Create User record
39
+ * 2. Initialize Credit record (free credits)
40
+ * 3. Initialize Subscription record (placeholder, status=INCOMPLETE)
41
+ * 4. Record CreditUsage (audit)
42
42
  *
43
- * 后续当用户通过 Stripe 订阅时:
44
- * - session.completed invoice.paid UPDATE subscription 记录
45
- * - 不需要 CREATE,只需 UPDATE 确保逻辑一致
43
+ * When the user subscribes via Stripe later:
44
+ * - session.completed or invoice.paid will UPDATE the subscription record
45
+ * - No CREATE needed, only UPDATE to ensure logical consistency
46
46
  */
47
47
  createNewRegisteredUser(clerkUserId, email, fingerprintId, userName, sourceRef) {
48
48
  return tslib.__awaiter(this, void 0, void 0, function* () {
@@ -68,7 +68,7 @@ class UserAggregateService {
68
68
  }));
69
69
  });
70
70
  }
71
- // 注意积分审查日志的处理
71
+ // Note: Handle credit review logs
72
72
  upgradeToRegistered(userId, email, clerkUserId, userName) {
73
73
  return tslib.__awaiter(this, void 0, void 0, function* () {
74
74
  return prismaTransactionUtil.runInTransaction((tx) => tslib.__awaiter(this, void 0, void 0, function* () {
@@ -77,9 +77,9 @@ class UserAggregateService {
77
77
  clerkUserId,
78
78
  userName
79
79
  }, tx);
80
- // 先清空匿名积分并审计日志留痕
80
+ // Clear anonymous credits first and audit for traceability
81
81
  yield credit_service.creditService.purgeFreeCredit(userId, 'user_registered_purge', userId, tx);
82
- // 再初始化完成注册获得免费积分
82
+ // Then initialize free credits upon successful registration
83
83
  const credit = yield credit_service.creditService.initializeCreditWithFree({
84
84
  userId: updateUser.userId,
85
85
  feature: 'user_registration_init',
@@ -95,20 +95,20 @@ class UserAggregateService {
95
95
  handleUserUnregister(clerkUserId) {
96
96
  return tslib.__awaiter(this, void 0, void 0, function* () {
97
97
  return prismaTransactionUtil.runInTransaction((tx) => tslib.__awaiter(this, void 0, void 0, function* () {
98
- // 根据clerkUserId查找用户
98
+ // query DB user
99
99
  const user = yield user_service.userService.findByClerkUserId(clerkUserId, tx);
100
100
  if (!user) {
101
101
  console.log(`User with clerkUserId ${clerkUserId} not found`);
102
102
  return null;
103
103
  }
104
104
  const userId = user.userId;
105
- // 更改用户状态,保留user信息尤其是FingerprintId,防止反复注册薅羊毛
105
+ // Update user status and retain user info (especially FingerprintId) to prevent repeated registration abuse
106
106
  yield user_service.userService.unregister(user.userId, tx);
107
- // 清空积分
107
+ // Clear credits
108
108
  yield credit_service.creditService.purgeCredit(userId, 'soft_delete_user', userId, tx);
109
109
  const subscription = yield subscription_service.subscriptionService.getActiveSubscription(userId, tx);
110
110
  if (subscription) {
111
- // 如果有订阅信息,则要更新
111
+ // Update subscription info if it exists
112
112
  yield subscription_service.subscriptionService.cancelSubscription(subscription.id, true, tx);
113
113
  }
114
114
  return user.userId;
@@ -30,17 +30,17 @@ class UserAggregateService {
30
30
  });
31
31
  }
32
32
  /**
33
- * 创建新的注册用户
33
+ * Create a new registered user
34
34
  *
35
- * 初始化步骤(与 credit 平行):
36
- * 1. 创建 User 记录
37
- * 2. 初始化 Credit 记录(免费积分)
38
- * 3. 初始化 Subscription 记录(占位符,status=INCOMPLETE
39
- * 4. 记录 CreditUsage(审计)
35
+ * Initialization steps (parallel to credit):
36
+ * 1. Create User record
37
+ * 2. Initialize Credit record (free credits)
38
+ * 3. Initialize Subscription record (placeholder, status=INCOMPLETE)
39
+ * 4. Record CreditUsage (audit)
40
40
  *
41
- * 后续当用户通过 Stripe 订阅时:
42
- * - session.completed invoice.paid UPDATE subscription 记录
43
- * - 不需要 CREATE,只需 UPDATE 确保逻辑一致
41
+ * When the user subscribes via Stripe later:
42
+ * - session.completed or invoice.paid will UPDATE the subscription record
43
+ * - No CREATE needed, only UPDATE to ensure logical consistency
44
44
  */
45
45
  createNewRegisteredUser(clerkUserId, email, fingerprintId, userName, sourceRef) {
46
46
  return __awaiter(this, void 0, void 0, function* () {
@@ -66,7 +66,7 @@ class UserAggregateService {
66
66
  }));
67
67
  });
68
68
  }
69
- // 注意积分审查日志的处理
69
+ // Note: Handle credit review logs
70
70
  upgradeToRegistered(userId, email, clerkUserId, userName) {
71
71
  return __awaiter(this, void 0, void 0, function* () {
72
72
  return runInTransaction((tx) => __awaiter(this, void 0, void 0, function* () {
@@ -75,9 +75,9 @@ class UserAggregateService {
75
75
  clerkUserId,
76
76
  userName
77
77
  }, tx);
78
- // 先清空匿名积分并审计日志留痕
78
+ // Clear anonymous credits first and audit for traceability
79
79
  yield creditService.purgeFreeCredit(userId, 'user_registered_purge', userId, tx);
80
- // 再初始化完成注册获得免费积分
80
+ // Then initialize free credits upon successful registration
81
81
  const credit = yield creditService.initializeCreditWithFree({
82
82
  userId: updateUser.userId,
83
83
  feature: 'user_registration_init',
@@ -93,20 +93,20 @@ class UserAggregateService {
93
93
  handleUserUnregister(clerkUserId) {
94
94
  return __awaiter(this, void 0, void 0, function* () {
95
95
  return runInTransaction((tx) => __awaiter(this, void 0, void 0, function* () {
96
- // 根据clerkUserId查找用户
96
+ // query DB user
97
97
  const user = yield userService.findByClerkUserId(clerkUserId, tx);
98
98
  if (!user) {
99
99
  console.log(`User with clerkUserId ${clerkUserId} not found`);
100
100
  return null;
101
101
  }
102
102
  const userId = user.userId;
103
- // 更改用户状态,保留user信息尤其是FingerprintId,防止反复注册薅羊毛
103
+ // Update user status and retain user info (especially FingerprintId) to prevent repeated registration abuse
104
104
  yield userService.unregister(user.userId, tx);
105
- // 清空积分
105
+ // Clear credits
106
106
  yield creditService.purgeCredit(userId, 'soft_delete_user', userId, tx);
107
107
  const subscription = yield subscriptionService.getActiveSubscription(userId, tx);
108
108
  if (subscription) {
109
- // 如果有订阅信息,则要更新
109
+ // Update subscription info if it exists
110
110
  yield subscriptionService.cancelSubscription(subscription.id, true, tx);
111
111
  }
112
112
  return user.userId;
@@ -3,91 +3,91 @@
3
3
  // Database Field Enums
4
4
  // Keep in sync with DB CHECK constraints
5
5
  const UserStatus = {
6
- // 匿名用户
6
+ // Anonymous user
7
7
  ANONYMOUS: 'anonymous',
8
- // 注册用户
8
+ // Registered user
9
9
  REGISTERED: 'registered',
10
- // 管理员介入管控
10
+ // Frozen by admin intervention
11
11
  FROZEN: 'frozen',
12
- // 用户注销,数据软删除,用户数据将不可复用
12
+ // Soft-deleted user data that must not be reused
13
13
  DELETED: 'deleted',
14
14
  };
15
15
  const SubscriptionStatus = {
16
- // 初始状态或注销后状态
16
+ // Initial or post-cancellation state
17
17
  INCOMPLETE: 'incomplete',
18
- // 订阅试用期
18
+ // Trial subscription period
19
19
  TRIALING: 'trialing',
20
- // 有效订阅激活
20
+ // Active subscription
21
21
  ACTIVE: 'active',
22
- // 订阅过期
22
+ // Past-due subscription
23
23
  PAST_DUE: 'past_due',
24
- // 取消订阅
24
+ // Canceled subscription
25
25
  CANCELED: 'canceled',
26
26
  };
27
27
  const OrderStatus = {
28
- // 初始状态
28
+ // Initial state
29
29
  CREATED: 'created',
30
- // 中间状态,待支付,可能是支付失败事件触发
30
+ // Intermediate state, awaiting payment; may be triggered by a payment failure event
31
31
  PENDING_UNPAID: 'pending_unpaid',
32
- // 中间状态(也可是最终状态),支付成功,后续可变为「退款或取消」
32
+ // Intermediate or final state; payment succeeded and may later become refunded or canceled
33
33
  SUCCESS: 'success',
34
- // 中间状态(也可是最终状态),CheckOut失败或者是支付失败,后续可变为「退款或取消」
34
+ // Intermediate or final state; checkout or payment failed and may later become refunded or canceled
35
35
  FAILED: 'failed',
36
- // 最终状态,已退款
36
+ // Final state, refunded
37
37
  REFUNDED: 'refunded',
38
- // 最终状态,已取消
38
+ // Final state, canceled
39
39
  CANCELED: 'canceled',
40
40
  };
41
41
  const TransactionType = {
42
- // 订阅订单
42
+ // Subscription order
43
43
  SUBSCRIPTION: 'subscription',
44
- // 即付订单
44
+ // One-time payment order
45
45
  ONE_TIME: 'one_time',
46
46
  };
47
47
  const CreditType = {
48
- // 订阅积分
48
+ // Subscription credits
49
49
  PAID: 'paid',
50
- // 即付积分
50
+ // One-time paid credits
51
51
  ONE_TIME_PAID: 'one_time_paid',
52
- // 免费积分
52
+ // Free credits
53
53
  FREE: 'free',
54
54
  };
55
55
  const OperationType = {
56
- // 系统奖励积分
56
+ // System-granted credits
57
57
  SYS_GIFT: 'system_gift',
58
- // 用户消费积分
58
+ // User credit consumption
59
59
  CONSUME: 'consume',
60
- // 用户充值积分
60
+ // User credit recharge
61
61
  RECHARGE: 'recharge',
62
- // 管理员介入冻结积分
62
+ // Admin credit freeze
63
63
  FREEZE: 'freeze',
64
- // 管理员介入解冻积分
64
+ // Admin credit unfreeze
65
65
  UNFREEZE: 'unfreeze',
66
- // 管理员介入赠送积分
66
+ // Admin credit increase
67
67
  ADJUST_INCREASE: 'adjust_increase',
68
- // 管理员介入抹去积分
68
+ // Admin credit decrease
69
69
  ADJUST_DECREASE: 'adjust_decrease',
70
- // 清理积分,事件触发或者是积分过期触发
70
+ // Credit purge triggered by an event or expiration
71
71
  PURGE: 'purge',
72
72
  };
73
- // 支付厂商类型
73
+ // Payment provider types
74
74
  const PaySupplier = {
75
75
  STRIPE: 'Stripe',
76
76
  APPLE: 'Apple',
77
77
  PAYPAL: 'Paypal',
78
78
  };
79
79
  const BillingReason = {
80
- // 首次订阅
80
+ // Initial subscription
81
81
  SUBSCRIPTION_CREATE: 'subscription_create',
82
- // 续订
82
+ // Subscription renewal
83
83
  SUBSCRIPTION_CYCLE: 'subscription_cycle',
84
84
  };
85
85
  const PaymentStatus = {
86
- // 已支付
86
+ // Paid
87
87
  PAID: 'paid',
88
- // 待支付
88
+ // Pending payment
89
89
  UN_PAID: 'un_paid',
90
- // 无需支付
90
+ // No payment required
91
91
  NO_PAYMENT_REQUIRED: 'no_payment_required',
92
92
  };
93
93
  // Validation Functions
@@ -1,91 +1,91 @@
1
1
  // Database Field Enums
2
2
  // Keep in sync with DB CHECK constraints
3
3
  const UserStatus = {
4
- // 匿名用户
4
+ // Anonymous user
5
5
  ANONYMOUS: 'anonymous',
6
- // 注册用户
6
+ // Registered user
7
7
  REGISTERED: 'registered',
8
- // 管理员介入管控
8
+ // Frozen by admin intervention
9
9
  FROZEN: 'frozen',
10
- // 用户注销,数据软删除,用户数据将不可复用
10
+ // Soft-deleted user data that must not be reused
11
11
  DELETED: 'deleted',
12
12
  };
13
13
  const SubscriptionStatus = {
14
- // 初始状态或注销后状态
14
+ // Initial or post-cancellation state
15
15
  INCOMPLETE: 'incomplete',
16
- // 订阅试用期
16
+ // Trial subscription period
17
17
  TRIALING: 'trialing',
18
- // 有效订阅激活
18
+ // Active subscription
19
19
  ACTIVE: 'active',
20
- // 订阅过期
20
+ // Past-due subscription
21
21
  PAST_DUE: 'past_due',
22
- // 取消订阅
22
+ // Canceled subscription
23
23
  CANCELED: 'canceled',
24
24
  };
25
25
  const OrderStatus = {
26
- // 初始状态
26
+ // Initial state
27
27
  CREATED: 'created',
28
- // 中间状态,待支付,可能是支付失败事件触发
28
+ // Intermediate state, awaiting payment; may be triggered by a payment failure event
29
29
  PENDING_UNPAID: 'pending_unpaid',
30
- // 中间状态(也可是最终状态),支付成功,后续可变为「退款或取消」
30
+ // Intermediate or final state; payment succeeded and may later become refunded or canceled
31
31
  SUCCESS: 'success',
32
- // 中间状态(也可是最终状态),CheckOut失败或者是支付失败,后续可变为「退款或取消」
32
+ // Intermediate or final state; checkout or payment failed and may later become refunded or canceled
33
33
  FAILED: 'failed',
34
- // 最终状态,已退款
34
+ // Final state, refunded
35
35
  REFUNDED: 'refunded',
36
- // 最终状态,已取消
36
+ // Final state, canceled
37
37
  CANCELED: 'canceled',
38
38
  };
39
39
  const TransactionType = {
40
- // 订阅订单
40
+ // Subscription order
41
41
  SUBSCRIPTION: 'subscription',
42
- // 即付订单
42
+ // One-time payment order
43
43
  ONE_TIME: 'one_time',
44
44
  };
45
45
  const CreditType = {
46
- // 订阅积分
46
+ // Subscription credits
47
47
  PAID: 'paid',
48
- // 即付积分
48
+ // One-time paid credits
49
49
  ONE_TIME_PAID: 'one_time_paid',
50
- // 免费积分
50
+ // Free credits
51
51
  FREE: 'free',
52
52
  };
53
53
  const OperationType = {
54
- // 系统奖励积分
54
+ // System-granted credits
55
55
  SYS_GIFT: 'system_gift',
56
- // 用户消费积分
56
+ // User credit consumption
57
57
  CONSUME: 'consume',
58
- // 用户充值积分
58
+ // User credit recharge
59
59
  RECHARGE: 'recharge',
60
- // 管理员介入冻结积分
60
+ // Admin credit freeze
61
61
  FREEZE: 'freeze',
62
- // 管理员介入解冻积分
62
+ // Admin credit unfreeze
63
63
  UNFREEZE: 'unfreeze',
64
- // 管理员介入赠送积分
64
+ // Admin credit increase
65
65
  ADJUST_INCREASE: 'adjust_increase',
66
- // 管理员介入抹去积分
66
+ // Admin credit decrease
67
67
  ADJUST_DECREASE: 'adjust_decrease',
68
- // 清理积分,事件触发或者是积分过期触发
68
+ // Credit purge triggered by an event or expiration
69
69
  PURGE: 'purge',
70
70
  };
71
- // 支付厂商类型
71
+ // Payment provider types
72
72
  const PaySupplier = {
73
73
  STRIPE: 'Stripe',
74
74
  APPLE: 'Apple',
75
75
  PAYPAL: 'Paypal',
76
76
  };
77
77
  const BillingReason = {
78
- // 首次订阅
78
+ // Initial subscription
79
79
  SUBSCRIPTION_CREATE: 'subscription_create',
80
- // 续订
80
+ // Subscription renewal
81
81
  SUBSCRIPTION_CYCLE: 'subscription_cycle',
82
82
  };
83
83
  const PaymentStatus = {
84
- // 已支付
84
+ // Paid
85
85
  PAID: 'paid',
86
- // 待支付
86
+ // Pending payment
87
87
  UN_PAID: 'un_paid',
88
- // 无需支付
88
+ // No payment required
89
89
  NO_PAYMENT_REQUIRED: 'no_payment_required',
90
90
  };
91
91
  // Validation Functions
@@ -208,7 +208,7 @@ class CreditService {
208
208
  const normalized = this.normalizeAmounts({ free: init.creditsChange });
209
209
  this.ensureNonNegative(normalized, 'initializeCredit');
210
210
  const client = prisma.checkAndFallbackWithNonTCClient(tx);
211
- // 这里使用upsert语义是为了代码复用,处理匿名初始化和匿名->注册的初始化
211
+ // Use upsert semantics to share initialization logic for anonymous users and anonymous-to-registered upgrades.
212
212
  const credit = yield client.credit.upsert({
213
213
  where: {
214
214
  userId: init.userId
@@ -430,7 +430,7 @@ class CreditService {
430
430
  where: { userId },
431
431
  data: updateData,
432
432
  });
433
- // 强制留痕,即使是积分变化为0也记录,操作留痕
433
+ // Always write an audit entry, even when the credit change is zero.
434
434
  const usage = yield this.recordCreditAuditLog(client, userId, constants.OperationType.PURGE, normalizedDeduction, { feature: reason, operationReferId });
435
435
  return { credit, usage };
436
436
  });
@@ -206,7 +206,7 @@ class CreditService {
206
206
  const normalized = this.normalizeAmounts({ free: init.creditsChange });
207
207
  this.ensureNonNegative(normalized, 'initializeCredit');
208
208
  const client = checkAndFallbackWithNonTCClient(tx);
209
- // 这里使用upsert语义是为了代码复用,处理匿名初始化和匿名->注册的初始化
209
+ // Use upsert semantics to share initialization logic for anonymous users and anonymous-to-registered upgrades.
210
210
  const credit = yield client.credit.upsert({
211
211
  where: {
212
212
  userId: init.userId
@@ -428,7 +428,7 @@ class CreditService {
428
428
  where: { userId },
429
429
  data: updateData,
430
430
  });
431
- // 强制留痕,即使是积分变化为0也记录,操作留痕
431
+ // Always write an audit entry, even when the credit change is zero.
432
432
  const usage = yield this.recordCreditAuditLog(client, userId, OperationType.PURGE, normalizedDeduction, { feature: reason, operationReferId });
433
433
  return { credit, usage };
434
434
  });