@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.
Files changed (225) hide show
  1. package/README.md +41 -0
  2. package/bin/playq.js +175 -0
  3. package/cucumber.js +10 -0
  4. package/dist/exec/featureFileCache.d.ts +21 -0
  5. package/dist/exec/featureFileCache.js +124 -0
  6. package/dist/exec/featureFilePreProcess.d.ts +12 -0
  7. package/dist/exec/featureFilePreProcess.js +208 -0
  8. package/dist/exec/preLoader.d.ts +1 -0
  9. package/dist/exec/preLoader.js +72 -0
  10. package/dist/exec/preProcessEntry.d.ts +1 -0
  11. package/dist/exec/preProcessEntry.js +83 -0
  12. package/dist/exec/preProcess_old_todelete.d.ts +1 -0
  13. package/dist/exec/preProcess_old_todelete.js +258 -0
  14. package/dist/exec/runner.d.ts +1 -0
  15. package/dist/exec/runner.js +221 -0
  16. package/dist/exec/runner_orchestrator.d.ts +1 -0
  17. package/dist/exec/runner_orchestrator.js +85 -0
  18. package/dist/exec/sgGenerator.d.ts +11 -0
  19. package/dist/exec/sgGenerator.js +310 -0
  20. package/dist/global.d.ts +15 -0
  21. package/dist/global.js +185 -0
  22. package/dist/helper/actions/api/apiRequestActions.d.ts +117 -0
  23. package/dist/helper/actions/api/apiRequestActions.js +374 -0
  24. package/dist/helper/actions/api/apiValidationActions.d.ts +119 -0
  25. package/dist/helper/actions/api/apiValidationActions.js +615 -0
  26. package/dist/helper/actions/apiActions.d.ts +18 -0
  27. package/dist/helper/actions/apiActions.js +34 -0
  28. package/dist/helper/actions/apiStepDefs.d.ts +1 -0
  29. package/dist/helper/actions/apiStepDefs.js +64 -0
  30. package/dist/helper/actions/comm/commonActions.d.ts +58 -0
  31. package/dist/helper/actions/comm/commonActions.js +198 -0
  32. package/dist/helper/actions/comm/utilityActions.d.ts +131 -0
  33. package/dist/helper/actions/comm/utilityActions.js +351 -0
  34. package/dist/helper/actions/commActions.d.ts +18 -0
  35. package/dist/helper/actions/commActions.js +34 -0
  36. package/dist/helper/actions/commStepDefs.d.ts +1 -0
  37. package/dist/helper/actions/commStepDefs.js +57 -0
  38. package/dist/helper/actions/stepGroupStepDefs.d.ts +1 -0
  39. package/dist/helper/actions/stepGroupStepDefs.js +15 -0
  40. package/dist/helper/actions/web/alertActions.d.ts +61 -0
  41. package/dist/helper/actions/web/alertActions.js +224 -0
  42. package/dist/helper/actions/web/cookieActions.d.ts +45 -0
  43. package/dist/helper/actions/web/cookieActions.js +186 -0
  44. package/dist/helper/actions/web/downloadActions.d.ts +40 -0
  45. package/dist/helper/actions/web/downloadActions.js +153 -0
  46. package/dist/helper/actions/web/elementReaderActions.d.ts +95 -0
  47. package/dist/helper/actions/web/elementReaderActions.js +326 -0
  48. package/dist/helper/actions/web/formActions.d.ts +122 -0
  49. package/dist/helper/actions/web/formActions.js +423 -0
  50. package/dist/helper/actions/web/iframeActions.d.ts +23 -0
  51. package/dist/helper/actions/web/iframeActions.js +108 -0
  52. package/dist/helper/actions/web/javascriptActions.d.ts +14 -0
  53. package/dist/helper/actions/web/javascriptActions.js +77 -0
  54. package/dist/helper/actions/web/keyboardActions.d.ts +35 -0
  55. package/dist/helper/actions/web/keyboardActions.js +118 -0
  56. package/dist/helper/actions/web/localStorageActions.d.ts +51 -0
  57. package/dist/helper/actions/web/localStorageActions.js +163 -0
  58. package/dist/helper/actions/web/mouseActions.d.ts +240 -0
  59. package/dist/helper/actions/web/mouseActions.js +609 -0
  60. package/dist/helper/actions/web/reportingActions.d.ts +34 -0
  61. package/dist/helper/actions/web/reportingActions.js +58 -0
  62. package/dist/helper/actions/web/screenshotActions.d.ts +34 -0
  63. package/dist/helper/actions/web/screenshotActions.js +151 -0
  64. package/dist/helper/actions/web/testDataActions.d.ts +21 -0
  65. package/dist/helper/actions/web/testDataActions.js +211 -0
  66. package/dist/helper/actions/web/validationActions.d.ts +547 -0
  67. package/dist/helper/actions/web/validationActions.js +1754 -0
  68. package/dist/helper/actions/web/waitActions.d.ts +191 -0
  69. package/dist/helper/actions/web/waitActions.js +589 -0
  70. package/dist/helper/actions/web/webNavigation.d.ts +104 -0
  71. package/dist/helper/actions/web/webNavigation.js +288 -0
  72. package/dist/helper/actions/webActions.d.ts +32 -0
  73. package/dist/helper/actions/webActions.js +48 -0
  74. package/dist/helper/actions/webStepDefs.d.ts +1 -0
  75. package/dist/helper/actions/webStepDefs.js +455 -0
  76. package/dist/helper/browsers/browserManager.d.ts +1 -0
  77. package/dist/helper/browsers/browserManager.js +56 -0
  78. package/dist/helper/bundle/defaultEntries.d.ts +6 -0
  79. package/dist/helper/bundle/defaultEntries.js +200 -0
  80. package/dist/helper/bundle/env.d.ts +1 -0
  81. package/dist/helper/bundle/env.js +157 -0
  82. package/dist/helper/bundle/vars.d.ts +9 -0
  83. package/dist/helper/bundle/vars.js +375 -0
  84. package/dist/helper/faker/customFaker.d.ts +55 -0
  85. package/dist/helper/faker/customFaker.js +45 -0
  86. package/dist/helper/faker/modules/data/postcodes_valid_sg.json +17 -0
  87. package/dist/helper/faker/modules/dateTime.d.ts +18 -0
  88. package/dist/helper/faker/modules/dateTime.js +106 -0
  89. package/dist/helper/faker/modules/mobile.d.ts +4 -0
  90. package/dist/helper/faker/modules/mobile.js +59 -0
  91. package/dist/helper/faker/modules/nric.d.ts +32 -0
  92. package/dist/helper/faker/modules/nric.js +84 -0
  93. package/dist/helper/faker/modules/passport.d.ts +3 -0
  94. package/dist/helper/faker/modules/passport.js +36 -0
  95. package/dist/helper/faker/modules/person.d.ts +14 -0
  96. package/dist/helper/faker/modules/person.js +73 -0
  97. package/dist/helper/faker/modules/postcode.d.ts +6 -0
  98. package/dist/helper/faker/modules/postcode.js +47 -0
  99. package/dist/helper/fixtures/locAggregate.d.ts +7 -0
  100. package/dist/helper/fixtures/locAggregate.js +94 -0
  101. package/dist/helper/fixtures/logFixture.d.ts +8 -0
  102. package/dist/helper/fixtures/logFixture.js +56 -0
  103. package/dist/helper/fixtures/webFixture.d.ts +19 -0
  104. package/dist/helper/fixtures/webFixture.js +186 -0
  105. package/dist/helper/fixtures/webLocFixture.d.ts +2 -0
  106. package/dist/helper/fixtures/webLocFixture.js +144 -0
  107. package/dist/helper/report/allureStepLogger.d.ts +0 -0
  108. package/dist/helper/report/allureStepLogger.js +25 -0
  109. package/dist/helper/report/customiseReport.d.ts +1 -0
  110. package/dist/helper/report/customiseReport.js +55 -0
  111. package/dist/helper/report/init.d.ts +1 -0
  112. package/dist/helper/report/init.js +14 -0
  113. package/dist/helper/report/report.d.ts +1 -0
  114. package/dist/helper/report/report.js +102 -0
  115. package/dist/helper/util/dataLoader.d.ts +10 -0
  116. package/dist/helper/util/dataLoader.js +73 -0
  117. package/dist/helper/util/logger.d.ts +4 -0
  118. package/dist/helper/util/logger.js +61 -0
  119. package/dist/helper/util/session/sessionUtil.d.ts +26 -0
  120. package/dist/helper/util/session/sessionUtil.js +729 -0
  121. package/dist/helper/util/stepHelpers.d.ts +2 -0
  122. package/dist/helper/util/stepHelpers.js +16 -0
  123. package/dist/helper/util/test-data/dataLoader.d.ts +7 -0
  124. package/dist/helper/util/test-data/dataLoader.js +145 -0
  125. package/dist/helper/util/test-data/dataTest.d.ts +10 -0
  126. package/dist/helper/util/test-data/dataTest.js +216 -0
  127. package/dist/helper/util/totp/totpHelper.d.ts +38 -0
  128. package/dist/helper/util/totp/totpHelper.js +117 -0
  129. package/dist/helper/util/utilities/cryptoUtil.d.ts +2 -0
  130. package/dist/helper/util/utilities/cryptoUtil.js +53 -0
  131. package/dist/helper/util/utilities/schemaGeneratorUtil.d.ts +2 -0
  132. package/dist/helper/util/utilities/schemaGeneratorUtil.js +129 -0
  133. package/dist/helper/util/utils.d.ts +2 -0
  134. package/dist/helper/util/utils.js +22 -0
  135. package/dist/helper/wrapper/PlaywrightWrappers.d.ts +8 -0
  136. package/dist/helper/wrapper/PlaywrightWrappers.js +26 -0
  137. package/dist/helper/wrapper/assert.d.ts +9 -0
  138. package/dist/helper/wrapper/assert.js +23 -0
  139. package/dist/index.d.ts +7 -0
  140. package/dist/index.js +57 -0
  141. package/dist/scripts/get-versions.d.ts +1 -0
  142. package/dist/scripts/get-versions.js +98 -0
  143. package/dist/scripts/posttest.d.ts +1 -0
  144. package/dist/scripts/posttest.js +29 -0
  145. package/dist/scripts/pretest.d.ts +1 -0
  146. package/dist/scripts/pretest.js +57 -0
  147. package/dist/scripts/util.d.ts +1 -0
  148. package/dist/scripts/util.js +376 -0
  149. package/package.json +68 -0
  150. package/src/exec/featureFileCache.ts +80 -0
  151. package/src/exec/featureFilePreProcess.ts +239 -0
  152. package/src/exec/preLoader.ts +72 -0
  153. package/src/exec/preProcessEntry.ts +59 -0
  154. package/src/exec/preProcess_old_todelete.ts +289 -0
  155. package/src/exec/runner.ts +241 -0
  156. package/src/exec/runnerCuke.js +90 -0
  157. package/src/exec/runner_orchestrator.ts +91 -0
  158. package/src/exec/sgGenerator.ts +373 -0
  159. package/src/global.ts +130 -0
  160. package/src/helper/actions/api/apiRequestActions.ts +362 -0
  161. package/src/helper/actions/api/apiValidationActions.ts +594 -0
  162. package/src/helper/actions/apiActions.ts +18 -0
  163. package/src/helper/actions/apiStepDefs.ts +80 -0
  164. package/src/helper/actions/comm/commonActions.ts +165 -0
  165. package/src/helper/actions/comm/utilityActions.ts +344 -0
  166. package/src/helper/actions/commActions.ts +18 -0
  167. package/src/helper/actions/commStepDefs.ts +72 -0
  168. package/src/helper/actions/stepGroupStepDefs.ts +17 -0
  169. package/src/helper/actions/web/alertActions.ts +179 -0
  170. package/src/helper/actions/web/cookieActions.ts +124 -0
  171. package/src/helper/actions/web/downloadActions.ts +129 -0
  172. package/src/helper/actions/web/elementReaderActions.ts +323 -0
  173. package/src/helper/actions/web/formActions.ts +469 -0
  174. package/src/helper/actions/web/iframeActions.ts +67 -0
  175. package/src/helper/actions/web/javascriptActions.ts +38 -0
  176. package/src/helper/actions/web/keyboardActions.ts +101 -0
  177. package/src/helper/actions/web/localStorageActions.ts +109 -0
  178. package/src/helper/actions/web/mouseActions.ts +864 -0
  179. package/src/helper/actions/web/reportingActions.ts +53 -0
  180. package/src/helper/actions/web/screenshotActions.ts +124 -0
  181. package/src/helper/actions/web/testDataActions.ts +162 -0
  182. package/src/helper/actions/web/validationActions.ts +2287 -0
  183. package/src/helper/actions/web/waitActions.ts +757 -0
  184. package/src/helper/actions/web/webNavigation.ts +313 -0
  185. package/src/helper/actions/webActions.ts +33 -0
  186. package/src/helper/actions/webStepDefs.ts +505 -0
  187. package/src/helper/browsers/browserManager.ts +23 -0
  188. package/src/helper/bundle/defaultEntries.ts +208 -0
  189. package/src/helper/bundle/env.ts +119 -0
  190. package/src/helper/bundle/vars.ts +368 -0
  191. package/src/helper/faker/customFaker.ts +107 -0
  192. package/src/helper/faker/modules/data/postcodes_valid_sg.json +17 -0
  193. package/src/helper/faker/modules/dateTime.ts +121 -0
  194. package/src/helper/faker/modules/mobile.ts +58 -0
  195. package/src/helper/faker/modules/nric.ts +109 -0
  196. package/src/helper/faker/modules/passport.ts +34 -0
  197. package/src/helper/faker/modules/person.ts +93 -0
  198. package/src/helper/faker/modules/postcode.ts +57 -0
  199. package/src/helper/fixtures/locAggregate.ts +61 -0
  200. package/src/helper/fixtures/logFixture.ts +57 -0
  201. package/src/helper/fixtures/webFixture.ts +206 -0
  202. package/src/helper/fixtures/webLocFixture.ts +143 -0
  203. package/src/helper/report/allureStepLogger.ts +26 -0
  204. package/src/helper/report/customiseReport.ts +61 -0
  205. package/src/helper/report/init.ts +18 -0
  206. package/src/helper/report/report.ts +72 -0
  207. package/src/helper/util/dataLoader.ts +42 -0
  208. package/src/helper/util/logger.ts +32 -0
  209. package/src/helper/util/session/sessionUtil.ts +839 -0
  210. package/src/helper/util/stepHelpers.ts +14 -0
  211. package/src/helper/util/test-data/dataLoader.ts +108 -0
  212. package/src/helper/util/test-data/dataTest.ts +191 -0
  213. package/src/helper/util/test-data/registerUser.json +7 -0
  214. package/src/helper/util/totp/totpHelper.ts +102 -0
  215. package/src/helper/util/utilities/cryptoUtil.ts +53 -0
  216. package/src/helper/util/utilities/schemaGeneratorUtil.ts +143 -0
  217. package/src/helper/util/utils.ts +28 -0
  218. package/src/helper/wrapper/PlaywrightWrappers.ts +28 -0
  219. package/src/helper/wrapper/assert.ts +25 -0
  220. package/src/index.ts +17 -0
  221. package/src/scripts/get-versions.ts +68 -0
  222. package/src/scripts/posttest.ts +32 -0
  223. package/src/scripts/pretest.ts +48 -0
  224. package/src/scripts/util.ts +406 -0
  225. 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
+ }