abmp-npm 10.0.71 → 10.0.73
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/backend/jobs.js +12 -0
- package/backend/tasks/consts.js +1 -0
- package/backend/tasks/daily-pull-check-methods.js +58 -0
- package/backend/tasks/index.js +1 -0
- package/backend/tasks/tasks-configs.js +8 -0
- package/package.json +1 -1
- package/pages/Home.js +20 -0
- package/public/Utils/homePage.js +29 -0
- package/public/Utils/homePageLoadTrace.js +58 -0
package/backend/jobs.js
CHANGED
|
@@ -2,6 +2,7 @@ const { taskManager } = require('psdev-task-manager');
|
|
|
2
2
|
|
|
3
3
|
const { MEMBER_ACTIONS } = require('./daily-pull/consts');
|
|
4
4
|
const { TASKS_NAMES } = require('./tasks/consts');
|
|
5
|
+
const { dailyPullExecutionCheck } = require('./tasks/daily-pull-check-methods');
|
|
5
6
|
const { TASKS } = require('./tasks/tasks-configs');
|
|
6
7
|
|
|
7
8
|
async function runScheduledTasks() {
|
|
@@ -96,6 +97,16 @@ async function scheduleFixUrlsWithSpacesTask() {
|
|
|
96
97
|
}
|
|
97
98
|
}
|
|
98
99
|
|
|
100
|
+
async function runDailyPullExecutionCheck() {
|
|
101
|
+
try {
|
|
102
|
+
console.log('runDailyPullExecutionCheck started!');
|
|
103
|
+
return await dailyPullExecutionCheck({});
|
|
104
|
+
} catch (error) {
|
|
105
|
+
console.error(`Failed to runDailyPullExecutionCheck: ${error.message}`);
|
|
106
|
+
throw new Error(`Failed to runDailyPullExecutionCheck: ${error.message}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
99
110
|
async function updateSiteMapS3() {
|
|
100
111
|
try {
|
|
101
112
|
return await taskManager().schedule({
|
|
@@ -115,4 +126,5 @@ module.exports = {
|
|
|
115
126
|
scheduleCreateContactsFromMembersTask,
|
|
116
127
|
scheduleFixPrimaryAddressForMembersTask,
|
|
117
128
|
scheduleFixUrlsWithSpacesTask,
|
|
129
|
+
runDailyPullExecutionCheck,
|
|
118
130
|
};
|
package/backend/tasks/consts.js
CHANGED
|
@@ -22,6 +22,7 @@ const TASKS_NAMES = {
|
|
|
22
22
|
fixPrimaryAddressChunk: 'fixPrimaryAddressChunk',
|
|
23
23
|
scheduleFixUrlsWithSpaces: 'scheduleFixUrlsWithSpaces',
|
|
24
24
|
fixUrlsWithSpacesChunk: 'fixUrlsWithSpacesChunk',
|
|
25
|
+
dailyPullExecutionCheck: 'dailyPullExecutionCheck',
|
|
25
26
|
};
|
|
26
27
|
|
|
27
28
|
module.exports = {
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
const { taskManager } = require('psdev-task-manager');
|
|
2
|
+
const { COLLECTIONS } = require('psdev-task-manager/public/consts');
|
|
3
|
+
|
|
4
|
+
const { wixData } = require('../elevated-modules');
|
|
5
|
+
const { queryAllItems } = require('../utils');
|
|
6
|
+
|
|
7
|
+
const { TASKS_NAMES } = require('./consts');
|
|
8
|
+
|
|
9
|
+
const DEFAULT_HOURS_BACK = 4;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Detects whether the daily pull was scheduled (cron / root task).
|
|
13
|
+
* If no `ScheduleDailyMembersDataSync` task exists in the lookback window, schedules it.
|
|
14
|
+
*/
|
|
15
|
+
async function dailyPullExecutionCheck(taskData) {
|
|
16
|
+
const hoursBack =
|
|
17
|
+
taskData?.hoursBack && Number.isFinite(taskData.hoursBack)
|
|
18
|
+
? taskData.hoursBack
|
|
19
|
+
: DEFAULT_HOURS_BACK;
|
|
20
|
+
const sinceDate = new Date(Date.now() - hoursBack * 60 * 60 * 1000);
|
|
21
|
+
|
|
22
|
+
console.log('dailyPullExecutionCheck started', { hoursBack, sinceDate });
|
|
23
|
+
|
|
24
|
+
const rootTasksQuery = wixData
|
|
25
|
+
.query(COLLECTIONS.TASKS)
|
|
26
|
+
.eq('name', TASKS_NAMES.ScheduleDailyMembersDataSync)
|
|
27
|
+
.ge('_createdDate', sinceDate);
|
|
28
|
+
|
|
29
|
+
const rootTasks = await queryAllItems(rootTasksQuery);
|
|
30
|
+
const rootTaskScheduled = rootTasks.length > 0;
|
|
31
|
+
|
|
32
|
+
const result = {
|
|
33
|
+
success: rootTaskScheduled,
|
|
34
|
+
sinceDate: sinceDate.toISOString(),
|
|
35
|
+
rootTaskName: TASKS_NAMES.ScheduleDailyMembersDataSync,
|
|
36
|
+
rootTasksFound: rootTasks.length,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
if (!rootTaskScheduled) {
|
|
40
|
+
console.log('ScheduleDailyMembersDataSync missing in window; scheduling root daily pull', {
|
|
41
|
+
hoursBack,
|
|
42
|
+
});
|
|
43
|
+
await taskManager().schedule({
|
|
44
|
+
name: TASKS_NAMES.ScheduleDailyMembersDataSync,
|
|
45
|
+
data: {},
|
|
46
|
+
type: 'scheduled',
|
|
47
|
+
});
|
|
48
|
+
result.fallbackScheduled = true;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
console.log('dailyPullExecutionCheck result', JSON.stringify(result, null, 2));
|
|
52
|
+
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
module.exports = {
|
|
57
|
+
dailyPullExecutionCheck,
|
|
58
|
+
};
|
package/backend/tasks/index.js
CHANGED
|
@@ -9,6 +9,7 @@ const {
|
|
|
9
9
|
fixPrimaryAddressChunk,
|
|
10
10
|
} = require('./address-primary-methods');
|
|
11
11
|
const { TASKS_NAMES } = require('./consts');
|
|
12
|
+
const { dailyPullExecutionCheck } = require('./daily-pull-check-methods');
|
|
12
13
|
const {
|
|
13
14
|
scheduleTaskForEmptyAboutYouMembers,
|
|
14
15
|
convertAboutYouHtmlToRichContent,
|
|
@@ -202,6 +203,13 @@ const TASKS = {
|
|
|
202
203
|
shouldSkipCheck: () => false,
|
|
203
204
|
estimatedDurationSec: 80,
|
|
204
205
|
},
|
|
206
|
+
[TASKS_NAMES.dailyPullExecutionCheck]: {
|
|
207
|
+
name: TASKS_NAMES.dailyPullExecutionCheck,
|
|
208
|
+
getIdentifier: task => task.data,
|
|
209
|
+
process: dailyPullExecutionCheck,
|
|
210
|
+
shouldSkipCheck: () => false,
|
|
211
|
+
estimatedDurationSec: 30,
|
|
212
|
+
},
|
|
205
213
|
};
|
|
206
214
|
|
|
207
215
|
module.exports = { TASKS };
|
package/package.json
CHANGED
package/pages/Home.js
CHANGED
|
@@ -5,6 +5,7 @@ const { withWarmUpData } = require('psdev-utils/frontend');
|
|
|
5
5
|
|
|
6
6
|
const { ADDRESS_STATUS_TYPES, DEFAULT_FILTER, DROPDOWN_OPTIONS } = require('../public/consts.js');
|
|
7
7
|
const { createHomepageUtils } = require('../public/Utils/homePage.js');
|
|
8
|
+
const { logHomePageLoadPhase } = require('../public/Utils/homePageLoadTrace.js');
|
|
8
9
|
const {
|
|
9
10
|
getMainAddress,
|
|
10
11
|
formatPracticeAreasForDisplay,
|
|
@@ -13,6 +14,8 @@ const {
|
|
|
13
14
|
normalizeExternalUrl,
|
|
14
15
|
} = require('../public/Utils/sharedUtils.js');
|
|
15
16
|
|
|
17
|
+
logHomePageLoadPhase('home_js_module_evaluated');
|
|
18
|
+
|
|
16
19
|
let filter = JSON.parse(JSON.stringify(DEFAULT_FILTER));
|
|
17
20
|
let dropDownOptions = JSON.parse(JSON.stringify(DROPDOWN_OPTIONS));
|
|
18
21
|
let stateCityMap;
|
|
@@ -36,6 +39,7 @@ const homePageOnReady = async ({
|
|
|
36
39
|
getNonCompiledFiltersOptions,
|
|
37
40
|
filterProfiles,
|
|
38
41
|
}) => {
|
|
42
|
+
logHomePageLoadPhase('wix_onready_handler_entered');
|
|
39
43
|
const {
|
|
40
44
|
getParamsMapping,
|
|
41
45
|
handlePagination,
|
|
@@ -58,7 +62,9 @@ const homePageOnReady = async ({
|
|
|
58
62
|
detectMobile();
|
|
59
63
|
initPageUI();
|
|
60
64
|
attachEventListeners();
|
|
65
|
+
logHomePageLoadPhase('before_handleUrlParams');
|
|
61
66
|
await handleUrlParams();
|
|
67
|
+
logHomePageLoadPhase('after_handleUrlParams');
|
|
62
68
|
|
|
63
69
|
async function detectMobile() {
|
|
64
70
|
try {
|
|
@@ -279,6 +285,7 @@ const homePageOnReady = async ({
|
|
|
279
285
|
}
|
|
280
286
|
|
|
281
287
|
async function handleUrlParams() {
|
|
288
|
+
logHomePageLoadPhase('handleUrlParams_start');
|
|
282
289
|
const { isDefaultStateParams, filter: newFilter } = await parseAndValidateQueryParams(
|
|
283
290
|
filter,
|
|
284
291
|
pagination
|
|
@@ -288,7 +295,9 @@ const homePageOnReady = async ({
|
|
|
288
295
|
}
|
|
289
296
|
|
|
290
297
|
async function applyFilterToUI(isDefaultStateParams) {
|
|
298
|
+
logHomePageLoadPhase('applyFilterToUI_start', { isDefaultStateParams });
|
|
291
299
|
const renderingEnv = await rendering.env();
|
|
300
|
+
logHomePageLoadPhase('applyFilterToUI_rendering_env', { env: renderingEnv });
|
|
292
301
|
const setFilterFromParams = async (isInitializeValue = true) => {
|
|
293
302
|
const params = await wixLocation.query();
|
|
294
303
|
console.log('params inside setFilterFromParams ', params);
|
|
@@ -322,7 +331,9 @@ const homePageOnReady = async ({
|
|
|
322
331
|
await setFilterFromParams(true);
|
|
323
332
|
if (isDefaultStateParams) {
|
|
324
333
|
console.log('default state set for nearby');
|
|
334
|
+
logHomePageLoadPhase('applyFilterToUI_default_path_fetch_and_nearby_start');
|
|
325
335
|
await Promise.all([fetchFilterData(), nearByHandler(true)]);
|
|
336
|
+
logHomePageLoadPhase('applyFilterToUI_default_path_complete');
|
|
326
337
|
return;
|
|
327
338
|
}
|
|
328
339
|
console.log('not default state');
|
|
@@ -341,12 +352,15 @@ const homePageOnReady = async ({
|
|
|
341
352
|
: () => updateResults('filterTimeout', true);
|
|
342
353
|
console.log('filter ..', filter);
|
|
343
354
|
try {
|
|
355
|
+
logHomePageLoadPhase('applyFilterToUI_non_default_path_start');
|
|
344
356
|
await Promise.all([
|
|
345
357
|
fetchFilterData().then(() => setFilterFromParams(false)),
|
|
346
358
|
//TODO: remove this workaround to fix issue with SSR showing invalid results
|
|
347
359
|
renderingEnv === 'backend' ? Promise.resolve() : searchPromise(),
|
|
348
360
|
]);
|
|
361
|
+
logHomePageLoadPhase('applyFilterToUI_non_default_path_complete');
|
|
349
362
|
} catch (error) {
|
|
363
|
+
logHomePageLoadPhase('applyFilterToUI_error', { message: String(error && error.message) });
|
|
350
364
|
console.error('[applyFilterToUI] failed with error:', error);
|
|
351
365
|
multiStateBoxSelector.changeState('errorState');
|
|
352
366
|
}
|
|
@@ -425,6 +439,7 @@ const homePageOnReady = async ({
|
|
|
425
439
|
}
|
|
426
440
|
// NEAR BY FILTER
|
|
427
441
|
async function nearByHandler(preservePagination = false) {
|
|
442
|
+
logHomePageLoadPhase('nearByHandler_start', { preservePagination });
|
|
428
443
|
const isSearchingNearby = _$w('#nearBy').checked;
|
|
429
444
|
const renderingEnv = await rendering.env();
|
|
430
445
|
// 1. Disable nearby input while processing
|
|
@@ -438,6 +453,7 @@ const homePageOnReady = async ({
|
|
|
438
453
|
filter = newFilter;
|
|
439
454
|
console.log('filter inside nearByHandler', filter);
|
|
440
455
|
if (!success) {
|
|
456
|
+
logHomePageLoadPhase('nearByHandler_geolocation_failed');
|
|
441
457
|
if (renderingEnv !== 'backend') {
|
|
442
458
|
//on Backend environment, geolocation API don't work, so makes no sense to change state for near by
|
|
443
459
|
multiStateBoxSelector.changeState('nearByState');
|
|
@@ -452,6 +468,7 @@ const homePageOnReady = async ({
|
|
|
452
468
|
// If location is not selected, change state to "resultsState"
|
|
453
469
|
if (!isSearchingNearby) {
|
|
454
470
|
if (await noSearchCriteria()) {
|
|
471
|
+
logHomePageLoadPhase('nearByHandler_no_search_criteria');
|
|
455
472
|
multiStateBoxSelector.changeState('noSearchCriteria');
|
|
456
473
|
// 4. Re-enable nearby input
|
|
457
474
|
_$w('#nearBy').enable();
|
|
@@ -463,6 +480,7 @@ const homePageOnReady = async ({
|
|
|
463
480
|
|
|
464
481
|
// 4. Re-enable nearby input when done
|
|
465
482
|
_$w('#nearBy').enable();
|
|
483
|
+
logHomePageLoadPhase('nearByHandler_complete', { success: true });
|
|
466
484
|
return true;
|
|
467
485
|
}
|
|
468
486
|
|
|
@@ -470,6 +488,7 @@ const homePageOnReady = async ({
|
|
|
470
488
|
// FETCH STATE/CITY/AREAS OF PRACTICE FROM BACKEND ONCE AND STORE IT
|
|
471
489
|
|
|
472
490
|
async function fetchFilterData() {
|
|
491
|
+
logHomePageLoadPhase('fetchFilterData_start');
|
|
473
492
|
let completeStateList, areasOfPracticesList, stateCityMapList;
|
|
474
493
|
try {
|
|
475
494
|
const { COMPILED_STATE_LIST, COMPILED_AREAS_OF_PRACTICES, COMPILED_STATE_CITY_MAP } =
|
|
@@ -510,6 +529,7 @@ const homePageOnReady = async ({
|
|
|
510
529
|
|
|
511
530
|
// Update filter states after data is loaded
|
|
512
531
|
updateFiltersState();
|
|
532
|
+
logHomePageLoadPhase('fetchFilterData_complete');
|
|
513
533
|
}
|
|
514
534
|
|
|
515
535
|
// CONSTRUCT DROPDOWN OPTIONS FOR STATE, CITY, AREA OF PRACTICES
|
package/public/Utils/homePage.js
CHANGED
|
@@ -3,6 +3,7 @@ const { window: wixWindow, rendering } = require('@wix/site-window');
|
|
|
3
3
|
|
|
4
4
|
const { DEFAULT_FILTER } = require('../consts.js');
|
|
5
5
|
|
|
6
|
+
const { logHomePageLoadPhase } = require('./homePageLoadTrace.js');
|
|
6
7
|
const { debouncedFunction } = require('./sharedUtils.js');
|
|
7
8
|
|
|
8
9
|
const createHomepageUtils = (_$w, filterProfiles) => {
|
|
@@ -362,6 +363,7 @@ const createHomepageUtils = (_$w, filterProfiles) => {
|
|
|
362
363
|
});
|
|
363
364
|
}
|
|
364
365
|
async function getAndSetUserLocation(isSearchingNearby, filter) {
|
|
366
|
+
logHomePageLoadPhase('getAndSetUserLocation_start', { isSearchingNearby });
|
|
365
367
|
try {
|
|
366
368
|
let location = {
|
|
367
369
|
coords: {
|
|
@@ -369,6 +371,7 @@ const createHomepageUtils = (_$w, filterProfiles) => {
|
|
|
369
371
|
longitude: 0,
|
|
370
372
|
},
|
|
371
373
|
};
|
|
374
|
+
logHomePageLoadPhase('getAndSetUserLocation_before_getCurrentGeolocation');
|
|
372
375
|
location = await wixWindow.getCurrentGeolocation();
|
|
373
376
|
|
|
374
377
|
console.log('location inside getAndSetUserLocation', location);
|
|
@@ -384,8 +387,15 @@ const createHomepageUtils = (_$w, filterProfiles) => {
|
|
|
384
387
|
latitude: userLat,
|
|
385
388
|
longitude: userLong,
|
|
386
389
|
};
|
|
390
|
+
logHomePageLoadPhase('getAndSetUserLocation_success', {
|
|
391
|
+
lat: userLat,
|
|
392
|
+
lng: userLong,
|
|
393
|
+
});
|
|
387
394
|
return { success: true, filter };
|
|
388
395
|
} catch (error) {
|
|
396
|
+
logHomePageLoadPhase('getAndSetUserLocation_error', {
|
|
397
|
+
message: String(error && error.message),
|
|
398
|
+
});
|
|
389
399
|
console.warn('Failed to get user location in getAndSetUserLocation', error);
|
|
390
400
|
return { success: false, filter };
|
|
391
401
|
}
|
|
@@ -504,6 +514,7 @@ const createHomepageUtils = (_$w, filterProfiles) => {
|
|
|
504
514
|
);
|
|
505
515
|
}
|
|
506
516
|
async function parseAndValidateQueryParams(filter, pagination) {
|
|
517
|
+
logHomePageLoadPhase('parseAndValidateQueryParams_start');
|
|
507
518
|
const params = await wixLocation.query();
|
|
508
519
|
const paramsMapping = getParamsMapping(filter, pagination);
|
|
509
520
|
const {
|
|
@@ -515,6 +526,11 @@ const createHomepageUtils = (_$w, filterProfiles) => {
|
|
|
515
526
|
const isSearchingNearby = params.nearby === 'true';
|
|
516
527
|
const isNoParams = !withoutPreviewParams || Object.keys(withoutPreviewParams).length === 0;
|
|
517
528
|
const { success, filter: newFilter } = await getAndSetUserLocation(isSearchingNearby, filter);
|
|
529
|
+
logHomePageLoadPhase('parseAndValidateQueryParams_after_geolocation', {
|
|
530
|
+
isNoParams,
|
|
531
|
+
isSearchingNearby,
|
|
532
|
+
success,
|
|
533
|
+
});
|
|
518
534
|
|
|
519
535
|
// Auto-enable nearby if GPS permission granted on fresh page load
|
|
520
536
|
if (
|
|
@@ -525,6 +541,7 @@ const createHomepageUtils = (_$w, filterProfiles) => {
|
|
|
525
541
|
!isSearchingNearby
|
|
526
542
|
) {
|
|
527
543
|
await wixQueryParams.add({ nearby: 'true', page: '1' });
|
|
544
|
+
logHomePageLoadPhase('parseAndValidateQueryParams_return', { branch: 'auto_nearby_url' });
|
|
528
545
|
return { isDefaultStateParams: true, filter: newFilter };
|
|
529
546
|
}
|
|
530
547
|
|
|
@@ -538,6 +555,7 @@ const createHomepageUtils = (_$w, filterProfiles) => {
|
|
|
538
555
|
// });
|
|
539
556
|
// Don't search yet - let the caller decide what to do
|
|
540
557
|
// The search will be handled in applyFilterToUI
|
|
558
|
+
logHomePageLoadPhase('parseAndValidateQueryParams_return', { branch: 'default_no_params' });
|
|
541
559
|
return { isDefaultStateParams: true, filter: newFilter };
|
|
542
560
|
}
|
|
543
561
|
let autoAdjustFilters = false;
|
|
@@ -577,6 +595,10 @@ const createHomepageUtils = (_$w, filterProfiles) => {
|
|
|
577
595
|
withoutPreviewParams.page) ||
|
|
578
596
|
(Object.keys(withoutPreviewParams).length === 1 && withoutPreviewParams.nearby);
|
|
579
597
|
const isDefaultStateParams = isNoParams || isNearbyFilter;
|
|
598
|
+
logHomePageLoadPhase('parseAndValidateQueryParams_return', {
|
|
599
|
+
branch: 'with_query_params',
|
|
600
|
+
isDefaultStateParams,
|
|
601
|
+
});
|
|
580
602
|
return { isDefaultStateParams, filter: newFilter };
|
|
581
603
|
}
|
|
582
604
|
|
|
@@ -660,6 +682,7 @@ const createHomepageUtils = (_$w, filterProfiles) => {
|
|
|
660
682
|
isSearchingNearby,
|
|
661
683
|
preservePagination = false,
|
|
662
684
|
}) {
|
|
685
|
+
logHomePageLoadPhase('search_start', { timeoutType, isSearchingNearby });
|
|
663
686
|
const multiStateBoxSelector = _$w('#resultsStateBox');
|
|
664
687
|
const renderingEnv = await rendering.env();
|
|
665
688
|
const initSearchResultsUI = () => {
|
|
@@ -681,6 +704,7 @@ const createHomepageUtils = (_$w, filterProfiles) => {
|
|
|
681
704
|
longitude: 0,
|
|
682
705
|
}) === JSON.stringify(DEFAULT_FILTER)
|
|
683
706
|
) {
|
|
707
|
+
logHomePageLoadPhase('search_short_circuit_no_criteria');
|
|
684
708
|
multiStateBoxSelector.changeState('noSearchCriteria');
|
|
685
709
|
return [];
|
|
686
710
|
}
|
|
@@ -704,14 +728,19 @@ const createHomepageUtils = (_$w, filterProfiles) => {
|
|
|
704
728
|
timeoutType,
|
|
705
729
|
args: { filter, isSearchingNearby },
|
|
706
730
|
});
|
|
731
|
+
logHomePageLoadPhase('search_before_filterProfiles', { renderingEnv });
|
|
707
732
|
const { success, response, error } = await funcPromise();
|
|
708
733
|
if (!success) {
|
|
709
734
|
_$w('#numberOfResults').text = '';
|
|
710
735
|
console.error('[search] failed with error:', error);
|
|
736
|
+
logHomePageLoadPhase('search_filterProfiles_failed', {
|
|
737
|
+
message: String(error && error.message),
|
|
738
|
+
});
|
|
711
739
|
multiStateBoxSelector.changeState('errorState');
|
|
712
740
|
return [];
|
|
713
741
|
}
|
|
714
742
|
const totalCount = response.items.length;
|
|
743
|
+
logHomePageLoadPhase('search_filterProfiles_success', { totalCount });
|
|
715
744
|
if (!totalCount) {
|
|
716
745
|
_$w('#numberOfResults').text = 'Showing 0 results';
|
|
717
746
|
_$w('#noResultsMessage').text = `${
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One session per full page load. First log call creates `loadId` (send this to support for GCL search).
|
|
3
|
+
* Logs are one JSON line per line for easy grep: type "HomePageLoad" and field loadId.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
function randomSegment() {
|
|
7
|
+
return Math.random().toString(36).slice(2, 10);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function nowMs() {
|
|
11
|
+
if (typeof performance !== 'undefined' && typeof performance.now === 'function') {
|
|
12
|
+
return performance.now();
|
|
13
|
+
}
|
|
14
|
+
return Date.now();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
let session = null;
|
|
18
|
+
|
|
19
|
+
function ensureSession() {
|
|
20
|
+
if (session) {
|
|
21
|
+
return session;
|
|
22
|
+
}
|
|
23
|
+
const t0 = nowMs();
|
|
24
|
+
session = {
|
|
25
|
+
loadId: `hpl_${Date.now()}_${randomSegment()}_${randomSegment()}`,
|
|
26
|
+
t0,
|
|
27
|
+
};
|
|
28
|
+
return session;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @param {string} phase
|
|
33
|
+
* @param {Record<string, unknown>} [detail]
|
|
34
|
+
*/
|
|
35
|
+
function logHomePageLoadPhase(phase, detail) {
|
|
36
|
+
const s = ensureSession();
|
|
37
|
+
const elapsed = Math.round(nowMs() - s.t0);
|
|
38
|
+
const payload = {
|
|
39
|
+
type: 'HomePageLoad',
|
|
40
|
+
loadId: s.loadId,
|
|
41
|
+
phase,
|
|
42
|
+
elapsedSinceStartMs: elapsed,
|
|
43
|
+
wallTimeIso: new Date().toISOString(),
|
|
44
|
+
};
|
|
45
|
+
if (detail && typeof detail === 'object') {
|
|
46
|
+
payload.detail = detail;
|
|
47
|
+
}
|
|
48
|
+
console.log(JSON.stringify(payload));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function getHomePageLoadId() {
|
|
52
|
+
return ensureSession().loadId;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
module.exports = {
|
|
56
|
+
logHomePageLoadPhase,
|
|
57
|
+
getHomePageLoadId,
|
|
58
|
+
};
|