@windrun-huaiin/backend-core 30.0.0 → 31.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/README.md +95 -0
- package/dist/app/api/user/anonymous/init/fingerprint-only-route.d.ts +8 -0
- package/dist/app/api/user/anonymous/init/fingerprint-only-route.d.ts.map +1 -0
- package/dist/app/api/user/anonymous/init/fingerprint-only-route.js +20 -0
- package/dist/app/api/user/anonymous/init/fingerprint-only-route.mjs +18 -0
- package/dist/app/api/user/anonymous/init/route-shared.d.ts +10 -0
- package/dist/app/api/user/anonymous/init/route-shared.d.ts.map +1 -0
- package/dist/app/api/user/anonymous/init/route-shared.js +557 -0
- package/dist/app/api/user/anonymous/init/route-shared.mjs +555 -0
- package/dist/app/api/user/anonymous/init/route.d.ts +3 -3
- package/dist/app/api/user/anonymous/init/route.d.ts.map +1 -1
- package/dist/app/api/user/anonymous/init/route.js +6 -554
- package/dist/app/api/user/anonymous/init/route.mjs +7 -555
- package/dist/app/api/webhook/clerk/user/route.js +16 -16
- package/dist/app/api/webhook/clerk/user/route.mjs +16 -16
- package/dist/auth/auth-utils.d.ts +8 -23
- package/dist/auth/auth-utils.d.ts.map +1 -1
- package/dist/auth/auth-utils.js +8 -20
- package/dist/auth/auth-utils.mjs +8 -20
- package/dist/lib/money-price-config.d.ts +28 -28
- package/dist/lib/money-price-config.js +31 -31
- package/dist/lib/money-price-config.mjs +31 -31
- package/dist/lib/stripe-config.js +3 -3
- package/dist/lib/stripe-config.mjs +3 -3
- package/dist/prisma/prisma-transaction-util.js +1 -1
- package/dist/prisma/prisma-transaction-util.mjs +1 -1
- package/dist/prisma/prisma.d.ts.map +1 -1
- package/dist/prisma/prisma.js +18 -19
- package/dist/prisma/prisma.mjs +18 -19
- package/dist/services/aggregate/billing.aggregate.service.js +6 -6
- package/dist/services/aggregate/billing.aggregate.service.mjs +6 -6
- package/dist/services/aggregate/user.aggregate.service.d.ts +9 -9
- package/dist/services/aggregate/user.aggregate.service.js +16 -16
- package/dist/services/aggregate/user.aggregate.service.mjs +16 -16
- package/dist/services/database/constants.js +34 -34
- package/dist/services/database/constants.mjs +34 -34
- package/dist/services/database/credit.service.js +2 -2
- package/dist/services/database/credit.service.mjs +2 -2
- package/dist/services/database/transaction.service.js +1 -1
- package/dist/services/database/transaction.service.mjs +1 -1
- package/dist/services/database/user.service.js +2 -2
- package/dist/services/database/user.service.mjs +2 -2
- package/dist/services/stripe/webhook-handler.js +5 -5
- package/dist/services/stripe/webhook-handler.mjs +5 -5
- package/package.json +18 -6
- package/src/app/api/user/anonymous/init/fingerprint-only-route.ts +14 -0
- package/src/app/api/user/anonymous/init/route-shared.ts +710 -0
- package/src/app/api/user/anonymous/init/route.ts +7 -712
- package/src/app/api/webhook/clerk/user/route.ts +17 -17
- package/src/auth/auth-utils.ts +8 -23
- package/src/lib/money-price-config.ts +31 -32
- package/src/lib/stripe-config.ts +3 -3
- package/src/prisma/prisma-transaction-util.ts +1 -1
- package/src/prisma/prisma.ts +18 -19
- package/src/services/aggregate/billing.aggregate.service.ts +7 -7
- package/src/services/aggregate/user.aggregate.service.ts +16 -16
- package/src/services/database/constants.ts +34 -34
- package/src/services/database/credit.service.ts +2 -2
- package/src/services/database/transaction.service.ts +1 -1
- package/src/services/database/user.service.ts +2 -2
- package/src/services/stripe/webhook-handler.ts +5 -5
|
@@ -1,565 +1,17 @@
|
|
|
1
|
-
import { __awaiter
|
|
2
|
-
import { anonymousAggregateService } from '../../../../../services/aggregate/anonymous.aggregate.service.mjs';
|
|
1
|
+
import { __awaiter } from 'tslib';
|
|
3
2
|
import { getOptionalServerAuthIdentity } from '../../../../../auth/auth-utils.mjs';
|
|
4
|
-
import {
|
|
5
|
-
import { NextResponse } from 'next/server';
|
|
6
|
-
import { fetchUserContextByClerkUserId, fetchLatestUserContextByFingerprintId, mapSubscriptionToXSubscription, mapCreditToXCredit, mapUserToXUser } from '../../../../../services/context/user-context-service.mjs';
|
|
7
|
-
import { finalizeUserContext } from '../../../../../services/context/user-context-finalizer.mjs';
|
|
3
|
+
import { handleFingerprintRequest } from './route-shared.mjs';
|
|
8
4
|
|
|
9
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
10
|
-
// Fix BigInt serialization issue
|
|
11
|
-
BigInt.prototype.toJSON = function () {
|
|
12
|
-
return this.toString();
|
|
13
|
-
};
|
|
14
|
-
// ==================== 工具函数 ====================
|
|
15
|
-
/** 创建成功响应对象 */
|
|
16
|
-
function createSuccessResponse(params) {
|
|
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
|
-
return finalizeUserContext(response);
|
|
19
|
-
}
|
|
20
|
-
/** 创建错误响应 */
|
|
21
|
-
function createErrorResponse(message, status = 400) {
|
|
22
|
-
const errorResponse = { error: message };
|
|
23
|
-
return NextResponse.json(errorResponse, { status });
|
|
24
|
-
}
|
|
25
|
-
const SOURCE_REF_MAX_LENGTH = 2048;
|
|
26
|
-
const QUERY_PARAM_MAX_LENGTH = 512;
|
|
27
|
-
const USER_AGENT_MAX_LENGTH = 1024;
|
|
28
|
-
const FIRST_TOUCH_HEADER_MAX_LENGTH = 4096;
|
|
29
|
-
const FIRST_TOUCH_HEADER_NAME = 'x-first-touch';
|
|
30
|
-
function normalizeSourceRef(ref) {
|
|
31
|
-
if (!ref) {
|
|
32
|
-
return null;
|
|
33
|
-
}
|
|
34
|
-
const trimmed = ref.trim();
|
|
35
|
-
if (!trimmed) {
|
|
36
|
-
return null;
|
|
37
|
-
}
|
|
38
|
-
return trimmed.length > SOURCE_REF_MAX_LENGTH
|
|
39
|
-
? trimmed.slice(0, SOURCE_REF_MAX_LENGTH)
|
|
40
|
-
: trimmed;
|
|
41
|
-
}
|
|
42
|
-
function normalizeQueryParam(value) {
|
|
43
|
-
if (!value) {
|
|
44
|
-
return null;
|
|
45
|
-
}
|
|
46
|
-
const trimmed = value.trim();
|
|
47
|
-
if (!trimmed) {
|
|
48
|
-
return null;
|
|
49
|
-
}
|
|
50
|
-
return trimmed.length > QUERY_PARAM_MAX_LENGTH
|
|
51
|
-
? trimmed.slice(0, QUERY_PARAM_MAX_LENGTH)
|
|
52
|
-
: trimmed;
|
|
53
|
-
}
|
|
54
|
-
function decodeHeaderValue(value) {
|
|
55
|
-
try {
|
|
56
|
-
return decodeURIComponent(value);
|
|
57
|
-
}
|
|
58
|
-
catch (_a) {
|
|
59
|
-
return null;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
function mergeSourceRef(target, source) {
|
|
63
|
-
if (!source) {
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
const entries = Object.entries(source);
|
|
67
|
-
for (const [key, value] of entries) {
|
|
68
|
-
if (value === undefined || value === null) {
|
|
69
|
-
continue;
|
|
70
|
-
}
|
|
71
|
-
if (target[key] === undefined) {
|
|
72
|
-
target[key] = value;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
function applySearchParams(sourceRef, params) {
|
|
77
|
-
const setIfEmpty = (key, value) => {
|
|
78
|
-
if (sourceRef[key] !== undefined) {
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
const normalized = normalizeQueryParam(value);
|
|
82
|
-
if (normalized) {
|
|
83
|
-
sourceRef[key] = normalized;
|
|
84
|
-
}
|
|
85
|
-
};
|
|
86
|
-
setIfEmpty('utmSource', params.get('utm_source'));
|
|
87
|
-
setIfEmpty('utmMedium', params.get('utm_medium'));
|
|
88
|
-
setIfEmpty('utmCampaign', params.get('utm_campaign'));
|
|
89
|
-
setIfEmpty('utmTerm', params.get('utm_term'));
|
|
90
|
-
setIfEmpty('utmContent', params.get('utm_content'));
|
|
91
|
-
setIfEmpty('utmId', params.get('utm_id'));
|
|
92
|
-
setIfEmpty('ref', params.get('ref'));
|
|
93
|
-
setIfEmpty('gclid', params.get('gclid'));
|
|
94
|
-
setIfEmpty('fbclid', params.get('fbclid'));
|
|
95
|
-
setIfEmpty('msclkid', params.get('msclkid'));
|
|
96
|
-
setIfEmpty('ttclid', params.get('ttclid'));
|
|
97
|
-
setIfEmpty('twclid', params.get('twclid'));
|
|
98
|
-
setIfEmpty('liFatId', params.get('li_fat_id'));
|
|
99
|
-
}
|
|
100
|
-
function normalizeHost(host) {
|
|
101
|
-
if (!host) {
|
|
102
|
-
return null;
|
|
103
|
-
}
|
|
104
|
-
return host.trim().toLowerCase() || null;
|
|
105
|
-
}
|
|
106
|
-
function getRootDomain(host) {
|
|
107
|
-
const normalizedHost = normalizeHost(host);
|
|
108
|
-
if (!normalizedHost) {
|
|
109
|
-
return null;
|
|
110
|
-
}
|
|
111
|
-
const hostname = normalizedHost.split(':')[0];
|
|
112
|
-
if (hostname === 'localhost' || /^\d{1,3}(\.\d{1,3}){3}$/.test(hostname)) {
|
|
113
|
-
return hostname;
|
|
114
|
-
}
|
|
115
|
-
const parts = hostname.split('.').filter(Boolean);
|
|
116
|
-
if (parts.length <= 2) {
|
|
117
|
-
return hostname;
|
|
118
|
-
}
|
|
119
|
-
return parts.slice(-2).join('.');
|
|
120
|
-
}
|
|
121
|
-
function isInternalReferer(landingHost, refererHost) {
|
|
122
|
-
const normalizedLandingHost = normalizeHost(landingHost);
|
|
123
|
-
const normalizedRefererHost = normalizeHost(refererHost);
|
|
124
|
-
if (!normalizedLandingHost || !normalizedRefererHost) {
|
|
125
|
-
return false;
|
|
126
|
-
}
|
|
127
|
-
if (normalizedLandingHost === normalizedRefererHost) {
|
|
128
|
-
return true;
|
|
129
|
-
}
|
|
130
|
-
return normalizedLandingHost.endsWith(`.${normalizedRefererHost}`)
|
|
131
|
-
|| normalizedRefererHost.endsWith(`.${normalizedLandingHost}`);
|
|
132
|
-
}
|
|
133
|
-
function detectPlatform(value) {
|
|
134
|
-
const normalized = value === null || value === void 0 ? void 0 : value.trim().toLowerCase();
|
|
135
|
-
if (!normalized) {
|
|
136
|
-
return null;
|
|
137
|
-
}
|
|
138
|
-
const matcherList = [
|
|
139
|
-
{ pattern: /chatgpt|chat-openai|openai/, platform: 'openai', channel: 'ai' },
|
|
140
|
-
{ pattern: /claude|anthropic/, platform: 'anthropic', channel: 'ai' },
|
|
141
|
-
{ pattern: /perplexity/, platform: 'perplexity', channel: 'ai' },
|
|
142
|
-
{ pattern: /gemini/, platform: 'gemini', channel: 'ai' },
|
|
143
|
-
{ pattern: /copilot/, platform: 'copilot', channel: 'ai' },
|
|
144
|
-
{ pattern: /google/, platform: 'google', channel: 'search' },
|
|
145
|
-
{ pattern: /bing/, platform: 'bing', channel: 'search' },
|
|
146
|
-
{ pattern: /baidu/, platform: 'baidu', channel: 'search' },
|
|
147
|
-
{ pattern: /yahoo/, platform: 'yahoo', channel: 'search' },
|
|
148
|
-
{ pattern: /duckduckgo/, platform: 'duckduckgo', channel: 'search' },
|
|
149
|
-
{ pattern: /facebook/, platform: 'facebook', channel: 'social' },
|
|
150
|
-
{ pattern: /instagram/, platform: 'instagram', channel: 'social' },
|
|
151
|
-
{ pattern: /x\.com|twitter/, platform: 'x', channel: 'social' },
|
|
152
|
-
{ pattern: /linkedin/, platform: 'linkedin', channel: 'social' },
|
|
153
|
-
{ pattern: /reddit/, platform: 'reddit', channel: 'social' },
|
|
154
|
-
{ pattern: /youtube/, platform: 'youtube', channel: 'social' },
|
|
155
|
-
];
|
|
156
|
-
const matched = matcherList.find(({ pattern }) => pattern.test(normalized));
|
|
157
|
-
if (!matched) {
|
|
158
|
-
return null;
|
|
159
|
-
}
|
|
160
|
-
return matched.platform;
|
|
161
|
-
}
|
|
162
|
-
function detectChannelFromPlatform(platform) {
|
|
163
|
-
switch (platform) {
|
|
164
|
-
case 'openai':
|
|
165
|
-
case 'anthropic':
|
|
166
|
-
case 'perplexity':
|
|
167
|
-
case 'gemini':
|
|
168
|
-
case 'copilot':
|
|
169
|
-
return 'ai';
|
|
170
|
-
case 'google':
|
|
171
|
-
case 'bing':
|
|
172
|
-
case 'baidu':
|
|
173
|
-
case 'yahoo':
|
|
174
|
-
case 'duckduckgo':
|
|
175
|
-
return 'search';
|
|
176
|
-
case 'facebook':
|
|
177
|
-
case 'instagram':
|
|
178
|
-
case 'x':
|
|
179
|
-
case 'linkedin':
|
|
180
|
-
case 'reddit':
|
|
181
|
-
case 'youtube':
|
|
182
|
-
return 'social';
|
|
183
|
-
default:
|
|
184
|
-
return null;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
function detectChannelFromUtmMedium(value) {
|
|
188
|
-
const normalized = value === null || value === void 0 ? void 0 : value.trim().toLowerCase();
|
|
189
|
-
if (!normalized) {
|
|
190
|
-
return null;
|
|
191
|
-
}
|
|
192
|
-
if (/^(cpc|ppc|paid|paid_search|display|banner|affiliate|email|newsletter|push|sms)$/.test(normalized)) {
|
|
193
|
-
return 'campaign';
|
|
194
|
-
}
|
|
195
|
-
if (/^(social|social_paid|social-organic|social_organic)$/.test(normalized)) {
|
|
196
|
-
return 'social';
|
|
197
|
-
}
|
|
198
|
-
if (/^(organic|seo|search)$/.test(normalized)) {
|
|
199
|
-
return 'search';
|
|
200
|
-
}
|
|
201
|
-
if (/^(referral|partner)$/.test(normalized)) {
|
|
202
|
-
return 'referral';
|
|
203
|
-
}
|
|
204
|
-
if (/^(ai|llm)$/.test(normalized)) {
|
|
205
|
-
return 'ai';
|
|
206
|
-
}
|
|
207
|
-
return 'campaign';
|
|
208
|
-
}
|
|
209
|
-
function parseUserAgent(request) {
|
|
210
|
-
var _a, _b, _c, _d, _e;
|
|
211
|
-
const userAgentHeader = request.headers.get('user-agent');
|
|
212
|
-
const secChUaMobile = (_a = normalizeQueryParam(request.headers.get('sec-ch-ua-mobile'))) !== null && _a !== void 0 ? _a : undefined;
|
|
213
|
-
const secChUaPlatform = (_b = normalizeQueryParam(request.headers.get('sec-ch-ua-platform'))) !== null && _b !== void 0 ? _b : undefined;
|
|
214
|
-
const userAgent = (_d = (_c = normalizeSourceRef(userAgentHeader)) === null || _c === void 0 ? void 0 : _c.slice(0, USER_AGENT_MAX_LENGTH)) !== null && _d !== void 0 ? _d : undefined;
|
|
215
|
-
const ua = (_e = userAgent === null || userAgent === void 0 ? void 0 : userAgent.toLowerCase()) !== null && _e !== void 0 ? _e : '';
|
|
216
|
-
let deviceType = 'desktop';
|
|
217
|
-
if (!ua) {
|
|
218
|
-
deviceType = 'unknown';
|
|
219
|
-
}
|
|
220
|
-
else if (/bot|spider|crawler|curl|wget|headless/.test(ua)) {
|
|
221
|
-
deviceType = 'bot';
|
|
222
|
-
}
|
|
223
|
-
else if (/ipad|tablet/.test(ua)) {
|
|
224
|
-
deviceType = 'tablet';
|
|
225
|
-
}
|
|
226
|
-
else if (/mobi|iphone|android/.test(ua) || secChUaMobile === '?1') {
|
|
227
|
-
deviceType = 'mobile';
|
|
228
|
-
}
|
|
229
|
-
let os = 'Unknown';
|
|
230
|
-
if (/iphone|ipad|ipod/.test(ua)) {
|
|
231
|
-
os = 'iOS';
|
|
232
|
-
}
|
|
233
|
-
else if (/android/.test(ua)) {
|
|
234
|
-
os = 'Android';
|
|
235
|
-
}
|
|
236
|
-
else if (/windows nt/.test(ua)) {
|
|
237
|
-
os = 'Windows';
|
|
238
|
-
}
|
|
239
|
-
else if (/mac os x|macintosh/.test(ua)) {
|
|
240
|
-
os = 'macOS';
|
|
241
|
-
}
|
|
242
|
-
else if (/cros/.test(ua)) {
|
|
243
|
-
os = 'Chrome OS';
|
|
244
|
-
}
|
|
245
|
-
else if (/linux/.test(ua)) {
|
|
246
|
-
os = 'Linux';
|
|
247
|
-
}
|
|
248
|
-
if (secChUaPlatform) {
|
|
249
|
-
const normalizedPlatform = secChUaPlatform.replaceAll('"', '');
|
|
250
|
-
if (normalizedPlatform && normalizedPlatform !== 'Unknown') {
|
|
251
|
-
os = normalizedPlatform;
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
let browser = 'Unknown';
|
|
255
|
-
if (/edg\//.test(ua)) {
|
|
256
|
-
browser = 'Edge';
|
|
257
|
-
}
|
|
258
|
-
else if (/opr\//.test(ua) || /opera/.test(ua)) {
|
|
259
|
-
browser = 'Opera';
|
|
260
|
-
}
|
|
261
|
-
else if (/samsungbrowser\//.test(ua)) {
|
|
262
|
-
browser = 'Samsung Internet';
|
|
263
|
-
}
|
|
264
|
-
else if (/crios\//.test(ua) || /chrome\//.test(ua)) {
|
|
265
|
-
browser = 'Chrome';
|
|
266
|
-
}
|
|
267
|
-
else if (/firefox\//.test(ua)) {
|
|
268
|
-
browser = 'Firefox';
|
|
269
|
-
}
|
|
270
|
-
else if (/safari\//.test(ua) && !/chrome\//.test(ua) && !/crios\//.test(ua)) {
|
|
271
|
-
browser = 'Safari';
|
|
272
|
-
}
|
|
273
|
-
return {
|
|
274
|
-
userAgent,
|
|
275
|
-
deviceType,
|
|
276
|
-
os,
|
|
277
|
-
browser,
|
|
278
|
-
secChUaMobile,
|
|
279
|
-
secChUaPlatform,
|
|
280
|
-
};
|
|
281
|
-
}
|
|
282
|
-
function parseFirstTouchHeader(request) {
|
|
283
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w;
|
|
284
|
-
const rawHeader = request.headers.get(FIRST_TOUCH_HEADER_NAME);
|
|
285
|
-
const normalizedHeader = (_a = normalizeSourceRef(rawHeader)) === null || _a === void 0 ? void 0 : _a.slice(0, FIRST_TOUCH_HEADER_MAX_LENGTH);
|
|
286
|
-
if (!normalizedHeader) {
|
|
287
|
-
return null;
|
|
288
|
-
}
|
|
289
|
-
const decodedHeader = decodeHeaderValue(normalizedHeader);
|
|
290
|
-
if (!decodedHeader) {
|
|
291
|
-
return null;
|
|
292
|
-
}
|
|
293
|
-
try {
|
|
294
|
-
const parsed = JSON.parse(decodedHeader);
|
|
295
|
-
const sourceRef = {};
|
|
296
|
-
sourceRef.capturedAt = (_b = normalizeQueryParam(typeof parsed.capturedAt === 'string' ? parsed.capturedAt : null)) !== null && _b !== void 0 ? _b : undefined;
|
|
297
|
-
sourceRef.landingUrl = (_c = normalizeSourceRef(typeof parsed.landingUrl === 'string' ? parsed.landingUrl : null)) !== null && _c !== void 0 ? _c : undefined;
|
|
298
|
-
sourceRef.landingPath = (_d = normalizeSourceRef(typeof parsed.landingPath === 'string' ? parsed.landingPath : null)) !== null && _d !== void 0 ? _d : undefined;
|
|
299
|
-
sourceRef.landingHost = (_e = normalizeHost(typeof parsed.landingHost === 'string' ? parsed.landingHost : null)) !== null && _e !== void 0 ? _e : undefined;
|
|
300
|
-
sourceRef.ref = (_f = normalizeQueryParam(typeof parsed.ref === 'string' ? parsed.ref : null)) !== null && _f !== void 0 ? _f : undefined;
|
|
301
|
-
sourceRef.utmSource = (_g = normalizeQueryParam(typeof parsed.utmSource === 'string' ? parsed.utmSource : null)) !== null && _g !== void 0 ? _g : undefined;
|
|
302
|
-
sourceRef.utmMedium = (_h = normalizeQueryParam(typeof parsed.utmMedium === 'string' ? parsed.utmMedium : null)) !== null && _h !== void 0 ? _h : undefined;
|
|
303
|
-
sourceRef.utmCampaign = (_j = normalizeQueryParam(typeof parsed.utmCampaign === 'string' ? parsed.utmCampaign : null)) !== null && _j !== void 0 ? _j : undefined;
|
|
304
|
-
sourceRef.utmTerm = (_k = normalizeQueryParam(typeof parsed.utmTerm === 'string' ? parsed.utmTerm : null)) !== null && _k !== void 0 ? _k : undefined;
|
|
305
|
-
sourceRef.utmContent = (_l = normalizeQueryParam(typeof parsed.utmContent === 'string' ? parsed.utmContent : null)) !== null && _l !== void 0 ? _l : undefined;
|
|
306
|
-
sourceRef.utmId = (_m = normalizeQueryParam(typeof parsed.utmId === 'string' ? parsed.utmId : null)) !== null && _m !== void 0 ? _m : undefined;
|
|
307
|
-
sourceRef.gclid = (_o = normalizeQueryParam(typeof parsed.gclid === 'string' ? parsed.gclid : null)) !== null && _o !== void 0 ? _o : undefined;
|
|
308
|
-
sourceRef.fbclid = (_p = normalizeQueryParam(typeof parsed.fbclid === 'string' ? parsed.fbclid : null)) !== null && _p !== void 0 ? _p : undefined;
|
|
309
|
-
sourceRef.msclkid = (_q = normalizeQueryParam(typeof parsed.msclkid === 'string' ? parsed.msclkid : null)) !== null && _q !== void 0 ? _q : undefined;
|
|
310
|
-
sourceRef.ttclid = (_r = normalizeQueryParam(typeof parsed.ttclid === 'string' ? parsed.ttclid : null)) !== null && _r !== void 0 ? _r : undefined;
|
|
311
|
-
sourceRef.twclid = (_s = normalizeQueryParam(typeof parsed.twclid === 'string' ? parsed.twclid : null)) !== null && _s !== void 0 ? _s : undefined;
|
|
312
|
-
sourceRef.liFatId = (_t = normalizeQueryParam(typeof parsed.liFatId === 'string' ? parsed.liFatId : null)) !== null && _t !== void 0 ? _t : undefined;
|
|
313
|
-
const externalReferrer = normalizeSourceRef(typeof parsed.externalReferrer === 'string' ? parsed.externalReferrer : null);
|
|
314
|
-
if (externalReferrer) {
|
|
315
|
-
sourceRef.httpRefer = externalReferrer;
|
|
316
|
-
try {
|
|
317
|
-
const refererUrl = new URL(externalReferrer);
|
|
318
|
-
sourceRef.refererHost = (_u = normalizeHost(refererUrl.host)) !== null && _u !== void 0 ? _u : undefined;
|
|
319
|
-
sourceRef.refererPath = (_v = normalizeSourceRef(refererUrl.pathname)) !== null && _v !== void 0 ? _v : undefined;
|
|
320
|
-
sourceRef.refererDomain = (_w = getRootDomain(refererUrl.host)) !== null && _w !== void 0 ? _w : undefined;
|
|
321
|
-
applySearchParams(sourceRef, refererUrl.searchParams);
|
|
322
|
-
}
|
|
323
|
-
catch (error) {
|
|
324
|
-
console.warn('Failed to parse first-touch referrer url:', error);
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
return Object.keys(sourceRef).length > 0 ? sourceRef : null;
|
|
328
|
-
}
|
|
329
|
-
catch (error) {
|
|
330
|
-
console.warn('Failed to parse first-touch header:', error);
|
|
331
|
-
return null;
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
function finalizeAttribution(sourceRef) {
|
|
335
|
-
var _a, _b, _c, _d, _e;
|
|
336
|
-
const landingHost = normalizeHost(sourceRef.landingHost);
|
|
337
|
-
const refererHost = normalizeHost(sourceRef.refererHost);
|
|
338
|
-
const internal = isInternalReferer(landingHost, refererHost);
|
|
339
|
-
const hasCampaignMarker = Boolean(sourceRef.utmSource
|
|
340
|
-
|| sourceRef.utmMedium
|
|
341
|
-
|| sourceRef.utmCampaign
|
|
342
|
-
|| sourceRef.utmTerm
|
|
343
|
-
|| sourceRef.utmContent
|
|
344
|
-
|| sourceRef.utmId
|
|
345
|
-
|| sourceRef.ref
|
|
346
|
-
|| sourceRef.gclid
|
|
347
|
-
|| sourceRef.fbclid
|
|
348
|
-
|| sourceRef.msclkid
|
|
349
|
-
|| sourceRef.ttclid
|
|
350
|
-
|| sourceRef.twclid
|
|
351
|
-
|| sourceRef.liFatId);
|
|
352
|
-
if (internal) {
|
|
353
|
-
sourceRef.isInternalReferer = true;
|
|
354
|
-
}
|
|
355
|
-
const utmPlatform = detectPlatform(sourceRef.utmSource) || detectPlatform(sourceRef.ref);
|
|
356
|
-
if (utmPlatform) {
|
|
357
|
-
sourceRef.sourcePlatform = utmPlatform;
|
|
358
|
-
sourceRef.sourceChannel = (_c = (_b = (_a = detectChannelFromPlatform(utmPlatform)) !== null && _a !== void 0 ? _a : detectChannelFromUtmMedium(sourceRef.utmMedium)) !== null && _b !== void 0 ? _b : sourceRef.sourceChannel) !== null && _c !== void 0 ? _c : 'campaign';
|
|
359
|
-
sourceRef.sourceType = 'campaign';
|
|
360
|
-
return;
|
|
361
|
-
}
|
|
362
|
-
if (sourceRef.gclid) {
|
|
363
|
-
sourceRef.sourcePlatform = 'google';
|
|
364
|
-
sourceRef.sourceChannel = 'search';
|
|
365
|
-
sourceRef.sourceType = 'campaign';
|
|
366
|
-
return;
|
|
367
|
-
}
|
|
368
|
-
if (sourceRef.msclkid) {
|
|
369
|
-
sourceRef.sourcePlatform = 'bing';
|
|
370
|
-
sourceRef.sourceChannel = 'search';
|
|
371
|
-
sourceRef.sourceType = 'campaign';
|
|
372
|
-
return;
|
|
373
|
-
}
|
|
374
|
-
if (sourceRef.fbclid) {
|
|
375
|
-
sourceRef.sourcePlatform = 'facebook';
|
|
376
|
-
sourceRef.sourceChannel = 'social';
|
|
377
|
-
sourceRef.sourceType = 'campaign';
|
|
378
|
-
return;
|
|
379
|
-
}
|
|
380
|
-
if (sourceRef.ttclid) {
|
|
381
|
-
sourceRef.sourcePlatform = 'tiktok';
|
|
382
|
-
sourceRef.sourceChannel = 'social';
|
|
383
|
-
sourceRef.sourceType = 'campaign';
|
|
384
|
-
return;
|
|
385
|
-
}
|
|
386
|
-
if (sourceRef.twclid) {
|
|
387
|
-
sourceRef.sourcePlatform = 'x';
|
|
388
|
-
sourceRef.sourceChannel = 'social';
|
|
389
|
-
sourceRef.sourceType = 'campaign';
|
|
390
|
-
return;
|
|
391
|
-
}
|
|
392
|
-
if (sourceRef.liFatId) {
|
|
393
|
-
sourceRef.sourcePlatform = 'linkedin';
|
|
394
|
-
sourceRef.sourceChannel = 'social';
|
|
395
|
-
sourceRef.sourceType = 'campaign';
|
|
396
|
-
return;
|
|
397
|
-
}
|
|
398
|
-
if (hasCampaignMarker) {
|
|
399
|
-
sourceRef.sourcePlatform = 'other';
|
|
400
|
-
sourceRef.sourceChannel = (_d = detectChannelFromUtmMedium(sourceRef.utmMedium)) !== null && _d !== void 0 ? _d : 'campaign';
|
|
401
|
-
sourceRef.sourceType = 'campaign';
|
|
402
|
-
return;
|
|
403
|
-
}
|
|
404
|
-
if (!internal && refererHost) {
|
|
405
|
-
const refererPlatform = detectPlatform(refererHost) || detectPlatform(sourceRef.httpRefer);
|
|
406
|
-
sourceRef.sourcePlatform = refererPlatform !== null && refererPlatform !== void 0 ? refererPlatform : 'other';
|
|
407
|
-
sourceRef.sourceChannel = (_e = detectChannelFromPlatform(refererPlatform)) !== null && _e !== void 0 ? _e : 'referral';
|
|
408
|
-
sourceRef.sourceType = 'referer';
|
|
409
|
-
return;
|
|
410
|
-
}
|
|
411
|
-
sourceRef.sourcePlatform = 'direct';
|
|
412
|
-
sourceRef.sourceChannel = 'direct';
|
|
413
|
-
sourceRef.sourceType = 'direct';
|
|
414
|
-
}
|
|
415
|
-
// 提取用户首次访问来源
|
|
416
|
-
function extractSourceRef(request) {
|
|
417
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
|
|
418
|
-
const headerRef = request.headers.get('referer') || request.headers.get('referrer');
|
|
419
|
-
const customRef = request.headers.get('x-source-ref');
|
|
420
|
-
const queryRef = request.nextUrl.searchParams.get('ref');
|
|
421
|
-
const firstTouchRef = parseFirstTouchHeader(request);
|
|
422
|
-
const sourceRef = Object.assign({}, parseUserAgent(request));
|
|
423
|
-
mergeSourceRef(sourceRef, firstTouchRef);
|
|
424
|
-
sourceRef.landingUrl = (_b = (_a = sourceRef.landingUrl) !== null && _a !== void 0 ? _a : normalizeSourceRef(request.nextUrl.toString())) !== null && _b !== void 0 ? _b : undefined;
|
|
425
|
-
sourceRef.landingPath = (_d = (_c = sourceRef.landingPath) !== null && _c !== void 0 ? _c : normalizeSourceRef(request.nextUrl.pathname)) !== null && _d !== void 0 ? _d : undefined;
|
|
426
|
-
sourceRef.landingHost = (_f = (_e = sourceRef.landingHost) !== null && _e !== void 0 ? _e : normalizeHost(request.nextUrl.host)) !== null && _f !== void 0 ? _f : undefined;
|
|
427
|
-
sourceRef.ref = (_h = (_g = sourceRef.ref) !== null && _g !== void 0 ? _g : normalizeQueryParam(queryRef)) !== null && _h !== void 0 ? _h : undefined;
|
|
428
|
-
let normalizedHttpRef = null;
|
|
429
|
-
const candidates = [customRef, headerRef];
|
|
430
|
-
for (const candidate of candidates) {
|
|
431
|
-
const normalized = normalizeSourceRef(candidate);
|
|
432
|
-
if (normalized) {
|
|
433
|
-
normalizedHttpRef = normalized;
|
|
434
|
-
sourceRef.httpRefer = (_j = sourceRef.httpRefer) !== null && _j !== void 0 ? _j : normalized;
|
|
435
|
-
break;
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
const searchParams = request.nextUrl.searchParams;
|
|
439
|
-
applySearchParams(sourceRef, searchParams);
|
|
440
|
-
if (normalizedHttpRef) {
|
|
441
|
-
try {
|
|
442
|
-
const refererUrl = new URL(normalizedHttpRef);
|
|
443
|
-
sourceRef.refererHost = (_l = (_k = sourceRef.refererHost) !== null && _k !== void 0 ? _k : normalizeHost(refererUrl.host)) !== null && _l !== void 0 ? _l : undefined;
|
|
444
|
-
sourceRef.refererPath = (_o = (_m = sourceRef.refererPath) !== null && _m !== void 0 ? _m : normalizeSourceRef(refererUrl.pathname)) !== null && _o !== void 0 ? _o : undefined;
|
|
445
|
-
sourceRef.refererDomain = (_q = (_p = sourceRef.refererDomain) !== null && _p !== void 0 ? _p : getRootDomain(refererUrl.host)) !== null && _q !== void 0 ? _q : undefined;
|
|
446
|
-
applySearchParams(sourceRef, refererUrl.searchParams);
|
|
447
|
-
}
|
|
448
|
-
catch (error) {
|
|
449
|
-
console.warn('Failed to parse referer url for utm/ref:', error);
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
finalizeAttribution(sourceRef);
|
|
453
|
-
return Object.keys(sourceRef).length > 0 ? sourceRef : null;
|
|
454
|
-
}
|
|
455
5
|
/**
|
|
456
|
-
*
|
|
457
|
-
*/
|
|
458
|
-
function getUserByClerkId(clerkUserId) {
|
|
459
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
460
|
-
const entities = yield fetchUserContextByClerkUserId(clerkUserId);
|
|
461
|
-
if (!entities) {
|
|
462
|
-
return null;
|
|
463
|
-
}
|
|
464
|
-
return createSuccessResponse({
|
|
465
|
-
entities,
|
|
466
|
-
isNewUser: false,
|
|
467
|
-
});
|
|
468
|
-
});
|
|
469
|
-
}
|
|
470
|
-
/**
|
|
471
|
-
* 根据fingerprint_id查询用户并返回响应数据
|
|
472
|
-
*/
|
|
473
|
-
function getUserByFingerprintId(fingerprintId) {
|
|
474
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
475
|
-
const result = yield fetchLatestUserContextByFingerprintId(fingerprintId);
|
|
476
|
-
if (!result) {
|
|
477
|
-
return null;
|
|
478
|
-
}
|
|
479
|
-
const { totalUsersOnDevice, hasAnonymousUser } = result, entities = __rest(result, ["totalUsersOnDevice", "hasAnonymousUser"]);
|
|
480
|
-
return createSuccessResponse({
|
|
481
|
-
entities,
|
|
482
|
-
isNewUser: false,
|
|
483
|
-
options: {
|
|
484
|
-
totalUsersOnDevice,
|
|
485
|
-
hasAnonymousUser,
|
|
486
|
-
},
|
|
487
|
-
});
|
|
488
|
-
});
|
|
489
|
-
}
|
|
490
|
-
/**
|
|
491
|
-
* 通用的fingerprint处理逻辑
|
|
492
|
-
*/
|
|
493
|
-
function handleFingerprintRequest(request_1) {
|
|
494
|
-
return __awaiter(this, arguments, void 0, function* (request, options = {}) {
|
|
495
|
-
var _a;
|
|
496
|
-
// 从请求中提取fingerprint ID
|
|
497
|
-
const fingerprintId = extractFingerprintFromNextRequest(request);
|
|
498
|
-
// 验证fingerprint ID
|
|
499
|
-
if (!fingerprintId) {
|
|
500
|
-
return createErrorResponse('Invalid or missing fingerprint ID');
|
|
501
|
-
}
|
|
502
|
-
console.log('Received fingerprintId:', fingerprintId);
|
|
503
|
-
const authIdentity = yield getOptionalServerAuthIdentity();
|
|
504
|
-
const clerkUserId = (_a = authIdentity === null || authIdentity === void 0 ? void 0 : authIdentity.providerUserId) !== null && _a !== void 0 ? _a : null;
|
|
505
|
-
try {
|
|
506
|
-
// 优先根据 Clerk ID 查询(如果已登录)
|
|
507
|
-
let existingUserResult = null;
|
|
508
|
-
if (clerkUserId) {
|
|
509
|
-
// 已登录一律按照clerkUserId去查
|
|
510
|
-
existingUserResult = yield getUserByClerkId(clerkUserId);
|
|
511
|
-
if (existingUserResult && existingUserResult.xUser.fingerprintId !== fingerprintId) {
|
|
512
|
-
// 说明当前用户的指纹ID发生了改变,为什么呢?因为它使用同一账号去注册Clerk,Clerk判定是同一用户!
|
|
513
|
-
// 这个时候一定以登录用户clerkUserId为准
|
|
514
|
-
// 但是考虑到同一指纹ID本身可以绑定多个账号,所以这里什么都不做
|
|
515
|
-
// 就是以当前登录用户去查他自己的数据就行!
|
|
516
|
-
console.warn(`Current login user used diff fp_ids: ${clerkUserId}, db_fp_id=${existingUserResult.xUser.fingerprintId}, req_fp_id=${fingerprintId}`);
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
else {
|
|
520
|
-
// 其次才是检查是否已存在该fingerprint的用户
|
|
521
|
-
existingUserResult = yield getUserByFingerprintId(fingerprintId);
|
|
522
|
-
}
|
|
523
|
-
if (existingUserResult) {
|
|
524
|
-
return NextResponse.json(existingUserResult);
|
|
525
|
-
}
|
|
526
|
-
// 如果不存在用户且不允许创建,返回404
|
|
527
|
-
if (!options.createIfNotExists) {
|
|
528
|
-
return createErrorResponse('User not found', 404);
|
|
529
|
-
}
|
|
530
|
-
const sourceRef = extractSourceRef(request);
|
|
531
|
-
const anonymousInitResult = yield anonymousAggregateService.getOrCreateByFingerprintId(fingerprintId, { sourceRef: sourceRef !== null && sourceRef !== void 0 ? sourceRef : undefined });
|
|
532
|
-
if (anonymousInitResult.isNewUser) {
|
|
533
|
-
console.log(`Created new anonymous user ${anonymousInitResult.user.userId} with fingerprint ${fingerprintId}`);
|
|
534
|
-
}
|
|
535
|
-
// 返回创建结果
|
|
536
|
-
const response = createSuccessResponse({
|
|
537
|
-
entities: {
|
|
538
|
-
user: anonymousInitResult.user,
|
|
539
|
-
credit: anonymousInitResult.credit,
|
|
540
|
-
subscription: anonymousInitResult.subscription,
|
|
541
|
-
},
|
|
542
|
-
isNewUser: anonymousInitResult.isNewUser,
|
|
543
|
-
options: {
|
|
544
|
-
totalUsersOnDevice: anonymousInitResult.totalUsersOnDevice,
|
|
545
|
-
hasAnonymousUser: anonymousInitResult.hasAnonymousUser,
|
|
546
|
-
},
|
|
547
|
-
});
|
|
548
|
-
return NextResponse.json(response);
|
|
549
|
-
}
|
|
550
|
-
catch (error) {
|
|
551
|
-
console.error('Fingerprint request error:', error);
|
|
552
|
-
return createErrorResponse('Internal server error', 500);
|
|
553
|
-
}
|
|
554
|
-
});
|
|
555
|
-
}
|
|
556
|
-
/**
|
|
557
|
-
* 匿名用户初始化API
|
|
6
|
+
* Clerk-aware anonymous user initialization API.
|
|
558
7
|
* POST /api/user/anonymous/init
|
|
559
8
|
*/
|
|
560
9
|
function POST(request) {
|
|
561
10
|
return __awaiter(this, void 0, void 0, function* () {
|
|
562
|
-
return handleFingerprintRequest(request, {
|
|
11
|
+
return handleFingerprintRequest(request, {
|
|
12
|
+
createIfNotExists: true,
|
|
13
|
+
getAuthIdentity: getOptionalServerAuthIdentity,
|
|
14
|
+
});
|
|
563
15
|
});
|
|
564
16
|
}
|
|
565
17
|
|
|
@@ -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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
146
|
+
// Find an existing user with the same email.
|
|
147
147
|
const sameEmailUser = existingUsers.find(user => user.email === email);
|
|
148
148
|
if (sameEmailUser) {
|
|
149
|
-
//
|
|
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
|
-
//
|
|
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* () {
|