1 | import { ApifyClient, Dictionary, TaskCallOptions } from 'apify-client@^2.19.0'; |
2 |
|
3 | type ApifyApiKey = { |
4 | api_key: string; |
5 | }; |
6 |
|
7 | type Apify = { |
8 | token: string; |
9 | }; |
10 |
|
11 | type MemoryInMb = |
12 | | '128' |
13 | | '256' |
14 | | '512' |
15 | | '1024' |
16 | | '2048' |
17 | | '4096' |
18 | | '8192' |
19 | | '16384' |
20 | | '32768'; |
21 |
|
22 | export type DynSelect_taskId = string; |
23 | export async function taskId(api_key?: ApifyApiKey, oauth_token?: Apify) { |
24 | if (!api_key?.api_key && !oauth_token?.token) { |
25 | return [{ value: '', label: 'Missing Apify API key or OAuth token' }]; |
26 | } |
27 |
|
28 | try { |
29 | const client = createClient(api_key, oauth_token); |
30 |
|
31 | const data = await client.tasks().list(); |
32 | const items = data?.items ?? []; |
33 |
|
34 | return items.map((task: any) => ({ |
35 | value: task.id, |
36 | label: task.title || task.name || task.id, |
37 | })); |
38 | } catch (error: any) { |
39 | return [ |
40 | { value: '', label: `Failed to load tasks: ${error.message || error}` }, |
41 | ]; |
42 | } |
43 | } |
44 |
|
45 | const createClient = (api_key?: ApifyApiKey, oauth_token?: Apify): ApifyClient => { |
46 | const token = oauth_token?.token ?? api_key?.api_key; |
47 | if (!token) { |
48 | throw new Error('Missing Apify API key or OAuth token'); |
49 | } |
50 |
|
51 | return new ApifyClient({ |
52 | token: token, |
53 | requestInterceptors: [ |
54 | (request) => { |
55 | if (!request.headers) { |
56 | request.headers = {}; |
57 | } |
58 | request.headers['x-apify-integration-platform'] = 'windmill'; |
59 | return request; |
60 | }, |
61 | ], |
62 | }); |
63 | }; |
64 |
|
65 | async function pollRunStatus( |
66 | client: ApifyClient, |
67 | runId: string, |
68 | options: { throwIfNotSucceeded: boolean; } = { throwIfNotSucceeded: false } |
69 | ): Promise<any> { |
70 | let status = ''; |
71 | let runData: any; |
72 | while (true) { |
73 | runData = await client.run(runId).get(); |
74 | status = runData.status; |
75 | if (['SUCCEEDED', 'FAILED', 'ABORTED', 'TIMED-OUT'].includes(status)) break; |
76 | await new Promise((res) => setTimeout(res, 1000)); |
77 | } |
78 |
|
79 | if (options.throwIfNotSucceeded && status !== 'SUCCEEDED') { |
80 | throw new Error(`Actor run did not succeed: ${status}`); |
81 | } |
82 |
|
83 | return runData; |
84 | } |
85 |
|
86 | export async function main( |
87 | actorTaskId: DynSelect_taskId, |
88 | customBody: object = {}, |
89 | timeout?: number | null, |
90 | memoryInMb: MemoryInMb = '1024', |
91 | build?: string, |
92 | waitForFinish: boolean = true, |
93 | api_key?: ApifyApiKey, |
94 | oauth_token?: Apify, |
95 | ) { |
96 | if (!actorTaskId) { |
97 | return { error: 'Task ID is required' }; |
98 | } |
99 |
|
100 | const client = createClient(api_key, oauth_token); |
101 |
|
102 | try { |
103 | const runOptions: TaskCallOptions = { |
104 | waitSecs: 0, |
105 | }; |
106 |
|
107 | if (timeout != null) runOptions.timeout = timeout; |
108 | if (memoryInMb != null) runOptions.memory = Number(memoryInMb); |
109 | if (build) runOptions.build = build; |
110 |
|
111 | |
112 | const apiResult = await client |
113 | .task(actorTaskId) |
114 | .call(customBody as Dictionary, runOptions); |
115 |
|
116 | if (!apiResult?.id) { |
117 | return { error: 'Run ID not found after running the task' }; |
118 | } |
119 |
|
120 | if (!waitForFinish) { |
121 | return { ...apiResult }; |
122 | } |
123 |
|
124 | const runId = apiResult.id; |
125 | const lastRunData = await pollRunStatus(client, runId); |
126 | return { ...lastRunData }; |
127 | } catch (error: any) { |
128 | return { |
129 | error: `Failed to run task. Reason: ${error.message}`, |
130 | }; |
131 | } |
132 | } |
133 |
|