@windrun-huaiin/backend-core 14.1.1 → 14.3.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.
- package/dist/app/api/user/anonymous/init/route.d.ts.map +1 -1
- package/dist/app/api/user/anonymous/init/route.js +60 -13
- package/dist/app/api/user/anonymous/init/route.mjs +61 -14
- package/dist/index.js +4 -1
- package/dist/index.mjs +3 -1
- package/dist/lib/money-price-helper.js +2 -1
- package/dist/lib/money-price-helper.mjs +3 -2
- package/dist/services/aggregate/anonymous.aggregate.service.d.ts +21 -0
- package/dist/services/aggregate/anonymous.aggregate.service.d.ts.map +1 -0
- package/dist/services/aggregate/anonymous.aggregate.service.js +87 -0
- package/dist/services/aggregate/anonymous.aggregate.service.mjs +85 -0
- package/dist/services/aggregate/index.d.ts +1 -0
- package/dist/services/aggregate/index.d.ts.map +1 -1
- package/dist/services/aggregate/index.js +2 -0
- package/dist/services/aggregate/index.mjs +1 -0
- package/dist/services/context/index.d.ts +1 -0
- package/dist/services/context/index.d.ts.map +1 -1
- package/dist/services/context/index.js +2 -1
- package/dist/services/context/index.mjs +2 -1
- package/dist/services/context/user-context-finalizer.d.ts +13 -0
- package/dist/services/context/user-context-finalizer.d.ts.map +1 -0
- package/dist/services/context/user-context-finalizer.js +74 -0
- package/dist/services/context/user-context-finalizer.mjs +72 -0
- package/dist/services/context/user-context-service.d.ts +0 -6
- package/dist/services/context/user-context-service.d.ts.map +1 -1
- package/dist/services/context/user-context-service.js +0 -64
- package/dist/services/context/user-context-service.mjs +1 -64
- package/package.json +7 -7
- package/src/app/api/user/anonymous/init/route.ts +72 -12
- package/src/lib/money-price-helper.ts +3 -3
- package/src/services/aggregate/anonymous.aggregate.service.ts +113 -0
- package/src/services/aggregate/index.ts +1 -0
- package/src/services/context/index.ts +2 -1
- package/src/services/context/user-context-finalizer.ts +84 -0
- package/src/services/context/user-context-service.ts +0 -77
|
@@ -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;
|
|
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"}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
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
|
|
4
|
+
var anonymous_aggregate_service = require('../../../../../services/aggregate/anonymous.aggregate.service.js');
|
|
5
5
|
var server = require('@windrun-huaiin/third-ui/fingerprint/server');
|
|
6
6
|
var server$1 = require('@clerk/nextjs/server');
|
|
7
7
|
var server$2 = require('next/server');
|
|
8
8
|
var userContextService = require('../../../../../services/context/user-context-service.js');
|
|
9
|
+
var userContextFinalizer = require('../../../../../services/context/user-context-finalizer.js');
|
|
9
10
|
|
|
10
11
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
11
12
|
// Fix BigInt serialization issue
|
|
@@ -16,7 +17,7 @@ BigInt.prototype.toJSON = function () {
|
|
|
16
17
|
/** 创建成功响应对象 */
|
|
17
18
|
function createSuccessResponse(params) {
|
|
18
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);
|
|
19
|
-
return
|
|
20
|
+
return userContextFinalizer.finalizeUserContext(response);
|
|
20
21
|
}
|
|
21
22
|
/** 创建错误响应 */
|
|
22
23
|
function createErrorResponse(message, status = 400) {
|
|
@@ -185,6 +186,28 @@ function detectChannelFromPlatform(platform) {
|
|
|
185
186
|
return null;
|
|
186
187
|
}
|
|
187
188
|
}
|
|
189
|
+
function detectChannelFromUtmMedium(value) {
|
|
190
|
+
const normalized = value === null || value === void 0 ? void 0 : value.trim().toLowerCase();
|
|
191
|
+
if (!normalized) {
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
if (/^(cpc|ppc|paid|paid_search|display|banner|affiliate|email|newsletter|push|sms)$/.test(normalized)) {
|
|
195
|
+
return 'campaign';
|
|
196
|
+
}
|
|
197
|
+
if (/^(social|social_paid|social-organic|social_organic)$/.test(normalized)) {
|
|
198
|
+
return 'social';
|
|
199
|
+
}
|
|
200
|
+
if (/^(organic|seo|search)$/.test(normalized)) {
|
|
201
|
+
return 'search';
|
|
202
|
+
}
|
|
203
|
+
if (/^(referral|partner)$/.test(normalized)) {
|
|
204
|
+
return 'referral';
|
|
205
|
+
}
|
|
206
|
+
if (/^(ai|llm)$/.test(normalized)) {
|
|
207
|
+
return 'ai';
|
|
208
|
+
}
|
|
209
|
+
return 'campaign';
|
|
210
|
+
}
|
|
188
211
|
function parseUserAgent(request) {
|
|
189
212
|
var _a, _b, _c, _d, _e;
|
|
190
213
|
const userAgentHeader = request.headers.get('user-agent');
|
|
@@ -311,17 +334,30 @@ function parseFirstTouchHeader(request) {
|
|
|
311
334
|
}
|
|
312
335
|
}
|
|
313
336
|
function finalizeAttribution(sourceRef) {
|
|
314
|
-
var _a, _b, _c, _d;
|
|
337
|
+
var _a, _b, _c, _d, _e;
|
|
315
338
|
const landingHost = normalizeHost(sourceRef.landingHost);
|
|
316
339
|
const refererHost = normalizeHost(sourceRef.refererHost);
|
|
317
340
|
const internal = isInternalReferer(landingHost, refererHost);
|
|
341
|
+
const hasCampaignMarker = Boolean(sourceRef.utmSource
|
|
342
|
+
|| sourceRef.utmMedium
|
|
343
|
+
|| sourceRef.utmCampaign
|
|
344
|
+
|| sourceRef.utmTerm
|
|
345
|
+
|| sourceRef.utmContent
|
|
346
|
+
|| sourceRef.utmId
|
|
347
|
+
|| sourceRef.ref
|
|
348
|
+
|| sourceRef.gclid
|
|
349
|
+
|| sourceRef.fbclid
|
|
350
|
+
|| sourceRef.msclkid
|
|
351
|
+
|| sourceRef.ttclid
|
|
352
|
+
|| sourceRef.twclid
|
|
353
|
+
|| sourceRef.liFatId);
|
|
318
354
|
if (internal) {
|
|
319
355
|
sourceRef.isInternalReferer = true;
|
|
320
356
|
}
|
|
321
357
|
const utmPlatform = detectPlatform(sourceRef.utmSource) || detectPlatform(sourceRef.ref);
|
|
322
358
|
if (utmPlatform) {
|
|
323
359
|
sourceRef.sourcePlatform = utmPlatform;
|
|
324
|
-
sourceRef.sourceChannel = (_b = (_a = detectChannelFromPlatform(utmPlatform)) !== null && _a !== void 0 ? _a : sourceRef.
|
|
360
|
+
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';
|
|
325
361
|
sourceRef.sourceType = 'campaign';
|
|
326
362
|
return;
|
|
327
363
|
}
|
|
@@ -361,10 +397,16 @@ function finalizeAttribution(sourceRef) {
|
|
|
361
397
|
sourceRef.sourceType = 'campaign';
|
|
362
398
|
return;
|
|
363
399
|
}
|
|
400
|
+
if (hasCampaignMarker) {
|
|
401
|
+
sourceRef.sourcePlatform = 'other';
|
|
402
|
+
sourceRef.sourceChannel = (_d = detectChannelFromUtmMedium(sourceRef.utmMedium)) !== null && _d !== void 0 ? _d : 'campaign';
|
|
403
|
+
sourceRef.sourceType = 'campaign';
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
364
406
|
if (!internal && refererHost) {
|
|
365
407
|
const refererPlatform = detectPlatform(refererHost) || detectPlatform(sourceRef.httpRefer);
|
|
366
|
-
sourceRef.sourcePlatform =
|
|
367
|
-
sourceRef.sourceChannel = (
|
|
408
|
+
sourceRef.sourcePlatform = refererPlatform !== null && refererPlatform !== void 0 ? refererPlatform : 'other';
|
|
409
|
+
sourceRef.sourceChannel = (_e = detectChannelFromPlatform(refererPlatform)) !== null && _e !== void 0 ? _e : 'referral';
|
|
368
410
|
sourceRef.sourceType = 'referer';
|
|
369
411
|
return;
|
|
370
412
|
}
|
|
@@ -486,17 +528,22 @@ function handleFingerprintRequest(request_1) {
|
|
|
486
528
|
return createErrorResponse('User not found', 404);
|
|
487
529
|
}
|
|
488
530
|
const sourceRef = extractSourceRef(request);
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
531
|
+
const anonymousInitResult = yield anonymous_aggregate_service.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
|
+
}
|
|
492
535
|
// 返回创建结果
|
|
493
536
|
const response = createSuccessResponse({
|
|
494
537
|
entities: {
|
|
495
|
-
user:
|
|
496
|
-
credit,
|
|
497
|
-
subscription:
|
|
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,
|
|
498
546
|
},
|
|
499
|
-
isNewUser: true,
|
|
500
547
|
});
|
|
501
548
|
return server$2.NextResponse.json(response);
|
|
502
549
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
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 {
|
|
2
|
+
import { anonymousAggregateService } from '../../../../../services/aggregate/anonymous.aggregate.service.mjs';
|
|
3
3
|
import { extractFingerprintFromNextRequest } from '@windrun-huaiin/third-ui/fingerprint/server';
|
|
4
4
|
import { auth } from '@clerk/nextjs/server';
|
|
5
5
|
import { NextResponse } from 'next/server';
|
|
6
|
-
import { fetchUserContextByClerkUserId, fetchLatestUserContextByFingerprintId, mapSubscriptionToXSubscription, mapCreditToXCredit, mapUserToXUser
|
|
6
|
+
import { fetchUserContextByClerkUserId, fetchLatestUserContextByFingerprintId, mapSubscriptionToXSubscription, mapCreditToXCredit, mapUserToXUser } from '../../../../../services/context/user-context-service.mjs';
|
|
7
|
+
import { finalizeUserContext } from '../../../../../services/context/user-context-finalizer.mjs';
|
|
7
8
|
|
|
8
9
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
9
10
|
// Fix BigInt serialization issue
|
|
@@ -14,7 +15,7 @@ BigInt.prototype.toJSON = function () {
|
|
|
14
15
|
/** 创建成功响应对象 */
|
|
15
16
|
function createSuccessResponse(params) {
|
|
16
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);
|
|
17
|
-
return
|
|
18
|
+
return finalizeUserContext(response);
|
|
18
19
|
}
|
|
19
20
|
/** 创建错误响应 */
|
|
20
21
|
function createErrorResponse(message, status = 400) {
|
|
@@ -183,6 +184,28 @@ function detectChannelFromPlatform(platform) {
|
|
|
183
184
|
return null;
|
|
184
185
|
}
|
|
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
|
+
}
|
|
186
209
|
function parseUserAgent(request) {
|
|
187
210
|
var _a, _b, _c, _d, _e;
|
|
188
211
|
const userAgentHeader = request.headers.get('user-agent');
|
|
@@ -309,17 +332,30 @@ function parseFirstTouchHeader(request) {
|
|
|
309
332
|
}
|
|
310
333
|
}
|
|
311
334
|
function finalizeAttribution(sourceRef) {
|
|
312
|
-
var _a, _b, _c, _d;
|
|
335
|
+
var _a, _b, _c, _d, _e;
|
|
313
336
|
const landingHost = normalizeHost(sourceRef.landingHost);
|
|
314
337
|
const refererHost = normalizeHost(sourceRef.refererHost);
|
|
315
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);
|
|
316
352
|
if (internal) {
|
|
317
353
|
sourceRef.isInternalReferer = true;
|
|
318
354
|
}
|
|
319
355
|
const utmPlatform = detectPlatform(sourceRef.utmSource) || detectPlatform(sourceRef.ref);
|
|
320
356
|
if (utmPlatform) {
|
|
321
357
|
sourceRef.sourcePlatform = utmPlatform;
|
|
322
|
-
sourceRef.sourceChannel = (_b = (_a = detectChannelFromPlatform(utmPlatform)) !== null && _a !== void 0 ? _a : sourceRef.
|
|
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';
|
|
323
359
|
sourceRef.sourceType = 'campaign';
|
|
324
360
|
return;
|
|
325
361
|
}
|
|
@@ -359,10 +395,16 @@ function finalizeAttribution(sourceRef) {
|
|
|
359
395
|
sourceRef.sourceType = 'campaign';
|
|
360
396
|
return;
|
|
361
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
|
+
}
|
|
362
404
|
if (!internal && refererHost) {
|
|
363
405
|
const refererPlatform = detectPlatform(refererHost) || detectPlatform(sourceRef.httpRefer);
|
|
364
|
-
sourceRef.sourcePlatform =
|
|
365
|
-
sourceRef.sourceChannel = (
|
|
406
|
+
sourceRef.sourcePlatform = refererPlatform !== null && refererPlatform !== void 0 ? refererPlatform : 'other';
|
|
407
|
+
sourceRef.sourceChannel = (_e = detectChannelFromPlatform(refererPlatform)) !== null && _e !== void 0 ? _e : 'referral';
|
|
366
408
|
sourceRef.sourceType = 'referer';
|
|
367
409
|
return;
|
|
368
410
|
}
|
|
@@ -484,17 +526,22 @@ function handleFingerprintRequest(request_1) {
|
|
|
484
526
|
return createErrorResponse('User not found', 404);
|
|
485
527
|
}
|
|
486
528
|
const sourceRef = extractSourceRef(request);
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
529
|
+
const anonymousInitResult = yield anonymousAggregateService.getOrCreateByFingerprintId(fingerprintId, { sourceRef: sourceRef !== null && sourceRef !== void 0 ? sourceRef : undefined });
|
|
530
|
+
if (anonymousInitResult.isNewUser) {
|
|
531
|
+
console.log(`Created new anonymous user ${anonymousInitResult.user.userId} with fingerprint ${fingerprintId}`);
|
|
532
|
+
}
|
|
490
533
|
// 返回创建结果
|
|
491
534
|
const response = createSuccessResponse({
|
|
492
535
|
entities: {
|
|
493
|
-
user:
|
|
494
|
-
credit,
|
|
495
|
-
subscription:
|
|
536
|
+
user: anonymousInitResult.user,
|
|
537
|
+
credit: anonymousInitResult.credit,
|
|
538
|
+
subscription: anonymousInitResult.subscription,
|
|
539
|
+
},
|
|
540
|
+
isNewUser: anonymousInitResult.isNewUser,
|
|
541
|
+
options: {
|
|
542
|
+
totalUsersOnDevice: anonymousInitResult.totalUsersOnDevice,
|
|
543
|
+
hasAnonymousUser: anonymousInitResult.hasAnonymousUser,
|
|
496
544
|
},
|
|
497
|
-
isNewUser: true,
|
|
498
545
|
});
|
|
499
546
|
return NextResponse.json(response);
|
|
500
547
|
}
|
package/dist/index.js
CHANGED
|
@@ -12,7 +12,9 @@ var apilog_service = require('./services/database/apilog.service.js');
|
|
|
12
12
|
var constants = require('./services/database/constants.js');
|
|
13
13
|
var user_aggregate_service = require('./services/aggregate/user.aggregate.service.js');
|
|
14
14
|
var billing_aggregate_service = require('./services/aggregate/billing.aggregate.service.js');
|
|
15
|
+
var anonymous_aggregate_service = require('./services/aggregate/anonymous.aggregate.service.js');
|
|
15
16
|
var userContextService = require('./services/context/user-context-service.js');
|
|
17
|
+
var userContextFinalizer = require('./services/context/user-context-finalizer.js');
|
|
16
18
|
var webhookHandler = require('./services/stripe/webhook-handler.js');
|
|
17
19
|
var moneyPriceConfig = require('./lib/money-price-config.js');
|
|
18
20
|
var moneyPriceHelper = require('./lib/money-price-helper.js');
|
|
@@ -60,13 +62,14 @@ exports.isValidTransactionType = constants.isValidTransactionType;
|
|
|
60
62
|
exports.isValidUserStatus = constants.isValidUserStatus;
|
|
61
63
|
exports.userAggregateService = user_aggregate_service.userAggregateService;
|
|
62
64
|
exports.billingAggregateService = billing_aggregate_service.billingAggregateService;
|
|
63
|
-
exports.
|
|
65
|
+
exports.anonymousAggregateService = anonymous_aggregate_service.anonymousAggregateService;
|
|
64
66
|
exports.buildInitUserContextFromEntities = userContextService.buildInitUserContextFromEntities;
|
|
65
67
|
exports.fetchLatestUserContextByFingerprintId = userContextService.fetchLatestUserContextByFingerprintId;
|
|
66
68
|
exports.fetchUserContextByClerkUserId = userContextService.fetchUserContextByClerkUserId;
|
|
67
69
|
exports.mapCreditToXCredit = userContextService.mapCreditToXCredit;
|
|
68
70
|
exports.mapSubscriptionToXSubscription = userContextService.mapSubscriptionToXSubscription;
|
|
69
71
|
exports.mapUserToXUser = userContextService.mapUserToXUser;
|
|
72
|
+
exports.finalizeUserContext = userContextFinalizer.finalizeUserContext;
|
|
70
73
|
exports.handleStripeEvent = webhookHandler.handleStripeEvent;
|
|
71
74
|
exports.getActiveProviderConfig = moneyPriceConfig.getActiveProviderConfig;
|
|
72
75
|
exports.getCreditsFromPriceId = moneyPriceConfig.getCreditsFromPriceId;
|
package/dist/index.mjs
CHANGED
|
@@ -10,7 +10,9 @@ export { Apilogger, apilogService } from './services/database/apilog.service.mjs
|
|
|
10
10
|
export { BillingReason, CreditType, OperationType, OrderStatus, PaySupplier, PaymentStatus, SubscriptionStatus, TransactionType, UserStatus, isValidBillingReason, isValidCreditType, isValidOperationType, isValidOrderStatus, isValidPaymentStatus, isValidSubscriptionStatus, isValidTransactionType, isValidUserStatus } from './services/database/constants.mjs';
|
|
11
11
|
export { userAggregateService } from './services/aggregate/user.aggregate.service.mjs';
|
|
12
12
|
export { billingAggregateService } from './services/aggregate/billing.aggregate.service.mjs';
|
|
13
|
-
export {
|
|
13
|
+
export { anonymousAggregateService } from './services/aggregate/anonymous.aggregate.service.mjs';
|
|
14
|
+
export { buildInitUserContextFromEntities, fetchLatestUserContextByFingerprintId, fetchUserContextByClerkUserId, mapCreditToXCredit, mapSubscriptionToXSubscription, mapUserToXUser } from './services/context/user-context-service.mjs';
|
|
15
|
+
export { finalizeUserContext } from './services/context/user-context-finalizer.mjs';
|
|
14
16
|
export { handleStripeEvent } from './services/stripe/webhook-handler.mjs';
|
|
15
17
|
export { getActiveProviderConfig, getCreditsFromPriceId, getPriceConfig, moneyPriceConfig } from './lib/money-price-config.mjs';
|
|
16
18
|
export { getMoneyPriceInitUserContext } from './lib/money-price-helper.mjs';
|
|
@@ -5,6 +5,7 @@ var server = require('@clerk/nextjs/server');
|
|
|
5
5
|
var headers = require('next/headers');
|
|
6
6
|
var server$1 = require('@windrun-huaiin/third-ui/fingerprint/server');
|
|
7
7
|
var userContextService = require('../services/context/user-context-service.js');
|
|
8
|
+
var userContextFinalizer = require('../services/context/user-context-finalizer.js');
|
|
8
9
|
|
|
9
10
|
function readFingerprintIdFromRequest() {
|
|
10
11
|
return tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
@@ -36,7 +37,7 @@ function getMoneyPriceInitUserContext() {
|
|
|
36
37
|
subscription: userContext.subscription,
|
|
37
38
|
isClerkAuthenticated: true,
|
|
38
39
|
});
|
|
39
|
-
return
|
|
40
|
+
return userContextFinalizer.finalizeUserContext(initUserContext);
|
|
40
41
|
}
|
|
41
42
|
const fingerprintId = yield readFingerprintIdFromRequest();
|
|
42
43
|
if (!fingerprintId) {
|
|
@@ -2,7 +2,8 @@ import { __awaiter } from '../node_modules/.pnpm/@rollup_plugin-typescript@12.1.
|
|
|
2
2
|
import { auth } from '@clerk/nextjs/server';
|
|
3
3
|
import { cookies, headers } from 'next/headers';
|
|
4
4
|
import { extractFingerprintFromNextStores } from '@windrun-huaiin/third-ui/fingerprint/server';
|
|
5
|
-
import { fetchUserContextByClerkUserId, buildInitUserContextFromEntities
|
|
5
|
+
import { fetchUserContextByClerkUserId, buildInitUserContextFromEntities } from '../services/context/user-context-service.mjs';
|
|
6
|
+
import { finalizeUserContext } from '../services/context/user-context-finalizer.mjs';
|
|
6
7
|
|
|
7
8
|
function readFingerprintIdFromRequest() {
|
|
8
9
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -34,7 +35,7 @@ function getMoneyPriceInitUserContext() {
|
|
|
34
35
|
subscription: userContext.subscription,
|
|
35
36
|
isClerkAuthenticated: true,
|
|
36
37
|
});
|
|
37
|
-
return
|
|
38
|
+
return finalizeUserContext(initUserContext);
|
|
38
39
|
}
|
|
39
40
|
const fingerprintId = yield readFingerprintIdFromRequest();
|
|
40
41
|
if (!fingerprintId) {
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Credit, Subscription, User } from '@/db/prisma-model-type';
|
|
2
|
+
import { Prisma } from '@/db/prisma-model-type';
|
|
3
|
+
type AnonymousInitContext = {
|
|
4
|
+
user: User;
|
|
5
|
+
credit: Credit | null;
|
|
6
|
+
subscription: Subscription | null;
|
|
7
|
+
isNewUser: boolean;
|
|
8
|
+
totalUsersOnDevice: number;
|
|
9
|
+
hasAnonymousUser: boolean;
|
|
10
|
+
};
|
|
11
|
+
declare class AnonymousAggregateService {
|
|
12
|
+
private lockFingerprintInit;
|
|
13
|
+
private findLatestUserContextByFingerprintId;
|
|
14
|
+
private createAnonymousUser;
|
|
15
|
+
getOrCreateByFingerprintId(fingerprintId: string, options?: {
|
|
16
|
+
sourceRef?: Prisma.InputJsonValue;
|
|
17
|
+
}): Promise<AnonymousInitContext>;
|
|
18
|
+
}
|
|
19
|
+
export declare const anonymousAggregateService: AnonymousAggregateService;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=anonymous.aggregate.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anonymous.aggregate.service.d.ts","sourceRoot":"","sources":["../../../src/services/aggregate/anonymous.aggregate.service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAIzE,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAIhD,KAAK,oBAAoB,GAAG;IAC1B,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAClC,SAAS,EAAE,OAAO,CAAC;IACnB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,gBAAgB,EAAE,OAAO,CAAC;CAC3B,CAAC;AAEF,cAAM,yBAAyB;YACf,mBAAmB;YAYnB,oCAAoC;YAyBpC,mBAAmB;IAsC3B,0BAA0B,CAC9B,aAAa,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;KAAE,GAC/C,OAAO,CAAC,oBAAoB,CAAC;CAYjC;AAED,eAAO,MAAM,yBAAyB,2BAAkC,CAAC"}
|
|
@@ -0,0 +1,87 @@
|
|
|
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_service = require('../database/user.service.js');
|
|
5
|
+
var subscription_service = require('../database/subscription.service.js');
|
|
6
|
+
var credit_service = require('../database/credit.service.js');
|
|
7
|
+
var client = require('@prisma/client');
|
|
8
|
+
var constants = require('../database/constants.js');
|
|
9
|
+
require('../../prisma/prisma.js');
|
|
10
|
+
var prismaTransactionUtil = require('../../prisma/prisma-transaction-util.js');
|
|
11
|
+
var creditInit = require('../../lib/credit-init.js');
|
|
12
|
+
|
|
13
|
+
const ANONYMOUS_INIT_LOCK_NAMESPACE = 92831;
|
|
14
|
+
class AnonymousAggregateService {
|
|
15
|
+
lockFingerprintInit(tx, fingerprintId) {
|
|
16
|
+
return tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
17
|
+
yield tx.$executeRaw `
|
|
18
|
+
SELECT pg_advisory_xact_lock(
|
|
19
|
+
${client.Prisma.raw(String(ANONYMOUS_INIT_LOCK_NAMESPACE))},
|
|
20
|
+
hashtext(${fingerprintId})
|
|
21
|
+
)
|
|
22
|
+
`;
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
findLatestUserContextByFingerprintId(fingerprintId, tx) {
|
|
26
|
+
return tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
27
|
+
const existingUsers = yield user_service.userService.findListByFingerprintId(fingerprintId, tx);
|
|
28
|
+
if (existingUsers.length === 0) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
const latestUser = existingUsers[0];
|
|
32
|
+
const [credit, subscription] = yield Promise.all([
|
|
33
|
+
credit_service.creditService.getCredit(latestUser.userId, tx),
|
|
34
|
+
subscription_service.subscriptionService.getActiveSubscription(latestUser.userId, tx),
|
|
35
|
+
]);
|
|
36
|
+
return {
|
|
37
|
+
user: latestUser,
|
|
38
|
+
credit,
|
|
39
|
+
subscription,
|
|
40
|
+
isNewUser: false,
|
|
41
|
+
totalUsersOnDevice: existingUsers.length,
|
|
42
|
+
hasAnonymousUser: true,
|
|
43
|
+
};
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
createAnonymousUser(fingerprintId, tx, options) {
|
|
47
|
+
return tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
48
|
+
const newUser = yield user_service.userService.createUser({
|
|
49
|
+
fingerprintId,
|
|
50
|
+
sourceRef: options === null || options === void 0 ? void 0 : options.sourceRef,
|
|
51
|
+
status: constants.UserStatus.ANONYMOUS,
|
|
52
|
+
}, tx);
|
|
53
|
+
const credit = yield credit_service.creditService.initializeCreditWithFree({
|
|
54
|
+
userId: newUser.userId,
|
|
55
|
+
feature: 'anonymous_user_init',
|
|
56
|
+
creditType: constants.CreditType.FREE,
|
|
57
|
+
operationType: constants.OperationType.SYS_GIFT,
|
|
58
|
+
operationReferId: newUser.userId,
|
|
59
|
+
creditsChange: creditInit.freeAmount,
|
|
60
|
+
}, tx);
|
|
61
|
+
yield subscription_service.subscriptionService.initializeSubscription(newUser.userId, tx);
|
|
62
|
+
return {
|
|
63
|
+
user: newUser,
|
|
64
|
+
credit,
|
|
65
|
+
subscription: null,
|
|
66
|
+
isNewUser: true,
|
|
67
|
+
totalUsersOnDevice: 1,
|
|
68
|
+
hasAnonymousUser: true,
|
|
69
|
+
};
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
getOrCreateByFingerprintId(fingerprintId, options) {
|
|
73
|
+
return tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
74
|
+
return prismaTransactionUtil.runInTransaction((tx) => tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
75
|
+
yield this.lockFingerprintInit(tx, fingerprintId);
|
|
76
|
+
const existingContext = yield this.findLatestUserContextByFingerprintId(fingerprintId, tx);
|
|
77
|
+
if (existingContext) {
|
|
78
|
+
return existingContext;
|
|
79
|
+
}
|
|
80
|
+
return this.createAnonymousUser(fingerprintId, tx, options);
|
|
81
|
+
}), 'anonymous_get_or_create_by_fingerprint_id');
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const anonymousAggregateService = new AnonymousAggregateService();
|
|
86
|
+
|
|
87
|
+
exports.anonymousAggregateService = anonymousAggregateService;
|
|
@@ -0,0 +1,85 @@
|
|
|
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 { userService } from '../database/user.service.mjs';
|
|
3
|
+
import { subscriptionService } from '../database/subscription.service.mjs';
|
|
4
|
+
import { creditService } from '../database/credit.service.mjs';
|
|
5
|
+
import { Prisma } from '@prisma/client';
|
|
6
|
+
import { UserStatus, OperationType, CreditType } from '../database/constants.mjs';
|
|
7
|
+
import '../../prisma/prisma.mjs';
|
|
8
|
+
import { runInTransaction } from '../../prisma/prisma-transaction-util.mjs';
|
|
9
|
+
import { freeAmount } from '../../lib/credit-init.mjs';
|
|
10
|
+
|
|
11
|
+
const ANONYMOUS_INIT_LOCK_NAMESPACE = 92831;
|
|
12
|
+
class AnonymousAggregateService {
|
|
13
|
+
lockFingerprintInit(tx, fingerprintId) {
|
|
14
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
15
|
+
yield tx.$executeRaw `
|
|
16
|
+
SELECT pg_advisory_xact_lock(
|
|
17
|
+
${Prisma.raw(String(ANONYMOUS_INIT_LOCK_NAMESPACE))},
|
|
18
|
+
hashtext(${fingerprintId})
|
|
19
|
+
)
|
|
20
|
+
`;
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
findLatestUserContextByFingerprintId(fingerprintId, tx) {
|
|
24
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
25
|
+
const existingUsers = yield userService.findListByFingerprintId(fingerprintId, tx);
|
|
26
|
+
if (existingUsers.length === 0) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
const latestUser = existingUsers[0];
|
|
30
|
+
const [credit, subscription] = yield Promise.all([
|
|
31
|
+
creditService.getCredit(latestUser.userId, tx),
|
|
32
|
+
subscriptionService.getActiveSubscription(latestUser.userId, tx),
|
|
33
|
+
]);
|
|
34
|
+
return {
|
|
35
|
+
user: latestUser,
|
|
36
|
+
credit,
|
|
37
|
+
subscription,
|
|
38
|
+
isNewUser: false,
|
|
39
|
+
totalUsersOnDevice: existingUsers.length,
|
|
40
|
+
hasAnonymousUser: true,
|
|
41
|
+
};
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
createAnonymousUser(fingerprintId, tx, options) {
|
|
45
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
46
|
+
const newUser = yield userService.createUser({
|
|
47
|
+
fingerprintId,
|
|
48
|
+
sourceRef: options === null || options === void 0 ? void 0 : options.sourceRef,
|
|
49
|
+
status: UserStatus.ANONYMOUS,
|
|
50
|
+
}, tx);
|
|
51
|
+
const credit = yield creditService.initializeCreditWithFree({
|
|
52
|
+
userId: newUser.userId,
|
|
53
|
+
feature: 'anonymous_user_init',
|
|
54
|
+
creditType: CreditType.FREE,
|
|
55
|
+
operationType: OperationType.SYS_GIFT,
|
|
56
|
+
operationReferId: newUser.userId,
|
|
57
|
+
creditsChange: freeAmount,
|
|
58
|
+
}, tx);
|
|
59
|
+
yield subscriptionService.initializeSubscription(newUser.userId, tx);
|
|
60
|
+
return {
|
|
61
|
+
user: newUser,
|
|
62
|
+
credit,
|
|
63
|
+
subscription: null,
|
|
64
|
+
isNewUser: true,
|
|
65
|
+
totalUsersOnDevice: 1,
|
|
66
|
+
hasAnonymousUser: true,
|
|
67
|
+
};
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
getOrCreateByFingerprintId(fingerprintId, options) {
|
|
71
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
72
|
+
return runInTransaction((tx) => __awaiter(this, void 0, void 0, function* () {
|
|
73
|
+
yield this.lockFingerprintInit(tx, fingerprintId);
|
|
74
|
+
const existingContext = yield this.findLatestUserContextByFingerprintId(fingerprintId, tx);
|
|
75
|
+
if (existingContext) {
|
|
76
|
+
return existingContext;
|
|
77
|
+
}
|
|
78
|
+
return this.createAnonymousUser(fingerprintId, tx, options);
|
|
79
|
+
}), 'anonymous_get_or_create_by_fingerprint_id');
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
const anonymousAggregateService = new AnonymousAggregateService();
|
|
84
|
+
|
|
85
|
+
export { anonymousAggregateService };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/aggregate/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/aggregate/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AACtE,OAAO,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAC"}
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
var user_aggregate_service = require('./user.aggregate.service.js');
|
|
4
4
|
var billing_aggregate_service = require('./billing.aggregate.service.js');
|
|
5
|
+
var anonymous_aggregate_service = require('./anonymous.aggregate.service.js');
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
exports.userAggregateService = user_aggregate_service.userAggregateService;
|
|
9
10
|
exports.billingAggregateService = billing_aggregate_service.billingAggregateService;
|
|
11
|
+
exports.anonymousAggregateService = anonymous_aggregate_service.anonymousAggregateService;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/context/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/context/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC"}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var userContextService = require('./user-context-service.js');
|
|
4
|
+
var userContextFinalizer = require('./user-context-finalizer.js');
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
|
|
7
|
-
exports.applyUserMockContext = userContextService.applyUserMockContext;
|
|
8
8
|
exports.buildInitUserContextFromEntities = userContextService.buildInitUserContextFromEntities;
|
|
9
9
|
exports.fetchLatestUserContextByFingerprintId = userContextService.fetchLatestUserContextByFingerprintId;
|
|
10
10
|
exports.fetchUserContextByClerkUserId = userContextService.fetchUserContextByClerkUserId;
|
|
11
11
|
exports.mapCreditToXCredit = userContextService.mapCreditToXCredit;
|
|
12
12
|
exports.mapSubscriptionToXSubscription = userContextService.mapSubscriptionToXSubscription;
|
|
13
13
|
exports.mapUserToXUser = userContextService.mapUserToXUser;
|
|
14
|
+
exports.finalizeUserContext = userContextFinalizer.finalizeUserContext;
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { buildInitUserContextFromEntities, fetchLatestUserContextByFingerprintId, fetchUserContextByClerkUserId, mapCreditToXCredit, mapSubscriptionToXSubscription, mapUserToXUser } from './user-context-service.mjs';
|
|
2
|
+
export { finalizeUserContext } from './user-context-finalizer.mjs';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { XSubscription, XUser } from '@windrun-huaiin/third-ui/fingerprint';
|
|
2
|
+
type FinalizableUserContext = {
|
|
3
|
+
xUser: XUser | null;
|
|
4
|
+
xSubscription: XSubscription | null;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Output finalizer for user-context payloads.
|
|
8
|
+
* Real data assembly should stay in user-context-service; any optional test-only
|
|
9
|
+
* shaping is isolated here so production services do not depend on mock code.
|
|
10
|
+
*/
|
|
11
|
+
export declare function finalizeUserContext<T extends FinalizableUserContext>(context: T): T;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=user-context-finalizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user-context-finalizer.d.ts","sourceRoot":"","sources":["../../../src/services/context/user-context-finalizer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,sCAAsC,CAAC;AAEjF,KAAK,sBAAsB,GAAG;IAC5B,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,aAAa,EAAE,aAAa,GAAG,IAAI,CAAC;CACrC,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,sBAAsB,EAAE,OAAO,EAAE,CAAC,GAAG,CAAC,CAsEnF"}
|