@epsilon-asi/actors 0.0.22 → 0.0.32

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 (193) hide show
  1. package/dist/browser/RuntimeConfig.d.ts +26 -0
  2. package/dist/browser/RuntimeConfig.d.ts.map +1 -1
  3. package/dist/browser/RuntimeConfig.js +29 -1
  4. package/dist/browser/RuntimeConfig.js.map +1 -1
  5. package/dist/core/ActorContext.d.ts +2 -0
  6. package/dist/core/ActorContext.d.ts.map +1 -1
  7. package/dist/core/ActorRunner.d.ts +3 -0
  8. package/dist/core/ActorRunner.d.ts.map +1 -1
  9. package/dist/core/ActorRunner.js +11 -1
  10. package/dist/core/ActorRunner.js.map +1 -1
  11. package/dist/index.d.ts +2 -0
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +2 -0
  14. package/dist/index.js.map +1 -1
  15. package/dist/native/CompositeNativeWindowDriver.d.ts +11 -0
  16. package/dist/native/CompositeNativeWindowDriver.d.ts.map +1 -0
  17. package/dist/native/CompositeNativeWindowDriver.js +31 -0
  18. package/dist/native/CompositeNativeWindowDriver.js.map +1 -0
  19. package/dist/native/NativeActionRegistry.d.ts +14 -0
  20. package/dist/native/NativeActionRegistry.d.ts.map +1 -0
  21. package/dist/native/NativeActionRegistry.js +101 -0
  22. package/dist/native/NativeActionRegistry.js.map +1 -0
  23. package/dist/native/NativeAutomation.d.ts +3 -0
  24. package/dist/native/NativeAutomation.d.ts.map +1 -0
  25. package/dist/native/NativeAutomation.js +12 -0
  26. package/dist/native/NativeAutomation.js.map +1 -0
  27. package/dist/native/NativeCoordinateMapper.d.ts +23 -0
  28. package/dist/native/NativeCoordinateMapper.d.ts.map +1 -0
  29. package/dist/native/NativeCoordinateMapper.js +201 -0
  30. package/dist/native/NativeCoordinateMapper.js.map +1 -0
  31. package/dist/native/NativeFileDialogService.d.ts +26 -0
  32. package/dist/native/NativeFileDialogService.d.ts.map +1 -0
  33. package/dist/native/NativeFileDialogService.js +121 -0
  34. package/dist/native/NativeFileDialogService.js.map +1 -0
  35. package/dist/native/NativeImageFinder.d.ts +12 -0
  36. package/dist/native/NativeImageFinder.d.ts.map +1 -0
  37. package/dist/native/NativeImageFinder.js +29 -0
  38. package/dist/native/NativeImageFinder.js.map +1 -0
  39. package/dist/native/NativeKeyboard.d.ts +10 -0
  40. package/dist/native/NativeKeyboard.d.ts.map +1 -0
  41. package/dist/native/NativeKeyboard.js +16 -0
  42. package/dist/native/NativeKeyboard.js.map +1 -0
  43. package/dist/native/NativeMouse.d.ts +38 -0
  44. package/dist/native/NativeMouse.d.ts.map +1 -0
  45. package/dist/native/NativeMouse.js +82 -0
  46. package/dist/native/NativeMouse.js.map +1 -0
  47. package/dist/native/NativeWindowService.d.ts +31 -0
  48. package/dist/native/NativeWindowService.d.ts.map +1 -0
  49. package/dist/native/NativeWindowService.js +183 -0
  50. package/dist/native/NativeWindowService.js.map +1 -0
  51. package/dist/native/UnsupportedNativeAutomation.d.ts +4 -0
  52. package/dist/native/UnsupportedNativeAutomation.d.ts.map +1 -0
  53. package/dist/native/UnsupportedNativeAutomation.js +77 -0
  54. package/dist/native/UnsupportedNativeAutomation.js.map +1 -0
  55. package/dist/native/WindowMatcher.d.ts +4 -0
  56. package/dist/native/WindowMatcher.d.ts.map +1 -0
  57. package/dist/native/WindowMatcher.js +39 -0
  58. package/dist/native/WindowMatcher.js.map +1 -0
  59. package/dist/native/drivers.d.ts +37 -0
  60. package/dist/native/drivers.d.ts.map +1 -0
  61. package/dist/native/drivers.js +2 -0
  62. package/dist/native/drivers.js.map +1 -0
  63. package/dist/native/errors.d.ts +23 -0
  64. package/dist/native/errors.d.ts.map +1 -0
  65. package/dist/native/errors.js +45 -0
  66. package/dist/native/errors.js.map +1 -0
  67. package/dist/native/index.d.ts +13 -0
  68. package/dist/native/index.d.ts.map +1 -0
  69. package/dist/native/index.js +13 -0
  70. package/dist/native/index.js.map +1 -0
  71. package/dist/native/macos/MacOSAccessibilityWindowDriver.d.ts +11 -0
  72. package/dist/native/macos/MacOSAccessibilityWindowDriver.d.ts.map +1 -0
  73. package/dist/native/macos/MacOSAccessibilityWindowDriver.js +180 -0
  74. package/dist/native/macos/MacOSAccessibilityWindowDriver.js.map +1 -0
  75. package/dist/native/macos/MacOSAppleScriptClient.d.ts +24 -0
  76. package/dist/native/macos/MacOSAppleScriptClient.d.ts.map +1 -0
  77. package/dist/native/macos/MacOSAppleScriptClient.js +163 -0
  78. package/dist/native/macos/MacOSAppleScriptClient.js.map +1 -0
  79. package/dist/native/macos/MacOSFileDialogAccessibilityStrategy.d.ts +10 -0
  80. package/dist/native/macos/MacOSFileDialogAccessibilityStrategy.d.ts.map +1 -0
  81. package/dist/native/macos/MacOSFileDialogAccessibilityStrategy.js +12 -0
  82. package/dist/native/macos/MacOSFileDialogAccessibilityStrategy.js.map +1 -0
  83. package/dist/native/macos/MacOSNativeAutomation.d.ts +3 -0
  84. package/dist/native/macos/MacOSNativeAutomation.d.ts.map +1 -0
  85. package/dist/native/macos/MacOSNativeAutomation.js +88 -0
  86. package/dist/native/macos/MacOSNativeAutomation.js.map +1 -0
  87. package/dist/native/nut/NutNativeImageFinder.d.ts +17 -0
  88. package/dist/native/nut/NutNativeImageFinder.d.ts.map +1 -0
  89. package/dist/native/nut/NutNativeImageFinder.js +84 -0
  90. package/dist/native/nut/NutNativeImageFinder.js.map +1 -0
  91. package/dist/native/nut/NutNativeKeyboardDriver.d.ts +8 -0
  92. package/dist/native/nut/NutNativeKeyboardDriver.d.ts.map +1 -0
  93. package/dist/native/nut/NutNativeKeyboardDriver.js +39 -0
  94. package/dist/native/nut/NutNativeKeyboardDriver.js.map +1 -0
  95. package/dist/native/nut/NutNativeMouseDriver.d.ts +8 -0
  96. package/dist/native/nut/NutNativeMouseDriver.d.ts.map +1 -0
  97. package/dist/native/nut/NutNativeMouseDriver.js +24 -0
  98. package/dist/native/nut/NutNativeMouseDriver.js.map +1 -0
  99. package/dist/native/nut/NutNativeScreenDriver.d.ts +6 -0
  100. package/dist/native/nut/NutNativeScreenDriver.d.ts.map +1 -0
  101. package/dist/native/nut/NutNativeScreenDriver.js +12 -0
  102. package/dist/native/nut/NutNativeScreenDriver.js.map +1 -0
  103. package/dist/native/nut/NutNativeWindowDriver.d.ts +6 -0
  104. package/dist/native/nut/NutNativeWindowDriver.d.ts.map +1 -0
  105. package/dist/native/nut/NutNativeWindowDriver.js +53 -0
  106. package/dist/native/nut/NutNativeWindowDriver.js.map +1 -0
  107. package/dist/native/nut/loadNut.d.ts +58 -0
  108. package/dist/native/nut/loadNut.d.ts.map +1 -0
  109. package/dist/native/nut/loadNut.js +25 -0
  110. package/dist/native/nut/loadNut.js.map +1 -0
  111. package/dist/native/types.d.ts +194 -0
  112. package/dist/native/types.d.ts.map +1 -0
  113. package/dist/native/types.js +2 -0
  114. package/dist/native/types.js.map +1 -0
  115. package/dist/native/utils/appleScriptEscape.d.ts +7 -0
  116. package/dist/native/utils/appleScriptEscape.d.ts.map +1 -0
  117. package/dist/native/utils/appleScriptEscape.js +11 -0
  118. package/dist/native/utils/appleScriptEscape.js.map +1 -0
  119. package/dist/native/utils/geometry.d.ts +12 -0
  120. package/dist/native/utils/geometry.d.ts.map +1 -0
  121. package/dist/native/utils/geometry.js +77 -0
  122. package/dist/native/utils/geometry.js.map +1 -0
  123. package/dist/native/utils/redactNative.d.ts +2 -0
  124. package/dist/native/utils/redactNative.d.ts.map +1 -0
  125. package/dist/native/utils/redactNative.js +7 -0
  126. package/dist/native/utils/redactNative.js.map +1 -0
  127. package/dist/native/utils/waitFor.d.ts +7 -0
  128. package/dist/native/utils/waitFor.d.ts.map +1 -0
  129. package/dist/native/utils/waitFor.js +17 -0
  130. package/dist/native/utils/waitFor.js.map +1 -0
  131. package/dist/sites/upwork-com/upwork-com.actor.d.ts +4 -1
  132. package/dist/sites/upwork-com/upwork-com.actor.d.ts.map +1 -1
  133. package/dist/sites/upwork-com/upwork-com.actor.js +30 -11
  134. package/dist/sites/upwork-com/upwork-com.actor.js.map +1 -1
  135. package/dist/sites/upwork-com/upwork-com.types.d.ts +3 -1
  136. package/dist/sites/upwork-com/upwork-com.types.d.ts.map +1 -1
  137. package/dist/sites/upwork-com/upwork-com.types.js.map +1 -1
  138. package/dist/sites/upwork-com/util/parseJobApplicationDetails.d.ts +70 -0
  139. package/dist/sites/upwork-com/util/parseJobApplicationDetails.d.ts.map +1 -0
  140. package/dist/sites/upwork-com/util/parseJobApplicationDetails.js +334 -0
  141. package/dist/sites/upwork-com/util/parseJobApplicationDetails.js.map +1 -0
  142. package/package.json +5 -1
  143. package/src/browser/RuntimeConfig.ts +57 -1
  144. package/src/core/ActorContext.ts +2 -0
  145. package/src/core/ActorRunner.ts +13 -1
  146. package/src/index.ts +2 -0
  147. package/src/native/CompositeNativeWindowDriver.ts +30 -0
  148. package/src/native/NativeActionRegistry.ts +114 -0
  149. package/src/native/NativeAutomation.ts +15 -0
  150. package/src/native/NativeCoordinateMapper.ts +258 -0
  151. package/src/native/NativeFileDialogService.ts +138 -0
  152. package/src/native/NativeImageFinder.ts +33 -0
  153. package/src/native/NativeKeyboard.ts +18 -0
  154. package/src/native/NativeMouse.ts +116 -0
  155. package/src/native/NativeWindowService.ts +229 -0
  156. package/src/native/UnsupportedNativeAutomation.ts +92 -0
  157. package/src/native/WindowMatcher.ts +31 -0
  158. package/src/native/drivers.ts +38 -0
  159. package/src/native/errors.ts +51 -0
  160. package/src/native/index.ts +12 -0
  161. package/src/native/macos/MacOSAccessibilityWindowDriver.ts +183 -0
  162. package/src/native/macos/MacOSAppleScriptClient.ts +182 -0
  163. package/src/native/macos/MacOSFileDialogAccessibilityStrategy.ts +11 -0
  164. package/src/native/macos/MacOSNativeAutomation.ts +86 -0
  165. package/src/native/nut/NutNativeImageFinder.ts +98 -0
  166. package/src/native/nut/NutNativeKeyboardDriver.ts +38 -0
  167. package/src/native/nut/NutNativeMouseDriver.ts +27 -0
  168. package/src/native/nut/NutNativeScreenDriver.ts +14 -0
  169. package/src/native/nut/NutNativeWindowDriver.ts +61 -0
  170. package/src/native/nut/loadNut.ts +86 -0
  171. package/src/native/types.ts +224 -0
  172. package/src/native/utils/appleScriptEscape.ts +11 -0
  173. package/src/native/utils/geometry.ts +88 -0
  174. package/src/native/utils/redactNative.ts +6 -0
  175. package/src/native/utils/waitFor.ts +25 -0
  176. package/src/sites/upwork-com/upwork-com.actor.ts +46 -14
  177. package/src/sites/upwork-com/upwork-com.types.ts +4 -1
  178. package/src/sites/upwork-com/util/parseJobApplicationDetails.ts +622 -0
  179. package/tests/fixtures/makeContext.ts +7 -2
  180. package/tests/fixtures/native/FakeNativeAutomation.ts +138 -0
  181. package/tests/unit/browser/RuntimeConfig.native.test.ts +63 -0
  182. package/tests/unit/core/ActorRunner.native.test.ts +69 -0
  183. package/tests/unit/native/MacOSAppleScriptClient.test.ts +35 -0
  184. package/tests/unit/native/NativeActionRegistry.test.ts +34 -0
  185. package/tests/unit/native/NativeCoordinateMapper.test.ts +92 -0
  186. package/tests/unit/native/NativeFileDialogService.test.ts +91 -0
  187. package/tests/unit/native/NativeMouse.test.ts +91 -0
  188. package/tests/unit/native/NativeWindowService.test.ts +87 -0
  189. package/tests/unit/native/WindowMatcher.test.ts +32 -0
  190. package/tests/unit/native/appleScriptEscape.test.ts +9 -0
  191. package/tests/unit/sites/myvistage-com.login.test.ts +1 -1
  192. package/tests/unit/sites/myvistage-com.postComment.test.ts +0 -1
  193. package/tests/unit/sites/upwork-com.login.test.ts +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"geometry.js","sourceRoot":"","sources":["../../../src/native/utils/geometry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function redactPath(filePath: string, reveal?: boolean): string;
2
+ //# sourceMappingURL=redactNative.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redactNative.d.ts","sourceRoot":"","sources":["../../../src/native/utils/redactNative.ts"],"names":[],"mappings":"AAEA,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,UAAQ,GAAG,MAAM,CAGnE"}
@@ -0,0 +1,7 @@
1
+ import path from 'node:path';
2
+ export function redactPath(filePath, reveal = false) {
3
+ if (reveal)
4
+ return filePath;
5
+ return path.basename(filePath) === '' ? '<path>' : `<path:${path.basename(filePath)}>`;
6
+ }
7
+ //# sourceMappingURL=redactNative.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redactNative.js","sourceRoot":"","sources":["../../../src/native/utils/redactNative.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,UAAU,UAAU,CAAC,QAAgB,EAAE,MAAM,GAAG,KAAK;IACzD,IAAI,MAAM;QAAE,OAAO,QAAQ,CAAC;IAC5B,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC;AACzF,CAAC"}
@@ -0,0 +1,7 @@
1
+ export interface WaitForOptions {
2
+ timeoutMs?: number;
3
+ intervalMs?: number;
4
+ description?: string;
5
+ }
6
+ export declare function waitFor<T>(predicate: () => Promise<T | null | undefined | false>, options?: WaitForOptions): Promise<T>;
7
+ //# sourceMappingURL=waitFor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"waitFor.d.ts","sourceRoot":"","sources":["../../../src/native/utils/waitFor.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAsB,OAAO,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,GAAG,IAAI,GAAG,SAAS,GAAG,KAAK,CAAC,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,CAAC,CAAC,CAgBjI"}
@@ -0,0 +1,17 @@
1
+ import { delay } from '../../utils/delay.js';
2
+ export async function waitFor(predicate, options = {}) {
3
+ const timeoutMs = options.timeoutMs ?? 15_000;
4
+ const intervalMs = options.intervalMs ?? 100;
5
+ const startedAt = Date.now();
6
+ let lastValue;
7
+ do {
8
+ lastValue = await predicate();
9
+ if (lastValue !== null && lastValue !== undefined && lastValue !== false) {
10
+ return lastValue;
11
+ }
12
+ await delay(intervalMs);
13
+ } while (Date.now() - startedAt < timeoutMs);
14
+ const description = options.description ?? 'condition';
15
+ throw new Error(`Timed out after ${timeoutMs}ms waiting for ${description}.`);
16
+ }
17
+ //# sourceMappingURL=waitFor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"waitFor.js","sourceRoot":"","sources":["../../../src/native/utils/waitFor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAQ7C,MAAM,CAAC,KAAK,UAAU,OAAO,CAAI,SAAsD,EAAE,UAA0B,EAAE;IACnH,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,MAAM,CAAC;IAC9C,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,GAAG,CAAC;IAC7C,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC7B,IAAI,SAAuC,CAAC;IAE5C,GAAG,CAAC;QACF,SAAS,GAAG,MAAM,SAAS,EAAE,CAAC;QAC9B,IAAI,SAAS,KAAK,IAAI,IAAI,SAAS,KAAK,SAAS,IAAI,SAAS,KAAK,KAAK,EAAE,CAAC;YACzE,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,MAAM,KAAK,CAAC,UAAU,CAAC,CAAC;IAC1B,CAAC,QAAQ,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,GAAG,SAAS,EAAE;IAE7C,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,WAAW,CAAC;IACvD,MAAM,IAAI,KAAK,CAAC,mBAAmB,SAAS,kBAAkB,WAAW,GAAG,CAAC,CAAC;AAChF,CAAC"}
@@ -1,9 +1,12 @@
1
1
  import type { UpworkApplyToJobInput, UpworkApplyToJobResult, UpworkJobSearchFields } from './upwork-com.types.js';
2
2
  import { ScrapeDashboardInput } from "../example/index.js";
3
3
  import { UpworkJobListing } from "./util/scrapeJobListing.js";
4
+ import { UpworkProposalQuestions } from "./util/parseJobApplicationDetails.js";
4
5
  export declare const upworkComActor: import("../../index.js").Actor<{
6
+ test: (context: import("../../index.js").ActorContext, input: any) => Promise<void>;
5
7
  searchJobs: (context: import("../../index.js").ActorContext, input?: UpworkJobSearchFields) => Promise<UpworkJobListing[]>;
6
8
  scrapeJobs: (context: import("../../index.js").ActorContext, input?: ScrapeDashboardInput) => Promise<any>;
7
- applyToJob: (_context: import("../../index.js").ActorContext, input: UpworkApplyToJobInput) => Promise<UpworkApplyToJobResult>;
9
+ applyToJobPart1: (_context: import("../../index.js").ActorContext, input: UpworkApplyToJobInput) => Promise<UpworkProposalQuestions>;
10
+ applyToJobPart2: (_context: import("../../index.js").ActorContext, input: UpworkApplyToJobInput) => Promise<UpworkApplyToJobResult>;
8
11
  }>;
9
12
  //# sourceMappingURL=upwork-com.actor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"upwork-com.actor.d.ts","sourceRoot":"","sources":["../../../src/sites/upwork-com/upwork-com.actor.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,qBAAqB,EAAE,sBAAsB,EAAE,qBAAqB,EAAC,MAAM,uBAAuB,CAAC;AAEhH,OAAO,EAAC,oBAAoB,EAAC,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAA2B,gBAAgB,EAAC,MAAM,4BAA4B,CAAC;AAGtF,eAAO,MAAM,cAAc;yEAkDgB,qBAAqB,KAAQ,OAAO,CAAC,gBAAgB,EAAE,CAAC;yEASxD,oBAAoB,KAAQ,OAAO,CAAC,GAAG,CAAC;yEAGvC,qBAAqB,KAAG,OAAO,CAAC,sBAAsB,CAAC;EAiBjG,CAAC"}
1
+ {"version":3,"file":"upwork-com.actor.d.ts","sourceRoot":"","sources":["../../../src/sites/upwork-com/upwork-com.actor.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,qBAAqB,EAAE,sBAAsB,EAAE,qBAAqB,EAAC,MAAM,uBAAuB,CAAC;AAEhH,OAAO,EAAC,oBAAoB,EAAC,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAA2B,gBAAgB,EAAC,MAAM,4BAA4B,CAAC;AAEtF,OAAO,EAGH,uBAAuB,EAC1B,MAAM,sCAAsC,CAAC;AAE9C,eAAO,MAAM,cAAc;;yEAqDgB,qBAAqB,KAAQ,OAAO,CAAC,gBAAgB,EAAE,CAAC;yEAOxD,oBAAoB,KAAQ,OAAO,CAAC,GAAG,CAAC;8EAGlC,qBAAqB,KAAG,OAAO,CAAC,uBAAuB,CAAC;8EAkCxD,qBAAqB,KAAG,OAAO,CAAC,sBAAsB,CAAC;EAStG,CAAC"}
@@ -3,6 +3,7 @@ import { defineActor } from '../../core/defineActor.js';
3
3
  import { upworkComSelectors } from './upwork-com.selectors.js';
4
4
  import { parseRate } from "./upwork-com.util.js";
5
5
  import { parseUpworkSearchResults } from "./util/scrapeJobListing.js";
6
+ import { fillUpworkProposalQuestions, parseUpworkProposalQuestions } from "./util/parseJobApplicationDetails.js";
6
7
  export const upworkComActor = defineActor({
7
8
  id: 'upwork-com',
8
9
  baseUrl: 'https://upwork.com',
@@ -53,6 +54,9 @@ export const upworkComActor = defineActor({
53
54
  ]
54
55
  }),
55
56
  tasks: {
57
+ test: async (context, input) => {
58
+ await context.native.mouse.moveTo({ x: 100, y: 200 });
59
+ },
56
60
  searchJobs: async (context, input = {}) => {
57
61
  const path = '/nx/s/universal-search/jobs?category2_uid=531770282580668420,531770282580668419,531770282580668418&client_hires=1-9,10-&payment_verified=1&q=%27rancher%27%20or%20%27terraform%27%20or%20%27gitops%27%20or%20%27azure%27%20or%20%27microsoft%20azure%27%20or%20%27cloud%20architect%27%20or%20%27ai%20architect%27%20or%20%27forward%20deployed%20engineer%27%20or%20%27aws%27%20or%20%27aks%27%20or%20%27eks%27%20or%20%27gke%27%20or%20%27cloud%20engineer%27%20or%20devops%20or%20kuberentes%20or%20%27platform%20engineer%27%20or%20%27infrastructure%20engineer%27%20or%20"google%20cloud%20platform"%20or%20"GCP"%20or%20"langsmith"%20or%20"langgraph"%20or%20"gemini%20enterprise"&sort=recency&user_location_match=1';
58
62
  await context.nav.goto(path, {});
@@ -61,18 +65,33 @@ export const upworkComActor = defineActor({
61
65
  scrapeJobs: async (context, input = {}) => {
62
66
  await parseUpworkSearchResults(context.session.page);
63
67
  },
64
- applyToJob: async (_context, input) => {
65
- const coverLetter = input.coverLetter.trim();
66
- if (coverLetter.length === 0) {
67
- throw new Error('coverLetter must be a non-empty string.');
68
- }
69
- const rate = parseRate(input.rate);
70
- if (!Number.isFinite(rate) || rate <= 0) {
71
- throw new Error('rate must be a positive number.');
72
- }
68
+ applyToJobPart1: async (_context, input) => {
69
+ await _context.cursor.scrollIntoView(`[data-ev-job-uid="${input.jobId}"]`);
70
+ await _context.cursor.move(`[data-ev-job-uid="${input.jobId}"]`);
71
+ await _context.cursor.click(`[data-ev-job-uid="${input.jobId}"]`);
72
+ await _context.cursor.move(`[data-test="Apply"]>button`);
73
+ // await _context.cursor.click(`[data-test="Apply"]>button`);
74
+ await _context.nav.goto(`/nx/proposals/job/~${input.jobId}/apply/`);
75
+ await _context.cursor.move('.up-fe-agency-member-selector > [data-test="dropdown-toggle"]');
76
+ await _context.cursor.click('.up-fe-agency-member-selector > [data-test="dropdown-toggle"]');
77
+ await _context.cursor.move('li[role="option"][tabindex="0"]');
78
+ await _context.cursor.click('li[role="option"][tabindex="0"]');
79
+ await _context.cursor.move('.up-fe-contractor-selector > [data-test="dropdown-toggle"]');
80
+ await _context.cursor.click('.up-fe-contractor-selector > [data-test="dropdown-toggle"]');
81
+ await _context.cursor.move('li[role="option"][tabindex="0"]');
82
+ await _context.cursor.click('li[role="option"][tabindex="0"]');
83
+ await _context.cursor.scrollIntoView('[data-test="sri-form-card"] > [data-test="dropdown-toggle"] > [aria-label="How often do you want a rate increase?"]');
84
+ await _context.cursor.move('[data-test="sri-form-card"] > [data-test="dropdown-toggle"] > [aria-label="How often do you want a rate increase?"]');
85
+ await _context.cursor.click('[data-test="sri-form-card"] > [data-test="dropdown-toggle"] > [aria-label="How often do you want a rate increase?"]');
86
+ await _context.cursor.move('li[role="option"][tabindex="0"]');
87
+ await _context.cursor.click('li[role="option"][tabindex="0"]');
88
+ return await parseUpworkProposalQuestions(_context.session.page);
89
+ },
90
+ applyToJobPart2: async (_context, input) => {
91
+ await fillUpworkProposalQuestions(_context.session.page, input.answers);
73
92
  return {
74
- coverLetter,
75
- rate
93
+ coverLetter: input.answers.coverLetter ?? '',
94
+ rate: parseRate(input.rate)
76
95
  };
77
96
  }
78
97
  }
@@ -1 +1 @@
1
- {"version":3,"file":"upwork-com.actor.js","sourceRoot":"","sources":["../../../src/sites/upwork-com/upwork-com.actor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"upwork-com.actor.js","sourceRoot":"","sources":["../../../src/sites/upwork-com/upwork-com.actor.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { UpworkProposalQuestionAnswers } from "./util/parseJobApplicationDetails.js";
1
2
  export declare enum JobSearchSort {
2
3
  BestMatch = "best_match"
3
4
  }
@@ -78,8 +79,9 @@ export interface UpworkJobSearchResult {
78
79
  filters: UpworkJobSearchFields;
79
80
  }
80
81
  export interface UpworkApplyToJobInput {
81
- coverLetter: string;
82
+ jobId: string;
82
83
  rate: number | string;
84
+ answers: UpworkProposalQuestionAnswers;
83
85
  }
84
86
  export interface UpworkApplyToJobResult {
85
87
  coverLetter: string;
@@ -1 +1 @@
1
- {"version":3,"file":"upwork-com.types.d.ts","sourceRoot":"","sources":["../../../src/sites/upwork-com/upwork-com.types.ts"],"names":[],"mappings":"AAAA,oBAAY,aAAa;IACvB,SAAS,eAAe;CACzB;AAED,oBAAY,cAAc;IACxB,MAAM,YAAY;CACnB;AAED,oBAAY,cAAc;IACxB,UAAU,MAAM;IAChB,YAAY,MAAM;IAClB,MAAM,MAAM;CACb;AAED,oBAAY,OAAO;IACjB,MAAM,WAAW;IACjB,UAAU,gBAAgB;CAC3B;AAED,oBAAY,eAAe;IACzB,WAAW,WAAW;IACtB,YAAY,eAAe;IAC3B,aAAa,gBAAgB;IAC7B,cAAc,iBAAiB;IAC/B,eAAe,aAAa;CAC7B;AAED,oBAAY,aAAa;IACvB,UAAU,QAAQ;IAClB,SAAS,QAAQ;IACjB,UAAU,UAAU;IACpB,UAAU,UAAU;IACpB,UAAU,UAAU;CACrB;AAED,oBAAY,gBAAgB;IAC1B,eAAe,qBAAqB;IACpC,eAAe,qBAAqB;CACrC;AAED,oBAAY,gBAAgB;IAC1B,OAAO,MAAM;IACb,QAAQ,QAAQ;IAChB,OAAO,QAAQ;CAChB;AAED,oBAAY,aAAa;IACvB,gBAAgB,SAAS;IACzB,gBAAgB,UAAU;IAC1B,gBAAgB,aAAa;IAC7B,iBAAiB,YAAY;CAC9B;AAED,oBAAY,YAAY;IACtB,UAAU,cAAc;IACxB,UAAU,cAAc;CACzB;AAED,oBAAY,WAAW;IACrB,cAAc,qBAAqB;CACpC;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,KAAK,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,cAAc,CAAC,EAAE,cAAc,EAAE,CAAC;IAClC,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;IACpB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,gBAAgB,CAAC,EAAE,eAAe,EAAE,CAAC;IACrC,gBAAgB,CAAC,EAAE,UAAU,CAAC;IAC9B,SAAS,CAAC,EAAE,aAAa,EAAE,CAAC;IAC5B,UAAU,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAChC,WAAW,CAAC,EAAE,gBAAgB,EAAE,CAAC;IACjC,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,aAAa,CAAC,EAAE,aAAa,EAAE,CAAC;IAChC,YAAY,CAAC,EAAE,YAAY,EAAE,CAAC;IAC9B,WAAW,CAAC,EAAE,WAAW,EAAE,CAAC;CAC7B,CAAC;AAEF,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,qBAAqB,CAAC;CAChC;AAED,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,sBAAsB;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd"}
1
+ {"version":3,"file":"upwork-com.types.d.ts","sourceRoot":"","sources":["../../../src/sites/upwork-com/upwork-com.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,6BAA6B,EAAC,MAAM,sCAAsC,CAAC;AAEnF,oBAAY,aAAa;IACvB,SAAS,eAAe;CACzB;AAED,oBAAY,cAAc;IACxB,MAAM,YAAY;CACnB;AAED,oBAAY,cAAc;IACxB,UAAU,MAAM;IAChB,YAAY,MAAM;IAClB,MAAM,MAAM;CACb;AAED,oBAAY,OAAO;IACjB,MAAM,WAAW;IACjB,UAAU,gBAAgB;CAC3B;AAED,oBAAY,eAAe;IACzB,WAAW,WAAW;IACtB,YAAY,eAAe;IAC3B,aAAa,gBAAgB;IAC7B,cAAc,iBAAiB;IAC/B,eAAe,aAAa;CAC7B;AAED,oBAAY,aAAa;IACvB,UAAU,QAAQ;IAClB,SAAS,QAAQ;IACjB,UAAU,UAAU;IACpB,UAAU,UAAU;IACpB,UAAU,UAAU;CACrB;AAED,oBAAY,gBAAgB;IAC1B,eAAe,qBAAqB;IACpC,eAAe,qBAAqB;CACrC;AAED,oBAAY,gBAAgB;IAC1B,OAAO,MAAM;IACb,QAAQ,QAAQ;IAChB,OAAO,QAAQ;CAChB;AAED,oBAAY,aAAa;IACvB,gBAAgB,SAAS;IACzB,gBAAgB,UAAU;IAC1B,gBAAgB,aAAa;IAC7B,iBAAiB,YAAY;CAC9B;AAED,oBAAY,YAAY;IACtB,UAAU,cAAc;IACxB,UAAU,cAAc;CACzB;AAED,oBAAY,WAAW;IACrB,cAAc,qBAAqB;CACpC;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,KAAK,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,cAAc,CAAC,EAAE,cAAc,EAAE,CAAC;IAClC,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;IACpB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,gBAAgB,CAAC,EAAE,eAAe,EAAE,CAAC;IACrC,gBAAgB,CAAC,EAAE,UAAU,CAAC;IAC9B,SAAS,CAAC,EAAE,aAAa,EAAE,CAAC;IAC5B,UAAU,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAChC,WAAW,CAAC,EAAE,gBAAgB,EAAE,CAAC;IACjC,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,aAAa,CAAC,EAAE,aAAa,EAAE,CAAC;IAChC,YAAY,CAAC,EAAE,YAAY,EAAE,CAAC;IAC9B,WAAW,CAAC,EAAE,WAAW,EAAE,CAAC;CAC7B,CAAC;AAEF,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,qBAAqB,CAAC;CAChC;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,OAAO,EAAE,6BAA6B,CAAA;CACvC;AAED,MAAM,WAAW,sBAAsB;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd"}
@@ -1 +1 @@
1
- {"version":3,"file":"upwork-com.types.js","sourceRoot":"","sources":["../../../src/sites/upwork-com/upwork-com.types.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,aAEX;AAFD,WAAY,aAAa;IACvB,yCAAwB,CAAA;AAC1B,CAAC,EAFW,aAAa,KAAb,aAAa,QAExB;AAED,MAAM,CAAN,IAAY,cAEX;AAFD,WAAY,cAAc;IACxB,oCAAkB,CAAA;AACpB,CAAC,EAFW,cAAc,KAAd,cAAc,QAEzB;AAED,MAAM,CAAN,IAAY,cAIX;AAJD,WAAY,cAAc;IACxB,kCAAgB,CAAA;IAChB,oCAAkB,CAAA;IAClB,8BAAY,CAAA;AACd,CAAC,EAJW,cAAc,KAAd,cAAc,QAIzB;AAED,MAAM,CAAN,IAAY,OAGX;AAHD,WAAY,OAAO;IACjB,4BAAiB,CAAA;IACjB,qCAA0B,CAAA;AAC5B,CAAC,EAHW,OAAO,KAAP,OAAO,QAGlB;AAED,MAAM,CAAN,IAAY,eAMX;AAND,WAAY,eAAe;IACzB,yCAAsB,CAAA;IACtB,8CAA2B,CAAA;IAC3B,gDAA6B,CAAA;IAC7B,kDAA+B,CAAA;IAC/B,+CAA4B,CAAA;AAC9B,CAAC,EANW,eAAe,KAAf,eAAe,QAM1B;AAED,MAAM,CAAN,IAAY,aAMX;AAND,WAAY,aAAa;IACvB,mCAAkB,CAAA;IAClB,kCAAiB,CAAA;IACjB,qCAAoB,CAAA;IACpB,qCAAoB,CAAA;IACpB,qCAAoB,CAAA;AACtB,CAAC,EANW,aAAa,KAAb,aAAa,QAMxB;AAED,MAAM,CAAN,IAAY,gBAGX;AAHD,WAAY,gBAAgB;IAC1B,wDAAoC,CAAA;IACpC,wDAAoC,CAAA;AACtC,CAAC,EAHW,gBAAgB,KAAhB,gBAAgB,QAG3B;AAED,MAAM,CAAN,IAAY,gBAIX;AAJD,WAAY,gBAAgB;IAC1B,iCAAa,CAAA;IACb,oCAAgB,CAAA;IAChB,mCAAe,CAAA;AACjB,CAAC,EAJW,gBAAgB,KAAhB,gBAAgB,QAI3B;AAED,MAAM,CAAN,IAAY,aAKX;AALD,WAAY,aAAa;IACvB,0CAAyB,CAAA;IACzB,2CAA0B,CAAA;IAC1B,8CAA6B,CAAA;IAC7B,8CAA6B,CAAA;AAC/B,CAAC,EALW,aAAa,KAAb,aAAa,QAKxB;AAED,MAAM,CAAN,IAAY,YAGX;AAHD,WAAY,YAAY;IACtB,wCAAwB,CAAA;IACxB,wCAAwB,CAAA;AAC1B,CAAC,EAHW,YAAY,KAAZ,YAAY,QAGvB;AAED,MAAM,CAAN,IAAY,WAEX;AAFD,WAAY,WAAW;IACrB,kDAAmC,CAAA;AACrC,CAAC,EAFW,WAAW,KAAX,WAAW,QAEtB"}
1
+ {"version":3,"file":"upwork-com.types.js","sourceRoot":"","sources":["../../../src/sites/upwork-com/upwork-com.types.ts"],"names":[],"mappings":"AAEA,MAAM,CAAN,IAAY,aAEX;AAFD,WAAY,aAAa;IACvB,yCAAwB,CAAA;AAC1B,CAAC,EAFW,aAAa,KAAb,aAAa,QAExB;AAED,MAAM,CAAN,IAAY,cAEX;AAFD,WAAY,cAAc;IACxB,oCAAkB,CAAA;AACpB,CAAC,EAFW,cAAc,KAAd,cAAc,QAEzB;AAED,MAAM,CAAN,IAAY,cAIX;AAJD,WAAY,cAAc;IACxB,kCAAgB,CAAA;IAChB,oCAAkB,CAAA;IAClB,8BAAY,CAAA;AACd,CAAC,EAJW,cAAc,KAAd,cAAc,QAIzB;AAED,MAAM,CAAN,IAAY,OAGX;AAHD,WAAY,OAAO;IACjB,4BAAiB,CAAA;IACjB,qCAA0B,CAAA;AAC5B,CAAC,EAHW,OAAO,KAAP,OAAO,QAGlB;AAED,MAAM,CAAN,IAAY,eAMX;AAND,WAAY,eAAe;IACzB,yCAAsB,CAAA;IACtB,8CAA2B,CAAA;IAC3B,gDAA6B,CAAA;IAC7B,kDAA+B,CAAA;IAC/B,+CAA4B,CAAA;AAC9B,CAAC,EANW,eAAe,KAAf,eAAe,QAM1B;AAED,MAAM,CAAN,IAAY,aAMX;AAND,WAAY,aAAa;IACvB,mCAAkB,CAAA;IAClB,kCAAiB,CAAA;IACjB,qCAAoB,CAAA;IACpB,qCAAoB,CAAA;IACpB,qCAAoB,CAAA;AACtB,CAAC,EANW,aAAa,KAAb,aAAa,QAMxB;AAED,MAAM,CAAN,IAAY,gBAGX;AAHD,WAAY,gBAAgB;IAC1B,wDAAoC,CAAA;IACpC,wDAAoC,CAAA;AACtC,CAAC,EAHW,gBAAgB,KAAhB,gBAAgB,QAG3B;AAED,MAAM,CAAN,IAAY,gBAIX;AAJD,WAAY,gBAAgB;IAC1B,iCAAa,CAAA;IACb,oCAAgB,CAAA;IAChB,mCAAe,CAAA;AACjB,CAAC,EAJW,gBAAgB,KAAhB,gBAAgB,QAI3B;AAED,MAAM,CAAN,IAAY,aAKX;AALD,WAAY,aAAa;IACvB,0CAAyB,CAAA;IACzB,2CAA0B,CAAA;IAC1B,8CAA6B,CAAA;IAC7B,8CAA6B,CAAA;AAC/B,CAAC,EALW,aAAa,KAAb,aAAa,QAKxB;AAED,MAAM,CAAN,IAAY,YAGX;AAHD,WAAY,YAAY;IACtB,wCAAwB,CAAA;IACxB,wCAAwB,CAAA;AAC1B,CAAC,EAHW,YAAY,KAAZ,YAAY,QAGvB;AAED,MAAM,CAAN,IAAY,WAEX;AAFD,WAAY,WAAW;IACrB,kDAAmC,CAAA;AACrC,CAAC,EAFW,WAAW,KAAX,WAAW,QAEtB"}
@@ -0,0 +1,70 @@
1
+ import type { ElementHandle, Page } from "puppeteer-core";
2
+ export type UpworkProposalQuestionKind = "cover_letter" | "custom_question";
3
+ export type UpworkProposalControlType = "textarea" | "input" | "select" | "unknown";
4
+ export interface UpworkProposalQuestionSelectors {
5
+ container: string | null;
6
+ label: string | null;
7
+ control: string | null;
8
+ }
9
+ export interface UpworkProposalQuestion {
10
+ id: string;
11
+ kind: UpworkProposalQuestionKind;
12
+ /**
13
+ * The visible prompt shown to the freelancer.
14
+ *
15
+ * Examples:
16
+ * - "Cover Letter"
17
+ * - "Describe your recent experience with similar projects"
18
+ */
19
+ prompt: string;
20
+ /**
21
+ * For cover letter this is always 0.
22
+ * For custom questions this is their order under `.questions-area`.
23
+ */
24
+ index: number;
25
+ controlType: UpworkProposalControlType;
26
+ /**
27
+ * Best-effort CSS selectors for later filling.
28
+ * These are generated from stable page sections, not Vue data-v-* attrs.
29
+ */
30
+ selectors: UpworkProposalQuestionSelectors;
31
+ /**
32
+ * `true` for Cover Letter.
33
+ * `true` for custom questions only when the DOM gives us a required marker/error.
34
+ * `null` means not determinable from the current DOM.
35
+ */
36
+ required: boolean | null;
37
+ placeholder: string | null;
38
+ currentValue: string;
39
+ rows: number | null;
40
+ maxLength: number | null;
41
+ ariaLabelledBy: string | null;
42
+ errorMessages: string[];
43
+ }
44
+ export interface UpworkProposalQuestions {
45
+ hasAdditionalDetailsSection: boolean;
46
+ sourceUrl: string | null;
47
+ coverLetter: UpworkProposalQuestion | null;
48
+ customQuestions: UpworkProposalQuestion[];
49
+ allQuestions: UpworkProposalQuestion[];
50
+ counts: {
51
+ total: number;
52
+ custom: number;
53
+ hasCoverLetter: boolean;
54
+ };
55
+ }
56
+ export declare function parseUpworkProposalQuestions(page: Page, options?: {
57
+ timeoutMs?: number;
58
+ }): Promise<UpworkProposalQuestions>;
59
+ export declare function parseUpworkProposalQuestionsFromRoot(root: ElementHandle<Element>, sourceUrl?: string | null): Promise<UpworkProposalQuestions>;
60
+ export interface UpworkProposalQuestionAnswers {
61
+ coverLetter?: string;
62
+ /**
63
+ * You can key custom answers by:
64
+ * - generated question id
65
+ * - exact prompt text
66
+ */
67
+ customQuestions?: Record<string, string>;
68
+ }
69
+ export declare function fillUpworkProposalQuestions(page: Page, answers: UpworkProposalQuestionAnswers): Promise<void>;
70
+ //# sourceMappingURL=parseJobApplicationDetails.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parseJobApplicationDetails.d.ts","sourceRoot":"","sources":["../../../../src/sites/upwork-com/util/parseJobApplicationDetails.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAM1D,MAAM,MAAM,0BAA0B,GAChC,cAAc,GACd,iBAAiB,CAAC;AAExB,MAAM,MAAM,yBAAyB,GAC/B,UAAU,GACV,OAAO,GACP,QAAQ,GACR,SAAS,CAAC;AAEhB,MAAM,WAAW,+BAA+B;IAC5C,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,sBAAsB;IACnC,EAAE,EAAE,MAAM,CAAC;IAEX,IAAI,EAAE,0BAA0B,CAAC;IAEjC;;;;;;OAMG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd,WAAW,EAAE,yBAAyB,CAAC;IAEvC;;;OAGG;IACH,SAAS,EAAE,+BAA+B,CAAC;IAE3C;;;;OAIG;IACH,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAC;IAEzB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAE3B,YAAY,EAAE,MAAM,CAAC;IAErB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAEpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAEzB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAE9B,aAAa,EAAE,MAAM,EAAE,CAAC;CAC3B;AAGD,MAAM,WAAW,uBAAuB;IACpC,2BAA2B,EAAE,OAAO,CAAC;IAErC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAEzB,WAAW,EAAE,sBAAsB,GAAG,IAAI,CAAC;IAE3C,eAAe,EAAE,sBAAsB,EAAE,CAAC;IAE1C,YAAY,EAAE,sBAAsB,EAAE,CAAC;IAEvC,MAAM,EAAE;QACJ,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,cAAc,EAAE,OAAO,CAAC;KAC3B,CAAC;CACL;AAwZD,wBAAsB,4BAA4B,CAC9C,IAAI,EAAE,IAAI,EACV,OAAO,CAAC,EAAE;IACN,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB,GACF,OAAO,CAAC,uBAAuB,CAAC,CAyBlC;AAED,wBAAsB,oCAAoC,CACtD,IAAI,EAAE,aAAa,CAAC,OAAO,CAAC,EAC5B,SAAS,GAAE,MAAM,GAAG,IAAW,GAChC,OAAO,CAAC,uBAAuB,CAAC,CAKlC;AAMD,MAAM,WAAW,6BAA6B;IAC1C,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC5C;AAED,wBAAsB,2BAA2B,CAC7C,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,6BAA6B,GACvC,OAAO,CAAC,IAAI,CAAC,CA4Bf"}
@@ -0,0 +1,334 @@
1
+ /* -------------------------------------------------------------------------------------------------
2
+ * Browser-context parser
3
+ *
4
+ * IMPORTANT:
5
+ * This function is intentionally self-contained because Puppeteer serializes it
6
+ * into the browser context. Do not close over Node-side variables here.
7
+ * ------------------------------------------------------------------------------------------------- */
8
+ function parseProposalQuestionsInBrowser(rootNode, sourceUrl) {
9
+ const root = rootNode ?? document;
10
+ const cleanText = (input) => {
11
+ return (input ?? "")
12
+ .replace(/\u00a0/g, " ")
13
+ .replace(/\s+/g, " ")
14
+ .trim();
15
+ };
16
+ const toNumber = (input) => {
17
+ const match = (input ?? "").match(/\d+/);
18
+ return match ? Number(match[0]) : null;
19
+ };
20
+ const slugify = (input) => {
21
+ const slug = input
22
+ .toLowerCase()
23
+ .normalize("NFKD")
24
+ .replace(/[^\w\s-]/g, "")
25
+ .replace(/\s+/g, "-")
26
+ .replace(/-+/g, "-")
27
+ .replace(/^-|-$/g, "")
28
+ .slice(0, 80);
29
+ return slug || "question";
30
+ };
31
+ const cssEscape = (input) => {
32
+ const css = globalThis.CSS;
33
+ if (css?.escape) {
34
+ return css.escape(input);
35
+ }
36
+ return input.replace(/["\\]/g, "\\$&");
37
+ };
38
+ const findCardByHeading = (headingText) => {
39
+ const headings = Array.from(root.querySelectorAll("h1, h2, h3, h4, h5"));
40
+ const heading = headings.find((el) => cleanText(el.textContent).toLowerCase() === headingText.toLowerCase());
41
+ if (!heading) {
42
+ return null;
43
+ }
44
+ return (heading.closest(".fe-proposal-additional-details") ??
45
+ heading.closest(".additional-details") ??
46
+ heading.closest(".air3-card") ??
47
+ heading.parentElement);
48
+ };
49
+ const additionalDetails = root.querySelector(".fe-proposal-additional-details") ??
50
+ root.querySelector(".additional-details") ??
51
+ findCardByHeading("Additional details");
52
+ const hasAdditionalDetailsSection = Boolean(additionalDetails);
53
+ const scope = additionalDetails ?? root;
54
+ const getErrorMessages = (container) => {
55
+ return Array.from(container.querySelectorAll(".air3-form-message-error, [role='alert'], .error, .has-error"))
56
+ .map((el) => cleanText(el.textContent))
57
+ .filter(Boolean)
58
+ .filter((value, index, array) => array.indexOf(value) === index);
59
+ };
60
+ const getControlType = (control) => {
61
+ if (!control)
62
+ return "unknown";
63
+ const tag = control.tagName.toLowerCase();
64
+ if (tag === "textarea")
65
+ return "textarea";
66
+ if (tag === "select")
67
+ return "select";
68
+ if (tag === "input")
69
+ return "input";
70
+ return "unknown";
71
+ };
72
+ const getControlValue = (control) => {
73
+ if (!control)
74
+ return "";
75
+ if (control instanceof HTMLTextAreaElement ||
76
+ control instanceof HTMLInputElement ||
77
+ control instanceof HTMLSelectElement) {
78
+ return control.value ?? "";
79
+ }
80
+ return "";
81
+ };
82
+ const getMaxLength = (control) => {
83
+ if (!control)
84
+ return null;
85
+ const value = control.getAttribute("maxlength");
86
+ if (!value)
87
+ return null;
88
+ const parsed = Number(value);
89
+ return Number.isFinite(parsed) ? parsed : null;
90
+ };
91
+ const getRows = (control) => {
92
+ if (!(control instanceof HTMLTextAreaElement)) {
93
+ return null;
94
+ }
95
+ return Number.isFinite(control.rows) ? control.rows : null;
96
+ };
97
+ const inferRequired = (kind, container, control, errors) => {
98
+ if (kind === "cover_letter") {
99
+ return true;
100
+ }
101
+ if (control?.hasAttribute("required")) {
102
+ return true;
103
+ }
104
+ const text = cleanText(container.textContent).toLowerCase();
105
+ const errorText = errors.join(" ").toLowerCase();
106
+ if (container.classList.contains("has-error") && /required/.test(errorText)) {
107
+ return true;
108
+ }
109
+ if (/\brequired\b/.test(errorText)) {
110
+ return true;
111
+ }
112
+ if (/\brequired\b/.test(text)) {
113
+ return true;
114
+ }
115
+ return null;
116
+ };
117
+ const buildQuestion = (params) => {
118
+ const label = params.container.querySelector("label.label, label");
119
+ const control = params.container.querySelector([
120
+ "textarea",
121
+ "input:not([type='hidden']):not([type='file'])",
122
+ "select",
123
+ ].join(", "));
124
+ const prompt = cleanText(label?.textContent);
125
+ if (!prompt || !control) {
126
+ return null;
127
+ }
128
+ const controlType = getControlType(control);
129
+ const controlTag = control.tagName.toLowerCase();
130
+ const errors = getErrorMessages(params.container);
131
+ const ariaLabelledBy = control.getAttribute("aria-labelledby") ||
132
+ control.getAttribute("aria-label") ||
133
+ null;
134
+ const id = params.kind === "cover_letter"
135
+ ? "cover-letter"
136
+ : `custom-question-${params.index + 1}-${slugify(prompt)}`;
137
+ let containerSelector = null;
138
+ let labelSelector = null;
139
+ let controlSelector = null;
140
+ if (params.kind === "cover_letter") {
141
+ containerSelector =
142
+ ".fe-proposal-additional-details .cover-letter-area .form-group";
143
+ labelSelector =
144
+ ".fe-proposal-additional-details .cover-letter-area label";
145
+ controlSelector =
146
+ ".fe-proposal-additional-details .cover-letter-area textarea";
147
+ }
148
+ else if (params.baseSelector) {
149
+ const nth = params.index + 1;
150
+ containerSelector =
151
+ `${params.baseSelector} .form-group:nth-of-type(${nth})`;
152
+ labelSelector =
153
+ `${containerSelector} label`;
154
+ controlSelector =
155
+ `${containerSelector} ${controlTag}`;
156
+ }
157
+ if (!controlSelector && control.id) {
158
+ controlSelector = `#${cssEscape(control.id)}`;
159
+ }
160
+ return {
161
+ id,
162
+ kind: params.kind,
163
+ prompt,
164
+ index: params.index,
165
+ controlType,
166
+ selectors: {
167
+ container: containerSelector,
168
+ label: labelSelector,
169
+ control: controlSelector,
170
+ },
171
+ required: inferRequired(params.kind, params.container, control, errors),
172
+ placeholder: control.getAttribute("placeholder") || null,
173
+ currentValue: getControlValue(control),
174
+ rows: getRows(control),
175
+ maxLength: getMaxLength(control),
176
+ ariaLabelledBy,
177
+ errorMessages: errors,
178
+ };
179
+ };
180
+ /* -----------------------------------------------------------------------------------------------
181
+ * Cover Letter
182
+ * --------------------------------------------------------------------------------------------- */
183
+ const coverLetterContainer = scope.querySelector(".cover-letter-area .form-group") ??
184
+ Array.from(scope.querySelectorAll(".form-group")).find((el) => cleanText(el.querySelector("label")?.textContent).toLowerCase() === "cover letter") ??
185
+ null;
186
+ const coverLetter = coverLetterContainer
187
+ ? buildQuestion({
188
+ kind: "cover_letter",
189
+ index: 0,
190
+ container: coverLetterContainer,
191
+ baseSelector: ".fe-proposal-additional-details .cover-letter-area",
192
+ })
193
+ : null;
194
+ /* -----------------------------------------------------------------------------------------------
195
+ * Custom Job Questions
196
+ * --------------------------------------------------------------------------------------------- */
197
+ const customQuestionArea = scope.querySelector(".fe-proposal-job-questions.questions-area") ??
198
+ scope.querySelector(".questions-area");
199
+ const customQuestionContainers = customQuestionArea
200
+ ? Array.from(customQuestionArea.querySelectorAll(".form-group"))
201
+ .filter((el) => Boolean(el.querySelector([
202
+ "textarea",
203
+ "input:not([type='hidden']):not([type='file'])",
204
+ "select",
205
+ ].join(", "))))
206
+ .filter((el) => {
207
+ const labelText = cleanText(el.querySelector("label")?.textContent).toLowerCase();
208
+ return (labelText !== "cover letter" &&
209
+ labelText !== "attachments");
210
+ })
211
+ : [];
212
+ const customQuestions = customQuestionContainers
213
+ .map((container, index) => buildQuestion({
214
+ kind: "custom_question",
215
+ index,
216
+ container,
217
+ baseSelector: ".fe-proposal-additional-details .fe-proposal-job-questions.questions-area",
218
+ }))
219
+ .filter((question) => Boolean(question));
220
+ /* -----------------------------------------------------------------------------------------------
221
+ * Attachments metadata
222
+ * --------------------------------------------------------------------------------------------- */
223
+ const attachmentsArea = scope.querySelector(".attachments-area") ??
224
+ Array.from(scope.querySelectorAll(".form-group")).find((el) => cleanText(el.querySelector("label")?.textContent).toLowerCase() === "attachments") ??
225
+ null;
226
+ const attachmentsText = cleanText(attachmentsArea?.textContent);
227
+ const fileInput = attachmentsArea?.querySelector("input[type='file']") ??
228
+ null;
229
+ const rejectTypesHolder = attachmentsArea?.querySelector("[reject_types]") ??
230
+ null;
231
+ const rejectedExtensions = cleanText(rejectTypesHolder?.getAttribute("reject_types") ?? "")
232
+ .split(",")
233
+ .map((value) => value.trim().replace(/^\./, ""))
234
+ .filter(Boolean);
235
+ const allQuestions = [
236
+ ...(coverLetter ? [coverLetter] : []),
237
+ ...customQuestions,
238
+ ];
239
+ return {
240
+ hasAdditionalDetailsSection,
241
+ sourceUrl,
242
+ coverLetter,
243
+ customQuestions,
244
+ allQuestions,
245
+ counts: {
246
+ total: allQuestions.length,
247
+ custom: customQuestions.length,
248
+ hasCoverLetter: Boolean(coverLetter),
249
+ },
250
+ };
251
+ }
252
+ /* -------------------------------------------------------------------------------------------------
253
+ * Puppeteer API
254
+ * ------------------------------------------------------------------------------------------------- */
255
+ export async function parseUpworkProposalQuestions(page, options) {
256
+ const timeoutMs = options?.timeoutMs ?? 15_000;
257
+ await page
258
+ .waitForSelector([
259
+ ".fe-proposal-additional-details",
260
+ ".additional-details",
261
+ ".cover-letter-area",
262
+ ".questions-area",
263
+ ].join(", "), {
264
+ timeout: timeoutMs,
265
+ })
266
+ .catch(() => {
267
+ // Some proposal pages may render only a cover letter or may lazy-render the
268
+ // additional details section. We still try to parse the current DOM.
269
+ });
270
+ return page.evaluate(parseProposalQuestionsInBrowser, null, page.url());
271
+ }
272
+ export async function parseUpworkProposalQuestionsFromRoot(root, sourceUrl = null) {
273
+ return root.evaluate(parseProposalQuestionsInBrowser, sourceUrl);
274
+ }
275
+ export async function fillUpworkProposalQuestions(page, answers) {
276
+ const parsed = await parseUpworkProposalQuestions(page);
277
+ if (answers.coverLetter && parsed.coverLetter?.selectors.control) {
278
+ await page.focus(parsed.coverLetter.selectors.control);
279
+ await page.keyboard.down(process.platform === "darwin" ? "Meta" : "Control");
280
+ await page.keyboard.press("A");
281
+ await page.keyboard.up(process.platform === "darwin" ? "Meta" : "Control");
282
+ await page.type(parsed.coverLetter.selectors.control, answers.coverLetter);
283
+ }
284
+ const customAnswers = answers.customQuestions ?? {};
285
+ for (const question of parsed.customQuestions) {
286
+ const answer = customAnswers[question.id] ??
287
+ customAnswers[question.prompt];
288
+ if (!answer || !question.selectors.control) {
289
+ continue;
290
+ }
291
+ await page.focus(question.selectors.control);
292
+ await page.keyboard.down(process.platform === "darwin" ? "Meta" : "Control");
293
+ await page.keyboard.press("A");
294
+ await page.keyboard.up(process.platform === "darwin" ? "Meta" : "Control");
295
+ await page.type(question.selectors.control, answer);
296
+ }
297
+ }
298
+ /* -------------------------------------------------------------------------------------------------
299
+ * Example
300
+ * ------------------------------------------------------------------------------------------------- */
301
+ /*
302
+ import puppeteer from "puppeteer";
303
+
304
+ async function main(): Promise<void> {
305
+ const browser = await puppeteer.launch({
306
+ headless: false,
307
+ });
308
+
309
+ const page = await browser.newPage();
310
+
311
+ await page.goto("https://www.upwork.com/ab/proposals/job/~YOUR_JOB_ID/apply/", {
312
+ waitUntil: "networkidle2",
313
+ });
314
+
315
+ const questions = await parseUpworkProposalQuestions(page);
316
+
317
+ console.dir(questions, {
318
+ depth: null,
319
+ });
320
+
321
+ await fillUpworkProposalQuestions(page, {
322
+ coverLetter: "Hi, I have relevant experience...",
323
+ customQuestions: {
324
+ "Describe your recent experience with similar projects":
325
+ "Recently I led a similar product and engineering effort...",
326
+ },
327
+ });
328
+
329
+ await browser.close();
330
+ }
331
+
332
+ void main();
333
+ */
334
+ //# sourceMappingURL=parseJobApplicationDetails.js.map