qa360 2.2.20 → 2.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (507) hide show
  1. package/README.md +155 -262
  2. package/{cli/dist → dist}/commands/ai.js +1 -1
  3. package/{cli/dist → dist}/commands/coverage.js +1 -1
  4. package/{cli/dist → dist}/commands/crawl.d.ts +12 -1
  5. package/{cli/dist → dist}/commands/crawl.js +70 -9
  6. package/{cli/dist → dist}/commands/doctor.js +2 -2
  7. package/{cli/dist → dist}/commands/explain.js +2 -2
  8. package/{cli/dist → dist}/commands/flakiness.js +1 -1
  9. package/{cli/dist → dist}/commands/generate.js +1 -1
  10. package/{cli/dist → dist}/commands/history.js +1 -1
  11. package/{cli/dist → dist}/commands/monitor.js +3 -3
  12. package/{cli/dist → dist}/commands/ollama.js +1 -1
  13. package/{cli/dist → dist}/commands/pack.js +2 -2
  14. package/{cli/dist → dist}/commands/regression.js +1 -1
  15. package/{cli/dist → dist}/commands/repair.js +1 -1
  16. package/{cli/dist → dist}/commands/retry.js +1 -1
  17. package/{cli/dist → dist}/commands/run.d.ts +1 -1
  18. package/{cli/dist → dist}/commands/run.js +1 -1
  19. package/{cli/dist → dist}/commands/secrets.js +1 -1
  20. package/{cli/dist → dist}/commands/serve.js +1 -1
  21. package/{cli/dist → dist}/commands/slo.js +1 -1
  22. package/{cli/dist → dist}/commands/verify.js +1 -1
  23. package/{cli/dist → dist}/core/adapters/playwright-native-api.d.ts +2 -0
  24. package/{cli/dist → dist}/core/adapters/playwright-native-api.js +20 -1
  25. package/{cli/dist → dist}/core/adapters/playwright-ui.d.ts +21 -0
  26. package/dist/core/adapters/playwright-ui.js +2050 -0
  27. package/{cli/dist → dist}/core/ai/ollama-provider.js +15 -3
  28. package/{cli/dist → dist}/core/artifacts/ui-artifacts.js +24 -4
  29. package/dist/core/auth/backup-codes-provider.d.ts +91 -0
  30. package/dist/core/auth/backup-codes-provider.js +215 -0
  31. package/{cli/dist → dist}/core/auth/basic-auth-provider.d.ts +6 -0
  32. package/{cli/dist → dist}/core/auth/basic-auth-provider.js +24 -6
  33. package/dist/core/auth/digest-auth-provider.d.ts +116 -0
  34. package/dist/core/auth/digest-auth-provider.js +244 -0
  35. package/dist/core/auth/hcaptcha-handler.d.ts +103 -0
  36. package/dist/core/auth/hcaptcha-handler.js +288 -0
  37. package/{cli/dist → dist}/core/auth/index.d.ts +81 -4
  38. package/{cli/dist → dist}/core/auth/index.js +15 -1
  39. package/dist/core/auth/oauth-handler.d.ts +408 -0
  40. package/dist/core/auth/oauth-handler.js +636 -0
  41. package/{cli/dist → dist}/core/auth/oauth2-provider.d.ts +9 -0
  42. package/dist/core/auth/oauth2-provider.js +227 -0
  43. package/dist/core/auth/otp-provider.d.ts +93 -0
  44. package/dist/core/auth/otp-provider.js +288 -0
  45. package/dist/core/auth/recaptcha-handler.d.ts +119 -0
  46. package/dist/core/auth/recaptcha-handler.js +301 -0
  47. package/dist/core/auth/remember-me-handler.d.ts +142 -0
  48. package/dist/core/auth/remember-me-handler.js +255 -0
  49. package/dist/core/auth/saml-handler.d.ts +173 -0
  50. package/dist/core/auth/saml-handler.js +364 -0
  51. package/dist/core/auth/webauthn-handler.d.ts +182 -0
  52. package/dist/core/auth/webauthn-handler.js +310 -0
  53. package/dist/core/crawler/advanced-interactions.d.ts +342 -0
  54. package/dist/core/crawler/advanced-interactions.js +1069 -0
  55. package/dist/core/crawler/blob-url-download-handler.d.ts +145 -0
  56. package/dist/core/crawler/blob-url-download-handler.js +392 -0
  57. package/dist/core/crawler/consent-handler.d.ts +49 -0
  58. package/dist/core/crawler/consent-handler.js +258 -0
  59. package/dist/core/crawler/cookie-manager.d.ts +166 -0
  60. package/dist/core/crawler/cookie-manager.js +353 -0
  61. package/dist/core/crawler/coop-coep-handler.d.ts +136 -0
  62. package/dist/core/crawler/coop-coep-handler.js +338 -0
  63. package/dist/core/crawler/csp-handler.d.ts +151 -0
  64. package/dist/core/crawler/csp-handler.js +415 -0
  65. package/dist/core/crawler/download-handler.d.ts +155 -0
  66. package/dist/core/crawler/download-handler.js +370 -0
  67. package/dist/core/crawler/email-testing-handler.d.ts +214 -0
  68. package/dist/core/crawler/email-testing-handler.js +398 -0
  69. package/dist/core/crawler/error-tracking-handler.d.ts +177 -0
  70. package/dist/core/crawler/error-tracking-handler.js +378 -0
  71. package/dist/core/crawler/form-handler.d.ts +100 -0
  72. package/dist/core/crawler/form-handler.js +465 -0
  73. package/dist/core/crawler/framework-wait-handler.d.ts +96 -0
  74. package/dist/core/crawler/framework-wait-handler.js +464 -0
  75. package/dist/core/crawler/geolocation-handler.d.ts +112 -0
  76. package/dist/core/crawler/geolocation-handler.js +276 -0
  77. package/dist/core/crawler/index.d.ts +78 -0
  78. package/{cli/dist → dist}/core/crawler/index.js +74 -1
  79. package/dist/core/crawler/intelligent-selector-generator.d.ts +164 -0
  80. package/dist/core/crawler/intelligent-selector-generator.js +612 -0
  81. package/{cli/dist → dist}/core/crawler/journey-generator.js +44 -1
  82. package/{cli/dist → dist}/core/crawler/page-analyzer.d.ts +16 -1
  83. package/{cli/dist → dist}/core/crawler/page-analyzer.js +469 -17
  84. package/dist/core/crawler/permissions-handler.d.ts +112 -0
  85. package/dist/core/crawler/permissions-handler.js +236 -0
  86. package/dist/core/crawler/permissions-policy-handler.d.ts +113 -0
  87. package/dist/core/crawler/permissions-policy-handler.js +402 -0
  88. package/dist/core/crawler/presets.d.ts +100 -0
  89. package/dist/core/crawler/presets.js +887 -0
  90. package/dist/core/crawler/repl-debug-handler.d.ts +105 -0
  91. package/dist/core/crawler/repl-debug-handler.js +552 -0
  92. package/dist/core/crawler/reporting-api-handler.d.ts +212 -0
  93. package/dist/core/crawler/reporting-api-handler.js +344 -0
  94. package/{cli/dist → dist}/core/crawler/selector-generator.d.ts +9 -0
  95. package/{cli/dist → dist}/core/crawler/selector-generator.js +99 -23
  96. package/dist/core/crawler/site-profiler.d.ts +89 -0
  97. package/dist/core/crawler/site-profiler.js +290 -0
  98. package/dist/core/crawler/sourcemaps-handler.d.ts +144 -0
  99. package/dist/core/crawler/sourcemaps-handler.js +420 -0
  100. package/dist/core/crawler/stacked-modals-handler.d.ts +118 -0
  101. package/dist/core/crawler/stacked-modals-handler.js +429 -0
  102. package/dist/core/crawler/trusted-types-handler.d.ts +149 -0
  103. package/dist/core/crawler/trusted-types-handler.js +413 -0
  104. package/{cli/dist → dist}/core/crawler/types.d.ts +68 -2
  105. package/dist/core/crawler/wait-strategies.d.ts +108 -0
  106. package/dist/core/crawler/wait-strategies.js +399 -0
  107. package/dist/core/fixtures/factories.d.ts +180 -0
  108. package/dist/core/fixtures/factories.js +279 -0
  109. package/dist/core/fixtures/index.d.ts +6 -0
  110. package/dist/core/fixtures/index.js +6 -0
  111. package/{cli/dist → dist}/core/generation/crawler-pack-generator.d.ts +13 -3
  112. package/dist/core/generation/crawler-pack-generator.js +232 -0
  113. package/{cli/dist → dist}/core/generation/index.d.ts +2 -0
  114. package/{cli/dist → dist}/core/generation/index.js +2 -0
  115. package/{cli/dist → dist}/core/index.d.ts +2 -0
  116. package/{cli/dist → dist}/core/index.js +4 -0
  117. package/dist/core/network/index.d.ts +7 -0
  118. package/dist/core/network/index.js +7 -0
  119. package/dist/core/network/network-manager.d.ts +237 -0
  120. package/dist/core/network/network-manager.js +343 -0
  121. package/dist/core/network/network-simulator.d.ts +158 -0
  122. package/dist/core/network/network-simulator.js +261 -0
  123. package/{cli/dist → dist}/core/pack/validator.js +2 -2
  124. package/{cli/dist → dist}/core/pack-v2/migrator.d.ts +5 -0
  125. package/{cli/dist → dist}/core/pack-v2/migrator.js +81 -6
  126. package/{cli/dist → dist}/core/pack-v2/validator.js +4 -3
  127. package/{cli/dist → dist}/core/pom/base-page.js +1 -1
  128. package/{cli/dist → dist}/core/pom/loader.js +1 -1
  129. package/dist/core/reporting/index.d.ts +9 -0
  130. package/dist/core/reporting/index.js +10 -0
  131. package/dist/core/reporting/junit-reporter.d.ts +114 -0
  132. package/dist/core/reporting/junit-reporter.js +306 -0
  133. package/{cli/dist → dist}/core/runner/e2e-helpers.d.ts +1 -1
  134. package/{cli/dist → dist}/core/runner/e2e-helpers.js +2 -2
  135. package/{cli/dist → dist}/core/runner/phase3-runner.d.ts +3 -0
  136. package/{cli/dist → dist}/core/runner/phase3-runner.js +45 -14
  137. package/dist/core/sharding/test-sharding.d.ts +137 -0
  138. package/dist/core/sharding/test-sharding.js +233 -0
  139. package/dist/core/storage/cookie-manager.d.ts +160 -0
  140. package/dist/core/storage/cookie-manager.js +268 -0
  141. package/dist/core/storage/index.d.ts +7 -0
  142. package/dist/core/storage/index.js +7 -0
  143. package/dist/core/storage/storage-helpers.d.ts +138 -0
  144. package/dist/core/storage/storage-helpers.js +315 -0
  145. package/dist/core/test-helpers/index.d.ts +6 -0
  146. package/dist/core/test-helpers/index.js +6 -0
  147. package/dist/core/test-helpers/state-reset.d.ts +119 -0
  148. package/dist/core/test-helpers/state-reset.js +234 -0
  149. package/{cli/dist → dist}/core/types/pack-v1.d.ts +15 -2
  150. package/{cli/dist → dist}/core/types/pack-v2.d.ts +1 -1
  151. package/dist/core/upload/chunked-uploader.d.ts +150 -0
  152. package/dist/core/upload/chunked-uploader.js +289 -0
  153. package/dist/core/upload/index.d.ts +11 -0
  154. package/dist/core/upload/index.js +8 -0
  155. package/dist/core/upload/mime-validator.d.ts +119 -0
  156. package/dist/core/upload/mime-validator.js +373 -0
  157. package/dist/core/upload/presigned-uploader.d.ts +118 -0
  158. package/dist/core/upload/presigned-uploader.js +274 -0
  159. package/dist/core/utils/device-emulation.d.ts +194 -0
  160. package/dist/core/utils/device-emulation.js +380 -0
  161. package/dist/core/utils/index.d.ts +8 -0
  162. package/dist/core/utils/index.js +8 -0
  163. package/dist/core/utils/retry.d.ts +145 -0
  164. package/dist/core/utils/retry.js +242 -0
  165. package/dist/core/utils/smart-wait.d.ts +133 -0
  166. package/dist/core/utils/smart-wait.js +417 -0
  167. package/dist/core/visual/index.d.ts +7 -0
  168. package/dist/core/visual/index.js +7 -0
  169. package/dist/core/visual/pixel-diff.d.ts +87 -0
  170. package/dist/core/visual/pixel-diff.js +213 -0
  171. package/dist/core/visual/screenshot-helper.d.ts +130 -0
  172. package/dist/core/visual/screenshot-helper.js +223 -0
  173. package/{cli/dist → dist}/utils/config.d.ts +1 -1
  174. package/examples/README.md +160 -0
  175. package/examples/accessibility.yml +48 -0
  176. package/examples/api-basic.yml +27 -0
  177. package/examples/complete.yml +146 -0
  178. package/examples/crawler.yml +38 -0
  179. package/examples/fullstack.yml +78 -0
  180. package/examples/security.yml +58 -0
  181. package/examples/ui-advanced.yml +49 -0
  182. package/examples/ui-basic.yml +24 -0
  183. package/package.json +33 -67
  184. package/CHANGELOG.md +0 -262
  185. package/CONTRIBUTING.md +0 -273
  186. package/QUICK_START.md +0 -191
  187. package/cli/CHANGELOG.md +0 -84
  188. package/cli/LICENSE +0 -24
  189. package/cli/README.md +0 -222
  190. package/cli/dist/core/adapters/playwright-ui.js +0 -864
  191. package/cli/dist/core/auth/oauth2-provider.js +0 -114
  192. package/cli/dist/core/coverage/analyzer.d.ts +0 -101
  193. package/cli/dist/core/coverage/analyzer.js +0 -415
  194. package/cli/dist/core/coverage/collector.d.ts +0 -74
  195. package/cli/dist/core/coverage/collector.js +0 -459
  196. package/cli/dist/core/coverage/config.d.ts +0 -37
  197. package/cli/dist/core/coverage/config.js +0 -156
  198. package/cli/dist/core/coverage/index.d.ts +0 -11
  199. package/cli/dist/core/coverage/index.js +0 -15
  200. package/cli/dist/core/coverage/types.d.ts +0 -267
  201. package/cli/dist/core/coverage/types.js +0 -6
  202. package/cli/dist/core/coverage/vault.d.ts +0 -95
  203. package/cli/dist/core/coverage/vault.js +0 -405
  204. package/cli/dist/core/crawler/index.d.ts +0 -57
  205. package/cli/dist/core/fixtures/index.d.ts +0 -8
  206. package/cli/dist/core/fixtures/index.js +0 -8
  207. package/cli/dist/core/generation/crawler-pack-generator.js +0 -231
  208. package/cli/dist/core/reporting/index.d.ts +0 -6
  209. package/cli/dist/core/reporting/index.js +0 -6
  210. package/cli/dist/core/visual/index.d.ts +0 -6
  211. package/cli/dist/core/visual/index.js +0 -6
  212. package/cli/package.json +0 -76
  213. package/core/LICENSE +0 -24
  214. package/core/README.md +0 -64
  215. package/core/package.json +0 -81
  216. package/core/schemas/pack.schema.json +0 -236
  217. /package/{cli/bin → bin}/qa360.js +0 -0
  218. /package/{cli/dist → dist}/cli-minimal.d.ts +0 -0
  219. /package/{cli/dist → dist}/cli-minimal.js +0 -0
  220. /package/{cli/dist → dist}/commands/ai.d.ts +0 -0
  221. /package/{cli/dist → dist}/commands/ask.d.ts +0 -0
  222. /package/{cli/dist → dist}/commands/ask.js +0 -0
  223. /package/{cli/dist → dist}/commands/coverage.d.ts +0 -0
  224. /package/{cli/dist → dist}/commands/doctor.d.ts +0 -0
  225. /package/{cli/dist → dist}/commands/examples.d.ts +0 -0
  226. /package/{cli/dist → dist}/commands/examples.js +0 -0
  227. /package/{cli/dist → dist}/commands/explain.d.ts +0 -0
  228. /package/{cli/dist → dist}/commands/flakiness.d.ts +0 -0
  229. /package/{cli/dist → dist}/commands/generate.d.ts +0 -0
  230. /package/{cli/dist → dist}/commands/history.d.ts +0 -0
  231. /package/{cli/dist → dist}/commands/init.d.ts +0 -0
  232. /package/{cli/dist → dist}/commands/init.js +0 -0
  233. /package/{cli/dist → dist}/commands/monitor.d.ts +0 -0
  234. /package/{cli/dist → dist}/commands/ollama.d.ts +0 -0
  235. /package/{cli/dist → dist}/commands/pack.d.ts +0 -0
  236. /package/{cli/dist → dist}/commands/regression.d.ts +0 -0
  237. /package/{cli/dist → dist}/commands/repair.d.ts +0 -0
  238. /package/{cli/dist → dist}/commands/report.d.ts +0 -0
  239. /package/{cli/dist → dist}/commands/report.js +0 -0
  240. /package/{cli/dist → dist}/commands/retry.d.ts +0 -0
  241. /package/{cli/dist → dist}/commands/scan.d.ts +0 -0
  242. /package/{cli/dist → dist}/commands/scan.js +0 -0
  243. /package/{cli/dist → dist}/commands/secrets.d.ts +0 -0
  244. /package/{cli/dist → dist}/commands/serve.d.ts +0 -0
  245. /package/{cli/dist → dist}/commands/slo.d.ts +0 -0
  246. /package/{cli/dist → dist}/commands/verify.d.ts +0 -0
  247. /package/{cli/dist → dist}/core/adapters/gitleaks-secrets.d.ts +0 -0
  248. /package/{cli/dist → dist}/core/adapters/gitleaks-secrets.js +0 -0
  249. /package/{cli/dist → dist}/core/adapters/jest-adapter.d.ts +0 -0
  250. /package/{cli/dist → dist}/core/adapters/jest-adapter.js +0 -0
  251. /package/{cli/dist → dist}/core/adapters/k6-perf.d.ts +0 -0
  252. /package/{cli/dist → dist}/core/adapters/k6-perf.js +0 -0
  253. /package/{cli/dist → dist}/core/adapters/osv-deps.d.ts +0 -0
  254. /package/{cli/dist → dist}/core/adapters/osv-deps.js +0 -0
  255. /package/{cli/dist → dist}/core/adapters/playwright-native-adapter.d.ts +0 -0
  256. /package/{cli/dist → dist}/core/adapters/playwright-native-adapter.js +0 -0
  257. /package/{cli/dist → dist}/core/adapters/pytest-adapter.d.ts +0 -0
  258. /package/{cli/dist → dist}/core/adapters/pytest-adapter.js +0 -0
  259. /package/{cli/dist → dist}/core/adapters/semgrep-sast.d.ts +0 -0
  260. /package/{cli/dist → dist}/core/adapters/semgrep-sast.js +0 -0
  261. /package/{cli/dist → dist}/core/adapters/unit-test-types.d.ts +0 -0
  262. /package/{cli/dist → dist}/core/adapters/unit-test-types.js +0 -0
  263. /package/{cli/dist → dist}/core/adapters/vitest-adapter.d.ts +0 -0
  264. /package/{cli/dist → dist}/core/adapters/vitest-adapter.js +0 -0
  265. /package/{cli/dist → dist}/core/adapters/zap-dast.d.ts +0 -0
  266. /package/{cli/dist → dist}/core/adapters/zap-dast.js +0 -0
  267. /package/{cli/dist → dist}/core/ai/anthropic-provider.d.ts +0 -0
  268. /package/{cli/dist → dist}/core/ai/anthropic-provider.js +0 -0
  269. /package/{cli/dist → dist}/core/ai/deepseek-provider.d.ts +0 -0
  270. /package/{cli/dist → dist}/core/ai/deepseek-provider.js +0 -0
  271. /package/{cli/dist → dist}/core/ai/index.d.ts +0 -0
  272. /package/{cli/dist → dist}/core/ai/index.js +0 -0
  273. /package/{cli/dist → dist}/core/ai/llm-client.d.ts +0 -0
  274. /package/{cli/dist → dist}/core/ai/llm-client.js +0 -0
  275. /package/{cli/dist → dist}/core/ai/mock-provider.d.ts +0 -0
  276. /package/{cli/dist → dist}/core/ai/mock-provider.js +0 -0
  277. /package/{cli/dist → dist}/core/ai/ollama-provider.d.ts +0 -0
  278. /package/{cli/dist → dist}/core/ai/openai-provider.d.ts +0 -0
  279. /package/{cli/dist → dist}/core/ai/openai-provider.js +0 -0
  280. /package/{cli/dist → dist}/core/ai/provider-factory.d.ts +0 -0
  281. /package/{cli/dist → dist}/core/ai/provider-factory.js +0 -0
  282. /package/{cli/dist → dist}/core/artifacts/index.d.ts +0 -0
  283. /package/{cli/dist → dist}/core/artifacts/index.js +0 -0
  284. /package/{cli/dist → dist}/core/artifacts/ui-artifacts.d.ts +0 -0
  285. /package/{cli/dist → dist}/core/assertions/engine.d.ts +0 -0
  286. /package/{cli/dist → dist}/core/assertions/engine.js +0 -0
  287. /package/{cli/dist → dist}/core/assertions/index.d.ts +0 -0
  288. /package/{cli/dist → dist}/core/assertions/index.js +0 -0
  289. /package/{cli/dist → dist}/core/assertions/types.d.ts +0 -0
  290. /package/{cli/dist → dist}/core/assertions/types.js +0 -0
  291. /package/{cli/dist → dist}/core/auth/api-key-provider.d.ts +0 -0
  292. /package/{cli/dist → dist}/core/auth/api-key-provider.js +0 -0
  293. /package/{cli/dist → dist}/core/auth/aws-iam-provider.d.ts +0 -0
  294. /package/{cli/dist → dist}/core/auth/aws-iam-provider.js +0 -0
  295. /package/{cli/dist → dist}/core/auth/azure-ad-provider.d.ts +0 -0
  296. /package/{cli/dist → dist}/core/auth/azure-ad-provider.js +0 -0
  297. /package/{cli/dist → dist}/core/auth/gcp-adc-provider.d.ts +0 -0
  298. /package/{cli/dist → dist}/core/auth/gcp-adc-provider.js +0 -0
  299. /package/{cli/dist → dist}/core/auth/jwt-provider.d.ts +0 -0
  300. /package/{cli/dist → dist}/core/auth/jwt-provider.js +0 -0
  301. /package/{cli/dist → dist}/core/auth/manager.d.ts +0 -0
  302. /package/{cli/dist → dist}/core/auth/manager.js +0 -0
  303. /package/{cli/dist → dist}/core/auth/totp-provider.d.ts +0 -0
  304. /package/{cli/dist → dist}/core/auth/totp-provider.js +0 -0
  305. /package/{cli/dist → dist}/core/auth/ui-login-provider.d.ts +0 -0
  306. /package/{cli/dist → dist}/core/auth/ui-login-provider.js +0 -0
  307. /package/{cli/dist → dist}/core/cache/index.d.ts +0 -0
  308. /package/{cli/dist → dist}/core/cache/index.js +0 -0
  309. /package/{cli/dist → dist}/core/cache/lru-cache.d.ts +0 -0
  310. /package/{cli/dist → dist}/core/cache/lru-cache.js +0 -0
  311. /package/{cli/dist/core → dist}/core/coverage/analyzer.d.ts +0 -0
  312. /package/{cli/dist/core → dist}/core/coverage/analyzer.js +0 -0
  313. /package/{cli/dist/core → dist}/core/coverage/collector.d.ts +0 -0
  314. /package/{cli/dist/core → dist}/core/coverage/collector.js +0 -0
  315. /package/{cli/dist/core → dist}/core/coverage/config.d.ts +0 -0
  316. /package/{cli/dist/core → dist}/core/coverage/config.js +0 -0
  317. /package/{cli/dist/core → dist}/core/coverage/index.d.ts +0 -0
  318. /package/{cli/dist/core → dist}/core/coverage/index.js +0 -0
  319. /package/{cli/dist/core → dist}/core/coverage/types.d.ts +0 -0
  320. /package/{cli/dist/core → dist}/core/coverage/types.js +0 -0
  321. /package/{cli/dist/core → dist}/core/coverage/vault.d.ts +0 -0
  322. /package/{cli/dist/core → dist}/core/coverage/vault.js +0 -0
  323. /package/{cli/dist → dist}/core/crawler/journey-generator.d.ts +0 -0
  324. /package/{cli/dist → dist}/core/crawler/types.js +0 -0
  325. /package/{cli/dist → dist}/core/dashboard/assets.d.ts +0 -0
  326. /package/{cli/dist → dist}/core/dashboard/assets.js +0 -0
  327. /package/{cli/dist → dist}/core/dashboard/index.d.ts +0 -0
  328. /package/{cli/dist → dist}/core/dashboard/index.js +0 -0
  329. /package/{cli/dist → dist}/core/dashboard/server.d.ts +0 -0
  330. /package/{cli/dist → dist}/core/dashboard/server.js +0 -0
  331. /package/{cli/dist → dist}/core/dashboard/types.d.ts +0 -0
  332. /package/{cli/dist → dist}/core/dashboard/types.js +0 -0
  333. /package/{cli/dist → dist}/core/discoverer/index.d.ts +0 -0
  334. /package/{cli/dist → dist}/core/discoverer/index.js +0 -0
  335. /package/{cli/dist → dist}/core/fixtures/loader.d.ts +0 -0
  336. /package/{cli/dist → dist}/core/fixtures/loader.js +0 -0
  337. /package/{cli/dist → dist}/core/fixtures/resolver.d.ts +0 -0
  338. /package/{cli/dist → dist}/core/fixtures/resolver.js +0 -0
  339. /package/{cli/dist → dist}/core/fixtures/types.d.ts +0 -0
  340. /package/{cli/dist → dist}/core/fixtures/types.js +0 -0
  341. /package/{cli/dist → dist}/core/flakiness/index.d.ts +0 -0
  342. /package/{cli/dist → dist}/core/flakiness/index.js +0 -0
  343. /package/{cli/dist → dist}/core/generation/code-formatter.d.ts +0 -0
  344. /package/{cli/dist → dist}/core/generation/code-formatter.js +0 -0
  345. /package/{cli/dist → dist}/core/generation/code-generator.d.ts +0 -0
  346. /package/{cli/dist → dist}/core/generation/code-generator.js +0 -0
  347. /package/{cli/dist → dist}/core/generation/generator.d.ts +0 -0
  348. /package/{cli/dist → dist}/core/generation/generator.js +0 -0
  349. /package/{cli/dist → dist}/core/generation/pack-generator.d.ts +0 -0
  350. /package/{cli/dist → dist}/core/generation/pack-generator.js +0 -0
  351. /package/{cli/dist → dist}/core/generation/prompt-builder.d.ts +0 -0
  352. /package/{cli/dist → dist}/core/generation/prompt-builder.js +0 -0
  353. /package/{cli/dist → dist}/core/generation/source-analyzer.d.ts +0 -0
  354. /package/{cli/dist → dist}/core/generation/source-analyzer.js +0 -0
  355. /package/{cli/dist → dist}/core/generation/test-optimizer.d.ts +0 -0
  356. /package/{cli/dist → dist}/core/generation/test-optimizer.js +0 -0
  357. /package/{cli/dist → dist}/core/generation/types.d.ts +0 -0
  358. /package/{cli/dist → dist}/core/generation/types.js +0 -0
  359. /package/{cli/dist → dist}/core/hooks/compose.d.ts +0 -0
  360. /package/{cli/dist → dist}/core/hooks/compose.js +0 -0
  361. /package/{cli/dist → dist}/core/hooks/runner.d.ts +0 -0
  362. /package/{cli/dist → dist}/core/hooks/runner.js +0 -0
  363. /package/{cli/dist → dist}/core/pack/migrator.d.ts +0 -0
  364. /package/{cli/dist → dist}/core/pack/migrator.js +0 -0
  365. /package/{cli/dist → dist}/core/pack/validator.d.ts +0 -0
  366. /package/{cli/dist → dist}/core/pack-v2/index.d.ts +0 -0
  367. /package/{cli/dist → dist}/core/pack-v2/index.js +0 -0
  368. /package/{cli/dist → dist}/core/pack-v2/loader.d.ts +0 -0
  369. /package/{cli/dist → dist}/core/pack-v2/loader.js +0 -0
  370. /package/{cli/dist → dist}/core/pack-v2/validator.d.ts +0 -0
  371. /package/{cli/dist → dist}/core/parallel/index.d.ts +0 -0
  372. /package/{cli/dist → dist}/core/parallel/index.js +0 -0
  373. /package/{cli/dist → dist}/core/parallel/parallel-runner.d.ts +0 -0
  374. /package/{cli/dist → dist}/core/parallel/parallel-runner.js +0 -0
  375. /package/{cli/dist → dist}/core/pom/base-page.d.ts +0 -0
  376. /package/{cli/dist → dist}/core/pom/index.d.ts +0 -0
  377. /package/{cli/dist → dist}/core/pom/index.js +0 -0
  378. /package/{cli/dist → dist}/core/pom/loader.d.ts +0 -0
  379. /package/{cli/dist → dist}/core/pom/types.d.ts +0 -0
  380. /package/{cli/dist → dist}/core/pom/types.js +0 -0
  381. /package/{cli/dist → dist}/core/proof/bundle.d.ts +0 -0
  382. /package/{cli/dist → dist}/core/proof/bundle.js +0 -0
  383. /package/{cli/dist → dist}/core/proof/canonicalize.d.ts +0 -0
  384. /package/{cli/dist → dist}/core/proof/canonicalize.js +0 -0
  385. /package/{cli/dist → dist}/core/proof/index.d.ts +0 -0
  386. /package/{cli/dist → dist}/core/proof/index.js +0 -0
  387. /package/{cli/dist → dist}/core/proof/schema.d.ts +0 -0
  388. /package/{cli/dist → dist}/core/proof/schema.js +0 -0
  389. /package/{cli/dist → dist}/core/proof/signer.d.ts +0 -0
  390. /package/{cli/dist → dist}/core/proof/signer.js +0 -0
  391. /package/{cli/dist → dist}/core/proof/verifier.d.ts +0 -0
  392. /package/{cli/dist → dist}/core/proof/verifier.js +0 -0
  393. /package/{cli/dist → dist}/core/regression/detector.d.ts +0 -0
  394. /package/{cli/dist → dist}/core/regression/detector.js +0 -0
  395. /package/{cli/dist → dist}/core/regression/index.d.ts +0 -0
  396. /package/{cli/dist → dist}/core/regression/index.js +0 -0
  397. /package/{cli/dist → dist}/core/regression/trend-analyzer.d.ts +0 -0
  398. /package/{cli/dist → dist}/core/regression/trend-analyzer.js +0 -0
  399. /package/{cli/dist → dist}/core/regression/types.d.ts +0 -0
  400. /package/{cli/dist → dist}/core/regression/types.js +0 -0
  401. /package/{cli/dist → dist}/core/regression/vault.d.ts +0 -0
  402. /package/{cli/dist → dist}/core/regression/vault.js +0 -0
  403. /package/{cli/dist → dist}/core/repair/engine/fixer.d.ts +0 -0
  404. /package/{cli/dist → dist}/core/repair/engine/fixer.js +0 -0
  405. /package/{cli/dist → dist}/core/repair/engine/suggestion-engine.d.ts +0 -0
  406. /package/{cli/dist → dist}/core/repair/engine/suggestion-engine.js +0 -0
  407. /package/{cli/dist → dist}/core/repair/index.d.ts +0 -0
  408. /package/{cli/dist → dist}/core/repair/index.js +0 -0
  409. /package/{cli/dist → dist}/core/repair/repairer.d.ts +0 -0
  410. /package/{cli/dist → dist}/core/repair/repairer.js +0 -0
  411. /package/{cli/dist → dist}/core/repair/types.d.ts +0 -0
  412. /package/{cli/dist → dist}/core/repair/types.js +0 -0
  413. /package/{cli/dist → dist}/core/repair/utils/error-analyzer.d.ts +0 -0
  414. /package/{cli/dist → dist}/core/repair/utils/error-analyzer.js +0 -0
  415. /package/{cli/dist → dist}/core/reporting/html-reporter.d.ts +0 -0
  416. /package/{cli/dist → dist}/core/reporting/html-reporter.js +0 -0
  417. /package/{cli/dist → dist}/core/retry/flakiness-integration.d.ts +0 -0
  418. /package/{cli/dist → dist}/core/retry/flakiness-integration.js +0 -0
  419. /package/{cli/dist → dist}/core/retry/index.d.ts +0 -0
  420. /package/{cli/dist → dist}/core/retry/index.js +0 -0
  421. /package/{cli/dist → dist}/core/retry/retry-engine.d.ts +0 -0
  422. /package/{cli/dist → dist}/core/retry/retry-engine.js +0 -0
  423. /package/{cli/dist → dist}/core/retry/types.d.ts +0 -0
  424. /package/{cli/dist → dist}/core/retry/types.js +0 -0
  425. /package/{cli/dist → dist}/core/retry/vault.d.ts +0 -0
  426. /package/{cli/dist → dist}/core/retry/vault.js +0 -0
  427. /package/{cli/dist → dist}/core/schemas/pack.schema.json +0 -0
  428. /package/{cli/dist → dist}/core/secrets/crypto.d.ts +0 -0
  429. /package/{cli/dist → dist}/core/secrets/crypto.js +0 -0
  430. /package/{cli/dist → dist}/core/secrets/manager.d.ts +0 -0
  431. /package/{cli/dist → dist}/core/secrets/manager.js +0 -0
  432. /package/{cli/dist → dist}/core/security/redaction-patterns-extended.d.ts +0 -0
  433. /package/{cli/dist → dist}/core/security/redaction-patterns-extended.js +0 -0
  434. /package/{cli/dist → dist}/core/security/redactor.d.ts +0 -0
  435. /package/{cli/dist → dist}/core/security/redactor.js +0 -0
  436. /package/{cli/dist → dist}/core/self-healing/assertion-healer.d.ts +0 -0
  437. /package/{cli/dist → dist}/core/self-healing/assertion-healer.js +0 -0
  438. /package/{cli/dist → dist}/core/self-healing/engine.d.ts +0 -0
  439. /package/{cli/dist → dist}/core/self-healing/engine.js +0 -0
  440. /package/{cli/dist → dist}/core/self-healing/index.d.ts +0 -0
  441. /package/{cli/dist → dist}/core/self-healing/index.js +0 -0
  442. /package/{cli/dist → dist}/core/self-healing/selector-healer.d.ts +0 -0
  443. /package/{cli/dist → dist}/core/self-healing/selector-healer.js +0 -0
  444. /package/{cli/dist → dist}/core/self-healing/types.d.ts +0 -0
  445. /package/{cli/dist → dist}/core/self-healing/types.js +0 -0
  446. /package/{cli/dist → dist}/core/serve/diagnostics-collector.d.ts +0 -0
  447. /package/{cli/dist → dist}/core/serve/diagnostics-collector.js +0 -0
  448. /package/{cli/dist → dist}/core/serve/health-checker.d.ts +0 -0
  449. /package/{cli/dist → dist}/core/serve/health-checker.js +0 -0
  450. /package/{cli/dist → dist}/core/serve/index.d.ts +0 -0
  451. /package/{cli/dist → dist}/core/serve/index.js +0 -0
  452. /package/{cli/dist → dist}/core/serve/metrics-collector.d.ts +0 -0
  453. /package/{cli/dist → dist}/core/serve/metrics-collector.js +0 -0
  454. /package/{cli/dist → dist}/core/serve/process-manager.d.ts +0 -0
  455. /package/{cli/dist → dist}/core/serve/process-manager.js +0 -0
  456. /package/{cli/dist → dist}/core/serve/server.d.ts +0 -0
  457. /package/{cli/dist → dist}/core/serve/server.js +0 -0
  458. /package/{cli/dist → dist}/core/slo/config.d.ts +0 -0
  459. /package/{cli/dist → dist}/core/slo/config.js +0 -0
  460. /package/{cli/dist → dist}/core/slo/index.d.ts +0 -0
  461. /package/{cli/dist → dist}/core/slo/index.js +0 -0
  462. /package/{cli/dist → dist}/core/slo/sli-calculator.d.ts +0 -0
  463. /package/{cli/dist → dist}/core/slo/sli-calculator.js +0 -0
  464. /package/{cli/dist → dist}/core/slo/slo-tracker.d.ts +0 -0
  465. /package/{cli/dist → dist}/core/slo/slo-tracker.js +0 -0
  466. /package/{cli/dist → dist}/core/slo/types.d.ts +0 -0
  467. /package/{cli/dist → dist}/core/slo/types.js +0 -0
  468. /package/{cli/dist → dist}/core/slo/vault.d.ts +0 -0
  469. /package/{cli/dist → dist}/core/slo/vault.js +0 -0
  470. /package/{cli/dist → dist}/core/tui/index.d.ts +0 -0
  471. /package/{cli/dist → dist}/core/tui/index.js +0 -0
  472. /package/{cli/dist → dist}/core/tui/monitor.d.ts +0 -0
  473. /package/{cli/dist → dist}/core/tui/monitor.js +0 -0
  474. /package/{cli/dist → dist}/core/tui/renderer.d.ts +0 -0
  475. /package/{cli/dist → dist}/core/tui/renderer.js +0 -0
  476. /package/{cli/dist → dist}/core/tui/types.d.ts +0 -0
  477. /package/{cli/dist → dist}/core/tui/types.js +0 -0
  478. /package/{cli/dist → dist}/core/types/pack-v1.js +0 -0
  479. /package/{cli/dist → dist}/core/types/pack-v2.js +0 -0
  480. /package/{cli/dist → dist}/core/types/trust-score.d.ts +0 -0
  481. /package/{cli/dist → dist}/core/types/trust-score.js +0 -0
  482. /package/{cli/dist → dist}/core/vault/cas.d.ts +0 -0
  483. /package/{cli/dist → dist}/core/vault/cas.js +0 -0
  484. /package/{cli/dist → dist}/core/vault/index.d.ts +0 -0
  485. /package/{cli/dist → dist}/core/vault/index.js +0 -0
  486. /package/{cli/dist → dist}/core/visual/visual-regression.d.ts +0 -0
  487. /package/{cli/dist → dist}/core/visual/visual-regression.js +0 -0
  488. /package/{cli/dist → dist}/core/watch/index.d.ts +0 -0
  489. /package/{cli/dist → dist}/core/watch/index.js +0 -0
  490. /package/{cli/dist → dist}/core/watch/watch-mode.d.ts +0 -0
  491. /package/{cli/dist → dist}/core/watch/watch-mode.js +0 -0
  492. /package/{cli/dist → dist}/generators/index.d.ts +0 -0
  493. /package/{cli/dist → dist}/generators/index.js +0 -0
  494. /package/{cli/dist → dist}/generators/json-reporter.d.ts +0 -0
  495. /package/{cli/dist → dist}/generators/json-reporter.js +0 -0
  496. /package/{cli/dist → dist}/generators/test-generator.d.ts +0 -0
  497. /package/{cli/dist → dist}/generators/test-generator.js +0 -0
  498. /package/{cli/dist → dist}/index.d.ts +0 -0
  499. /package/{cli/dist → dist}/index.js +0 -0
  500. /package/{cli/dist → dist}/scanners/dom-scanner.d.ts +0 -0
  501. /package/{cli/dist → dist}/scanners/dom-scanner.js +0 -0
  502. /package/{cli/dist → dist}/scanners/index.d.ts +0 -0
  503. /package/{cli/dist → dist}/scanners/index.js +0 -0
  504. /package/{cli/dist → dist}/schemas/pack.schema.json +0 -0
  505. /package/{cli/dist → dist}/types/scan.d.ts +0 -0
  506. /package/{cli/dist → dist}/types/scan.js +0 -0
  507. /package/{cli/dist → dist}/utils/config.js +0 -0
@@ -0,0 +1,636 @@
1
+ /**
2
+ * QA360 OAuth Handler
3
+ *
4
+ * P0 Features: OAuth2/OIDC flow testing support
5
+ * - Authorization Code flow with PKCE
6
+ * - Implicit flow (legacy) - P1
7
+ * - Client Credentials flow
8
+ * - Refresh Token flow
9
+ * - Token storage and management
10
+ * - OpenID Connect support - P1
11
+ *
12
+ * Supports testing against:
13
+ * - Real OAuth providers (Google, GitHub, Auth0, etc.)
14
+ * - Mock OAuth servers for development
15
+ */
16
+ import { createHash, randomBytes } from 'crypto';
17
+ /**
18
+ * OAuth Handler class
19
+ */
20
+ export class OAuthHandler {
21
+ context;
22
+ config;
23
+ accessToken = null;
24
+ refreshToken = null;
25
+ codeVerifier = null;
26
+ generatedState = null;
27
+ constructor(context, config) {
28
+ this.context = context;
29
+ this.config = config;
30
+ }
31
+ /**
32
+ * Generate random string for PKCE code verifier and state
33
+ * Uses cryptographically secure random bytes
34
+ */
35
+ generateRandomString(length = 32) {
36
+ const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~';
37
+ // Generate random bytes and map to character set
38
+ const randomValues = randomBytes(length);
39
+ let result = '';
40
+ for (let i = 0; i < length; i++) {
41
+ result += chars.charAt(randomValues[i] % chars.length);
42
+ }
43
+ return result;
44
+ }
45
+ /**
46
+ * Generate code challenge for PKCE
47
+ * Uses SHA256 to create challenge from verifier
48
+ */
49
+ generateCodeChallenge(verifier) {
50
+ // SHA-256 hash the verifier using Node.js crypto
51
+ const hash = createHash('sha256').update(verifier).digest('base64url');
52
+ return hash;
53
+ }
54
+ /**
55
+ * Build authorization URL
56
+ * P0: Construct the OAuth authorization URL with all required parameters
57
+ */
58
+ buildAuthorizationURL(options) {
59
+ const config = this.config;
60
+ const scope = typeof config.scope === 'string' ? config.scope : config.scope?.join(' ');
61
+ const state = options?.state || config.state || this.generateRandomString(32);
62
+ // Store state for verification
63
+ this.generatedState = state;
64
+ const params = new URLSearchParams({
65
+ response_type: config.responseType || 'code',
66
+ client_id: config.clientId,
67
+ redirect_uri: config.redirectUri,
68
+ scope: scope || '',
69
+ state,
70
+ });
71
+ // Add PKCE code challenge if using PKCE
72
+ if (config.usePKCE && options?.codeChallenge) {
73
+ params.append('code_challenge', options.codeChallenge);
74
+ params.append('code_challenge_method', 'S256');
75
+ }
76
+ return `${config.authEndpoint}?${params.toString()}`;
77
+ }
78
+ /**
79
+ * Start Authorization Code flow with PKCE
80
+ * P0: Begin OAuth login flow
81
+ *
82
+ * @returns Authorization URL to navigate user to
83
+ */
84
+ async startAuthorizationFlow() {
85
+ const verifier = this.generateRandomString(64);
86
+ this.codeVerifier = verifier;
87
+ const state = this.generateRandomString(32);
88
+ this.generatedState = state;
89
+ const challenge = this.generateCodeChallenge(verifier);
90
+ const authUrl = this.buildAuthorizationURL({ state, codeChallenge: challenge });
91
+ return {
92
+ authUrl,
93
+ verifier,
94
+ state,
95
+ };
96
+ }
97
+ /**
98
+ * Wait for OAuth callback
99
+ * P0: Wait for redirect to redirect_uri with code or error
100
+ *
101
+ * @returns Promise that resolves when callback is received
102
+ */
103
+ async waitForCallback(page, timeout = 60000) {
104
+ const redirectUri = new URL(this.config.redirectUri).pathname;
105
+ try {
106
+ // Wait for navigation to redirect URI
107
+ await page.waitForURL(`**${redirectUri}*`, { timeout });
108
+ // Get the URL parameters
109
+ const url = page.url();
110
+ const params = new URLSearchParams(url.split('?')[1] || '');
111
+ const code = params.get('code');
112
+ const error = params.get('error');
113
+ const errorDescription = params.get('error_description');
114
+ const state = params.get('state');
115
+ // Verify state if one was generated
116
+ if (this.generatedState && state !== this.generatedState) {
117
+ return {
118
+ success: false,
119
+ error: { error: 'invalid_state', error_description: 'State mismatch', state: state || undefined },
120
+ };
121
+ }
122
+ if (error) {
123
+ return {
124
+ success: false,
125
+ error: {
126
+ error,
127
+ error_description: errorDescription || undefined,
128
+ state: state || undefined,
129
+ },
130
+ };
131
+ }
132
+ return {
133
+ success: true,
134
+ code: code || undefined,
135
+ state: state || undefined,
136
+ };
137
+ }
138
+ catch (e) {
139
+ return {
140
+ success: false,
141
+ error: { error: 'timeout', error_description: 'Callback timeout' },
142
+ };
143
+ }
144
+ }
145
+ /**
146
+ * Exchange authorization code for tokens
147
+ * P0: Token exchange endpoint call
148
+ */
149
+ async exchangeCodeForToken(code) {
150
+ const config = this.config;
151
+ const body = new URLSearchParams({
152
+ grant_type: 'authorization_code',
153
+ code,
154
+ redirect_uri: config.redirectUri,
155
+ client_id: config.clientId,
156
+ });
157
+ // Add client secret if provided (confidential clients)
158
+ if (config.clientSecret) {
159
+ body.append('client_secret', config.clientSecret);
160
+ }
161
+ // Add PKCE code verifier if using PKCE
162
+ if (config.usePKCE && this.codeVerifier) {
163
+ body.append('code_verifier', this.codeVerifier);
164
+ }
165
+ // Make token request
166
+ const response = await this.context.request.post(config.tokenEndpoint, {
167
+ data: body.toString(),
168
+ headers: {
169
+ 'Content-Type': 'application/x-www-form-urlencoded',
170
+ },
171
+ });
172
+ if (!response.ok()) {
173
+ throw new Error(`Token request failed: ${response.status()} ${response.statusText()}`);
174
+ }
175
+ const token = await response.json();
176
+ // Store tokens
177
+ this.accessToken = token.access_token;
178
+ if (token.refresh_token) {
179
+ this.refreshToken = token.refresh_token;
180
+ }
181
+ return token;
182
+ }
183
+ /**
184
+ * Client Credentials flow
185
+ * P1: Server-to-server authentication without user interaction
186
+ * Used for machine-to-machine communication (service accounts, daemons, etc.)
187
+ *
188
+ * @returns OAuth token response (no refresh token in this flow)
189
+ */
190
+ async clientCredentials() {
191
+ const config = this.config;
192
+ if (!config.clientSecret) {
193
+ throw new Error('Client secret is required for Client Credentials flow');
194
+ }
195
+ const scope = typeof config.scope === 'string' ? config.scope : config.scope?.join(' ');
196
+ const body = new URLSearchParams({
197
+ grant_type: 'client_credentials',
198
+ client_id: config.clientId,
199
+ client_secret: config.clientSecret,
200
+ });
201
+ if (scope) {
202
+ body.append('scope', scope);
203
+ }
204
+ const response = await this.context.request.post(config.tokenEndpoint, {
205
+ data: body.toString(),
206
+ headers: {
207
+ 'Content-Type': 'application/x-www-form-urlencoded',
208
+ },
209
+ });
210
+ if (!response.ok()) {
211
+ const errorText = await response.text().catch(() => 'Unknown error');
212
+ throw new Error(`Client Credentials request failed: ${response.status()} ${response.statusText()} - ${errorText}`);
213
+ }
214
+ const token = await response.json();
215
+ // Store access token (no refresh token in Client Credentials flow)
216
+ this.accessToken = token.access_token;
217
+ return token;
218
+ }
219
+ /**
220
+ * Refresh access token
221
+ * P0: Use refresh token to get new access token
222
+ */
223
+ async refreshAccessToken() {
224
+ if (!this.refreshToken) {
225
+ throw new Error('No refresh token available');
226
+ }
227
+ const config = this.config;
228
+ const body = new URLSearchParams({
229
+ grant_type: 'refresh_token',
230
+ refresh_token: this.refreshToken,
231
+ client_id: config.clientId,
232
+ });
233
+ if (config.clientSecret) {
234
+ body.append('client_secret', config.clientSecret);
235
+ }
236
+ const response = await this.context.request.post(config.tokenEndpoint, {
237
+ data: body.toString(),
238
+ headers: {
239
+ 'Content-Type': 'application/x-www-form-urlencoded',
240
+ },
241
+ });
242
+ if (!response.ok()) {
243
+ throw new Error(`Token refresh failed: ${response.status()} ${response.statusText()}`);
244
+ }
245
+ const token = await response.json();
246
+ // Update tokens
247
+ this.accessToken = token.access_token;
248
+ if (token.refresh_token) {
249
+ this.refreshToken = token.refresh_token;
250
+ }
251
+ return token;
252
+ }
253
+ /**
254
+ * Get current access token
255
+ */
256
+ getAccessToken() {
257
+ return this.accessToken;
258
+ }
259
+ /**
260
+ * Get refresh token
261
+ */
262
+ getRefreshToken() {
263
+ return this.refreshToken;
264
+ }
265
+ /**
266
+ * Set tokens manually (useful for testing)
267
+ */
268
+ setTokens(tokens) {
269
+ this.accessToken = tokens.accessToken;
270
+ this.refreshToken = tokens.refreshToken || null;
271
+ }
272
+ /**
273
+ * Clear all stored tokens
274
+ */
275
+ clearTokens() {
276
+ this.accessToken = null;
277
+ this.refreshToken = null;
278
+ this.codeVerifier = null;
279
+ this.generatedState = null;
280
+ }
281
+ /**
282
+ * Full Authorization Code flow with PKCE
283
+ * P0: Complete OAuth flow from start to token exchange
284
+ *
285
+ * @param page - Playwright page instance
286
+ * @param userInteraction - Optional function to handle user login
287
+ * @returns OAuth token response
288
+ */
289
+ async completeFlow(page, userInteraction) {
290
+ // Start flow
291
+ const { authUrl, verifier, state } = await this.startAuthorizationFlow();
292
+ // Navigate to auth URL or call user interaction handler
293
+ if (userInteraction) {
294
+ await userInteraction(page, authUrl);
295
+ }
296
+ else {
297
+ await page.goto(authUrl);
298
+ }
299
+ // Wait for callback
300
+ const callback = await this.waitForCallback(page);
301
+ if (!callback.success || !callback.code) {
302
+ throw new Error(`OAuth flow failed: ${callback.error?.error || 'unknown'}`);
303
+ }
304
+ // Exchange code for token
305
+ return await this.exchangeCodeForToken(callback.code);
306
+ }
307
+ /**
308
+ * Set authorization header with Bearer token
309
+ * P0: Helper to set Authorization header for API requests
310
+ */
311
+ async setAuthHeader(page) {
312
+ if (!this.accessToken) {
313
+ throw new Error('No access token available. Call completeFlow() first.');
314
+ }
315
+ await page.setExtraHTTPHeaders({
316
+ Authorization: `Bearer ${this.accessToken}`,
317
+ });
318
+ }
319
+ /**
320
+ * P1: Implicit Flow (legacy OAuth2)
321
+ * Token is returned directly in URL fragment after redirect
322
+ *
323
+ * Note: Implicit flow is deprecated in OAuth 2.1. Use Authorization Code with PKCE instead.
324
+ * This method is provided for testing legacy applications.
325
+ *
326
+ * @param page - Playwright page instance
327
+ * @param userInteraction - Optional function to handle user login
328
+ * @returns Implicit flow result with access token from URL fragment
329
+ */
330
+ async implicitFlow(page, userInteraction) {
331
+ // Set response type to token for implicit flow
332
+ const originalResponseType = this.config.responseType;
333
+ this.config.responseType = 'token';
334
+ const state = this.generateRandomString(32);
335
+ this.generatedState = state;
336
+ const authUrl = this.buildAuthorizationURL({ state });
337
+ // Navigate to auth URL or call user interaction handler
338
+ if (userInteraction) {
339
+ await userInteraction(page, authUrl);
340
+ }
341
+ else {
342
+ await page.goto(authUrl);
343
+ }
344
+ // Wait for callback with token in fragment
345
+ const result = await this.waitForImplicitCallback(page);
346
+ // Restore original response type
347
+ this.config.responseType = originalResponseType;
348
+ if (result.success && result.accessToken) {
349
+ this.accessToken = result.accessToken;
350
+ }
351
+ return result;
352
+ }
353
+ /**
354
+ * P1: Wait for Implicit Flow callback
355
+ * Extracts token from URL fragment (hash)
356
+ */
357
+ async waitForImplicitCallback(page, timeout = 60000) {
358
+ const redirectUri = new URL(this.config.redirectUri).pathname;
359
+ try {
360
+ // Wait for navigation to redirect URI
361
+ await page.waitForURL(`**${redirectUri}*`, { timeout });
362
+ // Get URL fragment (hash) - tokens are in fragment for implicit flow
363
+ const fragment = await page.evaluate(() => window.location.hash.substring(1));
364
+ if (!fragment) {
365
+ // Also check query params for error
366
+ const url = page.url();
367
+ const params = new URLSearchParams(url.split('?')[1] || '');
368
+ const error = params.get('error');
369
+ const errorDescription = params.get('error_description');
370
+ const state = params.get('state');
371
+ return {
372
+ success: false,
373
+ error: {
374
+ error: error || 'no_fragment',
375
+ error_description: errorDescription || 'No fragment in callback URL',
376
+ state: state || undefined,
377
+ },
378
+ };
379
+ }
380
+ // Parse fragment parameters
381
+ const params = new URLSearchParams(fragment);
382
+ const accessToken = params.get('access_token');
383
+ const idToken = params.get('id_token');
384
+ const tokenType = params.get('token_type');
385
+ const expiresIn = params.get('expires_in');
386
+ const state = params.get('state');
387
+ const error = params.get('error');
388
+ const errorDescription = params.get('error_description');
389
+ // Verify state
390
+ if (this.generatedState && state !== this.generatedState) {
391
+ return {
392
+ success: false,
393
+ error: { error: 'invalid_state', error_description: 'State mismatch', state: state || undefined },
394
+ };
395
+ }
396
+ if (error) {
397
+ return {
398
+ success: false,
399
+ error: {
400
+ error,
401
+ error_description: errorDescription || undefined,
402
+ state: state || undefined,
403
+ },
404
+ };
405
+ }
406
+ return {
407
+ success: true,
408
+ accessToken: accessToken || undefined,
409
+ idToken: idToken || undefined,
410
+ tokenType: tokenType || undefined,
411
+ expires_in: expiresIn || undefined,
412
+ state: state || undefined,
413
+ };
414
+ }
415
+ catch (e) {
416
+ return {
417
+ success: false,
418
+ error: { error: 'timeout', error_description: 'Callback timeout' },
419
+ };
420
+ }
421
+ }
422
+ /**
423
+ * P1: OpenID Connect - Parse and validate ID token
424
+ *
425
+ * @param idToken - JWT ID token from OAuth response
426
+ * @returns Parsed OIDC claims
427
+ */
428
+ async parseIDToken(idToken) {
429
+ try {
430
+ // Split JWT into parts
431
+ const parts = idToken.split('.');
432
+ if (parts.length !== 3) {
433
+ throw new Error('Invalid ID token format');
434
+ }
435
+ // Decode payload (base64url)
436
+ const payload = parts[1];
437
+ // Add padding if needed
438
+ const paddedPayload = payload + '='.repeat((4 - payload.length % 4) % 4);
439
+ const decoded = Buffer.from(paddedPayload, 'base64url').toString('utf-8');
440
+ const claims = JSON.parse(decoded);
441
+ // Validate basic claims
442
+ if (!claims.iss || !claims.sub || !claims.aud || !claims.exp || !claims.iat) {
443
+ throw new Error('ID token missing required claims');
444
+ }
445
+ // Validate expiration
446
+ const now = Math.floor(Date.now() / 1000);
447
+ if (claims.exp < now) {
448
+ throw new Error('ID token has expired');
449
+ }
450
+ // Validate issuer if configured
451
+ const expectedIssuer = this.config.oidc?.expectedIssuer || this.config.oidc?.issuer;
452
+ if (expectedIssuer && claims.iss !== expectedIssuer) {
453
+ throw new Error(`ID token issuer mismatch: expected ${expectedIssuer}, got ${claims.iss}`);
454
+ }
455
+ // Validate audience if configured
456
+ const expectedAudience = this.config.oidc?.expectedAudience || this.config.clientId;
457
+ if (expectedAudience) {
458
+ const audiences = Array.isArray(claims.aud) ? claims.aud : [claims.aud];
459
+ if (!audiences.includes(expectedAudience) && !audiences.includes(this.config.clientId)) {
460
+ throw new Error(`ID token audience mismatch: expected ${expectedAudience}, got ${claims.aud}`);
461
+ }
462
+ }
463
+ return claims;
464
+ }
465
+ catch (e) {
466
+ throw new Error(`Failed to parse ID token: ${e instanceof Error ? e.message : 'unknown error'}`);
467
+ }
468
+ }
469
+ /**
470
+ * P1: OpenID Connect - Fetch UserInfo from endpoint
471
+ *
472
+ * @param accessToken - Access token for authorization
473
+ * @returns UserInfo response
474
+ */
475
+ async fetchUserInfo(accessToken) {
476
+ const userInfoEndpoint = this.config.oidc?.userInfoEndpoint;
477
+ if (!userInfoEndpoint) {
478
+ throw new Error('UserInfo endpoint not configured');
479
+ }
480
+ const response = await this.context.request.get(userInfoEndpoint, {
481
+ headers: {
482
+ Authorization: `Bearer ${accessToken}`,
483
+ },
484
+ });
485
+ if (!response.ok()) {
486
+ throw new Error(`UserInfo request failed: ${response.status()} ${response.statusText()}`);
487
+ }
488
+ return await response.json();
489
+ }
490
+ /**
491
+ * P1: OpenID Connect - Complete OIDC flow
492
+ * Performs Authorization Code flow and fetches UserInfo
493
+ *
494
+ * @param page - Playwright page instance
495
+ * @param userInteraction - Optional function to handle user login
496
+ * @returns OAuth token + parsed ID token claims + UserInfo
497
+ */
498
+ async completeOIDCFlow(page, userInteraction) {
499
+ // Ensure OpenID scope is included
500
+ const scopes = typeof this.config.scope === 'string'
501
+ ? this.config.scope.split(' ')
502
+ : this.config.scope || [];
503
+ if (!scopes.includes('openid')) {
504
+ scopes.push('openid');
505
+ this.config.scope = scopes.join(' ');
506
+ }
507
+ // Complete standard OAuth flow
508
+ const token = await this.completeFlow(page, userInteraction);
509
+ const result = { token };
510
+ // Parse ID token if present
511
+ if (token.id_token) {
512
+ try {
513
+ result.idTokenClaims = await this.parseIDToken(token.id_token);
514
+ }
515
+ catch (e) {
516
+ console.warn('Failed to parse ID token:', e);
517
+ }
518
+ }
519
+ // Fetch UserInfo if access token available
520
+ if (token.access_token && this.config.oidc?.userInfoEndpoint) {
521
+ try {
522
+ result.userInfo = await this.fetchUserInfo(token.access_token);
523
+ }
524
+ catch (e) {
525
+ console.warn('Failed to fetch UserInfo:', e);
526
+ }
527
+ }
528
+ return result;
529
+ }
530
+ /**
531
+ * P1: Validate ID token signature (basic validation)
532
+ * For full signature validation, you need the JWKS and crypto verification
533
+ *
534
+ * @param idToken - JWT ID token to validate
535
+ * @returns Validation result with claims if valid
536
+ */
537
+ async validateIDToken(idToken) {
538
+ try {
539
+ const claims = await this.parseIDToken(idToken);
540
+ // Note: Full signature validation requires JWKS and crypto verification
541
+ // This is a basic implementation that validates structure and timestamps
542
+ // For production use, implement full JWT signature verification with JWKS
543
+ return {
544
+ valid: true,
545
+ claims,
546
+ };
547
+ }
548
+ catch (e) {
549
+ return {
550
+ valid: false,
551
+ error: e instanceof Error ? e.message : 'Unknown validation error',
552
+ };
553
+ }
554
+ }
555
+ }
556
+ /**
557
+ * Mock OAuth Server for testing
558
+ * Simulates OAuth endpoints for development/testing
559
+ */
560
+ export class MockOAuthServer {
561
+ baseUrl;
562
+ authorizedCodes = new Map();
563
+ constructor(baseUrl = 'http://localhost:3001') {
564
+ this.baseUrl = baseUrl;
565
+ }
566
+ /**
567
+ * Get authorization endpoint URL
568
+ */
569
+ getAuthEndpoint() {
570
+ return `${this.baseUrl}/authorize`;
571
+ }
572
+ /**
573
+ * Get token endpoint URL
574
+ */
575
+ getTokenEndpoint() {
576
+ return `${this.baseUrl}/token`;
577
+ }
578
+ /**
579
+ * Generate a mock access token
580
+ */
581
+ generateMockToken(expiresIn = 3600) {
582
+ return {
583
+ access_token: `mock_token_${Date.now()}_${Math.random().toString(36).substring(7)}`,
584
+ token_type: 'Bearer',
585
+ expires_in: expiresIn,
586
+ refresh_token: `mock_refresh_${Date.now()}_${Math.random().toString(36).substring(7)}`,
587
+ scope: 'openid profile email',
588
+ };
589
+ }
590
+ /**
591
+ * Create a mock authorization code
592
+ * Stores code-to-token mapping for later exchange
593
+ */
594
+ createAuthorizationCode() {
595
+ const code = `mock_auth_code_${Date.now()}_${Math.random().toString(36).substring(7)}`;
596
+ const token = this.generateMockToken();
597
+ this.authorizedCodes.set(code, token);
598
+ return { code, token };
599
+ }
600
+ /**
601
+ * Validate and redeem authorization code
602
+ */
603
+ redeemCode(code) {
604
+ const token = this.authorizedCodes.get(code);
605
+ if (token) {
606
+ this.authorizedCodes.delete(code); // One-time use
607
+ return token;
608
+ }
609
+ return null;
610
+ }
611
+ /**
612
+ * Get OAuth config for mock server
613
+ */
614
+ getOAuthConfig(clientId = 'mock-client-id', redirectUri = 'http://localhost:3000/callback') {
615
+ return {
616
+ authEndpoint: this.getAuthEndpoint(),
617
+ tokenEndpoint: this.getTokenEndpoint(),
618
+ clientId,
619
+ redirectUri,
620
+ responseType: 'code',
621
+ usePKCE: true,
622
+ };
623
+ }
624
+ }
625
+ /**
626
+ * Convenience function to create OAuth handler
627
+ */
628
+ export function createOAuthHandler(context, config) {
629
+ return new OAuthHandler(context, config);
630
+ }
631
+ /**
632
+ * Convenience function to create mock OAuth server
633
+ */
634
+ export function createMockOAuthServer(baseUrl) {
635
+ return new MockOAuthServer(baseUrl);
636
+ }
@@ -5,12 +5,21 @@
5
5
  * - Client credentials grant
6
6
  * - Password grant (resource owner)
7
7
  * - Authorization code grant (requires pre-issued code)
8
+ *
9
+ * P0: Refresh token support for automatic token renewal
8
10
  */
9
11
  import { AuthProvider, AuthResult, OAuth2AuthConfig } from './index.js';
10
12
  export declare class OAuth2Provider implements AuthProvider<OAuth2AuthConfig> {
11
13
  readonly type: "oauth2";
12
14
  authenticate(config: OAuth2AuthConfig): Promise<AuthResult>;
15
+ /**
16
+ * P0: Refresh OAuth2 access token using refresh token
17
+ */
13
18
  refresh(config: OAuth2AuthConfig): Promise<AuthResult>;
19
+ /**
20
+ * P0: Perform refresh token flow
21
+ */
22
+ private performRefresh;
14
23
  clear(config: OAuth2AuthConfig): Promise<void>;
15
24
  validate(config: OAuth2AuthConfig): Promise<boolean>;
16
25
  private getCacheKey;