@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
package/README.md ADDED
@@ -0,0 +1,95 @@
1
+ # @windrun-huaiin/backend-core
2
+
3
+ Shared backend primitives for Next.js applications, including Prisma access, database services, authentication helpers, Stripe integration, credit and pricing server utilities, Upstash utilities, AI services, and ready-to-wire API route handlers.
4
+
5
+ This package is organized around public subpath exports. Import the narrowest entry point that matches the backend capability you need, especially when separating server-only code from route handlers.
6
+
7
+ ## Feature Areas
8
+
9
+ ### Core Backend Utilities
10
+
11
+ The root entry provides shared backend exports for application code that needs the common backend surface of the package.
12
+
13
+ | Entry | Purpose |
14
+ | --- | --- |
15
+ | `@windrun-huaiin/backend-core` | Shared backend primitives and common exports |
16
+
17
+ ### Prisma and Database Services
18
+
19
+ The Prisma and database entries provide the data-access layer for applications that share database models, service methods, and transaction-oriented backend logic.
20
+
21
+ | Entry | Purpose |
22
+ | --- | --- |
23
+ | `@windrun-huaiin/backend-core/prisma` | Prisma client and Prisma-related utilities |
24
+ | `@windrun-huaiin/backend-core/database` | Database service layer |
25
+ | `@windrun-huaiin/backend-core/aggregate` | Aggregate service layer |
26
+ | `@windrun-huaiin/backend-core/context` | Backend context helpers |
27
+
28
+ ### Authentication
29
+
30
+ Authentication entries provide shared server utilities, shared auth definitions, and middleware helpers for applications that need consistent auth handling.
31
+
32
+ | Entry | Purpose |
33
+ | --- | --- |
34
+ | `@windrun-huaiin/backend-core/auth/server` | Server-side authentication helpers |
35
+ | `@windrun-huaiin/backend-core/auth/shared` | Shared authentication utilities and definitions |
36
+ | `@windrun-huaiin/backend-core/auth/middleware` | Authentication middleware helpers |
37
+
38
+ ### Stripe, Pricing, and Credits
39
+
40
+ Commerce entries cover Stripe integration, checkout and customer portal route handlers, pricing server helpers, and credit server helpers.
41
+
42
+ | Entry | Purpose |
43
+ | --- | --- |
44
+ | `@windrun-huaiin/backend-core/stripe` | Stripe service layer |
45
+ | `@windrun-huaiin/backend-core/stripe/server` | Server-side Stripe configuration helpers |
46
+ | `@windrun-huaiin/backend-core/pricing/server` | Server-side pricing helpers |
47
+ | `@windrun-huaiin/backend-core/credit/server` | Server-side credit helpers |
48
+ | `@windrun-huaiin/backend-core/config/money-price` | Money-price configuration |
49
+ | `@windrun-huaiin/backend-core/app/api/stripe/checkout/route` | Stripe checkout API route handler |
50
+ | `@windrun-huaiin/backend-core/app/api/stripe/customer-portal/route` | Stripe customer portal API route handler |
51
+ | `@windrun-huaiin/backend-core/app/api/webhook/stripe/route` | Stripe webhook API route handler |
52
+
53
+ ### User and Clerk Routes
54
+
55
+ User route handlers provide reusable API endpoints for anonymous user initialization, credit overview, pricing context, and Clerk user webhooks.
56
+
57
+ | Entry | Purpose |
58
+ | --- | --- |
59
+ | `@windrun-huaiin/backend-core/app/api/user/anonymous/init/route` | Anonymous user initialization API route handler |
60
+ | `@windrun-huaiin/backend-core/app/api/user/credit-overview/route` | User credit overview API route handler |
61
+ | `@windrun-huaiin/backend-core/app/api/user/pricing-context/route` | User pricing context API route handler |
62
+ | `@windrun-huaiin/backend-core/app/api/webhook/clerk/user/route` | Clerk user webhook API route handler |
63
+
64
+ ### Fingerprint and Upstash
65
+
66
+ Fingerprint and Upstash entries expose server-side configuration and infrastructure helpers for identity and storage-related backend workflows.
67
+
68
+ | Entry | Purpose |
69
+ | --- | --- |
70
+ | `@windrun-huaiin/backend-core/config/fingerprint` | Fingerprint configuration |
71
+ | `@windrun-huaiin/backend-core/upstash/server` | Server-side Upstash helpers |
72
+
73
+ ### AI Services
74
+
75
+ AI entries provide shared AI service utilities and a reusable API route handler for AI endpoints.
76
+
77
+ | Entry | Purpose |
78
+ | --- | --- |
79
+ | `@windrun-huaiin/backend-core/ai` | AI service layer |
80
+ | `@windrun-huaiin/backend-core/app/api/ai/route` | AI API route handler |
81
+
82
+ ## Usage Notes
83
+
84
+ - Use server-only entries from server components, route handlers, server actions, or backend modules.
85
+ - Use API route handler entries when an application wants to mount the package-provided route behavior directly in a Next.js route.
86
+ - Keep Prisma, database, Stripe, auth, and Upstash imports out of client-side code.
87
+ - Prefer feature-specific subpath imports so each application depends only on the backend capabilities it actually uses.
88
+
89
+ ## Installation
90
+
91
+ ```bash
92
+ pnpm add @windrun-huaiin/backend-core
93
+ ```
94
+
95
+ This package is intended for Next.js backend usage. The consuming application is responsible for its environment variables, database setup, authentication provider setup, Stripe setup, and deployment configuration.
@@ -1,6 +1,6 @@
1
1
  import { NextRequest, NextResponse } from 'next/server';
2
2
  /**
3
- * 匿名用户初始化API
3
+ * Anonymous user initialization API.
4
4
  * POST /api/user/anonymous/init
5
5
  */
6
6
  export declare function POST(request: NextRequest): Promise<NextResponse<unknown>>;
@@ -1 +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;AA6rBxD;;;GAGG;AACH,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW,kCAE9C"}
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;AA4rBxD;;;GAGG;AACH,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW,kCAE9C"}
@@ -13,13 +13,13 @@ var userContextFinalizer = require('../../../../../services/context/user-context
13
13
  BigInt.prototype.toJSON = function () {
14
14
  return this.toString();
15
15
  };
16
- // ==================== 工具函数 ====================
17
- /** 创建成功响应对象 */
16
+ // ==================== Utilities ====================
17
+ /** Create a successful response payload */
18
18
  function createSuccessResponse(params) {
19
19
  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);
20
20
  return userContextFinalizer.finalizeUserContext(response);
21
21
  }
22
- /** 创建错误响应 */
22
+ /** Create an error response */
23
23
  function createErrorResponse(message, status = 400) {
24
24
  const errorResponse = { error: message };
25
25
  return server$1.NextResponse.json(errorResponse, { status });
@@ -414,7 +414,7 @@ function finalizeAttribution(sourceRef) {
414
414
  sourceRef.sourceChannel = 'direct';
415
415
  sourceRef.sourceType = 'direct';
416
416
  }
417
- // 提取用户首次访问来源
417
+ // Extract the user's first-touch attribution source.
418
418
  function extractSourceRef(request) {
419
419
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
420
420
  const headerRef = request.headers.get('referer') || request.headers.get('referrer');
@@ -455,7 +455,7 @@ function extractSourceRef(request) {
455
455
  return Object.keys(sourceRef).length > 0 ? sourceRef : null;
456
456
  }
457
457
  /**
458
- * 根据fingerprint_id查询用户并返回响应数据
458
+ * Query the user by Clerk user ID and return response data.
459
459
  */
460
460
  function getUserByClerkId(clerkUserId) {
461
461
  return tslib.__awaiter(this, void 0, void 0, function* () {
@@ -470,7 +470,7 @@ function getUserByClerkId(clerkUserId) {
470
470
  });
471
471
  }
472
472
  /**
473
- * 根据fingerprint_id查询用户并返回响应数据
473
+ * Query the user by fingerprint ID and return response data.
474
474
  */
475
475
  function getUserByFingerprintId(fingerprintId) {
476
476
  return tslib.__awaiter(this, void 0, void 0, function* () {
@@ -490,14 +490,14 @@ function getUserByFingerprintId(fingerprintId) {
490
490
  });
491
491
  }
492
492
  /**
493
- * 通用的fingerprint处理逻辑
493
+ * Shared fingerprint request handling logic.
494
494
  */
495
495
  function handleFingerprintRequest(request_1) {
496
496
  return tslib.__awaiter(this, arguments, void 0, function* (request, options = {}) {
497
497
  var _a;
498
- // 从请求中提取fingerprint ID
498
+ // Extract the fingerprint ID from the request.
499
499
  const fingerprintId = server.extractFingerprintFromNextRequest(request);
500
- // 验证fingerprint ID
500
+ // Validate the fingerprint ID.
501
501
  if (!fingerprintId) {
502
502
  return createErrorResponse('Invalid or missing fingerprint ID');
503
503
  }
@@ -505,27 +505,26 @@ function handleFingerprintRequest(request_1) {
505
505
  const authIdentity = yield authUtils.getOptionalServerAuthIdentity();
506
506
  const clerkUserId = (_a = authIdentity === null || authIdentity === void 0 ? void 0 : authIdentity.providerUserId) !== null && _a !== void 0 ? _a : null;
507
507
  try {
508
- // 优先根据 Clerk ID 查询(如果已登录)
508
+ // Prefer Clerk user ID lookup when the user is authenticated.
509
509
  let existingUserResult = null;
510
510
  if (clerkUserId) {
511
- // 已登录一律按照clerkUserId去查
511
+ // Authenticated users are always resolved by clerkUserId.
512
512
  existingUserResult = yield getUserByClerkId(clerkUserId);
513
513
  if (existingUserResult && existingUserResult.xUser.fingerprintId !== fingerprintId) {
514
- // 说明当前用户的指纹ID发生了改变,为什么呢?因为它使用同一账号去注册Clerk,Clerk判定是同一用户!
515
- // 这个时候一定以登录用户clerkUserId为准
516
- // 但是考虑到同一指纹ID本身可以绑定多个账号,所以这里什么都不做
517
- // 就是以当前登录用户去查他自己的数据就行!
514
+ // The authenticated user's fingerprint changed. Clerk still identifies the account as the same user.
515
+ // Trust clerkUserId as the source of truth and keep resolving the user's own data by login identity.
516
+ // A single fingerprint can be associated with multiple accounts, so no mutation is needed here.
518
517
  console.warn(`Current login user used diff fp_ids: ${clerkUserId}, db_fp_id=${existingUserResult.xUser.fingerprintId}, req_fp_id=${fingerprintId}`);
519
518
  }
520
519
  }
521
520
  else {
522
- // 其次才是检查是否已存在该fingerprint的用户
521
+ // For anonymous requests, fall back to fingerprint lookup.
523
522
  existingUserResult = yield getUserByFingerprintId(fingerprintId);
524
523
  }
525
524
  if (existingUserResult) {
526
525
  return server$1.NextResponse.json(existingUserResult);
527
526
  }
528
- // 如果不存在用户且不允许创建,返回404
527
+ // If the user does not exist and creation is disabled, return 404.
529
528
  if (!options.createIfNotExists) {
530
529
  return createErrorResponse('User not found', 404);
531
530
  }
@@ -534,7 +533,7 @@ function handleFingerprintRequest(request_1) {
534
533
  if (anonymousInitResult.isNewUser) {
535
534
  console.log(`Created new anonymous user ${anonymousInitResult.user.userId} with fingerprint ${fingerprintId}`);
536
535
  }
537
- // 返回创建结果
536
+ // Return the created or existing context.
538
537
  const response = createSuccessResponse({
539
538
  entities: {
540
539
  user: anonymousInitResult.user,
@@ -556,7 +555,7 @@ function handleFingerprintRequest(request_1) {
556
555
  });
557
556
  }
558
557
  /**
559
- * 匿名用户初始化API
558
+ * Anonymous user initialization API.
560
559
  * POST /api/user/anonymous/init
561
560
  */
562
561
  function POST(request) {
@@ -11,13 +11,13 @@ import { finalizeUserContext } from '../../../../../services/context/user-contex
11
11
  BigInt.prototype.toJSON = function () {
12
12
  return this.toString();
13
13
  };
14
- // ==================== 工具函数 ====================
15
- /** 创建成功响应对象 */
14
+ // ==================== Utilities ====================
15
+ /** Create a successful response payload */
16
16
  function createSuccessResponse(params) {
17
17
  const response = Object.assign({ success: true, xUser: mapUserToXUser(params.entities.user), xCredit: params.entities.credit ? mapCreditToXCredit(params.entities.credit) : null, xSubscription: mapSubscriptionToXSubscription(params.entities.subscription), isNewUser: params.isNewUser }, params.options);
18
18
  return finalizeUserContext(response);
19
19
  }
20
- /** 创建错误响应 */
20
+ /** Create an error response */
21
21
  function createErrorResponse(message, status = 400) {
22
22
  const errorResponse = { error: message };
23
23
  return NextResponse.json(errorResponse, { status });
@@ -412,7 +412,7 @@ function finalizeAttribution(sourceRef) {
412
412
  sourceRef.sourceChannel = 'direct';
413
413
  sourceRef.sourceType = 'direct';
414
414
  }
415
- // 提取用户首次访问来源
415
+ // Extract the user's first-touch attribution source.
416
416
  function extractSourceRef(request) {
417
417
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
418
418
  const headerRef = request.headers.get('referer') || request.headers.get('referrer');
@@ -453,7 +453,7 @@ function extractSourceRef(request) {
453
453
  return Object.keys(sourceRef).length > 0 ? sourceRef : null;
454
454
  }
455
455
  /**
456
- * 根据fingerprint_id查询用户并返回响应数据
456
+ * Query the user by Clerk user ID and return response data.
457
457
  */
458
458
  function getUserByClerkId(clerkUserId) {
459
459
  return __awaiter(this, void 0, void 0, function* () {
@@ -468,7 +468,7 @@ function getUserByClerkId(clerkUserId) {
468
468
  });
469
469
  }
470
470
  /**
471
- * 根据fingerprint_id查询用户并返回响应数据
471
+ * Query the user by fingerprint ID and return response data.
472
472
  */
473
473
  function getUserByFingerprintId(fingerprintId) {
474
474
  return __awaiter(this, void 0, void 0, function* () {
@@ -488,14 +488,14 @@ function getUserByFingerprintId(fingerprintId) {
488
488
  });
489
489
  }
490
490
  /**
491
- * 通用的fingerprint处理逻辑
491
+ * Shared fingerprint request handling logic.
492
492
  */
493
493
  function handleFingerprintRequest(request_1) {
494
494
  return __awaiter(this, arguments, void 0, function* (request, options = {}) {
495
495
  var _a;
496
- // 从请求中提取fingerprint ID
496
+ // Extract the fingerprint ID from the request.
497
497
  const fingerprintId = extractFingerprintFromNextRequest(request);
498
- // 验证fingerprint ID
498
+ // Validate the fingerprint ID.
499
499
  if (!fingerprintId) {
500
500
  return createErrorResponse('Invalid or missing fingerprint ID');
501
501
  }
@@ -503,27 +503,26 @@ function handleFingerprintRequest(request_1) {
503
503
  const authIdentity = yield getOptionalServerAuthIdentity();
504
504
  const clerkUserId = (_a = authIdentity === null || authIdentity === void 0 ? void 0 : authIdentity.providerUserId) !== null && _a !== void 0 ? _a : null;
505
505
  try {
506
- // 优先根据 Clerk ID 查询(如果已登录)
506
+ // Prefer Clerk user ID lookup when the user is authenticated.
507
507
  let existingUserResult = null;
508
508
  if (clerkUserId) {
509
- // 已登录一律按照clerkUserId去查
509
+ // Authenticated users are always resolved by clerkUserId.
510
510
  existingUserResult = yield getUserByClerkId(clerkUserId);
511
511
  if (existingUserResult && existingUserResult.xUser.fingerprintId !== fingerprintId) {
512
- // 说明当前用户的指纹ID发生了改变,为什么呢?因为它使用同一账号去注册Clerk,Clerk判定是同一用户!
513
- // 这个时候一定以登录用户clerkUserId为准
514
- // 但是考虑到同一指纹ID本身可以绑定多个账号,所以这里什么都不做
515
- // 就是以当前登录用户去查他自己的数据就行!
512
+ // The authenticated user's fingerprint changed. Clerk still identifies the account as the same user.
513
+ // Trust clerkUserId as the source of truth and keep resolving the user's own data by login identity.
514
+ // A single fingerprint can be associated with multiple accounts, so no mutation is needed here.
516
515
  console.warn(`Current login user used diff fp_ids: ${clerkUserId}, db_fp_id=${existingUserResult.xUser.fingerprintId}, req_fp_id=${fingerprintId}`);
517
516
  }
518
517
  }
519
518
  else {
520
- // 其次才是检查是否已存在该fingerprint的用户
519
+ // For anonymous requests, fall back to fingerprint lookup.
521
520
  existingUserResult = yield getUserByFingerprintId(fingerprintId);
522
521
  }
523
522
  if (existingUserResult) {
524
523
  return NextResponse.json(existingUserResult);
525
524
  }
526
- // 如果不存在用户且不允许创建,返回404
525
+ // If the user does not exist and creation is disabled, return 404.
527
526
  if (!options.createIfNotExists) {
528
527
  return createErrorResponse('User not found', 404);
529
528
  }
@@ -532,7 +531,7 @@ function handleFingerprintRequest(request_1) {
532
531
  if (anonymousInitResult.isNewUser) {
533
532
  console.log(`Created new anonymous user ${anonymousInitResult.user.userId} with fingerprint ${fingerprintId}`);
534
533
  }
535
- // 返回创建结果
534
+ // Return the created or existing context.
536
535
  const response = createSuccessResponse({
537
536
  entities: {
538
537
  user: anonymousInitResult.user,
@@ -554,7 +553,7 @@ function handleFingerprintRequest(request_1) {
554
553
  });
555
554
  }
556
555
  /**
557
- * 匿名用户初始化API
556
+ * Anonymous user initialization API.
558
557
  * POST /api/user/anonymous/init
559
558
  */
560
559
  function POST(request) {
@@ -20,10 +20,10 @@ function POST(request) {
20
20
  return tslib.__awaiter(this, void 0, void 0, function* () {
21
21
  var _a, _b, _c;
22
22
  try {
23
- // 获取原始请求体
23
+ // Read the raw request body.
24
24
  const rawBody = yield request.text();
25
25
  let event;
26
- // 开发环境跳过签名校验
26
+ // Skip signature verification in development.
27
27
  if (process.env.NODE_ENV === 'development') {
28
28
  console.log('Development mode: skipping webhook signature verification');
29
29
  try {
@@ -35,22 +35,22 @@ function POST(request) {
35
35
  }
36
36
  }
37
37
  else {
38
- // 生产环境进行签名校验
38
+ // Verify the signature in production.
39
39
  const headerPayload = yield headers.headers();
40
40
  const svix_id = headerPayload.get('svix-id');
41
41
  const svix_timestamp = headerPayload.get('svix-timestamp');
42
42
  const svix_signature = headerPayload.get('svix-signature');
43
- // 如果缺少必要的header,返回错误
43
+ // Reject requests missing required headers.
44
44
  if (!svix_id || !svix_timestamp || !svix_signature) {
45
45
  return server.NextResponse.json({ error: 'Missing webhook headers' }, { status: 400 });
46
46
  }
47
- // 获取webhook signing secret
47
+ // Load the webhook signing secret.
48
48
  const webhookSecret = process.env.CLERK_WEBHOOK_SECRET;
49
49
  if (!webhookSecret) {
50
50
  console.error('CLERK_WEBHOOK_SECRET is not configured');
51
51
  return server.NextResponse.json({ error: 'Webhook configuration error' }, { status: 500 });
52
52
  }
53
- // 验证webhook签名
53
+ // Verify the webhook signature.
54
54
  try {
55
55
  const wh = new svix.Webhook(webhookSecret);
56
56
  event = wh.verify(rawBody, {
@@ -72,7 +72,7 @@ function POST(request) {
72
72
  }, event);
73
73
  let processingResult = { success: true, message: 'Event processed successfully' };
74
74
  try {
75
- // 处理不同的事件类型
75
+ // Dispatch by event type.
76
76
  const { type } = event;
77
77
  switch (type) {
78
78
  case 'user.created':
@@ -108,7 +108,7 @@ function POST(request) {
108
108
  });
109
109
  }
110
110
  /**
111
- * 处理用户创建事件
111
+ * Handle the user.created event.
112
112
  */
113
113
  function handleUserCreated(event) {
114
114
  return tslib.__awaiter(this, void 0, void 0, function* () {
@@ -127,7 +127,7 @@ function handleUserCreated(event) {
127
127
  fingerprintId,
128
128
  userName
129
129
  });
130
- // 检查必要参数
130
+ // Validate required fields.
131
131
  if (!fingerprintId) {
132
132
  console.error('Missing fingerprintId in webhook data, process flow error');
133
133
  return;
@@ -137,16 +137,16 @@ function handleUserCreated(event) {
137
137
  return;
138
138
  }
139
139
  try {
140
- // 按fingerprintId查询该设备的所有未注销过的用户记录,注销过的记录相当于是死数据
140
+ // Find all non-deleted users for this device fingerprint.
141
141
  const existingUsers = yield user_service.userService.findListByFingerprintId(fingerprintId);
142
142
  if (!existingUsers || existingUsers.length === 0) {
143
143
  console.error('Invalid fingerprintId in webhook data, process flow error');
144
144
  return;
145
145
  }
146
- // 查找email相同的记录
146
+ // Find an existing user with the same email.
147
147
  const sameEmailUser = existingUsers.find(user => user.email === email);
148
148
  if (sameEmailUser) {
149
- // 同一账号,检查是否需要更新clerkUserId
149
+ // Same account; update clerkUserId if needed.
150
150
  if (sameEmailUser.clerkUserId !== clerkUserId) {
151
151
  yield user_service.userService.updateUser(sameEmailUser.userId, { clerkUserId, userName: userName, status: constants.UserStatus.REGISTERED });
152
152
  console.log(`Updated clerkUserId for user ${sameEmailUser.userId}`);
@@ -156,15 +156,15 @@ function handleUserCreated(event) {
156
156
  }
157
157
  return;
158
158
  }
159
- // 查找匿名用户(email为空且clerkUserId为空)
159
+ // Find an anonymous user with no email or clerkUserId.
160
160
  const anonymousUser = existingUsers.find(user => !user.email && !user.clerkUserId && user.status === constants.UserStatus.ANONYMOUS);
161
161
  if (anonymousUser) {
162
- // 匿名用户升级
162
+ // Upgrade the anonymous user.
163
163
  yield user_aggregate_service.userAggregateService.upgradeToRegistered(anonymousUser.userId, email, clerkUserId, userName);
164
164
  console.log(`Successfully upgraded anonymous user ${anonymousUser.userId} to registered user`);
165
165
  return;
166
166
  }
167
- // 同设备新账号,创建新用户
167
+ // New account on the same device; create a new user.
168
168
  yield user_aggregate_service.userAggregateService.createNewRegisteredUser(clerkUserId, email, fingerprintId, userName);
169
169
  console.log(`Created new user for device ${fingerprintId} with email ${email}`);
170
170
  }
@@ -175,7 +175,7 @@ function handleUserCreated(event) {
175
175
  });
176
176
  }
177
177
  /**
178
- * 处理用户删除事件
178
+ * Handle the user.deleted event.
179
179
  */
180
180
  function handleUserDeleted(event) {
181
181
  return tslib.__awaiter(this, void 0, void 0, function* () {
@@ -18,10 +18,10 @@ function POST(request) {
18
18
  return __awaiter(this, void 0, void 0, function* () {
19
19
  var _a, _b, _c;
20
20
  try {
21
- // 获取原始请求体
21
+ // Read the raw request body.
22
22
  const rawBody = yield request.text();
23
23
  let event;
24
- // 开发环境跳过签名校验
24
+ // Skip signature verification in development.
25
25
  if (process.env.NODE_ENV === 'development') {
26
26
  console.log('Development mode: skipping webhook signature verification');
27
27
  try {
@@ -33,22 +33,22 @@ function POST(request) {
33
33
  }
34
34
  }
35
35
  else {
36
- // 生产环境进行签名校验
36
+ // Verify the signature in production.
37
37
  const headerPayload = yield headers();
38
38
  const svix_id = headerPayload.get('svix-id');
39
39
  const svix_timestamp = headerPayload.get('svix-timestamp');
40
40
  const svix_signature = headerPayload.get('svix-signature');
41
- // 如果缺少必要的header,返回错误
41
+ // Reject requests missing required headers.
42
42
  if (!svix_id || !svix_timestamp || !svix_signature) {
43
43
  return NextResponse.json({ error: 'Missing webhook headers' }, { status: 400 });
44
44
  }
45
- // 获取webhook signing secret
45
+ // Load the webhook signing secret.
46
46
  const webhookSecret = process.env.CLERK_WEBHOOK_SECRET;
47
47
  if (!webhookSecret) {
48
48
  console.error('CLERK_WEBHOOK_SECRET is not configured');
49
49
  return NextResponse.json({ error: 'Webhook configuration error' }, { status: 500 });
50
50
  }
51
- // 验证webhook签名
51
+ // Verify the webhook signature.
52
52
  try {
53
53
  const wh = new Webhook(webhookSecret);
54
54
  event = wh.verify(rawBody, {
@@ -70,7 +70,7 @@ function POST(request) {
70
70
  }, event);
71
71
  let processingResult = { success: true, message: 'Event processed successfully' };
72
72
  try {
73
- // 处理不同的事件类型
73
+ // Dispatch by event type.
74
74
  const { type } = event;
75
75
  switch (type) {
76
76
  case 'user.created':
@@ -106,7 +106,7 @@ function POST(request) {
106
106
  });
107
107
  }
108
108
  /**
109
- * 处理用户创建事件
109
+ * Handle the user.created event.
110
110
  */
111
111
  function handleUserCreated(event) {
112
112
  return __awaiter(this, void 0, void 0, function* () {
@@ -125,7 +125,7 @@ function handleUserCreated(event) {
125
125
  fingerprintId,
126
126
  userName
127
127
  });
128
- // 检查必要参数
128
+ // Validate required fields.
129
129
  if (!fingerprintId) {
130
130
  console.error('Missing fingerprintId in webhook data, process flow error');
131
131
  return;
@@ -135,16 +135,16 @@ function handleUserCreated(event) {
135
135
  return;
136
136
  }
137
137
  try {
138
- // 按fingerprintId查询该设备的所有未注销过的用户记录,注销过的记录相当于是死数据
138
+ // Find all non-deleted users for this device fingerprint.
139
139
  const existingUsers = yield userService.findListByFingerprintId(fingerprintId);
140
140
  if (!existingUsers || existingUsers.length === 0) {
141
141
  console.error('Invalid fingerprintId in webhook data, process flow error');
142
142
  return;
143
143
  }
144
- // 查找email相同的记录
144
+ // Find an existing user with the same email.
145
145
  const sameEmailUser = existingUsers.find(user => user.email === email);
146
146
  if (sameEmailUser) {
147
- // 同一账号,检查是否需要更新clerkUserId
147
+ // Same account; update clerkUserId if needed.
148
148
  if (sameEmailUser.clerkUserId !== clerkUserId) {
149
149
  yield userService.updateUser(sameEmailUser.userId, { clerkUserId, userName: userName, status: UserStatus.REGISTERED });
150
150
  console.log(`Updated clerkUserId for user ${sameEmailUser.userId}`);
@@ -154,15 +154,15 @@ function handleUserCreated(event) {
154
154
  }
155
155
  return;
156
156
  }
157
- // 查找匿名用户(email为空且clerkUserId为空)
157
+ // Find an anonymous user with no email or clerkUserId.
158
158
  const anonymousUser = existingUsers.find(user => !user.email && !user.clerkUserId && user.status === UserStatus.ANONYMOUS);
159
159
  if (anonymousUser) {
160
- // 匿名用户升级
160
+ // Upgrade the anonymous user.
161
161
  yield userAggregateService.upgradeToRegistered(anonymousUser.userId, email, clerkUserId, userName);
162
162
  console.log(`Successfully upgraded anonymous user ${anonymousUser.userId} to registered user`);
163
163
  return;
164
164
  }
165
- // 同设备新账号,创建新用户
165
+ // New account on the same device; create a new user.
166
166
  yield userAggregateService.createNewRegisteredUser(clerkUserId, email, fingerprintId, userName);
167
167
  console.log(`Created new user for device ${fingerprintId} with email ${email}`);
168
168
  }
@@ -173,7 +173,7 @@ function handleUserCreated(event) {
173
173
  });
174
174
  }
175
175
  /**
176
- * 处理用户删除事件
176
+ * Handle the user.deleted event.
177
177
  */
178
178
  function handleUserDeleted(event) {
179
179
  return __awaiter(this, void 0, void 0, function* () {
@@ -1,9 +1,6 @@
1
1
  import { NextRequest } from 'next/server';
2
2
  import { User } from '../services/database/prisma-model-type';
3
3
  import { type AuthProvider, type ProviderIdentity } from './auth-shared';
4
- /**
5
- * 认证结果类型
6
- */
7
4
  export interface AuthResult {
8
5
  userId: string;
9
6
  user: User;
@@ -11,48 +8,36 @@ export interface AuthResult {
11
8
  providerUserId: string;
12
9
  }
13
10
  /**
14
- * 从中间件设置的 Clerk ID 获取完整用户信息
11
+ * Fetch User's info from header field by Middleware
15
12
  */
16
13
  export declare function getAuthenticatedUser(req: NextRequest): Promise<AuthResult>;
17
14
  /**
18
- * 要求用户必须已认证,返回用户ID
15
+ * Require Auth, success back user's id
19
16
  */
20
17
  export declare function requireAuth(req: NextRequest): Promise<string>;
21
18
  /**
22
- * 要求用户必须已认证,返回完整用户信息
19
+ * Require Auth, success back user's info
23
20
  */
24
21
  export declare function requireAuthWithUser(req: NextRequest): Promise<AuthResult>;
25
22
  /**
26
- * 服务端场景下获取当前已认证身份(如果存在)
27
- * 适用于只依赖登录态、不需要查询业务用户的逻辑
23
+ * Only use in server side
24
+ * Server Component / Server Action, just need user's login status
28
25
  */
29
26
  export declare function getOptionalServerAuthIdentity(): Promise<ProviderIdentity | null>;
30
27
  /**
31
- * 服务端场景下获取当前已认证用户(如果存在)
32
- * 适用于 Server Component / Server Action 中基于登录态控制展示的逻辑
28
+ * Only use in server side
29
+ * Server Component / Server Action, need user's login status and user's data, will check db
33
30
  */
34
31
  export declare function getOptionalServerAuthUser(): Promise<AuthResult | null>;
35
32
  /**
36
- * API Route版本的认证工具函数
33
+ * API Route Auth Util
37
34
  */
38
35
  export declare class ApiAuthUtils {
39
36
  private req;
40
37
  constructor(req: NextRequest);
41
- /**
42
- * 要求用户必须已认证,返回用户ID
43
- */
44
38
  requireAuth(): Promise<string>;
45
- /**
46
- * 要求用户必须已认证,返回完整用户信息
47
- */
48
39
  requireAuthWithUser(): Promise<AuthResult>;
49
- /**
50
- * 获取用户ID(如果已认证)
51
- */
52
40
  getUserId(): Promise<string | null>;
53
- /**
54
- * 获取完整用户信息(如果已认证)
55
- */
56
41
  getUser(): Promise<AuthResult | null>;
57
42
  }
58
43
  //# sourceMappingURL=auth-utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth-utils.d.ts","sourceRoot":"","sources":["../../src/auth/auth-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG1C,OAAO,EAAE,IAAI,EAAE,MAAM,wCAAwC,CAAC;AAC9D,OAAO,EAA6B,KAAK,YAAY,EAAE,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEpG;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,IAAI,CAAC;IACX,QAAQ,EAAE,YAAY,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAuBhF;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAGnE;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAE/E;AAED;;;GAGG;AACH,wBAAsB,6BAA6B,IAAI,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAetF;AAED;;;GAGG;AACH,wBAAsB,yBAAyB,IAAI,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAsB5E;AAED;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,GAAG,CAAc;gBAEb,GAAG,EAAE,WAAW;IAI5B;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC;IAIpC;;OAEG;IACG,mBAAmB,IAAI,OAAO,CAAC,UAAU,CAAC;IAIhD;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IASzC;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;CAO5C"}
1
+ {"version":3,"file":"auth-utils.d.ts","sourceRoot":"","sources":["../../src/auth/auth-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG1C,OAAO,EAAE,IAAI,EAAE,MAAM,wCAAwC,CAAC;AAC9D,OAAO,EAA6B,KAAK,YAAY,EAAE,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEpG,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,IAAI,CAAC;IACX,QAAQ,EAAE,YAAY,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAuBhF;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAGnE;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAE/E;AAED;;;GAGG;AACH,wBAAsB,6BAA6B,IAAI,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAetF;AAED;;;GAGG;AACH,wBAAsB,yBAAyB,IAAI,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAsB5E;AAED;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,GAAG,CAAc;gBAEb,GAAG,EAAE,WAAW;IAItB,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC;IAI9B,mBAAmB,IAAI,OAAO,CAAC,UAAU,CAAC;IAI1C,SAAS,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IASnC,OAAO,IAAI,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;CAO5C"}