196 lines · 5.6 KB · TypeScript
RawDownload
import { z } from "zod";import type { NodeRuntimeCreateOptions } from "./node-runtime.js"; const permissionModeSchema = z.enum(["allow", "deny"]);const stringArray = z.array(z.string());const vmIdSchema = z.number().int().min(0).max(0xffffffff);const vmAccountNameSchema = z	.string()	.min(1)	.refine((value) => !/[:\s\0]/u.test(value), "Invalid account name");const vmGuestPathSchema = z.string().startsWith("/");const vmUserAccountSchema = z	.object({		uid: vmIdSchema,		gid: vmIdSchema,		username: vmAccountNameSchema,		homedir: vmGuestPathSchema,		shell: vmGuestPathSchema,		gecos: z.string().optional(),		supplementaryGids: z.array(vmIdSchema).max(64),	})	.strict();const vmGroupSchema = z	.object({		gid: vmIdSchema,		name: vmAccountNameSchema,		members: z.array(vmAccountNameSchema),	})	.strict();const vmUserConfigSchema = z	.object({		uid: vmIdSchema.optional(),		gid: vmIdSchema.optional(),		euid: vmIdSchema.optional(),		egid: vmIdSchema.optional(),		username: z.string().optional(),		homedir: z.string().optional(),		shell: z.string().optional(),		gecos: z.string().optional(),		groupName: z.string().optional(),		supplementaryGids: z.array(vmIdSchema).max(64).optional(),		accounts: z.array(vmUserAccountSchema).max(64).optional(),		groups: z.array(vmGroupSchema).max(128).optional(),	})	.strict(); const fsPermissionRuleSchema = z	.object({		mode: permissionModeSchema,		operations: stringArray.optional(),		paths: stringArray.optional(),	})	.strict(); const patternPermissionRuleSchema = z	.object({		mode: permissionModeSchema,		operations: stringArray.optional(),		patterns: stringArray.optional(),	})	.strict(); const fsRulePermissionsSchema = z	.object({		default: permissionModeSchema.optional(),		rules: z.array(fsPermissionRuleSchema),	})	.strict(); const patternRulePermissionsSchema = z	.object({		default: permissionModeSchema.optional(),		rules: z.array(patternPermissionRuleSchema),	})	.strict(); const fsPermissionsSchema = z.union([permissionModeSchema, fsRulePermissionsSchema]);const patternPermissionsSchema = z.union([	permissionModeSchema,	patternRulePermissionsSchema,]); export const nodeRuntimePermissionsSchema = z	.object({		fs: fsPermissionsSchema.optional(),		network: patternPermissionsSchema.optional(),		childProcess: patternPermissionsSchema.optional(),		process: patternPermissionsSchema.optional(),		env: patternPermissionsSchema.optional(),		binding: patternPermissionsSchema.optional(),	})	.strict(); const uint8ArraySchema = z.custom<Uint8Array>(	(value: unknown) => value instanceof Uint8Array,	{ message: "Expected Uint8Array" },); const hostDirectoryMountSchema = z	.object({		guestPath: z.string(),		hostPath: z.string(),		readOnly: z.boolean().optional(),	})	.strict(); const nodeModulesMountSchema = z	.object({		hostPath: z.string(),		guestPath: z.string().optional(),	})	.strict(); const jsRuntimeSchema = z	.object({		platform: z.enum(["node", "browser", "neutral", "bare"]).optional(),		moduleResolution: z.enum(["node", "relative", "none"]).optional(),		allowedBuiltins: stringArray.optional(),		highResolutionTime: z.boolean().optional(),	})	.strict(); const bindingExampleSchema = z	.object({		description: z.string(),		input: z.unknown(),	})	.strict(); const bindingDefinitionSchema = z	.object({		description: z.string(),		inputSchema: z.custom<object>(			(value: unknown) => typeof value === "object" && value !== null,			{ message: "Expected JSON Schema object" },		),		timeoutMs: z.number().int().nonnegative().optional(),		examples: z.array(bindingExampleSchema).optional(),		commandAliases: stringArray.optional(),		handler: z.custom<(input: unknown) => unknown | Promise<unknown>>(			(value: unknown) => typeof value === "function",			{ message: "Expected function" },		),	})	.strict(); /** * Runtime validation for the public `NodeRuntime.create(...)` API. * * This is the TS-side guard for the ergonomic options shape. The sidecar VM * JSON it eventually produces is still validated by * `crates/vm-config/src/lib.rs::CreateVmConfig` with `deny_unknown_fields`. * Keep these in sync when adding high-level create options that translate into * the Rust VM config. */export const nodeRuntimeCreateOptionsSchema = z	.object({		filesystem: z.custom<NodeRuntimeCreateOptions["filesystem"]>(			(value: unknown) => typeof value === "object" && value !== null,			{ message: "Expected caller-owned VirtualFileSystem object" },		),		env: z.record(z.string(), z.string()).optional(),		cwd: z.string().optional(),		user: vmUserConfigSchema.optional(),		permissions: nodeRuntimePermissionsSchema.optional(),		commandsDir: z.string().optional(),		wasmCommandDirs: stringArray.optional(),		sidecar: z			.custom((value: unknown) => typeof value === "object" && value !== null, {				message: "Expected SidecarProcess object",			})			.optional(),		onBootTiming: z			.custom<(timing: unknown) => void>(				(value: unknown) => typeof value === "function",				{ message: "Expected function" },			)			.optional(),		files: z			.record(z.string(), z.union([z.string(), uint8ArraySchema]))			.optional(),		mounts: z.array(hostDirectoryMountSchema).optional(),		nodeModules: z.union([z.string(), nodeModulesMountSchema]).optional(),		bindings: z.record(z.string(), bindingDefinitionSchema).optional(),		loopbackExemptPorts: z			.array(z.number().int().min(0).max(65535))			.optional(),		jsRuntime: jsRuntimeSchema.optional(),	})	.strict() as z.ZodType<NodeRuntimeCreateOptions>; export function parseNodeRuntimeCreateOptions(	options: NodeRuntimeCreateOptions,): NodeRuntimeCreateOptions {	return nodeRuntimeCreateOptionsSchema.parse(options);}