1 | |
2 |
|
3 | export type DynSelect_table = string |
4 | export type DynMultiselect_fields = string[] |
5 |
|
6 | function authHeader(auth: RT.Servicenow) { |
7 | return auth.token |
8 | ? `Bearer ${auth.token}` |
9 | : `Basic ${btoa(`${auth.username}:${auth.password}`)}` |
10 | } |
11 |
|
12 | |
13 | export async function table(auth: RT.Servicenow) { |
14 | const response = await fetch( |
15 | `${auth.instance_url}/api/now/table/sys_db_object?sysparm_fields=name,label&sysparm_limit=10000`, |
16 | { |
17 | headers: { |
18 | Authorization: authHeader(auth), |
19 | Accept: "application/json", |
20 | }, |
21 | } |
22 | ) |
23 | if (!response.ok) { |
24 | throw new Error(`${response.status} ${await response.text()}`) |
25 | } |
26 | const { result } = (await response.json()) as { |
27 | result: { name: string; label: string }[] |
28 | } |
29 | return result |
30 | .filter((t) => t.name) |
31 | .map((t) => ({ value: t.name, label: `${t.label} (${t.name})` })) |
32 | .sort((a, b) => a.label.localeCompare(b.label)) |
33 | } |
34 |
|
35 | |
36 | |
37 | |
38 | |
39 | |
40 | async function tableChain(auth: RT.Servicenow, table: string) { |
41 | const chain: string[] = [] |
42 | let current: string | undefined = table |
43 | while (current && !chain.includes(current)) { |
44 | chain.push(current) |
45 | const response = await fetch( |
46 | `${auth.instance_url}/api/now/table/sys_db_object?sysparm_query=name=${current}&sysparm_fields=super_class.name&sysparm_limit=1`, |
47 | { |
48 | headers: { |
49 | Authorization: authHeader(auth), |
50 | Accept: "application/json", |
51 | }, |
52 | } |
53 | ) |
54 | if (!response.ok) break |
55 | const { result } = (await response.json()) as { |
56 | result: { "super_class.name"?: string }[] |
57 | } |
58 | current = result[0]?.["super_class.name"] || undefined |
59 | } |
60 | return chain |
61 | } |
62 |
|
63 | |
64 | |
65 | export async function fields(auth: RT.Servicenow, table: DynSelect_table) { |
66 | if (!table) return [] |
67 | const chain = await tableChain(auth, table) |
68 | const url = new URL(`${auth.instance_url}/api/now/table/sys_dictionary`) |
69 | url.searchParams.append( |
70 | "sysparm_query", |
71 | `nameIN${chain.join(",")}^elementISNOTEMPTY` |
72 | ) |
73 | url.searchParams.append("sysparm_fields", "element,column_label") |
74 | url.searchParams.append("sysparm_limit", "10000") |
75 |
|
76 | const response = await fetch(url, { |
77 | headers: { |
78 | Authorization: authHeader(auth), |
79 | Accept: "application/json", |
80 | }, |
81 | }) |
82 | if (!response.ok) { |
83 | throw new Error(`${response.status} ${await response.text()}`) |
84 | } |
85 | const { result } = (await response.json()) as { |
86 | result: { element: string; column_label: string }[] |
87 | } |
88 | return result |
89 | .filter((f) => f.element) |
90 | .map((f) => ({ |
91 | value: f.element, |
92 | label: `${f.column_label} (${f.element})`, |
93 | })) |
94 | .sort((a, b) => a.label.localeCompare(b.label)) |
95 | } |
96 |
|
97 | |
98 | * List Records |
99 | * Query records from any table with an encoded query (sysparm_query), pagination, column selection, and raw/display values. Returns one page; iterate offset until fewer than limit rows return. |
100 | */ |
101 | export async function main( |
102 | auth: RT.Servicenow, |
103 | table: DynSelect_table, |
104 | query: string | undefined, |
105 | limit: number | undefined, |
106 | offset: number | undefined, |
107 | fields: DynMultiselect_fields | undefined, |
108 | display_value: "false" | "true" | "all" | undefined |
109 | ) { |
110 | const url = new URL(`${auth.instance_url}/api/now/table/${table}`) |
111 | if (query !== undefined && query !== "") { |
112 | url.searchParams.append("sysparm_query", query) |
113 | } |
114 | url.searchParams.append("sysparm_limit", String(limit ?? 100)) |
115 | if (offset !== undefined) { |
116 | url.searchParams.append("sysparm_offset", String(offset)) |
117 | } |
118 | if (fields && fields.length > 0) { |
119 | url.searchParams.append("sysparm_fields", fields.join(",")) |
120 | } |
121 | if (display_value !== undefined && display_value !== "") { |
122 | url.searchParams.append("sysparm_display_value", display_value) |
123 | } |
124 |
|
125 | const response = await fetch(url, { |
126 | method: "GET", |
127 | headers: { |
128 | Authorization: authHeader(auth), |
129 | Accept: "application/json", |
130 | }, |
131 | }) |
132 |
|
133 | if (!response.ok) { |
134 | throw new Error(`${response.status} ${await response.text()}`) |
135 | } |
136 |
|
137 | return await response.json() |
138 | } |
139 |
|