@harborclient/team-hub 0.4.1 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/cli/argv.ts","../src/cli/program.ts","../src/config/serverConfig.ts","../src/config/llmConfig.ts","../src/config/loggingConfig.ts","../src/config/pluginsConfig.ts","../src/config/serverConfig.schema.ts","../src/cli/globalOptions.ts","../src/db/firestore/FirestoreDatabase.ts","../src/db/attribution.ts","../src/db/bootstrapUsers.ts","../src/db/firestore/const.ts","../src/db/systemUsers.ts","../src/db/firestore/schemas.ts","../src/db/firestore/utils.ts","../src/db/trimRequiredName.ts","../src/db/userNameValidation.ts","../src/db/types.ts","../src/db/validation.ts","../src/db/mysql/MysqlDatabase.ts","../src/db/apiTokenRows.ts","../src/db/auditLogRows.ts","../src/db/entityRows.ts","../src/db/mysql/migrations.ts","../src/db/mysql/schemas.ts","../src/db/userRows.ts","../src/db/llmUsageLogRows.ts","../src/db/llmUsageRows.ts","../src/db/postgres/PostgresDatabase.ts","../src/db/postgres/migrations.ts","../src/db/postgres/schemas.ts","../src/db/createDatabase.ts","../src/cli/collectionCommand.ts","../src/cli/llmCommand.ts","../src/cli/migrateCommand.ts","../src/cli/userCommand.ts","../src/server/auth/apiTokens.ts","../src/server/admin/userValidation.ts","../src/server/llm/models.ts","../src/server/createServer.ts","../src/server/logging/httpLogging.ts","../src/server/logging/logger.ts","../src/packageVersion.ts","../src/server/auth/accessControl.ts","../src/db/deletionLockedError.ts","../src/server/routes/schemas/common.ts","../src/server/routes/errors.ts","../src/server/routes/authorize.ts","../src/server/routes/schemas/admin.ts","../src/server/routes/schemas/auth.ts","../src/server/routes/schemas/llm.ts","../src/server/routes/schemas/entities.ts","../src/server/routes/admin.ts","../src/server/auth/sessionCapabilities.ts","../src/server/routes/auth.ts","../src/server/routes/collections.ts","../src/server/routes/environments.ts","../src/server/routes/snippets.ts","../src/server/routes/folders.ts","../src/server/routes/health.ts","../src/server/routes/requests.ts","../src/server/llm/client.ts","../src/server/llm/hubMcpToolNames.ts","../src/server/llm/mcpClient.ts","../src/server/llm/agent.ts","../src/server/routes/llm.ts","../src/server/routes/schemas/plugins.ts","../src/server/routes/plugins.ts","../src/server/auth/bearerAuthPlugin.ts","../src/server/routes/index.ts","../src/server/runtimeContext.ts","../src/server/auth/throttle/RedisThrottleStore.ts","../src/server/auth/throttle/IThrottleStore.ts","../src/server/auth/throttle/createThrottleStore.ts","../src/server.ts"],"sourcesContent":["import { CommanderError } from 'commander';\nimport { normalizeCliArgv } from '#/cli/argv.js';\nimport { createProgram } from '#/cli/program.js';\nimport { readPackageVersion } from '#/packageVersion.js';\n\nconst version = readPackageVersion();\n\n/**\n * CLI entry point: builds the Commander program and parses process arguments.\n */\nasync function main(): Promise<void> {\n const program = createProgram(version);\n program.exitOverride();\n\n try {\n await program.parseAsync(normalizeCliArgv(process.argv));\n } catch (error) {\n if (error instanceof CommanderError) {\n process.exitCode = error.exitCode;\n return;\n }\n\n console.error(error instanceof Error ? error.message : String(error));\n process.exitCode = 1;\n }\n}\n\nvoid main();\n","/**\n * Removes the `--` separator that package managers insert between the script\n * name and user-provided arguments (for example `pnpm dev -- user create`).\n *\n * Commander treats everything after `--` as positional operands, so subcommand\n * flags such as `--name` would otherwise be ignored.\n *\n * @param argv - Raw process arguments including the node binary and script path.\n * @returns Copy of argv with a script-following `--` removed when present.\n */\nexport function normalizeCliArgv(argv: readonly string[]): string[] {\n const scriptIndex = argv.findIndex((arg) => arg.endsWith('cli.ts') || arg.endsWith('cli.js'));\n if (scriptIndex === -1) {\n return [...argv];\n }\n\n const normalized = [...argv];\n if (normalized[scriptIndex + 1] === '--') {\n normalized.splice(scriptIndex + 1, 1);\n }\n\n return normalized;\n}\n","import { Command } from 'commander';\nimport { DEFAULT_CONFIG_PATH } from '#/config/serverConfig.js';\nimport {\n registerCollectionCommand,\n type CollectionCommandOptions\n} from '#/cli/collectionCommand.js';\nimport { registerLlmCommand, type LlmCommandOptions } from '#/cli/llmCommand.js';\nimport { registerMigrateCommand, type MigrateCommandOptions } from '#/cli/migrateCommand.js';\nimport {\n registerUserCommand,\n type UserCommandOptions,\n type UserCreateCommandOptions,\n type UserTokenCreateCommandOptions,\n type UserTokenListCommandOptions,\n type UserTokenRevokeCommandOptions,\n type UserUpdateCommandOptions\n} from '#/cli/userCommand.js';\nimport { registerStartCommand, type StartCommandOptions } from '#/server.js';\n\nexport interface ProgramDependencies {\n /**\n * Optional override for the start subcommand handler (used in tests).\n */\n startCommand?: (options: StartCommandOptions) => Promise<void>;\n\n /**\n * Optional override for the migrate subcommand handler (used in tests).\n */\n migrateCommand?: (options: MigrateCommandOptions) => Promise<void>;\n\n /**\n * Optional overrides for collection subcommand handlers (used in tests).\n */\n collectionCommand?: {\n list?: (options: CollectionCommandOptions) => Promise<void>;\n };\n\n /**\n * Optional overrides for LLM subcommand handlers (used in tests).\n */\n llmCommand?: {\n list?: (options: LlmCommandOptions) => Promise<void>;\n };\n\n /**\n * Optional overrides for user subcommand handlers (used in tests).\n */\n userCommand?: {\n create?: (options: UserCreateCommandOptions) => Promise<void>;\n list?: (options: UserCommandOptions) => Promise<void>;\n show?: (options: UserUpdateCommandOptions) => Promise<void>;\n update?: (options: UserUpdateCommandOptions) => Promise<void>;\n delete?: (options: UserUpdateCommandOptions) => Promise<void>;\n tokenCreate?: (options: UserTokenCreateCommandOptions) => Promise<void>;\n tokenList?: (options: UserTokenListCommandOptions) => Promise<void>;\n tokenRevoke?: (options: UserTokenRevokeCommandOptions) => Promise<void>;\n };\n}\n\n/**\n * Creates the root Commander program with global options and subcommands.\n *\n * @param version - Package version shown by `--version`.\n * @param deps - Injectable handlers for testing.\n * @returns Configured Commander program ready to parse argv.\n */\nexport function createProgram(version: string, deps: ProgramDependencies = {}): Command {\n const program = new Command();\n\n program\n .name('team-hub')\n .description('Team Hub — central server for HarborClient')\n .version(version)\n .showHelpAfterError()\n .enablePositionalOptions()\n .option('-v, --verbose', 'Enable verbose logging')\n .option(\n '-c, --config <path>',\n `Path to config file (default: ${DEFAULT_CONFIG_PATH})`,\n DEFAULT_CONFIG_PATH\n );\n\n registerStartCommand(program, deps.startCommand);\n registerMigrateCommand(program, deps.migrateCommand);\n registerCollectionCommand(program, deps.collectionCommand);\n registerLlmCommand(program, deps.llmCommand);\n registerUserCommand(program, deps.userCommand);\n\n return program;\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport path from 'node:path';\nimport { parse as parseYaml } from 'yaml';\nimport type { ZodError } from 'zod/v4';\nimport { normalizeLlmConfig, type LlmConfig } from '#/config/llmConfig.js';\nimport {\n DEFAULT_LOGGING_CONFIG,\n normalizeLoggingConfig,\n type LoggingConfig\n} from '#/config/loggingConfig.js';\nimport { normalizePluginsConfig, type PluginsConfig } from '#/config/pluginsConfig.js';\nimport {\n dbSectionSchema,\n llmSectionSchema,\n loggingSectionSchema,\n pluginsSectionSchema,\n redisSectionSchema,\n serverConfigDocumentSchema,\n serverSectionSchema\n} from '#/config/serverConfig.schema.js';\n\n/**\n * Default relative path to the server YAML config file.\n */\nexport const DEFAULT_CONFIG_PATH = 'server.yaml';\n\nexport interface ServerConfig {\n /**\n * TCP port the server listens on.\n */\n port: number;\n\n /**\n * Bind address (e.g. `127.0.0.1` or `0.0.0.0`).\n */\n host: string;\n\n /**\n * Raw `db` section from server.yaml; validated per driver by {@link createDatabase}.\n */\n db: Record<string, unknown>;\n\n /**\n * Raw `redis` section from server.yaml; validated by {@link RedisThrottleStore.fromConfig}.\n */\n redis: Record<string, unknown>;\n\n /**\n * Normalized LLM provider settings when the optional `llm` section is present.\n */\n llm: LlmConfig | null;\n\n /**\n * Normalized plugin source URLs when the optional `plugins` section is present.\n */\n plugins: PluginsConfig | null;\n\n /**\n * Normalized logging settings (defaults apply when the section is omitted).\n */\n logging: LoggingConfig;\n}\n\n/**\n * Error thrown when a config file cannot be read or fails validation.\n */\nexport class ConfigError extends Error {\n /**\n * Creates a config error with a user-facing message.\n *\n * @param message - Description of what went wrong.\n */\n constructor(message: string) {\n super(message);\n this.name = 'ConfigError';\n }\n}\n\n/**\n * Resolves a config path relative to the current working directory when needed.\n *\n * @param configPath - User-supplied config path (relative or absolute).\n * @returns Absolute filesystem path to the config file.\n */\n/**\n * Resolves a config path relative to the current working directory when needed.\n *\n * @param configPath - User-supplied config path (relative or absolute).\n * @returns Absolute filesystem path to the config file.\n */\nexport function resolveConfigPath(configPath: string): string {\n return path.isAbsolute(configPath) ? configPath : path.resolve(process.cwd(), configPath);\n}\n\n/**\n * Ensures the parsed YAML document has the expected top-level structure.\n *\n * Provides clearer error messages than Zod alone when required keys are missing.\n *\n * @param document - Parsed YAML value.\n * @throws {ConfigError} When the document shape is invalid.\n */\nfunction assertDocumentShape(document: unknown): void {\n if (document === null || typeof document !== 'object' || Array.isArray(document)) {\n throw new ConfigError('Config must be a YAML mapping.');\n }\n\n const root = document as Record<string, unknown>;\n const server = root.server;\n\n if (server === null || typeof server !== 'object' || Array.isArray(server)) {\n throw new ConfigError('Config must include a \"server\" mapping.');\n }\n\n const serverSection = server as Record<string, unknown>;\n\n if (!('port' in serverSection)) {\n throw new ConfigError('Config must include server.port.');\n }\n\n if (!('host' in serverSection)) {\n throw new ConfigError('Config must include server.host.');\n }\n\n const db = root.db;\n\n if (db === null || typeof db !== 'object' || Array.isArray(db)) {\n throw new ConfigError('Config must include a \"db\" mapping.');\n }\n\n const dbSection = db as Record<string, unknown>;\n\n if (!('driver' in dbSection)) {\n throw new ConfigError('Config must include db.driver.');\n }\n\n const redis = root.redis;\n\n if (redis === null || typeof redis !== 'object' || Array.isArray(redis)) {\n throw new ConfigError('Config must include a \"redis\" mapping.');\n }\n\n const redisSection = redis as Record<string, unknown>;\n\n if (!('host' in redisSection)) {\n throw new ConfigError('Config must include redis.host.');\n }\n\n if (!('port' in redisSection)) {\n throw new ConfigError('Config must include redis.port.');\n }\n}\n\n/**\n * Formats the first Zod validation issue into a short user-facing message.\n *\n * @param error - Zod validation error from schema parsing.\n * @returns Human-readable error string.\n */\nfunction formatZodError(error: ZodError): string {\n const issue = error.issues[0];\n if (!issue) {\n return 'Invalid config file.';\n }\n\n if (issue.message) {\n return issue.message;\n }\n\n return 'Invalid config file.';\n}\n\n/**\n * Validates and extracts server settings from a parsed YAML document.\n *\n * @param document - Parsed YAML root value.\n * @returns Normalized host and port settings.\n * @throws {ConfigError} When validation fails.\n */\nfunction parseServerConfig(document: unknown): ServerConfig {\n assertDocumentShape(document);\n\n const root = document as Record<string, unknown>;\n const parsedSection = serverSectionSchema.safeParse(root.server);\n\n if (!parsedSection.success) {\n throw new ConfigError(formatZodError(parsedSection.error));\n }\n\n const parsedDbSection = dbSectionSchema.safeParse(root.db);\n\n if (!parsedDbSection.success) {\n throw new ConfigError(formatZodError(parsedDbSection.error));\n }\n\n const parsedRedisSection = redisSectionSchema.safeParse(root.redis);\n\n if (!parsedRedisSection.success) {\n throw new ConfigError(formatZodError(parsedRedisSection.error));\n }\n\n const parsedDocument = serverConfigDocumentSchema.safeParse(document);\n if (!parsedDocument.success) {\n throw new ConfigError(formatZodError(parsedDocument.error));\n }\n\n let llm: LlmConfig | null = null;\n if (root.llm !== undefined) {\n const parsedLlmSection = llmSectionSchema.safeParse(root.llm);\n if (!parsedLlmSection.success) {\n throw new ConfigError(formatZodError(parsedLlmSection.error));\n }\n llm = normalizeLlmConfig(parsedLlmSection.data);\n }\n\n let plugins: PluginsConfig | null = null;\n if (root.plugins !== undefined) {\n const parsedPluginsSection = pluginsSectionSchema.safeParse(root.plugins);\n if (!parsedPluginsSection.success) {\n throw new ConfigError(formatZodError(parsedPluginsSection.error));\n }\n plugins = normalizePluginsConfig(parsedPluginsSection.data);\n }\n\n let logging = DEFAULT_LOGGING_CONFIG;\n if (root.logging !== undefined) {\n const parsedLoggingSection = loggingSectionSchema.safeParse(root.logging);\n if (!parsedLoggingSection.success) {\n throw new ConfigError(formatZodError(parsedLoggingSection.error));\n }\n logging = normalizeLoggingConfig(parsedLoggingSection.data);\n }\n\n return {\n port: parsedDocument.data.server.port,\n host: parsedDocument.data.server.host,\n db: parsedDbSection.data as Record<string, unknown>,\n redis: parsedRedisSection.data as Record<string, unknown>,\n llm,\n plugins,\n logging\n };\n}\n\n/**\n * Loads and validates server settings from a YAML config file.\n *\n * @param configPath - Path to the config file (relative to cwd or absolute).\n * @returns Parsed host and port settings.\n * @throws {ConfigError} When the file is missing, unreadable, or invalid.\n */\nexport function loadServerConfig(configPath: string): ServerConfig {\n const resolvedPath = resolveConfigPath(configPath);\n\n if (!existsSync(resolvedPath)) {\n throw new ConfigError(`Config file not found: ${configPath}`);\n }\n\n let document: unknown;\n try {\n document = parseYaml(readFileSync(resolvedPath, 'utf8'));\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new ConfigError(`Failed to parse config file: ${message}`);\n }\n\n try {\n return parseServerConfig(document);\n } catch (error) {\n if (error instanceof ConfigError) {\n throw error;\n }\n\n const message = error instanceof Error ? error.message : String(error);\n throw new ConfigError(message);\n }\n}\n","import type { LlmSection } from '#/config/serverConfig.schema.js';\n\n/**\n * Raw MCP headers value from server.yaml before normalization.\n */\ntype HubMcpHeadersInput = NonNullable<NonNullable<LlmSection['mcp']>[number]['headers']>;\n\n/**\n * Supported LLM providers exposed by Team Hub.\n */\nexport type LlmProvider = 'openai' | 'claude' | 'gemini';\n\n/**\n * HTTP header row for hub MCP server connections.\n */\nexport interface HubMcpHeader {\n /**\n * Header name.\n */\n key: string;\n\n /**\n * Header value.\n */\n value: string;\n}\n\n/**\n * One MCP server configured under llm.mcp in server.yaml.\n */\nexport interface HubMcpServerConfig {\n /**\n * Display name for logs and diagnostics.\n */\n name: string;\n\n /**\n * MCP server URL (Streamable HTTP or legacy SSE endpoint).\n */\n url: string;\n\n /**\n * Optional HTTP headers sent with MCP client requests.\n */\n headers: HubMcpHeader[];\n}\n\n/**\n * Normalized LLM configuration loaded from server.yaml.\n */\nexport interface LlmConfig {\n /**\n * Provider API keys configured on the hub.\n */\n providers: Partial<Record<LlmProvider, { apiKey: string }>>;\n\n /**\n * Optional allow-list of model ids the hub offers; when omitted, all catalog\n * models whose provider has a key are offered.\n */\n models?: string[];\n\n /**\n * Optional MCP servers the hub agent may call during chat steps.\n */\n mcp?: HubMcpServerConfig[];\n}\n\n/**\n * Converts one header object with a single key into a normalized header row.\n *\n * @param record - Object whose keys are header names.\n */\nfunction headerRowsFromSingleKeyObject(record: Record<string, string>): HubMcpHeader[] {\n const rows: HubMcpHeader[] = [];\n for (const [key, value] of Object.entries(record)) {\n const trimmedKey = key.trim();\n if (trimmedKey.length > 0) {\n rows.push({ key: trimmedKey, value: String(value) });\n }\n }\n return rows;\n}\n\n/**\n * Normalizes MCP server headers from flexible YAML shapes into key/value rows.\n *\n * @param headers - Raw headers from server.yaml.\n */\nexport function normalizeHubMcpHeaders(headers: HubMcpHeadersInput | undefined): HubMcpHeader[] {\n if (!headers) {\n return [];\n }\n\n if (!Array.isArray(headers)) {\n return headerRowsFromSingleKeyObject(headers);\n }\n\n const rows: HubMcpHeader[] = [];\n for (const item of headers) {\n if (Array.isArray(item)) {\n for (const nested of item) {\n rows.push(...headerRowsFromSingleKeyObject(nested));\n }\n continue;\n }\n\n rows.push(...headerRowsFromSingleKeyObject(item));\n }\n\n return rows;\n}\n\n/**\n * Converts a validated YAML llm section into normalized runtime config.\n *\n * @param section - Parsed llm section from server.yaml.\n * @returns Normalized LLM config for route handlers and the provider client.\n */\nexport function normalizeLlmConfig(section: LlmSection): LlmConfig {\n const providers: LlmConfig['providers'] = {};\n\n if (section.providers.openai?.apiKey) {\n providers.openai = { apiKey: section.providers.openai.apiKey };\n }\n if (section.providers.claude?.apiKey) {\n providers.claude = { apiKey: section.providers.claude.apiKey };\n }\n if (section.providers.gemini?.apiKey) {\n providers.gemini = { apiKey: section.providers.gemini.apiKey };\n }\n\n const mcp =\n section.mcp && section.mcp.length > 0\n ? section.mcp.map((entry) => ({\n name: entry.name.trim(),\n url: entry.url.trim().replace(/\\/+$/, ''),\n headers: normalizeHubMcpHeaders(entry.headers)\n }))\n : undefined;\n\n return {\n providers,\n ...(section.models && section.models.length > 0 ? { models: section.models } : {}),\n ...(mcp && mcp.length > 0 ? { mcp } : {})\n };\n}\n","import type { LoggingSection } from '#/config/serverConfig.schema.js';\n\n/**\n * Supported log levels for Team Hub.\n */\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error';\n\n/**\n * Normalized logging configuration loaded from server.yaml.\n */\nexport interface LoggingConfig {\n /**\n * Minimum severity written to configured transports.\n */\n level: LogLevel;\n\n /**\n * Optional file path for log output; null when file logging is disabled.\n */\n file: string | null;\n\n /**\n * When true, log messages are also written to the terminal.\n */\n console: boolean;\n}\n\n/**\n * Default logging settings applied when the `logging` section is omitted.\n */\nexport const DEFAULT_LOGGING_CONFIG: LoggingConfig = {\n level: 'info',\n file: null,\n console: true\n};\n\n/**\n * Converts a validated YAML logging section into normalized runtime config.\n *\n * @param section - Parsed logging section from server.yaml, when present.\n * @returns Normalized logging config with defaults applied for omitted fields.\n */\nexport function normalizeLoggingConfig(section?: LoggingSection): LoggingConfig {\n return {\n level: section?.level ?? DEFAULT_LOGGING_CONFIG.level,\n file: section?.file ?? DEFAULT_LOGGING_CONFIG.file,\n console: section?.console ?? DEFAULT_LOGGING_CONFIG.console\n };\n}\n","import type { PluginsSection } from '#/config/serverConfig.schema.js';\n\n/**\n * Normalized plugin source settings loaded from server.yaml.\n */\nexport interface PluginsConfig {\n /**\n * Plugin marketplace catalog JSON URLs offered by this Team Hub.\n */\n catalogs: string[];\n\n /**\n * Trusted publisher signing-key registry JSON URLs offered by this Team Hub.\n */\n trusted: string[];\n}\n\n/**\n * Deduplicates URL strings while preserving the first occurrence.\n *\n * @param urls - Raw URL list from server.yaml.\n * @returns Unique URLs in original order.\n */\nfunction dedupeUrls(urls: string[]): string[] {\n const seen = new Set<string>();\n const deduped: string[] = [];\n\n for (const url of urls) {\n if (seen.has(url)) {\n continue;\n }\n seen.add(url);\n deduped.push(url);\n }\n\n return deduped;\n}\n\n/**\n * Converts a validated YAML plugins section into normalized runtime config.\n *\n * @param section - Parsed plugins section from server.yaml.\n * @returns Normalized plugin source URLs for route handlers.\n */\nexport function normalizePluginsConfig(section: PluginsSection): PluginsConfig {\n return {\n catalogs: dedupeUrls(section.catalogs ?? []),\n trusted: dedupeUrls(section.trusted ?? [])\n };\n}\n","import { z } from 'zod/v4';\n\nconst portSchema = z.union([\n z\n .number()\n .int({ message: 'Port must be an integer between 1 and 65535.' })\n .min(1, { message: 'Port must be an integer between 1 and 65535.' })\n .max(65535, { message: 'Port must be an integer between 1 and 65535.' }),\n z\n .string()\n .regex(/^\\d+$/, { message: 'Port must be an integer between 1 and 65535.' })\n .transform(Number)\n .pipe(\n z\n .number()\n .int({ message: 'Port must be an integer between 1 and 65535.' })\n .min(1, { message: 'Port must be an integer between 1 and 65535.' })\n .max(65535, { message: 'Port must be an integer between 1 and 65535.' })\n )\n]);\n\n/**\n * Zod schema for the `server` section of the config file (host and port).\n */\nexport const serverSectionSchema = z.object({\n port: portSchema,\n host: z.string().trim().min(1, { message: 'Host must not be empty.' })\n});\n\n/**\n * Zod schema for the `db` section of the config file (driver discriminant only).\n *\n * Driver-specific fields are validated by each database implementation.\n */\nexport const dbSectionSchema = z\n .object({\n driver: z.string().trim().min(1, { message: 'Database driver must not be empty.' })\n })\n .loose();\n\n/**\n * Zod schema for the `redis` section of the config file.\n *\n * Throttle policy fields default to 10 failures / 900s window / 900s block when omitted.\n */\nexport const redisSectionSchema = z\n .object({\n host: z.string().trim().min(1, { message: 'Redis host must not be empty.' }),\n port: portSchema,\n password: z.string().optional(),\n db: z\n .union([\n z.number().int().min(0).max(15),\n z.string().regex(/^\\d+$/).transform(Number).pipe(z.number().int().min(0).max(15))\n ])\n .optional(),\n keyPrefix: z.string().optional(),\n maxFailures: z\n .union([\n z.number().int().min(1),\n z.string().regex(/^\\d+$/).transform(Number).pipe(z.number().int().min(1))\n ])\n .optional(),\n windowSeconds: z\n .union([\n z.number().int().min(1),\n z.string().regex(/^\\d+$/).transform(Number).pipe(z.number().int().min(1))\n ])\n .optional(),\n blockSeconds: z\n .union([\n z.number().int().min(1),\n z.string().regex(/^\\d+$/).transform(Number).pipe(z.number().int().min(1))\n ])\n .optional()\n })\n .loose();\n\n/**\n * Zod schema for a single LLM provider API key entry in server.yaml.\n */\nexport const llmProviderEntrySchema = z.object({\n apiKey: z.string().trim().min(1, { message: 'LLM provider apiKey must not be empty.' })\n});\n\n/**\n * Zod schema for MCP server HTTP headers in server.yaml.\n *\n * Accepts an object map, an array of single-key objects, or one nested array level.\n */\nexport const hubMcpHeadersSchema = z.union([\n z.record(z.string(), z.string()),\n z.array(z.union([z.record(z.string(), z.string()), z.array(z.record(z.string(), z.string()))]))\n]);\n\n/**\n * Zod schema for one MCP server entry under llm.mcp.\n */\nexport const hubMcpServerEntrySchema = z.object({\n name: z.string().trim().min(1),\n url: z.string().trim().min(1),\n headers: hubMcpHeadersSchema.optional()\n});\n\n/**\n * Zod schema for the optional `llm` section of the config file.\n */\nexport const llmSectionSchema = z.object({\n providers: z\n .object({\n openai: llmProviderEntrySchema.optional(),\n claude: llmProviderEntrySchema.optional(),\n gemini: llmProviderEntrySchema.optional()\n })\n .refine(\n (providers) =>\n Boolean(providers.openai?.apiKey || providers.claude?.apiKey || providers.gemini?.apiKey),\n { message: 'llm.providers must include at least one provider with an apiKey.' }\n ),\n models: z.array(z.string().trim().min(1)).optional(),\n mcp: z.array(hubMcpServerEntrySchema).optional()\n});\n\n/**\n * Zod schema for the optional `plugins` section of the config file.\n */\nexport const pluginsSectionSchema = z.object({\n catalogs: z.array(z.string().trim().url()).optional(),\n trusted: z.array(z.string().trim().url()).optional()\n});\n\n/**\n * Zod schema for supported log levels in the optional `logging` section.\n */\nexport const logLevelSchema = z.enum(['debug', 'info', 'warn', 'error']);\n\n/**\n * Zod schema for the optional `logging` section of the config file.\n */\nexport const loggingSectionSchema = z.object({\n level: logLevelSchema.optional(),\n file: z.string().trim().min(1).optional(),\n console: z.boolean().optional()\n});\n\n/**\n * Zod schema for the full server config document (`server.yaml` root mapping).\n */\nexport const serverConfigDocumentSchema = z.object({\n server: serverSectionSchema,\n db: dbSectionSchema,\n redis: redisSectionSchema,\n llm: llmSectionSchema.optional(),\n plugins: pluginsSectionSchema.optional(),\n logging: loggingSectionSchema.optional()\n});\n\n/**\n * Validated shape of a parsed server config YAML file.\n */\nexport type ServerConfigDocument = z.infer<typeof serverConfigDocumentSchema>;\n\n/**\n * Validated shape of the optional llm section.\n */\nexport type LlmSection = z.infer<typeof llmSectionSchema>;\n\n/**\n * Validated shape of the optional plugins section.\n */\nexport type PluginsSection = z.infer<typeof pluginsSectionSchema>;\n\n/**\n * Validated shape of the optional logging section.\n */\nexport type LoggingSection = z.infer<typeof loggingSectionSchema>;\n","import type { Command } from 'commander';\n\nexport interface GlobalCommandOptions {\n /**\n * When true, enables verbose server logging.\n */\n verbose?: boolean;\n\n /**\n * Path to the server YAML config file.\n */\n config?: string;\n}\n\n/**\n * Merges root-level CLI options into a subcommand's parsed options.\n *\n * Commander stores global flags on the root program. Nested subcommands such as\n * `user create` must read them via {@link Command.optsWithGlobals}.\n *\n * @param command - The subcommand instance handling the action.\n * @param options - Options parsed for the subcommand action.\n * @returns Options with global `verbose` and `config` values applied.\n */\nexport function mergeGlobalOptions<T extends GlobalCommandOptions>(\n command: Command,\n options: T\n): T {\n const globalOpts = command.optsWithGlobals() as GlobalCommandOptions;\n\n return {\n ...options,\n verbose: globalOpts.verbose ?? options.verbose,\n config: globalOpts.config ?? options.config\n };\n}\n","import { randomUUID } from 'node:crypto';\nimport { Firestore, type DocumentReference, type Query } from '@google-cloud/firestore';\nimport { resolveActingUserName } from '#/db/attribution.js';\nimport { BOOTSTRAP_USER_NAME } from '#/db/bootstrapUsers.js';\nimport {\n API_TOKENS_COLLECTION,\n AUDIT_LOG_COLLECTION,\n COLLECTIONS_COLLECTION,\n ENVIRONMENTS_COLLECTION,\n FOLDERS_COLLECTION,\n LLM_USAGE_COLLECTION,\n LLM_USAGE_LOG_COLLECTION,\n REQUESTS_COLLECTION,\n SNIPPETS_COLLECTION,\n USERS_COLLECTION,\n WRITE_BATCH_LIMIT\n} from '#/db/firestore/const.js';\nimport { createSystemUserInput, SYSTEM_USER_NAME } from '#/db/systemUsers.js';\nimport { firestoreConfigSchema } from '#/db/firestore/schemas.js';\nimport type {\n FirestoreApiTokenDocument,\n FirestoreAuditLogDocument,\n FirestoreCollectionDocument,\n FirestoreDatabaseConfig,\n FirestoreEnvironmentDocument,\n FirestoreFolderDocument,\n FirestoreLlmUsageDocument,\n FirestoreLlmUsageLogDocument,\n FirestoreRequestDocument,\n FirestoreSnippetDocument,\n FirestoreUserDocument\n} from '#/db/firestore/types.js';\nimport {\n mapFirestoreApiToken,\n mapFirestoreAuditLog,\n mapFirestoreCollection,\n mapFirestoreEnvironment,\n mapFirestoreFolder,\n mapFirestoreLlmUsage,\n mapFirestoreLlmUsageLog,\n mapFirestoreRequest,\n mapFirestoreSnippet,\n mapFirestoreUser\n} from '#/db/firestore/utils.js';\nimport type { IDatabase } from '#/db/IDatabase.js';\nimport { trimRequiredName } from '#/db/trimRequiredName.js';\nimport { assertUserNameAvailable, assertUserNameNotReserved } from '#/db/userNameValidation.js';\nimport type {\n ApiTokenRecord,\n AuditAction,\n AuditEntityType,\n AuditLogRecord,\n AuthConfig,\n CollectionRecord,\n CreateUserInput,\n CreateLlmUsageLogInput,\n EnvironmentRecord,\n FolderRecord,\n KeyValue,\n ListAuditLogOptions,\n LlmUsageLogRecord,\n LlmUsageRecord,\n SaveRequestInput,\n SavedRequestRecord,\n SnippetRecord,\n SnippetScope,\n UpdateUserInput,\n UserRecord,\n Variable\n} from '#/db/types.js';\nimport { defaultAuth } from '#/db/types.js';\nimport { formatZodError } from '#/db/validation.js';\n\n/**\n * Firestore-backed database implementation.\n */\nexport class FirestoreDatabase implements IDatabase {\n /**\n * Active Firestore client, or null when disconnected.\n */\n private client: Firestore | null = null;\n\n /**\n * Cached identifier of the internal system user, when provisioned during migration.\n */\n private systemUserId: string | null = null;\n\n /**\n * Creates a Firestore database instance from validated config.\n *\n * @param config - Parsed Firestore connection settings.\n */\n constructor(private readonly config: FirestoreDatabaseConfig) {}\n\n /**\n * Validates raw config and constructs a {@link FirestoreDatabase}.\n *\n * @param config - Raw `db` section from server.yaml.\n * @returns Configured Firestore database instance.\n * @throws {Error} When config fails Firestore-specific validation.\n */\n static fromConfig(config: unknown): FirestoreDatabase {\n const parsed = firestoreConfigSchema.safeParse(config);\n if (!parsed.success) {\n throw new Error(formatZodError(parsed.error));\n }\n\n return new FirestoreDatabase({\n projectId: parsed.data.projectId,\n keyFilename: parsed.data.keyFilename\n });\n }\n\n /**\n * Opens a Firestore client and verifies connectivity by listing collections.\n */\n async connect(): Promise<void> {\n if (this.client) {\n return;\n }\n\n const client = new Firestore({\n projectId: this.config.projectId,\n keyFilename: this.config.keyFilename\n });\n\n await client.listCollections();\n\n this.client = client;\n }\n\n /**\n * Terminates the Firestore client and releases resources.\n */\n async disconnect(): Promise<void> {\n if (!this.client) {\n return;\n }\n\n await this.client.terminate();\n this.client = null;\n }\n\n /**\n * Firestore uses schemaless documents; provisions the system user and migrates orphan tokens.\n */\n async migrate(): Promise<void> {\n await this.ensureSystemUser();\n await this.migrateOrphanTokensToBootstrapUser();\n await this.migrateSnippetAccessBackfill();\n }\n\n /**\n * Returns the stable identifier of the internal system user, when provisioned.\n */\n getSystemUserId(): string | null {\n return this.systemUserId;\n }\n\n /**\n * Lists audit log entries ordered newest-first with optional filters.\n *\n * @param options - Optional limit and filter criteria.\n */\n async listAuditLog(options: ListAuditLogOptions = {}): Promise<AuditLogRecord[]> {\n const limit = options.limit ?? 100;\n let query: Query = this.requireClient().collection(AUDIT_LOG_COLLECTION);\n\n if (options.userId !== undefined) {\n query = query.where('userId', '==', options.userId);\n }\n\n if (options.entityType !== undefined) {\n query = query.where('entityType', '==', options.entityType);\n }\n\n if (options.entityId !== undefined) {\n query = query.where('entityId', '==', options.entityId);\n }\n\n const snapshot = await query.orderBy('createdAt', 'desc').limit(limit).get();\n return snapshot.docs.map((doc) =>\n mapFirestoreAuditLog(doc.id, doc.data() as FirestoreAuditLogDocument)\n );\n }\n\n /**\n * Creates a new user account with the given role and access lists.\n *\n * @param input - User fields to persist.\n * @param actingUserId - User performing the create action.\n */\n async createUser(input: CreateUserInput, actingUserId: string): Promise<UserRecord> {\n const trimmedName = trimRequiredName(input.name, 'User name');\n assertUserNameNotReserved(trimmedName);\n const id = randomUUID();\n const now = new Date();\n const attributionUserId = trimmedName === SYSTEM_USER_NAME ? id : actingUserId;\n const data: FirestoreUserDocument = {\n name: trimmedName,\n role: input.role,\n collectionAccess: input.collectionAccess,\n environmentAccess: input.environmentAccess,\n snippetAccess: input.snippetAccess,\n llmAccess: input.llmAccess ?? false,\n llmModels: input.llmModels ?? [],\n llmMonthlyTokenLimit: input.llmMonthlyTokenLimit ?? null,\n createdAt: now,\n updatedAt: now,\n createdByUserId: attributionUserId,\n updatedByUserId: attributionUserId\n };\n\n await this.requireClient().collection(USERS_COLLECTION).doc(id).set(data);\n await this.recordAuditEntry(actingUserId, 'create', 'user', id);\n\n const created = await this.findUserById(id);\n if (!created) {\n throw new Error('User not found after insert');\n }\n\n return created;\n }\n\n /**\n * Finds a user by stable identifier.\n *\n * @param id - User identifier to look up.\n */\n async findUserById(id: string): Promise<UserRecord | null> {\n const snapshot = await this.requireClient().collection(USERS_COLLECTION).doc(id).get();\n if (!snapshot.exists) {\n return null;\n }\n\n return mapFirestoreUser(id, snapshot.data() as FirestoreUserDocument);\n }\n\n /**\n * Finds a user by unique display name.\n *\n * @param name - User name to look up.\n */\n async findUserByName(name: string): Promise<UserRecord | null> {\n const snapshot = await this.requireClient()\n .collection(USERS_COLLECTION)\n .where('name', '==', name)\n .limit(1)\n .get();\n\n const doc = snapshot.docs[0];\n if (!doc) {\n return null;\n }\n\n return mapFirestoreUser(doc.id, doc.data() as FirestoreUserDocument);\n }\n\n /**\n * Lists all user accounts ordered by name.\n */\n async listUsers(): Promise<UserRecord[]> {\n const snapshot = await this.requireClient().collection(USERS_COLLECTION).orderBy('name').get();\n return snapshot.docs.map((doc) =>\n mapFirestoreUser(doc.id, doc.data() as FirestoreUserDocument)\n );\n }\n\n /**\n * Updates an existing user account.\n *\n * @param id - User identifier to update.\n * @param input - Partial fields to apply.\n * @param actingUserId - User performing the update action.\n */\n async updateUser(id: string, input: UpdateUserInput, actingUserId: string): Promise<UserRecord> {\n const existing = await this.findUserById(id);\n if (!existing) {\n throw new Error('User not found');\n }\n\n const name =\n input.name !== undefined ? trimRequiredName(input.name, 'User name') : existing.name;\n\n if (name !== existing.name) {\n assertUserNameNotReserved(name);\n const duplicate = await this.findUserByName(name);\n assertUserNameAvailable(name, id, duplicate);\n }\n\n const role = input.role ?? existing.role;\n const collectionAccess = input.collectionAccess ?? existing.collectionAccess;\n const environmentAccess = input.environmentAccess ?? existing.environmentAccess;\n const snippetAccess = input.snippetAccess ?? existing.snippetAccess;\n const llmAccess = input.llmAccess ?? existing.llmAccess;\n const llmModels = input.llmModels ?? existing.llmModels;\n const llmMonthlyTokenLimit =\n input.llmMonthlyTokenLimit !== undefined\n ? input.llmMonthlyTokenLimit\n : existing.llmMonthlyTokenLimit;\n const updatedAt = new Date();\n\n await this.requireClient().collection(USERS_COLLECTION).doc(id).update({\n name,\n role,\n collectionAccess,\n environmentAccess,\n snippetAccess,\n llmAccess,\n llmModels,\n llmMonthlyTokenLimit,\n updatedAt,\n updatedByUserId: actingUserId\n });\n\n await this.recordAuditEntry(actingUserId, 'update', 'user', id);\n\n const updated = await this.findUserById(id);\n if (!updated) {\n throw new Error('User not found');\n }\n\n return updated;\n }\n\n /**\n * Deletes a user account and revokes all of their API tokens.\n *\n * @param id - User identifier to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteUser(id: string, actingUserId: string): Promise<void> {\n const client = this.requireClient();\n const tokenSnapshot = await client\n .collection(API_TOKENS_COLLECTION)\n .where('userId', '==', id)\n .get();\n\n const batch = client.batch();\n\n for (const doc of tokenSnapshot.docs) {\n batch.delete(doc.ref);\n }\n\n batch.delete(client.collection(USERS_COLLECTION).doc(id));\n await batch.commit();\n\n await this.recordAuditEntry(actingUserId, 'delete', 'user', id);\n }\n\n /**\n * Assigns legacy API tokens without an owner to the bootstrap user.\n */\n async migrateOrphanTokensToBootstrapUser(): Promise<void> {\n const client = this.requireClient();\n const snapshot = await client.collection(API_TOKENS_COLLECTION).get();\n const orphanDocs = snapshot.docs.filter((doc) => {\n const data = doc.data() as Partial<FirestoreApiTokenDocument>;\n return data.userId === undefined || data.userId === null || data.userId === '';\n });\n\n if (orphanDocs.length === 0) {\n return;\n }\n\n const systemUserId = this.getSystemUserId();\n if (!systemUserId) {\n throw new Error('System user is not provisioned');\n }\n\n let bootstrapUser = await this.findUserByName(BOOTSTRAP_USER_NAME);\n if (!bootstrapUser) {\n bootstrapUser = await this.createUser(\n {\n name: BOOTSTRAP_USER_NAME,\n role: 'user',\n collectionAccess: ['*'],\n environmentAccess: ['*'],\n snippetAccess: ['*']\n },\n systemUserId\n );\n }\n\n for (let index = 0; index < orphanDocs.length; index += WRITE_BATCH_LIMIT) {\n const batch = client.batch();\n const chunk = orphanDocs.slice(index, index + WRITE_BATCH_LIMIT);\n for (const doc of chunk) {\n batch.update(doc.ref, { userId: bootstrapUser.id });\n }\n await batch.commit();\n }\n }\n\n /**\n * Grants wildcard snippet access to user accounts that already have wildcard collection access.\n */\n async migrateSnippetAccessBackfill(): Promise<void> {\n const client = this.requireClient();\n const snapshot = await client.collection(USERS_COLLECTION).where('role', '==', 'user').get();\n if (snapshot.docs.length === 0) {\n return;\n }\n\n let batch = client.batch();\n let batchSize = 0;\n\n for (const doc of snapshot.docs) {\n const data = doc.data() as FirestoreUserDocument;\n if ((data.snippetAccess?.length ?? 0) > 0) {\n continue;\n }\n if (!data.collectionAccess?.includes('*')) {\n continue;\n }\n\n batch.update(doc.ref, { snippetAccess: ['*'] });\n batchSize += 1;\n\n if (batchSize >= WRITE_BATCH_LIMIT) {\n await batch.commit();\n batch = client.batch();\n batchSize = 0;\n }\n }\n\n if (batchSize > 0) {\n await batch.commit();\n }\n }\n\n /**\n * Inserts a new API token document.\n *\n * @param record - Token metadata to persist.\n * @param actingUserId - User performing the create action.\n */\n async createApiToken(record: ApiTokenRecord, actingUserId: string): Promise<void> {\n await this.requireClient().collection(API_TOKENS_COLLECTION).doc(record.id).set({\n userId: record.userId,\n name: record.name,\n tokenHash: record.tokenHash,\n tokenPrefix: record.tokenPrefix,\n createdAt: record.createdAt,\n lastUsedAt: record.lastUsedAt,\n revokedAt: record.revokedAt,\n createdByUserId: actingUserId,\n updatedByUserId: actingUserId\n });\n\n await this.recordAuditEntry(actingUserId, 'create', 'api_token', record.id);\n }\n\n /**\n * Finds an active token by its stored hash.\n *\n * @param tokenHash - sha256 hex digest of the bearer token secret.\n */\n async findActiveApiTokenByHash(tokenHash: string): Promise<ApiTokenRecord | null> {\n const snapshot = await this.requireClient()\n .collection(API_TOKENS_COLLECTION)\n .where('tokenHash', '==', tokenHash)\n .limit(1)\n .get();\n\n const doc = snapshot.docs[0];\n if (!doc) {\n return null;\n }\n\n const data = doc.data() as FirestoreApiTokenDocument;\n if (data.revokedAt !== null || !data.userId) {\n return null;\n }\n\n return mapFirestoreApiToken(doc.id, data);\n }\n\n /**\n * Lists all API tokens ordered by creation time descending.\n */\n async listApiTokens(): Promise<ApiTokenRecord[]> {\n const snapshot = await this.requireClient()\n .collection(API_TOKENS_COLLECTION)\n .orderBy('createdAt', 'desc')\n .get();\n\n return snapshot.docs\n .map((doc) => mapFirestoreApiToken(doc.id, doc.data() as FirestoreApiTokenDocument))\n .filter((token) => Boolean(token.userId));\n }\n\n /**\n * Returns API tokens owned by a specific user ordered newest-first.\n *\n * @param userId - Owning user identifier.\n */\n async listApiTokensByUserId(userId: string): Promise<ApiTokenRecord[]> {\n const snapshot = await this.requireClient()\n .collection(API_TOKENS_COLLECTION)\n .where('userId', '==', userId)\n .orderBy('createdAt', 'desc')\n .get();\n\n return snapshot.docs.map((doc) =>\n mapFirestoreApiToken(doc.id, doc.data() as FirestoreApiTokenDocument)\n );\n }\n\n /**\n * Finds an API token record by stable identifier.\n *\n * @param id - Token identifier to look up.\n */\n async findApiTokenById(id: string): Promise<ApiTokenRecord | null> {\n const docRef = this.requireClient().collection(API_TOKENS_COLLECTION).doc(id);\n const snapshot = await docRef.get();\n if (!snapshot.exists) {\n return null;\n }\n\n return mapFirestoreApiToken(snapshot.id, snapshot.data() as FirestoreApiTokenDocument);\n }\n\n /**\n * Permanently removes an API token record by id.\n *\n * @param id - Token identifier to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteApiToken(id: string, actingUserId: string): Promise<boolean> {\n const docRef = this.requireClient().collection(API_TOKENS_COLLECTION).doc(id);\n const snapshot = await docRef.get();\n if (!snapshot.exists) {\n return false;\n }\n\n await docRef.delete();\n await this.recordAuditEntry(actingUserId, 'delete', 'api_token', id);\n return true;\n }\n\n /**\n * Soft-revokes an active token by id.\n *\n * @param id - Token identifier to revoke.\n * @param actingUserId - User performing the revoke action.\n */\n async revokeApiToken(id: string, actingUserId: string): Promise<boolean> {\n const docRef = this.requireClient().collection(API_TOKENS_COLLECTION).doc(id);\n const snapshot = await docRef.get();\n if (!snapshot.exists) {\n return false;\n }\n\n const data = snapshot.data() as FirestoreApiTokenDocument;\n if (data.revokedAt !== null) {\n return false;\n }\n\n await docRef.update({ revokedAt: new Date(), updatedByUserId: actingUserId });\n await this.recordAuditEntry(actingUserId, 'update', 'api_token', id);\n return true;\n }\n\n /**\n * Updates the last-used timestamp for a token.\n *\n * @param id - Token identifier that authenticated a request.\n * @param when - Timestamp of the authenticated request.\n */\n async touchApiTokenLastUsed(id: string, when: Date): Promise<void> {\n await this.requireClient()\n .collection(API_TOKENS_COLLECTION)\n .doc(id)\n .update({ lastUsedAt: when });\n }\n\n /**\n * Lists all collections ordered by name.\n */\n async listCollections(): Promise<CollectionRecord[]> {\n const snapshot = await this.requireClient()\n .collection(COLLECTIONS_COLLECTION)\n .orderBy('name')\n .get();\n\n return snapshot.docs.map((doc) =>\n mapFirestoreCollection(doc.id, doc.data() as FirestoreCollectionDocument)\n );\n }\n\n /**\n * Creates a new collection with the given name.\n *\n * @param name - Display name for the collection.\n * @param actingUserId - User performing the create action.\n */\n async createCollection(name: string, actingUserId: string): Promise<CollectionRecord> {\n const trimmedName = trimRequiredName(name, 'Collection name');\n const id = randomUUID();\n const now = new Date();\n const data: FirestoreCollectionDocument = {\n name: trimmedName,\n variables: [],\n headers: [],\n auth: defaultAuth(),\n preRequestScript: '',\n postRequestScript: '',\n createdAt: now,\n updatedAt: now,\n createdByUserId: actingUserId,\n updatedByUserId: actingUserId,\n deletionLocked: false\n };\n\n await this.requireClient().collection(COLLECTIONS_COLLECTION).doc(id).set(data);\n await this.recordAuditEntry(actingUserId, 'create', 'collection', id);\n return mapFirestoreCollection(id, data);\n }\n\n /**\n * Updates a collection's name, variables, headers, and scripts.\n *\n * @param actingUserId - User performing the update action.\n */\n async updateCollection(\n id: string,\n name: string,\n variables: Variable[],\n headers: KeyValue[],\n preRequestScript: string,\n postRequestScript: string,\n auth: AuthConfig,\n actingUserId: string\n ): Promise<CollectionRecord> {\n const trimmedName = trimRequiredName(name, 'Collection name');\n const updatedAt = new Date();\n const docRef = this.requireClient().collection(COLLECTIONS_COLLECTION).doc(id);\n const snapshot = await docRef.get();\n if (!snapshot.exists) {\n throw new Error('Collection not found');\n }\n\n const existing = snapshot.data() as FirestoreCollectionDocument;\n const updated: FirestoreCollectionDocument = {\n ...existing,\n name: trimmedName,\n variables,\n headers,\n auth,\n preRequestScript,\n postRequestScript,\n updatedAt,\n updatedByUserId: actingUserId\n };\n\n await docRef.update({\n name: trimmedName,\n variables,\n headers,\n auth,\n preRequestScript,\n postRequestScript,\n updatedAt,\n updatedByUserId: actingUserId\n });\n\n await this.recordAuditEntry(actingUserId, 'update', 'collection', id);\n return mapFirestoreCollection(id, updated);\n }\n\n /**\n * Deletes a collection and all of its requests and folders.\n *\n * @param id - Collection ID to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteCollection(id: string, actingUserId: string): Promise<void> {\n await this.recordAuditEntry(actingUserId, 'delete', 'collection', id);\n\n const client = this.requireClient();\n const requestsSnap = await client\n .collection(REQUESTS_COLLECTION)\n .where('collectionId', '==', id)\n .get();\n const foldersSnap = await client\n .collection(FOLDERS_COLLECTION)\n .where('collectionId', '==', id)\n .get();\n\n const refs = [\n ...requestsSnap.docs.map((requestDoc) => requestDoc.ref),\n ...foldersSnap.docs.map((folderDoc) => folderDoc.ref),\n client.collection(COLLECTIONS_COLLECTION).doc(id)\n ];\n\n await this.commitBatchedDeletes(refs);\n }\n\n /**\n * Finds a collection by stable identifier.\n *\n * @param id - Collection ID to look up.\n */\n async findCollectionById(id: string): Promise<CollectionRecord | null> {\n const snapshot = await this.requireClient().collection(COLLECTIONS_COLLECTION).doc(id).get();\n if (!snapshot.exists) {\n return null;\n }\n\n return mapFirestoreCollection(id, snapshot.data() as FirestoreCollectionDocument);\n }\n\n /**\n * Updates whether non-admin users may delete a collection.\n *\n * @param id - Collection ID to update.\n * @param deletionLocked - When true, user-role tokens cannot delete the collection.\n * @param actingUserId - Admin user performing the update.\n */\n async setCollectionDeletionLocked(\n id: string,\n deletionLocked: boolean,\n actingUserId: string\n ): Promise<CollectionRecord> {\n const docRef = this.requireClient().collection(COLLECTIONS_COLLECTION).doc(id);\n const snapshot = await docRef.get();\n if (!snapshot.exists) {\n throw new Error('Collection not found');\n }\n\n const updatedAt = new Date();\n await docRef.update({\n deletionLocked,\n updatedAt,\n updatedByUserId: actingUserId\n });\n\n await this.recordAuditEntry(actingUserId, 'update', 'collection', id);\n\n const existing = snapshot.data() as FirestoreCollectionDocument;\n return mapFirestoreCollection(id, {\n ...existing,\n deletionLocked,\n updatedAt,\n updatedByUserId: actingUserId\n });\n }\n\n /**\n * Lists all environments ordered by name.\n */\n async listEnvironments(): Promise<EnvironmentRecord[]> {\n const snapshot = await this.requireClient()\n .collection(ENVIRONMENTS_COLLECTION)\n .orderBy('name')\n .get();\n\n return snapshot.docs.map((doc) =>\n mapFirestoreEnvironment(doc.id, doc.data() as FirestoreEnvironmentDocument)\n );\n }\n\n /**\n * Creates a new environment with the given name.\n *\n * @param name - Display name for the environment.\n * @param actingUserId - User performing the create action.\n */\n async createEnvironment(name: string, actingUserId: string): Promise<EnvironmentRecord> {\n const trimmedName = trimRequiredName(name, 'Environment name');\n const id = randomUUID();\n const now = new Date();\n const data: FirestoreEnvironmentDocument = {\n name: trimmedName,\n variables: [],\n createdAt: now,\n updatedAt: now,\n createdByUserId: actingUserId,\n updatedByUserId: actingUserId,\n deletionLocked: false\n };\n\n await this.requireClient().collection(ENVIRONMENTS_COLLECTION).doc(id).set(data);\n await this.recordAuditEntry(actingUserId, 'create', 'environment', id);\n return mapFirestoreEnvironment(id, data);\n }\n\n /**\n * Updates an environment's name and variables.\n *\n * @param actingUserId - User performing the update action.\n */\n async updateEnvironment(\n id: string,\n name: string,\n variables: Variable[],\n actingUserId: string\n ): Promise<EnvironmentRecord> {\n const trimmedName = trimRequiredName(name, 'Environment name');\n const updatedAt = new Date();\n const docRef = this.requireClient().collection(ENVIRONMENTS_COLLECTION).doc(id);\n const snapshot = await docRef.get();\n if (!snapshot.exists) {\n throw new Error('Environment not found');\n }\n\n const existing = snapshot.data() as FirestoreEnvironmentDocument;\n const updated: FirestoreEnvironmentDocument = {\n ...existing,\n name: trimmedName,\n variables,\n updatedAt,\n updatedByUserId: actingUserId\n };\n\n await docRef.update({\n name: trimmedName,\n variables,\n updatedAt,\n updatedByUserId: actingUserId\n });\n\n await this.recordAuditEntry(actingUserId, 'update', 'environment', id);\n return mapFirestoreEnvironment(id, updated);\n }\n\n /**\n * Deletes an environment.\n *\n * @param id - Environment ID to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteEnvironment(id: string, actingUserId: string): Promise<void> {\n await this.recordAuditEntry(actingUserId, 'delete', 'environment', id);\n await this.requireClient().collection(ENVIRONMENTS_COLLECTION).doc(id).delete();\n }\n\n /**\n * Finds an environment by stable identifier.\n *\n * @param id - Environment ID to look up.\n */\n async findEnvironmentById(id: string): Promise<EnvironmentRecord | null> {\n const snapshot = await this.requireClient().collection(ENVIRONMENTS_COLLECTION).doc(id).get();\n if (!snapshot.exists) {\n return null;\n }\n\n return mapFirestoreEnvironment(id, snapshot.data() as FirestoreEnvironmentDocument);\n }\n\n /**\n * Updates whether non-admin users may delete an environment.\n *\n * @param id - Environment ID to update.\n * @param deletionLocked - When true, user-role tokens cannot delete the environment.\n * @param actingUserId - Admin user performing the update.\n */\n async setEnvironmentDeletionLocked(\n id: string,\n deletionLocked: boolean,\n actingUserId: string\n ): Promise<EnvironmentRecord> {\n const docRef = this.requireClient().collection(ENVIRONMENTS_COLLECTION).doc(id);\n const snapshot = await docRef.get();\n if (!snapshot.exists) {\n throw new Error('Environment not found');\n }\n\n const updatedAt = new Date();\n await docRef.update({\n deletionLocked,\n updatedAt,\n updatedByUserId: actingUserId\n });\n\n await this.recordAuditEntry(actingUserId, 'update', 'environment', id);\n\n const existing = snapshot.data() as FirestoreEnvironmentDocument;\n return mapFirestoreEnvironment(id, {\n ...existing,\n deletionLocked,\n updatedAt,\n updatedByUserId: actingUserId\n });\n }\n\n /**\n * Lists all snippets ordered by sort order then name.\n */\n async listSnippets(): Promise<SnippetRecord[]> {\n const snapshot = await this.requireClient().collection(SNIPPETS_COLLECTION).get();\n\n return snapshot.docs\n .map((doc) => mapFirestoreSnippet(doc.id, doc.data() as FirestoreSnippetDocument))\n .sort((left, right) => {\n if (left.sortOrder !== right.sortOrder) {\n return left.sortOrder - right.sortOrder;\n }\n\n return left.name.localeCompare(right.name);\n });\n }\n\n /**\n * Creates a new snippet with the given fields.\n *\n * @param name - Display name for the snippet.\n * @param code - JavaScript source for the snippet.\n * @param scope - Execution scope for the snippet.\n * @param actingUserId - User performing the create action.\n */\n async createSnippet(\n name: string,\n code: string,\n scope: SnippetScope,\n actingUserId: string\n ): Promise<SnippetRecord> {\n const trimmedName = trimRequiredName(name, 'Snippet name');\n const id = randomUUID();\n const now = new Date();\n const existing = await this.listSnippets();\n const maxOrder = existing.reduce((max, snippet) => Math.max(max, snippet.sortOrder), -1);\n const data: FirestoreSnippetDocument = {\n name: trimmedName,\n code,\n scope,\n sortOrder: maxOrder + 1,\n createdAt: now,\n updatedAt: now,\n createdByUserId: actingUserId,\n updatedByUserId: actingUserId,\n deletionLocked: false\n };\n\n await this.requireClient().collection(SNIPPETS_COLLECTION).doc(id).set(data);\n await this.recordAuditEntry(actingUserId, 'create', 'snippet', id);\n return mapFirestoreSnippet(id, data);\n }\n\n /**\n * Updates a snippet's name, code, and scope. Sort order is left unchanged.\n *\n * @param actingUserId - User performing the update action.\n */\n async updateSnippet(\n id: string,\n name: string,\n code: string,\n scope: SnippetScope,\n actingUserId: string\n ): Promise<SnippetRecord> {\n const trimmedName = trimRequiredName(name, 'Snippet name');\n const updatedAt = new Date();\n const docRef = this.requireClient().collection(SNIPPETS_COLLECTION).doc(id);\n const snapshot = await docRef.get();\n if (!snapshot.exists) {\n throw new Error('Snippet not found');\n }\n\n const existing = snapshot.data() as FirestoreSnippetDocument;\n const updated: FirestoreSnippetDocument = {\n ...existing,\n name: trimmedName,\n code,\n scope,\n updatedAt,\n updatedByUserId: actingUserId\n };\n\n await docRef.update({\n name: trimmedName,\n code,\n scope,\n updatedAt,\n updatedByUserId: actingUserId\n });\n\n await this.recordAuditEntry(actingUserId, 'update', 'snippet', id);\n return mapFirestoreSnippet(id, updated);\n }\n\n /**\n * Deletes a snippet.\n *\n * @param id - Snippet ID to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteSnippet(id: string, actingUserId: string): Promise<void> {\n await this.recordAuditEntry(actingUserId, 'delete', 'snippet', id);\n await this.requireClient().collection(SNIPPETS_COLLECTION).doc(id).delete();\n }\n\n /**\n * Finds a snippet by stable identifier.\n *\n * @param id - Snippet ID to look up.\n */\n async findSnippetById(id: string): Promise<SnippetRecord | null> {\n const snapshot = await this.requireClient().collection(SNIPPETS_COLLECTION).doc(id).get();\n if (!snapshot.exists) {\n return null;\n }\n\n return mapFirestoreSnippet(id, snapshot.data() as FirestoreSnippetDocument);\n }\n\n /**\n * Updates whether non-admin users may delete a snippet.\n *\n * @param id - Snippet ID to update.\n * @param deletionLocked - When true, user-role tokens cannot delete the snippet.\n * @param actingUserId - Admin user performing the update.\n */\n async setSnippetDeletionLocked(\n id: string,\n deletionLocked: boolean,\n actingUserId: string\n ): Promise<SnippetRecord> {\n const docRef = this.requireClient().collection(SNIPPETS_COLLECTION).doc(id);\n const snapshot = await docRef.get();\n if (!snapshot.exists) {\n throw new Error('Snippet not found');\n }\n\n const updatedAt = new Date();\n await docRef.update({\n deletionLocked,\n updatedAt,\n updatedByUserId: actingUserId\n });\n\n await this.recordAuditEntry(actingUserId, 'update', 'snippet', id);\n\n const existing = snapshot.data() as FirestoreSnippetDocument;\n return mapFirestoreSnippet(id, {\n ...existing,\n deletionLocked,\n updatedAt,\n updatedByUserId: actingUserId\n });\n }\n\n /**\n * Lists all saved requests in a collection.\n *\n * @param collectionId - Collection to query.\n */\n async listRequests(collectionId: string): Promise<SavedRequestRecord[]> {\n const snapshot = await this.requireClient()\n .collection(REQUESTS_COLLECTION)\n .where('collectionId', '==', collectionId)\n .get();\n\n return snapshot.docs\n .map((doc) => mapFirestoreRequest(doc.id, doc.data() as FirestoreRequestDocument))\n .sort((left, right) => {\n if (left.sortOrder !== right.sortOrder) {\n return left.sortOrder - right.sortOrder;\n }\n\n return left.name.localeCompare(right.name);\n });\n }\n\n /**\n * Finds a saved request by id.\n *\n * @param id - Request identifier to look up.\n */\n async findRequestById(id: string): Promise<SavedRequestRecord | null> {\n const snapshot = await this.requireClient().collection(REQUESTS_COLLECTION).doc(id).get();\n if (!snapshot.exists) {\n return null;\n }\n\n return mapFirestoreRequest(id, snapshot.data() as FirestoreRequestDocument);\n }\n\n /**\n * Inserts a new request or updates an existing one.\n *\n * @param input - Request fields to persist.\n * @param actingUserId - User performing the save action.\n */\n async saveRequest(input: SaveRequestInput, actingUserId: string): Promise<SavedRequestRecord> {\n const trimmedName = trimRequiredName(input.name, 'Request name');\n const folderId = input.folderId ?? null;\n const now = new Date();\n const client = this.requireClient();\n\n if (folderId != null) {\n const folderSnap = await client.collection(FOLDERS_COLLECTION).doc(folderId).get();\n if (!folderSnap.exists) {\n throw new Error('Folder not found');\n }\n\n const folder = folderSnap.data() as FirestoreFolderDocument;\n if (folder.collectionId !== input.collectionId) {\n throw new Error('Folder not found');\n }\n }\n\n if (input.id) {\n const docRef = client.collection(REQUESTS_COLLECTION).doc(input.id);\n const snapshot = await docRef.get();\n if (snapshot.exists) {\n const existing = snapshot.data() as FirestoreRequestDocument;\n const updated: FirestoreRequestDocument = {\n ...existing,\n collectionId: input.collectionId,\n folderId,\n name: trimmedName,\n method: input.method,\n url: input.url,\n headers: input.headers,\n params: input.params,\n auth: input.auth,\n body: input.body,\n bodyType: input.bodyType,\n preRequestScript: input.preRequestScript,\n postRequestScript: input.postRequestScript,\n comment: input.comment,\n updatedAt: now,\n updatedByUserId: actingUserId\n };\n\n await docRef.update({\n collectionId: input.collectionId,\n folderId,\n name: trimmedName,\n method: input.method,\n url: input.url,\n headers: input.headers,\n params: input.params,\n auth: input.auth,\n body: input.body,\n bodyType: input.bodyType,\n preRequestScript: input.preRequestScript,\n postRequestScript: input.postRequestScript,\n comment: input.comment,\n updatedAt: now,\n updatedByUserId: actingUserId\n });\n\n await this.recordAuditEntry(actingUserId, 'update', 'request', input.id);\n return mapFirestoreRequest(input.id, updated);\n }\n }\n\n const existingRequests = await this.listRequests(input.collectionId);\n const maxOrder = existingRequests\n .filter((request) => request.folderId === folderId)\n .reduce((max, request) => Math.max(max, request.sortOrder), -1);\n const id = randomUUID();\n const data: FirestoreRequestDocument = {\n collectionId: input.collectionId,\n folderId,\n name: trimmedName,\n method: input.method,\n url: input.url,\n headers: input.headers,\n params: input.params,\n auth: input.auth,\n body: input.body,\n bodyType: input.bodyType,\n preRequestScript: input.preRequestScript,\n postRequestScript: input.postRequestScript,\n comment: input.comment,\n sortOrder: maxOrder + 1,\n createdAt: now,\n updatedAt: now,\n createdByUserId: actingUserId,\n updatedByUserId: actingUserId\n };\n\n await client.collection(REQUESTS_COLLECTION).doc(id).set(data);\n await this.recordAuditEntry(actingUserId, 'create', 'request', id);\n return mapFirestoreRequest(id, data);\n }\n\n /**\n * Deletes a saved request by ID.\n *\n * @param id - Request ID to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteRequest(id: string, actingUserId: string): Promise<void> {\n await this.recordAuditEntry(actingUserId, 'delete', 'request', id);\n await this.requireClient().collection(REQUESTS_COLLECTION).doc(id).delete();\n }\n\n /**\n * Lists all folders in a collection.\n *\n * @param collectionId - Collection to query.\n */\n async listFolders(collectionId: string): Promise<FolderRecord[]> {\n const snapshot = await this.requireClient()\n .collection(FOLDERS_COLLECTION)\n .where('collectionId', '==', collectionId)\n .get();\n\n return snapshot.docs\n .map((doc) => mapFirestoreFolder(doc.id, doc.data() as FirestoreFolderDocument))\n .sort((left, right) => {\n if (left.sortOrder !== right.sortOrder) {\n return left.sortOrder - right.sortOrder;\n }\n\n return left.name.localeCompare(right.name);\n });\n }\n\n /**\n * Finds a folder by id.\n *\n * @param id - Folder identifier to look up.\n */\n async findFolderById(id: string): Promise<FolderRecord | null> {\n const snapshot = await this.requireClient().collection(FOLDERS_COLLECTION).doc(id).get();\n if (!snapshot.exists) {\n return null;\n }\n\n return mapFirestoreFolder(id, snapshot.data() as FirestoreFolderDocument);\n }\n\n /**\n * Creates a new folder in a collection.\n *\n * @param collectionId - Collection to add the folder to.\n * @param name - Display name for the folder.\n * @param actingUserId - User performing the create action.\n */\n async createFolder(\n collectionId: string,\n name: string,\n actingUserId: string\n ): Promise<FolderRecord> {\n const trimmedName = trimRequiredName(name, 'Folder name');\n const id = randomUUID();\n const now = new Date();\n const existingFolders = await this.listFolders(collectionId);\n const maxOrder = existingFolders.reduce((max, folder) => Math.max(max, folder.sortOrder), -1);\n const data: FirestoreFolderDocument = {\n collectionId,\n name: trimmedName,\n sortOrder: maxOrder + 1,\n createdAt: now,\n updatedAt: now,\n createdByUserId: actingUserId,\n updatedByUserId: actingUserId\n };\n\n await this.requireClient().collection(FOLDERS_COLLECTION).doc(id).set(data);\n await this.recordAuditEntry(actingUserId, 'create', 'folder', id);\n return mapFirestoreFolder(id, data);\n }\n\n /**\n * Renames a folder.\n *\n * @param id - Folder ID to rename.\n * @param name - New display name.\n * @param actingUserId - User performing the rename action.\n */\n async renameFolder(id: string, name: string, actingUserId: string): Promise<FolderRecord> {\n const trimmedName = trimRequiredName(name, 'Folder name');\n const updatedAt = new Date();\n const docRef = this.requireClient().collection(FOLDERS_COLLECTION).doc(id);\n const snapshot = await docRef.get();\n if (!snapshot.exists) {\n throw new Error('Folder not found');\n }\n\n const existing = snapshot.data() as FirestoreFolderDocument;\n await docRef.update({ name: trimmedName, updatedAt, updatedByUserId: actingUserId });\n await this.recordAuditEntry(actingUserId, 'update', 'folder', id);\n return mapFirestoreFolder(id, {\n ...existing,\n name: trimmedName,\n updatedAt,\n updatedByUserId: actingUserId\n });\n }\n\n /**\n * Deletes a folder and all requests inside it.\n *\n * @param id - Folder ID to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteFolder(id: string, actingUserId: string): Promise<void> {\n await this.recordAuditEntry(actingUserId, 'delete', 'folder', id);\n\n const client = this.requireClient();\n const requestsSnap = await client\n .collection(REQUESTS_COLLECTION)\n .where('folderId', '==', id)\n .get();\n\n const refs = [\n ...requestsSnap.docs.map((requestDoc) => requestDoc.ref),\n client.collection(FOLDERS_COLLECTION).doc(id)\n ];\n\n await this.commitBatchedDeletes(refs);\n }\n\n /**\n * Reorders folders within a collection.\n *\n * @param collectionId - Collection containing the folders.\n * @param orderedFolderIds - Folder IDs in desired order.\n * @param actingUserId - User performing the reorder action.\n */\n async reorderFolders(\n collectionId: string,\n orderedFolderIds: string[],\n actingUserId: string\n ): Promise<void> {\n const client = this.requireClient();\n const updatedAt = new Date();\n const batch = client.batch();\n\n for (let index = 0; index < orderedFolderIds.length; index++) {\n const docRef = client.collection(FOLDERS_COLLECTION).doc(orderedFolderIds[index]);\n batch.update(docRef, {\n sortOrder: index,\n collectionId,\n updatedAt,\n updatedByUserId: actingUserId\n });\n }\n\n await batch.commit();\n await this.recordAuditEntry(actingUserId, 'reorder', 'folder', collectionId, {\n orderedFolderIds\n });\n }\n\n /**\n * Reorders requests within a folder or at collection root.\n *\n * @param actingUserId - User performing the reorder action.\n */\n async reorderRequests(\n collectionId: string,\n folderId: string | null,\n orderedRequestIds: string[],\n actingUserId: string\n ): Promise<void> {\n const client = this.requireClient();\n const updatedAt = new Date();\n const batch = client.batch();\n\n for (let index = 0; index < orderedRequestIds.length; index++) {\n const docRef = client.collection(REQUESTS_COLLECTION).doc(orderedRequestIds[index]);\n batch.update(docRef, {\n sortOrder: index,\n folderId,\n collectionId,\n updatedAt,\n updatedByUserId: actingUserId\n });\n }\n\n await batch.commit();\n await this.recordAuditEntry(actingUserId, 'reorder', 'request', collectionId, {\n folderId,\n orderedRequestIds\n });\n }\n\n /**\n * Moves a request to another folder or collection root at a given index.\n *\n * @param actingUserId - User performing the move action.\n */\n async moveRequest(\n requestId: string,\n folderId: string | null,\n index: number,\n actingUserId: string\n ): Promise<void> {\n const client = this.requireClient();\n const updatedAt = new Date();\n const requestSnap = await client.collection(REQUESTS_COLLECTION).doc(requestId).get();\n if (!requestSnap.exists) {\n throw new Error('Request not found');\n }\n\n const request = mapFirestoreRequest(\n requestSnap.id,\n requestSnap.data() as FirestoreRequestDocument\n );\n const collectionId = request.collectionId;\n const oldFolderId = request.folderId;\n\n if (folderId != null) {\n const folderSnap = await client.collection(FOLDERS_COLLECTION).doc(folderId).get();\n if (!folderSnap.exists) {\n throw new Error('Folder not found');\n }\n\n const folder = folderSnap.data() as FirestoreFolderDocument;\n if (folder.collectionId !== collectionId) {\n throw new Error('Folder not found');\n }\n }\n\n /**\n * Lists request ids in a container ordered for reindexing.\n *\n * @param targetFolderId - Folder id or null for collection root.\n */\n const listInContainer = async (targetFolderId: string | null): Promise<string[]> => {\n const requests = await this.listRequests(collectionId);\n return requests\n .filter((item) => item.folderId === targetFolderId)\n .sort((left, right) => {\n if (left.sortOrder !== right.sortOrder) {\n return left.sortOrder - right.sortOrder;\n }\n\n return left.name.localeCompare(right.name);\n })\n .map((item) => item.id);\n };\n\n /**\n * Rewrites sort_order and folder_id for a container's request list.\n *\n * @param targetFolderId - Folder id or null for collection root.\n * @param orderedIds - Request ids in desired order.\n */\n const reindexContainer = async (\n targetFolderId: string | null,\n orderedIds: string[]\n ): Promise<void> => {\n const batch = client.batch();\n for (let sortIndex = 0; sortIndex < orderedIds.length; sortIndex++) {\n const docRef = client.collection(REQUESTS_COLLECTION).doc(orderedIds[sortIndex]);\n batch.update(docRef, {\n sortOrder: sortIndex,\n folderId: targetFolderId,\n updatedAt,\n updatedByUserId: actingUserId\n });\n }\n await batch.commit();\n };\n\n if (oldFolderId === folderId) {\n const siblings = (await listInContainer(folderId)).filter((id) => id !== requestId);\n siblings.splice(index, 0, requestId);\n await reindexContainer(folderId, siblings);\n await this.recordAuditEntry(actingUserId, 'move', 'request', requestId, {\n folderId,\n index\n });\n return;\n }\n\n const oldIds = (await listInContainer(oldFolderId)).filter((id) => id !== requestId);\n await reindexContainer(oldFolderId, oldIds);\n\n const newIds = (await listInContainer(folderId)).filter((id) => id !== requestId);\n newIds.splice(index, 0, requestId);\n await reindexContainer(folderId, newIds);\n\n await this.recordAuditEntry(actingUserId, 'move', 'request', requestId, {\n folderId,\n index\n });\n }\n\n /**\n * Returns monthly LLM usage for a user, or null when no usage has been recorded.\n *\n * @param userId - Owning user identifier.\n * @param period - UTC calendar month key (`YYYY-MM`).\n */\n async getLlmUsage(userId: string, period: string): Promise<LlmUsageRecord | null> {\n const docId = `${userId}_${period}`;\n const snapshot = await this.requireClient().collection(LLM_USAGE_COLLECTION).doc(docId).get();\n\n if (!snapshot.exists) {\n return null;\n }\n\n return mapFirestoreLlmUsage(docId, snapshot.data() as FirestoreLlmUsageDocument);\n }\n\n /**\n * Atomically increments monthly LLM token usage for a user.\n *\n * @param userId - Owning user identifier.\n * @param period - UTC calendar month key (`YYYY-MM`).\n * @param promptTokens - Prompt tokens to add.\n * @param completionTokens - Completion tokens to add.\n */\n async addLlmUsage(\n userId: string,\n period: string,\n promptTokens: number,\n completionTokens: number\n ): Promise<LlmUsageRecord> {\n const docId = `${userId}_${period}`;\n const docRef = this.requireClient().collection(LLM_USAGE_COLLECTION).doc(docId);\n const now = new Date();\n const totalDelta = promptTokens + completionTokens;\n\n await this.requireClient().runTransaction(async (transaction) => {\n const snapshot = await transaction.get(docRef);\n if (!snapshot.exists) {\n const data: FirestoreLlmUsageDocument = {\n userId,\n period,\n promptTokens,\n completionTokens,\n totalTokens: totalDelta,\n updatedAt: now\n };\n transaction.set(docRef, data);\n return;\n }\n\n const existing = snapshot.data() as FirestoreLlmUsageDocument;\n transaction.update(docRef, {\n promptTokens: existing.promptTokens + promptTokens,\n completionTokens: existing.completionTokens + completionTokens,\n totalTokens: existing.totalTokens + totalDelta,\n updatedAt: now\n });\n });\n\n const usage = await this.getLlmUsage(userId, period);\n if (!usage) {\n throw new Error('LLM usage not found after upsert');\n }\n\n return usage;\n }\n\n /**\n * Inserts a per-request LLM usage log entry.\n *\n * @param input - Usage details for one successful completion step.\n */\n async createLlmUsageLog(input: CreateLlmUsageLogInput): Promise<LlmUsageLogRecord> {\n const id = randomUUID();\n const now = new Date();\n const data: FirestoreLlmUsageLogDocument = {\n userId: input.userId,\n apiTokenId: input.apiTokenId,\n period: input.period,\n model: input.model,\n provider: input.provider,\n promptTokens: input.promptTokens,\n completionTokens: input.completionTokens,\n totalTokens: input.totalTokens,\n isNewTurn: input.isNewTurn,\n hadToolCalls: input.hadToolCalls,\n messageCount: input.messageCount,\n createdAt: now\n };\n\n await this.requireClient().collection(LLM_USAGE_LOG_COLLECTION).doc(id).set(data);\n\n return mapFirestoreLlmUsageLog(id, data);\n }\n\n /**\n * Lists all per-request LLM usage log entries, newest first.\n */\n async listLlmUsageLogs(): Promise<LlmUsageLogRecord[]> {\n const snapshot = await this.requireClient()\n .collection(LLM_USAGE_LOG_COLLECTION)\n .orderBy('createdAt', 'desc')\n .get();\n\n return snapshot.docs.map((doc) =>\n mapFirestoreLlmUsageLog(doc.id, doc.data() as FirestoreLlmUsageLogDocument)\n );\n }\n\n /**\n * Commits document deletes in Firestore-sized batches.\n *\n * @param refs - Document refs to delete.\n */\n private async commitBatchedDeletes(refs: DocumentReference[]): Promise<void> {\n const client = this.requireClient();\n\n for (let offset = 0; offset < refs.length; offset += WRITE_BATCH_LIMIT) {\n const batch = client.batch();\n for (const ref of refs.slice(offset, offset + WRITE_BATCH_LIMIT)) {\n batch.delete(ref);\n }\n await batch.commit();\n }\n }\n\n /**\n * Ensures the internal system user exists and caches its identifier.\n *\n * Inserts directly rather than calling {@link createUser} to avoid recursion\n * during migration bootstrap.\n */\n private async ensureSystemUser(): Promise<void> {\n const existing = await this.findUserByName(SYSTEM_USER_NAME);\n if (existing) {\n this.systemUserId = existing.id;\n return;\n }\n\n const input = createSystemUserInput();\n const id = randomUUID();\n const now = new Date();\n const trimmedName = trimRequiredName(input.name, 'User name');\n const data: FirestoreUserDocument = {\n name: trimmedName,\n role: input.role,\n collectionAccess: input.collectionAccess,\n environmentAccess: input.environmentAccess,\n snippetAccess: input.snippetAccess,\n llmAccess: false,\n llmModels: [],\n llmMonthlyTokenLimit: null,\n createdAt: now,\n updatedAt: now,\n createdByUserId: id,\n updatedByUserId: id\n };\n\n await this.requireClient().collection(USERS_COLLECTION).doc(id).set(data);\n this.systemUserId = id;\n }\n\n /**\n * Persists a single audit log entry for a mutating action.\n *\n * @param actingUserId - User performing the action.\n * @param action - CRUD or structural action performed.\n * @param entityType - Kind of entity affected.\n * @param entityId - Identifier of the affected entity.\n * @param metadata - Optional structured context for the action.\n */\n private async recordAuditEntry(\n actingUserId: string,\n action: AuditAction,\n entityType: AuditEntityType,\n entityId: string,\n metadata?: Record<string, unknown> | null\n ): Promise<void> {\n const userName = await resolveActingUserName(\n (userId) => this.findUserById(userId),\n actingUserId\n );\n const id = randomUUID();\n const now = new Date();\n const data: FirestoreAuditLogDocument = {\n userId: actingUserId,\n userName,\n action,\n entityType,\n entityId,\n createdAt: now,\n metadata: metadata ?? null\n };\n\n await this.requireClient().collection(AUDIT_LOG_COLLECTION).doc(id).set(data);\n }\n\n /**\n * Returns the active Firestore client or throws when connect has not been called.\n *\n * @returns Connected Firestore client.\n * @throws {Error} When the database is not connected.\n */\n private requireClient(): Firestore {\n if (!this.client) {\n throw new Error('Firestore database is not connected.');\n }\n\n return this.client;\n }\n}\n","import type { UserRecord } from '#/db/types.js';\n\n/**\n * Resolves the display name for an acting user id.\n *\n * @param findUserById - Lookup function provided by the active database backend.\n * @param actingUserId - User identifier performing the action.\n * @returns The user's display name, or null when the user no longer exists.\n */\nexport async function resolveActingUserName(\n findUserById: (id: string) => Promise<UserRecord | null>,\n actingUserId: string\n): Promise<string | null> {\n const user = await findUserById(actingUserId);\n return user?.name ?? null;\n}\n","import { randomUUID } from 'node:crypto';\nimport type { UserRecord } from '#/db/types.js';\n\n/**\n * Display name assigned to the migration bootstrap user for orphan API tokens.\n */\nexport const BOOTSTRAP_USER_NAME = 'bootstrap';\n\n/**\n * Builds the bootstrap user record used when assigning legacy tokens during migration.\n *\n * @param now - Timestamp used for created and updated fields.\n * @returns Bootstrap user with full collection and environment access.\n */\nexport function createBootstrapUserRecord(now: Date): UserRecord {\n return {\n id: randomUUID(),\n name: BOOTSTRAP_USER_NAME,\n role: 'user',\n collectionAccess: ['*'],\n environmentAccess: ['*'],\n snippetAccess: ['*'],\n llmAccess: false,\n llmModels: [],\n llmMonthlyTokenLimit: null,\n createdAt: now,\n updatedAt: now,\n createdByUserId: null,\n updatedByUserId: null\n };\n}\n","/**\n * Firestore collection name for user account documents.\n */\nexport const USERS_COLLECTION = 'users';\n\n/**\n * Firestore collection name for API token documents.\n */\nexport const API_TOKENS_COLLECTION = 'apiTokens';\n\n/**\n * Firestore collection name for shared collection documents.\n */\nexport const COLLECTIONS_COLLECTION = 'collections';\n\n/**\n * Firestore collection name for environment documents.\n */\nexport const ENVIRONMENTS_COLLECTION = 'environments';\n\n/**\n * Firestore collection name for snippet documents.\n */\nexport const SNIPPETS_COLLECTION = 'snippets';\n\n/**\n * Firestore collection name for folder documents.\n */\nexport const FOLDERS_COLLECTION = 'folders';\n\n/**\n * Firestore collection name for saved request documents.\n */\nexport const REQUESTS_COLLECTION = 'requests';\n\n/**\n * Firestore collection name for audit log documents.\n */\nexport const AUDIT_LOG_COLLECTION = 'auditLog';\n\n/**\n * Firestore collection name for monthly LLM usage documents.\n */\nexport const LLM_USAGE_COLLECTION = 'llmUsage';\n\n/**\n * Firestore collection name for per-request LLM usage log documents.\n */\nexport const LLM_USAGE_LOG_COLLECTION = 'llmUsageLog';\n\n/**\n * Maximum writes per Firestore batch commit.\n */\nexport const WRITE_BATCH_LIMIT = 500;\n","import type { CreateUserInput, UserRecord } from '#/db/types.js';\n\n/**\n * Display name assigned to the internal system user for CLI and migration actions.\n */\nexport const SYSTEM_USER_NAME = 'system';\n\n/**\n * Returns true when the record is the internal system account used for migrations\n * and CLI attribution.\n *\n * When {@link systemUserId} is known (post-migration), matching is id-only so\n * unrelated accounts named `system` are not misclassified. Before migration,\n * falls back to name matching and logs a deprecation warning.\n *\n * @param user - User record or subset with id and name.\n * @param systemUserId - Cached system user id from the database, when known.\n * @returns True for the provisioned system account.\n */\nexport function isSystemUser(\n user: Pick<UserRecord, 'id' | 'name'>,\n systemUserId?: string | null\n): boolean {\n if (systemUserId != null) {\n return user.id === systemUserId;\n }\n\n if (user.name === SYSTEM_USER_NAME) {\n console.warn(\n 'System user detected by name only; run database migration so id-based detection is used.'\n );\n return true;\n }\n\n return false;\n}\n\n/**\n * Builds the input used when creating the system user during database migration.\n *\n * @returns CreateUserInput for the system account with admin role and no entity access.\n */\nexport function createSystemUserInput(): CreateUserInput {\n return {\n name: SYSTEM_USER_NAME,\n role: 'admin',\n collectionAccess: [],\n environmentAccess: [],\n snippetAccess: []\n };\n}\n","import { z } from 'zod/v4';\n\n/**\n * Zod schema for validating raw Firestore database config from server.yaml.\n */\nexport const firestoreConfigSchema = z.object({\n driver: z.literal('firestore'),\n projectId: z.string().trim().min(1, { message: 'Firestore projectId must not be empty.' }),\n keyFilename: z.string().trim().min(1).optional()\n});\n","import type {\n ApiTokenRecord,\n AuditEntityType,\n AuditLogRecord,\n CollectionRecord,\n EnvironmentRecord,\n FolderRecord,\n SnippetRecord,\n LlmUsageRecord,\n LlmUsageLogRecord,\n SavedRequestRecord,\n UserRecord\n} from '#/db/types.js';\nimport type {\n FirestoreApiTokenDocument,\n FirestoreAuditLogDocument,\n FirestoreCollectionDocument,\n FirestoreEnvironmentDocument,\n FirestoreSnippetDocument,\n FirestoreFolderDocument,\n FirestoreLlmUsageDocument,\n FirestoreLlmUsageLogDocument,\n FirestoreRequestDocument,\n FirestoreUserDocument\n} from '#/db/firestore/types.js';\n\n/**\n * Parses a stored entity type string into a typed {@link AuditEntityType}.\n *\n * @param value - Entity type from storage.\n * @returns Validated entity type.\n * @throws {Error} When the stored entity type is not recognized.\n */\nfunction parseAuditEntityType(value: string): AuditEntityType {\n if (\n value === 'user' ||\n value === 'api_token' ||\n value === 'collection' ||\n value === 'environment' ||\n value === 'snippet' ||\n value === 'folder' ||\n value === 'request'\n ) {\n return value;\n }\n\n throw new Error(`Invalid audit entity type: ${value}`);\n}\n\n/**\n * Maps a Firestore document to the shared {@link ApiTokenRecord} shape.\n *\n * @param id - Document identifier.\n * @param data - Stored token fields.\n * @returns Normalized token record for application code.\n */\nexport function mapFirestoreApiToken(id: string, data: FirestoreApiTokenDocument): ApiTokenRecord {\n if (!data.userId) {\n throw new Error(`API token ${id} is missing a userId`);\n }\n\n return {\n id,\n userId: data.userId,\n name: data.name,\n tokenHash: data.tokenHash,\n tokenPrefix: data.tokenPrefix,\n createdAt: data.createdAt,\n lastUsedAt: data.lastUsedAt,\n revokedAt: data.revokedAt,\n createdByUserId: data.createdByUserId ?? null,\n updatedByUserId: data.updatedByUserId ?? null\n };\n}\n\n/**\n * Maps a Firestore document to the shared {@link UserRecord} shape.\n *\n * @param id - Document identifier.\n * @param data - Stored user fields.\n * @returns Normalized user record for application code.\n */\nexport function mapFirestoreUser(id: string, data: FirestoreUserDocument): UserRecord {\n return {\n id,\n name: data.name,\n role: data.role,\n collectionAccess: data.collectionAccess,\n environmentAccess: data.environmentAccess,\n snippetAccess: data.snippetAccess ?? [],\n llmAccess: data.llmAccess ?? false,\n llmModels: data.llmModels ?? [],\n llmMonthlyTokenLimit: data.llmMonthlyTokenLimit ?? null,\n createdAt: data.createdAt,\n updatedAt: data.updatedAt,\n createdByUserId: data.createdByUserId ?? null,\n updatedByUserId: data.updatedByUserId ?? null\n };\n}\n\n/**\n * Maps a Firestore document to the shared {@link LlmUsageRecord} shape.\n *\n * @param id - Document identifier.\n * @param data - Stored LLM usage fields.\n * @returns Normalized usage record for application code.\n */\nexport function mapFirestoreLlmUsage(id: string, data: FirestoreLlmUsageDocument): LlmUsageRecord {\n return {\n id,\n userId: data.userId,\n period: data.period,\n promptTokens: data.promptTokens,\n completionTokens: data.completionTokens,\n totalTokens: data.totalTokens,\n updatedAt: data.updatedAt\n };\n}\n\n/**\n * Maps a Firestore document to the shared {@link LlmUsageLogRecord} shape.\n *\n * @param id - Document identifier.\n * @param data - Stored LLM usage log fields.\n * @returns Normalized usage log record for application code.\n */\nexport function mapFirestoreLlmUsageLog(\n id: string,\n data: FirestoreLlmUsageLogDocument\n): LlmUsageLogRecord {\n return {\n id,\n userId: data.userId,\n apiTokenId: data.apiTokenId,\n period: data.period,\n model: data.model,\n provider: data.provider as LlmUsageLogRecord['provider'],\n promptTokens: data.promptTokens,\n completionTokens: data.completionTokens,\n totalTokens: data.totalTokens,\n isNewTurn: data.isNewTurn,\n hadToolCalls: data.hadToolCalls,\n messageCount: data.messageCount,\n createdAt: data.createdAt\n };\n}\n\n/**\n * Maps a Firestore document to the shared {@link CollectionRecord} shape.\n *\n * @param id - Document identifier.\n * @param data - Stored collection fields.\n * @returns Normalized collection record for application code.\n */\nexport function mapFirestoreCollection(\n id: string,\n data: FirestoreCollectionDocument\n): CollectionRecord {\n return {\n id,\n name: data.name,\n variables: data.variables,\n headers: data.headers,\n auth: data.auth,\n preRequestScript: data.preRequestScript,\n postRequestScript: data.postRequestScript,\n createdAt: data.createdAt,\n updatedAt: data.updatedAt ?? data.createdAt,\n createdByUserId: data.createdByUserId ?? null,\n updatedByUserId: data.updatedByUserId ?? null,\n deletionLocked: data.deletionLocked ?? false\n };\n}\n\n/**\n * Maps a Firestore document to the shared {@link EnvironmentRecord} shape.\n *\n * @param id - Document identifier.\n * @param data - Stored environment fields.\n * @returns Normalized environment record for application code.\n */\nexport function mapFirestoreEnvironment(\n id: string,\n data: FirestoreEnvironmentDocument\n): EnvironmentRecord {\n return {\n id,\n name: data.name,\n variables: data.variables,\n createdAt: data.createdAt,\n updatedAt: data.updatedAt ?? data.createdAt,\n createdByUserId: data.createdByUserId ?? null,\n updatedByUserId: data.updatedByUserId ?? null,\n deletionLocked: data.deletionLocked ?? false\n };\n}\n\n/**\n * Maps a Firestore document to the shared {@link SnippetRecord} shape.\n *\n * @param id - Document identifier.\n * @param data - Stored snippet fields.\n * @returns Normalized snippet record for application code.\n */\nexport function mapFirestoreSnippet(id: string, data: FirestoreSnippetDocument): SnippetRecord {\n return {\n id,\n name: data.name,\n code: data.code,\n scope: data.scope,\n sortOrder: data.sortOrder,\n createdAt: data.createdAt,\n updatedAt: data.updatedAt ?? data.createdAt,\n createdByUserId: data.createdByUserId ?? null,\n updatedByUserId: data.updatedByUserId ?? null,\n deletionLocked: data.deletionLocked ?? false\n };\n}\n\n/**\n * Maps a Firestore document to the shared {@link FolderRecord} shape.\n *\n * @param id - Document identifier.\n * @param data - Stored folder fields.\n * @returns Normalized folder record for application code.\n */\nexport function mapFirestoreFolder(id: string, data: FirestoreFolderDocument): FolderRecord {\n return {\n id,\n collectionId: data.collectionId,\n name: data.name,\n sortOrder: data.sortOrder,\n createdAt: data.createdAt,\n updatedAt: data.updatedAt ?? data.createdAt,\n createdByUserId: data.createdByUserId ?? null,\n updatedByUserId: data.updatedByUserId ?? null\n };\n}\n\n/**\n * Maps a Firestore document to the shared {@link SavedRequestRecord} shape.\n *\n * @param id - Document identifier.\n * @param data - Stored request fields.\n * @returns Normalized saved request record for application code.\n */\nexport function mapFirestoreRequest(\n id: string,\n data: FirestoreRequestDocument\n): SavedRequestRecord {\n return {\n id,\n collectionId: data.collectionId,\n folderId: data.folderId,\n name: data.name,\n method: data.method as SavedRequestRecord['method'],\n url: data.url,\n headers: data.headers,\n params: data.params,\n auth: data.auth,\n body: data.body,\n bodyType: data.bodyType as SavedRequestRecord['bodyType'],\n preRequestScript: data.preRequestScript,\n postRequestScript: data.postRequestScript,\n comment: data.comment,\n sortOrder: data.sortOrder,\n createdAt: data.createdAt,\n updatedAt: data.updatedAt,\n createdByUserId: data.createdByUserId ?? null,\n updatedByUserId: data.updatedByUserId ?? null\n };\n}\n\n/**\n * Maps a Firestore document to the shared {@link AuditLogRecord} shape.\n *\n * @param id - Document identifier.\n * @param data - Stored audit log fields.\n * @returns Normalized audit log record for application code.\n */\nexport function mapFirestoreAuditLog(id: string, data: FirestoreAuditLogDocument): AuditLogRecord {\n return {\n id,\n userId: data.userId,\n userName: data.userName,\n action: data.action,\n entityType: parseAuditEntityType(data.entityType),\n entityId: data.entityId,\n createdAt: data.createdAt,\n metadata: data.metadata\n };\n}\n\n/**\n * Returns nullable attribution fields with defaults for legacy Firestore documents.\n *\n * @param createdByUserId - Stored creating user id, if any.\n * @param updatedByUserId - Stored updating user id, if any.\n * @returns Normalized attribution pair.\n */\nexport function normalizeAttributionFields(\n createdByUserId: string | null | undefined,\n updatedByUserId: string | null | undefined\n): { createdByUserId: string | null; updatedByUserId: string | null } {\n return {\n createdByUserId: createdByUserId ?? null,\n updatedByUserId: updatedByUserId ?? null\n };\n}\n","/**\n * Trims a display name and rejects empty results.\n *\n * @param name - Raw name from callers.\n * @param label - Entity label for the error message (e.g. \"Collection name\").\n * @returns Trimmed non-empty name.\n * @throws When the trimmed name is empty.\n */\nexport function trimRequiredName(name: string, label: string): string {\n const trimmed = name.trim();\n if (!trimmed) {\n throw new Error(`${label} is required`);\n }\n\n return trimmed;\n}\n","import { SYSTEM_USER_NAME } from '#/db/systemUsers.js';\nimport type { UserRecord } from '#/db/types.js';\n\n/**\n * Error thrown when a user name is already assigned to another account.\n */\nexport class DuplicateUserNameError extends Error {\n /**\n * Creates a duplicate-name error with a client-facing message.\n *\n * @param name - Display name that is already in use.\n */\n constructor(name: string) {\n super(`User name \"${name}\" is already in use.`);\n this.name = 'DuplicateUserNameError';\n }\n}\n\n/**\n * Error thrown when a display name is reserved for the internal system account.\n */\nexport class ReservedUserNameError extends Error {\n /**\n * Creates a reserved-name error with a client-facing message.\n *\n * @param name - Display name that is reserved.\n */\n constructor(name: string) {\n super(`User name \"${name}\" is reserved for the internal system account.`);\n this.name = 'ReservedUserNameError';\n }\n}\n\n/**\n * Ensures a display name is not reserved for the internal system account.\n *\n * @param name - Candidate display name.\n * @throws {ReservedUserNameError} When the name is reserved.\n */\nexport function assertUserNameNotReserved(name: string): void {\n if (name === SYSTEM_USER_NAME) {\n throw new ReservedUserNameError(name);\n }\n}\n\n/**\n * Ensures a display name is not already used by a different user account.\n *\n * @param name - Candidate display name.\n * @param userId - User identifier being updated.\n * @param existing - User record returned by {@link IDatabase.findUserByName}, if any.\n * @throws {DuplicateUserNameError} When another account already uses the name.\n */\nexport function assertUserNameAvailable(\n name: string,\n userId: string,\n existing: UserRecord | null\n): void {\n if (existing && existing.id !== userId) {\n throw new DuplicateUserNameError(name);\n }\n}\n","/**\n * Server account role controlling API and CLI capabilities.\n */\nexport type UserRole = 'admin' | 'user';\n\n/**\n * CRUD or structural action recorded in the audit log.\n */\nexport type AuditAction = 'create' | 'update' | 'delete' | 'reorder' | 'move';\n\n/**\n * Entity kinds tracked by the audit log.\n */\nexport type AuditEntityType =\n | 'user'\n | 'api_token'\n | 'collection'\n | 'environment'\n | 'snippet'\n | 'folder'\n | 'request';\n\n/**\n * Persisted audit log entry describing a single mutating action.\n */\nexport interface AuditLogRecord {\n /**\n * Stable identifier for the audit entry.\n */\n id: string;\n\n /**\n * User who performed the action, when known.\n */\n userId: string | null;\n\n /**\n * Snapshot of the acting user's display name at write time.\n */\n userName: string | null;\n\n /**\n * Action that was performed.\n */\n action: AuditAction;\n\n /**\n * Kind of entity affected by the action.\n */\n entityType: AuditEntityType;\n\n /**\n * Identifier of the affected entity.\n */\n entityId: string;\n\n /**\n * When the action was recorded.\n */\n createdAt: Date;\n\n /**\n * Optional structured context for the action.\n */\n metadata: Record<string, unknown> | null;\n}\n\n/**\n * Optional filters when listing audit log entries.\n */\nexport interface ListAuditLogOptions {\n /**\n * Maximum number of entries to return, newest first.\n */\n limit?: number;\n\n /**\n * Restrict results to a specific acting user.\n */\n userId?: string;\n\n /**\n * Restrict results to a specific entity type.\n */\n entityType?: AuditEntityType;\n\n /**\n * Restrict results to a specific entity id.\n */\n entityId?: string;\n}\n\n/**\n * Stored metadata for a Team Hub user account.\n */\nexport interface UserRecord {\n /**\n * Stable identifier used for token ownership and CLI operations.\n */\n id: string;\n\n /**\n * Unique display name chosen when the user was created.\n */\n name: string;\n\n /**\n * Role determining API capabilities: `user` for scoped entity access,\n * `admin` for management API access without entity access.\n */\n role: UserRole;\n\n /**\n * Collection ids the user may access, or `['*']` for all collections.\n */\n collectionAccess: string[];\n\n /**\n * Environment ids the user may access, or `['*']` for all environments.\n */\n environmentAccess: string[];\n\n /**\n * Snippet ids the user may access, or `['*']` for all snippets.\n */\n snippetAccess: string[];\n\n /**\n * When true, the user may call hub-proxied LLM routes.\n */\n llmAccess: boolean;\n\n /**\n * LLM model ids the user may use, or `['*']` for all hub-offered models.\n */\n llmModels: string[];\n\n /**\n * Maximum total tokens per UTC calendar month, or null for unlimited.\n */\n llmMonthlyTokenLimit: number | null;\n\n /**\n * When the user account was created.\n */\n createdAt: Date;\n\n /**\n * When the user account was last updated.\n */\n updatedAt: Date;\n\n /**\n * User who created the account.\n */\n createdByUserId: string | null;\n\n /**\n * User who last updated the account.\n */\n updatedByUserId: string | null;\n}\n\n/**\n * Fields required to create a new user account.\n */\nexport interface CreateUserInput {\n /**\n * Unique display name for the new account.\n */\n name: string;\n\n /**\n * Role assigned to the new account.\n */\n role: UserRole;\n\n /**\n * Collection access list; admins store an empty array.\n */\n collectionAccess: string[];\n\n /**\n * Environment access list; admins store an empty array.\n */\n environmentAccess: string[];\n\n /**\n * Snippet access list; admins store an empty array.\n */\n snippetAccess: string[];\n\n /**\n * Whether the user may use hub-proxied LLM routes.\n */\n llmAccess?: boolean;\n\n /**\n * Allowed LLM model ids, or `['*']` for all hub-offered models.\n */\n llmModels?: string[];\n\n /**\n * Monthly token limit, or null for unlimited.\n */\n llmMonthlyTokenLimit?: number | null;\n}\n\n/**\n * Partial fields accepted when updating an existing user account.\n */\nexport interface UpdateUserInput {\n /**\n * New unique display name, when changing the account label.\n */\n name?: string;\n\n /**\n * New role, when changing account capabilities.\n */\n role?: UserRole;\n\n /**\n * Replacement collection access list.\n */\n collectionAccess?: string[];\n\n /**\n * Replacement environment access list.\n */\n environmentAccess?: string[];\n\n /**\n * Replacement snippet access list.\n */\n snippetAccess?: string[];\n\n /**\n * Whether the user may use hub-proxied LLM routes.\n */\n llmAccess?: boolean;\n\n /**\n * Replacement LLM model access list.\n */\n llmModels?: string[];\n\n /**\n * Replacement monthly token limit, or null for unlimited.\n */\n llmMonthlyTokenLimit?: number | null;\n}\n\n/**\n * Stored metadata for a database-backed API bearer token.\n *\n * The raw secret is never persisted; only its sha256 hash is stored for lookup.\n */\nexport interface ApiTokenRecord {\n /**\n * Stable identifier used for revoke and audit operations.\n */\n id: string;\n\n /**\n * Owning user account that receives the token's access permissions.\n */\n userId: string;\n\n /**\n * Human-readable label chosen when the token was created.\n */\n name: string;\n\n /**\n * sha256 hex digest of the bearer token secret.\n */\n tokenHash: string;\n\n /**\n * Non-secret prefix shown in listings (for example `hbk_AbCd1234`).\n */\n tokenPrefix: string;\n\n /**\n * When the token was created.\n */\n createdAt: Date;\n\n /**\n * When the token was last used to authenticate a request, if ever.\n */\n lastUsedAt: Date | null;\n\n /**\n * When the token was revoked; null means the token is still active.\n */\n revokedAt: Date | null;\n\n /**\n * User who created the token record.\n */\n createdByUserId: string | null;\n\n /**\n * User who last updated the token record.\n */\n updatedByUserId: string | null;\n}\n\n/**\n * Persisted monthly LLM token usage for a user.\n */\nexport interface LlmUsageRecord {\n /**\n * Stable identifier for the usage row.\n */\n id: string;\n\n /**\n * Owning user account id.\n */\n userId: string;\n\n /**\n * UTC calendar month key (`YYYY-MM`).\n */\n period: string;\n\n /**\n * Prompt tokens consumed during the period.\n */\n promptTokens: number;\n\n /**\n * Completion tokens consumed during the period.\n */\n completionTokens: number;\n\n /**\n * Total tokens consumed during the period.\n */\n totalTokens: number;\n\n /**\n * When usage was last updated.\n */\n updatedAt: Date;\n}\n\n/**\n * LLM provider id stored on per-request usage log rows.\n */\nexport type LlmUsageLogProvider = 'openai' | 'claude' | 'gemini';\n\n/**\n * Persisted per-request LLM usage log entry.\n */\nexport interface LlmUsageLogRecord {\n /**\n * Stable identifier for the log row.\n */\n id: string;\n\n /**\n * User who consumed tokens.\n */\n userId: string;\n\n /**\n * Bearer token used for the request, when known.\n */\n apiTokenId: string | null;\n\n /**\n * UTC calendar month key (`YYYY-MM`).\n */\n period: string;\n\n /**\n * Provider-specific model id sent to the API.\n */\n model: string;\n\n /**\n * LLM provider that served the request.\n */\n provider: LlmUsageLogProvider;\n\n /**\n * Prompt tokens billed for the step.\n */\n promptTokens: number;\n\n /**\n * Completion tokens billed for the step.\n */\n completionTokens: number;\n\n /**\n * Total tokens billed for the step.\n */\n totalTokens: number;\n\n /**\n * Whether the last message in the request was from the user.\n */\n isNewTurn: boolean;\n\n /**\n * Whether the model returned tool calls.\n */\n hadToolCalls: boolean;\n\n /**\n * Number of messages included in the request body.\n */\n messageCount: number;\n\n /**\n * When the completion step finished.\n */\n createdAt: Date;\n}\n\n/**\n * Input for inserting a per-request LLM usage log row.\n */\nexport interface CreateLlmUsageLogInput {\n /**\n * User who consumed tokens.\n */\n userId: string;\n\n /**\n * Bearer token used for the request, when known.\n */\n apiTokenId: string | null;\n\n /**\n * UTC calendar month key (`YYYY-MM`).\n */\n period: string;\n\n /**\n * Provider-specific model id sent to the API.\n */\n model: string;\n\n /**\n * LLM provider that served the request.\n */\n provider: LlmUsageLogProvider;\n\n /**\n * Prompt tokens billed for the step.\n */\n promptTokens: number;\n\n /**\n * Completion tokens billed for the step.\n */\n completionTokens: number;\n\n /**\n * Total tokens billed for the step.\n */\n totalTokens: number;\n\n /**\n * Whether the last message in the request was from the user.\n */\n isNewTurn: boolean;\n\n /**\n * Whether the model returned tool calls.\n */\n hadToolCalls: boolean;\n\n /**\n * Number of messages included in the request body.\n */\n messageCount: number;\n}\n\n/**\n * Supported HTTP request methods.\n */\nexport type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS';\n\n/**\n * Request body content type.\n */\nexport type BodyType = 'none' | 'json' | 'text' | 'multipart' | 'urlencoded';\n\n/**\n * Authorization type for saved requests and collections.\n */\nexport type AuthType = 'none' | 'basic' | 'bearer';\n\n/**\n * Basic and bearer credential fields stored together so switching type preserves values.\n */\nexport interface AuthConfig {\n /**\n * Selected auth mode; none means no request-level override.\n */\n type: AuthType;\n\n /**\n * Username and password for Basic Auth.\n */\n basic: {\n username: string;\n password: string;\n };\n\n /**\n * Token value for Bearer Token auth.\n */\n bearer: {\n token: string;\n };\n}\n\n/**\n * A key-value pair with an enable toggle for headers and query params.\n */\nexport interface KeyValue {\n /**\n * Header or query parameter name.\n */\n key: string;\n\n /**\n * Header or query parameter value.\n */\n value: string;\n\n /**\n * When false, the pair is ignored when building the request.\n */\n enabled: boolean;\n}\n\n/**\n * A collection-scoped or environment-scoped variable for {{key}} substitution.\n */\nexport interface Variable {\n /**\n * Variable name referenced in {{key}} placeholders.\n */\n key: string;\n\n /**\n * Value substituted when the variable is resolved.\n */\n value: string;\n\n /**\n * Fallback value used when value is empty.\n */\n defaultValue: string;\n\n /**\n * When true, value is included in collection exports.\n */\n share: boolean;\n}\n\n/**\n * Persisted collection metadata and defaults shared by all requests in the collection.\n */\nexport interface CollectionRecord {\n /**\n * Stable collection identifier.\n */\n id: string;\n\n /**\n * Display name shown in the sidebar.\n */\n name: string;\n\n /**\n * Collection-scoped variables for {{key}} substitution in requests.\n */\n variables: Variable[];\n\n /**\n * Headers sent with every request in this collection.\n */\n headers: KeyValue[];\n\n /**\n * Default Authorization settings inherited by requests unless overridden.\n */\n auth: AuthConfig;\n\n /**\n * JavaScript run before every request in this collection.\n */\n preRequestScript: string;\n\n /**\n * JavaScript run after every request in this collection.\n */\n postRequestScript: string;\n\n /**\n * When the collection was created.\n */\n createdAt: Date;\n\n /**\n * When the collection was last updated.\n */\n updatedAt: Date;\n\n /**\n * User who created the collection.\n */\n createdByUserId: string | null;\n\n /**\n * User who last updated the collection.\n */\n updatedByUserId: string | null;\n\n /**\n * When true, non-admin users cannot delete this collection.\n */\n deletionLocked: boolean;\n}\n\n/**\n * Persisted environment with scoped variables.\n */\nexport interface EnvironmentRecord {\n /**\n * Stable environment identifier.\n */\n id: string;\n\n /**\n * Display name shown in the sidebar.\n */\n name: string;\n\n /**\n * Environment-scoped variables for {{key}} substitution in requests.\n */\n variables: Variable[];\n\n /**\n * When the environment was created.\n */\n createdAt: Date;\n\n /**\n * When the environment was last updated.\n */\n updatedAt: Date;\n\n /**\n * User who created the environment.\n */\n createdByUserId: string | null;\n\n /**\n * User who last updated the environment.\n */\n updatedByUserId: string | null;\n\n /**\n * When true, non-admin users cannot delete this environment.\n */\n deletionLocked: boolean;\n}\n\n/**\n * Execution scope for a reusable code snippet.\n */\nexport type SnippetScope = 'pre-request' | 'post-request' | 'any';\n\n/**\n * Persisted reusable script snippet.\n */\nexport interface SnippetRecord {\n /**\n * Stable snippet identifier.\n */\n id: string;\n\n /**\n * Display name shown in the sidebar.\n */\n name: string;\n\n /**\n * JavaScript source inserted into requests.\n */\n code: string;\n\n /**\n * When the snippet may be applied relative to a request.\n */\n scope: SnippetScope;\n\n /**\n * Position for sidebar ordering.\n */\n sortOrder: number;\n\n /**\n * When the snippet was created.\n */\n createdAt: Date;\n\n /**\n * When the snippet was last updated.\n */\n updatedAt: Date;\n\n /**\n * User who created the snippet.\n */\n createdByUserId: string | null;\n\n /**\n * User who last updated the snippet.\n */\n updatedByUserId: string | null;\n\n /**\n * When true, non-admin users cannot delete this snippet.\n */\n deletionLocked: boolean;\n}\n\n/**\n * A folder for organizing requests within a collection.\n */\nexport interface FolderRecord {\n /**\n * Stable folder identifier.\n */\n id: string;\n\n /**\n * ID of the collection this folder belongs to.\n */\n collectionId: string;\n\n /**\n * Display name shown in the sidebar.\n */\n name: string;\n\n /**\n * Position among sibling folders for sidebar ordering.\n */\n sortOrder: number;\n\n /**\n * When the folder was created.\n */\n createdAt: Date;\n\n /**\n * When the folder was last updated.\n */\n updatedAt: Date;\n\n /**\n * User who created the folder.\n */\n createdByUserId: string | null;\n\n /**\n * User who last updated the folder.\n */\n updatedByUserId: string | null;\n}\n\n/**\n * A saved HTTP request belonging to a collection.\n */\nexport interface SavedRequestRecord {\n /**\n * Stable request identifier.\n */\n id: string;\n\n /**\n * ID of the collection this request belongs to.\n */\n collectionId: string;\n\n /**\n * Display name shown in the sidebar.\n */\n name: string;\n\n /**\n * HTTP method used for the request.\n */\n method: HttpMethod;\n\n /**\n * Request URL without query parameters.\n */\n url: string;\n\n /**\n * Request headers as editable key-value pairs.\n */\n headers: KeyValue[];\n\n /**\n * Query parameters as editable key-value pairs.\n */\n params: KeyValue[];\n\n /**\n * Authorization settings; none inherits collection auth at send time.\n */\n auth: AuthConfig;\n\n /**\n * Raw request body content.\n */\n body: string;\n\n /**\n * Content type of the request body.\n */\n bodyType: BodyType;\n\n /**\n * JavaScript run before the request is sent.\n */\n preRequestScript: string;\n\n /**\n * JavaScript run after the response is received.\n */\n postRequestScript: string;\n\n /**\n * Free-form notes for this request.\n */\n comment: string;\n\n /**\n * ID of the folder containing this request, or null when at collection root.\n */\n folderId: string | null;\n\n /**\n * Position within the collection for sidebar ordering.\n */\n sortOrder: number;\n\n /**\n * When the request was created.\n */\n createdAt: Date;\n\n /**\n * When the request was last saved.\n */\n updatedAt: Date;\n\n /**\n * User who created the request.\n */\n createdByUserId: string | null;\n\n /**\n * User who last updated the request.\n */\n updatedByUserId: string | null;\n}\n\n/**\n * Input for creating or updating a saved request.\n */\nexport interface SaveRequestInput {\n /**\n * Existing request ID; omit to insert a new request.\n */\n id?: string;\n\n /**\n * ID of the collection to save the request in.\n */\n collectionId: string;\n\n /**\n * Display name for the saved request.\n */\n name: string;\n\n /**\n * HTTP method used for the request.\n */\n method: HttpMethod;\n\n /**\n * Request URL without query parameters.\n */\n url: string;\n\n /**\n * Request headers as editable key-value pairs.\n */\n headers: KeyValue[];\n\n /**\n * Query parameters as editable key-value pairs.\n */\n params: KeyValue[];\n\n /**\n * Authorization settings; none inherits collection auth at send time.\n */\n auth: AuthConfig;\n\n /**\n * Raw request body content.\n */\n body: string;\n\n /**\n * Content type of the request body.\n */\n bodyType: BodyType;\n\n /**\n * JavaScript run before the request is sent.\n */\n preRequestScript: string;\n\n /**\n * JavaScript run after the response is received.\n */\n postRequestScript: string;\n\n /**\n * Free-form notes for this request.\n */\n comment: string;\n\n /**\n * ID of the folder containing this request, or null when at collection root.\n */\n folderId?: string | null;\n}\n\n/**\n * Returns a default auth config with type none and empty credentials.\n *\n * @returns Empty AuthConfig safe for new requests and collections.\n */\nexport function defaultAuth(): AuthConfig {\n return {\n type: 'none',\n basic: { username: '', password: '' },\n bearer: { token: '' }\n };\n}\n\n/**\n * JSON string of {@link defaultAuth} for database column defaults.\n */\nexport const DEFAULT_AUTH_JSON = JSON.stringify(defaultAuth());\n\n/**\n * Normalizes a partial or legacy auth value from storage into a full AuthConfig.\n *\n * @param value - Parsed JSON or unknown field from the database.\n * @returns Valid AuthConfig with defaults for missing fields.\n */\nexport function normalizeAuth(value: unknown): AuthConfig {\n const fallback = defaultAuth();\n if (value == null || typeof value !== 'object') {\n return fallback;\n }\n\n const record = value as Record<string, unknown>;\n const type =\n record.type === 'basic' || record.type === 'bearer' || record.type === 'none'\n ? record.type\n : fallback.type;\n\n const basicRecord =\n record.basic != null && typeof record.basic === 'object'\n ? (record.basic as Record<string, unknown>)\n : {};\n const bearerRecord =\n record.bearer != null && typeof record.bearer === 'object'\n ? (record.bearer as Record<string, unknown>)\n : {};\n\n return {\n type,\n basic: {\n username: typeof basicRecord.username === 'string' ? basicRecord.username : '',\n password: typeof basicRecord.password === 'string' ? basicRecord.password : ''\n },\n bearer: {\n token: typeof bearerRecord.token === 'string' ? bearerRecord.token : ''\n }\n };\n}\n\n/**\n * Normalizes a variable row from storage.\n *\n * @param value - Partial variable from JSON.\n * @returns Variable with defaults for missing fields.\n */\nexport function normalizeVariable(value: Partial<Variable>): Variable {\n return {\n key: typeof value.key === 'string' ? value.key : '',\n value: typeof value.value === 'string' ? value.value : '',\n defaultValue: typeof value.defaultValue === 'string' ? value.defaultValue : '',\n share: typeof value.share === 'boolean' ? value.share : false\n };\n}\n","import type { ZodError } from 'zod/v4';\n\n/**\n * Formats the first Zod validation issue into a short user-facing message.\n *\n * @param error - Zod validation error from schema parsing.\n * @returns Human-readable error string.\n */\nexport function formatZodError(error: ZodError): string {\n const issue = error.issues[0];\n if (!issue) {\n return 'Invalid database configuration.';\n }\n\n if (issue.message) {\n return issue.message;\n }\n\n return 'Invalid database configuration.';\n}\n","import { randomUUID } from 'node:crypto';\nimport mysql, { type Pool, type ResultSetHeader, type RowDataPacket } from 'mysql2/promise';\nimport { mapApiTokenSqlRow, type ApiTokenSqlRow } from '#/db/apiTokenRows.js';\nimport { resolveActingUserName } from '#/db/attribution.js';\nimport {\n mapAuditLogSqlRow,\n serializeAuditMetadata,\n type AuditLogSqlRow\n} from '#/db/auditLogRows.js';\nimport { BOOTSTRAP_USER_NAME } from '#/db/bootstrapUsers.js';\nimport {\n mapCollectionSqlRow,\n mapEnvironmentSqlRow,\n mapFolderSqlRow,\n mapRequestSqlRow,\n mapSnippetSqlRow,\n type CollectionSqlRow,\n type EnvironmentSqlRow,\n type FolderSqlRow,\n type RequestSqlRow,\n type SnippetSqlRow\n} from '#/db/entityRows.js';\nimport type { IDatabase } from '#/db/IDatabase.js';\nimport { MYSQL_DEFAULT_AUTH_JSON, MYSQL_MIGRATIONS } from '#/db/mysql/migrations.js';\nimport { mysqlConfigSchema } from '#/db/mysql/schemas.js';\nimport type { MysqlDatabaseConfig } from '#/db/mysql/types.js';\nimport { createSystemUserInput, SYSTEM_USER_NAME } from '#/db/systemUsers.js';\nimport { trimRequiredName } from '#/db/trimRequiredName.js';\nimport { assertUserNameAvailable, assertUserNameNotReserved } from '#/db/userNameValidation.js';\nimport {\n API_TOKEN_SELECT_COLUMNS,\n AUDIT_LOG_SELECT_COLUMNS,\n COLLECTION_SELECT_COLUMNS,\n ENVIRONMENT_SELECT_COLUMNS,\n FOLDER_SELECT_COLUMNS,\n mapUserSqlRow,\n REQUEST_SELECT_COLUMNS,\n SNIPPET_SELECT_COLUMNS,\n serializeAccessList,\n USER_SELECT_COLUMNS,\n type UserSqlRow\n} from '#/db/userRows.js';\nimport {\n LLM_USAGE_LOG_SELECT_COLUMNS,\n mapLlmUsageLogSqlRow,\n type LlmUsageLogSqlRow\n} from '#/db/llmUsageLogRows.js';\nimport {\n LLM_USAGE_SELECT_COLUMNS,\n mapLlmUsageSqlRow,\n type LlmUsageSqlRow\n} from '#/db/llmUsageRows.js';\nimport type {\n ApiTokenRecord,\n AuditAction,\n AuditEntityType,\n AuditLogRecord,\n AuthConfig,\n CollectionRecord,\n CreateUserInput,\n CreateLlmUsageLogInput,\n EnvironmentRecord,\n FolderRecord,\n KeyValue,\n ListAuditLogOptions,\n LlmUsageLogRecord,\n LlmUsageRecord,\n SaveRequestInput,\n SavedRequestRecord,\n SnippetRecord,\n SnippetScope,\n UpdateUserInput,\n UserRecord,\n Variable\n} from '#/db/types.js';\nimport { formatZodError } from '#/db/validation.js';\n\nconst COLLECTION_SELECT = `SELECT ${COLLECTION_SELECT_COLUMNS} FROM collections`;\nconst ENVIRONMENT_SELECT = `SELECT ${ENVIRONMENT_SELECT_COLUMNS} FROM environments`;\nconst SNIPPET_SELECT = `SELECT ${SNIPPET_SELECT_COLUMNS} FROM snippets`;\nconst USER_SELECT = `SELECT ${USER_SELECT_COLUMNS} FROM users`;\nconst API_TOKEN_SELECT = `SELECT ${API_TOKEN_SELECT_COLUMNS} FROM api_tokens`;\nconst FOLDER_SELECT = `SELECT ${FOLDER_SELECT_COLUMNS} FROM folders`;\nconst REQUEST_SELECT = `SELECT ${REQUEST_SELECT_COLUMNS} FROM requests`;\nconst AUDIT_LOG_SELECT = `SELECT ${AUDIT_LOG_SELECT_COLUMNS} FROM audit_log`;\nconst LLM_USAGE_SELECT = `SELECT ${LLM_USAGE_SELECT_COLUMNS} FROM llm_usage`;\nconst LLM_USAGE_LOG_SELECT = `SELECT ${LLM_USAGE_LOG_SELECT_COLUMNS} FROM llm_usage_log`;\n\n/**\n * MySQL-backed database implementation.\n */\nexport class MysqlDatabase implements IDatabase {\n /**\n * Active MySQL connection pool, or null when disconnected.\n */\n private pool: Pool | null = null;\n\n /**\n * Cached identifier of the internal system user, when provisioned during migration.\n */\n private systemUserId: string | null = null;\n\n /**\n * Creates a MySQL database instance from validated config.\n *\n * @param config - Parsed MySQL connection settings.\n */\n constructor(private readonly config: MysqlDatabaseConfig) {}\n\n /**\n * Validates raw config and constructs a {@link MysqlDatabase}.\n *\n * @param config - Raw `db` section from server.yaml.\n * @returns Configured MySQL database instance.\n * @throws {Error} When config fails MySQL-specific validation.\n */\n static fromConfig(config: unknown): MysqlDatabase {\n const parsed = mysqlConfigSchema.safeParse(config);\n if (!parsed.success) {\n throw new Error(formatZodError(parsed.error));\n }\n\n return new MysqlDatabase({\n host: parsed.data.host,\n port: parsed.data.port,\n user: parsed.data.user,\n password: parsed.data.password,\n database: parsed.data.database\n });\n }\n\n /**\n * Opens a MySQL connection pool and verifies connectivity with a ping.\n */\n async connect(): Promise<void> {\n if (this.pool) {\n return;\n }\n\n const pool = mysql.createPool({\n host: this.config.host,\n port: this.config.port,\n user: this.config.user,\n password: this.config.password,\n database: this.config.database\n });\n\n const connection = await pool.getConnection();\n await connection.ping();\n connection.release();\n\n this.pool = pool;\n }\n\n /**\n * Closes the MySQL connection pool and releases resources.\n */\n async disconnect(): Promise<void> {\n if (!this.pool) {\n return;\n }\n\n await this.pool.end();\n this.pool = null;\n }\n\n /**\n * Creates required tables when they do not already exist.\n */\n async migrate(): Promise<void> {\n for (const sql of MYSQL_MIGRATIONS) {\n await this.executeStatement(sql);\n }\n\n await this.ensureSystemUser();\n await this.migrateOrphanTokensToBootstrapUser();\n }\n\n /**\n * Returns the stable identifier of the internal system user, when provisioned.\n */\n getSystemUserId(): string | null {\n return this.systemUserId;\n }\n\n /**\n * Lists audit log entries ordered newest-first with optional filters.\n *\n * @param options - Optional limit and filter criteria.\n */\n async listAuditLog(options: ListAuditLogOptions = {}): Promise<AuditLogRecord[]> {\n const limit = options.limit ?? 100;\n const conditions: string[] = [];\n const params: Array<string | number> = [];\n\n if (options.userId !== undefined) {\n conditions.push('user_id = ?');\n params.push(options.userId);\n }\n\n if (options.entityType !== undefined) {\n conditions.push('entity_type = ?');\n params.push(options.entityType);\n }\n\n if (options.entityId !== undefined) {\n conditions.push('entity_id = ?');\n params.push(options.entityId);\n }\n\n const whereClause = conditions.length > 0 ? ` WHERE ${conditions.join(' AND ')}` : '';\n const rows = await this.queryRows<AuditLogSqlRow & RowDataPacket>(\n `${AUDIT_LOG_SELECT}${whereClause} ORDER BY created_at DESC LIMIT ?`,\n [...params, limit]\n );\n\n return rows.map(mapAuditLogSqlRow);\n }\n\n /**\n * Creates a new user account with the given role and access lists.\n *\n * @param input - User fields to persist.\n * @param actingUserId - User performing the create action.\n */\n async createUser(input: CreateUserInput, actingUserId: string): Promise<UserRecord> {\n const trimmedName = trimRequiredName(input.name, 'User name');\n assertUserNameNotReserved(trimmedName);\n const id = randomUUID();\n const now = new Date();\n const attributionUserId = trimmedName === SYSTEM_USER_NAME ? id : actingUserId;\n\n await this.executeStatement(\n `INSERT INTO users (\n id,\n name,\n role,\n collection_access,\n environment_access,\n snippet_access,\n llm_access,\n llm_models,\n llm_monthly_token_limit,\n created_at,\n updated_at,\n created_by_user_id,\n updated_by_user_id\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n [\n id,\n trimmedName,\n input.role,\n serializeAccessList(input.collectionAccess),\n serializeAccessList(input.environmentAccess),\n serializeAccessList(input.snippetAccess),\n input.llmAccess ? 1 : 0,\n serializeAccessList(input.llmModels ?? []),\n input.llmMonthlyTokenLimit ?? null,\n now,\n now,\n attributionUserId,\n attributionUserId\n ]\n );\n\n await this.recordAuditEntry(actingUserId, 'create', 'user', id);\n\n const created = await this.findUserById(id);\n if (!created) {\n throw new Error('User not found after insert');\n }\n\n return created;\n }\n\n /**\n * Finds a user by stable identifier.\n *\n * @param id - User identifier to look up.\n */\n async findUserById(id: string): Promise<UserRecord | null> {\n const rows = await this.queryRows<UserSqlRow & RowDataPacket>(\n `${USER_SELECT} WHERE id = ? LIMIT 1`,\n [id]\n );\n const row = rows[0];\n return row ? mapUserSqlRow(row) : null;\n }\n\n /**\n * Finds a user by unique display name.\n *\n * @param name - User name to look up.\n */\n async findUserByName(name: string): Promise<UserRecord | null> {\n const rows = await this.queryRows<UserSqlRow & RowDataPacket>(\n `${USER_SELECT} WHERE name = ? LIMIT 1`,\n [name]\n );\n const row = rows[0];\n return row ? mapUserSqlRow(row) : null;\n }\n\n /**\n * Lists all user accounts ordered by name.\n */\n async listUsers(): Promise<UserRecord[]> {\n const rows = await this.queryRows<UserSqlRow & RowDataPacket>(\n `${USER_SELECT} ORDER BY name ASC`\n );\n return rows.map(mapUserSqlRow);\n }\n\n /**\n * Updates an existing user account.\n *\n * @param id - User identifier to update.\n * @param input - Partial fields to apply.\n * @param actingUserId - User performing the update action.\n */\n async updateUser(id: string, input: UpdateUserInput, actingUserId: string): Promise<UserRecord> {\n const existing = await this.findUserById(id);\n if (!existing) {\n throw new Error('User not found');\n }\n\n const name =\n input.name !== undefined ? trimRequiredName(input.name, 'User name') : existing.name;\n\n if (name !== existing.name) {\n assertUserNameNotReserved(name);\n const duplicate = await this.findUserByName(name);\n assertUserNameAvailable(name, id, duplicate);\n }\n\n const role = input.role ?? existing.role;\n const collectionAccess = input.collectionAccess ?? existing.collectionAccess;\n const environmentAccess = input.environmentAccess ?? existing.environmentAccess;\n const snippetAccess = input.snippetAccess ?? existing.snippetAccess;\n const llmAccess = input.llmAccess ?? existing.llmAccess;\n const llmModels = input.llmModels ?? existing.llmModels;\n const llmMonthlyTokenLimit =\n input.llmMonthlyTokenLimit !== undefined\n ? input.llmMonthlyTokenLimit\n : existing.llmMonthlyTokenLimit;\n const updatedAt = new Date();\n\n const result = await this.executeStatement(\n `UPDATE users\n SET name = ?,\n role = ?,\n collection_access = ?,\n environment_access = ?,\n snippet_access = ?,\n llm_access = ?,\n llm_models = ?,\n llm_monthly_token_limit = ?,\n updated_at = ?,\n updated_by_user_id = ?\n WHERE id = ?`,\n [\n name,\n role,\n serializeAccessList(collectionAccess),\n serializeAccessList(environmentAccess),\n serializeAccessList(snippetAccess),\n llmAccess ? 1 : 0,\n serializeAccessList(llmModels),\n llmMonthlyTokenLimit,\n updatedAt,\n actingUserId,\n id\n ]\n );\n\n if ((result.affectedRows ?? 0) === 0) {\n throw new Error('User not found');\n }\n\n await this.recordAuditEntry(actingUserId, 'update', 'user', id);\n\n const updated = await this.findUserById(id);\n if (!updated) {\n throw new Error('User not found');\n }\n\n return updated;\n }\n\n /**\n * Deletes a user account and revokes all of their API tokens.\n *\n * @param id - User identifier to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteUser(id: string, actingUserId: string): Promise<void> {\n const connection = await this.requirePool().getConnection();\n try {\n await connection.beginTransaction();\n await connection.execute('DELETE FROM api_tokens WHERE user_id = ?', [id]);\n await connection.execute('DELETE FROM users WHERE id = ?', [id]);\n await connection.commit();\n } catch (err) {\n await connection.rollback();\n throw err;\n } finally {\n connection.release();\n }\n\n await this.recordAuditEntry(actingUserId, 'delete', 'user', id);\n }\n\n /**\n * Assigns legacy API tokens without an owner to the bootstrap user.\n */\n async migrateOrphanTokensToBootstrapUser(): Promise<void> {\n const rows = await this.queryRows<{ count: number } & RowDataPacket>(\n 'SELECT COUNT(*) AS count FROM api_tokens WHERE user_id IS NULL'\n );\n const orphanCount = rows[0]?.count ?? 0;\n if (orphanCount === 0) {\n return;\n }\n\n let bootstrapUser = await this.findUserByName(BOOTSTRAP_USER_NAME);\n if (!bootstrapUser) {\n const systemUserId = this.systemUserId;\n if (!systemUserId) {\n throw new Error('System user is not provisioned');\n }\n\n bootstrapUser = await this.createUser(\n {\n name: BOOTSTRAP_USER_NAME,\n role: 'user',\n collectionAccess: ['*'],\n environmentAccess: ['*'],\n snippetAccess: ['*']\n },\n systemUserId\n );\n }\n\n await this.executeStatement('UPDATE api_tokens SET user_id = ? WHERE user_id IS NULL', [\n bootstrapUser.id\n ]);\n }\n\n /**\n * Inserts a new API token record.\n *\n * @param record - Token metadata to persist.\n * @param actingUserId - User performing the create action.\n */\n async createApiToken(record: ApiTokenRecord, actingUserId: string): Promise<void> {\n await this.executeStatement(\n `INSERT INTO api_tokens (\n id,\n user_id,\n name,\n token_hash,\n token_prefix,\n created_at,\n last_used_at,\n revoked_at,\n created_by_user_id,\n updated_by_user_id\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n [\n record.id,\n record.userId,\n record.name,\n record.tokenHash,\n record.tokenPrefix,\n record.createdAt,\n record.lastUsedAt,\n record.revokedAt,\n actingUserId,\n actingUserId\n ]\n );\n\n await this.recordAuditEntry(actingUserId, 'create', 'api_token', record.id);\n }\n\n /**\n * Finds an active token by its stored hash.\n *\n * @param tokenHash - sha256 hex digest of the bearer token secret.\n */\n async findActiveApiTokenByHash(tokenHash: string): Promise<ApiTokenRecord | null> {\n const rows = await this.queryRows<ApiTokenSqlRow & RowDataPacket>(\n `${API_TOKEN_SELECT}\n WHERE token_hash = ?\n AND revoked_at IS NULL\n AND user_id IS NOT NULL\n LIMIT 1`,\n [tokenHash]\n );\n\n const row = rows[0];\n return row ? mapApiTokenSqlRow(row) : null;\n }\n\n /**\n * Lists all API tokens ordered by creation time descending.\n */\n async listApiTokens(): Promise<ApiTokenRecord[]> {\n const rows = await this.queryRows<ApiTokenSqlRow & RowDataPacket>(\n `${API_TOKEN_SELECT}\n WHERE user_id IS NOT NULL\n ORDER BY created_at DESC`\n );\n\n return rows.map(mapApiTokenSqlRow);\n }\n\n /**\n * Returns API tokens owned by a specific user ordered newest-first.\n *\n * @param userId - Owning user identifier.\n */\n async listApiTokensByUserId(userId: string): Promise<ApiTokenRecord[]> {\n const rows = await this.queryRows<ApiTokenSqlRow & RowDataPacket>(\n `${API_TOKEN_SELECT}\n WHERE user_id = ?\n ORDER BY created_at DESC`,\n [userId]\n );\n\n return rows.map(mapApiTokenSqlRow);\n }\n\n /**\n * Finds an API token record by stable identifier.\n *\n * @param id - Token identifier to look up.\n */\n async findApiTokenById(id: string): Promise<ApiTokenRecord | null> {\n const rows = await this.queryRows<ApiTokenSqlRow & RowDataPacket>(\n `${API_TOKEN_SELECT} WHERE id = ? LIMIT 1`,\n [id]\n );\n const row = rows[0];\n return row ? mapApiTokenSqlRow(row) : null;\n }\n\n /**\n * Permanently removes an API token record by id.\n *\n * @param id - Token identifier to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteApiToken(id: string, actingUserId: string): Promise<boolean> {\n const result = await this.executeStatement('DELETE FROM api_tokens WHERE id = ?', [id]);\n const deleted = (result.affectedRows ?? 0) > 0;\n if (deleted) {\n await this.recordAuditEntry(actingUserId, 'delete', 'api_token', id);\n }\n\n return deleted;\n }\n\n /**\n * Soft-revokes an active token by id.\n *\n * @param id - Token identifier to revoke.\n * @param actingUserId - User performing the revoke action.\n */\n async revokeApiToken(id: string, actingUserId: string): Promise<boolean> {\n const result = await this.executeStatement(\n `UPDATE api_tokens\n SET revoked_at = ?,\n updated_by_user_id = ?\n WHERE id = ?\n AND revoked_at IS NULL`,\n [new Date(), actingUserId, id]\n );\n\n const revoked = (result.affectedRows ?? 0) > 0;\n if (revoked) {\n await this.recordAuditEntry(actingUserId, 'update', 'api_token', id);\n }\n\n return revoked;\n }\n\n /**\n * Updates the last-used timestamp for a token.\n *\n * @param id - Token identifier that authenticated a request.\n * @param when - Timestamp of the authenticated request.\n */\n async touchApiTokenLastUsed(id: string, when: Date): Promise<void> {\n await this.executeStatement(`UPDATE api_tokens SET last_used_at = ? WHERE id = ?`, [when, id]);\n }\n\n /**\n * Lists all collections ordered by name.\n */\n async listCollections(): Promise<CollectionRecord[]> {\n const rows = await this.queryRows<CollectionSqlRow & RowDataPacket>(\n `${COLLECTION_SELECT} ORDER BY name ASC`\n );\n return rows.map(mapCollectionSqlRow);\n }\n\n /**\n * Creates a new collection with the given name.\n *\n * @param name - Display name for the collection.\n * @param actingUserId - User performing the create action.\n */\n async createCollection(name: string, actingUserId: string): Promise<CollectionRecord> {\n const trimmedName = trimRequiredName(name, 'Collection name');\n const id = randomUUID();\n const now = new Date();\n\n await this.executeStatement(\n `INSERT INTO collections (\n id,\n name,\n variables,\n headers,\n auth,\n pre_request_script,\n post_request_script,\n created_at,\n updated_at,\n created_by_user_id,\n updated_by_user_id\n ) VALUES (?, ?, '[]', '[]', ?, '', '', ?, ?, ?, ?)`,\n [id, trimmedName, MYSQL_DEFAULT_AUTH_JSON, now, now, actingUserId, actingUserId]\n );\n\n await this.recordAuditEntry(actingUserId, 'create', 'collection', id);\n\n const rows = await this.queryRows<CollectionSqlRow & RowDataPacket>(\n `${COLLECTION_SELECT} WHERE id = ?`,\n [id]\n );\n const row = rows[0];\n if (!row) {\n throw new Error('Collection not found after insert');\n }\n\n return mapCollectionSqlRow(row);\n }\n\n /**\n * Updates a collection's name, variables, headers, and scripts.\n *\n * @param actingUserId - User performing the update action.\n */\n async updateCollection(\n id: string,\n name: string,\n variables: Variable[],\n headers: KeyValue[],\n preRequestScript: string,\n postRequestScript: string,\n auth: AuthConfig,\n actingUserId: string\n ): Promise<CollectionRecord> {\n const trimmedName = trimRequiredName(name, 'Collection name');\n const updatedAt = new Date();\n const result = await this.executeStatement(\n `UPDATE collections\n SET name = ?,\n variables = ?,\n headers = ?,\n auth = ?,\n pre_request_script = ?,\n post_request_script = ?,\n updated_at = ?,\n updated_by_user_id = ?\n WHERE id = ?`,\n [\n trimmedName,\n JSON.stringify(variables),\n JSON.stringify(headers),\n JSON.stringify(auth),\n preRequestScript,\n postRequestScript,\n updatedAt,\n actingUserId,\n id\n ]\n );\n\n if ((result.affectedRows ?? 0) === 0) {\n throw new Error('Collection not found');\n }\n\n await this.recordAuditEntry(actingUserId, 'update', 'collection', id);\n\n const rows = await this.queryRows<CollectionSqlRow & RowDataPacket>(\n `${COLLECTION_SELECT} WHERE id = ?`,\n [id]\n );\n const row = rows[0];\n if (!row) {\n throw new Error('Collection not found');\n }\n\n return mapCollectionSqlRow(row);\n }\n\n /**\n * Deletes a collection and all of its requests and folders.\n *\n * @param id - Collection ID to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteCollection(id: string, actingUserId: string): Promise<void> {\n await this.recordAuditEntry(actingUserId, 'delete', 'collection', id);\n await this.executeStatement('DELETE FROM collections WHERE id = ?', [id]);\n }\n\n /**\n * Finds a collection by stable identifier.\n *\n * @param id - Collection ID to look up.\n */\n async findCollectionById(id: string): Promise<CollectionRecord | null> {\n const rows = await this.queryRows<CollectionSqlRow & RowDataPacket>(\n `${COLLECTION_SELECT} WHERE id = ?`,\n [id]\n );\n const row = rows[0];\n return row ? mapCollectionSqlRow(row) : null;\n }\n\n /**\n * Updates whether non-admin users may delete a collection.\n *\n * @param id - Collection ID to update.\n * @param deletionLocked - When true, user-role tokens cannot delete the collection.\n * @param actingUserId - Admin user performing the update.\n */\n async setCollectionDeletionLocked(\n id: string,\n deletionLocked: boolean,\n actingUserId: string\n ): Promise<CollectionRecord> {\n const updatedAt = new Date();\n const result = await this.executeStatement(\n `UPDATE collections\n SET deletion_locked = ?,\n updated_at = ?,\n updated_by_user_id = ?\n WHERE id = ?`,\n [deletionLocked ? 1 : 0, updatedAt, actingUserId, id]\n );\n\n if ((result.affectedRows ?? 0) === 0) {\n throw new Error('Collection not found');\n }\n\n await this.recordAuditEntry(actingUserId, 'update', 'collection', id);\n\n const rows = await this.queryRows<CollectionSqlRow & RowDataPacket>(\n `${COLLECTION_SELECT} WHERE id = ?`,\n [id]\n );\n const row = rows[0];\n if (!row) {\n throw new Error('Collection not found');\n }\n\n return mapCollectionSqlRow(row);\n }\n\n /**\n * Lists all environments ordered by name.\n */\n async listEnvironments(): Promise<EnvironmentRecord[]> {\n const rows = await this.queryRows<EnvironmentSqlRow & RowDataPacket>(\n `${ENVIRONMENT_SELECT} ORDER BY name ASC`\n );\n return rows.map(mapEnvironmentSqlRow);\n }\n\n /**\n * Creates a new environment with the given name.\n *\n * @param name - Display name for the environment.\n * @param actingUserId - User performing the create action.\n */\n async createEnvironment(name: string, actingUserId: string): Promise<EnvironmentRecord> {\n const trimmedName = trimRequiredName(name, 'Environment name');\n const id = randomUUID();\n const now = new Date();\n\n await this.executeStatement(\n `INSERT INTO environments (\n id,\n name,\n variables,\n created_at,\n updated_at,\n created_by_user_id,\n updated_by_user_id\n ) VALUES (?, ?, '[]', ?, ?, ?, ?)`,\n [id, trimmedName, now, now, actingUserId, actingUserId]\n );\n\n await this.recordAuditEntry(actingUserId, 'create', 'environment', id);\n\n const rows = await this.queryRows<EnvironmentSqlRow & RowDataPacket>(\n `${ENVIRONMENT_SELECT} WHERE id = ?`,\n [id]\n );\n const row = rows[0];\n if (!row) {\n throw new Error('Environment not found after insert');\n }\n\n return mapEnvironmentSqlRow(row);\n }\n\n /**\n * Updates an environment's name and variables.\n *\n * @param actingUserId - User performing the update action.\n */\n async updateEnvironment(\n id: string,\n name: string,\n variables: Variable[],\n actingUserId: string\n ): Promise<EnvironmentRecord> {\n const trimmedName = trimRequiredName(name, 'Environment name');\n const updatedAt = new Date();\n const result = await this.executeStatement(\n `UPDATE environments\n SET name = ?,\n variables = ?,\n updated_at = ?,\n updated_by_user_id = ?\n WHERE id = ?`,\n [trimmedName, JSON.stringify(variables), updatedAt, actingUserId, id]\n );\n\n if ((result.affectedRows ?? 0) === 0) {\n throw new Error('Environment not found');\n }\n\n await this.recordAuditEntry(actingUserId, 'update', 'environment', id);\n\n const rows = await this.queryRows<EnvironmentSqlRow & RowDataPacket>(\n `${ENVIRONMENT_SELECT} WHERE id = ?`,\n [id]\n );\n const row = rows[0];\n if (!row) {\n throw new Error('Environment not found');\n }\n\n return mapEnvironmentSqlRow(row);\n }\n\n /**\n * Deletes an environment.\n *\n * @param id - Environment ID to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteEnvironment(id: string, actingUserId: string): Promise<void> {\n await this.recordAuditEntry(actingUserId, 'delete', 'environment', id);\n await this.executeStatement('DELETE FROM environments WHERE id = ?', [id]);\n }\n\n /**\n * Finds an environment by stable identifier.\n *\n * @param id - Environment ID to look up.\n */\n async findEnvironmentById(id: string): Promise<EnvironmentRecord | null> {\n const rows = await this.queryRows<EnvironmentSqlRow & RowDataPacket>(\n `${ENVIRONMENT_SELECT} WHERE id = ?`,\n [id]\n );\n const row = rows[0];\n return row ? mapEnvironmentSqlRow(row) : null;\n }\n\n /**\n * Updates whether non-admin users may delete an environment.\n *\n * @param id - Environment ID to update.\n * @param deletionLocked - When true, user-role tokens cannot delete the environment.\n * @param actingUserId - Admin user performing the update.\n */\n async setEnvironmentDeletionLocked(\n id: string,\n deletionLocked: boolean,\n actingUserId: string\n ): Promise<EnvironmentRecord> {\n const updatedAt = new Date();\n const result = await this.executeStatement(\n `UPDATE environments\n SET deletion_locked = ?,\n updated_at = ?,\n updated_by_user_id = ?\n WHERE id = ?`,\n [deletionLocked ? 1 : 0, updatedAt, actingUserId, id]\n );\n\n if ((result.affectedRows ?? 0) === 0) {\n throw new Error('Environment not found');\n }\n\n await this.recordAuditEntry(actingUserId, 'update', 'environment', id);\n\n const rows = await this.queryRows<EnvironmentSqlRow & RowDataPacket>(\n `${ENVIRONMENT_SELECT} WHERE id = ?`,\n [id]\n );\n const row = rows[0];\n if (!row) {\n throw new Error('Environment not found');\n }\n\n return mapEnvironmentSqlRow(row);\n }\n\n /**\n * Lists all snippets ordered by sort order then name.\n */\n async listSnippets(): Promise<SnippetRecord[]> {\n const rows = await this.queryRows<SnippetSqlRow & RowDataPacket>(\n `${SNIPPET_SELECT} ORDER BY sort_order ASC, name ASC`\n );\n return rows.map(mapSnippetSqlRow);\n }\n\n /**\n * Creates a new snippet with the given fields.\n *\n * @param name - Display name for the snippet.\n * @param code - JavaScript source for the snippet.\n * @param scope - Execution scope for the snippet.\n * @param actingUserId - User performing the create action.\n */\n async createSnippet(\n name: string,\n code: string,\n scope: SnippetScope,\n actingUserId: string\n ): Promise<SnippetRecord> {\n const trimmedName = trimRequiredName(name, 'Snippet name');\n const id = randomUUID();\n const now = new Date();\n const maxRows = await this.queryRows<{ max_order: number | null } & RowDataPacket>(\n 'SELECT COALESCE(MAX(sort_order), -1) AS max_order FROM snippets'\n );\n const maxOrder = maxRows[0]?.max_order ?? -1;\n\n await this.executeStatement(\n `INSERT INTO snippets (\n id,\n name,\n code,\n scope,\n sort_order,\n created_at,\n updated_at,\n created_by_user_id,\n updated_by_user_id,\n deletion_locked\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n [id, trimmedName, code, scope, maxOrder + 1, now, now, actingUserId, actingUserId, 0]\n );\n\n await this.recordAuditEntry(actingUserId, 'create', 'snippet', id);\n\n const rows = await this.queryRows<SnippetSqlRow & RowDataPacket>(\n `${SNIPPET_SELECT} WHERE id = ?`,\n [id]\n );\n const row = rows[0];\n if (!row) {\n throw new Error('Snippet not found after insert');\n }\n\n return mapSnippetSqlRow(row);\n }\n\n /**\n * Updates a snippet's name, code, and scope. Sort order is left unchanged.\n *\n * @param actingUserId - User performing the update action.\n */\n async updateSnippet(\n id: string,\n name: string,\n code: string,\n scope: SnippetScope,\n actingUserId: string\n ): Promise<SnippetRecord> {\n const trimmedName = trimRequiredName(name, 'Snippet name');\n const updatedAt = new Date();\n const result = await this.executeStatement(\n `UPDATE snippets\n SET name = ?,\n code = ?,\n scope = ?,\n updated_at = ?,\n updated_by_user_id = ?\n WHERE id = ?`,\n [trimmedName, code, scope, updatedAt, actingUserId, id]\n );\n\n if ((result.affectedRows ?? 0) === 0) {\n throw new Error('Snippet not found');\n }\n\n await this.recordAuditEntry(actingUserId, 'update', 'snippet', id);\n\n const rows = await this.queryRows<SnippetSqlRow & RowDataPacket>(\n `${SNIPPET_SELECT} WHERE id = ?`,\n [id]\n );\n const row = rows[0];\n if (!row) {\n throw new Error('Snippet not found');\n }\n\n return mapSnippetSqlRow(row);\n }\n\n /**\n * Deletes a snippet.\n *\n * @param id - Snippet ID to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteSnippet(id: string, actingUserId: string): Promise<void> {\n await this.recordAuditEntry(actingUserId, 'delete', 'snippet', id);\n await this.executeStatement('DELETE FROM snippets WHERE id = ?', [id]);\n }\n\n /**\n * Finds a snippet by stable identifier.\n *\n * @param id - Snippet ID to look up.\n */\n async findSnippetById(id: string): Promise<SnippetRecord | null> {\n const rows = await this.queryRows<SnippetSqlRow & RowDataPacket>(\n `${SNIPPET_SELECT} WHERE id = ?`,\n [id]\n );\n const row = rows[0];\n return row ? mapSnippetSqlRow(row) : null;\n }\n\n /**\n * Updates whether non-admin users may delete a snippet.\n *\n * @param id - Snippet ID to update.\n * @param deletionLocked - When true, user-role tokens cannot delete the snippet.\n * @param actingUserId - Admin user performing the update.\n */\n async setSnippetDeletionLocked(\n id: string,\n deletionLocked: boolean,\n actingUserId: string\n ): Promise<SnippetRecord> {\n const updatedAt = new Date();\n const result = await this.executeStatement(\n `UPDATE snippets\n SET deletion_locked = ?,\n updated_at = ?,\n updated_by_user_id = ?\n WHERE id = ?`,\n [deletionLocked ? 1 : 0, updatedAt, actingUserId, id]\n );\n\n if ((result.affectedRows ?? 0) === 0) {\n throw new Error('Snippet not found');\n }\n\n await this.recordAuditEntry(actingUserId, 'update', 'snippet', id);\n\n const rows = await this.queryRows<SnippetSqlRow & RowDataPacket>(\n `${SNIPPET_SELECT} WHERE id = ?`,\n [id]\n );\n const row = rows[0];\n if (!row) {\n throw new Error('Snippet not found');\n }\n\n return mapSnippetSqlRow(row);\n }\n\n /**\n * Lists all saved requests in a collection.\n *\n * @param collectionId - Collection to query.\n */\n async listRequests(collectionId: string): Promise<SavedRequestRecord[]> {\n const rows = await this.queryRows<RequestSqlRow & RowDataPacket>(\n `${REQUEST_SELECT} WHERE collection_id = ? ORDER BY sort_order ASC, name ASC`,\n [collectionId]\n );\n return rows.map(mapRequestSqlRow);\n }\n\n /**\n * Finds a saved request by id.\n *\n * @param id - Request identifier to look up.\n */\n async findRequestById(id: string): Promise<SavedRequestRecord | null> {\n const rows = await this.queryRows<RequestSqlRow & RowDataPacket>(\n `${REQUEST_SELECT} WHERE id = ? LIMIT 1`,\n [id]\n );\n const row = rows[0];\n return row ? mapRequestSqlRow(row) : null;\n }\n\n /**\n * Inserts a new request or updates an existing one.\n *\n * @param input - Request fields to persist.\n * @param actingUserId - User performing the save action.\n */\n async saveRequest(input: SaveRequestInput, actingUserId: string): Promise<SavedRequestRecord> {\n const trimmedName = trimRequiredName(input.name, 'Request name');\n const headers = JSON.stringify(input.headers);\n const params = JSON.stringify(input.params);\n const auth = JSON.stringify(input.auth);\n const folderId = input.folderId ?? null;\n const now = new Date();\n\n if (folderId != null) {\n const folderRows = await this.queryRows<{ collection_id: string } & RowDataPacket>(\n 'SELECT collection_id FROM folders WHERE id = ?',\n [folderId]\n );\n const folderRow = folderRows[0];\n if (!folderRow || folderRow.collection_id !== input.collectionId) {\n throw new Error('Folder not found');\n }\n }\n\n if (input.id) {\n const result = await this.executeStatement(\n `UPDATE requests SET\n collection_id = ?,\n folder_id = ?,\n name = ?,\n method = ?,\n url = ?,\n headers = ?,\n params = ?,\n auth = ?,\n body = ?,\n body_type = ?,\n pre_request_script = ?,\n post_request_script = ?,\n comment = ?,\n updated_at = ?,\n updated_by_user_id = ?\n WHERE id = ?`,\n [\n input.collectionId,\n folderId,\n trimmedName,\n input.method,\n input.url,\n headers,\n params,\n auth,\n input.body,\n input.bodyType,\n input.preRequestScript,\n input.postRequestScript,\n input.comment,\n now,\n actingUserId,\n input.id\n ]\n );\n\n if ((result.affectedRows ?? 0) > 0) {\n await this.recordAuditEntry(actingUserId, 'update', 'request', input.id);\n\n const rows = await this.queryRows<RequestSqlRow & RowDataPacket>(\n `${REQUEST_SELECT} WHERE id = ?`,\n [input.id]\n );\n const row = rows[0];\n if (row) {\n return mapRequestSqlRow(row);\n }\n }\n }\n\n const maxRows = await this.queryRows<{ max_order: number | null } & RowDataPacket>(\n `SELECT COALESCE(MAX(sort_order), -1) AS max_order FROM requests\n WHERE collection_id = ?\n AND ((? IS NULL AND folder_id IS NULL) OR folder_id = ?)`,\n [input.collectionId, folderId, folderId]\n );\n const maxOrder = maxRows[0]?.max_order ?? -1;\n const id = randomUUID();\n\n await this.executeStatement(\n `INSERT INTO requests (\n id,\n collection_id,\n folder_id,\n name,\n method,\n url,\n headers,\n params,\n auth,\n body,\n body_type,\n pre_request_script,\n post_request_script,\n comment,\n sort_order,\n created_at,\n updated_at,\n created_by_user_id,\n updated_by_user_id\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n [\n id,\n input.collectionId,\n folderId,\n trimmedName,\n input.method,\n input.url,\n headers,\n params,\n auth,\n input.body,\n input.bodyType,\n input.preRequestScript,\n input.postRequestScript,\n input.comment,\n maxOrder + 1,\n now,\n now,\n actingUserId,\n actingUserId\n ]\n );\n\n await this.recordAuditEntry(actingUserId, 'create', 'request', id);\n\n const rows = await this.queryRows<RequestSqlRow & RowDataPacket>(\n `${REQUEST_SELECT} WHERE id = ?`,\n [id]\n );\n const row = rows[0];\n if (!row) {\n throw new Error('Request not found after insert');\n }\n\n return mapRequestSqlRow(row);\n }\n\n /**\n * Deletes a saved request by ID.\n *\n * @param id - Request ID to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteRequest(id: string, actingUserId: string): Promise<void> {\n await this.recordAuditEntry(actingUserId, 'delete', 'request', id);\n await this.executeStatement('DELETE FROM requests WHERE id = ?', [id]);\n }\n\n /**\n * Lists all folders in a collection.\n *\n * @param collectionId - Collection to query.\n */\n async listFolders(collectionId: string): Promise<FolderRecord[]> {\n const rows = await this.queryRows<FolderSqlRow & RowDataPacket>(\n `${FOLDER_SELECT} WHERE collection_id = ? ORDER BY sort_order ASC, name ASC`,\n [collectionId]\n );\n return rows.map(mapFolderSqlRow);\n }\n\n /**\n * Finds a folder by id.\n *\n * @param id - Folder identifier to look up.\n */\n async findFolderById(id: string): Promise<FolderRecord | null> {\n const rows = await this.queryRows<FolderSqlRow & RowDataPacket>(\n `${FOLDER_SELECT} WHERE id = ? LIMIT 1`,\n [id]\n );\n const row = rows[0];\n return row ? mapFolderSqlRow(row) : null;\n }\n\n /**\n * Creates a new folder in a collection.\n *\n * @param collectionId - Collection to add the folder to.\n * @param name - Display name for the folder.\n * @param actingUserId - User performing the create action.\n */\n async createFolder(\n collectionId: string,\n name: string,\n actingUserId: string\n ): Promise<FolderRecord> {\n const trimmedName = trimRequiredName(name, 'Folder name');\n const id = randomUUID();\n const now = new Date();\n const maxRows = await this.queryRows<{ max_order: number | null } & RowDataPacket>(\n 'SELECT COALESCE(MAX(sort_order), -1) AS max_order FROM folders WHERE collection_id = ?',\n [collectionId]\n );\n const maxOrder = maxRows[0]?.max_order ?? -1;\n\n await this.executeStatement(\n `INSERT INTO folders (\n id,\n collection_id,\n name,\n sort_order,\n created_at,\n updated_at,\n created_by_user_id,\n updated_by_user_id\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,\n [id, collectionId, trimmedName, maxOrder + 1, now, now, actingUserId, actingUserId]\n );\n\n await this.recordAuditEntry(actingUserId, 'create', 'folder', id);\n\n const rows = await this.queryRows<FolderSqlRow & RowDataPacket>(\n `${FOLDER_SELECT} WHERE id = ?`,\n [id]\n );\n const row = rows[0];\n if (!row) {\n throw new Error('Folder not found after insert');\n }\n\n return mapFolderSqlRow(row);\n }\n\n /**\n * Renames a folder.\n *\n * @param id - Folder ID to rename.\n * @param name - New display name.\n * @param actingUserId - User performing the rename action.\n */\n async renameFolder(id: string, name: string, actingUserId: string): Promise<FolderRecord> {\n const trimmedName = trimRequiredName(name, 'Folder name');\n const updatedAt = new Date();\n const result = await this.executeStatement(\n `UPDATE folders\n SET name = ?,\n updated_at = ?,\n updated_by_user_id = ?\n WHERE id = ?`,\n [trimmedName, updatedAt, actingUserId, id]\n );\n\n if ((result.affectedRows ?? 0) === 0) {\n throw new Error('Folder not found');\n }\n\n await this.recordAuditEntry(actingUserId, 'update', 'folder', id);\n\n const rows = await this.queryRows<FolderSqlRow & RowDataPacket>(\n `${FOLDER_SELECT} WHERE id = ?`,\n [id]\n );\n const row = rows[0];\n if (!row) {\n throw new Error('Folder not found');\n }\n\n return mapFolderSqlRow(row);\n }\n\n /**\n * Deletes a folder and all requests inside it.\n *\n * @param id - Folder ID to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteFolder(id: string, actingUserId: string): Promise<void> {\n await this.recordAuditEntry(actingUserId, 'delete', 'folder', id);\n\n const connection = await this.requirePool().getConnection();\n try {\n await connection.beginTransaction();\n await connection.execute('DELETE FROM requests WHERE folder_id = ?', [id]);\n await connection.execute('DELETE FROM folders WHERE id = ?', [id]);\n await connection.commit();\n } catch (err) {\n await connection.rollback();\n throw err;\n } finally {\n connection.release();\n }\n }\n\n /**\n * Reorders folders within a collection.\n *\n * @param collectionId - Collection containing the folders.\n * @param orderedFolderIds - Folder IDs in desired order.\n * @param actingUserId - User performing the reorder action.\n */\n async reorderFolders(\n collectionId: string,\n orderedFolderIds: string[],\n actingUserId: string\n ): Promise<void> {\n const connection = await this.requirePool().getConnection();\n const updatedAt = new Date();\n try {\n await connection.beginTransaction();\n for (let index = 0; index < orderedFolderIds.length; index++) {\n await connection.execute(\n `UPDATE folders\n SET sort_order = ?,\n updated_at = ?,\n updated_by_user_id = ?\n WHERE id = ? AND collection_id = ?`,\n [index, updatedAt, actingUserId, orderedFolderIds[index], collectionId]\n );\n }\n await connection.commit();\n } catch (err) {\n await connection.rollback();\n throw err;\n } finally {\n connection.release();\n }\n\n await this.recordAuditEntry(actingUserId, 'reorder', 'collection', collectionId, {\n orderedFolderIds\n });\n }\n\n /**\n * Reorders requests within a folder or at collection root.\n *\n * @param actingUserId - User performing the reorder action.\n */\n async reorderRequests(\n collectionId: string,\n folderId: string | null,\n orderedRequestIds: string[],\n actingUserId: string\n ): Promise<void> {\n const connection = await this.requirePool().getConnection();\n const updatedAt = new Date();\n try {\n await connection.beginTransaction();\n for (let index = 0; index < orderedRequestIds.length; index++) {\n await connection.execute(\n `UPDATE requests\n SET sort_order = ?,\n folder_id = ?,\n updated_at = ?,\n updated_by_user_id = ?\n WHERE id = ? AND collection_id = ?`,\n [index, folderId, updatedAt, actingUserId, orderedRequestIds[index], collectionId]\n );\n }\n await connection.commit();\n } catch (err) {\n await connection.rollback();\n throw err;\n } finally {\n connection.release();\n }\n\n await this.recordAuditEntry(actingUserId, 'reorder', 'collection', collectionId, {\n folderId,\n orderedRequestIds\n });\n }\n\n /**\n * Moves a request to another folder or collection root at a given index.\n *\n * @param actingUserId - User performing the move action.\n */\n async moveRequest(\n requestId: string,\n folderId: string | null,\n index: number,\n actingUserId: string\n ): Promise<void> {\n const connection = await this.requirePool().getConnection();\n const updatedAt = new Date();\n\n /**\n * Lists request ids in a container ordered for reindexing.\n *\n * @param collectionId - Collection to query.\n * @param targetFolderId - Folder id or null for collection root.\n */\n const listInContainer = async (\n collectionId: string,\n targetFolderId: string | null\n ): Promise<string[]> => {\n const [rows] = await connection.execute<(RowDataPacket & { id: string })[]>(\n `SELECT id FROM requests WHERE collection_id = ?\n AND ((? IS NULL AND folder_id IS NULL) OR folder_id = ?)\n ORDER BY sort_order ASC, name ASC`,\n [collectionId, targetFolderId, targetFolderId]\n );\n return rows.map((row) => row.id);\n };\n\n /**\n * Rewrites sort_order and folder_id for a container's request list.\n *\n * @param targetFolderId - Folder id or null for collection root.\n * @param orderedIds - Request ids in desired order.\n */\n const reindexContainer = async (\n targetFolderId: string | null,\n orderedIds: string[]\n ): Promise<void> => {\n for (let sortIndex = 0; sortIndex < orderedIds.length; sortIndex++) {\n await connection.execute(\n `UPDATE requests\n SET sort_order = ?,\n folder_id = ?,\n updated_at = ?,\n updated_by_user_id = ?\n WHERE id = ?`,\n [sortIndex, targetFolderId, updatedAt, actingUserId, orderedIds[sortIndex]]\n );\n }\n };\n\n try {\n await connection.beginTransaction();\n\n const [requestRows] = await connection.execute<(RequestSqlRow & RowDataPacket)[]>(\n `${REQUEST_SELECT} WHERE id = ?`,\n [requestId]\n );\n const requestRow = requestRows[0];\n if (!requestRow) {\n throw new Error('Request not found');\n }\n\n const request = mapRequestSqlRow(requestRow);\n const collectionId = request.collectionId;\n const oldFolderId = request.folderId;\n\n if (folderId != null) {\n const [folderRows] = await connection.execute<\n (RowDataPacket & { collection_id: string })[]\n >('SELECT collection_id FROM folders WHERE id = ?', [folderId]);\n const folderRow = folderRows[0];\n if (!folderRow || folderRow.collection_id !== collectionId) {\n throw new Error('Folder not found');\n }\n }\n\n if (oldFolderId === folderId) {\n const siblings = (await listInContainer(collectionId, folderId)).filter(\n (id) => id !== requestId\n );\n siblings.splice(index, 0, requestId);\n await reindexContainer(folderId, siblings);\n } else {\n const oldIds = (await listInContainer(collectionId, oldFolderId)).filter(\n (id) => id !== requestId\n );\n await reindexContainer(oldFolderId, oldIds);\n\n const newIds = (await listInContainer(collectionId, folderId)).filter(\n (id) => id !== requestId\n );\n newIds.splice(index, 0, requestId);\n await reindexContainer(folderId, newIds);\n }\n\n await connection.commit();\n } catch (err) {\n await connection.rollback();\n throw err;\n } finally {\n connection.release();\n }\n\n await this.recordAuditEntry(actingUserId, 'move', 'request', requestId, {\n folderId,\n index\n });\n }\n\n /**\n * Returns monthly LLM usage for a user, or null when no usage has been recorded.\n *\n * @param userId - Owning user identifier.\n * @param period - UTC calendar month key (`YYYY-MM`).\n */\n async getLlmUsage(userId: string, period: string): Promise<LlmUsageRecord | null> {\n const [rows] = await this.requirePool().execute<(LlmUsageSqlRow & RowDataPacket)[]>(\n `${LLM_USAGE_SELECT} WHERE user_id = ? AND period = ? LIMIT 1`,\n [userId, period]\n );\n const row = rows[0];\n return row ? mapLlmUsageSqlRow(row) : null;\n }\n\n /**\n * Atomically increments monthly LLM token usage for a user.\n *\n * @param userId - Owning user identifier.\n * @param period - UTC calendar month key (`YYYY-MM`).\n * @param promptTokens - Prompt tokens to add.\n * @param completionTokens - Completion tokens to add.\n */\n async addLlmUsage(\n userId: string,\n period: string,\n promptTokens: number,\n completionTokens: number\n ): Promise<LlmUsageRecord> {\n const totalDelta = promptTokens + completionTokens;\n const now = new Date();\n const id = randomUUID();\n\n await this.executeStatement(\n `INSERT INTO llm_usage (\n id,\n user_id,\n period,\n prompt_tokens,\n completion_tokens,\n total_tokens,\n updated_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?)\n ON DUPLICATE KEY UPDATE\n prompt_tokens = prompt_tokens + VALUES(prompt_tokens),\n completion_tokens = completion_tokens + VALUES(completion_tokens),\n total_tokens = total_tokens + VALUES(total_tokens),\n updated_at = VALUES(updated_at)`,\n [id, userId, period, promptTokens, completionTokens, totalDelta, now]\n );\n\n const usage = await this.getLlmUsage(userId, period);\n if (!usage) {\n throw new Error('LLM usage not found after upsert');\n }\n\n return usage;\n }\n\n /**\n * Inserts a per-request LLM usage log entry.\n *\n * @param input - Usage details for one successful completion step.\n */\n async createLlmUsageLog(input: CreateLlmUsageLogInput): Promise<LlmUsageLogRecord> {\n const id = randomUUID();\n const now = new Date();\n\n await this.executeStatement(\n `INSERT INTO llm_usage_log (\n id,\n user_id,\n api_token_id,\n period,\n model,\n provider,\n prompt_tokens,\n completion_tokens,\n total_tokens,\n is_new_turn,\n had_tool_calls,\n message_count,\n created_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n [\n id,\n input.userId,\n input.apiTokenId,\n input.period,\n input.model,\n input.provider,\n input.promptTokens,\n input.completionTokens,\n input.totalTokens,\n input.isNewTurn ? 1 : 0,\n input.hadToolCalls ? 1 : 0,\n input.messageCount,\n now\n ]\n );\n\n const rows = await this.queryRows<LlmUsageLogSqlRow & RowDataPacket>(\n `${LLM_USAGE_LOG_SELECT} WHERE id = ?`,\n [id]\n );\n const row = rows[0];\n if (!row) {\n throw new Error('LLM usage log not found after insert');\n }\n\n return mapLlmUsageLogSqlRow(row);\n }\n\n /**\n * Lists all per-request LLM usage log entries, newest first.\n */\n async listLlmUsageLogs(): Promise<LlmUsageLogRecord[]> {\n const rows = await this.queryRows<LlmUsageLogSqlRow & RowDataPacket>(\n `${LLM_USAGE_LOG_SELECT} ORDER BY created_at DESC`\n );\n\n return rows.map(mapLlmUsageLogSqlRow);\n }\n\n /**\n * Ensures the internal system user exists and caches its identifier.\n */\n private async ensureSystemUser(): Promise<void> {\n const existing = await this.findUserByName(SYSTEM_USER_NAME);\n if (existing) {\n this.systemUserId = existing.id;\n return;\n }\n\n const input = createSystemUserInput();\n const id = randomUUID();\n const now = new Date();\n const trimmedName = trimRequiredName(input.name, 'User name');\n\n await this.executeStatement(\n `INSERT INTO users (\n id,\n name,\n role,\n collection_access,\n environment_access,\n snippet_access,\n llm_access,\n llm_models,\n llm_monthly_token_limit,\n created_at,\n updated_at,\n created_by_user_id,\n updated_by_user_id\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n [\n id,\n trimmedName,\n input.role,\n serializeAccessList(input.collectionAccess),\n serializeAccessList(input.environmentAccess),\n serializeAccessList(input.snippetAccess),\n 0,\n serializeAccessList([]),\n null,\n now,\n now,\n id,\n id\n ]\n );\n\n this.systemUserId = id;\n }\n\n /**\n * Persists a single audit log entry with a snapshot of the acting user's name.\n *\n * @param actingUserId - User performing the action.\n * @param action - CRUD or structural action performed.\n * @param entityType - Kind of entity affected.\n * @param entityId - Identifier of the affected entity.\n * @param metadata - Optional structured context for the action.\n */\n private async recordAuditEntry(\n actingUserId: string,\n action: AuditAction,\n entityType: AuditEntityType,\n entityId: string,\n metadata?: Record<string, unknown> | null\n ): Promise<void> {\n const userName = await resolveActingUserName(this.findUserById.bind(this), actingUserId);\n const id = randomUUID();\n const now = new Date();\n\n await this.executeStatement(\n `INSERT INTO audit_log (\n id,\n user_id,\n user_name,\n action,\n entity_type,\n entity_id,\n created_at,\n metadata\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,\n [\n id,\n actingUserId,\n userName,\n action,\n entityType,\n entityId,\n now,\n serializeAuditMetadata(metadata ?? null)\n ]\n );\n }\n\n /**\n * Returns the active pool or throws when connect has not been called.\n *\n * @returns Connected MySQL pool.\n * @throws {Error} When the database is not connected.\n */\n private requirePool(): Pool {\n if (!this.pool) {\n throw new Error('MySQL database is not connected.');\n }\n\n return this.pool;\n }\n\n /**\n * Executes a parameterized SELECT and returns matching rows.\n *\n * @param sql - SQL statement with ? placeholders.\n * @param params - Bound parameter values.\n * @returns Query rows from mysql2.\n */\n private async queryRows<T extends RowDataPacket>(\n sql: string,\n params: Array<string | number | Date | null> = []\n ): Promise<T[]> {\n const [rows] = await this.requirePool().execute<T[]>(sql, params);\n return rows;\n }\n\n /**\n * Executes a parameterized statement and returns result metadata.\n *\n * @param sql - SQL statement with ? placeholders.\n * @param params - Bound parameter values.\n * @returns Result metadata such as affected row counts.\n */\n private async executeStatement(\n sql: string,\n params: Array<string | number | Date | null> = []\n ): Promise<ResultSetHeader> {\n const [result] = await this.requirePool().execute(sql, params);\n return result as ResultSetHeader;\n }\n}\n","import type { ApiTokenRecord } from '#/db/types.js';\n\n/**\n * SQL row shape returned by relational backends for the api_tokens table.\n */\nexport interface ApiTokenSqlRow {\n /**\n * Primary key identifier.\n */\n id: string;\n\n /**\n * Owning user identifier column.\n */\n user_id: string | null;\n\n /**\n * Human-readable token label.\n */\n name: string;\n\n /**\n * sha256 hex digest column.\n */\n token_hash: string;\n\n /**\n * Display prefix column.\n */\n token_prefix: string;\n\n /**\n * Creation timestamp column.\n */\n created_at: Date;\n\n /**\n * Last-used timestamp column, if any.\n */\n last_used_at: Date | null;\n\n /**\n * Revocation timestamp column, if any.\n */\n revoked_at: Date | null;\n\n /**\n * Creating user identifier column.\n */\n created_by_user_id: string | null;\n\n /**\n * Last updating user identifier column.\n */\n updated_by_user_id: string | null;\n}\n\n/**\n * Maps a snake_case SQL row to the shared {@link ApiTokenRecord} shape.\n *\n * @param row - Database row from api_tokens.\n * @returns Normalized token record for application code.\n */\nexport function mapApiTokenSqlRow(row: ApiTokenSqlRow): ApiTokenRecord {\n if (!row.user_id) {\n throw new Error(`API token ${row.id} is missing a user_id`);\n }\n\n return {\n id: row.id,\n userId: row.user_id,\n name: row.name,\n tokenHash: row.token_hash,\n tokenPrefix: row.token_prefix,\n createdAt: row.created_at,\n lastUsedAt: row.last_used_at,\n revokedAt: row.revoked_at,\n createdByUserId: row.created_by_user_id ?? null,\n updatedByUserId: row.updated_by_user_id ?? null\n };\n}\n","import type { AuditAction, AuditEntityType, AuditLogRecord } from '#/db/types.js';\n\n/**\n * SQL row shape returned by relational backends for the audit_log table.\n */\nexport interface AuditLogSqlRow {\n /**\n * Primary key identifier.\n */\n id: string;\n\n /**\n * Acting user identifier column, when known.\n */\n user_id: string | null;\n\n /**\n * Snapshot of the acting user's display name at write time.\n */\n user_name: string | null;\n\n /**\n * CRUD or structural action performed.\n */\n action: string;\n\n /**\n * Entity kind affected by the action.\n */\n entity_type: string;\n\n /**\n * Identifier of the affected entity.\n */\n entity_id: string;\n\n /**\n * When the action was recorded.\n */\n created_at: Date;\n\n /**\n * JSON-encoded optional context for the action.\n */\n metadata: string;\n}\n\n/**\n * Parses a stored audit action string into a typed {@link AuditAction}.\n *\n * @param value - Action column from storage.\n * @returns Validated audit action.\n * @throws {Error} When the stored action is not recognized.\n */\nfunction parseAuditAction(value: string): AuditAction {\n if (\n value === 'create' ||\n value === 'update' ||\n value === 'delete' ||\n value === 'reorder' ||\n value === 'move'\n ) {\n return value;\n }\n\n throw new Error(`Invalid audit action: ${value}`);\n}\n\n/**\n * Parses a stored entity type string into a typed {@link AuditEntityType}.\n *\n * @param value - Entity type column from storage.\n * @returns Validated entity type.\n * @throws {Error} When the stored entity type is not recognized.\n */\nfunction parseAuditEntityType(value: string): AuditEntityType {\n if (\n value === 'user' ||\n value === 'api_token' ||\n value === 'collection' ||\n value === 'environment' ||\n value === 'snippet' ||\n value === 'folder' ||\n value === 'request'\n ) {\n return value;\n }\n\n throw new Error(`Invalid audit entity type: ${value}`);\n}\n\n/**\n * Parses optional JSON metadata from an audit log row.\n *\n * @param value - Raw metadata column text.\n * @returns Parsed metadata object, or null when empty or invalid.\n */\nfunction parseAuditMetadata(value: string): Record<string, unknown> | null {\n if (!value || value === '{}') {\n return null;\n }\n\n try {\n const parsed: unknown = JSON.parse(value);\n if (parsed != null && typeof parsed === 'object' && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n } catch {\n return null;\n }\n\n return null;\n}\n\n/**\n * Maps a snake_case SQL row to the shared {@link AuditLogRecord} shape.\n *\n * @param row - Database row from audit_log.\n * @returns Normalized audit log record for application code.\n */\nexport function mapAuditLogSqlRow(row: AuditLogSqlRow): AuditLogRecord {\n return {\n id: row.id,\n userId: row.user_id,\n userName: row.user_name,\n action: parseAuditAction(row.action),\n entityType: parseAuditEntityType(row.entity_type),\n entityId: row.entity_id,\n createdAt: row.created_at,\n metadata: parseAuditMetadata(row.metadata)\n };\n}\n\n/**\n * Serializes optional audit metadata for SQL storage.\n *\n * @param metadata - Context object to persist, or null when none.\n * @returns JSON string suitable for a TEXT column.\n */\nexport function serializeAuditMetadata(metadata: Record<string, unknown> | null): string {\n return JSON.stringify(metadata ?? {});\n}\n\n/**\n * Input describing a single audit log entry to persist.\n */\nexport interface RecordAuditInput {\n /**\n * Acting user identifier.\n */\n userId: string;\n\n /**\n * Snapshot of the acting user's display name.\n */\n userName: string | null;\n\n /**\n * Action performed on the entity.\n */\n action: AuditAction;\n\n /**\n * Kind of entity affected.\n */\n entityType: AuditEntityType;\n\n /**\n * Identifier of the affected entity.\n */\n entityId: string;\n\n /**\n * Optional structured context for the action.\n */\n metadata?: Record<string, unknown> | null;\n}\n","import type {\n AuthConfig,\n BodyType,\n CollectionRecord,\n EnvironmentRecord,\n FolderRecord,\n SnippetRecord,\n SnippetScope,\n HttpMethod,\n KeyValue,\n SavedRequestRecord,\n Variable\n} from '#/db/types.js';\nimport { defaultAuth, normalizeAuth, normalizeVariable } from '#/db/types.js';\n\n/**\n * Parses a JSON string, returning a fallback value on failure.\n *\n * @param value - Raw JSON text.\n * @param fallback - Value returned when parsing fails.\n * @returns Parsed value or fallback.\n */\nfunction parseJson<T>(value: string, fallback: T): T {\n try {\n return JSON.parse(value) as T;\n } catch {\n return fallback;\n }\n}\n\n/**\n * Parses auth JSON from a database row, falling back to defaultAuth when absent or invalid.\n *\n * @param value - Raw auth column from storage.\n * @returns Normalized AuthConfig.\n */\nfunction readAuth(value: string): AuthConfig {\n return normalizeAuth(parseJson(value, defaultAuth()));\n}\n\n/**\n * Parses and normalizes variable rows from storage.\n *\n * @param value - Raw variables JSON text.\n * @returns Normalized Variable array.\n */\nfunction readVariables(value: string): Variable[] {\n return parseJson<Partial<Variable>[]>(value, []).map(normalizeVariable);\n}\n\n/**\n * SQL row shape returned by relational backends for the collections table.\n */\nexport interface CollectionSqlRow {\n /**\n * Primary key identifier.\n */\n id: string;\n\n /**\n * Display name column.\n */\n name: string;\n\n /**\n * JSON-encoded variables column.\n */\n variables: string;\n\n /**\n * JSON-encoded headers column.\n */\n headers: string;\n\n /**\n * JSON-encoded auth column.\n */\n auth: string;\n\n /**\n * Pre-request script column.\n */\n pre_request_script: string;\n\n /**\n * Post-request script column.\n */\n post_request_script: string;\n\n /**\n * Creation timestamp column.\n */\n created_at: Date;\n\n /**\n * Last update timestamp column.\n */\n updated_at: Date;\n\n /**\n * Creating user identifier column.\n */\n created_by_user_id: string | null;\n\n /**\n * Last updating user identifier column.\n */\n updated_by_user_id: string | null;\n\n /**\n * Deletion lock column.\n */\n deletion_locked: boolean;\n}\n\n/**\n * SQL row shape returned by relational backends for the environments table.\n */\nexport interface EnvironmentSqlRow {\n /**\n * Primary key identifier.\n */\n id: string;\n\n /**\n * Display name column.\n */\n name: string;\n\n /**\n * JSON-encoded variables column.\n */\n variables: string;\n\n /**\n * Creation timestamp column.\n */\n created_at: Date;\n\n /**\n * Last update timestamp column.\n */\n updated_at: Date;\n\n /**\n * Creating user identifier column.\n */\n created_by_user_id: string | null;\n\n /**\n * Last updating user identifier column.\n */\n updated_by_user_id: string | null;\n\n /**\n * Deletion lock column.\n */\n deletion_locked: boolean;\n}\n\n/**\n * SQL row shape returned by relational backends for the snippets table.\n */\nexport interface SnippetSqlRow {\n /**\n * Primary key identifier.\n */\n id: string;\n\n /**\n * Display name column.\n */\n name: string;\n\n /**\n * JavaScript source column.\n */\n code: string;\n\n /**\n * Execution scope column.\n */\n scope: string;\n\n /**\n * Sidebar ordering column.\n */\n sort_order: number;\n\n /**\n * Creation timestamp column.\n */\n created_at: Date;\n\n /**\n * Last update timestamp column.\n */\n updated_at: Date;\n\n /**\n * Creating user identifier column.\n */\n created_by_user_id: string | null;\n\n /**\n * Last updating user identifier column.\n */\n updated_by_user_id: string | null;\n\n /**\n * Deletion lock column.\n */\n deletion_locked: boolean;\n}\n\n/**\n * SQL row shape returned by relational backends for the folders table.\n */\nexport interface FolderSqlRow {\n /**\n * Primary key identifier.\n */\n id: string;\n\n /**\n * Parent collection identifier column.\n */\n collection_id: string;\n\n /**\n * Display name column.\n */\n name: string;\n\n /**\n * Sort order column.\n */\n sort_order: number;\n\n /**\n * Creation timestamp column.\n */\n created_at: Date;\n\n /**\n * Last update timestamp column.\n */\n updated_at: Date;\n\n /**\n * Creating user identifier column.\n */\n created_by_user_id: string | null;\n\n /**\n * Last updating user identifier column.\n */\n updated_by_user_id: string | null;\n}\n\n/**\n * SQL row shape returned by relational backends for the requests table.\n */\nexport interface RequestSqlRow {\n /**\n * Primary key identifier.\n */\n id: string;\n\n /**\n * Parent collection identifier column.\n */\n collection_id: string;\n\n /**\n * Optional parent folder identifier column.\n */\n folder_id: string | null;\n\n /**\n * Display name column.\n */\n name: string;\n\n /**\n * HTTP method column.\n */\n method: string;\n\n /**\n * Request URL column.\n */\n url: string;\n\n /**\n * JSON-encoded headers column.\n */\n headers: string;\n\n /**\n * JSON-encoded params column.\n */\n params: string;\n\n /**\n * JSON-encoded auth column.\n */\n auth: string;\n\n /**\n * Request body column.\n */\n body: string;\n\n /**\n * Body type column.\n */\n body_type: string;\n\n /**\n * Pre-request script column.\n */\n pre_request_script: string;\n\n /**\n * Post-request script column.\n */\n post_request_script: string;\n\n /**\n * Comment column.\n */\n comment: string;\n\n /**\n * Sort order column.\n */\n sort_order: number;\n\n /**\n * Creation timestamp column.\n */\n created_at: Date;\n\n /**\n * Last-updated timestamp column.\n */\n updated_at: Date;\n\n /**\n * Creating user identifier column.\n */\n created_by_user_id: string | null;\n\n /**\n * Last updating user identifier column.\n */\n updated_by_user_id: string | null;\n}\n\n/**\n * Maps a snake_case SQL row to the shared {@link CollectionRecord} shape.\n *\n * @param row - Database row from collections.\n * @returns Normalized collection record for application code.\n */\nexport function mapCollectionSqlRow(row: CollectionSqlRow): CollectionRecord {\n return {\n id: row.id,\n name: row.name,\n variables: readVariables(row.variables),\n headers: parseJson<KeyValue[]>(row.headers, []),\n auth: readAuth(row.auth),\n preRequestScript: row.pre_request_script,\n postRequestScript: row.post_request_script,\n createdAt: row.created_at,\n updatedAt: row.updated_at ?? row.created_at,\n createdByUserId: row.created_by_user_id ?? null,\n updatedByUserId: row.updated_by_user_id ?? null,\n deletionLocked: Boolean(row.deletion_locked)\n };\n}\n\n/**\n * Maps a snake_case SQL row to the shared {@link EnvironmentRecord} shape.\n *\n * @param row - Database row from environments.\n * @returns Normalized environment record for application code.\n */\nexport function mapEnvironmentSqlRow(row: EnvironmentSqlRow): EnvironmentRecord {\n return {\n id: row.id,\n name: row.name,\n variables: readVariables(row.variables),\n createdAt: row.created_at,\n updatedAt: row.updated_at ?? row.created_at,\n createdByUserId: row.created_by_user_id ?? null,\n updatedByUserId: row.updated_by_user_id ?? null,\n deletionLocked: Boolean(row.deletion_locked)\n };\n}\n\n/**\n * Parses a stored snippet scope string into a {@link SnippetScope}.\n *\n * @param value - Scope value read from the database.\n * @returns Validated snippet scope.\n * @throws {Error} When the stored scope is not recognized.\n */\nfunction parseSnippetScope(value: string): SnippetScope {\n if (value === 'pre-request' || value === 'post-request' || value === 'any') {\n return value;\n }\n\n throw new Error(`Invalid snippet scope: ${value}`);\n}\n\n/**\n * Maps a snake_case SQL row to the shared {@link SnippetRecord} shape.\n *\n * @param row - Database row from snippets.\n * @returns Normalized snippet record for application code.\n */\nexport function mapSnippetSqlRow(row: SnippetSqlRow): SnippetRecord {\n return {\n id: row.id,\n name: row.name,\n code: row.code,\n scope: parseSnippetScope(row.scope),\n sortOrder: row.sort_order,\n createdAt: row.created_at,\n updatedAt: row.updated_at ?? row.created_at,\n createdByUserId: row.created_by_user_id ?? null,\n updatedByUserId: row.updated_by_user_id ?? null,\n deletionLocked: Boolean(row.deletion_locked)\n };\n}\n\n/**\n * Maps a snake_case SQL row to the shared {@link FolderRecord} shape.\n *\n * @param row - Database row from folders.\n * @returns Normalized folder record for application code.\n */\nexport function mapFolderSqlRow(row: FolderSqlRow): FolderRecord {\n return {\n id: row.id,\n collectionId: row.collection_id,\n name: row.name,\n sortOrder: row.sort_order,\n createdAt: row.created_at,\n updatedAt: row.updated_at ?? row.created_at,\n createdByUserId: row.created_by_user_id ?? null,\n updatedByUserId: row.updated_by_user_id ?? null\n };\n}\n\n/**\n * Maps a snake_case SQL row to the shared {@link SavedRequestRecord} shape.\n *\n * @param row - Database row from requests.\n * @returns Normalized saved request record for application code.\n */\nexport function mapRequestSqlRow(row: RequestSqlRow): SavedRequestRecord {\n return {\n id: row.id,\n collectionId: row.collection_id,\n folderId: row.folder_id,\n name: row.name,\n method: row.method as HttpMethod,\n url: row.url,\n headers: parseJson<KeyValue[]>(row.headers, []),\n params: parseJson<KeyValue[]>(row.params, []),\n auth: readAuth(row.auth),\n body: row.body,\n bodyType: row.body_type as BodyType,\n preRequestScript: row.pre_request_script,\n postRequestScript: row.post_request_script,\n comment: row.comment,\n sortOrder: row.sort_order,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n createdByUserId: row.created_by_user_id ?? null,\n updatedByUserId: row.updated_by_user_id ?? null\n };\n}\n","import { DEFAULT_AUTH_JSON } from '#/db/types.js';\n\n/**\n * DDL for creating the api_tokens table when absent.\n */\nexport const API_TOKENS_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS api_tokens (\n id VARCHAR(36) PRIMARY KEY,\n user_id VARCHAR(36) NULL,\n name VARCHAR(255) NOT NULL,\n token_hash CHAR(64) NOT NULL UNIQUE,\n token_prefix VARCHAR(255) NOT NULL,\n created_at DATETIME NOT NULL,\n last_used_at DATETIME NULL,\n revoked_at DATETIME NULL,\n created_by_user_id VARCHAR(36) NULL,\n updated_by_user_id VARCHAR(36) NULL,\n FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL,\n FOREIGN KEY (created_by_user_id) REFERENCES users(id) ON DELETE SET NULL,\n FOREIGN KEY (updated_by_user_id) REFERENCES users(id) ON DELETE SET NULL\n)\n`.trim();\n\n/**\n * DDL for creating the collections table when absent.\n */\nexport const COLLECTIONS_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS collections (\n id VARCHAR(36) PRIMARY KEY,\n name VARCHAR(255) NOT NULL,\n variables LONGTEXT NOT NULL,\n headers LONGTEXT NOT NULL,\n auth LONGTEXT NOT NULL,\n pre_request_script LONGTEXT NOT NULL,\n post_request_script LONGTEXT NOT NULL,\n created_at DATETIME NOT NULL,\n updated_at DATETIME NOT NULL,\n created_by_user_id VARCHAR(36) NULL,\n updated_by_user_id VARCHAR(36) NULL,\n FOREIGN KEY (created_by_user_id) REFERENCES users(id) ON DELETE SET NULL,\n FOREIGN KEY (updated_by_user_id) REFERENCES users(id) ON DELETE SET NULL\n)\n`.trim();\n\n/**\n * DDL for creating the environments table when absent.\n */\nexport const ENVIRONMENTS_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS environments (\n id VARCHAR(36) PRIMARY KEY,\n name VARCHAR(255) NOT NULL,\n variables LONGTEXT NOT NULL,\n created_at DATETIME NOT NULL,\n updated_at DATETIME NOT NULL,\n created_by_user_id VARCHAR(36) NULL,\n updated_by_user_id VARCHAR(36) NULL,\n FOREIGN KEY (created_by_user_id) REFERENCES users(id) ON DELETE SET NULL,\n FOREIGN KEY (updated_by_user_id) REFERENCES users(id) ON DELETE SET NULL\n)\n`.trim();\n\n/**\n * DDL for creating the snippets table when absent.\n */\nexport const SNIPPETS_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS snippets (\n id VARCHAR(36) PRIMARY KEY,\n name VARCHAR(255) NOT NULL,\n code LONGTEXT NOT NULL,\n scope VARCHAR(32) NOT NULL DEFAULT 'any',\n sort_order INT NOT NULL DEFAULT 0,\n created_at DATETIME NOT NULL,\n updated_at DATETIME NOT NULL,\n created_by_user_id VARCHAR(36) NULL,\n updated_by_user_id VARCHAR(36) NULL,\n deletion_locked TINYINT(1) NOT NULL DEFAULT 0,\n FOREIGN KEY (created_by_user_id) REFERENCES users(id) ON DELETE SET NULL,\n FOREIGN KEY (updated_by_user_id) REFERENCES users(id) ON DELETE SET NULL\n)\n`.trim();\n\n/**\n * DDL for creating the folders table when absent.\n */\nexport const FOLDERS_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS folders (\n id VARCHAR(36) PRIMARY KEY,\n collection_id VARCHAR(36) NOT NULL,\n name VARCHAR(255) NOT NULL,\n sort_order INT NOT NULL DEFAULT 0,\n created_at DATETIME NOT NULL,\n updated_at DATETIME NOT NULL,\n created_by_user_id VARCHAR(36) NULL,\n updated_by_user_id VARCHAR(36) NULL,\n FOREIGN KEY (collection_id) REFERENCES collections(id) ON DELETE CASCADE,\n FOREIGN KEY (created_by_user_id) REFERENCES users(id) ON DELETE SET NULL,\n FOREIGN KEY (updated_by_user_id) REFERENCES users(id) ON DELETE SET NULL\n)\n`.trim();\n\n/**\n * DDL for creating the requests table when absent.\n */\nexport const REQUESTS_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS requests (\n id VARCHAR(36) PRIMARY KEY,\n collection_id VARCHAR(36) NOT NULL,\n folder_id VARCHAR(36) NULL,\n name VARCHAR(255) NOT NULL,\n method VARCHAR(16) NOT NULL DEFAULT 'GET',\n url LONGTEXT NOT NULL,\n headers LONGTEXT NOT NULL,\n params LONGTEXT NOT NULL,\n auth LONGTEXT NOT NULL,\n body LONGTEXT NOT NULL,\n body_type VARCHAR(32) NOT NULL DEFAULT 'none',\n pre_request_script LONGTEXT NOT NULL,\n post_request_script LONGTEXT NOT NULL,\n comment LONGTEXT NOT NULL,\n sort_order INT NOT NULL DEFAULT 0,\n created_at DATETIME NOT NULL,\n updated_at DATETIME NOT NULL,\n created_by_user_id VARCHAR(36) NULL,\n updated_by_user_id VARCHAR(36) NULL,\n FOREIGN KEY (collection_id) REFERENCES collections(id) ON DELETE CASCADE,\n FOREIGN KEY (folder_id) REFERENCES folders(id) ON DELETE CASCADE,\n FOREIGN KEY (created_by_user_id) REFERENCES users(id) ON DELETE SET NULL,\n FOREIGN KEY (updated_by_user_id) REFERENCES users(id) ON DELETE SET NULL\n)\n`.trim();\n\n/**\n * DDL for creating the users table when absent.\n */\nexport const USERS_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS users (\n id VARCHAR(36) PRIMARY KEY,\n name VARCHAR(255) NOT NULL UNIQUE,\n role VARCHAR(16) NOT NULL,\n collection_access LONGTEXT NOT NULL,\n environment_access LONGTEXT NOT NULL,\n snippet_access LONGTEXT NOT NULL,\n created_at DATETIME NOT NULL,\n updated_at DATETIME NOT NULL,\n created_by_user_id VARCHAR(36) NULL,\n updated_by_user_id VARCHAR(36) NULL,\n FOREIGN KEY (created_by_user_id) REFERENCES users(id) ON DELETE SET NULL,\n FOREIGN KEY (updated_by_user_id) REFERENCES users(id) ON DELETE SET NULL\n)\n`.trim();\n\n/**\n * DDL for creating the audit_log table when absent.\n */\nexport const AUDIT_LOG_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS audit_log (\n id VARCHAR(36) PRIMARY KEY,\n user_id VARCHAR(36) NULL,\n user_name VARCHAR(255) NULL,\n action VARCHAR(16) NOT NULL,\n entity_type VARCHAR(32) NOT NULL,\n entity_id VARCHAR(36) NOT NULL,\n created_at DATETIME NOT NULL,\n metadata LONGTEXT NOT NULL\n)\n`.trim();\n\n/**\n * Adds the owning user reference to api_tokens when upgrading existing databases.\n */\nexport const API_TOKENS_USER_ID_MIGRATION_SQL = `\nALTER TABLE api_tokens\n ADD COLUMN IF NOT EXISTS user_id VARCHAR(36) NULL\n`.trim();\n\n/**\n * Adds user attribution columns to api_tokens when upgrading existing databases.\n */\nexport const API_TOKENS_ATTRIBUTION_MIGRATION_SQL = `\nALTER TABLE api_tokens\n ADD COLUMN IF NOT EXISTS created_by_user_id VARCHAR(36) NULL,\n ADD COLUMN IF NOT EXISTS updated_by_user_id VARCHAR(36) NULL\n`.trim();\n\n/**\n * Adds user attribution and updated_at to collections when upgrading existing databases.\n */\nexport const COLLECTIONS_ATTRIBUTION_MIGRATION_SQL = `\nALTER TABLE collections\n ADD COLUMN IF NOT EXISTS updated_at DATETIME NULL,\n ADD COLUMN IF NOT EXISTS created_by_user_id VARCHAR(36) NULL,\n ADD COLUMN IF NOT EXISTS updated_by_user_id VARCHAR(36) NULL\n`.trim();\n\n/**\n * Adds user attribution and updated_at to environments when upgrading existing databases.\n */\nexport const ENVIRONMENTS_ATTRIBUTION_MIGRATION_SQL = `\nALTER TABLE environments\n ADD COLUMN IF NOT EXISTS updated_at DATETIME NULL,\n ADD COLUMN IF NOT EXISTS created_by_user_id VARCHAR(36) NULL,\n ADD COLUMN IF NOT EXISTS updated_by_user_id VARCHAR(36) NULL\n`.trim();\n\n/**\n * Adds user attribution and updated_at to folders when upgrading existing databases.\n */\nexport const FOLDERS_ATTRIBUTION_MIGRATION_SQL = `\nALTER TABLE folders\n ADD COLUMN IF NOT EXISTS updated_at DATETIME NULL,\n ADD COLUMN IF NOT EXISTS created_by_user_id VARCHAR(36) NULL,\n ADD COLUMN IF NOT EXISTS updated_by_user_id VARCHAR(36) NULL\n`.trim();\n\n/**\n * Adds user attribution columns to requests when upgrading existing databases.\n */\nexport const REQUESTS_ATTRIBUTION_MIGRATION_SQL = `\nALTER TABLE requests\n ADD COLUMN IF NOT EXISTS created_by_user_id VARCHAR(36) NULL,\n ADD COLUMN IF NOT EXISTS updated_by_user_id VARCHAR(36) NULL\n`.trim();\n\n/**\n * Adds user attribution columns to users when upgrading existing databases.\n */\nexport const USERS_ATTRIBUTION_MIGRATION_SQL = `\nALTER TABLE users\n ADD COLUMN IF NOT EXISTS created_by_user_id VARCHAR(36) NULL,\n ADD COLUMN IF NOT EXISTS updated_by_user_id VARCHAR(36) NULL\n`.trim();\n\n/**\n * Backfills updated_at on collections from created_at for upgraded databases.\n */\nexport const COLLECTIONS_BACKFILL_UPDATED_AT_SQL = `\nUPDATE collections SET updated_at = created_at WHERE updated_at IS NULL\n`.trim();\n\n/**\n * Backfills updated_at on environments from created_at for upgraded databases.\n */\nexport const ENVIRONMENTS_BACKFILL_UPDATED_AT_SQL = `\nUPDATE environments SET updated_at = created_at WHERE updated_at IS NULL\n`.trim();\n\n/**\n * Backfills updated_at on folders from created_at for upgraded databases.\n */\nexport const FOLDERS_BACKFILL_UPDATED_AT_SQL = `\nUPDATE folders SET updated_at = created_at WHERE updated_at IS NULL\n`.trim();\n\n/**\n * Adds LLM access columns to users when upgrading existing databases.\n */\nexport const USERS_LLM_MIGRATION_SQL = `\nALTER TABLE users\n ADD COLUMN IF NOT EXISTS llm_access TINYINT(1) NOT NULL DEFAULT 0,\n ADD COLUMN IF NOT EXISTS llm_models LONGTEXT NOT NULL DEFAULT '[]',\n ADD COLUMN IF NOT EXISTS llm_monthly_token_limit INT NULL\n`.trim();\n\n/**\n * DDL for creating the llm_usage table when absent.\n */\nexport const LLM_USAGE_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS llm_usage (\n id VARCHAR(36) PRIMARY KEY,\n user_id VARCHAR(36) NOT NULL,\n period VARCHAR(7) NOT NULL,\n prompt_tokens INT NOT NULL DEFAULT 0,\n completion_tokens INT NOT NULL DEFAULT 0,\n total_tokens INT NOT NULL DEFAULT 0,\n updated_at DATETIME NOT NULL,\n UNIQUE KEY llm_usage_user_period (user_id, period),\n FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE\n)\n`.trim();\n\n/**\n * DDL for creating the llm_usage_log table when absent.\n */\nexport const LLM_USAGE_LOG_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS llm_usage_log (\n id VARCHAR(36) PRIMARY KEY,\n user_id VARCHAR(36) NOT NULL,\n api_token_id VARCHAR(36) NULL,\n period VARCHAR(7) NOT NULL,\n model VARCHAR(255) NOT NULL,\n provider VARCHAR(32) NOT NULL,\n prompt_tokens INT NOT NULL,\n completion_tokens INT NOT NULL,\n total_tokens INT NOT NULL,\n is_new_turn BOOLEAN NOT NULL DEFAULT FALSE,\n had_tool_calls BOOLEAN NOT NULL DEFAULT FALSE,\n message_count INT NOT NULL,\n created_at DATETIME NOT NULL,\n INDEX llm_usage_log_user_created_at_idx (user_id, created_at),\n INDEX llm_usage_log_period_idx (period),\n FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,\n FOREIGN KEY (api_token_id) REFERENCES api_tokens(id) ON DELETE SET NULL\n)\n`.trim();\n\n/**\n * Default LLM models JSON for MySQL user inserts on upgraded databases.\n */\nexport const MYSQL_DEFAULT_LLM_MODELS_JSON = '[]';\n\n/**\n * Default auth JSON for MySQL collection/request inserts.\n */\nexport const MYSQL_DEFAULT_AUTH_JSON = DEFAULT_AUTH_JSON;\n\n/**\n * Adds deletion lock columns to collections when upgrading existing databases.\n */\nexport const COLLECTIONS_DELETION_LOCKED_MIGRATION_SQL = `\nALTER TABLE collections\n ADD COLUMN IF NOT EXISTS deletion_locked TINYINT(1) NOT NULL DEFAULT 0;\n`.trim();\n\n/**\n * Adds deletion lock columns to environments when upgrading existing databases.\n */\nexport const ENVIRONMENTS_DELETION_LOCKED_MIGRATION_SQL = `\nALTER TABLE environments\n ADD COLUMN IF NOT EXISTS deletion_locked TINYINT(1) NOT NULL DEFAULT 0;\n`.trim();\n\n/**\n * Adds snippet access column to users when upgrading existing databases.\n */\nexport const USERS_SNIPPET_ACCESS_MIGRATION_SQL = `\nALTER TABLE users\n ADD COLUMN IF NOT EXISTS snippet_access LONGTEXT NOT NULL DEFAULT '[]';\n`.trim();\n\n/**\n * Adds snippet access for user accounts that have collection wildcard access but no snippet access.\n */\nexport const USERS_SNIPPET_ACCESS_BACKFILL_SQL = `\nUPDATE users\nSET snippet_access = '[\"*\"]'\nWHERE role = 'user'\n AND snippet_access = '[]'\n AND collection_access LIKE '%\"*\"%';\n`.trim();\n\n/**\n * Ordered MySQL migrations applied by {@link MysqlDatabase.migrate}.\n */\nexport const MYSQL_MIGRATIONS = [\n USERS_MIGRATION_SQL,\n API_TOKENS_MIGRATION_SQL,\n COLLECTIONS_MIGRATION_SQL,\n ENVIRONMENTS_MIGRATION_SQL,\n SNIPPETS_MIGRATION_SQL,\n FOLDERS_MIGRATION_SQL,\n REQUESTS_MIGRATION_SQL,\n AUDIT_LOG_MIGRATION_SQL,\n API_TOKENS_USER_ID_MIGRATION_SQL,\n API_TOKENS_ATTRIBUTION_MIGRATION_SQL,\n COLLECTIONS_ATTRIBUTION_MIGRATION_SQL,\n ENVIRONMENTS_ATTRIBUTION_MIGRATION_SQL,\n FOLDERS_ATTRIBUTION_MIGRATION_SQL,\n REQUESTS_ATTRIBUTION_MIGRATION_SQL,\n USERS_ATTRIBUTION_MIGRATION_SQL,\n COLLECTIONS_BACKFILL_UPDATED_AT_SQL,\n ENVIRONMENTS_BACKFILL_UPDATED_AT_SQL,\n FOLDERS_BACKFILL_UPDATED_AT_SQL,\n USERS_LLM_MIGRATION_SQL,\n LLM_USAGE_MIGRATION_SQL,\n LLM_USAGE_LOG_MIGRATION_SQL,\n COLLECTIONS_DELETION_LOCKED_MIGRATION_SQL,\n ENVIRONMENTS_DELETION_LOCKED_MIGRATION_SQL,\n USERS_SNIPPET_ACCESS_MIGRATION_SQL,\n USERS_SNIPPET_ACCESS_BACKFILL_SQL\n];\n","import { z } from 'zod/v4';\n\n/**\n * Zod schema for validating MySQL port values from server.yaml.\n */\nexport const portSchema = z.union([\n z\n .number()\n .int({ message: 'MySQL port must be an integer between 1 and 65535.' })\n .min(1, { message: 'MySQL port must be an integer between 1 and 65535.' })\n .max(65535, { message: 'MySQL port must be an integer between 1 and 65535.' }),\n z\n .string()\n .regex(/^\\d+$/, { message: 'MySQL port must be an integer between 1 and 65535.' })\n .transform(Number)\n .pipe(\n z\n .number()\n .int({ message: 'MySQL port must be an integer between 1 and 65535.' })\n .min(1, { message: 'MySQL port must be an integer between 1 and 65535.' })\n .max(65535, { message: 'MySQL port must be an integer between 1 and 65535.' })\n )\n]);\n\n/**\n * Zod schema for validating raw MySQL database config from server.yaml.\n */\nexport const mysqlConfigSchema = z.object({\n driver: z.literal('mysql'),\n host: z.string().trim().min(1, { message: 'MySQL host must not be empty.' }),\n port: portSchema,\n user: z.string().trim().min(1, { message: 'MySQL user must not be empty.' }),\n password: z.string(),\n database: z.string().trim().min(1, { message: 'MySQL database must not be empty.' })\n});\n","import type { UserRecord, UserRole } from '#/db/types.js';\n\n/**\n * SQL row shape returned by relational backends for the users table.\n */\nexport interface UserSqlRow {\n /**\n * Primary key identifier.\n */\n id: string;\n\n /**\n * Unique display name column.\n */\n name: string;\n\n /**\n * Role column (`admin` or `user`).\n */\n role: string;\n\n /**\n * JSON-encoded collection access list column.\n */\n collection_access: string;\n\n /**\n * JSON-encoded environment access list column.\n */\n environment_access: string;\n\n /**\n * JSON-encoded snippet access list column.\n */\n snippet_access: string;\n\n /**\n * Creation timestamp column.\n */\n created_at: Date;\n\n /**\n * Last update timestamp column.\n */\n updated_at: Date;\n\n /**\n * Creating user identifier column.\n */\n created_by_user_id: string | null;\n\n /**\n * Last updating user identifier column.\n */\n updated_by_user_id: string | null;\n\n /**\n * Whether LLM access is enabled for the account.\n */\n llm_access: boolean;\n\n /**\n * JSON-encoded LLM model access list column.\n */\n llm_models: string;\n\n /**\n * Monthly token limit column, or null for unlimited.\n */\n llm_monthly_token_limit: number | null;\n}\n\n/**\n * Parses a stored role string into a {@link UserRole}.\n *\n * @param role - Role value read from the database.\n * @returns Validated user role.\n * @throws {Error} When the stored role is not recognized.\n */\nfunction parseUserRole(role: string): UserRole {\n if (role === 'admin' || role === 'user') {\n return role;\n }\n\n throw new Error(`Invalid user role: ${role}`);\n}\n\n/**\n * Parses a JSON-encoded access list column from SQL storage.\n *\n * @param value - JSON array string from the database.\n * @returns Parsed access id list.\n */\nfunction parseAccessList(value: string | null | undefined): string[] {\n if (value == null || value === '') {\n return [];\n }\n\n const parsed: unknown = JSON.parse(value);\n if (!Array.isArray(parsed) || !parsed.every((entry) => typeof entry === 'string')) {\n throw new Error('Invalid access list JSON in users table');\n }\n\n return parsed;\n}\n\n/**\n * Maps a snake_case SQL row to the shared {@link UserRecord} shape.\n *\n * @param row - Database row from users.\n * @returns Normalized user record for application code.\n */\nexport function mapUserSqlRow(row: UserSqlRow): UserRecord {\n return {\n id: row.id,\n name: row.name,\n role: parseUserRole(row.role),\n collectionAccess: parseAccessList(row.collection_access),\n environmentAccess: parseAccessList(row.environment_access),\n snippetAccess: parseAccessList(row.snippet_access),\n llmAccess: Boolean(row.llm_access),\n llmModels: parseAccessList(row.llm_models),\n llmMonthlyTokenLimit: row.llm_monthly_token_limit,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n createdByUserId: row.created_by_user_id ?? null,\n updatedByUserId: row.updated_by_user_id ?? null\n };\n}\n\n/**\n * Serializes an access list for SQL storage.\n *\n * @param access - Collection or environment access ids.\n * @returns JSON string suitable for a TEXT column.\n */\nexport function serializeAccessList(access: string[]): string {\n return JSON.stringify(access);\n}\n\n/**\n * Column list for SELECT queries against the users table.\n */\nexport const USER_SELECT_COLUMNS = `id, name, role, collection_access, environment_access, snippet_access, llm_access, llm_models, llm_monthly_token_limit, created_at, updated_at, created_by_user_id, updated_by_user_id`;\n\n/**\n * Column list for SELECT queries against the collections table.\n */\nexport const COLLECTION_SELECT_COLUMNS = `id, name, variables, headers, auth, pre_request_script, post_request_script, created_at, updated_at, created_by_user_id, updated_by_user_id, deletion_locked`;\n\n/**\n * Column list for SELECT queries against the environments table.\n */\nexport const ENVIRONMENT_SELECT_COLUMNS = `id, name, variables, created_at, updated_at, created_by_user_id, updated_by_user_id, deletion_locked`;\n\n/**\n * Column list for SELECT queries against the snippets table.\n */\nexport const SNIPPET_SELECT_COLUMNS = `id, name, code, scope, sort_order, created_at, updated_at, created_by_user_id, updated_by_user_id, deletion_locked`;\n\n/**\n * Column list for SELECT queries against the folders table.\n */\nexport const FOLDER_SELECT_COLUMNS = `id, collection_id, name, sort_order, created_at, updated_at, created_by_user_id, updated_by_user_id`;\n\n/**\n * Column list for SELECT queries against the requests table.\n */\nexport const REQUEST_SELECT_COLUMNS = `id, collection_id, folder_id, name, method, url, headers, params, auth, body, body_type, pre_request_script, post_request_script, comment, sort_order, created_at, updated_at, created_by_user_id, updated_by_user_id`;\n\n/**\n * Column list for SELECT queries against the api_tokens table.\n */\nexport const API_TOKEN_SELECT_COLUMNS = `id, user_id, name, token_hash, token_prefix, created_at, last_used_at, revoked_at, created_by_user_id, updated_by_user_id`;\n\n/**\n * Column list for SELECT queries against the audit_log table.\n */\nexport const AUDIT_LOG_SELECT_COLUMNS = `id, user_id, user_name, action, entity_type, entity_id, created_at, metadata`;\n","import type { LlmUsageLogRecord } from '#/db/types.js';\n\n/**\n * SQL row shape returned by relational backends for the llm_usage_log table.\n */\nexport interface LlmUsageLogSqlRow {\n /**\n * Primary key identifier.\n */\n id: string;\n\n /**\n * Owning user identifier column.\n */\n user_id: string;\n\n /**\n * API token identifier column.\n */\n api_token_id: string | null;\n\n /**\n * UTC calendar month key column.\n */\n period: string;\n\n /**\n * Provider model id column.\n */\n model: string;\n\n /**\n * LLM provider column.\n */\n provider: string;\n\n /**\n * Prompt token count column.\n */\n prompt_tokens: number;\n\n /**\n * Completion token count column.\n */\n completion_tokens: number;\n\n /**\n * Total token count column.\n */\n total_tokens: number;\n\n /**\n * Whether the request started a new user turn.\n */\n is_new_turn: boolean;\n\n /**\n * Whether the model returned tool calls.\n */\n had_tool_calls: boolean;\n\n /**\n * Request message count column.\n */\n message_count: number;\n\n /**\n * Completion timestamp column.\n */\n created_at: Date;\n}\n\n/**\n * Maps a snake_case SQL row to the shared {@link LlmUsageLogRecord} shape.\n *\n * @param row - Database row from llm_usage_log.\n * @returns Normalized usage log record for application code.\n */\nexport function mapLlmUsageLogSqlRow(row: LlmUsageLogSqlRow): LlmUsageLogRecord {\n return {\n id: row.id,\n userId: row.user_id,\n apiTokenId: row.api_token_id,\n period: row.period,\n model: row.model,\n provider: row.provider as LlmUsageLogRecord['provider'],\n promptTokens: row.prompt_tokens,\n completionTokens: row.completion_tokens,\n totalTokens: row.total_tokens,\n isNewTurn: row.is_new_turn,\n hadToolCalls: row.had_tool_calls,\n messageCount: row.message_count,\n createdAt: row.created_at\n };\n}\n\n/**\n * Column list for SELECT queries against the llm_usage_log table.\n */\nexport const LLM_USAGE_LOG_SELECT_COLUMNS = `id, user_id, api_token_id, period, model, provider, prompt_tokens, completion_tokens, total_tokens, is_new_turn, had_tool_calls, message_count, created_at`;\n","import type { LlmUsageRecord } from '#/db/types.js';\n\n/**\n * SQL row shape returned by relational backends for the llm_usage table.\n */\nexport interface LlmUsageSqlRow {\n /**\n * Primary key identifier.\n */\n id: string;\n\n /**\n * Owning user identifier column.\n */\n user_id: string;\n\n /**\n * UTC calendar month key column.\n */\n period: string;\n\n /**\n * Prompt token count column.\n */\n prompt_tokens: number;\n\n /**\n * Completion token count column.\n */\n completion_tokens: number;\n\n /**\n * Total token count column.\n */\n total_tokens: number;\n\n /**\n * Last update timestamp column.\n */\n updated_at: Date;\n}\n\n/**\n * Maps a snake_case SQL row to the shared {@link LlmUsageRecord} shape.\n *\n * @param row - Database row from llm_usage.\n * @returns Normalized usage record for application code.\n */\nexport function mapLlmUsageSqlRow(row: LlmUsageSqlRow): LlmUsageRecord {\n return {\n id: row.id,\n userId: row.user_id,\n period: row.period,\n promptTokens: row.prompt_tokens,\n completionTokens: row.completion_tokens,\n totalTokens: row.total_tokens,\n updatedAt: row.updated_at\n };\n}\n\n/**\n * Column list for SELECT queries against the llm_usage table.\n */\nexport const LLM_USAGE_SELECT_COLUMNS = `id, user_id, period, prompt_tokens, completion_tokens, total_tokens, updated_at`;\n","import { randomUUID } from 'node:crypto';\nimport pg from 'pg';\nimport { mapApiTokenSqlRow, type ApiTokenSqlRow } from '#/db/apiTokenRows.js';\nimport { resolveActingUserName } from '#/db/attribution.js';\nimport {\n mapAuditLogSqlRow,\n serializeAuditMetadata,\n type AuditLogSqlRow\n} from '#/db/auditLogRows.js';\nimport { BOOTSTRAP_USER_NAME } from '#/db/bootstrapUsers.js';\nimport {\n mapCollectionSqlRow,\n mapEnvironmentSqlRow,\n mapFolderSqlRow,\n mapRequestSqlRow,\n mapSnippetSqlRow,\n type CollectionSqlRow,\n type EnvironmentSqlRow,\n type FolderSqlRow,\n type RequestSqlRow,\n type SnippetSqlRow\n} from '#/db/entityRows.js';\nimport type { IDatabase } from '#/db/IDatabase.js';\nimport { POSTGRES_MIGRATIONS } from '#/db/postgres/migrations.js';\nimport { postgresConfigSchema } from '#/db/postgres/schemas.js';\nimport type { PostgresDatabaseConfig } from '#/db/postgres/types.js';\nimport { createSystemUserInput, SYSTEM_USER_NAME } from '#/db/systemUsers.js';\nimport { trimRequiredName } from '#/db/trimRequiredName.js';\nimport { assertUserNameAvailable, assertUserNameNotReserved } from '#/db/userNameValidation.js';\nimport {\n API_TOKEN_SELECT_COLUMNS,\n AUDIT_LOG_SELECT_COLUMNS,\n COLLECTION_SELECT_COLUMNS,\n ENVIRONMENT_SELECT_COLUMNS,\n FOLDER_SELECT_COLUMNS,\n mapUserSqlRow,\n REQUEST_SELECT_COLUMNS,\n SNIPPET_SELECT_COLUMNS,\n serializeAccessList,\n USER_SELECT_COLUMNS,\n type UserSqlRow\n} from '#/db/userRows.js';\nimport {\n LLM_USAGE_LOG_SELECT_COLUMNS,\n mapLlmUsageLogSqlRow,\n type LlmUsageLogSqlRow\n} from '#/db/llmUsageLogRows.js';\nimport {\n LLM_USAGE_SELECT_COLUMNS,\n mapLlmUsageSqlRow,\n type LlmUsageSqlRow\n} from '#/db/llmUsageRows.js';\nimport type {\n ApiTokenRecord,\n AuditAction,\n AuditEntityType,\n AuditLogRecord,\n AuthConfig,\n CollectionRecord,\n CreateUserInput,\n CreateLlmUsageLogInput,\n EnvironmentRecord,\n FolderRecord,\n KeyValue,\n ListAuditLogOptions,\n LlmUsageLogRecord,\n LlmUsageRecord,\n SaveRequestInput,\n SavedRequestRecord,\n SnippetRecord,\n SnippetScope,\n UpdateUserInput,\n UserRecord,\n Variable\n} from '#/db/types.js';\nimport { DEFAULT_AUTH_JSON } from '#/db/types.js';\nimport { formatZodError } from '#/db/validation.js';\n\nconst { Pool } = pg;\n\nconst COLLECTION_SELECT = `SELECT ${COLLECTION_SELECT_COLUMNS} FROM collections`;\nconst ENVIRONMENT_SELECT = `SELECT ${ENVIRONMENT_SELECT_COLUMNS} FROM environments`;\nconst SNIPPET_SELECT = `SELECT ${SNIPPET_SELECT_COLUMNS} FROM snippets`;\nconst USER_SELECT = `SELECT ${USER_SELECT_COLUMNS} FROM users`;\nconst API_TOKEN_SELECT = `SELECT ${API_TOKEN_SELECT_COLUMNS} FROM api_tokens`;\nconst FOLDER_SELECT = `SELECT ${FOLDER_SELECT_COLUMNS} FROM folders`;\nconst REQUEST_SELECT = `SELECT ${REQUEST_SELECT_COLUMNS} FROM requests`;\nconst LLM_USAGE_SELECT = `SELECT ${LLM_USAGE_SELECT_COLUMNS} FROM llm_usage`;\nconst LLM_USAGE_LOG_SELECT = `SELECT ${LLM_USAGE_LOG_SELECT_COLUMNS} FROM llm_usage_log`;\n\n/**\n * Postgres-backed database implementation.\n */\nexport class PostgresDatabase implements IDatabase {\n /**\n * Active Postgres connection pool, or null when disconnected.\n */\n private pool: pg.Pool | null = null;\n\n /**\n * Cached identifier for the internal system user, when provisioned during migrate.\n */\n private systemUserId: string | null = null;\n\n /**\n * Creates a Postgres database instance from validated config.\n *\n * @param config - Parsed Postgres connection settings.\n */\n constructor(private readonly config: PostgresDatabaseConfig) {}\n\n /**\n * Validates raw config and constructs a {@link PostgresDatabase}.\n *\n * @param config - Raw `db` section from server.yaml.\n * @returns Configured Postgres database instance.\n * @throws {Error} When config fails Postgres-specific validation.\n */\n static fromConfig(config: unknown): PostgresDatabase {\n const parsed = postgresConfigSchema.safeParse(config);\n if (!parsed.success) {\n throw new Error(formatZodError(parsed.error));\n }\n\n return new PostgresDatabase({\n host: parsed.data.host,\n port: parsed.data.port,\n user: parsed.data.user,\n password: parsed.data.password,\n database: parsed.data.database\n });\n }\n\n /**\n * Opens a Postgres connection pool and verifies connectivity with a query.\n */\n async connect(): Promise<void> {\n if (this.pool) {\n return;\n }\n\n const pool = new Pool({\n host: this.config.host,\n port: this.config.port,\n user: this.config.user,\n password: this.config.password,\n database: this.config.database\n });\n\n const client = await pool.connect();\n await client.query('SELECT 1');\n client.release();\n\n this.pool = pool;\n }\n\n /**\n * Closes the Postgres connection pool and releases resources.\n */\n async disconnect(): Promise<void> {\n if (!this.pool) {\n return;\n }\n\n await this.pool.end();\n this.pool = null;\n }\n\n /**\n * Creates required tables when they do not already exist.\n */\n async migrate(): Promise<void> {\n for (const sql of POSTGRES_MIGRATIONS) {\n await this.query(sql);\n }\n\n await this.ensureSystemUser();\n await this.migrateOrphanTokensToBootstrapUser();\n }\n\n /**\n * Returns the stable identifier of the internal system user, when provisioned.\n */\n getSystemUserId(): string | null {\n return this.systemUserId;\n }\n\n /**\n * Lists audit log entries ordered newest-first with optional filters.\n *\n * @param options - Optional limit and filter criteria.\n */\n async listAuditLog(options?: ListAuditLogOptions): Promise<AuditLogRecord[]> {\n const limit = options?.limit ?? 100;\n const conditions: string[] = [];\n const params: unknown[] = [];\n let paramIndex = 1;\n\n if (options?.userId) {\n conditions.push(`user_id = $${paramIndex++}`);\n params.push(options.userId);\n }\n\n if (options?.entityType) {\n conditions.push(`entity_type = $${paramIndex++}`);\n params.push(options.entityType);\n }\n\n if (options?.entityId) {\n conditions.push(`entity_id = $${paramIndex++}`);\n params.push(options.entityId);\n }\n\n const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';\n params.push(limit);\n\n const result = await this.query<AuditLogSqlRow>(\n `SELECT ${AUDIT_LOG_SELECT_COLUMNS} FROM audit_log\n ${whereClause}\n ORDER BY created_at DESC\n LIMIT $${paramIndex}`,\n params\n );\n\n return result.rows.map(mapAuditLogSqlRow);\n }\n\n /**\n * Creates a new user account with the given role and access lists.\n *\n * @param input - User fields to persist.\n * @param actingUserId - User performing the create action.\n */\n async createUser(input: CreateUserInput, actingUserId: string): Promise<UserRecord> {\n const trimmedName = trimRequiredName(input.name, 'User name');\n assertUserNameNotReserved(trimmedName);\n const id = randomUUID();\n const now = new Date();\n\n const result = await this.query<UserSqlRow>(\n `INSERT INTO users (\n id,\n name,\n role,\n collection_access,\n environment_access,\n snippet_access,\n llm_access,\n llm_models,\n llm_monthly_token_limit,\n created_at,\n updated_at,\n created_by_user_id,\n updated_by_user_id\n ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)\n RETURNING ${USER_SELECT_COLUMNS}`,\n [\n id,\n trimmedName,\n input.role,\n serializeAccessList(input.collectionAccess),\n serializeAccessList(input.environmentAccess),\n serializeAccessList(input.snippetAccess),\n input.llmAccess ?? false,\n serializeAccessList(input.llmModels ?? []),\n input.llmMonthlyTokenLimit ?? null,\n now,\n now,\n actingUserId,\n actingUserId\n ]\n );\n\n const row = result.rows[0];\n if (!row) {\n throw new Error('User not found after insert');\n }\n\n await this.recordAuditEntry(actingUserId, 'create', 'user', id);\n\n return mapUserSqlRow(row);\n }\n\n /**\n * Finds a user by stable identifier.\n *\n * @param id - User identifier to look up.\n */\n async findUserById(id: string): Promise<UserRecord | null> {\n const result = await this.query<UserSqlRow>(`${USER_SELECT} WHERE id = $1 LIMIT 1`, [id]);\n const row = result.rows[0];\n return row ? mapUserSqlRow(row) : null;\n }\n\n /**\n * Finds a user by unique display name.\n *\n * @param name - User name to look up.\n */\n async findUserByName(name: string): Promise<UserRecord | null> {\n const result = await this.query<UserSqlRow>(`${USER_SELECT} WHERE name = $1 LIMIT 1`, [name]);\n const row = result.rows[0];\n return row ? mapUserSqlRow(row) : null;\n }\n\n /**\n * Lists all user accounts ordered by name.\n */\n async listUsers(): Promise<UserRecord[]> {\n const result = await this.query<UserSqlRow>(`${USER_SELECT} ORDER BY name ASC`);\n return result.rows.map(mapUserSqlRow);\n }\n\n /**\n * Updates an existing user account.\n *\n * @param id - User identifier to update.\n * @param input - Partial fields to apply.\n * @param actingUserId - User performing the update action.\n */\n async updateUser(id: string, input: UpdateUserInput, actingUserId: string): Promise<UserRecord> {\n const existing = await this.findUserById(id);\n if (!existing) {\n throw new Error('User not found');\n }\n\n const name =\n input.name !== undefined ? trimRequiredName(input.name, 'User name') : existing.name;\n\n if (name !== existing.name) {\n assertUserNameNotReserved(name);\n const duplicate = await this.findUserByName(name);\n assertUserNameAvailable(name, id, duplicate);\n }\n\n const role = input.role ?? existing.role;\n const collectionAccess = input.collectionAccess ?? existing.collectionAccess;\n const environmentAccess = input.environmentAccess ?? existing.environmentAccess;\n const snippetAccess = input.snippetAccess ?? existing.snippetAccess;\n const llmAccess = input.llmAccess ?? existing.llmAccess;\n const llmModels = input.llmModels ?? existing.llmModels;\n const llmMonthlyTokenLimit =\n input.llmMonthlyTokenLimit !== undefined\n ? input.llmMonthlyTokenLimit\n : existing.llmMonthlyTokenLimit;\n const updatedAt = new Date();\n\n const result = await this.query(\n `UPDATE users\n SET name = $1,\n role = $2,\n collection_access = $3,\n environment_access = $4,\n snippet_access = $5,\n llm_access = $6,\n llm_models = $7,\n llm_monthly_token_limit = $8,\n updated_at = $9,\n updated_by_user_id = $10\n WHERE id = $11`,\n [\n name,\n role,\n serializeAccessList(collectionAccess),\n serializeAccessList(environmentAccess),\n serializeAccessList(snippetAccess),\n llmAccess,\n serializeAccessList(llmModels),\n llmMonthlyTokenLimit,\n updatedAt,\n actingUserId,\n id\n ]\n );\n\n if ((result.rowCount ?? 0) === 0) {\n throw new Error('User not found');\n }\n\n await this.recordAuditEntry(actingUserId, 'update', 'user', id);\n\n const updated = await this.findUserById(id);\n if (!updated) {\n throw new Error('User not found');\n }\n\n return updated;\n }\n\n /**\n * Deletes a user account and revokes all of their API tokens.\n *\n * @param id - User identifier to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteUser(id: string, actingUserId: string): Promise<void> {\n const client = await this.requirePool().connect();\n try {\n await client.query('BEGIN');\n await client.query('DELETE FROM api_tokens WHERE user_id = $1', [id]);\n await client.query('DELETE FROM users WHERE id = $1', [id]);\n await client.query('COMMIT');\n } catch (err) {\n await client.query('ROLLBACK');\n throw err;\n } finally {\n client.release();\n }\n\n await this.recordAuditEntry(actingUserId, 'delete', 'user', id);\n }\n\n /**\n * Assigns legacy API tokens without an owner to the bootstrap user.\n */\n async migrateOrphanTokensToBootstrapUser(): Promise<void> {\n const orphanResult = await this.query<{ count: string }>(\n 'SELECT COUNT(*)::text AS count FROM api_tokens WHERE user_id IS NULL'\n );\n const orphanCount = Number(orphanResult.rows[0]?.count ?? 0);\n if (orphanCount === 0) {\n return;\n }\n\n const systemUserId = this.getSystemUserId();\n if (!systemUserId) {\n throw new Error('System user is not provisioned');\n }\n\n let bootstrapUser = await this.findUserByName(BOOTSTRAP_USER_NAME);\n if (!bootstrapUser) {\n bootstrapUser = await this.createUser(\n {\n name: BOOTSTRAP_USER_NAME,\n role: 'user',\n collectionAccess: ['*'],\n environmentAccess: ['*'],\n snippetAccess: ['*']\n },\n systemUserId\n );\n }\n\n await this.query('UPDATE api_tokens SET user_id = $1 WHERE user_id IS NULL', [\n bootstrapUser.id\n ]);\n }\n\n /**\n * Inserts a new API token record.\n *\n * @param record - Token metadata to persist.\n * @param actingUserId - User performing the create action.\n */\n async createApiToken(record: ApiTokenRecord, actingUserId: string): Promise<void> {\n await this.query(\n `INSERT INTO api_tokens (\n id,\n user_id,\n name,\n token_hash,\n token_prefix,\n created_at,\n last_used_at,\n revoked_at,\n created_by_user_id,\n updated_by_user_id\n ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)`,\n [\n record.id,\n record.userId,\n record.name,\n record.tokenHash,\n record.tokenPrefix,\n record.createdAt,\n record.lastUsedAt,\n record.revokedAt,\n actingUserId,\n actingUserId\n ]\n );\n\n await this.recordAuditEntry(actingUserId, 'create', 'api_token', record.id);\n }\n\n /**\n * Finds an active token by its stored hash.\n *\n * @param tokenHash - sha256 hex digest of the bearer token secret.\n */\n async findActiveApiTokenByHash(tokenHash: string): Promise<ApiTokenRecord | null> {\n const result = await this.query<ApiTokenSqlRow>(\n `${API_TOKEN_SELECT}\n WHERE token_hash = $1\n AND revoked_at IS NULL\n AND user_id IS NOT NULL\n LIMIT 1`,\n [tokenHash]\n );\n\n const row = result.rows[0];\n return row ? mapApiTokenSqlRow(row) : null;\n }\n\n /**\n * Lists all API tokens ordered by creation time descending.\n */\n async listApiTokens(): Promise<ApiTokenRecord[]> {\n const result = await this.query<ApiTokenSqlRow>(\n `${API_TOKEN_SELECT}\n WHERE user_id IS NOT NULL\n ORDER BY created_at DESC`\n );\n\n return result.rows.map(mapApiTokenSqlRow);\n }\n\n /**\n * Returns API tokens owned by a specific user ordered newest-first.\n *\n * @param userId - Owning user identifier.\n */\n async listApiTokensByUserId(userId: string): Promise<ApiTokenRecord[]> {\n const result = await this.query<ApiTokenSqlRow>(\n `${API_TOKEN_SELECT}\n WHERE user_id = $1\n ORDER BY created_at DESC`,\n [userId]\n );\n\n return result.rows.map(mapApiTokenSqlRow);\n }\n\n /**\n * Finds an API token record by stable identifier.\n *\n * @param id - Token identifier to look up.\n */\n async findApiTokenById(id: string): Promise<ApiTokenRecord | null> {\n const result = await this.query<ApiTokenSqlRow>(`${API_TOKEN_SELECT} WHERE id = $1 LIMIT 1`, [\n id\n ]);\n const row = result.rows[0];\n return row ? mapApiTokenSqlRow(row) : null;\n }\n\n /**\n * Permanently removes an API token record by id.\n *\n * @param id - Token identifier to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteApiToken(id: string, actingUserId: string): Promise<boolean> {\n const result = await this.query('DELETE FROM api_tokens WHERE id = $1', [id]);\n const deleted = (result.rowCount ?? 0) > 0;\n if (deleted) {\n await this.recordAuditEntry(actingUserId, 'delete', 'api_token', id);\n }\n\n return deleted;\n }\n\n /**\n * Soft-revokes an active token by id.\n *\n * @param id - Token identifier to revoke.\n * @param actingUserId - User performing the revoke action.\n */\n async revokeApiToken(id: string, actingUserId: string): Promise<boolean> {\n const result = await this.query(\n `UPDATE api_tokens\n SET revoked_at = $2,\n updated_by_user_id = $3\n WHERE id = $1\n AND revoked_at IS NULL`,\n [id, new Date(), actingUserId]\n );\n\n const revoked = (result.rowCount ?? 0) > 0;\n if (revoked) {\n await this.recordAuditEntry(actingUserId, 'update', 'api_token', id);\n }\n\n return revoked;\n }\n\n /**\n * Updates the last-used timestamp for a token.\n *\n * @param id - Token identifier that authenticated a request.\n * @param when - Timestamp of the authenticated request.\n */\n async touchApiTokenLastUsed(id: string, when: Date): Promise<void> {\n await this.query(`UPDATE api_tokens SET last_used_at = $2 WHERE id = $1`, [id, when]);\n }\n\n /**\n * Lists all collections ordered by name.\n */\n async listCollections(): Promise<CollectionRecord[]> {\n const result = await this.query<CollectionSqlRow>(`${COLLECTION_SELECT} ORDER BY name ASC`);\n return result.rows.map(mapCollectionSqlRow);\n }\n\n /**\n * Creates a new collection with the given name.\n *\n * @param name - Display name for the collection.\n * @param actingUserId - User performing the create action.\n */\n async createCollection(name: string, actingUserId: string): Promise<CollectionRecord> {\n const trimmedName = trimRequiredName(name, 'Collection name');\n const id = randomUUID();\n const now = new Date();\n\n const result = await this.query<CollectionSqlRow>(\n `INSERT INTO collections (\n id,\n name,\n variables,\n headers,\n auth,\n pre_request_script,\n post_request_script,\n created_at,\n updated_at,\n created_by_user_id,\n updated_by_user_id\n ) VALUES ($1, $2, '[]', '[]', $3, '', '', $4, $5, $6, $7)\n RETURNING ${COLLECTION_SELECT_COLUMNS}`,\n [id, trimmedName, DEFAULT_AUTH_JSON, now, now, actingUserId, actingUserId]\n );\n\n const row = result.rows[0];\n if (!row) {\n throw new Error('Collection not found after insert');\n }\n\n await this.recordAuditEntry(actingUserId, 'create', 'collection', id);\n\n return mapCollectionSqlRow(row);\n }\n\n /**\n * Updates a collection's name, variables, headers, and scripts.\n *\n * @param actingUserId - User performing the update action.\n */\n async updateCollection(\n id: string,\n name: string,\n variables: Variable[],\n headers: KeyValue[],\n preRequestScript: string,\n postRequestScript: string,\n auth: AuthConfig,\n actingUserId: string\n ): Promise<CollectionRecord> {\n const trimmedName = trimRequiredName(name, 'Collection name');\n const updatedAt = new Date();\n const result = await this.query(\n `UPDATE collections\n SET name = $1,\n variables = $2,\n headers = $3,\n auth = $4,\n pre_request_script = $5,\n post_request_script = $6,\n updated_at = $7,\n updated_by_user_id = $8\n WHERE id = $9`,\n [\n trimmedName,\n JSON.stringify(variables),\n JSON.stringify(headers),\n JSON.stringify(auth),\n preRequestScript,\n postRequestScript,\n updatedAt,\n actingUserId,\n id\n ]\n );\n\n if ((result.rowCount ?? 0) === 0) {\n throw new Error('Collection not found');\n }\n\n await this.recordAuditEntry(actingUserId, 'update', 'collection', id);\n\n const selectResult = await this.query<CollectionSqlRow>(`${COLLECTION_SELECT} WHERE id = $1`, [\n id\n ]);\n const row = selectResult.rows[0];\n if (!row) {\n throw new Error('Collection not found');\n }\n\n return mapCollectionSqlRow(row);\n }\n\n /**\n * Deletes a collection and all of its requests and folders.\n *\n * @param id - Collection ID to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteCollection(id: string, actingUserId: string): Promise<void> {\n await this.recordAuditEntry(actingUserId, 'delete', 'collection', id);\n await this.query('DELETE FROM collections WHERE id = $1', [id]);\n }\n\n /**\n * Finds a collection by stable identifier.\n *\n * @param id - Collection ID to look up.\n */\n async findCollectionById(id: string): Promise<CollectionRecord | null> {\n const result = await this.query<CollectionSqlRow>(`${COLLECTION_SELECT} WHERE id = $1`, [id]);\n const row = result.rows[0];\n return row ? mapCollectionSqlRow(row) : null;\n }\n\n /**\n * Updates whether non-admin users may delete a collection.\n *\n * @param id - Collection ID to update.\n * @param deletionLocked - When true, user-role tokens cannot delete the collection.\n * @param actingUserId - Admin user performing the update.\n */\n async setCollectionDeletionLocked(\n id: string,\n deletionLocked: boolean,\n actingUserId: string\n ): Promise<CollectionRecord> {\n const updatedAt = new Date();\n const result = await this.query(\n `UPDATE collections\n SET deletion_locked = $1,\n updated_at = $2,\n updated_by_user_id = $3\n WHERE id = $4`,\n [deletionLocked, updatedAt, actingUserId, id]\n );\n\n if ((result.rowCount ?? 0) === 0) {\n throw new Error('Collection not found');\n }\n\n await this.recordAuditEntry(actingUserId, 'update', 'collection', id);\n\n const selectResult = await this.query<CollectionSqlRow>(`${COLLECTION_SELECT} WHERE id = $1`, [\n id\n ]);\n const row = selectResult.rows[0];\n if (!row) {\n throw new Error('Collection not found');\n }\n\n return mapCollectionSqlRow(row);\n }\n\n /**\n * Lists all environments ordered by name.\n */\n async listEnvironments(): Promise<EnvironmentRecord[]> {\n const result = await this.query<EnvironmentSqlRow>(`${ENVIRONMENT_SELECT} ORDER BY name ASC`);\n return result.rows.map(mapEnvironmentSqlRow);\n }\n\n /**\n * Creates a new environment with the given name.\n *\n * @param name - Display name for the environment.\n * @param actingUserId - User performing the create action.\n */\n async createEnvironment(name: string, actingUserId: string): Promise<EnvironmentRecord> {\n const trimmedName = trimRequiredName(name, 'Environment name');\n const id = randomUUID();\n const now = new Date();\n\n const result = await this.query<EnvironmentSqlRow>(\n `INSERT INTO environments (\n id,\n name,\n variables,\n created_at,\n updated_at,\n created_by_user_id,\n updated_by_user_id\n ) VALUES ($1, $2, '[]', $3, $4, $5, $6)\n RETURNING ${ENVIRONMENT_SELECT_COLUMNS}`,\n [id, trimmedName, now, now, actingUserId, actingUserId]\n );\n\n const row = result.rows[0];\n if (!row) {\n throw new Error('Environment not found after insert');\n }\n\n await this.recordAuditEntry(actingUserId, 'create', 'environment', id);\n\n return mapEnvironmentSqlRow(row);\n }\n\n /**\n * Updates an environment's name and variables.\n *\n * @param actingUserId - User performing the update action.\n */\n async updateEnvironment(\n id: string,\n name: string,\n variables: Variable[],\n actingUserId: string\n ): Promise<EnvironmentRecord> {\n const trimmedName = trimRequiredName(name, 'Environment name');\n const updatedAt = new Date();\n const result = await this.query(\n `UPDATE environments\n SET name = $1,\n variables = $2,\n updated_at = $3,\n updated_by_user_id = $4\n WHERE id = $5`,\n [trimmedName, JSON.stringify(variables), updatedAt, actingUserId, id]\n );\n\n if ((result.rowCount ?? 0) === 0) {\n throw new Error('Environment not found');\n }\n\n await this.recordAuditEntry(actingUserId, 'update', 'environment', id);\n\n const selectResult = await this.query<EnvironmentSqlRow>(\n `${ENVIRONMENT_SELECT} WHERE id = $1`,\n [id]\n );\n const row = selectResult.rows[0];\n if (!row) {\n throw new Error('Environment not found');\n }\n\n return mapEnvironmentSqlRow(row);\n }\n\n /**\n * Deletes an environment.\n *\n * @param id - Environment ID to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteEnvironment(id: string, actingUserId: string): Promise<void> {\n await this.recordAuditEntry(actingUserId, 'delete', 'environment', id);\n await this.query('DELETE FROM environments WHERE id = $1', [id]);\n }\n\n /**\n * Finds an environment by stable identifier.\n *\n * @param id - Environment ID to look up.\n */\n async findEnvironmentById(id: string): Promise<EnvironmentRecord | null> {\n const result = await this.query<EnvironmentSqlRow>(`${ENVIRONMENT_SELECT} WHERE id = $1`, [id]);\n const row = result.rows[0];\n return row ? mapEnvironmentSqlRow(row) : null;\n }\n\n /**\n * Updates whether non-admin users may delete an environment.\n *\n * @param id - Environment ID to update.\n * @param deletionLocked - When true, user-role tokens cannot delete the environment.\n * @param actingUserId - Admin user performing the update.\n */\n async setEnvironmentDeletionLocked(\n id: string,\n deletionLocked: boolean,\n actingUserId: string\n ): Promise<EnvironmentRecord> {\n const updatedAt = new Date();\n const result = await this.query(\n `UPDATE environments\n SET deletion_locked = $1,\n updated_at = $2,\n updated_by_user_id = $3\n WHERE id = $4`,\n [deletionLocked, updatedAt, actingUserId, id]\n );\n\n if ((result.rowCount ?? 0) === 0) {\n throw new Error('Environment not found');\n }\n\n await this.recordAuditEntry(actingUserId, 'update', 'environment', id);\n\n const selectResult = await this.query<EnvironmentSqlRow>(\n `${ENVIRONMENT_SELECT} WHERE id = $1`,\n [id]\n );\n const row = selectResult.rows[0];\n if (!row) {\n throw new Error('Environment not found');\n }\n\n return mapEnvironmentSqlRow(row);\n }\n\n /**\n * Lists all snippets ordered by sort order then name.\n */\n async listSnippets(): Promise<SnippetRecord[]> {\n const result = await this.query<SnippetSqlRow>(\n `${SNIPPET_SELECT} ORDER BY sort_order ASC, name ASC`\n );\n return result.rows.map(mapSnippetSqlRow);\n }\n\n /**\n * Creates a new snippet with the given fields.\n *\n * @param name - Display name for the snippet.\n * @param code - JavaScript source for the snippet.\n * @param scope - Execution scope for the snippet.\n * @param actingUserId - User performing the create action.\n */\n async createSnippet(\n name: string,\n code: string,\n scope: SnippetScope,\n actingUserId: string\n ): Promise<SnippetRecord> {\n const trimmedName = trimRequiredName(name, 'Snippet name');\n const id = randomUUID();\n const now = new Date();\n const maxResult = await this.query<{ max_order: number | null }>(\n 'SELECT COALESCE(MAX(sort_order), -1) AS max_order FROM snippets'\n );\n const maxOrder = maxResult.rows[0]?.max_order ?? -1;\n\n const result = await this.query<SnippetSqlRow>(\n `INSERT INTO snippets (\n id,\n name,\n code,\n scope,\n sort_order,\n created_at,\n updated_at,\n created_by_user_id,\n updated_by_user_id\n ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)\n RETURNING ${SNIPPET_SELECT_COLUMNS}`,\n [id, trimmedName, code, scope, maxOrder + 1, now, now, actingUserId, actingUserId]\n );\n\n const row = result.rows[0];\n if (!row) {\n throw new Error('Snippet not found after insert');\n }\n\n await this.recordAuditEntry(actingUserId, 'create', 'snippet', id);\n\n return mapSnippetSqlRow(row);\n }\n\n /**\n * Updates a snippet's name, code, and scope. Sort order is left unchanged.\n *\n * @param actingUserId - User performing the update action.\n */\n async updateSnippet(\n id: string,\n name: string,\n code: string,\n scope: SnippetScope,\n actingUserId: string\n ): Promise<SnippetRecord> {\n const trimmedName = trimRequiredName(name, 'Snippet name');\n const updatedAt = new Date();\n const result = await this.query(\n `UPDATE snippets\n SET name = $1,\n code = $2,\n scope = $3,\n updated_at = $4,\n updated_by_user_id = $5\n WHERE id = $6`,\n [trimmedName, code, scope, updatedAt, actingUserId, id]\n );\n\n if ((result.rowCount ?? 0) === 0) {\n throw new Error('Snippet not found');\n }\n\n await this.recordAuditEntry(actingUserId, 'update', 'snippet', id);\n\n const selectResult = await this.query<SnippetSqlRow>(`${SNIPPET_SELECT} WHERE id = $1`, [id]);\n const row = selectResult.rows[0];\n if (!row) {\n throw new Error('Snippet not found');\n }\n\n return mapSnippetSqlRow(row);\n }\n\n /**\n * Deletes a snippet.\n *\n * @param id - Snippet ID to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteSnippet(id: string, actingUserId: string): Promise<void> {\n await this.recordAuditEntry(actingUserId, 'delete', 'snippet', id);\n await this.query('DELETE FROM snippets WHERE id = $1', [id]);\n }\n\n /**\n * Finds a snippet by stable identifier.\n *\n * @param id - Snippet ID to look up.\n */\n async findSnippetById(id: string): Promise<SnippetRecord | null> {\n const result = await this.query<SnippetSqlRow>(`${SNIPPET_SELECT} WHERE id = $1`, [id]);\n const row = result.rows[0];\n return row ? mapSnippetSqlRow(row) : null;\n }\n\n /**\n * Updates whether non-admin users may delete a snippet.\n *\n * @param id - Snippet ID to update.\n * @param deletionLocked - When true, user-role tokens cannot delete the snippet.\n * @param actingUserId - Admin user performing the update.\n */\n async setSnippetDeletionLocked(\n id: string,\n deletionLocked: boolean,\n actingUserId: string\n ): Promise<SnippetRecord> {\n const updatedAt = new Date();\n const result = await this.query(\n `UPDATE snippets\n SET deletion_locked = $1,\n updated_at = $2,\n updated_by_user_id = $3\n WHERE id = $4`,\n [deletionLocked, updatedAt, actingUserId, id]\n );\n\n if ((result.rowCount ?? 0) === 0) {\n throw new Error('Snippet not found');\n }\n\n await this.recordAuditEntry(actingUserId, 'update', 'snippet', id);\n\n const selectResult = await this.query<SnippetSqlRow>(`${SNIPPET_SELECT} WHERE id = $1`, [id]);\n const row = selectResult.rows[0];\n if (!row) {\n throw new Error('Snippet not found');\n }\n\n return mapSnippetSqlRow(row);\n }\n\n /**\n * Lists all saved requests in a collection.\n *\n * @param collectionId - Collection to query.\n */\n async listRequests(collectionId: string): Promise<SavedRequestRecord[]> {\n const result = await this.query<RequestSqlRow>(\n `${REQUEST_SELECT} WHERE collection_id = $1 ORDER BY sort_order ASC, name ASC`,\n [collectionId]\n );\n return result.rows.map(mapRequestSqlRow);\n }\n\n /**\n * Finds a saved request by id.\n *\n * @param id - Request identifier to look up.\n */\n async findRequestById(id: string): Promise<SavedRequestRecord | null> {\n const result = await this.query<RequestSqlRow>(`${REQUEST_SELECT} WHERE id = $1 LIMIT 1`, [id]);\n const row = result.rows[0];\n return row ? mapRequestSqlRow(row) : null;\n }\n\n /**\n * Inserts a new request or updates an existing one.\n *\n * @param input - Request fields to persist.\n * @param actingUserId - User performing the save action.\n */\n async saveRequest(input: SaveRequestInput, actingUserId: string): Promise<SavedRequestRecord> {\n const trimmedName = trimRequiredName(input.name, 'Request name');\n const headers = JSON.stringify(input.headers);\n const params = JSON.stringify(input.params);\n const auth = JSON.stringify(input.auth);\n const folderId = input.folderId ?? null;\n const now = new Date();\n\n if (folderId != null) {\n const folderResult = await this.query<{ collection_id: string }>(\n 'SELECT collection_id FROM folders WHERE id = $1',\n [folderId]\n );\n const folderRow = folderResult.rows[0];\n if (!folderRow || folderRow.collection_id !== input.collectionId) {\n throw new Error('Folder not found');\n }\n }\n\n if (input.id) {\n const result = await this.query(\n `UPDATE requests SET\n collection_id = $1,\n folder_id = $2,\n name = $3,\n method = $4,\n url = $5,\n headers = $6,\n params = $7,\n auth = $8,\n body = $9,\n body_type = $10,\n pre_request_script = $11,\n post_request_script = $12,\n comment = $13,\n updated_at = $14,\n updated_by_user_id = $15\n WHERE id = $16`,\n [\n input.collectionId,\n folderId,\n trimmedName,\n input.method,\n input.url,\n headers,\n params,\n auth,\n input.body,\n input.bodyType,\n input.preRequestScript,\n input.postRequestScript,\n input.comment,\n now,\n actingUserId,\n input.id\n ]\n );\n\n if ((result.rowCount ?? 0) > 0) {\n await this.recordAuditEntry(actingUserId, 'update', 'request', input.id);\n\n const selectResult = await this.query<RequestSqlRow>(`${REQUEST_SELECT} WHERE id = $1`, [\n input.id\n ]);\n const row = selectResult.rows[0];\n if (row) {\n return mapRequestSqlRow(row);\n }\n }\n }\n\n const maxResult = await this.query<{ max_order: number | null }>(\n `SELECT COALESCE(MAX(sort_order), -1) AS max_order FROM requests\n WHERE collection_id = $1\n AND (($2::text IS NULL AND folder_id IS NULL) OR folder_id = $2)`,\n [input.collectionId, folderId]\n );\n const maxOrder = maxResult.rows[0]?.max_order ?? -1;\n const id = randomUUID();\n\n const result = await this.query<RequestSqlRow>(\n `INSERT INTO requests (\n id,\n collection_id,\n folder_id,\n name,\n method,\n url,\n headers,\n params,\n auth,\n body,\n body_type,\n pre_request_script,\n post_request_script,\n comment,\n sort_order,\n created_at,\n updated_at,\n created_by_user_id,\n updated_by_user_id\n ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19)\n RETURNING ${REQUEST_SELECT_COLUMNS}`,\n [\n id,\n input.collectionId,\n folderId,\n trimmedName,\n input.method,\n input.url,\n headers,\n params,\n auth,\n input.body,\n input.bodyType,\n input.preRequestScript,\n input.postRequestScript,\n input.comment,\n maxOrder + 1,\n now,\n now,\n actingUserId,\n actingUserId\n ]\n );\n\n const row = result.rows[0];\n if (!row) {\n throw new Error('Request not found after insert');\n }\n\n await this.recordAuditEntry(actingUserId, 'create', 'request', id);\n\n return mapRequestSqlRow(row);\n }\n\n /**\n * Deletes a saved request by ID.\n *\n * @param id - Request ID to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteRequest(id: string, actingUserId: string): Promise<void> {\n await this.recordAuditEntry(actingUserId, 'delete', 'request', id);\n await this.query('DELETE FROM requests WHERE id = $1', [id]);\n }\n\n /**\n * Lists all folders in a collection.\n *\n * @param collectionId - Collection to query.\n */\n async listFolders(collectionId: string): Promise<FolderRecord[]> {\n const result = await this.query<FolderSqlRow>(\n `${FOLDER_SELECT} WHERE collection_id = $1 ORDER BY sort_order ASC, name ASC`,\n [collectionId]\n );\n return result.rows.map(mapFolderSqlRow);\n }\n\n /**\n * Finds a folder by id.\n *\n * @param id - Folder identifier to look up.\n */\n async findFolderById(id: string): Promise<FolderRecord | null> {\n const result = await this.query<FolderSqlRow>(`${FOLDER_SELECT} WHERE id = $1 LIMIT 1`, [id]);\n const row = result.rows[0];\n return row ? mapFolderSqlRow(row) : null;\n }\n\n /**\n * Creates a new folder in a collection.\n *\n * @param collectionId - Collection to add the folder to.\n * @param name - Display name for the folder.\n * @param actingUserId - User performing the create action.\n */\n async createFolder(\n collectionId: string,\n name: string,\n actingUserId: string\n ): Promise<FolderRecord> {\n const trimmedName = trimRequiredName(name, 'Folder name');\n const id = randomUUID();\n const now = new Date();\n const maxResult = await this.query<{ max_order: number | null }>(\n 'SELECT COALESCE(MAX(sort_order), -1) AS max_order FROM folders WHERE collection_id = $1',\n [collectionId]\n );\n const maxOrder = maxResult.rows[0]?.max_order ?? -1;\n\n const result = await this.query<FolderSqlRow>(\n `INSERT INTO folders (\n id,\n collection_id,\n name,\n sort_order,\n created_at,\n updated_at,\n created_by_user_id,\n updated_by_user_id\n ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)\n RETURNING ${FOLDER_SELECT_COLUMNS}`,\n [id, collectionId, trimmedName, maxOrder + 1, now, now, actingUserId, actingUserId]\n );\n\n const row = result.rows[0];\n if (!row) {\n throw new Error('Folder not found after insert');\n }\n\n await this.recordAuditEntry(actingUserId, 'create', 'folder', id);\n\n return mapFolderSqlRow(row);\n }\n\n /**\n * Renames a folder.\n *\n * @param id - Folder ID to rename.\n * @param name - New display name.\n * @param actingUserId - User performing the rename action.\n */\n async renameFolder(id: string, name: string, actingUserId: string): Promise<FolderRecord> {\n const trimmedName = trimRequiredName(name, 'Folder name');\n const updatedAt = new Date();\n const result = await this.query<FolderSqlRow>(\n `UPDATE folders\n SET name = $1,\n updated_at = $2,\n updated_by_user_id = $3\n WHERE id = $4\n RETURNING ${FOLDER_SELECT_COLUMNS}`,\n [trimmedName, updatedAt, actingUserId, id]\n );\n const row = result.rows[0];\n if (!row) {\n throw new Error('Folder not found');\n }\n\n await this.recordAuditEntry(actingUserId, 'update', 'folder', id);\n\n return mapFolderSqlRow(row);\n }\n\n /**\n * Deletes a folder and all requests inside it.\n *\n * @param id - Folder ID to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteFolder(id: string, actingUserId: string): Promise<void> {\n await this.recordAuditEntry(actingUserId, 'delete', 'folder', id);\n\n const client = await this.requirePool().connect();\n try {\n await client.query('BEGIN');\n await client.query('DELETE FROM requests WHERE folder_id = $1', [id]);\n await client.query('DELETE FROM folders WHERE id = $1', [id]);\n await client.query('COMMIT');\n } catch (err) {\n await client.query('ROLLBACK');\n throw err;\n } finally {\n client.release();\n }\n }\n\n /**\n * Reorders folders within a collection.\n *\n * @param collectionId - Collection containing the folders.\n * @param orderedFolderIds - Folder IDs in desired order.\n * @param actingUserId - User performing the reorder action.\n */\n async reorderFolders(\n collectionId: string,\n orderedFolderIds: string[],\n actingUserId: string\n ): Promise<void> {\n const client = await this.requirePool().connect();\n const updatedAt = new Date();\n try {\n await client.query('BEGIN');\n for (let index = 0; index < orderedFolderIds.length; index++) {\n await client.query(\n `UPDATE folders\n SET sort_order = $1,\n updated_at = $2,\n updated_by_user_id = $3\n WHERE id = $4 AND collection_id = $5`,\n [index, updatedAt, actingUserId, orderedFolderIds[index], collectionId]\n );\n }\n await client.query('COMMIT');\n } catch (err) {\n await client.query('ROLLBACK');\n throw err;\n } finally {\n client.release();\n }\n\n await this.recordAuditEntry(actingUserId, 'reorder', 'folder', collectionId, {\n orderedFolderIds\n });\n }\n\n /**\n * Reorders requests within a folder or at collection root.\n *\n * @param actingUserId - User performing the reorder action.\n */\n async reorderRequests(\n collectionId: string,\n folderId: string | null,\n orderedRequestIds: string[],\n actingUserId: string\n ): Promise<void> {\n const client = await this.requirePool().connect();\n const updatedAt = new Date();\n try {\n await client.query('BEGIN');\n for (let index = 0; index < orderedRequestIds.length; index++) {\n await client.query(\n `UPDATE requests\n SET sort_order = $1,\n folder_id = $2,\n updated_at = $3,\n updated_by_user_id = $4\n WHERE id = $5 AND collection_id = $6`,\n [index, folderId, updatedAt, actingUserId, orderedRequestIds[index], collectionId]\n );\n }\n await client.query('COMMIT');\n } catch (err) {\n await client.query('ROLLBACK');\n throw err;\n } finally {\n client.release();\n }\n\n await this.recordAuditEntry(actingUserId, 'reorder', 'request', collectionId, {\n folderId,\n orderedRequestIds\n });\n }\n\n /**\n * Moves a request to another folder or collection root at a given index.\n *\n * @param actingUserId - User performing the move action.\n */\n async moveRequest(\n requestId: string,\n folderId: string | null,\n index: number,\n actingUserId: string\n ): Promise<void> {\n const client = await this.requirePool().connect();\n const updatedAt = new Date();\n\n /**\n * Lists request ids in a container ordered for reindexing.\n *\n * @param collectionId - Collection to query.\n * @param targetFolderId - Folder id or null for collection root.\n */\n const listInContainer = async (\n collectionId: string,\n targetFolderId: string | null\n ): Promise<string[]> => {\n const result = await client.query<{ id: string }>(\n `SELECT id FROM requests WHERE collection_id = $1\n AND (($2::text IS NULL AND folder_id IS NULL) OR folder_id = $2)\n ORDER BY sort_order ASC, name ASC`,\n [collectionId, targetFolderId]\n );\n return result.rows.map((row) => row.id);\n };\n\n /**\n * Rewrites sort_order and folder_id for a container's request list.\n *\n * @param targetFolderId - Folder id or null for collection root.\n * @param orderedIds - Request ids in desired order.\n */\n const reindexContainer = async (\n targetFolderId: string | null,\n orderedIds: string[]\n ): Promise<void> => {\n for (let sortIndex = 0; sortIndex < orderedIds.length; sortIndex++) {\n await client.query(\n `UPDATE requests\n SET sort_order = $1,\n folder_id = $2,\n updated_at = $3,\n updated_by_user_id = $4\n WHERE id = $5`,\n [sortIndex, targetFolderId, updatedAt, actingUserId, orderedIds[sortIndex]]\n );\n }\n };\n\n try {\n await client.query('BEGIN');\n\n const requestResult = await client.query<RequestSqlRow>(`${REQUEST_SELECT} WHERE id = $1`, [\n requestId\n ]);\n const requestRow = requestResult.rows[0];\n if (!requestRow) {\n throw new Error('Request not found');\n }\n\n const request = mapRequestSqlRow(requestRow);\n const collectionId = request.collectionId;\n const oldFolderId = request.folderId;\n\n if (folderId != null) {\n const folderResult = await client.query<{ collection_id: string }>(\n 'SELECT collection_id FROM folders WHERE id = $1',\n [folderId]\n );\n const folderRow = folderResult.rows[0];\n if (!folderRow || folderRow.collection_id !== collectionId) {\n throw new Error('Folder not found');\n }\n }\n\n if (oldFolderId === folderId) {\n const siblings = (await listInContainer(collectionId, folderId)).filter(\n (id) => id !== requestId\n );\n siblings.splice(index, 0, requestId);\n await reindexContainer(folderId, siblings);\n } else {\n const oldIds = (await listInContainer(collectionId, oldFolderId)).filter(\n (id) => id !== requestId\n );\n await reindexContainer(oldFolderId, oldIds);\n\n const newIds = (await listInContainer(collectionId, folderId)).filter(\n (id) => id !== requestId\n );\n newIds.splice(index, 0, requestId);\n await reindexContainer(folderId, newIds);\n }\n\n await client.query('COMMIT');\n } catch (err) {\n await client.query('ROLLBACK');\n throw err;\n } finally {\n client.release();\n }\n\n await this.recordAuditEntry(actingUserId, 'move', 'request', requestId, {\n folderId,\n index\n });\n }\n\n /**\n * Returns monthly LLM usage for a user, or null when no usage has been recorded.\n *\n * @param userId - Owning user identifier.\n * @param period - UTC calendar month key (`YYYY-MM`).\n */\n async getLlmUsage(userId: string, period: string): Promise<LlmUsageRecord | null> {\n const result = await this.query<LlmUsageSqlRow>(\n `${LLM_USAGE_SELECT} WHERE user_id = $1 AND period = $2 LIMIT 1`,\n [userId, period]\n );\n const row = result.rows[0];\n return row ? mapLlmUsageSqlRow(row) : null;\n }\n\n /**\n * Atomically increments monthly LLM token usage for a user.\n *\n * @param userId - Owning user identifier.\n * @param period - UTC calendar month key (`YYYY-MM`).\n * @param promptTokens - Prompt tokens to add.\n * @param completionTokens - Completion tokens to add.\n */\n async addLlmUsage(\n userId: string,\n period: string,\n promptTokens: number,\n completionTokens: number\n ): Promise<LlmUsageRecord> {\n const totalDelta = promptTokens + completionTokens;\n const now = new Date();\n const id = randomUUID();\n\n const result = await this.query<LlmUsageSqlRow>(\n `INSERT INTO llm_usage (\n id,\n user_id,\n period,\n prompt_tokens,\n completion_tokens,\n total_tokens,\n updated_at\n ) VALUES ($1, $2, $3, $4, $5, $6, $7)\n ON CONFLICT (user_id, period) DO UPDATE\n SET prompt_tokens = llm_usage.prompt_tokens + EXCLUDED.prompt_tokens,\n completion_tokens = llm_usage.completion_tokens + EXCLUDED.completion_tokens,\n total_tokens = llm_usage.total_tokens + EXCLUDED.total_tokens,\n updated_at = EXCLUDED.updated_at\n RETURNING ${LLM_USAGE_SELECT_COLUMNS}`,\n [id, userId, period, promptTokens, completionTokens, totalDelta, now]\n );\n\n const row = result.rows[0];\n if (!row) {\n throw new Error('LLM usage not found after upsert');\n }\n\n return mapLlmUsageSqlRow(row);\n }\n\n /**\n * Inserts a per-request LLM usage log entry.\n *\n * @param input - Usage details for one successful completion step.\n */\n async createLlmUsageLog(input: CreateLlmUsageLogInput): Promise<LlmUsageLogRecord> {\n const id = randomUUID();\n const now = new Date();\n\n const result = await this.query<LlmUsageLogSqlRow>(\n `INSERT INTO llm_usage_log (\n id,\n user_id,\n api_token_id,\n period,\n model,\n provider,\n prompt_tokens,\n completion_tokens,\n total_tokens,\n is_new_turn,\n had_tool_calls,\n message_count,\n created_at\n ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)\n RETURNING ${LLM_USAGE_LOG_SELECT_COLUMNS}`,\n [\n id,\n input.userId,\n input.apiTokenId,\n input.period,\n input.model,\n input.provider,\n input.promptTokens,\n input.completionTokens,\n input.totalTokens,\n input.isNewTurn,\n input.hadToolCalls,\n input.messageCount,\n now\n ]\n );\n\n const row = result.rows[0];\n if (!row) {\n throw new Error('LLM usage log not found after insert');\n }\n\n return mapLlmUsageLogSqlRow(row);\n }\n\n /**\n * Lists all per-request LLM usage log entries, newest first.\n */\n async listLlmUsageLogs(): Promise<LlmUsageLogRecord[]> {\n const result = await this.query<LlmUsageLogSqlRow>(\n `${LLM_USAGE_LOG_SELECT} ORDER BY created_at DESC`\n );\n\n return result.rows.map(mapLlmUsageLogSqlRow);\n }\n\n /**\n * Returns the active pool or throws when connect has not been called.\n *\n * @returns Connected Postgres pool.\n * @throws {Error} When the database is not connected.\n */\n private requirePool(): pg.Pool {\n if (!this.pool) {\n throw new Error('Postgres database is not connected.');\n }\n\n return this.pool;\n }\n\n /**\n * Ensures the internal system user exists and caches its identifier.\n *\n * Inserts directly rather than calling {@link createUser} to avoid recursion\n * during migration bootstrap.\n */\n private async ensureSystemUser(): Promise<void> {\n const existing = await this.findUserByName(SYSTEM_USER_NAME);\n if (existing) {\n this.systemUserId = existing.id;\n return;\n }\n\n const id = randomUUID();\n const now = new Date();\n const input = createSystemUserInput();\n\n await this.query(\n `INSERT INTO users (\n id,\n name,\n role,\n collection_access,\n environment_access,\n snippet_access,\n llm_access,\n llm_models,\n llm_monthly_token_limit,\n created_at,\n updated_at,\n created_by_user_id,\n updated_by_user_id\n ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)`,\n [\n id,\n SYSTEM_USER_NAME,\n input.role,\n serializeAccessList(input.collectionAccess),\n serializeAccessList(input.environmentAccess),\n serializeAccessList(input.snippetAccess),\n false,\n serializeAccessList([]),\n null,\n now,\n now,\n id,\n id\n ]\n );\n\n this.systemUserId = id;\n }\n\n /**\n * Persists a single audit log entry for a mutating action.\n *\n * @param actingUserId - User performing the action.\n * @param action - CRUD or structural action performed.\n * @param entityType - Kind of entity affected.\n * @param entityId - Identifier of the affected entity.\n * @param metadata - Optional structured context for the action.\n */\n private async recordAuditEntry(\n actingUserId: string,\n action: AuditAction,\n entityType: AuditEntityType,\n entityId: string,\n metadata?: Record<string, unknown> | null\n ): Promise<void> {\n const userName = await resolveActingUserName(\n (userId) => this.findUserById(userId),\n actingUserId\n );\n const id = randomUUID();\n const now = new Date();\n\n await this.query(\n `INSERT INTO audit_log (\n id,\n user_id,\n user_name,\n action,\n entity_type,\n entity_id,\n created_at,\n metadata\n ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`,\n [\n id,\n actingUserId,\n userName,\n action,\n entityType,\n entityId,\n now,\n serializeAuditMetadata(metadata ?? null)\n ]\n );\n }\n\n /**\n * Executes a parameterized SQL statement against the active pool.\n *\n * @param sql - SQL statement with $1-style placeholders.\n * @param params - Bound parameter values.\n * @returns Query result from pg.\n */\n private async query<T extends pg.QueryResultRow>(\n sql: string,\n params: unknown[] = []\n ): Promise<pg.QueryResult<T>> {\n return this.requirePool().query<T>(sql, params);\n }\n}\n","import { DEFAULT_AUTH_JSON } from '#/db/types.js';\n\n/**\n * DDL for creating the api_tokens table when absent.\n */\nexport const API_TOKENS_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS api_tokens (\n id TEXT PRIMARY KEY,\n user_id TEXT REFERENCES users(id) ON DELETE SET NULL,\n name TEXT NOT NULL,\n token_hash CHAR(64) NOT NULL UNIQUE,\n token_prefix TEXT NOT NULL,\n created_at TIMESTAMPTZ NOT NULL,\n last_used_at TIMESTAMPTZ,\n revoked_at TIMESTAMPTZ,\n created_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,\n updated_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL\n);\n`.trim();\n\n/**\n * DDL for creating the collections table when absent.\n */\nexport const COLLECTIONS_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS collections (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n variables TEXT NOT NULL DEFAULT '[]',\n headers TEXT NOT NULL DEFAULT '[]',\n auth TEXT NOT NULL DEFAULT '${DEFAULT_AUTH_JSON.replace(/'/g, \"''\")}',\n pre_request_script TEXT NOT NULL DEFAULT '',\n post_request_script TEXT NOT NULL DEFAULT '',\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL,\n created_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,\n updated_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL\n);\n`.trim();\n\n/**\n * DDL for creating the environments table when absent.\n */\nexport const ENVIRONMENTS_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS environments (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n variables TEXT NOT NULL DEFAULT '[]',\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL,\n created_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,\n updated_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL\n);\n`.trim();\n\n/**\n * DDL for creating the snippets table when absent.\n */\nexport const SNIPPETS_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS snippets (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n code TEXT NOT NULL DEFAULT '',\n scope TEXT NOT NULL DEFAULT 'any' CHECK (scope IN ('pre-request', 'post-request', 'any')),\n sort_order INT NOT NULL DEFAULT 0,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL,\n created_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,\n updated_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,\n deletion_locked BOOLEAN NOT NULL DEFAULT FALSE\n);\n`.trim();\n\n/**\n * DDL for creating the folders table when absent.\n */\nexport const FOLDERS_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS folders (\n id TEXT PRIMARY KEY,\n collection_id TEXT NOT NULL,\n name TEXT NOT NULL,\n sort_order INT NOT NULL DEFAULT 0,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL,\n created_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,\n updated_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,\n FOREIGN KEY (collection_id) REFERENCES collections(id) ON DELETE CASCADE\n);\n`.trim();\n\n/**\n * DDL for creating the requests table when absent.\n */\nexport const REQUESTS_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS requests (\n id TEXT PRIMARY KEY,\n collection_id TEXT NOT NULL,\n folder_id TEXT,\n name TEXT NOT NULL,\n method TEXT NOT NULL DEFAULT 'GET',\n url TEXT NOT NULL DEFAULT '',\n headers TEXT NOT NULL DEFAULT '[]',\n params TEXT NOT NULL DEFAULT '[]',\n auth TEXT NOT NULL DEFAULT '${DEFAULT_AUTH_JSON.replace(/'/g, \"''\")}',\n body TEXT NOT NULL DEFAULT '',\n body_type TEXT NOT NULL DEFAULT 'none',\n pre_request_script TEXT NOT NULL DEFAULT '',\n post_request_script TEXT NOT NULL DEFAULT '',\n comment TEXT NOT NULL DEFAULT '',\n sort_order INT NOT NULL DEFAULT 0,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL,\n created_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,\n updated_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,\n FOREIGN KEY (collection_id) REFERENCES collections(id) ON DELETE CASCADE,\n FOREIGN KEY (folder_id) REFERENCES folders(id) ON DELETE CASCADE\n);\n`.trim();\n\n/**\n * DDL for creating the users table when absent.\n */\nexport const USERS_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS users (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL UNIQUE,\n role TEXT NOT NULL CHECK (role IN ('admin', 'user')),\n collection_access TEXT NOT NULL DEFAULT '[]',\n environment_access TEXT NOT NULL DEFAULT '[]',\n snippet_access TEXT NOT NULL DEFAULT '[]',\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL,\n created_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,\n updated_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL\n);\n`.trim();\n\n/**\n * DDL for creating the audit_log table when absent.\n */\nexport const AUDIT_LOG_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS audit_log (\n id TEXT PRIMARY KEY,\n user_id TEXT,\n user_name TEXT,\n action TEXT NOT NULL,\n entity_type TEXT NOT NULL,\n entity_id TEXT NOT NULL,\n created_at TIMESTAMPTZ NOT NULL,\n metadata TEXT NOT NULL DEFAULT '{}'\n);\n`.trim();\n\n/**\n * Adds the owning user reference to api_tokens when upgrading existing databases.\n */\nexport const API_TOKENS_USER_ID_MIGRATION_SQL = `\nALTER TABLE api_tokens\n ADD COLUMN IF NOT EXISTS user_id TEXT REFERENCES users(id) ON DELETE SET NULL;\n`.trim();\n\n/**\n * Adds user attribution columns to api_tokens when upgrading existing databases.\n */\nexport const API_TOKENS_ATTRIBUTION_MIGRATION_SQL = `\nALTER TABLE api_tokens\n ADD COLUMN IF NOT EXISTS created_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,\n ADD COLUMN IF NOT EXISTS updated_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL;\n`.trim();\n\n/**\n * Adds user attribution and updated_at to collections when upgrading existing databases.\n */\nexport const COLLECTIONS_ATTRIBUTION_MIGRATION_SQL = `\nALTER TABLE collections\n ADD COLUMN IF NOT EXISTS updated_at TIMESTAMPTZ,\n ADD COLUMN IF NOT EXISTS created_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,\n ADD COLUMN IF NOT EXISTS updated_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL;\n`.trim();\n\n/**\n * Adds user attribution and updated_at to environments when upgrading existing databases.\n */\nexport const ENVIRONMENTS_ATTRIBUTION_MIGRATION_SQL = `\nALTER TABLE environments\n ADD COLUMN IF NOT EXISTS updated_at TIMESTAMPTZ,\n ADD COLUMN IF NOT EXISTS created_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,\n ADD COLUMN IF NOT EXISTS updated_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL;\n`.trim();\n\n/**\n * Adds user attribution and updated_at to folders when upgrading existing databases.\n */\nexport const FOLDERS_ATTRIBUTION_MIGRATION_SQL = `\nALTER TABLE folders\n ADD COLUMN IF NOT EXISTS updated_at TIMESTAMPTZ,\n ADD COLUMN IF NOT EXISTS created_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,\n ADD COLUMN IF NOT EXISTS updated_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL;\n`.trim();\n\n/**\n * Adds user attribution columns to requests when upgrading existing databases.\n */\nexport const REQUESTS_ATTRIBUTION_MIGRATION_SQL = `\nALTER TABLE requests\n ADD COLUMN IF NOT EXISTS created_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,\n ADD COLUMN IF NOT EXISTS updated_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL;\n`.trim();\n\n/**\n * Adds user attribution columns to users when upgrading existing databases.\n */\nexport const USERS_ATTRIBUTION_MIGRATION_SQL = `\nALTER TABLE users\n ADD COLUMN IF NOT EXISTS created_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,\n ADD COLUMN IF NOT EXISTS updated_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL;\n`.trim();\n\n/**\n * Backfills updated_at on collections from created_at for upgraded databases.\n */\nexport const COLLECTIONS_BACKFILL_UPDATED_AT_SQL = `\nUPDATE collections SET updated_at = created_at WHERE updated_at IS NULL;\n`.trim();\n\n/**\n * Backfills updated_at on environments from created_at for upgraded databases.\n */\nexport const ENVIRONMENTS_BACKFILL_UPDATED_AT_SQL = `\nUPDATE environments SET updated_at = created_at WHERE updated_at IS NULL;\n`.trim();\n\n/**\n * Backfills updated_at on folders from created_at for upgraded databases.\n */\nexport const FOLDERS_BACKFILL_UPDATED_AT_SQL = `\nUPDATE folders SET updated_at = created_at WHERE updated_at IS NULL;\n`.trim();\n\n/**\n * Adds LLM access columns to users when upgrading existing databases.\n */\nexport const USERS_LLM_MIGRATION_SQL = `\nALTER TABLE users\n ADD COLUMN IF NOT EXISTS llm_access BOOLEAN NOT NULL DEFAULT FALSE,\n ADD COLUMN IF NOT EXISTS llm_models TEXT NOT NULL DEFAULT '[]',\n ADD COLUMN IF NOT EXISTS llm_monthly_token_limit INT;\n`.trim();\n\n/**\n * DDL for creating the llm_usage table when absent.\n */\nexport const LLM_USAGE_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS llm_usage (\n id TEXT PRIMARY KEY,\n user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,\n period TEXT NOT NULL,\n prompt_tokens INT NOT NULL DEFAULT 0,\n completion_tokens INT NOT NULL DEFAULT 0,\n total_tokens INT NOT NULL DEFAULT 0,\n updated_at TIMESTAMPTZ NOT NULL,\n UNIQUE (user_id, period)\n);\n`.trim();\n\n/**\n * DDL for creating the llm_usage_log table when absent.\n */\nexport const LLM_USAGE_LOG_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS llm_usage_log (\n id TEXT PRIMARY KEY,\n user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,\n api_token_id TEXT REFERENCES api_tokens(id) ON DELETE SET NULL,\n period TEXT NOT NULL,\n model TEXT NOT NULL,\n provider TEXT NOT NULL,\n prompt_tokens INT NOT NULL,\n completion_tokens INT NOT NULL,\n total_tokens INT NOT NULL,\n is_new_turn BOOLEAN NOT NULL DEFAULT FALSE,\n had_tool_calls BOOLEAN NOT NULL DEFAULT FALSE,\n message_count INT NOT NULL,\n created_at TIMESTAMPTZ NOT NULL\n);\n\nCREATE INDEX IF NOT EXISTS llm_usage_log_user_created_at_idx ON llm_usage_log (user_id, created_at DESC);\n\nCREATE INDEX IF NOT EXISTS llm_usage_log_period_idx ON llm_usage_log (period);\n`.trim();\n\n/**\n * Adds deletion lock columns to collections when upgrading existing databases.\n */\nexport const COLLECTIONS_DELETION_LOCKED_MIGRATION_SQL = `\nALTER TABLE collections\n ADD COLUMN IF NOT EXISTS deletion_locked BOOLEAN NOT NULL DEFAULT FALSE;\n`.trim();\n\n/**\n * Adds deletion lock columns to environments when upgrading existing databases.\n */\nexport const ENVIRONMENTS_DELETION_LOCKED_MIGRATION_SQL = `\nALTER TABLE environments\n ADD COLUMN IF NOT EXISTS deletion_locked BOOLEAN NOT NULL DEFAULT FALSE;\n`.trim();\n\n/**\n * Adds snippet access column to users when upgrading existing databases.\n */\nexport const USERS_SNIPPET_ACCESS_MIGRATION_SQL = `\nALTER TABLE users\n ADD COLUMN IF NOT EXISTS snippet_access TEXT NOT NULL DEFAULT '[]';\n`.trim();\n\n/**\n * Adds snippet access for user accounts that have collection wildcard access but no snippet access.\n */\nexport const USERS_SNIPPET_ACCESS_BACKFILL_SQL = `\nUPDATE users\nSET snippet_access = '[\"*\"]'\nWHERE role = 'user'\n AND snippet_access = '[]'\n AND collection_access LIKE '%\"*\"%';\n`.trim();\n\n/**\n * Ordered Postgres migrations applied by {@link PostgresDatabase.migrate}.\n */\nexport const POSTGRES_MIGRATIONS = [\n USERS_MIGRATION_SQL,\n API_TOKENS_MIGRATION_SQL,\n COLLECTIONS_MIGRATION_SQL,\n ENVIRONMENTS_MIGRATION_SQL,\n SNIPPETS_MIGRATION_SQL,\n FOLDERS_MIGRATION_SQL,\n REQUESTS_MIGRATION_SQL,\n AUDIT_LOG_MIGRATION_SQL,\n API_TOKENS_USER_ID_MIGRATION_SQL,\n API_TOKENS_ATTRIBUTION_MIGRATION_SQL,\n COLLECTIONS_ATTRIBUTION_MIGRATION_SQL,\n ENVIRONMENTS_ATTRIBUTION_MIGRATION_SQL,\n FOLDERS_ATTRIBUTION_MIGRATION_SQL,\n REQUESTS_ATTRIBUTION_MIGRATION_SQL,\n USERS_ATTRIBUTION_MIGRATION_SQL,\n COLLECTIONS_BACKFILL_UPDATED_AT_SQL,\n ENVIRONMENTS_BACKFILL_UPDATED_AT_SQL,\n FOLDERS_BACKFILL_UPDATED_AT_SQL,\n USERS_LLM_MIGRATION_SQL,\n LLM_USAGE_MIGRATION_SQL,\n LLM_USAGE_LOG_MIGRATION_SQL,\n COLLECTIONS_DELETION_LOCKED_MIGRATION_SQL,\n ENVIRONMENTS_DELETION_LOCKED_MIGRATION_SQL,\n USERS_SNIPPET_ACCESS_MIGRATION_SQL,\n USERS_SNIPPET_ACCESS_BACKFILL_SQL\n];\n","import { z } from 'zod/v4';\n\n/**\n * Zod schema for validating Postgres port values from server.yaml.\n */\nexport const portSchema = z.union([\n z\n .number()\n .int({ message: 'Postgres port must be an integer between 1 and 65535.' })\n .min(1, { message: 'Postgres port must be an integer between 1 and 65535.' })\n .max(65535, { message: 'Postgres port must be an integer between 1 and 65535.' }),\n z\n .string()\n .regex(/^\\d+$/, { message: 'Postgres port must be an integer between 1 and 65535.' })\n .transform(Number)\n .pipe(\n z\n .number()\n .int({ message: 'Postgres port must be an integer between 1 and 65535.' })\n .min(1, { message: 'Postgres port must be an integer between 1 and 65535.' })\n .max(65535, { message: 'Postgres port must be an integer between 1 and 65535.' })\n )\n]);\n\n/**\n * Zod schema for validating raw Postgres database config from server.yaml.\n */\nexport const postgresConfigSchema = z.object({\n driver: z.literal('postgres'),\n host: z.string().trim().min(1, { message: 'Postgres host must not be empty.' }),\n port: portSchema,\n user: z.string().trim().min(1, { message: 'Postgres user must not be empty.' }),\n password: z.string(),\n database: z.string().trim().min(1, { message: 'Postgres database must not be empty.' })\n});\n","import type { IDatabase } from '#/db/IDatabase.js';\nimport { FirestoreDatabase } from '#/db/firestore/FirestoreDatabase.js';\nimport { MysqlDatabase } from '#/db/mysql/MysqlDatabase.js';\nimport { PostgresDatabase } from '#/db/postgres/PostgresDatabase.js';\n\n/**\n * Reads the `driver` field from a raw db config mapping.\n *\n * @param config - Raw `db` section from server.yaml.\n * @returns Driver name when present and a string.\n * @throws {Error} When config is not a mapping or driver is missing.\n */\nfunction readDriver(config: unknown): string {\n if (config === null || typeof config !== 'object' || Array.isArray(config)) {\n throw new Error('Database config must be a mapping.');\n }\n\n const driver = (config as Record<string, unknown>).driver;\n if (typeof driver !== 'string' || driver.trim().length === 0) {\n throw new Error('Database config must include a non-empty db.driver.');\n }\n\n return driver;\n}\n\n/**\n * Creates a database instance from the raw `db` section of server.yaml.\n *\n * Each driver validates its own required fields via {@link FirestoreDatabase.fromConfig},\n * {@link MysqlDatabase.fromConfig}, or {@link PostgresDatabase.fromConfig}.\n *\n * @param config - Raw `db` section from server.yaml.\n * @returns Configured database implementation for the requested driver.\n * @throws {Error} When the driver is unknown or driver-specific validation fails.\n */\nexport function createDatabase(config: unknown): IDatabase {\n const driver = readDriver(config);\n\n switch (driver) {\n case 'firestore':\n return FirestoreDatabase.fromConfig(config);\n case 'mysql':\n return MysqlDatabase.fromConfig(config);\n case 'postgres':\n return PostgresDatabase.fromConfig(config);\n default:\n throw new Error(\n `Unsupported database driver \"${driver}\". Expected \"firestore\", \"mysql\", or \"postgres\".`\n );\n }\n}\n","import { Command } from 'commander';\nimport { mergeGlobalOptions } from '#/cli/globalOptions.js';\nimport { loadServerConfig } from '#/config/serverConfig.js';\nimport { createDatabase } from '#/db/index.js';\nimport type { CollectionRecord } from '#/db/types.js';\n\nexport interface CollectionCommandOptions {\n /**\n * Path to the server YAML config file (from global `-c` / `--config`).\n */\n config: string;\n}\n\n/**\n * Formats a stored user id for CLI attribution output.\n *\n * @param userId - User id from a record's attribution field, or null when unset.\n * @param usersById - Lookup map from user id to display name.\n * @returns Display name with id, raw id, or a dash placeholder.\n */\nfunction formatAttributionUser(userId: string | null, usersById: Map<string, string>): string {\n if (!userId) {\n return '-';\n }\n\n const name = usersById.get(userId);\n if (!name) {\n return userId;\n }\n\n return `${name} (${userId})`;\n}\n\n/**\n * Prints a collection record for CLI listings.\n *\n * @param collection - Collection record to display.\n * @param usersById - Lookup map from user id to display name.\n * @param requestCount - Number of saved requests in the collection.\n */\nfunction printCollection(\n collection: CollectionRecord,\n usersById: Map<string, string>,\n requestCount: number\n): void {\n console.log(`- id: ${collection.id}`);\n console.log(` name: ${collection.name}`);\n console.log(` requests: ${requestCount}`);\n console.log(` created: ${collection.createdAt.toISOString()}`);\n console.log(` updated: ${collection.updatedAt.toISOString()}`);\n console.log(` created by: ${formatAttributionUser(collection.createdByUserId, usersById)}`);\n console.log(` updated by: ${formatAttributionUser(collection.updatedByUserId, usersById)}`);\n}\n\n/**\n * Lists stored collections.\n *\n * @param options - Parsed collection list options including config path.\n */\nexport async function collectionListCommand(options: CollectionCommandOptions): Promise<void> {\n const config = loadServerConfig(options.config);\n const db = createDatabase(config.db);\n\n await db.connect();\n const collections = await db.listCollections();\n const users = await db.listUsers();\n const requestCounts = await Promise.all(\n collections.map(async (collection) => {\n const requests = await db.listRequests(collection.id);\n return [collection.id, requests.length] as const;\n })\n );\n await db.disconnect();\n\n const usersById = new Map(users.map((user) => [user.id, user.name]));\n const requestCountByCollectionId = new Map(requestCounts);\n\n if (collections.length === 0) {\n console.log('No collections found.');\n return;\n }\n\n for (const collection of collections) {\n printCollection(collection, usersById, requestCountByCollectionId.get(collection.id) ?? 0);\n }\n}\n\n/**\n * Registers the `collection` command group on a Commander program.\n *\n * @param program - Root or parent Commander instance.\n * @param handlers - Injectable handlers for testing.\n */\nexport function registerCollectionCommand(\n program: Command,\n handlers: {\n list?: (options: CollectionCommandOptions) => Promise<void>;\n } = {}\n): void {\n const collection = program.command('collection').description('Inspect stored collections');\n\n collection\n .command('list')\n .description('List stored collections')\n .action(\n /**\n * Runs the collection list subcommand after merging global CLI options.\n */\n async function collectionListAction(this: Command, options: CollectionCommandOptions) {\n await (handlers.list ?? collectionListCommand)(mergeGlobalOptions(this, options));\n }\n );\n}\n","import { Command } from 'commander';\nimport { mergeGlobalOptions } from '#/cli/globalOptions.js';\nimport { loadServerConfig } from '#/config/serverConfig.js';\nimport { createDatabase } from '#/db/index.js';\nimport type { LlmUsageLogRecord } from '#/db/types.js';\n\nexport interface LlmCommandOptions {\n /**\n * Path to the server YAML config file (from global `-c` / `--config`).\n */\n config: string;\n}\n\n/**\n * Formats a stored user id for CLI attribution output.\n *\n * @param userId - User id from a usage log row.\n * @param usersById - Lookup map from user id to display name.\n * @returns Display name with id, raw id, or a dash placeholder.\n */\nfunction formatUserLabel(userId: string, usersById: Map<string, string>): string {\n const name = usersById.get(userId);\n if (!name) {\n return userId;\n }\n\n return `${name} (${userId})`;\n}\n\n/**\n * Formats an API token id for CLI output.\n *\n * @param apiTokenId - Token id from a usage log row, or null when unset.\n * @param tokensById - Lookup map from token id to display name.\n * @returns Token name with id, raw id, or a dash placeholder.\n */\nfunction formatApiTokenLabel(apiTokenId: string | null, tokensById: Map<string, string>): string {\n if (!apiTokenId) {\n return '-';\n }\n\n const name = tokensById.get(apiTokenId);\n if (!name) {\n return apiTokenId;\n }\n\n return `${name} (${apiTokenId})`;\n}\n\n/**\n * Prints one per-request LLM usage log entry.\n *\n * @param entry - Usage log record to display.\n * @param usersById - Lookup map from user id to display name.\n * @param tokensById - Lookup map from token id to display name.\n */\nfunction printLlmUsageLog(\n entry: LlmUsageLogRecord,\n usersById: Map<string, string>,\n tokensById: Map<string, string>\n): void {\n console.log(`- id: ${entry.id}`);\n console.log(` user: ${formatUserLabel(entry.userId, usersById)}`);\n console.log(` api token: ${formatApiTokenLabel(entry.apiTokenId, tokensById)}`);\n console.log(` period: ${entry.period}`);\n console.log(` model: ${entry.model}`);\n console.log(` provider: ${entry.provider}`);\n console.log(` prompt tokens: ${entry.promptTokens}`);\n console.log(` completion tokens: ${entry.completionTokens}`);\n console.log(` total tokens: ${entry.totalTokens}`);\n console.log(` new turn: ${entry.isNewTurn ? 'yes' : 'no'}`);\n console.log(` tool calls: ${entry.hadToolCalls ? 'yes' : 'no'}`);\n console.log(` messages: ${entry.messageCount}`);\n console.log(` created: ${entry.createdAt.toISOString()}`);\n}\n\n/**\n * Lists all per-request LLM usage log entries.\n *\n * @param options - Parsed LLM list options including config path.\n */\nexport async function llmListCommand(options: LlmCommandOptions): Promise<void> {\n const config = loadServerConfig(options.config);\n const db = createDatabase(config.db);\n\n await db.connect();\n const entries = await db.listLlmUsageLogs();\n const users = await db.listUsers();\n const tokens = await db.listApiTokens();\n await db.disconnect();\n\n if (entries.length === 0) {\n console.log('No LLM usage records found.');\n return;\n }\n\n const usersById = new Map(users.map((user) => [user.id, user.name]));\n const tokensById = new Map(tokens.map((token) => [token.id, token.name]));\n\n for (const entry of entries) {\n printLlmUsageLog(entry, usersById, tokensById);\n }\n}\n\n/**\n * Registers the `llm` command group on a Commander program.\n *\n * @param program - Root or parent Commander instance.\n * @param handlers - Injectable handlers for testing.\n */\nexport function registerLlmCommand(\n program: Command,\n handlers: {\n list?: (options: LlmCommandOptions) => Promise<void>;\n } = {}\n): void {\n const llm = program.command('llm').description('Inspect LLM usage records');\n\n llm\n .command('list')\n .description('List all per-request LLM usage log entries')\n .action(\n /**\n * Runs the LLM list subcommand after merging global CLI options.\n */\n async function llmListAction(this: Command, options: LlmCommandOptions) {\n await (handlers.list ?? llmListCommand)(mergeGlobalOptions(this, options));\n }\n );\n}\n","import { Command } from 'commander';\nimport { mergeGlobalOptions } from '#/cli/globalOptions.js';\nimport { loadServerConfig } from '#/config/serverConfig.js';\nimport { createDatabase } from '#/db/index.js';\n\nexport interface MigrateCommandOptions {\n /**\n * Path to the server YAML config file (from global `-c` / `--config`).\n */\n config: string;\n}\n\n/**\n * Runs database schema migrations for the configured backend.\n *\n * @param options - Parsed migrate command options including config path.\n */\nexport async function migrateCommand(options: MigrateCommandOptions): Promise<void> {\n const config = loadServerConfig(options.config);\n const db = createDatabase(config.db);\n\n await db.connect();\n await db.migrate();\n await db.disconnect();\n\n console.log('Database migration completed successfully.');\n}\n\n/**\n * Registers the `migrate` subcommand on a Commander program.\n *\n * @param program - Root or parent Commander instance.\n * @param handler - Action to run when `migrate` is invoked (defaults to {@link migrateCommand}).\n */\nexport function registerMigrateCommand(\n program: Command,\n handler: (options: MigrateCommandOptions) => Promise<void> = migrateCommand\n): void {\n program\n .command('migrate')\n .description('Apply database schema migrations')\n .action(\n /**\n * Runs the migrate subcommand after merging global CLI options.\n */\n async function migrateAction(this: Command, options: MigrateCommandOptions) {\n await handler(mergeGlobalOptions(this, options));\n }\n );\n}\n","import { Command, InvalidArgumentError } from 'commander';\nimport { mergeGlobalOptions } from '#/cli/globalOptions.js';\nimport { loadServerConfig } from '#/config/serverConfig.js';\nimport type { LlmConfig } from '#/config/llmConfig.js';\nimport { createDatabase } from '#/db/index.js';\nimport type { ApiTokenRecord, UpdateUserInput, UserRole } from '#/db/types.js';\nimport { generateApiToken } from '#/server/auth/apiTokens.js';\nimport {\n buildAccessCatalogIds,\n buildAccessListWarnings,\n normalizeAccessForRole,\n normalizeLlmForRole,\n ValidationError,\n validateSubmittedAccessLists\n} from '#/server/admin/userValidation.js';\nimport { currentUsagePeriod, listHubOfferedModels } from '#/server/llm/models.js';\nimport type { IDatabase } from '#/db/IDatabase.js';\n\n/**\n * Ensures schema migrations ran and returns the internal system user id for CLI actions.\n *\n * @param db - Connected database instance.\n * @returns Stable system user identifier.\n * @throws {Error} When the system user cannot be provisioned.\n */\nasync function requireSystemUserId(db: IDatabase): Promise<string> {\n await db.migrate();\n const systemUserId = db.getSystemUserId();\n if (!systemUserId) {\n throw new Error('System user is not provisioned.');\n }\n\n return systemUserId;\n}\n\nexport interface UserCommandOptions {\n /**\n * Path to the server YAML config file (from global `-c` / `--config`).\n */\n config: string;\n}\n\nexport interface UserCreateCommandOptions extends UserCommandOptions {\n /**\n * Unique display name for the new user account.\n */\n name: string;\n\n /**\n * Role assigned to the new account.\n */\n role: UserRole;\n\n /**\n * Collection ids or `*` granting collection access.\n */\n collectionAccess: string[];\n\n /**\n * Environment ids or `*` granting environment access.\n */\n environmentAccess: string[];\n\n /**\n * Snippet ids or `*` granting snippet access.\n */\n snippetAccess: string[];\n\n /**\n * Whether the user may use hub-proxied LLM routes.\n */\n llmAccess?: boolean;\n\n /**\n * LLM model ids or `*` granting model access.\n */\n llmModels?: string[];\n\n /**\n * Monthly LLM token limit, or undefined for unlimited.\n */\n llmMonthlyTokens?: number;\n}\n\nexport interface UserUpdateCommandOptions extends UserCommandOptions {\n /**\n * Identifier of the user to update.\n */\n id: string;\n\n /**\n * New display name, when changing the account label.\n */\n name?: string;\n\n /**\n * New role, when changing account capabilities.\n */\n role?: UserRole;\n\n /**\n * Replacement collection access list.\n */\n collectionAccess?: string[];\n\n /**\n * Replacement environment access list.\n */\n environmentAccess?: string[];\n\n /**\n * Replacement snippet access list.\n */\n snippetAccess?: string[];\n\n /**\n * Whether the user may use hub-proxied LLM routes.\n */\n llmAccess?: boolean;\n\n /**\n * Replacement LLM model access list.\n */\n llmModels?: string[];\n\n /**\n * Replacement monthly LLM token limit.\n */\n llmMonthlyTokens?: number;\n}\n\nexport interface UserTokenCreateCommandOptions extends UserCommandOptions {\n /**\n * Owning user identifier.\n */\n user: string;\n\n /**\n * Human-readable label for the new token.\n */\n name: string;\n}\n\nexport interface UserTokenListCommandOptions extends UserCommandOptions {\n /**\n * Optional user identifier limiting token output.\n */\n user?: string;\n}\n\nexport interface UserTokenRevokeCommandOptions extends UserCommandOptions {\n /**\n * Identifier of the token to revoke.\n */\n id: string;\n}\n\n/**\n * Formats a nullable date for CLI output.\n *\n * @param value - Date to format, or null when unset.\n * @returns ISO string or a dash placeholder.\n */\nfunction formatOptionalDate(value: Date | null): string {\n return value ? value.toISOString() : '-';\n}\n\n/**\n * Formats an access list for CLI output.\n *\n * @param access - Collection or environment access ids.\n * @returns Comma-separated list or a dash when empty.\n */\nfunction formatAccessList(access: string[]): string {\n return access.length > 0 ? access.join(', ') : '-';\n}\n\n/**\n * Parses and validates a user or token name from CLI input.\n *\n * @param value - Name string from a Commander option or argument.\n * @returns Trimmed non-empty name.\n * @throws {InvalidArgumentError} When the name is empty after trimming.\n */\nfunction parseRequiredName(value: string): string {\n const name = value.trim();\n if (!name) {\n throw new InvalidArgumentError('Name must not be empty.');\n }\n\n return name;\n}\n\n/**\n * Parses a user role from CLI input.\n *\n * @param value - Role string from a Commander option.\n * @returns Validated user role.\n * @throws {InvalidArgumentError} When the role is not supported.\n */\nfunction parseUserRole(value: string): UserRole {\n const role = value.trim();\n if (role === 'admin' || role === 'user') {\n return role;\n }\n\n throw new InvalidArgumentError('Role must be \"admin\" or \"user\".');\n}\n\n/**\n * Parses repeated access flags into a normalized access list.\n *\n * @param _value - Current flag value (unused; Commander passes prior values).\n * @param previous - Accumulated values from earlier `--flag` occurrences.\n * @returns Updated access list including the latest parsed entry.\n * @throws {InvalidArgumentError} When wildcard access is combined with ids.\n */\nfunction parseAccessFlag(_value: string, previous: string[]): string[] {\n const entry = _value.trim();\n if (!entry) {\n throw new InvalidArgumentError('Access entries must not be empty.');\n }\n\n const next = [...previous, entry];\n if (next.includes('*') && next.length > 1) {\n throw new InvalidArgumentError('Wildcard access \"*\" must be the only entry.');\n }\n\n return next;\n}\n\n/**\n * Reads LLM model access ids from parsed Commander create/update options.\n *\n * Commander maps `--llm-model` to the `llmModel` property rather than `llmModels`.\n *\n * @param options - Parsed options that may include either property name.\n */\nfunction readLlmModelsOption(options: { llmModels?: string[]; llmModel?: string[] }): string[] {\n return options.llmModels ?? options.llmModel ?? [];\n}\n\n/**\n * Parses a positive integer token limit from CLI input.\n *\n * @param value - Token limit string from a Commander option.\n * @returns Parsed positive integer limit.\n * @throws {InvalidArgumentError} When the value is not a positive integer.\n */\nfunction parseMonthlyTokenLimit(value: string): number {\n const parsed = Number(value.trim());\n if (!Number.isInteger(parsed) || parsed <= 0) {\n throw new InvalidArgumentError('Monthly token limit must be a positive integer.');\n }\n\n return parsed;\n}\n\n/**\n * Optional monthly LLM usage fields for CLI user listings.\n */\ninterface UserDisplayUsage {\n /**\n * UTC calendar month key (`YYYY-MM`) for the usage total.\n */\n llmUsagePeriod: string;\n\n /**\n * Total tokens consumed during {@link UserDisplayUsage.llmUsagePeriod}.\n */\n llmTokensUsed: number;\n}\n\n/**\n * Prints a user record for CLI listings.\n *\n * @param user - User record to display.\n * @param usage - Current-month LLM usage when listing or showing users.\n */\nfunction printUser(\n user: {\n id: string;\n name: string;\n role: UserRole;\n collectionAccess: string[];\n environmentAccess: string[];\n snippetAccess: string[];\n llmAccess: boolean;\n llmModels: string[];\n llmMonthlyTokenLimit: number | null;\n createdAt: Date;\n updatedAt: Date;\n },\n usage?: UserDisplayUsage\n): void {\n console.log(`- id: ${user.id}`);\n console.log(` name: ${user.name}`);\n console.log(` role: ${user.role}`);\n console.log(` collection access: ${formatAccessList(user.collectionAccess)}`);\n console.log(` environment access: ${formatAccessList(user.environmentAccess)}`);\n console.log(` snippet access: ${formatAccessList(user.snippetAccess)}`);\n console.log(` llm access: ${user.llmAccess ? 'enabled' : 'disabled'}`);\n console.log(` llm models: ${formatAccessList(user.llmModels)}`);\n console.log(\n ` llm monthly tokens: ${user.llmMonthlyTokenLimit != null ? user.llmMonthlyTokenLimit : 'unlimited'}`\n );\n if (usage) {\n console.log(` llm tokens used (${usage.llmUsagePeriod}): ${usage.llmTokensUsed}`);\n }\n console.log(` created: ${user.createdAt.toISOString()}`);\n console.log(` updated: ${user.updatedAt.toISOString()}`);\n}\n\n/**\n * Prints a newly created API token and its one-time secret for CLI output.\n *\n * @param user - Owning user account.\n * @param record - Persisted token metadata (hash only).\n * @param secret - Plaintext bearer token shown once at creation.\n */\nfunction printCreatedApiToken(\n user: { name: string },\n record: ApiTokenRecord,\n secret: string\n): void {\n console.log(`Created API token \"${record.name}\" (${record.id}) for user \"${user.name}\".`);\n console.log(`Token prefix: ${record.tokenPrefix}`);\n console.log('');\n console.log('Store this token now; it will not be shown again:');\n console.log(secret);\n}\n\n/**\n * Loads hub resource catalogs used to validate and warn on access lists.\n *\n * @param db - Connected database instance.\n * @param llm - Normalized LLM config from server.yaml, or null when unset.\n * @returns Known collection, environment, and LLM model ids.\n */\nasync function loadAccessCatalogs(db: IDatabase, llm: LlmConfig | null) {\n const [collections, environments, snippets] = await Promise.all([\n db.listCollections(),\n db.listEnvironments(),\n db.listSnippets()\n ]);\n\n return buildAccessCatalogIds(\n collections,\n environments,\n snippets,\n llm ? listHubOfferedModels(llm).map((model) => model.id) : null\n );\n}\n\n/**\n * Runs a validation helper and maps {@link ValidationError} to Commander errors.\n *\n * @param fn - Validation or normalization function from the server admin module.\n * @returns The value returned by {@link fn}.\n * @throws {InvalidArgumentError} When {@link fn} throws {@link ValidationError}.\n */\nfunction mapValidationError<T>(fn: () => T): T {\n try {\n return fn();\n } catch (error) {\n if (error instanceof ValidationError) {\n throw new InvalidArgumentError(error.message);\n }\n\n throw error;\n }\n}\n\n/**\n * Validates submitted access lists and maps server validation errors to CLI errors.\n *\n * @param submitted - Access fields provided on the CLI command.\n * @param catalogs - Known collection, environment, and LLM model ids.\n * @throws {InvalidArgumentError} When a submitted list references unknown ids.\n */\nfunction validateSubmittedAccessListsOrThrow(\n submitted: Parameters<typeof validateSubmittedAccessLists>[0],\n catalogs: Parameters<typeof validateSubmittedAccessLists>[1]\n): void {\n mapValidationError(() => validateSubmittedAccessLists(submitted, catalogs));\n}\n\n/**\n * Prints stale access list warnings to stderr without changing stdout listings.\n *\n * @param warnings - Human-readable warnings for unknown access ids.\n */\nfunction printAccessListWarnings(warnings: string[]): void {\n for (const warning of warnings) {\n console.warn(`Warning: ${warning}`);\n }\n}\n\n/**\n * Creates a new user account.\n *\n * @param options - Parsed user create options.\n */\nexport async function userCreateCommand(options: UserCreateCommandOptions): Promise<void> {\n const config = loadServerConfig(options.config);\n const db = createDatabase(config.db);\n const access = mapValidationError(() =>\n normalizeAccessForRole(\n options.role,\n options.collectionAccess,\n options.environmentAccess,\n options.snippetAccess\n )\n );\n\n await db.connect();\n const actingUserId = await requireSystemUserId(db);\n const catalogs = await loadAccessCatalogs(db, config.llm);\n const llmModels = readLlmModelsOption(options);\n const llm = mapValidationError(() =>\n normalizeLlmForRole(options.role, options.llmAccess ?? false, llmModels)\n );\n validateSubmittedAccessListsOrThrow(\n {\n role: options.role,\n collectionAccess: access.collectionAccess,\n environmentAccess: access.environmentAccess,\n snippetAccess: access.snippetAccess,\n llmModels\n },\n catalogs\n );\n\n const user = await db.createUser(\n {\n name: options.name,\n role: options.role,\n collectionAccess: access.collectionAccess ?? [],\n environmentAccess: access.environmentAccess ?? [],\n snippetAccess: access.snippetAccess ?? [],\n llmAccess: llm.llmAccess,\n llmModels: llm.llmModels,\n llmMonthlyTokenLimit: options.llmMonthlyTokens ?? null\n },\n actingUserId\n );\n const { record, secret } = generateApiToken(user.id, user.name);\n await db.createApiToken(record, actingUserId);\n await db.disconnect();\n\n console.log(`Created user \"${user.name}\" (${user.id}) with role ${user.role}.`);\n printUser(user);\n console.log('');\n printCreatedApiToken(user, record, secret);\n}\n\n/**\n * Lists stored user accounts.\n *\n * @param options - Parsed user list options including config path.\n */\nexport async function userListCommand(options: UserCommandOptions): Promise<void> {\n const config = loadServerConfig(options.config);\n const db = createDatabase(config.db);\n\n await db.connect();\n const [users, catalogs] = await Promise.all([db.listUsers(), loadAccessCatalogs(db, config.llm)]);\n const period = currentUsagePeriod();\n const tokensUsedByUser = await Promise.all(\n users.map(async (user) => {\n const usage = await db.getLlmUsage(user.id, period);\n return usage?.totalTokens ?? 0;\n })\n );\n await db.disconnect();\n\n if (users.length === 0) {\n console.log('No users found.');\n return;\n }\n\n for (const [index, user] of users.entries()) {\n printAccessListWarnings(\n buildAccessListWarnings(\n {\n collectionAccess: user.collectionAccess,\n environmentAccess: user.environmentAccess,\n snippetAccess: user.snippetAccess,\n llmModels: user.llmModels\n },\n catalogs\n )\n );\n printUser(user, { llmUsagePeriod: period, llmTokensUsed: tokensUsedByUser[index] ?? 0 });\n }\n}\n\n/**\n * Shows a single user account by id.\n *\n * @param options - Parsed user show options including user id.\n */\nexport async function userShowCommand(options: UserUpdateCommandOptions): Promise<void> {\n const config = loadServerConfig(options.config);\n const db = createDatabase(config.db);\n\n await db.connect();\n const [user, catalogs] = await Promise.all([\n db.findUserById(options.id),\n loadAccessCatalogs(db, config.llm)\n ]);\n\n if (!user) {\n await db.disconnect();\n console.log(`No user found with id ${options.id}.`);\n return;\n }\n\n const period = currentUsagePeriod();\n const usage = await db.getLlmUsage(user.id, period);\n await db.disconnect();\n\n printAccessListWarnings(\n buildAccessListWarnings(\n {\n collectionAccess: user.collectionAccess,\n environmentAccess: user.environmentAccess,\n snippetAccess: user.snippetAccess,\n llmModels: user.llmModels\n },\n catalogs\n )\n );\n printUser(user, { llmUsagePeriod: period, llmTokensUsed: usage?.totalTokens ?? 0 });\n}\n\n/**\n * Updates an existing user account.\n *\n * @param options - Parsed user update options.\n */\nexport async function userUpdateCommand(options: UserUpdateCommandOptions): Promise<void> {\n const config = loadServerConfig(options.config);\n const db = createDatabase(config.db);\n\n await db.connect();\n const actingUserId = await requireSystemUserId(db);\n const existing = await db.findUserById(options.id);\n if (!existing) {\n await db.disconnect();\n console.log(`No user found with id ${options.id}.`);\n return;\n }\n\n const role = options.role ?? existing.role;\n const collectionAccess =\n options.collectionAccess ?? (options.role === 'admin' ? [] : existing.collectionAccess);\n const environmentAccess =\n options.environmentAccess ?? (options.role === 'admin' ? [] : existing.environmentAccess);\n const snippetAccess =\n options.snippetAccess ?? (options.role === 'admin' ? [] : existing.snippetAccess);\n const access = mapValidationError(() =>\n normalizeAccessForRole(role, collectionAccess, environmentAccess, snippetAccess)\n );\n const llmAccess = role === 'admin' ? false : (options.llmAccess ?? existing.llmAccess);\n const llmModels = role === 'admin' ? [] : (options.llmModels ?? existing.llmModels);\n const llm = mapValidationError(() => normalizeLlmForRole(role, llmAccess, llmModels));\n const catalogs = await loadAccessCatalogs(db, config.llm);\n validateSubmittedAccessListsOrThrow(\n {\n role,\n collectionAccess: options.collectionAccess,\n environmentAccess: options.environmentAccess,\n snippetAccess: options.snippetAccess,\n llmModels: options.llmModels\n },\n catalogs\n );\n\n const input: UpdateUserInput = {\n name: options.name,\n role: options.role,\n collectionAccess: access.collectionAccess,\n environmentAccess: access.environmentAccess,\n snippetAccess: access.snippetAccess,\n llmAccess: llm.llmAccess,\n llmModels: llm.llmModels,\n llmMonthlyTokenLimit:\n options.llmMonthlyTokens !== undefined ? options.llmMonthlyTokens : undefined\n };\n\n const user = await db.updateUser(options.id, input, actingUserId);\n await db.disconnect();\n\n console.log(`Updated user \"${user.name}\" (${user.id}).`);\n}\n\n/**\n * Deletes a user account and revokes their tokens.\n *\n * @param options - Parsed user delete options including user id.\n */\nexport async function userDeleteCommand(options: UserUpdateCommandOptions): Promise<void> {\n const config = loadServerConfig(options.config);\n const db = createDatabase(config.db);\n\n await db.connect();\n const actingUserId = await requireSystemUserId(db);\n const existing = await db.findUserById(options.id);\n if (!existing) {\n await db.disconnect();\n console.log(`No user found with id ${options.id}.`);\n return;\n }\n\n await db.deleteUser(options.id, actingUserId);\n await db.disconnect();\n\n console.log(`Deleted user \"${existing.name}\" (${existing.id}).`);\n}\n\n/**\n * Creates a new API token for a user-role account.\n *\n * @param options - Parsed token create options.\n */\nexport async function userTokenCreateCommand(\n options: UserTokenCreateCommandOptions\n): Promise<void> {\n const config = loadServerConfig(options.config);\n const db = createDatabase(config.db);\n\n await db.connect();\n const actingUserId = await requireSystemUserId(db);\n const user = await db.findUserById(options.user);\n if (!user) {\n await db.disconnect();\n throw new Error(`No user found with id ${options.user}.`);\n }\n\n const { record, secret } = generateApiToken(user.id, options.name);\n await db.createApiToken(record, actingUserId);\n await db.disconnect();\n\n printCreatedApiToken(user, record, secret);\n}\n\n/**\n * Lists stored API tokens, optionally filtered by user.\n *\n * @param options - Parsed token list options.\n */\nexport async function userTokenListCommand(options: UserTokenListCommandOptions): Promise<void> {\n const config = loadServerConfig(options.config);\n const db = createDatabase(config.db);\n\n await db.connect();\n const tokens = options.user\n ? await db.listApiTokensByUserId(options.user)\n : await db.listApiTokens();\n await db.disconnect();\n\n if (tokens.length === 0) {\n console.log('No API tokens found.');\n return;\n }\n\n for (const token of tokens) {\n console.log(`- id: ${token.id}`);\n console.log(` user id: ${token.userId}`);\n console.log(` name: ${token.name}`);\n console.log(` prefix: ${token.tokenPrefix}`);\n console.log(` created: ${formatOptionalDate(token.createdAt)}`);\n console.log(` last used: ${formatOptionalDate(token.lastUsedAt)}`);\n console.log(` revoked: ${formatOptionalDate(token.revokedAt)}`);\n }\n}\n\n/**\n * Soft-revokes an API token by id.\n *\n * @param options - Parsed token revoke options including token id.\n */\nexport async function userTokenRevokeCommand(\n options: UserTokenRevokeCommandOptions\n): Promise<void> {\n const config = loadServerConfig(options.config);\n const db = createDatabase(config.db);\n\n await db.connect();\n const actingUserId = await requireSystemUserId(db);\n const revoked = await db.revokeApiToken(options.id, actingUserId);\n await db.disconnect();\n\n if (revoked) {\n console.log(`Revoked API token ${options.id}.`);\n return;\n }\n\n console.log(`No active API token found with id ${options.id}.`);\n}\n\n/**\n * Registers the `user` command group on a Commander program.\n *\n * @param program - Root or parent Commander instance.\n * @param handlers - Injectable handlers for testing.\n */\nexport function registerUserCommand(\n program: Command,\n handlers: {\n create?: (options: UserCreateCommandOptions) => Promise<void>;\n list?: (options: UserCommandOptions) => Promise<void>;\n show?: (options: UserUpdateCommandOptions) => Promise<void>;\n update?: (options: UserUpdateCommandOptions) => Promise<void>;\n delete?: (options: UserUpdateCommandOptions) => Promise<void>;\n tokenCreate?: (options: UserTokenCreateCommandOptions) => Promise<void>;\n tokenList?: (options: UserTokenListCommandOptions) => Promise<void>;\n tokenRevoke?: (options: UserTokenRevokeCommandOptions) => Promise<void>;\n } = {}\n): void {\n const user = program.command('user').description('Manage user accounts and their API tokens');\n\n user\n .command('create')\n .description('Create a new user account')\n .requiredOption('--name <name>', 'Unique display name', parseRequiredName)\n .requiredOption('--role <role>', 'Account role (admin or user)', parseUserRole)\n .option(\n '--collection-access <id>',\n 'Collection id or * (repeatable)',\n parseAccessFlag,\n [] as string[]\n )\n .option(\n '--environment-access <id>',\n 'Environment id or * (repeatable)',\n parseAccessFlag,\n [] as string[]\n )\n .option(\n '--snippet-access <id>',\n 'Snippet id or * (repeatable)',\n parseAccessFlag,\n [] as string[]\n )\n .option('--llm-access', 'Enable hub-proxied LLM access for the user')\n .option('--llm-model <id>', 'LLM model id or * (repeatable)', parseAccessFlag, [] as string[])\n .option('--llm-monthly-tokens <count>', 'Monthly LLM token limit', parseMonthlyTokenLimit)\n .action(\n /**\n * Runs the user create subcommand after merging global CLI options.\n */\n async function userCreateAction(this: Command, options: UserCreateCommandOptions) {\n await (handlers.create ?? userCreateCommand)(mergeGlobalOptions(this, options));\n }\n );\n\n user\n .command('list')\n .description('List stored user accounts')\n .action(\n /**\n * Runs the user list subcommand after merging global CLI options.\n */\n async function userListAction(this: Command, options: UserCommandOptions) {\n await (handlers.list ?? userListCommand)(mergeGlobalOptions(this, options));\n }\n );\n\n user\n .command('show')\n .description('Show a user account by id')\n .argument('<id>', 'User identifier')\n .action(\n /**\n * Runs the user show subcommand after merging global CLI options.\n */\n async function userShowAction(this: Command, id: string, options: UserCommandOptions) {\n await (handlers.show ?? userShowCommand)(mergeGlobalOptions(this, { ...options, id }));\n }\n );\n\n user\n .command('update')\n .description('Update a user account')\n .argument('<id>', 'User identifier')\n .option('--name <name>', 'New display name', parseRequiredName)\n .option('--role <role>', 'New role (admin or user)', parseUserRole)\n .option(\n '--collection-access <id>',\n 'Replacement collection id or * (repeatable)',\n parseAccessFlag,\n [] as string[]\n )\n .option(\n '--environment-access <id>',\n 'Replacement environment id or * (repeatable)',\n parseAccessFlag,\n [] as string[]\n )\n .option(\n '--snippet-access <id>',\n 'Replacement snippet id or * (repeatable)',\n parseAccessFlag,\n [] as string[]\n )\n .option('--llm-access', 'Enable hub-proxied LLM access for the user')\n .option('--no-llm-access', 'Disable hub-proxied LLM access for the user')\n .option(\n '--llm-model <id>',\n 'Replacement LLM model id or * (repeatable)',\n parseAccessFlag,\n [] as string[]\n )\n .option('--llm-monthly-tokens <count>', 'Monthly LLM token limit', parseMonthlyTokenLimit)\n .action(\n /**\n * Runs the user update subcommand after merging global CLI options.\n */\n async function userUpdateAction(\n this: Command,\n id: string,\n options: UserUpdateCommandOptions\n ) {\n const merged = mergeGlobalOptions(this, { ...options, id });\n const input: UserUpdateCommandOptions = {\n ...merged,\n collectionAccess:\n (options.collectionAccess ?? []).length > 0 ? options.collectionAccess : undefined,\n environmentAccess:\n (options.environmentAccess ?? []).length > 0 ? options.environmentAccess : undefined,\n snippetAccess:\n (options.snippetAccess ?? []).length > 0 ? options.snippetAccess : undefined,\n llmModels: (() => {\n const llmModels = readLlmModelsOption(options);\n return llmModels.length > 0 ? llmModels : undefined;\n })()\n };\n await (handlers.update ?? userUpdateCommand)(input);\n }\n );\n\n user\n .command('delete')\n .description('Delete a user account and revoke their tokens')\n .argument('<id>', 'User identifier')\n .action(\n /**\n * Runs the user delete subcommand after merging global CLI options.\n */\n async function userDeleteAction(this: Command, id: string, options: UserCommandOptions) {\n await (handlers.delete ?? userDeleteCommand)(mergeGlobalOptions(this, { ...options, id }));\n }\n );\n\n const token = user.command('token').description('Manage API bearer tokens for user accounts');\n\n token\n .command('create')\n .description('Create a new API bearer token for a user')\n .requiredOption('--user <userId>', 'Owning user identifier')\n .requiredOption('--name <name>', 'Human-readable token label', parseRequiredName)\n .action(\n /**\n * Runs the user token create subcommand after merging global CLI options.\n */\n async function userTokenCreateAction(this: Command, options: UserTokenCreateCommandOptions) {\n await (handlers.tokenCreate ?? userTokenCreateCommand)(mergeGlobalOptions(this, options));\n }\n );\n\n token\n .command('list')\n .description('List stored API bearer tokens')\n .option('--user <userId>', 'Limit output to a single user')\n .action(\n /**\n * Runs the user token list subcommand after merging global CLI options.\n */\n async function userTokenListAction(this: Command, options: UserTokenListCommandOptions) {\n await (handlers.tokenList ?? userTokenListCommand)(mergeGlobalOptions(this, options));\n }\n );\n\n token\n .command('revoke')\n .description('Revoke an API bearer token by id')\n .argument('<id>', 'Token identifier to revoke')\n .action(\n /**\n * Runs the user token revoke subcommand after merging global CLI options.\n */\n async function userTokenRevokeAction(this: Command, id: string, options: UserCommandOptions) {\n await (handlers.tokenRevoke ?? userTokenRevokeCommand)(\n mergeGlobalOptions(this, { ...options, id })\n );\n }\n );\n}\n","import { createHash, randomBytes, randomUUID } from 'node:crypto';\nimport type { ApiTokenRecord } from '#/db/types.js';\n\n/**\n * Prefix applied to generated bearer token secrets and display prefixes.\n */\nconst TOKEN_PREFIX = 'hbk_';\n\n/**\n * Computes the sha256 hex digest used for database lookup of a bearer token.\n *\n * @param token - Raw bearer token secret from the Authorization header.\n * @returns Lowercase hex digest suitable for storage and lookup.\n */\nexport function hashToken(token: string): string {\n return createHash('sha256').update(token).digest('hex');\n}\n\n/**\n * Generates a new API token record and its one-time plaintext secret.\n *\n * @param userId - Owning user account identifier.\n * @param name - Human-readable label for operator listings.\n * @returns Persistable record (hash only) and the secret shown once at creation.\n */\nexport function generateApiToken(\n userId: string,\n name: string\n): { record: ApiTokenRecord; secret: string } {\n const secretSuffix = randomBytes(32).toString('base64url');\n const secret = `${TOKEN_PREFIX}${secretSuffix}`;\n const tokenPrefix = `${TOKEN_PREFIX}${secretSuffix.slice(0, 8)}`;\n const createdAt = new Date();\n\n const record: ApiTokenRecord = {\n id: randomUUID(),\n userId,\n name,\n tokenHash: hashToken(secret),\n tokenPrefix,\n createdAt,\n lastUsedAt: null,\n revokedAt: null,\n createdByUserId: null,\n updatedByUserId: null\n };\n\n return { record, secret };\n}\n\n/**\n * Extracts the bearer token value from an Authorization header.\n *\n * @param headerValue - Raw Authorization header value, if present.\n * @returns Token string after the `Bearer` scheme, or null when missing or malformed.\n */\nexport function extractBearer(headerValue?: string): string | null {\n if (!headerValue) {\n return null;\n }\n\n const match = /^Bearer\\s+(\\S+)$/i.exec(headerValue.trim());\n return match?.[1] ?? null;\n}\n","import type { CreateUserInput, UpdateUserInput, UserRole } from '#/db/types.js';\n\n/**\n * Error thrown when admin user update input fails validation.\n */\nexport class ValidationError extends Error {\n /**\n * Creates a validation error with a client-facing message.\n *\n * @param message - Description of the invalid input.\n */\n constructor(message: string) {\n super(message);\n this.name = 'ValidationError';\n }\n}\n\n/**\n * Returns true when an access list mixes the wildcard with specific ids.\n *\n * @param access - Collection, environment, snippet, or LLM model access ids.\n * @returns True when the list is invalid.\n */\nexport function hasInvalidWildcardAccess(access: string[]): boolean {\n return access.includes('*') && access.length > 1;\n}\n\n/**\n * Validates a single access list for wildcard usage.\n *\n * @param access - Collection, environment, snippet, or LLM model access ids.\n * @throws {ValidationError} When wildcard access is combined with specific ids.\n */\nexport function validateAccessList(access: string[]): void {\n if (hasInvalidWildcardAccess(access)) {\n throw new ValidationError('Wildcard access \"*\" must be the only entry.');\n }\n}\n\n/**\n * Normalizes LLM access for admin accounts and validates model access lists.\n *\n * @param role - Target user role.\n * @param llmAccess - Parsed LLM access flag.\n * @param llmModels - Parsed LLM model access ids.\n * @returns LLM fields suitable for persistence.\n * @throws {ValidationError} When admins receive LLM access or lists are invalid.\n */\nexport function normalizeLlmForRole(\n role: UserRole,\n llmAccess: boolean,\n llmModels: string[]\n): Pick<UpdateUserInput, 'llmAccess' | 'llmModels'> {\n if (role === 'admin') {\n if (llmAccess || llmModels.length > 0) {\n throw new ValidationError('Admin users cannot have LLM access.');\n }\n\n return {\n llmAccess: false,\n llmModels: []\n };\n }\n\n validateAccessList(llmModels);\n\n return {\n llmAccess,\n llmModels\n };\n}\n\n/**\n * Normalizes access lists for admin accounts and validates wildcard usage.\n *\n * @param role - Target user role.\n * @param collectionAccess - Parsed collection access ids.\n * @param environmentAccess - Parsed environment access ids.\n * @param snippetAccess - Parsed snippet access ids.\n * @returns Access lists suitable for persistence.\n * @throws {ValidationError} When admins receive access flags or lists are invalid.\n */\nexport function normalizeAccessForRole(\n role: UserRole,\n collectionAccess: string[],\n environmentAccess: string[],\n snippetAccess: string[]\n): Pick<UpdateUserInput, 'collectionAccess' | 'environmentAccess' | 'snippetAccess'> {\n if (role === 'admin') {\n if (collectionAccess.length > 0 || environmentAccess.length > 0 || snippetAccess.length > 0) {\n throw new ValidationError(\n 'Admin users cannot have collection, environment, or snippet access.'\n );\n }\n\n return {\n collectionAccess: [],\n environmentAccess: [],\n snippetAccess: []\n };\n }\n\n validateAccessList(collectionAccess);\n validateAccessList(environmentAccess);\n validateAccessList(snippetAccess);\n\n return {\n collectionAccess,\n environmentAccess,\n snippetAccess\n };\n}\n\n/**\n * Known resource ids used to validate or warn on access lists.\n */\nexport interface AccessCatalogIds {\n /**\n * Collection ids currently stored on the hub.\n */\n knownCollectionIds: ReadonlySet<string>;\n\n /**\n * Environment ids currently stored on the hub.\n */\n knownEnvironmentIds: ReadonlySet<string>;\n\n /**\n * Snippet ids currently stored on the hub.\n */\n knownSnippetIds: ReadonlySet<string>;\n\n /**\n * Hub-offered LLM model ids, or null when LLM support is not configured.\n */\n knownLlmModelIds: ReadonlySet<string> | null;\n}\n\n/**\n * Access list fields explicitly submitted in a create or update request.\n */\nexport interface SubmittedAccessLists {\n /**\n * Resulting user role after the update is applied.\n */\n role: UserRole;\n\n /**\n * Collection access ids from the request body or CLI flags, when provided.\n */\n collectionAccess?: string[];\n\n /**\n * Environment access ids from the request body or CLI flags, when provided.\n */\n environmentAccess?: string[];\n\n /**\n * Snippet access ids from the request body or CLI flags, when provided.\n */\n snippetAccess?: string[];\n\n /**\n * LLM model access ids from the request body or CLI flags, when provided.\n */\n llmModels?: string[];\n}\n\n/**\n * Stored access lists on a user record checked for stale references.\n */\nexport interface StoredAccessLists {\n /**\n * Persisted collection access ids.\n */\n collectionAccess: string[];\n\n /**\n * Persisted environment access ids.\n */\n environmentAccess: string[];\n\n /**\n * Persisted snippet access ids.\n */\n snippetAccess: string[];\n\n /**\n * Persisted LLM model access ids.\n */\n llmModels: string[];\n}\n\n/**\n * Returns ids from an access list that are not the wildcard and not in knownIds.\n *\n * @param access - Collection, environment, snippet, or LLM model access ids.\n * @param knownIds - Valid resource ids from the hub catalog.\n * @returns Unknown ids excluding the wildcard entry.\n */\nexport function findUnknownAccessIds(access: string[], knownIds: ReadonlySet<string>): string[] {\n return access.filter((id) => id !== '*' && !knownIds.has(id));\n}\n\n/**\n * Validates that every specific id in an access list exists in the catalog.\n *\n * @param access - Collection, environment, snippet, or LLM model access ids.\n * @param knownIds - Valid resource ids from the hub catalog.\n * @param resourceLabel - Singular resource label for error messages.\n * @throws {ValidationError} When one or more ids are unknown.\n */\nexport function validateKnownAccessIds(\n access: string[],\n knownIds: ReadonlySet<string>,\n resourceLabel: 'collection' | 'environment' | 'snippet' | 'LLM model'\n): void {\n const unknownIds = findUnknownAccessIds(access, knownIds);\n if (unknownIds.length === 0) {\n return;\n }\n\n const label = unknownIds.length === 1 ? `${resourceLabel} id` : `${resourceLabel} id(s)`;\n throw new ValidationError(`Unknown ${label}: ${unknownIds.join(', ')}.`);\n}\n\n/**\n * Validates explicitly submitted access lists against hub resource catalogs.\n *\n * @param submitted - Access fields provided in the request or CLI flags.\n * @param catalogs - Known collection, environment, snippet, and LLM model ids.\n * @throws {ValidationError} When a submitted list references unknown ids.\n */\nexport function validateSubmittedAccessLists(\n submitted: SubmittedAccessLists,\n catalogs: AccessCatalogIds\n): void {\n if (submitted.role !== 'admin') {\n if (submitted.collectionAccess !== undefined) {\n validateKnownAccessIds(submitted.collectionAccess, catalogs.knownCollectionIds, 'collection');\n }\n\n if (submitted.environmentAccess !== undefined) {\n validateKnownAccessIds(\n submitted.environmentAccess,\n catalogs.knownEnvironmentIds,\n 'environment'\n );\n }\n\n if (submitted.snippetAccess !== undefined) {\n validateKnownAccessIds(submitted.snippetAccess, catalogs.knownSnippetIds, 'snippet');\n }\n }\n\n if (submitted.llmModels !== undefined && catalogs.knownLlmModelIds !== null) {\n validateKnownAccessIds(submitted.llmModels, catalogs.knownLlmModelIds, 'LLM model');\n }\n}\n\n/**\n * Builds warning messages for stored access lists that reference missing resources.\n *\n * @param stored - Persisted access lists on a user record.\n * @param catalogs - Known collection, environment, snippet, and LLM model ids.\n * @returns Human-readable warnings for stale access references.\n */\nexport function buildAccessListWarnings(\n stored: StoredAccessLists,\n catalogs: AccessCatalogIds\n): string[] {\n const warnings: string[] = [];\n\n for (const id of findUnknownAccessIds(stored.collectionAccess, catalogs.knownCollectionIds)) {\n warnings.push(`Unknown collection id \"${id}\".`);\n }\n\n for (const id of findUnknownAccessIds(stored.environmentAccess, catalogs.knownEnvironmentIds)) {\n warnings.push(`Unknown environment id \"${id}\".`);\n }\n\n for (const id of findUnknownAccessIds(stored.snippetAccess, catalogs.knownSnippetIds)) {\n warnings.push(`Unknown snippet id \"${id}\".`);\n }\n\n if (catalogs.knownLlmModelIds !== null) {\n for (const id of findUnknownAccessIds(stored.llmModels, catalogs.knownLlmModelIds)) {\n warnings.push(`Unknown LLM model id \"${id}\".`);\n }\n }\n\n return warnings;\n}\n\n/**\n * Builds {@link AccessCatalogIds} from hub collection, environment, snippet, and model listings.\n *\n * @param collections - Collections returned by the database layer.\n * @param environments - Environments returned by the database layer.\n * @param snippets - Snippets returned by the database layer.\n * @param llmModelIds - Hub-offered LLM model ids, or null when LLM is not configured.\n * @returns Catalog id sets for validation and warnings.\n */\nexport function buildAccessCatalogIds(\n collections: ReadonlyArray<{ id: string }>,\n environments: ReadonlyArray<{ id: string }>,\n snippets: ReadonlyArray<{ id: string }>,\n llmModelIds: string[] | null\n): AccessCatalogIds {\n return {\n knownCollectionIds: new Set(collections.map((collection) => collection.id)),\n knownEnvironmentIds: new Set(environments.map((environment) => environment.id)),\n knownSnippetIds: new Set(snippets.map((snippet) => snippet.id)),\n knownLlmModelIds: llmModelIds === null ? null : new Set(llmModelIds)\n };\n}\n\n/**\n * Builds the update payload applied to an existing user record.\n *\n * @param existing - Current user record from the database.\n * @param body - Partial fields from the management API request body.\n * @returns Normalized update input for {@link IDatabase.updateUser}.\n * @throws {ValidationError} When access lists are invalid for the resulting role.\n */\nexport function buildAdminUserUpdateInput(\n existing: {\n name: string;\n role: UserRole;\n collectionAccess: string[];\n environmentAccess: string[];\n snippetAccess: string[];\n llmAccess: boolean;\n llmModels: string[];\n llmMonthlyTokenLimit: number | null;\n },\n body: {\n name?: string;\n role?: UserRole;\n collectionAccess?: string[];\n environmentAccess?: string[];\n snippetAccess?: string[];\n llmAccess?: boolean;\n llmModels?: string[];\n llmMonthlyTokenLimit?: number | null;\n }\n): UpdateUserInput {\n const role = body.role ?? existing.role;\n const collectionAccess =\n role === 'admin' ? [] : (body.collectionAccess ?? existing.collectionAccess);\n const environmentAccess =\n role === 'admin' ? [] : (body.environmentAccess ?? existing.environmentAccess);\n const snippetAccess = role === 'admin' ? [] : (body.snippetAccess ?? existing.snippetAccess);\n const access = normalizeAccessForRole(role, collectionAccess, environmentAccess, snippetAccess);\n const llmAccess = role === 'admin' ? false : (body.llmAccess ?? existing.llmAccess);\n const llmModels = role === 'admin' ? [] : (body.llmModels ?? existing.llmModels);\n const llm = normalizeLlmForRole(role, llmAccess, llmModels);\n\n return {\n name: body.name,\n role: body.role,\n collectionAccess: access.collectionAccess,\n environmentAccess: access.environmentAccess,\n snippetAccess: access.snippetAccess,\n llmAccess: llm.llmAccess,\n llmModels: llm.llmModels,\n llmMonthlyTokenLimit: body.llmMonthlyTokenLimit\n };\n}\n\n/**\n * Builds the create payload for a new user account.\n *\n * @param body - Fields from the management API create request body.\n * @returns Normalized create input for {@link IDatabase.createUser}.\n * @throws {ValidationError} When access lists are invalid for the role.\n */\nexport function buildAdminUserCreateInput(body: {\n name: string;\n role: UserRole;\n collectionAccess?: string[];\n environmentAccess?: string[];\n snippetAccess?: string[];\n llmAccess?: boolean;\n llmModels?: string[];\n llmMonthlyTokenLimit?: number | null;\n}): CreateUserInput {\n const collectionAccess = body.collectionAccess ?? [];\n const environmentAccess = body.environmentAccess ?? [];\n const snippetAccess = body.snippetAccess ?? [];\n const access = normalizeAccessForRole(\n body.role,\n collectionAccess,\n environmentAccess,\n snippetAccess\n );\n const llmAccess = body.role === 'admin' ? false : (body.llmAccess ?? false);\n const llmModels = body.role === 'admin' ? [] : (body.llmModels ?? []);\n const llm = normalizeLlmForRole(body.role, llmAccess, llmModels);\n\n return {\n name: body.name,\n role: body.role,\n collectionAccess: access.collectionAccess ?? [],\n environmentAccess: access.environmentAccess ?? [],\n snippetAccess: access.snippetAccess ?? [],\n llmAccess: llm.llmAccess ?? false,\n llmModels: llm.llmModels ?? [],\n llmMonthlyTokenLimit: body.llmMonthlyTokenLimit ?? null\n };\n}\n","import type { LlmConfig, LlmProvider } from '#/config/llmConfig.js';\n\n/**\n * Catalog entry for a hub-offered LLM model.\n */\nexport interface LlmModelCatalogEntry {\n /**\n * Provider-specific model id sent to the API.\n */\n id: string;\n\n /**\n * Human-readable label for listings.\n */\n label: string;\n\n /**\n * LLM provider that owns this model.\n */\n provider: LlmProvider;\n}\n\n/**\n * Full catalog of models Team Hub can offer when a provider key is configured.\n */\nexport const LLM_MODEL_CATALOG: LlmModelCatalogEntry[] = [\n { id: 'gpt-4o', label: 'GPT-4o', provider: 'openai' },\n { id: 'gpt-4o-mini', label: 'GPT-4o Mini', provider: 'openai' },\n { id: 'claude-3-5-sonnet-20241022', label: 'Claude 3.5 Sonnet', provider: 'claude' },\n { id: 'claude-3-5-haiku-20241022', label: 'Claude 3.5 Haiku', provider: 'claude' },\n { id: 'gemini-1.5-pro', label: 'Gemini 1.5 Pro', provider: 'gemini' },\n { id: 'gemini-1.5-flash', label: 'Gemini 1.5 Flash', provider: 'gemini' }\n];\n\n/**\n * Returns whether a provider has a configured API key on the hub.\n *\n * @param config - Normalized LLM config from server.yaml.\n * @param provider - Provider to check.\n */\nfunction hasProviderKey(config: LlmConfig, provider: LlmProvider): boolean {\n return Boolean(config.providers[provider]?.apiKey.trim());\n}\n\n/**\n * Returns catalog models the hub offers based on configured keys and optional allow-list.\n *\n * @param config - Normalized LLM config from server.yaml.\n */\nexport function listHubOfferedModels(config: LlmConfig): LlmModelCatalogEntry[] {\n const allowList = config.models ? new Set(config.models) : null;\n\n return LLM_MODEL_CATALOG.filter((model) => {\n if (!hasProviderKey(config, model.provider)) {\n return false;\n }\n\n if (allowList && !allowList.has(model.id)) {\n return false;\n }\n\n return true;\n });\n}\n\n/**\n * Looks up a catalog model by id.\n *\n * @param modelId - Provider-specific model id.\n */\nexport function getHubModelById(modelId: string): LlmModelCatalogEntry | undefined {\n return LLM_MODEL_CATALOG.find((model) => model.id === modelId);\n}\n\n/**\n * Returns true when the hub is configured to offer the given model id.\n *\n * @param config - Normalized LLM config from server.yaml.\n * @param modelId - Provider-specific model id.\n */\nexport function isHubModelOffered(config: LlmConfig, modelId: string): boolean {\n return listHubOfferedModels(config).some((model) => model.id === modelId);\n}\n\n/**\n * Returns the current UTC usage period key (`YYYY-MM`).\n *\n * @param now - Reference time; defaults to the current instant.\n */\nexport function currentUsagePeriod(now: Date = new Date()): string {\n const year = now.getUTCFullYear();\n const month = String(now.getUTCMonth() + 1).padStart(2, '0');\n return `${year}-${month}`;\n}\n","import Fastify, { type FastifyInstance } from 'fastify';\nimport {\n serializerCompiler,\n validatorCompiler,\n type ZodTypeProvider\n} from 'fastify-type-provider-zod';\nimport { DEFAULT_LOGGING_CONFIG } from '#/config/loggingConfig.js';\nimport type { IDatabase } from '#/db/IDatabase.js';\nimport type { IThrottleStore } from '#/server/auth/throttle/IThrottleStore.js';\nimport { registerHttpLogging } from '#/server/logging/httpLogging.js';\nimport { createLogger, type Logger } from '#/server/logging/logger.js';\nimport { readPackageVersion } from '#/packageVersion.js';\nimport { registerRoutes } from '#/server/routes/index.js';\nimport type { ReloadResult, RuntimeContext } from '#/server/runtimeContext.js';\n\nexport interface CreateServerOptions {\n /**\n * When true, enables Fastify's built-in request logger.\n */\n verbose?: boolean;\n\n /**\n * Package version exposed on the health endpoint (defaults to package.json).\n */\n version?: string;\n\n /**\n * Database used for bearer token validation on protected routes.\n */\n db?: IDatabase;\n\n /**\n * Redis-backed store for authentication throttling on protected routes.\n */\n throttleStore?: IThrottleStore;\n\n /**\n * Reloads server.yaml and returns a per-section report.\n */\n reloadConfig?: () => Promise<ReloadResult>;\n\n /**\n * Winston logger for HTTP request and error logging; defaults from config.\n */\n logger?: Logger;\n}\n\n/**\n * Builds a configured Fastify instance with Zod validation and registered routes.\n *\n * Does not call `listen`; use {@link runServer} or test inject for that.\n *\n * When a {@link RuntimeContext} is supplied, its stable db and throttle proxies are\n * wired automatically. Explicit `db` and `throttleStore` options override those defaults\n * for tests.\n *\n * @param ctxOrConfig - Runtime context, or legacy server config object for tests.\n * @param options - Logger, version, and optional dependency overrides.\n * @returns Fastify app with type provider and routes attached.\n */\nexport async function createServer(\n ctxOrConfig: RuntimeContext | import('#/config/serverConfig.js').ServerConfig,\n options: CreateServerOptions = {}\n): Promise<FastifyInstance> {\n const isRuntimeContext = 'getLlm' in ctxOrConfig && 'configPath' in ctxOrConfig;\n const ctx = isRuntimeContext ? (ctxOrConfig as RuntimeContext) : null;\n const legacyConfig = isRuntimeContext\n ? null\n : (ctxOrConfig as import('#/config/serverConfig.js').ServerConfig);\n\n const db = options.db ?? ctx?.db;\n const throttleStore = options.throttleStore ?? ctx?.throttleStore;\n\n if (!db || !throttleStore) {\n throw new Error('createServer requires db and throttleStore.');\n }\n\n const logger =\n options.logger ?? ctx?.logger ?? createLogger(legacyConfig?.logging ?? DEFAULT_LOGGING_CONFIG);\n\n const app = Fastify({\n logger: options.verbose ?? false\n }).withTypeProvider<ZodTypeProvider>();\n\n app.setValidatorCompiler(validatorCompiler);\n app.setSerializerCompiler(serializerCompiler);\n\n registerHttpLogging(app, logger);\n\n await registerRoutes(app, {\n version: options.version ?? readPackageVersion(),\n db,\n throttleStore,\n getLlm: ctx ? () => ctx.getLlm() : () => legacyConfig?.llm ?? null,\n getPlugins: ctx ? () => ctx.getPlugins() : () => legacyConfig?.plugins ?? null,\n reloadConfig: options.reloadConfig ?? (async () => ({ sections: [] }))\n });\n\n return app;\n}\n","import type { FastifyInstance } from 'fastify';\nimport type { Logger } from '#/server/logging/logger.js';\n\n/**\n * Registers HTTP request and error logging hooks on a Fastify instance.\n *\n * Logs every incoming request at debug level and logs unhandled request errors\n * at error level without altering response handling.\n *\n * @param app - Fastify server to attach hooks to.\n * @param logger - Winston logger configured from server.yaml.\n */\nexport function registerHttpLogging(app: FastifyInstance, logger: Logger): void {\n app.addHook('onRequest', async (request) => {\n logger.debug('request', {\n reqId: request.id,\n method: request.method,\n url: request.url,\n ip: request.ip\n });\n });\n\n app.addHook('onError', async (request, reply, error) => {\n logger.error('request error', {\n reqId: request.id,\n method: request.method,\n url: request.url,\n statusCode: reply.statusCode,\n message: error.message,\n stack: error.stack\n });\n });\n}\n","import winston from 'winston';\nimport type { LoggingConfig } from '#/config/loggingConfig.js';\n\n/**\n * Winston logger instance used by the Team Hub server.\n */\nexport type Logger = winston.Logger;\n\n/**\n * Builds a Winston logger from normalized logging configuration.\n *\n * Uses standard npm log levels. When both file and console output are disabled,\n * attaches a silent console transport so Winston does not warn about zero transports.\n *\n * @param config - Normalized logging settings from server.yaml.\n * @returns Configured Winston logger.\n */\nexport function createLogger(config: LoggingConfig): Logger {\n const transports: winston.transport[] = [];\n\n if (config.console) {\n transports.push(new winston.transports.Console());\n }\n\n if (config.file) {\n transports.push(new winston.transports.File({ filename: config.file }));\n }\n\n if (transports.length === 0) {\n transports.push(new winston.transports.Console({ silent: true }));\n }\n\n return winston.createLogger({\n level: config.level,\n format: winston.format.combine(winston.format.timestamp(), winston.format.json()),\n transports\n });\n}\n","import { readFileSync } from 'node:fs';\n\n/**\n * Reads the package version from the project root `package.json`.\n *\n * The module lives under `src/`, so `../package.json` resolves correctly when\n * running via tsx and when bundled to `dist/cli.js`.\n *\n * @returns Semantic version string from package.json.\n */\nexport function readPackageVersion(): string {\n const pkg = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')) as {\n version: string;\n };\n return pkg.version;\n}\n","import type {\n CollectionRecord,\n EnvironmentRecord,\n SavedRequestRecord,\n SnippetRecord,\n UserRecord\n} from '#/db/types.js';\n\n/**\n * Returns true when the authenticated user has an admin role.\n *\n * @param user - Authenticated user attached to the request.\n * @returns True for `admin`-role accounts.\n */\nexport function isAdmin(user: UserRecord): boolean {\n return user.role === 'admin';\n}\n\n/**\n * Returns true when the user may call management API routes for user and token administration.\n *\n * @param user - Authenticated user attached to the request.\n * @returns True for `admin`-role accounts.\n */\nexport function canUseManagementApi(user: UserRecord): boolean {\n return isAdmin(user);\n}\n\n/**\n * Returns true when the user may call entity data API routes for collections,\n * environments, snippets, folders, and requests.\n *\n * @param user - Authenticated user attached to the request.\n * @returns True for `user`-role accounts; false for admins.\n */\nexport function canUseDataApi(user: UserRecord): boolean {\n return user.role === 'user';\n}\n\n/**\n * Returns true when the user may list collections via `GET /collections`.\n *\n * Admins receive the full catalog; mutations and nested reads remain blocked.\n *\n * @param user - Authenticated user attached to the request.\n * @returns True for `user`- and `admin`-role accounts.\n */\nexport function canListCollections(user: UserRecord): boolean {\n return canUseDataApi(user) || canUseManagementApi(user);\n}\n\n/**\n * Returns true when the user may list environments via `GET /environments`.\n *\n * Admins receive the full catalog; mutations remain blocked.\n *\n * @param user - Authenticated user attached to the request.\n * @returns True for `user`- and `admin`-role accounts.\n */\nexport function canListEnvironments(user: UserRecord): boolean {\n return canUseDataApi(user) || canUseManagementApi(user);\n}\n\n/**\n * Returns true when the user may list snippets via `GET /snippets`.\n *\n * Admins receive the full catalog; mutations remain blocked.\n *\n * @param user - Authenticated user attached to the request.\n * @returns True for `user`- and `admin`-role accounts.\n */\nexport function canListSnippets(user: UserRecord): boolean {\n return canUseDataApi(user) || canUseManagementApi(user);\n}\n\n/**\n * Returns true when an access list grants all resources via the wildcard entry.\n *\n * @param access - Collection or environment access ids.\n * @returns True when the list contains `*`.\n */\nexport function hasWildcardAccess(access: string[]): boolean {\n return access.includes('*');\n}\n\n/**\n * Returns true when the user may read or mutate a specific collection.\n *\n * @param user - Authenticated user attached to the request.\n * @param collectionId - Collection identifier being accessed.\n * @returns True when the user role and access list permit the collection.\n */\nexport function canAccessCollection(user: UserRecord, collectionId: string): boolean {\n if (user.role === 'admin') {\n return false;\n }\n\n if (hasWildcardAccess(user.collectionAccess)) {\n return true;\n }\n\n return user.collectionAccess.includes(collectionId);\n}\n\n/**\n * Returns true when the user may read or mutate a specific environment.\n *\n * @param user - Authenticated user attached to the request.\n * @param environmentId - Environment identifier being accessed.\n * @returns True when the user role and access list permit the environment.\n */\nexport function canAccessEnvironment(user: UserRecord, environmentId: string): boolean {\n if (user.role === 'admin') {\n return false;\n }\n\n if (hasWildcardAccess(user.environmentAccess)) {\n return true;\n }\n\n return user.environmentAccess.includes(environmentId);\n}\n\n/**\n * Returns true when the user may read or mutate a specific snippet.\n *\n * @param user - Authenticated user attached to the request.\n * @param snippetId - Snippet identifier being accessed.\n * @returns True when the user role and access list permit the snippet.\n */\nexport function canAccessSnippet(user: UserRecord, snippetId: string): boolean {\n if (user.role === 'admin') {\n return false;\n }\n\n if (hasWildcardAccess(user.snippetAccess)) {\n return true;\n }\n\n return user.snippetAccess.includes(snippetId);\n}\n\n/**\n * Returns true when the user may delete a specific collection via the data API.\n *\n * @param user - Authenticated user attached to the request.\n * @param collection - Collection record being deleted.\n * @returns True when the user created the collection, has access, and deletion is not locked.\n */\nexport function canDeleteCollection(user: UserRecord, collection: CollectionRecord): boolean {\n return (\n canUseDataApi(user) &&\n canAccessCollection(user, collection.id) &&\n collection.createdByUserId === user.id &&\n !collection.deletionLocked\n );\n}\n\n/**\n * Returns true when the user may delete a specific environment via the data API.\n *\n * @param user - Authenticated user attached to the request.\n * @param environment - Environment record being deleted.\n * @returns True when the user has access and the environment is not deletion-locked.\n */\nexport function canDeleteEnvironment(user: UserRecord, environment: EnvironmentRecord): boolean {\n return (\n canUseDataApi(user) && canAccessEnvironment(user, environment.id) && !environment.deletionLocked\n );\n}\n\n/**\n * Returns true when the user may delete a specific snippet via the data API.\n *\n * @param user - Authenticated user attached to the request.\n * @param snippet - Snippet record being deleted.\n * @returns True when the user has access and the snippet is not deletion-locked.\n */\nexport function canDeleteSnippet(user: UserRecord, snippet: SnippetRecord): boolean {\n return canUseDataApi(user) && canAccessSnippet(user, snippet.id) && !snippet.deletionLocked;\n}\n\n/**\n * Returns true when the user may delete a specific saved request via the data API.\n *\n * @param user - Authenticated user attached to the request.\n * @param request - Saved request record being deleted.\n * @returns True when the user created the request and has access to its collection.\n */\nexport function canDeleteRequest(user: UserRecord, request: SavedRequestRecord): boolean {\n return (\n canUseDataApi(user) &&\n canAccessCollection(user, request.collectionId) &&\n request.createdByUserId === user.id\n );\n}\n\n/**\n * Returns true when the user may create new collections via the API.\n *\n * @param user - Authenticated user attached to the request.\n * @returns True when the user has wildcard collection access.\n */\nexport function canCreateCollection(user: UserRecord): boolean {\n return user.role === 'user' && hasWildcardAccess(user.collectionAccess);\n}\n\n/**\n * Returns true when the user may create new environments via the API.\n *\n * @param user - Authenticated user attached to the request.\n * @returns True when the user has wildcard environment access.\n */\nexport function canCreateEnvironment(user: UserRecord): boolean {\n return user.role === 'user' && hasWildcardAccess(user.environmentAccess);\n}\n\n/**\n * Returns true when the user may create new snippets via the API.\n *\n * @param user - Authenticated user attached to the request.\n * @returns True when the user has wildcard snippet access.\n */\nexport function canCreateSnippet(user: UserRecord): boolean {\n return user.role === 'user' && hasWildcardAccess(user.snippetAccess);\n}\n\n/**\n * Filters a collection list to entries the user is allowed to see.\n *\n * @param user - Authenticated user attached to the request.\n * @param collections - Unfiltered collections from the database.\n * @returns Collections visible to the user.\n */\nexport function filterAccessibleCollections(\n user: UserRecord,\n collections: CollectionRecord[]\n): CollectionRecord[] {\n if (user.role === 'admin' || hasWildcardAccess(user.collectionAccess)) {\n return collections;\n }\n\n const allowed = new Set(user.collectionAccess);\n return collections.filter((collection) => allowed.has(collection.id));\n}\n\n/**\n * Filters an environment list to entries the user is allowed to see.\n *\n * @param user - Authenticated user attached to the request.\n * @param environments - Unfiltered environments from the database.\n * @returns Environments visible to the user.\n */\nexport function filterAccessibleEnvironments(\n user: UserRecord,\n environments: EnvironmentRecord[]\n): EnvironmentRecord[] {\n if (user.role === 'admin' || hasWildcardAccess(user.environmentAccess)) {\n return environments;\n }\n\n const allowed = new Set(user.environmentAccess);\n return environments.filter((environment) => allowed.has(environment.id));\n}\n\n/**\n * Filters a snippet list to entries the user is allowed to see.\n *\n * @param user - Authenticated user attached to the request.\n * @param snippets - Unfiltered snippets from the database.\n * @returns Snippets visible to the user.\n */\nexport function filterAccessibleSnippets(\n user: UserRecord,\n snippets: SnippetRecord[]\n): SnippetRecord[] {\n if (user.role === 'admin' || hasWildcardAccess(user.snippetAccess)) {\n return snippets;\n }\n\n const allowed = new Set(user.snippetAccess);\n return snippets.filter((snippet) => allowed.has(snippet.id));\n}\n\n/**\n * Returns true when the user may call hub-proxied LLM routes.\n *\n * @param user - Authenticated user attached to the request.\n * @returns True when LLM access is enabled for the account.\n */\nexport function canUseLlm(user: UserRecord): boolean {\n return user.role !== 'admin' && user.llmAccess;\n}\n\n/**\n * Returns true when the user may request a specific hub-offered model.\n *\n * @param user - Authenticated user attached to the request.\n * @param modelId - Provider-specific model id.\n * @returns True when the user's model access list permits the model.\n */\nexport function isLlmModelAllowed(user: UserRecord, modelId: string): boolean {\n if (!user.llmAccess) {\n return false;\n }\n\n if (hasWildcardAccess(user.llmModels)) {\n return true;\n }\n\n return user.llmModels.includes(modelId);\n}\n\n/**\n * Returns true when usage has reached or exceeded the configured monthly limit.\n *\n * @param totalTokens - Tokens consumed in the current period.\n * @param limit - Configured monthly limit, or null for unlimited.\n */\nexport function isOverMonthlyLimit(totalTokens: number, limit: number | null): boolean {\n if (limit == null) {\n return false;\n }\n\n return totalTokens >= limit;\n}\n","/**\n * Thrown when a non-admin user attempts to delete a collection, environment, or snippet\n * that has deletion protection enabled.\n */\nexport class DeletionLockedError extends Error {\n /**\n * @param entityType - Human-readable entity kind shown in the error message.\n */\n constructor(entityType: 'collection' | 'environment' | 'snippet') {\n super(`Deletion is locked for this ${entityType}.`);\n this.name = 'DeletionLockedError';\n }\n}\n","import { z } from 'zod/v4';\n\n/**\n * Standard error body returned by protected API routes.\n */\nexport const errorResponseSchema = z.object({\n error: z.string()\n});\n\n/**\n * Route parameter schema for string entity identifiers (UUIDs).\n */\nexport const idParamSchema = z.object({\n id: z.string().trim().min(1)\n});\n\n/**\n * Route parameter schema for a parent collection identifier.\n */\nexport const collectionIdParamSchema = z.object({\n collectionId: z.string().trim().min(1)\n});\n\n/**\n * Supported HTTP request methods for saved requests.\n */\nexport const httpMethodSchema = z.enum([\n 'GET',\n 'POST',\n 'PUT',\n 'PATCH',\n 'DELETE',\n 'HEAD',\n 'OPTIONS'\n]);\n\n/**\n * Request body content type for saved requests.\n */\nexport const bodyTypeSchema = z.enum(['none', 'json', 'text', 'multipart', 'urlencoded']);\n\n/**\n * Authorization type for collections and saved requests.\n */\nexport const authTypeSchema = z.enum(['none', 'basic', 'bearer']);\n\n/**\n * Zod schema for a key-value pair with an enable toggle.\n */\nexport const keyValueSchema = z.object({\n key: z.string(),\n value: z.string(),\n enabled: z.boolean()\n});\n\n/**\n * Zod schema for a collection- or environment-scoped variable.\n */\nexport const variableSchema = z.object({\n key: z.string(),\n value: z.string(),\n defaultValue: z.string(),\n share: z.boolean()\n});\n\n/**\n * Zod schema for authorization settings on collections and requests.\n */\nexport const authConfigSchema = z.object({\n type: authTypeSchema,\n basic: z.object({\n username: z.string(),\n password: z.string()\n }),\n bearer: z.object({\n token: z.string()\n })\n});\n\n/**\n * ISO 8601 timestamp strings returned in JSON responses.\n */\nexport const timestampSchema = z.iso.datetime();\n","import type { FastifyReply } from 'fastify';\nimport { DuplicateUserNameError, ReservedUserNameError } from '#/db/userNameValidation.js';\nimport { DeletionLockedError } from '#/db/deletionLockedError.js';\nimport { ValidationError } from '#/server/admin/userValidation.js';\nimport { errorResponseSchema } from '#/server/routes/schemas/common.js';\n\nconst DUPLICATE_USER_NAME_MESSAGE = 'User name is already in use.';\n\n/**\n * Returns true when a database driver reports a unique violation on users.name.\n *\n * @param error - Thrown error from a relational backend write.\n * @returns True when the error is a duplicate user name constraint violation.\n */\nfunction isDuplicateUserNameDbError(error: Error): boolean {\n const candidate = error as Error & { code?: string; constraint?: string };\n\n if (candidate.code === '23505') {\n return (\n candidate.constraint === 'users_name_key' ||\n candidate.constraint?.endsWith('_name_key') === true ||\n error.message.includes('users_name_key') ||\n error.message.includes('(name)')\n );\n }\n\n if (candidate.code === 'ER_DUP_ENTRY') {\n return error.message.includes(\"'name'\") || error.message.includes('users.name');\n }\n\n return false;\n}\n\n/**\n * Maps validation errors to HTTP 400 responses.\n *\n * @param reply - Fastify reply used to send error payloads.\n * @param error - Thrown error from request validation.\n * @returns True when the error was handled and a response was sent.\n */\nexport function handleValidationError(reply: FastifyReply, error: unknown): boolean {\n if (!(error instanceof ValidationError)) {\n return false;\n }\n\n void reply.code(400).send(errorResponseSchema.parse({ error: error.message }));\n return true;\n}\n\n/**\n * Maps known database-layer errors to HTTP responses.\n *\n * @param reply - Fastify reply used to send error payloads.\n * @param error - Thrown error from an {@link IDatabase} operation.\n * @returns True when the error was handled and a response was sent.\n */\nexport function handleDbError(reply: FastifyReply, error: unknown): boolean {\n if (!(error instanceof Error)) {\n return false;\n }\n\n if (error instanceof DuplicateUserNameError) {\n void reply.code(400).send(errorResponseSchema.parse({ error: error.message }));\n return true;\n }\n\n if (error instanceof ReservedUserNameError) {\n void reply.code(400).send(errorResponseSchema.parse({ error: error.message }));\n return true;\n }\n\n if (error instanceof DeletionLockedError) {\n void reply.code(403).send(errorResponseSchema.parse({ error: error.message }));\n return true;\n }\n\n if (isDuplicateUserNameDbError(error)) {\n void reply.code(400).send(errorResponseSchema.parse({ error: DUPLICATE_USER_NAME_MESSAGE }));\n return true;\n }\n\n if (error.message.includes('is required')) {\n void reply.code(400).send(errorResponseSchema.parse({ error: error.message }));\n return true;\n }\n\n if (error.message.toLowerCase().includes('not found')) {\n void reply.code(404).send(errorResponseSchema.parse({ error: error.message }));\n return true;\n }\n\n return false;\n}\n","import type { FastifyReply, FastifyRequest } from 'fastify';\nimport type { UserRecord } from '#/db/types.js';\n\n/**\n * Returns the authenticated user attached by the bearer auth hook.\n *\n * @param request - Incoming HTTP request after authentication.\n * @returns User record resolved from the bearer token owner.\n * @throws {Error} When the request has no authenticated user.\n */\nexport function requireAuthenticatedUser(request: FastifyRequest): UserRecord {\n if (!request.user) {\n throw new Error('Authenticated user is required');\n }\n\n return request.user;\n}\n\n/**\n * Sends a standard forbidden response for authorization failures.\n *\n * @param reply - Fastify reply used to short-circuit the handler.\n * @returns The reply instance for early return in route handlers.\n */\nexport function sendForbidden(reply: FastifyReply): FastifyReply {\n return reply.code(403).send({ error: 'Forbidden' });\n}\n\n/**\n * Sends forbidden when the supplied condition is false.\n *\n * @param reply - Fastify reply used to short-circuit the handler.\n * @param allowed - True when the caller may proceed.\n * @returns True when the handler should return early with 403.\n */\nexport function denyUnlessAllowed(reply: FastifyReply, allowed: boolean): boolean {\n if (allowed) {\n return false;\n }\n\n sendForbidden(reply);\n return true;\n}\n","import { z } from 'zod/v4';\nimport type { ApiTokenRecord, UserRecord } from '#/db/types.js';\nimport { userRoleSchema } from '#/server/routes/schemas/auth.js';\nimport { timestampSchema } from '#/server/routes/schemas/common.js';\nimport { listLlmModelsResponseSchema } from '#/server/routes/schemas/llm.js';\nimport {\n createSnippetBodySchema,\n snippetRecordSchema,\n snippetScopeSchema\n} from '#/server/routes/schemas/entities.js';\n\n/**\n * Lightweight id/name pair returned by admin resource list routes.\n */\nexport const adminResourceOptionSchema = z.object({\n id: z.string(),\n name: z.string(),\n deletionLocked: z.boolean()\n});\n\n/**\n * Response body schema for admin collection/environment configuration updates.\n */\nexport const adminEntityConfigSchema = z.object({\n id: z.string(),\n name: z.string(),\n deletionLocked: z.boolean()\n});\n\n/**\n * Request body schema for `PUT /admin/collections/:id`.\n */\nexport const updateAdminCollectionBodySchema = z.object({\n deletionLocked: z.boolean()\n});\n\n/**\n * Request body schema for `PUT /admin/environments/:id`.\n */\nexport const updateAdminEnvironmentBodySchema = z.object({\n deletionLocked: z.boolean()\n});\n\n/**\n * Request body schema for `PUT /admin/snippets/:id`.\n */\nexport const updateAdminSnippetBodySchema = z\n .object({\n name: z.string().trim().min(1).optional(),\n code: z.string().optional(),\n scope: snippetScopeSchema.optional(),\n deletionLocked: z.boolean().optional()\n })\n .superRefine((body, ctx) => {\n const hasContentFields =\n body.name !== undefined || body.code !== undefined || body.scope !== undefined;\n const hasFullContent =\n body.name !== undefined && body.code !== undefined && body.scope !== undefined;\n\n if (hasContentFields && !hasFullContent) {\n ctx.addIssue({\n code: 'custom',\n message: 'name, code, and scope must be provided together'\n });\n }\n\n if (!hasContentFields && body.deletionLocked === undefined) {\n ctx.addIssue({\n code: 'custom',\n message: 'Provide snippet content (name, code, scope) and/or deletionLocked'\n });\n }\n });\n\n/**\n * Request body schema for `POST /admin/snippets`.\n */\nexport const createAdminSnippetBodySchema = createSnippetBodySchema;\n\n/**\n * Response body schema for `GET /admin/collections`.\n */\nexport const listAdminCollectionsResponseSchema = z.object({\n collections: z.array(adminResourceOptionSchema)\n});\n\n/**\n * Response body schema for `GET /admin/environments`.\n */\nexport const listAdminEnvironmentsResponseSchema = z.object({\n environments: z.array(adminResourceOptionSchema)\n});\n\n/**\n * Response body schema for `GET /admin/snippets`.\n */\nexport const listAdminSnippetsResponseSchema = z.object({\n snippets: z.array(snippetRecordSchema)\n});\n\n/**\n * Response body schema for admin snippet create and content updates.\n */\nexport const adminSnippetRecordSchema = snippetRecordSchema;\n\n/**\n * Response body schema for `GET /admin/llm/models`.\n */\nexport const listAdminLlmModelsResponseSchema = listLlmModelsResponseSchema;\nexport const hubUserRecordSchema = z.object({\n id: z.string(),\n name: z.string(),\n role: userRoleSchema,\n collectionAccess: z.array(z.string()),\n environmentAccess: z.array(z.string()),\n snippetAccess: z.array(z.string()),\n llmAccess: z.boolean(),\n llmModels: z.array(z.string()),\n llmMonthlyTokenLimit: z.number().int().nonnegative().nullable(),\n createdAt: timestampSchema,\n updatedAt: timestampSchema\n});\n\n/**\n * User record returned by `GET /admin/users`, including stale access warnings.\n */\nexport const adminUserListEntrySchema = hubUserRecordSchema.extend({\n warnings: z.array(z.string())\n});\n\n/**\n * Response body schema for `GET /admin/users`.\n */\nexport const listAdminUsersResponseSchema = z.object({\n users: z.array(adminUserListEntrySchema)\n});\n\n/**\n * Request body schema for `PUT /admin/users/:id`.\n */\nexport const updateAdminUserBodySchema = z.object({\n name: z.string().trim().min(1).optional(),\n role: userRoleSchema.optional(),\n collectionAccess: z.array(z.string()).optional(),\n environmentAccess: z.array(z.string()).optional(),\n snippetAccess: z.array(z.string()).optional(),\n llmAccess: z.boolean().optional(),\n llmModels: z.array(z.string()).optional(),\n llmMonthlyTokenLimit: z.number().int().nonnegative().nullable().optional()\n});\n\n/**\n * Request body schema for `POST /admin/users`.\n */\nexport const createAdminUserBodySchema = z.object({\n name: z.string().trim().min(1),\n role: userRoleSchema,\n collectionAccess: z.array(z.string()).optional(),\n environmentAccess: z.array(z.string()).optional(),\n snippetAccess: z.array(z.string()).optional(),\n llmAccess: z.boolean().optional(),\n llmModels: z.array(z.string()).optional(),\n llmMonthlyTokenLimit: z.number().int().nonnegative().nullable().optional()\n});\n\n/**\n * API token metadata returned by admin token routes (never includes the secret hash).\n */\nexport const hubApiTokenRecordSchema = z.object({\n id: z.string(),\n userId: z.string(),\n name: z.string(),\n tokenPrefix: z.string(),\n createdAt: timestampSchema,\n lastUsedAt: timestampSchema.nullable(),\n revokedAt: timestampSchema.nullable()\n});\n\n/**\n * Response body schema for `POST /admin/users`.\n */\nexport const createAdminUserResponseSchema = z.object({\n user: hubUserRecordSchema,\n token: hubApiTokenRecordSchema,\n secret: z.string()\n});\n\n/**\n * Request body schema for `POST /admin/users/:id/tokens`.\n */\nexport const createAdminTokenBodySchema = z.object({\n name: z.string().trim().min(1)\n});\n\n/**\n * Response body schema for `POST /admin/users/:id/tokens`.\n */\nexport const createdApiTokenResponseSchema = z.object({\n token: hubApiTokenRecordSchema,\n secret: z.string()\n});\n\n/**\n * Response body schema for `GET /admin/tokens`.\n */\nexport const listAdminTokensResponseSchema = z.object({\n tokens: z.array(hubApiTokenRecordSchema)\n});\n\n/**\n * Per-section outcome reported by config reload routes.\n */\nexport const reloadConfigSectionResultSchema = z.object({\n section: z.enum(['db', 'redis', 'llm', 'plugins', 'server']),\n status: z.enum(['reloaded', 'unchanged', 'failed', 'restart-required']),\n error: z.string().optional()\n});\n\n/**\n * Response body schema for `POST /admin/config/reload`.\n */\nexport const reloadConfigResponseSchema = z.object({\n sections: z.array(reloadConfigSectionResultSchema),\n fatalError: z.string().optional()\n});\n\n/**\n * Serializes a user record for JSON management API responses.\n *\n * @param user - User record from the database layer.\n * @returns User with ISO timestamp strings.\n */\nexport function serializeHubUser(user: UserRecord) {\n return {\n id: user.id,\n name: user.name,\n role: user.role,\n collectionAccess: user.collectionAccess,\n environmentAccess: user.environmentAccess,\n snippetAccess: user.snippetAccess,\n llmAccess: user.llmAccess,\n llmModels: user.llmModels,\n llmMonthlyTokenLimit: user.llmMonthlyTokenLimit,\n createdAt: user.createdAt.toISOString(),\n updatedAt: user.updatedAt.toISOString()\n };\n}\n\n/**\n * Serializes an API token record for JSON management API responses.\n *\n * @param token - Token record from the database layer.\n * @returns Token metadata with ISO timestamp strings.\n */\nexport function serializeApiToken(token: ApiTokenRecord) {\n return {\n id: token.id,\n userId: token.userId,\n name: token.name,\n tokenPrefix: token.tokenPrefix,\n createdAt: token.createdAt.toISOString(),\n lastUsedAt: token.lastUsedAt ? token.lastUsedAt.toISOString() : null,\n revokedAt: token.revokedAt ? token.revokedAt.toISOString() : null\n };\n}\n","import { z } from 'zod/v4';\n\n/**\n * Account role values exposed on the session endpoint.\n */\nexport const userRoleSchema = z.enum(['admin', 'user']);\n\n/**\n * Capability flags returned by `GET /auth/session`.\n */\nexport const sessionCapabilitiesSchema = z.object({\n dataApi: z.boolean(),\n managementApi: z.boolean(),\n llm: z.boolean()\n});\n\n/**\n * Response body schema for `GET /auth/session`.\n */\nexport const sessionResponseSchema = z.object({\n user: z.object({\n id: z.string(),\n name: z.string(),\n role: userRoleSchema\n }),\n token: z.object({\n id: z.string(),\n prefix: z.string()\n }),\n capabilities: sessionCapabilitiesSchema\n});\n","import { z } from 'zod/v4';\n\n/**\n * Zod schema for a tool call in an LLM chat step request or response.\n */\nexport const llmToolCallSchema = z.object({\n id: z.string(),\n name: z.string(),\n arguments: z.string()\n});\n\n/**\n * Zod schema for a message in an LLM chat step request.\n */\nexport const llmChatStepMessageSchema = z.object({\n role: z.enum(['system', 'user', 'assistant', 'tool']),\n content: z.string().nullable().optional(),\n tool_calls: z.array(llmToolCallSchema).optional(),\n tool_call_id: z.string().optional(),\n name: z.string().optional()\n});\n\n/**\n * Zod schema for POST /llm/chat/step request body.\n */\nexport const llmChatStepBodySchema = z.object({\n model: z.string().trim().min(1),\n messages: z.array(llmChatStepMessageSchema),\n tools: z.array(z.record(z.string(), z.unknown())).optional(),\n systemPrompt: z.string().optional()\n});\n\n/**\n * Zod schema for token usage returned by POST /llm/chat/step.\n */\nexport const llmUsageSchema = z.object({\n promptTokens: z.number().int().nonnegative(),\n completionTokens: z.number().int().nonnegative(),\n totalTokens: z.number().int().nonnegative()\n});\n\n/**\n * Zod schema for POST /llm/chat/step response body.\n */\nexport const llmChatStepResponseSchema = z.object({\n content: z.string().nullable(),\n toolCalls: z.array(llmToolCallSchema).optional(),\n usage: llmUsageSchema\n});\n\n/**\n * Zod schema for one model entry in GET /llm/models.\n */\nexport const llmModelSchema = z.object({\n id: z.string(),\n label: z.string(),\n provider: z.enum(['openai', 'claude', 'gemini'])\n});\n\n/**\n * Zod schema for GET /llm/models response body.\n */\nexport const listLlmModelsResponseSchema = z.object({\n models: z.array(llmModelSchema)\n});\n\n/**\n * Zod schema for GET /llm/usage response body.\n */\nexport const llmUsageSummaryResponseSchema = z.object({\n period: z.string(),\n totalTokens: z.number().int().nonnegative(),\n limit: z.number().int().positive().nullable()\n});\n","import { z } from 'zod/v4';\nimport type {\n CollectionRecord,\n EnvironmentRecord,\n FolderRecord,\n SavedRequestRecord,\n SnippetRecord\n} from '#/db/types.js';\nimport {\n authConfigSchema,\n bodyTypeSchema,\n httpMethodSchema,\n keyValueSchema,\n timestampSchema,\n variableSchema\n} from '#/server/routes/schemas/common.js';\n\n/**\n * JSON shape for a persisted collection record.\n */\nexport const collectionRecordSchema = z.object({\n id: z.string(),\n name: z.string(),\n variables: z.array(variableSchema),\n headers: z.array(keyValueSchema),\n auth: authConfigSchema,\n preRequestScript: z.string(),\n postRequestScript: z.string(),\n createdAt: timestampSchema,\n updatedAt: timestampSchema,\n createdByUserId: z.string().nullable(),\n updatedByUserId: z.string().nullable(),\n deletionLocked: z.boolean()\n});\n\n/**\n * JSON shape for a persisted environment record.\n */\nexport const environmentRecordSchema = z.object({\n id: z.string(),\n name: z.string(),\n variables: z.array(variableSchema),\n createdAt: timestampSchema,\n updatedAt: timestampSchema,\n createdByUserId: z.string().nullable(),\n updatedByUserId: z.string().nullable(),\n deletionLocked: z.boolean()\n});\n\n/**\n * Valid execution scopes for persisted snippets.\n */\nexport const snippetScopeSchema = z.enum(['pre-request', 'post-request', 'any']);\n\n/**\n * JSON shape for a persisted snippet record.\n */\nexport const snippetRecordSchema = z.object({\n id: z.string(),\n name: z.string(),\n code: z.string(),\n scope: snippetScopeSchema,\n sortOrder: z.number().int(),\n createdAt: timestampSchema,\n updatedAt: timestampSchema,\n createdByUserId: z.string().nullable(),\n updatedByUserId: z.string().nullable(),\n deletionLocked: z.boolean()\n});\n\n/**\n * JSON shape for a persisted folder record.\n */\nexport const folderRecordSchema = z.object({\n id: z.string(),\n collectionId: z.string(),\n name: z.string(),\n sortOrder: z.number().int(),\n createdAt: timestampSchema,\n updatedAt: timestampSchema,\n createdByUserId: z.string().nullable(),\n updatedByUserId: z.string().nullable()\n});\n\n/**\n * JSON shape for a persisted saved request record.\n */\nexport const savedRequestRecordSchema = z.object({\n id: z.string(),\n collectionId: z.string(),\n name: z.string(),\n method: httpMethodSchema,\n url: z.string(),\n headers: z.array(keyValueSchema),\n params: z.array(keyValueSchema),\n auth: authConfigSchema,\n body: z.string(),\n bodyType: bodyTypeSchema,\n preRequestScript: z.string(),\n postRequestScript: z.string(),\n comment: z.string(),\n folderId: z.string().nullable(),\n sortOrder: z.number().int(),\n createdAt: timestampSchema,\n updatedAt: timestampSchema,\n createdByUserId: z.string().nullable(),\n updatedByUserId: z.string().nullable()\n});\n\n/**\n * Request body for creating a collection.\n */\nexport const createCollectionBodySchema = z.object({\n name: z.string().trim().min(1)\n});\n\n/**\n * Request body for updating a collection.\n */\nexport const updateCollectionBodySchema = z.object({\n name: z.string().trim().min(1),\n variables: z.array(variableSchema),\n headers: z.array(keyValueSchema),\n preRequestScript: z.string(),\n postRequestScript: z.string(),\n auth: authConfigSchema\n});\n\n/**\n * Request body for creating an environment.\n */\nexport const createEnvironmentBodySchema = z.object({\n name: z.string().trim().min(1)\n});\n\n/**\n * Request body for updating an environment.\n */\nexport const updateEnvironmentBodySchema = z.object({\n name: z.string().trim().min(1),\n variables: z.array(variableSchema)\n});\n\n/**\n * Request body for creating a snippet.\n */\nexport const createSnippetBodySchema = z.object({\n name: z.string().trim().min(1),\n code: z.string().default(''),\n scope: snippetScopeSchema.default('any')\n});\n\n/**\n * Request body for updating a snippet.\n *\n * Sort order is not included: HarborClient's snippet update flow only\n * manages name/code/scope, so the server preserves the existing sort order.\n */\nexport const updateSnippetBodySchema = z.object({\n name: z.string().trim().min(1),\n code: z.string(),\n scope: snippetScopeSchema\n});\n\n/**\n * Request body for creating a folder.\n */\nexport const createFolderBodySchema = z.object({\n name: z.string().trim().min(1)\n});\n\n/**\n * Request body for renaming a folder.\n */\nexport const renameFolderBodySchema = z.object({\n name: z.string().trim().min(1)\n});\n\n/**\n * Request body for reordering folders within a collection.\n */\nexport const reorderFoldersBodySchema = z.object({\n orderedFolderIds: z.array(z.string().trim().min(1))\n});\n\n/**\n * Request body for creating or updating a saved request.\n */\nexport const saveRequestBodySchema = z.object({\n name: z.string().trim().min(1),\n method: httpMethodSchema,\n url: z.string(),\n headers: z.array(keyValueSchema),\n params: z.array(keyValueSchema),\n auth: authConfigSchema,\n body: z.string(),\n bodyType: bodyTypeSchema,\n preRequestScript: z.string(),\n postRequestScript: z.string(),\n comment: z.string(),\n folderId: z.string().nullable().optional()\n});\n\n/**\n * Request body for updating an existing saved request.\n */\nexport const updateSaveRequestBodySchema = saveRequestBodySchema.extend({\n collectionId: z.string().trim().min(1)\n});\n\n/**\n * Request body for reordering requests within a folder or collection root.\n */\nexport const reorderRequestsBodySchema = z.object({\n folderId: z.string().nullable(),\n orderedRequestIds: z.array(z.string().trim().min(1))\n});\n\n/**\n * Request body for moving a request to another folder or root index.\n */\nexport const moveRequestBodySchema = z.object({\n folderId: z.string().nullable(),\n index: z.number().int().min(0)\n});\n\n/**\n * List response wrapper for collections.\n */\nexport const listCollectionsResponseSchema = z.object({\n collections: z.array(collectionRecordSchema)\n});\n\n/**\n * List response wrapper for environments.\n */\nexport const listEnvironmentsResponseSchema = z.object({\n environments: z.array(environmentRecordSchema)\n});\n\n/**\n * List response wrapper for snippets.\n */\nexport const listSnippetsResponseSchema = z.object({\n snippets: z.array(snippetRecordSchema)\n});\n\n/**\n * List response wrapper for folders.\n */\nexport const listFoldersResponseSchema = z.object({\n folders: z.array(folderRecordSchema)\n});\n\n/**\n * List response wrapper for saved requests.\n */\nexport const listRequestsResponseSchema = z.object({\n requests: z.array(savedRequestRecordSchema)\n});\n\n/**\n * Empty JSON body schema for 204 No Content responses.\n */\nexport const emptyResponseSchema = z.null();\n\n/**\n * Serializes a collection record for JSON responses.\n *\n * @param record - Collection record from the database layer.\n * @returns Collection with ISO timestamp strings.\n */\nexport function serializeCollection(record: CollectionRecord) {\n return {\n ...record,\n createdAt: record.createdAt.toISOString(),\n updatedAt: record.updatedAt.toISOString()\n };\n}\n\n/**\n * Serializes an environment record for JSON responses.\n *\n * @param record - Environment record from the database layer.\n * @returns Environment with ISO timestamp strings.\n */\nexport function serializeEnvironment(record: EnvironmentRecord) {\n return {\n ...record,\n createdAt: record.createdAt.toISOString(),\n updatedAt: record.updatedAt.toISOString()\n };\n}\n\n/**\n * Serializes a snippet record for JSON responses.\n *\n * @param record - Snippet record from the database layer.\n * @returns Snippet with ISO timestamp strings.\n */\nexport function serializeSnippet(record: SnippetRecord) {\n return {\n ...record,\n createdAt: record.createdAt.toISOString(),\n updatedAt: record.updatedAt.toISOString()\n };\n}\n\n/**\n * Serializes a folder record for JSON responses.\n *\n * @param record - Folder record from the database layer.\n * @returns Folder with ISO timestamp strings.\n */\nexport function serializeFolder(record: FolderRecord) {\n return {\n ...record,\n createdAt: record.createdAt.toISOString(),\n updatedAt: record.updatedAt.toISOString()\n };\n}\n\n/**\n * Serializes a saved request record for JSON responses.\n *\n * @param record - Saved request record from the database layer.\n * @returns Saved request with ISO timestamp strings.\n */\nexport function serializeSavedRequest(record: SavedRequestRecord) {\n return {\n ...record,\n createdAt: record.createdAt.toISOString(),\n updatedAt: record.updatedAt.toISOString()\n };\n}\n","import type { FastifyInstance, FastifyReply } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport type { IDatabase } from '#/db/IDatabase.js';\nimport type { UserRole } from '#/db/types.js';\nimport { isSystemUser } from '#/db/systemUsers.js';\nimport {\n buildAccessCatalogIds,\n buildAccessListWarnings,\n buildAdminUserCreateInput,\n buildAdminUserUpdateInput,\n validateSubmittedAccessLists\n} from '#/server/admin/userValidation.js';\nimport { canUseManagementApi } from '#/server/auth/accessControl.js';\nimport { generateApiToken } from '#/server/auth/apiTokens.js';\nimport { listHubOfferedModels } from '#/server/llm/models.js';\nimport { handleDbError, handleValidationError } from '#/server/routes/errors.js';\nimport { denyUnlessAllowed, requireAuthenticatedUser } from '#/server/routes/authorize.js';\nimport {\n createAdminTokenBodySchema,\n createAdminUserBodySchema,\n createAdminUserResponseSchema,\n createAdminSnippetBodySchema,\n createdApiTokenResponseSchema,\n adminEntityConfigSchema,\n adminSnippetRecordSchema,\n hubUserRecordSchema,\n listAdminCollectionsResponseSchema,\n listAdminEnvironmentsResponseSchema,\n listAdminLlmModelsResponseSchema,\n listAdminSnippetsResponseSchema,\n listAdminTokensResponseSchema,\n listAdminUsersResponseSchema,\n reloadConfigResponseSchema,\n serializeApiToken,\n serializeHubUser,\n updateAdminCollectionBodySchema,\n updateAdminEnvironmentBodySchema,\n updateAdminSnippetBodySchema,\n updateAdminUserBodySchema\n} from '#/server/routes/schemas/admin.js';\nimport {\n errorResponseSchema,\n idParamSchema,\n collectionIdParamSchema\n} from '#/server/routes/schemas/common.js';\nimport {\n emptyResponseSchema,\n listFoldersResponseSchema,\n listRequestsResponseSchema,\n serializeFolder,\n serializeSavedRequest,\n serializeSnippet\n} from '#/server/routes/schemas/entities.js';\nimport type { LlmConfig } from '#/config/llmConfig.js';\nimport type { ReloadResult } from '#/server/runtimeContext.js';\n\n/**\n * Options for registering management routes.\n */\nexport interface RegisterAdminRoutesOptions {\n /**\n * Database used to read user accounts and entity metadata.\n */\n db: IDatabase;\n\n /**\n * Returns the current normalized LLM configuration from server.yaml.\n */\n getLlm: () => LlmConfig | null;\n\n /**\n * Reloads server.yaml and returns a per-section report.\n */\n reloadConfig: () => Promise<ReloadResult>;\n}\n\n/**\n * Sends a 503 response when LLM support is not configured on the hub.\n *\n * @param reply - Fastify reply used to short-circuit the handler.\n */\nfunction sendLlmUnavailable(reply: FastifyReply): FastifyReply {\n return reply.code(503).send({\n error: 'LLM support is not configured on this Team Hub.'\n });\n}\n\n/**\n * Returns 403 when the target account is the internal system user.\n *\n * @param reply - Fastify reply used to send error payloads.\n * @param existing - User record being updated or deleted.\n * @param systemUserId - Cached system user id from the database, when known.\n * @returns True when the request was denied and a response was sent.\n */\nfunction denySystemUserTarget(\n reply: Parameters<typeof denyUnlessAllowed>[0],\n existing: { id: string; name: string },\n systemUserId: string | null\n): boolean {\n if (!isSystemUser(existing, systemUserId)) {\n return false;\n }\n\n void reply.code(403).send(errorResponseSchema.parse({ error: 'Forbidden' }));\n return true;\n}\n\n/**\n * Returns 403 when the target account is the authenticated operator.\n *\n * @param reply - Fastify reply used to send error payloads.\n * @param targetUserId - User id from the route parameter.\n * @param actorUserId - Authenticated operator performing the action.\n * @returns True when the request was denied and a response was sent.\n */\nfunction denySelfUserTarget(\n reply: Parameters<typeof denyUnlessAllowed>[0],\n targetUserId: string,\n actorUserId: string\n): boolean {\n if (targetUserId !== actorUserId) {\n return false;\n }\n\n void reply.code(403).send(errorResponseSchema.parse({ error: 'Forbidden' }));\n return true;\n}\n\n/**\n * Returns 403 when an operator attempts to change their own role.\n *\n * @param reply - Fastify reply used to send error payloads.\n * @param targetUserId - User id from the route parameter.\n * @param actorUserId - Authenticated operator performing the action.\n * @param existingRole - Current role stored for the target account.\n * @param requestedRole - Role from the request body, when provided.\n * @returns True when the request was denied and a response was sent.\n */\nfunction denySelfRoleChange(\n reply: Parameters<typeof denyUnlessAllowed>[0],\n targetUserId: string,\n actorUserId: string,\n existingRole: UserRole,\n requestedRole: UserRole | undefined\n): boolean {\n if (targetUserId !== actorUserId) {\n return false;\n }\n\n if (requestedRole === undefined || requestedRole === existingRole) {\n return false;\n }\n\n void reply.code(403).send(errorResponseSchema.parse({ error: 'Forbidden' }));\n return true;\n}\n\n/**\n * Registers bearer-protected management routes for operator accounts.\n *\n * @param app - Encapsulated Fastify scope with auth applied.\n * @param options - Database and LLM configuration.\n */\nexport async function registerAdminRoutes(\n app: FastifyInstance,\n options: RegisterAdminRoutesOptions\n): Promise<void> {\n const { db, getLlm, reloadConfig } = options;\n const routes = app.withTypeProvider<ZodTypeProvider>();\n\n routes.route({\n method: 'GET',\n url: '/admin/users',\n schema: {\n response: {\n 200: listAdminUsersResponseSchema,\n 403: errorResponseSchema\n }\n },\n /**\n * Lists all user accounts for operator administration.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const systemUserId = db.getSystemUserId();\n const llm = getLlm();\n const [users, collections, environments, snippets] = await Promise.all([\n db.listUsers(),\n db.listCollections(),\n db.listEnvironments(),\n db.listSnippets()\n ]);\n const catalogs = buildAccessCatalogIds(\n collections,\n environments,\n snippets,\n llm ? listHubOfferedModels(llm).map((model) => model.id) : null\n );\n\n return reply.send({\n users: users\n .filter((record) => !isSystemUser(record, systemUserId))\n .map((record) => ({\n ...serializeHubUser(record),\n warnings: buildAccessListWarnings(\n {\n collectionAccess: record.collectionAccess,\n environmentAccess: record.environmentAccess,\n snippetAccess: record.snippetAccess,\n llmModels: record.llmModels\n },\n catalogs\n )\n }))\n });\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'POST',\n url: '/admin/users',\n schema: {\n body: createAdminUserBodySchema,\n response: {\n 201: createAdminUserResponseSchema,\n 400: errorResponseSchema,\n 403: errorResponseSchema\n }\n },\n /**\n * Creates a user account and an initial API bearer token.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const input = buildAdminUserCreateInput(request.body);\n const llm = getLlm();\n const [collections, environments, snippets] = await Promise.all([\n db.listCollections(),\n db.listEnvironments(),\n db.listSnippets()\n ]);\n const catalogs = buildAccessCatalogIds(\n collections,\n environments,\n snippets,\n llm ? listHubOfferedModels(llm).map((model) => model.id) : null\n );\n validateSubmittedAccessLists(\n {\n role: request.body.role,\n collectionAccess: request.body.collectionAccess,\n environmentAccess: request.body.environmentAccess,\n snippetAccess: request.body.snippetAccess,\n llmModels: request.body.llmModels\n },\n catalogs\n );\n\n const created = await db.createUser(input, user.id);\n const { record, secret } = generateApiToken(created.id, created.name);\n await db.createApiToken(record, user.id);\n\n return reply.code(201).send({\n user: serializeHubUser(created),\n token: serializeApiToken(record),\n secret\n });\n } catch (error) {\n if (handleValidationError(reply, error) || handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'GET',\n url: '/admin/collections',\n schema: {\n response: {\n 200: listAdminCollectionsResponseSchema,\n 403: errorResponseSchema\n }\n },\n /**\n * Lists all collections for operator user management.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const collections = await db.listCollections();\n return reply.send({\n collections: collections.map((collection) => ({\n id: collection.id,\n name: collection.name,\n deletionLocked: collection.deletionLocked\n }))\n });\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'GET',\n url: '/admin/collections/:collectionId/folders',\n schema: {\n params: collectionIdParamSchema,\n response: {\n 200: listFoldersResponseSchema,\n 403: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Lists folders in a collection for operator inspection.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const collection = await db.findCollectionById(request.params.collectionId);\n if (!collection) {\n void reply.code(404).send({ error: 'Collection not found' });\n return;\n }\n\n const folders = await db.listFolders(request.params.collectionId);\n return reply.send({\n folders: folders.map((folder) => serializeFolder(folder))\n });\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'GET',\n url: '/admin/collections/:collectionId/requests',\n schema: {\n params: collectionIdParamSchema,\n response: {\n 200: listRequestsResponseSchema,\n 403: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Lists saved requests in a collection for operator inspection.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const collection = await db.findCollectionById(request.params.collectionId);\n if (!collection) {\n void reply.code(404).send({ error: 'Collection not found' });\n return;\n }\n\n const requests = await db.listRequests(request.params.collectionId);\n return reply.send({\n requests: requests.map((savedRequest) => serializeSavedRequest(savedRequest))\n });\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'GET',\n url: '/admin/environments',\n schema: {\n response: {\n 200: listAdminEnvironmentsResponseSchema,\n 403: errorResponseSchema\n }\n },\n /**\n * Lists all environments for operator user management.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const environments = await db.listEnvironments();\n return reply.send({\n environments: environments.map((environment) => ({\n id: environment.id,\n name: environment.name,\n deletionLocked: environment.deletionLocked\n }))\n });\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'GET',\n url: '/admin/snippets',\n schema: {\n response: {\n 200: listAdminSnippetsResponseSchema,\n 403: errorResponseSchema\n }\n },\n /**\n * Lists all snippets for operator user management.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const snippets = await db.listSnippets();\n return reply.send({\n snippets: snippets.map((snippet) => serializeSnippet(snippet))\n });\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'POST',\n url: '/admin/snippets',\n schema: {\n body: createAdminSnippetBodySchema,\n response: {\n 201: adminSnippetRecordSchema,\n 403: errorResponseSchema\n }\n },\n /**\n * Creates a snippet through the management API.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const snippet = await db.createSnippet(\n request.body.name,\n request.body.code,\n request.body.scope,\n user.id\n );\n return reply.code(201).send(serializeSnippet(snippet));\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'DELETE',\n url: '/admin/collections/:id',\n schema: {\n params: idParamSchema,\n response: {\n 204: emptyResponseSchema,\n 403: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Deletes a collection regardless of deletion lock state.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const collection = await db.findCollectionById(request.params.id);\n if (!collection) {\n void reply.code(404).send({ error: 'Collection not found' });\n return;\n }\n\n await db.deleteCollection(request.params.id, user.id);\n return reply.code(204).send(null);\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'DELETE',\n url: '/admin/requests/:id',\n schema: {\n params: idParamSchema,\n response: {\n 204: emptyResponseSchema,\n 403: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Deletes a saved request regardless of collection access lists.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const existingRequest = await db.findRequestById(request.params.id);\n if (!existingRequest) {\n void reply.code(404).send({ error: 'Request not found' });\n return;\n }\n\n await db.deleteRequest(request.params.id, user.id);\n return reply.code(204).send(null);\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'DELETE',\n url: '/admin/snippets/:id',\n schema: {\n params: idParamSchema,\n response: {\n 204: emptyResponseSchema,\n 403: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Deletes a snippet regardless of deletion lock state.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const snippet = await db.findSnippetById(request.params.id);\n if (!snippet) {\n void reply.code(404).send({ error: 'Snippet not found' });\n return;\n }\n\n await db.deleteSnippet(request.params.id, user.id);\n return reply.code(204).send(null);\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'PUT',\n url: '/admin/snippets/:id',\n schema: {\n params: idParamSchema,\n body: updateAdminSnippetBodySchema,\n response: {\n 200: adminSnippetRecordSchema,\n 403: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Updates snippet content and/or admin configuration.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const existing = await db.findSnippetById(request.params.id);\n if (!existing) {\n void reply.code(404).send({ error: 'Snippet not found' });\n return;\n }\n\n let snippet = existing;\n const { name, code, scope, deletionLocked } = request.body;\n\n if (name !== undefined && code !== undefined && scope !== undefined) {\n snippet = await db.updateSnippet(request.params.id, name, code, scope, user.id);\n }\n\n if (deletionLocked !== undefined) {\n snippet = await db.setSnippetDeletionLocked(request.params.id, deletionLocked, user.id);\n }\n\n return reply.send(serializeSnippet(snippet));\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'PUT',\n url: '/admin/collections/:id',\n schema: {\n params: idParamSchema,\n body: updateAdminCollectionBodySchema,\n response: {\n 200: adminEntityConfigSchema,\n 403: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Updates admin configuration for a collection.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const collection = await db.setCollectionDeletionLocked(\n request.params.id,\n request.body.deletionLocked,\n user.id\n );\n\n return reply.send({\n id: collection.id,\n name: collection.name,\n deletionLocked: collection.deletionLocked\n });\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'DELETE',\n url: '/admin/environments/:id',\n schema: {\n params: idParamSchema,\n response: {\n 204: emptyResponseSchema,\n 403: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Deletes an environment regardless of deletion lock state.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const environment = await db.findEnvironmentById(request.params.id);\n if (!environment) {\n void reply.code(404).send({ error: 'Environment not found' });\n return;\n }\n\n await db.deleteEnvironment(request.params.id, user.id);\n return reply.code(204).send(null);\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'PUT',\n url: '/admin/environments/:id',\n schema: {\n params: idParamSchema,\n body: updateAdminEnvironmentBodySchema,\n response: {\n 200: adminEntityConfigSchema,\n 403: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Updates admin configuration for an environment.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const environment = await db.setEnvironmentDeletionLocked(\n request.params.id,\n request.body.deletionLocked,\n user.id\n );\n\n return reply.send({\n id: environment.id,\n name: environment.name,\n deletionLocked: environment.deletionLocked\n });\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'GET',\n url: '/admin/llm/models',\n schema: {\n response: {\n 200: listAdminLlmModelsResponseSchema,\n 403: errorResponseSchema,\n 503: errorResponseSchema\n }\n },\n /**\n * Lists all hub-offered LLM models for operator user management.\n */\n handler: async (request, reply) => {\n const llm = getLlm();\n if (!llm) {\n return sendLlmUnavailable(reply);\n }\n\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const models = listHubOfferedModels(llm).map((model) => ({\n id: model.id,\n label: model.label,\n provider: model.provider\n }));\n\n return reply.send({ models });\n }\n });\n\n routes.route({\n method: 'PUT',\n url: '/admin/users/:id',\n schema: {\n params: idParamSchema,\n body: updateAdminUserBodySchema,\n response: {\n 200: hubUserRecordSchema,\n 400: errorResponseSchema,\n 403: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Updates a user account for operator administration.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const systemUserId = db.getSystemUserId();\n const existing = await db.findUserById(request.params.id);\n if (!existing) {\n void reply.code(404).send(errorResponseSchema.parse({ error: 'User not found' }));\n return;\n }\n\n if (denySystemUserTarget(reply, existing, systemUserId)) {\n return;\n }\n\n if (\n denySelfRoleChange(reply, request.params.id, user.id, existing.role, request.body.role)\n ) {\n return;\n }\n\n const input = buildAdminUserUpdateInput(existing, request.body);\n const role = request.body.role ?? existing.role;\n const llm = getLlm();\n const [collections, environments, snippets] = await Promise.all([\n db.listCollections(),\n db.listEnvironments(),\n db.listSnippets()\n ]);\n const catalogs = buildAccessCatalogIds(\n collections,\n environments,\n snippets,\n llm ? listHubOfferedModels(llm).map((model) => model.id) : null\n );\n validateSubmittedAccessLists(\n {\n role,\n collectionAccess: request.body.collectionAccess,\n environmentAccess: request.body.environmentAccess,\n snippetAccess: request.body.snippetAccess,\n llmModels: request.body.llmModels\n },\n catalogs\n );\n\n const updated = await db.updateUser(request.params.id, input, user.id);\n return reply.send(serializeHubUser(updated));\n } catch (error) {\n if (handleValidationError(reply, error) || handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'DELETE',\n url: '/admin/users/:id',\n schema: {\n params: idParamSchema,\n response: {\n 204: emptyResponseSchema,\n 403: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Deletes a user account and removes all of their API tokens.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const systemUserId = db.getSystemUserId();\n const existing = await db.findUserById(request.params.id);\n if (!existing) {\n void reply.code(404).send(errorResponseSchema.parse({ error: 'User not found' }));\n return;\n }\n\n if (denySystemUserTarget(reply, existing, systemUserId)) {\n return;\n }\n\n if (denySelfUserTarget(reply, request.params.id, user.id)) {\n return;\n }\n\n await db.deleteUser(request.params.id, user.id);\n return reply.code(204).send(null);\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'GET',\n url: '/admin/tokens',\n schema: {\n response: {\n 200: listAdminTokensResponseSchema,\n 403: errorResponseSchema\n }\n },\n /**\n * Lists all API bearer tokens for operator administration.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const tokens = await db.listApiTokens();\n return reply.send({\n tokens: tokens.map((record) => serializeApiToken(record))\n });\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'POST',\n url: '/admin/users/:id/tokens',\n schema: {\n params: idParamSchema,\n body: createAdminTokenBodySchema,\n response: {\n 201: createdApiTokenResponseSchema,\n 400: errorResponseSchema,\n 403: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Creates an additional API bearer token for a user account.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const systemUserId = db.getSystemUserId();\n const existing = await db.findUserById(request.params.id);\n if (!existing) {\n void reply.code(404).send(errorResponseSchema.parse({ error: 'User not found' }));\n return;\n }\n\n if (denySystemUserTarget(reply, existing, systemUserId)) {\n return;\n }\n\n const { record, secret } = generateApiToken(existing.id, request.body.name);\n await db.createApiToken(record, user.id);\n\n return reply.code(201).send({\n token: serializeApiToken(record),\n secret\n });\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'DELETE',\n url: '/admin/tokens/:id',\n schema: {\n params: idParamSchema,\n response: {\n 204: emptyResponseSchema,\n 403: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Permanently deletes an API bearer token by id.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const systemUserId = db.getSystemUserId();\n const existing = await db.findApiTokenById(request.params.id);\n if (!existing) {\n void reply.code(404).send(errorResponseSchema.parse({ error: 'Token not found' }));\n return;\n }\n\n const owner = await db.findUserById(existing.userId);\n if (owner && denySystemUserTarget(reply, owner, systemUserId)) {\n return;\n }\n\n const deleted = await db.deleteApiToken(request.params.id, user.id);\n if (!deleted) {\n void reply.code(404).send(errorResponseSchema.parse({ error: 'Token not found' }));\n return;\n }\n\n return reply.code(204).send(null);\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'POST',\n url: '/admin/config/reload',\n schema: {\n response: {\n 200: reloadConfigResponseSchema,\n 400: reloadConfigResponseSchema,\n 403: errorResponseSchema\n }\n },\n /**\n * Re-reads server.yaml and applies reloadable config sections on a best-effort basis.\n */\n handler: async (request, reply) => {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const result = await reloadConfig();\n if (result.fatalError) {\n return reply.code(400).send(result);\n }\n\n return reply.send(result);\n }\n });\n}\n","import type { ApiTokenRecord, UserRecord } from '#/db/types.js';\nimport { canUseDataApi, canUseLlm, isAdmin } from '#/server/auth/accessControl.js';\n\n/**\n * Capability flags derived from the authenticated user account.\n */\nexport interface SessionCapabilities {\n /**\n * When true, the token may call entity data routes (collections, environments, etc.).\n */\n dataApi: boolean;\n\n /**\n * When true, the token may call management routes (user and token administration).\n */\n managementApi: boolean;\n\n /**\n * When true, the token may call hub-proxied LLM routes.\n */\n llm: boolean;\n}\n\n/**\n * JSON payload returned by `GET /auth/session`.\n */\nexport interface SessionPayload {\n /**\n * User account owning the authenticated bearer token.\n */\n user: {\n /**\n * Stable user account identifier.\n */\n id: string;\n\n /**\n * Unique display name for the account.\n */\n name: string;\n\n /**\n * Account role determining API capabilities.\n */\n role: UserRecord['role'];\n };\n\n /**\n * Metadata for the API token used to authenticate the request.\n */\n token: {\n /**\n * Stable token record identifier.\n */\n id: string;\n\n /**\n * Non-secret prefix shown in operator listings (for example `hbk_AbCd1234`).\n */\n prefix: string;\n };\n\n /**\n * Derived capability flags for clients such as HarborClient.\n */\n capabilities: SessionCapabilities;\n}\n\n/**\n * Builds the session payload for the authenticated user and API token.\n *\n * @param user - User account resolved from the bearer token.\n * @param apiToken - Active API token record used for authentication.\n * @returns Session payload suitable for JSON serialization.\n */\nexport function buildSessionPayload(user: UserRecord, apiToken: ApiTokenRecord): SessionPayload {\n return {\n user: {\n id: user.id,\n name: user.name,\n role: user.role\n },\n token: {\n id: apiToken.id,\n prefix: apiToken.tokenPrefix\n },\n capabilities: {\n dataApi: canUseDataApi(user),\n managementApi: isAdmin(user),\n llm: canUseLlm(user)\n }\n };\n}\n","import type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport { buildSessionPayload } from '#/server/auth/sessionCapabilities.js';\nimport { requireAuthenticatedUser } from '#/server/routes/authorize.js';\nimport { sessionResponseSchema } from '#/server/routes/schemas/auth.js';\n\n/**\n * Registers bearer-protected authentication introspection routes.\n *\n * @param app - Encapsulated Fastify scope with auth applied.\n */\nexport async function registerAuthRoutes(app: FastifyInstance): Promise<void> {\n const routes = app.withTypeProvider<ZodTypeProvider>();\n\n routes.route({\n method: 'GET',\n url: '/auth/session',\n schema: {\n response: {\n 200: sessionResponseSchema\n }\n },\n /**\n * Returns the authenticated user, token metadata, and derived API capabilities.\n */\n handler: async (request, reply) => {\n const user = requireAuthenticatedUser(request);\n const apiToken = request.apiToken;\n\n if (!apiToken) {\n throw new Error('Authenticated API token is required');\n }\n\n return reply.send(buildSessionPayload(user, apiToken));\n }\n });\n}\n","import type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport type { IDatabase } from '#/db/IDatabase.js';\nimport {\n canAccessCollection,\n canCreateCollection,\n canDeleteCollection,\n canListCollections,\n canUseDataApi,\n filterAccessibleCollections\n} from '#/server/auth/accessControl.js';\nimport { DeletionLockedError } from '#/db/deletionLockedError.js';\nimport { handleDbError } from '#/server/routes/errors.js';\nimport { denyUnlessAllowed, requireAuthenticatedUser } from '#/server/routes/authorize.js';\nimport { errorResponseSchema, idParamSchema } from '#/server/routes/schemas/common.js';\nimport {\n collectionRecordSchema,\n createCollectionBodySchema,\n emptyResponseSchema,\n listCollectionsResponseSchema,\n serializeCollection,\n updateCollectionBodySchema\n} from '#/server/routes/schemas/entities.js';\n\n/**\n * Registers bearer-protected collection CRUD routes.\n *\n * @param app - Encapsulated Fastify scope with auth applied.\n * @param db - Database used to persist collections.\n */\nexport async function registerCollectionRoutes(app: FastifyInstance, db: IDatabase): Promise<void> {\n const routes = app.withTypeProvider<ZodTypeProvider>();\n\n routes.route({\n method: 'GET',\n url: '/collections',\n schema: {\n response: {\n 200: listCollectionsResponseSchema\n }\n },\n /**\n * Lists all collections ordered by name.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canListCollections(user))) {\n return;\n }\n\n const collections = await db.listCollections();\n return reply.send({\n collections: filterAccessibleCollections(user, collections).map((collection) =>\n serializeCollection(collection)\n )\n });\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'POST',\n url: '/collections',\n schema: {\n body: createCollectionBodySchema,\n response: {\n 200: collectionRecordSchema,\n 400: errorResponseSchema\n }\n },\n /**\n * Creates a new collection with the given display name.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseDataApi(user) && canCreateCollection(user))) {\n return;\n }\n\n const collection = await db.createCollection(request.body.name, user.id);\n return reply.send(serializeCollection(collection));\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'PUT',\n url: '/collections/:id',\n schema: {\n params: idParamSchema,\n body: updateCollectionBodySchema,\n response: {\n 200: collectionRecordSchema,\n 400: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Updates a collection's metadata and defaults.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (\n denyUnlessAllowed(\n reply,\n canUseDataApi(user) && canAccessCollection(user, request.params.id)\n )\n ) {\n return;\n }\n\n const collection = await db.updateCollection(\n request.params.id,\n request.body.name,\n request.body.variables,\n request.body.headers,\n request.body.preRequestScript,\n request.body.postRequestScript,\n request.body.auth,\n user.id\n );\n return reply.send(serializeCollection(collection));\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'DELETE',\n url: '/collections/:id',\n schema: {\n params: idParamSchema,\n response: {\n 204: emptyResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Deletes a collection and all nested folders and requests.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n const collection = await db.findCollectionById(request.params.id);\n if (!collection) {\n void reply.code(404).send({ error: 'Collection not found' });\n return;\n }\n\n if (collection.deletionLocked) {\n throw new DeletionLockedError('collection');\n }\n\n if (denyUnlessAllowed(reply, canDeleteCollection(user, collection))) {\n return;\n }\n\n await db.deleteCollection(request.params.id, user.id);\n return reply.code(204).send(null);\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n}\n","import type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport type { IDatabase } from '#/db/IDatabase.js';\nimport {\n canAccessEnvironment,\n canCreateEnvironment,\n canListEnvironments,\n canUseDataApi,\n filterAccessibleEnvironments\n} from '#/server/auth/accessControl.js';\nimport { DeletionLockedError } from '#/db/deletionLockedError.js';\nimport { handleDbError } from '#/server/routes/errors.js';\nimport { denyUnlessAllowed, requireAuthenticatedUser } from '#/server/routes/authorize.js';\nimport { errorResponseSchema, idParamSchema } from '#/server/routes/schemas/common.js';\nimport {\n createEnvironmentBodySchema,\n emptyResponseSchema,\n environmentRecordSchema,\n listEnvironmentsResponseSchema,\n serializeEnvironment,\n updateEnvironmentBodySchema\n} from '#/server/routes/schemas/entities.js';\n\n/**\n * Registers bearer-protected environment CRUD routes.\n *\n * @param app - Encapsulated Fastify scope with auth applied.\n * @param db - Database used to persist environments.\n */\nexport async function registerEnvironmentRoutes(\n app: FastifyInstance,\n db: IDatabase\n): Promise<void> {\n const routes = app.withTypeProvider<ZodTypeProvider>();\n\n routes.route({\n method: 'GET',\n url: '/environments',\n schema: {\n response: {\n 200: listEnvironmentsResponseSchema\n }\n },\n /**\n * Lists all environments ordered by name.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canListEnvironments(user))) {\n return;\n }\n\n const environments = await db.listEnvironments();\n return reply.send({\n environments: filterAccessibleEnvironments(user, environments).map((environment) =>\n serializeEnvironment(environment)\n )\n });\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'POST',\n url: '/environments',\n schema: {\n body: createEnvironmentBodySchema,\n response: {\n 200: environmentRecordSchema,\n 400: errorResponseSchema\n }\n },\n /**\n * Creates a new environment with the given display name.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseDataApi(user) && canCreateEnvironment(user))) {\n return;\n }\n\n const environment = await db.createEnvironment(request.body.name, user.id);\n return reply.send(serializeEnvironment(environment));\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'PUT',\n url: '/environments/:id',\n schema: {\n params: idParamSchema,\n body: updateEnvironmentBodySchema,\n response: {\n 200: environmentRecordSchema,\n 400: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Updates an environment's name and variables.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (\n denyUnlessAllowed(\n reply,\n canUseDataApi(user) && canAccessEnvironment(user, request.params.id)\n )\n ) {\n return;\n }\n\n const environment = await db.updateEnvironment(\n request.params.id,\n request.body.name,\n request.body.variables,\n user.id\n );\n return reply.send(serializeEnvironment(environment));\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'DELETE',\n url: '/environments/:id',\n schema: {\n params: idParamSchema,\n response: {\n 204: emptyResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Deletes an environment by id.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (\n denyUnlessAllowed(\n reply,\n canUseDataApi(user) && canAccessEnvironment(user, request.params.id)\n )\n ) {\n return;\n }\n\n const environment = await db.findEnvironmentById(request.params.id);\n if (!environment) {\n void reply.code(404).send({ error: 'Environment not found' });\n return;\n }\n\n if (environment.deletionLocked) {\n throw new DeletionLockedError('environment');\n }\n\n await db.deleteEnvironment(request.params.id, user.id);\n return reply.code(204).send(null);\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n}\n","import type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport type { IDatabase } from '#/db/IDatabase.js';\nimport {\n canAccessSnippet,\n canCreateSnippet,\n canListSnippets,\n canUseDataApi,\n filterAccessibleSnippets\n} from '#/server/auth/accessControl.js';\nimport { DeletionLockedError } from '#/db/deletionLockedError.js';\nimport { handleDbError } from '#/server/routes/errors.js';\nimport { denyUnlessAllowed, requireAuthenticatedUser } from '#/server/routes/authorize.js';\nimport { errorResponseSchema, idParamSchema } from '#/server/routes/schemas/common.js';\nimport {\n createSnippetBodySchema,\n emptyResponseSchema,\n listSnippetsResponseSchema,\n serializeSnippet,\n snippetRecordSchema,\n updateSnippetBodySchema\n} from '#/server/routes/schemas/entities.js';\n\n/**\n * Registers bearer-protected snippet CRUD routes.\n *\n * @param app - Encapsulated Fastify scope with auth applied.\n * @param db - Database used to persist snippets.\n */\nexport async function registerSnippetRoutes(app: FastifyInstance, db: IDatabase): Promise<void> {\n const routes = app.withTypeProvider<ZodTypeProvider>();\n\n routes.route({\n method: 'GET',\n url: '/snippets',\n schema: {\n response: {\n 200: listSnippetsResponseSchema\n }\n },\n /**\n * Lists all snippets ordered by sort order then name.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canListSnippets(user))) {\n return;\n }\n\n const snippets = await db.listSnippets();\n return reply.send({\n snippets: filterAccessibleSnippets(user, snippets).map((snippet) =>\n serializeSnippet(snippet)\n )\n });\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'POST',\n url: '/snippets',\n schema: {\n body: createSnippetBodySchema,\n response: {\n 200: snippetRecordSchema,\n 400: errorResponseSchema\n }\n },\n /**\n * Creates a new snippet with the given display name and content.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseDataApi(user) && canCreateSnippet(user))) {\n return;\n }\n\n const snippet = await db.createSnippet(\n request.body.name,\n request.body.code,\n request.body.scope,\n user.id\n );\n return reply.send(serializeSnippet(snippet));\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'PUT',\n url: '/snippets/:id',\n schema: {\n params: idParamSchema,\n body: updateSnippetBodySchema,\n response: {\n 200: snippetRecordSchema,\n 400: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Updates a snippet's name, code, and scope. Sort order is preserved.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (\n denyUnlessAllowed(reply, canUseDataApi(user) && canAccessSnippet(user, request.params.id))\n ) {\n return;\n }\n\n const snippet = await db.updateSnippet(\n request.params.id,\n request.body.name,\n request.body.code,\n request.body.scope,\n user.id\n );\n return reply.send(serializeSnippet(snippet));\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'DELETE',\n url: '/snippets/:id',\n schema: {\n params: idParamSchema,\n response: {\n 204: emptyResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Deletes a snippet by id.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (\n denyUnlessAllowed(reply, canUseDataApi(user) && canAccessSnippet(user, request.params.id))\n ) {\n return;\n }\n\n const snippet = await db.findSnippetById(request.params.id);\n if (!snippet) {\n void reply.code(404).send({ error: 'Snippet not found' });\n return;\n }\n\n if (snippet.deletionLocked) {\n throw new DeletionLockedError('snippet');\n }\n\n await db.deleteSnippet(request.params.id, user.id);\n return reply.code(204).send(null);\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n}\n","import type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport type { IDatabase } from '#/db/IDatabase.js';\nimport { canAccessCollection, canUseDataApi } from '#/server/auth/accessControl.js';\nimport { handleDbError } from '#/server/routes/errors.js';\nimport { denyUnlessAllowed, requireAuthenticatedUser } from '#/server/routes/authorize.js';\nimport {\n collectionIdParamSchema,\n errorResponseSchema,\n idParamSchema\n} from '#/server/routes/schemas/common.js';\nimport {\n createFolderBodySchema,\n emptyResponseSchema,\n folderRecordSchema,\n listFoldersResponseSchema,\n renameFolderBodySchema,\n reorderFoldersBodySchema,\n serializeFolder\n} from '#/server/routes/schemas/entities.js';\n\n/**\n * Registers bearer-protected folder CRUD and reorder routes.\n *\n * @param app - Encapsulated Fastify scope with auth applied.\n * @param db - Database used to persist folders.\n */\nexport async function registerFolderRoutes(app: FastifyInstance, db: IDatabase): Promise<void> {\n const routes = app.withTypeProvider<ZodTypeProvider>();\n\n routes.route({\n method: 'GET',\n url: '/collections/:collectionId/folders',\n schema: {\n params: collectionIdParamSchema,\n response: {\n 200: listFoldersResponseSchema\n }\n },\n /**\n * Lists folders in a collection ordered by sort order then name.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (\n denyUnlessAllowed(\n reply,\n canUseDataApi(user) && canAccessCollection(user, request.params.collectionId)\n )\n ) {\n return;\n }\n\n const folders = await db.listFolders(request.params.collectionId);\n return reply.send({\n folders: folders.map((folder) => serializeFolder(folder))\n });\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'POST',\n url: '/collections/:collectionId/folders',\n schema: {\n params: collectionIdParamSchema,\n body: createFolderBodySchema,\n response: {\n 200: folderRecordSchema,\n 400: errorResponseSchema\n }\n },\n /**\n * Creates a folder in the given collection.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (\n denyUnlessAllowed(\n reply,\n canUseDataApi(user) && canAccessCollection(user, request.params.collectionId)\n )\n ) {\n return;\n }\n\n const folder = await db.createFolder(\n request.params.collectionId,\n request.body.name,\n user.id\n );\n return reply.send(serializeFolder(folder));\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'PATCH',\n url: '/folders/:id',\n schema: {\n params: idParamSchema,\n body: renameFolderBodySchema,\n response: {\n 200: folderRecordSchema,\n 400: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Renames a folder by id.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n const existingFolder = await db.findFolderById(request.params.id);\n if (!existingFolder) {\n return reply.code(404).send({ error: 'Folder not found' });\n }\n\n if (\n denyUnlessAllowed(\n reply,\n canUseDataApi(user) && canAccessCollection(user, existingFolder.collectionId)\n )\n ) {\n return;\n }\n\n const folder = await db.renameFolder(request.params.id, request.body.name, user.id);\n return reply.send(serializeFolder(folder));\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'DELETE',\n url: '/folders/:id',\n schema: {\n params: idParamSchema,\n response: {\n 204: emptyResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Deletes a folder and all requests inside it.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n const existingFolder = await db.findFolderById(request.params.id);\n if (!existingFolder) {\n return reply.code(404).send({ error: 'Folder not found' });\n }\n\n if (\n denyUnlessAllowed(\n reply,\n canUseDataApi(user) && canAccessCollection(user, existingFolder.collectionId)\n )\n ) {\n return;\n }\n\n await db.deleteFolder(request.params.id, user.id);\n return reply.code(204).send(null);\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'PUT',\n url: '/collections/:collectionId/folders/reorder',\n schema: {\n params: collectionIdParamSchema,\n body: reorderFoldersBodySchema,\n response: {\n 204: emptyResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Reorders folders within a collection.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (\n denyUnlessAllowed(\n reply,\n canUseDataApi(user) && canAccessCollection(user, request.params.collectionId)\n )\n ) {\n return;\n }\n\n await db.reorderFolders(\n request.params.collectionId,\n request.body.orderedFolderIds,\n user.id\n );\n return reply.code(204).send(null);\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n}\n","import { z } from 'zod/v4';\nimport type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\n\n/**\n * Response body schema for `GET /health`.\n */\nexport const healthResponseSchema = z.object({\n status: z.literal('ok'),\n version: z.string()\n});\n\n/**\n * Registers the health check route used by probes and desktop client connectivity checks.\n *\n * @param app - Fastify server instance.\n * @param version - Application version included in the JSON response.\n */\nexport async function registerHealthRoute(app: FastifyInstance, version: string): Promise<void> {\n app.withTypeProvider<ZodTypeProvider>().route({\n method: 'GET',\n url: '/health',\n schema: {\n response: {\n 200: healthResponseSchema\n }\n },\n /**\n * Returns the standard health payload for load balancers and client pings.\n */\n handler: async (_request, reply) => {\n return reply.send({\n status: 'ok' as const,\n version\n });\n }\n });\n}\n","import type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport type { IDatabase } from '#/db/IDatabase.js';\nimport {\n canAccessCollection,\n canDeleteRequest,\n canUseDataApi\n} from '#/server/auth/accessControl.js';\nimport { handleDbError } from '#/server/routes/errors.js';\nimport { denyUnlessAllowed, requireAuthenticatedUser } from '#/server/routes/authorize.js';\nimport {\n collectionIdParamSchema,\n errorResponseSchema,\n idParamSchema\n} from '#/server/routes/schemas/common.js';\nimport {\n emptyResponseSchema,\n listRequestsResponseSchema,\n moveRequestBodySchema,\n reorderRequestsBodySchema,\n savedRequestRecordSchema,\n saveRequestBodySchema,\n serializeSavedRequest,\n updateSaveRequestBodySchema\n} from '#/server/routes/schemas/entities.js';\n\n/**\n * Registers bearer-protected saved request CRUD, reorder, and move routes.\n *\n * @param app - Encapsulated Fastify scope with auth applied.\n * @param db - Database used to persist saved requests.\n */\nexport async function registerRequestRoutes(app: FastifyInstance, db: IDatabase): Promise<void> {\n const routes = app.withTypeProvider<ZodTypeProvider>();\n\n routes.route({\n method: 'GET',\n url: '/collections/:collectionId/requests',\n schema: {\n params: collectionIdParamSchema,\n response: {\n 200: listRequestsResponseSchema\n }\n },\n /**\n * Lists saved requests in a collection.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (\n denyUnlessAllowed(\n reply,\n canUseDataApi(user) && canAccessCollection(user, request.params.collectionId)\n )\n ) {\n return;\n }\n\n const requests = await db.listRequests(request.params.collectionId);\n return reply.send({\n requests: requests.map((savedRequest) => serializeSavedRequest(savedRequest))\n });\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'POST',\n url: '/collections/:collectionId/requests',\n schema: {\n params: collectionIdParamSchema,\n body: saveRequestBodySchema,\n response: {\n 200: savedRequestRecordSchema,\n 400: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Creates a new saved request in a collection.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (\n denyUnlessAllowed(\n reply,\n canUseDataApi(user) && canAccessCollection(user, request.params.collectionId)\n )\n ) {\n return;\n }\n\n const savedRequest = await db.saveRequest(\n {\n collectionId: request.params.collectionId,\n name: request.body.name,\n method: request.body.method,\n url: request.body.url,\n headers: request.body.headers,\n params: request.body.params,\n auth: request.body.auth,\n body: request.body.body,\n bodyType: request.body.bodyType,\n preRequestScript: request.body.preRequestScript,\n postRequestScript: request.body.postRequestScript,\n comment: request.body.comment,\n folderId: request.body.folderId ?? null\n },\n user.id\n );\n return reply.send(serializeSavedRequest(savedRequest));\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'PUT',\n url: '/requests/:id',\n schema: {\n params: idParamSchema,\n body: updateSaveRequestBodySchema,\n response: {\n 200: savedRequestRecordSchema,\n 400: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Updates an existing saved request by id.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (\n denyUnlessAllowed(\n reply,\n canUseDataApi(user) && canAccessCollection(user, request.body.collectionId)\n )\n ) {\n return;\n }\n\n const savedRequest = await db.saveRequest(\n {\n id: request.params.id,\n collectionId: request.body.collectionId,\n name: request.body.name,\n method: request.body.method,\n url: request.body.url,\n headers: request.body.headers,\n params: request.body.params,\n auth: request.body.auth,\n body: request.body.body,\n bodyType: request.body.bodyType,\n preRequestScript: request.body.preRequestScript,\n postRequestScript: request.body.postRequestScript,\n comment: request.body.comment,\n folderId: request.body.folderId ?? null\n },\n user.id\n );\n return reply.send(serializeSavedRequest(savedRequest));\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'DELETE',\n url: '/requests/:id',\n schema: {\n params: idParamSchema,\n response: {\n 204: emptyResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Deletes a saved request by id.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n const existingRequest = await db.findRequestById(request.params.id);\n if (!existingRequest) {\n return reply.code(404).send({ error: 'Request not found' });\n }\n\n if (denyUnlessAllowed(reply, canDeleteRequest(user, existingRequest))) {\n return;\n }\n\n await db.deleteRequest(request.params.id, user.id);\n return reply.code(204).send(null);\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'PUT',\n url: '/collections/:collectionId/requests/reorder',\n schema: {\n params: collectionIdParamSchema,\n body: reorderRequestsBodySchema,\n response: {\n 204: emptyResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Reorders saved requests within a folder or collection root.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (\n denyUnlessAllowed(\n reply,\n canUseDataApi(user) && canAccessCollection(user, request.params.collectionId)\n )\n ) {\n return;\n }\n\n await db.reorderRequests(\n request.params.collectionId,\n request.body.folderId,\n request.body.orderedRequestIds,\n user.id\n );\n return reply.code(204).send(null);\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'PUT',\n url: '/requests/:id/move',\n schema: {\n params: idParamSchema,\n body: moveRequestBodySchema,\n response: {\n 204: emptyResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Moves a saved request to another folder or collection root index.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n const existingRequest = await db.findRequestById(request.params.id);\n if (!existingRequest) {\n return reply.code(404).send({ error: 'Request not found' });\n }\n\n if (\n denyUnlessAllowed(\n reply,\n canUseDataApi(user) && canAccessCollection(user, existingRequest.collectionId)\n )\n ) {\n return;\n }\n\n await db.moveRequest(request.params.id, request.body.folderId, request.body.index, user.id);\n return reply.code(204).send(null);\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n}\n","import type { LlmConfig, LlmProvider } from '#/config/llmConfig.js';\nimport { getHubModelById } from '#/server/llm/models.js';\n\nconst OPENAI_BASE_URL = 'https://api.openai.com/v1';\nconst CLAUDE_BASE_URL = 'https://api.anthropic.com/v1';\nconst GEMINI_BASE_URL = 'https://generativelanguage.googleapis.com/v1beta/openai';\n\n/**\n * Serializable tool call returned from a provider completion.\n */\nexport interface LlmToolCall {\n /**\n * Tool call id from the model.\n */\n id: string;\n\n /**\n * Tool function name.\n */\n name: string;\n\n /**\n * JSON-encoded tool arguments.\n */\n arguments: string;\n}\n\n/**\n * Token usage reported by the provider for one completion.\n */\nexport interface LlmCompletionUsage {\n /**\n * Prompt tokens consumed by the request.\n */\n promptTokens: number;\n\n /**\n * Completion tokens generated by the model.\n */\n completionTokens: number;\n\n /**\n * Total tokens billed for the request.\n */\n totalTokens: number;\n}\n\n/**\n * Normalized result of one OpenAI-compatible chat completion.\n */\nexport interface LlmCompletionResult {\n /**\n * Assistant text when the model finishes without tool calls.\n */\n content: string | null;\n\n /**\n * Tool calls requested by the assistant, when present.\n */\n toolCalls?: LlmToolCall[];\n\n /**\n * Token usage for metering.\n */\n usage: LlmCompletionUsage;\n}\n\n/**\n * Message role accepted by the OpenAI-compatible chat API.\n */\nexport type LlmChatMessageRole = 'system' | 'user' | 'assistant' | 'tool';\n\n/**\n * Serializable chat message for provider requests.\n */\nexport interface LlmChatMessage {\n /**\n * OpenAI-compatible message role.\n */\n role: LlmChatMessageRole;\n\n /**\n * Text content for the message.\n */\n content?: string | null;\n\n /**\n * Tool calls on assistant messages.\n */\n tool_calls?: LlmToolCall[];\n\n /**\n * Tool call id for tool role messages.\n */\n tool_call_id?: string;\n\n /**\n * Optional tool name for tool role messages.\n */\n name?: string;\n}\n\n/**\n * OpenAI-compatible tool definition passed through from the client.\n */\nexport type LlmToolDefinition = Record<string, unknown>;\n\n/**\n * Input for one hub-proxied chat completion.\n */\nexport interface RunLlmCompletionInput {\n /**\n * Provider-specific model id.\n */\n model: string;\n\n /**\n * Conversation messages excluding the system prompt.\n */\n messages: LlmChatMessage[];\n\n /**\n * Optional system prompt injected ahead of messages.\n */\n systemPrompt?: string;\n\n /**\n * Optional tool definitions forwarded to the provider.\n */\n tools?: LlmToolDefinition[];\n}\n\n/**\n * Resolves the base URL for an OpenAI-compatible provider.\n *\n * @param provider - LLM provider to call.\n */\nfunction resolveProviderBaseUrl(provider: LlmProvider): string {\n switch (provider) {\n case 'openai':\n return OPENAI_BASE_URL;\n case 'claude':\n return CLAUDE_BASE_URL;\n case 'gemini':\n return GEMINI_BASE_URL;\n default: {\n const exhaustive: never = provider;\n return exhaustive;\n }\n }\n}\n\n/**\n * Maps hub messages into OpenAI-compatible request message objects.\n *\n * @param messages - Messages from the client step request.\n */\nfunction toProviderMessages(messages: LlmChatMessage[]): Record<string, unknown>[] {\n return messages.map((message) => {\n if (message.role === 'assistant' && message.tool_calls?.length) {\n return {\n role: 'assistant',\n content: message.content ?? null,\n tool_calls: message.tool_calls.map((call) => ({\n id: call.id,\n type: 'function',\n function: {\n name: call.name,\n arguments: call.arguments\n }\n }))\n };\n }\n\n if (message.role === 'tool') {\n return {\n role: 'tool',\n tool_call_id: message.tool_call_id ?? '',\n content: message.content ?? ''\n };\n }\n\n return {\n role: message.role,\n content: message.content ?? ''\n };\n });\n}\n\n/**\n * Parses provider usage fields into normalized token counts.\n *\n * @param usage - Raw usage object from the provider response.\n */\nfunction parseUsage(usage: Record<string, unknown> | undefined): LlmCompletionUsage {\n const promptTokens = typeof usage?.prompt_tokens === 'number' ? usage.prompt_tokens : 0;\n const completionTokens =\n typeof usage?.completion_tokens === 'number' ? usage.completion_tokens : 0;\n const totalTokens =\n typeof usage?.total_tokens === 'number' ? usage.total_tokens : promptTokens + completionTokens;\n\n return {\n promptTokens,\n completionTokens,\n totalTokens\n };\n}\n\n/**\n * Parses an OpenAI-compatible chat completion response body.\n *\n * @param json - Parsed JSON response body.\n */\nfunction parseCompletionResponse(json: Record<string, unknown>): LlmCompletionResult {\n const choices = json.choices;\n if (!Array.isArray(choices) || choices.length === 0) {\n throw new Error('The model returned an empty response.');\n }\n\n const message = choices[0]?.message as Record<string, unknown> | undefined;\n if (!message) {\n throw new Error('The model returned an empty response.');\n }\n\n const rawToolCalls = message.tool_calls;\n const toolCalls = Array.isArray(rawToolCalls)\n ? rawToolCalls\n .filter((call): call is Record<string, unknown> => call != null && typeof call === 'object')\n .filter((call) => call.type === 'function')\n .map((call) => {\n const fn = call.function as Record<string, unknown> | undefined;\n return {\n id: String(call.id ?? ''),\n name: String(fn?.name ?? ''),\n arguments: String(fn?.arguments ?? '')\n };\n })\n .filter((call) => call.id && call.name)\n : undefined;\n\n const content = typeof message.content === 'string' ? message.content : null;\n\n return {\n content,\n ...(toolCalls && toolCalls.length > 0 ? { toolCalls } : {}),\n usage: parseUsage(json.usage as Record<string, unknown> | undefined)\n };\n}\n\n/**\n * Runs one OpenAI-compatible chat completion against a configured provider.\n *\n * @param config - Hub LLM configuration with provider API keys.\n * @param input - Model, messages, optional system prompt, and tools.\n * @returns Normalized assistant content, tool calls, and usage.\n */\nexport async function runLlmCompletion(\n config: LlmConfig,\n input: RunLlmCompletionInput\n): Promise<LlmCompletionResult> {\n const modelEntry = getHubModelById(input.model);\n if (!modelEntry) {\n throw new Error(`Unknown model: ${input.model}`);\n }\n\n const providerConfig = config.providers[modelEntry.provider];\n if (!providerConfig?.apiKey.trim()) {\n throw new Error(`Provider ${modelEntry.provider} is not configured on this hub.`);\n }\n\n const messages: Record<string, unknown>[] = [];\n if (input.systemPrompt?.trim()) {\n messages.push({ role: 'system', content: input.systemPrompt });\n }\n messages.push(...toProviderMessages(input.messages));\n\n const body: Record<string, unknown> = {\n model: modelEntry.id,\n messages\n };\n\n if (input.tools && input.tools.length > 0) {\n body.tools = input.tools;\n }\n\n const response = await fetch(`${resolveProviderBaseUrl(modelEntry.provider)}/chat/completions`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${providerConfig.apiKey}`,\n 'Content-Type': 'application/json',\n Accept: 'application/json'\n },\n body: JSON.stringify(body)\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n errorText.trim() || `LLM request failed with status ${response.status.toString()}`\n );\n }\n\n const json = (await response.json()) as Record<string, unknown>;\n return parseCompletionResponse(json);\n}\n","/**\n * Prefix for hub-configured MCP tools merged into chat completions.\n */\nexport const HUB_MCP_TOOL_PREFIX = 'hubmcp__';\n\n/**\n * Builds a prefixed hub MCP tool name for LLM routing.\n *\n * @param serverIndex - Zero-based index in llm.mcp config.\n * @param toolName - Original tool name from the remote server.\n */\nexport function encodeHubMcpToolName(serverIndex: number, toolName: string): string {\n return `${HUB_MCP_TOOL_PREFIX}${serverIndex}__${toolName}`;\n}\n\n/**\n * Parses a prefixed hub MCP tool name into server index and original tool name.\n *\n * @param prefixed - Tool name from an assistant tool call.\n */\nexport function decodeHubMcpToolName(\n prefixed: string\n): { serverIndex: number; toolName: string } | null {\n if (!prefixed.startsWith(HUB_MCP_TOOL_PREFIX)) {\n return null;\n }\n\n const rest = prefixed.slice(HUB_MCP_TOOL_PREFIX.length);\n const separatorIndex = rest.indexOf('__');\n if (separatorIndex <= 0) {\n return null;\n }\n\n const serverIndex = Number.parseInt(rest.slice(0, separatorIndex), 10);\n if (!Number.isInteger(serverIndex) || serverIndex < 0) {\n return null;\n }\n\n const toolName = rest.slice(separatorIndex + 2);\n if (!toolName) {\n return null;\n }\n\n return { serverIndex, toolName };\n}\n\n/**\n * Returns whether a tool name belongs to a hub-configured MCP server.\n *\n * @param name - Tool name from the model.\n */\nexport function isHubMcpToolName(name: string): boolean {\n return decodeHubMcpToolName(name) !== null;\n}\n","import { Client } from '@modelcontextprotocol/sdk/client/index.js';\nimport { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';\nimport { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';\nimport type { Tool } from '@modelcontextprotocol/sdk/types.js';\nimport type { HubMcpHeader, LlmConfig } from '#/config/llmConfig.js';\nimport type { LlmToolDefinition } from '#/server/llm/client.js';\nimport { decodeHubMcpToolName, encodeHubMcpToolName } from '#/server/llm/hubMcpToolNames.js';\n\n/**\n * OpenAI-compatible tool definition returned to the LLM provider.\n */\nexport interface HubMcpOpenAiTool extends LlmToolDefinition {\n type: 'function';\n function: {\n name: string;\n description?: string;\n parameters: Record<string, unknown>;\n };\n}\n\ninterface ConnectedHubMcpClient {\n serverIndex: number;\n client: Client;\n remoteTools: Tool[];\n}\n\nconst connectedClients = new Map<number, ConnectedHubMcpClient>();\nlet activeConfigSignature = '';\n\n/**\n * Builds HTTP headers for one hub MCP connection.\n *\n * @param headers - Normalized header rows from config.\n */\nfunction buildRequestHeaders(headers: HubMcpHeader[]): Record<string, string> {\n const result: Record<string, string> = {};\n for (const row of headers) {\n if (row.key.trim()) {\n result[row.key.trim()] = row.value;\n }\n }\n return result;\n}\n\n/**\n * Serializes llm.mcp for connection cache comparisons.\n *\n * @param config - Hub LLM configuration.\n */\nfunction buildMcpConfigSignature(config: LlmConfig): string {\n return JSON.stringify(config.mcp ?? []);\n}\n\n/**\n * Flattens MCP callTool content into a JSON string for the agent loop.\n *\n * @param content - MCP tool result content array.\n */\nfunction flattenMcpToolContent(content: unknown): string {\n if (!Array.isArray(content)) {\n return JSON.stringify(content ?? null);\n }\n\n const parts = content.map((item) => {\n if (!item || typeof item !== 'object') {\n return String(item);\n }\n\n const record = item as { type?: string; text?: string; uri?: string };\n if (record.type === 'text' && typeof record.text === 'string') {\n return record.text;\n }\n\n if (record.type === 'resource' && typeof record.uri === 'string') {\n return record.uri;\n }\n\n return JSON.stringify(record);\n });\n\n return parts.join('\\n');\n}\n\n/**\n * Converts remote MCP tool metadata into an OpenAI function tool definition.\n *\n * @param serverIndex - Zero-based index in llm.mcp.\n * @param tool - Tool metadata from tools/list.\n */\nfunction toOpenAiTool(serverIndex: number, tool: Tool): HubMcpOpenAiTool {\n return {\n type: 'function',\n function: {\n name: encodeHubMcpToolName(serverIndex, tool.name),\n description: tool.description ?? `MCP tool ${tool.name}`,\n parameters: (tool.inputSchema as Record<string, unknown> | undefined) ?? {\n type: 'object',\n properties: {},\n additionalProperties: true\n }\n }\n };\n}\n\n/**\n * Connects to one configured hub MCP server and caches its tools.\n *\n * @param serverIndex - Zero-based index in llm.mcp.\n * @param server - MCP server configuration entry.\n */\nasync function connectHubMcpServer(\n serverIndex: number,\n server: NonNullable<LlmConfig['mcp']>[number]\n): Promise<ConnectedHubMcpClient> {\n const headers = buildRequestHeaders(server.headers);\n const url = new URL(server.url);\n\n const client = new Client(\n {\n name: 'team-hub',\n version: '1.0.0'\n },\n {}\n );\n\n let transport: StreamableHTTPClientTransport | SSEClientTransport;\n try {\n transport = new StreamableHTTPClientTransport(url, {\n requestInit: { headers }\n });\n await client.connect(transport);\n } catch {\n transport = new SSEClientTransport(url, {\n requestInit: { headers }\n });\n await client.connect(transport);\n }\n\n const { tools } = await client.listTools();\n\n return {\n serverIndex,\n client,\n remoteTools: tools\n };\n}\n\n/**\n * Reconciles cached MCP connections with the current llm.mcp configuration.\n *\n * @param config - Hub LLM configuration.\n */\nexport async function ensureHubMcpConnections(config: LlmConfig): Promise<void> {\n const servers = config.mcp ?? [];\n const signature = buildMcpConfigSignature(config);\n\n if (signature !== activeConfigSignature) {\n await disposeHubMcpConnections();\n activeConfigSignature = signature;\n }\n\n if (servers.length === 0) {\n return;\n }\n\n for (const [index, server] of servers.entries()) {\n if (connectedClients.has(index)) {\n continue;\n }\n\n try {\n const connected = await connectHubMcpServer(index, server);\n connectedClients.set(index, connected);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Connection failed';\n console.warn(`Hub MCP server \"${server.name}\" failed to connect: ${message}`);\n }\n }\n}\n\n/**\n * Lists hub MCP tools in OpenAI chat completion format.\n *\n * Call {@link ensureHubMcpConnections} first so the connection cache is populated.\n */\nexport function listHubMcpTools(): HubMcpOpenAiTool[] {\n const tools: HubMcpOpenAiTool[] = [];\n\n for (const entry of connectedClients.values()) {\n for (const tool of entry.remoteTools) {\n tools.push(toOpenAiTool(entry.serverIndex, tool));\n }\n }\n\n return tools;\n}\n\n/**\n * Invokes one prefixed hub MCP tool on the matching remote server.\n *\n * @param prefixedName - Tool name with hubmcp__ prefix from the model.\n * @param args - Parsed tool arguments object.\n */\nexport async function callHubMcpTool(prefixedName: string, args: unknown): Promise<string> {\n const decoded = decodeHubMcpToolName(prefixedName);\n if (!decoded) {\n return JSON.stringify({ error: `Unknown hub MCP tool: ${prefixedName}` });\n }\n\n const entry = connectedClients.get(decoded.serverIndex);\n if (!entry) {\n return JSON.stringify({ error: `Hub MCP server ${decoded.serverIndex} is not connected.` });\n }\n\n try {\n const result = await entry.client.callTool({\n name: decoded.toolName,\n arguments: (args ?? {}) as Record<string, unknown>\n });\n\n if (result.isError) {\n return JSON.stringify({\n error: flattenMcpToolContent(result.content)\n });\n }\n\n return flattenMcpToolContent(result.content);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'MCP tool execution failed.';\n return JSON.stringify({ error: message });\n }\n}\n\n/**\n * Closes all hub MCP client connections.\n */\nexport async function disposeHubMcpConnections(): Promise<void> {\n const closePromises = [...connectedClients.values()].map(async (entry) => {\n try {\n await entry.client.close();\n } catch {\n // Ignore close errors during teardown.\n }\n });\n\n connectedClients.clear();\n activeConfigSignature = '';\n await Promise.allSettled(closePromises);\n}\n","import type { LlmConfig } from '#/config/llmConfig.js';\nimport {\n runLlmCompletion,\n type LlmChatMessage,\n type LlmCompletionResult,\n type LlmCompletionUsage,\n type LlmToolCall,\n type LlmToolDefinition\n} from '#/server/llm/client.js';\nimport { isHubMcpToolName } from '#/server/llm/hubMcpToolNames.js';\nimport {\n callHubMcpTool,\n ensureHubMcpConnections,\n listHubMcpTools,\n type HubMcpOpenAiTool\n} from '#/server/llm/mcpClient.js';\n\n/**\n * Maximum server-side MCP tool iterations per chat step.\n */\nexport const HUB_CHAT_STEP_MAX_ITERATIONS = 8;\n\n/**\n * Input for one hub chat step, including client tools and conversation history.\n */\nexport interface HubChatStepInput {\n model: string;\n messages: LlmChatMessage[];\n systemPrompt?: string;\n tools?: LlmToolDefinition[];\n}\n\n/**\n * Result of one hub chat step after optional server-side MCP execution.\n */\nexport interface HubChatStepResult {\n content: string | null;\n toolCalls?: LlmToolCall[];\n usage: LlmCompletionUsage;\n}\n\n/**\n * Injectable dependencies for {@link runHubChatStep} in tests.\n */\nexport interface HubChatStepDeps {\n runCompletion: (\n config: LlmConfig,\n input: {\n model: string;\n messages: LlmChatMessage[];\n systemPrompt?: string;\n tools?: HubChatStepInput['tools'];\n }\n ) => Promise<LlmCompletionResult>;\n ensureConnections: (config: LlmConfig) => Promise<void>;\n listTools: () => HubMcpOpenAiTool[];\n callTool: (prefixedName: string, args: unknown) => Promise<string>;\n}\n\n/**\n * Sums token usage across multiple provider completions.\n *\n * @param current - Accumulated usage so far.\n * @param next - Usage from the latest completion.\n */\nfunction addUsage(current: LlmCompletionUsage, next: LlmCompletionUsage): LlmCompletionUsage {\n return {\n promptTokens: current.promptTokens + next.promptTokens,\n completionTokens: current.completionTokens + next.completionTokens,\n totalTokens: current.totalTokens + next.totalTokens\n };\n}\n\n/**\n * Parses tool call arguments from the provider into a JSON value.\n *\n * @param raw - Raw arguments string from the model.\n */\nfunction parseToolArguments(raw: string): unknown {\n try {\n return JSON.parse(raw) as unknown;\n } catch {\n return {};\n }\n}\n\n/**\n * Runs one hub chat step, executing hub MCP tools server-side until a client\n * tool call or final text response is reached.\n *\n * @param config - Hub LLM configuration including optional MCP servers.\n * @param input - Model, messages, system prompt, and client tools.\n * @param deps - Optional overrides for completion and MCP helpers (tests).\n */\nexport async function runHubChatStep(\n config: LlmConfig,\n input: HubChatStepInput,\n deps: Partial<HubChatStepDeps> = {}\n): Promise<HubChatStepResult> {\n const runCompletion = deps.runCompletion ?? runLlmCompletion;\n const ensureConnections = deps.ensureConnections ?? ensureHubMcpConnections;\n const listTools = deps.listTools ?? listHubMcpTools;\n const callTool = deps.callTool ?? callHubMcpTool;\n\n await ensureConnections(config);\n\n const hubTools = listTools();\n const mergedTools: LlmToolDefinition[] | undefined =\n hubTools.length > 0 || (input.tools?.length ?? 0) > 0\n ? [...hubTools, ...(input.tools ?? [])]\n : undefined;\n\n let messages = [...input.messages];\n let usage: LlmCompletionUsage = { promptTokens: 0, completionTokens: 0, totalTokens: 0 };\n let lastContent: string | null = null;\n\n for (let iteration = 0; iteration < HUB_CHAT_STEP_MAX_ITERATIONS; iteration += 1) {\n const result = await runCompletion(config, {\n model: input.model,\n messages,\n systemPrompt: input.systemPrompt,\n tools: mergedTools\n });\n\n usage = addUsage(usage, result.usage);\n lastContent = result.content;\n\n const toolCalls = result.toolCalls ?? [];\n if (toolCalls.length === 0) {\n return {\n content: result.content,\n usage\n };\n }\n\n const hubCalls = toolCalls.filter((call) => isHubMcpToolName(call.name));\n const passthroughCalls = toolCalls.filter((call) => !isHubMcpToolName(call.name));\n\n if (passthroughCalls.length > 0) {\n return {\n content: result.content,\n toolCalls: passthroughCalls,\n usage\n };\n }\n\n messages = [\n ...messages,\n {\n role: 'assistant',\n content: result.content,\n tool_calls: hubCalls\n }\n ];\n\n for (const call of hubCalls) {\n const toolResult = await callTool(call.name, parseToolArguments(call.arguments));\n messages.push({\n role: 'tool',\n tool_call_id: call.id,\n content: toolResult\n });\n }\n }\n\n return {\n content: lastContent,\n usage\n };\n}\n","import type { FastifyInstance } from 'fastify';\nimport type { FastifyReply } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport type { LlmConfig } from '#/config/llmConfig.js';\nimport type { IDatabase } from '#/db/IDatabase.js';\nimport { canUseLlm, isLlmModelAllowed, isOverMonthlyLimit } from '#/server/auth/accessControl.js';\nimport { runHubChatStep } from '#/server/llm/agent.js';\nimport {\n currentUsagePeriod,\n getHubModelById,\n isHubModelOffered,\n listHubOfferedModels\n} from '#/server/llm/models.js';\nimport { denyUnlessAllowed, requireAuthenticatedUser } from '#/server/routes/authorize.js';\nimport { errorResponseSchema } from '#/server/routes/schemas/common.js';\nimport {\n listLlmModelsResponseSchema,\n llmChatStepBodySchema,\n llmChatStepResponseSchema,\n llmUsageSummaryResponseSchema\n} from '#/server/routes/schemas/llm.js';\n\n/**\n * Options for registering LLM proxy routes.\n */\nexport interface RegisterLlmRoutesOptions {\n /**\n * Database used for usage metering and user access checks.\n */\n db: IDatabase;\n\n /**\n * Returns the current normalized LLM configuration from server.yaml.\n */\n getLlm: () => LlmConfig | null;\n}\n\n/**\n * Sends a 402 response when the user has exceeded their monthly token limit.\n *\n * @param reply - Fastify reply used to short-circuit the handler.\n */\nfunction sendMonthlyLimitExceeded(reply: FastifyReply): FastifyReply {\n return reply.code(402).send({\n error: 'Monthly LLM token limit reached. Try again next month or contact your administrator.'\n });\n}\n\n/**\n * Sends a 503 response when LLM support is not configured on the hub.\n *\n * @param reply - Fastify reply used to short-circuit the handler.\n */\nfunction sendLlmUnavailable(reply: FastifyReply): FastifyReply {\n return reply.code(503).send({\n error: 'LLM support is not configured on this Team Hub.'\n });\n}\n\n/**\n * Registers bearer-protected LLM proxy routes.\n *\n * @param app - Encapsulated Fastify scope with auth applied.\n * @param options - Database and LLM configuration.\n */\nexport async function registerLlmRoutes(\n app: FastifyInstance,\n options: RegisterLlmRoutesOptions\n): Promise<void> {\n const routes = app.withTypeProvider<ZodTypeProvider>();\n\n routes.route({\n method: 'GET',\n url: '/llm/models',\n schema: {\n response: {\n 200: listLlmModelsResponseSchema,\n 403: errorResponseSchema,\n 503: errorResponseSchema\n }\n },\n /**\n * Lists hub-offered models the authenticated user may use.\n */\n handler: async (request, reply) => {\n const llm = options.getLlm();\n if (!llm) {\n return sendLlmUnavailable(reply);\n }\n\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseLlm(user))) {\n return;\n }\n\n const offered = listHubOfferedModels(llm).filter((model) =>\n isLlmModelAllowed(user, model.id)\n );\n\n return reply.send({\n models: offered.map((model) => ({\n id: model.id,\n label: model.label,\n provider: model.provider\n }))\n });\n }\n });\n\n routes.route({\n method: 'GET',\n url: '/llm/usage',\n schema: {\n response: {\n 200: llmUsageSummaryResponseSchema,\n 403: errorResponseSchema,\n 503: errorResponseSchema\n }\n },\n /**\n * Returns the authenticated user's current monthly LLM usage summary.\n */\n handler: async (request, reply) => {\n const llm = options.getLlm();\n if (!llm) {\n return sendLlmUnavailable(reply);\n }\n\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseLlm(user))) {\n return;\n }\n\n const period = currentUsagePeriod();\n const usage = await options.db.getLlmUsage(user.id, period);\n\n return reply.send({\n period,\n totalTokens: usage?.totalTokens ?? 0,\n limit: user.llmMonthlyTokenLimit\n });\n }\n });\n\n routes.route({\n method: 'POST',\n url: '/llm/chat/step',\n schema: {\n body: llmChatStepBodySchema,\n response: {\n 200: llmChatStepResponseSchema,\n 402: errorResponseSchema,\n 403: errorResponseSchema,\n 503: errorResponseSchema\n }\n },\n /**\n * Runs one stateless LLM completion step using hub-configured provider keys.\n */\n handler: async (request, reply) => {\n const llm = options.getLlm();\n if (!llm) {\n return sendLlmUnavailable(reply);\n }\n\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseLlm(user))) {\n return;\n }\n\n const { model, messages, tools, systemPrompt } = request.body;\n\n if (!isHubModelOffered(llm, model)) {\n return reply.code(403).send({ error: 'Model is not offered by this Team Hub.' });\n }\n\n if (!isLlmModelAllowed(user, model)) {\n return reply.code(403).send({ error: 'You are not allowed to use this model.' });\n }\n\n const period = currentUsagePeriod();\n const usage = await options.db.getLlmUsage(user.id, period);\n const totalTokens = usage?.totalTokens ?? 0;\n const lastMessage = messages.at(-1);\n const isNewTurn = lastMessage?.role === 'user';\n\n if (isNewTurn && isOverMonthlyLimit(totalTokens, user.llmMonthlyTokenLimit)) {\n return sendMonthlyLimitExceeded(reply);\n }\n\n const result = await runHubChatStep(llm, {\n model,\n messages,\n tools,\n systemPrompt\n });\n\n const catalogModel = getHubModelById(model);\n if (!catalogModel) {\n throw new Error(`Unknown hub model: ${model}`);\n }\n\n await options.db.addLlmUsage(\n user.id,\n period,\n result.usage.promptTokens,\n result.usage.completionTokens\n );\n\n await options.db.createLlmUsageLog({\n userId: user.id,\n apiTokenId: request.apiToken?.id ?? null,\n period,\n model,\n provider: catalogModel.provider,\n promptTokens: result.usage.promptTokens,\n completionTokens: result.usage.completionTokens,\n totalTokens: result.usage.totalTokens,\n isNewTurn,\n hadToolCalls: Boolean(result.toolCalls && result.toolCalls.length > 0),\n messageCount: messages.length\n });\n\n return reply.send({\n content: result.content,\n ...(result.toolCalls && result.toolCalls.length > 0 ? { toolCalls: result.toolCalls } : {}),\n usage: result.usage\n });\n }\n });\n}\n","import { z } from 'zod/v4';\n\n/**\n * Response schema for Team Hub plugin source URLs exposed to HarborClient.\n */\nexport const pluginSourcesResponseSchema = z.object({\n catalogs: z.array(z.string()),\n trusted: z.array(z.string())\n});\n\n/**\n * Validated plugin source URLs returned by GET /plugins/sources.\n */\nexport type PluginSourcesResponse = z.infer<typeof pluginSourcesResponseSchema>;\n","import type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport type { PluginsConfig } from '#/config/pluginsConfig.js';\nimport { pluginSourcesResponseSchema } from '#/server/routes/schemas/plugins.js';\n\n/**\n * Options for registering plugin source routes.\n */\nexport interface RegisterPluginsRoutesOptions {\n /**\n * Returns the current normalized plugin source configuration from server.yaml.\n */\n getPlugins: () => PluginsConfig | null;\n}\n\n/**\n * Registers bearer-protected plugin source routes.\n *\n * @param app - Encapsulated Fastify scope with auth applied.\n * @param options - Plugin source configuration from server.yaml.\n */\nexport async function registerPluginsRoutes(\n app: FastifyInstance,\n options: RegisterPluginsRoutesOptions\n): Promise<void> {\n const routes = app.withTypeProvider<ZodTypeProvider>();\n\n routes.route({\n method: 'GET',\n url: '/plugins/sources',\n schema: {\n response: {\n 200: pluginSourcesResponseSchema\n }\n },\n /**\n * Returns plugin catalog and trusted-publisher URLs configured on this Team Hub.\n */\n handler: async (_request, reply) => {\n const plugins = options.getPlugins();\n if (!plugins) {\n return reply.send({\n catalogs: [],\n trusted: []\n });\n }\n\n return reply.send({\n catalogs: plugins.catalogs,\n trusted: plugins.trusted\n });\n }\n });\n}\n","import type { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify';\nimport type { IDatabase } from '#/db/IDatabase.js';\nimport type { ApiTokenRecord } from '#/db/types.js';\nimport type { UserRecord } from '#/db/types.js';\nimport { extractBearer, hashToken } from '#/server/auth/apiTokens.js';\nimport type { IThrottleStore } from '#/server/auth/throttle/IThrottleStore.js';\n\ndeclare module 'fastify' {\n interface FastifyRequest {\n /**\n * Authenticated API token attached by the bearer auth hook on protected routes.\n */\n apiToken: ApiTokenRecord | null;\n\n /**\n * User account owning the authenticated API token.\n */\n user: UserRecord | null;\n }\n}\n\n/**\n * Registers the auth-related request decorators used by protected route handlers.\n *\n * @param app - Fastify instance or encapsulated scope to decorate.\n */\nexport function registerBearerAuthDecorator(app: FastifyInstance): void {\n app.decorateRequest('apiToken', null);\n app.decorateRequest('user', null);\n}\n\n/**\n * Builds the throttle key for a request from client IP and bearer token material.\n *\n * Raw token secrets are hashed before inclusion in the key.\n *\n * @param request - Incoming HTTP request.\n * @param token - Raw bearer token, or null when missing.\n * @returns Throttle key in the form `{ip}:{tokenHash|none}`.\n */\nexport function buildAuthThrottleKey(request: FastifyRequest, token: string | null): string {\n const tokenPart = token ? hashToken(token) : 'none';\n return `${request.ip}:${tokenPart}`;\n}\n\n/**\n * Builds an onRequest hook that validates bearer tokens against the database.\n *\n * @param db - Database used to resolve active token hashes and owning users.\n * @param throttleStore - Redis-backed store for failed auth throttling.\n * @returns Hook that rejects unauthenticated requests with HTTP 401.\n */\nexport function createBearerAuthHook(db: IDatabase, throttleStore: IThrottleStore) {\n /**\n * Validates Authorization: Bearer and attaches the matching token and user.\n *\n * @param request - Incoming HTTP request.\n * @param reply - Fastify reply used to short-circuit unauthorized requests.\n */\n return async function bearerAuth(request: FastifyRequest, reply: FastifyReply): Promise<void> {\n const policy = throttleStore.getPolicy();\n const token = extractBearer(request.headers.authorization);\n const throttleKey = buildAuthThrottleKey(request, token);\n\n try {\n if (await throttleStore.isBlocked(throttleKey)) {\n return reply\n .header('Retry-After', String(policy.blockSeconds))\n .code(429)\n .send({ error: 'Too Many Requests' });\n }\n } catch {\n return reply.code(503).send({ error: 'Service Unavailable' });\n }\n\n if (!token) {\n try {\n await throttleStore.recordFailure(throttleKey);\n } catch {\n return reply.code(503).send({ error: 'Service Unavailable' });\n }\n\n return reply.header('WWW-Authenticate', 'Bearer').code(401).send({ error: 'Unauthorized' });\n }\n\n const record = await db.findActiveApiTokenByHash(hashToken(token));\n if (!record) {\n try {\n await throttleStore.recordFailure(throttleKey);\n } catch {\n return reply.code(503).send({ error: 'Service Unavailable' });\n }\n\n return reply.header('WWW-Authenticate', 'Bearer').code(401).send({ error: 'Unauthorized' });\n }\n\n const user = await db.findUserById(record.userId);\n if (!user) {\n try {\n await throttleStore.recordFailure(throttleKey);\n } catch {\n return reply.code(503).send({ error: 'Service Unavailable' });\n }\n\n return reply.header('WWW-Authenticate', 'Bearer').code(401).send({ error: 'Unauthorized' });\n }\n\n try {\n await throttleStore.reset(throttleKey);\n } catch {\n return reply.code(503).send({ error: 'Service Unavailable' });\n }\n\n request.apiToken = record;\n request.user = user;\n void db.touchApiTokenLastUsed(record.id, new Date()).catch(() => undefined);\n };\n}\n","import type { FastifyInstance } from 'fastify';\nimport type { LlmConfig } from '#/config/llmConfig.js';\nimport type { PluginsConfig } from '#/config/pluginsConfig.js';\nimport type { IDatabase } from '#/db/IDatabase.js';\nimport type { IThrottleStore } from '#/server/auth/throttle/IThrottleStore.js';\nimport { registerAdminRoutes } from '#/server/routes/admin.js';\nimport { registerAuthRoutes } from '#/server/routes/auth.js';\nimport { registerCollectionRoutes } from '#/server/routes/collections.js';\nimport { registerEnvironmentRoutes } from '#/server/routes/environments.js';\nimport { registerSnippetRoutes } from '#/server/routes/snippets.js';\nimport { registerFolderRoutes } from '#/server/routes/folders.js';\nimport { registerHealthRoute } from '#/server/routes/health.js';\nimport { registerRequestRoutes } from '#/server/routes/requests.js';\nimport { registerLlmRoutes } from '#/server/routes/llm.js';\nimport { registerPluginsRoutes } from '#/server/routes/plugins.js';\nimport {\n createBearerAuthHook,\n registerBearerAuthDecorator\n} from '#/server/auth/bearerAuthPlugin.js';\nimport type { ReloadResult } from '#/server/runtimeContext.js';\n\nexport interface RegisterRoutesOptions {\n /**\n * Application version reported by the health endpoint.\n */\n version: string;\n\n /**\n * Database used to validate bearer tokens on protected routes.\n */\n db: IDatabase;\n\n /**\n * Redis-backed store for authentication throttling on protected routes.\n */\n throttleStore: IThrottleStore;\n\n /**\n * Returns the current normalized LLM configuration from server.yaml.\n */\n getLlm: () => LlmConfig | null;\n\n /**\n * Returns the current normalized plugin source configuration from server.yaml.\n */\n getPlugins: () => PluginsConfig | null;\n\n /**\n * Reloads server.yaml and returns a per-section report.\n */\n reloadConfig: () => Promise<ReloadResult>;\n}\n\n/**\n * Registers routes that do not require authentication.\n *\n * @param app - Fastify server or encapsulated scope.\n * @param options - Shared route metadata such as app version.\n */\nexport async function registerPublicRoutes(\n app: FastifyInstance,\n options: Pick<RegisterRoutesOptions, 'version'>\n): Promise<void> {\n await registerHealthRoute(app, options.version);\n}\n\n/**\n * Registers routes that require a valid bearer token.\n *\n * @param app - Encapsulated Fastify scope with bearer auth applied.\n * @param options - Shared route metadata and database access.\n */\nexport async function registerProtectedRoutes(\n app: FastifyInstance,\n options: RegisterRoutesOptions\n): Promise<void> {\n registerBearerAuthDecorator(app);\n app.addHook('onRequest', createBearerAuthHook(options.db, options.throttleStore));\n\n await registerAuthRoutes(app);\n await registerAdminRoutes(app, {\n db: options.db,\n getLlm: options.getLlm,\n reloadConfig: options.reloadConfig\n });\n await registerCollectionRoutes(app, options.db);\n await registerEnvironmentRoutes(app, options.db);\n await registerSnippetRoutes(app, options.db);\n await registerFolderRoutes(app, options.db);\n await registerRequestRoutes(app, options.db);\n await registerLlmRoutes(app, { db: options.db, getLlm: options.getLlm });\n await registerPluginsRoutes(app, { getPlugins: options.getPlugins });\n}\n\n/**\n * Registers all HTTP routes on the Fastify instance.\n *\n * Public routes (such as health checks) and protected API routes are registered\n * in separate encapsulated scopes so authentication can be scoped correctly.\n *\n * @param app - Fastify server to attach routes to.\n * @param options - Shared route metadata and database access.\n */\nexport async function registerRoutes(\n app: FastifyInstance,\n options: RegisterRoutesOptions\n): Promise<void> {\n await app.register(async (publicApp) => {\n await registerPublicRoutes(publicApp, options);\n });\n\n await app.register(async (protectedApp) => {\n await registerProtectedRoutes(protectedApp, options);\n });\n}\n","import { isDeepStrictEqual } from 'node:util';\nimport type { LlmConfig } from '#/config/llmConfig.js';\nimport type { PluginsConfig } from '#/config/pluginsConfig.js';\nimport { ConfigError, loadServerConfig, type ServerConfig } from '#/config/serverConfig.js';\nimport { createDatabase, type IDatabase } from '#/db/index.js';\nimport { createThrottleStore } from '#/server/auth/throttle/createThrottleStore.js';\nimport type { IThrottleStore } from '#/server/auth/throttle/IThrottleStore.js';\nimport { createLogger, type Logger } from '#/server/logging/logger.js';\n\n/**\n * Outcome for a single config section during reload.\n */\nexport type ReloadSectionStatus = 'reloaded' | 'unchanged' | 'failed' | 'restart-required';\n\n/**\n * Config section name reported in reload results.\n */\nexport type ReloadSectionName = 'db' | 'redis' | 'llm' | 'plugins' | 'server';\n\n/**\n * Per-section reload outcome.\n */\nexport interface ReloadSectionResult {\n /**\n * Config section that was evaluated.\n */\n section: ReloadSectionName;\n\n /**\n * Whether the section was applied, skipped, failed, or needs a process restart.\n */\n status: ReloadSectionStatus;\n\n /**\n * Human-readable error when status is `failed` or `restart-required`.\n */\n error?: string;\n}\n\n/**\n * Result of reloading server.yaml at runtime.\n */\nexport interface ReloadResult {\n /**\n * Per-section reload outcomes when the config file parsed successfully.\n */\n sections: ReloadSectionResult[];\n\n /**\n * When set, the config file could not be read or parsed; no sections were changed.\n */\n fatalError?: string;\n}\n\n/**\n * Live server resources backed by server.yaml, with swappable database and throttle connections.\n */\nexport interface RuntimeContext {\n /**\n * Absolute path to the config file re-read on reload.\n */\n readonly configPath: string;\n\n /**\n * HTTP bind host from the active config (changes require a process restart).\n */\n readonly host: string;\n\n /**\n * HTTP bind port from the active config (changes require a process restart).\n */\n readonly port: number;\n\n /**\n * Stable database handle; underlying connection swaps on reload.\n */\n readonly db: IDatabase;\n\n /**\n * Stable throttle store handle; underlying Redis client swaps on reload.\n */\n readonly throttleStore: IThrottleStore;\n\n /**\n * Returns the current normalized LLM configuration.\n */\n getLlm(): LlmConfig | null;\n\n /**\n * Returns the current normalized plugin source configuration.\n */\n getPlugins(): PluginsConfig | null;\n\n /**\n * Winston logger configured at process startup from server.yaml.\n */\n readonly logger: Logger;\n}\n\n/**\n * Mutable holder for a swappable service instance.\n */\ninterface SwappableHolder<T> {\n underlying: T;\n}\n\n/**\n * Internal mutable state for a {@link RuntimeContext}.\n */\ninterface RuntimeContextState {\n configPath: string;\n host: string;\n port: number;\n activeDbConfig: Record<string, unknown>;\n activeRedisConfig: Record<string, unknown>;\n dbHolder: SwappableHolder<IDatabase>;\n throttleHolder: SwappableHolder<IThrottleStore>;\n llm: LlmConfig | null;\n plugins: PluginsConfig | null;\n}\n\nconst runtimeContextStates = new WeakMap<RuntimeContext, RuntimeContextState>();\n\n/**\n * Builds a stable proxy that forwards property access to a swappable underlying object.\n *\n * @param holder - Mutable holder whose `underlying` reference may change on reload.\n * @returns Proxy implementing the same surface as the underlying instance.\n */\nfunction createSwappableProxy<T extends object>(holder: SwappableHolder<T>): T {\n return new Proxy({} as T, {\n /**\n * Forwards property reads to the current underlying instance.\n */\n get(_target, prop) {\n const value = Reflect.get(holder.underlying, prop, holder.underlying);\n if (typeof value === 'function') {\n return value.bind(holder.underlying);\n }\n\n return value;\n }\n });\n}\n\n/**\n * Returns internal state for a runtime context created by {@link createRuntimeContext}.\n *\n * @param ctx - Runtime context instance.\n * @returns Mutable internal state used for reload and lifecycle.\n * @throws {Error} When the context was not created by {@link createRuntimeContext}.\n */\nfunction getState(ctx: RuntimeContext): RuntimeContextState {\n const state = runtimeContextStates.get(ctx);\n if (!state) {\n throw new Error('Invalid runtime context.');\n }\n\n return state;\n}\n\n/**\n * Formats an unknown error for reload result payloads.\n *\n * @param error - Caught reload error.\n * @returns Message suitable for API and log output.\n */\nfunction formatReloadError(error: unknown): string {\n if (error instanceof Error) {\n return error.message;\n }\n\n return String(error);\n}\n\n/**\n * Creates runtime resources from an initial validated config snapshot.\n *\n * @param config - Parsed server.yaml contents.\n * @param configPath - Absolute path to the config file for subsequent reloads.\n * @returns Runtime context with stable db and throttle proxies.\n */\nexport function createRuntimeContext(config: ServerConfig, configPath: string): RuntimeContext {\n const state: RuntimeContextState = {\n configPath,\n host: config.host,\n port: config.port,\n activeDbConfig: config.db,\n activeRedisConfig: config.redis,\n dbHolder: { underlying: createDatabase(config.db) },\n throttleHolder: { underlying: createThrottleStore(config.redis) },\n llm: config.llm,\n plugins: config.plugins\n };\n\n const ctx: RuntimeContext = {\n configPath: state.configPath,\n get host() {\n return state.host;\n },\n get port() {\n return state.port;\n },\n db: createSwappableProxy(state.dbHolder),\n throttleStore: createSwappableProxy(state.throttleHolder),\n getLlm: () => state.llm,\n getPlugins: () => state.plugins,\n logger: createLogger(config.logging)\n };\n\n runtimeContextStates.set(ctx, state);\n return ctx;\n}\n\n/**\n * Opens connections for the current database and throttle store instances.\n *\n * @param ctx - Runtime context to connect.\n */\nexport async function connectRuntimeContext(ctx: RuntimeContext): Promise<void> {\n const state = getState(ctx);\n await state.dbHolder.underlying.connect();\n await state.throttleHolder.underlying.connect();\n}\n\n/**\n * Closes connections for the current database and throttle store instances.\n *\n * @param ctx - Runtime context to disconnect.\n */\nexport async function disconnectAll(ctx: RuntimeContext): Promise<void> {\n const state = getState(ctx);\n await state.dbHolder.underlying.disconnect();\n await state.throttleHolder.underlying.disconnect();\n}\n\n/**\n * Attempts to reconnect the database section when its raw config changed.\n *\n * @param state - Mutable runtime state.\n * @param nextDbConfig - Parsed `db` section from the reloaded config file.\n * @returns Section reload outcome.\n */\nasync function reloadDbSection(\n state: RuntimeContextState,\n nextDbConfig: Record<string, unknown>\n): Promise<ReloadSectionResult> {\n if (isDeepStrictEqual(state.activeDbConfig, nextDbConfig)) {\n return { section: 'db', status: 'unchanged' };\n }\n\n try {\n const nextDb = createDatabase(nextDbConfig);\n await nextDb.connect();\n const previousDb = state.dbHolder.underlying;\n state.dbHolder.underlying = nextDb;\n state.activeDbConfig = nextDbConfig;\n await previousDb.disconnect();\n return { section: 'db', status: 'reloaded' };\n } catch (error) {\n return { section: 'db', status: 'failed', error: formatReloadError(error) };\n }\n}\n\n/**\n * Attempts to reconnect the Redis throttle store when its raw config changed.\n *\n * @param state - Mutable runtime state.\n * @param nextRedisConfig - Parsed `redis` section from the reloaded config file.\n * @returns Section reload outcome.\n */\nasync function reloadRedisSection(\n state: RuntimeContextState,\n nextRedisConfig: Record<string, unknown>\n): Promise<ReloadSectionResult> {\n if (isDeepStrictEqual(state.activeRedisConfig, nextRedisConfig)) {\n return { section: 'redis', status: 'unchanged' };\n }\n\n try {\n const nextStore = createThrottleStore(nextRedisConfig);\n await nextStore.connect();\n const previousStore = state.throttleHolder.underlying;\n state.throttleHolder.underlying = nextStore;\n state.activeRedisConfig = nextRedisConfig;\n await previousStore.disconnect();\n return { section: 'redis', status: 'reloaded' };\n } catch (error) {\n return { section: 'redis', status: 'failed', error: formatReloadError(error) };\n }\n}\n\n/**\n * Reports when server bind settings changed and cannot be applied without restart.\n *\n * @param state - Active runtime state.\n * @param nextConfig - Newly parsed config file contents.\n * @returns Section reload outcome.\n */\nfunction reloadServerSection(\n state: RuntimeContextState,\n nextConfig: ServerConfig\n): ReloadSectionResult {\n if (state.host === nextConfig.host && state.port === nextConfig.port) {\n return { section: 'server', status: 'unchanged' };\n }\n\n return {\n section: 'server',\n status: 'restart-required',\n error: 'Changes to server.host or server.port require a full process restart.'\n };\n}\n\n/**\n * Re-reads server.yaml and applies reloadable sections on a best-effort basis.\n *\n * When the config file is invalid, nothing is changed and {@link ReloadResult.fatalError} is set.\n *\n * @param ctx - Runtime context to update.\n * @returns Per-section reload report.\n */\nexport async function reloadRuntimeConfig(ctx: RuntimeContext): Promise<ReloadResult> {\n const state = getState(ctx);\n\n let nextConfig: ServerConfig;\n try {\n nextConfig = loadServerConfig(state.configPath);\n } catch (error) {\n const message = error instanceof ConfigError ? error.message : formatReloadError(error);\n return { sections: [], fatalError: message };\n }\n\n const sections: ReloadSectionResult[] = [];\n\n sections.push(await reloadDbSection(state, nextConfig.db));\n sections.push(await reloadRedisSection(state, nextConfig.redis));\n\n state.llm = nextConfig.llm;\n sections.push({ section: 'llm', status: 'reloaded' });\n\n state.plugins = nextConfig.plugins;\n sections.push({ section: 'plugins', status: 'reloaded' });\n\n sections.push(reloadServerSection(state, nextConfig));\n\n return { sections };\n}\n\n/**\n * Formats per-section reload outcomes for console output.\n *\n * @param result - Reload report returned by {@link reloadRuntimeConfig}.\n * @returns Single-line summary of section statuses.\n */\nfunction formatConfigReloadSummary(result: ReloadResult): string {\n return result.sections\n .map((section) => {\n if (section.error) {\n return `${section.section}: ${section.status} (${section.error})`;\n }\n\n return `${section.section}: ${section.status}`;\n })\n .join(', ');\n}\n\n/**\n * Writes a user-facing console message after a config reload attempt.\n *\n * Called for both SIGHUP and `POST /admin/config/reload` reloads.\n *\n * @param result - Reload report returned by {@link reloadRuntimeConfig}.\n */\nexport function logConfigReloadResult(result: ReloadResult): void {\n if (result.fatalError) {\n console.error(`Team Hub config reload failed: ${result.fatalError}`);\n return;\n }\n\n console.log(`Team Hub config reloaded (${formatConfigReloadSummary(result)}).`);\n}\n","import Redis from 'ioredis';\nimport { redisSectionSchema } from '#/config/serverConfig.schema.js';\nimport { formatZodError } from '#/db/validation.js';\nimport {\n DEFAULT_THROTTLE_POLICY,\n type IThrottleStore,\n type ThrottlePolicy\n} from '#/server/auth/throttle/IThrottleStore.js';\n\n/**\n * Minimal Redis client surface used by {@link RedisThrottleStore}.\n */\nexport interface RedisThrottleClient {\n /**\n * Increments a key and returns the new value.\n */\n incr(key: string): Promise<number>;\n\n /**\n * Sets a key's time-to-live in seconds.\n */\n expire(key: string, seconds: number): Promise<number>;\n\n /**\n * Returns whether a key exists.\n */\n exists(...keys: string[]): Promise<number>;\n\n /**\n * Sets a key with an optional expiry in seconds.\n */\n set(key: string, value: string, mode: 'EX', seconds: number): Promise<'OK' | null>;\n\n /**\n * Deletes one or more keys.\n */\n del(...keys: string[]): Promise<number>;\n\n /**\n * Opens the Redis connection.\n */\n connect(): Promise<void>;\n\n /**\n * Closes the Redis connection.\n */\n quit(): Promise<'OK' | undefined>;\n}\n\n/**\n * Validated Redis connection settings from server.yaml.\n */\nexport interface RedisThrottleConfig {\n host: string;\n port: number;\n password?: string;\n db?: number;\n keyPrefix?: string;\n maxFailures?: number;\n windowSeconds?: number;\n blockSeconds?: number;\n}\n\n/**\n * Redis-backed implementation of authentication throttling counters and blocks.\n */\nexport class RedisThrottleStore implements IThrottleStore {\n /**\n * Creates a Redis throttle store from an injected client and policy.\n *\n * @param client - Redis client implementing the throttle command surface.\n * @param config - Connection metadata including optional key prefix.\n * @param policy - Failure counting and block duration settings.\n */\n constructor(\n private readonly client: RedisThrottleClient,\n private readonly config: Pick<RedisThrottleConfig, 'keyPrefix'>,\n private readonly policy: ThrottlePolicy\n ) {}\n\n /**\n * Validates raw config and constructs a {@link RedisThrottleStore}.\n *\n * @param config - Raw `redis` section from server.yaml.\n * @returns Configured Redis throttle store instance.\n * @throws {Error} When config fails Redis-specific validation.\n */\n static fromConfig(config: unknown): RedisThrottleStore {\n const parsed = redisSectionSchema.safeParse(config);\n if (!parsed.success) {\n throw new Error(formatZodError(parsed.error));\n }\n\n const policy: ThrottlePolicy = {\n maxFailures: parsed.data.maxFailures ?? DEFAULT_THROTTLE_POLICY.maxFailures,\n windowSeconds: parsed.data.windowSeconds ?? DEFAULT_THROTTLE_POLICY.windowSeconds,\n blockSeconds: parsed.data.blockSeconds ?? DEFAULT_THROTTLE_POLICY.blockSeconds\n };\n\n const client = new Redis({\n host: parsed.data.host,\n port: parsed.data.port,\n password: parsed.data.password,\n db: parsed.data.db,\n lazyConnect: true\n }) as unknown as RedisThrottleClient;\n\n return new RedisThrottleStore(client, { keyPrefix: parsed.data.keyPrefix }, policy);\n }\n\n /**\n * Opens the underlying Redis connection.\n */\n async connect(): Promise<void> {\n await this.client.connect();\n }\n\n /**\n * Closes the underlying Redis connection.\n */\n async disconnect(): Promise<void> {\n await this.client.quit();\n }\n\n /**\n * Returns the configured throttle policy.\n */\n getPolicy(): ThrottlePolicy {\n return this.policy;\n }\n\n /**\n * Checks whether the throttle block key exists for the given auth key.\n *\n * @param key - Throttle key (typically client IP plus token hash).\n */\n async isBlocked(key: string): Promise<boolean> {\n const blocked = await this.client.exists(this.blockKey(key));\n return blocked > 0;\n }\n\n /**\n * Increments the failure counter and applies a block when the threshold is reached.\n *\n * @param key - Throttle key (typically client IP plus token hash).\n * @returns True when a new block was applied.\n */\n async recordFailure(key: string): Promise<boolean> {\n const failKey = this.failKey(key);\n const count = await this.client.incr(failKey);\n\n if (count === 1) {\n await this.client.expire(failKey, this.policy.windowSeconds);\n }\n\n if (count >= this.policy.maxFailures) {\n await this.client.set(this.blockKey(key), '1', 'EX', this.policy.blockSeconds);\n return true;\n }\n\n return false;\n }\n\n /**\n * Clears failure and block keys after successful authentication.\n *\n * @param key - Throttle key (typically client IP plus token hash).\n */\n async reset(key: string): Promise<void> {\n await this.client.del(this.failKey(key), this.blockKey(key));\n }\n\n /**\n * Builds the Redis key used to count failed auth attempts.\n *\n * @param key - Throttle key (typically client IP plus token hash).\n */\n private failKey(key: string): string {\n return `${this.prefix()}throttle:fail:${key}`;\n }\n\n /**\n * Builds the Redis key used to mark an auth key as blocked.\n *\n * @param key - Throttle key (typically client IP plus token hash).\n */\n private blockKey(key: string): string {\n return `${this.prefix()}throttle:block:${key}`;\n }\n\n /**\n * Returns the configured key prefix, if any.\n */\n private prefix(): string {\n const keyPrefix = this.config.keyPrefix;\n if (!keyPrefix) {\n return '';\n }\n\n return keyPrefix.endsWith(':') ? keyPrefix : `${keyPrefix}:`;\n }\n}\n","/**\n * Policy controlling how failed authentication attempts are counted and blocked.\n */\nexport interface ThrottlePolicy {\n /**\n * Number of failures within the window before a block is applied.\n */\n maxFailures: number;\n\n /**\n * Sliding window length in seconds for counting failures.\n */\n windowSeconds: number;\n\n /**\n * Block duration in seconds after the failure threshold is reached.\n */\n blockSeconds: number;\n}\n\n/**\n * Default throttle policy: 10 failures within 15 minutes triggers a 15 minute block.\n */\nexport const DEFAULT_THROTTLE_POLICY: ThrottlePolicy = {\n maxFailures: 10,\n windowSeconds: 900,\n blockSeconds: 900\n};\n\n/**\n * Contract for Redis-backed authentication throttling storage.\n */\nexport interface IThrottleStore {\n /**\n * Opens a connection to the throttle store.\n */\n connect(): Promise<void>;\n\n /**\n * Closes the throttle store connection and releases resources.\n */\n disconnect(): Promise<void>;\n\n /**\n * Returns the configured throttle policy for this store.\n */\n getPolicy(): ThrottlePolicy;\n\n /**\n * Checks whether the given key is currently blocked.\n *\n * @param key - Throttle key (typically client IP plus token hash).\n * @returns True when further auth attempts should be rejected with HTTP 429.\n */\n isBlocked(key: string): Promise<boolean>;\n\n /**\n * Records a failed authentication attempt for the given key.\n *\n * @param key - Throttle key (typically client IP plus token hash).\n * @returns True when the failure threshold was reached and a block was applied.\n */\n recordFailure(key: string): Promise<boolean>;\n\n /**\n * Clears failure counters and blocks for the given key after successful auth.\n *\n * @param key - Throttle key (typically client IP plus token hash).\n */\n reset(key: string): Promise<void>;\n}\n","import type { IThrottleStore } from '#/server/auth/throttle/IThrottleStore.js';\nimport { RedisThrottleStore } from '#/server/auth/throttle/RedisThrottleStore.js';\n\n/**\n * Creates a throttle store instance from the raw `redis` section of server.yaml.\n *\n * @param config - Raw `redis` section from server.yaml.\n * @returns Configured throttle store for authentication rate limiting.\n * @throws {Error} When config fails validation.\n */\nexport function createThrottleStore(config: unknown): IThrottleStore {\n return RedisThrottleStore.fromConfig(config);\n}\n","import { Command } from 'commander';\nimport type { FastifyInstance } from 'fastify';\nimport { mergeGlobalOptions } from '#/cli/globalOptions.js';\nimport { loadServerConfig, resolveConfigPath } from '#/config/serverConfig.js';\nimport { createServer } from '#/index.js';\nimport { disposeHubMcpConnections } from '#/server/llm/mcpClient.js';\nimport {\n connectRuntimeContext,\n createRuntimeContext,\n disconnectAll,\n logConfigReloadResult,\n reloadRuntimeConfig,\n type ReloadResult,\n type RuntimeContext\n} from '#/server/runtimeContext.js';\n\nexport interface StartCommandOptions {\n /**\n * When true, enables verbose server logging.\n */\n verbose?: boolean;\n\n /**\n * Path to the server YAML config file (from global `-c` / `--config`).\n */\n config: string;\n}\n\nexport interface RunServerOptions {\n /**\n * When true, logs resolved config and enables Fastify request logging.\n */\n verbose?: boolean;\n}\n\n/**\n * Formats a listen address for user-facing console output.\n *\n * Wildcard bind addresses (`0.0.0.0`, `::`) are shown as localhost so operators\n * know which URL to open locally.\n *\n * @param address - Address returned by the HTTP server after listen.\n * @param port - TCP port the server is listening on.\n * @returns HTTP URL suitable for display (e.g. `http://127.0.0.1:8787`).\n */\nfunction formatListenAddress(address: string | null, port: number): string {\n if (!address) {\n return `http://127.0.0.1:${port}`;\n }\n\n if (address === '0.0.0.0' || address === '::') {\n return `http://127.0.0.1:${port}`;\n }\n\n const host = address.includes(':') && !address.startsWith('[') ? `[${address}]` : address;\n return `http://${host}:${port}`;\n}\n\n/**\n * Registers SIGINT and SIGTERM handlers that close the Fastify instance cleanly.\n *\n * @param app - Running Fastify server to shut down on signal.\n * @param ctx - Runtime context whose connections are closed during shutdown.\n */\nfunction registerGracefulShutdown(app: FastifyInstance, ctx: RuntimeContext): void {\n /**\n * Closes the server and exits the process after a termination signal.\n *\n * @param signal - Signal that triggered shutdown.\n */\n const shutdown = async (signal: NodeJS.Signals) => {\n app.log.info(`Received ${signal}, shutting down.`);\n await app.close();\n await disposeHubMcpConnections();\n await disconnectAll(ctx);\n process.exit(0);\n };\n\n /**\n * Forwards SIGINT to the shared shutdown handler.\n */\n process.once('SIGINT', () => {\n void shutdown('SIGINT');\n });\n\n /**\n * Forwards SIGTERM to the shared shutdown handler.\n */\n process.once('SIGTERM', () => {\n void shutdown('SIGTERM');\n });\n}\n\n/**\n * Registers a repeatable SIGHUP handler that reloads server.yaml at runtime.\n *\n * @param reloadConfig - Shared reload handler that logs results and returns the report.\n */\nfunction registerConfigReloadHandler(reloadConfig: () => Promise<ReloadResult>): void {\n process.on('SIGHUP', () => {\n void reloadConfig();\n });\n}\n\n/**\n * Creates, listens on, and runs the Team Hub HTTP server until shutdown.\n *\n * @param ctx - Runtime context with bind settings and swappable connections.\n * @param options - Runtime options such as verbose logging.\n * @returns The listening Fastify instance (also registered for graceful shutdown).\n */\nexport async function runServer(\n ctx: RuntimeContext,\n options: RunServerOptions = {}\n): Promise<FastifyInstance> {\n /**\n * Reloads server.yaml, logs the outcome, and returns the per-section report.\n */\n const reloadConfig = async (): Promise<ReloadResult> => {\n const result = await reloadRuntimeConfig(ctx);\n logConfigReloadResult(result);\n return result;\n };\n\n const app = await createServer(ctx, {\n verbose: options.verbose,\n reloadConfig\n });\n\n await connectRuntimeContext(ctx);\n\n await app.listen({\n host: ctx.host,\n port: ctx.port\n });\n\n const address = app.server.address();\n const port = typeof address === 'object' && address ? address.port : ctx.port;\n const host = typeof address === 'object' && address ? address.address : ctx.host;\n\n if (options.verbose) {\n console.log('Starting server with config path:', ctx.configPath);\n }\n\n console.log(`Team Hub listening on ${formatListenAddress(host, port)}`);\n\n registerGracefulShutdown(app, ctx);\n registerConfigReloadHandler(reloadConfig);\n\n return app;\n}\n\n/**\n * CLI handler for the `start` subcommand: loads config and runs the server.\n *\n * @param options - Parsed start command options including config path.\n */\nexport async function startCommand(options: StartCommandOptions): Promise<void> {\n const configPath = resolveConfigPath(options.config);\n const config = loadServerConfig(options.config);\n const ctx = createRuntimeContext(config, configPath);\n await runServer(ctx, { verbose: options.verbose });\n}\n\n/**\n * Registers the `start` subcommand on a Commander program.\n *\n * @param program - Root or parent Commander instance.\n * @param handler - Action to run when `start` is invoked (defaults to {@link startCommand}).\n */\nexport function registerStartCommand(\n program: Command,\n handler: (options: StartCommandOptions) => Promise<void> = startCommand\n): void {\n program\n .command('start')\n .description('Start the Team Hub server')\n .action(\n /**\n * Runs the start subcommand after merging global CLI options.\n */\n async function startAction(this: Command, options: StartCommandOptions) {\n await handler(mergeGlobalOptions(this, options));\n }\n );\n}\n"],"mappings":"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","names":["Command","randomUUID","z","formatZodError","formatZodError","randomUUID","randomUUID","parseAuditEntityType","z","portSchema","formatZodError","randomUUID","rows","row","randomUUID","API_TOKENS_MIGRATION_SQL","COLLECTIONS_MIGRATION_SQL","ENVIRONMENTS_MIGRATION_SQL","SNIPPETS_MIGRATION_SQL","FOLDERS_MIGRATION_SQL","REQUESTS_MIGRATION_SQL","USERS_MIGRATION_SQL","AUDIT_LOG_MIGRATION_SQL","API_TOKENS_USER_ID_MIGRATION_SQL","API_TOKENS_ATTRIBUTION_MIGRATION_SQL","COLLECTIONS_ATTRIBUTION_MIGRATION_SQL","ENVIRONMENTS_ATTRIBUTION_MIGRATION_SQL","FOLDERS_ATTRIBUTION_MIGRATION_SQL","REQUESTS_ATTRIBUTION_MIGRATION_SQL","USERS_ATTRIBUTION_MIGRATION_SQL","COLLECTIONS_BACKFILL_UPDATED_AT_SQL","ENVIRONMENTS_BACKFILL_UPDATED_AT_SQL","FOLDERS_BACKFILL_UPDATED_AT_SQL","USERS_LLM_MIGRATION_SQL","LLM_USAGE_MIGRATION_SQL","LLM_USAGE_LOG_MIGRATION_SQL","COLLECTIONS_DELETION_LOCKED_MIGRATION_SQL","ENVIRONMENTS_DELETION_LOCKED_MIGRATION_SQL","USERS_SNIPPET_ACCESS_MIGRATION_SQL","USERS_SNIPPET_ACCESS_BACKFILL_SQL","z","portSchema","COLLECTION_SELECT","ENVIRONMENT_SELECT","SNIPPET_SELECT","USER_SELECT","API_TOKEN_SELECT","FOLDER_SELECT","REQUEST_SELECT","LLM_USAGE_SELECT","LLM_USAGE_LOG_SELECT","formatZodError","randomUUID","result","row","randomUUID","parseUserRole","readFileSync","z","z","z","z","z","z","z","z","version","sendLlmUnavailable","z","formatZodError","version","Command"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/cli/argv.ts","../src/cli/program.ts","../src/config/serverConfig.ts","../src/config/docsConfig.ts","../src/config/llmConfig.ts","../src/config/loggingConfig.ts","../src/config/pluginsConfig.ts","../src/config/serverConfig.schema.ts","../src/cli/globalOptions.ts","../src/db/firestore/FirestoreDatabase.ts","../src/db/attribution.ts","../src/db/bootstrapUsers.ts","../src/db/firestore/const.ts","../src/db/systemUsers.ts","../src/db/firestore/schemas.ts","../src/db/firestore/utils.ts","../src/db/runResultPayload.ts","../src/db/trimRequiredName.ts","../src/db/userNameValidation.ts","../src/db/types.ts","../src/db/validation.ts","../src/db/mysql/MysqlDatabase.ts","../src/db/apiTokenRows.ts","../src/db/auditLogRows.ts","../src/db/entityRows.ts","../src/db/mysql/migrations.ts","../src/db/mysql/schemas.ts","../src/db/userRows.ts","../src/db/llmUsageLogRows.ts","../src/db/llmUsageRows.ts","../src/db/postgres/PostgresDatabase.ts","../src/db/postgres/migrations.ts","../src/db/postgres/schemas.ts","../src/db/createDatabase.ts","../src/cli/collectionCommand.ts","../src/cli/llmCommand.ts","../src/cli/migrateCommand.ts","../src/cli/userCommand.ts","../src/server/auth/apiTokens.ts","../src/server/admin/userValidation.ts","../src/server/llm/models.ts","../src/server/createServer.ts","../src/server/logging/httpLogging.ts","../src/server/logging/logger.ts","../src/packageVersion.ts","../src/server/auth/accessControl.ts","../src/db/deletionLockedError.ts","../src/server/routes/schemas/common.ts","../src/server/routes/errors.ts","../src/server/routes/authorize.ts","../src/server/routes/schemas/admin.ts","../src/server/routes/schemas/auth.ts","../src/server/routes/schemas/llm.ts","../src/server/routes/schemas/entities.ts","../src/server/routes/admin.ts","../src/server/auth/sessionCapabilities.ts","../src/server/routes/auth.ts","../src/server/routes/collections.ts","../src/server/routes/environments.ts","../src/server/routes/snippets.ts","../src/server/routes/folders.ts","../src/server/routes/health.ts","../src/server/routes/requests.ts","../src/server/routes/runResults.ts","../src/server/llm/client.ts","../src/server/docs/docsSearch.ts","../src/server/llm/hubNativeTools.ts","../src/server/llm/hubMcpToolNames.ts","../src/server/llm/mcpClient.ts","../src/server/llm/agent.ts","../src/server/routes/llm.ts","../src/server/routes/schemas/plugins.ts","../src/server/routes/plugins.ts","../src/server/auth/bearerAuthPlugin.ts","../src/server/routes/index.ts","../src/server/runtimeContext.ts","../src/server/auth/throttle/RedisThrottleStore.ts","../src/server/auth/throttle/IThrottleStore.ts","../src/server/auth/throttle/createThrottleStore.ts","../src/server.ts"],"sourcesContent":["import { CommanderError } from 'commander';\nimport { normalizeCliArgv } from '#/cli/argv.js';\nimport { createProgram } from '#/cli/program.js';\nimport { readPackageVersion } from '#/packageVersion.js';\n\nconst version = readPackageVersion();\n\n/**\n * CLI entry point: builds the Commander program and parses process arguments.\n */\nasync function main(): Promise<void> {\n const program = createProgram(version);\n program.exitOverride();\n\n try {\n await program.parseAsync(normalizeCliArgv(process.argv));\n } catch (error) {\n if (error instanceof CommanderError) {\n process.exitCode = error.exitCode;\n return;\n }\n\n console.error(error instanceof Error ? error.message : String(error));\n process.exitCode = 1;\n }\n}\n\nvoid main();\n","/**\n * Removes the `--` separator that package managers insert between the script\n * name and user-provided arguments (for example `pnpm dev -- user create`).\n *\n * Commander treats everything after `--` as positional operands, so subcommand\n * flags such as `--name` would otherwise be ignored.\n *\n * @param argv - Raw process arguments including the node binary and script path.\n * @returns Copy of argv with a script-following `--` removed when present.\n */\nexport function normalizeCliArgv(argv: readonly string[]): string[] {\n const scriptIndex = argv.findIndex((arg) => arg.endsWith('cli.ts') || arg.endsWith('cli.js'));\n if (scriptIndex === -1) {\n return [...argv];\n }\n\n const normalized = [...argv];\n if (normalized[scriptIndex + 1] === '--') {\n normalized.splice(scriptIndex + 1, 1);\n }\n\n return normalized;\n}\n","import { Command } from 'commander';\nimport { DEFAULT_CONFIG_PATH } from '#/config/serverConfig.js';\nimport {\n registerCollectionCommand,\n type CollectionCommandOptions\n} from '#/cli/collectionCommand.js';\nimport { registerLlmCommand, type LlmCommandOptions } from '#/cli/llmCommand.js';\nimport { registerMigrateCommand, type MigrateCommandOptions } from '#/cli/migrateCommand.js';\nimport {\n registerUserCommand,\n type UserCommandOptions,\n type UserCreateCommandOptions,\n type UserTokenCreateCommandOptions,\n type UserTokenListCommandOptions,\n type UserTokenRevokeCommandOptions,\n type UserUpdateCommandOptions\n} from '#/cli/userCommand.js';\nimport { registerStartCommand, type StartCommandOptions } from '#/server.js';\n\nexport interface ProgramDependencies {\n /**\n * Optional override for the start subcommand handler (used in tests).\n */\n startCommand?: (options: StartCommandOptions) => Promise<void>;\n\n /**\n * Optional override for the migrate subcommand handler (used in tests).\n */\n migrateCommand?: (options: MigrateCommandOptions) => Promise<void>;\n\n /**\n * Optional overrides for collection subcommand handlers (used in tests).\n */\n collectionCommand?: {\n list?: (options: CollectionCommandOptions) => Promise<void>;\n };\n\n /**\n * Optional overrides for LLM subcommand handlers (used in tests).\n */\n llmCommand?: {\n list?: (options: LlmCommandOptions) => Promise<void>;\n };\n\n /**\n * Optional overrides for user subcommand handlers (used in tests).\n */\n userCommand?: {\n create?: (options: UserCreateCommandOptions) => Promise<void>;\n list?: (options: UserCommandOptions) => Promise<void>;\n show?: (options: UserUpdateCommandOptions) => Promise<void>;\n update?: (options: UserUpdateCommandOptions) => Promise<void>;\n delete?: (options: UserUpdateCommandOptions) => Promise<void>;\n tokenCreate?: (options: UserTokenCreateCommandOptions) => Promise<void>;\n tokenList?: (options: UserTokenListCommandOptions) => Promise<void>;\n tokenRevoke?: (options: UserTokenRevokeCommandOptions) => Promise<void>;\n };\n}\n\n/**\n * Creates the root Commander program with global options and subcommands.\n *\n * @param version - Package version shown by `--version`.\n * @param deps - Injectable handlers for testing.\n * @returns Configured Commander program ready to parse argv.\n */\nexport function createProgram(version: string, deps: ProgramDependencies = {}): Command {\n const program = new Command();\n\n program\n .name('team-hub')\n .description('Team Hub — central server for HarborClient')\n .version(version)\n .showHelpAfterError()\n .enablePositionalOptions()\n .option('-v, --verbose', 'Enable verbose logging')\n .option(\n '-c, --config <path>',\n `Path to config file (default: ${DEFAULT_CONFIG_PATH})`,\n DEFAULT_CONFIG_PATH\n );\n\n registerStartCommand(program, deps.startCommand);\n registerMigrateCommand(program, deps.migrateCommand);\n registerCollectionCommand(program, deps.collectionCommand);\n registerLlmCommand(program, deps.llmCommand);\n registerUserCommand(program, deps.userCommand);\n\n return program;\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport path from 'node:path';\nimport { parse as parseYaml } from 'yaml';\nimport type { ZodError } from 'zod/v4';\nimport { normalizeDocsConfig, type DocsConfig } from '#/config/docsConfig.js';\nimport { normalizeLlmConfig, type LlmConfig } from '#/config/llmConfig.js';\nimport {\n DEFAULT_LOGGING_CONFIG,\n normalizeLoggingConfig,\n type LoggingConfig\n} from '#/config/loggingConfig.js';\nimport { normalizePluginsConfig, type PluginsConfig } from '#/config/pluginsConfig.js';\nimport {\n dbSectionSchema,\n docsSectionSchema,\n llmSectionSchema,\n loggingSectionSchema,\n pluginsSectionSchema,\n redisSectionSchema,\n serverConfigDocumentSchema,\n serverSectionSchema\n} from '#/config/serverConfig.schema.js';\n\n/**\n * Default relative path to the server YAML config file.\n */\nexport const DEFAULT_CONFIG_PATH = 'server.yaml';\n\nexport interface ServerConfig {\n /**\n * TCP port the server listens on.\n */\n port: number;\n\n /**\n * Bind address (e.g. `127.0.0.1` or `0.0.0.0`).\n */\n host: string;\n\n /**\n * Raw `db` section from server.yaml; validated per driver by {@link createDatabase}.\n */\n db: Record<string, unknown>;\n\n /**\n * Raw `redis` section from server.yaml; validated by {@link RedisThrottleStore.fromConfig}.\n */\n redis: Record<string, unknown>;\n\n /**\n * Normalized LLM provider settings when the optional `llm` section is present.\n */\n llm: LlmConfig | null;\n\n /**\n * Normalized plugin source URLs when the optional `plugins` section is present.\n */\n plugins: PluginsConfig | null;\n\n /**\n * Normalized documentation search settings when the optional `docs` section is present.\n */\n docs: DocsConfig | null;\n\n /**\n * Normalized logging settings (defaults apply when the section is omitted).\n */\n logging: LoggingConfig;\n}\n\n/**\n * Error thrown when a config file cannot be read or fails validation.\n */\nexport class ConfigError extends Error {\n /**\n * Creates a config error with a user-facing message.\n *\n * @param message - Description of what went wrong.\n */\n constructor(message: string) {\n super(message);\n this.name = 'ConfigError';\n }\n}\n\n/**\n * Resolves a config path relative to the current working directory when needed.\n *\n * @param configPath - User-supplied config path (relative or absolute).\n * @returns Absolute filesystem path to the config file.\n */\n/**\n * Resolves a config path relative to the current working directory when needed.\n *\n * @param configPath - User-supplied config path (relative or absolute).\n * @returns Absolute filesystem path to the config file.\n */\nexport function resolveConfigPath(configPath: string): string {\n return path.isAbsolute(configPath) ? configPath : path.resolve(process.cwd(), configPath);\n}\n\n/**\n * Ensures the parsed YAML document has the expected top-level structure.\n *\n * Provides clearer error messages than Zod alone when required keys are missing.\n *\n * @param document - Parsed YAML value.\n * @throws {ConfigError} When the document shape is invalid.\n */\nfunction assertDocumentShape(document: unknown): void {\n if (document === null || typeof document !== 'object' || Array.isArray(document)) {\n throw new ConfigError('Config must be a YAML mapping.');\n }\n\n const root = document as Record<string, unknown>;\n const server = root.server;\n\n if (server === null || typeof server !== 'object' || Array.isArray(server)) {\n throw new ConfigError('Config must include a \"server\" mapping.');\n }\n\n const serverSection = server as Record<string, unknown>;\n\n if (!('port' in serverSection)) {\n throw new ConfigError('Config must include server.port.');\n }\n\n if (!('host' in serverSection)) {\n throw new ConfigError('Config must include server.host.');\n }\n\n const db = root.db;\n\n if (db === null || typeof db !== 'object' || Array.isArray(db)) {\n throw new ConfigError('Config must include a \"db\" mapping.');\n }\n\n const dbSection = db as Record<string, unknown>;\n\n if (!('driver' in dbSection)) {\n throw new ConfigError('Config must include db.driver.');\n }\n\n const redis = root.redis;\n\n if (redis === null || typeof redis !== 'object' || Array.isArray(redis)) {\n throw new ConfigError('Config must include a \"redis\" mapping.');\n }\n\n const redisSection = redis as Record<string, unknown>;\n\n if (!('host' in redisSection)) {\n throw new ConfigError('Config must include redis.host.');\n }\n\n if (!('port' in redisSection)) {\n throw new ConfigError('Config must include redis.port.');\n }\n}\n\n/**\n * Formats the first Zod validation issue into a short user-facing message.\n *\n * @param error - Zod validation error from schema parsing.\n * @returns Human-readable error string.\n */\nfunction formatZodError(error: ZodError): string {\n const issue = error.issues[0];\n if (!issue) {\n return 'Invalid config file.';\n }\n\n if (issue.message) {\n return issue.message;\n }\n\n return 'Invalid config file.';\n}\n\n/**\n * Validates and extracts server settings from a parsed YAML document.\n *\n * @param document - Parsed YAML root value.\n * @returns Normalized host and port settings.\n * @throws {ConfigError} When validation fails.\n */\nfunction parseServerConfig(document: unknown): ServerConfig {\n assertDocumentShape(document);\n\n const root = document as Record<string, unknown>;\n const parsedSection = serverSectionSchema.safeParse(root.server);\n\n if (!parsedSection.success) {\n throw new ConfigError(formatZodError(parsedSection.error));\n }\n\n const parsedDbSection = dbSectionSchema.safeParse(root.db);\n\n if (!parsedDbSection.success) {\n throw new ConfigError(formatZodError(parsedDbSection.error));\n }\n\n const parsedRedisSection = redisSectionSchema.safeParse(root.redis);\n\n if (!parsedRedisSection.success) {\n throw new ConfigError(formatZodError(parsedRedisSection.error));\n }\n\n const parsedDocument = serverConfigDocumentSchema.safeParse(document);\n if (!parsedDocument.success) {\n throw new ConfigError(formatZodError(parsedDocument.error));\n }\n\n let llm: LlmConfig | null = null;\n if (root.llm !== undefined) {\n const parsedLlmSection = llmSectionSchema.safeParse(root.llm);\n if (!parsedLlmSection.success) {\n throw new ConfigError(formatZodError(parsedLlmSection.error));\n }\n llm = normalizeLlmConfig(parsedLlmSection.data);\n }\n\n let plugins: PluginsConfig | null = null;\n if (root.plugins !== undefined) {\n const parsedPluginsSection = pluginsSectionSchema.safeParse(root.plugins);\n if (!parsedPluginsSection.success) {\n throw new ConfigError(formatZodError(parsedPluginsSection.error));\n }\n plugins = normalizePluginsConfig(parsedPluginsSection.data);\n }\n\n let docs: DocsConfig | null = null;\n if (root.docs !== undefined) {\n const parsedDocsSection = docsSectionSchema.safeParse(root.docs);\n if (!parsedDocsSection.success) {\n throw new ConfigError(formatZodError(parsedDocsSection.error));\n }\n docs = normalizeDocsConfig(parsedDocsSection.data);\n }\n\n let logging = DEFAULT_LOGGING_CONFIG;\n if (root.logging !== undefined) {\n const parsedLoggingSection = loggingSectionSchema.safeParse(root.logging);\n if (!parsedLoggingSection.success) {\n throw new ConfigError(formatZodError(parsedLoggingSection.error));\n }\n logging = normalizeLoggingConfig(parsedLoggingSection.data);\n }\n\n return {\n port: parsedDocument.data.server.port,\n host: parsedDocument.data.server.host,\n db: parsedDbSection.data as Record<string, unknown>,\n redis: parsedRedisSection.data as Record<string, unknown>,\n llm,\n plugins,\n docs,\n logging\n };\n}\n\n/**\n * Loads and validates server settings from a YAML config file.\n *\n * @param configPath - Path to the config file (relative to cwd or absolute).\n * @returns Parsed host and port settings.\n * @throws {ConfigError} When the file is missing, unreadable, or invalid.\n */\nexport function loadServerConfig(configPath: string): ServerConfig {\n const resolvedPath = resolveConfigPath(configPath);\n\n if (!existsSync(resolvedPath)) {\n throw new ConfigError(`Config file not found: ${configPath}`);\n }\n\n let document: unknown;\n try {\n document = parseYaml(readFileSync(resolvedPath, 'utf8'));\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new ConfigError(`Failed to parse config file: ${message}`);\n }\n\n try {\n return parseServerConfig(document);\n } catch (error) {\n if (error instanceof ConfigError) {\n throw error;\n }\n\n const message = error instanceof Error ? error.message : String(error);\n throw new ConfigError(message);\n }\n}\n","import path from 'node:path';\nimport type { DocsSection } from '#/config/serverConfig.schema.js';\n\n/**\n * Default filesystem path for the bundled documentation search index in Docker.\n */\nexport const DEFAULT_DOCS_SEARCH_INDEX_PATH = '/app/data/docsSearchIndex.json';\n\n/**\n * Normalized documentation search settings loaded from server.yaml.\n */\nexport interface DocsConfig {\n /**\n * Absolute or cwd-relative path to the serialized Orama docs index JSON file.\n */\n searchIndexPath: string;\n}\n\n/**\n * Resolves a docs index path relative to the process working directory when needed.\n *\n * @param searchIndexPath - Path from server.yaml or the default.\n * @returns Absolute filesystem path to the index file.\n */\nexport function resolveDocsSearchIndexPath(searchIndexPath: string): string {\n return path.isAbsolute(searchIndexPath)\n ? searchIndexPath\n : path.resolve(process.cwd(), searchIndexPath);\n}\n\n/**\n * Converts a validated YAML docs section into normalized runtime config.\n *\n * @param section - Parsed docs section from server.yaml.\n * @returns Normalized docs search settings for route handlers and tools.\n */\nexport function normalizeDocsConfig(section: DocsSection): DocsConfig {\n const trimmed = section.searchIndexPath?.trim();\n return {\n searchIndexPath: trimmed && trimmed.length > 0 ? trimmed : DEFAULT_DOCS_SEARCH_INDEX_PATH\n };\n}\n","import type { LlmSection } from '#/config/serverConfig.schema.js';\n\n/**\n * Raw MCP headers value from server.yaml before normalization.\n */\ntype HubMcpHeadersInput = NonNullable<NonNullable<LlmSection['mcp']>[number]['headers']>;\n\n/**\n * Supported LLM providers exposed by Team Hub.\n */\nexport type LlmProvider = 'openai' | 'claude' | 'gemini';\n\n/**\n * HTTP header row for hub MCP server connections.\n */\nexport interface HubMcpHeader {\n /**\n * Header name.\n */\n key: string;\n\n /**\n * Header value.\n */\n value: string;\n}\n\n/**\n * One MCP server configured under llm.mcp in server.yaml.\n */\nexport interface HubMcpServerConfig {\n /**\n * Display name for logs and diagnostics.\n */\n name: string;\n\n /**\n * MCP server URL (Streamable HTTP or legacy SSE endpoint).\n */\n url: string;\n\n /**\n * Optional HTTP headers sent with MCP client requests.\n */\n headers: HubMcpHeader[];\n}\n\n/**\n * Normalized LLM configuration loaded from server.yaml.\n */\nexport interface LlmConfig {\n /**\n * Provider API keys configured on the hub.\n */\n providers: Partial<Record<LlmProvider, { apiKey: string }>>;\n\n /**\n * Optional allow-list of model ids the hub offers; when omitted, all catalog\n * models whose provider has a key are offered.\n */\n models?: string[];\n\n /**\n * Optional MCP servers the hub agent may call during chat steps.\n */\n mcp?: HubMcpServerConfig[];\n}\n\n/**\n * Converts one header object with a single key into a normalized header row.\n *\n * @param record - Object whose keys are header names.\n */\nfunction headerRowsFromSingleKeyObject(record: Record<string, string>): HubMcpHeader[] {\n const rows: HubMcpHeader[] = [];\n for (const [key, value] of Object.entries(record)) {\n const trimmedKey = key.trim();\n if (trimmedKey.length > 0) {\n rows.push({ key: trimmedKey, value: String(value) });\n }\n }\n return rows;\n}\n\n/**\n * Normalizes MCP server headers from flexible YAML shapes into key/value rows.\n *\n * @param headers - Raw headers from server.yaml.\n */\nexport function normalizeHubMcpHeaders(headers: HubMcpHeadersInput | undefined): HubMcpHeader[] {\n if (!headers) {\n return [];\n }\n\n if (!Array.isArray(headers)) {\n return headerRowsFromSingleKeyObject(headers);\n }\n\n const rows: HubMcpHeader[] = [];\n for (const item of headers) {\n if (Array.isArray(item)) {\n for (const nested of item) {\n rows.push(...headerRowsFromSingleKeyObject(nested));\n }\n continue;\n }\n\n rows.push(...headerRowsFromSingleKeyObject(item));\n }\n\n return rows;\n}\n\n/**\n * Converts a validated YAML llm section into normalized runtime config.\n *\n * @param section - Parsed llm section from server.yaml.\n * @returns Normalized LLM config for route handlers and the provider client.\n */\nexport function normalizeLlmConfig(section: LlmSection): LlmConfig {\n const providers: LlmConfig['providers'] = {};\n\n if (section.providers.openai?.apiKey) {\n providers.openai = { apiKey: section.providers.openai.apiKey };\n }\n if (section.providers.claude?.apiKey) {\n providers.claude = { apiKey: section.providers.claude.apiKey };\n }\n if (section.providers.gemini?.apiKey) {\n providers.gemini = { apiKey: section.providers.gemini.apiKey };\n }\n\n const mcp =\n section.mcp && section.mcp.length > 0\n ? section.mcp.map((entry) => ({\n name: entry.name.trim(),\n url: entry.url.trim().replace(/\\/+$/, ''),\n headers: normalizeHubMcpHeaders(entry.headers)\n }))\n : undefined;\n\n return {\n providers,\n ...(section.models && section.models.length > 0 ? { models: section.models } : {}),\n ...(mcp && mcp.length > 0 ? { mcp } : {})\n };\n}\n","import type { LoggingSection } from '#/config/serverConfig.schema.js';\n\n/**\n * Supported log levels for Team Hub.\n */\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error';\n\n/**\n * Normalized logging configuration loaded from server.yaml.\n */\nexport interface LoggingConfig {\n /**\n * Minimum severity written to configured transports.\n */\n level: LogLevel;\n\n /**\n * Optional file path for log output; null when file logging is disabled.\n */\n file: string | null;\n\n /**\n * When true, log messages are also written to the terminal.\n */\n console: boolean;\n}\n\n/**\n * Default logging settings applied when the `logging` section is omitted.\n */\nexport const DEFAULT_LOGGING_CONFIG: LoggingConfig = {\n level: 'info',\n file: null,\n console: true\n};\n\n/**\n * Converts a validated YAML logging section into normalized runtime config.\n *\n * @param section - Parsed logging section from server.yaml, when present.\n * @returns Normalized logging config with defaults applied for omitted fields.\n */\nexport function normalizeLoggingConfig(section?: LoggingSection): LoggingConfig {\n return {\n level: section?.level ?? DEFAULT_LOGGING_CONFIG.level,\n file: section?.file ?? DEFAULT_LOGGING_CONFIG.file,\n console: section?.console ?? DEFAULT_LOGGING_CONFIG.console\n };\n}\n","import type { PluginsSection } from '#/config/serverConfig.schema.js';\n\n/**\n * Normalized plugin source settings loaded from server.yaml.\n */\nexport interface PluginsConfig {\n /**\n * Plugin marketplace catalog JSON URLs offered by this Team Hub.\n */\n catalogs: string[];\n\n /**\n * Trusted publisher signing-key registry JSON URLs offered by this Team Hub.\n */\n trusted: string[];\n}\n\n/**\n * Deduplicates URL strings while preserving the first occurrence.\n *\n * @param urls - Raw URL list from server.yaml.\n * @returns Unique URLs in original order.\n */\nfunction dedupeUrls(urls: string[]): string[] {\n const seen = new Set<string>();\n const deduped: string[] = [];\n\n for (const url of urls) {\n if (seen.has(url)) {\n continue;\n }\n seen.add(url);\n deduped.push(url);\n }\n\n return deduped;\n}\n\n/**\n * Converts a validated YAML plugins section into normalized runtime config.\n *\n * @param section - Parsed plugins section from server.yaml.\n * @returns Normalized plugin source URLs for route handlers.\n */\nexport function normalizePluginsConfig(section: PluginsSection): PluginsConfig {\n return {\n catalogs: dedupeUrls(section.catalogs ?? []),\n trusted: dedupeUrls(section.trusted ?? [])\n };\n}\n","import { z } from 'zod/v4';\n\nconst portSchema = z.union([\n z\n .number()\n .int({ message: 'Port must be an integer between 1 and 65535.' })\n .min(1, { message: 'Port must be an integer between 1 and 65535.' })\n .max(65535, { message: 'Port must be an integer between 1 and 65535.' }),\n z\n .string()\n .regex(/^\\d+$/, { message: 'Port must be an integer between 1 and 65535.' })\n .transform(Number)\n .pipe(\n z\n .number()\n .int({ message: 'Port must be an integer between 1 and 65535.' })\n .min(1, { message: 'Port must be an integer between 1 and 65535.' })\n .max(65535, { message: 'Port must be an integer between 1 and 65535.' })\n )\n]);\n\n/**\n * Zod schema for the `server` section of the config file (host and port).\n */\nexport const serverSectionSchema = z.object({\n port: portSchema,\n host: z.string().trim().min(1, { message: 'Host must not be empty.' })\n});\n\n/**\n * Zod schema for the `db` section of the config file (driver discriminant only).\n *\n * Driver-specific fields are validated by each database implementation.\n */\nexport const dbSectionSchema = z\n .object({\n driver: z.string().trim().min(1, { message: 'Database driver must not be empty.' })\n })\n .loose();\n\n/**\n * Zod schema for the `redis` section of the config file.\n *\n * Throttle policy fields default to 10 failures / 900s window / 900s block when omitted.\n */\nexport const redisSectionSchema = z\n .object({\n host: z.string().trim().min(1, { message: 'Redis host must not be empty.' }),\n port: portSchema,\n password: z.string().optional(),\n db: z\n .union([\n z.number().int().min(0).max(15),\n z.string().regex(/^\\d+$/).transform(Number).pipe(z.number().int().min(0).max(15))\n ])\n .optional(),\n keyPrefix: z.string().optional(),\n maxFailures: z\n .union([\n z.number().int().min(1),\n z.string().regex(/^\\d+$/).transform(Number).pipe(z.number().int().min(1))\n ])\n .optional(),\n windowSeconds: z\n .union([\n z.number().int().min(1),\n z.string().regex(/^\\d+$/).transform(Number).pipe(z.number().int().min(1))\n ])\n .optional(),\n blockSeconds: z\n .union([\n z.number().int().min(1),\n z.string().regex(/^\\d+$/).transform(Number).pipe(z.number().int().min(1))\n ])\n .optional()\n })\n .loose();\n\n/**\n * Zod schema for a single LLM provider API key entry in server.yaml.\n */\nexport const llmProviderEntrySchema = z.object({\n apiKey: z.string().trim().min(1, { message: 'LLM provider apiKey must not be empty.' })\n});\n\n/**\n * Zod schema for MCP server HTTP headers in server.yaml.\n *\n * Accepts an object map, an array of single-key objects, or one nested array level.\n */\nexport const hubMcpHeadersSchema = z.union([\n z.record(z.string(), z.string()),\n z.array(z.union([z.record(z.string(), z.string()), z.array(z.record(z.string(), z.string()))]))\n]);\n\n/**\n * Zod schema for one MCP server entry under llm.mcp.\n */\nexport const hubMcpServerEntrySchema = z.object({\n name: z.string().trim().min(1),\n url: z.string().trim().min(1),\n headers: hubMcpHeadersSchema.optional()\n});\n\n/**\n * Zod schema for the optional `llm` section of the config file.\n */\nexport const llmSectionSchema = z.object({\n providers: z\n .object({\n openai: llmProviderEntrySchema.optional(),\n claude: llmProviderEntrySchema.optional(),\n gemini: llmProviderEntrySchema.optional()\n })\n .refine(\n (providers) =>\n Boolean(providers.openai?.apiKey || providers.claude?.apiKey || providers.gemini?.apiKey),\n { message: 'llm.providers must include at least one provider with an apiKey.' }\n ),\n models: z.array(z.string().trim().min(1)).optional(),\n mcp: z.array(hubMcpServerEntrySchema).optional()\n});\n\n/**\n * Zod schema for the optional `plugins` section of the config file.\n */\nexport const pluginsSectionSchema = z.object({\n catalogs: z.array(z.string().trim().url()).optional(),\n trusted: z.array(z.string().trim().url()).optional()\n});\n\n/**\n * Zod schema for the optional `docs` section of the config file.\n */\nexport const docsSectionSchema = z.object({\n searchIndexPath: z.string().trim().min(1).optional()\n});\n\n/**\n * Zod schema for supported log levels in the optional `logging` section.\n */\nexport const logLevelSchema = z.enum(['debug', 'info', 'warn', 'error']);\n\n/**\n * Zod schema for the optional `logging` section of the config file.\n */\nexport const loggingSectionSchema = z.object({\n level: logLevelSchema.optional(),\n file: z.string().trim().min(1).optional(),\n console: z.boolean().optional()\n});\n\n/**\n * Zod schema for the full server config document (`server.yaml` root mapping).\n */\nexport const serverConfigDocumentSchema = z.object({\n server: serverSectionSchema,\n db: dbSectionSchema,\n redis: redisSectionSchema,\n llm: llmSectionSchema.optional(),\n plugins: pluginsSectionSchema.optional(),\n docs: docsSectionSchema.optional(),\n logging: loggingSectionSchema.optional()\n});\n\n/**\n * Validated shape of a parsed server config YAML file.\n */\nexport type ServerConfigDocument = z.infer<typeof serverConfigDocumentSchema>;\n\n/**\n * Validated shape of the optional llm section.\n */\nexport type LlmSection = z.infer<typeof llmSectionSchema>;\n\n/**\n * Validated shape of the optional plugins section.\n */\nexport type PluginsSection = z.infer<typeof pluginsSectionSchema>;\n\n/**\n * Validated shape of the optional docs section.\n */\nexport type DocsSection = z.infer<typeof docsSectionSchema>;\n\n/**\n * Validated shape of the optional logging section.\n */\nexport type LoggingSection = z.infer<typeof loggingSectionSchema>;\n","import type { Command } from 'commander';\n\nexport interface GlobalCommandOptions {\n /**\n * When true, enables verbose server logging.\n */\n verbose?: boolean;\n\n /**\n * Path to the server YAML config file.\n */\n config?: string;\n}\n\n/**\n * Merges root-level CLI options into a subcommand's parsed options.\n *\n * Commander stores global flags on the root program. Nested subcommands such as\n * `user create` must read them via {@link Command.optsWithGlobals}.\n *\n * @param command - The subcommand instance handling the action.\n * @param options - Options parsed for the subcommand action.\n * @returns Options with global `verbose` and `config` values applied.\n */\nexport function mergeGlobalOptions<T extends GlobalCommandOptions>(\n command: Command,\n options: T\n): T {\n const globalOpts = command.optsWithGlobals() as GlobalCommandOptions;\n\n return {\n ...options,\n verbose: globalOpts.verbose ?? options.verbose,\n config: globalOpts.config ?? options.config\n };\n}\n","import { randomUUID } from 'node:crypto';\nimport { Firestore, type DocumentReference, type Query } from '@google-cloud/firestore';\nimport { resolveActingUserName } from '#/db/attribution.js';\nimport { BOOTSTRAP_USER_NAME } from '#/db/bootstrapUsers.js';\nimport {\n API_TOKENS_COLLECTION,\n AUDIT_LOG_COLLECTION,\n COLLECTIONS_COLLECTION,\n ENVIRONMENTS_COLLECTION,\n FOLDERS_COLLECTION,\n LLM_USAGE_COLLECTION,\n LLM_USAGE_LOG_COLLECTION,\n REQUESTS_COLLECTION,\n RUN_RESULTS_COLLECTION,\n SNIPPETS_COLLECTION,\n USERS_COLLECTION,\n WRITE_BATCH_LIMIT\n} from '#/db/firestore/const.js';\nimport { createSystemUserInput, SYSTEM_USER_NAME } from '#/db/systemUsers.js';\nimport { firestoreConfigSchema } from '#/db/firestore/schemas.js';\nimport type {\n FirestoreApiTokenDocument,\n FirestoreAuditLogDocument,\n FirestoreCollectionDocument,\n FirestoreDatabaseConfig,\n FirestoreEnvironmentDocument,\n FirestoreFolderDocument,\n FirestoreLlmUsageDocument,\n FirestoreLlmUsageLogDocument,\n FirestoreRequestDocument,\n FirestoreRunResultDocument,\n FirestoreSnippetDocument,\n FirestoreUserDocument\n} from '#/db/firestore/types.js';\nimport {\n mapFirestoreApiToken,\n mapFirestoreAuditLog,\n mapFirestoreCollection,\n mapFirestoreEnvironment,\n mapFirestoreFolder,\n mapFirestoreLlmUsage,\n mapFirestoreLlmUsageLog,\n mapFirestoreRequest,\n mapFirestoreRunResult,\n mapFirestoreSnippet,\n mapFirestoreUser\n} from '#/db/firestore/utils.js';\nimport type { IDatabase } from '#/db/IDatabase.js';\nimport { buildDefaultRunResultLabel, parseRunResultPayload } from '#/db/runResultPayload.js';\nimport { trimRequiredName } from '#/db/trimRequiredName.js';\nimport { assertUserNameAvailable, assertUserNameNotReserved } from '#/db/userNameValidation.js';\nimport type {\n ApiTokenRecord,\n AuditAction,\n AuditEntityType,\n AuditLogRecord,\n AuthConfig,\n CollectionRecord,\n CreateRunResultInput,\n CreateUserInput,\n CreateLlmUsageLogInput,\n EnvironmentRecord,\n FolderRecord,\n KeyValue,\n ListAuditLogOptions,\n LlmUsageLogRecord,\n LlmUsageRecord,\n SaveRequestInput,\n RunResultRecord,\n SavedRequestRecord,\n SnippetRecord,\n SnippetScope,\n UpdateUserInput,\n UserRecord,\n Variable\n} from '#/db/types.js';\nimport { defaultAuth } from '#/db/types.js';\nimport { formatZodError } from '#/db/validation.js';\n\n/**\n * Firestore-backed database implementation.\n */\nexport class FirestoreDatabase implements IDatabase {\n /**\n * Active Firestore client, or null when disconnected.\n */\n private client: Firestore | null = null;\n\n /**\n * Cached identifier of the internal system user, when provisioned during migration.\n */\n private systemUserId: string | null = null;\n\n /**\n * Creates a Firestore database instance from validated config.\n *\n * @param config - Parsed Firestore connection settings.\n */\n constructor(private readonly config: FirestoreDatabaseConfig) {}\n\n /**\n * Validates raw config and constructs a {@link FirestoreDatabase}.\n *\n * @param config - Raw `db` section from server.yaml.\n * @returns Configured Firestore database instance.\n * @throws {Error} When config fails Firestore-specific validation.\n */\n static fromConfig(config: unknown): FirestoreDatabase {\n const parsed = firestoreConfigSchema.safeParse(config);\n if (!parsed.success) {\n throw new Error(formatZodError(parsed.error));\n }\n\n return new FirestoreDatabase({\n projectId: parsed.data.projectId,\n keyFilename: parsed.data.keyFilename\n });\n }\n\n /**\n * Opens a Firestore client and verifies connectivity by listing collections.\n */\n async connect(): Promise<void> {\n if (this.client) {\n return;\n }\n\n const client = new Firestore({\n projectId: this.config.projectId,\n keyFilename: this.config.keyFilename\n });\n\n await client.listCollections();\n\n this.client = client;\n }\n\n /**\n * Terminates the Firestore client and releases resources.\n */\n async disconnect(): Promise<void> {\n if (!this.client) {\n return;\n }\n\n await this.client.terminate();\n this.client = null;\n }\n\n /**\n * Firestore uses schemaless documents; provisions the system user and migrates orphan tokens.\n */\n async migrate(): Promise<void> {\n await this.ensureSystemUser();\n await this.migrateOrphanTokensToBootstrapUser();\n await this.migrateSnippetAccessBackfill();\n }\n\n /**\n * Returns the stable identifier of the internal system user, when provisioned.\n */\n getSystemUserId(): string | null {\n return this.systemUserId;\n }\n\n /**\n * Lists audit log entries ordered newest-first with optional filters.\n *\n * @param options - Optional limit and filter criteria.\n */\n async listAuditLog(options: ListAuditLogOptions = {}): Promise<AuditLogRecord[]> {\n const limit = options.limit ?? 100;\n let query: Query = this.requireClient().collection(AUDIT_LOG_COLLECTION);\n\n if (options.userId !== undefined) {\n query = query.where('userId', '==', options.userId);\n }\n\n if (options.entityType !== undefined) {\n query = query.where('entityType', '==', options.entityType);\n }\n\n if (options.entityId !== undefined) {\n query = query.where('entityId', '==', options.entityId);\n }\n\n const snapshot = await query.orderBy('createdAt', 'desc').limit(limit).get();\n return snapshot.docs.map((doc) =>\n mapFirestoreAuditLog(doc.id, doc.data() as FirestoreAuditLogDocument)\n );\n }\n\n /**\n * Creates a new user account with the given role and access lists.\n *\n * @param input - User fields to persist.\n * @param actingUserId - User performing the create action.\n */\n async createUser(input: CreateUserInput, actingUserId: string): Promise<UserRecord> {\n const trimmedName = trimRequiredName(input.name, 'User name');\n assertUserNameNotReserved(trimmedName);\n const id = randomUUID();\n const now = new Date();\n const attributionUserId = trimmedName === SYSTEM_USER_NAME ? id : actingUserId;\n const data: FirestoreUserDocument = {\n name: trimmedName,\n role: input.role,\n collectionAccess: input.collectionAccess,\n environmentAccess: input.environmentAccess,\n snippetAccess: input.snippetAccess,\n llmAccess: input.llmAccess ?? false,\n llmModels: input.llmModels ?? [],\n llmMonthlyTokenLimit: input.llmMonthlyTokenLimit ?? null,\n createdAt: now,\n updatedAt: now,\n createdByUserId: attributionUserId,\n updatedByUserId: attributionUserId\n };\n\n await this.requireClient().collection(USERS_COLLECTION).doc(id).set(data);\n await this.recordAuditEntry(actingUserId, 'create', 'user', id);\n\n const created = await this.findUserById(id);\n if (!created) {\n throw new Error('User not found after insert');\n }\n\n return created;\n }\n\n /**\n * Finds a user by stable identifier.\n *\n * @param id - User identifier to look up.\n */\n async findUserById(id: string): Promise<UserRecord | null> {\n const snapshot = await this.requireClient().collection(USERS_COLLECTION).doc(id).get();\n if (!snapshot.exists) {\n return null;\n }\n\n return mapFirestoreUser(id, snapshot.data() as FirestoreUserDocument);\n }\n\n /**\n * Finds a user by unique display name.\n *\n * @param name - User name to look up.\n */\n async findUserByName(name: string): Promise<UserRecord | null> {\n const snapshot = await this.requireClient()\n .collection(USERS_COLLECTION)\n .where('name', '==', name)\n .limit(1)\n .get();\n\n const doc = snapshot.docs[0];\n if (!doc) {\n return null;\n }\n\n return mapFirestoreUser(doc.id, doc.data() as FirestoreUserDocument);\n }\n\n /**\n * Lists all user accounts ordered by name.\n */\n async listUsers(): Promise<UserRecord[]> {\n const snapshot = await this.requireClient().collection(USERS_COLLECTION).orderBy('name').get();\n return snapshot.docs.map((doc) =>\n mapFirestoreUser(doc.id, doc.data() as FirestoreUserDocument)\n );\n }\n\n /**\n * Updates an existing user account.\n *\n * @param id - User identifier to update.\n * @param input - Partial fields to apply.\n * @param actingUserId - User performing the update action.\n */\n async updateUser(id: string, input: UpdateUserInput, actingUserId: string): Promise<UserRecord> {\n const existing = await this.findUserById(id);\n if (!existing) {\n throw new Error('User not found');\n }\n\n const name =\n input.name !== undefined ? trimRequiredName(input.name, 'User name') : existing.name;\n\n if (name !== existing.name) {\n assertUserNameNotReserved(name);\n const duplicate = await this.findUserByName(name);\n assertUserNameAvailable(name, id, duplicate);\n }\n\n const role = input.role ?? existing.role;\n const collectionAccess = input.collectionAccess ?? existing.collectionAccess;\n const environmentAccess = input.environmentAccess ?? existing.environmentAccess;\n const snippetAccess = input.snippetAccess ?? existing.snippetAccess;\n const llmAccess = input.llmAccess ?? existing.llmAccess;\n const llmModels = input.llmModels ?? existing.llmModels;\n const llmMonthlyTokenLimit =\n input.llmMonthlyTokenLimit !== undefined\n ? input.llmMonthlyTokenLimit\n : existing.llmMonthlyTokenLimit;\n const updatedAt = new Date();\n\n await this.requireClient().collection(USERS_COLLECTION).doc(id).update({\n name,\n role,\n collectionAccess,\n environmentAccess,\n snippetAccess,\n llmAccess,\n llmModels,\n llmMonthlyTokenLimit,\n updatedAt,\n updatedByUserId: actingUserId\n });\n\n await this.recordAuditEntry(actingUserId, 'update', 'user', id);\n\n const updated = await this.findUserById(id);\n if (!updated) {\n throw new Error('User not found');\n }\n\n return updated;\n }\n\n /**\n * Deletes a user account and revokes all of their API tokens.\n *\n * @param id - User identifier to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteUser(id: string, actingUserId: string): Promise<void> {\n const client = this.requireClient();\n const tokenSnapshot = await client\n .collection(API_TOKENS_COLLECTION)\n .where('userId', '==', id)\n .get();\n\n const batch = client.batch();\n\n for (const doc of tokenSnapshot.docs) {\n batch.delete(doc.ref);\n }\n\n batch.delete(client.collection(USERS_COLLECTION).doc(id));\n await batch.commit();\n\n await this.recordAuditEntry(actingUserId, 'delete', 'user', id);\n }\n\n /**\n * Assigns legacy API tokens without an owner to the bootstrap user.\n */\n async migrateOrphanTokensToBootstrapUser(): Promise<void> {\n const client = this.requireClient();\n const snapshot = await client.collection(API_TOKENS_COLLECTION).get();\n const orphanDocs = snapshot.docs.filter((doc) => {\n const data = doc.data() as Partial<FirestoreApiTokenDocument>;\n return data.userId === undefined || data.userId === null || data.userId === '';\n });\n\n if (orphanDocs.length === 0) {\n return;\n }\n\n const systemUserId = this.getSystemUserId();\n if (!systemUserId) {\n throw new Error('System user is not provisioned');\n }\n\n let bootstrapUser = await this.findUserByName(BOOTSTRAP_USER_NAME);\n if (!bootstrapUser) {\n bootstrapUser = await this.createUser(\n {\n name: BOOTSTRAP_USER_NAME,\n role: 'user',\n collectionAccess: ['*'],\n environmentAccess: ['*'],\n snippetAccess: ['*']\n },\n systemUserId\n );\n }\n\n for (let index = 0; index < orphanDocs.length; index += WRITE_BATCH_LIMIT) {\n const batch = client.batch();\n const chunk = orphanDocs.slice(index, index + WRITE_BATCH_LIMIT);\n for (const doc of chunk) {\n batch.update(doc.ref, { userId: bootstrapUser.id });\n }\n await batch.commit();\n }\n }\n\n /**\n * Grants wildcard snippet access to user accounts that already have wildcard collection access.\n */\n async migrateSnippetAccessBackfill(): Promise<void> {\n const client = this.requireClient();\n const snapshot = await client.collection(USERS_COLLECTION).where('role', '==', 'user').get();\n if (snapshot.docs.length === 0) {\n return;\n }\n\n let batch = client.batch();\n let batchSize = 0;\n\n for (const doc of snapshot.docs) {\n const data = doc.data() as FirestoreUserDocument;\n if ((data.snippetAccess?.length ?? 0) > 0) {\n continue;\n }\n if (!data.collectionAccess?.includes('*')) {\n continue;\n }\n\n batch.update(doc.ref, { snippetAccess: ['*'] });\n batchSize += 1;\n\n if (batchSize >= WRITE_BATCH_LIMIT) {\n await batch.commit();\n batch = client.batch();\n batchSize = 0;\n }\n }\n\n if (batchSize > 0) {\n await batch.commit();\n }\n }\n\n /**\n * Inserts a new API token document.\n *\n * @param record - Token metadata to persist.\n * @param actingUserId - User performing the create action.\n */\n async createApiToken(record: ApiTokenRecord, actingUserId: string): Promise<void> {\n await this.requireClient().collection(API_TOKENS_COLLECTION).doc(record.id).set({\n userId: record.userId,\n name: record.name,\n tokenHash: record.tokenHash,\n tokenPrefix: record.tokenPrefix,\n createdAt: record.createdAt,\n lastUsedAt: record.lastUsedAt,\n revokedAt: record.revokedAt,\n createdByUserId: actingUserId,\n updatedByUserId: actingUserId\n });\n\n await this.recordAuditEntry(actingUserId, 'create', 'api_token', record.id);\n }\n\n /**\n * Finds an active token by its stored hash.\n *\n * @param tokenHash - sha256 hex digest of the bearer token secret.\n */\n async findActiveApiTokenByHash(tokenHash: string): Promise<ApiTokenRecord | null> {\n const snapshot = await this.requireClient()\n .collection(API_TOKENS_COLLECTION)\n .where('tokenHash', '==', tokenHash)\n .limit(1)\n .get();\n\n const doc = snapshot.docs[0];\n if (!doc) {\n return null;\n }\n\n const data = doc.data() as FirestoreApiTokenDocument;\n if (data.revokedAt !== null || !data.userId) {\n return null;\n }\n\n return mapFirestoreApiToken(doc.id, data);\n }\n\n /**\n * Lists all API tokens ordered by creation time descending.\n */\n async listApiTokens(): Promise<ApiTokenRecord[]> {\n const snapshot = await this.requireClient()\n .collection(API_TOKENS_COLLECTION)\n .orderBy('createdAt', 'desc')\n .get();\n\n return snapshot.docs\n .map((doc) => mapFirestoreApiToken(doc.id, doc.data() as FirestoreApiTokenDocument))\n .filter((token) => Boolean(token.userId));\n }\n\n /**\n * Returns API tokens owned by a specific user ordered newest-first.\n *\n * @param userId - Owning user identifier.\n */\n async listApiTokensByUserId(userId: string): Promise<ApiTokenRecord[]> {\n const snapshot = await this.requireClient()\n .collection(API_TOKENS_COLLECTION)\n .where('userId', '==', userId)\n .orderBy('createdAt', 'desc')\n .get();\n\n return snapshot.docs.map((doc) =>\n mapFirestoreApiToken(doc.id, doc.data() as FirestoreApiTokenDocument)\n );\n }\n\n /**\n * Finds an API token record by stable identifier.\n *\n * @param id - Token identifier to look up.\n */\n async findApiTokenById(id: string): Promise<ApiTokenRecord | null> {\n const docRef = this.requireClient().collection(API_TOKENS_COLLECTION).doc(id);\n const snapshot = await docRef.get();\n if (!snapshot.exists) {\n return null;\n }\n\n return mapFirestoreApiToken(snapshot.id, snapshot.data() as FirestoreApiTokenDocument);\n }\n\n /**\n * Permanently removes an API token record by id.\n *\n * @param id - Token identifier to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteApiToken(id: string, actingUserId: string): Promise<boolean> {\n const docRef = this.requireClient().collection(API_TOKENS_COLLECTION).doc(id);\n const snapshot = await docRef.get();\n if (!snapshot.exists) {\n return false;\n }\n\n await docRef.delete();\n await this.recordAuditEntry(actingUserId, 'delete', 'api_token', id);\n return true;\n }\n\n /**\n * Soft-revokes an active token by id.\n *\n * @param id - Token identifier to revoke.\n * @param actingUserId - User performing the revoke action.\n */\n async revokeApiToken(id: string, actingUserId: string): Promise<boolean> {\n const docRef = this.requireClient().collection(API_TOKENS_COLLECTION).doc(id);\n const snapshot = await docRef.get();\n if (!snapshot.exists) {\n return false;\n }\n\n const data = snapshot.data() as FirestoreApiTokenDocument;\n if (data.revokedAt !== null) {\n return false;\n }\n\n await docRef.update({ revokedAt: new Date(), updatedByUserId: actingUserId });\n await this.recordAuditEntry(actingUserId, 'update', 'api_token', id);\n return true;\n }\n\n /**\n * Updates the last-used timestamp for a token.\n *\n * @param id - Token identifier that authenticated a request.\n * @param when - Timestamp of the authenticated request.\n */\n async touchApiTokenLastUsed(id: string, when: Date): Promise<void> {\n await this.requireClient()\n .collection(API_TOKENS_COLLECTION)\n .doc(id)\n .update({ lastUsedAt: when });\n }\n\n /**\n * Lists all collections ordered by name.\n */\n async listCollections(): Promise<CollectionRecord[]> {\n const snapshot = await this.requireClient()\n .collection(COLLECTIONS_COLLECTION)\n .orderBy('name')\n .get();\n\n return snapshot.docs.map((doc) =>\n mapFirestoreCollection(doc.id, doc.data() as FirestoreCollectionDocument)\n );\n }\n\n /**\n * Creates a new collection with the given name.\n *\n * @param name - Display name for the collection.\n * @param actingUserId - User performing the create action.\n */\n async createCollection(name: string, actingUserId: string): Promise<CollectionRecord> {\n const trimmedName = trimRequiredName(name, 'Collection name');\n const id = randomUUID();\n const now = new Date();\n const data: FirestoreCollectionDocument = {\n name: trimmedName,\n variables: [],\n headers: [],\n auth: defaultAuth(),\n preRequestScript: '',\n postRequestScript: '',\n createdAt: now,\n updatedAt: now,\n createdByUserId: actingUserId,\n updatedByUserId: actingUserId,\n deletionLocked: false\n };\n\n await this.requireClient().collection(COLLECTIONS_COLLECTION).doc(id).set(data);\n await this.recordAuditEntry(actingUserId, 'create', 'collection', id);\n return mapFirestoreCollection(id, data);\n }\n\n /**\n * Updates a collection's name, variables, headers, and scripts.\n *\n * @param actingUserId - User performing the update action.\n */\n async updateCollection(\n id: string,\n name: string,\n variables: Variable[],\n headers: KeyValue[],\n preRequestScript: string,\n postRequestScript: string,\n auth: AuthConfig,\n actingUserId: string\n ): Promise<CollectionRecord> {\n const trimmedName = trimRequiredName(name, 'Collection name');\n const updatedAt = new Date();\n const docRef = this.requireClient().collection(COLLECTIONS_COLLECTION).doc(id);\n const snapshot = await docRef.get();\n if (!snapshot.exists) {\n throw new Error('Collection not found');\n }\n\n const existing = snapshot.data() as FirestoreCollectionDocument;\n const updated: FirestoreCollectionDocument = {\n ...existing,\n name: trimmedName,\n variables,\n headers,\n auth,\n preRequestScript,\n postRequestScript,\n updatedAt,\n updatedByUserId: actingUserId\n };\n\n await docRef.update({\n name: trimmedName,\n variables,\n headers,\n auth,\n preRequestScript,\n postRequestScript,\n updatedAt,\n updatedByUserId: actingUserId\n });\n\n await this.recordAuditEntry(actingUserId, 'update', 'collection', id);\n return mapFirestoreCollection(id, updated);\n }\n\n /**\n * Deletes a collection and all of its requests and folders.\n *\n * @param id - Collection ID to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteCollection(id: string, actingUserId: string): Promise<void> {\n await this.recordAuditEntry(actingUserId, 'delete', 'collection', id);\n\n const client = this.requireClient();\n const requestsSnap = await client\n .collection(REQUESTS_COLLECTION)\n .where('collectionId', '==', id)\n .get();\n const foldersSnap = await client\n .collection(FOLDERS_COLLECTION)\n .where('collectionId', '==', id)\n .get();\n\n const refs = [\n ...requestsSnap.docs.map((requestDoc) => requestDoc.ref),\n ...foldersSnap.docs.map((folderDoc) => folderDoc.ref),\n client.collection(COLLECTIONS_COLLECTION).doc(id)\n ];\n\n await this.commitBatchedDeletes(refs);\n }\n\n /**\n * Finds a collection by stable identifier.\n *\n * @param id - Collection ID to look up.\n */\n async findCollectionById(id: string): Promise<CollectionRecord | null> {\n const snapshot = await this.requireClient().collection(COLLECTIONS_COLLECTION).doc(id).get();\n if (!snapshot.exists) {\n return null;\n }\n\n return mapFirestoreCollection(id, snapshot.data() as FirestoreCollectionDocument);\n }\n\n /**\n * Updates whether non-admin users may delete a collection.\n *\n * @param id - Collection ID to update.\n * @param deletionLocked - When true, user-role tokens cannot delete the collection.\n * @param actingUserId - Admin user performing the update.\n */\n async setCollectionDeletionLocked(\n id: string,\n deletionLocked: boolean,\n actingUserId: string\n ): Promise<CollectionRecord> {\n const docRef = this.requireClient().collection(COLLECTIONS_COLLECTION).doc(id);\n const snapshot = await docRef.get();\n if (!snapshot.exists) {\n throw new Error('Collection not found');\n }\n\n const updatedAt = new Date();\n await docRef.update({\n deletionLocked,\n updatedAt,\n updatedByUserId: actingUserId\n });\n\n await this.recordAuditEntry(actingUserId, 'update', 'collection', id);\n\n const existing = snapshot.data() as FirestoreCollectionDocument;\n return mapFirestoreCollection(id, {\n ...existing,\n deletionLocked,\n updatedAt,\n updatedByUserId: actingUserId\n });\n }\n\n /**\n * Lists all environments ordered by name.\n */\n async listEnvironments(): Promise<EnvironmentRecord[]> {\n const snapshot = await this.requireClient()\n .collection(ENVIRONMENTS_COLLECTION)\n .orderBy('name')\n .get();\n\n return snapshot.docs.map((doc) =>\n mapFirestoreEnvironment(doc.id, doc.data() as FirestoreEnvironmentDocument)\n );\n }\n\n /**\n * Creates a new environment with the given name.\n *\n * @param name - Display name for the environment.\n * @param actingUserId - User performing the create action.\n */\n async createEnvironment(name: string, actingUserId: string): Promise<EnvironmentRecord> {\n const trimmedName = trimRequiredName(name, 'Environment name');\n const id = randomUUID();\n const now = new Date();\n const data: FirestoreEnvironmentDocument = {\n name: trimmedName,\n variables: [],\n createdAt: now,\n updatedAt: now,\n createdByUserId: actingUserId,\n updatedByUserId: actingUserId,\n deletionLocked: false\n };\n\n await this.requireClient().collection(ENVIRONMENTS_COLLECTION).doc(id).set(data);\n await this.recordAuditEntry(actingUserId, 'create', 'environment', id);\n return mapFirestoreEnvironment(id, data);\n }\n\n /**\n * Updates an environment's name and variables.\n *\n * @param actingUserId - User performing the update action.\n */\n async updateEnvironment(\n id: string,\n name: string,\n variables: Variable[],\n actingUserId: string\n ): Promise<EnvironmentRecord> {\n const trimmedName = trimRequiredName(name, 'Environment name');\n const updatedAt = new Date();\n const docRef = this.requireClient().collection(ENVIRONMENTS_COLLECTION).doc(id);\n const snapshot = await docRef.get();\n if (!snapshot.exists) {\n throw new Error('Environment not found');\n }\n\n const existing = snapshot.data() as FirestoreEnvironmentDocument;\n const updated: FirestoreEnvironmentDocument = {\n ...existing,\n name: trimmedName,\n variables,\n updatedAt,\n updatedByUserId: actingUserId\n };\n\n await docRef.update({\n name: trimmedName,\n variables,\n updatedAt,\n updatedByUserId: actingUserId\n });\n\n await this.recordAuditEntry(actingUserId, 'update', 'environment', id);\n return mapFirestoreEnvironment(id, updated);\n }\n\n /**\n * Deletes an environment.\n *\n * @param id - Environment ID to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteEnvironment(id: string, actingUserId: string): Promise<void> {\n await this.recordAuditEntry(actingUserId, 'delete', 'environment', id);\n await this.requireClient().collection(ENVIRONMENTS_COLLECTION).doc(id).delete();\n }\n\n /**\n * Finds an environment by stable identifier.\n *\n * @param id - Environment ID to look up.\n */\n async findEnvironmentById(id: string): Promise<EnvironmentRecord | null> {\n const snapshot = await this.requireClient().collection(ENVIRONMENTS_COLLECTION).doc(id).get();\n if (!snapshot.exists) {\n return null;\n }\n\n return mapFirestoreEnvironment(id, snapshot.data() as FirestoreEnvironmentDocument);\n }\n\n /**\n * Updates whether non-admin users may delete an environment.\n *\n * @param id - Environment ID to update.\n * @param deletionLocked - When true, user-role tokens cannot delete the environment.\n * @param actingUserId - Admin user performing the update.\n */\n async setEnvironmentDeletionLocked(\n id: string,\n deletionLocked: boolean,\n actingUserId: string\n ): Promise<EnvironmentRecord> {\n const docRef = this.requireClient().collection(ENVIRONMENTS_COLLECTION).doc(id);\n const snapshot = await docRef.get();\n if (!snapshot.exists) {\n throw new Error('Environment not found');\n }\n\n const updatedAt = new Date();\n await docRef.update({\n deletionLocked,\n updatedAt,\n updatedByUserId: actingUserId\n });\n\n await this.recordAuditEntry(actingUserId, 'update', 'environment', id);\n\n const existing = snapshot.data() as FirestoreEnvironmentDocument;\n return mapFirestoreEnvironment(id, {\n ...existing,\n deletionLocked,\n updatedAt,\n updatedByUserId: actingUserId\n });\n }\n\n /**\n * Lists all snippets ordered by sort order then name.\n */\n async listSnippets(): Promise<SnippetRecord[]> {\n const snapshot = await this.requireClient().collection(SNIPPETS_COLLECTION).get();\n\n return snapshot.docs\n .map((doc) => mapFirestoreSnippet(doc.id, doc.data() as FirestoreSnippetDocument))\n .sort((left, right) => {\n if (left.sortOrder !== right.sortOrder) {\n return left.sortOrder - right.sortOrder;\n }\n\n return left.name.localeCompare(right.name);\n });\n }\n\n /**\n * Creates a new snippet with the given fields.\n *\n * @param name - Display name for the snippet.\n * @param code - JavaScript source for the snippet.\n * @param scope - Execution scope for the snippet.\n * @param actingUserId - User performing the create action.\n */\n async createSnippet(\n name: string,\n code: string,\n scope: SnippetScope,\n actingUserId: string\n ): Promise<SnippetRecord> {\n const trimmedName = trimRequiredName(name, 'Snippet name');\n const id = randomUUID();\n const now = new Date();\n const existing = await this.listSnippets();\n const maxOrder = existing.reduce((max, snippet) => Math.max(max, snippet.sortOrder), -1);\n const data: FirestoreSnippetDocument = {\n name: trimmedName,\n code,\n scope,\n sortOrder: maxOrder + 1,\n createdAt: now,\n updatedAt: now,\n createdByUserId: actingUserId,\n updatedByUserId: actingUserId,\n deletionLocked: false\n };\n\n await this.requireClient().collection(SNIPPETS_COLLECTION).doc(id).set(data);\n await this.recordAuditEntry(actingUserId, 'create', 'snippet', id);\n return mapFirestoreSnippet(id, data);\n }\n\n /**\n * Updates a snippet's name, code, and scope. Sort order is left unchanged.\n *\n * @param actingUserId - User performing the update action.\n */\n async updateSnippet(\n id: string,\n name: string,\n code: string,\n scope: SnippetScope,\n actingUserId: string\n ): Promise<SnippetRecord> {\n const trimmedName = trimRequiredName(name, 'Snippet name');\n const updatedAt = new Date();\n const docRef = this.requireClient().collection(SNIPPETS_COLLECTION).doc(id);\n const snapshot = await docRef.get();\n if (!snapshot.exists) {\n throw new Error('Snippet not found');\n }\n\n const existing = snapshot.data() as FirestoreSnippetDocument;\n const updated: FirestoreSnippetDocument = {\n ...existing,\n name: trimmedName,\n code,\n scope,\n updatedAt,\n updatedByUserId: actingUserId\n };\n\n await docRef.update({\n name: trimmedName,\n code,\n scope,\n updatedAt,\n updatedByUserId: actingUserId\n });\n\n await this.recordAuditEntry(actingUserId, 'update', 'snippet', id);\n return mapFirestoreSnippet(id, updated);\n }\n\n /**\n * Deletes a snippet.\n *\n * @param id - Snippet ID to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteSnippet(id: string, actingUserId: string): Promise<void> {\n await this.recordAuditEntry(actingUserId, 'delete', 'snippet', id);\n await this.requireClient().collection(SNIPPETS_COLLECTION).doc(id).delete();\n }\n\n /**\n * Finds a snippet by stable identifier.\n *\n * @param id - Snippet ID to look up.\n */\n async findSnippetById(id: string): Promise<SnippetRecord | null> {\n const snapshot = await this.requireClient().collection(SNIPPETS_COLLECTION).doc(id).get();\n if (!snapshot.exists) {\n return null;\n }\n\n return mapFirestoreSnippet(id, snapshot.data() as FirestoreSnippetDocument);\n }\n\n /**\n * Updates whether non-admin users may delete a snippet.\n *\n * @param id - Snippet ID to update.\n * @param deletionLocked - When true, user-role tokens cannot delete the snippet.\n * @param actingUserId - Admin user performing the update.\n */\n async setSnippetDeletionLocked(\n id: string,\n deletionLocked: boolean,\n actingUserId: string\n ): Promise<SnippetRecord> {\n const docRef = this.requireClient().collection(SNIPPETS_COLLECTION).doc(id);\n const snapshot = await docRef.get();\n if (!snapshot.exists) {\n throw new Error('Snippet not found');\n }\n\n const updatedAt = new Date();\n await docRef.update({\n deletionLocked,\n updatedAt,\n updatedByUserId: actingUserId\n });\n\n await this.recordAuditEntry(actingUserId, 'update', 'snippet', id);\n\n const existing = snapshot.data() as FirestoreSnippetDocument;\n return mapFirestoreSnippet(id, {\n ...existing,\n deletionLocked,\n updatedAt,\n updatedByUserId: actingUserId\n });\n }\n\n /**\n * Lists all saved requests in a collection.\n *\n * @param collectionId - Collection to query.\n */\n async listRequests(collectionId: string): Promise<SavedRequestRecord[]> {\n const snapshot = await this.requireClient()\n .collection(REQUESTS_COLLECTION)\n .where('collectionId', '==', collectionId)\n .get();\n\n return snapshot.docs\n .map((doc) => mapFirestoreRequest(doc.id, doc.data() as FirestoreRequestDocument))\n .sort((left, right) => {\n if (left.sortOrder !== right.sortOrder) {\n return left.sortOrder - right.sortOrder;\n }\n\n return left.name.localeCompare(right.name);\n });\n }\n\n /**\n * Finds a saved request by id.\n *\n * @param id - Request identifier to look up.\n */\n async findRequestById(id: string): Promise<SavedRequestRecord | null> {\n const snapshot = await this.requireClient().collection(REQUESTS_COLLECTION).doc(id).get();\n if (!snapshot.exists) {\n return null;\n }\n\n return mapFirestoreRequest(id, snapshot.data() as FirestoreRequestDocument);\n }\n\n /**\n * Inserts a new request or updates an existing one.\n *\n * @param input - Request fields to persist.\n * @param actingUserId - User performing the save action.\n */\n async saveRequest(input: SaveRequestInput, actingUserId: string): Promise<SavedRequestRecord> {\n const trimmedName = trimRequiredName(input.name, 'Request name');\n const folderId = input.folderId ?? null;\n const now = new Date();\n const client = this.requireClient();\n\n if (folderId != null) {\n const folderSnap = await client.collection(FOLDERS_COLLECTION).doc(folderId).get();\n if (!folderSnap.exists) {\n throw new Error('Folder not found');\n }\n\n const folder = folderSnap.data() as FirestoreFolderDocument;\n if (folder.collectionId !== input.collectionId) {\n throw new Error('Folder not found');\n }\n }\n\n if (input.id) {\n const docRef = client.collection(REQUESTS_COLLECTION).doc(input.id);\n const snapshot = await docRef.get();\n if (snapshot.exists) {\n const existing = snapshot.data() as FirestoreRequestDocument;\n const updated: FirestoreRequestDocument = {\n ...existing,\n collectionId: input.collectionId,\n folderId,\n name: trimmedName,\n method: input.method,\n url: input.url,\n headers: input.headers,\n params: input.params,\n auth: input.auth,\n body: input.body,\n bodyType: input.bodyType,\n preRequestScript: input.preRequestScript,\n postRequestScript: input.postRequestScript,\n comment: input.comment,\n updatedAt: now,\n updatedByUserId: actingUserId\n };\n\n await docRef.update({\n collectionId: input.collectionId,\n folderId,\n name: trimmedName,\n method: input.method,\n url: input.url,\n headers: input.headers,\n params: input.params,\n auth: input.auth,\n body: input.body,\n bodyType: input.bodyType,\n preRequestScript: input.preRequestScript,\n postRequestScript: input.postRequestScript,\n comment: input.comment,\n updatedAt: now,\n updatedByUserId: actingUserId\n });\n\n await this.recordAuditEntry(actingUserId, 'update', 'request', input.id);\n return mapFirestoreRequest(input.id, updated);\n }\n }\n\n const existingRequests = await this.listRequests(input.collectionId);\n const maxOrder = existingRequests\n .filter((request) => request.folderId === folderId)\n .reduce((max, request) => Math.max(max, request.sortOrder), -1);\n const id = randomUUID();\n const data: FirestoreRequestDocument = {\n collectionId: input.collectionId,\n folderId,\n name: trimmedName,\n method: input.method,\n url: input.url,\n headers: input.headers,\n params: input.params,\n auth: input.auth,\n body: input.body,\n bodyType: input.bodyType,\n preRequestScript: input.preRequestScript,\n postRequestScript: input.postRequestScript,\n comment: input.comment,\n sortOrder: maxOrder + 1,\n createdAt: now,\n updatedAt: now,\n createdByUserId: actingUserId,\n updatedByUserId: actingUserId\n };\n\n await client.collection(REQUESTS_COLLECTION).doc(id).set(data);\n await this.recordAuditEntry(actingUserId, 'create', 'request', id);\n return mapFirestoreRequest(id, data);\n }\n\n /**\n * Deletes a saved request by ID.\n *\n * @param id - Request ID to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteRequest(id: string, actingUserId: string): Promise<void> {\n await this.recordAuditEntry(actingUserId, 'delete', 'request', id);\n await this.requireClient().collection(REQUESTS_COLLECTION).doc(id).delete();\n }\n\n /**\n * Lists all folders in a collection.\n *\n * @param collectionId - Collection to query.\n */\n async listFolders(collectionId: string): Promise<FolderRecord[]> {\n const snapshot = await this.requireClient()\n .collection(FOLDERS_COLLECTION)\n .where('collectionId', '==', collectionId)\n .get();\n\n return snapshot.docs\n .map((doc) => mapFirestoreFolder(doc.id, doc.data() as FirestoreFolderDocument))\n .sort((left, right) => {\n if (left.sortOrder !== right.sortOrder) {\n return left.sortOrder - right.sortOrder;\n }\n\n return left.name.localeCompare(right.name);\n });\n }\n\n /**\n * Finds a folder by id.\n *\n * @param id - Folder identifier to look up.\n */\n async findFolderById(id: string): Promise<FolderRecord | null> {\n const snapshot = await this.requireClient().collection(FOLDERS_COLLECTION).doc(id).get();\n if (!snapshot.exists) {\n return null;\n }\n\n return mapFirestoreFolder(id, snapshot.data() as FirestoreFolderDocument);\n }\n\n /**\n * Creates a new folder in a collection.\n *\n * @param collectionId - Collection to add the folder to.\n * @param name - Display name for the folder.\n * @param actingUserId - User performing the create action.\n */\n async createFolder(\n collectionId: string,\n name: string,\n actingUserId: string\n ): Promise<FolderRecord> {\n const trimmedName = trimRequiredName(name, 'Folder name');\n const id = randomUUID();\n const now = new Date();\n const existingFolders = await this.listFolders(collectionId);\n const maxOrder = existingFolders.reduce((max, folder) => Math.max(max, folder.sortOrder), -1);\n const data: FirestoreFolderDocument = {\n collectionId,\n name: trimmedName,\n sortOrder: maxOrder + 1,\n createdAt: now,\n updatedAt: now,\n createdByUserId: actingUserId,\n updatedByUserId: actingUserId\n };\n\n await this.requireClient().collection(FOLDERS_COLLECTION).doc(id).set(data);\n await this.recordAuditEntry(actingUserId, 'create', 'folder', id);\n return mapFirestoreFolder(id, data);\n }\n\n /**\n * Renames a folder.\n *\n * @param id - Folder ID to rename.\n * @param name - New display name.\n * @param actingUserId - User performing the rename action.\n */\n async renameFolder(id: string, name: string, actingUserId: string): Promise<FolderRecord> {\n const trimmedName = trimRequiredName(name, 'Folder name');\n const updatedAt = new Date();\n const docRef = this.requireClient().collection(FOLDERS_COLLECTION).doc(id);\n const snapshot = await docRef.get();\n if (!snapshot.exists) {\n throw new Error('Folder not found');\n }\n\n const existing = snapshot.data() as FirestoreFolderDocument;\n await docRef.update({ name: trimmedName, updatedAt, updatedByUserId: actingUserId });\n await this.recordAuditEntry(actingUserId, 'update', 'folder', id);\n return mapFirestoreFolder(id, {\n ...existing,\n name: trimmedName,\n updatedAt,\n updatedByUserId: actingUserId\n });\n }\n\n /**\n * Deletes a folder and all requests inside it.\n *\n * @param id - Folder ID to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteFolder(id: string, actingUserId: string): Promise<void> {\n await this.recordAuditEntry(actingUserId, 'delete', 'folder', id);\n\n const client = this.requireClient();\n const requestsSnap = await client\n .collection(REQUESTS_COLLECTION)\n .where('folderId', '==', id)\n .get();\n\n const refs = [\n ...requestsSnap.docs.map((requestDoc) => requestDoc.ref),\n client.collection(FOLDERS_COLLECTION).doc(id)\n ];\n\n await this.commitBatchedDeletes(refs);\n }\n\n /**\n * Reorders folders within a collection.\n *\n * @param collectionId - Collection containing the folders.\n * @param orderedFolderIds - Folder IDs in desired order.\n * @param actingUserId - User performing the reorder action.\n */\n async reorderFolders(\n collectionId: string,\n orderedFolderIds: string[],\n actingUserId: string\n ): Promise<void> {\n const client = this.requireClient();\n const updatedAt = new Date();\n const batch = client.batch();\n\n for (let index = 0; index < orderedFolderIds.length; index++) {\n const docRef = client.collection(FOLDERS_COLLECTION).doc(orderedFolderIds[index]);\n batch.update(docRef, {\n sortOrder: index,\n collectionId,\n updatedAt,\n updatedByUserId: actingUserId\n });\n }\n\n await batch.commit();\n await this.recordAuditEntry(actingUserId, 'reorder', 'folder', collectionId, {\n orderedFolderIds\n });\n }\n\n /**\n * Reorders requests within a folder or at collection root.\n *\n * @param actingUserId - User performing the reorder action.\n */\n async reorderRequests(\n collectionId: string,\n folderId: string | null,\n orderedRequestIds: string[],\n actingUserId: string\n ): Promise<void> {\n const client = this.requireClient();\n const updatedAt = new Date();\n const batch = client.batch();\n\n for (let index = 0; index < orderedRequestIds.length; index++) {\n const docRef = client.collection(REQUESTS_COLLECTION).doc(orderedRequestIds[index]);\n batch.update(docRef, {\n sortOrder: index,\n folderId,\n collectionId,\n updatedAt,\n updatedByUserId: actingUserId\n });\n }\n\n await batch.commit();\n await this.recordAuditEntry(actingUserId, 'reorder', 'request', collectionId, {\n folderId,\n orderedRequestIds\n });\n }\n\n /**\n * Moves a request to another folder or collection root at a given index.\n *\n * @param actingUserId - User performing the move action.\n */\n async moveRequest(\n requestId: string,\n folderId: string | null,\n index: number,\n actingUserId: string\n ): Promise<void> {\n const client = this.requireClient();\n const updatedAt = new Date();\n const requestSnap = await client.collection(REQUESTS_COLLECTION).doc(requestId).get();\n if (!requestSnap.exists) {\n throw new Error('Request not found');\n }\n\n const request = mapFirestoreRequest(\n requestSnap.id,\n requestSnap.data() as FirestoreRequestDocument\n );\n const collectionId = request.collectionId;\n const oldFolderId = request.folderId;\n\n if (folderId != null) {\n const folderSnap = await client.collection(FOLDERS_COLLECTION).doc(folderId).get();\n if (!folderSnap.exists) {\n throw new Error('Folder not found');\n }\n\n const folder = folderSnap.data() as FirestoreFolderDocument;\n if (folder.collectionId !== collectionId) {\n throw new Error('Folder not found');\n }\n }\n\n /**\n * Lists request ids in a container ordered for reindexing.\n *\n * @param targetFolderId - Folder id or null for collection root.\n */\n const listInContainer = async (targetFolderId: string | null): Promise<string[]> => {\n const requests = await this.listRequests(collectionId);\n return requests\n .filter((item) => item.folderId === targetFolderId)\n .sort((left, right) => {\n if (left.sortOrder !== right.sortOrder) {\n return left.sortOrder - right.sortOrder;\n }\n\n return left.name.localeCompare(right.name);\n })\n .map((item) => item.id);\n };\n\n /**\n * Rewrites sort_order and folder_id for a container's request list.\n *\n * @param targetFolderId - Folder id or null for collection root.\n * @param orderedIds - Request ids in desired order.\n */\n const reindexContainer = async (\n targetFolderId: string | null,\n orderedIds: string[]\n ): Promise<void> => {\n const batch = client.batch();\n for (let sortIndex = 0; sortIndex < orderedIds.length; sortIndex++) {\n const docRef = client.collection(REQUESTS_COLLECTION).doc(orderedIds[sortIndex]);\n batch.update(docRef, {\n sortOrder: sortIndex,\n folderId: targetFolderId,\n updatedAt,\n updatedByUserId: actingUserId\n });\n }\n await batch.commit();\n };\n\n if (oldFolderId === folderId) {\n const siblings = (await listInContainer(folderId)).filter((id) => id !== requestId);\n siblings.splice(index, 0, requestId);\n await reindexContainer(folderId, siblings);\n await this.recordAuditEntry(actingUserId, 'move', 'request', requestId, {\n folderId,\n index\n });\n return;\n }\n\n const oldIds = (await listInContainer(oldFolderId)).filter((id) => id !== requestId);\n await reindexContainer(oldFolderId, oldIds);\n\n const newIds = (await listInContainer(folderId)).filter((id) => id !== requestId);\n newIds.splice(index, 0, requestId);\n await reindexContainer(folderId, newIds);\n\n await this.recordAuditEntry(actingUserId, 'move', 'request', requestId, {\n folderId,\n index\n });\n }\n\n /**\n * Returns monthly LLM usage for a user, or null when no usage has been recorded.\n *\n * @param userId - Owning user identifier.\n * @param period - UTC calendar month key (`YYYY-MM`).\n */\n async getLlmUsage(userId: string, period: string): Promise<LlmUsageRecord | null> {\n const docId = `${userId}_${period}`;\n const snapshot = await this.requireClient().collection(LLM_USAGE_COLLECTION).doc(docId).get();\n\n if (!snapshot.exists) {\n return null;\n }\n\n return mapFirestoreLlmUsage(docId, snapshot.data() as FirestoreLlmUsageDocument);\n }\n\n /**\n * Atomically increments monthly LLM token usage for a user.\n *\n * @param userId - Owning user identifier.\n * @param period - UTC calendar month key (`YYYY-MM`).\n * @param promptTokens - Prompt tokens to add.\n * @param completionTokens - Completion tokens to add.\n */\n async addLlmUsage(\n userId: string,\n period: string,\n promptTokens: number,\n completionTokens: number\n ): Promise<LlmUsageRecord> {\n const docId = `${userId}_${period}`;\n const docRef = this.requireClient().collection(LLM_USAGE_COLLECTION).doc(docId);\n const now = new Date();\n const totalDelta = promptTokens + completionTokens;\n\n await this.requireClient().runTransaction(async (transaction) => {\n const snapshot = await transaction.get(docRef);\n if (!snapshot.exists) {\n const data: FirestoreLlmUsageDocument = {\n userId,\n period,\n promptTokens,\n completionTokens,\n totalTokens: totalDelta,\n updatedAt: now\n };\n transaction.set(docRef, data);\n return;\n }\n\n const existing = snapshot.data() as FirestoreLlmUsageDocument;\n transaction.update(docRef, {\n promptTokens: existing.promptTokens + promptTokens,\n completionTokens: existing.completionTokens + completionTokens,\n totalTokens: existing.totalTokens + totalDelta,\n updatedAt: now\n });\n });\n\n const usage = await this.getLlmUsage(userId, period);\n if (!usage) {\n throw new Error('LLM usage not found after upsert');\n }\n\n return usage;\n }\n\n /**\n * Lists run results saved by the given user, newest first.\n *\n * @param userId - Owning user identifier.\n */\n async listRunResultsForUser(userId: string): Promise<RunResultRecord[]> {\n const snapshot = await this.requireClient()\n .collection(RUN_RESULTS_COLLECTION)\n .where('createdByUserId', '==', userId)\n .orderBy('createdAt', 'desc')\n .get();\n\n return snapshot.docs.map((doc) =>\n mapFirestoreRunResult(doc.id, doc.data() as FirestoreRunResultDocument)\n );\n }\n\n /**\n * Lists all run results for admin inspection, newest first.\n */\n async listAllRunResults(): Promise<RunResultRecord[]> {\n const snapshot = await this.requireClient()\n .collection(RUN_RESULTS_COLLECTION)\n .orderBy('createdAt', 'desc')\n .get();\n\n return snapshot.docs.map((doc) =>\n mapFirestoreRunResult(doc.id, doc.data() as FirestoreRunResultDocument)\n );\n }\n\n /**\n * Creates a standalone run result snapshot.\n *\n * @param input - HarborClient export payload and optional label.\n * @param actingUserId - User performing the create action.\n */\n async createRunResult(\n input: CreateRunResultInput,\n actingUserId: string\n ): Promise<RunResultRecord> {\n const metadata = parseRunResultPayload(input.payload);\n const label = input.label?.trim() || buildDefaultRunResultLabel(metadata);\n const id = randomUUID();\n const now = new Date();\n const data: FirestoreRunResultDocument = {\n kind: metadata.kind,\n label,\n collectionName: metadata.collectionName,\n requestName: metadata.requestName,\n summary: metadata.summary,\n payload: input.payload,\n createdAt: now,\n createdByUserId: actingUserId\n };\n\n await this.requireClient().collection(RUN_RESULTS_COLLECTION).doc(id).set(data);\n await this.recordAuditEntry(actingUserId, 'create', 'run_result', id);\n return mapFirestoreRunResult(id, data);\n }\n\n /**\n * Finds a run result by stable identifier.\n *\n * @param id - Run result ID to look up.\n */\n async findRunResultById(id: string): Promise<RunResultRecord | null> {\n const snapshot = await this.requireClient().collection(RUN_RESULTS_COLLECTION).doc(id).get();\n if (!snapshot.exists) {\n return null;\n }\n\n return mapFirestoreRunResult(id, snapshot.data() as FirestoreRunResultDocument);\n }\n\n /**\n * Deletes a run result.\n *\n * @param id - Run result ID to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteRunResult(id: string, actingUserId: string): Promise<void> {\n const docRef = this.requireClient().collection(RUN_RESULTS_COLLECTION).doc(id);\n const snapshot = await docRef.get();\n if (!snapshot.exists) {\n throw new Error('Run result not found');\n }\n\n await this.recordAuditEntry(actingUserId, 'delete', 'run_result', id);\n await docRef.delete();\n }\n\n /**\n * Inserts a per-request LLM usage log entry.\n *\n * @param input - Usage details for one successful completion step.\n */\n async createLlmUsageLog(input: CreateLlmUsageLogInput): Promise<LlmUsageLogRecord> {\n const id = randomUUID();\n const now = new Date();\n const data: FirestoreLlmUsageLogDocument = {\n userId: input.userId,\n apiTokenId: input.apiTokenId,\n period: input.period,\n model: input.model,\n provider: input.provider,\n promptTokens: input.promptTokens,\n completionTokens: input.completionTokens,\n totalTokens: input.totalTokens,\n isNewTurn: input.isNewTurn,\n hadToolCalls: input.hadToolCalls,\n messageCount: input.messageCount,\n createdAt: now\n };\n\n await this.requireClient().collection(LLM_USAGE_LOG_COLLECTION).doc(id).set(data);\n\n return mapFirestoreLlmUsageLog(id, data);\n }\n\n /**\n * Lists all per-request LLM usage log entries, newest first.\n */\n async listLlmUsageLogs(): Promise<LlmUsageLogRecord[]> {\n const snapshot = await this.requireClient()\n .collection(LLM_USAGE_LOG_COLLECTION)\n .orderBy('createdAt', 'desc')\n .get();\n\n return snapshot.docs.map((doc) =>\n mapFirestoreLlmUsageLog(doc.id, doc.data() as FirestoreLlmUsageLogDocument)\n );\n }\n\n /**\n * Commits document deletes in Firestore-sized batches.\n *\n * @param refs - Document refs to delete.\n */\n private async commitBatchedDeletes(refs: DocumentReference[]): Promise<void> {\n const client = this.requireClient();\n\n for (let offset = 0; offset < refs.length; offset += WRITE_BATCH_LIMIT) {\n const batch = client.batch();\n for (const ref of refs.slice(offset, offset + WRITE_BATCH_LIMIT)) {\n batch.delete(ref);\n }\n await batch.commit();\n }\n }\n\n /**\n * Ensures the internal system user exists and caches its identifier.\n *\n * Inserts directly rather than calling {@link createUser} to avoid recursion\n * during migration bootstrap.\n */\n private async ensureSystemUser(): Promise<void> {\n const existing = await this.findUserByName(SYSTEM_USER_NAME);\n if (existing) {\n this.systemUserId = existing.id;\n return;\n }\n\n const input = createSystemUserInput();\n const id = randomUUID();\n const now = new Date();\n const trimmedName = trimRequiredName(input.name, 'User name');\n const data: FirestoreUserDocument = {\n name: trimmedName,\n role: input.role,\n collectionAccess: input.collectionAccess,\n environmentAccess: input.environmentAccess,\n snippetAccess: input.snippetAccess,\n llmAccess: false,\n llmModels: [],\n llmMonthlyTokenLimit: null,\n createdAt: now,\n updatedAt: now,\n createdByUserId: id,\n updatedByUserId: id\n };\n\n await this.requireClient().collection(USERS_COLLECTION).doc(id).set(data);\n this.systemUserId = id;\n }\n\n /**\n * Persists a single audit log entry for a mutating action.\n *\n * @param actingUserId - User performing the action.\n * @param action - CRUD or structural action performed.\n * @param entityType - Kind of entity affected.\n * @param entityId - Identifier of the affected entity.\n * @param metadata - Optional structured context for the action.\n */\n private async recordAuditEntry(\n actingUserId: string,\n action: AuditAction,\n entityType: AuditEntityType,\n entityId: string,\n metadata?: Record<string, unknown> | null\n ): Promise<void> {\n const userName = await resolveActingUserName(\n (userId) => this.findUserById(userId),\n actingUserId\n );\n const id = randomUUID();\n const now = new Date();\n const data: FirestoreAuditLogDocument = {\n userId: actingUserId,\n userName,\n action,\n entityType,\n entityId,\n createdAt: now,\n metadata: metadata ?? null\n };\n\n await this.requireClient().collection(AUDIT_LOG_COLLECTION).doc(id).set(data);\n }\n\n /**\n * Returns the active Firestore client or throws when connect has not been called.\n *\n * @returns Connected Firestore client.\n * @throws {Error} When the database is not connected.\n */\n private requireClient(): Firestore {\n if (!this.client) {\n throw new Error('Firestore database is not connected.');\n }\n\n return this.client;\n }\n}\n","import type { UserRecord } from '#/db/types.js';\n\n/**\n * Resolves the display name for an acting user id.\n *\n * @param findUserById - Lookup function provided by the active database backend.\n * @param actingUserId - User identifier performing the action.\n * @returns The user's display name, or null when the user no longer exists.\n */\nexport async function resolveActingUserName(\n findUserById: (id: string) => Promise<UserRecord | null>,\n actingUserId: string\n): Promise<string | null> {\n const user = await findUserById(actingUserId);\n return user?.name ?? null;\n}\n","import { randomUUID } from 'node:crypto';\nimport type { UserRecord } from '#/db/types.js';\n\n/**\n * Display name assigned to the migration bootstrap user for orphan API tokens.\n */\nexport const BOOTSTRAP_USER_NAME = 'bootstrap';\n\n/**\n * Builds the bootstrap user record used when assigning legacy tokens during migration.\n *\n * @param now - Timestamp used for created and updated fields.\n * @returns Bootstrap user with full collection and environment access.\n */\nexport function createBootstrapUserRecord(now: Date): UserRecord {\n return {\n id: randomUUID(),\n name: BOOTSTRAP_USER_NAME,\n role: 'user',\n collectionAccess: ['*'],\n environmentAccess: ['*'],\n snippetAccess: ['*'],\n llmAccess: false,\n llmModels: [],\n llmMonthlyTokenLimit: null,\n createdAt: now,\n updatedAt: now,\n createdByUserId: null,\n updatedByUserId: null\n };\n}\n","/**\n * Firestore collection name for user account documents.\n */\nexport const USERS_COLLECTION = 'users';\n\n/**\n * Firestore collection name for API token documents.\n */\nexport const API_TOKENS_COLLECTION = 'apiTokens';\n\n/**\n * Firestore collection name for shared collection documents.\n */\nexport const COLLECTIONS_COLLECTION = 'collections';\n\n/**\n * Firestore collection name for environment documents.\n */\nexport const ENVIRONMENTS_COLLECTION = 'environments';\n\n/**\n * Firestore collection name for snippet documents.\n */\nexport const SNIPPETS_COLLECTION = 'snippets';\n\n/**\n * Firestore collection name for folder documents.\n */\nexport const FOLDERS_COLLECTION = 'folders';\n\n/**\n * Firestore collection name for saved request documents.\n */\nexport const REQUESTS_COLLECTION = 'requests';\n\n/**\n * Firestore collection name for audit log documents.\n */\nexport const AUDIT_LOG_COLLECTION = 'auditLog';\n\n/**\n * Firestore collection name for monthly LLM usage documents.\n */\nexport const LLM_USAGE_COLLECTION = 'llmUsage';\n\n/**\n * Firestore collection name for per-request LLM usage log documents.\n */\nexport const LLM_USAGE_LOG_COLLECTION = 'llmUsageLog';\n\n/**\n * Firestore collection name for run result documents.\n */\nexport const RUN_RESULTS_COLLECTION = 'runResults';\n\n/**\n * Maximum writes per Firestore batch commit.\n */\nexport const WRITE_BATCH_LIMIT = 500;\n","import type { CreateUserInput, UserRecord } from '#/db/types.js';\n\n/**\n * Display name assigned to the internal system user for CLI and migration actions.\n */\nexport const SYSTEM_USER_NAME = 'system';\n\n/**\n * Returns true when the record is the internal system account used for migrations\n * and CLI attribution.\n *\n * When {@link systemUserId} is known (post-migration), matching is id-only so\n * unrelated accounts named `system` are not misclassified. Before migration,\n * falls back to name matching and logs a deprecation warning.\n *\n * @param user - User record or subset with id and name.\n * @param systemUserId - Cached system user id from the database, when known.\n * @returns True for the provisioned system account.\n */\nexport function isSystemUser(\n user: Pick<UserRecord, 'id' | 'name'>,\n systemUserId?: string | null\n): boolean {\n if (systemUserId != null) {\n return user.id === systemUserId;\n }\n\n if (user.name === SYSTEM_USER_NAME) {\n console.warn(\n 'System user detected by name only; run database migration so id-based detection is used.'\n );\n return true;\n }\n\n return false;\n}\n\n/**\n * Builds the input used when creating the system user during database migration.\n *\n * @returns CreateUserInput for the system account with admin role and no entity access.\n */\nexport function createSystemUserInput(): CreateUserInput {\n return {\n name: SYSTEM_USER_NAME,\n role: 'admin',\n collectionAccess: [],\n environmentAccess: [],\n snippetAccess: []\n };\n}\n","import { z } from 'zod/v4';\n\n/**\n * Zod schema for validating raw Firestore database config from server.yaml.\n */\nexport const firestoreConfigSchema = z.object({\n driver: z.literal('firestore'),\n projectId: z.string().trim().min(1, { message: 'Firestore projectId must not be empty.' }),\n keyFilename: z.string().trim().min(1).optional()\n});\n","import type {\n ApiTokenRecord,\n AuditEntityType,\n AuditLogRecord,\n CollectionRecord,\n EnvironmentRecord,\n FolderRecord,\n SnippetRecord,\n LlmUsageRecord,\n LlmUsageLogRecord,\n RunResultRecord,\n SavedRequestRecord,\n UserRecord\n} from '#/db/types.js';\nimport type {\n FirestoreApiTokenDocument,\n FirestoreAuditLogDocument,\n FirestoreCollectionDocument,\n FirestoreEnvironmentDocument,\n FirestoreSnippetDocument,\n FirestoreFolderDocument,\n FirestoreLlmUsageDocument,\n FirestoreLlmUsageLogDocument,\n FirestoreRequestDocument,\n FirestoreRunResultDocument,\n FirestoreUserDocument\n} from '#/db/firestore/types.js';\n\n/**\n * Parses a stored entity type string into a typed {@link AuditEntityType}.\n *\n * @param value - Entity type from storage.\n * @returns Validated entity type.\n * @throws {Error} When the stored entity type is not recognized.\n */\nfunction parseAuditEntityType(value: string): AuditEntityType {\n if (\n value === 'user' ||\n value === 'api_token' ||\n value === 'collection' ||\n value === 'environment' ||\n value === 'snippet' ||\n value === 'folder' ||\n value === 'request' ||\n value === 'run_result'\n ) {\n return value;\n }\n\n throw new Error(`Invalid audit entity type: ${value}`);\n}\n\n/**\n * Maps a Firestore document to the shared {@link ApiTokenRecord} shape.\n *\n * @param id - Document identifier.\n * @param data - Stored token fields.\n * @returns Normalized token record for application code.\n */\nexport function mapFirestoreApiToken(id: string, data: FirestoreApiTokenDocument): ApiTokenRecord {\n if (!data.userId) {\n throw new Error(`API token ${id} is missing a userId`);\n }\n\n return {\n id,\n userId: data.userId,\n name: data.name,\n tokenHash: data.tokenHash,\n tokenPrefix: data.tokenPrefix,\n createdAt: data.createdAt,\n lastUsedAt: data.lastUsedAt,\n revokedAt: data.revokedAt,\n createdByUserId: data.createdByUserId ?? null,\n updatedByUserId: data.updatedByUserId ?? null\n };\n}\n\n/**\n * Maps a Firestore document to the shared {@link UserRecord} shape.\n *\n * @param id - Document identifier.\n * @param data - Stored user fields.\n * @returns Normalized user record for application code.\n */\nexport function mapFirestoreUser(id: string, data: FirestoreUserDocument): UserRecord {\n return {\n id,\n name: data.name,\n role: data.role,\n collectionAccess: data.collectionAccess,\n environmentAccess: data.environmentAccess,\n snippetAccess: data.snippetAccess ?? [],\n llmAccess: data.llmAccess ?? false,\n llmModels: data.llmModels ?? [],\n llmMonthlyTokenLimit: data.llmMonthlyTokenLimit ?? null,\n createdAt: data.createdAt,\n updatedAt: data.updatedAt,\n createdByUserId: data.createdByUserId ?? null,\n updatedByUserId: data.updatedByUserId ?? null\n };\n}\n\n/**\n * Maps a Firestore document to the shared {@link LlmUsageRecord} shape.\n *\n * @param id - Document identifier.\n * @param data - Stored LLM usage fields.\n * @returns Normalized usage record for application code.\n */\nexport function mapFirestoreLlmUsage(id: string, data: FirestoreLlmUsageDocument): LlmUsageRecord {\n return {\n id,\n userId: data.userId,\n period: data.period,\n promptTokens: data.promptTokens,\n completionTokens: data.completionTokens,\n totalTokens: data.totalTokens,\n updatedAt: data.updatedAt\n };\n}\n\n/**\n * Maps a Firestore document to the shared {@link LlmUsageLogRecord} shape.\n *\n * @param id - Document identifier.\n * @param data - Stored LLM usage log fields.\n * @returns Normalized usage log record for application code.\n */\nexport function mapFirestoreLlmUsageLog(\n id: string,\n data: FirestoreLlmUsageLogDocument\n): LlmUsageLogRecord {\n return {\n id,\n userId: data.userId,\n apiTokenId: data.apiTokenId,\n period: data.period,\n model: data.model,\n provider: data.provider as LlmUsageLogRecord['provider'],\n promptTokens: data.promptTokens,\n completionTokens: data.completionTokens,\n totalTokens: data.totalTokens,\n isNewTurn: data.isNewTurn,\n hadToolCalls: data.hadToolCalls,\n messageCount: data.messageCount,\n createdAt: data.createdAt\n };\n}\n\n/**\n * Maps a Firestore document to the shared {@link CollectionRecord} shape.\n *\n * @param id - Document identifier.\n * @param data - Stored collection fields.\n * @returns Normalized collection record for application code.\n */\nexport function mapFirestoreCollection(\n id: string,\n data: FirestoreCollectionDocument\n): CollectionRecord {\n return {\n id,\n name: data.name,\n variables: data.variables,\n headers: data.headers,\n auth: data.auth,\n preRequestScript: data.preRequestScript,\n postRequestScript: data.postRequestScript,\n createdAt: data.createdAt,\n updatedAt: data.updatedAt ?? data.createdAt,\n createdByUserId: data.createdByUserId ?? null,\n updatedByUserId: data.updatedByUserId ?? null,\n deletionLocked: data.deletionLocked ?? false\n };\n}\n\n/**\n * Maps a Firestore document to the shared {@link EnvironmentRecord} shape.\n *\n * @param id - Document identifier.\n * @param data - Stored environment fields.\n * @returns Normalized environment record for application code.\n */\nexport function mapFirestoreEnvironment(\n id: string,\n data: FirestoreEnvironmentDocument\n): EnvironmentRecord {\n return {\n id,\n name: data.name,\n variables: data.variables,\n createdAt: data.createdAt,\n updatedAt: data.updatedAt ?? data.createdAt,\n createdByUserId: data.createdByUserId ?? null,\n updatedByUserId: data.updatedByUserId ?? null,\n deletionLocked: data.deletionLocked ?? false\n };\n}\n\n/**\n * Maps a Firestore document to the shared {@link SnippetRecord} shape.\n *\n * @param id - Document identifier.\n * @param data - Stored snippet fields.\n * @returns Normalized snippet record for application code.\n */\nexport function mapFirestoreSnippet(id: string, data: FirestoreSnippetDocument): SnippetRecord {\n return {\n id,\n name: data.name,\n code: data.code,\n scope: data.scope,\n sortOrder: data.sortOrder,\n createdAt: data.createdAt,\n updatedAt: data.updatedAt ?? data.createdAt,\n createdByUserId: data.createdByUserId ?? null,\n updatedByUserId: data.updatedByUserId ?? null,\n deletionLocked: data.deletionLocked ?? false\n };\n}\n\n/**\n * Maps a Firestore document to the shared {@link FolderRecord} shape.\n *\n * @param id - Document identifier.\n * @param data - Stored folder fields.\n * @returns Normalized folder record for application code.\n */\nexport function mapFirestoreFolder(id: string, data: FirestoreFolderDocument): FolderRecord {\n return {\n id,\n collectionId: data.collectionId,\n name: data.name,\n sortOrder: data.sortOrder,\n createdAt: data.createdAt,\n updatedAt: data.updatedAt ?? data.createdAt,\n createdByUserId: data.createdByUserId ?? null,\n updatedByUserId: data.updatedByUserId ?? null\n };\n}\n\n/**\n * Maps a Firestore document to the shared {@link SavedRequestRecord} shape.\n *\n * @param id - Document identifier.\n * @param data - Stored request fields.\n * @returns Normalized saved request record for application code.\n */\nexport function mapFirestoreRequest(\n id: string,\n data: FirestoreRequestDocument\n): SavedRequestRecord {\n return {\n id,\n collectionId: data.collectionId,\n folderId: data.folderId,\n name: data.name,\n method: data.method as SavedRequestRecord['method'],\n url: data.url,\n headers: data.headers,\n params: data.params,\n auth: data.auth,\n body: data.body,\n bodyType: data.bodyType as SavedRequestRecord['bodyType'],\n preRequestScript: data.preRequestScript,\n postRequestScript: data.postRequestScript,\n comment: data.comment,\n sortOrder: data.sortOrder,\n createdAt: data.createdAt,\n updatedAt: data.updatedAt,\n createdByUserId: data.createdByUserId ?? null,\n updatedByUserId: data.updatedByUserId ?? null\n };\n}\n\n/**\n * Maps a Firestore document to the shared {@link RunResultRecord} shape.\n *\n * @param id - Document identifier.\n * @param data - Stored run result fields.\n * @returns Normalized run result record for application code.\n */\nexport function mapFirestoreRunResult(\n id: string,\n data: FirestoreRunResultDocument\n): RunResultRecord {\n return {\n id,\n kind: data.kind,\n label: data.label,\n collectionName: data.collectionName,\n requestName: data.requestName,\n summary: data.summary,\n payload: data.payload,\n createdAt: data.createdAt,\n createdByUserId: data.createdByUserId ?? null\n };\n}\n\n/**\n * Maps a Firestore document to the shared {@link AuditLogRecord} shape.\n *\n * @param id - Document identifier.\n * @param data - Stored audit log fields.\n * @returns Normalized audit log record for application code.\n */\nexport function mapFirestoreAuditLog(id: string, data: FirestoreAuditLogDocument): AuditLogRecord {\n return {\n id,\n userId: data.userId,\n userName: data.userName,\n action: data.action,\n entityType: parseAuditEntityType(data.entityType),\n entityId: data.entityId,\n createdAt: data.createdAt,\n metadata: data.metadata\n };\n}\n\n/**\n * Returns nullable attribution fields with defaults for legacy Firestore documents.\n *\n * @param createdByUserId - Stored creating user id, if any.\n * @param updatedByUserId - Stored updating user id, if any.\n * @returns Normalized attribution pair.\n */\nexport function normalizeAttributionFields(\n createdByUserId: string | null | undefined,\n updatedByUserId: string | null | undefined\n): { createdByUserId: string | null; updatedByUserId: string | null } {\n return {\n createdByUserId: createdByUserId ?? null,\n updatedByUserId: updatedByUserId ?? null\n };\n}\n","import type { RunResultKind, RunResultSummaryCounts } from '#/db/types.js';\n\n/**\n * Parsed metadata extracted from a HarborClient run-results export payload.\n */\nexport interface ParsedRunResultPayload {\n /**\n * Export discriminator for collection-wide or single-request runs.\n */\n kind: RunResultKind;\n\n /**\n * Collection display name captured in the export, when present.\n */\n collectionName: string | null;\n\n /**\n * Request display name captured in the export, when present.\n */\n requestName: string | null;\n\n /**\n * Pass/fail/skip counts derived from export result rows.\n */\n summary: RunResultSummaryCounts;\n}\n\n/**\n * Returns whether a value is a plain object record.\n *\n * @param value - Candidate payload fragment.\n * @returns True when the value is a non-null object.\n */\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value != null && typeof value === 'object' && !Array.isArray(value);\n}\n\n/**\n * Derives pass/fail/skip counts from HarborClient runner result rows.\n *\n * @param results - Result rows from the export payload.\n * @returns Summary counts for persistence and list views.\n */\nfunction summarizeResultRows(results: unknown[]): RunResultSummaryCounts {\n let passed = 0;\n let failed = 0;\n let skipped = 0;\n\n for (const row of results) {\n if (!isRecord(row)) {\n continue;\n }\n const status = row.status;\n if (status === 'passed') {\n passed += 1;\n } else if (status === 'failed') {\n failed += 1;\n } else if (status === 'skipped') {\n skipped += 1;\n }\n }\n\n return { passed, failed, skipped };\n}\n\n/**\n * Builds a default label from parsed run-result metadata.\n *\n * @param metadata - Parsed payload metadata.\n * @returns Short human-readable label for list rows.\n */\nexport function buildDefaultRunResultLabel(metadata: ParsedRunResultPayload): string {\n const target = metadata.requestName ?? metadata.collectionName ?? 'Run';\n const timestamp = new Date().toISOString().replace('T', ' ').slice(0, 19);\n return `${target} — ${timestamp}`;\n}\n\n/**\n * Validates and extracts metadata from a HarborClient run-results export payload.\n *\n * @param payload - Raw JSON payload submitted by HarborClient.\n * @returns Parsed kind, names, and summary counts.\n * @throws {Error} When required export fields are missing or invalid.\n */\nexport function parseRunResultPayload(payload: Record<string, unknown>): ParsedRunResultPayload {\n const kind = payload.harborclientExport;\n if (kind !== 'collection-run-results' && kind !== 'request-run-results') {\n throw new Error('Invalid run result payload: harborclientExport is required');\n }\n\n const results = payload.results;\n if (!Array.isArray(results) || results.length === 0) {\n throw new Error('Invalid run result payload: results are required');\n }\n\n const collection = isRecord(payload.collection) ? payload.collection : undefined;\n const request = isRecord(payload.request) ? payload.request : undefined;\n\n return {\n kind,\n collectionName: typeof collection?.name === 'string' ? collection.name : null,\n requestName: typeof request?.name === 'string' ? request.name : null,\n summary: summarizeResultRows(results)\n };\n}\n","/**\n * Trims a display name and rejects empty results.\n *\n * @param name - Raw name from callers.\n * @param label - Entity label for the error message (e.g. \"Collection name\").\n * @returns Trimmed non-empty name.\n * @throws When the trimmed name is empty.\n */\nexport function trimRequiredName(name: string, label: string): string {\n const trimmed = name.trim();\n if (!trimmed) {\n throw new Error(`${label} is required`);\n }\n\n return trimmed;\n}\n","import { SYSTEM_USER_NAME } from '#/db/systemUsers.js';\nimport type { UserRecord } from '#/db/types.js';\n\n/**\n * Error thrown when a user name is already assigned to another account.\n */\nexport class DuplicateUserNameError extends Error {\n /**\n * Creates a duplicate-name error with a client-facing message.\n *\n * @param name - Display name that is already in use.\n */\n constructor(name: string) {\n super(`User name \"${name}\" is already in use.`);\n this.name = 'DuplicateUserNameError';\n }\n}\n\n/**\n * Error thrown when a display name is reserved for the internal system account.\n */\nexport class ReservedUserNameError extends Error {\n /**\n * Creates a reserved-name error with a client-facing message.\n *\n * @param name - Display name that is reserved.\n */\n constructor(name: string) {\n super(`User name \"${name}\" is reserved for the internal system account.`);\n this.name = 'ReservedUserNameError';\n }\n}\n\n/**\n * Ensures a display name is not reserved for the internal system account.\n *\n * @param name - Candidate display name.\n * @throws {ReservedUserNameError} When the name is reserved.\n */\nexport function assertUserNameNotReserved(name: string): void {\n if (name === SYSTEM_USER_NAME) {\n throw new ReservedUserNameError(name);\n }\n}\n\n/**\n * Ensures a display name is not already used by a different user account.\n *\n * @param name - Candidate display name.\n * @param userId - User identifier being updated.\n * @param existing - User record returned by {@link IDatabase.findUserByName}, if any.\n * @throws {DuplicateUserNameError} When another account already uses the name.\n */\nexport function assertUserNameAvailable(\n name: string,\n userId: string,\n existing: UserRecord | null\n): void {\n if (existing && existing.id !== userId) {\n throw new DuplicateUserNameError(name);\n }\n}\n","/**\n * Server account role controlling API and CLI capabilities.\n */\nexport type UserRole = 'admin' | 'user';\n\n/**\n * CRUD or structural action recorded in the audit log.\n */\nexport type AuditAction = 'create' | 'update' | 'delete' | 'reorder' | 'move';\n\n/**\n * Entity kinds tracked by the audit log.\n */\nexport type AuditEntityType =\n | 'user'\n | 'api_token'\n | 'collection'\n | 'environment'\n | 'snippet'\n | 'folder'\n | 'request'\n | 'run_result';\n\n/**\n * Persisted audit log entry describing a single mutating action.\n */\nexport interface AuditLogRecord {\n /**\n * Stable identifier for the audit entry.\n */\n id: string;\n\n /**\n * User who performed the action, when known.\n */\n userId: string | null;\n\n /**\n * Snapshot of the acting user's display name at write time.\n */\n userName: string | null;\n\n /**\n * Action that was performed.\n */\n action: AuditAction;\n\n /**\n * Kind of entity affected by the action.\n */\n entityType: AuditEntityType;\n\n /**\n * Identifier of the affected entity.\n */\n entityId: string;\n\n /**\n * When the action was recorded.\n */\n createdAt: Date;\n\n /**\n * Optional structured context for the action.\n */\n metadata: Record<string, unknown> | null;\n}\n\n/**\n * Optional filters when listing audit log entries.\n */\nexport interface ListAuditLogOptions {\n /**\n * Maximum number of entries to return, newest first.\n */\n limit?: number;\n\n /**\n * Restrict results to a specific acting user.\n */\n userId?: string;\n\n /**\n * Restrict results to a specific entity type.\n */\n entityType?: AuditEntityType;\n\n /**\n * Restrict results to a specific entity id.\n */\n entityId?: string;\n}\n\n/**\n * Stored metadata for a Team Hub user account.\n */\nexport interface UserRecord {\n /**\n * Stable identifier used for token ownership and CLI operations.\n */\n id: string;\n\n /**\n * Unique display name chosen when the user was created.\n */\n name: string;\n\n /**\n * Role determining API capabilities: `user` for scoped entity access,\n * `admin` for management API access without entity access.\n */\n role: UserRole;\n\n /**\n * Collection ids the user may access, or `['*']` for all collections.\n */\n collectionAccess: string[];\n\n /**\n * Environment ids the user may access, or `['*']` for all environments.\n */\n environmentAccess: string[];\n\n /**\n * Snippet ids the user may access, or `['*']` for all snippets.\n */\n snippetAccess: string[];\n\n /**\n * When true, the user may call hub-proxied LLM routes.\n */\n llmAccess: boolean;\n\n /**\n * LLM model ids the user may use, or `['*']` for all hub-offered models.\n */\n llmModels: string[];\n\n /**\n * Maximum total tokens per UTC calendar month, or null for unlimited.\n */\n llmMonthlyTokenLimit: number | null;\n\n /**\n * When the user account was created.\n */\n createdAt: Date;\n\n /**\n * When the user account was last updated.\n */\n updatedAt: Date;\n\n /**\n * User who created the account.\n */\n createdByUserId: string | null;\n\n /**\n * User who last updated the account.\n */\n updatedByUserId: string | null;\n}\n\n/**\n * Fields required to create a new user account.\n */\nexport interface CreateUserInput {\n /**\n * Unique display name for the new account.\n */\n name: string;\n\n /**\n * Role assigned to the new account.\n */\n role: UserRole;\n\n /**\n * Collection access list; admins store an empty array.\n */\n collectionAccess: string[];\n\n /**\n * Environment access list; admins store an empty array.\n */\n environmentAccess: string[];\n\n /**\n * Snippet access list; admins store an empty array.\n */\n snippetAccess: string[];\n\n /**\n * Whether the user may use hub-proxied LLM routes.\n */\n llmAccess?: boolean;\n\n /**\n * Allowed LLM model ids, or `['*']` for all hub-offered models.\n */\n llmModels?: string[];\n\n /**\n * Monthly token limit, or null for unlimited.\n */\n llmMonthlyTokenLimit?: number | null;\n}\n\n/**\n * Partial fields accepted when updating an existing user account.\n */\nexport interface UpdateUserInput {\n /**\n * New unique display name, when changing the account label.\n */\n name?: string;\n\n /**\n * New role, when changing account capabilities.\n */\n role?: UserRole;\n\n /**\n * Replacement collection access list.\n */\n collectionAccess?: string[];\n\n /**\n * Replacement environment access list.\n */\n environmentAccess?: string[];\n\n /**\n * Replacement snippet access list.\n */\n snippetAccess?: string[];\n\n /**\n * Whether the user may use hub-proxied LLM routes.\n */\n llmAccess?: boolean;\n\n /**\n * Replacement LLM model access list.\n */\n llmModels?: string[];\n\n /**\n * Replacement monthly token limit, or null for unlimited.\n */\n llmMonthlyTokenLimit?: number | null;\n}\n\n/**\n * Stored metadata for a database-backed API bearer token.\n *\n * The raw secret is never persisted; only its sha256 hash is stored for lookup.\n */\nexport interface ApiTokenRecord {\n /**\n * Stable identifier used for revoke and audit operations.\n */\n id: string;\n\n /**\n * Owning user account that receives the token's access permissions.\n */\n userId: string;\n\n /**\n * Human-readable label chosen when the token was created.\n */\n name: string;\n\n /**\n * sha256 hex digest of the bearer token secret.\n */\n tokenHash: string;\n\n /**\n * Non-secret prefix shown in listings (for example `hbk_AbCd1234`).\n */\n tokenPrefix: string;\n\n /**\n * When the token was created.\n */\n createdAt: Date;\n\n /**\n * When the token was last used to authenticate a request, if ever.\n */\n lastUsedAt: Date | null;\n\n /**\n * When the token was revoked; null means the token is still active.\n */\n revokedAt: Date | null;\n\n /**\n * User who created the token record.\n */\n createdByUserId: string | null;\n\n /**\n * User who last updated the token record.\n */\n updatedByUserId: string | null;\n}\n\n/**\n * Persisted monthly LLM token usage for a user.\n */\nexport interface LlmUsageRecord {\n /**\n * Stable identifier for the usage row.\n */\n id: string;\n\n /**\n * Owning user account id.\n */\n userId: string;\n\n /**\n * UTC calendar month key (`YYYY-MM`).\n */\n period: string;\n\n /**\n * Prompt tokens consumed during the period.\n */\n promptTokens: number;\n\n /**\n * Completion tokens consumed during the period.\n */\n completionTokens: number;\n\n /**\n * Total tokens consumed during the period.\n */\n totalTokens: number;\n\n /**\n * When usage was last updated.\n */\n updatedAt: Date;\n}\n\n/**\n * LLM provider id stored on per-request usage log rows.\n */\nexport type LlmUsageLogProvider = 'openai' | 'claude' | 'gemini';\n\n/**\n * Persisted per-request LLM usage log entry.\n */\nexport interface LlmUsageLogRecord {\n /**\n * Stable identifier for the log row.\n */\n id: string;\n\n /**\n * User who consumed tokens.\n */\n userId: string;\n\n /**\n * Bearer token used for the request, when known.\n */\n apiTokenId: string | null;\n\n /**\n * UTC calendar month key (`YYYY-MM`).\n */\n period: string;\n\n /**\n * Provider-specific model id sent to the API.\n */\n model: string;\n\n /**\n * LLM provider that served the request.\n */\n provider: LlmUsageLogProvider;\n\n /**\n * Prompt tokens billed for the step.\n */\n promptTokens: number;\n\n /**\n * Completion tokens billed for the step.\n */\n completionTokens: number;\n\n /**\n * Total tokens billed for the step.\n */\n totalTokens: number;\n\n /**\n * Whether the last message in the request was from the user.\n */\n isNewTurn: boolean;\n\n /**\n * Whether the model returned tool calls.\n */\n hadToolCalls: boolean;\n\n /**\n * Number of messages included in the request body.\n */\n messageCount: number;\n\n /**\n * When the completion step finished.\n */\n createdAt: Date;\n}\n\n/**\n * Input for inserting a per-request LLM usage log row.\n */\nexport interface CreateLlmUsageLogInput {\n /**\n * User who consumed tokens.\n */\n userId: string;\n\n /**\n * Bearer token used for the request, when known.\n */\n apiTokenId: string | null;\n\n /**\n * UTC calendar month key (`YYYY-MM`).\n */\n period: string;\n\n /**\n * Provider-specific model id sent to the API.\n */\n model: string;\n\n /**\n * LLM provider that served the request.\n */\n provider: LlmUsageLogProvider;\n\n /**\n * Prompt tokens billed for the step.\n */\n promptTokens: number;\n\n /**\n * Completion tokens billed for the step.\n */\n completionTokens: number;\n\n /**\n * Total tokens billed for the step.\n */\n totalTokens: number;\n\n /**\n * Whether the last message in the request was from the user.\n */\n isNewTurn: boolean;\n\n /**\n * Whether the model returned tool calls.\n */\n hadToolCalls: boolean;\n\n /**\n * Number of messages included in the request body.\n */\n messageCount: number;\n}\n\n/**\n * Supported HTTP request methods.\n */\nexport type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS';\n\n/**\n * Request body content type.\n */\nexport type BodyType = 'none' | 'json' | 'text' | 'multipart' | 'urlencoded';\n\n/**\n * Authorization type for saved requests and collections.\n */\nexport type AuthType = 'none' | 'basic' | 'bearer';\n\n/**\n * Basic and bearer credential fields stored together so switching type preserves values.\n */\nexport interface AuthConfig {\n /**\n * Selected auth mode; none means no request-level override.\n */\n type: AuthType;\n\n /**\n * Username and password for Basic Auth.\n */\n basic: {\n username: string;\n password: string;\n };\n\n /**\n * Token value for Bearer Token auth.\n */\n bearer: {\n token: string;\n };\n}\n\n/**\n * A key-value pair with an enable toggle for headers and query params.\n */\nexport interface KeyValue {\n /**\n * Header or query parameter name.\n */\n key: string;\n\n /**\n * Header or query parameter value.\n */\n value: string;\n\n /**\n * When false, the pair is ignored when building the request.\n */\n enabled: boolean;\n}\n\n/**\n * A collection-scoped or environment-scoped variable for {{key}} substitution.\n */\nexport interface Variable {\n /**\n * Variable name referenced in {{key}} placeholders.\n */\n key: string;\n\n /**\n * Value substituted when the variable is resolved.\n */\n value: string;\n\n /**\n * Fallback value used when value is empty.\n */\n defaultValue: string;\n\n /**\n * When true, value is included in collection exports.\n */\n share: boolean;\n}\n\n/**\n * Persisted collection metadata and defaults shared by all requests in the collection.\n */\nexport interface CollectionRecord {\n /**\n * Stable collection identifier.\n */\n id: string;\n\n /**\n * Display name shown in the sidebar.\n */\n name: string;\n\n /**\n * Collection-scoped variables for {{key}} substitution in requests.\n */\n variables: Variable[];\n\n /**\n * Headers sent with every request in this collection.\n */\n headers: KeyValue[];\n\n /**\n * Default Authorization settings inherited by requests unless overridden.\n */\n auth: AuthConfig;\n\n /**\n * JavaScript run before every request in this collection.\n */\n preRequestScript: string;\n\n /**\n * JavaScript run after every request in this collection.\n */\n postRequestScript: string;\n\n /**\n * When the collection was created.\n */\n createdAt: Date;\n\n /**\n * When the collection was last updated.\n */\n updatedAt: Date;\n\n /**\n * User who created the collection.\n */\n createdByUserId: string | null;\n\n /**\n * User who last updated the collection.\n */\n updatedByUserId: string | null;\n\n /**\n * When true, non-admin users cannot delete this collection.\n */\n deletionLocked: boolean;\n}\n\n/**\n * Persisted environment with scoped variables.\n */\nexport interface EnvironmentRecord {\n /**\n * Stable environment identifier.\n */\n id: string;\n\n /**\n * Display name shown in the sidebar.\n */\n name: string;\n\n /**\n * Environment-scoped variables for {{key}} substitution in requests.\n */\n variables: Variable[];\n\n /**\n * When the environment was created.\n */\n createdAt: Date;\n\n /**\n * When the environment was last updated.\n */\n updatedAt: Date;\n\n /**\n * User who created the environment.\n */\n createdByUserId: string | null;\n\n /**\n * User who last updated the environment.\n */\n updatedByUserId: string | null;\n\n /**\n * When true, non-admin users cannot delete this environment.\n */\n deletionLocked: boolean;\n}\n\n/**\n * Execution scope for a reusable code snippet.\n */\nexport type SnippetScope = 'pre-request' | 'post-request' | 'any';\n\n/**\n * Persisted reusable script snippet.\n */\nexport interface SnippetRecord {\n /**\n * Stable snippet identifier.\n */\n id: string;\n\n /**\n * Display name shown in the sidebar.\n */\n name: string;\n\n /**\n * JavaScript source inserted into requests.\n */\n code: string;\n\n /**\n * When the snippet may be applied relative to a request.\n */\n scope: SnippetScope;\n\n /**\n * Position for sidebar ordering.\n */\n sortOrder: number;\n\n /**\n * When the snippet was created.\n */\n createdAt: Date;\n\n /**\n * When the snippet was last updated.\n */\n updatedAt: Date;\n\n /**\n * User who created the snippet.\n */\n createdByUserId: string | null;\n\n /**\n * User who last updated the snippet.\n */\n updatedByUserId: string | null;\n\n /**\n * When true, non-admin users cannot delete this snippet.\n */\n deletionLocked: boolean;\n}\n\n/**\n * Discriminator for collection-wide or single-request run result snapshots.\n */\nexport type RunResultKind = 'collection-run-results' | 'request-run-results';\n\n/**\n * Pass/fail/skip counts stored with a run result snapshot.\n */\nexport interface RunResultSummaryCounts {\n /**\n * Number of requests that passed.\n */\n passed: number;\n\n /**\n * Number of requests that failed.\n */\n failed: number;\n\n /**\n * Number of requests that were skipped.\n */\n skipped: number;\n}\n\n/**\n * Persisted collection runner result snapshot.\n */\nexport interface RunResultRecord {\n /**\n * Stable run result identifier.\n */\n id: string;\n\n /**\n * Whether the snapshot is a collection-wide or single-request run.\n */\n kind: RunResultKind;\n\n /**\n * User-facing label for list rows.\n */\n label: string;\n\n /**\n * Collection display name captured at save time.\n */\n collectionName: string | null;\n\n /**\n * Request display name when the run targeted one request.\n */\n requestName: string | null;\n\n /**\n * Pass/fail/skip counts derived from the saved result rows.\n */\n summary: RunResultSummaryCounts;\n\n /**\n * Complete HarborClient export payload stored as JSON.\n */\n payload: Record<string, unknown>;\n\n /**\n * When the run result was saved.\n */\n createdAt: Date;\n\n /**\n * User who saved the run result.\n */\n createdByUserId: string | null;\n}\n\n/**\n * Input for creating a run result snapshot.\n */\nexport interface CreateRunResultInput {\n /**\n * Optional display label; generated from payload metadata when omitted.\n */\n label?: string;\n\n /**\n * HarborClient run-results export payload to persist.\n */\n payload: Record<string, unknown>;\n}\n\n/**\n * A folder for organizing requests within a collection.\n */\nexport interface FolderRecord {\n /**\n * Stable folder identifier.\n */\n id: string;\n\n /**\n * ID of the collection this folder belongs to.\n */\n collectionId: string;\n\n /**\n * Display name shown in the sidebar.\n */\n name: string;\n\n /**\n * Position among sibling folders for sidebar ordering.\n */\n sortOrder: number;\n\n /**\n * When the folder was created.\n */\n createdAt: Date;\n\n /**\n * When the folder was last updated.\n */\n updatedAt: Date;\n\n /**\n * User who created the folder.\n */\n createdByUserId: string | null;\n\n /**\n * User who last updated the folder.\n */\n updatedByUserId: string | null;\n}\n\n/**\n * A saved HTTP request belonging to a collection.\n */\nexport interface SavedRequestRecord {\n /**\n * Stable request identifier.\n */\n id: string;\n\n /**\n * ID of the collection this request belongs to.\n */\n collectionId: string;\n\n /**\n * Display name shown in the sidebar.\n */\n name: string;\n\n /**\n * HTTP method used for the request.\n */\n method: HttpMethod;\n\n /**\n * Request URL without query parameters.\n */\n url: string;\n\n /**\n * Request headers as editable key-value pairs.\n */\n headers: KeyValue[];\n\n /**\n * Query parameters as editable key-value pairs.\n */\n params: KeyValue[];\n\n /**\n * Authorization settings; none inherits collection auth at send time.\n */\n auth: AuthConfig;\n\n /**\n * Raw request body content.\n */\n body: string;\n\n /**\n * Content type of the request body.\n */\n bodyType: BodyType;\n\n /**\n * JavaScript run before the request is sent.\n */\n preRequestScript: string;\n\n /**\n * JavaScript run after the response is received.\n */\n postRequestScript: string;\n\n /**\n * Free-form notes for this request.\n */\n comment: string;\n\n /**\n * ID of the folder containing this request, or null when at collection root.\n */\n folderId: string | null;\n\n /**\n * Position within the collection for sidebar ordering.\n */\n sortOrder: number;\n\n /**\n * When the request was created.\n */\n createdAt: Date;\n\n /**\n * When the request was last saved.\n */\n updatedAt: Date;\n\n /**\n * User who created the request.\n */\n createdByUserId: string | null;\n\n /**\n * User who last updated the request.\n */\n updatedByUserId: string | null;\n}\n\n/**\n * Input for creating or updating a saved request.\n */\nexport interface SaveRequestInput {\n /**\n * Existing request ID; omit to insert a new request.\n */\n id?: string;\n\n /**\n * ID of the collection to save the request in.\n */\n collectionId: string;\n\n /**\n * Display name for the saved request.\n */\n name: string;\n\n /**\n * HTTP method used for the request.\n */\n method: HttpMethod;\n\n /**\n * Request URL without query parameters.\n */\n url: string;\n\n /**\n * Request headers as editable key-value pairs.\n */\n headers: KeyValue[];\n\n /**\n * Query parameters as editable key-value pairs.\n */\n params: KeyValue[];\n\n /**\n * Authorization settings; none inherits collection auth at send time.\n */\n auth: AuthConfig;\n\n /**\n * Raw request body content.\n */\n body: string;\n\n /**\n * Content type of the request body.\n */\n bodyType: BodyType;\n\n /**\n * JavaScript run before the request is sent.\n */\n preRequestScript: string;\n\n /**\n * JavaScript run after the response is received.\n */\n postRequestScript: string;\n\n /**\n * Free-form notes for this request.\n */\n comment: string;\n\n /**\n * ID of the folder containing this request, or null when at collection root.\n */\n folderId?: string | null;\n}\n\n/**\n * Returns a default auth config with type none and empty credentials.\n *\n * @returns Empty AuthConfig safe for new requests and collections.\n */\nexport function defaultAuth(): AuthConfig {\n return {\n type: 'none',\n basic: { username: '', password: '' },\n bearer: { token: '' }\n };\n}\n\n/**\n * JSON string of {@link defaultAuth} for database column defaults.\n */\nexport const DEFAULT_AUTH_JSON = JSON.stringify(defaultAuth());\n\n/**\n * Normalizes a partial or legacy auth value from storage into a full AuthConfig.\n *\n * @param value - Parsed JSON or unknown field from the database.\n * @returns Valid AuthConfig with defaults for missing fields.\n */\nexport function normalizeAuth(value: unknown): AuthConfig {\n const fallback = defaultAuth();\n if (value == null || typeof value !== 'object') {\n return fallback;\n }\n\n const record = value as Record<string, unknown>;\n const type =\n record.type === 'basic' || record.type === 'bearer' || record.type === 'none'\n ? record.type\n : fallback.type;\n\n const basicRecord =\n record.basic != null && typeof record.basic === 'object'\n ? (record.basic as Record<string, unknown>)\n : {};\n const bearerRecord =\n record.bearer != null && typeof record.bearer === 'object'\n ? (record.bearer as Record<string, unknown>)\n : {};\n\n return {\n type,\n basic: {\n username: typeof basicRecord.username === 'string' ? basicRecord.username : '',\n password: typeof basicRecord.password === 'string' ? basicRecord.password : ''\n },\n bearer: {\n token: typeof bearerRecord.token === 'string' ? bearerRecord.token : ''\n }\n };\n}\n\n/**\n * Normalizes a variable row from storage.\n *\n * @param value - Partial variable from JSON.\n * @returns Variable with defaults for missing fields.\n */\nexport function normalizeVariable(value: Partial<Variable>): Variable {\n return {\n key: typeof value.key === 'string' ? value.key : '',\n value: typeof value.value === 'string' ? value.value : '',\n defaultValue: typeof value.defaultValue === 'string' ? value.defaultValue : '',\n share: typeof value.share === 'boolean' ? value.share : false\n };\n}\n","import type { ZodError } from 'zod/v4';\n\n/**\n * Formats the first Zod validation issue into a short user-facing message.\n *\n * @param error - Zod validation error from schema parsing.\n * @returns Human-readable error string.\n */\nexport function formatZodError(error: ZodError): string {\n const issue = error.issues[0];\n if (!issue) {\n return 'Invalid database configuration.';\n }\n\n if (issue.message) {\n return issue.message;\n }\n\n return 'Invalid database configuration.';\n}\n","import { randomUUID } from 'node:crypto';\nimport mysql, { type Pool, type ResultSetHeader, type RowDataPacket } from 'mysql2/promise';\nimport { mapApiTokenSqlRow, type ApiTokenSqlRow } from '#/db/apiTokenRows.js';\nimport { resolveActingUserName } from '#/db/attribution.js';\nimport {\n mapAuditLogSqlRow,\n serializeAuditMetadata,\n type AuditLogSqlRow\n} from '#/db/auditLogRows.js';\nimport { BOOTSTRAP_USER_NAME } from '#/db/bootstrapUsers.js';\nimport {\n mapCollectionSqlRow,\n mapEnvironmentSqlRow,\n mapFolderSqlRow,\n mapRequestSqlRow,\n mapRunResultSqlRow,\n mapSnippetSqlRow,\n type CollectionSqlRow,\n type EnvironmentSqlRow,\n type FolderSqlRow,\n type RequestSqlRow,\n type RunResultSqlRow,\n type SnippetSqlRow\n} from '#/db/entityRows.js';\nimport { buildDefaultRunResultLabel, parseRunResultPayload } from '#/db/runResultPayload.js';\nimport type { IDatabase } from '#/db/IDatabase.js';\nimport { MYSQL_DEFAULT_AUTH_JSON, MYSQL_MIGRATIONS } from '#/db/mysql/migrations.js';\nimport { mysqlConfigSchema } from '#/db/mysql/schemas.js';\nimport type { MysqlDatabaseConfig } from '#/db/mysql/types.js';\nimport { createSystemUserInput, SYSTEM_USER_NAME } from '#/db/systemUsers.js';\nimport { trimRequiredName } from '#/db/trimRequiredName.js';\nimport { assertUserNameAvailable, assertUserNameNotReserved } from '#/db/userNameValidation.js';\nimport {\n API_TOKEN_SELECT_COLUMNS,\n AUDIT_LOG_SELECT_COLUMNS,\n COLLECTION_SELECT_COLUMNS,\n ENVIRONMENT_SELECT_COLUMNS,\n FOLDER_SELECT_COLUMNS,\n mapUserSqlRow,\n REQUEST_SELECT_COLUMNS,\n SNIPPET_SELECT_COLUMNS,\n serializeAccessList,\n USER_SELECT_COLUMNS,\n type UserSqlRow\n} from '#/db/userRows.js';\nimport {\n LLM_USAGE_LOG_SELECT_COLUMNS,\n mapLlmUsageLogSqlRow,\n type LlmUsageLogSqlRow\n} from '#/db/llmUsageLogRows.js';\nimport {\n LLM_USAGE_SELECT_COLUMNS,\n mapLlmUsageSqlRow,\n type LlmUsageSqlRow\n} from '#/db/llmUsageRows.js';\nimport type {\n ApiTokenRecord,\n AuditAction,\n AuditEntityType,\n AuditLogRecord,\n AuthConfig,\n CollectionRecord,\n CreateUserInput,\n CreateLlmUsageLogInput,\n CreateRunResultInput,\n EnvironmentRecord,\n FolderRecord,\n KeyValue,\n ListAuditLogOptions,\n LlmUsageLogRecord,\n LlmUsageRecord,\n RunResultRecord,\n SaveRequestInput,\n SavedRequestRecord,\n SnippetRecord,\n SnippetScope,\n UpdateUserInput,\n UserRecord,\n Variable\n} from '#/db/types.js';\nimport { formatZodError } from '#/db/validation.js';\n\nconst COLLECTION_SELECT = `SELECT ${COLLECTION_SELECT_COLUMNS} FROM collections`;\nconst ENVIRONMENT_SELECT = `SELECT ${ENVIRONMENT_SELECT_COLUMNS} FROM environments`;\nconst SNIPPET_SELECT = `SELECT ${SNIPPET_SELECT_COLUMNS} FROM snippets`;\nconst RUN_RESULT_SELECT_COLUMNS =\n 'id, kind, label, collection_name, request_name, summary_passed, summary_failed, summary_skipped, payload, created_at, created_by_user_id';\nconst RUN_RESULT_SELECT = `SELECT ${RUN_RESULT_SELECT_COLUMNS} FROM run_results`;\nconst USER_SELECT = `SELECT ${USER_SELECT_COLUMNS} FROM users`;\nconst API_TOKEN_SELECT = `SELECT ${API_TOKEN_SELECT_COLUMNS} FROM api_tokens`;\nconst FOLDER_SELECT = `SELECT ${FOLDER_SELECT_COLUMNS} FROM folders`;\nconst REQUEST_SELECT = `SELECT ${REQUEST_SELECT_COLUMNS} FROM requests`;\nconst AUDIT_LOG_SELECT = `SELECT ${AUDIT_LOG_SELECT_COLUMNS} FROM audit_log`;\nconst LLM_USAGE_SELECT = `SELECT ${LLM_USAGE_SELECT_COLUMNS} FROM llm_usage`;\nconst LLM_USAGE_LOG_SELECT = `SELECT ${LLM_USAGE_LOG_SELECT_COLUMNS} FROM llm_usage_log`;\n\n/**\n * MySQL-backed database implementation.\n */\nexport class MysqlDatabase implements IDatabase {\n /**\n * Active MySQL connection pool, or null when disconnected.\n */\n private pool: Pool | null = null;\n\n /**\n * Cached identifier of the internal system user, when provisioned during migration.\n */\n private systemUserId: string | null = null;\n\n /**\n * Creates a MySQL database instance from validated config.\n *\n * @param config - Parsed MySQL connection settings.\n */\n constructor(private readonly config: MysqlDatabaseConfig) {}\n\n /**\n * Validates raw config and constructs a {@link MysqlDatabase}.\n *\n * @param config - Raw `db` section from server.yaml.\n * @returns Configured MySQL database instance.\n * @throws {Error} When config fails MySQL-specific validation.\n */\n static fromConfig(config: unknown): MysqlDatabase {\n const parsed = mysqlConfigSchema.safeParse(config);\n if (!parsed.success) {\n throw new Error(formatZodError(parsed.error));\n }\n\n return new MysqlDatabase({\n host: parsed.data.host,\n port: parsed.data.port,\n user: parsed.data.user,\n password: parsed.data.password,\n database: parsed.data.database\n });\n }\n\n /**\n * Opens a MySQL connection pool and verifies connectivity with a ping.\n */\n async connect(): Promise<void> {\n if (this.pool) {\n return;\n }\n\n const pool = mysql.createPool({\n host: this.config.host,\n port: this.config.port,\n user: this.config.user,\n password: this.config.password,\n database: this.config.database\n });\n\n const connection = await pool.getConnection();\n await connection.ping();\n connection.release();\n\n this.pool = pool;\n }\n\n /**\n * Closes the MySQL connection pool and releases resources.\n */\n async disconnect(): Promise<void> {\n if (!this.pool) {\n return;\n }\n\n await this.pool.end();\n this.pool = null;\n }\n\n /**\n * Creates required tables when they do not already exist.\n */\n async migrate(): Promise<void> {\n for (const sql of MYSQL_MIGRATIONS) {\n await this.executeStatement(sql);\n }\n\n await this.ensureSystemUser();\n await this.migrateOrphanTokensToBootstrapUser();\n }\n\n /**\n * Returns the stable identifier of the internal system user, when provisioned.\n */\n getSystemUserId(): string | null {\n return this.systemUserId;\n }\n\n /**\n * Lists audit log entries ordered newest-first with optional filters.\n *\n * @param options - Optional limit and filter criteria.\n */\n async listAuditLog(options: ListAuditLogOptions = {}): Promise<AuditLogRecord[]> {\n const limit = options.limit ?? 100;\n const conditions: string[] = [];\n const params: Array<string | number> = [];\n\n if (options.userId !== undefined) {\n conditions.push('user_id = ?');\n params.push(options.userId);\n }\n\n if (options.entityType !== undefined) {\n conditions.push('entity_type = ?');\n params.push(options.entityType);\n }\n\n if (options.entityId !== undefined) {\n conditions.push('entity_id = ?');\n params.push(options.entityId);\n }\n\n const whereClause = conditions.length > 0 ? ` WHERE ${conditions.join(' AND ')}` : '';\n const rows = await this.queryRows<AuditLogSqlRow & RowDataPacket>(\n `${AUDIT_LOG_SELECT}${whereClause} ORDER BY created_at DESC LIMIT ?`,\n [...params, limit]\n );\n\n return rows.map(mapAuditLogSqlRow);\n }\n\n /**\n * Creates a new user account with the given role and access lists.\n *\n * @param input - User fields to persist.\n * @param actingUserId - User performing the create action.\n */\n async createUser(input: CreateUserInput, actingUserId: string): Promise<UserRecord> {\n const trimmedName = trimRequiredName(input.name, 'User name');\n assertUserNameNotReserved(trimmedName);\n const id = randomUUID();\n const now = new Date();\n const attributionUserId = trimmedName === SYSTEM_USER_NAME ? id : actingUserId;\n\n await this.executeStatement(\n `INSERT INTO users (\n id,\n name,\n role,\n collection_access,\n environment_access,\n snippet_access,\n llm_access,\n llm_models,\n llm_monthly_token_limit,\n created_at,\n updated_at,\n created_by_user_id,\n updated_by_user_id\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n [\n id,\n trimmedName,\n input.role,\n serializeAccessList(input.collectionAccess),\n serializeAccessList(input.environmentAccess),\n serializeAccessList(input.snippetAccess),\n input.llmAccess ? 1 : 0,\n serializeAccessList(input.llmModels ?? []),\n input.llmMonthlyTokenLimit ?? null,\n now,\n now,\n attributionUserId,\n attributionUserId\n ]\n );\n\n await this.recordAuditEntry(actingUserId, 'create', 'user', id);\n\n const created = await this.findUserById(id);\n if (!created) {\n throw new Error('User not found after insert');\n }\n\n return created;\n }\n\n /**\n * Finds a user by stable identifier.\n *\n * @param id - User identifier to look up.\n */\n async findUserById(id: string): Promise<UserRecord | null> {\n const rows = await this.queryRows<UserSqlRow & RowDataPacket>(\n `${USER_SELECT} WHERE id = ? LIMIT 1`,\n [id]\n );\n const row = rows[0];\n return row ? mapUserSqlRow(row) : null;\n }\n\n /**\n * Finds a user by unique display name.\n *\n * @param name - User name to look up.\n */\n async findUserByName(name: string): Promise<UserRecord | null> {\n const rows = await this.queryRows<UserSqlRow & RowDataPacket>(\n `${USER_SELECT} WHERE name = ? LIMIT 1`,\n [name]\n );\n const row = rows[0];\n return row ? mapUserSqlRow(row) : null;\n }\n\n /**\n * Lists all user accounts ordered by name.\n */\n async listUsers(): Promise<UserRecord[]> {\n const rows = await this.queryRows<UserSqlRow & RowDataPacket>(\n `${USER_SELECT} ORDER BY name ASC`\n );\n return rows.map(mapUserSqlRow);\n }\n\n /**\n * Updates an existing user account.\n *\n * @param id - User identifier to update.\n * @param input - Partial fields to apply.\n * @param actingUserId - User performing the update action.\n */\n async updateUser(id: string, input: UpdateUserInput, actingUserId: string): Promise<UserRecord> {\n const existing = await this.findUserById(id);\n if (!existing) {\n throw new Error('User not found');\n }\n\n const name =\n input.name !== undefined ? trimRequiredName(input.name, 'User name') : existing.name;\n\n if (name !== existing.name) {\n assertUserNameNotReserved(name);\n const duplicate = await this.findUserByName(name);\n assertUserNameAvailable(name, id, duplicate);\n }\n\n const role = input.role ?? existing.role;\n const collectionAccess = input.collectionAccess ?? existing.collectionAccess;\n const environmentAccess = input.environmentAccess ?? existing.environmentAccess;\n const snippetAccess = input.snippetAccess ?? existing.snippetAccess;\n const llmAccess = input.llmAccess ?? existing.llmAccess;\n const llmModels = input.llmModels ?? existing.llmModels;\n const llmMonthlyTokenLimit =\n input.llmMonthlyTokenLimit !== undefined\n ? input.llmMonthlyTokenLimit\n : existing.llmMonthlyTokenLimit;\n const updatedAt = new Date();\n\n const result = await this.executeStatement(\n `UPDATE users\n SET name = ?,\n role = ?,\n collection_access = ?,\n environment_access = ?,\n snippet_access = ?,\n llm_access = ?,\n llm_models = ?,\n llm_monthly_token_limit = ?,\n updated_at = ?,\n updated_by_user_id = ?\n WHERE id = ?`,\n [\n name,\n role,\n serializeAccessList(collectionAccess),\n serializeAccessList(environmentAccess),\n serializeAccessList(snippetAccess),\n llmAccess ? 1 : 0,\n serializeAccessList(llmModels),\n llmMonthlyTokenLimit,\n updatedAt,\n actingUserId,\n id\n ]\n );\n\n if ((result.affectedRows ?? 0) === 0) {\n throw new Error('User not found');\n }\n\n await this.recordAuditEntry(actingUserId, 'update', 'user', id);\n\n const updated = await this.findUserById(id);\n if (!updated) {\n throw new Error('User not found');\n }\n\n return updated;\n }\n\n /**\n * Deletes a user account and revokes all of their API tokens.\n *\n * @param id - User identifier to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteUser(id: string, actingUserId: string): Promise<void> {\n const connection = await this.requirePool().getConnection();\n try {\n await connection.beginTransaction();\n await connection.execute('DELETE FROM api_tokens WHERE user_id = ?', [id]);\n await connection.execute('DELETE FROM users WHERE id = ?', [id]);\n await connection.commit();\n } catch (err) {\n await connection.rollback();\n throw err;\n } finally {\n connection.release();\n }\n\n await this.recordAuditEntry(actingUserId, 'delete', 'user', id);\n }\n\n /**\n * Assigns legacy API tokens without an owner to the bootstrap user.\n */\n async migrateOrphanTokensToBootstrapUser(): Promise<void> {\n const rows = await this.queryRows<{ count: number } & RowDataPacket>(\n 'SELECT COUNT(*) AS count FROM api_tokens WHERE user_id IS NULL'\n );\n const orphanCount = rows[0]?.count ?? 0;\n if (orphanCount === 0) {\n return;\n }\n\n let bootstrapUser = await this.findUserByName(BOOTSTRAP_USER_NAME);\n if (!bootstrapUser) {\n const systemUserId = this.systemUserId;\n if (!systemUserId) {\n throw new Error('System user is not provisioned');\n }\n\n bootstrapUser = await this.createUser(\n {\n name: BOOTSTRAP_USER_NAME,\n role: 'user',\n collectionAccess: ['*'],\n environmentAccess: ['*'],\n snippetAccess: ['*']\n },\n systemUserId\n );\n }\n\n await this.executeStatement('UPDATE api_tokens SET user_id = ? WHERE user_id IS NULL', [\n bootstrapUser.id\n ]);\n }\n\n /**\n * Inserts a new API token record.\n *\n * @param record - Token metadata to persist.\n * @param actingUserId - User performing the create action.\n */\n async createApiToken(record: ApiTokenRecord, actingUserId: string): Promise<void> {\n await this.executeStatement(\n `INSERT INTO api_tokens (\n id,\n user_id,\n name,\n token_hash,\n token_prefix,\n created_at,\n last_used_at,\n revoked_at,\n created_by_user_id,\n updated_by_user_id\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n [\n record.id,\n record.userId,\n record.name,\n record.tokenHash,\n record.tokenPrefix,\n record.createdAt,\n record.lastUsedAt,\n record.revokedAt,\n actingUserId,\n actingUserId\n ]\n );\n\n await this.recordAuditEntry(actingUserId, 'create', 'api_token', record.id);\n }\n\n /**\n * Finds an active token by its stored hash.\n *\n * @param tokenHash - sha256 hex digest of the bearer token secret.\n */\n async findActiveApiTokenByHash(tokenHash: string): Promise<ApiTokenRecord | null> {\n const rows = await this.queryRows<ApiTokenSqlRow & RowDataPacket>(\n `${API_TOKEN_SELECT}\n WHERE token_hash = ?\n AND revoked_at IS NULL\n AND user_id IS NOT NULL\n LIMIT 1`,\n [tokenHash]\n );\n\n const row = rows[0];\n return row ? mapApiTokenSqlRow(row) : null;\n }\n\n /**\n * Lists all API tokens ordered by creation time descending.\n */\n async listApiTokens(): Promise<ApiTokenRecord[]> {\n const rows = await this.queryRows<ApiTokenSqlRow & RowDataPacket>(\n `${API_TOKEN_SELECT}\n WHERE user_id IS NOT NULL\n ORDER BY created_at DESC`\n );\n\n return rows.map(mapApiTokenSqlRow);\n }\n\n /**\n * Returns API tokens owned by a specific user ordered newest-first.\n *\n * @param userId - Owning user identifier.\n */\n async listApiTokensByUserId(userId: string): Promise<ApiTokenRecord[]> {\n const rows = await this.queryRows<ApiTokenSqlRow & RowDataPacket>(\n `${API_TOKEN_SELECT}\n WHERE user_id = ?\n ORDER BY created_at DESC`,\n [userId]\n );\n\n return rows.map(mapApiTokenSqlRow);\n }\n\n /**\n * Finds an API token record by stable identifier.\n *\n * @param id - Token identifier to look up.\n */\n async findApiTokenById(id: string): Promise<ApiTokenRecord | null> {\n const rows = await this.queryRows<ApiTokenSqlRow & RowDataPacket>(\n `${API_TOKEN_SELECT} WHERE id = ? LIMIT 1`,\n [id]\n );\n const row = rows[0];\n return row ? mapApiTokenSqlRow(row) : null;\n }\n\n /**\n * Permanently removes an API token record by id.\n *\n * @param id - Token identifier to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteApiToken(id: string, actingUserId: string): Promise<boolean> {\n const result = await this.executeStatement('DELETE FROM api_tokens WHERE id = ?', [id]);\n const deleted = (result.affectedRows ?? 0) > 0;\n if (deleted) {\n await this.recordAuditEntry(actingUserId, 'delete', 'api_token', id);\n }\n\n return deleted;\n }\n\n /**\n * Soft-revokes an active token by id.\n *\n * @param id - Token identifier to revoke.\n * @param actingUserId - User performing the revoke action.\n */\n async revokeApiToken(id: string, actingUserId: string): Promise<boolean> {\n const result = await this.executeStatement(\n `UPDATE api_tokens\n SET revoked_at = ?,\n updated_by_user_id = ?\n WHERE id = ?\n AND revoked_at IS NULL`,\n [new Date(), actingUserId, id]\n );\n\n const revoked = (result.affectedRows ?? 0) > 0;\n if (revoked) {\n await this.recordAuditEntry(actingUserId, 'update', 'api_token', id);\n }\n\n return revoked;\n }\n\n /**\n * Updates the last-used timestamp for a token.\n *\n * @param id - Token identifier that authenticated a request.\n * @param when - Timestamp of the authenticated request.\n */\n async touchApiTokenLastUsed(id: string, when: Date): Promise<void> {\n await this.executeStatement(`UPDATE api_tokens SET last_used_at = ? WHERE id = ?`, [when, id]);\n }\n\n /**\n * Lists all collections ordered by name.\n */\n async listCollections(): Promise<CollectionRecord[]> {\n const rows = await this.queryRows<CollectionSqlRow & RowDataPacket>(\n `${COLLECTION_SELECT} ORDER BY name ASC`\n );\n return rows.map(mapCollectionSqlRow);\n }\n\n /**\n * Creates a new collection with the given name.\n *\n * @param name - Display name for the collection.\n * @param actingUserId - User performing the create action.\n */\n async createCollection(name: string, actingUserId: string): Promise<CollectionRecord> {\n const trimmedName = trimRequiredName(name, 'Collection name');\n const id = randomUUID();\n const now = new Date();\n\n await this.executeStatement(\n `INSERT INTO collections (\n id,\n name,\n variables,\n headers,\n auth,\n pre_request_script,\n post_request_script,\n created_at,\n updated_at,\n created_by_user_id,\n updated_by_user_id\n ) VALUES (?, ?, '[]', '[]', ?, '', '', ?, ?, ?, ?)`,\n [id, trimmedName, MYSQL_DEFAULT_AUTH_JSON, now, now, actingUserId, actingUserId]\n );\n\n await this.recordAuditEntry(actingUserId, 'create', 'collection', id);\n\n const rows = await this.queryRows<CollectionSqlRow & RowDataPacket>(\n `${COLLECTION_SELECT} WHERE id = ?`,\n [id]\n );\n const row = rows[0];\n if (!row) {\n throw new Error('Collection not found after insert');\n }\n\n return mapCollectionSqlRow(row);\n }\n\n /**\n * Updates a collection's name, variables, headers, and scripts.\n *\n * @param actingUserId - User performing the update action.\n */\n async updateCollection(\n id: string,\n name: string,\n variables: Variable[],\n headers: KeyValue[],\n preRequestScript: string,\n postRequestScript: string,\n auth: AuthConfig,\n actingUserId: string\n ): Promise<CollectionRecord> {\n const trimmedName = trimRequiredName(name, 'Collection name');\n const updatedAt = new Date();\n const result = await this.executeStatement(\n `UPDATE collections\n SET name = ?,\n variables = ?,\n headers = ?,\n auth = ?,\n pre_request_script = ?,\n post_request_script = ?,\n updated_at = ?,\n updated_by_user_id = ?\n WHERE id = ?`,\n [\n trimmedName,\n JSON.stringify(variables),\n JSON.stringify(headers),\n JSON.stringify(auth),\n preRequestScript,\n postRequestScript,\n updatedAt,\n actingUserId,\n id\n ]\n );\n\n if ((result.affectedRows ?? 0) === 0) {\n throw new Error('Collection not found');\n }\n\n await this.recordAuditEntry(actingUserId, 'update', 'collection', id);\n\n const rows = await this.queryRows<CollectionSqlRow & RowDataPacket>(\n `${COLLECTION_SELECT} WHERE id = ?`,\n [id]\n );\n const row = rows[0];\n if (!row) {\n throw new Error('Collection not found');\n }\n\n return mapCollectionSqlRow(row);\n }\n\n /**\n * Deletes a collection and all of its requests and folders.\n *\n * @param id - Collection ID to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteCollection(id: string, actingUserId: string): Promise<void> {\n await this.recordAuditEntry(actingUserId, 'delete', 'collection', id);\n await this.executeStatement('DELETE FROM collections WHERE id = ?', [id]);\n }\n\n /**\n * Finds a collection by stable identifier.\n *\n * @param id - Collection ID to look up.\n */\n async findCollectionById(id: string): Promise<CollectionRecord | null> {\n const rows = await this.queryRows<CollectionSqlRow & RowDataPacket>(\n `${COLLECTION_SELECT} WHERE id = ?`,\n [id]\n );\n const row = rows[0];\n return row ? mapCollectionSqlRow(row) : null;\n }\n\n /**\n * Updates whether non-admin users may delete a collection.\n *\n * @param id - Collection ID to update.\n * @param deletionLocked - When true, user-role tokens cannot delete the collection.\n * @param actingUserId - Admin user performing the update.\n */\n async setCollectionDeletionLocked(\n id: string,\n deletionLocked: boolean,\n actingUserId: string\n ): Promise<CollectionRecord> {\n const updatedAt = new Date();\n const result = await this.executeStatement(\n `UPDATE collections\n SET deletion_locked = ?,\n updated_at = ?,\n updated_by_user_id = ?\n WHERE id = ?`,\n [deletionLocked ? 1 : 0, updatedAt, actingUserId, id]\n );\n\n if ((result.affectedRows ?? 0) === 0) {\n throw new Error('Collection not found');\n }\n\n await this.recordAuditEntry(actingUserId, 'update', 'collection', id);\n\n const rows = await this.queryRows<CollectionSqlRow & RowDataPacket>(\n `${COLLECTION_SELECT} WHERE id = ?`,\n [id]\n );\n const row = rows[0];\n if (!row) {\n throw new Error('Collection not found');\n }\n\n return mapCollectionSqlRow(row);\n }\n\n /**\n * Lists all environments ordered by name.\n */\n async listEnvironments(): Promise<EnvironmentRecord[]> {\n const rows = await this.queryRows<EnvironmentSqlRow & RowDataPacket>(\n `${ENVIRONMENT_SELECT} ORDER BY name ASC`\n );\n return rows.map(mapEnvironmentSqlRow);\n }\n\n /**\n * Creates a new environment with the given name.\n *\n * @param name - Display name for the environment.\n * @param actingUserId - User performing the create action.\n */\n async createEnvironment(name: string, actingUserId: string): Promise<EnvironmentRecord> {\n const trimmedName = trimRequiredName(name, 'Environment name');\n const id = randomUUID();\n const now = new Date();\n\n await this.executeStatement(\n `INSERT INTO environments (\n id,\n name,\n variables,\n created_at,\n updated_at,\n created_by_user_id,\n updated_by_user_id\n ) VALUES (?, ?, '[]', ?, ?, ?, ?)`,\n [id, trimmedName, now, now, actingUserId, actingUserId]\n );\n\n await this.recordAuditEntry(actingUserId, 'create', 'environment', id);\n\n const rows = await this.queryRows<EnvironmentSqlRow & RowDataPacket>(\n `${ENVIRONMENT_SELECT} WHERE id = ?`,\n [id]\n );\n const row = rows[0];\n if (!row) {\n throw new Error('Environment not found after insert');\n }\n\n return mapEnvironmentSqlRow(row);\n }\n\n /**\n * Updates an environment's name and variables.\n *\n * @param actingUserId - User performing the update action.\n */\n async updateEnvironment(\n id: string,\n name: string,\n variables: Variable[],\n actingUserId: string\n ): Promise<EnvironmentRecord> {\n const trimmedName = trimRequiredName(name, 'Environment name');\n const updatedAt = new Date();\n const result = await this.executeStatement(\n `UPDATE environments\n SET name = ?,\n variables = ?,\n updated_at = ?,\n updated_by_user_id = ?\n WHERE id = ?`,\n [trimmedName, JSON.stringify(variables), updatedAt, actingUserId, id]\n );\n\n if ((result.affectedRows ?? 0) === 0) {\n throw new Error('Environment not found');\n }\n\n await this.recordAuditEntry(actingUserId, 'update', 'environment', id);\n\n const rows = await this.queryRows<EnvironmentSqlRow & RowDataPacket>(\n `${ENVIRONMENT_SELECT} WHERE id = ?`,\n [id]\n );\n const row = rows[0];\n if (!row) {\n throw new Error('Environment not found');\n }\n\n return mapEnvironmentSqlRow(row);\n }\n\n /**\n * Deletes an environment.\n *\n * @param id - Environment ID to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteEnvironment(id: string, actingUserId: string): Promise<void> {\n await this.recordAuditEntry(actingUserId, 'delete', 'environment', id);\n await this.executeStatement('DELETE FROM environments WHERE id = ?', [id]);\n }\n\n /**\n * Finds an environment by stable identifier.\n *\n * @param id - Environment ID to look up.\n */\n async findEnvironmentById(id: string): Promise<EnvironmentRecord | null> {\n const rows = await this.queryRows<EnvironmentSqlRow & RowDataPacket>(\n `${ENVIRONMENT_SELECT} WHERE id = ?`,\n [id]\n );\n const row = rows[0];\n return row ? mapEnvironmentSqlRow(row) : null;\n }\n\n /**\n * Updates whether non-admin users may delete an environment.\n *\n * @param id - Environment ID to update.\n * @param deletionLocked - When true, user-role tokens cannot delete the environment.\n * @param actingUserId - Admin user performing the update.\n */\n async setEnvironmentDeletionLocked(\n id: string,\n deletionLocked: boolean,\n actingUserId: string\n ): Promise<EnvironmentRecord> {\n const updatedAt = new Date();\n const result = await this.executeStatement(\n `UPDATE environments\n SET deletion_locked = ?,\n updated_at = ?,\n updated_by_user_id = ?\n WHERE id = ?`,\n [deletionLocked ? 1 : 0, updatedAt, actingUserId, id]\n );\n\n if ((result.affectedRows ?? 0) === 0) {\n throw new Error('Environment not found');\n }\n\n await this.recordAuditEntry(actingUserId, 'update', 'environment', id);\n\n const rows = await this.queryRows<EnvironmentSqlRow & RowDataPacket>(\n `${ENVIRONMENT_SELECT} WHERE id = ?`,\n [id]\n );\n const row = rows[0];\n if (!row) {\n throw new Error('Environment not found');\n }\n\n return mapEnvironmentSqlRow(row);\n }\n\n /**\n * Lists all snippets ordered by sort order then name.\n */\n async listSnippets(): Promise<SnippetRecord[]> {\n const rows = await this.queryRows<SnippetSqlRow & RowDataPacket>(\n `${SNIPPET_SELECT} ORDER BY sort_order ASC, name ASC`\n );\n return rows.map(mapSnippetSqlRow);\n }\n\n /**\n * Creates a new snippet with the given fields.\n *\n * @param name - Display name for the snippet.\n * @param code - JavaScript source for the snippet.\n * @param scope - Execution scope for the snippet.\n * @param actingUserId - User performing the create action.\n */\n async createSnippet(\n name: string,\n code: string,\n scope: SnippetScope,\n actingUserId: string\n ): Promise<SnippetRecord> {\n const trimmedName = trimRequiredName(name, 'Snippet name');\n const id = randomUUID();\n const now = new Date();\n const maxRows = await this.queryRows<{ max_order: number | null } & RowDataPacket>(\n 'SELECT COALESCE(MAX(sort_order), -1) AS max_order FROM snippets'\n );\n const maxOrder = maxRows[0]?.max_order ?? -1;\n\n await this.executeStatement(\n `INSERT INTO snippets (\n id,\n name,\n code,\n scope,\n sort_order,\n created_at,\n updated_at,\n created_by_user_id,\n updated_by_user_id,\n deletion_locked\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n [id, trimmedName, code, scope, maxOrder + 1, now, now, actingUserId, actingUserId, 0]\n );\n\n await this.recordAuditEntry(actingUserId, 'create', 'snippet', id);\n\n const rows = await this.queryRows<SnippetSqlRow & RowDataPacket>(\n `${SNIPPET_SELECT} WHERE id = ?`,\n [id]\n );\n const row = rows[0];\n if (!row) {\n throw new Error('Snippet not found after insert');\n }\n\n return mapSnippetSqlRow(row);\n }\n\n /**\n * Updates a snippet's name, code, and scope. Sort order is left unchanged.\n *\n * @param actingUserId - User performing the update action.\n */\n async updateSnippet(\n id: string,\n name: string,\n code: string,\n scope: SnippetScope,\n actingUserId: string\n ): Promise<SnippetRecord> {\n const trimmedName = trimRequiredName(name, 'Snippet name');\n const updatedAt = new Date();\n const result = await this.executeStatement(\n `UPDATE snippets\n SET name = ?,\n code = ?,\n scope = ?,\n updated_at = ?,\n updated_by_user_id = ?\n WHERE id = ?`,\n [trimmedName, code, scope, updatedAt, actingUserId, id]\n );\n\n if ((result.affectedRows ?? 0) === 0) {\n throw new Error('Snippet not found');\n }\n\n await this.recordAuditEntry(actingUserId, 'update', 'snippet', id);\n\n const rows = await this.queryRows<SnippetSqlRow & RowDataPacket>(\n `${SNIPPET_SELECT} WHERE id = ?`,\n [id]\n );\n const row = rows[0];\n if (!row) {\n throw new Error('Snippet not found');\n }\n\n return mapSnippetSqlRow(row);\n }\n\n /**\n * Deletes a snippet.\n *\n * @param id - Snippet ID to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteSnippet(id: string, actingUserId: string): Promise<void> {\n await this.recordAuditEntry(actingUserId, 'delete', 'snippet', id);\n await this.executeStatement('DELETE FROM snippets WHERE id = ?', [id]);\n }\n\n /**\n * Finds a snippet by stable identifier.\n *\n * @param id - Snippet ID to look up.\n */\n async findSnippetById(id: string): Promise<SnippetRecord | null> {\n const rows = await this.queryRows<SnippetSqlRow & RowDataPacket>(\n `${SNIPPET_SELECT} WHERE id = ?`,\n [id]\n );\n const row = rows[0];\n return row ? mapSnippetSqlRow(row) : null;\n }\n\n /**\n * Updates whether non-admin users may delete a snippet.\n *\n * @param id - Snippet ID to update.\n * @param deletionLocked - When true, user-role tokens cannot delete the snippet.\n * @param actingUserId - Admin user performing the update.\n */\n async setSnippetDeletionLocked(\n id: string,\n deletionLocked: boolean,\n actingUserId: string\n ): Promise<SnippetRecord> {\n const updatedAt = new Date();\n const result = await this.executeStatement(\n `UPDATE snippets\n SET deletion_locked = ?,\n updated_at = ?,\n updated_by_user_id = ?\n WHERE id = ?`,\n [deletionLocked ? 1 : 0, updatedAt, actingUserId, id]\n );\n\n if ((result.affectedRows ?? 0) === 0) {\n throw new Error('Snippet not found');\n }\n\n await this.recordAuditEntry(actingUserId, 'update', 'snippet', id);\n\n const rows = await this.queryRows<SnippetSqlRow & RowDataPacket>(\n `${SNIPPET_SELECT} WHERE id = ?`,\n [id]\n );\n const row = rows[0];\n if (!row) {\n throw new Error('Snippet not found');\n }\n\n return mapSnippetSqlRow(row);\n }\n\n /**\n * Lists all saved requests in a collection.\n *\n * @param collectionId - Collection to query.\n */\n async listRequests(collectionId: string): Promise<SavedRequestRecord[]> {\n const rows = await this.queryRows<RequestSqlRow & RowDataPacket>(\n `${REQUEST_SELECT} WHERE collection_id = ? ORDER BY sort_order ASC, name ASC`,\n [collectionId]\n );\n return rows.map(mapRequestSqlRow);\n }\n\n /**\n * Finds a saved request by id.\n *\n * @param id - Request identifier to look up.\n */\n async findRequestById(id: string): Promise<SavedRequestRecord | null> {\n const rows = await this.queryRows<RequestSqlRow & RowDataPacket>(\n `${REQUEST_SELECT} WHERE id = ? LIMIT 1`,\n [id]\n );\n const row = rows[0];\n return row ? mapRequestSqlRow(row) : null;\n }\n\n /**\n * Inserts a new request or updates an existing one.\n *\n * @param input - Request fields to persist.\n * @param actingUserId - User performing the save action.\n */\n async saveRequest(input: SaveRequestInput, actingUserId: string): Promise<SavedRequestRecord> {\n const trimmedName = trimRequiredName(input.name, 'Request name');\n const headers = JSON.stringify(input.headers);\n const params = JSON.stringify(input.params);\n const auth = JSON.stringify(input.auth);\n const folderId = input.folderId ?? null;\n const now = new Date();\n\n if (folderId != null) {\n const folderRows = await this.queryRows<{ collection_id: string } & RowDataPacket>(\n 'SELECT collection_id FROM folders WHERE id = ?',\n [folderId]\n );\n const folderRow = folderRows[0];\n if (!folderRow || folderRow.collection_id !== input.collectionId) {\n throw new Error('Folder not found');\n }\n }\n\n if (input.id) {\n const result = await this.executeStatement(\n `UPDATE requests SET\n collection_id = ?,\n folder_id = ?,\n name = ?,\n method = ?,\n url = ?,\n headers = ?,\n params = ?,\n auth = ?,\n body = ?,\n body_type = ?,\n pre_request_script = ?,\n post_request_script = ?,\n comment = ?,\n updated_at = ?,\n updated_by_user_id = ?\n WHERE id = ?`,\n [\n input.collectionId,\n folderId,\n trimmedName,\n input.method,\n input.url,\n headers,\n params,\n auth,\n input.body,\n input.bodyType,\n input.preRequestScript,\n input.postRequestScript,\n input.comment,\n now,\n actingUserId,\n input.id\n ]\n );\n\n if ((result.affectedRows ?? 0) > 0) {\n await this.recordAuditEntry(actingUserId, 'update', 'request', input.id);\n\n const rows = await this.queryRows<RequestSqlRow & RowDataPacket>(\n `${REQUEST_SELECT} WHERE id = ?`,\n [input.id]\n );\n const row = rows[0];\n if (row) {\n return mapRequestSqlRow(row);\n }\n }\n }\n\n const maxRows = await this.queryRows<{ max_order: number | null } & RowDataPacket>(\n `SELECT COALESCE(MAX(sort_order), -1) AS max_order FROM requests\n WHERE collection_id = ?\n AND ((? IS NULL AND folder_id IS NULL) OR folder_id = ?)`,\n [input.collectionId, folderId, folderId]\n );\n const maxOrder = maxRows[0]?.max_order ?? -1;\n const id = randomUUID();\n\n await this.executeStatement(\n `INSERT INTO requests (\n id,\n collection_id,\n folder_id,\n name,\n method,\n url,\n headers,\n params,\n auth,\n body,\n body_type,\n pre_request_script,\n post_request_script,\n comment,\n sort_order,\n created_at,\n updated_at,\n created_by_user_id,\n updated_by_user_id\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n [\n id,\n input.collectionId,\n folderId,\n trimmedName,\n input.method,\n input.url,\n headers,\n params,\n auth,\n input.body,\n input.bodyType,\n input.preRequestScript,\n input.postRequestScript,\n input.comment,\n maxOrder + 1,\n now,\n now,\n actingUserId,\n actingUserId\n ]\n );\n\n await this.recordAuditEntry(actingUserId, 'create', 'request', id);\n\n const rows = await this.queryRows<RequestSqlRow & RowDataPacket>(\n `${REQUEST_SELECT} WHERE id = ?`,\n [id]\n );\n const row = rows[0];\n if (!row) {\n throw new Error('Request not found after insert');\n }\n\n return mapRequestSqlRow(row);\n }\n\n /**\n * Deletes a saved request by ID.\n *\n * @param id - Request ID to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteRequest(id: string, actingUserId: string): Promise<void> {\n await this.recordAuditEntry(actingUserId, 'delete', 'request', id);\n await this.executeStatement('DELETE FROM requests WHERE id = ?', [id]);\n }\n\n /**\n * Lists all folders in a collection.\n *\n * @param collectionId - Collection to query.\n */\n async listFolders(collectionId: string): Promise<FolderRecord[]> {\n const rows = await this.queryRows<FolderSqlRow & RowDataPacket>(\n `${FOLDER_SELECT} WHERE collection_id = ? ORDER BY sort_order ASC, name ASC`,\n [collectionId]\n );\n return rows.map(mapFolderSqlRow);\n }\n\n /**\n * Finds a folder by id.\n *\n * @param id - Folder identifier to look up.\n */\n async findFolderById(id: string): Promise<FolderRecord | null> {\n const rows = await this.queryRows<FolderSqlRow & RowDataPacket>(\n `${FOLDER_SELECT} WHERE id = ? LIMIT 1`,\n [id]\n );\n const row = rows[0];\n return row ? mapFolderSqlRow(row) : null;\n }\n\n /**\n * Creates a new folder in a collection.\n *\n * @param collectionId - Collection to add the folder to.\n * @param name - Display name for the folder.\n * @param actingUserId - User performing the create action.\n */\n async createFolder(\n collectionId: string,\n name: string,\n actingUserId: string\n ): Promise<FolderRecord> {\n const trimmedName = trimRequiredName(name, 'Folder name');\n const id = randomUUID();\n const now = new Date();\n const maxRows = await this.queryRows<{ max_order: number | null } & RowDataPacket>(\n 'SELECT COALESCE(MAX(sort_order), -1) AS max_order FROM folders WHERE collection_id = ?',\n [collectionId]\n );\n const maxOrder = maxRows[0]?.max_order ?? -1;\n\n await this.executeStatement(\n `INSERT INTO folders (\n id,\n collection_id,\n name,\n sort_order,\n created_at,\n updated_at,\n created_by_user_id,\n updated_by_user_id\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,\n [id, collectionId, trimmedName, maxOrder + 1, now, now, actingUserId, actingUserId]\n );\n\n await this.recordAuditEntry(actingUserId, 'create', 'folder', id);\n\n const rows = await this.queryRows<FolderSqlRow & RowDataPacket>(\n `${FOLDER_SELECT} WHERE id = ?`,\n [id]\n );\n const row = rows[0];\n if (!row) {\n throw new Error('Folder not found after insert');\n }\n\n return mapFolderSqlRow(row);\n }\n\n /**\n * Renames a folder.\n *\n * @param id - Folder ID to rename.\n * @param name - New display name.\n * @param actingUserId - User performing the rename action.\n */\n async renameFolder(id: string, name: string, actingUserId: string): Promise<FolderRecord> {\n const trimmedName = trimRequiredName(name, 'Folder name');\n const updatedAt = new Date();\n const result = await this.executeStatement(\n `UPDATE folders\n SET name = ?,\n updated_at = ?,\n updated_by_user_id = ?\n WHERE id = ?`,\n [trimmedName, updatedAt, actingUserId, id]\n );\n\n if ((result.affectedRows ?? 0) === 0) {\n throw new Error('Folder not found');\n }\n\n await this.recordAuditEntry(actingUserId, 'update', 'folder', id);\n\n const rows = await this.queryRows<FolderSqlRow & RowDataPacket>(\n `${FOLDER_SELECT} WHERE id = ?`,\n [id]\n );\n const row = rows[0];\n if (!row) {\n throw new Error('Folder not found');\n }\n\n return mapFolderSqlRow(row);\n }\n\n /**\n * Deletes a folder and all requests inside it.\n *\n * @param id - Folder ID to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteFolder(id: string, actingUserId: string): Promise<void> {\n await this.recordAuditEntry(actingUserId, 'delete', 'folder', id);\n\n const connection = await this.requirePool().getConnection();\n try {\n await connection.beginTransaction();\n await connection.execute('DELETE FROM requests WHERE folder_id = ?', [id]);\n await connection.execute('DELETE FROM folders WHERE id = ?', [id]);\n await connection.commit();\n } catch (err) {\n await connection.rollback();\n throw err;\n } finally {\n connection.release();\n }\n }\n\n /**\n * Reorders folders within a collection.\n *\n * @param collectionId - Collection containing the folders.\n * @param orderedFolderIds - Folder IDs in desired order.\n * @param actingUserId - User performing the reorder action.\n */\n async reorderFolders(\n collectionId: string,\n orderedFolderIds: string[],\n actingUserId: string\n ): Promise<void> {\n const connection = await this.requirePool().getConnection();\n const updatedAt = new Date();\n try {\n await connection.beginTransaction();\n for (let index = 0; index < orderedFolderIds.length; index++) {\n await connection.execute(\n `UPDATE folders\n SET sort_order = ?,\n updated_at = ?,\n updated_by_user_id = ?\n WHERE id = ? AND collection_id = ?`,\n [index, updatedAt, actingUserId, orderedFolderIds[index], collectionId]\n );\n }\n await connection.commit();\n } catch (err) {\n await connection.rollback();\n throw err;\n } finally {\n connection.release();\n }\n\n await this.recordAuditEntry(actingUserId, 'reorder', 'collection', collectionId, {\n orderedFolderIds\n });\n }\n\n /**\n * Reorders requests within a folder or at collection root.\n *\n * @param actingUserId - User performing the reorder action.\n */\n async reorderRequests(\n collectionId: string,\n folderId: string | null,\n orderedRequestIds: string[],\n actingUserId: string\n ): Promise<void> {\n const connection = await this.requirePool().getConnection();\n const updatedAt = new Date();\n try {\n await connection.beginTransaction();\n for (let index = 0; index < orderedRequestIds.length; index++) {\n await connection.execute(\n `UPDATE requests\n SET sort_order = ?,\n folder_id = ?,\n updated_at = ?,\n updated_by_user_id = ?\n WHERE id = ? AND collection_id = ?`,\n [index, folderId, updatedAt, actingUserId, orderedRequestIds[index], collectionId]\n );\n }\n await connection.commit();\n } catch (err) {\n await connection.rollback();\n throw err;\n } finally {\n connection.release();\n }\n\n await this.recordAuditEntry(actingUserId, 'reorder', 'collection', collectionId, {\n folderId,\n orderedRequestIds\n });\n }\n\n /**\n * Moves a request to another folder or collection root at a given index.\n *\n * @param actingUserId - User performing the move action.\n */\n async moveRequest(\n requestId: string,\n folderId: string | null,\n index: number,\n actingUserId: string\n ): Promise<void> {\n const connection = await this.requirePool().getConnection();\n const updatedAt = new Date();\n\n /**\n * Lists request ids in a container ordered for reindexing.\n *\n * @param collectionId - Collection to query.\n * @param targetFolderId - Folder id or null for collection root.\n */\n const listInContainer = async (\n collectionId: string,\n targetFolderId: string | null\n ): Promise<string[]> => {\n const [rows] = await connection.execute<(RowDataPacket & { id: string })[]>(\n `SELECT id FROM requests WHERE collection_id = ?\n AND ((? IS NULL AND folder_id IS NULL) OR folder_id = ?)\n ORDER BY sort_order ASC, name ASC`,\n [collectionId, targetFolderId, targetFolderId]\n );\n return rows.map((row) => row.id);\n };\n\n /**\n * Rewrites sort_order and folder_id for a container's request list.\n *\n * @param targetFolderId - Folder id or null for collection root.\n * @param orderedIds - Request ids in desired order.\n */\n const reindexContainer = async (\n targetFolderId: string | null,\n orderedIds: string[]\n ): Promise<void> => {\n for (let sortIndex = 0; sortIndex < orderedIds.length; sortIndex++) {\n await connection.execute(\n `UPDATE requests\n SET sort_order = ?,\n folder_id = ?,\n updated_at = ?,\n updated_by_user_id = ?\n WHERE id = ?`,\n [sortIndex, targetFolderId, updatedAt, actingUserId, orderedIds[sortIndex]]\n );\n }\n };\n\n try {\n await connection.beginTransaction();\n\n const [requestRows] = await connection.execute<(RequestSqlRow & RowDataPacket)[]>(\n `${REQUEST_SELECT} WHERE id = ?`,\n [requestId]\n );\n const requestRow = requestRows[0];\n if (!requestRow) {\n throw new Error('Request not found');\n }\n\n const request = mapRequestSqlRow(requestRow);\n const collectionId = request.collectionId;\n const oldFolderId = request.folderId;\n\n if (folderId != null) {\n const [folderRows] = await connection.execute<\n (RowDataPacket & { collection_id: string })[]\n >('SELECT collection_id FROM folders WHERE id = ?', [folderId]);\n const folderRow = folderRows[0];\n if (!folderRow || folderRow.collection_id !== collectionId) {\n throw new Error('Folder not found');\n }\n }\n\n if (oldFolderId === folderId) {\n const siblings = (await listInContainer(collectionId, folderId)).filter(\n (id) => id !== requestId\n );\n siblings.splice(index, 0, requestId);\n await reindexContainer(folderId, siblings);\n } else {\n const oldIds = (await listInContainer(collectionId, oldFolderId)).filter(\n (id) => id !== requestId\n );\n await reindexContainer(oldFolderId, oldIds);\n\n const newIds = (await listInContainer(collectionId, folderId)).filter(\n (id) => id !== requestId\n );\n newIds.splice(index, 0, requestId);\n await reindexContainer(folderId, newIds);\n }\n\n await connection.commit();\n } catch (err) {\n await connection.rollback();\n throw err;\n } finally {\n connection.release();\n }\n\n await this.recordAuditEntry(actingUserId, 'move', 'request', requestId, {\n folderId,\n index\n });\n }\n\n /**\n * Returns monthly LLM usage for a user, or null when no usage has been recorded.\n *\n * @param userId - Owning user identifier.\n * @param period - UTC calendar month key (`YYYY-MM`).\n */\n async getLlmUsage(userId: string, period: string): Promise<LlmUsageRecord | null> {\n const [rows] = await this.requirePool().execute<(LlmUsageSqlRow & RowDataPacket)[]>(\n `${LLM_USAGE_SELECT} WHERE user_id = ? AND period = ? LIMIT 1`,\n [userId, period]\n );\n const row = rows[0];\n return row ? mapLlmUsageSqlRow(row) : null;\n }\n\n /**\n * Atomically increments monthly LLM token usage for a user.\n *\n * @param userId - Owning user identifier.\n * @param period - UTC calendar month key (`YYYY-MM`).\n * @param promptTokens - Prompt tokens to add.\n * @param completionTokens - Completion tokens to add.\n */\n async addLlmUsage(\n userId: string,\n period: string,\n promptTokens: number,\n completionTokens: number\n ): Promise<LlmUsageRecord> {\n const totalDelta = promptTokens + completionTokens;\n const now = new Date();\n const id = randomUUID();\n\n await this.executeStatement(\n `INSERT INTO llm_usage (\n id,\n user_id,\n period,\n prompt_tokens,\n completion_tokens,\n total_tokens,\n updated_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?)\n ON DUPLICATE KEY UPDATE\n prompt_tokens = prompt_tokens + VALUES(prompt_tokens),\n completion_tokens = completion_tokens + VALUES(completion_tokens),\n total_tokens = total_tokens + VALUES(total_tokens),\n updated_at = VALUES(updated_at)`,\n [id, userId, period, promptTokens, completionTokens, totalDelta, now]\n );\n\n const usage = await this.getLlmUsage(userId, period);\n if (!usage) {\n throw new Error('LLM usage not found after upsert');\n }\n\n return usage;\n }\n\n /**\n * Inserts a per-request LLM usage log entry.\n *\n * @param input - Usage details for one successful completion step.\n */\n async createLlmUsageLog(input: CreateLlmUsageLogInput): Promise<LlmUsageLogRecord> {\n const id = randomUUID();\n const now = new Date();\n\n await this.executeStatement(\n `INSERT INTO llm_usage_log (\n id,\n user_id,\n api_token_id,\n period,\n model,\n provider,\n prompt_tokens,\n completion_tokens,\n total_tokens,\n is_new_turn,\n had_tool_calls,\n message_count,\n created_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n [\n id,\n input.userId,\n input.apiTokenId,\n input.period,\n input.model,\n input.provider,\n input.promptTokens,\n input.completionTokens,\n input.totalTokens,\n input.isNewTurn ? 1 : 0,\n input.hadToolCalls ? 1 : 0,\n input.messageCount,\n now\n ]\n );\n\n const rows = await this.queryRows<LlmUsageLogSqlRow & RowDataPacket>(\n `${LLM_USAGE_LOG_SELECT} WHERE id = ?`,\n [id]\n );\n const row = rows[0];\n if (!row) {\n throw new Error('LLM usage log not found after insert');\n }\n\n return mapLlmUsageLogSqlRow(row);\n }\n\n /**\n * Lists all per-request LLM usage log entries, newest first.\n */\n async listLlmUsageLogs(): Promise<LlmUsageLogRecord[]> {\n const rows = await this.queryRows<LlmUsageLogSqlRow & RowDataPacket>(\n `${LLM_USAGE_LOG_SELECT} ORDER BY created_at DESC`\n );\n\n return rows.map(mapLlmUsageLogSqlRow);\n }\n\n /**\n * Lists run results saved by the given user, newest first.\n */\n async listRunResultsForUser(userId: string): Promise<RunResultRecord[]> {\n const rows = await this.queryRows<RunResultSqlRow & RowDataPacket>(\n `${RUN_RESULT_SELECT} WHERE created_by_user_id = ? ORDER BY created_at DESC`,\n [userId]\n );\n return rows.map(mapRunResultSqlRow);\n }\n\n /**\n * Lists all run results for admin inspection, newest first.\n */\n async listAllRunResults(): Promise<RunResultRecord[]> {\n const rows = await this.queryRows<RunResultSqlRow & RowDataPacket>(\n `${RUN_RESULT_SELECT} ORDER BY created_at DESC`\n );\n return rows.map(mapRunResultSqlRow);\n }\n\n /**\n * Creates a standalone run result snapshot.\n */\n async createRunResult(\n input: CreateRunResultInput,\n actingUserId: string\n ): Promise<RunResultRecord> {\n const metadata = parseRunResultPayload(input.payload);\n const label = input.label?.trim() || buildDefaultRunResultLabel(metadata);\n const id = randomUUID();\n const now = new Date();\n\n await this.executeStatement(\n `INSERT INTO run_results (\n id,\n kind,\n label,\n collection_name,\n request_name,\n summary_passed,\n summary_failed,\n summary_skipped,\n payload,\n created_at,\n created_by_user_id\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n [\n id,\n metadata.kind,\n label,\n metadata.collectionName,\n metadata.requestName,\n metadata.summary.passed,\n metadata.summary.failed,\n metadata.summary.skipped,\n JSON.stringify(input.payload),\n now,\n actingUserId\n ]\n );\n\n const rows = await this.queryRows<RunResultSqlRow & RowDataPacket>(\n `${RUN_RESULT_SELECT} WHERE id = ?`,\n [id]\n );\n const row = rows[0];\n if (!row) {\n throw new Error('Run result not found after insert');\n }\n\n await this.recordAuditEntry(actingUserId, 'create', 'run_result', id);\n return mapRunResultSqlRow(row);\n }\n\n /**\n * Finds a run result by id.\n */\n async findRunResultById(id: string): Promise<RunResultRecord | null> {\n const rows = await this.queryRows<RunResultSqlRow & RowDataPacket>(\n `${RUN_RESULT_SELECT} WHERE id = ?`,\n [id]\n );\n const row = rows[0];\n return row ? mapRunResultSqlRow(row) : null;\n }\n\n /**\n * Deletes a run result by id.\n */\n async deleteRunResult(id: string, actingUserId: string): Promise<void> {\n const result = await this.executeStatement('DELETE FROM run_results WHERE id = ?', [id]);\n if ((result as ResultSetHeader).affectedRows === 0) {\n throw new Error('Run result not found');\n }\n\n await this.recordAuditEntry(actingUserId, 'delete', 'run_result', id);\n }\n\n /**\n * Ensures the internal system user exists and caches its identifier.\n */\n private async ensureSystemUser(): Promise<void> {\n const existing = await this.findUserByName(SYSTEM_USER_NAME);\n if (existing) {\n this.systemUserId = existing.id;\n return;\n }\n\n const input = createSystemUserInput();\n const id = randomUUID();\n const now = new Date();\n const trimmedName = trimRequiredName(input.name, 'User name');\n\n await this.executeStatement(\n `INSERT INTO users (\n id,\n name,\n role,\n collection_access,\n environment_access,\n snippet_access,\n llm_access,\n llm_models,\n llm_monthly_token_limit,\n created_at,\n updated_at,\n created_by_user_id,\n updated_by_user_id\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n [\n id,\n trimmedName,\n input.role,\n serializeAccessList(input.collectionAccess),\n serializeAccessList(input.environmentAccess),\n serializeAccessList(input.snippetAccess),\n 0,\n serializeAccessList([]),\n null,\n now,\n now,\n id,\n id\n ]\n );\n\n this.systemUserId = id;\n }\n\n /**\n * Persists a single audit log entry with a snapshot of the acting user's name.\n *\n * @param actingUserId - User performing the action.\n * @param action - CRUD or structural action performed.\n * @param entityType - Kind of entity affected.\n * @param entityId - Identifier of the affected entity.\n * @param metadata - Optional structured context for the action.\n */\n private async recordAuditEntry(\n actingUserId: string,\n action: AuditAction,\n entityType: AuditEntityType,\n entityId: string,\n metadata?: Record<string, unknown> | null\n ): Promise<void> {\n const userName = await resolveActingUserName(this.findUserById.bind(this), actingUserId);\n const id = randomUUID();\n const now = new Date();\n\n await this.executeStatement(\n `INSERT INTO audit_log (\n id,\n user_id,\n user_name,\n action,\n entity_type,\n entity_id,\n created_at,\n metadata\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,\n [\n id,\n actingUserId,\n userName,\n action,\n entityType,\n entityId,\n now,\n serializeAuditMetadata(metadata ?? null)\n ]\n );\n }\n\n /**\n * Returns the active pool or throws when connect has not been called.\n *\n * @returns Connected MySQL pool.\n * @throws {Error} When the database is not connected.\n */\n private requirePool(): Pool {\n if (!this.pool) {\n throw new Error('MySQL database is not connected.');\n }\n\n return this.pool;\n }\n\n /**\n * Executes a parameterized SELECT and returns matching rows.\n *\n * @param sql - SQL statement with ? placeholders.\n * @param params - Bound parameter values.\n * @returns Query rows from mysql2.\n */\n private async queryRows<T extends RowDataPacket>(\n sql: string,\n params: Array<string | number | Date | null> = []\n ): Promise<T[]> {\n const [rows] = await this.requirePool().execute<T[]>(sql, params);\n return rows;\n }\n\n /**\n * Executes a parameterized statement and returns result metadata.\n *\n * @param sql - SQL statement with ? placeholders.\n * @param params - Bound parameter values.\n * @returns Result metadata such as affected row counts.\n */\n private async executeStatement(\n sql: string,\n params: Array<string | number | Date | null> = []\n ): Promise<ResultSetHeader> {\n const [result] = await this.requirePool().execute(sql, params);\n return result as ResultSetHeader;\n }\n}\n","import type { ApiTokenRecord } from '#/db/types.js';\n\n/**\n * SQL row shape returned by relational backends for the api_tokens table.\n */\nexport interface ApiTokenSqlRow {\n /**\n * Primary key identifier.\n */\n id: string;\n\n /**\n * Owning user identifier column.\n */\n user_id: string | null;\n\n /**\n * Human-readable token label.\n */\n name: string;\n\n /**\n * sha256 hex digest column.\n */\n token_hash: string;\n\n /**\n * Display prefix column.\n */\n token_prefix: string;\n\n /**\n * Creation timestamp column.\n */\n created_at: Date;\n\n /**\n * Last-used timestamp column, if any.\n */\n last_used_at: Date | null;\n\n /**\n * Revocation timestamp column, if any.\n */\n revoked_at: Date | null;\n\n /**\n * Creating user identifier column.\n */\n created_by_user_id: string | null;\n\n /**\n * Last updating user identifier column.\n */\n updated_by_user_id: string | null;\n}\n\n/**\n * Maps a snake_case SQL row to the shared {@link ApiTokenRecord} shape.\n *\n * @param row - Database row from api_tokens.\n * @returns Normalized token record for application code.\n */\nexport function mapApiTokenSqlRow(row: ApiTokenSqlRow): ApiTokenRecord {\n if (!row.user_id) {\n throw new Error(`API token ${row.id} is missing a user_id`);\n }\n\n return {\n id: row.id,\n userId: row.user_id,\n name: row.name,\n tokenHash: row.token_hash,\n tokenPrefix: row.token_prefix,\n createdAt: row.created_at,\n lastUsedAt: row.last_used_at,\n revokedAt: row.revoked_at,\n createdByUserId: row.created_by_user_id ?? null,\n updatedByUserId: row.updated_by_user_id ?? null\n };\n}\n","import type { AuditAction, AuditEntityType, AuditLogRecord } from '#/db/types.js';\n\n/**\n * SQL row shape returned by relational backends for the audit_log table.\n */\nexport interface AuditLogSqlRow {\n /**\n * Primary key identifier.\n */\n id: string;\n\n /**\n * Acting user identifier column, when known.\n */\n user_id: string | null;\n\n /**\n * Snapshot of the acting user's display name at write time.\n */\n user_name: string | null;\n\n /**\n * CRUD or structural action performed.\n */\n action: string;\n\n /**\n * Entity kind affected by the action.\n */\n entity_type: string;\n\n /**\n * Identifier of the affected entity.\n */\n entity_id: string;\n\n /**\n * When the action was recorded.\n */\n created_at: Date;\n\n /**\n * JSON-encoded optional context for the action.\n */\n metadata: string;\n}\n\n/**\n * Parses a stored audit action string into a typed {@link AuditAction}.\n *\n * @param value - Action column from storage.\n * @returns Validated audit action.\n * @throws {Error} When the stored action is not recognized.\n */\nfunction parseAuditAction(value: string): AuditAction {\n if (\n value === 'create' ||\n value === 'update' ||\n value === 'delete' ||\n value === 'reorder' ||\n value === 'move'\n ) {\n return value;\n }\n\n throw new Error(`Invalid audit action: ${value}`);\n}\n\n/**\n * Parses a stored entity type string into a typed {@link AuditEntityType}.\n *\n * @param value - Entity type column from storage.\n * @returns Validated entity type.\n * @throws {Error} When the stored entity type is not recognized.\n */\nfunction parseAuditEntityType(value: string): AuditEntityType {\n if (\n value === 'user' ||\n value === 'api_token' ||\n value === 'collection' ||\n value === 'environment' ||\n value === 'snippet' ||\n value === 'folder' ||\n value === 'request' ||\n value === 'run_result'\n ) {\n return value;\n }\n\n throw new Error(`Invalid audit entity type: ${value}`);\n}\n\n/**\n * Parses optional JSON metadata from an audit log row.\n *\n * @param value - Raw metadata column text.\n * @returns Parsed metadata object, or null when empty or invalid.\n */\nfunction parseAuditMetadata(value: string): Record<string, unknown> | null {\n if (!value || value === '{}') {\n return null;\n }\n\n try {\n const parsed: unknown = JSON.parse(value);\n if (parsed != null && typeof parsed === 'object' && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n } catch {\n return null;\n }\n\n return null;\n}\n\n/**\n * Maps a snake_case SQL row to the shared {@link AuditLogRecord} shape.\n *\n * @param row - Database row from audit_log.\n * @returns Normalized audit log record for application code.\n */\nexport function mapAuditLogSqlRow(row: AuditLogSqlRow): AuditLogRecord {\n return {\n id: row.id,\n userId: row.user_id,\n userName: row.user_name,\n action: parseAuditAction(row.action),\n entityType: parseAuditEntityType(row.entity_type),\n entityId: row.entity_id,\n createdAt: row.created_at,\n metadata: parseAuditMetadata(row.metadata)\n };\n}\n\n/**\n * Serializes optional audit metadata for SQL storage.\n *\n * @param metadata - Context object to persist, or null when none.\n * @returns JSON string suitable for a TEXT column.\n */\nexport function serializeAuditMetadata(metadata: Record<string, unknown> | null): string {\n return JSON.stringify(metadata ?? {});\n}\n\n/**\n * Input describing a single audit log entry to persist.\n */\nexport interface RecordAuditInput {\n /**\n * Acting user identifier.\n */\n userId: string;\n\n /**\n * Snapshot of the acting user's display name.\n */\n userName: string | null;\n\n /**\n * Action performed on the entity.\n */\n action: AuditAction;\n\n /**\n * Kind of entity affected.\n */\n entityType: AuditEntityType;\n\n /**\n * Identifier of the affected entity.\n */\n entityId: string;\n\n /**\n * Optional structured context for the action.\n */\n metadata?: Record<string, unknown> | null;\n}\n","import type {\n AuthConfig,\n BodyType,\n CollectionRecord,\n EnvironmentRecord,\n FolderRecord,\n RunResultKind,\n RunResultRecord,\n SnippetRecord,\n SnippetScope,\n HttpMethod,\n KeyValue,\n SavedRequestRecord,\n Variable\n} from '#/db/types.js';\nimport { defaultAuth, normalizeAuth, normalizeVariable } from '#/db/types.js';\n\n/**\n * Parses a JSON string, returning a fallback value on failure.\n *\n * @param value - Raw JSON text.\n * @param fallback - Value returned when parsing fails.\n * @returns Parsed value or fallback.\n */\nfunction parseJson<T>(value: string, fallback: T): T {\n try {\n return JSON.parse(value) as T;\n } catch {\n return fallback;\n }\n}\n\n/**\n * Parses auth JSON from a database row, falling back to defaultAuth when absent or invalid.\n *\n * @param value - Raw auth column from storage.\n * @returns Normalized AuthConfig.\n */\nfunction readAuth(value: string): AuthConfig {\n return normalizeAuth(parseJson(value, defaultAuth()));\n}\n\n/**\n * Parses and normalizes variable rows from storage.\n *\n * @param value - Raw variables JSON text.\n * @returns Normalized Variable array.\n */\nfunction readVariables(value: string): Variable[] {\n return parseJson<Partial<Variable>[]>(value, []).map(normalizeVariable);\n}\n\n/**\n * SQL row shape returned by relational backends for the collections table.\n */\nexport interface CollectionSqlRow {\n /**\n * Primary key identifier.\n */\n id: string;\n\n /**\n * Display name column.\n */\n name: string;\n\n /**\n * JSON-encoded variables column.\n */\n variables: string;\n\n /**\n * JSON-encoded headers column.\n */\n headers: string;\n\n /**\n * JSON-encoded auth column.\n */\n auth: string;\n\n /**\n * Pre-request script column.\n */\n pre_request_script: string;\n\n /**\n * Post-request script column.\n */\n post_request_script: string;\n\n /**\n * Creation timestamp column.\n */\n created_at: Date;\n\n /**\n * Last update timestamp column.\n */\n updated_at: Date;\n\n /**\n * Creating user identifier column.\n */\n created_by_user_id: string | null;\n\n /**\n * Last updating user identifier column.\n */\n updated_by_user_id: string | null;\n\n /**\n * Deletion lock column.\n */\n deletion_locked: boolean;\n}\n\n/**\n * SQL row shape returned by relational backends for the environments table.\n */\nexport interface EnvironmentSqlRow {\n /**\n * Primary key identifier.\n */\n id: string;\n\n /**\n * Display name column.\n */\n name: string;\n\n /**\n * JSON-encoded variables column.\n */\n variables: string;\n\n /**\n * Creation timestamp column.\n */\n created_at: Date;\n\n /**\n * Last update timestamp column.\n */\n updated_at: Date;\n\n /**\n * Creating user identifier column.\n */\n created_by_user_id: string | null;\n\n /**\n * Last updating user identifier column.\n */\n updated_by_user_id: string | null;\n\n /**\n * Deletion lock column.\n */\n deletion_locked: boolean;\n}\n\n/**\n * SQL row shape returned by relational backends for the snippets table.\n */\nexport interface SnippetSqlRow {\n /**\n * Primary key identifier.\n */\n id: string;\n\n /**\n * Display name column.\n */\n name: string;\n\n /**\n * JavaScript source column.\n */\n code: string;\n\n /**\n * Execution scope column.\n */\n scope: string;\n\n /**\n * Sidebar ordering column.\n */\n sort_order: number;\n\n /**\n * Creation timestamp column.\n */\n created_at: Date;\n\n /**\n * Last update timestamp column.\n */\n updated_at: Date;\n\n /**\n * Creating user identifier column.\n */\n created_by_user_id: string | null;\n\n /**\n * Last updating user identifier column.\n */\n updated_by_user_id: string | null;\n\n /**\n * Deletion lock column.\n */\n deletion_locked: boolean;\n}\n\n/**\n * SQL row shape returned by relational backends for the folders table.\n */\nexport interface FolderSqlRow {\n /**\n * Primary key identifier.\n */\n id: string;\n\n /**\n * Parent collection identifier column.\n */\n collection_id: string;\n\n /**\n * Display name column.\n */\n name: string;\n\n /**\n * Sort order column.\n */\n sort_order: number;\n\n /**\n * Creation timestamp column.\n */\n created_at: Date;\n\n /**\n * Last update timestamp column.\n */\n updated_at: Date;\n\n /**\n * Creating user identifier column.\n */\n created_by_user_id: string | null;\n\n /**\n * Last updating user identifier column.\n */\n updated_by_user_id: string | null;\n}\n\n/**\n * SQL row shape returned by relational backends for the requests table.\n */\nexport interface RequestSqlRow {\n /**\n * Primary key identifier.\n */\n id: string;\n\n /**\n * Parent collection identifier column.\n */\n collection_id: string;\n\n /**\n * Optional parent folder identifier column.\n */\n folder_id: string | null;\n\n /**\n * Display name column.\n */\n name: string;\n\n /**\n * HTTP method column.\n */\n method: string;\n\n /**\n * Request URL column.\n */\n url: string;\n\n /**\n * JSON-encoded headers column.\n */\n headers: string;\n\n /**\n * JSON-encoded params column.\n */\n params: string;\n\n /**\n * JSON-encoded auth column.\n */\n auth: string;\n\n /**\n * Request body column.\n */\n body: string;\n\n /**\n * Body type column.\n */\n body_type: string;\n\n /**\n * Pre-request script column.\n */\n pre_request_script: string;\n\n /**\n * Post-request script column.\n */\n post_request_script: string;\n\n /**\n * Comment column.\n */\n comment: string;\n\n /**\n * Sort order column.\n */\n sort_order: number;\n\n /**\n * Creation timestamp column.\n */\n created_at: Date;\n\n /**\n * Last-updated timestamp column.\n */\n updated_at: Date;\n\n /**\n * Creating user identifier column.\n */\n created_by_user_id: string | null;\n\n /**\n * Last updating user identifier column.\n */\n updated_by_user_id: string | null;\n}\n\n/**\n * Maps a snake_case SQL row to the shared {@link CollectionRecord} shape.\n *\n * @param row - Database row from collections.\n * @returns Normalized collection record for application code.\n */\nexport function mapCollectionSqlRow(row: CollectionSqlRow): CollectionRecord {\n return {\n id: row.id,\n name: row.name,\n variables: readVariables(row.variables),\n headers: parseJson<KeyValue[]>(row.headers, []),\n auth: readAuth(row.auth),\n preRequestScript: row.pre_request_script,\n postRequestScript: row.post_request_script,\n createdAt: row.created_at,\n updatedAt: row.updated_at ?? row.created_at,\n createdByUserId: row.created_by_user_id ?? null,\n updatedByUserId: row.updated_by_user_id ?? null,\n deletionLocked: Boolean(row.deletion_locked)\n };\n}\n\n/**\n * Maps a snake_case SQL row to the shared {@link EnvironmentRecord} shape.\n *\n * @param row - Database row from environments.\n * @returns Normalized environment record for application code.\n */\nexport function mapEnvironmentSqlRow(row: EnvironmentSqlRow): EnvironmentRecord {\n return {\n id: row.id,\n name: row.name,\n variables: readVariables(row.variables),\n createdAt: row.created_at,\n updatedAt: row.updated_at ?? row.created_at,\n createdByUserId: row.created_by_user_id ?? null,\n updatedByUserId: row.updated_by_user_id ?? null,\n deletionLocked: Boolean(row.deletion_locked)\n };\n}\n\n/**\n * Parses a stored snippet scope string into a {@link SnippetScope}.\n *\n * @param value - Scope value read from the database.\n * @returns Validated snippet scope.\n * @throws {Error} When the stored scope is not recognized.\n */\nfunction parseSnippetScope(value: string): SnippetScope {\n if (value === 'pre-request' || value === 'post-request' || value === 'any') {\n return value;\n }\n\n throw new Error(`Invalid snippet scope: ${value}`);\n}\n\n/**\n * Maps a snake_case SQL row to the shared {@link SnippetRecord} shape.\n *\n * @param row - Database row from snippets.\n * @returns Normalized snippet record for application code.\n */\nexport function mapSnippetSqlRow(row: SnippetSqlRow): SnippetRecord {\n return {\n id: row.id,\n name: row.name,\n code: row.code,\n scope: parseSnippetScope(row.scope),\n sortOrder: row.sort_order,\n createdAt: row.created_at,\n updatedAt: row.updated_at ?? row.created_at,\n createdByUserId: row.created_by_user_id ?? null,\n updatedByUserId: row.updated_by_user_id ?? null,\n deletionLocked: Boolean(row.deletion_locked)\n };\n}\n\n/**\n * SQL row shape for persisted run results.\n */\nexport interface RunResultSqlRow {\n id: string;\n kind: RunResultKind;\n label: string;\n collection_name: string | null;\n request_name: string | null;\n summary_passed: number;\n summary_failed: number;\n summary_skipped: number;\n payload: string;\n created_at: Date;\n created_by_user_id: string | null;\n}\n\n/**\n * Maps a snake_case SQL row to the shared {@link RunResultRecord} shape.\n *\n * @param row - Database row from run_results.\n * @returns Normalized run result record for application code.\n */\nexport function mapRunResultSqlRow(row: RunResultSqlRow): RunResultRecord {\n return {\n id: row.id,\n kind: row.kind,\n label: row.label,\n collectionName: row.collection_name,\n requestName: row.request_name,\n summary: {\n passed: row.summary_passed,\n failed: row.summary_failed,\n skipped: row.summary_skipped\n },\n payload: parseJson<Record<string, unknown>>(row.payload, {}),\n createdAt: row.created_at,\n createdByUserId: row.created_by_user_id ?? null\n };\n}\n\n/**\n * Maps a snake_case SQL row to the shared {@link FolderRecord} shape.\n *\n * @param row - Database row from folders.\n * @returns Normalized folder record for application code.\n */\nexport function mapFolderSqlRow(row: FolderSqlRow): FolderRecord {\n return {\n id: row.id,\n collectionId: row.collection_id,\n name: row.name,\n sortOrder: row.sort_order,\n createdAt: row.created_at,\n updatedAt: row.updated_at ?? row.created_at,\n createdByUserId: row.created_by_user_id ?? null,\n updatedByUserId: row.updated_by_user_id ?? null\n };\n}\n\n/**\n * Maps a snake_case SQL row to the shared {@link SavedRequestRecord} shape.\n *\n * @param row - Database row from requests.\n * @returns Normalized saved request record for application code.\n */\nexport function mapRequestSqlRow(row: RequestSqlRow): SavedRequestRecord {\n return {\n id: row.id,\n collectionId: row.collection_id,\n folderId: row.folder_id,\n name: row.name,\n method: row.method as HttpMethod,\n url: row.url,\n headers: parseJson<KeyValue[]>(row.headers, []),\n params: parseJson<KeyValue[]>(row.params, []),\n auth: readAuth(row.auth),\n body: row.body,\n bodyType: row.body_type as BodyType,\n preRequestScript: row.pre_request_script,\n postRequestScript: row.post_request_script,\n comment: row.comment,\n sortOrder: row.sort_order,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n createdByUserId: row.created_by_user_id ?? null,\n updatedByUserId: row.updated_by_user_id ?? null\n };\n}\n","import { DEFAULT_AUTH_JSON } from '#/db/types.js';\n\n/**\n * DDL for creating the api_tokens table when absent.\n */\nexport const API_TOKENS_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS api_tokens (\n id VARCHAR(36) PRIMARY KEY,\n user_id VARCHAR(36) NULL,\n name VARCHAR(255) NOT NULL,\n token_hash CHAR(64) NOT NULL UNIQUE,\n token_prefix VARCHAR(255) NOT NULL,\n created_at DATETIME NOT NULL,\n last_used_at DATETIME NULL,\n revoked_at DATETIME NULL,\n created_by_user_id VARCHAR(36) NULL,\n updated_by_user_id VARCHAR(36) NULL,\n FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL,\n FOREIGN KEY (created_by_user_id) REFERENCES users(id) ON DELETE SET NULL,\n FOREIGN KEY (updated_by_user_id) REFERENCES users(id) ON DELETE SET NULL\n)\n`.trim();\n\n/**\n * DDL for creating the collections table when absent.\n */\nexport const COLLECTIONS_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS collections (\n id VARCHAR(36) PRIMARY KEY,\n name VARCHAR(255) NOT NULL,\n variables LONGTEXT NOT NULL,\n headers LONGTEXT NOT NULL,\n auth LONGTEXT NOT NULL,\n pre_request_script LONGTEXT NOT NULL,\n post_request_script LONGTEXT NOT NULL,\n created_at DATETIME NOT NULL,\n updated_at DATETIME NOT NULL,\n created_by_user_id VARCHAR(36) NULL,\n updated_by_user_id VARCHAR(36) NULL,\n FOREIGN KEY (created_by_user_id) REFERENCES users(id) ON DELETE SET NULL,\n FOREIGN KEY (updated_by_user_id) REFERENCES users(id) ON DELETE SET NULL\n)\n`.trim();\n\n/**\n * DDL for creating the environments table when absent.\n */\nexport const ENVIRONMENTS_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS environments (\n id VARCHAR(36) PRIMARY KEY,\n name VARCHAR(255) NOT NULL,\n variables LONGTEXT NOT NULL,\n created_at DATETIME NOT NULL,\n updated_at DATETIME NOT NULL,\n created_by_user_id VARCHAR(36) NULL,\n updated_by_user_id VARCHAR(36) NULL,\n FOREIGN KEY (created_by_user_id) REFERENCES users(id) ON DELETE SET NULL,\n FOREIGN KEY (updated_by_user_id) REFERENCES users(id) ON DELETE SET NULL\n)\n`.trim();\n\n/**\n * DDL for creating the snippets table when absent.\n */\nexport const SNIPPETS_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS snippets (\n id VARCHAR(36) PRIMARY KEY,\n name VARCHAR(255) NOT NULL,\n code LONGTEXT NOT NULL,\n scope VARCHAR(32) NOT NULL DEFAULT 'any',\n sort_order INT NOT NULL DEFAULT 0,\n created_at DATETIME NOT NULL,\n updated_at DATETIME NOT NULL,\n created_by_user_id VARCHAR(36) NULL,\n updated_by_user_id VARCHAR(36) NULL,\n deletion_locked TINYINT(1) NOT NULL DEFAULT 0,\n FOREIGN KEY (created_by_user_id) REFERENCES users(id) ON DELETE SET NULL,\n FOREIGN KEY (updated_by_user_id) REFERENCES users(id) ON DELETE SET NULL\n)\n`.trim();\n\n/**\n * DDL for creating the folders table when absent.\n */\nexport const FOLDERS_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS folders (\n id VARCHAR(36) PRIMARY KEY,\n collection_id VARCHAR(36) NOT NULL,\n name VARCHAR(255) NOT NULL,\n sort_order INT NOT NULL DEFAULT 0,\n created_at DATETIME NOT NULL,\n updated_at DATETIME NOT NULL,\n created_by_user_id VARCHAR(36) NULL,\n updated_by_user_id VARCHAR(36) NULL,\n FOREIGN KEY (collection_id) REFERENCES collections(id) ON DELETE CASCADE,\n FOREIGN KEY (created_by_user_id) REFERENCES users(id) ON DELETE SET NULL,\n FOREIGN KEY (updated_by_user_id) REFERENCES users(id) ON DELETE SET NULL\n)\n`.trim();\n\n/**\n * DDL for creating the requests table when absent.\n */\nexport const REQUESTS_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS requests (\n id VARCHAR(36) PRIMARY KEY,\n collection_id VARCHAR(36) NOT NULL,\n folder_id VARCHAR(36) NULL,\n name VARCHAR(255) NOT NULL,\n method VARCHAR(16) NOT NULL DEFAULT 'GET',\n url LONGTEXT NOT NULL,\n headers LONGTEXT NOT NULL,\n params LONGTEXT NOT NULL,\n auth LONGTEXT NOT NULL,\n body LONGTEXT NOT NULL,\n body_type VARCHAR(32) NOT NULL DEFAULT 'none',\n pre_request_script LONGTEXT NOT NULL,\n post_request_script LONGTEXT NOT NULL,\n comment LONGTEXT NOT NULL,\n sort_order INT NOT NULL DEFAULT 0,\n created_at DATETIME NOT NULL,\n updated_at DATETIME NOT NULL,\n created_by_user_id VARCHAR(36) NULL,\n updated_by_user_id VARCHAR(36) NULL,\n FOREIGN KEY (collection_id) REFERENCES collections(id) ON DELETE CASCADE,\n FOREIGN KEY (folder_id) REFERENCES folders(id) ON DELETE CASCADE,\n FOREIGN KEY (created_by_user_id) REFERENCES users(id) ON DELETE SET NULL,\n FOREIGN KEY (updated_by_user_id) REFERENCES users(id) ON DELETE SET NULL\n)\n`.trim();\n\n/**\n * DDL for creating the users table when absent.\n */\nexport const USERS_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS users (\n id VARCHAR(36) PRIMARY KEY,\n name VARCHAR(255) NOT NULL UNIQUE,\n role VARCHAR(16) NOT NULL,\n collection_access LONGTEXT NOT NULL,\n environment_access LONGTEXT NOT NULL,\n snippet_access LONGTEXT NOT NULL,\n created_at DATETIME NOT NULL,\n updated_at DATETIME NOT NULL,\n created_by_user_id VARCHAR(36) NULL,\n updated_by_user_id VARCHAR(36) NULL,\n FOREIGN KEY (created_by_user_id) REFERENCES users(id) ON DELETE SET NULL,\n FOREIGN KEY (updated_by_user_id) REFERENCES users(id) ON DELETE SET NULL\n)\n`.trim();\n\n/**\n * DDL for creating the audit_log table when absent.\n */\nexport const AUDIT_LOG_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS audit_log (\n id VARCHAR(36) PRIMARY KEY,\n user_id VARCHAR(36) NULL,\n user_name VARCHAR(255) NULL,\n action VARCHAR(16) NOT NULL,\n entity_type VARCHAR(32) NOT NULL,\n entity_id VARCHAR(36) NOT NULL,\n created_at DATETIME NOT NULL,\n metadata LONGTEXT NOT NULL\n)\n`.trim();\n\n/**\n * Adds the owning user reference to api_tokens when upgrading existing databases.\n */\nexport const API_TOKENS_USER_ID_MIGRATION_SQL = `\nALTER TABLE api_tokens\n ADD COLUMN IF NOT EXISTS user_id VARCHAR(36) NULL\n`.trim();\n\n/**\n * Adds user attribution columns to api_tokens when upgrading existing databases.\n */\nexport const API_TOKENS_ATTRIBUTION_MIGRATION_SQL = `\nALTER TABLE api_tokens\n ADD COLUMN IF NOT EXISTS created_by_user_id VARCHAR(36) NULL,\n ADD COLUMN IF NOT EXISTS updated_by_user_id VARCHAR(36) NULL\n`.trim();\n\n/**\n * Adds user attribution and updated_at to collections when upgrading existing databases.\n */\nexport const COLLECTIONS_ATTRIBUTION_MIGRATION_SQL = `\nALTER TABLE collections\n ADD COLUMN IF NOT EXISTS updated_at DATETIME NULL,\n ADD COLUMN IF NOT EXISTS created_by_user_id VARCHAR(36) NULL,\n ADD COLUMN IF NOT EXISTS updated_by_user_id VARCHAR(36) NULL\n`.trim();\n\n/**\n * Adds user attribution and updated_at to environments when upgrading existing databases.\n */\nexport const ENVIRONMENTS_ATTRIBUTION_MIGRATION_SQL = `\nALTER TABLE environments\n ADD COLUMN IF NOT EXISTS updated_at DATETIME NULL,\n ADD COLUMN IF NOT EXISTS created_by_user_id VARCHAR(36) NULL,\n ADD COLUMN IF NOT EXISTS updated_by_user_id VARCHAR(36) NULL\n`.trim();\n\n/**\n * Adds user attribution and updated_at to folders when upgrading existing databases.\n */\nexport const FOLDERS_ATTRIBUTION_MIGRATION_SQL = `\nALTER TABLE folders\n ADD COLUMN IF NOT EXISTS updated_at DATETIME NULL,\n ADD COLUMN IF NOT EXISTS created_by_user_id VARCHAR(36) NULL,\n ADD COLUMN IF NOT EXISTS updated_by_user_id VARCHAR(36) NULL\n`.trim();\n\n/**\n * Adds user attribution columns to requests when upgrading existing databases.\n */\nexport const REQUESTS_ATTRIBUTION_MIGRATION_SQL = `\nALTER TABLE requests\n ADD COLUMN IF NOT EXISTS created_by_user_id VARCHAR(36) NULL,\n ADD COLUMN IF NOT EXISTS updated_by_user_id VARCHAR(36) NULL\n`.trim();\n\n/**\n * Adds user attribution columns to users when upgrading existing databases.\n */\nexport const USERS_ATTRIBUTION_MIGRATION_SQL = `\nALTER TABLE users\n ADD COLUMN IF NOT EXISTS created_by_user_id VARCHAR(36) NULL,\n ADD COLUMN IF NOT EXISTS updated_by_user_id VARCHAR(36) NULL\n`.trim();\n\n/**\n * Backfills updated_at on collections from created_at for upgraded databases.\n */\nexport const COLLECTIONS_BACKFILL_UPDATED_AT_SQL = `\nUPDATE collections SET updated_at = created_at WHERE updated_at IS NULL\n`.trim();\n\n/**\n * Backfills updated_at on environments from created_at for upgraded databases.\n */\nexport const ENVIRONMENTS_BACKFILL_UPDATED_AT_SQL = `\nUPDATE environments SET updated_at = created_at WHERE updated_at IS NULL\n`.trim();\n\n/**\n * Backfills updated_at on folders from created_at for upgraded databases.\n */\nexport const FOLDERS_BACKFILL_UPDATED_AT_SQL = `\nUPDATE folders SET updated_at = created_at WHERE updated_at IS NULL\n`.trim();\n\n/**\n * Adds LLM access columns to users when upgrading existing databases.\n */\nexport const USERS_LLM_MIGRATION_SQL = `\nALTER TABLE users\n ADD COLUMN IF NOT EXISTS llm_access TINYINT(1) NOT NULL DEFAULT 0,\n ADD COLUMN IF NOT EXISTS llm_models LONGTEXT NOT NULL DEFAULT '[]',\n ADD COLUMN IF NOT EXISTS llm_monthly_token_limit INT NULL\n`.trim();\n\n/**\n * DDL for creating the llm_usage table when absent.\n */\nexport const LLM_USAGE_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS llm_usage (\n id VARCHAR(36) PRIMARY KEY,\n user_id VARCHAR(36) NOT NULL,\n period VARCHAR(7) NOT NULL,\n prompt_tokens INT NOT NULL DEFAULT 0,\n completion_tokens INT NOT NULL DEFAULT 0,\n total_tokens INT NOT NULL DEFAULT 0,\n updated_at DATETIME NOT NULL,\n UNIQUE KEY llm_usage_user_period (user_id, period),\n FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE\n)\n`.trim();\n\n/**\n * DDL for creating the llm_usage_log table when absent.\n */\nexport const LLM_USAGE_LOG_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS llm_usage_log (\n id VARCHAR(36) PRIMARY KEY,\n user_id VARCHAR(36) NOT NULL,\n api_token_id VARCHAR(36) NULL,\n period VARCHAR(7) NOT NULL,\n model VARCHAR(255) NOT NULL,\n provider VARCHAR(32) NOT NULL,\n prompt_tokens INT NOT NULL,\n completion_tokens INT NOT NULL,\n total_tokens INT NOT NULL,\n is_new_turn BOOLEAN NOT NULL DEFAULT FALSE,\n had_tool_calls BOOLEAN NOT NULL DEFAULT FALSE,\n message_count INT NOT NULL,\n created_at DATETIME NOT NULL,\n INDEX llm_usage_log_user_created_at_idx (user_id, created_at),\n INDEX llm_usage_log_period_idx (period),\n FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,\n FOREIGN KEY (api_token_id) REFERENCES api_tokens(id) ON DELETE SET NULL\n)\n`.trim();\n\n/**\n * Default LLM models JSON for MySQL user inserts on upgraded databases.\n */\nexport const MYSQL_DEFAULT_LLM_MODELS_JSON = '[]';\n\n/**\n * Default auth JSON for MySQL collection/request inserts.\n */\nexport const MYSQL_DEFAULT_AUTH_JSON = DEFAULT_AUTH_JSON;\n\n/**\n * Adds deletion lock columns to collections when upgrading existing databases.\n */\nexport const COLLECTIONS_DELETION_LOCKED_MIGRATION_SQL = `\nALTER TABLE collections\n ADD COLUMN IF NOT EXISTS deletion_locked TINYINT(1) NOT NULL DEFAULT 0;\n`.trim();\n\n/**\n * Adds deletion lock columns to environments when upgrading existing databases.\n */\nexport const ENVIRONMENTS_DELETION_LOCKED_MIGRATION_SQL = `\nALTER TABLE environments\n ADD COLUMN IF NOT EXISTS deletion_locked TINYINT(1) NOT NULL DEFAULT 0;\n`.trim();\n\n/**\n * Adds snippet access column to users when upgrading existing databases.\n */\nexport const USERS_SNIPPET_ACCESS_MIGRATION_SQL = `\nALTER TABLE users\n ADD COLUMN IF NOT EXISTS snippet_access LONGTEXT NOT NULL DEFAULT '[]';\n`.trim();\n\n/**\n * Adds snippet access for user accounts that have collection wildcard access but no snippet access.\n */\nexport const USERS_SNIPPET_ACCESS_BACKFILL_SQL = `\nUPDATE users\nSET snippet_access = '[\"*\"]'\nWHERE role = 'user'\n AND snippet_access = '[]'\n AND collection_access LIKE '%\"*\"%';\n`.trim();\n\n/**\n * DDL for creating the run_results table when absent.\n */\nexport const RUN_RESULTS_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS run_results (\n id VARCHAR(36) PRIMARY KEY,\n kind VARCHAR(64) NOT NULL,\n label VARCHAR(512) NOT NULL,\n collection_name VARCHAR(512),\n request_name VARCHAR(512),\n summary_passed INT NOT NULL DEFAULT 0,\n summary_failed INT NOT NULL DEFAULT 0,\n summary_skipped INT NOT NULL DEFAULT 0,\n payload LONGTEXT NOT NULL,\n created_at DATETIME NOT NULL,\n created_by_user_id VARCHAR(36),\n INDEX run_results_created_idx (created_at)\n)\n`.trim();\n\n/**\n * Ordered MySQL migrations applied by {@link MysqlDatabase.migrate}.\n */\nexport const MYSQL_MIGRATIONS = [\n USERS_MIGRATION_SQL,\n API_TOKENS_MIGRATION_SQL,\n COLLECTIONS_MIGRATION_SQL,\n ENVIRONMENTS_MIGRATION_SQL,\n SNIPPETS_MIGRATION_SQL,\n FOLDERS_MIGRATION_SQL,\n REQUESTS_MIGRATION_SQL,\n AUDIT_LOG_MIGRATION_SQL,\n API_TOKENS_USER_ID_MIGRATION_SQL,\n API_TOKENS_ATTRIBUTION_MIGRATION_SQL,\n COLLECTIONS_ATTRIBUTION_MIGRATION_SQL,\n ENVIRONMENTS_ATTRIBUTION_MIGRATION_SQL,\n FOLDERS_ATTRIBUTION_MIGRATION_SQL,\n REQUESTS_ATTRIBUTION_MIGRATION_SQL,\n USERS_ATTRIBUTION_MIGRATION_SQL,\n COLLECTIONS_BACKFILL_UPDATED_AT_SQL,\n ENVIRONMENTS_BACKFILL_UPDATED_AT_SQL,\n FOLDERS_BACKFILL_UPDATED_AT_SQL,\n USERS_LLM_MIGRATION_SQL,\n LLM_USAGE_MIGRATION_SQL,\n LLM_USAGE_LOG_MIGRATION_SQL,\n COLLECTIONS_DELETION_LOCKED_MIGRATION_SQL,\n ENVIRONMENTS_DELETION_LOCKED_MIGRATION_SQL,\n USERS_SNIPPET_ACCESS_MIGRATION_SQL,\n USERS_SNIPPET_ACCESS_BACKFILL_SQL,\n RUN_RESULTS_MIGRATION_SQL\n];\n","import { z } from 'zod/v4';\n\n/**\n * Zod schema for validating MySQL port values from server.yaml.\n */\nexport const portSchema = z.union([\n z\n .number()\n .int({ message: 'MySQL port must be an integer between 1 and 65535.' })\n .min(1, { message: 'MySQL port must be an integer between 1 and 65535.' })\n .max(65535, { message: 'MySQL port must be an integer between 1 and 65535.' }),\n z\n .string()\n .regex(/^\\d+$/, { message: 'MySQL port must be an integer between 1 and 65535.' })\n .transform(Number)\n .pipe(\n z\n .number()\n .int({ message: 'MySQL port must be an integer between 1 and 65535.' })\n .min(1, { message: 'MySQL port must be an integer between 1 and 65535.' })\n .max(65535, { message: 'MySQL port must be an integer between 1 and 65535.' })\n )\n]);\n\n/**\n * Zod schema for validating raw MySQL database config from server.yaml.\n */\nexport const mysqlConfigSchema = z.object({\n driver: z.literal('mysql'),\n host: z.string().trim().min(1, { message: 'MySQL host must not be empty.' }),\n port: portSchema,\n user: z.string().trim().min(1, { message: 'MySQL user must not be empty.' }),\n password: z.string(),\n database: z.string().trim().min(1, { message: 'MySQL database must not be empty.' })\n});\n","import type { UserRecord, UserRole } from '#/db/types.js';\n\n/**\n * SQL row shape returned by relational backends for the users table.\n */\nexport interface UserSqlRow {\n /**\n * Primary key identifier.\n */\n id: string;\n\n /**\n * Unique display name column.\n */\n name: string;\n\n /**\n * Role column (`admin` or `user`).\n */\n role: string;\n\n /**\n * JSON-encoded collection access list column.\n */\n collection_access: string;\n\n /**\n * JSON-encoded environment access list column.\n */\n environment_access: string;\n\n /**\n * JSON-encoded snippet access list column.\n */\n snippet_access: string;\n\n /**\n * Creation timestamp column.\n */\n created_at: Date;\n\n /**\n * Last update timestamp column.\n */\n updated_at: Date;\n\n /**\n * Creating user identifier column.\n */\n created_by_user_id: string | null;\n\n /**\n * Last updating user identifier column.\n */\n updated_by_user_id: string | null;\n\n /**\n * Whether LLM access is enabled for the account.\n */\n llm_access: boolean;\n\n /**\n * JSON-encoded LLM model access list column.\n */\n llm_models: string;\n\n /**\n * Monthly token limit column, or null for unlimited.\n */\n llm_monthly_token_limit: number | null;\n}\n\n/**\n * Parses a stored role string into a {@link UserRole}.\n *\n * @param role - Role value read from the database.\n * @returns Validated user role.\n * @throws {Error} When the stored role is not recognized.\n */\nfunction parseUserRole(role: string): UserRole {\n if (role === 'admin' || role === 'user') {\n return role;\n }\n\n throw new Error(`Invalid user role: ${role}`);\n}\n\n/**\n * Parses a JSON-encoded access list column from SQL storage.\n *\n * @param value - JSON array string from the database.\n * @returns Parsed access id list.\n */\nfunction parseAccessList(value: string | null | undefined): string[] {\n if (value == null || value === '') {\n return [];\n }\n\n const parsed: unknown = JSON.parse(value);\n if (!Array.isArray(parsed) || !parsed.every((entry) => typeof entry === 'string')) {\n throw new Error('Invalid access list JSON in users table');\n }\n\n return parsed;\n}\n\n/**\n * Maps a snake_case SQL row to the shared {@link UserRecord} shape.\n *\n * @param row - Database row from users.\n * @returns Normalized user record for application code.\n */\nexport function mapUserSqlRow(row: UserSqlRow): UserRecord {\n return {\n id: row.id,\n name: row.name,\n role: parseUserRole(row.role),\n collectionAccess: parseAccessList(row.collection_access),\n environmentAccess: parseAccessList(row.environment_access),\n snippetAccess: parseAccessList(row.snippet_access),\n llmAccess: Boolean(row.llm_access),\n llmModels: parseAccessList(row.llm_models),\n llmMonthlyTokenLimit: row.llm_monthly_token_limit,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n createdByUserId: row.created_by_user_id ?? null,\n updatedByUserId: row.updated_by_user_id ?? null\n };\n}\n\n/**\n * Serializes an access list for SQL storage.\n *\n * @param access - Collection or environment access ids.\n * @returns JSON string suitable for a TEXT column.\n */\nexport function serializeAccessList(access: string[]): string {\n return JSON.stringify(access);\n}\n\n/**\n * Column list for SELECT queries against the users table.\n */\nexport const USER_SELECT_COLUMNS = `id, name, role, collection_access, environment_access, snippet_access, llm_access, llm_models, llm_monthly_token_limit, created_at, updated_at, created_by_user_id, updated_by_user_id`;\n\n/**\n * Column list for SELECT queries against the collections table.\n */\nexport const COLLECTION_SELECT_COLUMNS = `id, name, variables, headers, auth, pre_request_script, post_request_script, created_at, updated_at, created_by_user_id, updated_by_user_id, deletion_locked`;\n\n/**\n * Column list for SELECT queries against the environments table.\n */\nexport const ENVIRONMENT_SELECT_COLUMNS = `id, name, variables, created_at, updated_at, created_by_user_id, updated_by_user_id, deletion_locked`;\n\n/**\n * Column list for SELECT queries against the snippets table.\n */\nexport const SNIPPET_SELECT_COLUMNS = `id, name, code, scope, sort_order, created_at, updated_at, created_by_user_id, updated_by_user_id, deletion_locked`;\n\n/**\n * Column list for SELECT queries against the folders table.\n */\nexport const FOLDER_SELECT_COLUMNS = `id, collection_id, name, sort_order, created_at, updated_at, created_by_user_id, updated_by_user_id`;\n\n/**\n * Column list for SELECT queries against the requests table.\n */\nexport const REQUEST_SELECT_COLUMNS = `id, collection_id, folder_id, name, method, url, headers, params, auth, body, body_type, pre_request_script, post_request_script, comment, sort_order, created_at, updated_at, created_by_user_id, updated_by_user_id`;\n\n/**\n * Column list for SELECT queries against the api_tokens table.\n */\nexport const API_TOKEN_SELECT_COLUMNS = `id, user_id, name, token_hash, token_prefix, created_at, last_used_at, revoked_at, created_by_user_id, updated_by_user_id`;\n\n/**\n * Column list for SELECT queries against the audit_log table.\n */\nexport const AUDIT_LOG_SELECT_COLUMNS = `id, user_id, user_name, action, entity_type, entity_id, created_at, metadata`;\n","import type { LlmUsageLogRecord } from '#/db/types.js';\n\n/**\n * SQL row shape returned by relational backends for the llm_usage_log table.\n */\nexport interface LlmUsageLogSqlRow {\n /**\n * Primary key identifier.\n */\n id: string;\n\n /**\n * Owning user identifier column.\n */\n user_id: string;\n\n /**\n * API token identifier column.\n */\n api_token_id: string | null;\n\n /**\n * UTC calendar month key column.\n */\n period: string;\n\n /**\n * Provider model id column.\n */\n model: string;\n\n /**\n * LLM provider column.\n */\n provider: string;\n\n /**\n * Prompt token count column.\n */\n prompt_tokens: number;\n\n /**\n * Completion token count column.\n */\n completion_tokens: number;\n\n /**\n * Total token count column.\n */\n total_tokens: number;\n\n /**\n * Whether the request started a new user turn.\n */\n is_new_turn: boolean;\n\n /**\n * Whether the model returned tool calls.\n */\n had_tool_calls: boolean;\n\n /**\n * Request message count column.\n */\n message_count: number;\n\n /**\n * Completion timestamp column.\n */\n created_at: Date;\n}\n\n/**\n * Maps a snake_case SQL row to the shared {@link LlmUsageLogRecord} shape.\n *\n * @param row - Database row from llm_usage_log.\n * @returns Normalized usage log record for application code.\n */\nexport function mapLlmUsageLogSqlRow(row: LlmUsageLogSqlRow): LlmUsageLogRecord {\n return {\n id: row.id,\n userId: row.user_id,\n apiTokenId: row.api_token_id,\n period: row.period,\n model: row.model,\n provider: row.provider as LlmUsageLogRecord['provider'],\n promptTokens: row.prompt_tokens,\n completionTokens: row.completion_tokens,\n totalTokens: row.total_tokens,\n isNewTurn: row.is_new_turn,\n hadToolCalls: row.had_tool_calls,\n messageCount: row.message_count,\n createdAt: row.created_at\n };\n}\n\n/**\n * Column list for SELECT queries against the llm_usage_log table.\n */\nexport const LLM_USAGE_LOG_SELECT_COLUMNS = `id, user_id, api_token_id, period, model, provider, prompt_tokens, completion_tokens, total_tokens, is_new_turn, had_tool_calls, message_count, created_at`;\n","import type { LlmUsageRecord } from '#/db/types.js';\n\n/**\n * SQL row shape returned by relational backends for the llm_usage table.\n */\nexport interface LlmUsageSqlRow {\n /**\n * Primary key identifier.\n */\n id: string;\n\n /**\n * Owning user identifier column.\n */\n user_id: string;\n\n /**\n * UTC calendar month key column.\n */\n period: string;\n\n /**\n * Prompt token count column.\n */\n prompt_tokens: number;\n\n /**\n * Completion token count column.\n */\n completion_tokens: number;\n\n /**\n * Total token count column.\n */\n total_tokens: number;\n\n /**\n * Last update timestamp column.\n */\n updated_at: Date;\n}\n\n/**\n * Maps a snake_case SQL row to the shared {@link LlmUsageRecord} shape.\n *\n * @param row - Database row from llm_usage.\n * @returns Normalized usage record for application code.\n */\nexport function mapLlmUsageSqlRow(row: LlmUsageSqlRow): LlmUsageRecord {\n return {\n id: row.id,\n userId: row.user_id,\n period: row.period,\n promptTokens: row.prompt_tokens,\n completionTokens: row.completion_tokens,\n totalTokens: row.total_tokens,\n updatedAt: row.updated_at\n };\n}\n\n/**\n * Column list for SELECT queries against the llm_usage table.\n */\nexport const LLM_USAGE_SELECT_COLUMNS = `id, user_id, period, prompt_tokens, completion_tokens, total_tokens, updated_at`;\n","import { randomUUID } from 'node:crypto';\nimport pg from 'pg';\nimport { mapApiTokenSqlRow, type ApiTokenSqlRow } from '#/db/apiTokenRows.js';\nimport { resolveActingUserName } from '#/db/attribution.js';\nimport {\n mapAuditLogSqlRow,\n serializeAuditMetadata,\n type AuditLogSqlRow\n} from '#/db/auditLogRows.js';\nimport { BOOTSTRAP_USER_NAME } from '#/db/bootstrapUsers.js';\nimport {\n mapCollectionSqlRow,\n mapEnvironmentSqlRow,\n mapFolderSqlRow,\n mapRequestSqlRow,\n mapRunResultSqlRow,\n mapSnippetSqlRow,\n type CollectionSqlRow,\n type EnvironmentSqlRow,\n type FolderSqlRow,\n type RequestSqlRow,\n type RunResultSqlRow,\n type SnippetSqlRow\n} from '#/db/entityRows.js';\nimport { buildDefaultRunResultLabel, parseRunResultPayload } from '#/db/runResultPayload.js';\nimport type { IDatabase } from '#/db/IDatabase.js';\nimport { POSTGRES_MIGRATIONS } from '#/db/postgres/migrations.js';\nimport { postgresConfigSchema } from '#/db/postgres/schemas.js';\nimport type { PostgresDatabaseConfig } from '#/db/postgres/types.js';\nimport { createSystemUserInput, SYSTEM_USER_NAME } from '#/db/systemUsers.js';\nimport { trimRequiredName } from '#/db/trimRequiredName.js';\nimport { assertUserNameAvailable, assertUserNameNotReserved } from '#/db/userNameValidation.js';\nimport {\n API_TOKEN_SELECT_COLUMNS,\n AUDIT_LOG_SELECT_COLUMNS,\n COLLECTION_SELECT_COLUMNS,\n ENVIRONMENT_SELECT_COLUMNS,\n FOLDER_SELECT_COLUMNS,\n mapUserSqlRow,\n REQUEST_SELECT_COLUMNS,\n SNIPPET_SELECT_COLUMNS,\n serializeAccessList,\n USER_SELECT_COLUMNS,\n type UserSqlRow\n} from '#/db/userRows.js';\nimport {\n LLM_USAGE_LOG_SELECT_COLUMNS,\n mapLlmUsageLogSqlRow,\n type LlmUsageLogSqlRow\n} from '#/db/llmUsageLogRows.js';\nimport {\n LLM_USAGE_SELECT_COLUMNS,\n mapLlmUsageSqlRow,\n type LlmUsageSqlRow\n} from '#/db/llmUsageRows.js';\nimport type {\n ApiTokenRecord,\n AuditAction,\n AuditEntityType,\n AuditLogRecord,\n AuthConfig,\n CollectionRecord,\n CreateUserInput,\n CreateLlmUsageLogInput,\n CreateRunResultInput,\n EnvironmentRecord,\n FolderRecord,\n KeyValue,\n ListAuditLogOptions,\n LlmUsageLogRecord,\n LlmUsageRecord,\n RunResultRecord,\n SaveRequestInput,\n SavedRequestRecord,\n SnippetRecord,\n SnippetScope,\n UpdateUserInput,\n UserRecord,\n Variable\n} from '#/db/types.js';\nimport { DEFAULT_AUTH_JSON } from '#/db/types.js';\nimport { formatZodError } from '#/db/validation.js';\n\nconst { Pool } = pg;\n\nconst COLLECTION_SELECT = `SELECT ${COLLECTION_SELECT_COLUMNS} FROM collections`;\nconst ENVIRONMENT_SELECT = `SELECT ${ENVIRONMENT_SELECT_COLUMNS} FROM environments`;\nconst SNIPPET_SELECT = `SELECT ${SNIPPET_SELECT_COLUMNS} FROM snippets`;\nconst RUN_RESULT_SELECT_COLUMNS =\n 'id, kind, label, collection_name, request_name, summary_passed, summary_failed, summary_skipped, payload, created_at, created_by_user_id';\nconst RUN_RESULT_SELECT = `SELECT ${RUN_RESULT_SELECT_COLUMNS} FROM run_results`;\nconst USER_SELECT = `SELECT ${USER_SELECT_COLUMNS} FROM users`;\nconst API_TOKEN_SELECT = `SELECT ${API_TOKEN_SELECT_COLUMNS} FROM api_tokens`;\nconst FOLDER_SELECT = `SELECT ${FOLDER_SELECT_COLUMNS} FROM folders`;\nconst REQUEST_SELECT = `SELECT ${REQUEST_SELECT_COLUMNS} FROM requests`;\nconst LLM_USAGE_SELECT = `SELECT ${LLM_USAGE_SELECT_COLUMNS} FROM llm_usage`;\nconst LLM_USAGE_LOG_SELECT = `SELECT ${LLM_USAGE_LOG_SELECT_COLUMNS} FROM llm_usage_log`;\n\n/**\n * Postgres-backed database implementation.\n */\nexport class PostgresDatabase implements IDatabase {\n /**\n * Active Postgres connection pool, or null when disconnected.\n */\n private pool: pg.Pool | null = null;\n\n /**\n * Cached identifier for the internal system user, when provisioned during migrate.\n */\n private systemUserId: string | null = null;\n\n /**\n * Creates a Postgres database instance from validated config.\n *\n * @param config - Parsed Postgres connection settings.\n */\n constructor(private readonly config: PostgresDatabaseConfig) {}\n\n /**\n * Validates raw config and constructs a {@link PostgresDatabase}.\n *\n * @param config - Raw `db` section from server.yaml.\n * @returns Configured Postgres database instance.\n * @throws {Error} When config fails Postgres-specific validation.\n */\n static fromConfig(config: unknown): PostgresDatabase {\n const parsed = postgresConfigSchema.safeParse(config);\n if (!parsed.success) {\n throw new Error(formatZodError(parsed.error));\n }\n\n return new PostgresDatabase({\n host: parsed.data.host,\n port: parsed.data.port,\n user: parsed.data.user,\n password: parsed.data.password,\n database: parsed.data.database\n });\n }\n\n /**\n * Opens a Postgres connection pool and verifies connectivity with a query.\n */\n async connect(): Promise<void> {\n if (this.pool) {\n return;\n }\n\n const pool = new Pool({\n host: this.config.host,\n port: this.config.port,\n user: this.config.user,\n password: this.config.password,\n database: this.config.database\n });\n\n const client = await pool.connect();\n await client.query('SELECT 1');\n client.release();\n\n this.pool = pool;\n }\n\n /**\n * Closes the Postgres connection pool and releases resources.\n */\n async disconnect(): Promise<void> {\n if (!this.pool) {\n return;\n }\n\n await this.pool.end();\n this.pool = null;\n }\n\n /**\n * Creates required tables when they do not already exist.\n */\n async migrate(): Promise<void> {\n for (const sql of POSTGRES_MIGRATIONS) {\n await this.query(sql);\n }\n\n await this.ensureSystemUser();\n await this.migrateOrphanTokensToBootstrapUser();\n }\n\n /**\n * Returns the stable identifier of the internal system user, when provisioned.\n */\n getSystemUserId(): string | null {\n return this.systemUserId;\n }\n\n /**\n * Lists audit log entries ordered newest-first with optional filters.\n *\n * @param options - Optional limit and filter criteria.\n */\n async listAuditLog(options?: ListAuditLogOptions): Promise<AuditLogRecord[]> {\n const limit = options?.limit ?? 100;\n const conditions: string[] = [];\n const params: unknown[] = [];\n let paramIndex = 1;\n\n if (options?.userId) {\n conditions.push(`user_id = $${paramIndex++}`);\n params.push(options.userId);\n }\n\n if (options?.entityType) {\n conditions.push(`entity_type = $${paramIndex++}`);\n params.push(options.entityType);\n }\n\n if (options?.entityId) {\n conditions.push(`entity_id = $${paramIndex++}`);\n params.push(options.entityId);\n }\n\n const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';\n params.push(limit);\n\n const result = await this.query<AuditLogSqlRow>(\n `SELECT ${AUDIT_LOG_SELECT_COLUMNS} FROM audit_log\n ${whereClause}\n ORDER BY created_at DESC\n LIMIT $${paramIndex}`,\n params\n );\n\n return result.rows.map(mapAuditLogSqlRow);\n }\n\n /**\n * Creates a new user account with the given role and access lists.\n *\n * @param input - User fields to persist.\n * @param actingUserId - User performing the create action.\n */\n async createUser(input: CreateUserInput, actingUserId: string): Promise<UserRecord> {\n const trimmedName = trimRequiredName(input.name, 'User name');\n assertUserNameNotReserved(trimmedName);\n const id = randomUUID();\n const now = new Date();\n\n const result = await this.query<UserSqlRow>(\n `INSERT INTO users (\n id,\n name,\n role,\n collection_access,\n environment_access,\n snippet_access,\n llm_access,\n llm_models,\n llm_monthly_token_limit,\n created_at,\n updated_at,\n created_by_user_id,\n updated_by_user_id\n ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)\n RETURNING ${USER_SELECT_COLUMNS}`,\n [\n id,\n trimmedName,\n input.role,\n serializeAccessList(input.collectionAccess),\n serializeAccessList(input.environmentAccess),\n serializeAccessList(input.snippetAccess),\n input.llmAccess ?? false,\n serializeAccessList(input.llmModels ?? []),\n input.llmMonthlyTokenLimit ?? null,\n now,\n now,\n actingUserId,\n actingUserId\n ]\n );\n\n const row = result.rows[0];\n if (!row) {\n throw new Error('User not found after insert');\n }\n\n await this.recordAuditEntry(actingUserId, 'create', 'user', id);\n\n return mapUserSqlRow(row);\n }\n\n /**\n * Finds a user by stable identifier.\n *\n * @param id - User identifier to look up.\n */\n async findUserById(id: string): Promise<UserRecord | null> {\n const result = await this.query<UserSqlRow>(`${USER_SELECT} WHERE id = $1 LIMIT 1`, [id]);\n const row = result.rows[0];\n return row ? mapUserSqlRow(row) : null;\n }\n\n /**\n * Finds a user by unique display name.\n *\n * @param name - User name to look up.\n */\n async findUserByName(name: string): Promise<UserRecord | null> {\n const result = await this.query<UserSqlRow>(`${USER_SELECT} WHERE name = $1 LIMIT 1`, [name]);\n const row = result.rows[0];\n return row ? mapUserSqlRow(row) : null;\n }\n\n /**\n * Lists all user accounts ordered by name.\n */\n async listUsers(): Promise<UserRecord[]> {\n const result = await this.query<UserSqlRow>(`${USER_SELECT} ORDER BY name ASC`);\n return result.rows.map(mapUserSqlRow);\n }\n\n /**\n * Updates an existing user account.\n *\n * @param id - User identifier to update.\n * @param input - Partial fields to apply.\n * @param actingUserId - User performing the update action.\n */\n async updateUser(id: string, input: UpdateUserInput, actingUserId: string): Promise<UserRecord> {\n const existing = await this.findUserById(id);\n if (!existing) {\n throw new Error('User not found');\n }\n\n const name =\n input.name !== undefined ? trimRequiredName(input.name, 'User name') : existing.name;\n\n if (name !== existing.name) {\n assertUserNameNotReserved(name);\n const duplicate = await this.findUserByName(name);\n assertUserNameAvailable(name, id, duplicate);\n }\n\n const role = input.role ?? existing.role;\n const collectionAccess = input.collectionAccess ?? existing.collectionAccess;\n const environmentAccess = input.environmentAccess ?? existing.environmentAccess;\n const snippetAccess = input.snippetAccess ?? existing.snippetAccess;\n const llmAccess = input.llmAccess ?? existing.llmAccess;\n const llmModels = input.llmModels ?? existing.llmModels;\n const llmMonthlyTokenLimit =\n input.llmMonthlyTokenLimit !== undefined\n ? input.llmMonthlyTokenLimit\n : existing.llmMonthlyTokenLimit;\n const updatedAt = new Date();\n\n const result = await this.query(\n `UPDATE users\n SET name = $1,\n role = $2,\n collection_access = $3,\n environment_access = $4,\n snippet_access = $5,\n llm_access = $6,\n llm_models = $7,\n llm_monthly_token_limit = $8,\n updated_at = $9,\n updated_by_user_id = $10\n WHERE id = $11`,\n [\n name,\n role,\n serializeAccessList(collectionAccess),\n serializeAccessList(environmentAccess),\n serializeAccessList(snippetAccess),\n llmAccess,\n serializeAccessList(llmModels),\n llmMonthlyTokenLimit,\n updatedAt,\n actingUserId,\n id\n ]\n );\n\n if ((result.rowCount ?? 0) === 0) {\n throw new Error('User not found');\n }\n\n await this.recordAuditEntry(actingUserId, 'update', 'user', id);\n\n const updated = await this.findUserById(id);\n if (!updated) {\n throw new Error('User not found');\n }\n\n return updated;\n }\n\n /**\n * Deletes a user account and revokes all of their API tokens.\n *\n * @param id - User identifier to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteUser(id: string, actingUserId: string): Promise<void> {\n const client = await this.requirePool().connect();\n try {\n await client.query('BEGIN');\n await client.query('DELETE FROM api_tokens WHERE user_id = $1', [id]);\n await client.query('DELETE FROM users WHERE id = $1', [id]);\n await client.query('COMMIT');\n } catch (err) {\n await client.query('ROLLBACK');\n throw err;\n } finally {\n client.release();\n }\n\n await this.recordAuditEntry(actingUserId, 'delete', 'user', id);\n }\n\n /**\n * Assigns legacy API tokens without an owner to the bootstrap user.\n */\n async migrateOrphanTokensToBootstrapUser(): Promise<void> {\n const orphanResult = await this.query<{ count: string }>(\n 'SELECT COUNT(*)::text AS count FROM api_tokens WHERE user_id IS NULL'\n );\n const orphanCount = Number(orphanResult.rows[0]?.count ?? 0);\n if (orphanCount === 0) {\n return;\n }\n\n const systemUserId = this.getSystemUserId();\n if (!systemUserId) {\n throw new Error('System user is not provisioned');\n }\n\n let bootstrapUser = await this.findUserByName(BOOTSTRAP_USER_NAME);\n if (!bootstrapUser) {\n bootstrapUser = await this.createUser(\n {\n name: BOOTSTRAP_USER_NAME,\n role: 'user',\n collectionAccess: ['*'],\n environmentAccess: ['*'],\n snippetAccess: ['*']\n },\n systemUserId\n );\n }\n\n await this.query('UPDATE api_tokens SET user_id = $1 WHERE user_id IS NULL', [\n bootstrapUser.id\n ]);\n }\n\n /**\n * Inserts a new API token record.\n *\n * @param record - Token metadata to persist.\n * @param actingUserId - User performing the create action.\n */\n async createApiToken(record: ApiTokenRecord, actingUserId: string): Promise<void> {\n await this.query(\n `INSERT INTO api_tokens (\n id,\n user_id,\n name,\n token_hash,\n token_prefix,\n created_at,\n last_used_at,\n revoked_at,\n created_by_user_id,\n updated_by_user_id\n ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)`,\n [\n record.id,\n record.userId,\n record.name,\n record.tokenHash,\n record.tokenPrefix,\n record.createdAt,\n record.lastUsedAt,\n record.revokedAt,\n actingUserId,\n actingUserId\n ]\n );\n\n await this.recordAuditEntry(actingUserId, 'create', 'api_token', record.id);\n }\n\n /**\n * Finds an active token by its stored hash.\n *\n * @param tokenHash - sha256 hex digest of the bearer token secret.\n */\n async findActiveApiTokenByHash(tokenHash: string): Promise<ApiTokenRecord | null> {\n const result = await this.query<ApiTokenSqlRow>(\n `${API_TOKEN_SELECT}\n WHERE token_hash = $1\n AND revoked_at IS NULL\n AND user_id IS NOT NULL\n LIMIT 1`,\n [tokenHash]\n );\n\n const row = result.rows[0];\n return row ? mapApiTokenSqlRow(row) : null;\n }\n\n /**\n * Lists all API tokens ordered by creation time descending.\n */\n async listApiTokens(): Promise<ApiTokenRecord[]> {\n const result = await this.query<ApiTokenSqlRow>(\n `${API_TOKEN_SELECT}\n WHERE user_id IS NOT NULL\n ORDER BY created_at DESC`\n );\n\n return result.rows.map(mapApiTokenSqlRow);\n }\n\n /**\n * Returns API tokens owned by a specific user ordered newest-first.\n *\n * @param userId - Owning user identifier.\n */\n async listApiTokensByUserId(userId: string): Promise<ApiTokenRecord[]> {\n const result = await this.query<ApiTokenSqlRow>(\n `${API_TOKEN_SELECT}\n WHERE user_id = $1\n ORDER BY created_at DESC`,\n [userId]\n );\n\n return result.rows.map(mapApiTokenSqlRow);\n }\n\n /**\n * Finds an API token record by stable identifier.\n *\n * @param id - Token identifier to look up.\n */\n async findApiTokenById(id: string): Promise<ApiTokenRecord | null> {\n const result = await this.query<ApiTokenSqlRow>(`${API_TOKEN_SELECT} WHERE id = $1 LIMIT 1`, [\n id\n ]);\n const row = result.rows[0];\n return row ? mapApiTokenSqlRow(row) : null;\n }\n\n /**\n * Permanently removes an API token record by id.\n *\n * @param id - Token identifier to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteApiToken(id: string, actingUserId: string): Promise<boolean> {\n const result = await this.query('DELETE FROM api_tokens WHERE id = $1', [id]);\n const deleted = (result.rowCount ?? 0) > 0;\n if (deleted) {\n await this.recordAuditEntry(actingUserId, 'delete', 'api_token', id);\n }\n\n return deleted;\n }\n\n /**\n * Soft-revokes an active token by id.\n *\n * @param id - Token identifier to revoke.\n * @param actingUserId - User performing the revoke action.\n */\n async revokeApiToken(id: string, actingUserId: string): Promise<boolean> {\n const result = await this.query(\n `UPDATE api_tokens\n SET revoked_at = $2,\n updated_by_user_id = $3\n WHERE id = $1\n AND revoked_at IS NULL`,\n [id, new Date(), actingUserId]\n );\n\n const revoked = (result.rowCount ?? 0) > 0;\n if (revoked) {\n await this.recordAuditEntry(actingUserId, 'update', 'api_token', id);\n }\n\n return revoked;\n }\n\n /**\n * Updates the last-used timestamp for a token.\n *\n * @param id - Token identifier that authenticated a request.\n * @param when - Timestamp of the authenticated request.\n */\n async touchApiTokenLastUsed(id: string, when: Date): Promise<void> {\n await this.query(`UPDATE api_tokens SET last_used_at = $2 WHERE id = $1`, [id, when]);\n }\n\n /**\n * Lists all collections ordered by name.\n */\n async listCollections(): Promise<CollectionRecord[]> {\n const result = await this.query<CollectionSqlRow>(`${COLLECTION_SELECT} ORDER BY name ASC`);\n return result.rows.map(mapCollectionSqlRow);\n }\n\n /**\n * Creates a new collection with the given name.\n *\n * @param name - Display name for the collection.\n * @param actingUserId - User performing the create action.\n */\n async createCollection(name: string, actingUserId: string): Promise<CollectionRecord> {\n const trimmedName = trimRequiredName(name, 'Collection name');\n const id = randomUUID();\n const now = new Date();\n\n const result = await this.query<CollectionSqlRow>(\n `INSERT INTO collections (\n id,\n name,\n variables,\n headers,\n auth,\n pre_request_script,\n post_request_script,\n created_at,\n updated_at,\n created_by_user_id,\n updated_by_user_id\n ) VALUES ($1, $2, '[]', '[]', $3, '', '', $4, $5, $6, $7)\n RETURNING ${COLLECTION_SELECT_COLUMNS}`,\n [id, trimmedName, DEFAULT_AUTH_JSON, now, now, actingUserId, actingUserId]\n );\n\n const row = result.rows[0];\n if (!row) {\n throw new Error('Collection not found after insert');\n }\n\n await this.recordAuditEntry(actingUserId, 'create', 'collection', id);\n\n return mapCollectionSqlRow(row);\n }\n\n /**\n * Updates a collection's name, variables, headers, and scripts.\n *\n * @param actingUserId - User performing the update action.\n */\n async updateCollection(\n id: string,\n name: string,\n variables: Variable[],\n headers: KeyValue[],\n preRequestScript: string,\n postRequestScript: string,\n auth: AuthConfig,\n actingUserId: string\n ): Promise<CollectionRecord> {\n const trimmedName = trimRequiredName(name, 'Collection name');\n const updatedAt = new Date();\n const result = await this.query(\n `UPDATE collections\n SET name = $1,\n variables = $2,\n headers = $3,\n auth = $4,\n pre_request_script = $5,\n post_request_script = $6,\n updated_at = $7,\n updated_by_user_id = $8\n WHERE id = $9`,\n [\n trimmedName,\n JSON.stringify(variables),\n JSON.stringify(headers),\n JSON.stringify(auth),\n preRequestScript,\n postRequestScript,\n updatedAt,\n actingUserId,\n id\n ]\n );\n\n if ((result.rowCount ?? 0) === 0) {\n throw new Error('Collection not found');\n }\n\n await this.recordAuditEntry(actingUserId, 'update', 'collection', id);\n\n const selectResult = await this.query<CollectionSqlRow>(`${COLLECTION_SELECT} WHERE id = $1`, [\n id\n ]);\n const row = selectResult.rows[0];\n if (!row) {\n throw new Error('Collection not found');\n }\n\n return mapCollectionSqlRow(row);\n }\n\n /**\n * Deletes a collection and all of its requests and folders.\n *\n * @param id - Collection ID to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteCollection(id: string, actingUserId: string): Promise<void> {\n await this.recordAuditEntry(actingUserId, 'delete', 'collection', id);\n await this.query('DELETE FROM collections WHERE id = $1', [id]);\n }\n\n /**\n * Finds a collection by stable identifier.\n *\n * @param id - Collection ID to look up.\n */\n async findCollectionById(id: string): Promise<CollectionRecord | null> {\n const result = await this.query<CollectionSqlRow>(`${COLLECTION_SELECT} WHERE id = $1`, [id]);\n const row = result.rows[0];\n return row ? mapCollectionSqlRow(row) : null;\n }\n\n /**\n * Updates whether non-admin users may delete a collection.\n *\n * @param id - Collection ID to update.\n * @param deletionLocked - When true, user-role tokens cannot delete the collection.\n * @param actingUserId - Admin user performing the update.\n */\n async setCollectionDeletionLocked(\n id: string,\n deletionLocked: boolean,\n actingUserId: string\n ): Promise<CollectionRecord> {\n const updatedAt = new Date();\n const result = await this.query(\n `UPDATE collections\n SET deletion_locked = $1,\n updated_at = $2,\n updated_by_user_id = $3\n WHERE id = $4`,\n [deletionLocked, updatedAt, actingUserId, id]\n );\n\n if ((result.rowCount ?? 0) === 0) {\n throw new Error('Collection not found');\n }\n\n await this.recordAuditEntry(actingUserId, 'update', 'collection', id);\n\n const selectResult = await this.query<CollectionSqlRow>(`${COLLECTION_SELECT} WHERE id = $1`, [\n id\n ]);\n const row = selectResult.rows[0];\n if (!row) {\n throw new Error('Collection not found');\n }\n\n return mapCollectionSqlRow(row);\n }\n\n /**\n * Lists all environments ordered by name.\n */\n async listEnvironments(): Promise<EnvironmentRecord[]> {\n const result = await this.query<EnvironmentSqlRow>(`${ENVIRONMENT_SELECT} ORDER BY name ASC`);\n return result.rows.map(mapEnvironmentSqlRow);\n }\n\n /**\n * Creates a new environment with the given name.\n *\n * @param name - Display name for the environment.\n * @param actingUserId - User performing the create action.\n */\n async createEnvironment(name: string, actingUserId: string): Promise<EnvironmentRecord> {\n const trimmedName = trimRequiredName(name, 'Environment name');\n const id = randomUUID();\n const now = new Date();\n\n const result = await this.query<EnvironmentSqlRow>(\n `INSERT INTO environments (\n id,\n name,\n variables,\n created_at,\n updated_at,\n created_by_user_id,\n updated_by_user_id\n ) VALUES ($1, $2, '[]', $3, $4, $5, $6)\n RETURNING ${ENVIRONMENT_SELECT_COLUMNS}`,\n [id, trimmedName, now, now, actingUserId, actingUserId]\n );\n\n const row = result.rows[0];\n if (!row) {\n throw new Error('Environment not found after insert');\n }\n\n await this.recordAuditEntry(actingUserId, 'create', 'environment', id);\n\n return mapEnvironmentSqlRow(row);\n }\n\n /**\n * Updates an environment's name and variables.\n *\n * @param actingUserId - User performing the update action.\n */\n async updateEnvironment(\n id: string,\n name: string,\n variables: Variable[],\n actingUserId: string\n ): Promise<EnvironmentRecord> {\n const trimmedName = trimRequiredName(name, 'Environment name');\n const updatedAt = new Date();\n const result = await this.query(\n `UPDATE environments\n SET name = $1,\n variables = $2,\n updated_at = $3,\n updated_by_user_id = $4\n WHERE id = $5`,\n [trimmedName, JSON.stringify(variables), updatedAt, actingUserId, id]\n );\n\n if ((result.rowCount ?? 0) === 0) {\n throw new Error('Environment not found');\n }\n\n await this.recordAuditEntry(actingUserId, 'update', 'environment', id);\n\n const selectResult = await this.query<EnvironmentSqlRow>(\n `${ENVIRONMENT_SELECT} WHERE id = $1`,\n [id]\n );\n const row = selectResult.rows[0];\n if (!row) {\n throw new Error('Environment not found');\n }\n\n return mapEnvironmentSqlRow(row);\n }\n\n /**\n * Deletes an environment.\n *\n * @param id - Environment ID to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteEnvironment(id: string, actingUserId: string): Promise<void> {\n await this.recordAuditEntry(actingUserId, 'delete', 'environment', id);\n await this.query('DELETE FROM environments WHERE id = $1', [id]);\n }\n\n /**\n * Finds an environment by stable identifier.\n *\n * @param id - Environment ID to look up.\n */\n async findEnvironmentById(id: string): Promise<EnvironmentRecord | null> {\n const result = await this.query<EnvironmentSqlRow>(`${ENVIRONMENT_SELECT} WHERE id = $1`, [id]);\n const row = result.rows[0];\n return row ? mapEnvironmentSqlRow(row) : null;\n }\n\n /**\n * Updates whether non-admin users may delete an environment.\n *\n * @param id - Environment ID to update.\n * @param deletionLocked - When true, user-role tokens cannot delete the environment.\n * @param actingUserId - Admin user performing the update.\n */\n async setEnvironmentDeletionLocked(\n id: string,\n deletionLocked: boolean,\n actingUserId: string\n ): Promise<EnvironmentRecord> {\n const updatedAt = new Date();\n const result = await this.query(\n `UPDATE environments\n SET deletion_locked = $1,\n updated_at = $2,\n updated_by_user_id = $3\n WHERE id = $4`,\n [deletionLocked, updatedAt, actingUserId, id]\n );\n\n if ((result.rowCount ?? 0) === 0) {\n throw new Error('Environment not found');\n }\n\n await this.recordAuditEntry(actingUserId, 'update', 'environment', id);\n\n const selectResult = await this.query<EnvironmentSqlRow>(\n `${ENVIRONMENT_SELECT} WHERE id = $1`,\n [id]\n );\n const row = selectResult.rows[0];\n if (!row) {\n throw new Error('Environment not found');\n }\n\n return mapEnvironmentSqlRow(row);\n }\n\n /**\n * Lists all snippets ordered by sort order then name.\n */\n async listSnippets(): Promise<SnippetRecord[]> {\n const result = await this.query<SnippetSqlRow>(\n `${SNIPPET_SELECT} ORDER BY sort_order ASC, name ASC`\n );\n return result.rows.map(mapSnippetSqlRow);\n }\n\n /**\n * Creates a new snippet with the given fields.\n *\n * @param name - Display name for the snippet.\n * @param code - JavaScript source for the snippet.\n * @param scope - Execution scope for the snippet.\n * @param actingUserId - User performing the create action.\n */\n async createSnippet(\n name: string,\n code: string,\n scope: SnippetScope,\n actingUserId: string\n ): Promise<SnippetRecord> {\n const trimmedName = trimRequiredName(name, 'Snippet name');\n const id = randomUUID();\n const now = new Date();\n const maxResult = await this.query<{ max_order: number | null }>(\n 'SELECT COALESCE(MAX(sort_order), -1) AS max_order FROM snippets'\n );\n const maxOrder = maxResult.rows[0]?.max_order ?? -1;\n\n const result = await this.query<SnippetSqlRow>(\n `INSERT INTO snippets (\n id,\n name,\n code,\n scope,\n sort_order,\n created_at,\n updated_at,\n created_by_user_id,\n updated_by_user_id\n ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)\n RETURNING ${SNIPPET_SELECT_COLUMNS}`,\n [id, trimmedName, code, scope, maxOrder + 1, now, now, actingUserId, actingUserId]\n );\n\n const row = result.rows[0];\n if (!row) {\n throw new Error('Snippet not found after insert');\n }\n\n await this.recordAuditEntry(actingUserId, 'create', 'snippet', id);\n\n return mapSnippetSqlRow(row);\n }\n\n /**\n * Updates a snippet's name, code, and scope. Sort order is left unchanged.\n *\n * @param actingUserId - User performing the update action.\n */\n async updateSnippet(\n id: string,\n name: string,\n code: string,\n scope: SnippetScope,\n actingUserId: string\n ): Promise<SnippetRecord> {\n const trimmedName = trimRequiredName(name, 'Snippet name');\n const updatedAt = new Date();\n const result = await this.query(\n `UPDATE snippets\n SET name = $1,\n code = $2,\n scope = $3,\n updated_at = $4,\n updated_by_user_id = $5\n WHERE id = $6`,\n [trimmedName, code, scope, updatedAt, actingUserId, id]\n );\n\n if ((result.rowCount ?? 0) === 0) {\n throw new Error('Snippet not found');\n }\n\n await this.recordAuditEntry(actingUserId, 'update', 'snippet', id);\n\n const selectResult = await this.query<SnippetSqlRow>(`${SNIPPET_SELECT} WHERE id = $1`, [id]);\n const row = selectResult.rows[0];\n if (!row) {\n throw new Error('Snippet not found');\n }\n\n return mapSnippetSqlRow(row);\n }\n\n /**\n * Deletes a snippet.\n *\n * @param id - Snippet ID to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteSnippet(id: string, actingUserId: string): Promise<void> {\n await this.recordAuditEntry(actingUserId, 'delete', 'snippet', id);\n await this.query('DELETE FROM snippets WHERE id = $1', [id]);\n }\n\n /**\n * Finds a snippet by stable identifier.\n *\n * @param id - Snippet ID to look up.\n */\n async findSnippetById(id: string): Promise<SnippetRecord | null> {\n const result = await this.query<SnippetSqlRow>(`${SNIPPET_SELECT} WHERE id = $1`, [id]);\n const row = result.rows[0];\n return row ? mapSnippetSqlRow(row) : null;\n }\n\n /**\n * Updates whether non-admin users may delete a snippet.\n *\n * @param id - Snippet ID to update.\n * @param deletionLocked - When true, user-role tokens cannot delete the snippet.\n * @param actingUserId - Admin user performing the update.\n */\n async setSnippetDeletionLocked(\n id: string,\n deletionLocked: boolean,\n actingUserId: string\n ): Promise<SnippetRecord> {\n const updatedAt = new Date();\n const result = await this.query(\n `UPDATE snippets\n SET deletion_locked = $1,\n updated_at = $2,\n updated_by_user_id = $3\n WHERE id = $4`,\n [deletionLocked, updatedAt, actingUserId, id]\n );\n\n if ((result.rowCount ?? 0) === 0) {\n throw new Error('Snippet not found');\n }\n\n await this.recordAuditEntry(actingUserId, 'update', 'snippet', id);\n\n const selectResult = await this.query<SnippetSqlRow>(`${SNIPPET_SELECT} WHERE id = $1`, [id]);\n const row = selectResult.rows[0];\n if (!row) {\n throw new Error('Snippet not found');\n }\n\n return mapSnippetSqlRow(row);\n }\n\n /**\n * Lists all saved requests in a collection.\n *\n * @param collectionId - Collection to query.\n */\n async listRequests(collectionId: string): Promise<SavedRequestRecord[]> {\n const result = await this.query<RequestSqlRow>(\n `${REQUEST_SELECT} WHERE collection_id = $1 ORDER BY sort_order ASC, name ASC`,\n [collectionId]\n );\n return result.rows.map(mapRequestSqlRow);\n }\n\n /**\n * Finds a saved request by id.\n *\n * @param id - Request identifier to look up.\n */\n async findRequestById(id: string): Promise<SavedRequestRecord | null> {\n const result = await this.query<RequestSqlRow>(`${REQUEST_SELECT} WHERE id = $1 LIMIT 1`, [id]);\n const row = result.rows[0];\n return row ? mapRequestSqlRow(row) : null;\n }\n\n /**\n * Inserts a new request or updates an existing one.\n *\n * @param input - Request fields to persist.\n * @param actingUserId - User performing the save action.\n */\n async saveRequest(input: SaveRequestInput, actingUserId: string): Promise<SavedRequestRecord> {\n const trimmedName = trimRequiredName(input.name, 'Request name');\n const headers = JSON.stringify(input.headers);\n const params = JSON.stringify(input.params);\n const auth = JSON.stringify(input.auth);\n const folderId = input.folderId ?? null;\n const now = new Date();\n\n if (folderId != null) {\n const folderResult = await this.query<{ collection_id: string }>(\n 'SELECT collection_id FROM folders WHERE id = $1',\n [folderId]\n );\n const folderRow = folderResult.rows[0];\n if (!folderRow || folderRow.collection_id !== input.collectionId) {\n throw new Error('Folder not found');\n }\n }\n\n if (input.id) {\n const result = await this.query(\n `UPDATE requests SET\n collection_id = $1,\n folder_id = $2,\n name = $3,\n method = $4,\n url = $5,\n headers = $6,\n params = $7,\n auth = $8,\n body = $9,\n body_type = $10,\n pre_request_script = $11,\n post_request_script = $12,\n comment = $13,\n updated_at = $14,\n updated_by_user_id = $15\n WHERE id = $16`,\n [\n input.collectionId,\n folderId,\n trimmedName,\n input.method,\n input.url,\n headers,\n params,\n auth,\n input.body,\n input.bodyType,\n input.preRequestScript,\n input.postRequestScript,\n input.comment,\n now,\n actingUserId,\n input.id\n ]\n );\n\n if ((result.rowCount ?? 0) > 0) {\n await this.recordAuditEntry(actingUserId, 'update', 'request', input.id);\n\n const selectResult = await this.query<RequestSqlRow>(`${REQUEST_SELECT} WHERE id = $1`, [\n input.id\n ]);\n const row = selectResult.rows[0];\n if (row) {\n return mapRequestSqlRow(row);\n }\n }\n }\n\n const maxResult = await this.query<{ max_order: number | null }>(\n `SELECT COALESCE(MAX(sort_order), -1) AS max_order FROM requests\n WHERE collection_id = $1\n AND (($2::text IS NULL AND folder_id IS NULL) OR folder_id = $2)`,\n [input.collectionId, folderId]\n );\n const maxOrder = maxResult.rows[0]?.max_order ?? -1;\n const id = randomUUID();\n\n const result = await this.query<RequestSqlRow>(\n `INSERT INTO requests (\n id,\n collection_id,\n folder_id,\n name,\n method,\n url,\n headers,\n params,\n auth,\n body,\n body_type,\n pre_request_script,\n post_request_script,\n comment,\n sort_order,\n created_at,\n updated_at,\n created_by_user_id,\n updated_by_user_id\n ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19)\n RETURNING ${REQUEST_SELECT_COLUMNS}`,\n [\n id,\n input.collectionId,\n folderId,\n trimmedName,\n input.method,\n input.url,\n headers,\n params,\n auth,\n input.body,\n input.bodyType,\n input.preRequestScript,\n input.postRequestScript,\n input.comment,\n maxOrder + 1,\n now,\n now,\n actingUserId,\n actingUserId\n ]\n );\n\n const row = result.rows[0];\n if (!row) {\n throw new Error('Request not found after insert');\n }\n\n await this.recordAuditEntry(actingUserId, 'create', 'request', id);\n\n return mapRequestSqlRow(row);\n }\n\n /**\n * Deletes a saved request by ID.\n *\n * @param id - Request ID to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteRequest(id: string, actingUserId: string): Promise<void> {\n await this.recordAuditEntry(actingUserId, 'delete', 'request', id);\n await this.query('DELETE FROM requests WHERE id = $1', [id]);\n }\n\n /**\n * Lists all folders in a collection.\n *\n * @param collectionId - Collection to query.\n */\n async listFolders(collectionId: string): Promise<FolderRecord[]> {\n const result = await this.query<FolderSqlRow>(\n `${FOLDER_SELECT} WHERE collection_id = $1 ORDER BY sort_order ASC, name ASC`,\n [collectionId]\n );\n return result.rows.map(mapFolderSqlRow);\n }\n\n /**\n * Finds a folder by id.\n *\n * @param id - Folder identifier to look up.\n */\n async findFolderById(id: string): Promise<FolderRecord | null> {\n const result = await this.query<FolderSqlRow>(`${FOLDER_SELECT} WHERE id = $1 LIMIT 1`, [id]);\n const row = result.rows[0];\n return row ? mapFolderSqlRow(row) : null;\n }\n\n /**\n * Creates a new folder in a collection.\n *\n * @param collectionId - Collection to add the folder to.\n * @param name - Display name for the folder.\n * @param actingUserId - User performing the create action.\n */\n async createFolder(\n collectionId: string,\n name: string,\n actingUserId: string\n ): Promise<FolderRecord> {\n const trimmedName = trimRequiredName(name, 'Folder name');\n const id = randomUUID();\n const now = new Date();\n const maxResult = await this.query<{ max_order: number | null }>(\n 'SELECT COALESCE(MAX(sort_order), -1) AS max_order FROM folders WHERE collection_id = $1',\n [collectionId]\n );\n const maxOrder = maxResult.rows[0]?.max_order ?? -1;\n\n const result = await this.query<FolderSqlRow>(\n `INSERT INTO folders (\n id,\n collection_id,\n name,\n sort_order,\n created_at,\n updated_at,\n created_by_user_id,\n updated_by_user_id\n ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)\n RETURNING ${FOLDER_SELECT_COLUMNS}`,\n [id, collectionId, trimmedName, maxOrder + 1, now, now, actingUserId, actingUserId]\n );\n\n const row = result.rows[0];\n if (!row) {\n throw new Error('Folder not found after insert');\n }\n\n await this.recordAuditEntry(actingUserId, 'create', 'folder', id);\n\n return mapFolderSqlRow(row);\n }\n\n /**\n * Renames a folder.\n *\n * @param id - Folder ID to rename.\n * @param name - New display name.\n * @param actingUserId - User performing the rename action.\n */\n async renameFolder(id: string, name: string, actingUserId: string): Promise<FolderRecord> {\n const trimmedName = trimRequiredName(name, 'Folder name');\n const updatedAt = new Date();\n const result = await this.query<FolderSqlRow>(\n `UPDATE folders\n SET name = $1,\n updated_at = $2,\n updated_by_user_id = $3\n WHERE id = $4\n RETURNING ${FOLDER_SELECT_COLUMNS}`,\n [trimmedName, updatedAt, actingUserId, id]\n );\n const row = result.rows[0];\n if (!row) {\n throw new Error('Folder not found');\n }\n\n await this.recordAuditEntry(actingUserId, 'update', 'folder', id);\n\n return mapFolderSqlRow(row);\n }\n\n /**\n * Deletes a folder and all requests inside it.\n *\n * @param id - Folder ID to delete.\n * @param actingUserId - User performing the delete action.\n */\n async deleteFolder(id: string, actingUserId: string): Promise<void> {\n await this.recordAuditEntry(actingUserId, 'delete', 'folder', id);\n\n const client = await this.requirePool().connect();\n try {\n await client.query('BEGIN');\n await client.query('DELETE FROM requests WHERE folder_id = $1', [id]);\n await client.query('DELETE FROM folders WHERE id = $1', [id]);\n await client.query('COMMIT');\n } catch (err) {\n await client.query('ROLLBACK');\n throw err;\n } finally {\n client.release();\n }\n }\n\n /**\n * Reorders folders within a collection.\n *\n * @param collectionId - Collection containing the folders.\n * @param orderedFolderIds - Folder IDs in desired order.\n * @param actingUserId - User performing the reorder action.\n */\n async reorderFolders(\n collectionId: string,\n orderedFolderIds: string[],\n actingUserId: string\n ): Promise<void> {\n const client = await this.requirePool().connect();\n const updatedAt = new Date();\n try {\n await client.query('BEGIN');\n for (let index = 0; index < orderedFolderIds.length; index++) {\n await client.query(\n `UPDATE folders\n SET sort_order = $1,\n updated_at = $2,\n updated_by_user_id = $3\n WHERE id = $4 AND collection_id = $5`,\n [index, updatedAt, actingUserId, orderedFolderIds[index], collectionId]\n );\n }\n await client.query('COMMIT');\n } catch (err) {\n await client.query('ROLLBACK');\n throw err;\n } finally {\n client.release();\n }\n\n await this.recordAuditEntry(actingUserId, 'reorder', 'folder', collectionId, {\n orderedFolderIds\n });\n }\n\n /**\n * Reorders requests within a folder or at collection root.\n *\n * @param actingUserId - User performing the reorder action.\n */\n async reorderRequests(\n collectionId: string,\n folderId: string | null,\n orderedRequestIds: string[],\n actingUserId: string\n ): Promise<void> {\n const client = await this.requirePool().connect();\n const updatedAt = new Date();\n try {\n await client.query('BEGIN');\n for (let index = 0; index < orderedRequestIds.length; index++) {\n await client.query(\n `UPDATE requests\n SET sort_order = $1,\n folder_id = $2,\n updated_at = $3,\n updated_by_user_id = $4\n WHERE id = $5 AND collection_id = $6`,\n [index, folderId, updatedAt, actingUserId, orderedRequestIds[index], collectionId]\n );\n }\n await client.query('COMMIT');\n } catch (err) {\n await client.query('ROLLBACK');\n throw err;\n } finally {\n client.release();\n }\n\n await this.recordAuditEntry(actingUserId, 'reorder', 'request', collectionId, {\n folderId,\n orderedRequestIds\n });\n }\n\n /**\n * Moves a request to another folder or collection root at a given index.\n *\n * @param actingUserId - User performing the move action.\n */\n async moveRequest(\n requestId: string,\n folderId: string | null,\n index: number,\n actingUserId: string\n ): Promise<void> {\n const client = await this.requirePool().connect();\n const updatedAt = new Date();\n\n /**\n * Lists request ids in a container ordered for reindexing.\n *\n * @param collectionId - Collection to query.\n * @param targetFolderId - Folder id or null for collection root.\n */\n const listInContainer = async (\n collectionId: string,\n targetFolderId: string | null\n ): Promise<string[]> => {\n const result = await client.query<{ id: string }>(\n `SELECT id FROM requests WHERE collection_id = $1\n AND (($2::text IS NULL AND folder_id IS NULL) OR folder_id = $2)\n ORDER BY sort_order ASC, name ASC`,\n [collectionId, targetFolderId]\n );\n return result.rows.map((row) => row.id);\n };\n\n /**\n * Rewrites sort_order and folder_id for a container's request list.\n *\n * @param targetFolderId - Folder id or null for collection root.\n * @param orderedIds - Request ids in desired order.\n */\n const reindexContainer = async (\n targetFolderId: string | null,\n orderedIds: string[]\n ): Promise<void> => {\n for (let sortIndex = 0; sortIndex < orderedIds.length; sortIndex++) {\n await client.query(\n `UPDATE requests\n SET sort_order = $1,\n folder_id = $2,\n updated_at = $3,\n updated_by_user_id = $4\n WHERE id = $5`,\n [sortIndex, targetFolderId, updatedAt, actingUserId, orderedIds[sortIndex]]\n );\n }\n };\n\n try {\n await client.query('BEGIN');\n\n const requestResult = await client.query<RequestSqlRow>(`${REQUEST_SELECT} WHERE id = $1`, [\n requestId\n ]);\n const requestRow = requestResult.rows[0];\n if (!requestRow) {\n throw new Error('Request not found');\n }\n\n const request = mapRequestSqlRow(requestRow);\n const collectionId = request.collectionId;\n const oldFolderId = request.folderId;\n\n if (folderId != null) {\n const folderResult = await client.query<{ collection_id: string }>(\n 'SELECT collection_id FROM folders WHERE id = $1',\n [folderId]\n );\n const folderRow = folderResult.rows[0];\n if (!folderRow || folderRow.collection_id !== collectionId) {\n throw new Error('Folder not found');\n }\n }\n\n if (oldFolderId === folderId) {\n const siblings = (await listInContainer(collectionId, folderId)).filter(\n (id) => id !== requestId\n );\n siblings.splice(index, 0, requestId);\n await reindexContainer(folderId, siblings);\n } else {\n const oldIds = (await listInContainer(collectionId, oldFolderId)).filter(\n (id) => id !== requestId\n );\n await reindexContainer(oldFolderId, oldIds);\n\n const newIds = (await listInContainer(collectionId, folderId)).filter(\n (id) => id !== requestId\n );\n newIds.splice(index, 0, requestId);\n await reindexContainer(folderId, newIds);\n }\n\n await client.query('COMMIT');\n } catch (err) {\n await client.query('ROLLBACK');\n throw err;\n } finally {\n client.release();\n }\n\n await this.recordAuditEntry(actingUserId, 'move', 'request', requestId, {\n folderId,\n index\n });\n }\n\n /**\n * Returns monthly LLM usage for a user, or null when no usage has been recorded.\n *\n * @param userId - Owning user identifier.\n * @param period - UTC calendar month key (`YYYY-MM`).\n */\n async getLlmUsage(userId: string, period: string): Promise<LlmUsageRecord | null> {\n const result = await this.query<LlmUsageSqlRow>(\n `${LLM_USAGE_SELECT} WHERE user_id = $1 AND period = $2 LIMIT 1`,\n [userId, period]\n );\n const row = result.rows[0];\n return row ? mapLlmUsageSqlRow(row) : null;\n }\n\n /**\n * Atomically increments monthly LLM token usage for a user.\n *\n * @param userId - Owning user identifier.\n * @param period - UTC calendar month key (`YYYY-MM`).\n * @param promptTokens - Prompt tokens to add.\n * @param completionTokens - Completion tokens to add.\n */\n async addLlmUsage(\n userId: string,\n period: string,\n promptTokens: number,\n completionTokens: number\n ): Promise<LlmUsageRecord> {\n const totalDelta = promptTokens + completionTokens;\n const now = new Date();\n const id = randomUUID();\n\n const result = await this.query<LlmUsageSqlRow>(\n `INSERT INTO llm_usage (\n id,\n user_id,\n period,\n prompt_tokens,\n completion_tokens,\n total_tokens,\n updated_at\n ) VALUES ($1, $2, $3, $4, $5, $6, $7)\n ON CONFLICT (user_id, period) DO UPDATE\n SET prompt_tokens = llm_usage.prompt_tokens + EXCLUDED.prompt_tokens,\n completion_tokens = llm_usage.completion_tokens + EXCLUDED.completion_tokens,\n total_tokens = llm_usage.total_tokens + EXCLUDED.total_tokens,\n updated_at = EXCLUDED.updated_at\n RETURNING ${LLM_USAGE_SELECT_COLUMNS}`,\n [id, userId, period, promptTokens, completionTokens, totalDelta, now]\n );\n\n const row = result.rows[0];\n if (!row) {\n throw new Error('LLM usage not found after upsert');\n }\n\n return mapLlmUsageSqlRow(row);\n }\n\n /**\n * Inserts a per-request LLM usage log entry.\n *\n * @param input - Usage details for one successful completion step.\n */\n async createLlmUsageLog(input: CreateLlmUsageLogInput): Promise<LlmUsageLogRecord> {\n const id = randomUUID();\n const now = new Date();\n\n const result = await this.query<LlmUsageLogSqlRow>(\n `INSERT INTO llm_usage_log (\n id,\n user_id,\n api_token_id,\n period,\n model,\n provider,\n prompt_tokens,\n completion_tokens,\n total_tokens,\n is_new_turn,\n had_tool_calls,\n message_count,\n created_at\n ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)\n RETURNING ${LLM_USAGE_LOG_SELECT_COLUMNS}`,\n [\n id,\n input.userId,\n input.apiTokenId,\n input.period,\n input.model,\n input.provider,\n input.promptTokens,\n input.completionTokens,\n input.totalTokens,\n input.isNewTurn,\n input.hadToolCalls,\n input.messageCount,\n now\n ]\n );\n\n const row = result.rows[0];\n if (!row) {\n throw new Error('LLM usage log not found after insert');\n }\n\n return mapLlmUsageLogSqlRow(row);\n }\n\n /**\n * Lists all per-request LLM usage log entries, newest first.\n */\n async listLlmUsageLogs(): Promise<LlmUsageLogRecord[]> {\n const result = await this.query<LlmUsageLogSqlRow>(\n `${LLM_USAGE_LOG_SELECT} ORDER BY created_at DESC`\n );\n\n return result.rows.map(mapLlmUsageLogSqlRow);\n }\n\n /**\n * Lists run results saved by the given user, newest first.\n */\n async listRunResultsForUser(userId: string): Promise<RunResultRecord[]> {\n const result = await this.query<RunResultSqlRow>(\n `${RUN_RESULT_SELECT} WHERE created_by_user_id = $1 ORDER BY created_at DESC`,\n [userId]\n );\n return result.rows.map(mapRunResultSqlRow);\n }\n\n /**\n * Lists all run results for admin inspection, newest first.\n */\n async listAllRunResults(): Promise<RunResultRecord[]> {\n const result = await this.query<RunResultSqlRow>(\n `${RUN_RESULT_SELECT} ORDER BY created_at DESC`\n );\n return result.rows.map(mapRunResultSqlRow);\n }\n\n /**\n * Creates a standalone run result snapshot.\n */\n async createRunResult(\n input: CreateRunResultInput,\n actingUserId: string\n ): Promise<RunResultRecord> {\n const metadata = parseRunResultPayload(input.payload);\n const label = input.label?.trim() || buildDefaultRunResultLabel(metadata);\n const id = randomUUID();\n const now = new Date();\n\n const result = await this.query<RunResultSqlRow>(\n `INSERT INTO run_results (\n id,\n kind,\n label,\n collection_name,\n request_name,\n summary_passed,\n summary_failed,\n summary_skipped,\n payload,\n created_at,\n created_by_user_id\n ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)\n RETURNING ${RUN_RESULT_SELECT_COLUMNS}`,\n [\n id,\n metadata.kind,\n label,\n metadata.collectionName,\n metadata.requestName,\n metadata.summary.passed,\n metadata.summary.failed,\n metadata.summary.skipped,\n JSON.stringify(input.payload),\n now,\n actingUserId\n ]\n );\n\n const row = result.rows[0];\n if (!row) {\n throw new Error('Run result not found after insert');\n }\n\n await this.recordAuditEntry(actingUserId, 'create', 'run_result', id);\n return mapRunResultSqlRow(row);\n }\n\n /**\n * Finds a run result by id.\n */\n async findRunResultById(id: string): Promise<RunResultRecord | null> {\n const result = await this.query<RunResultSqlRow>(`${RUN_RESULT_SELECT} WHERE id = $1`, [id]);\n const row = result.rows[0];\n return row ? mapRunResultSqlRow(row) : null;\n }\n\n /**\n * Deletes a run result by id.\n */\n async deleteRunResult(id: string, actingUserId: string): Promise<void> {\n const result = await this.query('DELETE FROM run_results WHERE id = $1', [id]);\n if ((result.rowCount ?? 0) === 0) {\n throw new Error('Run result not found');\n }\n\n await this.recordAuditEntry(actingUserId, 'delete', 'run_result', id);\n }\n\n /**\n * Returns the active pool or throws when connect has not been called.\n *\n * @returns Connected Postgres pool.\n * @throws {Error} When the database is not connected.\n */\n private requirePool(): pg.Pool {\n if (!this.pool) {\n throw new Error('Postgres database is not connected.');\n }\n\n return this.pool;\n }\n\n /**\n * Ensures the internal system user exists and caches its identifier.\n *\n * Inserts directly rather than calling {@link createUser} to avoid recursion\n * during migration bootstrap.\n */\n private async ensureSystemUser(): Promise<void> {\n const existing = await this.findUserByName(SYSTEM_USER_NAME);\n if (existing) {\n this.systemUserId = existing.id;\n return;\n }\n\n const id = randomUUID();\n const now = new Date();\n const input = createSystemUserInput();\n\n await this.query(\n `INSERT INTO users (\n id,\n name,\n role,\n collection_access,\n environment_access,\n snippet_access,\n llm_access,\n llm_models,\n llm_monthly_token_limit,\n created_at,\n updated_at,\n created_by_user_id,\n updated_by_user_id\n ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)`,\n [\n id,\n SYSTEM_USER_NAME,\n input.role,\n serializeAccessList(input.collectionAccess),\n serializeAccessList(input.environmentAccess),\n serializeAccessList(input.snippetAccess),\n false,\n serializeAccessList([]),\n null,\n now,\n now,\n id,\n id\n ]\n );\n\n this.systemUserId = id;\n }\n\n /**\n * Persists a single audit log entry for a mutating action.\n *\n * @param actingUserId - User performing the action.\n * @param action - CRUD or structural action performed.\n * @param entityType - Kind of entity affected.\n * @param entityId - Identifier of the affected entity.\n * @param metadata - Optional structured context for the action.\n */\n private async recordAuditEntry(\n actingUserId: string,\n action: AuditAction,\n entityType: AuditEntityType,\n entityId: string,\n metadata?: Record<string, unknown> | null\n ): Promise<void> {\n const userName = await resolveActingUserName(\n (userId) => this.findUserById(userId),\n actingUserId\n );\n const id = randomUUID();\n const now = new Date();\n\n await this.query(\n `INSERT INTO audit_log (\n id,\n user_id,\n user_name,\n action,\n entity_type,\n entity_id,\n created_at,\n metadata\n ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`,\n [\n id,\n actingUserId,\n userName,\n action,\n entityType,\n entityId,\n now,\n serializeAuditMetadata(metadata ?? null)\n ]\n );\n }\n\n /**\n * Executes a parameterized SQL statement against the active pool.\n *\n * @param sql - SQL statement with $1-style placeholders.\n * @param params - Bound parameter values.\n * @returns Query result from pg.\n */\n private async query<T extends pg.QueryResultRow>(\n sql: string,\n params: unknown[] = []\n ): Promise<pg.QueryResult<T>> {\n return this.requirePool().query<T>(sql, params);\n }\n}\n","import { DEFAULT_AUTH_JSON } from '#/db/types.js';\n\n/**\n * DDL for creating the api_tokens table when absent.\n */\nexport const API_TOKENS_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS api_tokens (\n id TEXT PRIMARY KEY,\n user_id TEXT REFERENCES users(id) ON DELETE SET NULL,\n name TEXT NOT NULL,\n token_hash CHAR(64) NOT NULL UNIQUE,\n token_prefix TEXT NOT NULL,\n created_at TIMESTAMPTZ NOT NULL,\n last_used_at TIMESTAMPTZ,\n revoked_at TIMESTAMPTZ,\n created_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,\n updated_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL\n);\n`.trim();\n\n/**\n * DDL for creating the collections table when absent.\n */\nexport const COLLECTIONS_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS collections (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n variables TEXT NOT NULL DEFAULT '[]',\n headers TEXT NOT NULL DEFAULT '[]',\n auth TEXT NOT NULL DEFAULT '${DEFAULT_AUTH_JSON.replace(/'/g, \"''\")}',\n pre_request_script TEXT NOT NULL DEFAULT '',\n post_request_script TEXT NOT NULL DEFAULT '',\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL,\n created_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,\n updated_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL\n);\n`.trim();\n\n/**\n * DDL for creating the environments table when absent.\n */\nexport const ENVIRONMENTS_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS environments (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n variables TEXT NOT NULL DEFAULT '[]',\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL,\n created_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,\n updated_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL\n);\n`.trim();\n\n/**\n * DDL for creating the snippets table when absent.\n */\nexport const SNIPPETS_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS snippets (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n code TEXT NOT NULL DEFAULT '',\n scope TEXT NOT NULL DEFAULT 'any' CHECK (scope IN ('pre-request', 'post-request', 'any')),\n sort_order INT NOT NULL DEFAULT 0,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL,\n created_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,\n updated_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,\n deletion_locked BOOLEAN NOT NULL DEFAULT FALSE\n);\n`.trim();\n\n/**\n * DDL for creating the folders table when absent.\n */\nexport const FOLDERS_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS folders (\n id TEXT PRIMARY KEY,\n collection_id TEXT NOT NULL,\n name TEXT NOT NULL,\n sort_order INT NOT NULL DEFAULT 0,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL,\n created_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,\n updated_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,\n FOREIGN KEY (collection_id) REFERENCES collections(id) ON DELETE CASCADE\n);\n`.trim();\n\n/**\n * DDL for creating the requests table when absent.\n */\nexport const REQUESTS_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS requests (\n id TEXT PRIMARY KEY,\n collection_id TEXT NOT NULL,\n folder_id TEXT,\n name TEXT NOT NULL,\n method TEXT NOT NULL DEFAULT 'GET',\n url TEXT NOT NULL DEFAULT '',\n headers TEXT NOT NULL DEFAULT '[]',\n params TEXT NOT NULL DEFAULT '[]',\n auth TEXT NOT NULL DEFAULT '${DEFAULT_AUTH_JSON.replace(/'/g, \"''\")}',\n body TEXT NOT NULL DEFAULT '',\n body_type TEXT NOT NULL DEFAULT 'none',\n pre_request_script TEXT NOT NULL DEFAULT '',\n post_request_script TEXT NOT NULL DEFAULT '',\n comment TEXT NOT NULL DEFAULT '',\n sort_order INT NOT NULL DEFAULT 0,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL,\n created_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,\n updated_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,\n FOREIGN KEY (collection_id) REFERENCES collections(id) ON DELETE CASCADE,\n FOREIGN KEY (folder_id) REFERENCES folders(id) ON DELETE CASCADE\n);\n`.trim();\n\n/**\n * DDL for creating the users table when absent.\n */\nexport const USERS_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS users (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL UNIQUE,\n role TEXT NOT NULL CHECK (role IN ('admin', 'user')),\n collection_access TEXT NOT NULL DEFAULT '[]',\n environment_access TEXT NOT NULL DEFAULT '[]',\n snippet_access TEXT NOT NULL DEFAULT '[]',\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL,\n created_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,\n updated_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL\n);\n`.trim();\n\n/**\n * DDL for creating the audit_log table when absent.\n */\nexport const AUDIT_LOG_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS audit_log (\n id TEXT PRIMARY KEY,\n user_id TEXT,\n user_name TEXT,\n action TEXT NOT NULL,\n entity_type TEXT NOT NULL,\n entity_id TEXT NOT NULL,\n created_at TIMESTAMPTZ NOT NULL,\n metadata TEXT NOT NULL DEFAULT '{}'\n);\n`.trim();\n\n/**\n * Adds the owning user reference to api_tokens when upgrading existing databases.\n */\nexport const API_TOKENS_USER_ID_MIGRATION_SQL = `\nALTER TABLE api_tokens\n ADD COLUMN IF NOT EXISTS user_id TEXT REFERENCES users(id) ON DELETE SET NULL;\n`.trim();\n\n/**\n * Adds user attribution columns to api_tokens when upgrading existing databases.\n */\nexport const API_TOKENS_ATTRIBUTION_MIGRATION_SQL = `\nALTER TABLE api_tokens\n ADD COLUMN IF NOT EXISTS created_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,\n ADD COLUMN IF NOT EXISTS updated_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL;\n`.trim();\n\n/**\n * Adds user attribution and updated_at to collections when upgrading existing databases.\n */\nexport const COLLECTIONS_ATTRIBUTION_MIGRATION_SQL = `\nALTER TABLE collections\n ADD COLUMN IF NOT EXISTS updated_at TIMESTAMPTZ,\n ADD COLUMN IF NOT EXISTS created_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,\n ADD COLUMN IF NOT EXISTS updated_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL;\n`.trim();\n\n/**\n * Adds user attribution and updated_at to environments when upgrading existing databases.\n */\nexport const ENVIRONMENTS_ATTRIBUTION_MIGRATION_SQL = `\nALTER TABLE environments\n ADD COLUMN IF NOT EXISTS updated_at TIMESTAMPTZ,\n ADD COLUMN IF NOT EXISTS created_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,\n ADD COLUMN IF NOT EXISTS updated_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL;\n`.trim();\n\n/**\n * Adds user attribution and updated_at to folders when upgrading existing databases.\n */\nexport const FOLDERS_ATTRIBUTION_MIGRATION_SQL = `\nALTER TABLE folders\n ADD COLUMN IF NOT EXISTS updated_at TIMESTAMPTZ,\n ADD COLUMN IF NOT EXISTS created_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,\n ADD COLUMN IF NOT EXISTS updated_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL;\n`.trim();\n\n/**\n * Adds user attribution columns to requests when upgrading existing databases.\n */\nexport const REQUESTS_ATTRIBUTION_MIGRATION_SQL = `\nALTER TABLE requests\n ADD COLUMN IF NOT EXISTS created_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,\n ADD COLUMN IF NOT EXISTS updated_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL;\n`.trim();\n\n/**\n * Adds user attribution columns to users when upgrading existing databases.\n */\nexport const USERS_ATTRIBUTION_MIGRATION_SQL = `\nALTER TABLE users\n ADD COLUMN IF NOT EXISTS created_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,\n ADD COLUMN IF NOT EXISTS updated_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL;\n`.trim();\n\n/**\n * Backfills updated_at on collections from created_at for upgraded databases.\n */\nexport const COLLECTIONS_BACKFILL_UPDATED_AT_SQL = `\nUPDATE collections SET updated_at = created_at WHERE updated_at IS NULL;\n`.trim();\n\n/**\n * Backfills updated_at on environments from created_at for upgraded databases.\n */\nexport const ENVIRONMENTS_BACKFILL_UPDATED_AT_SQL = `\nUPDATE environments SET updated_at = created_at WHERE updated_at IS NULL;\n`.trim();\n\n/**\n * Backfills updated_at on folders from created_at for upgraded databases.\n */\nexport const FOLDERS_BACKFILL_UPDATED_AT_SQL = `\nUPDATE folders SET updated_at = created_at WHERE updated_at IS NULL;\n`.trim();\n\n/**\n * Adds LLM access columns to users when upgrading existing databases.\n */\nexport const USERS_LLM_MIGRATION_SQL = `\nALTER TABLE users\n ADD COLUMN IF NOT EXISTS llm_access BOOLEAN NOT NULL DEFAULT FALSE,\n ADD COLUMN IF NOT EXISTS llm_models TEXT NOT NULL DEFAULT '[]',\n ADD COLUMN IF NOT EXISTS llm_monthly_token_limit INT;\n`.trim();\n\n/**\n * DDL for creating the llm_usage table when absent.\n */\nexport const LLM_USAGE_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS llm_usage (\n id TEXT PRIMARY KEY,\n user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,\n period TEXT NOT NULL,\n prompt_tokens INT NOT NULL DEFAULT 0,\n completion_tokens INT NOT NULL DEFAULT 0,\n total_tokens INT NOT NULL DEFAULT 0,\n updated_at TIMESTAMPTZ NOT NULL,\n UNIQUE (user_id, period)\n);\n`.trim();\n\n/**\n * DDL for creating the llm_usage_log table when absent.\n */\nexport const LLM_USAGE_LOG_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS llm_usage_log (\n id TEXT PRIMARY KEY,\n user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,\n api_token_id TEXT REFERENCES api_tokens(id) ON DELETE SET NULL,\n period TEXT NOT NULL,\n model TEXT NOT NULL,\n provider TEXT NOT NULL,\n prompt_tokens INT NOT NULL,\n completion_tokens INT NOT NULL,\n total_tokens INT NOT NULL,\n is_new_turn BOOLEAN NOT NULL DEFAULT FALSE,\n had_tool_calls BOOLEAN NOT NULL DEFAULT FALSE,\n message_count INT NOT NULL,\n created_at TIMESTAMPTZ NOT NULL\n);\n\nCREATE INDEX IF NOT EXISTS llm_usage_log_user_created_at_idx ON llm_usage_log (user_id, created_at DESC);\n\nCREATE INDEX IF NOT EXISTS llm_usage_log_period_idx ON llm_usage_log (period);\n`.trim();\n\n/**\n * Adds deletion lock columns to collections when upgrading existing databases.\n */\nexport const COLLECTIONS_DELETION_LOCKED_MIGRATION_SQL = `\nALTER TABLE collections\n ADD COLUMN IF NOT EXISTS deletion_locked BOOLEAN NOT NULL DEFAULT FALSE;\n`.trim();\n\n/**\n * Adds deletion lock columns to environments when upgrading existing databases.\n */\nexport const ENVIRONMENTS_DELETION_LOCKED_MIGRATION_SQL = `\nALTER TABLE environments\n ADD COLUMN IF NOT EXISTS deletion_locked BOOLEAN NOT NULL DEFAULT FALSE;\n`.trim();\n\n/**\n * Adds snippet access column to users when upgrading existing databases.\n */\nexport const USERS_SNIPPET_ACCESS_MIGRATION_SQL = `\nALTER TABLE users\n ADD COLUMN IF NOT EXISTS snippet_access TEXT NOT NULL DEFAULT '[]';\n`.trim();\n\n/**\n * Adds snippet access for user accounts that have collection wildcard access but no snippet access.\n */\nexport const USERS_SNIPPET_ACCESS_BACKFILL_SQL = `\nUPDATE users\nSET snippet_access = '[\"*\"]'\nWHERE role = 'user'\n AND snippet_access = '[]'\n AND collection_access LIKE '%\"*\"%';\n`.trim();\n\n/**\n * DDL for creating the run_results table when absent.\n */\nexport const RUN_RESULTS_MIGRATION_SQL = `\nCREATE TABLE IF NOT EXISTS run_results (\n id TEXT PRIMARY KEY,\n kind TEXT NOT NULL CHECK (kind IN ('collection-run-results', 'request-run-results')),\n label TEXT NOT NULL,\n collection_name TEXT,\n request_name TEXT,\n summary_passed INT NOT NULL DEFAULT 0,\n summary_failed INT NOT NULL DEFAULT 0,\n summary_skipped INT NOT NULL DEFAULT 0,\n payload TEXT NOT NULL,\n created_at TIMESTAMPTZ NOT NULL,\n created_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL\n);\nCREATE INDEX IF NOT EXISTS run_results_created_idx ON run_results (created_at DESC);\n`.trim();\n\n/**\n * Ordered Postgres migrations applied by {@link PostgresDatabase.migrate}.\n */\nexport const POSTGRES_MIGRATIONS = [\n USERS_MIGRATION_SQL,\n API_TOKENS_MIGRATION_SQL,\n COLLECTIONS_MIGRATION_SQL,\n ENVIRONMENTS_MIGRATION_SQL,\n SNIPPETS_MIGRATION_SQL,\n FOLDERS_MIGRATION_SQL,\n REQUESTS_MIGRATION_SQL,\n AUDIT_LOG_MIGRATION_SQL,\n API_TOKENS_USER_ID_MIGRATION_SQL,\n API_TOKENS_ATTRIBUTION_MIGRATION_SQL,\n COLLECTIONS_ATTRIBUTION_MIGRATION_SQL,\n ENVIRONMENTS_ATTRIBUTION_MIGRATION_SQL,\n FOLDERS_ATTRIBUTION_MIGRATION_SQL,\n REQUESTS_ATTRIBUTION_MIGRATION_SQL,\n USERS_ATTRIBUTION_MIGRATION_SQL,\n COLLECTIONS_BACKFILL_UPDATED_AT_SQL,\n ENVIRONMENTS_BACKFILL_UPDATED_AT_SQL,\n FOLDERS_BACKFILL_UPDATED_AT_SQL,\n USERS_LLM_MIGRATION_SQL,\n LLM_USAGE_MIGRATION_SQL,\n LLM_USAGE_LOG_MIGRATION_SQL,\n COLLECTIONS_DELETION_LOCKED_MIGRATION_SQL,\n ENVIRONMENTS_DELETION_LOCKED_MIGRATION_SQL,\n USERS_SNIPPET_ACCESS_MIGRATION_SQL,\n USERS_SNIPPET_ACCESS_BACKFILL_SQL,\n RUN_RESULTS_MIGRATION_SQL\n];\n","import { z } from 'zod/v4';\n\n/**\n * Zod schema for validating Postgres port values from server.yaml.\n */\nexport const portSchema = z.union([\n z\n .number()\n .int({ message: 'Postgres port must be an integer between 1 and 65535.' })\n .min(1, { message: 'Postgres port must be an integer between 1 and 65535.' })\n .max(65535, { message: 'Postgres port must be an integer between 1 and 65535.' }),\n z\n .string()\n .regex(/^\\d+$/, { message: 'Postgres port must be an integer between 1 and 65535.' })\n .transform(Number)\n .pipe(\n z\n .number()\n .int({ message: 'Postgres port must be an integer between 1 and 65535.' })\n .min(1, { message: 'Postgres port must be an integer between 1 and 65535.' })\n .max(65535, { message: 'Postgres port must be an integer between 1 and 65535.' })\n )\n]);\n\n/**\n * Zod schema for validating raw Postgres database config from server.yaml.\n */\nexport const postgresConfigSchema = z.object({\n driver: z.literal('postgres'),\n host: z.string().trim().min(1, { message: 'Postgres host must not be empty.' }),\n port: portSchema,\n user: z.string().trim().min(1, { message: 'Postgres user must not be empty.' }),\n password: z.string(),\n database: z.string().trim().min(1, { message: 'Postgres database must not be empty.' })\n});\n","import type { IDatabase } from '#/db/IDatabase.js';\nimport { FirestoreDatabase } from '#/db/firestore/FirestoreDatabase.js';\nimport { MysqlDatabase } from '#/db/mysql/MysqlDatabase.js';\nimport { PostgresDatabase } from '#/db/postgres/PostgresDatabase.js';\n\n/**\n * Reads the `driver` field from a raw db config mapping.\n *\n * @param config - Raw `db` section from server.yaml.\n * @returns Driver name when present and a string.\n * @throws {Error} When config is not a mapping or driver is missing.\n */\nfunction readDriver(config: unknown): string {\n if (config === null || typeof config !== 'object' || Array.isArray(config)) {\n throw new Error('Database config must be a mapping.');\n }\n\n const driver = (config as Record<string, unknown>).driver;\n if (typeof driver !== 'string' || driver.trim().length === 0) {\n throw new Error('Database config must include a non-empty db.driver.');\n }\n\n return driver;\n}\n\n/**\n * Creates a database instance from the raw `db` section of server.yaml.\n *\n * Each driver validates its own required fields via {@link FirestoreDatabase.fromConfig},\n * {@link MysqlDatabase.fromConfig}, or {@link PostgresDatabase.fromConfig}.\n *\n * @param config - Raw `db` section from server.yaml.\n * @returns Configured database implementation for the requested driver.\n * @throws {Error} When the driver is unknown or driver-specific validation fails.\n */\nexport function createDatabase(config: unknown): IDatabase {\n const driver = readDriver(config);\n\n switch (driver) {\n case 'firestore':\n return FirestoreDatabase.fromConfig(config);\n case 'mysql':\n return MysqlDatabase.fromConfig(config);\n case 'postgres':\n return PostgresDatabase.fromConfig(config);\n default:\n throw new Error(\n `Unsupported database driver \"${driver}\". Expected \"firestore\", \"mysql\", or \"postgres\".`\n );\n }\n}\n","import { Command } from 'commander';\nimport { mergeGlobalOptions } from '#/cli/globalOptions.js';\nimport { loadServerConfig } from '#/config/serverConfig.js';\nimport { createDatabase } from '#/db/index.js';\nimport type { CollectionRecord } from '#/db/types.js';\n\nexport interface CollectionCommandOptions {\n /**\n * Path to the server YAML config file (from global `-c` / `--config`).\n */\n config: string;\n}\n\n/**\n * Formats a stored user id for CLI attribution output.\n *\n * @param userId - User id from a record's attribution field, or null when unset.\n * @param usersById - Lookup map from user id to display name.\n * @returns Display name with id, raw id, or a dash placeholder.\n */\nfunction formatAttributionUser(userId: string | null, usersById: Map<string, string>): string {\n if (!userId) {\n return '-';\n }\n\n const name = usersById.get(userId);\n if (!name) {\n return userId;\n }\n\n return `${name} (${userId})`;\n}\n\n/**\n * Prints a collection record for CLI listings.\n *\n * @param collection - Collection record to display.\n * @param usersById - Lookup map from user id to display name.\n * @param requestCount - Number of saved requests in the collection.\n */\nfunction printCollection(\n collection: CollectionRecord,\n usersById: Map<string, string>,\n requestCount: number\n): void {\n console.log(`- id: ${collection.id}`);\n console.log(` name: ${collection.name}`);\n console.log(` requests: ${requestCount}`);\n console.log(` created: ${collection.createdAt.toISOString()}`);\n console.log(` updated: ${collection.updatedAt.toISOString()}`);\n console.log(` created by: ${formatAttributionUser(collection.createdByUserId, usersById)}`);\n console.log(` updated by: ${formatAttributionUser(collection.updatedByUserId, usersById)}`);\n}\n\n/**\n * Lists stored collections.\n *\n * @param options - Parsed collection list options including config path.\n */\nexport async function collectionListCommand(options: CollectionCommandOptions): Promise<void> {\n const config = loadServerConfig(options.config);\n const db = createDatabase(config.db);\n\n await db.connect();\n const collections = await db.listCollections();\n const users = await db.listUsers();\n const requestCounts = await Promise.all(\n collections.map(async (collection) => {\n const requests = await db.listRequests(collection.id);\n return [collection.id, requests.length] as const;\n })\n );\n await db.disconnect();\n\n const usersById = new Map(users.map((user) => [user.id, user.name]));\n const requestCountByCollectionId = new Map(requestCounts);\n\n if (collections.length === 0) {\n console.log('No collections found.');\n return;\n }\n\n for (const collection of collections) {\n printCollection(collection, usersById, requestCountByCollectionId.get(collection.id) ?? 0);\n }\n}\n\n/**\n * Registers the `collection` command group on a Commander program.\n *\n * @param program - Root or parent Commander instance.\n * @param handlers - Injectable handlers for testing.\n */\nexport function registerCollectionCommand(\n program: Command,\n handlers: {\n list?: (options: CollectionCommandOptions) => Promise<void>;\n } = {}\n): void {\n const collection = program.command('collection').description('Inspect stored collections');\n\n collection\n .command('list')\n .description('List stored collections')\n .action(\n /**\n * Runs the collection list subcommand after merging global CLI options.\n */\n async function collectionListAction(this: Command, options: CollectionCommandOptions) {\n await (handlers.list ?? collectionListCommand)(mergeGlobalOptions(this, options));\n }\n );\n}\n","import { Command } from 'commander';\nimport { mergeGlobalOptions } from '#/cli/globalOptions.js';\nimport { loadServerConfig } from '#/config/serverConfig.js';\nimport { createDatabase } from '#/db/index.js';\nimport type { LlmUsageLogRecord } from '#/db/types.js';\n\nexport interface LlmCommandOptions {\n /**\n * Path to the server YAML config file (from global `-c` / `--config`).\n */\n config: string;\n}\n\n/**\n * Formats a stored user id for CLI attribution output.\n *\n * @param userId - User id from a usage log row.\n * @param usersById - Lookup map from user id to display name.\n * @returns Display name with id, raw id, or a dash placeholder.\n */\nfunction formatUserLabel(userId: string, usersById: Map<string, string>): string {\n const name = usersById.get(userId);\n if (!name) {\n return userId;\n }\n\n return `${name} (${userId})`;\n}\n\n/**\n * Formats an API token id for CLI output.\n *\n * @param apiTokenId - Token id from a usage log row, or null when unset.\n * @param tokensById - Lookup map from token id to display name.\n * @returns Token name with id, raw id, or a dash placeholder.\n */\nfunction formatApiTokenLabel(apiTokenId: string | null, tokensById: Map<string, string>): string {\n if (!apiTokenId) {\n return '-';\n }\n\n const name = tokensById.get(apiTokenId);\n if (!name) {\n return apiTokenId;\n }\n\n return `${name} (${apiTokenId})`;\n}\n\n/**\n * Prints one per-request LLM usage log entry.\n *\n * @param entry - Usage log record to display.\n * @param usersById - Lookup map from user id to display name.\n * @param tokensById - Lookup map from token id to display name.\n */\nfunction printLlmUsageLog(\n entry: LlmUsageLogRecord,\n usersById: Map<string, string>,\n tokensById: Map<string, string>\n): void {\n console.log(`- id: ${entry.id}`);\n console.log(` user: ${formatUserLabel(entry.userId, usersById)}`);\n console.log(` api token: ${formatApiTokenLabel(entry.apiTokenId, tokensById)}`);\n console.log(` period: ${entry.period}`);\n console.log(` model: ${entry.model}`);\n console.log(` provider: ${entry.provider}`);\n console.log(` prompt tokens: ${entry.promptTokens}`);\n console.log(` completion tokens: ${entry.completionTokens}`);\n console.log(` total tokens: ${entry.totalTokens}`);\n console.log(` new turn: ${entry.isNewTurn ? 'yes' : 'no'}`);\n console.log(` tool calls: ${entry.hadToolCalls ? 'yes' : 'no'}`);\n console.log(` messages: ${entry.messageCount}`);\n console.log(` created: ${entry.createdAt.toISOString()}`);\n}\n\n/**\n * Lists all per-request LLM usage log entries.\n *\n * @param options - Parsed LLM list options including config path.\n */\nexport async function llmListCommand(options: LlmCommandOptions): Promise<void> {\n const config = loadServerConfig(options.config);\n const db = createDatabase(config.db);\n\n await db.connect();\n const entries = await db.listLlmUsageLogs();\n const users = await db.listUsers();\n const tokens = await db.listApiTokens();\n await db.disconnect();\n\n if (entries.length === 0) {\n console.log('No LLM usage records found.');\n return;\n }\n\n const usersById = new Map(users.map((user) => [user.id, user.name]));\n const tokensById = new Map(tokens.map((token) => [token.id, token.name]));\n\n for (const entry of entries) {\n printLlmUsageLog(entry, usersById, tokensById);\n }\n}\n\n/**\n * Registers the `llm` command group on a Commander program.\n *\n * @param program - Root or parent Commander instance.\n * @param handlers - Injectable handlers for testing.\n */\nexport function registerLlmCommand(\n program: Command,\n handlers: {\n list?: (options: LlmCommandOptions) => Promise<void>;\n } = {}\n): void {\n const llm = program.command('llm').description('Inspect LLM usage records');\n\n llm\n .command('list')\n .description('List all per-request LLM usage log entries')\n .action(\n /**\n * Runs the LLM list subcommand after merging global CLI options.\n */\n async function llmListAction(this: Command, options: LlmCommandOptions) {\n await (handlers.list ?? llmListCommand)(mergeGlobalOptions(this, options));\n }\n );\n}\n","import { Command } from 'commander';\nimport { mergeGlobalOptions } from '#/cli/globalOptions.js';\nimport { loadServerConfig } from '#/config/serverConfig.js';\nimport { createDatabase } from '#/db/index.js';\n\nexport interface MigrateCommandOptions {\n /**\n * Path to the server YAML config file (from global `-c` / `--config`).\n */\n config: string;\n}\n\n/**\n * Runs database schema migrations for the configured backend.\n *\n * @param options - Parsed migrate command options including config path.\n */\nexport async function migrateCommand(options: MigrateCommandOptions): Promise<void> {\n const config = loadServerConfig(options.config);\n const db = createDatabase(config.db);\n\n await db.connect();\n await db.migrate();\n await db.disconnect();\n\n console.log('Database migration completed successfully.');\n}\n\n/**\n * Registers the `migrate` subcommand on a Commander program.\n *\n * @param program - Root or parent Commander instance.\n * @param handler - Action to run when `migrate` is invoked (defaults to {@link migrateCommand}).\n */\nexport function registerMigrateCommand(\n program: Command,\n handler: (options: MigrateCommandOptions) => Promise<void> = migrateCommand\n): void {\n program\n .command('migrate')\n .description('Apply database schema migrations')\n .action(\n /**\n * Runs the migrate subcommand after merging global CLI options.\n */\n async function migrateAction(this: Command, options: MigrateCommandOptions) {\n await handler(mergeGlobalOptions(this, options));\n }\n );\n}\n","import { Command, InvalidArgumentError } from 'commander';\nimport { mergeGlobalOptions } from '#/cli/globalOptions.js';\nimport { loadServerConfig } from '#/config/serverConfig.js';\nimport type { LlmConfig } from '#/config/llmConfig.js';\nimport { createDatabase } from '#/db/index.js';\nimport type { ApiTokenRecord, UpdateUserInput, UserRole } from '#/db/types.js';\nimport { generateApiToken } from '#/server/auth/apiTokens.js';\nimport {\n buildAccessCatalogIds,\n buildAccessListWarnings,\n normalizeAccessForRole,\n normalizeLlmForRole,\n ValidationError,\n validateSubmittedAccessLists\n} from '#/server/admin/userValidation.js';\nimport { currentUsagePeriod, listHubOfferedModels } from '#/server/llm/models.js';\nimport type { IDatabase } from '#/db/IDatabase.js';\n\n/**\n * Ensures schema migrations ran and returns the internal system user id for CLI actions.\n *\n * @param db - Connected database instance.\n * @returns Stable system user identifier.\n * @throws {Error} When the system user cannot be provisioned.\n */\nasync function requireSystemUserId(db: IDatabase): Promise<string> {\n await db.migrate();\n const systemUserId = db.getSystemUserId();\n if (!systemUserId) {\n throw new Error('System user is not provisioned.');\n }\n\n return systemUserId;\n}\n\nexport interface UserCommandOptions {\n /**\n * Path to the server YAML config file (from global `-c` / `--config`).\n */\n config: string;\n}\n\nexport interface UserCreateCommandOptions extends UserCommandOptions {\n /**\n * Unique display name for the new user account.\n */\n name: string;\n\n /**\n * Role assigned to the new account.\n */\n role: UserRole;\n\n /**\n * Collection ids or `*` granting collection access.\n */\n collectionAccess: string[];\n\n /**\n * Environment ids or `*` granting environment access.\n */\n environmentAccess: string[];\n\n /**\n * Snippet ids or `*` granting snippet access.\n */\n snippetAccess: string[];\n\n /**\n * Whether the user may use hub-proxied LLM routes.\n */\n llmAccess?: boolean;\n\n /**\n * LLM model ids or `*` granting model access.\n */\n llmModels?: string[];\n\n /**\n * Monthly LLM token limit, or undefined for unlimited.\n */\n llmMonthlyTokens?: number;\n}\n\nexport interface UserUpdateCommandOptions extends UserCommandOptions {\n /**\n * Identifier of the user to update.\n */\n id: string;\n\n /**\n * New display name, when changing the account label.\n */\n name?: string;\n\n /**\n * New role, when changing account capabilities.\n */\n role?: UserRole;\n\n /**\n * Replacement collection access list.\n */\n collectionAccess?: string[];\n\n /**\n * Replacement environment access list.\n */\n environmentAccess?: string[];\n\n /**\n * Replacement snippet access list.\n */\n snippetAccess?: string[];\n\n /**\n * Whether the user may use hub-proxied LLM routes.\n */\n llmAccess?: boolean;\n\n /**\n * Replacement LLM model access list.\n */\n llmModels?: string[];\n\n /**\n * Replacement monthly LLM token limit.\n */\n llmMonthlyTokens?: number;\n}\n\nexport interface UserTokenCreateCommandOptions extends UserCommandOptions {\n /**\n * Owning user identifier.\n */\n user: string;\n\n /**\n * Human-readable label for the new token.\n */\n name: string;\n}\n\nexport interface UserTokenListCommandOptions extends UserCommandOptions {\n /**\n * Optional user identifier limiting token output.\n */\n user?: string;\n}\n\nexport interface UserTokenRevokeCommandOptions extends UserCommandOptions {\n /**\n * Identifier of the token to revoke.\n */\n id: string;\n}\n\n/**\n * Formats a nullable date for CLI output.\n *\n * @param value - Date to format, or null when unset.\n * @returns ISO string or a dash placeholder.\n */\nfunction formatOptionalDate(value: Date | null): string {\n return value ? value.toISOString() : '-';\n}\n\n/**\n * Formats an access list for CLI output.\n *\n * @param access - Collection or environment access ids.\n * @returns Comma-separated list or a dash when empty.\n */\nfunction formatAccessList(access: string[]): string {\n return access.length > 0 ? access.join(', ') : '-';\n}\n\n/**\n * Parses and validates a user or token name from CLI input.\n *\n * @param value - Name string from a Commander option or argument.\n * @returns Trimmed non-empty name.\n * @throws {InvalidArgumentError} When the name is empty after trimming.\n */\nfunction parseRequiredName(value: string): string {\n const name = value.trim();\n if (!name) {\n throw new InvalidArgumentError('Name must not be empty.');\n }\n\n return name;\n}\n\n/**\n * Parses a user role from CLI input.\n *\n * @param value - Role string from a Commander option.\n * @returns Validated user role.\n * @throws {InvalidArgumentError} When the role is not supported.\n */\nfunction parseUserRole(value: string): UserRole {\n const role = value.trim();\n if (role === 'admin' || role === 'user') {\n return role;\n }\n\n throw new InvalidArgumentError('Role must be \"admin\" or \"user\".');\n}\n\n/**\n * Parses repeated access flags into a normalized access list.\n *\n * @param _value - Current flag value (unused; Commander passes prior values).\n * @param previous - Accumulated values from earlier `--flag` occurrences.\n * @returns Updated access list including the latest parsed entry.\n * @throws {InvalidArgumentError} When wildcard access is combined with ids.\n */\nfunction parseAccessFlag(_value: string, previous: string[]): string[] {\n const entry = _value.trim();\n if (!entry) {\n throw new InvalidArgumentError('Access entries must not be empty.');\n }\n\n const next = [...previous, entry];\n if (next.includes('*') && next.length > 1) {\n throw new InvalidArgumentError('Wildcard access \"*\" must be the only entry.');\n }\n\n return next;\n}\n\n/**\n * Reads LLM model access ids from parsed Commander create/update options.\n *\n * Commander maps `--llm-model` to the `llmModel` property rather than `llmModels`.\n *\n * @param options - Parsed options that may include either property name.\n */\nfunction readLlmModelsOption(options: { llmModels?: string[]; llmModel?: string[] }): string[] {\n return options.llmModels ?? options.llmModel ?? [];\n}\n\n/**\n * Parses a positive integer token limit from CLI input.\n *\n * @param value - Token limit string from a Commander option.\n * @returns Parsed positive integer limit.\n * @throws {InvalidArgumentError} When the value is not a positive integer.\n */\nfunction parseMonthlyTokenLimit(value: string): number {\n const parsed = Number(value.trim());\n if (!Number.isInteger(parsed) || parsed <= 0) {\n throw new InvalidArgumentError('Monthly token limit must be a positive integer.');\n }\n\n return parsed;\n}\n\n/**\n * Optional monthly LLM usage fields for CLI user listings.\n */\ninterface UserDisplayUsage {\n /**\n * UTC calendar month key (`YYYY-MM`) for the usage total.\n */\n llmUsagePeriod: string;\n\n /**\n * Total tokens consumed during {@link UserDisplayUsage.llmUsagePeriod}.\n */\n llmTokensUsed: number;\n}\n\n/**\n * Prints a user record for CLI listings.\n *\n * @param user - User record to display.\n * @param usage - Current-month LLM usage when listing or showing users.\n */\nfunction printUser(\n user: {\n id: string;\n name: string;\n role: UserRole;\n collectionAccess: string[];\n environmentAccess: string[];\n snippetAccess: string[];\n llmAccess: boolean;\n llmModels: string[];\n llmMonthlyTokenLimit: number | null;\n createdAt: Date;\n updatedAt: Date;\n },\n usage?: UserDisplayUsage\n): void {\n console.log(`- id: ${user.id}`);\n console.log(` name: ${user.name}`);\n console.log(` role: ${user.role}`);\n console.log(` collection access: ${formatAccessList(user.collectionAccess)}`);\n console.log(` environment access: ${formatAccessList(user.environmentAccess)}`);\n console.log(` snippet access: ${formatAccessList(user.snippetAccess)}`);\n console.log(` llm access: ${user.llmAccess ? 'enabled' : 'disabled'}`);\n console.log(` llm models: ${formatAccessList(user.llmModels)}`);\n console.log(\n ` llm monthly tokens: ${user.llmMonthlyTokenLimit != null ? user.llmMonthlyTokenLimit : 'unlimited'}`\n );\n if (usage) {\n console.log(` llm tokens used (${usage.llmUsagePeriod}): ${usage.llmTokensUsed}`);\n }\n console.log(` created: ${user.createdAt.toISOString()}`);\n console.log(` updated: ${user.updatedAt.toISOString()}`);\n}\n\n/**\n * Prints a newly created API token and its one-time secret for CLI output.\n *\n * @param user - Owning user account.\n * @param record - Persisted token metadata (hash only).\n * @param secret - Plaintext bearer token shown once at creation.\n */\nfunction printCreatedApiToken(\n user: { name: string },\n record: ApiTokenRecord,\n secret: string\n): void {\n console.log(`Created API token \"${record.name}\" (${record.id}) for user \"${user.name}\".`);\n console.log(`Token prefix: ${record.tokenPrefix}`);\n console.log('');\n console.log('Store this token now; it will not be shown again:');\n console.log(secret);\n}\n\n/**\n * Loads hub resource catalogs used to validate and warn on access lists.\n *\n * @param db - Connected database instance.\n * @param llm - Normalized LLM config from server.yaml, or null when unset.\n * @returns Known collection, environment, and LLM model ids.\n */\nasync function loadAccessCatalogs(db: IDatabase, llm: LlmConfig | null) {\n const [collections, environments, snippets] = await Promise.all([\n db.listCollections(),\n db.listEnvironments(),\n db.listSnippets()\n ]);\n\n return buildAccessCatalogIds(\n collections,\n environments,\n snippets,\n llm ? listHubOfferedModels(llm).map((model) => model.id) : null\n );\n}\n\n/**\n * Runs a validation helper and maps {@link ValidationError} to Commander errors.\n *\n * @param fn - Validation or normalization function from the server admin module.\n * @returns The value returned by {@link fn}.\n * @throws {InvalidArgumentError} When {@link fn} throws {@link ValidationError}.\n */\nfunction mapValidationError<T>(fn: () => T): T {\n try {\n return fn();\n } catch (error) {\n if (error instanceof ValidationError) {\n throw new InvalidArgumentError(error.message);\n }\n\n throw error;\n }\n}\n\n/**\n * Validates submitted access lists and maps server validation errors to CLI errors.\n *\n * @param submitted - Access fields provided on the CLI command.\n * @param catalogs - Known collection, environment, and LLM model ids.\n * @throws {InvalidArgumentError} When a submitted list references unknown ids.\n */\nfunction validateSubmittedAccessListsOrThrow(\n submitted: Parameters<typeof validateSubmittedAccessLists>[0],\n catalogs: Parameters<typeof validateSubmittedAccessLists>[1]\n): void {\n mapValidationError(() => validateSubmittedAccessLists(submitted, catalogs));\n}\n\n/**\n * Prints stale access list warnings to stderr without changing stdout listings.\n *\n * @param warnings - Human-readable warnings for unknown access ids.\n */\nfunction printAccessListWarnings(warnings: string[]): void {\n for (const warning of warnings) {\n console.warn(`Warning: ${warning}`);\n }\n}\n\n/**\n * Creates a new user account.\n *\n * @param options - Parsed user create options.\n */\nexport async function userCreateCommand(options: UserCreateCommandOptions): Promise<void> {\n const config = loadServerConfig(options.config);\n const db = createDatabase(config.db);\n const access = mapValidationError(() =>\n normalizeAccessForRole(\n options.role,\n options.collectionAccess,\n options.environmentAccess,\n options.snippetAccess\n )\n );\n\n await db.connect();\n const actingUserId = await requireSystemUserId(db);\n const catalogs = await loadAccessCatalogs(db, config.llm);\n const llmModels = readLlmModelsOption(options);\n const llm = mapValidationError(() =>\n normalizeLlmForRole(options.role, options.llmAccess ?? false, llmModels)\n );\n validateSubmittedAccessListsOrThrow(\n {\n role: options.role,\n collectionAccess: access.collectionAccess,\n environmentAccess: access.environmentAccess,\n snippetAccess: access.snippetAccess,\n llmModels\n },\n catalogs\n );\n\n const user = await db.createUser(\n {\n name: options.name,\n role: options.role,\n collectionAccess: access.collectionAccess ?? [],\n environmentAccess: access.environmentAccess ?? [],\n snippetAccess: access.snippetAccess ?? [],\n llmAccess: llm.llmAccess,\n llmModels: llm.llmModels,\n llmMonthlyTokenLimit: options.llmMonthlyTokens ?? null\n },\n actingUserId\n );\n const { record, secret } = generateApiToken(user.id, user.name);\n await db.createApiToken(record, actingUserId);\n await db.disconnect();\n\n console.log(`Created user \"${user.name}\" (${user.id}) with role ${user.role}.`);\n printUser(user);\n console.log('');\n printCreatedApiToken(user, record, secret);\n}\n\n/**\n * Lists stored user accounts.\n *\n * @param options - Parsed user list options including config path.\n */\nexport async function userListCommand(options: UserCommandOptions): Promise<void> {\n const config = loadServerConfig(options.config);\n const db = createDatabase(config.db);\n\n await db.connect();\n const [users, catalogs] = await Promise.all([db.listUsers(), loadAccessCatalogs(db, config.llm)]);\n const period = currentUsagePeriod();\n const tokensUsedByUser = await Promise.all(\n users.map(async (user) => {\n const usage = await db.getLlmUsage(user.id, period);\n return usage?.totalTokens ?? 0;\n })\n );\n await db.disconnect();\n\n if (users.length === 0) {\n console.log('No users found.');\n return;\n }\n\n for (const [index, user] of users.entries()) {\n printAccessListWarnings(\n buildAccessListWarnings(\n {\n collectionAccess: user.collectionAccess,\n environmentAccess: user.environmentAccess,\n snippetAccess: user.snippetAccess,\n llmModels: user.llmModels\n },\n catalogs\n )\n );\n printUser(user, { llmUsagePeriod: period, llmTokensUsed: tokensUsedByUser[index] ?? 0 });\n }\n}\n\n/**\n * Shows a single user account by id.\n *\n * @param options - Parsed user show options including user id.\n */\nexport async function userShowCommand(options: UserUpdateCommandOptions): Promise<void> {\n const config = loadServerConfig(options.config);\n const db = createDatabase(config.db);\n\n await db.connect();\n const [user, catalogs] = await Promise.all([\n db.findUserById(options.id),\n loadAccessCatalogs(db, config.llm)\n ]);\n\n if (!user) {\n await db.disconnect();\n console.log(`No user found with id ${options.id}.`);\n return;\n }\n\n const period = currentUsagePeriod();\n const usage = await db.getLlmUsage(user.id, period);\n await db.disconnect();\n\n printAccessListWarnings(\n buildAccessListWarnings(\n {\n collectionAccess: user.collectionAccess,\n environmentAccess: user.environmentAccess,\n snippetAccess: user.snippetAccess,\n llmModels: user.llmModels\n },\n catalogs\n )\n );\n printUser(user, { llmUsagePeriod: period, llmTokensUsed: usage?.totalTokens ?? 0 });\n}\n\n/**\n * Updates an existing user account.\n *\n * @param options - Parsed user update options.\n */\nexport async function userUpdateCommand(options: UserUpdateCommandOptions): Promise<void> {\n const config = loadServerConfig(options.config);\n const db = createDatabase(config.db);\n\n await db.connect();\n const actingUserId = await requireSystemUserId(db);\n const existing = await db.findUserById(options.id);\n if (!existing) {\n await db.disconnect();\n console.log(`No user found with id ${options.id}.`);\n return;\n }\n\n const role = options.role ?? existing.role;\n const collectionAccess =\n options.collectionAccess ?? (options.role === 'admin' ? [] : existing.collectionAccess);\n const environmentAccess =\n options.environmentAccess ?? (options.role === 'admin' ? [] : existing.environmentAccess);\n const snippetAccess =\n options.snippetAccess ?? (options.role === 'admin' ? [] : existing.snippetAccess);\n const access = mapValidationError(() =>\n normalizeAccessForRole(role, collectionAccess, environmentAccess, snippetAccess)\n );\n const llmAccess = role === 'admin' ? false : (options.llmAccess ?? existing.llmAccess);\n const llmModels = role === 'admin' ? [] : (options.llmModels ?? existing.llmModels);\n const llm = mapValidationError(() => normalizeLlmForRole(role, llmAccess, llmModels));\n const catalogs = await loadAccessCatalogs(db, config.llm);\n validateSubmittedAccessListsOrThrow(\n {\n role,\n collectionAccess: options.collectionAccess,\n environmentAccess: options.environmentAccess,\n snippetAccess: options.snippetAccess,\n llmModels: options.llmModels\n },\n catalogs\n );\n\n const input: UpdateUserInput = {\n name: options.name,\n role: options.role,\n collectionAccess: access.collectionAccess,\n environmentAccess: access.environmentAccess,\n snippetAccess: access.snippetAccess,\n llmAccess: llm.llmAccess,\n llmModels: llm.llmModels,\n llmMonthlyTokenLimit:\n options.llmMonthlyTokens !== undefined ? options.llmMonthlyTokens : undefined\n };\n\n const user = await db.updateUser(options.id, input, actingUserId);\n await db.disconnect();\n\n console.log(`Updated user \"${user.name}\" (${user.id}).`);\n}\n\n/**\n * Deletes a user account and revokes their tokens.\n *\n * @param options - Parsed user delete options including user id.\n */\nexport async function userDeleteCommand(options: UserUpdateCommandOptions): Promise<void> {\n const config = loadServerConfig(options.config);\n const db = createDatabase(config.db);\n\n await db.connect();\n const actingUserId = await requireSystemUserId(db);\n const existing = await db.findUserById(options.id);\n if (!existing) {\n await db.disconnect();\n console.log(`No user found with id ${options.id}.`);\n return;\n }\n\n await db.deleteUser(options.id, actingUserId);\n await db.disconnect();\n\n console.log(`Deleted user \"${existing.name}\" (${existing.id}).`);\n}\n\n/**\n * Creates a new API token for a user-role account.\n *\n * @param options - Parsed token create options.\n */\nexport async function userTokenCreateCommand(\n options: UserTokenCreateCommandOptions\n): Promise<void> {\n const config = loadServerConfig(options.config);\n const db = createDatabase(config.db);\n\n await db.connect();\n const actingUserId = await requireSystemUserId(db);\n const user = await db.findUserById(options.user);\n if (!user) {\n await db.disconnect();\n throw new Error(`No user found with id ${options.user}.`);\n }\n\n const { record, secret } = generateApiToken(user.id, options.name);\n await db.createApiToken(record, actingUserId);\n await db.disconnect();\n\n printCreatedApiToken(user, record, secret);\n}\n\n/**\n * Lists stored API tokens, optionally filtered by user.\n *\n * @param options - Parsed token list options.\n */\nexport async function userTokenListCommand(options: UserTokenListCommandOptions): Promise<void> {\n const config = loadServerConfig(options.config);\n const db = createDatabase(config.db);\n\n await db.connect();\n const tokens = options.user\n ? await db.listApiTokensByUserId(options.user)\n : await db.listApiTokens();\n await db.disconnect();\n\n if (tokens.length === 0) {\n console.log('No API tokens found.');\n return;\n }\n\n for (const token of tokens) {\n console.log(`- id: ${token.id}`);\n console.log(` user id: ${token.userId}`);\n console.log(` name: ${token.name}`);\n console.log(` prefix: ${token.tokenPrefix}`);\n console.log(` created: ${formatOptionalDate(token.createdAt)}`);\n console.log(` last used: ${formatOptionalDate(token.lastUsedAt)}`);\n console.log(` revoked: ${formatOptionalDate(token.revokedAt)}`);\n }\n}\n\n/**\n * Soft-revokes an API token by id.\n *\n * @param options - Parsed token revoke options including token id.\n */\nexport async function userTokenRevokeCommand(\n options: UserTokenRevokeCommandOptions\n): Promise<void> {\n const config = loadServerConfig(options.config);\n const db = createDatabase(config.db);\n\n await db.connect();\n const actingUserId = await requireSystemUserId(db);\n const revoked = await db.revokeApiToken(options.id, actingUserId);\n await db.disconnect();\n\n if (revoked) {\n console.log(`Revoked API token ${options.id}.`);\n return;\n }\n\n console.log(`No active API token found with id ${options.id}.`);\n}\n\n/**\n * Registers the `user` command group on a Commander program.\n *\n * @param program - Root or parent Commander instance.\n * @param handlers - Injectable handlers for testing.\n */\nexport function registerUserCommand(\n program: Command,\n handlers: {\n create?: (options: UserCreateCommandOptions) => Promise<void>;\n list?: (options: UserCommandOptions) => Promise<void>;\n show?: (options: UserUpdateCommandOptions) => Promise<void>;\n update?: (options: UserUpdateCommandOptions) => Promise<void>;\n delete?: (options: UserUpdateCommandOptions) => Promise<void>;\n tokenCreate?: (options: UserTokenCreateCommandOptions) => Promise<void>;\n tokenList?: (options: UserTokenListCommandOptions) => Promise<void>;\n tokenRevoke?: (options: UserTokenRevokeCommandOptions) => Promise<void>;\n } = {}\n): void {\n const user = program.command('user').description('Manage user accounts and their API tokens');\n\n user\n .command('create')\n .description('Create a new user account')\n .requiredOption('--name <name>', 'Unique display name', parseRequiredName)\n .requiredOption('--role <role>', 'Account role (admin or user)', parseUserRole)\n .option(\n '--collection-access <id>',\n 'Collection id or * (repeatable)',\n parseAccessFlag,\n [] as string[]\n )\n .option(\n '--environment-access <id>',\n 'Environment id or * (repeatable)',\n parseAccessFlag,\n [] as string[]\n )\n .option(\n '--snippet-access <id>',\n 'Snippet id or * (repeatable)',\n parseAccessFlag,\n [] as string[]\n )\n .option('--llm-access', 'Enable hub-proxied LLM access for the user')\n .option('--llm-model <id>', 'LLM model id or * (repeatable)', parseAccessFlag, [] as string[])\n .option('--llm-monthly-tokens <count>', 'Monthly LLM token limit', parseMonthlyTokenLimit)\n .action(\n /**\n * Runs the user create subcommand after merging global CLI options.\n */\n async function userCreateAction(this: Command, options: UserCreateCommandOptions) {\n await (handlers.create ?? userCreateCommand)(mergeGlobalOptions(this, options));\n }\n );\n\n user\n .command('list')\n .description('List stored user accounts')\n .action(\n /**\n * Runs the user list subcommand after merging global CLI options.\n */\n async function userListAction(this: Command, options: UserCommandOptions) {\n await (handlers.list ?? userListCommand)(mergeGlobalOptions(this, options));\n }\n );\n\n user\n .command('show')\n .description('Show a user account by id')\n .argument('<id>', 'User identifier')\n .action(\n /**\n * Runs the user show subcommand after merging global CLI options.\n */\n async function userShowAction(this: Command, id: string, options: UserCommandOptions) {\n await (handlers.show ?? userShowCommand)(mergeGlobalOptions(this, { ...options, id }));\n }\n );\n\n user\n .command('update')\n .description('Update a user account')\n .argument('<id>', 'User identifier')\n .option('--name <name>', 'New display name', parseRequiredName)\n .option('--role <role>', 'New role (admin or user)', parseUserRole)\n .option(\n '--collection-access <id>',\n 'Replacement collection id or * (repeatable)',\n parseAccessFlag,\n [] as string[]\n )\n .option(\n '--environment-access <id>',\n 'Replacement environment id or * (repeatable)',\n parseAccessFlag,\n [] as string[]\n )\n .option(\n '--snippet-access <id>',\n 'Replacement snippet id or * (repeatable)',\n parseAccessFlag,\n [] as string[]\n )\n .option('--llm-access', 'Enable hub-proxied LLM access for the user')\n .option('--no-llm-access', 'Disable hub-proxied LLM access for the user')\n .option(\n '--llm-model <id>',\n 'Replacement LLM model id or * (repeatable)',\n parseAccessFlag,\n [] as string[]\n )\n .option('--llm-monthly-tokens <count>', 'Monthly LLM token limit', parseMonthlyTokenLimit)\n .action(\n /**\n * Runs the user update subcommand after merging global CLI options.\n */\n async function userUpdateAction(\n this: Command,\n id: string,\n options: UserUpdateCommandOptions\n ) {\n const merged = mergeGlobalOptions(this, { ...options, id });\n const input: UserUpdateCommandOptions = {\n ...merged,\n collectionAccess:\n (options.collectionAccess ?? []).length > 0 ? options.collectionAccess : undefined,\n environmentAccess:\n (options.environmentAccess ?? []).length > 0 ? options.environmentAccess : undefined,\n snippetAccess:\n (options.snippetAccess ?? []).length > 0 ? options.snippetAccess : undefined,\n llmModels: (() => {\n const llmModels = readLlmModelsOption(options);\n return llmModels.length > 0 ? llmModels : undefined;\n })()\n };\n await (handlers.update ?? userUpdateCommand)(input);\n }\n );\n\n user\n .command('delete')\n .description('Delete a user account and revoke their tokens')\n .argument('<id>', 'User identifier')\n .action(\n /**\n * Runs the user delete subcommand after merging global CLI options.\n */\n async function userDeleteAction(this: Command, id: string, options: UserCommandOptions) {\n await (handlers.delete ?? userDeleteCommand)(mergeGlobalOptions(this, { ...options, id }));\n }\n );\n\n const token = user.command('token').description('Manage API bearer tokens for user accounts');\n\n token\n .command('create')\n .description('Create a new API bearer token for a user')\n .requiredOption('--user <userId>', 'Owning user identifier')\n .requiredOption('--name <name>', 'Human-readable token label', parseRequiredName)\n .action(\n /**\n * Runs the user token create subcommand after merging global CLI options.\n */\n async function userTokenCreateAction(this: Command, options: UserTokenCreateCommandOptions) {\n await (handlers.tokenCreate ?? userTokenCreateCommand)(mergeGlobalOptions(this, options));\n }\n );\n\n token\n .command('list')\n .description('List stored API bearer tokens')\n .option('--user <userId>', 'Limit output to a single user')\n .action(\n /**\n * Runs the user token list subcommand after merging global CLI options.\n */\n async function userTokenListAction(this: Command, options: UserTokenListCommandOptions) {\n await (handlers.tokenList ?? userTokenListCommand)(mergeGlobalOptions(this, options));\n }\n );\n\n token\n .command('revoke')\n .description('Revoke an API bearer token by id')\n .argument('<id>', 'Token identifier to revoke')\n .action(\n /**\n * Runs the user token revoke subcommand after merging global CLI options.\n */\n async function userTokenRevokeAction(this: Command, id: string, options: UserCommandOptions) {\n await (handlers.tokenRevoke ?? userTokenRevokeCommand)(\n mergeGlobalOptions(this, { ...options, id })\n );\n }\n );\n}\n","import { createHash, randomBytes, randomUUID } from 'node:crypto';\nimport type { ApiTokenRecord } from '#/db/types.js';\n\n/**\n * Prefix applied to generated bearer token secrets and display prefixes.\n */\nconst TOKEN_PREFIX = 'hbk_';\n\n/**\n * Computes the sha256 hex digest used for database lookup of a bearer token.\n *\n * @param token - Raw bearer token secret from the Authorization header.\n * @returns Lowercase hex digest suitable for storage and lookup.\n */\nexport function hashToken(token: string): string {\n return createHash('sha256').update(token).digest('hex');\n}\n\n/**\n * Generates a new API token record and its one-time plaintext secret.\n *\n * @param userId - Owning user account identifier.\n * @param name - Human-readable label for operator listings.\n * @returns Persistable record (hash only) and the secret shown once at creation.\n */\nexport function generateApiToken(\n userId: string,\n name: string\n): { record: ApiTokenRecord; secret: string } {\n const secretSuffix = randomBytes(32).toString('base64url');\n const secret = `${TOKEN_PREFIX}${secretSuffix}`;\n const tokenPrefix = `${TOKEN_PREFIX}${secretSuffix.slice(0, 8)}`;\n const createdAt = new Date();\n\n const record: ApiTokenRecord = {\n id: randomUUID(),\n userId,\n name,\n tokenHash: hashToken(secret),\n tokenPrefix,\n createdAt,\n lastUsedAt: null,\n revokedAt: null,\n createdByUserId: null,\n updatedByUserId: null\n };\n\n return { record, secret };\n}\n\n/**\n * Extracts the bearer token value from an Authorization header.\n *\n * @param headerValue - Raw Authorization header value, if present.\n * @returns Token string after the `Bearer` scheme, or null when missing or malformed.\n */\nexport function extractBearer(headerValue?: string): string | null {\n if (!headerValue) {\n return null;\n }\n\n const match = /^Bearer\\s+(\\S+)$/i.exec(headerValue.trim());\n return match?.[1] ?? null;\n}\n","import type { CreateUserInput, UpdateUserInput, UserRole } from '#/db/types.js';\n\n/**\n * Error thrown when admin user update input fails validation.\n */\nexport class ValidationError extends Error {\n /**\n * Creates a validation error with a client-facing message.\n *\n * @param message - Description of the invalid input.\n */\n constructor(message: string) {\n super(message);\n this.name = 'ValidationError';\n }\n}\n\n/**\n * Returns true when an access list mixes the wildcard with specific ids.\n *\n * @param access - Collection, environment, snippet, or LLM model access ids.\n * @returns True when the list is invalid.\n */\nexport function hasInvalidWildcardAccess(access: string[]): boolean {\n return access.includes('*') && access.length > 1;\n}\n\n/**\n * Validates a single access list for wildcard usage.\n *\n * @param access - Collection, environment, snippet, or LLM model access ids.\n * @throws {ValidationError} When wildcard access is combined with specific ids.\n */\nexport function validateAccessList(access: string[]): void {\n if (hasInvalidWildcardAccess(access)) {\n throw new ValidationError('Wildcard access \"*\" must be the only entry.');\n }\n}\n\n/**\n * Normalizes LLM access for admin accounts and validates model access lists.\n *\n * @param role - Target user role.\n * @param llmAccess - Parsed LLM access flag.\n * @param llmModels - Parsed LLM model access ids.\n * @returns LLM fields suitable for persistence.\n * @throws {ValidationError} When admins receive LLM access or lists are invalid.\n */\nexport function normalizeLlmForRole(\n role: UserRole,\n llmAccess: boolean,\n llmModels: string[]\n): Pick<UpdateUserInput, 'llmAccess' | 'llmModels'> {\n if (role === 'admin') {\n if (llmAccess || llmModels.length > 0) {\n throw new ValidationError('Admin users cannot have LLM access.');\n }\n\n return {\n llmAccess: false,\n llmModels: []\n };\n }\n\n validateAccessList(llmModels);\n\n return {\n llmAccess,\n llmModels\n };\n}\n\n/**\n * Normalizes access lists for admin accounts and validates wildcard usage.\n *\n * @param role - Target user role.\n * @param collectionAccess - Parsed collection access ids.\n * @param environmentAccess - Parsed environment access ids.\n * @param snippetAccess - Parsed snippet access ids.\n * @returns Access lists suitable for persistence.\n * @throws {ValidationError} When admins receive access flags or lists are invalid.\n */\nexport function normalizeAccessForRole(\n role: UserRole,\n collectionAccess: string[],\n environmentAccess: string[],\n snippetAccess: string[]\n): Pick<UpdateUserInput, 'collectionAccess' | 'environmentAccess' | 'snippetAccess'> {\n if (role === 'admin') {\n if (collectionAccess.length > 0 || environmentAccess.length > 0 || snippetAccess.length > 0) {\n throw new ValidationError(\n 'Admin users cannot have collection, environment, or snippet access.'\n );\n }\n\n return {\n collectionAccess: [],\n environmentAccess: [],\n snippetAccess: []\n };\n }\n\n validateAccessList(collectionAccess);\n validateAccessList(environmentAccess);\n validateAccessList(snippetAccess);\n\n return {\n collectionAccess,\n environmentAccess,\n snippetAccess\n };\n}\n\n/**\n * Known resource ids used to validate or warn on access lists.\n */\nexport interface AccessCatalogIds {\n /**\n * Collection ids currently stored on the hub.\n */\n knownCollectionIds: ReadonlySet<string>;\n\n /**\n * Environment ids currently stored on the hub.\n */\n knownEnvironmentIds: ReadonlySet<string>;\n\n /**\n * Snippet ids currently stored on the hub.\n */\n knownSnippetIds: ReadonlySet<string>;\n\n /**\n * Hub-offered LLM model ids, or null when LLM support is not configured.\n */\n knownLlmModelIds: ReadonlySet<string> | null;\n}\n\n/**\n * Access list fields explicitly submitted in a create or update request.\n */\nexport interface SubmittedAccessLists {\n /**\n * Resulting user role after the update is applied.\n */\n role: UserRole;\n\n /**\n * Collection access ids from the request body or CLI flags, when provided.\n */\n collectionAccess?: string[];\n\n /**\n * Environment access ids from the request body or CLI flags, when provided.\n */\n environmentAccess?: string[];\n\n /**\n * Snippet access ids from the request body or CLI flags, when provided.\n */\n snippetAccess?: string[];\n\n /**\n * LLM model access ids from the request body or CLI flags, when provided.\n */\n llmModels?: string[];\n}\n\n/**\n * Stored access lists on a user record checked for stale references.\n */\nexport interface StoredAccessLists {\n /**\n * Persisted collection access ids.\n */\n collectionAccess: string[];\n\n /**\n * Persisted environment access ids.\n */\n environmentAccess: string[];\n\n /**\n * Persisted snippet access ids.\n */\n snippetAccess: string[];\n\n /**\n * Persisted LLM model access ids.\n */\n llmModels: string[];\n}\n\n/**\n * Returns ids from an access list that are not the wildcard and not in knownIds.\n *\n * @param access - Collection, environment, snippet, or LLM model access ids.\n * @param knownIds - Valid resource ids from the hub catalog.\n * @returns Unknown ids excluding the wildcard entry.\n */\nexport function findUnknownAccessIds(access: string[], knownIds: ReadonlySet<string>): string[] {\n return access.filter((id) => id !== '*' && !knownIds.has(id));\n}\n\n/**\n * Validates that every specific id in an access list exists in the catalog.\n *\n * @param access - Collection, environment, snippet, or LLM model access ids.\n * @param knownIds - Valid resource ids from the hub catalog.\n * @param resourceLabel - Singular resource label for error messages.\n * @throws {ValidationError} When one or more ids are unknown.\n */\nexport function validateKnownAccessIds(\n access: string[],\n knownIds: ReadonlySet<string>,\n resourceLabel: 'collection' | 'environment' | 'snippet' | 'LLM model'\n): void {\n const unknownIds = findUnknownAccessIds(access, knownIds);\n if (unknownIds.length === 0) {\n return;\n }\n\n const label = unknownIds.length === 1 ? `${resourceLabel} id` : `${resourceLabel} id(s)`;\n throw new ValidationError(`Unknown ${label}: ${unknownIds.join(', ')}.`);\n}\n\n/**\n * Validates explicitly submitted access lists against hub resource catalogs.\n *\n * @param submitted - Access fields provided in the request or CLI flags.\n * @param catalogs - Known collection, environment, snippet, and LLM model ids.\n * @throws {ValidationError} When a submitted list references unknown ids.\n */\nexport function validateSubmittedAccessLists(\n submitted: SubmittedAccessLists,\n catalogs: AccessCatalogIds\n): void {\n if (submitted.role !== 'admin') {\n if (submitted.collectionAccess !== undefined) {\n validateKnownAccessIds(submitted.collectionAccess, catalogs.knownCollectionIds, 'collection');\n }\n\n if (submitted.environmentAccess !== undefined) {\n validateKnownAccessIds(\n submitted.environmentAccess,\n catalogs.knownEnvironmentIds,\n 'environment'\n );\n }\n\n if (submitted.snippetAccess !== undefined) {\n validateKnownAccessIds(submitted.snippetAccess, catalogs.knownSnippetIds, 'snippet');\n }\n }\n\n if (submitted.llmModels !== undefined && catalogs.knownLlmModelIds !== null) {\n validateKnownAccessIds(submitted.llmModels, catalogs.knownLlmModelIds, 'LLM model');\n }\n}\n\n/**\n * Builds warning messages for stored access lists that reference missing resources.\n *\n * @param stored - Persisted access lists on a user record.\n * @param catalogs - Known collection, environment, snippet, and LLM model ids.\n * @returns Human-readable warnings for stale access references.\n */\nexport function buildAccessListWarnings(\n stored: StoredAccessLists,\n catalogs: AccessCatalogIds\n): string[] {\n const warnings: string[] = [];\n\n for (const id of findUnknownAccessIds(stored.collectionAccess, catalogs.knownCollectionIds)) {\n warnings.push(`Unknown collection id \"${id}\".`);\n }\n\n for (const id of findUnknownAccessIds(stored.environmentAccess, catalogs.knownEnvironmentIds)) {\n warnings.push(`Unknown environment id \"${id}\".`);\n }\n\n for (const id of findUnknownAccessIds(stored.snippetAccess, catalogs.knownSnippetIds)) {\n warnings.push(`Unknown snippet id \"${id}\".`);\n }\n\n if (catalogs.knownLlmModelIds !== null) {\n for (const id of findUnknownAccessIds(stored.llmModels, catalogs.knownLlmModelIds)) {\n warnings.push(`Unknown LLM model id \"${id}\".`);\n }\n }\n\n return warnings;\n}\n\n/**\n * Builds {@link AccessCatalogIds} from hub collection, environment, snippet, and model listings.\n *\n * @param collections - Collections returned by the database layer.\n * @param environments - Environments returned by the database layer.\n * @param snippets - Snippets returned by the database layer.\n * @param llmModelIds - Hub-offered LLM model ids, or null when LLM is not configured.\n * @returns Catalog id sets for validation and warnings.\n */\nexport function buildAccessCatalogIds(\n collections: ReadonlyArray<{ id: string }>,\n environments: ReadonlyArray<{ id: string }>,\n snippets: ReadonlyArray<{ id: string }>,\n llmModelIds: string[] | null\n): AccessCatalogIds {\n return {\n knownCollectionIds: new Set(collections.map((collection) => collection.id)),\n knownEnvironmentIds: new Set(environments.map((environment) => environment.id)),\n knownSnippetIds: new Set(snippets.map((snippet) => snippet.id)),\n knownLlmModelIds: llmModelIds === null ? null : new Set(llmModelIds)\n };\n}\n\n/**\n * Builds the update payload applied to an existing user record.\n *\n * @param existing - Current user record from the database.\n * @param body - Partial fields from the management API request body.\n * @returns Normalized update input for {@link IDatabase.updateUser}.\n * @throws {ValidationError} When access lists are invalid for the resulting role.\n */\nexport function buildAdminUserUpdateInput(\n existing: {\n name: string;\n role: UserRole;\n collectionAccess: string[];\n environmentAccess: string[];\n snippetAccess: string[];\n llmAccess: boolean;\n llmModels: string[];\n llmMonthlyTokenLimit: number | null;\n },\n body: {\n name?: string;\n role?: UserRole;\n collectionAccess?: string[];\n environmentAccess?: string[];\n snippetAccess?: string[];\n llmAccess?: boolean;\n llmModels?: string[];\n llmMonthlyTokenLimit?: number | null;\n }\n): UpdateUserInput {\n const role = body.role ?? existing.role;\n const collectionAccess =\n role === 'admin' ? [] : (body.collectionAccess ?? existing.collectionAccess);\n const environmentAccess =\n role === 'admin' ? [] : (body.environmentAccess ?? existing.environmentAccess);\n const snippetAccess = role === 'admin' ? [] : (body.snippetAccess ?? existing.snippetAccess);\n const access = normalizeAccessForRole(role, collectionAccess, environmentAccess, snippetAccess);\n const llmAccess = role === 'admin' ? false : (body.llmAccess ?? existing.llmAccess);\n const llmModels = role === 'admin' ? [] : (body.llmModels ?? existing.llmModels);\n const llm = normalizeLlmForRole(role, llmAccess, llmModels);\n\n return {\n name: body.name,\n role: body.role,\n collectionAccess: access.collectionAccess,\n environmentAccess: access.environmentAccess,\n snippetAccess: access.snippetAccess,\n llmAccess: llm.llmAccess,\n llmModels: llm.llmModels,\n llmMonthlyTokenLimit: body.llmMonthlyTokenLimit\n };\n}\n\n/**\n * Builds the create payload for a new user account.\n *\n * @param body - Fields from the management API create request body.\n * @returns Normalized create input for {@link IDatabase.createUser}.\n * @throws {ValidationError} When access lists are invalid for the role.\n */\nexport function buildAdminUserCreateInput(body: {\n name: string;\n role: UserRole;\n collectionAccess?: string[];\n environmentAccess?: string[];\n snippetAccess?: string[];\n llmAccess?: boolean;\n llmModels?: string[];\n llmMonthlyTokenLimit?: number | null;\n}): CreateUserInput {\n const collectionAccess = body.collectionAccess ?? [];\n const environmentAccess = body.environmentAccess ?? [];\n const snippetAccess = body.snippetAccess ?? [];\n const access = normalizeAccessForRole(\n body.role,\n collectionAccess,\n environmentAccess,\n snippetAccess\n );\n const llmAccess = body.role === 'admin' ? false : (body.llmAccess ?? false);\n const llmModels = body.role === 'admin' ? [] : (body.llmModels ?? []);\n const llm = normalizeLlmForRole(body.role, llmAccess, llmModels);\n\n return {\n name: body.name,\n role: body.role,\n collectionAccess: access.collectionAccess ?? [],\n environmentAccess: access.environmentAccess ?? [],\n snippetAccess: access.snippetAccess ?? [],\n llmAccess: llm.llmAccess ?? false,\n llmModels: llm.llmModels ?? [],\n llmMonthlyTokenLimit: body.llmMonthlyTokenLimit ?? null\n };\n}\n","import type { LlmConfig, LlmProvider } from '#/config/llmConfig.js';\n\n/**\n * Catalog entry for a hub-offered LLM model.\n */\nexport interface LlmModelCatalogEntry {\n /**\n * Provider-specific model id sent to the API.\n */\n id: string;\n\n /**\n * Human-readable label for listings.\n */\n label: string;\n\n /**\n * LLM provider that owns this model.\n */\n provider: LlmProvider;\n}\n\n/**\n * Full catalog of models Team Hub can offer when a provider key is configured.\n */\nexport const LLM_MODEL_CATALOG: LlmModelCatalogEntry[] = [\n { id: 'gpt-4o', label: 'GPT-4o', provider: 'openai' },\n { id: 'gpt-4o-mini', label: 'GPT-4o Mini', provider: 'openai' },\n { id: 'claude-3-5-sonnet-20241022', label: 'Claude 3.5 Sonnet', provider: 'claude' },\n { id: 'claude-3-5-haiku-20241022', label: 'Claude 3.5 Haiku', provider: 'claude' },\n { id: 'gemini-1.5-pro', label: 'Gemini 1.5 Pro', provider: 'gemini' },\n { id: 'gemini-1.5-flash', label: 'Gemini 1.5 Flash', provider: 'gemini' }\n];\n\n/**\n * Returns whether a provider has a configured API key on the hub.\n *\n * @param config - Normalized LLM config from server.yaml.\n * @param provider - Provider to check.\n */\nfunction hasProviderKey(config: LlmConfig, provider: LlmProvider): boolean {\n return Boolean(config.providers[provider]?.apiKey.trim());\n}\n\n/**\n * Returns whether a provider has a configured API key on the hub.\n *\n * @param config - Normalized LLM config from server.yaml.\n * @param provider - Provider to check.\n */\nexport function hasHubOpenAiProvider(config: LlmConfig): boolean {\n return hasProviderKey(config, 'openai');\n}\n\n/**\n * Returns hub LLM capability flags advertised to HarborClient clients.\n *\n * @param config - Normalized LLM config from server.yaml.\n */\nexport function getHubLlmCapabilities(config: LlmConfig): { openai: boolean } {\n return {\n openai: hasProviderKey(config, 'openai')\n };\n}\n\n/**\n * Returns catalog models the hub offers based on configured keys and optional allow-list.\n *\n * @param config - Normalized LLM config from server.yaml.\n */\nexport function listHubOfferedModels(config: LlmConfig): LlmModelCatalogEntry[] {\n const allowList = config.models ? new Set(config.models) : null;\n\n return LLM_MODEL_CATALOG.filter((model) => {\n if (!hasProviderKey(config, model.provider)) {\n return false;\n }\n\n if (allowList && !allowList.has(model.id)) {\n return false;\n }\n\n return true;\n });\n}\n\n/**\n * Looks up a catalog model by id.\n *\n * @param modelId - Provider-specific model id.\n */\nexport function getHubModelById(modelId: string): LlmModelCatalogEntry | undefined {\n return LLM_MODEL_CATALOG.find((model) => model.id === modelId);\n}\n\n/**\n * Returns true when the hub is configured to offer the given model id.\n *\n * @param config - Normalized LLM config from server.yaml.\n * @param modelId - Provider-specific model id.\n */\nexport function isHubModelOffered(config: LlmConfig, modelId: string): boolean {\n return listHubOfferedModels(config).some((model) => model.id === modelId);\n}\n\n/**\n * Returns the current UTC usage period key (`YYYY-MM`).\n *\n * @param now - Reference time; defaults to the current instant.\n */\nexport function currentUsagePeriod(now: Date = new Date()): string {\n const year = now.getUTCFullYear();\n const month = String(now.getUTCMonth() + 1).padStart(2, '0');\n return `${year}-${month}`;\n}\n","import Fastify, { type FastifyInstance } from 'fastify';\nimport {\n serializerCompiler,\n validatorCompiler,\n type ZodTypeProvider\n} from 'fastify-type-provider-zod';\nimport { DEFAULT_LOGGING_CONFIG } from '#/config/loggingConfig.js';\nimport type { IDatabase } from '#/db/IDatabase.js';\nimport type { IThrottleStore } from '#/server/auth/throttle/IThrottleStore.js';\nimport { registerHttpLogging } from '#/server/logging/httpLogging.js';\nimport { createLogger, type Logger } from '#/server/logging/logger.js';\nimport { readPackageVersion } from '#/packageVersion.js';\nimport { registerRoutes } from '#/server/routes/index.js';\nimport type { ReloadResult, RuntimeContext } from '#/server/runtimeContext.js';\n\nexport interface CreateServerOptions {\n /**\n * When true, enables Fastify's built-in request logger.\n */\n verbose?: boolean;\n\n /**\n * Package version exposed on the health endpoint (defaults to package.json).\n */\n version?: string;\n\n /**\n * Database used for bearer token validation on protected routes.\n */\n db?: IDatabase;\n\n /**\n * Redis-backed store for authentication throttling on protected routes.\n */\n throttleStore?: IThrottleStore;\n\n /**\n * Reloads server.yaml and returns a per-section report.\n */\n reloadConfig?: () => Promise<ReloadResult>;\n\n /**\n * Winston logger for HTTP request and error logging; defaults from config.\n */\n logger?: Logger;\n}\n\n/**\n * Builds a configured Fastify instance with Zod validation and registered routes.\n *\n * Does not call `listen`; use {@link runServer} or test inject for that.\n *\n * When a {@link RuntimeContext} is supplied, its stable db and throttle proxies are\n * wired automatically. Explicit `db` and `throttleStore` options override those defaults\n * for tests.\n *\n * @param ctxOrConfig - Runtime context, or legacy server config object for tests.\n * @param options - Logger, version, and optional dependency overrides.\n * @returns Fastify app with type provider and routes attached.\n */\nexport async function createServer(\n ctxOrConfig: RuntimeContext | import('#/config/serverConfig.js').ServerConfig,\n options: CreateServerOptions = {}\n): Promise<FastifyInstance> {\n const isRuntimeContext = 'getLlm' in ctxOrConfig && 'configPath' in ctxOrConfig;\n const ctx = isRuntimeContext ? (ctxOrConfig as RuntimeContext) : null;\n const legacyConfig = isRuntimeContext\n ? null\n : (ctxOrConfig as import('#/config/serverConfig.js').ServerConfig);\n\n const db = options.db ?? ctx?.db;\n const throttleStore = options.throttleStore ?? ctx?.throttleStore;\n\n if (!db || !throttleStore) {\n throw new Error('createServer requires db and throttleStore.');\n }\n\n const logger =\n options.logger ?? ctx?.logger ?? createLogger(legacyConfig?.logging ?? DEFAULT_LOGGING_CONFIG);\n\n const app = Fastify({\n logger: options.verbose ?? false\n }).withTypeProvider<ZodTypeProvider>();\n\n app.setValidatorCompiler(validatorCompiler);\n app.setSerializerCompiler(serializerCompiler);\n\n registerHttpLogging(app, logger);\n\n await registerRoutes(app, {\n version: options.version ?? readPackageVersion(),\n db,\n throttleStore,\n getLlm: ctx ? () => ctx.getLlm() : () => legacyConfig?.llm ?? null,\n getPlugins: ctx ? () => ctx.getPlugins() : () => legacyConfig?.plugins ?? null,\n getDocs: ctx ? () => ctx.getDocs() : () => legacyConfig?.docs ?? null,\n reloadConfig: options.reloadConfig ?? (async () => ({ sections: [] }))\n });\n\n return app;\n}\n","import type { FastifyInstance } from 'fastify';\nimport type { Logger } from '#/server/logging/logger.js';\n\n/**\n * Registers HTTP request and error logging hooks on a Fastify instance.\n *\n * Logs every incoming request at debug level and logs unhandled request errors\n * at error level without altering response handling.\n *\n * @param app - Fastify server to attach hooks to.\n * @param logger - Winston logger configured from server.yaml.\n */\nexport function registerHttpLogging(app: FastifyInstance, logger: Logger): void {\n app.addHook('onRequest', async (request) => {\n logger.debug('request', {\n reqId: request.id,\n method: request.method,\n url: request.url,\n ip: request.ip\n });\n });\n\n app.addHook('onError', async (request, reply, error) => {\n logger.error('request error', {\n reqId: request.id,\n method: request.method,\n url: request.url,\n statusCode: reply.statusCode,\n message: error.message,\n stack: error.stack\n });\n });\n}\n","import winston from 'winston';\nimport type { LoggingConfig } from '#/config/loggingConfig.js';\n\n/**\n * Winston logger instance used by the Team Hub server.\n */\nexport type Logger = winston.Logger;\n\n/**\n * Builds a Winston logger from normalized logging configuration.\n *\n * Uses standard npm log levels. When both file and console output are disabled,\n * attaches a silent console transport so Winston does not warn about zero transports.\n *\n * @param config - Normalized logging settings from server.yaml.\n * @returns Configured Winston logger.\n */\nexport function createLogger(config: LoggingConfig): Logger {\n const transports: winston.transport[] = [];\n\n if (config.console) {\n transports.push(new winston.transports.Console());\n }\n\n if (config.file) {\n transports.push(new winston.transports.File({ filename: config.file }));\n }\n\n if (transports.length === 0) {\n transports.push(new winston.transports.Console({ silent: true }));\n }\n\n return winston.createLogger({\n level: config.level,\n format: winston.format.combine(winston.format.timestamp(), winston.format.json()),\n transports\n });\n}\n","import { readFileSync } from 'node:fs';\n\n/**\n * Reads the package version from the project root `package.json`.\n *\n * The module lives under `src/`, so `../package.json` resolves correctly when\n * running via tsx and when bundled to `dist/cli.js`.\n *\n * @returns Semantic version string from package.json.\n */\nexport function readPackageVersion(): string {\n const pkg = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')) as {\n version: string;\n };\n return pkg.version;\n}\n","import type {\n CollectionRecord,\n EnvironmentRecord,\n RunResultRecord,\n SavedRequestRecord,\n SnippetRecord,\n UserRecord\n} from '#/db/types.js';\n\n/**\n * Returns true when the authenticated user has an admin role.\n *\n * @param user - Authenticated user attached to the request.\n * @returns True for `admin`-role accounts.\n */\nexport function isAdmin(user: UserRecord): boolean {\n return user.role === 'admin';\n}\n\n/**\n * Returns true when the user may call management API routes for user and token administration.\n *\n * @param user - Authenticated user attached to the request.\n * @returns True for `admin`-role accounts.\n */\nexport function canUseManagementApi(user: UserRecord): boolean {\n return isAdmin(user);\n}\n\n/**\n * Returns true when the user may call entity data API routes for collections,\n * environments, snippets, folders, and requests.\n *\n * @param user - Authenticated user attached to the request.\n * @returns True for `user`-role accounts; false for admins.\n */\nexport function canUseDataApi(user: UserRecord): boolean {\n return user.role === 'user';\n}\n\n/**\n * Returns true when the user may list collections via `GET /collections`.\n *\n * Admins receive the full catalog; mutations and nested reads remain blocked.\n *\n * @param user - Authenticated user attached to the request.\n * @returns True for `user`- and `admin`-role accounts.\n */\nexport function canListCollections(user: UserRecord): boolean {\n return canUseDataApi(user) || canUseManagementApi(user);\n}\n\n/**\n * Returns true when the user may list environments via `GET /environments`.\n *\n * Admins receive the full catalog; mutations remain blocked.\n *\n * @param user - Authenticated user attached to the request.\n * @returns True for `user`- and `admin`-role accounts.\n */\nexport function canListEnvironments(user: UserRecord): boolean {\n return canUseDataApi(user) || canUseManagementApi(user);\n}\n\n/**\n * Returns true when the user may list snippets via `GET /snippets`.\n *\n * Admins receive the full catalog; mutations remain blocked.\n *\n * @param user - Authenticated user attached to the request.\n * @returns True for `user`- and `admin`-role accounts.\n */\nexport function canListSnippets(user: UserRecord): boolean {\n return canUseDataApi(user) || canUseManagementApi(user);\n}\n\n/**\n * Returns true when the user may list their own run results via `GET /run-results`.\n *\n * Admins receive an empty list (they created none) rather than a 403, matching the\n * collections/environments/snippets listing endpoints.\n *\n * @param user - Authenticated user attached to the request.\n * @returns True for `user`- and `admin`-role accounts.\n */\nexport function canListRunResults(user: UserRecord): boolean {\n return canUseDataApi(user) || canUseManagementApi(user);\n}\n\n/**\n * Returns true when an access list grants all resources via the wildcard entry.\n *\n * @param access - Collection or environment access ids.\n * @returns True when the list contains `*`.\n */\nexport function hasWildcardAccess(access: string[]): boolean {\n return access.includes('*');\n}\n\n/**\n * Returns true when the user may read or mutate a specific collection.\n *\n * @param user - Authenticated user attached to the request.\n * @param collectionId - Collection identifier being accessed.\n * @returns True when the user role and access list permit the collection.\n */\nexport function canAccessCollection(user: UserRecord, collectionId: string): boolean {\n if (user.role === 'admin') {\n return false;\n }\n\n if (hasWildcardAccess(user.collectionAccess)) {\n return true;\n }\n\n return user.collectionAccess.includes(collectionId);\n}\n\n/**\n * Returns true when the user may read or mutate a specific environment.\n *\n * @param user - Authenticated user attached to the request.\n * @param environmentId - Environment identifier being accessed.\n * @returns True when the user role and access list permit the environment.\n */\nexport function canAccessEnvironment(user: UserRecord, environmentId: string): boolean {\n if (user.role === 'admin') {\n return false;\n }\n\n if (hasWildcardAccess(user.environmentAccess)) {\n return true;\n }\n\n return user.environmentAccess.includes(environmentId);\n}\n\n/**\n * Returns true when the user may read or mutate a specific snippet.\n *\n * @param user - Authenticated user attached to the request.\n * @param snippetId - Snippet identifier being accessed.\n * @returns True when the user role and access list permit the snippet.\n */\nexport function canAccessSnippet(user: UserRecord, snippetId: string): boolean {\n if (user.role === 'admin') {\n return false;\n }\n\n if (hasWildcardAccess(user.snippetAccess)) {\n return true;\n }\n\n return user.snippetAccess.includes(snippetId);\n}\n\n/**\n * Returns true when the user may delete a specific collection via the data API.\n *\n * @param user - Authenticated user attached to the request.\n * @param collection - Collection record being deleted.\n * @returns True when the user created the collection, has access, and deletion is not locked.\n */\nexport function canDeleteCollection(user: UserRecord, collection: CollectionRecord): boolean {\n return (\n canUseDataApi(user) &&\n canAccessCollection(user, collection.id) &&\n collection.createdByUserId === user.id &&\n !collection.deletionLocked\n );\n}\n\n/**\n * Returns true when the user may delete a specific environment via the data API.\n *\n * @param user - Authenticated user attached to the request.\n * @param environment - Environment record being deleted.\n * @returns True when the user has access and the environment is not deletion-locked.\n */\nexport function canDeleteEnvironment(user: UserRecord, environment: EnvironmentRecord): boolean {\n return (\n canUseDataApi(user) && canAccessEnvironment(user, environment.id) && !environment.deletionLocked\n );\n}\n\n/**\n * Returns true when the user may delete a specific snippet via the data API.\n *\n * @param user - Authenticated user attached to the request.\n * @param snippet - Snippet record being deleted.\n * @returns True when the user has access and the snippet is not deletion-locked.\n */\nexport function canDeleteSnippet(user: UserRecord, snippet: SnippetRecord): boolean {\n return canUseDataApi(user) && canAccessSnippet(user, snippet.id) && !snippet.deletionLocked;\n}\n\n/**\n * Returns true when the user may delete a specific saved request via the data API.\n *\n * @param user - Authenticated user attached to the request.\n * @param request - Saved request record being deleted.\n * @returns True when the user created the request and has access to its collection.\n */\nexport function canDeleteRequest(user: UserRecord, request: SavedRequestRecord): boolean {\n return (\n canUseDataApi(user) &&\n canAccessCollection(user, request.collectionId) &&\n request.createdByUserId === user.id\n );\n}\n\n/**\n * Returns true when the user may delete a specific run result via the data API.\n *\n * @param user - Authenticated user attached to the request.\n * @param runResult - Run result record being deleted.\n * @returns True when the user created the run result.\n */\nexport function canDeleteRunResult(user: UserRecord, runResult: RunResultRecord): boolean {\n return canUseDataApi(user) && runResult.createdByUserId === user.id;\n}\n\n/**\n * Returns true when the user may create new collections via the API.\n *\n * @param user - Authenticated user attached to the request.\n * @returns True when the user has wildcard collection access.\n */\nexport function canCreateCollection(user: UserRecord): boolean {\n return user.role === 'user' && hasWildcardAccess(user.collectionAccess);\n}\n\n/**\n * Returns true when the user may create new environments via the API.\n *\n * @param user - Authenticated user attached to the request.\n * @returns True when the user has wildcard environment access.\n */\nexport function canCreateEnvironment(user: UserRecord): boolean {\n return user.role === 'user' && hasWildcardAccess(user.environmentAccess);\n}\n\n/**\n * Returns true when the user may create new snippets via the API.\n *\n * @param user - Authenticated user attached to the request.\n * @returns True when the user has wildcard snippet access.\n */\nexport function canCreateSnippet(user: UserRecord): boolean {\n return user.role === 'user' && hasWildcardAccess(user.snippetAccess);\n}\n\n/**\n * Filters a collection list to entries the user is allowed to see.\n *\n * @param user - Authenticated user attached to the request.\n * @param collections - Unfiltered collections from the database.\n * @returns Collections visible to the user.\n */\nexport function filterAccessibleCollections(\n user: UserRecord,\n collections: CollectionRecord[]\n): CollectionRecord[] {\n if (user.role === 'admin' || hasWildcardAccess(user.collectionAccess)) {\n return collections;\n }\n\n const allowed = new Set(user.collectionAccess);\n return collections.filter((collection) => allowed.has(collection.id));\n}\n\n/**\n * Filters an environment list to entries the user is allowed to see.\n *\n * @param user - Authenticated user attached to the request.\n * @param environments - Unfiltered environments from the database.\n * @returns Environments visible to the user.\n */\nexport function filterAccessibleEnvironments(\n user: UserRecord,\n environments: EnvironmentRecord[]\n): EnvironmentRecord[] {\n if (user.role === 'admin' || hasWildcardAccess(user.environmentAccess)) {\n return environments;\n }\n\n const allowed = new Set(user.environmentAccess);\n return environments.filter((environment) => allowed.has(environment.id));\n}\n\n/**\n * Filters a snippet list to entries the user is allowed to see.\n *\n * @param user - Authenticated user attached to the request.\n * @param snippets - Unfiltered snippets from the database.\n * @returns Snippets visible to the user.\n */\nexport function filterAccessibleSnippets(\n user: UserRecord,\n snippets: SnippetRecord[]\n): SnippetRecord[] {\n if (user.role === 'admin' || hasWildcardAccess(user.snippetAccess)) {\n return snippets;\n }\n\n const allowed = new Set(user.snippetAccess);\n return snippets.filter((snippet) => allowed.has(snippet.id));\n}\n\n/**\n * Returns true when the user may call hub-proxied LLM routes.\n *\n * @param user - Authenticated user attached to the request.\n * @returns True when LLM access is enabled for the account.\n */\nexport function canUseLlm(user: UserRecord): boolean {\n return user.role !== 'admin' && user.llmAccess;\n}\n\n/**\n * Returns true when the user may request a specific hub-offered model.\n *\n * @param user - Authenticated user attached to the request.\n * @param modelId - Provider-specific model id.\n * @returns True when the user's model access list permits the model.\n */\nexport function isLlmModelAllowed(user: UserRecord, modelId: string): boolean {\n if (!user.llmAccess) {\n return false;\n }\n\n if (hasWildcardAccess(user.llmModels)) {\n return true;\n }\n\n return user.llmModels.includes(modelId);\n}\n\n/**\n * Returns true when usage has reached or exceeded the configured monthly limit.\n *\n * @param totalTokens - Tokens consumed in the current period.\n * @param limit - Configured monthly limit, or null for unlimited.\n */\nexport function isOverMonthlyLimit(totalTokens: number, limit: number | null): boolean {\n if (limit == null) {\n return false;\n }\n\n return totalTokens >= limit;\n}\n","/**\n * Thrown when a non-admin user attempts to delete a collection, environment, or snippet\n * that has deletion protection enabled.\n */\nexport class DeletionLockedError extends Error {\n /**\n * @param entityType - Human-readable entity kind shown in the error message.\n */\n constructor(entityType: 'collection' | 'environment' | 'snippet') {\n super(`Deletion is locked for this ${entityType}.`);\n this.name = 'DeletionLockedError';\n }\n}\n","import { z } from 'zod/v4';\n\n/**\n * Standard error body returned by protected API routes.\n */\nexport const errorResponseSchema = z.object({\n error: z.string()\n});\n\n/**\n * Route parameter schema for string entity identifiers (UUIDs).\n */\nexport const idParamSchema = z.object({\n id: z.string().trim().min(1)\n});\n\n/**\n * Route parameter schema for a parent collection identifier.\n */\nexport const collectionIdParamSchema = z.object({\n collectionId: z.string().trim().min(1)\n});\n\n/**\n * Supported HTTP request methods for saved requests.\n */\nexport const httpMethodSchema = z.enum([\n 'GET',\n 'POST',\n 'PUT',\n 'PATCH',\n 'DELETE',\n 'HEAD',\n 'OPTIONS'\n]);\n\n/**\n * Request body content type for saved requests.\n */\nexport const bodyTypeSchema = z.enum(['none', 'json', 'text', 'multipart', 'urlencoded']);\n\n/**\n * Authorization type for collections and saved requests.\n */\nexport const authTypeSchema = z.enum(['none', 'basic', 'bearer']);\n\n/**\n * Zod schema for a key-value pair with an enable toggle.\n */\nexport const keyValueSchema = z.object({\n key: z.string(),\n value: z.string(),\n enabled: z.boolean()\n});\n\n/**\n * Zod schema for a collection- or environment-scoped variable.\n */\nexport const variableSchema = z.object({\n key: z.string(),\n value: z.string(),\n defaultValue: z.string(),\n share: z.boolean()\n});\n\n/**\n * Zod schema for authorization settings on collections and requests.\n */\nexport const authConfigSchema = z.object({\n type: authTypeSchema,\n basic: z.object({\n username: z.string(),\n password: z.string()\n }),\n bearer: z.object({\n token: z.string()\n })\n});\n\n/**\n * ISO 8601 timestamp strings returned in JSON responses.\n */\nexport const timestampSchema = z.iso.datetime();\n","import type { FastifyReply } from 'fastify';\nimport { DuplicateUserNameError, ReservedUserNameError } from '#/db/userNameValidation.js';\nimport { DeletionLockedError } from '#/db/deletionLockedError.js';\nimport { ValidationError } from '#/server/admin/userValidation.js';\nimport { errorResponseSchema } from '#/server/routes/schemas/common.js';\n\nconst DUPLICATE_USER_NAME_MESSAGE = 'User name is already in use.';\n\n/**\n * Returns true when a database driver reports a unique violation on users.name.\n *\n * @param error - Thrown error from a relational backend write.\n * @returns True when the error is a duplicate user name constraint violation.\n */\nfunction isDuplicateUserNameDbError(error: Error): boolean {\n const candidate = error as Error & { code?: string; constraint?: string };\n\n if (candidate.code === '23505') {\n return (\n candidate.constraint === 'users_name_key' ||\n candidate.constraint?.endsWith('_name_key') === true ||\n error.message.includes('users_name_key') ||\n error.message.includes('(name)')\n );\n }\n\n if (candidate.code === 'ER_DUP_ENTRY') {\n return error.message.includes(\"'name'\") || error.message.includes('users.name');\n }\n\n return false;\n}\n\n/**\n * Maps validation errors to HTTP 400 responses.\n *\n * @param reply - Fastify reply used to send error payloads.\n * @param error - Thrown error from request validation.\n * @returns True when the error was handled and a response was sent.\n */\nexport function handleValidationError(reply: FastifyReply, error: unknown): boolean {\n if (!(error instanceof ValidationError)) {\n return false;\n }\n\n void reply.code(400).send(errorResponseSchema.parse({ error: error.message }));\n return true;\n}\n\n/**\n * Maps known database-layer errors to HTTP responses.\n *\n * @param reply - Fastify reply used to send error payloads.\n * @param error - Thrown error from an {@link IDatabase} operation.\n * @returns True when the error was handled and a response was sent.\n */\nexport function handleDbError(reply: FastifyReply, error: unknown): boolean {\n if (!(error instanceof Error)) {\n return false;\n }\n\n if (error instanceof DuplicateUserNameError) {\n void reply.code(400).send(errorResponseSchema.parse({ error: error.message }));\n return true;\n }\n\n if (error instanceof ReservedUserNameError) {\n void reply.code(400).send(errorResponseSchema.parse({ error: error.message }));\n return true;\n }\n\n if (error instanceof DeletionLockedError) {\n void reply.code(403).send(errorResponseSchema.parse({ error: error.message }));\n return true;\n }\n\n if (isDuplicateUserNameDbError(error)) {\n void reply.code(400).send(errorResponseSchema.parse({ error: DUPLICATE_USER_NAME_MESSAGE }));\n return true;\n }\n\n if (error.message.includes('is required')) {\n void reply.code(400).send(errorResponseSchema.parse({ error: error.message }));\n return true;\n }\n\n if (error.message.toLowerCase().includes('not found')) {\n void reply.code(404).send(errorResponseSchema.parse({ error: error.message }));\n return true;\n }\n\n return false;\n}\n","import type { FastifyReply, FastifyRequest } from 'fastify';\nimport type { UserRecord } from '#/db/types.js';\n\n/**\n * Returns the authenticated user attached by the bearer auth hook.\n *\n * @param request - Incoming HTTP request after authentication.\n * @returns User record resolved from the bearer token owner.\n * @throws {Error} When the request has no authenticated user.\n */\nexport function requireAuthenticatedUser(request: FastifyRequest): UserRecord {\n if (!request.user) {\n throw new Error('Authenticated user is required');\n }\n\n return request.user;\n}\n\n/**\n * Sends a standard forbidden response for authorization failures.\n *\n * @param reply - Fastify reply used to short-circuit the handler.\n * @returns The reply instance for early return in route handlers.\n */\nexport function sendForbidden(reply: FastifyReply): FastifyReply {\n return reply.code(403).send({ error: 'Forbidden' });\n}\n\n/**\n * Sends forbidden when the supplied condition is false.\n *\n * @param reply - Fastify reply used to short-circuit the handler.\n * @param allowed - True when the caller may proceed.\n * @returns True when the handler should return early with 403.\n */\nexport function denyUnlessAllowed(reply: FastifyReply, allowed: boolean): boolean {\n if (allowed) {\n return false;\n }\n\n sendForbidden(reply);\n return true;\n}\n","import { z } from 'zod/v4';\nimport type { ApiTokenRecord, UserRecord } from '#/db/types.js';\nimport { userRoleSchema } from '#/server/routes/schemas/auth.js';\nimport { timestampSchema } from '#/server/routes/schemas/common.js';\nimport { listLlmModelsResponseSchema } from '#/server/routes/schemas/llm.js';\nimport {\n createSnippetBodySchema,\n runResultRecordSchema,\n snippetRecordSchema,\n snippetScopeSchema\n} from '#/server/routes/schemas/entities.js';\n\n/**\n * Lightweight id/name pair returned by admin resource list routes.\n */\nexport const adminResourceOptionSchema = z.object({\n id: z.string(),\n name: z.string(),\n deletionLocked: z.boolean()\n});\n\n/**\n * Response body schema for admin collection/environment configuration updates.\n */\nexport const adminEntityConfigSchema = z.object({\n id: z.string(),\n name: z.string(),\n deletionLocked: z.boolean()\n});\n\n/**\n * Request body schema for `PUT /admin/collections/:id`.\n */\nexport const updateAdminCollectionBodySchema = z.object({\n deletionLocked: z.boolean()\n});\n\n/**\n * Request body schema for `PUT /admin/environments/:id`.\n */\nexport const updateAdminEnvironmentBodySchema = z.object({\n deletionLocked: z.boolean()\n});\n\n/**\n * Request body schema for `PUT /admin/snippets/:id`.\n */\nexport const updateAdminSnippetBodySchema = z\n .object({\n name: z.string().trim().min(1).optional(),\n code: z.string().optional(),\n scope: snippetScopeSchema.optional(),\n deletionLocked: z.boolean().optional()\n })\n .superRefine((body, ctx) => {\n const hasContentFields =\n body.name !== undefined || body.code !== undefined || body.scope !== undefined;\n const hasFullContent =\n body.name !== undefined && body.code !== undefined && body.scope !== undefined;\n\n if (hasContentFields && !hasFullContent) {\n ctx.addIssue({\n code: 'custom',\n message: 'name, code, and scope must be provided together'\n });\n }\n\n if (!hasContentFields && body.deletionLocked === undefined) {\n ctx.addIssue({\n code: 'custom',\n message: 'Provide snippet content (name, code, scope) and/or deletionLocked'\n });\n }\n });\n\n/**\n * Request body schema for `POST /admin/snippets`.\n */\nexport const createAdminSnippetBodySchema = createSnippetBodySchema;\n\n/**\n * Response body schema for `GET /admin/collections`.\n */\nexport const listAdminCollectionsResponseSchema = z.object({\n collections: z.array(adminResourceOptionSchema)\n});\n\n/**\n * Response body schema for `GET /admin/environments`.\n */\nexport const listAdminEnvironmentsResponseSchema = z.object({\n environments: z.array(adminResourceOptionSchema)\n});\n\n/**\n * Response body schema for `GET /admin/snippets`.\n */\nexport const listAdminSnippetsResponseSchema = z.object({\n snippets: z.array(snippetRecordSchema)\n});\n\n/**\n * Response body schema for admin run result listing.\n */\nexport const listAdminRunResultsResponseSchema = z.object({\n runResults: z.array(runResultRecordSchema)\n});\n\n/**\n * Response body schema for admin snippet create and content updates.\n */\nexport const adminSnippetRecordSchema = snippetRecordSchema;\n\n/**\n * Response body schema for `GET /admin/llm/models`.\n */\nexport const listAdminLlmModelsResponseSchema = listLlmModelsResponseSchema;\nexport const hubUserRecordSchema = z.object({\n id: z.string(),\n name: z.string(),\n role: userRoleSchema,\n collectionAccess: z.array(z.string()),\n environmentAccess: z.array(z.string()),\n snippetAccess: z.array(z.string()),\n llmAccess: z.boolean(),\n llmModels: z.array(z.string()),\n llmMonthlyTokenLimit: z.number().int().nonnegative().nullable(),\n createdAt: timestampSchema,\n updatedAt: timestampSchema\n});\n\n/**\n * User record returned by `GET /admin/users`, including stale access warnings.\n */\nexport const adminUserListEntrySchema = hubUserRecordSchema.extend({\n warnings: z.array(z.string())\n});\n\n/**\n * Response body schema for `GET /admin/users`.\n */\nexport const listAdminUsersResponseSchema = z.object({\n users: z.array(adminUserListEntrySchema)\n});\n\n/**\n * Request body schema for `PUT /admin/users/:id`.\n */\nexport const updateAdminUserBodySchema = z.object({\n name: z.string().trim().min(1).optional(),\n role: userRoleSchema.optional(),\n collectionAccess: z.array(z.string()).optional(),\n environmentAccess: z.array(z.string()).optional(),\n snippetAccess: z.array(z.string()).optional(),\n llmAccess: z.boolean().optional(),\n llmModels: z.array(z.string()).optional(),\n llmMonthlyTokenLimit: z.number().int().nonnegative().nullable().optional()\n});\n\n/**\n * Request body schema for `POST /admin/users`.\n */\nexport const createAdminUserBodySchema = z.object({\n name: z.string().trim().min(1),\n role: userRoleSchema,\n collectionAccess: z.array(z.string()).optional(),\n environmentAccess: z.array(z.string()).optional(),\n snippetAccess: z.array(z.string()).optional(),\n llmAccess: z.boolean().optional(),\n llmModels: z.array(z.string()).optional(),\n llmMonthlyTokenLimit: z.number().int().nonnegative().nullable().optional()\n});\n\n/**\n * API token metadata returned by admin token routes (never includes the secret hash).\n */\nexport const hubApiTokenRecordSchema = z.object({\n id: z.string(),\n userId: z.string(),\n name: z.string(),\n tokenPrefix: z.string(),\n createdAt: timestampSchema,\n lastUsedAt: timestampSchema.nullable(),\n revokedAt: timestampSchema.nullable()\n});\n\n/**\n * Response body schema for `POST /admin/users`.\n */\nexport const createAdminUserResponseSchema = z.object({\n user: hubUserRecordSchema,\n token: hubApiTokenRecordSchema,\n secret: z.string()\n});\n\n/**\n * Request body schema for `POST /admin/users/:id/tokens`.\n */\nexport const createAdminTokenBodySchema = z.object({\n name: z.string().trim().min(1)\n});\n\n/**\n * Response body schema for `POST /admin/users/:id/tokens`.\n */\nexport const createdApiTokenResponseSchema = z.object({\n token: hubApiTokenRecordSchema,\n secret: z.string()\n});\n\n/**\n * Response body schema for `GET /admin/tokens`.\n */\nexport const listAdminTokensResponseSchema = z.object({\n tokens: z.array(hubApiTokenRecordSchema)\n});\n\n/**\n * Per-section outcome reported by config reload routes.\n */\nexport const reloadConfigSectionResultSchema = z.object({\n section: z.enum(['db', 'redis', 'llm', 'plugins', 'docs', 'server']),\n status: z.enum(['reloaded', 'unchanged', 'failed', 'restart-required']),\n error: z.string().optional()\n});\n\n/**\n * Response body schema for `POST /admin/config/reload`.\n */\nexport const reloadConfigResponseSchema = z.object({\n sections: z.array(reloadConfigSectionResultSchema),\n fatalError: z.string().optional()\n});\n\n/**\n * Serializes a user record for JSON management API responses.\n *\n * @param user - User record from the database layer.\n * @returns User with ISO timestamp strings.\n */\nexport function serializeHubUser(user: UserRecord) {\n return {\n id: user.id,\n name: user.name,\n role: user.role,\n collectionAccess: user.collectionAccess,\n environmentAccess: user.environmentAccess,\n snippetAccess: user.snippetAccess,\n llmAccess: user.llmAccess,\n llmModels: user.llmModels,\n llmMonthlyTokenLimit: user.llmMonthlyTokenLimit,\n createdAt: user.createdAt.toISOString(),\n updatedAt: user.updatedAt.toISOString()\n };\n}\n\n/**\n * Serializes an API token record for JSON management API responses.\n *\n * @param token - Token record from the database layer.\n * @returns Token metadata with ISO timestamp strings.\n */\nexport function serializeApiToken(token: ApiTokenRecord) {\n return {\n id: token.id,\n userId: token.userId,\n name: token.name,\n tokenPrefix: token.tokenPrefix,\n createdAt: token.createdAt.toISOString(),\n lastUsedAt: token.lastUsedAt ? token.lastUsedAt.toISOString() : null,\n revokedAt: token.revokedAt ? token.revokedAt.toISOString() : null\n };\n}\n","import { z } from 'zod/v4';\n\n/**\n * Account role values exposed on the session endpoint.\n */\nexport const userRoleSchema = z.enum(['admin', 'user']);\n\n/**\n * Capability flags returned by `GET /auth/session`.\n */\nexport const sessionCapabilitiesSchema = z.object({\n dataApi: z.boolean(),\n managementApi: z.boolean(),\n llm: z.boolean()\n});\n\n/**\n * Response body schema for `GET /auth/session`.\n */\nexport const sessionResponseSchema = z.object({\n user: z.object({\n id: z.string(),\n name: z.string(),\n role: userRoleSchema\n }),\n token: z.object({\n id: z.string(),\n prefix: z.string()\n }),\n capabilities: sessionCapabilitiesSchema\n});\n","import { z } from 'zod/v4';\n\n/**\n * Zod schema for a tool call in an LLM chat step request or response.\n */\nexport const llmToolCallSchema = z.object({\n id: z.string(),\n name: z.string(),\n arguments: z.string()\n});\n\n/**\n * Zod schema for a message in an LLM chat step request.\n */\nexport const llmChatStepMessageSchema = z.object({\n role: z.enum(['system', 'user', 'assistant', 'tool']),\n content: z.string().nullable().optional(),\n tool_calls: z.array(llmToolCallSchema).optional(),\n tool_call_id: z.string().optional(),\n name: z.string().optional()\n});\n\n/**\n * Zod schema for POST /llm/chat/step request body.\n */\nexport const llmChatStepBodySchema = z.object({\n model: z.string().trim().min(1),\n messages: z.array(llmChatStepMessageSchema),\n tools: z.array(z.record(z.string(), z.unknown())).optional(),\n systemPrompt: z.string().optional()\n});\n\n/**\n * Zod schema for token usage returned by POST /llm/chat/step.\n */\nexport const llmUsageSchema = z.object({\n promptTokens: z.number().int().nonnegative(),\n completionTokens: z.number().int().nonnegative(),\n totalTokens: z.number().int().nonnegative()\n});\n\n/**\n * Zod schema for POST /llm/chat/step response body.\n */\nexport const llmChatStepResponseSchema = z.object({\n content: z.string().nullable(),\n toolCalls: z.array(llmToolCallSchema).optional(),\n usage: llmUsageSchema\n});\n\n/**\n * Zod schema for one model entry in GET /llm/models.\n */\nexport const llmModelSchema = z.object({\n id: z.string(),\n label: z.string(),\n provider: z.enum(['openai', 'claude', 'gemini'])\n});\n\n/**\n * Zod schema for hub LLM capability flags returned by GET /llm/models.\n */\nexport const llmCapabilitiesSchema = z.object({\n openai: z.boolean()\n});\n\n/**\n * Zod schema for GET /llm/models response body.\n */\nexport const listLlmModelsResponseSchema = z.object({\n models: z.array(llmModelSchema),\n capabilities: llmCapabilitiesSchema\n});\n\n/**\n * Zod schema for GET /llm/usage response body.\n */\nexport const llmUsageSummaryResponseSchema = z.object({\n period: z.string(),\n totalTokens: z.number().int().nonnegative(),\n limit: z.number().int().positive().nullable()\n});\n","import { z } from 'zod/v4';\nimport type {\n CollectionRecord,\n EnvironmentRecord,\n FolderRecord,\n RunResultRecord,\n SavedRequestRecord,\n SnippetRecord\n} from '#/db/types.js';\nimport {\n authConfigSchema,\n bodyTypeSchema,\n httpMethodSchema,\n keyValueSchema,\n timestampSchema,\n variableSchema\n} from '#/server/routes/schemas/common.js';\n\n/**\n * JSON shape for a persisted collection record.\n */\nexport const collectionRecordSchema = z.object({\n id: z.string(),\n name: z.string(),\n variables: z.array(variableSchema),\n headers: z.array(keyValueSchema),\n auth: authConfigSchema,\n preRequestScript: z.string(),\n postRequestScript: z.string(),\n createdAt: timestampSchema,\n updatedAt: timestampSchema,\n createdByUserId: z.string().nullable(),\n updatedByUserId: z.string().nullable(),\n deletionLocked: z.boolean()\n});\n\n/**\n * JSON shape for a persisted environment record.\n */\nexport const environmentRecordSchema = z.object({\n id: z.string(),\n name: z.string(),\n variables: z.array(variableSchema),\n createdAt: timestampSchema,\n updatedAt: timestampSchema,\n createdByUserId: z.string().nullable(),\n updatedByUserId: z.string().nullable(),\n deletionLocked: z.boolean()\n});\n\n/**\n * Valid execution scopes for persisted snippets.\n */\nexport const snippetScopeSchema = z.enum(['pre-request', 'post-request', 'any']);\n\n/**\n * JSON shape for a persisted snippet record.\n */\nexport const snippetRecordSchema = z.object({\n id: z.string(),\n name: z.string(),\n code: z.string(),\n scope: snippetScopeSchema,\n sortOrder: z.number().int(),\n createdAt: timestampSchema,\n updatedAt: timestampSchema,\n createdByUserId: z.string().nullable(),\n updatedByUserId: z.string().nullable(),\n deletionLocked: z.boolean()\n});\n\n/**\n * JSON shape for a persisted folder record.\n */\nexport const folderRecordSchema = z.object({\n id: z.string(),\n collectionId: z.string(),\n name: z.string(),\n sortOrder: z.number().int(),\n createdAt: timestampSchema,\n updatedAt: timestampSchema,\n createdByUserId: z.string().nullable(),\n updatedByUserId: z.string().nullable()\n});\n\n/**\n * JSON shape for a persisted saved request record.\n */\nexport const savedRequestRecordSchema = z.object({\n id: z.string(),\n collectionId: z.string(),\n name: z.string(),\n method: httpMethodSchema,\n url: z.string(),\n headers: z.array(keyValueSchema),\n params: z.array(keyValueSchema),\n auth: authConfigSchema,\n body: z.string(),\n bodyType: bodyTypeSchema,\n preRequestScript: z.string(),\n postRequestScript: z.string(),\n comment: z.string(),\n folderId: z.string().nullable(),\n sortOrder: z.number().int(),\n createdAt: timestampSchema,\n updatedAt: timestampSchema,\n createdByUserId: z.string().nullable(),\n updatedByUserId: z.string().nullable()\n});\n\n/**\n * Request body for creating a collection.\n */\nexport const createCollectionBodySchema = z.object({\n name: z.string().trim().min(1)\n});\n\n/**\n * Request body for updating a collection.\n */\nexport const updateCollectionBodySchema = z.object({\n name: z.string().trim().min(1),\n variables: z.array(variableSchema),\n headers: z.array(keyValueSchema),\n preRequestScript: z.string(),\n postRequestScript: z.string(),\n auth: authConfigSchema\n});\n\n/**\n * Request body for creating an environment.\n */\nexport const createEnvironmentBodySchema = z.object({\n name: z.string().trim().min(1)\n});\n\n/**\n * Request body for updating an environment.\n */\nexport const updateEnvironmentBodySchema = z.object({\n name: z.string().trim().min(1),\n variables: z.array(variableSchema)\n});\n\n/**\n * Request body for creating a snippet.\n */\nexport const createSnippetBodySchema = z.object({\n name: z.string().trim().min(1),\n code: z.string().default(''),\n scope: snippetScopeSchema.default('any')\n});\n\n/**\n * Request body for updating a snippet.\n *\n * Sort order is not included: HarborClient's snippet update flow only\n * manages name/code/scope, so the server preserves the existing sort order.\n */\nexport const updateSnippetBodySchema = z.object({\n name: z.string().trim().min(1),\n code: z.string(),\n scope: snippetScopeSchema\n});\n\n/**\n * Request body for creating a folder.\n */\nexport const createFolderBodySchema = z.object({\n name: z.string().trim().min(1)\n});\n\n/**\n * Request body for renaming a folder.\n */\nexport const renameFolderBodySchema = z.object({\n name: z.string().trim().min(1)\n});\n\n/**\n * Request body for reordering folders within a collection.\n */\nexport const reorderFoldersBodySchema = z.object({\n orderedFolderIds: z.array(z.string().trim().min(1))\n});\n\n/**\n * Request body for creating or updating a saved request.\n */\nexport const saveRequestBodySchema = z.object({\n name: z.string().trim().min(1),\n method: httpMethodSchema,\n url: z.string(),\n headers: z.array(keyValueSchema),\n params: z.array(keyValueSchema),\n auth: authConfigSchema,\n body: z.string(),\n bodyType: bodyTypeSchema,\n preRequestScript: z.string(),\n postRequestScript: z.string(),\n comment: z.string(),\n folderId: z.string().nullable().optional()\n});\n\n/**\n * Request body for updating an existing saved request.\n */\nexport const updateSaveRequestBodySchema = saveRequestBodySchema.extend({\n collectionId: z.string().trim().min(1)\n});\n\n/**\n * Request body for reordering requests within a folder or collection root.\n */\nexport const reorderRequestsBodySchema = z.object({\n folderId: z.string().nullable(),\n orderedRequestIds: z.array(z.string().trim().min(1))\n});\n\n/**\n * Request body for moving a request to another folder or root index.\n */\nexport const moveRequestBodySchema = z.object({\n folderId: z.string().nullable(),\n index: z.number().int().min(0)\n});\n\n/**\n * List response wrapper for collections.\n */\nexport const listCollectionsResponseSchema = z.object({\n collections: z.array(collectionRecordSchema)\n});\n\n/**\n * List response wrapper for environments.\n */\nexport const listEnvironmentsResponseSchema = z.object({\n environments: z.array(environmentRecordSchema)\n});\n\n/**\n * List response wrapper for snippets.\n */\nexport const listSnippetsResponseSchema = z.object({\n snippets: z.array(snippetRecordSchema)\n});\n\n/**\n * List response wrapper for folders.\n */\nexport const listFoldersResponseSchema = z.object({\n folders: z.array(folderRecordSchema)\n});\n\n/**\n * List response wrapper for saved requests.\n */\nexport const listRequestsResponseSchema = z.object({\n requests: z.array(savedRequestRecordSchema)\n});\n\n/**\n * Empty JSON body schema for 204 No Content responses.\n */\nexport const emptyResponseSchema = z.null();\n\n/**\n * Serializes a collection record for JSON responses.\n *\n * @param record - Collection record from the database layer.\n * @returns Collection with ISO timestamp strings.\n */\nexport function serializeCollection(record: CollectionRecord) {\n return {\n ...record,\n createdAt: record.createdAt.toISOString(),\n updatedAt: record.updatedAt.toISOString()\n };\n}\n\n/**\n * Serializes an environment record for JSON responses.\n *\n * @param record - Environment record from the database layer.\n * @returns Environment with ISO timestamp strings.\n */\nexport function serializeEnvironment(record: EnvironmentRecord) {\n return {\n ...record,\n createdAt: record.createdAt.toISOString(),\n updatedAt: record.updatedAt.toISOString()\n };\n}\n\n/**\n * Serializes a snippet record for JSON responses.\n *\n * @param record - Snippet record from the database layer.\n * @returns Snippet with ISO timestamp strings.\n */\nexport function serializeSnippet(record: SnippetRecord) {\n return {\n ...record,\n createdAt: record.createdAt.toISOString(),\n updatedAt: record.updatedAt.toISOString()\n };\n}\n\n/**\n * Serializes a folder record for JSON responses.\n *\n * @param record - Folder record from the database layer.\n * @returns Folder with ISO timestamp strings.\n */\nexport function serializeFolder(record: FolderRecord) {\n return {\n ...record,\n createdAt: record.createdAt.toISOString(),\n updatedAt: record.updatedAt.toISOString()\n };\n}\n\n/**\n * Serializes a saved request record for JSON responses.\n *\n * @param record - Saved request record from the database layer.\n * @returns Saved request with ISO timestamp strings.\n */\nexport function serializeSavedRequest(record: SavedRequestRecord) {\n return {\n ...record,\n createdAt: record.createdAt.toISOString(),\n updatedAt: record.updatedAt.toISOString()\n };\n}\n\n/**\n * JSON shape for a persisted run result list record.\n */\nexport const runResultRecordSchema = z.object({\n id: z.string(),\n kind: z.enum(['collection-run-results', 'request-run-results']),\n label: z.string(),\n collectionName: z.string().nullable(),\n requestName: z.string().nullable(),\n summary: z.object({\n passed: z.number().int().nonnegative(),\n failed: z.number().int().nonnegative(),\n skipped: z.number().int().nonnegative()\n }),\n createdAt: timestampSchema,\n createdByUserId: z.string().nullable()\n});\n\n/**\n * JSON shape for a run result detail response including payload.\n */\nexport const runResultDetailSchema = runResultRecordSchema.extend({\n payload: z.record(z.string(), z.unknown())\n});\n\n/**\n * Request body schema for `POST /run-results`.\n */\nexport const createRunResultBodySchema = z.object({\n label: z.string().trim().min(1).optional(),\n payload: z.record(z.string(), z.unknown())\n});\n\n/**\n * List response wrapper for run results.\n */\nexport const listRunResultsResponseSchema = z.object({\n runResults: z.array(runResultRecordSchema)\n});\n\n/**\n * Serializes a run result record for JSON list responses.\n *\n * @param record - Run result record from the database layer.\n * @returns Run result metadata without the stored payload body.\n */\nexport function serializeRunResult(record: RunResultRecord) {\n return {\n id: record.id,\n kind: record.kind,\n label: record.label,\n collectionName: record.collectionName,\n requestName: record.requestName,\n summary: record.summary,\n createdAt: record.createdAt.toISOString(),\n createdByUserId: record.createdByUserId\n };\n}\n\n/**\n * Serializes a run result record for JSON detail responses.\n *\n * @param record - Run result record from the database layer.\n * @returns Run result metadata plus the stored payload body.\n */\nexport function serializeRunResultDetail(record: RunResultRecord) {\n return {\n ...serializeRunResult(record),\n payload: record.payload\n };\n}\n","import type { FastifyInstance, FastifyReply } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport type { IDatabase } from '#/db/IDatabase.js';\nimport type { UserRole } from '#/db/types.js';\nimport { isSystemUser } from '#/db/systemUsers.js';\nimport {\n buildAccessCatalogIds,\n buildAccessListWarnings,\n buildAdminUserCreateInput,\n buildAdminUserUpdateInput,\n validateSubmittedAccessLists\n} from '#/server/admin/userValidation.js';\nimport { canUseManagementApi } from '#/server/auth/accessControl.js';\nimport { generateApiToken } from '#/server/auth/apiTokens.js';\nimport { getHubLlmCapabilities, listHubOfferedModels } from '#/server/llm/models.js';\nimport { handleDbError, handleValidationError } from '#/server/routes/errors.js';\nimport { denyUnlessAllowed, requireAuthenticatedUser } from '#/server/routes/authorize.js';\nimport {\n createAdminTokenBodySchema,\n createAdminUserBodySchema,\n createAdminUserResponseSchema,\n createAdminSnippetBodySchema,\n createdApiTokenResponseSchema,\n adminEntityConfigSchema,\n adminSnippetRecordSchema,\n hubUserRecordSchema,\n listAdminCollectionsResponseSchema,\n listAdminEnvironmentsResponseSchema,\n listAdminLlmModelsResponseSchema,\n listAdminSnippetsResponseSchema,\n listAdminRunResultsResponseSchema,\n listAdminTokensResponseSchema,\n listAdminUsersResponseSchema,\n reloadConfigResponseSchema,\n serializeApiToken,\n serializeHubUser,\n updateAdminCollectionBodySchema,\n updateAdminEnvironmentBodySchema,\n updateAdminSnippetBodySchema,\n updateAdminUserBodySchema\n} from '#/server/routes/schemas/admin.js';\nimport {\n errorResponseSchema,\n idParamSchema,\n collectionIdParamSchema\n} from '#/server/routes/schemas/common.js';\nimport {\n emptyResponseSchema,\n listFoldersResponseSchema,\n listRequestsResponseSchema,\n serializeFolder,\n serializeRunResult,\n serializeSavedRequest,\n serializeSnippet\n} from '#/server/routes/schemas/entities.js';\nimport type { LlmConfig } from '#/config/llmConfig.js';\nimport type { ReloadResult } from '#/server/runtimeContext.js';\n\n/**\n * Options for registering management routes.\n */\nexport interface RegisterAdminRoutesOptions {\n /**\n * Database used to read user accounts and entity metadata.\n */\n db: IDatabase;\n\n /**\n * Returns the current normalized LLM configuration from server.yaml.\n */\n getLlm: () => LlmConfig | null;\n\n /**\n * Reloads server.yaml and returns a per-section report.\n */\n reloadConfig: () => Promise<ReloadResult>;\n}\n\n/**\n * Sends a 503 response when LLM support is not configured on the hub.\n *\n * @param reply - Fastify reply used to short-circuit the handler.\n */\nfunction sendLlmUnavailable(reply: FastifyReply): FastifyReply {\n return reply.code(503).send({\n error: 'LLM support is not configured on this Team Hub.'\n });\n}\n\n/**\n * Returns 403 when the target account is the internal system user.\n *\n * @param reply - Fastify reply used to send error payloads.\n * @param existing - User record being updated or deleted.\n * @param systemUserId - Cached system user id from the database, when known.\n * @returns True when the request was denied and a response was sent.\n */\nfunction denySystemUserTarget(\n reply: Parameters<typeof denyUnlessAllowed>[0],\n existing: { id: string; name: string },\n systemUserId: string | null\n): boolean {\n if (!isSystemUser(existing, systemUserId)) {\n return false;\n }\n\n void reply.code(403).send(errorResponseSchema.parse({ error: 'Forbidden' }));\n return true;\n}\n\n/**\n * Returns 403 when the target account is the authenticated operator.\n *\n * @param reply - Fastify reply used to send error payloads.\n * @param targetUserId - User id from the route parameter.\n * @param actorUserId - Authenticated operator performing the action.\n * @returns True when the request was denied and a response was sent.\n */\nfunction denySelfUserTarget(\n reply: Parameters<typeof denyUnlessAllowed>[0],\n targetUserId: string,\n actorUserId: string\n): boolean {\n if (targetUserId !== actorUserId) {\n return false;\n }\n\n void reply.code(403).send(errorResponseSchema.parse({ error: 'Forbidden' }));\n return true;\n}\n\n/**\n * Returns 403 when an operator attempts to change their own role.\n *\n * @param reply - Fastify reply used to send error payloads.\n * @param targetUserId - User id from the route parameter.\n * @param actorUserId - Authenticated operator performing the action.\n * @param existingRole - Current role stored for the target account.\n * @param requestedRole - Role from the request body, when provided.\n * @returns True when the request was denied and a response was sent.\n */\nfunction denySelfRoleChange(\n reply: Parameters<typeof denyUnlessAllowed>[0],\n targetUserId: string,\n actorUserId: string,\n existingRole: UserRole,\n requestedRole: UserRole | undefined\n): boolean {\n if (targetUserId !== actorUserId) {\n return false;\n }\n\n if (requestedRole === undefined || requestedRole === existingRole) {\n return false;\n }\n\n void reply.code(403).send(errorResponseSchema.parse({ error: 'Forbidden' }));\n return true;\n}\n\n/**\n * Registers bearer-protected management routes for operator accounts.\n *\n * @param app - Encapsulated Fastify scope with auth applied.\n * @param options - Database and LLM configuration.\n */\nexport async function registerAdminRoutes(\n app: FastifyInstance,\n options: RegisterAdminRoutesOptions\n): Promise<void> {\n const { db, getLlm, reloadConfig } = options;\n const routes = app.withTypeProvider<ZodTypeProvider>();\n\n routes.route({\n method: 'GET',\n url: '/admin/users',\n schema: {\n response: {\n 200: listAdminUsersResponseSchema,\n 403: errorResponseSchema\n }\n },\n /**\n * Lists all user accounts for operator administration.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const systemUserId = db.getSystemUserId();\n const llm = getLlm();\n const [users, collections, environments, snippets] = await Promise.all([\n db.listUsers(),\n db.listCollections(),\n db.listEnvironments(),\n db.listSnippets()\n ]);\n const catalogs = buildAccessCatalogIds(\n collections,\n environments,\n snippets,\n llm ? listHubOfferedModels(llm).map((model) => model.id) : null\n );\n\n return reply.send({\n users: users\n .filter((record) => !isSystemUser(record, systemUserId))\n .map((record) => ({\n ...serializeHubUser(record),\n warnings: buildAccessListWarnings(\n {\n collectionAccess: record.collectionAccess,\n environmentAccess: record.environmentAccess,\n snippetAccess: record.snippetAccess,\n llmModels: record.llmModels\n },\n catalogs\n )\n }))\n });\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'POST',\n url: '/admin/users',\n schema: {\n body: createAdminUserBodySchema,\n response: {\n 201: createAdminUserResponseSchema,\n 400: errorResponseSchema,\n 403: errorResponseSchema\n }\n },\n /**\n * Creates a user account and an initial API bearer token.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const input = buildAdminUserCreateInput(request.body);\n const llm = getLlm();\n const [collections, environments, snippets] = await Promise.all([\n db.listCollections(),\n db.listEnvironments(),\n db.listSnippets()\n ]);\n const catalogs = buildAccessCatalogIds(\n collections,\n environments,\n snippets,\n llm ? listHubOfferedModels(llm).map((model) => model.id) : null\n );\n validateSubmittedAccessLists(\n {\n role: request.body.role,\n collectionAccess: request.body.collectionAccess,\n environmentAccess: request.body.environmentAccess,\n snippetAccess: request.body.snippetAccess,\n llmModels: request.body.llmModels\n },\n catalogs\n );\n\n const created = await db.createUser(input, user.id);\n const { record, secret } = generateApiToken(created.id, created.name);\n await db.createApiToken(record, user.id);\n\n return reply.code(201).send({\n user: serializeHubUser(created),\n token: serializeApiToken(record),\n secret\n });\n } catch (error) {\n if (handleValidationError(reply, error) || handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'GET',\n url: '/admin/collections',\n schema: {\n response: {\n 200: listAdminCollectionsResponseSchema,\n 403: errorResponseSchema\n }\n },\n /**\n * Lists all collections for operator user management.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const collections = await db.listCollections();\n return reply.send({\n collections: collections.map((collection) => ({\n id: collection.id,\n name: collection.name,\n deletionLocked: collection.deletionLocked\n }))\n });\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'GET',\n url: '/admin/collections/:collectionId/folders',\n schema: {\n params: collectionIdParamSchema,\n response: {\n 200: listFoldersResponseSchema,\n 403: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Lists folders in a collection for operator inspection.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const collection = await db.findCollectionById(request.params.collectionId);\n if (!collection) {\n void reply.code(404).send({ error: 'Collection not found' });\n return;\n }\n\n const folders = await db.listFolders(request.params.collectionId);\n return reply.send({\n folders: folders.map((folder) => serializeFolder(folder))\n });\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'GET',\n url: '/admin/collections/:collectionId/requests',\n schema: {\n params: collectionIdParamSchema,\n response: {\n 200: listRequestsResponseSchema,\n 403: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Lists saved requests in a collection for operator inspection.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const collection = await db.findCollectionById(request.params.collectionId);\n if (!collection) {\n void reply.code(404).send({ error: 'Collection not found' });\n return;\n }\n\n const requests = await db.listRequests(request.params.collectionId);\n return reply.send({\n requests: requests.map((savedRequest) => serializeSavedRequest(savedRequest))\n });\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'GET',\n url: '/admin/environments',\n schema: {\n response: {\n 200: listAdminEnvironmentsResponseSchema,\n 403: errorResponseSchema\n }\n },\n /**\n * Lists all environments for operator user management.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const environments = await db.listEnvironments();\n return reply.send({\n environments: environments.map((environment) => ({\n id: environment.id,\n name: environment.name,\n deletionLocked: environment.deletionLocked\n }))\n });\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'GET',\n url: '/admin/snippets',\n schema: {\n response: {\n 200: listAdminSnippetsResponseSchema,\n 403: errorResponseSchema\n }\n },\n /**\n * Lists all snippets for operator user management.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const snippets = await db.listSnippets();\n return reply.send({\n snippets: snippets.map((snippet) => serializeSnippet(snippet))\n });\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'POST',\n url: '/admin/snippets',\n schema: {\n body: createAdminSnippetBodySchema,\n response: {\n 201: adminSnippetRecordSchema,\n 403: errorResponseSchema\n }\n },\n /**\n * Creates a snippet through the management API.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const snippet = await db.createSnippet(\n request.body.name,\n request.body.code,\n request.body.scope,\n user.id\n );\n return reply.code(201).send(serializeSnippet(snippet));\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'DELETE',\n url: '/admin/collections/:id',\n schema: {\n params: idParamSchema,\n response: {\n 204: emptyResponseSchema,\n 403: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Deletes a collection regardless of deletion lock state.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const collection = await db.findCollectionById(request.params.id);\n if (!collection) {\n void reply.code(404).send({ error: 'Collection not found' });\n return;\n }\n\n await db.deleteCollection(request.params.id, user.id);\n return reply.code(204).send(null);\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'DELETE',\n url: '/admin/requests/:id',\n schema: {\n params: idParamSchema,\n response: {\n 204: emptyResponseSchema,\n 403: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Deletes a saved request regardless of collection access lists.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const existingRequest = await db.findRequestById(request.params.id);\n if (!existingRequest) {\n void reply.code(404).send({ error: 'Request not found' });\n return;\n }\n\n await db.deleteRequest(request.params.id, user.id);\n return reply.code(204).send(null);\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'DELETE',\n url: '/admin/snippets/:id',\n schema: {\n params: idParamSchema,\n response: {\n 204: emptyResponseSchema,\n 403: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Deletes a snippet regardless of deletion lock state.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const snippet = await db.findSnippetById(request.params.id);\n if (!snippet) {\n void reply.code(404).send({ error: 'Snippet not found' });\n return;\n }\n\n await db.deleteSnippet(request.params.id, user.id);\n return reply.code(204).send(null);\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'GET',\n url: '/admin/run-results',\n schema: {\n response: {\n 200: listAdminRunResultsResponseSchema,\n 403: errorResponseSchema\n }\n },\n /**\n * Lists all run results for operator management.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const runResults = await db.listAllRunResults();\n return reply.send({\n runResults: runResults.map((record) => serializeRunResult(record))\n });\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'DELETE',\n url: '/admin/run-results/:id',\n schema: {\n params: idParamSchema,\n response: {\n 204: emptyResponseSchema,\n 403: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Deletes a run result regardless of creator ownership.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const record = await db.findRunResultById(request.params.id);\n if (!record) {\n void reply.code(404).send({ error: 'Run result not found' });\n return;\n }\n\n await db.deleteRunResult(request.params.id, user.id);\n return reply.code(204).send(null);\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'PUT',\n url: '/admin/snippets/:id',\n schema: {\n params: idParamSchema,\n body: updateAdminSnippetBodySchema,\n response: {\n 200: adminSnippetRecordSchema,\n 403: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Updates snippet content and/or admin configuration.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const existing = await db.findSnippetById(request.params.id);\n if (!existing) {\n void reply.code(404).send({ error: 'Snippet not found' });\n return;\n }\n\n let snippet = existing;\n const { name, code, scope, deletionLocked } = request.body;\n\n if (name !== undefined && code !== undefined && scope !== undefined) {\n snippet = await db.updateSnippet(request.params.id, name, code, scope, user.id);\n }\n\n if (deletionLocked !== undefined) {\n snippet = await db.setSnippetDeletionLocked(request.params.id, deletionLocked, user.id);\n }\n\n return reply.send(serializeSnippet(snippet));\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'PUT',\n url: '/admin/collections/:id',\n schema: {\n params: idParamSchema,\n body: updateAdminCollectionBodySchema,\n response: {\n 200: adminEntityConfigSchema,\n 403: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Updates admin configuration for a collection.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const collection = await db.setCollectionDeletionLocked(\n request.params.id,\n request.body.deletionLocked,\n user.id\n );\n\n return reply.send({\n id: collection.id,\n name: collection.name,\n deletionLocked: collection.deletionLocked\n });\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'DELETE',\n url: '/admin/environments/:id',\n schema: {\n params: idParamSchema,\n response: {\n 204: emptyResponseSchema,\n 403: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Deletes an environment regardless of deletion lock state.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const environment = await db.findEnvironmentById(request.params.id);\n if (!environment) {\n void reply.code(404).send({ error: 'Environment not found' });\n return;\n }\n\n await db.deleteEnvironment(request.params.id, user.id);\n return reply.code(204).send(null);\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'PUT',\n url: '/admin/environments/:id',\n schema: {\n params: idParamSchema,\n body: updateAdminEnvironmentBodySchema,\n response: {\n 200: adminEntityConfigSchema,\n 403: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Updates admin configuration for an environment.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const environment = await db.setEnvironmentDeletionLocked(\n request.params.id,\n request.body.deletionLocked,\n user.id\n );\n\n return reply.send({\n id: environment.id,\n name: environment.name,\n deletionLocked: environment.deletionLocked\n });\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'GET',\n url: '/admin/llm/models',\n schema: {\n response: {\n 200: listAdminLlmModelsResponseSchema,\n 403: errorResponseSchema,\n 503: errorResponseSchema\n }\n },\n /**\n * Lists all hub-offered LLM models for operator user management.\n */\n handler: async (request, reply) => {\n const llm = getLlm();\n if (!llm) {\n return sendLlmUnavailable(reply);\n }\n\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const models = listHubOfferedModels(llm).map((model) => ({\n id: model.id,\n label: model.label,\n provider: model.provider\n }));\n\n return reply.send({ models, capabilities: getHubLlmCapabilities(llm) });\n }\n });\n\n routes.route({\n method: 'PUT',\n url: '/admin/users/:id',\n schema: {\n params: idParamSchema,\n body: updateAdminUserBodySchema,\n response: {\n 200: hubUserRecordSchema,\n 400: errorResponseSchema,\n 403: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Updates a user account for operator administration.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const systemUserId = db.getSystemUserId();\n const existing = await db.findUserById(request.params.id);\n if (!existing) {\n void reply.code(404).send(errorResponseSchema.parse({ error: 'User not found' }));\n return;\n }\n\n if (denySystemUserTarget(reply, existing, systemUserId)) {\n return;\n }\n\n if (\n denySelfRoleChange(reply, request.params.id, user.id, existing.role, request.body.role)\n ) {\n return;\n }\n\n const input = buildAdminUserUpdateInput(existing, request.body);\n const role = request.body.role ?? existing.role;\n const llm = getLlm();\n const [collections, environments, snippets] = await Promise.all([\n db.listCollections(),\n db.listEnvironments(),\n db.listSnippets()\n ]);\n const catalogs = buildAccessCatalogIds(\n collections,\n environments,\n snippets,\n llm ? listHubOfferedModels(llm).map((model) => model.id) : null\n );\n validateSubmittedAccessLists(\n {\n role,\n collectionAccess: request.body.collectionAccess,\n environmentAccess: request.body.environmentAccess,\n snippetAccess: request.body.snippetAccess,\n llmModels: request.body.llmModels\n },\n catalogs\n );\n\n const updated = await db.updateUser(request.params.id, input, user.id);\n return reply.send(serializeHubUser(updated));\n } catch (error) {\n if (handleValidationError(reply, error) || handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'DELETE',\n url: '/admin/users/:id',\n schema: {\n params: idParamSchema,\n response: {\n 204: emptyResponseSchema,\n 403: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Deletes a user account and removes all of their API tokens.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const systemUserId = db.getSystemUserId();\n const existing = await db.findUserById(request.params.id);\n if (!existing) {\n void reply.code(404).send(errorResponseSchema.parse({ error: 'User not found' }));\n return;\n }\n\n if (denySystemUserTarget(reply, existing, systemUserId)) {\n return;\n }\n\n if (denySelfUserTarget(reply, request.params.id, user.id)) {\n return;\n }\n\n await db.deleteUser(request.params.id, user.id);\n return reply.code(204).send(null);\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'GET',\n url: '/admin/tokens',\n schema: {\n response: {\n 200: listAdminTokensResponseSchema,\n 403: errorResponseSchema\n }\n },\n /**\n * Lists all API bearer tokens for operator administration.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const tokens = await db.listApiTokens();\n return reply.send({\n tokens: tokens.map((record) => serializeApiToken(record))\n });\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'POST',\n url: '/admin/users/:id/tokens',\n schema: {\n params: idParamSchema,\n body: createAdminTokenBodySchema,\n response: {\n 201: createdApiTokenResponseSchema,\n 400: errorResponseSchema,\n 403: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Creates an additional API bearer token for a user account.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const systemUserId = db.getSystemUserId();\n const existing = await db.findUserById(request.params.id);\n if (!existing) {\n void reply.code(404).send(errorResponseSchema.parse({ error: 'User not found' }));\n return;\n }\n\n if (denySystemUserTarget(reply, existing, systemUserId)) {\n return;\n }\n\n const { record, secret } = generateApiToken(existing.id, request.body.name);\n await db.createApiToken(record, user.id);\n\n return reply.code(201).send({\n token: serializeApiToken(record),\n secret\n });\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'DELETE',\n url: '/admin/tokens/:id',\n schema: {\n params: idParamSchema,\n response: {\n 204: emptyResponseSchema,\n 403: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Permanently deletes an API bearer token by id.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const systemUserId = db.getSystemUserId();\n const existing = await db.findApiTokenById(request.params.id);\n if (!existing) {\n void reply.code(404).send(errorResponseSchema.parse({ error: 'Token not found' }));\n return;\n }\n\n const owner = await db.findUserById(existing.userId);\n if (owner && denySystemUserTarget(reply, owner, systemUserId)) {\n return;\n }\n\n const deleted = await db.deleteApiToken(request.params.id, user.id);\n if (!deleted) {\n void reply.code(404).send(errorResponseSchema.parse({ error: 'Token not found' }));\n return;\n }\n\n return reply.code(204).send(null);\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'POST',\n url: '/admin/config/reload',\n schema: {\n response: {\n 200: reloadConfigResponseSchema,\n 400: reloadConfigResponseSchema,\n 403: errorResponseSchema\n }\n },\n /**\n * Re-reads server.yaml and applies reloadable config sections on a best-effort basis.\n */\n handler: async (request, reply) => {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseManagementApi(user))) {\n return;\n }\n\n const result = await reloadConfig();\n if (result.fatalError) {\n return reply.code(400).send(result);\n }\n\n return reply.send(result);\n }\n });\n}\n","import type { ApiTokenRecord, UserRecord } from '#/db/types.js';\nimport { canUseDataApi, canUseLlm, isAdmin } from '#/server/auth/accessControl.js';\n\n/**\n * Capability flags derived from the authenticated user account.\n */\nexport interface SessionCapabilities {\n /**\n * When true, the token may call entity data routes (collections, environments, etc.).\n */\n dataApi: boolean;\n\n /**\n * When true, the token may call management routes (user and token administration).\n */\n managementApi: boolean;\n\n /**\n * When true, the token may call hub-proxied LLM routes.\n */\n llm: boolean;\n}\n\n/**\n * JSON payload returned by `GET /auth/session`.\n */\nexport interface SessionPayload {\n /**\n * User account owning the authenticated bearer token.\n */\n user: {\n /**\n * Stable user account identifier.\n */\n id: string;\n\n /**\n * Unique display name for the account.\n */\n name: string;\n\n /**\n * Account role determining API capabilities.\n */\n role: UserRecord['role'];\n };\n\n /**\n * Metadata for the API token used to authenticate the request.\n */\n token: {\n /**\n * Stable token record identifier.\n */\n id: string;\n\n /**\n * Non-secret prefix shown in operator listings (for example `hbk_AbCd1234`).\n */\n prefix: string;\n };\n\n /**\n * Derived capability flags for clients such as HarborClient.\n */\n capabilities: SessionCapabilities;\n}\n\n/**\n * Builds the session payload for the authenticated user and API token.\n *\n * @param user - User account resolved from the bearer token.\n * @param apiToken - Active API token record used for authentication.\n * @returns Session payload suitable for JSON serialization.\n */\nexport function buildSessionPayload(user: UserRecord, apiToken: ApiTokenRecord): SessionPayload {\n return {\n user: {\n id: user.id,\n name: user.name,\n role: user.role\n },\n token: {\n id: apiToken.id,\n prefix: apiToken.tokenPrefix\n },\n capabilities: {\n dataApi: canUseDataApi(user),\n managementApi: isAdmin(user),\n llm: canUseLlm(user)\n }\n };\n}\n","import type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport { buildSessionPayload } from '#/server/auth/sessionCapabilities.js';\nimport { requireAuthenticatedUser } from '#/server/routes/authorize.js';\nimport { sessionResponseSchema } from '#/server/routes/schemas/auth.js';\n\n/**\n * Registers bearer-protected authentication introspection routes.\n *\n * @param app - Encapsulated Fastify scope with auth applied.\n */\nexport async function registerAuthRoutes(app: FastifyInstance): Promise<void> {\n const routes = app.withTypeProvider<ZodTypeProvider>();\n\n routes.route({\n method: 'GET',\n url: '/auth/session',\n schema: {\n response: {\n 200: sessionResponseSchema\n }\n },\n /**\n * Returns the authenticated user, token metadata, and derived API capabilities.\n */\n handler: async (request, reply) => {\n const user = requireAuthenticatedUser(request);\n const apiToken = request.apiToken;\n\n if (!apiToken) {\n throw new Error('Authenticated API token is required');\n }\n\n return reply.send(buildSessionPayload(user, apiToken));\n }\n });\n}\n","import type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport type { IDatabase } from '#/db/IDatabase.js';\nimport {\n canAccessCollection,\n canCreateCollection,\n canDeleteCollection,\n canListCollections,\n canUseDataApi,\n filterAccessibleCollections\n} from '#/server/auth/accessControl.js';\nimport { DeletionLockedError } from '#/db/deletionLockedError.js';\nimport { handleDbError } from '#/server/routes/errors.js';\nimport { denyUnlessAllowed, requireAuthenticatedUser } from '#/server/routes/authorize.js';\nimport { errorResponseSchema, idParamSchema } from '#/server/routes/schemas/common.js';\nimport {\n collectionRecordSchema,\n createCollectionBodySchema,\n emptyResponseSchema,\n listCollectionsResponseSchema,\n serializeCollection,\n updateCollectionBodySchema\n} from '#/server/routes/schemas/entities.js';\n\n/**\n * Registers bearer-protected collection CRUD routes.\n *\n * @param app - Encapsulated Fastify scope with auth applied.\n * @param db - Database used to persist collections.\n */\nexport async function registerCollectionRoutes(app: FastifyInstance, db: IDatabase): Promise<void> {\n const routes = app.withTypeProvider<ZodTypeProvider>();\n\n routes.route({\n method: 'GET',\n url: '/collections',\n schema: {\n response: {\n 200: listCollectionsResponseSchema\n }\n },\n /**\n * Lists all collections ordered by name.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canListCollections(user))) {\n return;\n }\n\n const collections = await db.listCollections();\n return reply.send({\n collections: filterAccessibleCollections(user, collections).map((collection) =>\n serializeCollection(collection)\n )\n });\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'POST',\n url: '/collections',\n schema: {\n body: createCollectionBodySchema,\n response: {\n 200: collectionRecordSchema,\n 400: errorResponseSchema\n }\n },\n /**\n * Creates a new collection with the given display name.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseDataApi(user) && canCreateCollection(user))) {\n return;\n }\n\n const collection = await db.createCollection(request.body.name, user.id);\n return reply.send(serializeCollection(collection));\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'PUT',\n url: '/collections/:id',\n schema: {\n params: idParamSchema,\n body: updateCollectionBodySchema,\n response: {\n 200: collectionRecordSchema,\n 400: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Updates a collection's metadata and defaults.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (\n denyUnlessAllowed(\n reply,\n canUseDataApi(user) && canAccessCollection(user, request.params.id)\n )\n ) {\n return;\n }\n\n const collection = await db.updateCollection(\n request.params.id,\n request.body.name,\n request.body.variables,\n request.body.headers,\n request.body.preRequestScript,\n request.body.postRequestScript,\n request.body.auth,\n user.id\n );\n return reply.send(serializeCollection(collection));\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'DELETE',\n url: '/collections/:id',\n schema: {\n params: idParamSchema,\n response: {\n 204: emptyResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Deletes a collection and all nested folders and requests.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n const collection = await db.findCollectionById(request.params.id);\n if (!collection) {\n void reply.code(404).send({ error: 'Collection not found' });\n return;\n }\n\n if (collection.deletionLocked) {\n throw new DeletionLockedError('collection');\n }\n\n if (denyUnlessAllowed(reply, canDeleteCollection(user, collection))) {\n return;\n }\n\n await db.deleteCollection(request.params.id, user.id);\n return reply.code(204).send(null);\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n}\n","import type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport type { IDatabase } from '#/db/IDatabase.js';\nimport {\n canAccessEnvironment,\n canCreateEnvironment,\n canListEnvironments,\n canUseDataApi,\n filterAccessibleEnvironments\n} from '#/server/auth/accessControl.js';\nimport { DeletionLockedError } from '#/db/deletionLockedError.js';\nimport { handleDbError } from '#/server/routes/errors.js';\nimport { denyUnlessAllowed, requireAuthenticatedUser } from '#/server/routes/authorize.js';\nimport { errorResponseSchema, idParamSchema } from '#/server/routes/schemas/common.js';\nimport {\n createEnvironmentBodySchema,\n emptyResponseSchema,\n environmentRecordSchema,\n listEnvironmentsResponseSchema,\n serializeEnvironment,\n updateEnvironmentBodySchema\n} from '#/server/routes/schemas/entities.js';\n\n/**\n * Registers bearer-protected environment CRUD routes.\n *\n * @param app - Encapsulated Fastify scope with auth applied.\n * @param db - Database used to persist environments.\n */\nexport async function registerEnvironmentRoutes(\n app: FastifyInstance,\n db: IDatabase\n): Promise<void> {\n const routes = app.withTypeProvider<ZodTypeProvider>();\n\n routes.route({\n method: 'GET',\n url: '/environments',\n schema: {\n response: {\n 200: listEnvironmentsResponseSchema\n }\n },\n /**\n * Lists all environments ordered by name.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canListEnvironments(user))) {\n return;\n }\n\n const environments = await db.listEnvironments();\n return reply.send({\n environments: filterAccessibleEnvironments(user, environments).map((environment) =>\n serializeEnvironment(environment)\n )\n });\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'POST',\n url: '/environments',\n schema: {\n body: createEnvironmentBodySchema,\n response: {\n 200: environmentRecordSchema,\n 400: errorResponseSchema\n }\n },\n /**\n * Creates a new environment with the given display name.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseDataApi(user) && canCreateEnvironment(user))) {\n return;\n }\n\n const environment = await db.createEnvironment(request.body.name, user.id);\n return reply.send(serializeEnvironment(environment));\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'PUT',\n url: '/environments/:id',\n schema: {\n params: idParamSchema,\n body: updateEnvironmentBodySchema,\n response: {\n 200: environmentRecordSchema,\n 400: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Updates an environment's name and variables.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (\n denyUnlessAllowed(\n reply,\n canUseDataApi(user) && canAccessEnvironment(user, request.params.id)\n )\n ) {\n return;\n }\n\n const environment = await db.updateEnvironment(\n request.params.id,\n request.body.name,\n request.body.variables,\n user.id\n );\n return reply.send(serializeEnvironment(environment));\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'DELETE',\n url: '/environments/:id',\n schema: {\n params: idParamSchema,\n response: {\n 204: emptyResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Deletes an environment by id.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (\n denyUnlessAllowed(\n reply,\n canUseDataApi(user) && canAccessEnvironment(user, request.params.id)\n )\n ) {\n return;\n }\n\n const environment = await db.findEnvironmentById(request.params.id);\n if (!environment) {\n void reply.code(404).send({ error: 'Environment not found' });\n return;\n }\n\n if (environment.deletionLocked) {\n throw new DeletionLockedError('environment');\n }\n\n await db.deleteEnvironment(request.params.id, user.id);\n return reply.code(204).send(null);\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n}\n","import type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport type { IDatabase } from '#/db/IDatabase.js';\nimport {\n canAccessSnippet,\n canCreateSnippet,\n canListSnippets,\n canUseDataApi,\n filterAccessibleSnippets\n} from '#/server/auth/accessControl.js';\nimport { DeletionLockedError } from '#/db/deletionLockedError.js';\nimport { handleDbError } from '#/server/routes/errors.js';\nimport { denyUnlessAllowed, requireAuthenticatedUser } from '#/server/routes/authorize.js';\nimport { errorResponseSchema, idParamSchema } from '#/server/routes/schemas/common.js';\nimport {\n createSnippetBodySchema,\n emptyResponseSchema,\n listSnippetsResponseSchema,\n serializeSnippet,\n snippetRecordSchema,\n updateSnippetBodySchema\n} from '#/server/routes/schemas/entities.js';\n\n/**\n * Registers bearer-protected snippet CRUD routes.\n *\n * @param app - Encapsulated Fastify scope with auth applied.\n * @param db - Database used to persist snippets.\n */\nexport async function registerSnippetRoutes(app: FastifyInstance, db: IDatabase): Promise<void> {\n const routes = app.withTypeProvider<ZodTypeProvider>();\n\n routes.route({\n method: 'GET',\n url: '/snippets',\n schema: {\n response: {\n 200: listSnippetsResponseSchema\n }\n },\n /**\n * Lists all snippets ordered by sort order then name.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canListSnippets(user))) {\n return;\n }\n\n const snippets = await db.listSnippets();\n return reply.send({\n snippets: filterAccessibleSnippets(user, snippets).map((snippet) =>\n serializeSnippet(snippet)\n )\n });\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'POST',\n url: '/snippets',\n schema: {\n body: createSnippetBodySchema,\n response: {\n 200: snippetRecordSchema,\n 400: errorResponseSchema\n }\n },\n /**\n * Creates a new snippet with the given display name and content.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseDataApi(user) && canCreateSnippet(user))) {\n return;\n }\n\n const snippet = await db.createSnippet(\n request.body.name,\n request.body.code,\n request.body.scope,\n user.id\n );\n return reply.send(serializeSnippet(snippet));\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'PUT',\n url: '/snippets/:id',\n schema: {\n params: idParamSchema,\n body: updateSnippetBodySchema,\n response: {\n 200: snippetRecordSchema,\n 400: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Updates a snippet's name, code, and scope. Sort order is preserved.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (\n denyUnlessAllowed(reply, canUseDataApi(user) && canAccessSnippet(user, request.params.id))\n ) {\n return;\n }\n\n const snippet = await db.updateSnippet(\n request.params.id,\n request.body.name,\n request.body.code,\n request.body.scope,\n user.id\n );\n return reply.send(serializeSnippet(snippet));\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'DELETE',\n url: '/snippets/:id',\n schema: {\n params: idParamSchema,\n response: {\n 204: emptyResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Deletes a snippet by id.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (\n denyUnlessAllowed(reply, canUseDataApi(user) && canAccessSnippet(user, request.params.id))\n ) {\n return;\n }\n\n const snippet = await db.findSnippetById(request.params.id);\n if (!snippet) {\n void reply.code(404).send({ error: 'Snippet not found' });\n return;\n }\n\n if (snippet.deletionLocked) {\n throw new DeletionLockedError('snippet');\n }\n\n await db.deleteSnippet(request.params.id, user.id);\n return reply.code(204).send(null);\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n}\n","import type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport type { IDatabase } from '#/db/IDatabase.js';\nimport { canAccessCollection, canUseDataApi } from '#/server/auth/accessControl.js';\nimport { handleDbError } from '#/server/routes/errors.js';\nimport { denyUnlessAllowed, requireAuthenticatedUser } from '#/server/routes/authorize.js';\nimport {\n collectionIdParamSchema,\n errorResponseSchema,\n idParamSchema\n} from '#/server/routes/schemas/common.js';\nimport {\n createFolderBodySchema,\n emptyResponseSchema,\n folderRecordSchema,\n listFoldersResponseSchema,\n renameFolderBodySchema,\n reorderFoldersBodySchema,\n serializeFolder\n} from '#/server/routes/schemas/entities.js';\n\n/**\n * Registers bearer-protected folder CRUD and reorder routes.\n *\n * @param app - Encapsulated Fastify scope with auth applied.\n * @param db - Database used to persist folders.\n */\nexport async function registerFolderRoutes(app: FastifyInstance, db: IDatabase): Promise<void> {\n const routes = app.withTypeProvider<ZodTypeProvider>();\n\n routes.route({\n method: 'GET',\n url: '/collections/:collectionId/folders',\n schema: {\n params: collectionIdParamSchema,\n response: {\n 200: listFoldersResponseSchema\n }\n },\n /**\n * Lists folders in a collection ordered by sort order then name.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (\n denyUnlessAllowed(\n reply,\n canUseDataApi(user) && canAccessCollection(user, request.params.collectionId)\n )\n ) {\n return;\n }\n\n const folders = await db.listFolders(request.params.collectionId);\n return reply.send({\n folders: folders.map((folder) => serializeFolder(folder))\n });\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'POST',\n url: '/collections/:collectionId/folders',\n schema: {\n params: collectionIdParamSchema,\n body: createFolderBodySchema,\n response: {\n 200: folderRecordSchema,\n 400: errorResponseSchema\n }\n },\n /**\n * Creates a folder in the given collection.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (\n denyUnlessAllowed(\n reply,\n canUseDataApi(user) && canAccessCollection(user, request.params.collectionId)\n )\n ) {\n return;\n }\n\n const folder = await db.createFolder(\n request.params.collectionId,\n request.body.name,\n user.id\n );\n return reply.send(serializeFolder(folder));\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'PATCH',\n url: '/folders/:id',\n schema: {\n params: idParamSchema,\n body: renameFolderBodySchema,\n response: {\n 200: folderRecordSchema,\n 400: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Renames a folder by id.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n const existingFolder = await db.findFolderById(request.params.id);\n if (!existingFolder) {\n return reply.code(404).send({ error: 'Folder not found' });\n }\n\n if (\n denyUnlessAllowed(\n reply,\n canUseDataApi(user) && canAccessCollection(user, existingFolder.collectionId)\n )\n ) {\n return;\n }\n\n const folder = await db.renameFolder(request.params.id, request.body.name, user.id);\n return reply.send(serializeFolder(folder));\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'DELETE',\n url: '/folders/:id',\n schema: {\n params: idParamSchema,\n response: {\n 204: emptyResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Deletes a folder and all requests inside it.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n const existingFolder = await db.findFolderById(request.params.id);\n if (!existingFolder) {\n return reply.code(404).send({ error: 'Folder not found' });\n }\n\n if (\n denyUnlessAllowed(\n reply,\n canUseDataApi(user) && canAccessCollection(user, existingFolder.collectionId)\n )\n ) {\n return;\n }\n\n await db.deleteFolder(request.params.id, user.id);\n return reply.code(204).send(null);\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'PUT',\n url: '/collections/:collectionId/folders/reorder',\n schema: {\n params: collectionIdParamSchema,\n body: reorderFoldersBodySchema,\n response: {\n 204: emptyResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Reorders folders within a collection.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (\n denyUnlessAllowed(\n reply,\n canUseDataApi(user) && canAccessCollection(user, request.params.collectionId)\n )\n ) {\n return;\n }\n\n await db.reorderFolders(\n request.params.collectionId,\n request.body.orderedFolderIds,\n user.id\n );\n return reply.code(204).send(null);\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n}\n","import { z } from 'zod/v4';\nimport type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\n\n/**\n * Response body schema for `GET /health`.\n */\nexport const healthResponseSchema = z.object({\n status: z.literal('ok'),\n version: z.string()\n});\n\n/**\n * Registers the health check route used by probes and desktop client connectivity checks.\n *\n * @param app - Fastify server instance.\n * @param version - Application version included in the JSON response.\n */\nexport async function registerHealthRoute(app: FastifyInstance, version: string): Promise<void> {\n app.withTypeProvider<ZodTypeProvider>().route({\n method: 'GET',\n url: '/health',\n schema: {\n response: {\n 200: healthResponseSchema\n }\n },\n /**\n * Returns the standard health payload for load balancers and client pings.\n */\n handler: async (_request, reply) => {\n return reply.send({\n status: 'ok' as const,\n version\n });\n }\n });\n}\n","import type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport type { IDatabase } from '#/db/IDatabase.js';\nimport {\n canAccessCollection,\n canDeleteRequest,\n canUseDataApi\n} from '#/server/auth/accessControl.js';\nimport { handleDbError } from '#/server/routes/errors.js';\nimport { denyUnlessAllowed, requireAuthenticatedUser } from '#/server/routes/authorize.js';\nimport {\n collectionIdParamSchema,\n errorResponseSchema,\n idParamSchema\n} from '#/server/routes/schemas/common.js';\nimport {\n emptyResponseSchema,\n listRequestsResponseSchema,\n moveRequestBodySchema,\n reorderRequestsBodySchema,\n savedRequestRecordSchema,\n saveRequestBodySchema,\n serializeSavedRequest,\n updateSaveRequestBodySchema\n} from '#/server/routes/schemas/entities.js';\n\n/**\n * Registers bearer-protected saved request CRUD, reorder, and move routes.\n *\n * @param app - Encapsulated Fastify scope with auth applied.\n * @param db - Database used to persist saved requests.\n */\nexport async function registerRequestRoutes(app: FastifyInstance, db: IDatabase): Promise<void> {\n const routes = app.withTypeProvider<ZodTypeProvider>();\n\n routes.route({\n method: 'GET',\n url: '/collections/:collectionId/requests',\n schema: {\n params: collectionIdParamSchema,\n response: {\n 200: listRequestsResponseSchema\n }\n },\n /**\n * Lists saved requests in a collection.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (\n denyUnlessAllowed(\n reply,\n canUseDataApi(user) && canAccessCollection(user, request.params.collectionId)\n )\n ) {\n return;\n }\n\n const requests = await db.listRequests(request.params.collectionId);\n return reply.send({\n requests: requests.map((savedRequest) => serializeSavedRequest(savedRequest))\n });\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'POST',\n url: '/collections/:collectionId/requests',\n schema: {\n params: collectionIdParamSchema,\n body: saveRequestBodySchema,\n response: {\n 200: savedRequestRecordSchema,\n 400: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Creates a new saved request in a collection.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (\n denyUnlessAllowed(\n reply,\n canUseDataApi(user) && canAccessCollection(user, request.params.collectionId)\n )\n ) {\n return;\n }\n\n const savedRequest = await db.saveRequest(\n {\n collectionId: request.params.collectionId,\n name: request.body.name,\n method: request.body.method,\n url: request.body.url,\n headers: request.body.headers,\n params: request.body.params,\n auth: request.body.auth,\n body: request.body.body,\n bodyType: request.body.bodyType,\n preRequestScript: request.body.preRequestScript,\n postRequestScript: request.body.postRequestScript,\n comment: request.body.comment,\n folderId: request.body.folderId ?? null\n },\n user.id\n );\n return reply.send(serializeSavedRequest(savedRequest));\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'PUT',\n url: '/requests/:id',\n schema: {\n params: idParamSchema,\n body: updateSaveRequestBodySchema,\n response: {\n 200: savedRequestRecordSchema,\n 400: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Updates an existing saved request by id.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (\n denyUnlessAllowed(\n reply,\n canUseDataApi(user) && canAccessCollection(user, request.body.collectionId)\n )\n ) {\n return;\n }\n\n const savedRequest = await db.saveRequest(\n {\n id: request.params.id,\n collectionId: request.body.collectionId,\n name: request.body.name,\n method: request.body.method,\n url: request.body.url,\n headers: request.body.headers,\n params: request.body.params,\n auth: request.body.auth,\n body: request.body.body,\n bodyType: request.body.bodyType,\n preRequestScript: request.body.preRequestScript,\n postRequestScript: request.body.postRequestScript,\n comment: request.body.comment,\n folderId: request.body.folderId ?? null\n },\n user.id\n );\n return reply.send(serializeSavedRequest(savedRequest));\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'DELETE',\n url: '/requests/:id',\n schema: {\n params: idParamSchema,\n response: {\n 204: emptyResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Deletes a saved request by id.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n const existingRequest = await db.findRequestById(request.params.id);\n if (!existingRequest) {\n return reply.code(404).send({ error: 'Request not found' });\n }\n\n if (denyUnlessAllowed(reply, canDeleteRequest(user, existingRequest))) {\n return;\n }\n\n await db.deleteRequest(request.params.id, user.id);\n return reply.code(204).send(null);\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'PUT',\n url: '/collections/:collectionId/requests/reorder',\n schema: {\n params: collectionIdParamSchema,\n body: reorderRequestsBodySchema,\n response: {\n 204: emptyResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Reorders saved requests within a folder or collection root.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (\n denyUnlessAllowed(\n reply,\n canUseDataApi(user) && canAccessCollection(user, request.params.collectionId)\n )\n ) {\n return;\n }\n\n await db.reorderRequests(\n request.params.collectionId,\n request.body.folderId,\n request.body.orderedRequestIds,\n user.id\n );\n return reply.code(204).send(null);\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'PUT',\n url: '/requests/:id/move',\n schema: {\n params: idParamSchema,\n body: moveRequestBodySchema,\n response: {\n 204: emptyResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Moves a saved request to another folder or collection root index.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n const existingRequest = await db.findRequestById(request.params.id);\n if (!existingRequest) {\n return reply.code(404).send({ error: 'Request not found' });\n }\n\n if (\n denyUnlessAllowed(\n reply,\n canUseDataApi(user) && canAccessCollection(user, existingRequest.collectionId)\n )\n ) {\n return;\n }\n\n await db.moveRequest(request.params.id, request.body.folderId, request.body.index, user.id);\n return reply.code(204).send(null);\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n}\n","import type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport type { IDatabase } from '#/db/IDatabase.js';\nimport {\n canDeleteRunResult,\n canListRunResults,\n canUseDataApi\n} from '#/server/auth/accessControl.js';\nimport { handleDbError } from '#/server/routes/errors.js';\nimport { denyUnlessAllowed, requireAuthenticatedUser } from '#/server/routes/authorize.js';\nimport { errorResponseSchema, idParamSchema } from '#/server/routes/schemas/common.js';\nimport {\n createRunResultBodySchema,\n emptyResponseSchema,\n listRunResultsResponseSchema,\n runResultDetailSchema,\n serializeRunResult,\n serializeRunResultDetail\n} from '#/server/routes/schemas/entities.js';\n\n/**\n * Registers bearer-protected run result routes.\n *\n * @param app - Encapsulated Fastify scope with auth applied.\n * @param db - Database used to persist run result snapshots.\n */\nexport async function registerRunResultRoutes(app: FastifyInstance, db: IDatabase): Promise<void> {\n const routes = app.withTypeProvider<ZodTypeProvider>();\n\n routes.route({\n method: 'GET',\n url: '/run-results',\n schema: {\n response: {\n 200: listRunResultsResponseSchema\n }\n },\n /**\n * Lists run results saved by the authenticated user token.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canListRunResults(user))) {\n return;\n }\n\n const runResults = await db.listRunResultsForUser(user.id);\n return reply.send({\n runResults: runResults.map((record) => serializeRunResult(record))\n });\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'POST',\n url: '/run-results',\n schema: {\n body: createRunResultBodySchema,\n response: {\n 200: runResultDetailSchema,\n 400: errorResponseSchema\n }\n },\n /**\n * Saves a standalone run result snapshot.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseDataApi(user))) {\n return;\n }\n\n const record = await db.createRunResult(request.body, user.id);\n return reply.send(serializeRunResultDetail(record));\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'GET',\n url: '/run-results/:id',\n schema: {\n params: idParamSchema,\n response: {\n 200: runResultDetailSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Loads a run result snapshot by id for shared deep links.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseDataApi(user))) {\n return;\n }\n\n const record = await db.findRunResultById(request.params.id);\n if (!record) {\n void reply.code(404).send({ error: 'Run result not found' });\n return;\n }\n\n return reply.send(serializeRunResultDetail(record));\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n\n routes.route({\n method: 'DELETE',\n url: '/run-results/:id',\n schema: {\n params: idParamSchema,\n response: {\n 204: emptyResponseSchema,\n 403: errorResponseSchema,\n 404: errorResponseSchema\n }\n },\n /**\n * Deletes a run result saved by the authenticated user when permitted.\n */\n handler: async (request, reply) => {\n try {\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseDataApi(user))) {\n return;\n }\n\n const record = await db.findRunResultById(request.params.id);\n if (!record) {\n void reply.code(404).send({ error: 'Run result not found' });\n return;\n }\n\n if (denyUnlessAllowed(reply, canDeleteRunResult(user, record))) {\n return;\n }\n\n await db.deleteRunResult(request.params.id, user.id);\n return reply.code(204).send(null);\n } catch (error) {\n if (handleDbError(reply, error)) {\n return;\n }\n\n throw error;\n }\n }\n });\n}\n","import type { LlmConfig, LlmProvider } from '#/config/llmConfig.js';\nimport { getHubModelById } from '#/server/llm/models.js';\n\nconst OPENAI_BASE_URL = 'https://api.openai.com/v1';\nconst CLAUDE_BASE_URL = 'https://api.anthropic.com/v1';\nconst GEMINI_BASE_URL = 'https://generativelanguage.googleapis.com/v1beta/openai';\n\n/**\n * Serializable tool call returned from a provider completion.\n */\nexport interface LlmToolCall {\n /**\n * Tool call id from the model.\n */\n id: string;\n\n /**\n * Tool function name.\n */\n name: string;\n\n /**\n * JSON-encoded tool arguments.\n */\n arguments: string;\n}\n\n/**\n * Token usage reported by the provider for one completion.\n */\nexport interface LlmCompletionUsage {\n /**\n * Prompt tokens consumed by the request.\n */\n promptTokens: number;\n\n /**\n * Completion tokens generated by the model.\n */\n completionTokens: number;\n\n /**\n * Total tokens billed for the request.\n */\n totalTokens: number;\n}\n\n/**\n * Normalized result of one OpenAI-compatible chat completion.\n */\nexport interface LlmCompletionResult {\n /**\n * Assistant text when the model finishes without tool calls.\n */\n content: string | null;\n\n /**\n * Tool calls requested by the assistant, when present.\n */\n toolCalls?: LlmToolCall[];\n\n /**\n * Token usage for metering.\n */\n usage: LlmCompletionUsage;\n}\n\n/**\n * Message role accepted by the OpenAI-compatible chat API.\n */\nexport type LlmChatMessageRole = 'system' | 'user' | 'assistant' | 'tool';\n\n/**\n * Serializable chat message for provider requests.\n */\nexport interface LlmChatMessage {\n /**\n * OpenAI-compatible message role.\n */\n role: LlmChatMessageRole;\n\n /**\n * Text content for the message.\n */\n content?: string | null;\n\n /**\n * Tool calls on assistant messages.\n */\n tool_calls?: LlmToolCall[];\n\n /**\n * Tool call id for tool role messages.\n */\n tool_call_id?: string;\n\n /**\n * Optional tool name for tool role messages.\n */\n name?: string;\n}\n\n/**\n * OpenAI-compatible tool definition passed through from the client.\n */\nexport type LlmToolDefinition = Record<string, unknown>;\n\n/**\n * Input for one hub-proxied chat completion.\n */\nexport interface RunLlmCompletionInput {\n /**\n * Provider-specific model id.\n */\n model: string;\n\n /**\n * Conversation messages excluding the system prompt.\n */\n messages: LlmChatMessage[];\n\n /**\n * Optional system prompt injected ahead of messages.\n */\n systemPrompt?: string;\n\n /**\n * Optional tool definitions forwarded to the provider.\n */\n tools?: LlmToolDefinition[];\n}\n\n/**\n * Resolves the base URL for an OpenAI-compatible provider.\n *\n * @param provider - LLM provider to call.\n */\nfunction resolveProviderBaseUrl(provider: LlmProvider): string {\n switch (provider) {\n case 'openai':\n return OPENAI_BASE_URL;\n case 'claude':\n return CLAUDE_BASE_URL;\n case 'gemini':\n return GEMINI_BASE_URL;\n default: {\n const exhaustive: never = provider;\n return exhaustive;\n }\n }\n}\n\n/**\n * Maps hub messages into OpenAI-compatible request message objects.\n *\n * @param messages - Messages from the client step request.\n */\nfunction toProviderMessages(messages: LlmChatMessage[]): Record<string, unknown>[] {\n return messages.map((message) => {\n if (message.role === 'assistant' && message.tool_calls?.length) {\n return {\n role: 'assistant',\n content: message.content ?? null,\n tool_calls: message.tool_calls.map((call) => ({\n id: call.id,\n type: 'function',\n function: {\n name: call.name,\n arguments: call.arguments\n }\n }))\n };\n }\n\n if (message.role === 'tool') {\n return {\n role: 'tool',\n tool_call_id: message.tool_call_id ?? '',\n content: message.content ?? ''\n };\n }\n\n return {\n role: message.role,\n content: message.content ?? ''\n };\n });\n}\n\n/**\n * Parses provider usage fields into normalized token counts.\n *\n * @param usage - Raw usage object from the provider response.\n */\nfunction parseUsage(usage: Record<string, unknown> | undefined): LlmCompletionUsage {\n const promptTokens = typeof usage?.prompt_tokens === 'number' ? usage.prompt_tokens : 0;\n const completionTokens =\n typeof usage?.completion_tokens === 'number' ? usage.completion_tokens : 0;\n const totalTokens =\n typeof usage?.total_tokens === 'number' ? usage.total_tokens : promptTokens + completionTokens;\n\n return {\n promptTokens,\n completionTokens,\n totalTokens\n };\n}\n\n/**\n * Parses an OpenAI-compatible chat completion response body.\n *\n * @param json - Parsed JSON response body.\n */\nfunction parseCompletionResponse(json: Record<string, unknown>): LlmCompletionResult {\n const choices = json.choices;\n if (!Array.isArray(choices) || choices.length === 0) {\n throw new Error('The model returned an empty response.');\n }\n\n const message = choices[0]?.message as Record<string, unknown> | undefined;\n if (!message) {\n throw new Error('The model returned an empty response.');\n }\n\n const rawToolCalls = message.tool_calls;\n const toolCalls = Array.isArray(rawToolCalls)\n ? rawToolCalls\n .filter((call): call is Record<string, unknown> => call != null && typeof call === 'object')\n .filter((call) => call.type === 'function')\n .map((call) => {\n const fn = call.function as Record<string, unknown> | undefined;\n return {\n id: String(call.id ?? ''),\n name: String(fn?.name ?? ''),\n arguments: String(fn?.arguments ?? '')\n };\n })\n .filter((call) => call.id && call.name)\n : undefined;\n\n const content = typeof message.content === 'string' ? message.content : null;\n\n return {\n content,\n ...(toolCalls && toolCalls.length > 0 ? { toolCalls } : {}),\n usage: parseUsage(json.usage as Record<string, unknown> | undefined)\n };\n}\n\n/**\n * Runs one OpenAI-compatible chat completion against a configured provider.\n *\n * @param config - Hub LLM configuration with provider API keys.\n * @param input - Model, messages, optional system prompt, and tools.\n * @returns Normalized assistant content, tool calls, and usage.\n */\nexport async function runLlmCompletion(\n config: LlmConfig,\n input: RunLlmCompletionInput\n): Promise<LlmCompletionResult> {\n const modelEntry = getHubModelById(input.model);\n if (!modelEntry) {\n throw new Error(`Unknown model: ${input.model}`);\n }\n\n const providerConfig = config.providers[modelEntry.provider];\n if (!providerConfig?.apiKey.trim()) {\n throw new Error(`Provider ${modelEntry.provider} is not configured on this hub.`);\n }\n\n const messages: Record<string, unknown>[] = [];\n if (input.systemPrompt?.trim()) {\n messages.push({ role: 'system', content: input.systemPrompt });\n }\n messages.push(...toProviderMessages(input.messages));\n\n const body: Record<string, unknown> = {\n model: modelEntry.id,\n messages\n };\n\n if (input.tools && input.tools.length > 0) {\n body.tools = input.tools;\n }\n\n const response = await fetch(`${resolveProviderBaseUrl(modelEntry.provider)}/chat/completions`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${providerConfig.apiKey}`,\n 'Content-Type': 'application/json',\n Accept: 'application/json'\n },\n body: JSON.stringify(body)\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n errorText.trim() || `LLM request failed with status ${response.status.toString()}`\n );\n }\n\n const json = (await response.json()) as Record<string, unknown>;\n return parseCompletionResponse(json);\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport path from 'node:path';\nimport { create, load, search, type AnyOrama } from '@orama/orama';\nimport OpenAI from 'openai';\nimport {\n DEFAULT_DOCS_SEARCH_INDEX_PATH,\n resolveDocsSearchIndexPath,\n type DocsConfig\n} from '#/config/docsConfig.js';\nimport type { LlmConfig } from '#/config/llmConfig.js';\n\n/**\n * Embedding model used for docs search queries. Must match harborclient scripts/index-docs.mjs.\n */\nexport const DOCS_EMBEDDING_MODEL = 'text-embedding-3-small';\n\n/**\n * Embedding vector size for the docs index. Must match harborclient scripts/index-docs.mjs.\n */\nexport const DOCS_EMBEDDING_DIMENSIONS = 1536;\n\nconst DEFAULT_RESULT_LIMIT = 5;\nconst MAX_RESULT_LIMIT = 10;\nconst DEFAULT_SIMILARITY = 0.5;\nconst SNIPPET_MAX_CHARS = 600;\n\nconst DOCS_SEARCH_SCHEMA = {\n id: 'string',\n source: 'string',\n path: 'string',\n url: 'string',\n title: 'string',\n heading: 'string',\n content: 'string',\n embedding: `vector[${DOCS_EMBEDDING_DIMENSIONS}]`\n} as const;\n\n/**\n * Arguments accepted by the hub-native search_docs tool.\n */\nexport interface SearchDocsToolArgs {\n /**\n * Natural-language query describing what to find in HarborClient or SDK docs.\n */\n query: string;\n\n /**\n * Maximum number of documentation passages to return; defaults to 5.\n */\n limit?: number;\n\n /**\n * Restrict results to site user docs or SDK plugin docs.\n */\n source?: 'site' | 'sdk';\n}\n\n/**\n * One ranked documentation hit returned to the AI assistant.\n */\nexport interface DocsSearchHit {\n /** Page title from the indexed document. */\n title: string;\n /** Section heading within the page. */\n heading: string;\n /** Public documentation URL. */\n url: string;\n /** Documentation source repository: site or sdk. */\n source: string;\n /** Repo-relative markdown path. */\n path: string;\n /** Orama vector similarity score. */\n score: number;\n /** Truncated passage text from the matched chunk. */\n snippet: string;\n}\n\ntype DocsSearchDocument = {\n id: string;\n source: string;\n path: string;\n url: string;\n title: string;\n heading: string;\n content: string;\n embedding: number[];\n};\n\nlet cachedDb: AnyOrama | null = null;\nlet indexUnavailable = false;\n\n/**\n * Candidate filesystem paths for the bundled documentation search index.\n *\n * @param docsConfig - Optional docs section from server.yaml.\n * @returns Absolute paths to try in priority order.\n */\nexport function getDocsSearchIndexPaths(docsConfig: DocsConfig | null): string[] {\n const paths = new Set<string>();\n\n if (docsConfig?.searchIndexPath) {\n paths.add(resolveDocsSearchIndexPath(docsConfig.searchIndexPath));\n }\n\n paths.add(DEFAULT_DOCS_SEARCH_INDEX_PATH);\n paths.add(path.resolve(process.cwd(), 'data/docsSearchIndex.json'));\n\n return [...paths];\n}\n\n/**\n * Clears the lazy-loaded docs search index cache (for tests).\n */\nexport function resetDocsSearchCache(): void {\n cachedDb = null;\n indexUnavailable = false;\n}\n\n/**\n * Returns whether the docs search index file exists on disk.\n *\n * @param docsConfig - Optional docs section from server.yaml.\n */\nexport function isDocsSearchIndexAvailable(docsConfig: DocsConfig | null): boolean {\n return getDocsSearchIndexPaths(docsConfig).some((candidate) => existsSync(candidate));\n}\n\n/**\n * Truncates long passage text for compact tool responses.\n *\n * @param content - Full chunk content from the index.\n * @param maxChars - Maximum characters to retain.\n */\nfunction truncateSnippet(content: string, maxChars = SNIPPET_MAX_CHARS): string {\n if (content.length <= maxChars) {\n return content;\n }\n return `${content.slice(0, maxChars)}...`;\n}\n\n/**\n * Clamps the requested result limit to a safe default and maximum.\n *\n * @param limit - Optional limit from tool arguments.\n */\nfunction clampResultLimit(limit: number | undefined): number {\n if (limit == null || !Number.isFinite(limit)) {\n return DEFAULT_RESULT_LIMIT;\n }\n return Math.min(Math.max(1, Math.floor(limit)), MAX_RESULT_LIMIT);\n}\n\n/**\n * Loads and caches the serialized Orama documentation index.\n *\n * @param docsConfig - Optional docs section from server.yaml.\n * @param paths - Optional path override list for tests.\n */\nfunction loadDocsSearchIndex(docsConfig: DocsConfig | null, paths?: string[]): AnyOrama {\n if (cachedDb != null) {\n return cachedDb;\n }\n\n if (indexUnavailable) {\n throw new Error(\n 'Documentation search index is not available. Deploy docsSearchIndex.json to the Team Hub server.'\n );\n }\n\n const candidates = paths ?? getDocsSearchIndexPaths(docsConfig);\n const catalogPath = candidates.find((candidate) => existsSync(candidate));\n if (catalogPath == null) {\n indexUnavailable = true;\n throw new Error(\n 'Documentation search index is not available. Deploy docsSearchIndex.json to the Team Hub server.'\n );\n }\n\n const raw = JSON.parse(readFileSync(catalogPath, 'utf8')) as Parameters<typeof load>[1];\n const db = create({ schema: DOCS_SEARCH_SCHEMA });\n load(db, raw);\n cachedDb = db;\n return db;\n}\n\n/**\n * Embeds a user query with the same model used to build the docs index.\n *\n * @param query - Raw search text from the AI tool.\n * @param apiKey - OpenAI API key from server.yaml llm.providers.openai.\n */\nasync function embedDocsQuery(query: string, apiKey: string): Promise<number[]> {\n const client = new OpenAI({ apiKey });\n const response = await client.embeddings.create({\n model: DOCS_EMBEDDING_MODEL,\n input: query\n });\n\n const embedding = response.data[0]?.embedding;\n if (!Array.isArray(embedding) || embedding.length !== DOCS_EMBEDDING_DIMENSIONS) {\n throw new Error('Unexpected embedding size from OpenAI.');\n }\n\n return embedding;\n}\n\n/**\n * Runs vector search over the bundled documentation index using the hub OpenAI key.\n *\n * @param llmConfig - Hub LLM configuration with provider API keys.\n * @param docsConfig - Optional docs section with index path overrides.\n * @param args - Tool arguments with query text and optional limit/source filter.\n * @returns Ranked documentation hits for the assistant.\n */\nexport async function searchDocs(\n llmConfig: LlmConfig,\n docsConfig: DocsConfig | null,\n args: SearchDocsToolArgs\n): Promise<DocsSearchHit[]> {\n const query = args.query?.trim();\n if (!query) {\n throw new Error('query is required.');\n }\n\n const apiKey = llmConfig.providers.openai?.apiKey.trim();\n if (!apiKey) {\n throw new Error(\n 'OpenAI provider is not configured on this Team Hub. Documentation search requires an OpenAI API key.'\n );\n }\n\n const db = loadDocsSearchIndex(docsConfig);\n const embedding = await embedDocsQuery(query, apiKey);\n const limit = clampResultLimit(args.limit);\n\n const results = search(db, {\n mode: 'vector',\n vector: {\n value: embedding,\n property: 'embedding'\n },\n similarity: DEFAULT_SIMILARITY,\n limit,\n ...(args.source != null ? { where: { source: args.source } } : {})\n });\n\n const resolved = results instanceof Promise ? await results : results;\n\n return resolved.hits.map((hit) => {\n const document = hit.document as DocsSearchDocument;\n return {\n title: document.title,\n heading: document.heading,\n url: document.url,\n source: document.source,\n path: document.path,\n score: hit.score,\n snippet: truncateSnippet(document.content)\n };\n });\n}\n","import type { DocsConfig } from '#/config/docsConfig.js';\nimport type { LlmConfig } from '#/config/llmConfig.js';\nimport { hasHubOpenAiProvider } from '#/server/llm/models.js';\nimport {\n isDocsSearchIndexAvailable,\n searchDocs,\n type SearchDocsToolArgs\n} from '#/server/docs/docsSearch.js';\nimport type { LlmToolDefinition } from '#/server/llm/client.js';\n\n/**\n * Hub-native tool names executed server-side during chat steps.\n */\nexport const HUB_NATIVE_TOOL_NAMES = ['search_docs'] as const;\n\n/**\n * Union of hub-native tool names.\n */\nexport type HubNativeToolName = (typeof HUB_NATIVE_TOOL_NAMES)[number];\n\n/**\n * Returns whether a tool name is a hub-native built-in tool.\n *\n * @param name - Tool name from the model.\n */\nexport function isHubNativeToolName(name: string): name is HubNativeToolName {\n return (HUB_NATIVE_TOOL_NAMES as readonly string[]).includes(name);\n}\n\n/**\n * Returns whether the hub can execute hub-native documentation search.\n *\n * Requires an OpenAI provider key and a readable docs search index file.\n *\n * @param llmConfig - Hub LLM configuration.\n * @param docsConfig - Optional docs section from server.yaml.\n */\nexport function canExecuteHubDocsSearch(\n llmConfig: LlmConfig | null,\n docsConfig: DocsConfig | null\n): boolean {\n if (!llmConfig || !hasHubOpenAiProvider(llmConfig)) {\n return false;\n }\n\n return isDocsSearchIndexAvailable(docsConfig);\n}\n\n/**\n * Removes hub-native tools the server cannot execute from client tool definitions.\n *\n * @param tools - Tool definitions forwarded from HarborClient.\n * @param llmConfig - Hub LLM configuration.\n * @param docsConfig - Optional docs section from server.yaml.\n */\nexport function filterClientToolsForHub(\n tools: LlmToolDefinition[] | undefined,\n llmConfig: LlmConfig | null,\n docsConfig: DocsConfig | null\n): LlmToolDefinition[] | undefined {\n if (!tools || tools.length === 0) {\n return tools;\n }\n\n if (canExecuteHubDocsSearch(llmConfig, docsConfig)) {\n return tools;\n }\n\n const filtered = tools.filter((tool) => {\n const name = (tool as { function?: { name?: string } }).function?.name;\n return name !== 'search_docs';\n });\n\n return filtered.length > 0 ? filtered : undefined;\n}\n\n/**\n * Invokes one hub-native tool and returns a JSON string for the agent loop.\n *\n * @param name - Tool name from the model.\n * @param args - Parsed tool arguments object.\n * @param llmConfig - Hub LLM configuration.\n * @param docsConfig - Optional docs section from server.yaml.\n */\nexport async function callHubNativeTool(\n name: HubNativeToolName,\n args: unknown,\n llmConfig: LlmConfig,\n docsConfig: DocsConfig | null\n): Promise<string> {\n if (name !== 'search_docs') {\n return JSON.stringify({ error: `Unknown hub-native tool: ${name}` });\n }\n\n try {\n const parsed = args as SearchDocsToolArgs;\n const hits = await searchDocs(llmConfig, docsConfig, parsed);\n return JSON.stringify(hits);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Documentation search failed.';\n return JSON.stringify({ error: message });\n }\n}\n","/**\n * Prefix for hub-configured MCP tools merged into chat completions.\n */\nexport const HUB_MCP_TOOL_PREFIX = 'hubmcp__';\n\n/**\n * Builds a prefixed hub MCP tool name for LLM routing.\n *\n * @param serverIndex - Zero-based index in llm.mcp config.\n * @param toolName - Original tool name from the remote server.\n */\nexport function encodeHubMcpToolName(serverIndex: number, toolName: string): string {\n return `${HUB_MCP_TOOL_PREFIX}${serverIndex}__${toolName}`;\n}\n\n/**\n * Parses a prefixed hub MCP tool name into server index and original tool name.\n *\n * @param prefixed - Tool name from an assistant tool call.\n */\nexport function decodeHubMcpToolName(\n prefixed: string\n): { serverIndex: number; toolName: string } | null {\n if (!prefixed.startsWith(HUB_MCP_TOOL_PREFIX)) {\n return null;\n }\n\n const rest = prefixed.slice(HUB_MCP_TOOL_PREFIX.length);\n const separatorIndex = rest.indexOf('__');\n if (separatorIndex <= 0) {\n return null;\n }\n\n const serverIndex = Number.parseInt(rest.slice(0, separatorIndex), 10);\n if (!Number.isInteger(serverIndex) || serverIndex < 0) {\n return null;\n }\n\n const toolName = rest.slice(separatorIndex + 2);\n if (!toolName) {\n return null;\n }\n\n return { serverIndex, toolName };\n}\n\n/**\n * Returns whether a tool name belongs to a hub-configured MCP server.\n *\n * @param name - Tool name from the model.\n */\nexport function isHubMcpToolName(name: string): boolean {\n return decodeHubMcpToolName(name) !== null;\n}\n","import { Client } from '@modelcontextprotocol/sdk/client/index.js';\nimport { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';\nimport { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';\nimport type { Tool } from '@modelcontextprotocol/sdk/types.js';\nimport type { HubMcpHeader, LlmConfig } from '#/config/llmConfig.js';\nimport type { LlmToolDefinition } from '#/server/llm/client.js';\nimport { decodeHubMcpToolName, encodeHubMcpToolName } from '#/server/llm/hubMcpToolNames.js';\n\n/**\n * OpenAI-compatible tool definition returned to the LLM provider.\n */\nexport interface HubMcpOpenAiTool extends LlmToolDefinition {\n type: 'function';\n function: {\n name: string;\n description?: string;\n parameters: Record<string, unknown>;\n };\n}\n\ninterface ConnectedHubMcpClient {\n serverIndex: number;\n client: Client;\n remoteTools: Tool[];\n}\n\nconst connectedClients = new Map<number, ConnectedHubMcpClient>();\nlet activeConfigSignature = '';\n\n/**\n * Builds HTTP headers for one hub MCP connection.\n *\n * @param headers - Normalized header rows from config.\n */\nfunction buildRequestHeaders(headers: HubMcpHeader[]): Record<string, string> {\n const result: Record<string, string> = {};\n for (const row of headers) {\n if (row.key.trim()) {\n result[row.key.trim()] = row.value;\n }\n }\n return result;\n}\n\n/**\n * Serializes llm.mcp for connection cache comparisons.\n *\n * @param config - Hub LLM configuration.\n */\nfunction buildMcpConfigSignature(config: LlmConfig): string {\n return JSON.stringify(config.mcp ?? []);\n}\n\n/**\n * Flattens MCP callTool content into a JSON string for the agent loop.\n *\n * @param content - MCP tool result content array.\n */\nfunction flattenMcpToolContent(content: unknown): string {\n if (!Array.isArray(content)) {\n return JSON.stringify(content ?? null);\n }\n\n const parts = content.map((item) => {\n if (!item || typeof item !== 'object') {\n return String(item);\n }\n\n const record = item as { type?: string; text?: string; uri?: string };\n if (record.type === 'text' && typeof record.text === 'string') {\n return record.text;\n }\n\n if (record.type === 'resource' && typeof record.uri === 'string') {\n return record.uri;\n }\n\n return JSON.stringify(record);\n });\n\n return parts.join('\\n');\n}\n\n/**\n * Converts remote MCP tool metadata into an OpenAI function tool definition.\n *\n * @param serverIndex - Zero-based index in llm.mcp.\n * @param tool - Tool metadata from tools/list.\n */\nfunction toOpenAiTool(serverIndex: number, tool: Tool): HubMcpOpenAiTool {\n return {\n type: 'function',\n function: {\n name: encodeHubMcpToolName(serverIndex, tool.name),\n description: tool.description ?? `MCP tool ${tool.name}`,\n parameters: (tool.inputSchema as Record<string, unknown> | undefined) ?? {\n type: 'object',\n properties: {},\n additionalProperties: true\n }\n }\n };\n}\n\n/**\n * Connects to one configured hub MCP server and caches its tools.\n *\n * @param serverIndex - Zero-based index in llm.mcp.\n * @param server - MCP server configuration entry.\n */\nasync function connectHubMcpServer(\n serverIndex: number,\n server: NonNullable<LlmConfig['mcp']>[number]\n): Promise<ConnectedHubMcpClient> {\n const headers = buildRequestHeaders(server.headers);\n const url = new URL(server.url);\n\n const client = new Client(\n {\n name: 'team-hub',\n version: '1.0.0'\n },\n {}\n );\n\n let transport: StreamableHTTPClientTransport | SSEClientTransport;\n try {\n transport = new StreamableHTTPClientTransport(url, {\n requestInit: { headers }\n });\n await client.connect(transport);\n } catch {\n transport = new SSEClientTransport(url, {\n requestInit: { headers }\n });\n await client.connect(transport);\n }\n\n const { tools } = await client.listTools();\n\n return {\n serverIndex,\n client,\n remoteTools: tools\n };\n}\n\n/**\n * Reconciles cached MCP connections with the current llm.mcp configuration.\n *\n * @param config - Hub LLM configuration.\n */\nexport async function ensureHubMcpConnections(config: LlmConfig): Promise<void> {\n const servers = config.mcp ?? [];\n const signature = buildMcpConfigSignature(config);\n\n if (signature !== activeConfigSignature) {\n await disposeHubMcpConnections();\n activeConfigSignature = signature;\n }\n\n if (servers.length === 0) {\n return;\n }\n\n for (const [index, server] of servers.entries()) {\n if (connectedClients.has(index)) {\n continue;\n }\n\n try {\n const connected = await connectHubMcpServer(index, server);\n connectedClients.set(index, connected);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Connection failed';\n console.warn(`Hub MCP server \"${server.name}\" failed to connect: ${message}`);\n }\n }\n}\n\n/**\n * Lists hub MCP tools in OpenAI chat completion format.\n *\n * Call {@link ensureHubMcpConnections} first so the connection cache is populated.\n */\nexport function listHubMcpTools(): HubMcpOpenAiTool[] {\n const tools: HubMcpOpenAiTool[] = [];\n\n for (const entry of connectedClients.values()) {\n for (const tool of entry.remoteTools) {\n tools.push(toOpenAiTool(entry.serverIndex, tool));\n }\n }\n\n return tools;\n}\n\n/**\n * Invokes one prefixed hub MCP tool on the matching remote server.\n *\n * @param prefixedName - Tool name with hubmcp__ prefix from the model.\n * @param args - Parsed tool arguments object.\n */\nexport async function callHubMcpTool(prefixedName: string, args: unknown): Promise<string> {\n const decoded = decodeHubMcpToolName(prefixedName);\n if (!decoded) {\n return JSON.stringify({ error: `Unknown hub MCP tool: ${prefixedName}` });\n }\n\n const entry = connectedClients.get(decoded.serverIndex);\n if (!entry) {\n return JSON.stringify({ error: `Hub MCP server ${decoded.serverIndex} is not connected.` });\n }\n\n try {\n const result = await entry.client.callTool({\n name: decoded.toolName,\n arguments: (args ?? {}) as Record<string, unknown>\n });\n\n if (result.isError) {\n return JSON.stringify({\n error: flattenMcpToolContent(result.content)\n });\n }\n\n return flattenMcpToolContent(result.content);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'MCP tool execution failed.';\n return JSON.stringify({ error: message });\n }\n}\n\n/**\n * Closes all hub MCP client connections.\n */\nexport async function disposeHubMcpConnections(): Promise<void> {\n const closePromises = [...connectedClients.values()].map(async (entry) => {\n try {\n await entry.client.close();\n } catch {\n // Ignore close errors during teardown.\n }\n });\n\n connectedClients.clear();\n activeConfigSignature = '';\n await Promise.allSettled(closePromises);\n}\n","import type { DocsConfig } from '#/config/docsConfig.js';\nimport type { LlmConfig } from '#/config/llmConfig.js';\nimport {\n runLlmCompletion,\n type LlmChatMessage,\n type LlmCompletionResult,\n type LlmCompletionUsage,\n type LlmToolCall,\n type LlmToolDefinition\n} from '#/server/llm/client.js';\nimport {\n callHubNativeTool,\n filterClientToolsForHub,\n isHubNativeToolName,\n type HubNativeToolName\n} from '#/server/llm/hubNativeTools.js';\nimport { isHubMcpToolName } from '#/server/llm/hubMcpToolNames.js';\nimport {\n callHubMcpTool,\n ensureHubMcpConnections,\n listHubMcpTools,\n type HubMcpOpenAiTool\n} from '#/server/llm/mcpClient.js';\n\n/**\n * Maximum server-side tool iterations per chat step.\n */\nexport const HUB_CHAT_STEP_MAX_ITERATIONS = 8;\n\n/**\n * Input for one hub chat step, including client tools and conversation history.\n */\nexport interface HubChatStepInput {\n model: string;\n messages: LlmChatMessage[];\n systemPrompt?: string;\n tools?: LlmToolDefinition[];\n}\n\n/**\n * Result of one hub chat step after optional server-side tool execution.\n */\nexport interface HubChatStepResult {\n content: string | null;\n toolCalls?: LlmToolCall[];\n usage: LlmCompletionUsage;\n}\n\n/**\n * Injectable dependencies for {@link runHubChatStep} in tests.\n */\nexport interface HubChatStepDeps {\n runCompletion: (\n config: LlmConfig,\n input: {\n model: string;\n messages: LlmChatMessage[];\n systemPrompt?: string;\n tools?: HubChatStepInput['tools'];\n }\n ) => Promise<LlmCompletionResult>;\n ensureConnections: (config: LlmConfig) => Promise<void>;\n listTools: () => HubMcpOpenAiTool[];\n callTool: (prefixedName: string, args: unknown) => Promise<string>;\n callNativeTool: (\n name: HubNativeToolName,\n args: unknown,\n config: LlmConfig,\n docsConfig: DocsConfig | null\n ) => Promise<string>;\n}\n\n/**\n * Sums token usage across multiple provider completions.\n *\n * @param current - Accumulated usage so far.\n * @param next - Usage from the latest completion.\n */\nfunction addUsage(current: LlmCompletionUsage, next: LlmCompletionUsage): LlmCompletionUsage {\n return {\n promptTokens: current.promptTokens + next.promptTokens,\n completionTokens: current.completionTokens + next.completionTokens,\n totalTokens: current.totalTokens + next.totalTokens\n };\n}\n\n/**\n * Parses tool call arguments from the provider into a JSON value.\n *\n * @param raw - Raw arguments string from the model.\n */\nfunction parseToolArguments(raw: string): unknown {\n try {\n return JSON.parse(raw) as unknown;\n } catch {\n return {};\n }\n}\n\n/**\n * Runs one hub chat step, executing hub-native and hub MCP tools server-side until a\n * client tool call or final text response is reached.\n *\n * @param config - Hub LLM configuration including optional MCP servers.\n * @param input - Model, messages, system prompt, and client tools.\n * @param deps - Optional overrides for completion and tool helpers (tests).\n * @param docsConfig - Optional docs search configuration from server.yaml.\n */\nexport async function runHubChatStep(\n config: LlmConfig,\n input: HubChatStepInput,\n deps: Partial<HubChatStepDeps> = {},\n docsConfig: DocsConfig | null = null\n): Promise<HubChatStepResult> {\n const runCompletion = deps.runCompletion ?? runLlmCompletion;\n const ensureConnections = deps.ensureConnections ?? ensureHubMcpConnections;\n const listTools = deps.listTools ?? listHubMcpTools;\n const callTool = deps.callTool ?? callHubMcpTool;\n const callNativeTool = deps.callNativeTool ?? callHubNativeTool;\n\n await ensureConnections(config);\n\n const hubTools = listTools();\n const clientTools = filterClientToolsForHub(input.tools, config, docsConfig);\n const mergedTools: LlmToolDefinition[] | undefined =\n hubTools.length > 0 || (clientTools?.length ?? 0) > 0\n ? [...hubTools, ...(clientTools ?? [])]\n : undefined;\n\n let messages = [...input.messages];\n let usage: LlmCompletionUsage = { promptTokens: 0, completionTokens: 0, totalTokens: 0 };\n let lastContent: string | null = null;\n\n for (let iteration = 0; iteration < HUB_CHAT_STEP_MAX_ITERATIONS; iteration += 1) {\n const result = await runCompletion(config, {\n model: input.model,\n messages,\n systemPrompt: input.systemPrompt,\n tools: mergedTools\n });\n\n usage = addUsage(usage, result.usage);\n lastContent = result.content;\n\n const toolCalls = result.toolCalls ?? [];\n if (toolCalls.length === 0) {\n return {\n content: result.content,\n usage\n };\n }\n\n const nativeCalls = toolCalls.filter((call) => isHubNativeToolName(call.name));\n const hubCalls = toolCalls.filter((call) => isHubMcpToolName(call.name));\n const passthroughCalls = toolCalls.filter(\n (call) => !isHubNativeToolName(call.name) && !isHubMcpToolName(call.name)\n );\n\n if (passthroughCalls.length > 0) {\n return {\n content: result.content,\n toolCalls: passthroughCalls,\n usage\n };\n }\n\n const serverCalls = [...nativeCalls, ...hubCalls];\n\n messages = [\n ...messages,\n {\n role: 'assistant',\n content: result.content,\n tool_calls: serverCalls\n }\n ];\n\n for (const call of nativeCalls) {\n const toolResult = await callNativeTool(\n call.name as HubNativeToolName,\n parseToolArguments(call.arguments),\n config,\n docsConfig\n );\n messages.push({\n role: 'tool',\n tool_call_id: call.id,\n content: toolResult\n });\n }\n\n for (const call of hubCalls) {\n const toolResult = await callTool(call.name, parseToolArguments(call.arguments));\n messages.push({\n role: 'tool',\n tool_call_id: call.id,\n content: toolResult\n });\n }\n }\n\n return {\n content: lastContent,\n usage\n };\n}\n","import type { FastifyInstance } from 'fastify';\nimport type { FastifyReply } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport type { DocsConfig } from '#/config/docsConfig.js';\nimport type { LlmConfig } from '#/config/llmConfig.js';\nimport type { IDatabase } from '#/db/IDatabase.js';\nimport { canUseLlm, isLlmModelAllowed, isOverMonthlyLimit } from '#/server/auth/accessControl.js';\nimport { runHubChatStep } from '#/server/llm/agent.js';\nimport {\n currentUsagePeriod,\n getHubLlmCapabilities,\n getHubModelById,\n isHubModelOffered,\n listHubOfferedModels\n} from '#/server/llm/models.js';\nimport { denyUnlessAllowed, requireAuthenticatedUser } from '#/server/routes/authorize.js';\nimport { errorResponseSchema } from '#/server/routes/schemas/common.js';\nimport {\n listLlmModelsResponseSchema,\n llmChatStepBodySchema,\n llmChatStepResponseSchema,\n llmUsageSummaryResponseSchema\n} from '#/server/routes/schemas/llm.js';\n\n/**\n * Options for registering LLM proxy routes.\n */\nexport interface RegisterLlmRoutesOptions {\n /**\n * Database used for usage metering and user access checks.\n */\n db: IDatabase;\n\n /**\n * Returns the current normalized LLM configuration from server.yaml.\n */\n getLlm: () => LlmConfig | null;\n\n /**\n * Returns the current normalized documentation search configuration from server.yaml.\n */\n getDocs: () => DocsConfig | null;\n}\n\n/**\n * Sends a 402 response when the user has exceeded their monthly token limit.\n *\n * @param reply - Fastify reply used to short-circuit the handler.\n */\nfunction sendMonthlyLimitExceeded(reply: FastifyReply): FastifyReply {\n return reply.code(402).send({\n error: 'Monthly LLM token limit reached. Try again next month or contact your administrator.'\n });\n}\n\n/**\n * Sends a 503 response when LLM support is not configured on the hub.\n *\n * @param reply - Fastify reply used to short-circuit the handler.\n */\nfunction sendLlmUnavailable(reply: FastifyReply): FastifyReply {\n return reply.code(503).send({\n error: 'LLM support is not configured on this Team Hub.'\n });\n}\n\n/**\n * Registers bearer-protected LLM proxy routes.\n *\n * @param app - Encapsulated Fastify scope with auth applied.\n * @param options - Database and LLM configuration.\n */\nexport async function registerLlmRoutes(\n app: FastifyInstance,\n options: RegisterLlmRoutesOptions\n): Promise<void> {\n const routes = app.withTypeProvider<ZodTypeProvider>();\n\n routes.route({\n method: 'GET',\n url: '/llm/models',\n schema: {\n response: {\n 200: listLlmModelsResponseSchema,\n 403: errorResponseSchema,\n 503: errorResponseSchema\n }\n },\n /**\n * Lists hub-offered models the authenticated user may use.\n */\n handler: async (request, reply) => {\n const llm = options.getLlm();\n if (!llm) {\n return sendLlmUnavailable(reply);\n }\n\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseLlm(user))) {\n return;\n }\n\n const offered = listHubOfferedModels(llm).filter((model) =>\n isLlmModelAllowed(user, model.id)\n );\n\n return reply.send({\n models: offered.map((model) => ({\n id: model.id,\n label: model.label,\n provider: model.provider\n })),\n capabilities: getHubLlmCapabilities(llm)\n });\n }\n });\n\n routes.route({\n method: 'GET',\n url: '/llm/usage',\n schema: {\n response: {\n 200: llmUsageSummaryResponseSchema,\n 403: errorResponseSchema,\n 503: errorResponseSchema\n }\n },\n /**\n * Returns the authenticated user's current monthly LLM usage summary.\n */\n handler: async (request, reply) => {\n const llm = options.getLlm();\n if (!llm) {\n return sendLlmUnavailable(reply);\n }\n\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseLlm(user))) {\n return;\n }\n\n const period = currentUsagePeriod();\n const usage = await options.db.getLlmUsage(user.id, period);\n\n return reply.send({\n period,\n totalTokens: usage?.totalTokens ?? 0,\n limit: user.llmMonthlyTokenLimit\n });\n }\n });\n\n routes.route({\n method: 'POST',\n url: '/llm/chat/step',\n schema: {\n body: llmChatStepBodySchema,\n response: {\n 200: llmChatStepResponseSchema,\n 402: errorResponseSchema,\n 403: errorResponseSchema,\n 503: errorResponseSchema\n }\n },\n /**\n * Runs one stateless LLM completion step using hub-configured provider keys.\n */\n handler: async (request, reply) => {\n const llm = options.getLlm();\n if (!llm) {\n return sendLlmUnavailable(reply);\n }\n\n const user = requireAuthenticatedUser(request);\n if (denyUnlessAllowed(reply, canUseLlm(user))) {\n return;\n }\n\n const { model, messages, tools, systemPrompt } = request.body;\n\n if (!isHubModelOffered(llm, model)) {\n return reply.code(403).send({ error: 'Model is not offered by this Team Hub.' });\n }\n\n if (!isLlmModelAllowed(user, model)) {\n return reply.code(403).send({ error: 'You are not allowed to use this model.' });\n }\n\n const period = currentUsagePeriod();\n const usage = await options.db.getLlmUsage(user.id, period);\n const totalTokens = usage?.totalTokens ?? 0;\n const lastMessage = messages.at(-1);\n const isNewTurn = lastMessage?.role === 'user';\n\n if (isNewTurn && isOverMonthlyLimit(totalTokens, user.llmMonthlyTokenLimit)) {\n return sendMonthlyLimitExceeded(reply);\n }\n\n const result = await runHubChatStep(\n llm,\n {\n model,\n messages,\n tools,\n systemPrompt\n },\n {},\n options.getDocs()\n );\n\n const catalogModel = getHubModelById(model);\n if (!catalogModel) {\n throw new Error(`Unknown hub model: ${model}`);\n }\n\n await options.db.addLlmUsage(\n user.id,\n period,\n result.usage.promptTokens,\n result.usage.completionTokens\n );\n\n await options.db.createLlmUsageLog({\n userId: user.id,\n apiTokenId: request.apiToken?.id ?? null,\n period,\n model,\n provider: catalogModel.provider,\n promptTokens: result.usage.promptTokens,\n completionTokens: result.usage.completionTokens,\n totalTokens: result.usage.totalTokens,\n isNewTurn,\n hadToolCalls: Boolean(result.toolCalls && result.toolCalls.length > 0),\n messageCount: messages.length\n });\n\n return reply.send({\n content: result.content,\n ...(result.toolCalls && result.toolCalls.length > 0 ? { toolCalls: result.toolCalls } : {}),\n usage: result.usage\n });\n }\n });\n}\n","import { z } from 'zod/v4';\n\n/**\n * Response schema for Team Hub plugin source URLs exposed to HarborClient.\n */\nexport const pluginSourcesResponseSchema = z.object({\n catalogs: z.array(z.string()),\n trusted: z.array(z.string())\n});\n\n/**\n * Validated plugin source URLs returned by GET /plugins/sources.\n */\nexport type PluginSourcesResponse = z.infer<typeof pluginSourcesResponseSchema>;\n","import type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport type { PluginsConfig } from '#/config/pluginsConfig.js';\nimport { pluginSourcesResponseSchema } from '#/server/routes/schemas/plugins.js';\n\n/**\n * Options for registering plugin source routes.\n */\nexport interface RegisterPluginsRoutesOptions {\n /**\n * Returns the current normalized plugin source configuration from server.yaml.\n */\n getPlugins: () => PluginsConfig | null;\n}\n\n/**\n * Registers bearer-protected plugin source routes.\n *\n * @param app - Encapsulated Fastify scope with auth applied.\n * @param options - Plugin source configuration from server.yaml.\n */\nexport async function registerPluginsRoutes(\n app: FastifyInstance,\n options: RegisterPluginsRoutesOptions\n): Promise<void> {\n const routes = app.withTypeProvider<ZodTypeProvider>();\n\n routes.route({\n method: 'GET',\n url: '/plugins/sources',\n schema: {\n response: {\n 200: pluginSourcesResponseSchema\n }\n },\n /**\n * Returns plugin catalog and trusted-publisher URLs configured on this Team Hub.\n */\n handler: async (_request, reply) => {\n const plugins = options.getPlugins();\n if (!plugins) {\n return reply.send({\n catalogs: [],\n trusted: []\n });\n }\n\n return reply.send({\n catalogs: plugins.catalogs,\n trusted: plugins.trusted\n });\n }\n });\n}\n","import type { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify';\nimport type { IDatabase } from '#/db/IDatabase.js';\nimport type { ApiTokenRecord } from '#/db/types.js';\nimport type { UserRecord } from '#/db/types.js';\nimport { extractBearer, hashToken } from '#/server/auth/apiTokens.js';\nimport type { IThrottleStore } from '#/server/auth/throttle/IThrottleStore.js';\n\ndeclare module 'fastify' {\n interface FastifyRequest {\n /**\n * Authenticated API token attached by the bearer auth hook on protected routes.\n */\n apiToken: ApiTokenRecord | null;\n\n /**\n * User account owning the authenticated API token.\n */\n user: UserRecord | null;\n }\n}\n\n/**\n * Registers the auth-related request decorators used by protected route handlers.\n *\n * @param app - Fastify instance or encapsulated scope to decorate.\n */\nexport function registerBearerAuthDecorator(app: FastifyInstance): void {\n app.decorateRequest('apiToken', null);\n app.decorateRequest('user', null);\n}\n\n/**\n * Builds the throttle key for a request from client IP and bearer token material.\n *\n * Raw token secrets are hashed before inclusion in the key.\n *\n * @param request - Incoming HTTP request.\n * @param token - Raw bearer token, or null when missing.\n * @returns Throttle key in the form `{ip}:{tokenHash|none}`.\n */\nexport function buildAuthThrottleKey(request: FastifyRequest, token: string | null): string {\n const tokenPart = token ? hashToken(token) : 'none';\n return `${request.ip}:${tokenPart}`;\n}\n\n/**\n * Builds an onRequest hook that validates bearer tokens against the database.\n *\n * @param db - Database used to resolve active token hashes and owning users.\n * @param throttleStore - Redis-backed store for failed auth throttling.\n * @returns Hook that rejects unauthenticated requests with HTTP 401.\n */\nexport function createBearerAuthHook(db: IDatabase, throttleStore: IThrottleStore) {\n /**\n * Validates Authorization: Bearer and attaches the matching token and user.\n *\n * @param request - Incoming HTTP request.\n * @param reply - Fastify reply used to short-circuit unauthorized requests.\n */\n return async function bearerAuth(request: FastifyRequest, reply: FastifyReply): Promise<void> {\n const policy = throttleStore.getPolicy();\n const token = extractBearer(request.headers.authorization);\n const throttleKey = buildAuthThrottleKey(request, token);\n\n try {\n if (await throttleStore.isBlocked(throttleKey)) {\n return reply\n .header('Retry-After', String(policy.blockSeconds))\n .code(429)\n .send({ error: 'Too Many Requests' });\n }\n } catch {\n return reply.code(503).send({ error: 'Service Unavailable' });\n }\n\n if (!token) {\n try {\n await throttleStore.recordFailure(throttleKey);\n } catch {\n return reply.code(503).send({ error: 'Service Unavailable' });\n }\n\n return reply.header('WWW-Authenticate', 'Bearer').code(401).send({ error: 'Unauthorized' });\n }\n\n const record = await db.findActiveApiTokenByHash(hashToken(token));\n if (!record) {\n try {\n await throttleStore.recordFailure(throttleKey);\n } catch {\n return reply.code(503).send({ error: 'Service Unavailable' });\n }\n\n return reply.header('WWW-Authenticate', 'Bearer').code(401).send({ error: 'Unauthorized' });\n }\n\n const user = await db.findUserById(record.userId);\n if (!user) {\n try {\n await throttleStore.recordFailure(throttleKey);\n } catch {\n return reply.code(503).send({ error: 'Service Unavailable' });\n }\n\n return reply.header('WWW-Authenticate', 'Bearer').code(401).send({ error: 'Unauthorized' });\n }\n\n try {\n await throttleStore.reset(throttleKey);\n } catch {\n return reply.code(503).send({ error: 'Service Unavailable' });\n }\n\n request.apiToken = record;\n request.user = user;\n void db.touchApiTokenLastUsed(record.id, new Date()).catch(() => undefined);\n };\n}\n","import type { FastifyInstance } from 'fastify';\nimport type { DocsConfig } from '#/config/docsConfig.js';\nimport type { LlmConfig } from '#/config/llmConfig.js';\nimport type { PluginsConfig } from '#/config/pluginsConfig.js';\nimport type { IDatabase } from '#/db/IDatabase.js';\nimport type { IThrottleStore } from '#/server/auth/throttle/IThrottleStore.js';\nimport { registerAdminRoutes } from '#/server/routes/admin.js';\nimport { registerAuthRoutes } from '#/server/routes/auth.js';\nimport { registerCollectionRoutes } from '#/server/routes/collections.js';\nimport { registerEnvironmentRoutes } from '#/server/routes/environments.js';\nimport { registerSnippetRoutes } from '#/server/routes/snippets.js';\nimport { registerFolderRoutes } from '#/server/routes/folders.js';\nimport { registerHealthRoute } from '#/server/routes/health.js';\nimport { registerRequestRoutes } from '#/server/routes/requests.js';\nimport { registerRunResultRoutes } from '#/server/routes/runResults.js';\nimport { registerLlmRoutes } from '#/server/routes/llm.js';\nimport { registerPluginsRoutes } from '#/server/routes/plugins.js';\nimport {\n createBearerAuthHook,\n registerBearerAuthDecorator\n} from '#/server/auth/bearerAuthPlugin.js';\nimport type { ReloadResult } from '#/server/runtimeContext.js';\n\nexport interface RegisterRoutesOptions {\n /**\n * Application version reported by the health endpoint.\n */\n version: string;\n\n /**\n * Database used to validate bearer tokens on protected routes.\n */\n db: IDatabase;\n\n /**\n * Redis-backed store for authentication throttling on protected routes.\n */\n throttleStore: IThrottleStore;\n\n /**\n * Returns the current normalized LLM configuration from server.yaml.\n */\n getLlm: () => LlmConfig | null;\n\n /**\n * Returns the current normalized plugin source configuration from server.yaml.\n */\n getPlugins: () => PluginsConfig | null;\n\n /**\n * Returns the current normalized documentation search configuration from server.yaml.\n */\n getDocs: () => DocsConfig | null;\n\n /**\n * Reloads server.yaml and returns a per-section report.\n */\n reloadConfig: () => Promise<ReloadResult>;\n}\n\n/**\n * Registers routes that do not require authentication.\n *\n * @param app - Fastify server or encapsulated scope.\n * @param options - Shared route metadata such as app version.\n */\nexport async function registerPublicRoutes(\n app: FastifyInstance,\n options: Pick<RegisterRoutesOptions, 'version'>\n): Promise<void> {\n await registerHealthRoute(app, options.version);\n}\n\n/**\n * Registers routes that require a valid bearer token.\n *\n * @param app - Encapsulated Fastify scope with bearer auth applied.\n * @param options - Shared route metadata and database access.\n */\nexport async function registerProtectedRoutes(\n app: FastifyInstance,\n options: RegisterRoutesOptions\n): Promise<void> {\n registerBearerAuthDecorator(app);\n app.addHook('onRequest', createBearerAuthHook(options.db, options.throttleStore));\n\n await registerAuthRoutes(app);\n await registerAdminRoutes(app, {\n db: options.db,\n getLlm: options.getLlm,\n reloadConfig: options.reloadConfig\n });\n await registerCollectionRoutes(app, options.db);\n await registerEnvironmentRoutes(app, options.db);\n await registerSnippetRoutes(app, options.db);\n await registerFolderRoutes(app, options.db);\n await registerRequestRoutes(app, options.db);\n await registerRunResultRoutes(app, options.db);\n await registerLlmRoutes(app, {\n db: options.db,\n getLlm: options.getLlm,\n getDocs: options.getDocs\n });\n await registerPluginsRoutes(app, { getPlugins: options.getPlugins });\n}\n\n/**\n * Registers all HTTP routes on the Fastify instance.\n *\n * Public routes (such as health checks) and protected API routes are registered\n * in separate encapsulated scopes so authentication can be scoped correctly.\n *\n * @param app - Fastify server to attach routes to.\n * @param options - Shared route metadata and database access.\n */\nexport async function registerRoutes(\n app: FastifyInstance,\n options: RegisterRoutesOptions\n): Promise<void> {\n await app.register(async (publicApp) => {\n await registerPublicRoutes(publicApp, options);\n });\n\n await app.register(async (protectedApp) => {\n await registerProtectedRoutes(protectedApp, options);\n });\n}\n","import { isDeepStrictEqual } from 'node:util';\nimport type { DocsConfig } from '#/config/docsConfig.js';\nimport type { LlmConfig } from '#/config/llmConfig.js';\nimport type { PluginsConfig } from '#/config/pluginsConfig.js';\nimport { ConfigError, loadServerConfig, type ServerConfig } from '#/config/serverConfig.js';\nimport { createDatabase, type IDatabase } from '#/db/index.js';\nimport { createThrottleStore } from '#/server/auth/throttle/createThrottleStore.js';\nimport type { IThrottleStore } from '#/server/auth/throttle/IThrottleStore.js';\nimport { createLogger, type Logger } from '#/server/logging/logger.js';\n\n/**\n * Outcome for a single config section during reload.\n */\nexport type ReloadSectionStatus = 'reloaded' | 'unchanged' | 'failed' | 'restart-required';\n\n/**\n * Config section name reported in reload results.\n */\nexport type ReloadSectionName = 'db' | 'redis' | 'llm' | 'plugins' | 'docs' | 'server';\n\n/**\n * Per-section reload outcome.\n */\nexport interface ReloadSectionResult {\n /**\n * Config section that was evaluated.\n */\n section: ReloadSectionName;\n\n /**\n * Whether the section was applied, skipped, failed, or needs a process restart.\n */\n status: ReloadSectionStatus;\n\n /**\n * Human-readable error when status is `failed` or `restart-required`.\n */\n error?: string;\n}\n\n/**\n * Result of reloading server.yaml at runtime.\n */\nexport interface ReloadResult {\n /**\n * Per-section reload outcomes when the config file parsed successfully.\n */\n sections: ReloadSectionResult[];\n\n /**\n * When set, the config file could not be read or parsed; no sections were changed.\n */\n fatalError?: string;\n}\n\n/**\n * Live server resources backed by server.yaml, with swappable database and throttle connections.\n */\nexport interface RuntimeContext {\n /**\n * Absolute path to the config file re-read on reload.\n */\n readonly configPath: string;\n\n /**\n * HTTP bind host from the active config (changes require a process restart).\n */\n readonly host: string;\n\n /**\n * HTTP bind port from the active config (changes require a process restart).\n */\n readonly port: number;\n\n /**\n * Stable database handle; underlying connection swaps on reload.\n */\n readonly db: IDatabase;\n\n /**\n * Stable throttle store handle; underlying Redis client swaps on reload.\n */\n readonly throttleStore: IThrottleStore;\n\n /**\n * Returns the current normalized LLM configuration.\n */\n getLlm(): LlmConfig | null;\n\n /**\n * Returns the current normalized plugin source configuration.\n */\n getPlugins(): PluginsConfig | null;\n\n /**\n * Returns the current normalized documentation search configuration.\n */\n getDocs(): DocsConfig | null;\n\n /**\n * Winston logger configured at process startup from server.yaml.\n */\n readonly logger: Logger;\n}\n\n/**\n * Mutable holder for a swappable service instance.\n */\ninterface SwappableHolder<T> {\n underlying: T;\n}\n\n/**\n * Internal mutable state for a {@link RuntimeContext}.\n */\ninterface RuntimeContextState {\n configPath: string;\n host: string;\n port: number;\n activeDbConfig: Record<string, unknown>;\n activeRedisConfig: Record<string, unknown>;\n dbHolder: SwappableHolder<IDatabase>;\n throttleHolder: SwappableHolder<IThrottleStore>;\n llm: LlmConfig | null;\n plugins: PluginsConfig | null;\n docs: DocsConfig | null;\n}\n\nconst runtimeContextStates = new WeakMap<RuntimeContext, RuntimeContextState>();\n\n/**\n * Builds a stable proxy that forwards property access to a swappable underlying object.\n *\n * @param holder - Mutable holder whose `underlying` reference may change on reload.\n * @returns Proxy implementing the same surface as the underlying instance.\n */\nfunction createSwappableProxy<T extends object>(holder: SwappableHolder<T>): T {\n return new Proxy({} as T, {\n /**\n * Forwards property reads to the current underlying instance.\n */\n get(_target, prop) {\n const value = Reflect.get(holder.underlying, prop, holder.underlying);\n if (typeof value === 'function') {\n return value.bind(holder.underlying);\n }\n\n return value;\n }\n });\n}\n\n/**\n * Returns internal state for a runtime context created by {@link createRuntimeContext}.\n *\n * @param ctx - Runtime context instance.\n * @returns Mutable internal state used for reload and lifecycle.\n * @throws {Error} When the context was not created by {@link createRuntimeContext}.\n */\nfunction getState(ctx: RuntimeContext): RuntimeContextState {\n const state = runtimeContextStates.get(ctx);\n if (!state) {\n throw new Error('Invalid runtime context.');\n }\n\n return state;\n}\n\n/**\n * Formats an unknown error for reload result payloads.\n *\n * @param error - Caught reload error.\n * @returns Message suitable for API and log output.\n */\nfunction formatReloadError(error: unknown): string {\n if (error instanceof Error) {\n return error.message;\n }\n\n return String(error);\n}\n\n/**\n * Creates runtime resources from an initial validated config snapshot.\n *\n * @param config - Parsed server.yaml contents.\n * @param configPath - Absolute path to the config file for subsequent reloads.\n * @returns Runtime context with stable db and throttle proxies.\n */\nexport function createRuntimeContext(config: ServerConfig, configPath: string): RuntimeContext {\n const state: RuntimeContextState = {\n configPath,\n host: config.host,\n port: config.port,\n activeDbConfig: config.db,\n activeRedisConfig: config.redis,\n dbHolder: { underlying: createDatabase(config.db) },\n throttleHolder: { underlying: createThrottleStore(config.redis) },\n llm: config.llm,\n plugins: config.plugins,\n docs: config.docs\n };\n\n const ctx: RuntimeContext = {\n configPath: state.configPath,\n get host() {\n return state.host;\n },\n get port() {\n return state.port;\n },\n db: createSwappableProxy(state.dbHolder),\n throttleStore: createSwappableProxy(state.throttleHolder),\n getLlm: () => state.llm,\n getPlugins: () => state.plugins,\n getDocs: () => state.docs,\n logger: createLogger(config.logging)\n };\n\n runtimeContextStates.set(ctx, state);\n return ctx;\n}\n\n/**\n * Opens connections for the current database and throttle store instances.\n *\n * @param ctx - Runtime context to connect.\n */\nexport async function connectRuntimeContext(ctx: RuntimeContext): Promise<void> {\n const state = getState(ctx);\n await state.dbHolder.underlying.connect();\n await state.throttleHolder.underlying.connect();\n}\n\n/**\n * Closes connections for the current database and throttle store instances.\n *\n * @param ctx - Runtime context to disconnect.\n */\nexport async function disconnectAll(ctx: RuntimeContext): Promise<void> {\n const state = getState(ctx);\n await state.dbHolder.underlying.disconnect();\n await state.throttleHolder.underlying.disconnect();\n}\n\n/**\n * Attempts to reconnect the database section when its raw config changed.\n *\n * @param state - Mutable runtime state.\n * @param nextDbConfig - Parsed `db` section from the reloaded config file.\n * @returns Section reload outcome.\n */\nasync function reloadDbSection(\n state: RuntimeContextState,\n nextDbConfig: Record<string, unknown>\n): Promise<ReloadSectionResult> {\n if (isDeepStrictEqual(state.activeDbConfig, nextDbConfig)) {\n return { section: 'db', status: 'unchanged' };\n }\n\n try {\n const nextDb = createDatabase(nextDbConfig);\n await nextDb.connect();\n const previousDb = state.dbHolder.underlying;\n state.dbHolder.underlying = nextDb;\n state.activeDbConfig = nextDbConfig;\n await previousDb.disconnect();\n return { section: 'db', status: 'reloaded' };\n } catch (error) {\n return { section: 'db', status: 'failed', error: formatReloadError(error) };\n }\n}\n\n/**\n * Attempts to reconnect the Redis throttle store when its raw config changed.\n *\n * @param state - Mutable runtime state.\n * @param nextRedisConfig - Parsed `redis` section from the reloaded config file.\n * @returns Section reload outcome.\n */\nasync function reloadRedisSection(\n state: RuntimeContextState,\n nextRedisConfig: Record<string, unknown>\n): Promise<ReloadSectionResult> {\n if (isDeepStrictEqual(state.activeRedisConfig, nextRedisConfig)) {\n return { section: 'redis', status: 'unchanged' };\n }\n\n try {\n const nextStore = createThrottleStore(nextRedisConfig);\n await nextStore.connect();\n const previousStore = state.throttleHolder.underlying;\n state.throttleHolder.underlying = nextStore;\n state.activeRedisConfig = nextRedisConfig;\n await previousStore.disconnect();\n return { section: 'redis', status: 'reloaded' };\n } catch (error) {\n return { section: 'redis', status: 'failed', error: formatReloadError(error) };\n }\n}\n\n/**\n * Reports when server bind settings changed and cannot be applied without restart.\n *\n * @param state - Active runtime state.\n * @param nextConfig - Newly parsed config file contents.\n * @returns Section reload outcome.\n */\nfunction reloadServerSection(\n state: RuntimeContextState,\n nextConfig: ServerConfig\n): ReloadSectionResult {\n if (state.host === nextConfig.host && state.port === nextConfig.port) {\n return { section: 'server', status: 'unchanged' };\n }\n\n return {\n section: 'server',\n status: 'restart-required',\n error: 'Changes to server.host or server.port require a full process restart.'\n };\n}\n\n/**\n * Re-reads server.yaml and applies reloadable sections on a best-effort basis.\n *\n * When the config file is invalid, nothing is changed and {@link ReloadResult.fatalError} is set.\n *\n * @param ctx - Runtime context to update.\n * @returns Per-section reload report.\n */\nexport async function reloadRuntimeConfig(ctx: RuntimeContext): Promise<ReloadResult> {\n const state = getState(ctx);\n\n let nextConfig: ServerConfig;\n try {\n nextConfig = loadServerConfig(state.configPath);\n } catch (error) {\n const message = error instanceof ConfigError ? error.message : formatReloadError(error);\n return { sections: [], fatalError: message };\n }\n\n const sections: ReloadSectionResult[] = [];\n\n sections.push(await reloadDbSection(state, nextConfig.db));\n sections.push(await reloadRedisSection(state, nextConfig.redis));\n\n state.llm = nextConfig.llm;\n sections.push({ section: 'llm', status: 'reloaded' });\n\n state.plugins = nextConfig.plugins;\n sections.push({ section: 'plugins', status: 'reloaded' });\n\n state.docs = nextConfig.docs;\n sections.push({ section: 'docs', status: 'reloaded' });\n\n sections.push(reloadServerSection(state, nextConfig));\n\n return { sections };\n}\n\n/**\n * Formats per-section reload outcomes for console output.\n *\n * @param result - Reload report returned by {@link reloadRuntimeConfig}.\n * @returns Single-line summary of section statuses.\n */\nfunction formatConfigReloadSummary(result: ReloadResult): string {\n return result.sections\n .map((section) => {\n if (section.error) {\n return `${section.section}: ${section.status} (${section.error})`;\n }\n\n return `${section.section}: ${section.status}`;\n })\n .join(', ');\n}\n\n/**\n * Writes a user-facing console message after a config reload attempt.\n *\n * Called for both SIGHUP and `POST /admin/config/reload` reloads.\n *\n * @param result - Reload report returned by {@link reloadRuntimeConfig}.\n */\nexport function logConfigReloadResult(result: ReloadResult): void {\n if (result.fatalError) {\n console.error(`Team Hub config reload failed: ${result.fatalError}`);\n return;\n }\n\n console.log(`Team Hub config reloaded (${formatConfigReloadSummary(result)}).`);\n}\n","import Redis from 'ioredis';\nimport { redisSectionSchema } from '#/config/serverConfig.schema.js';\nimport { formatZodError } from '#/db/validation.js';\nimport {\n DEFAULT_THROTTLE_POLICY,\n type IThrottleStore,\n type ThrottlePolicy\n} from '#/server/auth/throttle/IThrottleStore.js';\n\n/**\n * Minimal Redis client surface used by {@link RedisThrottleStore}.\n */\nexport interface RedisThrottleClient {\n /**\n * Increments a key and returns the new value.\n */\n incr(key: string): Promise<number>;\n\n /**\n * Sets a key's time-to-live in seconds.\n */\n expire(key: string, seconds: number): Promise<number>;\n\n /**\n * Returns whether a key exists.\n */\n exists(...keys: string[]): Promise<number>;\n\n /**\n * Sets a key with an optional expiry in seconds.\n */\n set(key: string, value: string, mode: 'EX', seconds: number): Promise<'OK' | null>;\n\n /**\n * Deletes one or more keys.\n */\n del(...keys: string[]): Promise<number>;\n\n /**\n * Opens the Redis connection.\n */\n connect(): Promise<void>;\n\n /**\n * Closes the Redis connection.\n */\n quit(): Promise<'OK' | undefined>;\n}\n\n/**\n * Validated Redis connection settings from server.yaml.\n */\nexport interface RedisThrottleConfig {\n host: string;\n port: number;\n password?: string;\n db?: number;\n keyPrefix?: string;\n maxFailures?: number;\n windowSeconds?: number;\n blockSeconds?: number;\n}\n\n/**\n * Redis-backed implementation of authentication throttling counters and blocks.\n */\nexport class RedisThrottleStore implements IThrottleStore {\n /**\n * Creates a Redis throttle store from an injected client and policy.\n *\n * @param client - Redis client implementing the throttle command surface.\n * @param config - Connection metadata including optional key prefix.\n * @param policy - Failure counting and block duration settings.\n */\n constructor(\n private readonly client: RedisThrottleClient,\n private readonly config: Pick<RedisThrottleConfig, 'keyPrefix'>,\n private readonly policy: ThrottlePolicy\n ) {}\n\n /**\n * Validates raw config and constructs a {@link RedisThrottleStore}.\n *\n * @param config - Raw `redis` section from server.yaml.\n * @returns Configured Redis throttle store instance.\n * @throws {Error} When config fails Redis-specific validation.\n */\n static fromConfig(config: unknown): RedisThrottleStore {\n const parsed = redisSectionSchema.safeParse(config);\n if (!parsed.success) {\n throw new Error(formatZodError(parsed.error));\n }\n\n const policy: ThrottlePolicy = {\n maxFailures: parsed.data.maxFailures ?? DEFAULT_THROTTLE_POLICY.maxFailures,\n windowSeconds: parsed.data.windowSeconds ?? DEFAULT_THROTTLE_POLICY.windowSeconds,\n blockSeconds: parsed.data.blockSeconds ?? DEFAULT_THROTTLE_POLICY.blockSeconds\n };\n\n const client = new Redis({\n host: parsed.data.host,\n port: parsed.data.port,\n password: parsed.data.password,\n db: parsed.data.db,\n lazyConnect: true\n }) as unknown as RedisThrottleClient;\n\n return new RedisThrottleStore(client, { keyPrefix: parsed.data.keyPrefix }, policy);\n }\n\n /**\n * Opens the underlying Redis connection.\n */\n async connect(): Promise<void> {\n await this.client.connect();\n }\n\n /**\n * Closes the underlying Redis connection.\n */\n async disconnect(): Promise<void> {\n await this.client.quit();\n }\n\n /**\n * Returns the configured throttle policy.\n */\n getPolicy(): ThrottlePolicy {\n return this.policy;\n }\n\n /**\n * Checks whether the throttle block key exists for the given auth key.\n *\n * @param key - Throttle key (typically client IP plus token hash).\n */\n async isBlocked(key: string): Promise<boolean> {\n const blocked = await this.client.exists(this.blockKey(key));\n return blocked > 0;\n }\n\n /**\n * Increments the failure counter and applies a block when the threshold is reached.\n *\n * @param key - Throttle key (typically client IP plus token hash).\n * @returns True when a new block was applied.\n */\n async recordFailure(key: string): Promise<boolean> {\n const failKey = this.failKey(key);\n const count = await this.client.incr(failKey);\n\n if (count === 1) {\n await this.client.expire(failKey, this.policy.windowSeconds);\n }\n\n if (count >= this.policy.maxFailures) {\n await this.client.set(this.blockKey(key), '1', 'EX', this.policy.blockSeconds);\n return true;\n }\n\n return false;\n }\n\n /**\n * Clears failure and block keys after successful authentication.\n *\n * @param key - Throttle key (typically client IP plus token hash).\n */\n async reset(key: string): Promise<void> {\n await this.client.del(this.failKey(key), this.blockKey(key));\n }\n\n /**\n * Builds the Redis key used to count failed auth attempts.\n *\n * @param key - Throttle key (typically client IP plus token hash).\n */\n private failKey(key: string): string {\n return `${this.prefix()}throttle:fail:${key}`;\n }\n\n /**\n * Builds the Redis key used to mark an auth key as blocked.\n *\n * @param key - Throttle key (typically client IP plus token hash).\n */\n private blockKey(key: string): string {\n return `${this.prefix()}throttle:block:${key}`;\n }\n\n /**\n * Returns the configured key prefix, if any.\n */\n private prefix(): string {\n const keyPrefix = this.config.keyPrefix;\n if (!keyPrefix) {\n return '';\n }\n\n return keyPrefix.endsWith(':') ? keyPrefix : `${keyPrefix}:`;\n }\n}\n","/**\n * Policy controlling how failed authentication attempts are counted and blocked.\n */\nexport interface ThrottlePolicy {\n /**\n * Number of failures within the window before a block is applied.\n */\n maxFailures: number;\n\n /**\n * Sliding window length in seconds for counting failures.\n */\n windowSeconds: number;\n\n /**\n * Block duration in seconds after the failure threshold is reached.\n */\n blockSeconds: number;\n}\n\n/**\n * Default throttle policy: 10 failures within 15 minutes triggers a 15 minute block.\n */\nexport const DEFAULT_THROTTLE_POLICY: ThrottlePolicy = {\n maxFailures: 10,\n windowSeconds: 900,\n blockSeconds: 900\n};\n\n/**\n * Contract for Redis-backed authentication throttling storage.\n */\nexport interface IThrottleStore {\n /**\n * Opens a connection to the throttle store.\n */\n connect(): Promise<void>;\n\n /**\n * Closes the throttle store connection and releases resources.\n */\n disconnect(): Promise<void>;\n\n /**\n * Returns the configured throttle policy for this store.\n */\n getPolicy(): ThrottlePolicy;\n\n /**\n * Checks whether the given key is currently blocked.\n *\n * @param key - Throttle key (typically client IP plus token hash).\n * @returns True when further auth attempts should be rejected with HTTP 429.\n */\n isBlocked(key: string): Promise<boolean>;\n\n /**\n * Records a failed authentication attempt for the given key.\n *\n * @param key - Throttle key (typically client IP plus token hash).\n * @returns True when the failure threshold was reached and a block was applied.\n */\n recordFailure(key: string): Promise<boolean>;\n\n /**\n * Clears failure counters and blocks for the given key after successful auth.\n *\n * @param key - Throttle key (typically client IP plus token hash).\n */\n reset(key: string): Promise<void>;\n}\n","import type { IThrottleStore } from '#/server/auth/throttle/IThrottleStore.js';\nimport { RedisThrottleStore } from '#/server/auth/throttle/RedisThrottleStore.js';\n\n/**\n * Creates a throttle store instance from the raw `redis` section of server.yaml.\n *\n * @param config - Raw `redis` section from server.yaml.\n * @returns Configured throttle store for authentication rate limiting.\n * @throws {Error} When config fails validation.\n */\nexport function createThrottleStore(config: unknown): IThrottleStore {\n return RedisThrottleStore.fromConfig(config);\n}\n","import { Command } from 'commander';\nimport type { FastifyInstance } from 'fastify';\nimport { mergeGlobalOptions } from '#/cli/globalOptions.js';\nimport { loadServerConfig, resolveConfigPath } from '#/config/serverConfig.js';\nimport { createServer } from '#/index.js';\nimport { disposeHubMcpConnections } from '#/server/llm/mcpClient.js';\nimport {\n connectRuntimeContext,\n createRuntimeContext,\n disconnectAll,\n logConfigReloadResult,\n reloadRuntimeConfig,\n type ReloadResult,\n type RuntimeContext\n} from '#/server/runtimeContext.js';\n\nexport interface StartCommandOptions {\n /**\n * When true, enables verbose server logging.\n */\n verbose?: boolean;\n\n /**\n * Path to the server YAML config file (from global `-c` / `--config`).\n */\n config: string;\n}\n\nexport interface RunServerOptions {\n /**\n * When true, logs resolved config and enables Fastify request logging.\n */\n verbose?: boolean;\n}\n\n/**\n * Formats a listen address for user-facing console output.\n *\n * Wildcard bind addresses (`0.0.0.0`, `::`) are shown as localhost so operators\n * know which URL to open locally.\n *\n * @param address - Address returned by the HTTP server after listen.\n * @param port - TCP port the server is listening on.\n * @returns HTTP URL suitable for display (e.g. `http://127.0.0.1:8787`).\n */\nfunction formatListenAddress(address: string | null, port: number): string {\n if (!address) {\n return `http://127.0.0.1:${port}`;\n }\n\n if (address === '0.0.0.0' || address === '::') {\n return `http://127.0.0.1:${port}`;\n }\n\n const host = address.includes(':') && !address.startsWith('[') ? `[${address}]` : address;\n return `http://${host}:${port}`;\n}\n\n/**\n * Registers SIGINT and SIGTERM handlers that close the Fastify instance cleanly.\n *\n * @param app - Running Fastify server to shut down on signal.\n * @param ctx - Runtime context whose connections are closed during shutdown.\n */\nfunction registerGracefulShutdown(app: FastifyInstance, ctx: RuntimeContext): void {\n /**\n * Closes the server and exits the process after a termination signal.\n *\n * @param signal - Signal that triggered shutdown.\n */\n const shutdown = async (signal: NodeJS.Signals) => {\n app.log.info(`Received ${signal}, shutting down.`);\n await app.close();\n await disposeHubMcpConnections();\n await disconnectAll(ctx);\n process.exit(0);\n };\n\n /**\n * Forwards SIGINT to the shared shutdown handler.\n */\n process.once('SIGINT', () => {\n void shutdown('SIGINT');\n });\n\n /**\n * Forwards SIGTERM to the shared shutdown handler.\n */\n process.once('SIGTERM', () => {\n void shutdown('SIGTERM');\n });\n}\n\n/**\n * Registers a repeatable SIGHUP handler that reloads server.yaml at runtime.\n *\n * @param reloadConfig - Shared reload handler that logs results and returns the report.\n */\nfunction registerConfigReloadHandler(reloadConfig: () => Promise<ReloadResult>): void {\n process.on('SIGHUP', () => {\n void reloadConfig();\n });\n}\n\n/**\n * Creates, listens on, and runs the Team Hub HTTP server until shutdown.\n *\n * @param ctx - Runtime context with bind settings and swappable connections.\n * @param options - Runtime options such as verbose logging.\n * @returns The listening Fastify instance (also registered for graceful shutdown).\n */\nexport async function runServer(\n ctx: RuntimeContext,\n options: RunServerOptions = {}\n): Promise<FastifyInstance> {\n /**\n * Reloads server.yaml, logs the outcome, and returns the per-section report.\n */\n const reloadConfig = async (): Promise<ReloadResult> => {\n const result = await reloadRuntimeConfig(ctx);\n logConfigReloadResult(result);\n return result;\n };\n\n const app = await createServer(ctx, {\n verbose: options.verbose,\n reloadConfig\n });\n\n await connectRuntimeContext(ctx);\n\n await app.listen({\n host: ctx.host,\n port: ctx.port\n });\n\n const address = app.server.address();\n const port = typeof address === 'object' && address ? address.port : ctx.port;\n const host = typeof address === 'object' && address ? address.address : ctx.host;\n\n if (options.verbose) {\n console.log('Starting server with config path:', ctx.configPath);\n }\n\n console.log(`Team Hub listening on ${formatListenAddress(host, port)}`);\n\n registerGracefulShutdown(app, ctx);\n registerConfigReloadHandler(reloadConfig);\n\n return app;\n}\n\n/**\n * CLI handler for the `start` subcommand: loads config and runs the server.\n *\n * @param options - Parsed start command options including config path.\n */\nexport async function startCommand(options: StartCommandOptions): Promise<void> {\n const configPath = resolveConfigPath(options.config);\n const config = loadServerConfig(options.config);\n const ctx = createRuntimeContext(config, configPath);\n await runServer(ctx, { verbose: options.verbose });\n}\n\n/**\n * Registers the `start` subcommand on a Commander program.\n *\n * @param program - Root or parent Commander instance.\n * @param handler - Action to run when `start` is invoked (defaults to {@link startCommand}).\n */\nexport function registerStartCommand(\n program: Command,\n handler: (options: StartCommandOptions) => Promise<void> = startCommand\n): void {\n program\n .command('start')\n .description('Start the Team Hub server')\n .action(\n /**\n * Runs the start subcommand after merging global CLI options.\n */\n async function startAction(this: Command, options: StartCommandOptions) {\n await handler(mergeGlobalOptions(this, options));\n }\n );\n}\n"],"mappings":"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","names":["Command","path","path","randomUUID","z","formatZodError","formatZodError","randomUUID","randomUUID","parseAuditEntityType","z","portSchema","formatZodError","randomUUID","rows","row","randomUUID","API_TOKENS_MIGRATION_SQL","COLLECTIONS_MIGRATION_SQL","ENVIRONMENTS_MIGRATION_SQL","SNIPPETS_MIGRATION_SQL","FOLDERS_MIGRATION_SQL","REQUESTS_MIGRATION_SQL","USERS_MIGRATION_SQL","AUDIT_LOG_MIGRATION_SQL","API_TOKENS_USER_ID_MIGRATION_SQL","API_TOKENS_ATTRIBUTION_MIGRATION_SQL","COLLECTIONS_ATTRIBUTION_MIGRATION_SQL","ENVIRONMENTS_ATTRIBUTION_MIGRATION_SQL","FOLDERS_ATTRIBUTION_MIGRATION_SQL","REQUESTS_ATTRIBUTION_MIGRATION_SQL","USERS_ATTRIBUTION_MIGRATION_SQL","COLLECTIONS_BACKFILL_UPDATED_AT_SQL","ENVIRONMENTS_BACKFILL_UPDATED_AT_SQL","FOLDERS_BACKFILL_UPDATED_AT_SQL","USERS_LLM_MIGRATION_SQL","LLM_USAGE_MIGRATION_SQL","LLM_USAGE_LOG_MIGRATION_SQL","COLLECTIONS_DELETION_LOCKED_MIGRATION_SQL","ENVIRONMENTS_DELETION_LOCKED_MIGRATION_SQL","USERS_SNIPPET_ACCESS_MIGRATION_SQL","USERS_SNIPPET_ACCESS_BACKFILL_SQL","RUN_RESULTS_MIGRATION_SQL","z","portSchema","COLLECTION_SELECT","ENVIRONMENT_SELECT","SNIPPET_SELECT","RUN_RESULT_SELECT_COLUMNS","RUN_RESULT_SELECT","USER_SELECT","API_TOKEN_SELECT","FOLDER_SELECT","REQUEST_SELECT","LLM_USAGE_SELECT","LLM_USAGE_LOG_SELECT","formatZodError","randomUUID","result","row","randomUUID","parseUserRole","readFileSync","z","z","z","z","z","z","z","z","version","existsSync","readFileSync","path","path","existsSync","readFileSync","sendLlmUnavailable","z","formatZodError","version","Command"]}