@playq/core 0.2.77
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 +41 -0
- package/bin/playq.js +175 -0
- package/cucumber.js +10 -0
- package/dist/exec/featureFileCache.d.ts +21 -0
- package/dist/exec/featureFileCache.js +124 -0
- package/dist/exec/featureFilePreProcess.d.ts +12 -0
- package/dist/exec/featureFilePreProcess.js +208 -0
- package/dist/exec/preLoader.d.ts +1 -0
- package/dist/exec/preLoader.js +72 -0
- package/dist/exec/preProcessEntry.d.ts +1 -0
- package/dist/exec/preProcessEntry.js +83 -0
- package/dist/exec/preProcess_old_todelete.d.ts +1 -0
- package/dist/exec/preProcess_old_todelete.js +258 -0
- package/dist/exec/runner.d.ts +1 -0
- package/dist/exec/runner.js +221 -0
- package/dist/exec/runner_orchestrator.d.ts +1 -0
- package/dist/exec/runner_orchestrator.js +85 -0
- package/dist/exec/sgGenerator.d.ts +11 -0
- package/dist/exec/sgGenerator.js +310 -0
- package/dist/global.d.ts +15 -0
- package/dist/global.js +185 -0
- package/dist/helper/actions/api/apiRequestActions.d.ts +117 -0
- package/dist/helper/actions/api/apiRequestActions.js +374 -0
- package/dist/helper/actions/api/apiValidationActions.d.ts +119 -0
- package/dist/helper/actions/api/apiValidationActions.js +615 -0
- package/dist/helper/actions/apiActions.d.ts +18 -0
- package/dist/helper/actions/apiActions.js +34 -0
- package/dist/helper/actions/apiStepDefs.d.ts +1 -0
- package/dist/helper/actions/apiStepDefs.js +64 -0
- package/dist/helper/actions/comm/commonActions.d.ts +58 -0
- package/dist/helper/actions/comm/commonActions.js +198 -0
- package/dist/helper/actions/comm/utilityActions.d.ts +131 -0
- package/dist/helper/actions/comm/utilityActions.js +351 -0
- package/dist/helper/actions/commActions.d.ts +18 -0
- package/dist/helper/actions/commActions.js +34 -0
- package/dist/helper/actions/commStepDefs.d.ts +1 -0
- package/dist/helper/actions/commStepDefs.js +57 -0
- package/dist/helper/actions/stepGroupStepDefs.d.ts +1 -0
- package/dist/helper/actions/stepGroupStepDefs.js +15 -0
- package/dist/helper/actions/web/alertActions.d.ts +61 -0
- package/dist/helper/actions/web/alertActions.js +224 -0
- package/dist/helper/actions/web/cookieActions.d.ts +45 -0
- package/dist/helper/actions/web/cookieActions.js +186 -0
- package/dist/helper/actions/web/downloadActions.d.ts +40 -0
- package/dist/helper/actions/web/downloadActions.js +153 -0
- package/dist/helper/actions/web/elementReaderActions.d.ts +95 -0
- package/dist/helper/actions/web/elementReaderActions.js +326 -0
- package/dist/helper/actions/web/formActions.d.ts +122 -0
- package/dist/helper/actions/web/formActions.js +423 -0
- package/dist/helper/actions/web/iframeActions.d.ts +23 -0
- package/dist/helper/actions/web/iframeActions.js +108 -0
- package/dist/helper/actions/web/javascriptActions.d.ts +14 -0
- package/dist/helper/actions/web/javascriptActions.js +77 -0
- package/dist/helper/actions/web/keyboardActions.d.ts +35 -0
- package/dist/helper/actions/web/keyboardActions.js +118 -0
- package/dist/helper/actions/web/localStorageActions.d.ts +51 -0
- package/dist/helper/actions/web/localStorageActions.js +163 -0
- package/dist/helper/actions/web/mouseActions.d.ts +240 -0
- package/dist/helper/actions/web/mouseActions.js +609 -0
- package/dist/helper/actions/web/reportingActions.d.ts +34 -0
- package/dist/helper/actions/web/reportingActions.js +58 -0
- package/dist/helper/actions/web/screenshotActions.d.ts +34 -0
- package/dist/helper/actions/web/screenshotActions.js +151 -0
- package/dist/helper/actions/web/testDataActions.d.ts +21 -0
- package/dist/helper/actions/web/testDataActions.js +211 -0
- package/dist/helper/actions/web/validationActions.d.ts +547 -0
- package/dist/helper/actions/web/validationActions.js +1754 -0
- package/dist/helper/actions/web/waitActions.d.ts +191 -0
- package/dist/helper/actions/web/waitActions.js +589 -0
- package/dist/helper/actions/web/webNavigation.d.ts +104 -0
- package/dist/helper/actions/web/webNavigation.js +288 -0
- package/dist/helper/actions/webActions.d.ts +32 -0
- package/dist/helper/actions/webActions.js +48 -0
- package/dist/helper/actions/webStepDefs.d.ts +1 -0
- package/dist/helper/actions/webStepDefs.js +455 -0
- package/dist/helper/browsers/browserManager.d.ts +1 -0
- package/dist/helper/browsers/browserManager.js +56 -0
- package/dist/helper/bundle/defaultEntries.d.ts +6 -0
- package/dist/helper/bundle/defaultEntries.js +200 -0
- package/dist/helper/bundle/env.d.ts +1 -0
- package/dist/helper/bundle/env.js +157 -0
- package/dist/helper/bundle/vars.d.ts +9 -0
- package/dist/helper/bundle/vars.js +375 -0
- package/dist/helper/faker/customFaker.d.ts +55 -0
- package/dist/helper/faker/customFaker.js +45 -0
- package/dist/helper/faker/modules/data/postcodes_valid_sg.json +17 -0
- package/dist/helper/faker/modules/dateTime.d.ts +18 -0
- package/dist/helper/faker/modules/dateTime.js +106 -0
- package/dist/helper/faker/modules/mobile.d.ts +4 -0
- package/dist/helper/faker/modules/mobile.js +59 -0
- package/dist/helper/faker/modules/nric.d.ts +32 -0
- package/dist/helper/faker/modules/nric.js +84 -0
- package/dist/helper/faker/modules/passport.d.ts +3 -0
- package/dist/helper/faker/modules/passport.js +36 -0
- package/dist/helper/faker/modules/person.d.ts +14 -0
- package/dist/helper/faker/modules/person.js +73 -0
- package/dist/helper/faker/modules/postcode.d.ts +6 -0
- package/dist/helper/faker/modules/postcode.js +47 -0
- package/dist/helper/fixtures/locAggregate.d.ts +7 -0
- package/dist/helper/fixtures/locAggregate.js +94 -0
- package/dist/helper/fixtures/logFixture.d.ts +8 -0
- package/dist/helper/fixtures/logFixture.js +56 -0
- package/dist/helper/fixtures/webFixture.d.ts +19 -0
- package/dist/helper/fixtures/webFixture.js +186 -0
- package/dist/helper/fixtures/webLocFixture.d.ts +2 -0
- package/dist/helper/fixtures/webLocFixture.js +144 -0
- package/dist/helper/report/allureStepLogger.d.ts +0 -0
- package/dist/helper/report/allureStepLogger.js +25 -0
- package/dist/helper/report/customiseReport.d.ts +1 -0
- package/dist/helper/report/customiseReport.js +55 -0
- package/dist/helper/report/init.d.ts +1 -0
- package/dist/helper/report/init.js +14 -0
- package/dist/helper/report/report.d.ts +1 -0
- package/dist/helper/report/report.js +102 -0
- package/dist/helper/util/dataLoader.d.ts +10 -0
- package/dist/helper/util/dataLoader.js +73 -0
- package/dist/helper/util/logger.d.ts +4 -0
- package/dist/helper/util/logger.js +61 -0
- package/dist/helper/util/session/sessionUtil.d.ts +26 -0
- package/dist/helper/util/session/sessionUtil.js +729 -0
- package/dist/helper/util/stepHelpers.d.ts +2 -0
- package/dist/helper/util/stepHelpers.js +16 -0
- package/dist/helper/util/test-data/dataLoader.d.ts +7 -0
- package/dist/helper/util/test-data/dataLoader.js +145 -0
- package/dist/helper/util/test-data/dataTest.d.ts +10 -0
- package/dist/helper/util/test-data/dataTest.js +216 -0
- package/dist/helper/util/totp/totpHelper.d.ts +38 -0
- package/dist/helper/util/totp/totpHelper.js +117 -0
- package/dist/helper/util/utilities/cryptoUtil.d.ts +2 -0
- package/dist/helper/util/utilities/cryptoUtil.js +53 -0
- package/dist/helper/util/utilities/schemaGeneratorUtil.d.ts +2 -0
- package/dist/helper/util/utilities/schemaGeneratorUtil.js +129 -0
- package/dist/helper/util/utils.d.ts +2 -0
- package/dist/helper/util/utils.js +22 -0
- package/dist/helper/wrapper/PlaywrightWrappers.d.ts +8 -0
- package/dist/helper/wrapper/PlaywrightWrappers.js +26 -0
- package/dist/helper/wrapper/assert.d.ts +9 -0
- package/dist/helper/wrapper/assert.js +23 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +57 -0
- package/dist/scripts/get-versions.d.ts +1 -0
- package/dist/scripts/get-versions.js +98 -0
- package/dist/scripts/posttest.d.ts +1 -0
- package/dist/scripts/posttest.js +29 -0
- package/dist/scripts/pretest.d.ts +1 -0
- package/dist/scripts/pretest.js +57 -0
- package/dist/scripts/util.d.ts +1 -0
- package/dist/scripts/util.js +376 -0
- package/package.json +68 -0
- package/src/exec/featureFileCache.ts +80 -0
- package/src/exec/featureFilePreProcess.ts +239 -0
- package/src/exec/preLoader.ts +72 -0
- package/src/exec/preProcessEntry.ts +59 -0
- package/src/exec/preProcess_old_todelete.ts +289 -0
- package/src/exec/runner.ts +241 -0
- package/src/exec/runnerCuke.js +90 -0
- package/src/exec/runner_orchestrator.ts +91 -0
- package/src/exec/sgGenerator.ts +373 -0
- package/src/global.ts +130 -0
- package/src/helper/actions/api/apiRequestActions.ts +362 -0
- package/src/helper/actions/api/apiValidationActions.ts +594 -0
- package/src/helper/actions/apiActions.ts +18 -0
- package/src/helper/actions/apiStepDefs.ts +80 -0
- package/src/helper/actions/comm/commonActions.ts +165 -0
- package/src/helper/actions/comm/utilityActions.ts +344 -0
- package/src/helper/actions/commActions.ts +18 -0
- package/src/helper/actions/commStepDefs.ts +72 -0
- package/src/helper/actions/stepGroupStepDefs.ts +17 -0
- package/src/helper/actions/web/alertActions.ts +179 -0
- package/src/helper/actions/web/cookieActions.ts +124 -0
- package/src/helper/actions/web/downloadActions.ts +129 -0
- package/src/helper/actions/web/elementReaderActions.ts +323 -0
- package/src/helper/actions/web/formActions.ts +469 -0
- package/src/helper/actions/web/iframeActions.ts +67 -0
- package/src/helper/actions/web/javascriptActions.ts +38 -0
- package/src/helper/actions/web/keyboardActions.ts +101 -0
- package/src/helper/actions/web/localStorageActions.ts +109 -0
- package/src/helper/actions/web/mouseActions.ts +864 -0
- package/src/helper/actions/web/reportingActions.ts +53 -0
- package/src/helper/actions/web/screenshotActions.ts +124 -0
- package/src/helper/actions/web/testDataActions.ts +162 -0
- package/src/helper/actions/web/validationActions.ts +2287 -0
- package/src/helper/actions/web/waitActions.ts +757 -0
- package/src/helper/actions/web/webNavigation.ts +313 -0
- package/src/helper/actions/webActions.ts +33 -0
- package/src/helper/actions/webStepDefs.ts +505 -0
- package/src/helper/browsers/browserManager.ts +23 -0
- package/src/helper/bundle/defaultEntries.ts +208 -0
- package/src/helper/bundle/env.ts +119 -0
- package/src/helper/bundle/vars.ts +368 -0
- package/src/helper/faker/customFaker.ts +107 -0
- package/src/helper/faker/modules/data/postcodes_valid_sg.json +17 -0
- package/src/helper/faker/modules/dateTime.ts +121 -0
- package/src/helper/faker/modules/mobile.ts +58 -0
- package/src/helper/faker/modules/nric.ts +109 -0
- package/src/helper/faker/modules/passport.ts +34 -0
- package/src/helper/faker/modules/person.ts +93 -0
- package/src/helper/faker/modules/postcode.ts +57 -0
- package/src/helper/fixtures/locAggregate.ts +61 -0
- package/src/helper/fixtures/logFixture.ts +57 -0
- package/src/helper/fixtures/webFixture.ts +206 -0
- package/src/helper/fixtures/webLocFixture.ts +143 -0
- package/src/helper/report/allureStepLogger.ts +26 -0
- package/src/helper/report/customiseReport.ts +61 -0
- package/src/helper/report/init.ts +18 -0
- package/src/helper/report/report.ts +72 -0
- package/src/helper/util/dataLoader.ts +42 -0
- package/src/helper/util/logger.ts +32 -0
- package/src/helper/util/session/sessionUtil.ts +839 -0
- package/src/helper/util/stepHelpers.ts +14 -0
- package/src/helper/util/test-data/dataLoader.ts +108 -0
- package/src/helper/util/test-data/dataTest.ts +191 -0
- package/src/helper/util/test-data/registerUser.json +7 -0
- package/src/helper/util/totp/totpHelper.ts +102 -0
- package/src/helper/util/utilities/cryptoUtil.ts +53 -0
- package/src/helper/util/utilities/schemaGeneratorUtil.ts +143 -0
- package/src/helper/util/utils.ts +28 -0
- package/src/helper/wrapper/PlaywrightWrappers.ts +28 -0
- package/src/helper/wrapper/assert.ts +25 -0
- package/src/index.ts +17 -0
- package/src/scripts/get-versions.ts +68 -0
- package/src/scripts/posttest.ts +32 -0
- package/src/scripts/pretest.ts +48 -0
- package/src/scripts/util.ts +406 -0
- package/tsconfig.json +30 -0
|
@@ -0,0 +1,729 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.saveSession = saveSession;
|
|
7
|
+
exports.saveSessionSimplified = saveSessionSimplified;
|
|
8
|
+
exports.loadSession = loadSession;
|
|
9
|
+
exports.loadSessionIntoExistingContext = loadSessionIntoExistingContext;
|
|
10
|
+
exports.deleteSession = deleteSession;
|
|
11
|
+
exports.isSessionValid = isSessionValid;
|
|
12
|
+
// src/helper/util/sessionUtil.ts
|
|
13
|
+
const fs_1 = __importDefault(require("fs"));
|
|
14
|
+
const path_1 = __importDefault(require("path"));
|
|
15
|
+
function originOf(url) {
|
|
16
|
+
try {
|
|
17
|
+
const u = new URL(url);
|
|
18
|
+
return `${u.protocol}//${u.host}`;
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return '';
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
async function readSessionStorage(page) {
|
|
25
|
+
try {
|
|
26
|
+
// Wait for page to be ready and check if context is still valid
|
|
27
|
+
await page.waitForLoadState('domcontentloaded', { timeout: 5000 });
|
|
28
|
+
return await page.evaluate(() => {
|
|
29
|
+
const out = {};
|
|
30
|
+
try {
|
|
31
|
+
const ss = globalThis.sessionStorage;
|
|
32
|
+
if (ss) {
|
|
33
|
+
for (let i = 0; i < ss.length; i++) {
|
|
34
|
+
const k = ss.key(i);
|
|
35
|
+
if (k) {
|
|
36
|
+
const value = ss.getItem(k);
|
|
37
|
+
if (value) {
|
|
38
|
+
out[k] = value;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
console.warn('Failed to read sessionStorage:', error);
|
|
46
|
+
}
|
|
47
|
+
return out;
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
console.warn(`Failed to read sessionStorage for ${page.url()}:`, error);
|
|
52
|
+
return {};
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async function writeSessionStorage(page, data) {
|
|
56
|
+
try {
|
|
57
|
+
await page.waitForLoadState('domcontentloaded', { timeout: 5000 });
|
|
58
|
+
await page.evaluate((d) => {
|
|
59
|
+
try {
|
|
60
|
+
const ss = globalThis.sessionStorage;
|
|
61
|
+
if (ss) {
|
|
62
|
+
for (const [k, v] of Object.entries(d)) {
|
|
63
|
+
ss.setItem(k, v);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
console.warn('Failed to write sessionStorage:', error);
|
|
69
|
+
}
|
|
70
|
+
}, data);
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
console.warn(`Failed to write sessionStorage for ${page.url()}:`, error);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// /**
|
|
77
|
+
// * Save session with auto-discovery of origins - no need to pass URLs manually
|
|
78
|
+
// */
|
|
79
|
+
// export async function saveSession(page: Page, sessionName: string, additionalUrls: string[] = []): Promise<void> {
|
|
80
|
+
// const sessionPath = `_Temp/sessions/${sessionName}.json`;
|
|
81
|
+
// try {
|
|
82
|
+
// console.log('🔄 Saving session state...');
|
|
83
|
+
// // First, save the storage state (cookies + localStorage)
|
|
84
|
+
// const storageState = await page.context().storageState();
|
|
85
|
+
// const state: HybridState = {
|
|
86
|
+
// storageState,
|
|
87
|
+
// sessionByOrigin: {},
|
|
88
|
+
// };
|
|
89
|
+
// // ✅ AUTO-DISCOVER ORIGINS from current browser context
|
|
90
|
+
// const discoveredOrigins = new Set<string>();
|
|
91
|
+
// // Get current page origin
|
|
92
|
+
// const currentUrl = page.url();
|
|
93
|
+
// if (currentUrl) {
|
|
94
|
+
// const currentOrigin = originOf(currentUrl);
|
|
95
|
+
// if (currentOrigin) {
|
|
96
|
+
// discoveredOrigins.add(currentOrigin);
|
|
97
|
+
// }
|
|
98
|
+
// }
|
|
99
|
+
// // Get origins from existing cookies (these are domains the user has visited)
|
|
100
|
+
// if (storageState.cookies) {
|
|
101
|
+
// storageState.cookies.forEach(cookie => {
|
|
102
|
+
// if (cookie.domain) {
|
|
103
|
+
// // Convert cookie domain to origin
|
|
104
|
+
// const protocol = cookie.secure ? 'https' : 'http';
|
|
105
|
+
// const domain = cookie.domain.startsWith('.') ? cookie.domain.substring(1) : cookie.domain;
|
|
106
|
+
// const origin = `${protocol}://${domain}`;
|
|
107
|
+
// discoveredOrigins.add(origin);
|
|
108
|
+
// }
|
|
109
|
+
// });
|
|
110
|
+
// }
|
|
111
|
+
// // Get origins from localStorage data
|
|
112
|
+
// if (storageState.origins) {
|
|
113
|
+
// storageState.origins.forEach(originData => {
|
|
114
|
+
// discoveredOrigins.add(originData.origin);
|
|
115
|
+
// });
|
|
116
|
+
// }
|
|
117
|
+
// // Add any additional URLs if provided
|
|
118
|
+
// additionalUrls.forEach(url => {
|
|
119
|
+
// const origin = originOf(url);
|
|
120
|
+
// if (origin) discoveredOrigins.add(origin);
|
|
121
|
+
// });
|
|
122
|
+
// // Filter out invalid origins and common unwanted ones
|
|
123
|
+
// const validOrigins = Array.from(discoveredOrigins).filter(origin => {
|
|
124
|
+
// try {
|
|
125
|
+
// const url = new URL(origin);
|
|
126
|
+
// // Skip localhost, file://, and other unwanted protocols
|
|
127
|
+
// return url.protocol === 'https:' || url.protocol === 'http:';
|
|
128
|
+
// } catch {
|
|
129
|
+
// return false;
|
|
130
|
+
// }
|
|
131
|
+
// });
|
|
132
|
+
// console.log(`🔍 Auto-discovered ${validOrigins.length} origins to save:`, validOrigins);
|
|
133
|
+
// // Save sessionStorage for current page first (most reliable)
|
|
134
|
+
// if (currentUrl) {
|
|
135
|
+
// const currentOrigin = originOf(currentUrl);
|
|
136
|
+
// if (currentOrigin && !page.isClosed()) {
|
|
137
|
+
// try {
|
|
138
|
+
// state.sessionByOrigin[currentOrigin] = await readSessionStorage(page);
|
|
139
|
+
// console.log(`✅ Saved sessionStorage for current origin: ${currentOrigin}`);
|
|
140
|
+
// } catch (error) {
|
|
141
|
+
// console.warn(`⚠️ Could not save sessionStorage for current origin ${currentOrigin}:`, error);
|
|
142
|
+
// }
|
|
143
|
+
// }
|
|
144
|
+
// }
|
|
145
|
+
// // Process other discovered origins
|
|
146
|
+
// const otherOrigins = validOrigins.filter(origin => origin !== originOf(currentUrl));
|
|
147
|
+
// for (const origin of otherOrigins) {
|
|
148
|
+
// try {
|
|
149
|
+
// console.log(`🔄 Navigating to origin for sessionStorage: ${origin}`);
|
|
150
|
+
// // Navigate with error handling
|
|
151
|
+
// await page.goto(origin, {
|
|
152
|
+
// waitUntil: 'domcontentloaded',
|
|
153
|
+
// timeout: 10000
|
|
154
|
+
// });
|
|
155
|
+
// // Small delay to ensure page is stable
|
|
156
|
+
// await page.waitForTimeout(500);
|
|
157
|
+
// state.sessionByOrigin[origin] = await readSessionStorage(page);
|
|
158
|
+
// console.log(`✅ Saved sessionStorage for origin: ${origin}`);
|
|
159
|
+
// } catch (error) {
|
|
160
|
+
// console.warn(`⚠️ Could not save sessionStorage for origin ${origin}:`, error);
|
|
161
|
+
// state.sessionByOrigin[origin] = {};
|
|
162
|
+
// }
|
|
163
|
+
// }
|
|
164
|
+
// // Ensure directory exists and save file
|
|
165
|
+
// await fs.promises.mkdir(path.dirname(sessionPath), { recursive: true });
|
|
166
|
+
// await fs.promises.writeFile(sessionPath, JSON.stringify(state, null, 2));
|
|
167
|
+
// console.log(`✅ Session saved to: ${sessionPath}`);
|
|
168
|
+
// console.log(`📊 Saved data for ${Object.keys(state.sessionByOrigin).length} origins`);
|
|
169
|
+
// } catch (error) {
|
|
170
|
+
// console.error('❌ Failed to save session:', error);
|
|
171
|
+
// throw error;
|
|
172
|
+
// }
|
|
173
|
+
// }
|
|
174
|
+
async function saveSession(page, sessionName, additionalUrls = []) {
|
|
175
|
+
const sessionPath = `_Temp/sessions/${sessionName}.json`;
|
|
176
|
+
try {
|
|
177
|
+
console.log('🔄 Saving session state...');
|
|
178
|
+
// First, save the storage state (cookies + localStorage)
|
|
179
|
+
const storageState = await page.context().storageState();
|
|
180
|
+
const state = {
|
|
181
|
+
storageState,
|
|
182
|
+
sessionByOrigin: {},
|
|
183
|
+
};
|
|
184
|
+
// ✅ CONSERVATIVE AUTO-DISCOVERY
|
|
185
|
+
const discoveredOrigins = new Set();
|
|
186
|
+
// Get current page origin (most reliable)
|
|
187
|
+
const currentUrl = page.url();
|
|
188
|
+
if (currentUrl) {
|
|
189
|
+
const currentOrigin = originOf(currentUrl);
|
|
190
|
+
if (currentOrigin) {
|
|
191
|
+
discoveredOrigins.add(currentOrigin);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
// Get origins from localStorage data (proven origins)
|
|
195
|
+
if (storageState.origins) {
|
|
196
|
+
storageState.origins.forEach(originData => {
|
|
197
|
+
discoveredOrigins.add(originData.origin);
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
// Add manually provided URLs (if any)
|
|
201
|
+
additionalUrls.forEach(url => {
|
|
202
|
+
const origin = originOf(url);
|
|
203
|
+
if (origin)
|
|
204
|
+
discoveredOrigins.add(origin);
|
|
205
|
+
});
|
|
206
|
+
// ✅ ONLY GET MICROSOFT ORIGINS FROM COOKIES (safer approach)
|
|
207
|
+
if (storageState.cookies) {
|
|
208
|
+
const microsoftCookies = storageState.cookies.filter(cookie => cookie.domain && (cookie.domain.includes('microsoft') ||
|
|
209
|
+
cookie.domain.includes('office365') ||
|
|
210
|
+
cookie.domain.includes('dynamics')));
|
|
211
|
+
microsoftCookies.forEach(cookie => {
|
|
212
|
+
if (cookie.domain) {
|
|
213
|
+
const protocol = cookie.secure ? 'https' : 'http';
|
|
214
|
+
let domain = cookie.domain.startsWith('.') ? cookie.domain.substring(1) : cookie.domain;
|
|
215
|
+
// ✅ Map to known Microsoft origins
|
|
216
|
+
const knownOrigins = [
|
|
217
|
+
'https://login.microsoftonline.com',
|
|
218
|
+
'https://graph.microsoft.com',
|
|
219
|
+
`https://${domain}`
|
|
220
|
+
];
|
|
221
|
+
knownOrigins.forEach(origin => {
|
|
222
|
+
try {
|
|
223
|
+
new URL(origin); // Validate URL
|
|
224
|
+
discoveredOrigins.add(origin);
|
|
225
|
+
}
|
|
226
|
+
catch {
|
|
227
|
+
// Skip invalid URLs
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
const validOrigins = Array.from(discoveredOrigins).filter(origin => {
|
|
234
|
+
try {
|
|
235
|
+
const url = new URL(origin);
|
|
236
|
+
return (url.protocol === 'https:' || url.protocol === 'http:') &&
|
|
237
|
+
!url.hostname.includes('localhost');
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
console.log(`🔍 Auto-discovered ${validOrigins.length} origins to save:`, validOrigins);
|
|
244
|
+
// ✅ LIMIT TO MAXIMUM 5 ORIGINS (performance)
|
|
245
|
+
const limitedOrigins = validOrigins.slice(0, 5);
|
|
246
|
+
if (limitedOrigins.length < validOrigins.length) {
|
|
247
|
+
console.log(`⚠️ Limited to ${limitedOrigins.length} origins for performance`);
|
|
248
|
+
}
|
|
249
|
+
// Save sessionStorage for current page first
|
|
250
|
+
if (currentUrl) {
|
|
251
|
+
const currentOrigin = originOf(currentUrl);
|
|
252
|
+
if (currentOrigin && !page.isClosed()) {
|
|
253
|
+
try {
|
|
254
|
+
state.sessionByOrigin[currentOrigin] = await readSessionStorage(page);
|
|
255
|
+
console.log(`✅ Saved sessionStorage for current origin: ${currentOrigin}`);
|
|
256
|
+
}
|
|
257
|
+
catch (error) {
|
|
258
|
+
console.warn(`⚠️ Could not save sessionStorage for current origin:`, error);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
// Process other origins with conservative approach
|
|
263
|
+
const otherOrigins = limitedOrigins.filter(origin => origin !== originOf(currentUrl));
|
|
264
|
+
for (const origin of otherOrigins) {
|
|
265
|
+
try {
|
|
266
|
+
console.log(`🔄 Navigating to origin: ${origin}`);
|
|
267
|
+
// ✅ More robust navigation with shorter timeout
|
|
268
|
+
await page.goto(origin, {
|
|
269
|
+
waitUntil: 'domcontentloaded',
|
|
270
|
+
timeout: 8000
|
|
271
|
+
});
|
|
272
|
+
// ✅ Check if page is still valid
|
|
273
|
+
if (page.isClosed()) {
|
|
274
|
+
console.warn(`⚠️ Page closed during navigation to ${origin}`);
|
|
275
|
+
break;
|
|
276
|
+
}
|
|
277
|
+
await page.waitForTimeout(500);
|
|
278
|
+
const sessionData = await readSessionStorage(page);
|
|
279
|
+
state.sessionByOrigin[origin] = sessionData;
|
|
280
|
+
console.log(`✅ Saved sessionStorage for origin: ${origin}`);
|
|
281
|
+
}
|
|
282
|
+
catch (error) {
|
|
283
|
+
console.warn(`⚠️ Could not save sessionStorage for origin ${origin}:`, error.message);
|
|
284
|
+
state.sessionByOrigin[origin] = {};
|
|
285
|
+
// ✅ If multiple failures, stop trying
|
|
286
|
+
const failureCount = Object.values(state.sessionByOrigin).filter(data => Object.keys(data).length === 0).length;
|
|
287
|
+
if (failureCount >= 3) {
|
|
288
|
+
console.warn('⚠️ Multiple origin failures, stopping further navigation');
|
|
289
|
+
break;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
// Save file
|
|
294
|
+
await fs_1.default.promises.mkdir(path_1.default.dirname(sessionPath), { recursive: true });
|
|
295
|
+
await fs_1.default.promises.writeFile(sessionPath, JSON.stringify(state, null, 2));
|
|
296
|
+
console.log(`✅ Session saved to: ${sessionPath}`);
|
|
297
|
+
console.log(`📊 Saved data for ${Object.keys(state.sessionByOrigin).length} origins`);
|
|
298
|
+
}
|
|
299
|
+
catch (error) {
|
|
300
|
+
console.error('❌ Failed to save session:', error);
|
|
301
|
+
throw error;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
async function saveSessionSimplified(page, sessionName, additionalUrls = []) {
|
|
305
|
+
const sessionPath = `_Temp/sessions/${sessionName}.json`;
|
|
306
|
+
try {
|
|
307
|
+
console.log('🔄 Saving session state (simplified)...');
|
|
308
|
+
// Get storage state (cookies + localStorage for all origins)
|
|
309
|
+
const storageState = await page.context().storageState();
|
|
310
|
+
const state = {
|
|
311
|
+
storageState,
|
|
312
|
+
sessionByOrigin: {},
|
|
313
|
+
};
|
|
314
|
+
// Only save sessionStorage for current page
|
|
315
|
+
const currentUrl = page.url();
|
|
316
|
+
if (currentUrl) {
|
|
317
|
+
const currentOrigin = originOf(currentUrl);
|
|
318
|
+
if (currentOrigin && !page.isClosed()) {
|
|
319
|
+
try {
|
|
320
|
+
state.sessionByOrigin[currentOrigin] = await readSessionStorage(page);
|
|
321
|
+
console.log(`✅ Saved sessionStorage for current origin: ${currentOrigin}`);
|
|
322
|
+
}
|
|
323
|
+
catch (error) {
|
|
324
|
+
console.warn(`⚠️ Could not save sessionStorage for current origin:`, error);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
// Optionally save sessionStorage for manually provided URLs only
|
|
329
|
+
if (additionalUrls.length > 0) {
|
|
330
|
+
for (const url of additionalUrls) {
|
|
331
|
+
try {
|
|
332
|
+
const origin = originOf(url);
|
|
333
|
+
if (origin && origin !== originOf(currentUrl)) {
|
|
334
|
+
console.log(`🔄 Saving sessionStorage for manually specified origin: ${origin}`);
|
|
335
|
+
await page.goto(origin, {
|
|
336
|
+
waitUntil: 'domcontentloaded',
|
|
337
|
+
timeout: 8000
|
|
338
|
+
});
|
|
339
|
+
await page.waitForTimeout(500);
|
|
340
|
+
state.sessionByOrigin[origin] = await readSessionStorage(page);
|
|
341
|
+
console.log(`✅ Saved sessionStorage for: ${origin}`);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
catch (error) {
|
|
345
|
+
console.warn(`⚠️ Could not save sessionStorage for ${url}:`, error);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
// Save file
|
|
350
|
+
await fs_1.default.promises.mkdir(path_1.default.dirname(sessionPath), { recursive: true });
|
|
351
|
+
await fs_1.default.promises.writeFile(sessionPath, JSON.stringify(state, null, 2));
|
|
352
|
+
console.log(`✅ Session saved to: ${sessionPath}`);
|
|
353
|
+
}
|
|
354
|
+
catch (error) {
|
|
355
|
+
console.error('❌ Failed to save session:', error);
|
|
356
|
+
throw error;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
// /**
|
|
360
|
+
// * Save session with improved error handling and navigation safety
|
|
361
|
+
// */
|
|
362
|
+
// export async function saveSession(page: Page, sessionName: string, extraOrigins: string[] = []): Promise<void> {
|
|
363
|
+
// const filePath = `_Temp/sessions/${sessionName}.json`;
|
|
364
|
+
// try {
|
|
365
|
+
// console.log('🔄 Saving session state...');
|
|
366
|
+
// // First, save the storage state (cookies + localStorage)
|
|
367
|
+
// const storageState = await page.context().storageState();
|
|
368
|
+
// const state: HybridState = {
|
|
369
|
+
// storageState,
|
|
370
|
+
// sessionByOrigin: {},
|
|
371
|
+
// };
|
|
372
|
+
// const currentUrl = page.url();
|
|
373
|
+
// const currentOrigin = currentUrl ? originOf(currentUrl) : '';
|
|
374
|
+
// // Read sessionStorage from current page first (if valid)
|
|
375
|
+
// if (currentOrigin && !page.isClosed()) {
|
|
376
|
+
// try {
|
|
377
|
+
// state.sessionByOrigin[currentOrigin] = await readSessionStorage(page);
|
|
378
|
+
// console.log(`✅ Saved sessionStorage for current origin: ${currentOrigin}`);
|
|
379
|
+
// } catch (error) {
|
|
380
|
+
// console.warn(`⚠️ Could not save sessionStorage for current origin ${currentOrigin}:`, error);
|
|
381
|
+
// }
|
|
382
|
+
// }
|
|
383
|
+
// // Process extra origins
|
|
384
|
+
// const normalizedExtra = extraOrigins.map(originOf).filter(Boolean);
|
|
385
|
+
// const origins = Array.from(new Set(normalizedExtra.filter(o => o !== currentOrigin)));
|
|
386
|
+
// for (const origin of origins) {
|
|
387
|
+
// try {
|
|
388
|
+
// console.log(`🔄 Navigating to origin: ${origin}`);
|
|
389
|
+
// // Navigate with error handling
|
|
390
|
+
// await page.goto(origin, {
|
|
391
|
+
// waitUntil: 'domcontentloaded',
|
|
392
|
+
// timeout: 10000
|
|
393
|
+
// });
|
|
394
|
+
// // Small delay to ensure page is stable
|
|
395
|
+
// await page.waitForTimeout(500);
|
|
396
|
+
// state.sessionByOrigin[origin] = await readSessionStorage(page);
|
|
397
|
+
// console.log(`✅ Saved sessionStorage for origin: ${origin}`);
|
|
398
|
+
// } catch (error) {
|
|
399
|
+
// console.warn(`⚠️ Could not save sessionStorage for origin ${origin}:`, error);
|
|
400
|
+
// state.sessionByOrigin[origin] = {};
|
|
401
|
+
// }
|
|
402
|
+
// }
|
|
403
|
+
// // Ensure directory exists and save file
|
|
404
|
+
// await fs.promises.mkdir(path.dirname(filePath), { recursive: true });
|
|
405
|
+
// await fs.promises.writeFile(filePath, JSON.stringify(state, null, 2));
|
|
406
|
+
// console.log(`✅ Session saved to: ${filePath}`);
|
|
407
|
+
// } catch (error) {
|
|
408
|
+
// console.error('❌ Failed to save session:', error);
|
|
409
|
+
// throw error;
|
|
410
|
+
// }
|
|
411
|
+
// }
|
|
412
|
+
/**
|
|
413
|
+
* Load session with improved error handling
|
|
414
|
+
*/
|
|
415
|
+
async function loadSession(browser, filePath, warmOrigins = []) {
|
|
416
|
+
try {
|
|
417
|
+
if (!fs_1.default.existsSync(filePath)) {
|
|
418
|
+
throw new Error(`Session file not found: ${filePath}`);
|
|
419
|
+
}
|
|
420
|
+
console.log(`🔄 Loading session from: ${filePath}`);
|
|
421
|
+
const saved = JSON.parse(await fs_1.default.promises.readFile(filePath, 'utf8'));
|
|
422
|
+
const context = await browser.newContext({ storageState: saved.storageState });
|
|
423
|
+
const page = await context.newPage();
|
|
424
|
+
const warm = warmOrigins.map(originOf).filter(Boolean);
|
|
425
|
+
const origins = new Set([...Object.keys(saved.sessionByOrigin), ...warm]);
|
|
426
|
+
for (const origin of origins) {
|
|
427
|
+
try {
|
|
428
|
+
console.log(`🔄 Warming origin: ${origin}`);
|
|
429
|
+
await page.goto(origin, {
|
|
430
|
+
waitUntil: 'domcontentloaded',
|
|
431
|
+
timeout: 10000
|
|
432
|
+
});
|
|
433
|
+
// Small delay for stability
|
|
434
|
+
await page.waitForTimeout(500);
|
|
435
|
+
const data = saved.sessionByOrigin[origin];
|
|
436
|
+
if (data && Object.keys(data).length > 0) {
|
|
437
|
+
await writeSessionStorage(page, data);
|
|
438
|
+
console.log(`✅ Restored sessionStorage for origin: ${origin}`);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
catch (error) {
|
|
442
|
+
console.warn(`⚠️ Could not restore sessionStorage for origin ${origin}:`, error);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
console.log('✅ Session loaded successfully');
|
|
446
|
+
return { context, page };
|
|
447
|
+
}
|
|
448
|
+
catch (error) {
|
|
449
|
+
console.error('❌ Failed to load session:', error);
|
|
450
|
+
throw error;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
/**
|
|
454
|
+
* Load session into existing context without creating new browser/page
|
|
455
|
+
* Auto-discovers origins from saved session data - no need to pass URLs
|
|
456
|
+
*/
|
|
457
|
+
async function loadSessionIntoExistingContext(page, sessionName, additionalUrls = []) {
|
|
458
|
+
var _a;
|
|
459
|
+
const sessionPath = `_Temp/sessions/${sessionName}.json`;
|
|
460
|
+
try {
|
|
461
|
+
if (!fs_1.default.existsSync(sessionPath)) {
|
|
462
|
+
throw new Error(`Session file not found: ${sessionPath}`);
|
|
463
|
+
}
|
|
464
|
+
console.log(`🔄 Loading session into existing context from: ${sessionPath}`);
|
|
465
|
+
const savedData = JSON.parse(fs_1.default.readFileSync(sessionPath, 'utf8'));
|
|
466
|
+
// Handle both hybrid state and simple storage state formats
|
|
467
|
+
let storageState;
|
|
468
|
+
let sessionByOrigin = {};
|
|
469
|
+
if (savedData.storageState && savedData.sessionByOrigin) {
|
|
470
|
+
// Hybrid state format
|
|
471
|
+
storageState = savedData.storageState;
|
|
472
|
+
sessionByOrigin = savedData.sessionByOrigin;
|
|
473
|
+
}
|
|
474
|
+
else if (savedData.cookies || savedData.origins) {
|
|
475
|
+
// Simple storage state format
|
|
476
|
+
storageState = savedData;
|
|
477
|
+
}
|
|
478
|
+
else {
|
|
479
|
+
throw new Error('Invalid session file format');
|
|
480
|
+
}
|
|
481
|
+
// Add cookies to existing context
|
|
482
|
+
if ((storageState === null || storageState === void 0 ? void 0 : storageState.cookies) && Array.isArray(storageState.cookies)) {
|
|
483
|
+
try {
|
|
484
|
+
await page.context().addCookies(storageState.cookies);
|
|
485
|
+
console.log('✅ Cookies restored to existing context');
|
|
486
|
+
}
|
|
487
|
+
catch (error) {
|
|
488
|
+
console.warn('⚠️ Failed to add cookies:', error);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
// ✅ AUTO-DISCOVER ORIGINS - No need to pass URLs manually
|
|
492
|
+
const discoveredOrigins = new Set();
|
|
493
|
+
// Get origins from sessionStorage data
|
|
494
|
+
Object.keys(sessionByOrigin || {}).forEach(origin => {
|
|
495
|
+
discoveredOrigins.add(origin);
|
|
496
|
+
});
|
|
497
|
+
// Get origins from localStorage data
|
|
498
|
+
if (storageState === null || storageState === void 0 ? void 0 : storageState.origins) {
|
|
499
|
+
storageState.origins.forEach((o) => {
|
|
500
|
+
discoveredOrigins.add(o.origin);
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
// Add any additional URLs if provided (optional)
|
|
504
|
+
additionalUrls.forEach(url => {
|
|
505
|
+
const origin = originOf(url);
|
|
506
|
+
if (origin)
|
|
507
|
+
discoveredOrigins.add(origin);
|
|
508
|
+
});
|
|
509
|
+
console.log(`🔍 Discovered ${discoveredOrigins.size} origins to restore:`, Array.from(discoveredOrigins));
|
|
510
|
+
// Restore storage for each discovered origin
|
|
511
|
+
for (const origin of discoveredOrigins) {
|
|
512
|
+
try {
|
|
513
|
+
console.log(`🔄 Restoring storage for origin: ${origin}`);
|
|
514
|
+
// Navigate to the origin
|
|
515
|
+
await page.goto(origin, {
|
|
516
|
+
waitUntil: 'domcontentloaded',
|
|
517
|
+
timeout: 15000
|
|
518
|
+
});
|
|
519
|
+
// Wait for page stability
|
|
520
|
+
await page.waitForTimeout(1000);
|
|
521
|
+
// Restore localStorage
|
|
522
|
+
const originData = (_a = storageState === null || storageState === void 0 ? void 0 : storageState.origins) === null || _a === void 0 ? void 0 : _a.find((o) => o.origin === origin);
|
|
523
|
+
if ((originData === null || originData === void 0 ? void 0 : originData.localStorage) && Array.isArray(originData.localStorage)) {
|
|
524
|
+
for (const item of originData.localStorage) {
|
|
525
|
+
try {
|
|
526
|
+
await page.evaluate(({ name, value }) => {
|
|
527
|
+
const ls = globalThis.localStorage;
|
|
528
|
+
if (ls)
|
|
529
|
+
ls.setItem(name, value);
|
|
530
|
+
}, item);
|
|
531
|
+
}
|
|
532
|
+
catch (error) {
|
|
533
|
+
console.warn(`Failed to set localStorage item ${item.name}:`, error);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
console.log(`✅ localStorage restored for ${origin}`);
|
|
537
|
+
}
|
|
538
|
+
// Restore sessionStorage
|
|
539
|
+
const sessionData = sessionByOrigin[origin];
|
|
540
|
+
if (sessionData && Object.keys(sessionData).length > 0) {
|
|
541
|
+
try {
|
|
542
|
+
await page.evaluate((data) => {
|
|
543
|
+
const ss = globalThis.sessionStorage;
|
|
544
|
+
if (ss) {
|
|
545
|
+
for (const [key, value] of Object.entries(data)) {
|
|
546
|
+
ss.setItem(key, value);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
}, sessionData);
|
|
550
|
+
console.log(`✅ sessionStorage restored for ${origin}`);
|
|
551
|
+
}
|
|
552
|
+
catch (error) {
|
|
553
|
+
console.warn(`Failed to restore sessionStorage for ${origin}:`, error);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
catch (error) {
|
|
558
|
+
console.warn(`⚠️ Could not restore storage for origin ${origin}:`, error);
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
console.log('✅ Session loaded into existing context successfully');
|
|
562
|
+
}
|
|
563
|
+
catch (error) {
|
|
564
|
+
console.error('❌ Failed to load session into existing context:', error);
|
|
565
|
+
throw error;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
// /**
|
|
569
|
+
// * Check if session file exists and is valid
|
|
570
|
+
// */
|
|
571
|
+
// export function isSessionValid(filePath: string, maxAgeHours: number = 24): boolean {
|
|
572
|
+
// try {
|
|
573
|
+
// if (!fs.existsSync(filePath)) {
|
|
574
|
+
// return false;
|
|
575
|
+
// }
|
|
576
|
+
// const stats = fs.statSync(filePath);
|
|
577
|
+
// const ageInHours = (Date.now() - stats.mtime.getTime()) / (1000 * 60 * 60);
|
|
578
|
+
// return ageInHours < maxAgeHours;
|
|
579
|
+
// } catch {
|
|
580
|
+
// return false;
|
|
581
|
+
// }
|
|
582
|
+
// }
|
|
583
|
+
/**
|
|
584
|
+
* Delete session file
|
|
585
|
+
*/
|
|
586
|
+
function deleteSession(filePath) {
|
|
587
|
+
try {
|
|
588
|
+
if (fs_1.default.existsSync(filePath)) {
|
|
589
|
+
fs_1.default.unlinkSync(filePath);
|
|
590
|
+
console.log(`🗑️ Session file deleted: ${filePath}`);
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
catch (error) {
|
|
594
|
+
console.warn(`⚠️ Could not delete session file: ${error}`);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
// /**
|
|
598
|
+
// * Load session into existing context without creating new browser/page
|
|
599
|
+
// */
|
|
600
|
+
// export async function loadSessionIntoExistingContext(page: Page, sessionName: string, urls: string[] = []): Promise<void> {
|
|
601
|
+
// const sessionPath = `_Temp/sessions/${sessionName}.json`;
|
|
602
|
+
// try {
|
|
603
|
+
// if (!fs.existsSync(sessionPath)) {
|
|
604
|
+
// throw new Error(`Session file not found: ${sessionPath}`);
|
|
605
|
+
// }
|
|
606
|
+
// console.log(`🔄 Loading session into existing context from: ${sessionPath}`);
|
|
607
|
+
// const savedData = JSON.parse(fs.readFileSync(sessionPath, 'utf8'));
|
|
608
|
+
// // Handle both hybrid state and simple storage state formats
|
|
609
|
+
// let storageState: any;
|
|
610
|
+
// let sessionByOrigin: Record<string, SessionKV> = {};
|
|
611
|
+
// if (savedData.storageState && savedData.sessionByOrigin) {
|
|
612
|
+
// // Hybrid state format
|
|
613
|
+
// storageState = savedData.storageState;
|
|
614
|
+
// sessionByOrigin = savedData.sessionByOrigin;
|
|
615
|
+
// } else if (savedData.cookies || savedData.origins) {
|
|
616
|
+
// // Simple storage state format
|
|
617
|
+
// storageState = savedData;
|
|
618
|
+
// } else {
|
|
619
|
+
// throw new Error('Invalid session file format');
|
|
620
|
+
// }
|
|
621
|
+
// // Add cookies to existing context
|
|
622
|
+
// if (storageState?.cookies && Array.isArray(storageState.cookies)) {
|
|
623
|
+
// try {
|
|
624
|
+
// await page.context().addCookies(storageState.cookies);
|
|
625
|
+
// console.log('✅ Cookies restored to existing context');
|
|
626
|
+
// } catch (error) {
|
|
627
|
+
// console.warn('⚠️ Failed to add cookies:', error);
|
|
628
|
+
// }
|
|
629
|
+
// }
|
|
630
|
+
// // Determine origins to restore
|
|
631
|
+
// const targetUrls = urls.length > 0 ? urls : ['https://login.microsoftonline.com'];
|
|
632
|
+
// const origins = new Set<string>();
|
|
633
|
+
// // Add origins from URLs
|
|
634
|
+
// targetUrls.forEach(url => {
|
|
635
|
+
// const origin = originOf(url);
|
|
636
|
+
// if (origin) origins.add(origin);
|
|
637
|
+
// });
|
|
638
|
+
// // Add origins from session data
|
|
639
|
+
// if (storageState?.origins) {
|
|
640
|
+
// storageState.origins.forEach((o: any) => origins.add(o.origin));
|
|
641
|
+
// }
|
|
642
|
+
// Object.keys(sessionByOrigin).forEach(origin => origins.add(origin));
|
|
643
|
+
// // Restore storage for each origin
|
|
644
|
+
// for (const origin of origins) {
|
|
645
|
+
// try {
|
|
646
|
+
// console.log(`🔄 Restoring storage for origin: ${origin}`);
|
|
647
|
+
// // Navigate to the origin
|
|
648
|
+
// await page.goto(origin, {
|
|
649
|
+
// waitUntil: 'domcontentloaded',
|
|
650
|
+
// timeout: 15000
|
|
651
|
+
// });
|
|
652
|
+
// // Wait for page stability
|
|
653
|
+
// await page.waitForTimeout(1000);
|
|
654
|
+
// // Restore localStorage
|
|
655
|
+
// const originData = storageState?.origins?.find((o: any) => o.origin === origin);
|
|
656
|
+
// if (originData?.localStorage && Array.isArray(originData.localStorage)) {
|
|
657
|
+
// for (const item of originData.localStorage) {
|
|
658
|
+
// try {
|
|
659
|
+
// await page.evaluate(
|
|
660
|
+
// ({ name, value }) => {
|
|
661
|
+
// localStorage.setItem(name, value);
|
|
662
|
+
// },
|
|
663
|
+
// item
|
|
664
|
+
// );
|
|
665
|
+
// } catch (error) {
|
|
666
|
+
// console.warn(`Failed to set localStorage item ${item.name}:`, error);
|
|
667
|
+
// }
|
|
668
|
+
// }
|
|
669
|
+
// console.log(`✅ localStorage restored for ${origin}`);
|
|
670
|
+
// }
|
|
671
|
+
// // Restore sessionStorage
|
|
672
|
+
// const sessionData = sessionByOrigin[origin];
|
|
673
|
+
// if (sessionData && Object.keys(sessionData).length > 0) {
|
|
674
|
+
// try {
|
|
675
|
+
// await page.evaluate((data) => {
|
|
676
|
+
// for (const [key, value] of Object.entries(data)) {
|
|
677
|
+
// sessionStorage.setItem(key, value as string);
|
|
678
|
+
// }
|
|
679
|
+
// }, sessionData);
|
|
680
|
+
// console.log(`✅ sessionStorage restored for ${origin}`);
|
|
681
|
+
// } catch (error) {
|
|
682
|
+
// console.warn(`Failed to restore sessionStorage for ${origin}:`, error);
|
|
683
|
+
// }
|
|
684
|
+
// }
|
|
685
|
+
// } catch (error) {
|
|
686
|
+
// console.warn(`⚠️ Could not restore storage for origin ${origin}:`, error);
|
|
687
|
+
// }
|
|
688
|
+
// }
|
|
689
|
+
// // Navigate to the target URL if provided
|
|
690
|
+
// if (urls.length > 0) {
|
|
691
|
+
// const targetUrl = urls[0];
|
|
692
|
+
// console.log(`🔄 Navigating to target URL: ${targetUrl}`);
|
|
693
|
+
// try {
|
|
694
|
+
// await page.goto(targetUrl, {
|
|
695
|
+
// waitUntil: 'domcontentloaded',
|
|
696
|
+
// timeout: 15000
|
|
697
|
+
// });
|
|
698
|
+
// await page.waitForTimeout(500);
|
|
699
|
+
// } catch (error) {
|
|
700
|
+
// console.warn(`⚠️ Failed to navigate to ${targetUrl}:`, error);
|
|
701
|
+
// }
|
|
702
|
+
// }
|
|
703
|
+
// console.log('✅ Session loaded into existing context successfully');
|
|
704
|
+
// } catch (error) {
|
|
705
|
+
// console.error('❌ Failed to load session into existing context:', error);
|
|
706
|
+
// throw error;
|
|
707
|
+
// }
|
|
708
|
+
// }
|
|
709
|
+
/**
|
|
710
|
+
* Checks if the session file exists and is not older than maxAgeHours.
|
|
711
|
+
* @param filePath - Path to the session file.
|
|
712
|
+
* @param maxAgeHours - Maximum allowed age in hours.
|
|
713
|
+
* @returns true if session file exists and is valid, false otherwise.
|
|
714
|
+
*/
|
|
715
|
+
function isSessionValid(sessionName, maxAgeHours = 24) {
|
|
716
|
+
const sessionPath = `_Temp/sessions/${sessionName}.json`;
|
|
717
|
+
try {
|
|
718
|
+
if (!fs_1.default.existsSync(sessionPath)) {
|
|
719
|
+
return false;
|
|
720
|
+
}
|
|
721
|
+
const stats = fs_1.default.statSync(sessionPath);
|
|
722
|
+
const ageMs = Date.now() - stats.mtime.getTime();
|
|
723
|
+
const ageHours = ageMs / (1000 * 60 * 60);
|
|
724
|
+
return ageHours < maxAgeHours;
|
|
725
|
+
}
|
|
726
|
+
catch {
|
|
727
|
+
return false;
|
|
728
|
+
}
|
|
729
|
+
}
|