@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.
- package/LICENSE +21 -0
- package/dist/app/api/stripe/checkout/route.d.ts +19 -0
- package/dist/app/api/stripe/checkout/route.d.ts.map +1 -0
- package/dist/app/api/stripe/checkout/route.js +120 -0
- package/dist/app/api/stripe/checkout/route.mjs +118 -0
- package/dist/app/api/stripe/customer-portal/route.d.ts +11 -0
- package/dist/app/api/stripe/customer-portal/route.d.ts.map +1 -0
- package/dist/app/api/stripe/customer-portal/route.js +73 -0
- package/dist/app/api/stripe/customer-portal/route.mjs +71 -0
- package/dist/app/api/user/anonymous/init/route.d.ts +7 -0
- package/dist/app/api/user/anonymous/init/route.d.ts.map +1 -0
- package/dist/app/api/user/anonymous/init/route.js +210 -0
- package/dist/app/api/user/anonymous/init/route.mjs +208 -0
- package/dist/app/api/webhook/clerk/user/route.d.ts +7 -0
- package/dist/app/api/webhook/clerk/user/route.d.ts.map +1 -0
- package/dist/app/api/webhook/clerk/user/route.js +202 -0
- package/dist/app/api/webhook/clerk/user/route.mjs +200 -0
- package/dist/app/api/webhook/stripe/route.d.ts +8 -0
- package/dist/app/api/webhook/stripe/route.d.ts.map +1 -0
- package/dist/app/api/webhook/stripe/route.js +70 -0
- package/dist/app/api/webhook/stripe/route.mjs +67 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +83 -0
- package/dist/index.mjs +18 -0
- package/dist/lib/auth-utils.d.ts +46 -0
- package/dist/lib/auth-utils.d.ts.map +1 -0
- package/dist/lib/auth-utils.js +107 -0
- package/dist/lib/auth-utils.mjs +102 -0
- package/dist/lib/credit-init.d.ts +8 -0
- package/dist/lib/credit-init.d.ts.map +1 -0
- package/dist/lib/credit-init.js +16 -0
- package/dist/lib/credit-init.mjs +10 -0
- package/dist/lib/index.d.ts +5 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +31 -0
- package/dist/lib/index.mjs +4 -0
- package/dist/lib/money-price-config.d.ts +51 -0
- package/dist/lib/money-price-config.d.ts.map +1 -0
- package/dist/lib/money-price-config.js +156 -0
- package/dist/lib/money-price-config.mjs +151 -0
- package/dist/lib/stripe-config.d.ts +31 -0
- package/dist/lib/stripe-config.d.ts.map +1 -0
- package/dist/lib/stripe-config.js +278 -0
- package/dist/lib/stripe-config.mjs +268 -0
- 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
- 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
- package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/classic/errors.js +54 -0
- package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/classic/errors.mjs +51 -0
- package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/classic/iso.js +44 -0
- package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/classic/iso.mjs +35 -0
- package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/classic/parse.js +31 -0
- package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/classic/parse.mjs +18 -0
- package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/classic/schemas.js +587 -0
- package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/classic/schemas.mjs +527 -0
- package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/api.js +447 -0
- package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/api.mjs +399 -0
- package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/checks.js +245 -0
- package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/checks.mjs +232 -0
- package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/core.js +68 -0
- package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/core.mjs +62 -0
- package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/doc.js +39 -0
- package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/doc.mjs +37 -0
- package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/errors.js +80 -0
- package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/errors.mjs +75 -0
- package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/parse.js +101 -0
- package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/parse.mjs +86 -0
- package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/regexes.js +102 -0
- package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/regexes.mjs +76 -0
- package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/registries.js +56 -0
- package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/registries.mjs +52 -0
- package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/schemas.js +1205 -0
- package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/schemas.mjs +1157 -0
- package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/util.js +407 -0
- package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/util.mjs +374 -0
- package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/versions.js +9 -0
- package/dist/node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/core/versions.mjs +7 -0
- package/dist/prisma/client.d.ts +2 -0
- package/dist/prisma/client.d.ts.map +1 -0
- package/dist/prisma/client.js +12 -0
- package/dist/prisma/client.mjs +1 -0
- package/dist/prisma/index.d.ts +4 -0
- package/dist/prisma/index.d.ts.map +1 -0
- package/dist/prisma/index.js +10 -0
- package/dist/prisma/index.mjs +2 -0
- package/dist/prisma/prisma-transaction-util.d.ts +3 -0
- package/dist/prisma/prisma-transaction-util.d.ts.map +1 -0
- package/dist/prisma/prisma-transaction-util.js +29 -0
- package/dist/prisma/prisma-transaction-util.mjs +27 -0
- package/dist/prisma/prisma.d.ts +4 -0
- package/dist/prisma/prisma.d.ts.map +1 -0
- package/dist/prisma/prisma.js +109 -0
- package/dist/prisma/prisma.mjs +106 -0
- package/dist/services/aggregate/billing.aggregate.service.d.ts +83 -0
- package/dist/services/aggregate/billing.aggregate.service.d.ts.map +1 -0
- package/dist/services/aggregate/billing.aggregate.service.js +308 -0
- package/dist/services/aggregate/billing.aggregate.service.mjs +306 -0
- package/dist/services/aggregate/index.d.ts +3 -0
- package/dist/services/aggregate/index.d.ts.map +1 -0
- package/dist/services/aggregate/index.js +9 -0
- package/dist/services/aggregate/index.mjs +2 -0
- package/dist/services/aggregate/user.aggregate.service.d.ts +34 -0
- package/dist/services/aggregate/user.aggregate.service.d.ts.map +1 -0
- package/dist/services/aggregate/user.aggregate.service.js +136 -0
- package/dist/services/aggregate/user.aggregate.service.mjs +133 -0
- package/dist/services/context/index.d.ts +2 -0
- package/dist/services/context/index.d.ts.map +1 -0
- package/dist/services/context/index.js +13 -0
- package/dist/services/context/index.mjs +1 -0
- package/dist/services/context/user-context-service.d.ts +30 -0
- package/dist/services/context/user-context-service.d.ts.map +1 -0
- package/dist/services/context/user-context-service.js +170 -0
- package/dist/services/context/user-context-service.mjs +162 -0
- package/dist/services/database/apilog.service.d.ts +39 -0
- package/dist/services/database/apilog.service.d.ts.map +1 -0
- package/dist/services/database/apilog.service.js +174 -0
- package/dist/services/database/apilog.service.mjs +170 -0
- package/dist/services/database/constants.d.ts +73 -0
- package/dist/services/database/constants.d.ts.map +1 -0
- package/dist/services/database/constants.js +135 -0
- package/dist/services/database/constants.mjs +117 -0
- package/dist/services/database/credit.service.d.ts +107 -0
- package/dist/services/database/credit.service.d.ts.map +1 -0
- package/dist/services/database/credit.service.js +515 -0
- package/dist/services/database/credit.service.mjs +512 -0
- package/dist/services/database/creditAuditLog.service.d.ts +73 -0
- package/dist/services/database/creditAuditLog.service.d.ts.map +1 -0
- package/dist/services/database/creditAuditLog.service.js +305 -0
- package/dist/services/database/creditAuditLog.service.mjs +302 -0
- package/dist/services/database/index.d.ts +10 -0
- package/dist/services/database/index.d.ts.map +1 -0
- package/dist/services/database/index.js +38 -0
- package/dist/services/database/index.mjs +8 -0
- package/dist/services/database/prisma-model-type.d.ts +3 -0
- package/dist/services/database/prisma-model-type.d.ts.map +1 -0
- package/dist/services/database/subscription.service.d.ts +48 -0
- package/dist/services/database/subscription.service.d.ts.map +1 -0
- package/dist/services/database/subscription.service.js +267 -0
- package/dist/services/database/subscription.service.mjs +264 -0
- package/dist/services/database/transaction.service.d.ts +92 -0
- package/dist/services/database/transaction.service.d.ts.map +1 -0
- package/dist/services/database/transaction.service.js +326 -0
- package/dist/services/database/transaction.service.mjs +323 -0
- package/dist/services/database/user.service.d.ts +45 -0
- package/dist/services/database/user.service.d.ts.map +1 -0
- package/dist/services/database/user.service.js +180 -0
- package/dist/services/database/user.service.mjs +177 -0
- package/dist/services/database/userBackup.service.d.ts +45 -0
- package/dist/services/database/userBackup.service.d.ts.map +1 -0
- package/dist/services/database/userBackup.service.js +249 -0
- package/dist/services/database/userBackup.service.mjs +246 -0
- package/dist/services/stripe/index.d.ts +2 -0
- package/dist/services/stripe/index.d.ts.map +1 -0
- package/dist/services/stripe/index.js +7 -0
- package/dist/services/stripe/index.mjs +1 -0
- package/dist/services/stripe/webhook-handler.d.ts +6 -0
- package/dist/services/stripe/webhook-handler.d.ts.map +1 -0
- package/dist/services/stripe/webhook-handler.js +537 -0
- package/dist/services/stripe/webhook-handler.mjs +535 -0
- package/migrations/create.sql +176 -0
- package/migrations/db.init.sql +13 -0
- package/migrations/init-schema.sql +19 -0
- package/migrations/purge.sql +27 -0
- package/migrations/test-check.sql +167 -0
- package/package.json +123 -0
- package/prisma/schema.prisma +191 -0
- package/src/app/api/stripe/checkout/route.ts +145 -0
- package/src/app/api/stripe/customer-portal/route.ts +83 -0
- package/src/app/api/user/anonymous/init/route.ts +284 -0
- package/src/app/api/webhook/clerk/user/route.ts +249 -0
- package/src/app/api/webhook/stripe/route.ts +93 -0
- package/src/index.ts +6 -0
- package/src/lib/auth-utils.ts +101 -0
- package/src/lib/credit-init.ts +9 -0
- package/src/lib/index.ts +4 -0
- package/src/lib/money-price-config.ts +168 -0
- package/src/lib/stripe-config.ts +333 -0
- package/src/prisma/client.ts +2 -0
- package/src/prisma/index.ts +3 -0
- package/src/prisma/prisma-transaction-util.ts +24 -0
- package/src/prisma/prisma.ts +122 -0
- package/src/services/aggregate/billing.aggregate.service.ts +498 -0
- package/src/services/aggregate/index.ts +2 -0
- package/src/services/aggregate/user.aggregate.service.ts +168 -0
- package/src/services/context/index.ts +1 -0
- package/src/services/context/user-context-service.ts +200 -0
- package/src/services/database/apilog.service.ts +185 -0
- package/src/services/database/constants.ts +148 -0
- package/src/services/database/credit.service.ts +747 -0
- package/src/services/database/creditAuditLog.service.ts +402 -0
- package/src/services/database/index.ts +41 -0
- package/src/services/database/prisma-model-type.ts +13 -0
- package/src/services/database/subscription.service.ts +319 -0
- package/src/services/database/transaction.service.ts +447 -0
- package/src/services/database/user.service.ts +218 -0
- package/src/services/database/userBackup.service.ts +290 -0
- package/src/services/stripe/index.ts +1 -0
- package/src/services/stripe/webhook-handler.ts +648 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { __awaiter, __rest } 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 { userAggregateService } from '../../../../../services/aggregate/user.aggregate.service.mjs';
|
|
3
|
+
import '../../../../../prisma/prisma.mjs';
|
|
4
|
+
import '../../../../../services/database/credit.service.mjs';
|
|
5
|
+
import '@prisma/client';
|
|
6
|
+
import { extractFingerprintFromNextRequest } from '@windrun-huaiin/third-ui/fingerprint/server';
|
|
7
|
+
import { auth } from '@clerk/nextjs/server';
|
|
8
|
+
import { NextResponse } from 'next/server';
|
|
9
|
+
import { fetchUserContextByClerkUserId, fetchLatestUserContextByFingerprintId, mapSubscriptionToXSubscription, mapCreditToXCredit, mapUserToXUser, applyUserMockContext } from '../../../../../services/context/user-context-service.mjs';
|
|
10
|
+
|
|
11
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
12
|
+
// Fix BigInt serialization issue
|
|
13
|
+
BigInt.prototype.toJSON = function () {
|
|
14
|
+
return this.toString();
|
|
15
|
+
};
|
|
16
|
+
// ==================== 工具函数 ====================
|
|
17
|
+
/** 创建成功响应对象 */
|
|
18
|
+
function createSuccessResponse(params) {
|
|
19
|
+
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);
|
|
20
|
+
return applyUserMockContext(response);
|
|
21
|
+
}
|
|
22
|
+
/** 创建错误响应 */
|
|
23
|
+
function createErrorResponse(message, status = 400) {
|
|
24
|
+
const errorResponse = { error: message };
|
|
25
|
+
return NextResponse.json(errorResponse, { status });
|
|
26
|
+
}
|
|
27
|
+
const SOURCE_REF_MAX_LENGTH = 2048;
|
|
28
|
+
const QUERY_PARAM_MAX_LENGTH = 512;
|
|
29
|
+
function normalizeSourceRef(ref) {
|
|
30
|
+
if (!ref) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
const trimmed = ref.trim();
|
|
34
|
+
if (!trimmed) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
return trimmed.length > SOURCE_REF_MAX_LENGTH
|
|
38
|
+
? trimmed.slice(0, SOURCE_REF_MAX_LENGTH)
|
|
39
|
+
: trimmed;
|
|
40
|
+
}
|
|
41
|
+
function normalizeQueryParam(value) {
|
|
42
|
+
if (!value) {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
const trimmed = value.trim();
|
|
46
|
+
if (!trimmed) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
return trimmed.length > QUERY_PARAM_MAX_LENGTH
|
|
50
|
+
? trimmed.slice(0, QUERY_PARAM_MAX_LENGTH)
|
|
51
|
+
: trimmed;
|
|
52
|
+
}
|
|
53
|
+
function applySearchParams(sourceRef, params) {
|
|
54
|
+
const setIfEmpty = (key, value) => {
|
|
55
|
+
if (sourceRef[key] !== undefined) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const normalized = normalizeQueryParam(value);
|
|
59
|
+
if (normalized) {
|
|
60
|
+
sourceRef[key] = normalized;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
setIfEmpty('utmSource', params.get('utm_source'));
|
|
64
|
+
setIfEmpty('utmMedium', params.get('utm_medium'));
|
|
65
|
+
setIfEmpty('utmCampaign', params.get('utm_campaign'));
|
|
66
|
+
setIfEmpty('utmTerm', params.get('utm_term'));
|
|
67
|
+
setIfEmpty('utmContent', params.get('utm_content'));
|
|
68
|
+
setIfEmpty('ref', params.get('ref'));
|
|
69
|
+
}
|
|
70
|
+
// 提取用户首次访问来源
|
|
71
|
+
function extractSourceRef(request) {
|
|
72
|
+
const headerRef = request.headers.get('referer') || request.headers.get('referrer');
|
|
73
|
+
const customRef = request.headers.get('x-source-ref');
|
|
74
|
+
const queryRef = request.nextUrl.searchParams.get('ref');
|
|
75
|
+
console.log({
|
|
76
|
+
headerRef,
|
|
77
|
+
customRef,
|
|
78
|
+
queryRef
|
|
79
|
+
});
|
|
80
|
+
const sourceRef = {};
|
|
81
|
+
let normalizedHttpRef = null;
|
|
82
|
+
const candidates = [headerRef, customRef, queryRef];
|
|
83
|
+
for (const candidate of candidates) {
|
|
84
|
+
const normalized = normalizeSourceRef(candidate);
|
|
85
|
+
if (normalized) {
|
|
86
|
+
normalizedHttpRef = normalized;
|
|
87
|
+
sourceRef.httpRefer = normalized;
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const searchParams = request.nextUrl.searchParams;
|
|
92
|
+
applySearchParams(sourceRef, searchParams);
|
|
93
|
+
if (normalizedHttpRef) {
|
|
94
|
+
try {
|
|
95
|
+
const refererUrl = new URL(normalizedHttpRef);
|
|
96
|
+
applySearchParams(sourceRef, refererUrl.searchParams);
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
console.warn('Failed to parse referer url for utm/ref:', error);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return Object.keys(sourceRef).length > 0 ? sourceRef : null;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* 根据fingerprint_id查询用户并返回响应数据
|
|
106
|
+
*/
|
|
107
|
+
function getUserByClerkId(clerkUserId) {
|
|
108
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
109
|
+
const entities = yield fetchUserContextByClerkUserId(clerkUserId);
|
|
110
|
+
if (!entities) {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
return createSuccessResponse({
|
|
114
|
+
entities,
|
|
115
|
+
isNewUser: false,
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* 根据fingerprint_id查询用户并返回响应数据
|
|
121
|
+
*/
|
|
122
|
+
function getUserByFingerprintId(fingerprintId) {
|
|
123
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
124
|
+
const result = yield fetchLatestUserContextByFingerprintId(fingerprintId);
|
|
125
|
+
if (!result) {
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
const { totalUsersOnDevice, hasAnonymousUser } = result, entities = __rest(result, ["totalUsersOnDevice", "hasAnonymousUser"]);
|
|
129
|
+
return createSuccessResponse({
|
|
130
|
+
entities,
|
|
131
|
+
isNewUser: false,
|
|
132
|
+
options: {
|
|
133
|
+
totalUsersOnDevice,
|
|
134
|
+
hasAnonymousUser,
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* 通用的fingerprint处理逻辑
|
|
141
|
+
*/
|
|
142
|
+
function handleFingerprintRequest(request_1) {
|
|
143
|
+
return __awaiter(this, arguments, void 0, function* (request, options = {}) {
|
|
144
|
+
// 从请求中提取fingerprint ID
|
|
145
|
+
const fingerprintId = extractFingerprintFromNextRequest(request);
|
|
146
|
+
// 验证fingerprint ID
|
|
147
|
+
if (!fingerprintId) {
|
|
148
|
+
return createErrorResponse('Invalid or missing fingerprint ID');
|
|
149
|
+
}
|
|
150
|
+
console.log('Received fingerprintId:', fingerprintId);
|
|
151
|
+
const { userId: clerkUserId } = yield auth();
|
|
152
|
+
try {
|
|
153
|
+
// 优先根据 Clerk ID 查询(如果已登录)
|
|
154
|
+
let existingUserResult = null;
|
|
155
|
+
if (clerkUserId) {
|
|
156
|
+
// 已登录一律按照clerkUserId去查
|
|
157
|
+
existingUserResult = yield getUserByClerkId(clerkUserId);
|
|
158
|
+
if (existingUserResult && existingUserResult.xUser.fingerprintId !== fingerprintId) {
|
|
159
|
+
// 说明当前用户的指纹ID发生了改变,为什么呢?因为它使用同一账号去注册Clerk,Clerk判定是同一用户!
|
|
160
|
+
// 这个时候一定以登录用户clerkUserId为准
|
|
161
|
+
// 但是考虑到同一指纹ID本身可以绑定多个账号,所以这里什么都不做
|
|
162
|
+
// 就是以当前登录用户去查他自己的数据就行!
|
|
163
|
+
console.warn(`Current login user used diff fp_ids: ${clerkUserId}, db_fp_id=${existingUserResult.xUser.fingerprintId}, req_fp_id=${fingerprintId}`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
// 其次才是检查是否已存在该fingerprint的用户
|
|
168
|
+
existingUserResult = yield getUserByFingerprintId(fingerprintId);
|
|
169
|
+
}
|
|
170
|
+
if (existingUserResult) {
|
|
171
|
+
return NextResponse.json(existingUserResult);
|
|
172
|
+
}
|
|
173
|
+
// 如果不存在用户且不允许创建,返回404
|
|
174
|
+
if (!options.createIfNotExists) {
|
|
175
|
+
return createErrorResponse('User not found', 404);
|
|
176
|
+
}
|
|
177
|
+
const sourceRef = extractSourceRef(request);
|
|
178
|
+
// 创建新的匿名用户
|
|
179
|
+
const { newUser, credit } = yield userAggregateService.initAnonymousUser(fingerprintId, { sourceRef: sourceRef !== null && sourceRef !== void 0 ? sourceRef : undefined });
|
|
180
|
+
console.log(`Created new anonymous user ${newUser.userId} with fingerprint ${fingerprintId}`);
|
|
181
|
+
// 返回创建结果
|
|
182
|
+
const response = createSuccessResponse({
|
|
183
|
+
entities: {
|
|
184
|
+
user: newUser,
|
|
185
|
+
credit,
|
|
186
|
+
subscription: null,
|
|
187
|
+
},
|
|
188
|
+
isNewUser: true,
|
|
189
|
+
});
|
|
190
|
+
return NextResponse.json(response);
|
|
191
|
+
}
|
|
192
|
+
catch (error) {
|
|
193
|
+
console.error('Fingerprint request error:', error);
|
|
194
|
+
return createErrorResponse('Internal server error', 500);
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* 匿名用户初始化API
|
|
200
|
+
* POST /api/user/anonymous/init
|
|
201
|
+
*/
|
|
202
|
+
function POST(request) {
|
|
203
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
204
|
+
return handleFingerprintRequest(request, { createIfNotExists: true });
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export { POST };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../../src/app/api/webhook/clerk/user/route.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AA+BxD,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW;;;;IAiH9C"}
|
|
@@ -0,0 +1,202 @@
|
|
|
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
|
+
var user_service = require('../../../../../services/database/user.service.js');
|
|
6
|
+
var constants = require('../../../../../services/database/constants.js');
|
|
7
|
+
require('../../../../../prisma/prisma.js');
|
|
8
|
+
require('../../../../../services/database/credit.service.js');
|
|
9
|
+
require('@prisma/client');
|
|
10
|
+
var apilog_service = require('../../../../../services/database/apilog.service.js');
|
|
11
|
+
var headers = require('next/headers');
|
|
12
|
+
var server = require('next/server');
|
|
13
|
+
var svix = require('svix');
|
|
14
|
+
|
|
15
|
+
// Fix BigInt serialization issue
|
|
16
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17
|
+
BigInt.prototype.toJSON = function () {
|
|
18
|
+
return this.toString();
|
|
19
|
+
};
|
|
20
|
+
function POST(request) {
|
|
21
|
+
return tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
22
|
+
var _a, _b, _c;
|
|
23
|
+
try {
|
|
24
|
+
// 获取原始请求体
|
|
25
|
+
const rawBody = yield request.text();
|
|
26
|
+
let event;
|
|
27
|
+
// 开发环境跳过签名校验
|
|
28
|
+
if (process.env.NODE_ENV === 'development') {
|
|
29
|
+
console.log('Development mode: skipping webhook signature verification');
|
|
30
|
+
try {
|
|
31
|
+
event = JSON.parse(rawBody);
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
console.error('Failed to parse webhook body:', err);
|
|
35
|
+
return server.NextResponse.json({ error: 'Invalid webhook body' }, { status: 400 });
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
// 生产环境进行签名校验
|
|
40
|
+
const headerPayload = yield headers.headers();
|
|
41
|
+
const svix_id = headerPayload.get('svix-id');
|
|
42
|
+
const svix_timestamp = headerPayload.get('svix-timestamp');
|
|
43
|
+
const svix_signature = headerPayload.get('svix-signature');
|
|
44
|
+
// 如果缺少必要的header,返回错误
|
|
45
|
+
if (!svix_id || !svix_timestamp || !svix_signature) {
|
|
46
|
+
return server.NextResponse.json({ error: 'Missing webhook headers' }, { status: 400 });
|
|
47
|
+
}
|
|
48
|
+
// 获取webhook signing secret
|
|
49
|
+
const webhookSecret = process.env.CLERK_WEBHOOK_SECRET;
|
|
50
|
+
if (!webhookSecret) {
|
|
51
|
+
console.error('CLERK_WEBHOOK_SECRET is not configured');
|
|
52
|
+
return server.NextResponse.json({ error: 'Webhook configuration error' }, { status: 500 });
|
|
53
|
+
}
|
|
54
|
+
// 验证webhook签名
|
|
55
|
+
try {
|
|
56
|
+
const wh = new svix.Webhook(webhookSecret);
|
|
57
|
+
event = wh.verify(rawBody, {
|
|
58
|
+
'svix-id': svix_id,
|
|
59
|
+
'svix-timestamp': svix_timestamp,
|
|
60
|
+
'svix-signature': svix_signature,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
console.error('Webhook signature verification failed:', err);
|
|
65
|
+
return server.NextResponse.json({ error: 'Webhook signature verification failed' }, { status: 400 });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// Log the incoming webhook
|
|
69
|
+
const logId = yield apilog_service.Apilogger.logClerkIncoming(`${event.type}`, {
|
|
70
|
+
clerk_user_id: event.data.id,
|
|
71
|
+
email: (_b = (_a = event.data.email_addresses) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.email_address,
|
|
72
|
+
fingerprint_id: (_c = event.data.unsafe_metadata) === null || _c === void 0 ? void 0 : _c.fingerprint_id
|
|
73
|
+
}, event);
|
|
74
|
+
let processingResult = { success: true, message: 'Event processed successfully' };
|
|
75
|
+
try {
|
|
76
|
+
// 处理不同的事件类型
|
|
77
|
+
const { type } = event;
|
|
78
|
+
switch (type) {
|
|
79
|
+
case 'user.created':
|
|
80
|
+
yield handleUserCreated(event);
|
|
81
|
+
break;
|
|
82
|
+
case 'user.deleted':
|
|
83
|
+
yield handleUserDeleted(event);
|
|
84
|
+
break;
|
|
85
|
+
default:
|
|
86
|
+
console.log(`Unhandled event type: ${type}`);
|
|
87
|
+
processingResult = { success: false, message: `Unhandled event type: ${type}` };
|
|
88
|
+
}
|
|
89
|
+
// Update response in log
|
|
90
|
+
apilog_service.Apilogger.updateResponse(logId, processingResult);
|
|
91
|
+
return server.NextResponse.json({ received: true });
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
console.error('Webhook processing error:', error);
|
|
95
|
+
// Update error response in log
|
|
96
|
+
const errorResult = {
|
|
97
|
+
success: false,
|
|
98
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
99
|
+
stack: error instanceof Error ? error.stack : undefined
|
|
100
|
+
};
|
|
101
|
+
apilog_service.Apilogger.updateResponse(logId, errorResult);
|
|
102
|
+
return server.NextResponse.json({ error: 'Internal server error' }, { status: 500 });
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
console.error('Webhook processing error:', error);
|
|
107
|
+
return server.NextResponse.json({ error: 'Internal server error' }, { status: 500 });
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* 处理用户创建事件
|
|
113
|
+
*/
|
|
114
|
+
function handleUserCreated(event) {
|
|
115
|
+
return tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
116
|
+
var _a, _b;
|
|
117
|
+
const { data } = event;
|
|
118
|
+
const clerkUserId = data.id;
|
|
119
|
+
const email = (_b = (_a = data.email_addresses) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.email_address;
|
|
120
|
+
const unsafeMetadata = data.unsafe_metadata;
|
|
121
|
+
const fingerprintId = unsafeMetadata === null || unsafeMetadata === void 0 ? void 0 : unsafeMetadata.fingerprint_id;
|
|
122
|
+
const userName = data.username
|
|
123
|
+
? data.username
|
|
124
|
+
: [data.first_name, data.last_name].filter(Boolean).join(' ') || undefined;
|
|
125
|
+
console.log('Processing user.created event:', {
|
|
126
|
+
clerkUserId,
|
|
127
|
+
email,
|
|
128
|
+
fingerprintId,
|
|
129
|
+
userName
|
|
130
|
+
});
|
|
131
|
+
// 检查必要参数
|
|
132
|
+
if (!fingerprintId) {
|
|
133
|
+
console.error('Missing fingerprintId in webhook data, process flow error');
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
if (!email) {
|
|
137
|
+
console.error('Missing email in webhook data');
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
try {
|
|
141
|
+
// 按fingerprintId查询该设备的所有未注销过的用户记录,注销过的记录相当于是死数据
|
|
142
|
+
const existingUsers = yield user_service.userService.findListByFingerprintId(fingerprintId);
|
|
143
|
+
if (!existingUsers || existingUsers.length === 0) {
|
|
144
|
+
console.error('Invalid fingerprintId in webhook data, process flow error');
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
// 查找email相同的记录
|
|
148
|
+
const sameEmailUser = existingUsers.find(user => user.email === email);
|
|
149
|
+
if (sameEmailUser) {
|
|
150
|
+
// 同一账号,检查是否需要更新clerkUserId
|
|
151
|
+
if (sameEmailUser.clerkUserId !== clerkUserId) {
|
|
152
|
+
yield user_service.userService.updateUser(sameEmailUser.userId, { clerkUserId, userName: userName, status: constants.UserStatus.REGISTERED });
|
|
153
|
+
console.log(`Updated clerkUserId for user ${sameEmailUser.userId}`);
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
console.log(`User with email ${email} already exists, skipping duplicate message`);
|
|
157
|
+
}
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
// 查找匿名用户(email为空且clerkUserId为空)
|
|
161
|
+
const anonymousUser = existingUsers.find(user => !user.email && !user.clerkUserId && user.status === constants.UserStatus.ANONYMOUS);
|
|
162
|
+
if (anonymousUser) {
|
|
163
|
+
// 匿名用户升级
|
|
164
|
+
yield user_aggregate_service.userAggregateService.upgradeToRegistered(anonymousUser.userId, email, clerkUserId, userName);
|
|
165
|
+
console.log(`Successfully upgraded anonymous user ${anonymousUser.userId} to registered user`);
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
// 同设备新账号,创建新用户
|
|
169
|
+
yield user_aggregate_service.userAggregateService.createNewRegisteredUser(clerkUserId, email, fingerprintId, userName);
|
|
170
|
+
console.log(`Created new user for device ${fingerprintId} with email ${email}`);
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
console.error('Error handling user.created event:', error);
|
|
174
|
+
throw error;
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* 处理用户删除事件
|
|
180
|
+
*/
|
|
181
|
+
function handleUserDeleted(event) {
|
|
182
|
+
return tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
183
|
+
const { data } = event;
|
|
184
|
+
const clerkUserId = data.id;
|
|
185
|
+
console.log('Processing user.deleted event:', { clerkUserId });
|
|
186
|
+
try {
|
|
187
|
+
const userId = yield user_aggregate_service.userAggregateService.handleUserUnregister(clerkUserId);
|
|
188
|
+
if (!userId) {
|
|
189
|
+
console.warn(`User not found, skipping oprate , (clerkUserId: ${clerkUserId})`);
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
console.log(`Successfully deleted user ${userId} , (clerkUserId: ${clerkUserId})`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
catch (error) {
|
|
196
|
+
console.error('Error handling user.deleted event:', error);
|
|
197
|
+
throw error;
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
exports.POST = POST;
|
|
@@ -0,0 +1,200 @@
|
|
|
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 { userAggregateService } from '../../../../../services/aggregate/user.aggregate.service.mjs';
|
|
3
|
+
import { userService } from '../../../../../services/database/user.service.mjs';
|
|
4
|
+
import { UserStatus } from '../../../../../services/database/constants.mjs';
|
|
5
|
+
import '../../../../../prisma/prisma.mjs';
|
|
6
|
+
import '../../../../../services/database/credit.service.mjs';
|
|
7
|
+
import '@prisma/client';
|
|
8
|
+
import { Apilogger } from '../../../../../services/database/apilog.service.mjs';
|
|
9
|
+
import { headers } from 'next/headers';
|
|
10
|
+
import { NextResponse } from 'next/server';
|
|
11
|
+
import { Webhook } from 'svix';
|
|
12
|
+
|
|
13
|
+
// Fix BigInt serialization issue
|
|
14
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
15
|
+
BigInt.prototype.toJSON = function () {
|
|
16
|
+
return this.toString();
|
|
17
|
+
};
|
|
18
|
+
function POST(request) {
|
|
19
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
20
|
+
var _a, _b, _c;
|
|
21
|
+
try {
|
|
22
|
+
// 获取原始请求体
|
|
23
|
+
const rawBody = yield request.text();
|
|
24
|
+
let event;
|
|
25
|
+
// 开发环境跳过签名校验
|
|
26
|
+
if (process.env.NODE_ENV === 'development') {
|
|
27
|
+
console.log('Development mode: skipping webhook signature verification');
|
|
28
|
+
try {
|
|
29
|
+
event = JSON.parse(rawBody);
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
console.error('Failed to parse webhook body:', err);
|
|
33
|
+
return NextResponse.json({ error: 'Invalid webhook body' }, { status: 400 });
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
// 生产环境进行签名校验
|
|
38
|
+
const headerPayload = yield headers();
|
|
39
|
+
const svix_id = headerPayload.get('svix-id');
|
|
40
|
+
const svix_timestamp = headerPayload.get('svix-timestamp');
|
|
41
|
+
const svix_signature = headerPayload.get('svix-signature');
|
|
42
|
+
// 如果缺少必要的header,返回错误
|
|
43
|
+
if (!svix_id || !svix_timestamp || !svix_signature) {
|
|
44
|
+
return NextResponse.json({ error: 'Missing webhook headers' }, { status: 400 });
|
|
45
|
+
}
|
|
46
|
+
// 获取webhook signing secret
|
|
47
|
+
const webhookSecret = process.env.CLERK_WEBHOOK_SECRET;
|
|
48
|
+
if (!webhookSecret) {
|
|
49
|
+
console.error('CLERK_WEBHOOK_SECRET is not configured');
|
|
50
|
+
return NextResponse.json({ error: 'Webhook configuration error' }, { status: 500 });
|
|
51
|
+
}
|
|
52
|
+
// 验证webhook签名
|
|
53
|
+
try {
|
|
54
|
+
const wh = new Webhook(webhookSecret);
|
|
55
|
+
event = wh.verify(rawBody, {
|
|
56
|
+
'svix-id': svix_id,
|
|
57
|
+
'svix-timestamp': svix_timestamp,
|
|
58
|
+
'svix-signature': svix_signature,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
console.error('Webhook signature verification failed:', err);
|
|
63
|
+
return NextResponse.json({ error: 'Webhook signature verification failed' }, { status: 400 });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// Log the incoming webhook
|
|
67
|
+
const logId = yield Apilogger.logClerkIncoming(`${event.type}`, {
|
|
68
|
+
clerk_user_id: event.data.id,
|
|
69
|
+
email: (_b = (_a = event.data.email_addresses) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.email_address,
|
|
70
|
+
fingerprint_id: (_c = event.data.unsafe_metadata) === null || _c === void 0 ? void 0 : _c.fingerprint_id
|
|
71
|
+
}, event);
|
|
72
|
+
let processingResult = { success: true, message: 'Event processed successfully' };
|
|
73
|
+
try {
|
|
74
|
+
// 处理不同的事件类型
|
|
75
|
+
const { type } = event;
|
|
76
|
+
switch (type) {
|
|
77
|
+
case 'user.created':
|
|
78
|
+
yield handleUserCreated(event);
|
|
79
|
+
break;
|
|
80
|
+
case 'user.deleted':
|
|
81
|
+
yield handleUserDeleted(event);
|
|
82
|
+
break;
|
|
83
|
+
default:
|
|
84
|
+
console.log(`Unhandled event type: ${type}`);
|
|
85
|
+
processingResult = { success: false, message: `Unhandled event type: ${type}` };
|
|
86
|
+
}
|
|
87
|
+
// Update response in log
|
|
88
|
+
Apilogger.updateResponse(logId, processingResult);
|
|
89
|
+
return NextResponse.json({ received: true });
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
console.error('Webhook processing error:', error);
|
|
93
|
+
// Update error response in log
|
|
94
|
+
const errorResult = {
|
|
95
|
+
success: false,
|
|
96
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
97
|
+
stack: error instanceof Error ? error.stack : undefined
|
|
98
|
+
};
|
|
99
|
+
Apilogger.updateResponse(logId, errorResult);
|
|
100
|
+
return NextResponse.json({ error: 'Internal server error' }, { status: 500 });
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
console.error('Webhook processing error:', error);
|
|
105
|
+
return NextResponse.json({ error: 'Internal server error' }, { status: 500 });
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* 处理用户创建事件
|
|
111
|
+
*/
|
|
112
|
+
function handleUserCreated(event) {
|
|
113
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
114
|
+
var _a, _b;
|
|
115
|
+
const { data } = event;
|
|
116
|
+
const clerkUserId = data.id;
|
|
117
|
+
const email = (_b = (_a = data.email_addresses) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.email_address;
|
|
118
|
+
const unsafeMetadata = data.unsafe_metadata;
|
|
119
|
+
const fingerprintId = unsafeMetadata === null || unsafeMetadata === void 0 ? void 0 : unsafeMetadata.fingerprint_id;
|
|
120
|
+
const userName = data.username
|
|
121
|
+
? data.username
|
|
122
|
+
: [data.first_name, data.last_name].filter(Boolean).join(' ') || undefined;
|
|
123
|
+
console.log('Processing user.created event:', {
|
|
124
|
+
clerkUserId,
|
|
125
|
+
email,
|
|
126
|
+
fingerprintId,
|
|
127
|
+
userName
|
|
128
|
+
});
|
|
129
|
+
// 检查必要参数
|
|
130
|
+
if (!fingerprintId) {
|
|
131
|
+
console.error('Missing fingerprintId in webhook data, process flow error');
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
if (!email) {
|
|
135
|
+
console.error('Missing email in webhook data');
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
// 按fingerprintId查询该设备的所有未注销过的用户记录,注销过的记录相当于是死数据
|
|
140
|
+
const existingUsers = yield userService.findListByFingerprintId(fingerprintId);
|
|
141
|
+
if (!existingUsers || existingUsers.length === 0) {
|
|
142
|
+
console.error('Invalid fingerprintId in webhook data, process flow error');
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
// 查找email相同的记录
|
|
146
|
+
const sameEmailUser = existingUsers.find(user => user.email === email);
|
|
147
|
+
if (sameEmailUser) {
|
|
148
|
+
// 同一账号,检查是否需要更新clerkUserId
|
|
149
|
+
if (sameEmailUser.clerkUserId !== clerkUserId) {
|
|
150
|
+
yield userService.updateUser(sameEmailUser.userId, { clerkUserId, userName: userName, status: UserStatus.REGISTERED });
|
|
151
|
+
console.log(`Updated clerkUserId for user ${sameEmailUser.userId}`);
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
console.log(`User with email ${email} already exists, skipping duplicate message`);
|
|
155
|
+
}
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
// 查找匿名用户(email为空且clerkUserId为空)
|
|
159
|
+
const anonymousUser = existingUsers.find(user => !user.email && !user.clerkUserId && user.status === UserStatus.ANONYMOUS);
|
|
160
|
+
if (anonymousUser) {
|
|
161
|
+
// 匿名用户升级
|
|
162
|
+
yield userAggregateService.upgradeToRegistered(anonymousUser.userId, email, clerkUserId, userName);
|
|
163
|
+
console.log(`Successfully upgraded anonymous user ${anonymousUser.userId} to registered user`);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
// 同设备新账号,创建新用户
|
|
167
|
+
yield userAggregateService.createNewRegisteredUser(clerkUserId, email, fingerprintId, userName);
|
|
168
|
+
console.log(`Created new user for device ${fingerprintId} with email ${email}`);
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
console.error('Error handling user.created event:', error);
|
|
172
|
+
throw error;
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* 处理用户删除事件
|
|
178
|
+
*/
|
|
179
|
+
function handleUserDeleted(event) {
|
|
180
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
181
|
+
const { data } = event;
|
|
182
|
+
const clerkUserId = data.id;
|
|
183
|
+
console.log('Processing user.deleted event:', { clerkUserId });
|
|
184
|
+
try {
|
|
185
|
+
const userId = yield userAggregateService.handleUserUnregister(clerkUserId);
|
|
186
|
+
if (!userId) {
|
|
187
|
+
console.warn(`User not found, skipping oprate , (clerkUserId: ${clerkUserId})`);
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
console.log(`Successfully deleted user ${userId} , (clerkUserId: ${clerkUserId})`);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
catch (error) {
|
|
194
|
+
console.error('Error handling user.deleted event:', error);
|
|
195
|
+
throw error;
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export { POST };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
export declare const runtime = "nodejs";
|
|
3
|
+
export declare function POST(request: NextRequest): Promise<NextResponse<{
|
|
4
|
+
error: string;
|
|
5
|
+
}> | NextResponse<{
|
|
6
|
+
received: boolean;
|
|
7
|
+
}>>;
|
|
8
|
+
//# sourceMappingURL=route.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../src/app/api/webhook/stripe/route.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAQxD,eAAO,MAAM,OAAO,WAAW,CAAC;AAEhC,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW;;;;IAkF9C"}
|