@epsilon-asi/actors 0.0.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/.ai/generators/_template.ts +37 -0
- package/.ai/generators/abstract.ts +24 -0
- package/.ai/generators/actor-task-form-filler.ts +140 -0
- package/.ai/generators/actor-task.ts +122 -0
- package/.ai/generators/auth-core.ts +126 -0
- package/.ai/generators/browser-runtime.ts +114 -0
- package/.ai/generators/cli-command.ts +96 -0
- package/.ai/generators/core-framework.ts +80 -0
- package/.ai/generators/docs.ts +92 -0
- package/.ai/generators/error-logging.ts +102 -0
- package/.ai/generators/extraction-helper.ts +96 -0
- package/.ai/generators/interaction-behavior.ts +129 -0
- package/.ai/generators/site-actor.ts +125 -0
- package/.ai/generators/site-login-flow.ts +117 -0
- package/.ai/generators/unit-test.ts +109 -0
- package/.ai/workflows/_template.ts +20 -0
- package/.ai/workflows/starter.ts +20 -0
- package/README.md +435 -0
- package/ai-gen.config.ts +67 -0
- package/dist/auth/AuthStateDetector.d.ts +6 -0
- package/dist/auth/AuthStateDetector.d.ts.map +1 -0
- package/dist/auth/AuthStateDetector.js +14 -0
- package/dist/auth/AuthStateDetector.js.map +1 -0
- package/dist/auth/CredentialsProvider.d.ts +22 -0
- package/dist/auth/CredentialsProvider.d.ts.map +1 -0
- package/dist/auth/CredentialsProvider.js +30 -0
- package/dist/auth/CredentialsProvider.js.map +1 -0
- package/dist/auth/LoginFlow.d.ts +27 -0
- package/dist/auth/LoginFlow.d.ts.map +1 -0
- package/dist/auth/LoginFlow.js +233 -0
- package/dist/auth/LoginFlow.js.map +1 -0
- package/dist/auth/LoginFlow.types.d.ts +123 -0
- package/dist/auth/LoginFlow.types.d.ts.map +1 -0
- package/dist/auth/LoginFlow.types.js +7 -0
- package/dist/auth/LoginFlow.types.js.map +1 -0
- package/dist/auth/SessionStore.d.ts +16 -0
- package/dist/auth/SessionStore.d.ts.map +1 -0
- package/dist/auth/SessionStore.js +8 -0
- package/dist/auth/SessionStore.js.map +1 -0
- package/dist/auth/index.d.ts +6 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +6 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/browser/BrowserFactory.d.ts +16 -0
- package/dist/browser/BrowserFactory.d.ts.map +1 -0
- package/dist/browser/BrowserFactory.js +209 -0
- package/dist/browser/BrowserFactory.js.map +1 -0
- package/dist/browser/BrowserSession.d.ts +15 -0
- package/dist/browser/BrowserSession.d.ts.map +1 -0
- package/dist/browser/BrowserSession.js +42 -0
- package/dist/browser/BrowserSession.js.map +1 -0
- package/dist/browser/PuppeteerLike.d.ts +45 -0
- package/dist/browser/PuppeteerLike.d.ts.map +1 -0
- package/dist/browser/PuppeteerLike.js +10 -0
- package/dist/browser/PuppeteerLike.js.map +1 -0
- package/dist/browser/RuntimeConfig.d.ts +82 -0
- package/dist/browser/RuntimeConfig.d.ts.map +1 -0
- package/dist/browser/RuntimeConfig.js +64 -0
- package/dist/browser/RuntimeConfig.js.map +1 -0
- package/dist/browser/index.d.ts +6 -0
- package/dist/browser/index.d.ts.map +1 -0
- package/dist/browser/index.js +6 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/browser/profileValidation.d.ts +6 -0
- package/dist/browser/profileValidation.d.ts.map +1 -0
- package/dist/browser/profileValidation.js +59 -0
- package/dist/browser/profileValidation.js.map +1 -0
- package/dist/cli/run.d.ts +3 -0
- package/dist/cli/run.d.ts.map +1 -0
- package/dist/cli/run.js +103 -0
- package/dist/cli/run.js.map +1 -0
- package/dist/core/Actor.d.ts +54 -0
- package/dist/core/Actor.d.ts.map +1 -0
- package/dist/core/Actor.js +68 -0
- package/dist/core/Actor.js.map +1 -0
- package/dist/core/ActorContext.d.ts +32 -0
- package/dist/core/ActorContext.d.ts.map +1 -0
- package/dist/core/ActorContext.js +2 -0
- package/dist/core/ActorContext.js.map +1 -0
- package/dist/core/ActorRegistry.d.ts +8 -0
- package/dist/core/ActorRegistry.d.ts.map +1 -0
- package/dist/core/ActorRegistry.js +22 -0
- package/dist/core/ActorRegistry.js.map +1 -0
- package/dist/core/ActorRunner.d.ts +57 -0
- package/dist/core/ActorRunner.d.ts.map +1 -0
- package/dist/core/ActorRunner.js +157 -0
- package/dist/core/ActorRunner.js.map +1 -0
- package/dist/core/defineActor.d.ts +3 -0
- package/dist/core/defineActor.d.ts.map +1 -0
- package/dist/core/defineActor.js +4 -0
- package/dist/core/defineActor.js.map +1 -0
- package/dist/core/index.d.ts +6 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +6 -0
- package/dist/core/index.js.map +1 -0
- package/dist/errors/AuthError.d.ts +5 -0
- package/dist/errors/AuthError.d.ts.map +1 -0
- package/dist/errors/AuthError.js +7 -0
- package/dist/errors/AuthError.js.map +1 -0
- package/dist/errors/AutomationError.d.ts +17 -0
- package/dist/errors/AutomationError.d.ts.map +1 -0
- package/dist/errors/AutomationError.js +17 -0
- package/dist/errors/AutomationError.js.map +1 -0
- package/dist/errors/ConfigError.d.ts +5 -0
- package/dist/errors/ConfigError.d.ts.map +1 -0
- package/dist/errors/ConfigError.js +7 -0
- package/dist/errors/ConfigError.js.map +1 -0
- package/dist/errors/ExtractionError.d.ts +5 -0
- package/dist/errors/ExtractionError.d.ts.map +1 -0
- package/dist/errors/ExtractionError.js +7 -0
- package/dist/errors/ExtractionError.js.map +1 -0
- package/dist/errors/NavigationError.d.ts +5 -0
- package/dist/errors/NavigationError.d.ts.map +1 -0
- package/dist/errors/NavigationError.js +7 -0
- package/dist/errors/NavigationError.js.map +1 -0
- package/dist/errors/SelectorError.d.ts +6 -0
- package/dist/errors/SelectorError.d.ts.map +1 -0
- package/dist/errors/SelectorError.js +9 -0
- package/dist/errors/SelectorError.js.map +1 -0
- package/dist/errors/index.d.ts +7 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +7 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/extraction/Extractor.d.ts +16 -0
- package/dist/extraction/Extractor.d.ts.map +1 -0
- package/dist/extraction/Extractor.js +54 -0
- package/dist/extraction/Extractor.js.map +1 -0
- package/dist/extraction/Pagination.d.ts +16 -0
- package/dist/extraction/Pagination.d.ts.map +1 -0
- package/dist/extraction/Pagination.js +36 -0
- package/dist/extraction/Pagination.js.map +1 -0
- package/dist/extraction/index.d.ts +3 -0
- package/dist/extraction/index.d.ts.map +1 -0
- package/dist/extraction/index.js +3 -0
- package/dist/extraction/index.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/interaction/FieldClearer.d.ts +7 -0
- package/dist/interaction/FieldClearer.d.ts.map +1 -0
- package/dist/interaction/FieldClearer.js +53 -0
- package/dist/interaction/FieldClearer.js.map +1 -0
- package/dist/interaction/Forms.d.ts +13 -0
- package/dist/interaction/Forms.d.ts.map +1 -0
- package/dist/interaction/Forms.js +22 -0
- package/dist/interaction/Forms.js.map +1 -0
- package/dist/interaction/GhostCursorAdapter.d.ts +27 -0
- package/dist/interaction/GhostCursorAdapter.d.ts.map +1 -0
- package/dist/interaction/GhostCursorAdapter.js +51 -0
- package/dist/interaction/GhostCursorAdapter.js.map +1 -0
- package/dist/interaction/HumanInteractor.d.ts +29 -0
- package/dist/interaction/HumanInteractor.d.ts.map +1 -0
- package/dist/interaction/HumanInteractor.js +2 -0
- package/dist/interaction/HumanInteractor.js.map +1 -0
- package/dist/interaction/HumanTyping.d.ts +43 -0
- package/dist/interaction/HumanTyping.d.ts.map +1 -0
- package/dist/interaction/HumanTyping.js +85 -0
- package/dist/interaction/HumanTyping.js.map +1 -0
- package/dist/interaction/NativePuppeteerInteractor.d.ts +20 -0
- package/dist/interaction/NativePuppeteerInteractor.d.ts.map +1 -0
- package/dist/interaction/NativePuppeteerInteractor.js +47 -0
- package/dist/interaction/NativePuppeteerInteractor.js.map +1 -0
- package/dist/interaction/Navigation.d.ts +17 -0
- package/dist/interaction/Navigation.d.ts.map +1 -0
- package/dist/interaction/Navigation.js +28 -0
- package/dist/interaction/Navigation.js.map +1 -0
- package/dist/interaction/PageAdapter.d.ts +32 -0
- package/dist/interaction/PageAdapter.d.ts.map +1 -0
- package/dist/interaction/PageAdapter.js +62 -0
- package/dist/interaction/PageAdapter.js.map +1 -0
- package/dist/interaction/Waits.d.ts +3 -0
- package/dist/interaction/Waits.d.ts.map +1 -0
- package/dist/interaction/Waits.js +4 -0
- package/dist/interaction/Waits.js.map +1 -0
- package/dist/interaction/index.d.ts +10 -0
- package/dist/interaction/index.d.ts.map +1 -0
- package/dist/interaction/index.js +10 -0
- package/dist/interaction/index.js.map +1 -0
- package/dist/interaction/textToKeystrokeEvents.d.ts +13 -0
- package/dist/interaction/textToKeystrokeEvents.d.ts.map +1 -0
- package/dist/interaction/textToKeystrokeEvents.js +15 -0
- package/dist/interaction/textToKeystrokeEvents.js.map +1 -0
- package/dist/logging/ConsoleLogger.d.ts +12 -0
- package/dist/logging/ConsoleLogger.d.ts.map +1 -0
- package/dist/logging/ConsoleLogger.js +42 -0
- package/dist/logging/ConsoleLogger.js.map +1 -0
- package/dist/logging/Logger.d.ts +14 -0
- package/dist/logging/Logger.d.ts.map +1 -0
- package/dist/logging/Logger.js +2 -0
- package/dist/logging/Logger.js.map +1 -0
- package/dist/logging/MemoryLogger.d.ts +10 -0
- package/dist/logging/MemoryLogger.d.ts.map +1 -0
- package/dist/logging/MemoryLogger.js +28 -0
- package/dist/logging/MemoryLogger.js.map +1 -0
- package/dist/logging/NullLogger.d.ts +8 -0
- package/dist/logging/NullLogger.d.ts.map +1 -0
- package/dist/logging/NullLogger.js +7 -0
- package/dist/logging/NullLogger.js.map +1 -0
- package/dist/logging/index.d.ts +5 -0
- package/dist/logging/index.d.ts.map +1 -0
- package/dist/logging/index.js +5 -0
- package/dist/logging/index.js.map +1 -0
- package/dist/sites/example/example.actor.d.ts +6 -0
- package/dist/sites/example/example.actor.d.ts.map +1 -0
- package/dist/sites/example/example.actor.js +47 -0
- package/dist/sites/example/example.actor.js.map +1 -0
- package/dist/sites/example/example.selectors.d.ts +18 -0
- package/dist/sites/example/example.selectors.d.ts.map +1 -0
- package/dist/sites/example/example.selectors.js +18 -0
- package/dist/sites/example/example.selectors.js.map +1 -0
- package/dist/sites/example/example.types.d.ts +16 -0
- package/dist/sites/example/example.types.d.ts.map +1 -0
- package/dist/sites/example/example.types.js +2 -0
- package/dist/sites/example/example.types.js.map +1 -0
- package/dist/sites/example/index.d.ts +4 -0
- package/dist/sites/example/index.d.ts.map +1 -0
- package/dist/sites/example/index.js +4 -0
- package/dist/sites/example/index.js.map +1 -0
- package/dist/sites/index.d.ts +4 -0
- package/dist/sites/index.d.ts.map +1 -0
- package/dist/sites/index.js +4 -0
- package/dist/sites/index.js.map +1 -0
- package/dist/sites/myvistage-com/index.d.ts +4 -0
- package/dist/sites/myvistage-com/index.d.ts.map +1 -0
- package/dist/sites/myvistage-com/index.js +4 -0
- package/dist/sites/myvistage-com/index.js.map +1 -0
- package/dist/sites/myvistage-com/myvistage-com.actor.d.ts +6 -0
- package/dist/sites/myvistage-com/myvistage-com.actor.d.ts.map +1 -0
- package/dist/sites/myvistage-com/myvistage-com.actor.js +44 -0
- package/dist/sites/myvistage-com/myvistage-com.actor.js.map +1 -0
- package/dist/sites/myvistage-com/myvistage-com.selectors.d.ts +15 -0
- package/dist/sites/myvistage-com/myvistage-com.selectors.d.ts.map +1 -0
- package/dist/sites/myvistage-com/myvistage-com.selectors.js +15 -0
- package/dist/sites/myvistage-com/myvistage-com.selectors.js.map +1 -0
- package/dist/sites/myvistage-com/myvistage-com.types.d.ts +16 -0
- package/dist/sites/myvistage-com/myvistage-com.types.d.ts.map +1 -0
- package/dist/sites/myvistage-com/myvistage-com.types.js +2 -0
- package/dist/sites/myvistage-com/myvistage-com.types.js.map +1 -0
- package/dist/sites/upwork-com/index.d.ts +6 -0
- package/dist/sites/upwork-com/index.d.ts.map +1 -0
- package/dist/sites/upwork-com/index.js +6 -0
- package/dist/sites/upwork-com/index.js.map +1 -0
- package/dist/sites/upwork-com/upwork-com.actor.d.ts +6 -0
- package/dist/sites/upwork-com/upwork-com.actor.d.ts.map +1 -0
- package/dist/sites/upwork-com/upwork-com.actor.js +82 -0
- package/dist/sites/upwork-com/upwork-com.actor.js.map +1 -0
- package/dist/sites/upwork-com/upwork-com.runner.d.ts +2 -0
- package/dist/sites/upwork-com/upwork-com.runner.d.ts.map +1 -0
- package/dist/sites/upwork-com/upwork-com.runner.js +14 -0
- package/dist/sites/upwork-com/upwork-com.runner.js.map +1 -0
- package/dist/sites/upwork-com/upwork-com.selectors.d.ts +11 -0
- package/dist/sites/upwork-com/upwork-com.selectors.d.ts.map +1 -0
- package/dist/sites/upwork-com/upwork-com.selectors.js +11 -0
- package/dist/sites/upwork-com/upwork-com.selectors.js.map +1 -0
- package/dist/sites/upwork-com/upwork-com.types.d.ts +88 -0
- package/dist/sites/upwork-com/upwork-com.types.d.ts.map +1 -0
- package/dist/sites/upwork-com/upwork-com.types.js +63 -0
- package/dist/sites/upwork-com/upwork-com.types.js.map +1 -0
- package/dist/sites/upwork-com/upwork-com.util.d.ts +4 -0
- package/dist/sites/upwork-com/upwork-com.util.d.ts.map +1 -0
- package/dist/sites/upwork-com/upwork-com.util.js +43 -0
- package/dist/sites/upwork-com/upwork-com.util.js.map +1 -0
- package/dist/utils/delay.d.ts +2 -0
- package/dist/utils/delay.d.ts.map +1 -0
- package/dist/utils/delay.js +6 -0
- package/dist/utils/delay.js.map +1 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +6 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/invariant.d.ts +2 -0
- package/dist/utils/invariant.d.ts.map +1 -0
- package/dist/utils/invariant.js +7 -0
- package/dist/utils/invariant.js.map +1 -0
- package/dist/utils/redact.d.ts +6 -0
- package/dist/utils/redact.d.ts.map +1 -0
- package/dist/utils/redact.js +40 -0
- package/dist/utils/redact.js.map +1 -0
- package/dist/utils/retry.d.ts +8 -0
- package/dist/utils/retry.d.ts.map +1 -0
- package/dist/utils/retry.js +23 -0
- package/dist/utils/retry.js.map +1 -0
- package/dist/utils/url.d.ts +2 -0
- package/dist/utils/url.d.ts.map +1 -0
- package/dist/utils/url.js +9 -0
- package/dist/utils/url.js.map +1 -0
- package/package.json +39 -0
- package/src/auth/AuthStateDetector.ts +18 -0
- package/src/auth/CredentialsProvider.ts +48 -0
- package/src/auth/LoginFlow.ts +332 -0
- package/src/auth/LoginFlow.types.ts +141 -0
- package/src/auth/SessionStore.ts +21 -0
- package/src/auth/index.ts +5 -0
- package/src/browser/BrowserFactory.ts +253 -0
- package/src/browser/BrowserSession.ts +50 -0
- package/src/browser/PuppeteerLike.ts +65 -0
- package/src/browser/RuntimeConfig.ts +152 -0
- package/src/browser/index.ts +5 -0
- package/src/browser/profileValidation.ts +73 -0
- package/src/cli/run.ts +112 -0
- package/src/core/Actor.ts +167 -0
- package/src/core/ActorContext.ts +34 -0
- package/src/core/ActorRegistry.ts +26 -0
- package/src/core/ActorRunner.ts +240 -0
- package/src/core/defineActor.ts +5 -0
- package/src/core/index.ts +5 -0
- package/src/errors/AuthError.ts +7 -0
- package/src/errors/AutomationError.ts +26 -0
- package/src/errors/ConfigError.ts +7 -0
- package/src/errors/ExtractionError.ts +7 -0
- package/src/errors/NavigationError.ts +7 -0
- package/src/errors/SelectorError.ts +10 -0
- package/src/errors/index.ts +6 -0
- package/src/extraction/Extractor.ts +65 -0
- package/src/extraction/Pagination.ts +47 -0
- package/src/extraction/index.ts +2 -0
- package/src/index.ts +9 -0
- package/src/interaction/FieldClearer.ts +73 -0
- package/src/interaction/Forms.ts +27 -0
- package/src/interaction/GhostCursorAdapter.ts +79 -0
- package/src/interaction/HumanInteractor.ts +32 -0
- package/src/interaction/HumanTyping.ts +157 -0
- package/src/interaction/NativePuppeteerInteractor.ts +68 -0
- package/src/interaction/Navigation.ts +37 -0
- package/src/interaction/PageAdapter.ts +86 -0
- package/src/interaction/Waits.ts +5 -0
- package/src/interaction/index.ts +9 -0
- package/src/logging/ConsoleLogger.ts +44 -0
- package/src/logging/Logger.ts +15 -0
- package/src/logging/MemoryLogger.ts +34 -0
- package/src/logging/NullLogger.ts +8 -0
- package/src/logging/index.ts +4 -0
- package/src/sites/example/example.actor.ts +53 -0
- package/src/sites/example/example.selectors.ts +17 -0
- package/src/sites/example/example.types.ts +18 -0
- package/src/sites/example/index.ts +3 -0
- package/src/sites/index.ts +3 -0
- package/src/sites/myvistage-com/index.ts +3 -0
- package/src/sites/myvistage-com/login-action-list.json +349 -0
- package/src/sites/myvistage-com/myvistage-com.actor.ts +50 -0
- package/src/sites/myvistage-com/myvistage-com.selectors.ts +14 -0
- package/src/sites/myvistage-com/myvistage-com.types.ts +18 -0
- package/src/sites/myvistage-com/post-comment-action.json +81 -0
- package/src/sites/upwork-com/index.ts +6 -0
- package/src/sites/upwork-com/upwork-com.actor.ts +97 -0
- package/src/sites/upwork-com/upwork-com.runner.ts +17 -0
- package/src/sites/upwork-com/upwork-com.selectors.ts +10 -0
- package/src/sites/upwork-com/upwork-com.types.ts +102 -0
- package/src/sites/upwork-com/upwork-com.util.ts +41 -0
- package/src/utils/delay.ts +4 -0
- package/src/utils/index.ts +5 -0
- package/src/utils/invariant.ts +7 -0
- package/src/utils/redact.ts +53 -0
- package/src/utils/retry.ts +31 -0
- package/src/utils/url.ts +7 -0
- package/tests/fixtures/FakeCredentialsProvider.ts +12 -0
- package/tests/fixtures/FakeCursor.ts +48 -0
- package/tests/fixtures/FakePage.ts +266 -0
- package/tests/fixtures/makeContext.ts +76 -0
- package/tests/unit/auth/AuthStateDetector.test.ts +80 -0
- package/tests/unit/auth/LoginFlow.test.ts +296 -0
- package/tests/unit/browser/BrowserFactory.test.ts +370 -0
- package/tests/unit/core/ActorRunner.test.ts +370 -0
- package/tests/unit/core/defineActor.test.ts +112 -0
- package/tests/unit/extraction/Extractor.test.ts +48 -0
- package/tests/unit/extraction/Pagination.test.ts +54 -0
- package/tests/unit/interaction/FieldClearer.test.ts +29 -0
- package/tests/unit/interaction/Forms.test.ts +35 -0
- package/tests/unit/interaction/GhostCursorAdapter.test.ts +68 -0
- package/tests/unit/interaction/HumanTyping.test.ts +54 -0
- package/tests/unit/interaction/NativePuppeteerInteractor.test.ts +22 -0
- package/tests/unit/interaction/PageAdapter.test.ts +25 -0
- package/tests/unit/logging/redact.test.ts +36 -0
- package/tests/unit/sites/myvistage-com.actor.test.ts +19 -0
- package/tests/unit/sites/myvistage-com.login.test.ts +22 -0
- package/tests/unit/sites/myvistage-com.postComment.test.ts +70 -0
- package/tests/unit/sites/upwork-com.login.test.ts +52 -0
- package/tsconfig.build.json +9 -0
- package/tsconfig.json +22 -0
- package/vitest.config.ts +12 -0
package/README.md
ADDED
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
# Puppeteer Actor Framework
|
|
2
|
+
|
|
3
|
+
A TypeScript framework for building website-specific Puppeteer scrapers and actors with reusable login, navigation, extraction, pagination, and human-like interaction abstractions.
|
|
4
|
+
|
|
5
|
+
The browser runtime supports three practical flows:
|
|
6
|
+
|
|
7
|
+
1. Launch installed Chrome with an existing persistent profile.
|
|
8
|
+
2. Attach to an already-running Chrome through a local DevTools / remote-debugging endpoint.
|
|
9
|
+
3. Try flow 1 first, and if Chrome reports that the profile is already running, automatically fall back to flow 2.
|
|
10
|
+
|
|
11
|
+
That third flow is the default for `existing-profile` mode. It lets the caller pass a normal Chrome profile config while still supporting multiple concurrent actors against a single debug-enabled Chrome host.
|
|
12
|
+
|
|
13
|
+
## What it gives you
|
|
14
|
+
|
|
15
|
+
- Existing Chrome profile launch via `userDataDir` and optional `--profile-directory`.
|
|
16
|
+
- Automatic profile-lock fallback through Puppeteer `connect()`.
|
|
17
|
+
- Explicit remote-debugging mode using `browserURL` or `browserWSEndpoint`.
|
|
18
|
+
- `browser.defaultBrowserContext()` usage instead of isolated contexts.
|
|
19
|
+
- Fresh tab per connected actor by default, so simultaneous automations do not fight over the same tab.
|
|
20
|
+
- Connected sessions call `browser.disconnect()` instead of closing the shared browser.
|
|
21
|
+
- Reusable `LoginFlow` for simple and multi-step username/password login when the existing profile is not already authenticated.
|
|
22
|
+
- `ghost-cursor` adapter behind a `HumanInteractor` interface.
|
|
23
|
+
- Human-like key-by-key typing at approximately 65 WPM by default, with small randomized inter-key jitter.
|
|
24
|
+
- Login-flow `clearFieldBeforeTyping` support that selects and deletes existing username/password field contents before typing.
|
|
25
|
+
- Ordered multi-step login flows for username-first/password-second forms like Apple ID, Upwork, and similar staged UIs.
|
|
26
|
+
- Strict TypeScript configuration and Vitest unit tests with fake browser/page/cursor fixtures.
|
|
27
|
+
|
|
28
|
+
## Install
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Verify
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm run check
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
This runs:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npm run typecheck
|
|
44
|
+
npm test
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Existing profile mode with automatic running-Chrome fallback
|
|
48
|
+
|
|
49
|
+
Use the parent Chrome user data directory as `userDataDir`, and use `profileDirectory` for the nested profile folder.
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
import { ActorRunner, exampleActor } from 'puppeteer-actor-framework';
|
|
53
|
+
|
|
54
|
+
const runner = new ActorRunner({
|
|
55
|
+
config: {
|
|
56
|
+
browser: {
|
|
57
|
+
mode: 'existing-profile',
|
|
58
|
+
userDataDir: '/Users/alex/ChromeAutomation/UserData',
|
|
59
|
+
profileDirectory: 'Default',
|
|
60
|
+
channel: 'chrome',
|
|
61
|
+
headless: false,
|
|
62
|
+
runningInstance: {
|
|
63
|
+
enabled: true,
|
|
64
|
+
remoteDebuggingHost: '127.0.0.1',
|
|
65
|
+
remoteDebuggingPort: 9222,
|
|
66
|
+
reuseExistingPage: false,
|
|
67
|
+
disconnectOnFinish: true
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const rows = await runner.run(exampleActor, 'scrapeDashboard', { limit: 20 });
|
|
74
|
+
console.log(rows);
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Behavior:
|
|
78
|
+
|
|
79
|
+
```txt
|
|
80
|
+
Chrome profile not already running:
|
|
81
|
+
puppeteer.launch({ userDataDir, args: ['--profile-directory=Default'] })
|
|
82
|
+
|
|
83
|
+
Chrome profile already running:
|
|
84
|
+
puppeteer.connect({ browserURL: 'http://127.0.0.1:9222' })
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
`runningInstance.enabled` defaults to `true`, so this fallback happens automatically when a profile-lock launch error is detected. To disable it:
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
browser: {
|
|
91
|
+
mode: 'existing-profile',
|
|
92
|
+
userDataDir: '/Users/alex/ChromeAutomation/UserData',
|
|
93
|
+
profileDirectory: 'Default',
|
|
94
|
+
runningInstance: { enabled: false }
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Correct profile path usage:
|
|
99
|
+
|
|
100
|
+
```txt
|
|
101
|
+
userDataDir: /Users/alex/ChromeAutomation/UserData
|
|
102
|
+
profileDirectory: Default
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Incorrect:
|
|
106
|
+
|
|
107
|
+
```txt
|
|
108
|
+
userDataDir: /Users/alex/ChromeAutomation/UserData/Default
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Explicit remote-debugging mode
|
|
112
|
+
|
|
113
|
+
Use this when you know Chrome is already running and you only want to attach.
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
const runner = new ActorRunner({
|
|
117
|
+
config: {
|
|
118
|
+
browser: {
|
|
119
|
+
mode: 'remote-debugging',
|
|
120
|
+
browserURL: 'http://127.0.0.1:9222',
|
|
121
|
+
reuseExistingPage: false
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
In connect mode, `reuseExistingPage` defaults to `false`, so each actor run opens a fresh tab in the connected Chrome instance.
|
|
128
|
+
|
|
129
|
+
## Enabling Chrome's debug endpoint
|
|
130
|
+
|
|
131
|
+
Start Chrome with a local remote-debugging endpoint and a persistent automation profile. Keep the endpoint bound to `127.0.0.1` unless you have a secured tunneling setup.
|
|
132
|
+
|
|
133
|
+
### macOS
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
mkdir -p "$HOME/.chrome-automation/user-data"
|
|
137
|
+
|
|
138
|
+
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \
|
|
139
|
+
--remote-debugging-address=127.0.0.1 \
|
|
140
|
+
--remote-debugging-port=9222 \
|
|
141
|
+
--user-data-dir="$HOME/.chrome-automation/user-data" \
|
|
142
|
+
--profile-directory="Default" \
|
|
143
|
+
--no-first-run \
|
|
144
|
+
--no-default-browser-check
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Linux
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
mkdir -p "$HOME/.chrome-automation/user-data"
|
|
151
|
+
|
|
152
|
+
google-chrome \
|
|
153
|
+
--remote-debugging-address=127.0.0.1 \
|
|
154
|
+
--remote-debugging-port=9222 \
|
|
155
|
+
--user-data-dir="$HOME/.chrome-automation/user-data" \
|
|
156
|
+
--profile-directory="Default" \
|
|
157
|
+
--no-first-run \
|
|
158
|
+
--no-default-browser-check
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Windows PowerShell
|
|
162
|
+
|
|
163
|
+
```powershell
|
|
164
|
+
New-Item -ItemType Directory -Force "$env:USERPROFILE\.chrome-automation\user-data"
|
|
165
|
+
|
|
166
|
+
& "C:\Program Files\Google\Chrome\Application\chrome.exe" `
|
|
167
|
+
--remote-debugging-address=127.0.0.1 `
|
|
168
|
+
--remote-debugging-port=9222 `
|
|
169
|
+
--user-data-dir="$env:USERPROFILE\.chrome-automation\user-data" `
|
|
170
|
+
--profile-directory="Default" `
|
|
171
|
+
--no-first-run `
|
|
172
|
+
--no-default-browser-check
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Verify the endpoint:
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
curl http://127.0.0.1:9222/json/version
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
You should see JSON containing a `webSocketDebuggerUrl`.
|
|
182
|
+
|
|
183
|
+
## CLI examples
|
|
184
|
+
|
|
185
|
+
Build first:
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
npm run build
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Pass a profile and let the framework launch or connect automatically:
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
CHROME_USER_DATA_DIR="$HOME/.chrome-automation/user-data" \
|
|
195
|
+
CHROME_PROFILE_DIRECTORY="Default" \
|
|
196
|
+
CHROME_REMOTE_DEBUGGING_PORT="9222" \
|
|
197
|
+
node dist/cli/run.js example scrapeDashboard '{"limit": 10}'
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Attach directly to an already-running Chrome:
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
CHROME_REMOTE_DEBUGGING_URL="http://127.0.0.1:9222" \
|
|
204
|
+
node dist/cli/run.js example scrapeDashboard '{"limit": 10}'
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Run multiple actors simultaneously against the same Chrome host:
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
CHROME_USER_DATA_DIR="$HOME/.chrome-automation/user-data" \
|
|
211
|
+
CHROME_PROFILE_DIRECTORY="Default" \
|
|
212
|
+
node dist/cli/run.js example scrapeDashboard '{"limit": 10}' &
|
|
213
|
+
|
|
214
|
+
CHROME_USER_DATA_DIR="$HOME/.chrome-automation/user-data" \
|
|
215
|
+
CHROME_PROFILE_DIRECTORY="Default" \
|
|
216
|
+
node dist/cli/run.js example scrapeDashboard '{"limit": 20}' &
|
|
217
|
+
|
|
218
|
+
wait
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Each connected actor opens its own page and disconnects its Puppeteer client on completion without closing Chrome.
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
## Human-like typing
|
|
225
|
+
|
|
226
|
+
Text entry is key-by-key by default. The framework targets approximately 65 WPM using the standard typing-speed convention of five characters per word, so the default average inter-key interval is about 185 ms. A small symmetric jitter is applied per keystroke so typing is not perfectly mechanical.
|
|
227
|
+
|
|
228
|
+
You can tune typing globally through `RuntimeConfig.interaction.typing`:
|
|
229
|
+
|
|
230
|
+
```ts
|
|
231
|
+
const runner = new ActorRunner({
|
|
232
|
+
config: {
|
|
233
|
+
browser: {
|
|
234
|
+
mode: 'existing-profile',
|
|
235
|
+
userDataDir: '/Users/alex/ChromeAutomation/UserData',
|
|
236
|
+
profileDirectory: 'Default'
|
|
237
|
+
},
|
|
238
|
+
interaction: {
|
|
239
|
+
typing: {
|
|
240
|
+
targetWordsPerMinute: 65,
|
|
241
|
+
intervalJitterMs: 18,
|
|
242
|
+
minimumIntervalMs: 20
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
You can also tune a specific form field or actor task:
|
|
250
|
+
|
|
251
|
+
```ts
|
|
252
|
+
await context.forms.fillText('#search', 'quarterly report', {
|
|
253
|
+
typing: {
|
|
254
|
+
targetWordsPerMinute: 65,
|
|
255
|
+
intervalJitterMs: 12
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
To disable human typing for a field and send the whole value through Puppeteer's bulk keyboard input:
|
|
261
|
+
|
|
262
|
+
```ts
|
|
263
|
+
await context.forms.fillText('#fast-field', 'value', {
|
|
264
|
+
typing: { enabled: false }
|
|
265
|
+
});
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
## Login field clearing
|
|
269
|
+
|
|
270
|
+
The standardized login flow now clears username and password fields by selecting the existing contents, pressing `Backspace`, and then typing the new value. This is enabled by default.
|
|
271
|
+
|
|
272
|
+
```ts
|
|
273
|
+
auth: defineLoginFlow({
|
|
274
|
+
loginUrl: 'https://example.com/login',
|
|
275
|
+
credentials: { id: 'my-site' },
|
|
276
|
+
selectors: {
|
|
277
|
+
username: '#email',
|
|
278
|
+
password: '#password',
|
|
279
|
+
submit: 'button[type="submit"]',
|
|
280
|
+
loggedInSignal: '[data-testid="account-menu"]'
|
|
281
|
+
},
|
|
282
|
+
behavior: {
|
|
283
|
+
clearFieldBeforeTyping: true,
|
|
284
|
+
typing: {
|
|
285
|
+
targetWordsPerMinute: 65,
|
|
286
|
+
intervalJitterMs: 18
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
})
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
Set `clearFieldBeforeTyping: false` only for unusual sites where clearing fields breaks the login widget.
|
|
293
|
+
|
|
294
|
+
## Multi-step login forms
|
|
295
|
+
|
|
296
|
+
Some sites do not show the password field until after the username step. For those cases, keep `selectors.loggedInSignal` and define an ordered `steps` array. The simple `selectors.username/password/submit` fields become optional because the steps provide each field and button.
|
|
297
|
+
|
|
298
|
+
```ts
|
|
299
|
+
auth: defineLoginFlow({
|
|
300
|
+
loginUrl: 'https://example.com/login',
|
|
301
|
+
credentials: {
|
|
302
|
+
id: 'staged-site',
|
|
303
|
+
usernameEnv: 'STAGED_SITE_USERNAME',
|
|
304
|
+
passwordEnv: 'STAGED_SITE_PASSWORD'
|
|
305
|
+
},
|
|
306
|
+
selectors: {
|
|
307
|
+
loggedInSignal: '[data-testid="account-menu"]',
|
|
308
|
+
errorMessage: '[data-testid="login-error"]'
|
|
309
|
+
},
|
|
310
|
+
behavior: {
|
|
311
|
+
clearFieldBeforeTyping: true,
|
|
312
|
+
errorTimeoutMs: 750,
|
|
313
|
+
typing: {
|
|
314
|
+
targetWordsPerMinute: 65,
|
|
315
|
+
intervalJitterMs: 18
|
|
316
|
+
}
|
|
317
|
+
},
|
|
318
|
+
steps: [
|
|
319
|
+
{
|
|
320
|
+
type: 'fill',
|
|
321
|
+
name: 'username',
|
|
322
|
+
selector: '#username',
|
|
323
|
+
credential: 'username'
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
type: 'click',
|
|
327
|
+
name: 'continue to password',
|
|
328
|
+
selector: 'button[type="submit"]',
|
|
329
|
+
waitForSelector: '#password',
|
|
330
|
+
waitForSelectorTimeoutMs: 10_000
|
|
331
|
+
},
|
|
332
|
+
{
|
|
333
|
+
type: 'fill',
|
|
334
|
+
name: 'password',
|
|
335
|
+
selector: '#password',
|
|
336
|
+
credential: 'password'
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
type: 'click',
|
|
340
|
+
name: 'submit password',
|
|
341
|
+
selector: 'button[type="submit"]',
|
|
342
|
+
submit: true,
|
|
343
|
+
waitForNavigation: true,
|
|
344
|
+
navigationOptions: { waitUntil: 'domcontentloaded' }
|
|
345
|
+
}
|
|
346
|
+
]
|
|
347
|
+
})
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
The `click` step can wait for the next stage with `waitForSelector`. If `selectors.errorMessage` is configured, the framework checks for that error after click/wait steps, so an invalid username can fail cleanly before the password field ever appears.
|
|
351
|
+
|
|
352
|
+
Each fill step can override the global login behavior:
|
|
353
|
+
|
|
354
|
+
```ts
|
|
355
|
+
steps: [
|
|
356
|
+
{
|
|
357
|
+
type: 'fill',
|
|
358
|
+
selector: '#username',
|
|
359
|
+
credential: 'username',
|
|
360
|
+
clearFieldBeforeTyping: true
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
type: 'fill',
|
|
364
|
+
selector: '#password',
|
|
365
|
+
credential: 'password',
|
|
366
|
+
clearFieldBeforeTyping: false,
|
|
367
|
+
typing: { targetWordsPerMinute: 72, intervalJitterMs: 10 }
|
|
368
|
+
}
|
|
369
|
+
]
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
The `submit: true` flag marks the final button step, so existing `beforeSubmit` and `afterSubmit` hooks still run around that click. For unusual login screens, a step can also provide `before` and `after` hooks, or you can insert a custom hook step:
|
|
373
|
+
|
|
374
|
+
```ts
|
|
375
|
+
steps: [
|
|
376
|
+
{ type: 'fill', selector: '#email', credential: 'username' },
|
|
377
|
+
{ type: 'click', selector: '#continue', waitForSelector: '#password' },
|
|
378
|
+
{
|
|
379
|
+
type: 'hook',
|
|
380
|
+
name: 'accept optional prompt',
|
|
381
|
+
run: async context => {
|
|
382
|
+
if (await context.page.exists('#remember-device', { timeout: 500 })) {
|
|
383
|
+
await context.cursor.click('#remember-device');
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
},
|
|
387
|
+
{ type: 'fill', selector: '#password', credential: 'password' },
|
|
388
|
+
{ type: 'click', selector: '#sign-in', submit: true }
|
|
389
|
+
]
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
## Creating a site actor
|
|
393
|
+
|
|
394
|
+
```ts
|
|
395
|
+
import { defineActor, defineLoginFlow } from 'puppeteer-actor-framework';
|
|
396
|
+
|
|
397
|
+
export const mySiteActor = defineActor({
|
|
398
|
+
id: 'my-site',
|
|
399
|
+
baseUrl: 'https://example.com',
|
|
400
|
+
auth: defineLoginFlow({
|
|
401
|
+
loginUrl: 'https://example.com/login',
|
|
402
|
+
credentials: {
|
|
403
|
+
id: 'my-site',
|
|
404
|
+
usernameEnv: 'MY_SITE_USERNAME',
|
|
405
|
+
passwordEnv: 'MY_SITE_PASSWORD'
|
|
406
|
+
},
|
|
407
|
+
selectors: {
|
|
408
|
+
username: '#email',
|
|
409
|
+
password: '#password',
|
|
410
|
+
submit: 'button[type="submit"]',
|
|
411
|
+
loggedInSignal: '[data-testid="account-menu"]'
|
|
412
|
+
}
|
|
413
|
+
}),
|
|
414
|
+
tasks: {
|
|
415
|
+
scrapeDashboard: async context => {
|
|
416
|
+
await context.nav.goto('/dashboard');
|
|
417
|
+
return context.extract.textList('[data-testid="dashboard-row"]');
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
});
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
## Important operational notes
|
|
424
|
+
|
|
425
|
+
Chrome can lock a profile while it is already open. This framework responds by connecting to the local debug endpoint when `runningInstance.enabled` is true.
|
|
426
|
+
|
|
427
|
+
Recent Chrome versions require a non-standard `--user-data-dir` when using remote debugging. The recommended setup is a dedicated persistent automation profile, such as:
|
|
428
|
+
|
|
429
|
+
```txt
|
|
430
|
+
~/.chrome-automation/user-data
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
Log into the required sites once in that Chrome window, then reuse the profile for automation.
|
|
434
|
+
|
|
435
|
+
Do not expose the remote debugging port publicly. Bind it to `127.0.0.1` unless you have a separately secured tunnel. Use this for legitimate automation and scraping you are authorized to perform; this project does not include CAPTCHA bypassing, stealth evasion, credential harvesting, or anti-bot circumvention logic.
|
package/ai-gen.config.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export const config = {
|
|
2
|
+
"repoRoot": ".",
|
|
3
|
+
"generationsDir": ".ai/generators",
|
|
4
|
+
"workflowsDir": ".ai/workflows",
|
|
5
|
+
"model": "gpt-5.3-codex",
|
|
6
|
+
"maxToolRounds": 100,
|
|
7
|
+
"maxContextFileSizeBytes": 60000,
|
|
8
|
+
"defaultMaxOutputFiles": 10,
|
|
9
|
+
"ignore": [
|
|
10
|
+
".git",
|
|
11
|
+
"node_modules",
|
|
12
|
+
"dist",
|
|
13
|
+
"build",
|
|
14
|
+
".next",
|
|
15
|
+
".turbo",
|
|
16
|
+
".cache",
|
|
17
|
+
"coverage",
|
|
18
|
+
".idea",
|
|
19
|
+
".vscode",
|
|
20
|
+
".langgraph_api",
|
|
21
|
+
".langgraph_checkpoint",
|
|
22
|
+
".easigen",
|
|
23
|
+
"dist",
|
|
24
|
+
|
|
25
|
+
"package-lock.json",
|
|
26
|
+
],
|
|
27
|
+
"offLimits": [
|
|
28
|
+
".env",
|
|
29
|
+
".env.*",
|
|
30
|
+
"*.pem",
|
|
31
|
+
"*.key",
|
|
32
|
+
"*.crt",
|
|
33
|
+
"*.p12",
|
|
34
|
+
"*.pfx",
|
|
35
|
+
".easigen",
|
|
36
|
+
"dist",
|
|
37
|
+
".git",
|
|
38
|
+
|
|
39
|
+
"node_modules",
|
|
40
|
+
"dist",
|
|
41
|
+
"build",
|
|
42
|
+
".next",
|
|
43
|
+
".turbo",
|
|
44
|
+
".cache",
|
|
45
|
+
"coverage",
|
|
46
|
+
".idea",
|
|
47
|
+
".vscode",
|
|
48
|
+
".langgraph_api",
|
|
49
|
+
".langgraph_checkpoint",
|
|
50
|
+
".easigen",
|
|
51
|
+
"dist",
|
|
52
|
+
|
|
53
|
+
"package-lock.json",
|
|
54
|
+
],
|
|
55
|
+
"defaultContext": [],
|
|
56
|
+
"defaultKeywordContexts": [],
|
|
57
|
+
"openai": {
|
|
58
|
+
"timeoutMs": 120000,
|
|
59
|
+
"reconnectPollTimeoutMs": 30000,
|
|
60
|
+
"reconnectPollIntervalMs": 2000
|
|
61
|
+
},
|
|
62
|
+
"logging": {
|
|
63
|
+
"level": "info",
|
|
64
|
+
"pretty": true
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
export default config;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ActorContext } from '../core/ActorContext.js';
|
|
2
|
+
import type { LoginFlowDefinition } from './LoginFlow.types.js';
|
|
3
|
+
export declare class AuthStateDetector {
|
|
4
|
+
isLoggedIn(context: ActorContext, definition: LoginFlowDefinition): Promise<boolean>;
|
|
5
|
+
}
|
|
6
|
+
//# sourceMappingURL=AuthStateDetector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthStateDetector.d.ts","sourceRoot":"","sources":["../../src/auth/AuthStateDetector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAEhE,qBAAa,iBAAiB;IACtB,UAAU,CAAC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,mBAAmB,GAAG,OAAO,CAAC,OAAO,CAAC;CAa3F"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export class AuthStateDetector {
|
|
2
|
+
async isLoggedIn(context, definition) {
|
|
3
|
+
if (definition.behavior?.authCheckUrl !== undefined) {
|
|
4
|
+
await context.nav.goto(definition.behavior.authCheckUrl);
|
|
5
|
+
}
|
|
6
|
+
if (definition.hooks?.verifyLoggedIn !== undefined) {
|
|
7
|
+
return Boolean(await definition.hooks.verifyLoggedIn(context));
|
|
8
|
+
}
|
|
9
|
+
return context.page.exists(definition.selectors.loggedInSignal, {
|
|
10
|
+
timeout: definition.behavior?.loggedInTimeoutMs ?? 2_000
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=AuthStateDetector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthStateDetector.js","sourceRoot":"","sources":["../../src/auth/AuthStateDetector.ts"],"names":[],"mappings":"AAGA,MAAM,OAAO,iBAAiB;IAC5B,KAAK,CAAC,UAAU,CAAC,OAAqB,EAAE,UAA+B;QACrE,IAAI,UAAU,CAAC,QAAQ,EAAE,YAAY,KAAK,SAAS,EAAE,CAAC;YACpD,MAAM,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;QAC3D,CAAC;QAED,IAAI,UAAU,CAAC,KAAK,EAAE,cAAc,KAAK,SAAS,EAAE,CAAC;YACnD,OAAO,OAAO,CAAC,MAAM,UAAU,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;QACjE,CAAC;QAED,OAAO,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,cAAc,EAAE;YAC9D,OAAO,EAAE,UAAU,CAAC,QAAQ,EAAE,iBAAiB,IAAI,KAAK;SACzD,CAAC,CAAC;IACL,CAAC;CACF"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface Credentials {
|
|
2
|
+
username: string;
|
|
3
|
+
password: string;
|
|
4
|
+
accountId?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface CredentialRef {
|
|
7
|
+
id: string;
|
|
8
|
+
usernameEnv?: string;
|
|
9
|
+
passwordEnv?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface CredentialsProvider {
|
|
12
|
+
getCredentials(ref: CredentialRef): Promise<Credentials>;
|
|
13
|
+
}
|
|
14
|
+
export declare class EnvCredentialsProvider implements CredentialsProvider {
|
|
15
|
+
getCredentials(ref: CredentialRef): Promise<Credentials>;
|
|
16
|
+
}
|
|
17
|
+
export declare class StaticCredentialsProvider implements CredentialsProvider {
|
|
18
|
+
private readonly credentials;
|
|
19
|
+
constructor(credentials: Record<string, Credentials>);
|
|
20
|
+
getCredentials(ref: CredentialRef): Promise<Credentials>;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=CredentialsProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CredentialsProvider.d.ts","sourceRoot":"","sources":["../../src/auth/CredentialsProvider.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,cAAc,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;CAC1D;AAED,qBAAa,sBAAuB,YAAW,mBAAmB;IAC1D,cAAc,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,WAAW,CAAC;CAgB/D;AAED,qBAAa,yBAA0B,YAAW,mBAAmB;IACvD,OAAO,CAAC,QAAQ,CAAC,WAAW;gBAAX,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC;IAE/D,cAAc,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,WAAW,CAAC;CAO/D"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { AuthError } from '../errors/AuthError.js';
|
|
2
|
+
export class EnvCredentialsProvider {
|
|
3
|
+
async getCredentials(ref) {
|
|
4
|
+
const usernameKey = ref.usernameEnv ?? `${ref.id.toUpperCase()}_USERNAME`;
|
|
5
|
+
const passwordKey = ref.passwordEnv ?? `${ref.id.toUpperCase()}_PASSWORD`;
|
|
6
|
+
const username = process.env[usernameKey];
|
|
7
|
+
const password = process.env[passwordKey];
|
|
8
|
+
if (username === undefined || username.length === 0) {
|
|
9
|
+
throw new AuthError(`Missing username environment variable: ${usernameKey}`);
|
|
10
|
+
}
|
|
11
|
+
if (password === undefined || password.length === 0) {
|
|
12
|
+
throw new AuthError(`Missing password environment variable: ${passwordKey}`);
|
|
13
|
+
}
|
|
14
|
+
return { username, password, accountId: ref.id };
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export class StaticCredentialsProvider {
|
|
18
|
+
credentials;
|
|
19
|
+
constructor(credentials) {
|
|
20
|
+
this.credentials = credentials;
|
|
21
|
+
}
|
|
22
|
+
async getCredentials(ref) {
|
|
23
|
+
const credential = this.credentials[ref.id];
|
|
24
|
+
if (credential === undefined) {
|
|
25
|
+
throw new AuthError(`No static credentials registered for credential id: ${ref.id}`);
|
|
26
|
+
}
|
|
27
|
+
return credential;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=CredentialsProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CredentialsProvider.js","sourceRoot":"","sources":["../../src/auth/CredentialsProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAkBnD,MAAM,OAAO,sBAAsB;IACjC,KAAK,CAAC,cAAc,CAAC,GAAkB;QACrC,MAAM,WAAW,GAAG,GAAG,CAAC,WAAW,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC,WAAW,EAAE,WAAW,CAAC;QAC1E,MAAM,WAAW,GAAG,GAAG,CAAC,WAAW,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC,WAAW,EAAE,WAAW,CAAC;QAC1E,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAC1C,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAE1C,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACpD,MAAM,IAAI,SAAS,CAAC,0CAA0C,WAAW,EAAE,CAAC,CAAC;QAC/E,CAAC;QAED,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACpD,MAAM,IAAI,SAAS,CAAC,0CAA0C,WAAW,EAAE,CAAC,CAAC;QAC/E,CAAC;QAED,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC;IACnD,CAAC;CACF;AAED,MAAM,OAAO,yBAAyB;IACP;IAA7B,YAA6B,WAAwC;QAAxC,gBAAW,GAAX,WAAW,CAA6B;IAAG,CAAC;IAEzE,KAAK,CAAC,cAAc,CAAC,GAAkB;QACrC,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC5C,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;YAC7B,MAAM,IAAI,SAAS,CAAC,uDAAuD,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;QACvF,CAAC;QACD,OAAO,UAAU,CAAC;IACpB,CAAC;CACF"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ActorContext } from '../core/ActorContext.js';
|
|
2
|
+
import type { CredentialsProvider } from './CredentialsProvider.js';
|
|
3
|
+
import { AuthStateDetector } from './AuthStateDetector.js';
|
|
4
|
+
import { type LoginFlowDefinition } from './LoginFlow.types.js';
|
|
5
|
+
export declare class LoginFlow {
|
|
6
|
+
private readonly credentialsProvider;
|
|
7
|
+
private readonly detector;
|
|
8
|
+
constructor(credentialsProvider: CredentialsProvider, detector?: AuthStateDetector);
|
|
9
|
+
ensureAuthenticated(context: ActorContext, definition: LoginFlowDefinition): Promise<void>;
|
|
10
|
+
login(context: ActorContext, definition: LoginFlowDefinition): Promise<void>;
|
|
11
|
+
private resolveSteps;
|
|
12
|
+
private executeSteps;
|
|
13
|
+
private executeFillStep;
|
|
14
|
+
private executeClickStep;
|
|
15
|
+
private executeWaitForSelectorStep;
|
|
16
|
+
private waitForNextStageSelector;
|
|
17
|
+
private waitForRequiredSelector;
|
|
18
|
+
private buildFillOptions;
|
|
19
|
+
private mergeStepTyping;
|
|
20
|
+
private resolveFillValue;
|
|
21
|
+
private isCredentialFillStep;
|
|
22
|
+
private clickOptions;
|
|
23
|
+
private shouldCheckForStepError;
|
|
24
|
+
private throwIfConfiguredErrorIsVisible;
|
|
25
|
+
private stepLabel;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=LoginFlow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LoginFlow.d.ts","sourceRoot":"","sources":["../../src/auth/LoginFlow.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAG5D,OAAO,KAAK,EAAe,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAKL,KAAK,mBAAmB,EAGzB,MAAM,sBAAsB,CAAC;AAE9B,qBAAa,SAAS;IAElB,OAAO,CAAC,QAAQ,CAAC,mBAAmB;IACpC,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBADR,mBAAmB,EAAE,mBAAmB,EACxC,QAAQ,oBAA0B;IAG/C,mBAAmB,CAAC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAW1F,KAAK,CAAC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IA0ClF,OAAO,CAAC,YAAY;YAyCN,YAAY;YAiCZ,eAAe;YAkBf,gBAAgB;YAoChB,0BAA0B;YAa1B,wBAAwB;YAexB,uBAAuB;IAkBrC,OAAO,CAAC,gBAAgB;IAsBxB,OAAO,CAAC,eAAe;YAQT,gBAAgB;IAgB9B,OAAO,CAAC,oBAAoB;IAI5B,OAAO,CAAC,YAAY;IAKpB,OAAO,CAAC,uBAAuB;YAIjB,+BAA+B;IAkB7C,OAAO,CAAC,SAAS;CAGlB"}
|