import { ArrayIsArray, ArrayPrototypePush, ObjectSetPrototypeOf, ReflectOwnKeys, TypeError, } from "ext:core/primordials"; import { op_pledge } from "ext:core/ops"; import { usv } from "ext:web/idl.js"; const categories = [ "net", "read", "write", "jsExec", "env", "sys", "run", "ffi", ] as const; export type PledgeRow = [ category: typeof categories[number], allow: string[] | null, deny: string[], ]; function object(value: unknown): value is Record { return value !== null && (typeof value === "object" || typeof value === "function"); } function keys(value: object, allowed: readonly string[]): void { const names = ReflectOwnKeys(value); for (let index = 0; index < names.length; index++) { let known = false; for (let key = 0; key < allowed.length; key++) { if (names[index] === allowed[key]) known = true; } if (!known) throw new TypeError("Unknown pledge member"); } } function list(value: unknown): string[] | null { if (value === undefined) return null; if (!ArrayIsArray(value)) throw new TypeError("Pledge grants must be arrays"); const result: string[] = []; ObjectSetPrototypeOf(result, null); const length = value.length; for (let index = 0; index < length; index++) { const item = value[index]; ArrayPrototypePush(result, usv(item)); } return result; } export function preparePledge(restrictions: unknown): PledgeRow[] { if (!object(restrictions) || ArrayIsArray(restrictions)) { throw new TypeError("Pledge requires a restrictions object"); } keys(restrictions, categories); const request: PledgeRow[] = []; ObjectSetPrototypeOf(request, null); for (let index = 0; index < categories.length; index++) { const category = categories[index]; const value = restrictions[category]; if (value === undefined) continue; let allow: string[] | null, deny: string[]; if (value === false) { allow = []; deny = []; } else { if (!object(value) || ArrayIsArray(value)) { throw new TypeError( "Pledge restrictions must be false or { allow, deny }", ); } keys(value, ["allow", "deny"]); allow = list(value.allow); deny = list(value.deny) ?? []; } ArrayPrototypePush(request, [category, allow, deny]); } return request; } export function pledge(restrictions: unknown): void { const error = op_pledge(preparePledge(restrictions)); if (error !== null) throw new TypeError(error); }