//native
export type DynSelect_table = string
export type DynMultiselect_fields = string[]
function authHeader(auth: RT.Servicenow) {
return auth.token
? `Bearer ${auth.token}`
: `Basic ${btoa(`${auth.username}:${auth.password}`)}`
}
// Dropdown of the instance's tables (sys_db_object).
export async function table(auth: RT.Servicenow) {
const response = await fetch(
`${auth.instance_url}/api/now/table/sys_db_object?sysparm_fields=name,label&sysparm_limit=10000`,
{
headers: {
Authorization: authHeader(auth),
Accept: "application/json",
},
}
)
if (!response.ok) {
throw new Error(`${response.status} ${await response.text()}`)
}
const { result } = (await response.json()) as {
result: { name: string; label: string }[]
}
return result
.filter((t) => t.name)
.map((t) => ({ value: t.name, label: `${t.label} (${t.name})` }))
.sort((a, b) => a.label.localeCompare(b.label))
}
// Walk the table's inheritance chain (sys_db_object.super_class) so the column
// list includes fields inherited from parent tables, not just fields defined on
// the chosen table (sys_dictionary stores each field under its defining table —
// e.g. incident extends task, so short_description/priority live on task).
// Best-effort: any failure falls back to just the table itself.
async function tableChain(auth: RT.Servicenow, table: string) {
const chain: string[] = []
let current: string | undefined = table
while (current && !chain.includes(current)) {
chain.push(current)
const response = await fetch(
`${auth.instance_url}/api/now/table/sys_db_object?sysparm_query=name=${current}&sysparm_fields=super_class.name&sysparm_limit=1`,
{
headers: {
Authorization: authHeader(auth),
Accept: "application/json",
},
}
)
if (!response.ok) break
const { result } = (await response.json()) as {
result: { "super_class.name"?: string }[]
}
current = result[0]?.["super_class.name"] || undefined
}
return chain
}
// Dependent multi-select: the chosen table's columns (sys_dictionary), including
// columns inherited from parent tables.
export async function fields(auth: RT.Servicenow, table: DynSelect_table) {
if (!table) return []
const chain = await tableChain(auth, table)
const url = new URL(`${auth.instance_url}/api/now/table/sys_dictionary`)
url.searchParams.append(
"sysparm_query",
`nameIN${chain.join(",")}^elementISNOTEMPTY`
)
url.searchParams.append("sysparm_fields", "element,column_label")
url.searchParams.append("sysparm_limit", "10000")
const response = await fetch(url, {
headers: {
Authorization: authHeader(auth),
Accept: "application/json",
},
})
if (!response.ok) {
throw new Error(`${response.status} ${await response.text()}`)
}
const { result } = (await response.json()) as {
result: { element: string; column_label: string }[]
}
return result
.filter((f) => f.element)
.map((f) => ({
value: f.element,
label: `${f.column_label} (${f.element})`,
}))
.sort((a, b) => a.label.localeCompare(b.label))
}
/**
* Get Record
* Retrieve a single record by sys_id. Optionally restrict the returned columns, and choose raw vs. display values.
*/
export async function main(
auth: RT.Servicenow,
table: DynSelect_table,
sys_id: string,
fields: DynMultiselect_fields | undefined,
display_value: "false" | "true" | "all" | undefined
) {
const url = new URL(`${auth.instance_url}/api/now/table/${table}/${sys_id}`)
if (fields && fields.length > 0) {
url.searchParams.append("sysparm_fields", fields.join(","))
}
if (display_value !== undefined && display_value !== "") {
url.searchParams.append("sysparm_display_value", display_value)
}
const response = await fetch(url, {
method: "GET",
headers: {
Authorization: authHeader(auth),
Accept: "application/json",
},
})
if (!response.ok) {
throw new Error(`${response.status} ${await response.text()}`)
}
return await response.json()
}
Submitted by hugo989 5 days ago