@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.
Files changed (381) hide show
  1. package/.ai/generators/_template.ts +37 -0
  2. package/.ai/generators/abstract.ts +24 -0
  3. package/.ai/generators/actor-task-form-filler.ts +140 -0
  4. package/.ai/generators/actor-task.ts +122 -0
  5. package/.ai/generators/auth-core.ts +126 -0
  6. package/.ai/generators/browser-runtime.ts +114 -0
  7. package/.ai/generators/cli-command.ts +96 -0
  8. package/.ai/generators/core-framework.ts +80 -0
  9. package/.ai/generators/docs.ts +92 -0
  10. package/.ai/generators/error-logging.ts +102 -0
  11. package/.ai/generators/extraction-helper.ts +96 -0
  12. package/.ai/generators/interaction-behavior.ts +129 -0
  13. package/.ai/generators/site-actor.ts +125 -0
  14. package/.ai/generators/site-login-flow.ts +117 -0
  15. package/.ai/generators/unit-test.ts +109 -0
  16. package/.ai/workflows/_template.ts +20 -0
  17. package/.ai/workflows/starter.ts +20 -0
  18. package/README.md +435 -0
  19. package/ai-gen.config.ts +67 -0
  20. package/dist/auth/AuthStateDetector.d.ts +6 -0
  21. package/dist/auth/AuthStateDetector.d.ts.map +1 -0
  22. package/dist/auth/AuthStateDetector.js +14 -0
  23. package/dist/auth/AuthStateDetector.js.map +1 -0
  24. package/dist/auth/CredentialsProvider.d.ts +22 -0
  25. package/dist/auth/CredentialsProvider.d.ts.map +1 -0
  26. package/dist/auth/CredentialsProvider.js +30 -0
  27. package/dist/auth/CredentialsProvider.js.map +1 -0
  28. package/dist/auth/LoginFlow.d.ts +27 -0
  29. package/dist/auth/LoginFlow.d.ts.map +1 -0
  30. package/dist/auth/LoginFlow.js +233 -0
  31. package/dist/auth/LoginFlow.js.map +1 -0
  32. package/dist/auth/LoginFlow.types.d.ts +123 -0
  33. package/dist/auth/LoginFlow.types.d.ts.map +1 -0
  34. package/dist/auth/LoginFlow.types.js +7 -0
  35. package/dist/auth/LoginFlow.types.js.map +1 -0
  36. package/dist/auth/SessionStore.d.ts +16 -0
  37. package/dist/auth/SessionStore.d.ts.map +1 -0
  38. package/dist/auth/SessionStore.js +8 -0
  39. package/dist/auth/SessionStore.js.map +1 -0
  40. package/dist/auth/index.d.ts +6 -0
  41. package/dist/auth/index.d.ts.map +1 -0
  42. package/dist/auth/index.js +6 -0
  43. package/dist/auth/index.js.map +1 -0
  44. package/dist/browser/BrowserFactory.d.ts +16 -0
  45. package/dist/browser/BrowserFactory.d.ts.map +1 -0
  46. package/dist/browser/BrowserFactory.js +209 -0
  47. package/dist/browser/BrowserFactory.js.map +1 -0
  48. package/dist/browser/BrowserSession.d.ts +15 -0
  49. package/dist/browser/BrowserSession.d.ts.map +1 -0
  50. package/dist/browser/BrowserSession.js +42 -0
  51. package/dist/browser/BrowserSession.js.map +1 -0
  52. package/dist/browser/PuppeteerLike.d.ts +45 -0
  53. package/dist/browser/PuppeteerLike.d.ts.map +1 -0
  54. package/dist/browser/PuppeteerLike.js +10 -0
  55. package/dist/browser/PuppeteerLike.js.map +1 -0
  56. package/dist/browser/RuntimeConfig.d.ts +82 -0
  57. package/dist/browser/RuntimeConfig.d.ts.map +1 -0
  58. package/dist/browser/RuntimeConfig.js +64 -0
  59. package/dist/browser/RuntimeConfig.js.map +1 -0
  60. package/dist/browser/index.d.ts +6 -0
  61. package/dist/browser/index.d.ts.map +1 -0
  62. package/dist/browser/index.js +6 -0
  63. package/dist/browser/index.js.map +1 -0
  64. package/dist/browser/profileValidation.d.ts +6 -0
  65. package/dist/browser/profileValidation.d.ts.map +1 -0
  66. package/dist/browser/profileValidation.js +59 -0
  67. package/dist/browser/profileValidation.js.map +1 -0
  68. package/dist/cli/run.d.ts +3 -0
  69. package/dist/cli/run.d.ts.map +1 -0
  70. package/dist/cli/run.js +103 -0
  71. package/dist/cli/run.js.map +1 -0
  72. package/dist/core/Actor.d.ts +54 -0
  73. package/dist/core/Actor.d.ts.map +1 -0
  74. package/dist/core/Actor.js +68 -0
  75. package/dist/core/Actor.js.map +1 -0
  76. package/dist/core/ActorContext.d.ts +32 -0
  77. package/dist/core/ActorContext.d.ts.map +1 -0
  78. package/dist/core/ActorContext.js +2 -0
  79. package/dist/core/ActorContext.js.map +1 -0
  80. package/dist/core/ActorRegistry.d.ts +8 -0
  81. package/dist/core/ActorRegistry.d.ts.map +1 -0
  82. package/dist/core/ActorRegistry.js +22 -0
  83. package/dist/core/ActorRegistry.js.map +1 -0
  84. package/dist/core/ActorRunner.d.ts +57 -0
  85. package/dist/core/ActorRunner.d.ts.map +1 -0
  86. package/dist/core/ActorRunner.js +157 -0
  87. package/dist/core/ActorRunner.js.map +1 -0
  88. package/dist/core/defineActor.d.ts +3 -0
  89. package/dist/core/defineActor.d.ts.map +1 -0
  90. package/dist/core/defineActor.js +4 -0
  91. package/dist/core/defineActor.js.map +1 -0
  92. package/dist/core/index.d.ts +6 -0
  93. package/dist/core/index.d.ts.map +1 -0
  94. package/dist/core/index.js +6 -0
  95. package/dist/core/index.js.map +1 -0
  96. package/dist/errors/AuthError.d.ts +5 -0
  97. package/dist/errors/AuthError.d.ts.map +1 -0
  98. package/dist/errors/AuthError.js +7 -0
  99. package/dist/errors/AuthError.js.map +1 -0
  100. package/dist/errors/AutomationError.d.ts +17 -0
  101. package/dist/errors/AutomationError.d.ts.map +1 -0
  102. package/dist/errors/AutomationError.js +17 -0
  103. package/dist/errors/AutomationError.js.map +1 -0
  104. package/dist/errors/ConfigError.d.ts +5 -0
  105. package/dist/errors/ConfigError.d.ts.map +1 -0
  106. package/dist/errors/ConfigError.js +7 -0
  107. package/dist/errors/ConfigError.js.map +1 -0
  108. package/dist/errors/ExtractionError.d.ts +5 -0
  109. package/dist/errors/ExtractionError.d.ts.map +1 -0
  110. package/dist/errors/ExtractionError.js +7 -0
  111. package/dist/errors/ExtractionError.js.map +1 -0
  112. package/dist/errors/NavigationError.d.ts +5 -0
  113. package/dist/errors/NavigationError.d.ts.map +1 -0
  114. package/dist/errors/NavigationError.js +7 -0
  115. package/dist/errors/NavigationError.js.map +1 -0
  116. package/dist/errors/SelectorError.d.ts +6 -0
  117. package/dist/errors/SelectorError.d.ts.map +1 -0
  118. package/dist/errors/SelectorError.js +9 -0
  119. package/dist/errors/SelectorError.js.map +1 -0
  120. package/dist/errors/index.d.ts +7 -0
  121. package/dist/errors/index.d.ts.map +1 -0
  122. package/dist/errors/index.js +7 -0
  123. package/dist/errors/index.js.map +1 -0
  124. package/dist/extraction/Extractor.d.ts +16 -0
  125. package/dist/extraction/Extractor.d.ts.map +1 -0
  126. package/dist/extraction/Extractor.js +54 -0
  127. package/dist/extraction/Extractor.js.map +1 -0
  128. package/dist/extraction/Pagination.d.ts +16 -0
  129. package/dist/extraction/Pagination.d.ts.map +1 -0
  130. package/dist/extraction/Pagination.js +36 -0
  131. package/dist/extraction/Pagination.js.map +1 -0
  132. package/dist/extraction/index.d.ts +3 -0
  133. package/dist/extraction/index.d.ts.map +1 -0
  134. package/dist/extraction/index.js +3 -0
  135. package/dist/extraction/index.js.map +1 -0
  136. package/dist/index.d.ts +10 -0
  137. package/dist/index.d.ts.map +1 -0
  138. package/dist/index.js +10 -0
  139. package/dist/index.js.map +1 -0
  140. package/dist/interaction/FieldClearer.d.ts +7 -0
  141. package/dist/interaction/FieldClearer.d.ts.map +1 -0
  142. package/dist/interaction/FieldClearer.js +53 -0
  143. package/dist/interaction/FieldClearer.js.map +1 -0
  144. package/dist/interaction/Forms.d.ts +13 -0
  145. package/dist/interaction/Forms.d.ts.map +1 -0
  146. package/dist/interaction/Forms.js +22 -0
  147. package/dist/interaction/Forms.js.map +1 -0
  148. package/dist/interaction/GhostCursorAdapter.d.ts +27 -0
  149. package/dist/interaction/GhostCursorAdapter.d.ts.map +1 -0
  150. package/dist/interaction/GhostCursorAdapter.js +51 -0
  151. package/dist/interaction/GhostCursorAdapter.js.map +1 -0
  152. package/dist/interaction/HumanInteractor.d.ts +29 -0
  153. package/dist/interaction/HumanInteractor.d.ts.map +1 -0
  154. package/dist/interaction/HumanInteractor.js +2 -0
  155. package/dist/interaction/HumanInteractor.js.map +1 -0
  156. package/dist/interaction/HumanTyping.d.ts +43 -0
  157. package/dist/interaction/HumanTyping.d.ts.map +1 -0
  158. package/dist/interaction/HumanTyping.js +85 -0
  159. package/dist/interaction/HumanTyping.js.map +1 -0
  160. package/dist/interaction/NativePuppeteerInteractor.d.ts +20 -0
  161. package/dist/interaction/NativePuppeteerInteractor.d.ts.map +1 -0
  162. package/dist/interaction/NativePuppeteerInteractor.js +47 -0
  163. package/dist/interaction/NativePuppeteerInteractor.js.map +1 -0
  164. package/dist/interaction/Navigation.d.ts +17 -0
  165. package/dist/interaction/Navigation.d.ts.map +1 -0
  166. package/dist/interaction/Navigation.js +28 -0
  167. package/dist/interaction/Navigation.js.map +1 -0
  168. package/dist/interaction/PageAdapter.d.ts +32 -0
  169. package/dist/interaction/PageAdapter.d.ts.map +1 -0
  170. package/dist/interaction/PageAdapter.js +62 -0
  171. package/dist/interaction/PageAdapter.js.map +1 -0
  172. package/dist/interaction/Waits.d.ts +3 -0
  173. package/dist/interaction/Waits.d.ts.map +1 -0
  174. package/dist/interaction/Waits.js +4 -0
  175. package/dist/interaction/Waits.js.map +1 -0
  176. package/dist/interaction/index.d.ts +10 -0
  177. package/dist/interaction/index.d.ts.map +1 -0
  178. package/dist/interaction/index.js +10 -0
  179. package/dist/interaction/index.js.map +1 -0
  180. package/dist/interaction/textToKeystrokeEvents.d.ts +13 -0
  181. package/dist/interaction/textToKeystrokeEvents.d.ts.map +1 -0
  182. package/dist/interaction/textToKeystrokeEvents.js +15 -0
  183. package/dist/interaction/textToKeystrokeEvents.js.map +1 -0
  184. package/dist/logging/ConsoleLogger.d.ts +12 -0
  185. package/dist/logging/ConsoleLogger.d.ts.map +1 -0
  186. package/dist/logging/ConsoleLogger.js +42 -0
  187. package/dist/logging/ConsoleLogger.js.map +1 -0
  188. package/dist/logging/Logger.d.ts +14 -0
  189. package/dist/logging/Logger.d.ts.map +1 -0
  190. package/dist/logging/Logger.js +2 -0
  191. package/dist/logging/Logger.js.map +1 -0
  192. package/dist/logging/MemoryLogger.d.ts +10 -0
  193. package/dist/logging/MemoryLogger.d.ts.map +1 -0
  194. package/dist/logging/MemoryLogger.js +28 -0
  195. package/dist/logging/MemoryLogger.js.map +1 -0
  196. package/dist/logging/NullLogger.d.ts +8 -0
  197. package/dist/logging/NullLogger.d.ts.map +1 -0
  198. package/dist/logging/NullLogger.js +7 -0
  199. package/dist/logging/NullLogger.js.map +1 -0
  200. package/dist/logging/index.d.ts +5 -0
  201. package/dist/logging/index.d.ts.map +1 -0
  202. package/dist/logging/index.js +5 -0
  203. package/dist/logging/index.js.map +1 -0
  204. package/dist/sites/example/example.actor.d.ts +6 -0
  205. package/dist/sites/example/example.actor.d.ts.map +1 -0
  206. package/dist/sites/example/example.actor.js +47 -0
  207. package/dist/sites/example/example.actor.js.map +1 -0
  208. package/dist/sites/example/example.selectors.d.ts +18 -0
  209. package/dist/sites/example/example.selectors.d.ts.map +1 -0
  210. package/dist/sites/example/example.selectors.js +18 -0
  211. package/dist/sites/example/example.selectors.js.map +1 -0
  212. package/dist/sites/example/example.types.d.ts +16 -0
  213. package/dist/sites/example/example.types.d.ts.map +1 -0
  214. package/dist/sites/example/example.types.js +2 -0
  215. package/dist/sites/example/example.types.js.map +1 -0
  216. package/dist/sites/example/index.d.ts +4 -0
  217. package/dist/sites/example/index.d.ts.map +1 -0
  218. package/dist/sites/example/index.js +4 -0
  219. package/dist/sites/example/index.js.map +1 -0
  220. package/dist/sites/index.d.ts +4 -0
  221. package/dist/sites/index.d.ts.map +1 -0
  222. package/dist/sites/index.js +4 -0
  223. package/dist/sites/index.js.map +1 -0
  224. package/dist/sites/myvistage-com/index.d.ts +4 -0
  225. package/dist/sites/myvistage-com/index.d.ts.map +1 -0
  226. package/dist/sites/myvistage-com/index.js +4 -0
  227. package/dist/sites/myvistage-com/index.js.map +1 -0
  228. package/dist/sites/myvistage-com/myvistage-com.actor.d.ts +6 -0
  229. package/dist/sites/myvistage-com/myvistage-com.actor.d.ts.map +1 -0
  230. package/dist/sites/myvistage-com/myvistage-com.actor.js +44 -0
  231. package/dist/sites/myvistage-com/myvistage-com.actor.js.map +1 -0
  232. package/dist/sites/myvistage-com/myvistage-com.selectors.d.ts +15 -0
  233. package/dist/sites/myvistage-com/myvistage-com.selectors.d.ts.map +1 -0
  234. package/dist/sites/myvistage-com/myvistage-com.selectors.js +15 -0
  235. package/dist/sites/myvistage-com/myvistage-com.selectors.js.map +1 -0
  236. package/dist/sites/myvistage-com/myvistage-com.types.d.ts +16 -0
  237. package/dist/sites/myvistage-com/myvistage-com.types.d.ts.map +1 -0
  238. package/dist/sites/myvistage-com/myvistage-com.types.js +2 -0
  239. package/dist/sites/myvistage-com/myvistage-com.types.js.map +1 -0
  240. package/dist/sites/upwork-com/index.d.ts +6 -0
  241. package/dist/sites/upwork-com/index.d.ts.map +1 -0
  242. package/dist/sites/upwork-com/index.js +6 -0
  243. package/dist/sites/upwork-com/index.js.map +1 -0
  244. package/dist/sites/upwork-com/upwork-com.actor.d.ts +6 -0
  245. package/dist/sites/upwork-com/upwork-com.actor.d.ts.map +1 -0
  246. package/dist/sites/upwork-com/upwork-com.actor.js +82 -0
  247. package/dist/sites/upwork-com/upwork-com.actor.js.map +1 -0
  248. package/dist/sites/upwork-com/upwork-com.runner.d.ts +2 -0
  249. package/dist/sites/upwork-com/upwork-com.runner.d.ts.map +1 -0
  250. package/dist/sites/upwork-com/upwork-com.runner.js +14 -0
  251. package/dist/sites/upwork-com/upwork-com.runner.js.map +1 -0
  252. package/dist/sites/upwork-com/upwork-com.selectors.d.ts +11 -0
  253. package/dist/sites/upwork-com/upwork-com.selectors.d.ts.map +1 -0
  254. package/dist/sites/upwork-com/upwork-com.selectors.js +11 -0
  255. package/dist/sites/upwork-com/upwork-com.selectors.js.map +1 -0
  256. package/dist/sites/upwork-com/upwork-com.types.d.ts +88 -0
  257. package/dist/sites/upwork-com/upwork-com.types.d.ts.map +1 -0
  258. package/dist/sites/upwork-com/upwork-com.types.js +63 -0
  259. package/dist/sites/upwork-com/upwork-com.types.js.map +1 -0
  260. package/dist/sites/upwork-com/upwork-com.util.d.ts +4 -0
  261. package/dist/sites/upwork-com/upwork-com.util.d.ts.map +1 -0
  262. package/dist/sites/upwork-com/upwork-com.util.js +43 -0
  263. package/dist/sites/upwork-com/upwork-com.util.js.map +1 -0
  264. package/dist/utils/delay.d.ts +2 -0
  265. package/dist/utils/delay.d.ts.map +1 -0
  266. package/dist/utils/delay.js +6 -0
  267. package/dist/utils/delay.js.map +1 -0
  268. package/dist/utils/index.d.ts +6 -0
  269. package/dist/utils/index.d.ts.map +1 -0
  270. package/dist/utils/index.js +6 -0
  271. package/dist/utils/index.js.map +1 -0
  272. package/dist/utils/invariant.d.ts +2 -0
  273. package/dist/utils/invariant.d.ts.map +1 -0
  274. package/dist/utils/invariant.js +7 -0
  275. package/dist/utils/invariant.js.map +1 -0
  276. package/dist/utils/redact.d.ts +6 -0
  277. package/dist/utils/redact.d.ts.map +1 -0
  278. package/dist/utils/redact.js +40 -0
  279. package/dist/utils/redact.js.map +1 -0
  280. package/dist/utils/retry.d.ts +8 -0
  281. package/dist/utils/retry.d.ts.map +1 -0
  282. package/dist/utils/retry.js +23 -0
  283. package/dist/utils/retry.js.map +1 -0
  284. package/dist/utils/url.d.ts +2 -0
  285. package/dist/utils/url.d.ts.map +1 -0
  286. package/dist/utils/url.js +9 -0
  287. package/dist/utils/url.js.map +1 -0
  288. package/package.json +39 -0
  289. package/src/auth/AuthStateDetector.ts +18 -0
  290. package/src/auth/CredentialsProvider.ts +48 -0
  291. package/src/auth/LoginFlow.ts +332 -0
  292. package/src/auth/LoginFlow.types.ts +141 -0
  293. package/src/auth/SessionStore.ts +21 -0
  294. package/src/auth/index.ts +5 -0
  295. package/src/browser/BrowserFactory.ts +253 -0
  296. package/src/browser/BrowserSession.ts +50 -0
  297. package/src/browser/PuppeteerLike.ts +65 -0
  298. package/src/browser/RuntimeConfig.ts +152 -0
  299. package/src/browser/index.ts +5 -0
  300. package/src/browser/profileValidation.ts +73 -0
  301. package/src/cli/run.ts +112 -0
  302. package/src/core/Actor.ts +167 -0
  303. package/src/core/ActorContext.ts +34 -0
  304. package/src/core/ActorRegistry.ts +26 -0
  305. package/src/core/ActorRunner.ts +240 -0
  306. package/src/core/defineActor.ts +5 -0
  307. package/src/core/index.ts +5 -0
  308. package/src/errors/AuthError.ts +7 -0
  309. package/src/errors/AutomationError.ts +26 -0
  310. package/src/errors/ConfigError.ts +7 -0
  311. package/src/errors/ExtractionError.ts +7 -0
  312. package/src/errors/NavigationError.ts +7 -0
  313. package/src/errors/SelectorError.ts +10 -0
  314. package/src/errors/index.ts +6 -0
  315. package/src/extraction/Extractor.ts +65 -0
  316. package/src/extraction/Pagination.ts +47 -0
  317. package/src/extraction/index.ts +2 -0
  318. package/src/index.ts +9 -0
  319. package/src/interaction/FieldClearer.ts +73 -0
  320. package/src/interaction/Forms.ts +27 -0
  321. package/src/interaction/GhostCursorAdapter.ts +79 -0
  322. package/src/interaction/HumanInteractor.ts +32 -0
  323. package/src/interaction/HumanTyping.ts +157 -0
  324. package/src/interaction/NativePuppeteerInteractor.ts +68 -0
  325. package/src/interaction/Navigation.ts +37 -0
  326. package/src/interaction/PageAdapter.ts +86 -0
  327. package/src/interaction/Waits.ts +5 -0
  328. package/src/interaction/index.ts +9 -0
  329. package/src/logging/ConsoleLogger.ts +44 -0
  330. package/src/logging/Logger.ts +15 -0
  331. package/src/logging/MemoryLogger.ts +34 -0
  332. package/src/logging/NullLogger.ts +8 -0
  333. package/src/logging/index.ts +4 -0
  334. package/src/sites/example/example.actor.ts +53 -0
  335. package/src/sites/example/example.selectors.ts +17 -0
  336. package/src/sites/example/example.types.ts +18 -0
  337. package/src/sites/example/index.ts +3 -0
  338. package/src/sites/index.ts +3 -0
  339. package/src/sites/myvistage-com/index.ts +3 -0
  340. package/src/sites/myvistage-com/login-action-list.json +349 -0
  341. package/src/sites/myvistage-com/myvistage-com.actor.ts +50 -0
  342. package/src/sites/myvistage-com/myvistage-com.selectors.ts +14 -0
  343. package/src/sites/myvistage-com/myvistage-com.types.ts +18 -0
  344. package/src/sites/myvistage-com/post-comment-action.json +81 -0
  345. package/src/sites/upwork-com/index.ts +6 -0
  346. package/src/sites/upwork-com/upwork-com.actor.ts +97 -0
  347. package/src/sites/upwork-com/upwork-com.runner.ts +17 -0
  348. package/src/sites/upwork-com/upwork-com.selectors.ts +10 -0
  349. package/src/sites/upwork-com/upwork-com.types.ts +102 -0
  350. package/src/sites/upwork-com/upwork-com.util.ts +41 -0
  351. package/src/utils/delay.ts +4 -0
  352. package/src/utils/index.ts +5 -0
  353. package/src/utils/invariant.ts +7 -0
  354. package/src/utils/redact.ts +53 -0
  355. package/src/utils/retry.ts +31 -0
  356. package/src/utils/url.ts +7 -0
  357. package/tests/fixtures/FakeCredentialsProvider.ts +12 -0
  358. package/tests/fixtures/FakeCursor.ts +48 -0
  359. package/tests/fixtures/FakePage.ts +266 -0
  360. package/tests/fixtures/makeContext.ts +76 -0
  361. package/tests/unit/auth/AuthStateDetector.test.ts +80 -0
  362. package/tests/unit/auth/LoginFlow.test.ts +296 -0
  363. package/tests/unit/browser/BrowserFactory.test.ts +370 -0
  364. package/tests/unit/core/ActorRunner.test.ts +370 -0
  365. package/tests/unit/core/defineActor.test.ts +112 -0
  366. package/tests/unit/extraction/Extractor.test.ts +48 -0
  367. package/tests/unit/extraction/Pagination.test.ts +54 -0
  368. package/tests/unit/interaction/FieldClearer.test.ts +29 -0
  369. package/tests/unit/interaction/Forms.test.ts +35 -0
  370. package/tests/unit/interaction/GhostCursorAdapter.test.ts +68 -0
  371. package/tests/unit/interaction/HumanTyping.test.ts +54 -0
  372. package/tests/unit/interaction/NativePuppeteerInteractor.test.ts +22 -0
  373. package/tests/unit/interaction/PageAdapter.test.ts +25 -0
  374. package/tests/unit/logging/redact.test.ts +36 -0
  375. package/tests/unit/sites/myvistage-com.actor.test.ts +19 -0
  376. package/tests/unit/sites/myvistage-com.login.test.ts +22 -0
  377. package/tests/unit/sites/myvistage-com.postComment.test.ts +70 -0
  378. package/tests/unit/sites/upwork-com.login.test.ts +52 -0
  379. package/tsconfig.build.json +9 -0
  380. package/tsconfig.json +22 -0
  381. package/vitest.config.ts +12 -0
@@ -0,0 +1,266 @@
1
+ import type { HTTPResponse, WaitForOptions, WaitForSelectorOptions } from 'puppeteer-core';
2
+ import type { BrowserContextLike, BrowserLike, KeyboardLike, PageLike } from '../../src/browser/PuppeteerLike.js';
3
+
4
+ interface FakeElementState {
5
+ textContent?: string;
6
+ attributes?: Record<string, string>;
7
+ value?: string;
8
+ isContentEditable?: boolean;
9
+ selected?: boolean;
10
+ focused?: boolean;
11
+ events?: string[];
12
+ selectionStart?: number;
13
+ selectionEnd?: number;
14
+ scrolled?: boolean;
15
+ }
16
+
17
+ class FakeElement {
18
+ private readonly attributes: Record<string, string>;
19
+
20
+ constructor(private readonly state: FakeElementState = {}) {
21
+ this.attributes = state.attributes ?? {};
22
+ this.state.events ??= [];
23
+ }
24
+
25
+ get textContent(): string {
26
+ return this.state.textContent ?? '';
27
+ }
28
+
29
+ set textContent(value: string) {
30
+ this.state.textContent = value;
31
+ }
32
+
33
+ get value(): string {
34
+ return this.state.value ?? '';
35
+ }
36
+
37
+ set value(value: string) {
38
+ this.state.value = value;
39
+ }
40
+
41
+ get isContentEditable(): boolean {
42
+ return this.state.isContentEditable ?? false;
43
+ }
44
+
45
+ get events(): string[] {
46
+ return this.state.events ?? [];
47
+ }
48
+
49
+ getAttribute(name: string): string | null {
50
+ return this.attributes[name] ?? null;
51
+ }
52
+
53
+ dispatchEvent(event: Event): boolean {
54
+ this.state.events ??= [];
55
+ this.state.events.push(event.type);
56
+ return true;
57
+ }
58
+
59
+ focus(): void {
60
+ this.state.focused = true;
61
+ }
62
+
63
+ select(): void {
64
+ this.state.selected = true;
65
+ this.state.selectionStart = 0;
66
+ this.state.selectionEnd = this.value.length;
67
+ }
68
+
69
+ setSelectionRange(start: number, end: number): void {
70
+ this.state.selected = true;
71
+ this.state.selectionStart = start;
72
+ this.state.selectionEnd = end;
73
+ }
74
+
75
+ scrollIntoView(): void {
76
+ this.state.scrolled = true;
77
+ }
78
+
79
+ querySelectorAll(selector: string): FakeElement[] {
80
+ if (selector === 'thead th') {
81
+ return this.attributes.__headers?.split('|').map(textContent => new FakeElement({ textContent })) ?? [];
82
+ }
83
+ if (selector === 'tbody tr') {
84
+ const rowTexts = this.attributes.__rows?.split('\n').filter(Boolean) ?? [];
85
+ return rowTexts.map(rowText => new FakeTableRow(rowText));
86
+ }
87
+ return [];
88
+ }
89
+ }
90
+
91
+ class FakeTableRow extends FakeElement {
92
+ constructor(private readonly rowText: string) {
93
+ super();
94
+ }
95
+
96
+ override querySelectorAll(selector: string): FakeElement[] {
97
+ if (selector !== 'td') return [];
98
+ return this.rowText.split('|').map(textContent => new FakeElement({ textContent }));
99
+ }
100
+ }
101
+
102
+ export class FakeKeyboard implements KeyboardLike {
103
+ typed: Array<{ text: string; options?: { delay?: number } }> = [];
104
+ pressed: Array<{ key: string; options?: { delay?: number } }> = [];
105
+
106
+ async type(text: string, options?: { delay?: number }): Promise<void> {
107
+ const record: { text: string; options?: { delay?: number } } = { text };
108
+ if (options !== undefined) record.options = options;
109
+ this.typed.push(record);
110
+ }
111
+
112
+ async press(key: string, options?: { delay?: number }): Promise<void> {
113
+ const record: { key: string; options?: { delay?: number } } = { key };
114
+ if (options !== undefined) record.options = options;
115
+ this.pressed.push(record);
116
+ }
117
+ }
118
+
119
+ export class FakePage implements PageLike {
120
+ keyboard = new FakeKeyboard();
121
+ readonly selectors = new Map<string, FakeElementState>();
122
+ readonly selectorLists = new Map<string, FakeElementState[]>();
123
+ readonly gotos: Array<{ url: string; options?: WaitForOptions }> = [];
124
+ readonly waitedSelectors: Array<{ selector: string; options?: WaitForSelectorOptions }> = [];
125
+ readonly waitedNavigations: WaitForOptions[] = [];
126
+ readonly clicked: string[] = [];
127
+ readonly focused: string[] = [];
128
+ defaultTimeout?: number;
129
+ defaultNavigationTimeout?: number;
130
+ currentUrl = 'about:blank';
131
+ pageTitle = 'Fake Page';
132
+ pageContent = '<html></html>';
133
+ screenshots: Record<string, unknown>[] = [];
134
+
135
+ setSelector(selector: string, state: FakeElementState = {}): this {
136
+ this.selectors.set(selector, state);
137
+ return this;
138
+ }
139
+
140
+ setTextList(selector: string, texts: string[]): this {
141
+ this.selectorLists.set(selector, texts.map(textContent => ({ textContent })));
142
+ return this;
143
+ }
144
+
145
+ removeSelector(selector: string): this {
146
+ this.selectors.delete(selector);
147
+ return this;
148
+ }
149
+
150
+ async goto(url: string, options?: WaitForOptions): Promise<HTTPResponse | null> {
151
+ this.currentUrl = url;
152
+ const record: { url: string; options?: WaitForOptions } = { url };
153
+ if (options !== undefined) record.options = options;
154
+ this.gotos.push(record);
155
+ return null;
156
+ }
157
+
158
+ async waitForSelector(selector: string, options?: WaitForSelectorOptions): Promise<unknown> {
159
+ const record: { selector: string; options?: WaitForSelectorOptions } = { selector };
160
+ if (options !== undefined) record.options = options;
161
+ this.waitedSelectors.push(record);
162
+ if (!this.selectors.has(selector) && !this.selectorLists.has(selector)) {
163
+ throw new Error(`Missing selector: ${selector}`);
164
+ }
165
+ return {};
166
+ }
167
+
168
+ async waitForNavigation(options?: WaitForOptions): Promise<HTTPResponse | null> {
169
+ this.waitedNavigations.push(options ?? {});
170
+ return null;
171
+ }
172
+
173
+ async click(selector: string): Promise<void> {
174
+ await this.waitForSelector(selector);
175
+ this.clicked.push(selector);
176
+ }
177
+
178
+ async focus(selector: string): Promise<void> {
179
+ await this.waitForSelector(selector);
180
+ this.focused.push(selector);
181
+ }
182
+
183
+ async $eval<T>(selector: string, pageFunction: (element: Element, ...args: unknown[]) => T, ...args: unknown[]): Promise<T> {
184
+ const state = this.selectors.get(selector);
185
+ if (state === undefined) throw new Error(`Missing selector: ${selector}`);
186
+ return pageFunction(new FakeElement(state) as unknown as Element, ...args);
187
+ }
188
+
189
+ async $$eval<T>(selector: string, pageFunction: (elements: Element[], ...args: unknown[]) => T, ...args: unknown[]): Promise<T> {
190
+ const states = this.selectorLists.get(selector) ?? (this.selectors.has(selector) ? [this.selectors.get(selector)!] : []);
191
+ const elements = states.map(state => new FakeElement(state) as unknown as Element);
192
+ return pageFunction(elements, ...args);
193
+ }
194
+
195
+ async evaluate<T>(pageFunction: (...args: unknown[]) => T, ...args: unknown[]): Promise<T> {
196
+ return pageFunction(...args);
197
+ }
198
+
199
+ url(): string {
200
+ return this.currentUrl;
201
+ }
202
+
203
+ async title(): Promise<string> {
204
+ return this.pageTitle;
205
+ }
206
+
207
+ async content(): Promise<string> {
208
+ return this.pageContent;
209
+ }
210
+
211
+ async screenshot(options?: Record<string, unknown>): Promise<Uint8Array | string> {
212
+ this.screenshots.push(options ?? {});
213
+ return new Uint8Array();
214
+ }
215
+
216
+ setDefaultTimeout(timeout: number): void {
217
+ this.defaultTimeout = timeout;
218
+ }
219
+
220
+ setDefaultNavigationTimeout(timeout: number): void {
221
+ this.defaultNavigationTimeout = timeout;
222
+ }
223
+ }
224
+
225
+ export class FakeBrowserContext implements BrowserContextLike {}
226
+
227
+ export class FakeBrowser implements BrowserLike {
228
+ readonly context = new FakeBrowserContext();
229
+ readonly closeCalls: number[] = [];
230
+ readonly disconnectCalls: number[] = [];
231
+ defaultBrowserContextCalls = 0;
232
+ newPageCalls = 0;
233
+ createBrowserContextCalls = 0;
234
+
235
+ constructor(private readonly pageList: FakePage[] = [new FakePage()]) {}
236
+
237
+ defaultBrowserContext(): BrowserContextLike {
238
+ this.defaultBrowserContextCalls += 1;
239
+ return this.context;
240
+ }
241
+
242
+ async pages(): Promise<PageLike[]> {
243
+ return this.pageList;
244
+ }
245
+
246
+ async newPage(): Promise<PageLike> {
247
+ this.newPageCalls += 1;
248
+ const page = new FakePage();
249
+ this.pageList.push(page);
250
+ return page;
251
+ }
252
+
253
+ // Deliberately not part of BrowserLike. Tests assert BrowserFactory never calls it.
254
+ async createBrowserContext(): Promise<BrowserContextLike> {
255
+ this.createBrowserContextCalls += 1;
256
+ return new FakeBrowserContext();
257
+ }
258
+
259
+ async close(): Promise<void> {
260
+ this.closeCalls.push(Date.now());
261
+ }
262
+
263
+ async disconnect(): Promise<void> {
264
+ this.disconnectCalls.push(Date.now());
265
+ }
266
+ }
@@ -0,0 +1,76 @@
1
+ import fs from 'node:fs';
2
+ import os from 'node:os';
3
+ import path from 'node:path';
4
+ import { BrowserSession } from '../../src/browser/BrowserSession.js';
5
+ import type { RuntimeConfig } from '../../src/browser/RuntimeConfig.js';
6
+ import type { ActorContext, AuthController } from '../../src/core/ActorContext.js';
7
+ import { Extractor } from '../../src/extraction/Extractor.js';
8
+ import { Pagination } from '../../src/extraction/Pagination.js';
9
+ import { FormFiller } from '../../src/interaction/Forms.js';
10
+ import type { HumanInteractor } from '../../src/interaction/HumanInteractor.js';
11
+ import { Navigator } from '../../src/interaction/Navigation.js';
12
+ import { PuppeteerPageAdapter } from '../../src/interaction/PageAdapter.js';
13
+ import { MemoryLogger } from '../../src/logging/MemoryLogger.js';
14
+ import { FakeHumanInteractor } from './FakeCursor.js';
15
+ import { FakeBrowser, FakePage } from './FakePage.js';
16
+
17
+ export interface TestContextParts {
18
+ context: ActorContext;
19
+ fakePage: FakePage;
20
+ fakeInteractor: FakeHumanInteractor;
21
+ logger: MemoryLogger;
22
+ config: RuntimeConfig;
23
+ }
24
+
25
+ export function makeContext(overrides: Partial<{
26
+ page: FakePage;
27
+ interactor: HumanInteractor;
28
+ actorId: string;
29
+ baseUrl: string;
30
+ auth: AuthController;
31
+ }> = {}): TestContextParts {
32
+ const fakePage = overrides.page ?? new FakePage();
33
+ const fakeInteractor = overrides.interactor instanceof FakeHumanInteractor
34
+ ? overrides.interactor
35
+ : new FakeHumanInteractor();
36
+ const userDataDir = fs.mkdtempSync(path.join(os.tmpdir(), 'paf-test-context-'));
37
+ fs.mkdirSync(path.join(userDataDir, 'Default'));
38
+ const config: RuntimeConfig = {
39
+ browser: {
40
+ mode: 'existing-profile',
41
+ userDataDir,
42
+ profileDirectory: 'Default',
43
+ headless: false
44
+ }
45
+ };
46
+ const fakeBrowser = new FakeBrowser([fakePage]);
47
+ const session = new BrowserSession(fakeBrowser, fakeBrowser.context, fakePage, config.browser, 'launched');
48
+ const page = new PuppeteerPageAdapter(fakePage);
49
+ const cursor = overrides.interactor ?? fakeInteractor;
50
+ const forms = new FormFiller(page, cursor);
51
+ const nav = new Navigator(page, cursor, overrides.baseUrl ?? 'https://example.com');
52
+ const extract = new Extractor(page);
53
+ const pagination = new Pagination(page, cursor);
54
+ const logger = new MemoryLogger();
55
+
56
+ const auth: AuthController = overrides.auth ?? {
57
+ isLoggedIn: async () => false,
58
+ ensureAuthenticated: async () => undefined
59
+ };
60
+
61
+ const context: ActorContext = {
62
+ actor: { id: overrides.actorId ?? 'example', baseUrl: overrides.baseUrl ?? 'https://example.com' },
63
+ config,
64
+ session,
65
+ page,
66
+ cursor,
67
+ forms,
68
+ nav,
69
+ extract,
70
+ pagination,
71
+ auth,
72
+ logger
73
+ };
74
+
75
+ return { context, fakePage, fakeInteractor, logger, config };
76
+ }
@@ -0,0 +1,80 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { AuthStateDetector } from '../../../src/auth/AuthStateDetector.js';
3
+ import { defineLoginFlow } from '../../../src/auth/LoginFlow.types.js';
4
+ import { makeContext } from '../../fixtures/makeContext.js';
5
+
6
+ describe('AuthStateDetector', () => {
7
+ it('returns true when the logged-in signal exists', async () => {
8
+ const { context, fakePage } = makeContext();
9
+ fakePage.setSelector('[data-testid="account"]');
10
+ const detector = new AuthStateDetector();
11
+
12
+ const result = await detector.isLoggedIn(context, defineLoginFlow({
13
+ loginUrl: '/login',
14
+ selectors: {
15
+ username: '#email',
16
+ password: '#password',
17
+ submit: '#submit',
18
+ loggedInSignal: '[data-testid="account"]'
19
+ }
20
+ }));
21
+
22
+ expect(result).toBe(true);
23
+ });
24
+
25
+ it('returns false when the logged-in signal is absent', async () => {
26
+ const { context } = makeContext();
27
+ const detector = new AuthStateDetector();
28
+
29
+ await expect(detector.isLoggedIn(context, defineLoginFlow({
30
+ loginUrl: '/login',
31
+ selectors: {
32
+ username: '#email',
33
+ password: '#password',
34
+ submit: '#submit',
35
+ loggedInSignal: '#missing'
36
+ }
37
+ }))).resolves.toBe(false);
38
+ });
39
+
40
+ it('visits authCheckUrl before checking auth state', async () => {
41
+ const { context, fakePage } = makeContext();
42
+ fakePage.setSelector('#account');
43
+ const detector = new AuthStateDetector();
44
+
45
+ await detector.isLoggedIn(context, defineLoginFlow({
46
+ loginUrl: '/login',
47
+ selectors: {
48
+ username: '#email',
49
+ password: '#password',
50
+ submit: '#submit',
51
+ loggedInSignal: '#account'
52
+ },
53
+ behavior: {
54
+ authCheckUrl: '/dashboard'
55
+ }
56
+ }));
57
+
58
+ expect(fakePage.gotos[0]?.url).toBe('https://example.com/dashboard');
59
+ });
60
+
61
+ it('uses custom verifyLoggedIn hook when provided', async () => {
62
+ const { context } = makeContext();
63
+ const detector = new AuthStateDetector();
64
+
65
+ const result = await detector.isLoggedIn(context, defineLoginFlow({
66
+ loginUrl: '/login',
67
+ selectors: {
68
+ username: '#email',
69
+ password: '#password',
70
+ submit: '#submit',
71
+ loggedInSignal: '#account'
72
+ },
73
+ hooks: {
74
+ verifyLoggedIn: async () => true
75
+ }
76
+ }));
77
+
78
+ expect(result).toBe(true);
79
+ });
80
+ });