qa360 2.3.0 → 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.
- package/README.md +155 -262
- package/{cli/dist → dist}/commands/ai.js +1 -1
- package/{cli/dist → dist}/commands/coverage.js +1 -1
- package/{cli/dist → dist}/commands/crawl.js +2 -2
- package/{cli/dist → dist}/commands/doctor.js +2 -2
- package/{cli/dist → dist}/commands/explain.js +2 -2
- package/{cli/dist → dist}/commands/flakiness.js +1 -1
- package/{cli/dist → dist}/commands/generate.js +1 -1
- package/{cli/dist → dist}/commands/history.js +1 -1
- package/{cli/dist → dist}/commands/monitor.js +3 -3
- package/{cli/dist → dist}/commands/ollama.js +1 -1
- package/{cli/dist → dist}/commands/pack.js +2 -2
- package/{cli/dist → dist}/commands/regression.js +1 -1
- package/{cli/dist → dist}/commands/repair.js +1 -1
- package/{cli/dist → dist}/commands/retry.js +1 -1
- package/{cli/dist → dist}/commands/run.d.ts +1 -1
- package/{cli/dist → dist}/commands/run.js +1 -1
- package/{cli/dist → dist}/commands/secrets.js +1 -1
- package/{cli/dist → dist}/commands/serve.js +1 -1
- package/{cli/dist → dist}/commands/slo.js +1 -1
- package/{cli/dist → dist}/commands/verify.js +1 -1
- package/{cli/dist → dist}/core/adapters/playwright-native-api.d.ts +2 -0
- package/{cli/dist → dist}/core/adapters/playwright-native-api.js +20 -1
- package/{cli/dist → dist}/core/adapters/playwright-ui.d.ts +21 -0
- package/dist/core/adapters/playwright-ui.js +2050 -0
- package/{cli/dist → dist}/core/ai/ollama-provider.js +15 -3
- package/{cli/dist → dist}/core/artifacts/ui-artifacts.js +24 -4
- package/dist/core/auth/backup-codes-provider.d.ts +91 -0
- package/dist/core/auth/backup-codes-provider.js +215 -0
- package/{cli/dist → dist}/core/auth/basic-auth-provider.d.ts +6 -0
- package/{cli/dist → dist}/core/auth/basic-auth-provider.js +24 -6
- package/dist/core/auth/digest-auth-provider.d.ts +116 -0
- package/dist/core/auth/digest-auth-provider.js +244 -0
- package/dist/core/auth/hcaptcha-handler.d.ts +103 -0
- package/dist/core/auth/hcaptcha-handler.js +288 -0
- package/{cli/dist → dist}/core/auth/index.d.ts +81 -4
- package/{cli/dist → dist}/core/auth/index.js +15 -1
- package/dist/core/auth/oauth-handler.d.ts +408 -0
- package/dist/core/auth/oauth-handler.js +636 -0
- package/{cli/dist → dist}/core/auth/oauth2-provider.d.ts +9 -0
- package/dist/core/auth/oauth2-provider.js +227 -0
- package/dist/core/auth/otp-provider.d.ts +93 -0
- package/dist/core/auth/otp-provider.js +288 -0
- package/dist/core/auth/recaptcha-handler.d.ts +119 -0
- package/dist/core/auth/recaptcha-handler.js +301 -0
- package/dist/core/auth/remember-me-handler.d.ts +142 -0
- package/dist/core/auth/remember-me-handler.js +255 -0
- package/dist/core/auth/saml-handler.d.ts +173 -0
- package/dist/core/auth/saml-handler.js +364 -0
- package/dist/core/auth/webauthn-handler.d.ts +182 -0
- package/dist/core/auth/webauthn-handler.js +310 -0
- package/dist/core/crawler/advanced-interactions.d.ts +342 -0
- package/dist/core/crawler/advanced-interactions.js +1069 -0
- package/dist/core/crawler/blob-url-download-handler.d.ts +145 -0
- package/dist/core/crawler/blob-url-download-handler.js +392 -0
- package/dist/core/crawler/consent-handler.d.ts +49 -0
- package/dist/core/crawler/consent-handler.js +258 -0
- package/dist/core/crawler/cookie-manager.d.ts +166 -0
- package/dist/core/crawler/cookie-manager.js +353 -0
- package/dist/core/crawler/coop-coep-handler.d.ts +136 -0
- package/dist/core/crawler/coop-coep-handler.js +338 -0
- package/dist/core/crawler/csp-handler.d.ts +151 -0
- package/dist/core/crawler/csp-handler.js +415 -0
- package/dist/core/crawler/download-handler.d.ts +155 -0
- package/dist/core/crawler/download-handler.js +370 -0
- package/dist/core/crawler/email-testing-handler.d.ts +214 -0
- package/dist/core/crawler/email-testing-handler.js +398 -0
- package/dist/core/crawler/error-tracking-handler.d.ts +177 -0
- package/dist/core/crawler/error-tracking-handler.js +378 -0
- package/dist/core/crawler/form-handler.d.ts +100 -0
- package/dist/core/crawler/form-handler.js +465 -0
- package/dist/core/crawler/framework-wait-handler.d.ts +96 -0
- package/dist/core/crawler/framework-wait-handler.js +464 -0
- package/dist/core/crawler/geolocation-handler.d.ts +112 -0
- package/dist/core/crawler/geolocation-handler.js +276 -0
- package/dist/core/crawler/index.d.ts +78 -0
- package/{cli/dist → dist}/core/crawler/index.js +74 -1
- package/dist/core/crawler/intelligent-selector-generator.d.ts +164 -0
- package/dist/core/crawler/intelligent-selector-generator.js +612 -0
- package/{cli/dist → dist}/core/crawler/journey-generator.js +44 -1
- package/{cli/dist → dist}/core/crawler/page-analyzer.d.ts +16 -1
- package/{cli/dist → dist}/core/crawler/page-analyzer.js +469 -17
- package/dist/core/crawler/permissions-handler.d.ts +112 -0
- package/dist/core/crawler/permissions-handler.js +236 -0
- package/dist/core/crawler/permissions-policy-handler.d.ts +113 -0
- package/dist/core/crawler/permissions-policy-handler.js +402 -0
- package/dist/core/crawler/presets.d.ts +100 -0
- package/dist/core/crawler/presets.js +887 -0
- package/dist/core/crawler/repl-debug-handler.d.ts +105 -0
- package/dist/core/crawler/repl-debug-handler.js +552 -0
- package/dist/core/crawler/reporting-api-handler.d.ts +212 -0
- package/dist/core/crawler/reporting-api-handler.js +344 -0
- package/{cli/dist → dist}/core/crawler/selector-generator.d.ts +9 -0
- package/{cli/dist → dist}/core/crawler/selector-generator.js +99 -23
- package/dist/core/crawler/site-profiler.d.ts +89 -0
- package/dist/core/crawler/site-profiler.js +290 -0
- package/dist/core/crawler/sourcemaps-handler.d.ts +144 -0
- package/dist/core/crawler/sourcemaps-handler.js +420 -0
- package/dist/core/crawler/stacked-modals-handler.d.ts +118 -0
- package/dist/core/crawler/stacked-modals-handler.js +429 -0
- package/dist/core/crawler/trusted-types-handler.d.ts +149 -0
- package/dist/core/crawler/trusted-types-handler.js +413 -0
- package/{cli/dist → dist}/core/crawler/types.d.ts +68 -2
- package/dist/core/crawler/wait-strategies.d.ts +108 -0
- package/dist/core/crawler/wait-strategies.js +399 -0
- package/dist/core/fixtures/factories.d.ts +180 -0
- package/dist/core/fixtures/factories.js +279 -0
- package/dist/core/fixtures/index.d.ts +6 -0
- package/dist/core/fixtures/index.js +6 -0
- package/{cli/dist → dist}/core/generation/crawler-pack-generator.d.ts +13 -3
- package/dist/core/generation/crawler-pack-generator.js +232 -0
- package/{cli/dist → dist}/core/generation/index.d.ts +2 -0
- package/{cli/dist → dist}/core/generation/index.js +2 -0
- package/{cli/dist → dist}/core/index.d.ts +2 -0
- package/{cli/dist → dist}/core/index.js +4 -0
- package/dist/core/network/index.d.ts +7 -0
- package/dist/core/network/index.js +7 -0
- package/dist/core/network/network-manager.d.ts +237 -0
- package/dist/core/network/network-manager.js +343 -0
- package/dist/core/network/network-simulator.d.ts +158 -0
- package/dist/core/network/network-simulator.js +261 -0
- package/{cli/dist → dist}/core/pack/validator.js +2 -2
- package/{cli/dist → dist}/core/pack-v2/migrator.d.ts +5 -0
- package/{cli/dist → dist}/core/pack-v2/migrator.js +81 -6
- package/{cli/dist → dist}/core/pack-v2/validator.js +4 -3
- package/{cli/dist → dist}/core/pom/base-page.js +1 -1
- package/{cli/dist → dist}/core/pom/loader.js +1 -1
- package/dist/core/reporting/index.d.ts +9 -0
- package/dist/core/reporting/index.js +10 -0
- package/dist/core/reporting/junit-reporter.d.ts +114 -0
- package/dist/core/reporting/junit-reporter.js +306 -0
- package/{cli/dist → dist}/core/runner/e2e-helpers.d.ts +1 -1
- package/{cli/dist → dist}/core/runner/e2e-helpers.js +2 -2
- package/{cli/dist → dist}/core/runner/phase3-runner.d.ts +3 -0
- package/{cli/dist → dist}/core/runner/phase3-runner.js +45 -14
- package/dist/core/sharding/test-sharding.d.ts +137 -0
- package/dist/core/sharding/test-sharding.js +233 -0
- package/dist/core/storage/cookie-manager.d.ts +160 -0
- package/dist/core/storage/cookie-manager.js +268 -0
- package/dist/core/storage/index.d.ts +7 -0
- package/dist/core/storage/index.js +7 -0
- package/dist/core/storage/storage-helpers.d.ts +138 -0
- package/dist/core/storage/storage-helpers.js +315 -0
- package/dist/core/test-helpers/index.d.ts +6 -0
- package/dist/core/test-helpers/index.js +6 -0
- package/dist/core/test-helpers/state-reset.d.ts +119 -0
- package/dist/core/test-helpers/state-reset.js +234 -0
- package/{cli/dist → dist}/core/types/pack-v1.d.ts +15 -2
- package/{cli/dist → dist}/core/types/pack-v2.d.ts +1 -1
- package/dist/core/upload/chunked-uploader.d.ts +150 -0
- package/dist/core/upload/chunked-uploader.js +289 -0
- package/dist/core/upload/index.d.ts +11 -0
- package/dist/core/upload/index.js +8 -0
- package/dist/core/upload/mime-validator.d.ts +119 -0
- package/dist/core/upload/mime-validator.js +373 -0
- package/dist/core/upload/presigned-uploader.d.ts +118 -0
- package/dist/core/upload/presigned-uploader.js +274 -0
- package/dist/core/utils/device-emulation.d.ts +194 -0
- package/dist/core/utils/device-emulation.js +380 -0
- package/dist/core/utils/index.d.ts +8 -0
- package/dist/core/utils/index.js +8 -0
- package/dist/core/utils/retry.d.ts +145 -0
- package/dist/core/utils/retry.js +242 -0
- package/dist/core/utils/smart-wait.d.ts +133 -0
- package/dist/core/utils/smart-wait.js +417 -0
- package/dist/core/visual/index.d.ts +7 -0
- package/dist/core/visual/index.js +7 -0
- package/dist/core/visual/pixel-diff.d.ts +87 -0
- package/dist/core/visual/pixel-diff.js +213 -0
- package/dist/core/visual/screenshot-helper.d.ts +130 -0
- package/dist/core/visual/screenshot-helper.js +223 -0
- package/{cli/dist → dist}/utils/config.d.ts +1 -1
- package/examples/README.md +160 -0
- package/examples/accessibility.yml +48 -0
- package/examples/api-basic.yml +27 -0
- package/examples/complete.yml +146 -0
- package/examples/crawler.yml +38 -0
- package/examples/fullstack.yml +78 -0
- package/examples/security.yml +58 -0
- package/examples/ui-advanced.yml +49 -0
- package/examples/ui-basic.yml +24 -0
- package/package.json +33 -67
- package/CHANGELOG.md +0 -330
- package/CONTRIBUTING.md +0 -273
- package/QUICK_START.md +0 -191
- package/cli/CHANGELOG.md +0 -84
- package/cli/LICENSE +0 -24
- package/cli/README.md +0 -222
- package/cli/dist/core/adapters/playwright-ui.js +0 -864
- package/cli/dist/core/auth/oauth2-provider.js +0 -114
- package/cli/dist/core/coverage/analyzer.d.ts +0 -101
- package/cli/dist/core/coverage/analyzer.js +0 -415
- package/cli/dist/core/coverage/collector.d.ts +0 -74
- package/cli/dist/core/coverage/collector.js +0 -459
- package/cli/dist/core/coverage/config.d.ts +0 -37
- package/cli/dist/core/coverage/config.js +0 -156
- package/cli/dist/core/coverage/index.d.ts +0 -11
- package/cli/dist/core/coverage/index.js +0 -15
- package/cli/dist/core/coverage/types.d.ts +0 -267
- package/cli/dist/core/coverage/types.js +0 -6
- package/cli/dist/core/coverage/vault.d.ts +0 -95
- package/cli/dist/core/coverage/vault.js +0 -405
- package/cli/dist/core/crawler/index.d.ts +0 -57
- package/cli/dist/core/fixtures/index.d.ts +0 -8
- package/cli/dist/core/fixtures/index.js +0 -8
- package/cli/dist/core/generation/crawler-pack-generator.js +0 -231
- package/cli/dist/core/reporting/index.d.ts +0 -6
- package/cli/dist/core/reporting/index.js +0 -6
- package/cli/dist/core/visual/index.d.ts +0 -6
- package/cli/dist/core/visual/index.js +0 -6
- package/cli/package.json +0 -76
- package/core/LICENSE +0 -24
- package/core/README.md +0 -105
- package/core/package.json +0 -90
- package/core/schemas/pack.schema.json +0 -236
- /package/{cli/bin → bin}/qa360.js +0 -0
- /package/{cli/dist → dist}/cli-minimal.d.ts +0 -0
- /package/{cli/dist → dist}/cli-minimal.js +0 -0
- /package/{cli/dist → dist}/commands/ai.d.ts +0 -0
- /package/{cli/dist → dist}/commands/ask.d.ts +0 -0
- /package/{cli/dist → dist}/commands/ask.js +0 -0
- /package/{cli/dist → dist}/commands/coverage.d.ts +0 -0
- /package/{cli/dist → dist}/commands/crawl.d.ts +0 -0
- /package/{cli/dist → dist}/commands/doctor.d.ts +0 -0
- /package/{cli/dist → dist}/commands/examples.d.ts +0 -0
- /package/{cli/dist → dist}/commands/examples.js +0 -0
- /package/{cli/dist → dist}/commands/explain.d.ts +0 -0
- /package/{cli/dist → dist}/commands/flakiness.d.ts +0 -0
- /package/{cli/dist → dist}/commands/generate.d.ts +0 -0
- /package/{cli/dist → dist}/commands/history.d.ts +0 -0
- /package/{cli/dist → dist}/commands/init.d.ts +0 -0
- /package/{cli/dist → dist}/commands/init.js +0 -0
- /package/{cli/dist → dist}/commands/monitor.d.ts +0 -0
- /package/{cli/dist → dist}/commands/ollama.d.ts +0 -0
- /package/{cli/dist → dist}/commands/pack.d.ts +0 -0
- /package/{cli/dist → dist}/commands/regression.d.ts +0 -0
- /package/{cli/dist → dist}/commands/repair.d.ts +0 -0
- /package/{cli/dist → dist}/commands/report.d.ts +0 -0
- /package/{cli/dist → dist}/commands/report.js +0 -0
- /package/{cli/dist → dist}/commands/retry.d.ts +0 -0
- /package/{cli/dist → dist}/commands/scan.d.ts +0 -0
- /package/{cli/dist → dist}/commands/scan.js +0 -0
- /package/{cli/dist → dist}/commands/secrets.d.ts +0 -0
- /package/{cli/dist → dist}/commands/serve.d.ts +0 -0
- /package/{cli/dist → dist}/commands/slo.d.ts +0 -0
- /package/{cli/dist → dist}/commands/verify.d.ts +0 -0
- /package/{cli/dist → dist}/core/adapters/gitleaks-secrets.d.ts +0 -0
- /package/{cli/dist → dist}/core/adapters/gitleaks-secrets.js +0 -0
- /package/{cli/dist → dist}/core/adapters/jest-adapter.d.ts +0 -0
- /package/{cli/dist → dist}/core/adapters/jest-adapter.js +0 -0
- /package/{cli/dist → dist}/core/adapters/k6-perf.d.ts +0 -0
- /package/{cli/dist → dist}/core/adapters/k6-perf.js +0 -0
- /package/{cli/dist → dist}/core/adapters/osv-deps.d.ts +0 -0
- /package/{cli/dist → dist}/core/adapters/osv-deps.js +0 -0
- /package/{cli/dist → dist}/core/adapters/playwright-native-adapter.d.ts +0 -0
- /package/{cli/dist → dist}/core/adapters/playwright-native-adapter.js +0 -0
- /package/{cli/dist → dist}/core/adapters/pytest-adapter.d.ts +0 -0
- /package/{cli/dist → dist}/core/adapters/pytest-adapter.js +0 -0
- /package/{cli/dist → dist}/core/adapters/semgrep-sast.d.ts +0 -0
- /package/{cli/dist → dist}/core/adapters/semgrep-sast.js +0 -0
- /package/{cli/dist → dist}/core/adapters/unit-test-types.d.ts +0 -0
- /package/{cli/dist → dist}/core/adapters/unit-test-types.js +0 -0
- /package/{cli/dist → dist}/core/adapters/vitest-adapter.d.ts +0 -0
- /package/{cli/dist → dist}/core/adapters/vitest-adapter.js +0 -0
- /package/{cli/dist → dist}/core/adapters/zap-dast.d.ts +0 -0
- /package/{cli/dist → dist}/core/adapters/zap-dast.js +0 -0
- /package/{cli/dist → dist}/core/ai/anthropic-provider.d.ts +0 -0
- /package/{cli/dist → dist}/core/ai/anthropic-provider.js +0 -0
- /package/{cli/dist → dist}/core/ai/deepseek-provider.d.ts +0 -0
- /package/{cli/dist → dist}/core/ai/deepseek-provider.js +0 -0
- /package/{cli/dist → dist}/core/ai/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/ai/index.js +0 -0
- /package/{cli/dist → dist}/core/ai/llm-client.d.ts +0 -0
- /package/{cli/dist → dist}/core/ai/llm-client.js +0 -0
- /package/{cli/dist → dist}/core/ai/mock-provider.d.ts +0 -0
- /package/{cli/dist → dist}/core/ai/mock-provider.js +0 -0
- /package/{cli/dist → dist}/core/ai/ollama-provider.d.ts +0 -0
- /package/{cli/dist → dist}/core/ai/openai-provider.d.ts +0 -0
- /package/{cli/dist → dist}/core/ai/openai-provider.js +0 -0
- /package/{cli/dist → dist}/core/ai/provider-factory.d.ts +0 -0
- /package/{cli/dist → dist}/core/ai/provider-factory.js +0 -0
- /package/{cli/dist → dist}/core/artifacts/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/artifacts/index.js +0 -0
- /package/{cli/dist → dist}/core/artifacts/ui-artifacts.d.ts +0 -0
- /package/{cli/dist → dist}/core/assertions/engine.d.ts +0 -0
- /package/{cli/dist → dist}/core/assertions/engine.js +0 -0
- /package/{cli/dist → dist}/core/assertions/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/assertions/index.js +0 -0
- /package/{cli/dist → dist}/core/assertions/types.d.ts +0 -0
- /package/{cli/dist → dist}/core/assertions/types.js +0 -0
- /package/{cli/dist → dist}/core/auth/api-key-provider.d.ts +0 -0
- /package/{cli/dist → dist}/core/auth/api-key-provider.js +0 -0
- /package/{cli/dist → dist}/core/auth/aws-iam-provider.d.ts +0 -0
- /package/{cli/dist → dist}/core/auth/aws-iam-provider.js +0 -0
- /package/{cli/dist → dist}/core/auth/azure-ad-provider.d.ts +0 -0
- /package/{cli/dist → dist}/core/auth/azure-ad-provider.js +0 -0
- /package/{cli/dist → dist}/core/auth/gcp-adc-provider.d.ts +0 -0
- /package/{cli/dist → dist}/core/auth/gcp-adc-provider.js +0 -0
- /package/{cli/dist → dist}/core/auth/jwt-provider.d.ts +0 -0
- /package/{cli/dist → dist}/core/auth/jwt-provider.js +0 -0
- /package/{cli/dist → dist}/core/auth/manager.d.ts +0 -0
- /package/{cli/dist → dist}/core/auth/manager.js +0 -0
- /package/{cli/dist → dist}/core/auth/totp-provider.d.ts +0 -0
- /package/{cli/dist → dist}/core/auth/totp-provider.js +0 -0
- /package/{cli/dist → dist}/core/auth/ui-login-provider.d.ts +0 -0
- /package/{cli/dist → dist}/core/auth/ui-login-provider.js +0 -0
- /package/{cli/dist → dist}/core/cache/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/cache/index.js +0 -0
- /package/{cli/dist → dist}/core/cache/lru-cache.d.ts +0 -0
- /package/{cli/dist → dist}/core/cache/lru-cache.js +0 -0
- /package/{cli/dist/core → dist}/core/coverage/analyzer.d.ts +0 -0
- /package/{cli/dist/core → dist}/core/coverage/analyzer.js +0 -0
- /package/{cli/dist/core → dist}/core/coverage/collector.d.ts +0 -0
- /package/{cli/dist/core → dist}/core/coverage/collector.js +0 -0
- /package/{cli/dist/core → dist}/core/coverage/config.d.ts +0 -0
- /package/{cli/dist/core → dist}/core/coverage/config.js +0 -0
- /package/{cli/dist/core → dist}/core/coverage/index.d.ts +0 -0
- /package/{cli/dist/core → dist}/core/coverage/index.js +0 -0
- /package/{cli/dist/core → dist}/core/coverage/types.d.ts +0 -0
- /package/{cli/dist/core → dist}/core/coverage/types.js +0 -0
- /package/{cli/dist/core → dist}/core/coverage/vault.d.ts +0 -0
- /package/{cli/dist/core → dist}/core/coverage/vault.js +0 -0
- /package/{cli/dist → dist}/core/crawler/journey-generator.d.ts +0 -0
- /package/{cli/dist → dist}/core/crawler/types.js +0 -0
- /package/{cli/dist → dist}/core/dashboard/assets.d.ts +0 -0
- /package/{cli/dist → dist}/core/dashboard/assets.js +0 -0
- /package/{cli/dist → dist}/core/dashboard/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/dashboard/index.js +0 -0
- /package/{cli/dist → dist}/core/dashboard/server.d.ts +0 -0
- /package/{cli/dist → dist}/core/dashboard/server.js +0 -0
- /package/{cli/dist → dist}/core/dashboard/types.d.ts +0 -0
- /package/{cli/dist → dist}/core/dashboard/types.js +0 -0
- /package/{cli/dist → dist}/core/discoverer/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/discoverer/index.js +0 -0
- /package/{cli/dist → dist}/core/fixtures/loader.d.ts +0 -0
- /package/{cli/dist → dist}/core/fixtures/loader.js +0 -0
- /package/{cli/dist → dist}/core/fixtures/resolver.d.ts +0 -0
- /package/{cli/dist → dist}/core/fixtures/resolver.js +0 -0
- /package/{cli/dist → dist}/core/fixtures/types.d.ts +0 -0
- /package/{cli/dist → dist}/core/fixtures/types.js +0 -0
- /package/{cli/dist → dist}/core/flakiness/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/flakiness/index.js +0 -0
- /package/{cli/dist → dist}/core/generation/code-formatter.d.ts +0 -0
- /package/{cli/dist → dist}/core/generation/code-formatter.js +0 -0
- /package/{cli/dist → dist}/core/generation/code-generator.d.ts +0 -0
- /package/{cli/dist → dist}/core/generation/code-generator.js +0 -0
- /package/{cli/dist → dist}/core/generation/generator.d.ts +0 -0
- /package/{cli/dist → dist}/core/generation/generator.js +0 -0
- /package/{cli/dist → dist}/core/generation/pack-generator.d.ts +0 -0
- /package/{cli/dist → dist}/core/generation/pack-generator.js +0 -0
- /package/{cli/dist → dist}/core/generation/prompt-builder.d.ts +0 -0
- /package/{cli/dist → dist}/core/generation/prompt-builder.js +0 -0
- /package/{cli/dist → dist}/core/generation/source-analyzer.d.ts +0 -0
- /package/{cli/dist → dist}/core/generation/source-analyzer.js +0 -0
- /package/{cli/dist → dist}/core/generation/test-optimizer.d.ts +0 -0
- /package/{cli/dist → dist}/core/generation/test-optimizer.js +0 -0
- /package/{cli/dist → dist}/core/generation/types.d.ts +0 -0
- /package/{cli/dist → dist}/core/generation/types.js +0 -0
- /package/{cli/dist → dist}/core/hooks/compose.d.ts +0 -0
- /package/{cli/dist → dist}/core/hooks/compose.js +0 -0
- /package/{cli/dist → dist}/core/hooks/runner.d.ts +0 -0
- /package/{cli/dist → dist}/core/hooks/runner.js +0 -0
- /package/{cli/dist → dist}/core/pack/migrator.d.ts +0 -0
- /package/{cli/dist → dist}/core/pack/migrator.js +0 -0
- /package/{cli/dist → dist}/core/pack/validator.d.ts +0 -0
- /package/{cli/dist → dist}/core/pack-v2/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/pack-v2/index.js +0 -0
- /package/{cli/dist → dist}/core/pack-v2/loader.d.ts +0 -0
- /package/{cli/dist → dist}/core/pack-v2/loader.js +0 -0
- /package/{cli/dist → dist}/core/pack-v2/validator.d.ts +0 -0
- /package/{cli/dist → dist}/core/parallel/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/parallel/index.js +0 -0
- /package/{cli/dist → dist}/core/parallel/parallel-runner.d.ts +0 -0
- /package/{cli/dist → dist}/core/parallel/parallel-runner.js +0 -0
- /package/{cli/dist → dist}/core/pom/base-page.d.ts +0 -0
- /package/{cli/dist → dist}/core/pom/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/pom/index.js +0 -0
- /package/{cli/dist → dist}/core/pom/loader.d.ts +0 -0
- /package/{cli/dist → dist}/core/pom/types.d.ts +0 -0
- /package/{cli/dist → dist}/core/pom/types.js +0 -0
- /package/{cli/dist → dist}/core/proof/bundle.d.ts +0 -0
- /package/{cli/dist → dist}/core/proof/bundle.js +0 -0
- /package/{cli/dist → dist}/core/proof/canonicalize.d.ts +0 -0
- /package/{cli/dist → dist}/core/proof/canonicalize.js +0 -0
- /package/{cli/dist → dist}/core/proof/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/proof/index.js +0 -0
- /package/{cli/dist → dist}/core/proof/schema.d.ts +0 -0
- /package/{cli/dist → dist}/core/proof/schema.js +0 -0
- /package/{cli/dist → dist}/core/proof/signer.d.ts +0 -0
- /package/{cli/dist → dist}/core/proof/signer.js +0 -0
- /package/{cli/dist → dist}/core/proof/verifier.d.ts +0 -0
- /package/{cli/dist → dist}/core/proof/verifier.js +0 -0
- /package/{cli/dist → dist}/core/regression/detector.d.ts +0 -0
- /package/{cli/dist → dist}/core/regression/detector.js +0 -0
- /package/{cli/dist → dist}/core/regression/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/regression/index.js +0 -0
- /package/{cli/dist → dist}/core/regression/trend-analyzer.d.ts +0 -0
- /package/{cli/dist → dist}/core/regression/trend-analyzer.js +0 -0
- /package/{cli/dist → dist}/core/regression/types.d.ts +0 -0
- /package/{cli/dist → dist}/core/regression/types.js +0 -0
- /package/{cli/dist → dist}/core/regression/vault.d.ts +0 -0
- /package/{cli/dist → dist}/core/regression/vault.js +0 -0
- /package/{cli/dist → dist}/core/repair/engine/fixer.d.ts +0 -0
- /package/{cli/dist → dist}/core/repair/engine/fixer.js +0 -0
- /package/{cli/dist → dist}/core/repair/engine/suggestion-engine.d.ts +0 -0
- /package/{cli/dist → dist}/core/repair/engine/suggestion-engine.js +0 -0
- /package/{cli/dist → dist}/core/repair/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/repair/index.js +0 -0
- /package/{cli/dist → dist}/core/repair/repairer.d.ts +0 -0
- /package/{cli/dist → dist}/core/repair/repairer.js +0 -0
- /package/{cli/dist → dist}/core/repair/types.d.ts +0 -0
- /package/{cli/dist → dist}/core/repair/types.js +0 -0
- /package/{cli/dist → dist}/core/repair/utils/error-analyzer.d.ts +0 -0
- /package/{cli/dist → dist}/core/repair/utils/error-analyzer.js +0 -0
- /package/{cli/dist → dist}/core/reporting/html-reporter.d.ts +0 -0
- /package/{cli/dist → dist}/core/reporting/html-reporter.js +0 -0
- /package/{cli/dist → dist}/core/retry/flakiness-integration.d.ts +0 -0
- /package/{cli/dist → dist}/core/retry/flakiness-integration.js +0 -0
- /package/{cli/dist → dist}/core/retry/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/retry/index.js +0 -0
- /package/{cli/dist → dist}/core/retry/retry-engine.d.ts +0 -0
- /package/{cli/dist → dist}/core/retry/retry-engine.js +0 -0
- /package/{cli/dist → dist}/core/retry/types.d.ts +0 -0
- /package/{cli/dist → dist}/core/retry/types.js +0 -0
- /package/{cli/dist → dist}/core/retry/vault.d.ts +0 -0
- /package/{cli/dist → dist}/core/retry/vault.js +0 -0
- /package/{cli/dist → dist}/core/schemas/pack.schema.json +0 -0
- /package/{cli/dist → dist}/core/secrets/crypto.d.ts +0 -0
- /package/{cli/dist → dist}/core/secrets/crypto.js +0 -0
- /package/{cli/dist → dist}/core/secrets/manager.d.ts +0 -0
- /package/{cli/dist → dist}/core/secrets/manager.js +0 -0
- /package/{cli/dist → dist}/core/security/redaction-patterns-extended.d.ts +0 -0
- /package/{cli/dist → dist}/core/security/redaction-patterns-extended.js +0 -0
- /package/{cli/dist → dist}/core/security/redactor.d.ts +0 -0
- /package/{cli/dist → dist}/core/security/redactor.js +0 -0
- /package/{cli/dist → dist}/core/self-healing/assertion-healer.d.ts +0 -0
- /package/{cli/dist → dist}/core/self-healing/assertion-healer.js +0 -0
- /package/{cli/dist → dist}/core/self-healing/engine.d.ts +0 -0
- /package/{cli/dist → dist}/core/self-healing/engine.js +0 -0
- /package/{cli/dist → dist}/core/self-healing/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/self-healing/index.js +0 -0
- /package/{cli/dist → dist}/core/self-healing/selector-healer.d.ts +0 -0
- /package/{cli/dist → dist}/core/self-healing/selector-healer.js +0 -0
- /package/{cli/dist → dist}/core/self-healing/types.d.ts +0 -0
- /package/{cli/dist → dist}/core/self-healing/types.js +0 -0
- /package/{cli/dist → dist}/core/serve/diagnostics-collector.d.ts +0 -0
- /package/{cli/dist → dist}/core/serve/diagnostics-collector.js +0 -0
- /package/{cli/dist → dist}/core/serve/health-checker.d.ts +0 -0
- /package/{cli/dist → dist}/core/serve/health-checker.js +0 -0
- /package/{cli/dist → dist}/core/serve/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/serve/index.js +0 -0
- /package/{cli/dist → dist}/core/serve/metrics-collector.d.ts +0 -0
- /package/{cli/dist → dist}/core/serve/metrics-collector.js +0 -0
- /package/{cli/dist → dist}/core/serve/process-manager.d.ts +0 -0
- /package/{cli/dist → dist}/core/serve/process-manager.js +0 -0
- /package/{cli/dist → dist}/core/serve/server.d.ts +0 -0
- /package/{cli/dist → dist}/core/serve/server.js +0 -0
- /package/{cli/dist → dist}/core/slo/config.d.ts +0 -0
- /package/{cli/dist → dist}/core/slo/config.js +0 -0
- /package/{cli/dist → dist}/core/slo/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/slo/index.js +0 -0
- /package/{cli/dist → dist}/core/slo/sli-calculator.d.ts +0 -0
- /package/{cli/dist → dist}/core/slo/sli-calculator.js +0 -0
- /package/{cli/dist → dist}/core/slo/slo-tracker.d.ts +0 -0
- /package/{cli/dist → dist}/core/slo/slo-tracker.js +0 -0
- /package/{cli/dist → dist}/core/slo/types.d.ts +0 -0
- /package/{cli/dist → dist}/core/slo/types.js +0 -0
- /package/{cli/dist → dist}/core/slo/vault.d.ts +0 -0
- /package/{cli/dist → dist}/core/slo/vault.js +0 -0
- /package/{cli/dist → dist}/core/tui/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/tui/index.js +0 -0
- /package/{cli/dist → dist}/core/tui/monitor.d.ts +0 -0
- /package/{cli/dist → dist}/core/tui/monitor.js +0 -0
- /package/{cli/dist → dist}/core/tui/renderer.d.ts +0 -0
- /package/{cli/dist → dist}/core/tui/renderer.js +0 -0
- /package/{cli/dist → dist}/core/tui/types.d.ts +0 -0
- /package/{cli/dist → dist}/core/tui/types.js +0 -0
- /package/{cli/dist → dist}/core/types/pack-v1.js +0 -0
- /package/{cli/dist → dist}/core/types/pack-v2.js +0 -0
- /package/{cli/dist → dist}/core/types/trust-score.d.ts +0 -0
- /package/{cli/dist → dist}/core/types/trust-score.js +0 -0
- /package/{cli/dist → dist}/core/vault/cas.d.ts +0 -0
- /package/{cli/dist → dist}/core/vault/cas.js +0 -0
- /package/{cli/dist → dist}/core/vault/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/vault/index.js +0 -0
- /package/{cli/dist → dist}/core/visual/visual-regression.d.ts +0 -0
- /package/{cli/dist → dist}/core/visual/visual-regression.js +0 -0
- /package/{cli/dist → dist}/core/watch/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/watch/index.js +0 -0
- /package/{cli/dist → dist}/core/watch/watch-mode.d.ts +0 -0
- /package/{cli/dist → dist}/core/watch/watch-mode.js +0 -0
- /package/{cli/dist → dist}/generators/index.d.ts +0 -0
- /package/{cli/dist → dist}/generators/index.js +0 -0
- /package/{cli/dist → dist}/generators/json-reporter.d.ts +0 -0
- /package/{cli/dist → dist}/generators/json-reporter.js +0 -0
- /package/{cli/dist → dist}/generators/test-generator.d.ts +0 -0
- /package/{cli/dist → dist}/generators/test-generator.js +0 -0
- /package/{cli/dist → dist}/index.d.ts +0 -0
- /package/{cli/dist → dist}/index.js +0 -0
- /package/{cli/dist → dist}/scanners/dom-scanner.d.ts +0 -0
- /package/{cli/dist → dist}/scanners/dom-scanner.js +0 -0
- /package/{cli/dist → dist}/scanners/index.d.ts +0 -0
- /package/{cli/dist → dist}/scanners/index.js +0 -0
- /package/{cli/dist → dist}/schemas/pack.schema.json +0 -0
- /package/{cli/dist → dist}/types/scan.d.ts +0 -0
- /package/{cli/dist → dist}/types/scan.js +0 -0
- /package/{cli/dist → dist}/utils/config.js +0 -0
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OAuth2 Authentication Provider
|
|
3
|
+
*
|
|
4
|
+
* Handles OAuth2 authentication with support for:
|
|
5
|
+
* - Client credentials grant
|
|
6
|
+
* - Password grant (resource owner)
|
|
7
|
+
* - Authorization code grant (requires pre-issued code)
|
|
8
|
+
*
|
|
9
|
+
* P0: Refresh token support for automatic token renewal
|
|
10
|
+
*/
|
|
11
|
+
import { authCache, createCacheKey } from './index.js';
|
|
12
|
+
export class OAuth2Provider {
|
|
13
|
+
type = 'oauth2';
|
|
14
|
+
async authenticate(config) {
|
|
15
|
+
const cacheKey = this.getCacheKey(config);
|
|
16
|
+
// Check cache first
|
|
17
|
+
if (config.cache?.enabled !== false) {
|
|
18
|
+
const cached = authCache.get(cacheKey);
|
|
19
|
+
if (cached) {
|
|
20
|
+
// P0: Check if token is expired and auto_refresh is enabled
|
|
21
|
+
if (config.auto_refresh && cached.expiresAt && cached.expiresAt < Date.now()) {
|
|
22
|
+
// Token expired, try to refresh
|
|
23
|
+
if (cached.refreshToken || config.refresh_token) {
|
|
24
|
+
const refreshResult = await this.refresh(config);
|
|
25
|
+
if (refreshResult.success) {
|
|
26
|
+
return refreshResult;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return { success: true, credentials: cached };
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// If we have a refresh_token in config, use refresh flow
|
|
34
|
+
if (config.refresh_token && config.grant_type !== 'refresh_token') {
|
|
35
|
+
return this.performRefresh(config);
|
|
36
|
+
}
|
|
37
|
+
// Prepare token request based on grant type
|
|
38
|
+
const grantType = config.grant_type || 'client_credentials';
|
|
39
|
+
const body = {
|
|
40
|
+
grant_type: grantType,
|
|
41
|
+
client_id: config.client_id,
|
|
42
|
+
};
|
|
43
|
+
// Add client secret for most grants (except some implicit flows)
|
|
44
|
+
if (config.client_secret) {
|
|
45
|
+
body.client_secret = config.client_secret;
|
|
46
|
+
}
|
|
47
|
+
// Grant-specific parameters
|
|
48
|
+
if (grantType === 'password') {
|
|
49
|
+
if (!config.username || !config.password) {
|
|
50
|
+
return {
|
|
51
|
+
success: false,
|
|
52
|
+
error: 'Username and password required for password grant'
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
body.username = config.username;
|
|
56
|
+
body.password = config.password;
|
|
57
|
+
}
|
|
58
|
+
if (config.scopes && config.scopes.length > 0) {
|
|
59
|
+
body.scope = config.scopes.join(' ');
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
const response = await fetch(config.token_url, {
|
|
63
|
+
method: 'POST',
|
|
64
|
+
headers: {
|
|
65
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
66
|
+
},
|
|
67
|
+
body: new URLSearchParams(body).toString(),
|
|
68
|
+
});
|
|
69
|
+
if (!response.ok) {
|
|
70
|
+
const error = await response.text().catch(() => 'Unknown error');
|
|
71
|
+
return {
|
|
72
|
+
success: false,
|
|
73
|
+
error: `OAuth2 token request failed: ${response.status} ${error}`
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
const data = await response.json();
|
|
77
|
+
const token = data.access_token;
|
|
78
|
+
if (!token) {
|
|
79
|
+
return {
|
|
80
|
+
success: false,
|
|
81
|
+
error: 'No access_token in OAuth2 response'
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
// Calculate expiration
|
|
85
|
+
let expiresAt;
|
|
86
|
+
if (data.expires_in) {
|
|
87
|
+
expiresAt = Date.now() + data.expires_in * 1000;
|
|
88
|
+
}
|
|
89
|
+
const credentials = {
|
|
90
|
+
type: 'oauth2',
|
|
91
|
+
headers: {
|
|
92
|
+
'Authorization': `Bearer ${token}`
|
|
93
|
+
},
|
|
94
|
+
// P0: Store refresh token for later use
|
|
95
|
+
refreshToken: data.refresh_token,
|
|
96
|
+
expiresAt,
|
|
97
|
+
};
|
|
98
|
+
// Cache if enabled
|
|
99
|
+
if (config.cache?.enabled !== false) {
|
|
100
|
+
const ttl = config.cache?.ttl || data.expires_in || 3600;
|
|
101
|
+
authCache.set(cacheKey, credentials, ttl);
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
success: true,
|
|
105
|
+
credentials,
|
|
106
|
+
expiresAt
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
return {
|
|
111
|
+
success: false,
|
|
112
|
+
error: `OAuth2 request failed: ${error.message}`
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* P0: Refresh OAuth2 access token using refresh token
|
|
118
|
+
*/
|
|
119
|
+
async refresh(config) {
|
|
120
|
+
return this.performRefresh(config);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* P0: Perform refresh token flow
|
|
124
|
+
*/
|
|
125
|
+
async performRefresh(config) {
|
|
126
|
+
const cacheKey = this.getCacheKey(config);
|
|
127
|
+
// Get refresh token from config or cached credentials
|
|
128
|
+
let refreshToken = config.refresh_token;
|
|
129
|
+
if (!refreshToken && config.cache?.enabled !== false) {
|
|
130
|
+
const cached = authCache.get(cacheKey);
|
|
131
|
+
if (cached?.refreshToken) {
|
|
132
|
+
refreshToken = cached.refreshToken;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
if (!refreshToken) {
|
|
136
|
+
// No refresh token available, fall back to full authentication
|
|
137
|
+
return this.authenticate({ ...config, refresh_token: undefined });
|
|
138
|
+
}
|
|
139
|
+
// Prepare refresh token request
|
|
140
|
+
const body = {
|
|
141
|
+
grant_type: 'refresh_token',
|
|
142
|
+
refresh_token: refreshToken,
|
|
143
|
+
client_id: config.client_id,
|
|
144
|
+
};
|
|
145
|
+
if (config.client_secret) {
|
|
146
|
+
body.client_secret = config.client_secret;
|
|
147
|
+
}
|
|
148
|
+
if (config.scopes && config.scopes.length > 0) {
|
|
149
|
+
body.scope = config.scopes.join(' ');
|
|
150
|
+
}
|
|
151
|
+
const tokenUrl = config.refresh_url || config.token_url;
|
|
152
|
+
try {
|
|
153
|
+
const response = await fetch(tokenUrl, {
|
|
154
|
+
method: 'POST',
|
|
155
|
+
headers: {
|
|
156
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
157
|
+
},
|
|
158
|
+
body: new URLSearchParams(body).toString(),
|
|
159
|
+
});
|
|
160
|
+
if (!response.ok) {
|
|
161
|
+
const error = await response.text().catch(() => 'Unknown error');
|
|
162
|
+
// Refresh token failed - might be expired, try full auth
|
|
163
|
+
const fullAuthResult = await this.authenticate({ ...config, refresh_token: undefined });
|
|
164
|
+
return fullAuthResult;
|
|
165
|
+
}
|
|
166
|
+
const data = await response.json();
|
|
167
|
+
const token = data.access_token;
|
|
168
|
+
if (!token) {
|
|
169
|
+
return {
|
|
170
|
+
success: false,
|
|
171
|
+
error: 'No access_token in OAuth2 refresh response'
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
// Calculate expiration
|
|
175
|
+
let expiresAt;
|
|
176
|
+
if (data.expires_in) {
|
|
177
|
+
expiresAt = Date.now() + data.expires_in * 1000;
|
|
178
|
+
}
|
|
179
|
+
// Use new refresh token if provided (rotation), otherwise keep existing
|
|
180
|
+
const newRefreshToken = data.refresh_token || refreshToken;
|
|
181
|
+
const credentials = {
|
|
182
|
+
type: 'oauth2',
|
|
183
|
+
headers: {
|
|
184
|
+
'Authorization': `Bearer ${token}`
|
|
185
|
+
},
|
|
186
|
+
refreshToken: newRefreshToken,
|
|
187
|
+
expiresAt,
|
|
188
|
+
};
|
|
189
|
+
// Update cache
|
|
190
|
+
if (config.cache?.enabled !== false) {
|
|
191
|
+
const ttl = config.cache?.ttl || data.expires_in || 3600;
|
|
192
|
+
authCache.set(cacheKey, credentials, ttl);
|
|
193
|
+
}
|
|
194
|
+
return {
|
|
195
|
+
success: true,
|
|
196
|
+
credentials,
|
|
197
|
+
expiresAt
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
return {
|
|
202
|
+
success: false,
|
|
203
|
+
error: `OAuth2 refresh failed: ${error.message}`
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
clear(config) {
|
|
208
|
+
const key = this.getCacheKey(config);
|
|
209
|
+
authCache.clear(key);
|
|
210
|
+
return Promise.resolve();
|
|
211
|
+
}
|
|
212
|
+
async validate(config) {
|
|
213
|
+
const key = this.getCacheKey(config);
|
|
214
|
+
const cached = authCache.get(key);
|
|
215
|
+
if (!cached) {
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
// Check if token is expired
|
|
219
|
+
if (cached.expiresAt && cached.expiresAt < Date.now()) {
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
return true;
|
|
223
|
+
}
|
|
224
|
+
getCacheKey(config) {
|
|
225
|
+
return createCacheKey('oauth2', config.client_id);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OTP (One-Time Password) Authentication Provider
|
|
3
|
+
*
|
|
4
|
+
* Handles OTP-based authentication including:
|
|
5
|
+
* - SMS OTP: One-time passwords sent via SMS
|
|
6
|
+
* - Email OTP: One-time passwords sent via email
|
|
7
|
+
* - Magic Links: Login links sent via email
|
|
8
|
+
*
|
|
9
|
+
* P1 Feature: OTP-based authentication is widely used for 2FA and passwordless flows
|
|
10
|
+
*/
|
|
11
|
+
import type { AuthProvider, AuthResult } from './index.js';
|
|
12
|
+
import { type OTPAuthConfig } from './index.js';
|
|
13
|
+
/**
|
|
14
|
+
* OTP delivery method
|
|
15
|
+
*/
|
|
16
|
+
export type OTPDeliveryMethod = 'sms' | 'email' | 'magic_link';
|
|
17
|
+
/**
|
|
18
|
+
* Generates a random OTP code
|
|
19
|
+
* @param digits Number of digits (default 6)
|
|
20
|
+
*/
|
|
21
|
+
export declare function generateOTP(digits?: number): string;
|
|
22
|
+
/**
|
|
23
|
+
* Validates OTP format
|
|
24
|
+
* @param code OTP code to validate
|
|
25
|
+
* @param digits Expected number of digits
|
|
26
|
+
*/
|
|
27
|
+
export declare function validateOTPFormat(code: string, digits?: number): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Generates a magic link URL
|
|
30
|
+
* @param baseUrl Base URL of the application
|
|
31
|
+
* @param token Authentication token
|
|
32
|
+
* @param email User email
|
|
33
|
+
*/
|
|
34
|
+
export declare function generateMagicLink(baseUrl: string, token: string, email: string): string;
|
|
35
|
+
/**
|
|
36
|
+
* Extracts token from magic link URL
|
|
37
|
+
* @param url Magic link URL
|
|
38
|
+
*/
|
|
39
|
+
export declare function extractTokenFromMagicLink(url: string): string | null;
|
|
40
|
+
/**
|
|
41
|
+
* OTP Authentication Provider
|
|
42
|
+
*/
|
|
43
|
+
export declare class OTPProvider implements AuthProvider<OTPAuthConfig> {
|
|
44
|
+
readonly type: "otp";
|
|
45
|
+
private otpStates;
|
|
46
|
+
private maxAttempts;
|
|
47
|
+
authenticate(config: OTPAuthConfig): Promise<AuthResult>;
|
|
48
|
+
/**
|
|
49
|
+
* Requests a new OTP to be sent
|
|
50
|
+
*/
|
|
51
|
+
requestOTP(config: OTPAuthConfig): Promise<AuthResult>;
|
|
52
|
+
/**
|
|
53
|
+
* Verifies an OTP code
|
|
54
|
+
*/
|
|
55
|
+
verifyOTP(config: OTPAuthConfig): Promise<AuthResult>;
|
|
56
|
+
/**
|
|
57
|
+
* Verifies a magic link
|
|
58
|
+
*/
|
|
59
|
+
verifyMagicLink(config: OTPAuthConfig): Promise<AuthResult>;
|
|
60
|
+
/**
|
|
61
|
+
* Generates a session token
|
|
62
|
+
*/
|
|
63
|
+
private generateSessionToken;
|
|
64
|
+
/**
|
|
65
|
+
* Validates OTP configuration
|
|
66
|
+
*/
|
|
67
|
+
validate(config: OTPAuthConfig): Promise<boolean>;
|
|
68
|
+
/**
|
|
69
|
+
* Clears cached OTP state
|
|
70
|
+
*/
|
|
71
|
+
clear(config: OTPAuthConfig): Promise<void>;
|
|
72
|
+
/**
|
|
73
|
+
* Gets remaining time for OTP expiration
|
|
74
|
+
*/
|
|
75
|
+
getOTPTimeRemaining(destination: string): number | null;
|
|
76
|
+
/**
|
|
77
|
+
* Gets remaining attempts for OTP verification
|
|
78
|
+
*/
|
|
79
|
+
getRemainingAttempts(destination: string): number;
|
|
80
|
+
/**
|
|
81
|
+
* Sets maximum verification attempts
|
|
82
|
+
*/
|
|
83
|
+
setMaxAttempts(max: number): void;
|
|
84
|
+
/**
|
|
85
|
+
* Clears all OTP states
|
|
86
|
+
*/
|
|
87
|
+
clearAllStates(): void;
|
|
88
|
+
private getCacheKey;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Creates an OTP auth provider instance
|
|
92
|
+
*/
|
|
93
|
+
export declare function createOTPProvider(): OTPProvider;
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OTP (One-Time Password) Authentication Provider
|
|
3
|
+
*
|
|
4
|
+
* Handles OTP-based authentication including:
|
|
5
|
+
* - SMS OTP: One-time passwords sent via SMS
|
|
6
|
+
* - Email OTP: One-time passwords sent via email
|
|
7
|
+
* - Magic Links: Login links sent via email
|
|
8
|
+
*
|
|
9
|
+
* P1 Feature: OTP-based authentication is widely used for 2FA and passwordless flows
|
|
10
|
+
*/
|
|
11
|
+
import { createCacheKey, authCache } from './index.js';
|
|
12
|
+
/**
|
|
13
|
+
* Generates a random OTP code
|
|
14
|
+
* @param digits Number of digits (default 6)
|
|
15
|
+
*/
|
|
16
|
+
export function generateOTP(digits = 6) {
|
|
17
|
+
const min = Math.pow(10, digits - 1);
|
|
18
|
+
const max = Math.pow(10, digits) - 1;
|
|
19
|
+
return Math.floor(min + Math.random() * (max - min + 1)).toString().padStart(digits, '0');
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Validates OTP format
|
|
23
|
+
* @param code OTP code to validate
|
|
24
|
+
* @param digits Expected number of digits
|
|
25
|
+
*/
|
|
26
|
+
export function validateOTPFormat(code, digits = 6) {
|
|
27
|
+
const regex = new RegExp(`^\\d{${digits}}$`);
|
|
28
|
+
return regex.test(code);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Generates a magic link URL
|
|
32
|
+
* @param baseUrl Base URL of the application
|
|
33
|
+
* @param token Authentication token
|
|
34
|
+
* @param email User email
|
|
35
|
+
*/
|
|
36
|
+
export function generateMagicLink(baseUrl, token, email) {
|
|
37
|
+
const url = new URL(baseUrl);
|
|
38
|
+
url.searchParams.set('token', token);
|
|
39
|
+
url.searchParams.set('email', email);
|
|
40
|
+
return url.toString();
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Extracts token from magic link URL
|
|
44
|
+
* @param url Magic link URL
|
|
45
|
+
*/
|
|
46
|
+
export function extractTokenFromMagicLink(url) {
|
|
47
|
+
try {
|
|
48
|
+
const parsed = new URL(url);
|
|
49
|
+
return parsed.searchParams.get('token');
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* OTP Authentication Provider
|
|
57
|
+
*/
|
|
58
|
+
export class OTPProvider {
|
|
59
|
+
type = 'otp';
|
|
60
|
+
otpStates = new Map();
|
|
61
|
+
maxAttempts = 3;
|
|
62
|
+
async authenticate(config) {
|
|
63
|
+
const { method, destination, code, magicLinkUrl, verifyEndpoint, headers } = config;
|
|
64
|
+
if (!destination) {
|
|
65
|
+
return {
|
|
66
|
+
success: false,
|
|
67
|
+
error: `${method} destination is required`
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
const cacheKey = this.getCacheKey(config);
|
|
71
|
+
// If code is provided, verify it
|
|
72
|
+
if (code) {
|
|
73
|
+
return this.verifyOTP(config);
|
|
74
|
+
}
|
|
75
|
+
// If magic link URL is provided, extract token
|
|
76
|
+
if (magicLinkUrl && method === 'magic_link') {
|
|
77
|
+
return this.verifyMagicLink(config);
|
|
78
|
+
}
|
|
79
|
+
// Otherwise, request a new OTP
|
|
80
|
+
return this.requestOTP(config);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Requests a new OTP to be sent
|
|
84
|
+
*/
|
|
85
|
+
async requestOTP(config) {
|
|
86
|
+
const { method, destination, requestEndpoint, headers: customHeaders } = config;
|
|
87
|
+
// In a real implementation, this would call an API to send the OTP
|
|
88
|
+
// For now, we simulate the OTP generation
|
|
89
|
+
const otp = generateOTP(6);
|
|
90
|
+
const expiresAt = Date.now() + 5 * 60 * 1000; // 5 minutes
|
|
91
|
+
// Store OTP state (in production, this would be on the server)
|
|
92
|
+
this.otpStates.set(destination, {
|
|
93
|
+
code: otp,
|
|
94
|
+
expiresAt,
|
|
95
|
+
attempts: 0,
|
|
96
|
+
});
|
|
97
|
+
// Simulate API call if endpoint provided
|
|
98
|
+
if (requestEndpoint) {
|
|
99
|
+
// In real implementation, would make HTTP request
|
|
100
|
+
console.log(`[OTP Mock] Sending ${method} to ${destination}: ${otp}`);
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
success: true,
|
|
104
|
+
credentials: {
|
|
105
|
+
type: 'otp',
|
|
106
|
+
headers: {
|
|
107
|
+
'X-OTP-Destination': destination,
|
|
108
|
+
'X-OTP-Method': method,
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Verifies an OTP code
|
|
115
|
+
*/
|
|
116
|
+
async verifyOTP(config) {
|
|
117
|
+
const { destination, code, verifyEndpoint } = config;
|
|
118
|
+
if (!code) {
|
|
119
|
+
return {
|
|
120
|
+
success: false,
|
|
121
|
+
error: 'OTP code is required for verification'
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
// Check local state
|
|
125
|
+
const state = this.otpStates.get(destination);
|
|
126
|
+
if (!state) {
|
|
127
|
+
return {
|
|
128
|
+
success: false,
|
|
129
|
+
error: 'No OTP requested for this destination'
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
// Check expiration
|
|
133
|
+
if (Date.now() > state.expiresAt) {
|
|
134
|
+
this.otpStates.delete(destination);
|
|
135
|
+
return {
|
|
136
|
+
success: false,
|
|
137
|
+
error: 'OTP has expired'
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
// Check attempts
|
|
141
|
+
if (state.attempts >= this.maxAttempts) {
|
|
142
|
+
this.otpStates.delete(destination);
|
|
143
|
+
return {
|
|
144
|
+
success: false,
|
|
145
|
+
error: 'Maximum verification attempts exceeded'
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
// Increment attempts
|
|
149
|
+
state.attempts++;
|
|
150
|
+
// Verify code
|
|
151
|
+
if (code !== state.code) {
|
|
152
|
+
return {
|
|
153
|
+
success: false,
|
|
154
|
+
error: 'Invalid OTP code',
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
// Success - clean up state
|
|
158
|
+
this.otpStates.delete(destination);
|
|
159
|
+
// Generate a session token
|
|
160
|
+
const token = this.generateSessionToken();
|
|
161
|
+
return {
|
|
162
|
+
success: true,
|
|
163
|
+
credentials: {
|
|
164
|
+
type: 'otp',
|
|
165
|
+
headers: {
|
|
166
|
+
'Authorization': `Bearer ${token}`,
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
expiresAt: Date.now() + 24 * 60 * 60 * 1000, // 24 hours
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Verifies a magic link
|
|
174
|
+
*/
|
|
175
|
+
async verifyMagicLink(config) {
|
|
176
|
+
const { magicLinkUrl, destination } = config;
|
|
177
|
+
if (!magicLinkUrl) {
|
|
178
|
+
return {
|
|
179
|
+
success: false,
|
|
180
|
+
error: 'Magic link URL is required'
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
const token = extractTokenFromMagicLink(magicLinkUrl);
|
|
184
|
+
if (!token) {
|
|
185
|
+
return {
|
|
186
|
+
success: false,
|
|
187
|
+
error: 'Invalid magic link URL'
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
// In a real implementation, verify token with server
|
|
191
|
+
// For now, accept any valid-looking token
|
|
192
|
+
if (token.length < 10) {
|
|
193
|
+
return {
|
|
194
|
+
success: false,
|
|
195
|
+
error: 'Invalid magic link token'
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
return {
|
|
199
|
+
success: true,
|
|
200
|
+
credentials: {
|
|
201
|
+
type: 'otp',
|
|
202
|
+
headers: {
|
|
203
|
+
'Authorization': `Bearer ${token}`,
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
expiresAt: Date.now() + 7 * 24 * 60 * 60 * 1000, // 7 days
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Generates a session token
|
|
211
|
+
*/
|
|
212
|
+
generateSessionToken() {
|
|
213
|
+
const crypto = require('node:crypto');
|
|
214
|
+
return crypto.randomBytes(32).toString('hex');
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Validates OTP configuration
|
|
218
|
+
*/
|
|
219
|
+
async validate(config) {
|
|
220
|
+
if (!config.destination) {
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
if (config.method === 'sms') {
|
|
224
|
+
// Validate phone number format (basic)
|
|
225
|
+
return /^[\d\s+()-]{10,}$/.test(config.destination);
|
|
226
|
+
}
|
|
227
|
+
if (config.method === 'email' || config.method === 'magic_link') {
|
|
228
|
+
// Validate email format
|
|
229
|
+
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(config.destination);
|
|
230
|
+
}
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Clears cached OTP state
|
|
235
|
+
*/
|
|
236
|
+
async clear(config) {
|
|
237
|
+
const key = this.getCacheKey(config);
|
|
238
|
+
authCache.clear(key);
|
|
239
|
+
this.otpStates.delete(config.destination);
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Gets remaining time for OTP expiration
|
|
243
|
+
*/
|
|
244
|
+
getOTPTimeRemaining(destination) {
|
|
245
|
+
const state = this.otpStates.get(destination);
|
|
246
|
+
if (!state)
|
|
247
|
+
return null;
|
|
248
|
+
const remaining = state.expiresAt - Date.now();
|
|
249
|
+
return remaining > 0 ? remaining : 0;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Gets remaining attempts for OTP verification
|
|
253
|
+
*/
|
|
254
|
+
getRemainingAttempts(destination) {
|
|
255
|
+
const state = this.otpStates.get(destination);
|
|
256
|
+
if (!state)
|
|
257
|
+
return this.maxAttempts;
|
|
258
|
+
return this.maxAttempts - state.attempts;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Sets maximum verification attempts
|
|
262
|
+
*/
|
|
263
|
+
setMaxAttempts(max) {
|
|
264
|
+
this.maxAttempts = max;
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Clears all OTP states
|
|
268
|
+
*/
|
|
269
|
+
clearAllStates() {
|
|
270
|
+
this.otpStates.clear();
|
|
271
|
+
}
|
|
272
|
+
getCacheKey(config) {
|
|
273
|
+
const crypto = require('node:crypto');
|
|
274
|
+
const hash = crypto
|
|
275
|
+
.createHash('sha256')
|
|
276
|
+
.update(`${config.method}:${config.destination}`)
|
|
277
|
+
.digest('hex')
|
|
278
|
+
.substring(0, 16);
|
|
279
|
+
return createCacheKey('otp', hash);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Creates an OTP auth provider instance
|
|
284
|
+
*/
|
|
285
|
+
export function createOTPProvider() {
|
|
286
|
+
return new OTPProvider();
|
|
287
|
+
}
|
|
288
|
+
// Types are exported from index.ts
|