1 | |
2 |
|
3 | import * as wmill from "windmill-client" |
4 |
|
5 | export type DynSelect_operation = string |
6 |
|
7 | |
8 | async function listOperations() { |
9 | const response = await fetch(`${wmill.OpenAPI.BASE}/openapi.json`) |
10 | if (!response.ok) { |
11 | throw new Error(`${response.status} ${await response.text()}`) |
12 | } |
13 | const spec = (await response.json()) as { |
14 | paths: { [path: string]: { [method: string]: { operationId?: string } } } |
15 | } |
16 | return Object.entries(spec.paths).flatMap(([path, methods]) => |
17 | Object.entries(methods) |
18 | .filter(([, op]) => op?.operationId) |
19 | .map(([method, op]) => ({ |
20 | id: op.operationId!, |
21 | value: `${method.toUpperCase()} ${path}`, |
22 | })) |
23 | ) |
24 | } |
25 |
|
26 | export async function operation() { |
27 | return (await listOperations()) |
28 | .map((op) => ({ value: op.value, label: `${op.id}: ${op.value}` })) |
29 | .sort((a, b) => a.label.localeCompare(b.label)) |
30 | } |
31 |
|
32 | |
33 | * Call Windmill API |
34 | * Call any operation of this instance's own API, picked from its OpenAPI document. Runs with the job's token, which only reaches the job's workspace; pass a user API token to call instance-level operations or another workspace. |
35 | */ |
36 | export async function main( |
37 | operation: DynSelect_operation, |
38 | path_params: { [key: string]: any } | undefined, |
39 | query: { [key: string]: any } | undefined, |
40 | body: { [key: string]: any } | undefined, |
41 | token: string | undefined |
42 | ) { |
43 | |
44 | const resolved = operation.includes(" ") |
45 | ? operation |
46 | : (await listOperations()).find((op) => op.id === operation)?.value |
47 | if (!resolved) { |
48 | throw new Error(`Unknown operation ${operation}`) |
49 | } |
50 | const [method, path] = resolved.split(" ") |
51 |
|
52 | const params: { [key: string]: any } = { |
53 | workspace: wmill.getWorkspace(), |
54 | ...path_params, |
55 | } |
56 | const url = new URL( |
57 | wmill.OpenAPI.BASE + |
58 | path.replace(/\{(\w+)\}/g, (_, name) => { |
59 | if (params[name] == null || params[name] === "") { |
60 | throw new Error(`Missing path parameter ${name} for ${resolved}`) |
61 | } |
62 | return encodeURI(String(params[name])) |
63 | }) |
64 | ) |
65 | for (const [name, value] of Object.entries(query ?? {})) { |
66 | if (value != null && value !== "") { |
67 | url.searchParams.append(name, String(value)) |
68 | } |
69 | } |
70 |
|
71 | const hasBody = body != null && method !== "GET" |
72 | const response = await fetch(url, { |
73 | method, |
74 | headers: { |
75 | |
76 | Authorization: `Bearer ${token || wmill.OpenAPI.TOKEN}`, |
77 | ...(hasBody ? { "Content-Type": "application/json" } : {}), |
78 | }, |
79 | body: hasBody ? JSON.stringify(body) : undefined, |
80 | }) |
81 |
|
82 | if (!response.ok) { |
83 | throw new Error(`${response.status} ${await response.text()}`) |
84 | } |
85 |
|
86 | const text = await response.text() |
87 | return response.headers.get("Content-Type")?.includes("json") |
88 | ? JSON.parse(text) |
89 | : text |
90 | } |
91 |
|