@emeryld/rrroutes-openapi 2.3.1 → 2.3.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/README.md +21 -10
- package/dist/docs/LeafDocsPage.d.ts +3 -23
- package/dist/docs/docs.d.ts +4 -7
- package/dist/docs/schemaIntrospection.d.ts +4 -13
- package/dist/docs/serializer.d.ts +5 -19
- package/dist/index.cjs +468 -670
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +30 -105
- package/dist/index.mjs +471 -670
- package/dist/index.mjs.map +1 -1
- package/dist/public/assets/docs.css +1 -1
- package/dist/public/assets/docs.js +260 -21
- package/dist/web/app.d.ts +1 -8
- package/dist/web/main.d.ts +1 -1
- package/dist/web/utils/grouping.d.ts +2 -8
- package/dist/web/utils/security.d.ts +21 -0
- package/dist/web/utils/types.d.ts +17 -0
- package/dist/web/v2/AppShell.d.ts +7 -0
- package/dist/web/v2/components/JsonInput.d.ts +10 -0
- package/dist/web/v2/components/JsonViewer.d.ts +12 -0
- package/dist/web/v2/components/MethodBadge.d.ts +4 -0
- package/dist/web/v2/components/New/HttpMethodChip.d.ts +7 -0
- package/dist/web/v2/components/New/ListToolBar.d.ts +11 -0
- package/dist/web/v2/components/New/MethodFiltersChips.d.ts +7 -0
- package/dist/web/v2/components/New/RequestStatusChip.d.ts +6 -0
- package/dist/web/v2/components/New/SplitPageLayout.d.ts +7 -0
- package/dist/web/v2/components/New/StabilityChip.d.ts +7 -0
- package/dist/web/v2/components/New/StatusRangeFilter.d.ts +8 -0
- package/dist/web/v2/components/RecordItem.d.ts +34 -0
- package/dist/web/v2/components/ResizableSidePanel.d.ts +12 -0
- package/dist/web/v2/components/SchemaTable.d.ts +5 -0
- package/dist/web/v2/components/SectionHeader.d.ts +9 -0
- package/dist/web/v2/endpoints/EndpointDetailsPanel.d.ts +5 -0
- package/dist/web/v2/endpoints/EndpointList.d.ts +12 -0
- package/dist/web/v2/endpoints/EndpointsPage.d.ts +4 -0
- package/dist/web/v2/endpoints/endpoints.utils.d.ts +3 -0
- package/dist/web/v2/stores/clientStore.d.ts +48 -0
- package/dist/web/v2/theme.d.ts +21 -0
- package/dist/web/v2/types/types.base.d.ts +30 -0
- package/dist/web/v2/types/types.cacheLog.d.ts +165 -0
- package/dist/web/v2/types/types.endpoint.d.ts +326 -0
- package/dist/web/v2/types/types.log.d.ts +119 -0
- package/dist/web/v2/types/types.preset.d.ts +251 -0
- package/dist/web/v2/types/types.requestLog.d.ts +264 -0
- package/package.json +16 -5
- package/dist/docs/presets.d.ts +0 -14
- package/dist/web/components/Analytics.d.ts +0 -68
- package/dist/web/components/CopyablePre.d.ts +0 -7
- package/dist/web/components/EndpointCard.d.ts +0 -10
- package/dist/web/components/Filters.d.ts +0 -9
- package/dist/web/components/FiltersBar.d.ts +0 -25
- package/dist/web/components/HelperEnumInput.d.ts +0 -11
- package/dist/web/components/HistoryView.d.ts +0 -7
- package/dist/web/components/LogsView.d.ts +0 -1
- package/dist/web/components/PlaygroundOverlay.d.ts +0 -94
- package/dist/web/components/PresetsView.d.ts +0 -15
- package/dist/web/components/RequestLogs.d.ts +0 -10
- package/dist/web/components/SchemaTable.d.ts +0 -4
- package/dist/web/components/ui/Button.d.ts +0 -8
- package/dist/web/components/ui/Clickable.d.ts +0 -7
- package/dist/web/components/ui/Tag.d.ts +0 -9
- package/dist/web/components/ui/Text.d.ts +0 -8
- package/dist/web/components/ui/index.d.ts +0 -4
- package/dist/web/historyStore.d.ts +0 -68
- package/dist/web/logsStore.d.ts +0 -51
- package/dist/web/types.d.ts +0 -5
- package/dist/webhooks.d.ts +0 -181
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/docs/LeafDocsPage.tsx","../src/docs/schemaIntrospection.ts","../src/docs/serializer.ts","../src/docs/docs.ts","../src/webhooks.ts"],"sourcesContent":["/**\n * dry styles\nfake history logs data for testing\ngraphs for history data\nlogs webhook\nsecurity -> gated access + give environment and if environment='production' -> extra \"Are you sure you want to do this\" pop-up for each non-get action\n */\n\nimport type { AnyLeaf } from '@emeryld/rrroutes-contract';\nimport { randomBytes } from 'crypto';\nimport type { Request, Response, Router } from 'express';\nimport { static as expressStatic } from 'express';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport z from 'zod';\nimport type { SerializableHistoryEntry } from './docs/docs.js';\nimport { renderLeafDocsHTML } from './docs/docs.js';\nimport type { SerializablePreset } from './docs/presets.js';\nimport {\n historyFeedEntrySchema,\n historyFeedQuerySchema,\n historyWebhookResponseSchema,\n logFeedEntrySchema,\n logFeedQuerySchema,\n logWebhookResponseSchema,\n type HistoryFeedEntry,\n type HistoryFeedQuery,\n type LogFeedEntry,\n type LogFeedQuery,\n type LogType,\n type WebhookPage,\n type WebhookPaths\n} from './webhooks.js';\n\nexport type DocsRequestContext = {\n req: Request;\n res: Response;\n leaves: AnyLeaf[];\n presets: PresetGroup<AnyLeaf>[];\n};\n\nexport type DocsOnRequestResult = {\n leaves?: AnyLeaf[];\n presets?: PresetGroup<AnyLeaf>[];\n nonce?: string;\n html?: string;\n};\n\nexport type DocsAuthOptions = {\n /** Turn auth on/off. Enabled by default. */\n enabled?: boolean;\n /** Password to require for docs access. Falls back to the env var when omitted. */\n password?: string;\n /** Realm used for the HTTP Basic challenge prompt. */\n realm?: string;\n};\n\nexport type LogRedactor = (entry: LogFeedEntry) => LogFeedEntry | null | undefined;\n\nexport type OpenApiDocsOptions = {\n /** Path where docs are mounted. Defaults to `/__rrroutes/docs`. */\n path?: string;\n prefix?: string;\n /** Whether to emit a CSP header + nonce. Defaults to true. */\n csp?: boolean;\n /** Override where static assets are served from. Defaults to `${path}/assets`. */\n assetBasePath?: string;\n /** Optional seed history entries that will pre-populate the docs UI history. */\n historySeeds?: SerializableHistoryEntry[];\n /** Optional seed log entries that will pre-populate the docs UI logs tab. */\n logSeeds?: LogFeedEntry[];\n /** Handlers + settings for webhook-driven history/log feeds. */\n logWebhook?: LogWebhookConfig;\n /**\n * Optional hook to redact or drop log entries before they are persisted or sent to the UI.\n * Return `null`/`undefined` to skip an entry entirely.\n */\n redactLogEntry?: LogRedactor;\n /** Password protection + realm configuration for the mounted docs. */\n auth?: DocsAuthOptions;\n /**\n * Hook that runs on every request. Use it to adjust leaves, override nonce, or\n * provide a fully custom HTML response.\n */\n onRequest?: (ctx: DocsRequestContext) => DocsOnRequestResult | void;\n};\n\nexport type Preset<L extends AnyLeaf> = L extends infer A extends AnyLeaf? {\n method: A['method'];\n path: A['path'];\n // pre-set values for schemas. Does not have to be complete.\n body?: z.output<A['cfg']['bodySchema']>;\n query?: z.output<A['cfg']['querySchema']>;\n params?: z.output<A['cfg']['paramsSchema']>;\n}:never;\n\nexport type PresetGroup<L extends AnyLeaf> = {\n name: string;\n description?: string;\n tags: string[];\n docsGroup?: string;\n\n ops: Preset<L>[];\n};\n\nexport type MountDocsArgs<L extends AnyLeaf> = {\n router: Router;\n leaves: L[];\n presets?: PresetGroup<L>[];\n options?: OpenApiDocsOptions;\n};\n\nexport type WebhookLeafMap = {\n history: AnyLeaf;\n logs: AnyLeaf;\n};\n\nexport type WebhookSchemaMap = {\n history: {\n query: typeof historyFeedQuerySchema;\n response: typeof historyWebhookResponseSchema;\n entry: typeof historyFeedEntrySchema;\n };\n logs: {\n query: typeof logFeedQuerySchema;\n response: typeof logWebhookResponseSchema;\n entry: typeof logFeedEntrySchema;\n };\n};\n\nexport type MountDocsResult = {\n path: string;\n webhooks: WebhookPaths;\n webhookLeaves: WebhookLeafMap;\n webhookSchemas: WebhookSchemaMap;\n};\n\ntype WebhookHandler<Q, R> = (ctx: { query: Q; req: Request; res: Response }) => Promise<WebhookPage<R>> | WebhookPage<R>;\n\nexport type LogWebhookConfig = {\n /** Base path for webhook endpoints. Defaults to `${docsPath}/webhooks`. */\n basePath?: string;\n /** Handler to hydrate the history feed. */\n history?: WebhookHandler<HistoryFeedQuery, HistoryFeedEntry>;\n /** Handler to hydrate the log feed. */\n logs?: WebhookHandler<LogFeedQuery, LogFeedEntry>;\n};\n\nconst trimTrailingSlash = (value: string) =>\n value.endsWith('/') && value.length > 1 ? value.slice(0, -1) : value;\n\nexport function mountRRRoutesDocs<L extends AnyLeaf>({\n router,\n leaves,\n presets = [],\n options = {},\n}: MountDocsArgs<L>): MountDocsResult {\n const prefix = options.prefix ? trimTrailingSlash(options.prefix) : '';\n const docsPath = options.path ?? '/__rrroutes/docs';\n const normalizedDocsPath = trimTrailingSlash(docsPath);\n const assetsMountPath = trimTrailingSlash(\n options.assetBasePath ?? `${normalizedDocsPath}/assets`,\n );\n const webhookBaseInput = options.logWebhook?.basePath ?? `${normalizedDocsPath}/webhooks`;\n const webhookBasePath = trimTrailingSlash(\n webhookBaseInput.startsWith('/') ? webhookBaseInput : `/${webhookBaseInput}`,\n );\n const defaultHistoryLimit = 200;\n const defaultLogLimit = 400;\n const redactLogEntry = createLogRedactor(options.redactLogEntry);\n const seededHistory = normalizeHistorySeeds(options.historySeeds, defaultHistoryLimit);\n const seededLogs = normalizeLogSeeds(options.logSeeds, defaultLogLimit, redactLogEntry);\n const inMemoryHistory: HistoryFeedEntry[] = seededHistory.slice();\n const inMemoryLogs: LogFeedEntry[] = seededLogs.slice();\n const historySeedsForUi: SerializableHistoryEntry[] = seededHistory.map((entry) => ({\n ...entry,\n fullUrl: entry.fullUrl || entry.path,\n }));\n const webhookPaths: WebhookPaths = {\n history: `${webhookBasePath}/history`,\n logs: `${webhookBasePath}/logs`,\n };\n const webhookSchemas: WebhookSchemaMap = {\n history: {\n query: historyFeedQuerySchema,\n response: historyWebhookResponseSchema,\n entry: historyFeedEntrySchema,\n },\n logs: {\n query: logFeedQuerySchema,\n response: logWebhookResponseSchema,\n entry: logFeedEntrySchema,\n },\n };\n const webhookLeaves = {\n history: {\n method: 'get',\n path: webhookPaths.history,\n cfg: {\n summary: 'RRRoutes docs history feed',\n description: 'Returns request history for the docs UI.',\n querySchema: historyFeedQuerySchema,\n outputSchema: historyWebhookResponseSchema,\n tags: ['rrroutes', 'docs'],\n },\n },\n logs: {\n method: 'get',\n path: webhookPaths.logs,\n cfg: {\n summary: 'RRRoutes docs request logs',\n description: 'Returns request logs for the docs UI.',\n querySchema: logFeedQuerySchema,\n outputSchema: logWebhookResponseSchema,\n tags: ['rrroutes', 'docs'],\n },\n },\n } as const satisfies WebhookLeafMap;\n const publicDir = resolvePublicDir();\n const assetsDir = path.join(publicDir, 'assets');\n const cspEnabled = options.csp !== false;\n const authConfig = options.auth;\n const authEnabled = authConfig?.enabled !== false;\n const docsPassword = resolveDocsPassword(authConfig);\n const authRealm = authConfig?.realm || 'RRRoutes Docs';\n\n if (authEnabled) {\n const guard = docsPassword\n ? createPasswordGuard(docsPassword, authRealm)\n : createMissingPasswordGuard();\n [normalizedDocsPath, assetsMountPath, webhookBasePath].forEach((p) => {\n router.use(p, guard);\n });\n }\n\n router.use(assetsMountPath, expressStatic(assetsDir, { immutable: true, maxAge: '365d' }));\n const usingFakeHistory = !options.logWebhook?.history;\n const usingFakeLogs = !options.logWebhook?.logs;\n\n if (usingFakeHistory || usingFakeLogs) {\n router.use((req, res, next) => {\n if (\n req.path.startsWith(webhookBasePath) ||\n req.path.startsWith(assetsMountPath) ||\n req.path.startsWith(normalizedDocsPath)\n ) {\n return next();\n }\n const start = Date.now();\n const requestIdHeader =\n req.headers['x-request-id'] || req.headers['x-requestid'] || req.headers['x-request_id'];\n const requestId = Array.isArray(requestIdHeader) ? requestIdHeader[0] : requestIdHeader;\n res.once('finish', () => {\n const timestamp = Date.now();\n const durationMs = Math.max(timestamp - start, 0);\n const methodUpper = String(req.method || 'GET').toUpperCase();\n const pathOnly = req.path || req.originalUrl || '';\n const status = res.statusCode;\n const errorMsg = status >= 400 ? `${status}` : undefined;\n\n if (usingFakeHistory) {\n inMemoryHistory.unshift({\n id: randomBytes(8).toString('hex'),\n requestId: requestId ? String(requestId) : undefined,\n timestamp,\n method: methodUpper,\n path: pathOnly,\n fullUrl: req.originalUrl || pathOnly,\n params: {},\n query: coerceQueryRecord(req.query),\n body: coercePayload(req.body),\n output: '',\n status,\n durationMs,\n error: errorMsg,\n });\n if (inMemoryHistory.length > defaultHistoryLimit) inMemoryHistory.length = defaultHistoryLimit;\n }\n\n if (usingFakeLogs) {\n const logType: LogType = status >= 500 ? 'error' : status >= 400 ? 'warn' : 'info';\n const metadata = JSON.stringify({\n query: req.query,\n durationMs,\n });\n const redacted = redactLogEntry({\n id: randomBytes(8).toString('hex'),\n type: logType,\n message: `${methodUpper} ${pathOnly} -> ${status}`,\n timestamp,\n requestId: requestId ? String(requestId) : undefined,\n tags: [],\n metadata,\n });\n if (redacted) {\n inMemoryLogs.unshift(redacted);\n if (inMemoryLogs.length > defaultLogLimit) inMemoryLogs.length = defaultLogLimit;\n }\n }\n });\n next();\n });\n }\n\n router.get(webhookPaths.history, async (req, res) => {\n const handler = options.logWebhook?.history;\n try {\n applyDocsSecurityHeaders(res);\n const query = parseHistoryWebhookQuery(req);\n if (!handler) {\n const filtered = applyHistoryQuery(inMemoryHistory, query, defaultHistoryLimit);\n res.json(filtered);\n return;\n }\n const result = await handler({ query, req, res });\n\n const normalized = normalizeWebhookPage(result);\n const filtered = applyHistoryQuery(normalized.items, query, defaultHistoryLimit);\n res.json(filtered);\n } catch (err) {\n console.error('Failed to serve history webhook', err);\n res.status(500).json({ error: 'Failed to load history feed' });\n }\n });\n\n router.get(webhookPaths.logs, async (req, res) => {\n const handler = options.logWebhook?.logs;\n try {\n applyDocsSecurityHeaders(res);\n const query = parseLogWebhookQuery(req);\n if (!handler) {\n const filtered = applyLogsQuery(inMemoryLogs, query, defaultLogLimit);\n res.json(filtered);\n return;\n }\n const result = await handler({ query, req, res });\n const normalized = normalizeWebhookPage(result);\n const redacted = applyLogRedaction(normalized.items, redactLogEntry);\n const filtered = applyLogsQuery(redacted, query, defaultLogLimit);\n res.json(filtered);\n } catch (err) {\n console.error('Failed to serve log webhook', err);\n res.status(500).json({ error: 'Failed to load logs feed' });\n }\n });\n\n const docsRoutePaths = [normalizedDocsPath, `${normalizedDocsPath}/`, `${normalizedDocsPath}/*id`];\n\n router.get(docsRoutePaths, (req, res) => {\n const preparedLeaves = Array.isArray(leaves)\n ? leaves.filter((leaf) => leaf.cfg.docsHidden !== true)\n : [];\n const preparedPresets = Array.isArray(presets) ? presets : [];\n const onRequestResult =\n options.onRequest?.({ req, res, leaves: preparedLeaves, presets: preparedPresets }) ?? {};\n const finalLeaves = onRequestResult.leaves ?? preparedLeaves;\n const finalPresets = onRequestResult.presets ?? preparedPresets;\n\n const hasCustomHtml = typeof onRequestResult.html === 'string';\n\n let nonce = onRequestResult.nonce;\n if (!nonce && cspEnabled && !hasCustomHtml) {\n nonce = randomBytes(16).toString('base64');\n }\n\n const html = hasCustomHtml\n ? (onRequestResult.html as string)\n : renderLeafDocsHTML(finalLeaves, {\n cspNonce: nonce,\n assetBasePath: `${prefix}${assetsMountPath}`,\n docsBasePath: `${prefix}${normalizedDocsPath}`,\n baseUrlSuffix: prefix,\n historySeeds: historySeedsForUi,\n logSeeds: seededLogs,\n presets: normalizePresets(finalPresets),\n webhooks: {\n history: `${prefix}${webhookPaths.history}`,\n logs: `${prefix}${webhookPaths.logs}`,\n },\n });\n\n applyDocsSecurityHeaders(res);\n if (cspEnabled && nonce) {\n res.setHeader(\n 'Content-Security-Policy',\n [\n \"default-src 'self'\",\n `script-src 'self' 'nonce-${nonce}'`,\n `style-src 'self' 'nonce-${nonce}'`,\n \"img-src 'self' data:\",\n \"connect-src 'self'\",\n \"font-src 'self'\",\n \"frame-ancestors 'self'\",\n ].join('; '),\n );\n }\n\n res.send(html);\n });\n\n return { path: docsPath, webhooks: webhookPaths, webhookLeaves, webhookSchemas };\n}\n\nfunction resolvePublicDir() {\n const moduleDir =\n typeof __dirname !== 'undefined'\n ? __dirname\n : path.dirname(fileURLToPath(import.meta.url));\n const fromModule = path.resolve(moduleDir, '../public');\n if (fs.existsSync(fromModule)) return fromModule;\n\n // When running from source (ts-node), fall back to the built output path.\n const fallback = path.resolve(moduleDir, '../dist/public');\n if (fs.existsSync(fallback)) return fallback;\n\n return fromModule; // fallback; express static will 404 if missing\n}\n\nfunction normalizePresets(presets: PresetGroup<AnyLeaf>[]): SerializablePreset[] {\n if (!Array.isArray(presets)) return [];\n return presets.map((preset) => ({\n name: preset.name,\n description: preset.description,\n tags: Array.isArray(preset.tags) ? preset.tags.slice() : [],\n docsGroup: preset.docsGroup,\n ops: Array.isArray(preset.ops)\n ? preset.ops.map((op) => ({\n method: typeof op.method === 'string' ? op.method.toUpperCase() : '',\n path: typeof op.path === 'string' ? op.path : '',\n body: op.body,\n query: op.query,\n params: op.params,\n }))\n : [],\n }));\n}\n\nfunction parseHistoryWebhookQuery(req: Request): HistoryFeedQuery {\n const query = req.query || {};\n const methods = parseStringList(query.methods);\n const path = typeof query.path === 'string' ? query.path : undefined;\n const status = typeof query.status === 'string' ? query.status : undefined;\n const text = typeof query.text === 'string' ? query.text : undefined;\n const cursor = typeof query.cursor === 'string' ? query.cursor : undefined;\n const sortBy = isSortKey(query.sortBy) ? (query.sortBy as HistoryFeedQuery['sortBy']) : undefined;\n const sortDir = isSortDir(query.sortDir) ? (query.sortDir as HistoryFeedQuery['sortDir']) : undefined;\n const limit = parseLimit(query.limit);\n const from = parseDateInput(query.from);\n const to = parseDateInput(query.to);\n\n return {\n cursor,\n methods,\n path,\n status,\n text,\n limit,\n from,\n to,\n sortBy,\n sortDir,\n };\n}\n\nfunction parseLogWebhookQuery(req: Request): LogFeedQuery {\n const query = req.query || {};\n const types = parseStringList(query.types) as LogFeedQuery['types'];\n const tags = parseStringList(query.tags);\n const requestId = typeof query.requestId === 'string' ? query.requestId : undefined;\n const text = typeof query.text === 'string' ? query.text : undefined;\n const cursor = typeof query.cursor === 'string' ? query.cursor : undefined;\n const limit = parseLimit(query.limit);\n const from = parseDateInput(query.from);\n const to = parseDateInput(query.to);\n const sortDir = isSortDir(query.sortDir) ? (query.sortDir as LogFeedQuery['sortDir']) : undefined;\n\n return {\n cursor,\n types,\n tags,\n requestId,\n text,\n limit,\n from,\n to,\n sortDir,\n };\n}\n\nfunction parseStringList(value: unknown) {\n if (typeof value !== 'string') return undefined;\n const parts = value\n .split(',')\n .map((p) => p.trim())\n .filter(Boolean);\n return parts.length ? parts : undefined;\n}\n\nfunction parseLimit(value: unknown) {\n if (value === undefined) return undefined;\n const num = Number(value);\n if (!Number.isFinite(num) || num <= 0) return undefined;\n return num;\n}\n\nfunction parseDateInput(value: unknown) {\n if (typeof value !== 'string') return undefined;\n const numeric = Number(value);\n if (Number.isFinite(numeric)) return numeric;\n const timestamp = Date.parse(value);\n if (Number.isNaN(timestamp)) return undefined;\n return timestamp;\n}\n\nfunction isSortKey(value: unknown) {\n return value === 'timestamp' || value === 'path' || value === 'duration';\n}\n\nfunction isSortDir(value: unknown) {\n return value === 'asc' || value === 'desc';\n}\n\nfunction normalizeWebhookPage<T>(page: WebhookPage<T> | null | undefined): WebhookPage<T> {\n if (!page || typeof page !== 'object') return { items: [] };\n return {\n items: Array.isArray(page.items) ? page.items : [],\n nextCursor: page.nextCursor,\n prevCursor: page.prevCursor,\n total: page.total,\n };\n}\n\nfunction applyHistoryQuery(\n items: HistoryFeedEntry[],\n query: HistoryFeedQuery,\n hardLimit: number,\n): WebhookPage<HistoryFeedEntry> {\n const fromTs = typeof query.from === 'number' ? query.from : undefined;\n const toTs = typeof query.to === 'number' ? query.to : undefined;\n const methods = query.methods ? new Set(query.methods.map((m) => m.toUpperCase())) : undefined;\n const pathNeedle = (query.path || '').toLowerCase();\n const textNeedle = (query.text || '').toLowerCase();\n const statusNeedle = (query.status || '').trim();\n const filtered = (Array.isArray(items) ? items : []).filter((entry) => {\n if (methods?.size && !methods.has(String(entry.method || '').toUpperCase())) return false;\n if (pathNeedle && !String(entry.path || '').toLowerCase().includes(pathNeedle)) return false;\n if (statusNeedle) {\n const statusStr =\n entry.status !== undefined && entry.status !== null ? String(entry.status) : 'ERR';\n if (!statusStr.startsWith(statusNeedle)) return false;\n }\n if (Number.isFinite(fromTs) && entry.timestamp < (fromTs as number)) return false;\n if (Number.isFinite(toTs) && entry.timestamp > (toTs as number)) return false;\n if (textNeedle) {\n const haystack = [\n entry.path,\n entry.fullUrl,\n entry.body,\n entry.output,\n entry.error,\n JSON.stringify(entry.params || {}),\n JSON.stringify(entry.query || {}),\n ]\n .filter(Boolean)\n .join(' ')\n .toLowerCase();\n if (!haystack.includes(textNeedle)) return false;\n }\n return true;\n });\n\n const sortBy = query.sortBy || 'timestamp';\n const direction = query.sortDir === 'asc' ? 1 : -1;\n const sorted = filtered.slice().sort((a, b) => {\n let delta = 0;\n if (sortBy === 'path') {\n delta = String(a.path || '').localeCompare(String(b.path || ''));\n } else if (sortBy === 'duration') {\n delta = (a.durationMs || 0) - (b.durationMs || 0);\n } else {\n delta = (a.timestamp || 0) - (b.timestamp || 0);\n }\n return delta * direction;\n });\n\n return paginateItems(sorted, query.cursor, query.limit, hardLimit, 25);\n}\n\nfunction applyLogsQuery(\n items: LogFeedEntry[],\n query: LogFeedQuery,\n hardLimit: number,\n): WebhookPage<LogFeedEntry> {\n const fromTs = typeof query.from === 'number' ? query.from : undefined;\n const toTs = typeof query.to === 'number' ? query.to : undefined;\n const textNeedle = (query.text || '').toLowerCase();\n const requestIdNeedle = (query.requestId || '').toLowerCase();\n const types = query.types ? new Set(query.types) : undefined;\n const tags = query.tags ? new Set(query.tags) : undefined;\n const filtered = (Array.isArray(items) ? items : []).filter((entry) => {\n if (types?.size && !types.has(entry.type)) return false;\n const entryTags = Array.isArray(entry.tags) ? entry.tags : [];\n if (tags?.size && !entryTags.some((tag) => tags.has(tag))) return false;\n if (requestIdNeedle && !(entry.requestId || '').toLowerCase().includes(requestIdNeedle))\n return false;\n if (Number.isFinite(fromTs) && entry.timestamp < (fromTs as number)) return false;\n if (Number.isFinite(toTs) && entry.timestamp > (toTs as number)) return false;\n if (textNeedle) {\n const haystack = [\n entry.message,\n entry.requestId,\n entryTags.join(' '),\n typeof entry.metadata === 'string' ? entry.metadata : JSON.stringify(entry.metadata || ''),\n ]\n .filter(Boolean)\n .join(' ')\n .toLowerCase();\n if (!haystack.includes(textNeedle)) return false;\n }\n return true;\n });\n\n const direction = query.sortDir === 'asc' ? 1 : -1;\n const sorted = filtered.slice().sort((a, b) => (a.timestamp - b.timestamp) * direction);\n\n return paginateItems(sorted, query.cursor, query.limit, hardLimit, 50);\n}\n\nfunction paginateItems<T>(\n items: T[],\n cursor: string | undefined,\n limit: number | undefined,\n hardLimit: number,\n fallbackLimit: number,\n): WebhookPage<T> {\n const safeLimit = clampLimit(limit, hardLimit, fallbackLimit);\n const start = parseCursor(cursor);\n const end = start + safeLimit;\n const slice = items.slice(start, end);\n const nextCursor = end < items.length ? String(end) : undefined;\n const prevCursor = start > 0 ? String(Math.max(start - safeLimit, 0)) : undefined;\n return {\n items: slice,\n nextCursor,\n prevCursor,\n total: items.length,\n };\n}\n\nfunction clampLimit(value: number | undefined, hardLimit: number, fallback: number) {\n if (!Number.isFinite(value)) return Math.min(hardLimit, fallback);\n const safe = Math.max(1, Math.min(hardLimit, value as number));\n return safe;\n}\n\nfunction parseCursor(cursor: string | undefined | null) {\n const num = Number(cursor);\n if (Number.isFinite(num) && num >= 0) return Math.floor(num);\n return 0;\n}\n\nfunction normalizeHistorySeeds(\n seeds: SerializableHistoryEntry[] | undefined,\n hardLimit: number,\n): HistoryFeedEntry[] {\n if (!Array.isArray(seeds)) return [];\n return seeds\n .slice(0, hardLimit)\n .map((entry, idx) => ({\n id: entry.id || randomBytes(8).toString('hex'),\n requestId: typeof (entry as any).requestId === 'string' ? (entry as any).requestId : undefined,\n timestamp: entry.timestamp ?? Date.now() - idx * 1000,\n method: entry.method || 'GET',\n path: entry.path || '/',\n fullUrl: entry.fullUrl || entry.path || '/',\n params: entry.params || {},\n query: entry.query || {},\n body: entry.body || '',\n output: entry.output || '',\n status: entry.status,\n durationMs: entry.durationMs ?? 0,\n error: entry.error,\n }))\n .filter((entry) => entry.method && entry.path);\n}\n\nfunction normalizeLogSeeds(\n seeds: LogFeedEntry[] | undefined,\n hardLimit: number,\n redactor: ReturnType<typeof createLogRedactor>,\n): LogFeedEntry[] {\n if (!Array.isArray(seeds)) return [];\n const normalized = seeds\n .slice(0, hardLimit)\n .map((entry, idx) => ({\n id: entry.id || randomBytes(8).toString('hex'),\n type: entry.type || 'info',\n message: entry.message || '',\n timestamp: entry.timestamp ?? Date.now() - idx * 1000,\n requestId: entry.requestId,\n tags: Array.isArray(entry.tags) ? entry.tags : [],\n metadata: entry.metadata,\n }))\n .filter((entry) => entry.message);\n\n return applyLogRedaction(normalized, redactor);\n}\n\nfunction coerceQueryRecord(query: Request['query']): Record<string, string> {\n if (!query || typeof query !== 'object') return {};\n return Object.fromEntries(\n Object.entries(query).map(([key, value]) => [key, coerceValue(value)]),\n );\n}\n\nfunction coercePayload(body: unknown): string {\n if (body === undefined || body === null) return '';\n if (typeof body === 'string') return body;\n try {\n return JSON.stringify(body);\n } catch {\n return String(body);\n }\n}\n\nfunction coerceValue(value: unknown): string {\n if (value === undefined || value === null) return '';\n if (Array.isArray(value)) return value.map(coerceValue).join(',');\n if (typeof value === 'object') {\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n }\n return String(value);\n}\n\nfunction createLogRedactor(redactor?: LogRedactor) {\n if (!redactor) return (entry: LogFeedEntry) => entry;\n return (entry: LogFeedEntry) => {\n try {\n return redactor(entry) ?? null;\n } catch (err) {\n console.error('Log redaction failed – dropping log entry', err);\n return null;\n }\n };\n}\n\nfunction applyLogRedaction(\n entries: LogFeedEntry[] | undefined,\n redactor: ReturnType<typeof createLogRedactor>,\n): LogFeedEntry[] {\n if (!Array.isArray(entries)) return [];\n const next: LogFeedEntry[] = [];\n for (const entry of entries) {\n const redacted = redactor(entry);\n if (redacted) next.push(redacted);\n }\n return next;\n}\n\nfunction resolveDocsPassword(auth?: DocsAuthOptions) {\n if (auth?.password) return auth.password;\n return undefined;\n}\n\nfunction createPasswordGuard(password: string, realm: string) {\n const trimmed = password.trim();\n return (req: Request, res: Response, next: () => void) => {\n const provided = extractPassword(req.headers.authorization);\n if (provided && provided === trimmed) {\n return next();\n }\n applyDocsSecurityHeaders(res);\n res.setHeader('WWW-Authenticate', `Basic realm=\"${realm}\"`);\n res.status(401).send(renderAuthErrorPage('Docs are password protected. Provide the configured password.'));\n };\n}\n\nfunction createMissingPasswordGuard() {\n return (_req: Request, res: Response) => {\n applyDocsSecurityHeaders(res);\n res\n .status(500)\n .send(renderAuthErrorPage('Provide password to mounted docs'));\n };\n}\n\nfunction extractPassword(authHeader: string | string[] | undefined) {\n if (!authHeader) return undefined;\n const header = Array.isArray(authHeader) ? authHeader[0] : authHeader;\n if (typeof header !== 'string' || !header.startsWith('Basic ')) return undefined;\n const token = header.slice('Basic '.length);\n try {\n const decoded = Buffer.from(token, 'base64').toString('utf8');\n const parts = decoded.split(':');\n parts.shift(); // username\n return parts.join(':');\n } catch {\n return undefined;\n }\n}\n\nfunction renderAuthErrorPage(message: string) {\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>RRRoutes docs locked</title>\n <style>\n body { margin:0; font-family: system-ui, -apple-system, Segoe UI, sans-serif; background: #0f172a; color: #e2e8f0; display:flex; align-items:center; justify-content:center; min-height:100vh; }\n .card { padding:32px; border:1px solid #1e293b; border-radius:12px; max-width:420px; background: rgba(15,23,42,0.8); box-shadow:0 15px 45px rgba(0,0,0,0.35); }\n h1 { margin:0 0 12px; font-size:22px; }\n p { margin:0; line-height:1.5; color:#cbd5e1; }\n code { background: rgba(226,232,240,0.1); padding: 2px 4px; border-radius: 4px; }\n </style>\n</head>\n<body>\n <div class=\"card\">\n <h1>Docs locked</h1>\n <p>${message}</p>\n </div>\n</body>\n</html>`;\n}\n\nfunction applyDocsSecurityHeaders(res: Response) {\n res.setHeader('X-Content-Type-Options', 'nosniff');\n res.setHeader('Referrer-Policy', 'same-origin');\n res.setHeader('X-Frame-Options', 'SAMEORIGIN');\n res.setHeader('Cache-Control', 'no-store');\n}\n\nexport { renderLeafDocsHTML } from './docs/docs.js';\nexport { serializeLeaf } from './docs/serializer.js';\nexport type { SerializableLeaf } from './docs/serializer.js';\nexport type {\n HistoryFeedEntry, historyFeedEntrySchema, HistoryFeedQuery, historyFeedQuerySchema,\n historyWebhookResponseSchema, LogFeedEntry, logFeedEntrySchema, LogFeedQuery, logFeedQuerySchema, LogType, logTypeSchema, logWebhookResponseSchema, WebhookPage, webhookPageSchema, WebhookPaths\n} from './webhooks.js';\n","import type { AnyLeaf } from '@emeryld/rrroutes-contract';\nimport type { ReactElement } from 'react';\nimport { renderToStaticMarkup } from 'react-dom/server';\nimport type { SerializablePreset } from './presets.js';\nimport { serializeLeaf } from './serializer.js';\nimport type { WebhookPaths } from '../webhooks.js';\nimport type { LogFeedEntry } from '../webhooks.js';\n\nexport interface RenderOptions {\n /** CSP nonce applied to data + script tags. */\n cspNonce?: string;\n /** Base URL where static assets are served (e.g. `/__rrroutes/docs/assets`). */\n assetBasePath?: string;\n /** Root path where the docs are mounted (e.g. `/__rrroutes/docs`). Used for client routing. */\n docsBasePath?: string;\n /** Optional suffix appended to the window origin when building default playground base URLs. */\n baseUrlSuffix?: string;\n /** Preset collections rendered into the docs UI. */\n presets?: SerializablePreset[];\n /** Optional seed history entries to pre-populate the UI (useful in dev). */\n historySeeds?: SerializableHistoryEntry[];\n /** Optional seed log entries to pre-populate the logs UI. */\n logSeeds?: LogFeedEntry[];\n /** Paths for webhook-backed history/log feeds. */\n webhooks?: WebhookPaths;\n}\n\nconst DEFAULT_ASSET_BASE = '/__rrroutes/docs/assets';\n\nfunction normalizeBase(base: string) {\n if (!base) return DEFAULT_ASSET_BASE;\n return base.endsWith('/') ? base.slice(0, -1) : base;\n}\n\nfunction normalizeDocsBase(base: string | undefined) {\n if (!base) return '';\n if (base === '/') return '/';\n return base.endsWith('/') && base.length > 1 ? base.slice(0, -1) : base;\n}\n\nfunction normalizeBaseUrlSuffix(suffix: string | undefined) {\n if (!suffix) return '';\n const trimmed = suffix.endsWith('/') && suffix.length > 1 ? suffix.slice(0, -1) : suffix;\n return trimmed.startsWith('/') ? trimmed : `/${trimmed}`;\n}\n\ntype DocsDocumentProps = {\n leavesJson: string;\n presetsJson: string;\n assetBase: string;\n docsBase: string;\n historyJson: string;\n logsJson: string;\n baseUrlSuffix?: string;\n webhooks?: WebhookPaths;\n cspNonce?: string;\n};\n\nexport const DocsDocument = ({\n leavesJson,\n presetsJson,\n assetBase,\n docsBase,\n historyJson,\n logsJson,\n baseUrlSuffix,\n webhooks,\n cspNonce,\n}: DocsDocumentProps) => {\n const cssHref = `${assetBase}/docs.css`;\n const jsSrc = `${assetBase}/docs.js`;\n const configJson = serializeConfig({ docsBasePath: docsBase, baseUrlSuffix, webhooks });\n\n return (\n <html lang=\"en\">\n <head>\n <meta charSet=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>API Reference</title>\n <link rel=\"stylesheet\" href={cssHref} />\n </head>\n <body>\n <div id=\"docs-root\"></div>\n <script\n id=\"leaf-data\"\n type=\"application/json\"\n nonce={cspNonce}\n dangerouslySetInnerHTML={{ __html: leavesJson }}\n />\n <script\n id=\"preset-data\"\n type=\"application/json\"\n nonce={cspNonce}\n dangerouslySetInnerHTML={{ __html: presetsJson }}\n />\n <script\n id=\"history-data\"\n type=\"application/json\"\n nonce={cspNonce}\n dangerouslySetInnerHTML={{ __html: historyJson }}\n />\n <script\n id=\"logs-data\"\n type=\"application/json\"\n nonce={cspNonce}\n dangerouslySetInnerHTML={{ __html: logsJson }}\n />\n <script\n id=\"docs-config\"\n type=\"application/json\"\n nonce={cspNonce}\n dangerouslySetInnerHTML={{ __html: configJson }}\n />\n <script type=\"module\" src={jsSrc} nonce={cspNonce} />\n </body>\n </html>\n );\n};\n\nfunction serializeLeaves(leaves: AnyLeaf[]) {\n return JSON.stringify(leaves.map(serializeLeaf)).replace(/<\\//g, '<\\\\/');\n}\n\nfunction serializePresets(presets: SerializablePreset[] | undefined) {\n return JSON.stringify(Array.isArray(presets) ? presets : []).replace(/<\\//g, '<\\\\/');\n}\n\nfunction serializeHistorySeeds(historySeeds: SerializableHistoryEntry[] | undefined) {\n return JSON.stringify(Array.isArray(historySeeds) ? historySeeds : []).replace(/<\\//g, '<\\\\/');\n}\n\nfunction serializeLogSeeds(logSeeds: LogFeedEntry[] | undefined) {\n return JSON.stringify(Array.isArray(logSeeds) ? logSeeds : []).replace(/<\\//g, '<\\\\/');\n}\n\ntype DocsConfig = { docsBasePath: string; baseUrlSuffix?: string; webhooks?: WebhookPaths };\n\nfunction serializeConfig(config: DocsConfig) {\n return JSON.stringify(config).replace(/<\\//g, '<\\\\/');\n}\n\nexport function createLeafDocsDocument(\n leaves: AnyLeaf[],\n options: RenderOptions = {},\n): ReactElement {\n const assetBase = normalizeBase(options.assetBasePath ?? DEFAULT_ASSET_BASE);\n const leavesJson = serializeLeaves(leaves);\n const presetsJson = serializePresets(options.presets);\n const docsBase = normalizeDocsBase(options.docsBasePath);\n const historyJson = serializeHistorySeeds(options.historySeeds);\n const logsJson = serializeLogSeeds(options.logSeeds);\n const baseUrlSuffix = normalizeBaseUrlSuffix(options.baseUrlSuffix);\n const webhooks = options.webhooks;\n\n return (\n <DocsDocument\n leavesJson={leavesJson}\n presetsJson={presetsJson}\n assetBase={assetBase}\n docsBase={docsBase}\n historyJson={historyJson}\n logsJson={logsJson}\n baseUrlSuffix={baseUrlSuffix}\n webhooks={webhooks}\n cspNonce={options.cspNonce}\n />\n );\n}\n\nexport function renderLeafDocsHTML(leaves: AnyLeaf[], options: RenderOptions = {}): string {\n const doc = createLeafDocsDocument(leaves, options);\n const html = renderToStaticMarkup(doc);\n return `<!DOCTYPE html>${html}`;\n}\n\nexport type SerializableHistoryEntry = {\n id?: string;\n timestamp: number;\n method: string;\n path: string;\n fullUrl: string;\n params?: Record<string, string>;\n query?: Record<string, string>;\n body?: string;\n output?: string;\n status?: number;\n durationMs: number;\n error?: string;\n};\n","// schemaIntrospection.ts\nimport * as z from \"zod\";\n\nexport type SerializableSchemaNode = {\n kind: string; // \"object\" | \"string\" | \"number\" | ...\n optional?: boolean;\n nullable?: boolean;\n description?: string;\n\n // object\n properties?: Record<string, SerializableSchemaNode>;\n // array\n element?: SerializableSchemaNode;\n // union\n union?: SerializableSchemaNode[];\n // literal\n literal?: unknown;\n // enum\n enumValues?: string[];\n};\n\ntype ZodAny = z.ZodTypeAny;\n\n/**\n * Zod 3 uses `schema._def`, Zod 4 uses `schema._zod.def`.\n */\nfunction getDef(schema: unknown): any | undefined {\n if (!schema || typeof schema !== \"object\") return undefined;\n const anySchema = schema as any;\n return anySchema._zod?.def ?? anySchema._def;\n}\n\n/**\n * Try to get a human-readable description.\n * Zod 4: use metadata/registry; fallback to internal def.description.\n * Zod 3: only internal def.description exists.\n */\nfunction getDescription(schema: ZodAny): string | undefined {\n const anyZ: any = z as any;\n\n // Zod 4 global registry metadata, if present\n const registry = anyZ.globalRegistry?.get\n ? anyZ.globalRegistry.get(schema)\n : undefined;\n if (registry && typeof registry.description === \"string\") {\n return registry.description;\n }\n\n // Legacy / internal description\n const def = getDef(schema);\n if (def && typeof def.description === \"string\") {\n return def.description;\n }\n\n return undefined;\n}\n\n/**\n * Peel off wrappers (effects, optional, nullable, default) and\n * return the inner schema + flags.\n *\n * Supports:\n * - Zod 3: ZodEffects, ZodOptional, ZodNullable, ZodDefault\n * - Zod 4: ZodOptional, ZodNullable, ZodDefault\n */\nfunction unwrap(schema: ZodAny): {\n base: ZodAny;\n optional: boolean;\n nullable: boolean;\n} {\n let s: ZodAny = schema;\n let optional = false;\n let nullable = false;\n\n // Zod 3 only (undefined in Zod 4)\n const ZodEffectsCtor: any = (z as any).ZodEffects;\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\n // Zod 3: ZodEffects wrapper\n if (ZodEffectsCtor && s instanceof ZodEffectsCtor) {\n const def = getDef(s) || {};\n const sourceType =\n typeof (s as any).sourceType === \"function\"\n ? (s as any).sourceType()\n : def.schema;\n if (!sourceType) break;\n s = sourceType;\n continue;\n }\n\n // Zod 3 + 4: optional/nullable/default wrappers\n if (s instanceof z.ZodOptional) {\n optional = true;\n const def = getDef(s);\n s = (def && def.innerType) || s; // innerType exists in both 3 & 4\n continue;\n }\n\n if (s instanceof z.ZodNullable) {\n nullable = true;\n const def = getDef(s);\n s = (def && def.innerType) || s;\n continue;\n }\n\n if (s instanceof z.ZodDefault) {\n const def = getDef(s);\n s = (def && def.innerType) || s;\n continue;\n }\n\n break;\n }\n\n return { base: s, optional, nullable };\n}\n\nexport function introspectSchema(\n schema: ZodAny | undefined\n): SerializableSchemaNode | undefined {\n if (!schema) return undefined;\n\n const { base, optional, nullable } = unwrap(schema);\n const def = getDef(base);\n\n const node: SerializableSchemaNode = {\n kind: inferKind(base),\n optional: optional || undefined,\n nullable: nullable || undefined,\n description: getDescription(base),\n };\n\n // OBJECT\n if (base instanceof z.ZodObject) {\n // Zod 3: _def.shape() (function)\n // Zod 4: .shape getter returns an object\n const rawShape: any =\n (base as any).shape ?? (def && typeof def.shape === \"function\"\n ? def.shape()\n : def?.shape);\n\n const shape =\n typeof rawShape === \"function\" ? rawShape() : rawShape ?? {};\n\n const props: Record<string, SerializableSchemaNode> = {};\n for (const key of Object.keys(shape)) {\n const child = shape[key] as ZodAny;\n const childNode = introspectSchema(child);\n if (childNode) props[key] = childNode;\n }\n node.properties = props;\n }\n\n // ARRAY\n if (base instanceof z.ZodArray) {\n // Zod 3: def.type is inner schema\n // Zod 4: def.element is inner schema\n const inner =\n (def && (def.element as ZodAny)) ||\n (def && (def.type as ZodAny)) ||\n undefined;\n if (inner) {\n node.element = introspectSchema(inner);\n }\n }\n\n // UNION\n if (base instanceof z.ZodUnion) {\n const options: ZodAny[] = (def && def.options) || [];\n node.union = options\n .map((opt) => introspectSchema(opt))\n .filter(Boolean) as SerializableSchemaNode[];\n }\n\n // LITERAL\n if (base instanceof z.ZodLiteral) {\n if (def) {\n // Zod 4: def.values (multi-literal)\n if (Array.isArray(def.values)) {\n node.literal =\n def.values.length === 1 ? def.values[0] : def.values.slice();\n } else {\n // Zod 3: def.value\n node.literal = def.value;\n }\n }\n }\n\n // ENUM\n if (base instanceof z.ZodEnum) {\n if (def) {\n if (Array.isArray(def.values)) {\n // Zod 3\n node.enumValues = def.values.slice();\n } else if (def.entries && typeof def.entries === \"object\") {\n // Zod 4: entries is a { key: value } map\n node.enumValues = Object.values(def.entries).map((v: unknown) =>\n String(v)\n );\n }\n }\n }\n\n return node;\n}\n\nfunction inferKind(schema: ZodAny): string {\n // This path still uses instanceof; it works with Zod 4 Classic\n // (importing from \"zod\"). Anything unknown falls back to \"unknown\".\n if (schema instanceof z.ZodString) return \"string\";\n if (schema instanceof z.ZodNumber) return \"number\";\n if (schema instanceof z.ZodBoolean) return \"boolean\";\n if (schema instanceof z.ZodBigInt) return \"bigint\";\n if (schema instanceof z.ZodDate) return \"date\";\n if (schema instanceof z.ZodArray) return \"array\";\n if (schema instanceof z.ZodObject) return \"object\";\n if (schema instanceof z.ZodUnion) return \"union\";\n if (schema instanceof z.ZodLiteral) return \"literal\";\n if (schema instanceof z.ZodEnum) return \"enum\";\n if (schema instanceof z.ZodRecord) return \"record\";\n if (schema instanceof z.ZodTuple) return \"tuple\";\n if (schema instanceof z.ZodUnknown) return \"unknown\";\n if (schema instanceof z.ZodAny) return \"any\";\n\n return \"unknown\";\n}\n","// serializer.ts\nimport type { AnyLeaf, MethodCfg } from \"@emeryld/rrroutes-contract\";\nimport { introspectSchema, SerializableSchemaNode } from \"./schemaIntrospection.js\";\n\ntype SerializableMethodCfg = Pick<\n MethodCfg,\n | \"description\"\n | \"summary\"\n | \"docsGroup\"\n | \"tags\"\n | \"deprecated\"\n | \"stability\"\n | \"feed\"\n | \"docsMeta\"\n> & {\n hasBody: boolean;\n hasQuery: boolean;\n hasParams: boolean;\n hasOutput: boolean;\n\n // NEW: full Zod ASTs\n bodySchema?: SerializableSchemaNode;\n querySchema?: SerializableSchemaNode;\n paramsSchema?: SerializableSchemaNode;\n outputSchema?: SerializableSchemaNode;\n};\n\nexport type SerializableLeaf = {\n method: string;\n path: string;\n cfg: SerializableMethodCfg;\n};\n\nexport type { SerializableSchemaNode } from \"./schemaIntrospection.js\";\n\nexport function serializeLeaf(leaf: AnyLeaf): SerializableLeaf {\n const cfg = leaf.cfg;\n\n const tags = Array.isArray(cfg.tags) ? cfg.tags.slice() : [];\n\n return {\n method: leaf.method, // 'get' | 'post' | ...\n path: leaf.path,\n cfg: {\n description: cfg.description,\n summary: cfg.summary,\n docsGroup: cfg.docsGroup,\n tags,\n deprecated: cfg.deprecated,\n stability: cfg.stability,\n feed: !!cfg.feed,\n docsMeta: cfg.docsMeta,\n hasBody: !!cfg.bodySchema || !!cfg.bodyFiles?.length,\n hasQuery: !!cfg.querySchema,\n hasParams: !!cfg.paramsSchema,\n hasOutput: !!cfg.outputSchema,\n\n bodySchema: introspectSchema(cfg.bodySchema),\n querySchema: introspectSchema(cfg.querySchema),\n paramsSchema: introspectSchema(cfg.paramsSchema),\n outputSchema: introspectSchema(cfg.outputSchema),\n },\n };\n}\n","// renderLeafDocsHTML.ts\nimport type { AnyLeaf } from \"@emeryld/rrroutes-contract\";\nimport {\n createLeafDocsDocument,\n renderLeafDocsHTML as LeafDocsPage,\n RenderOptions,\n} from \"./LeafDocsPage.js\";\n\nexport function renderLeafDocsHTML(leaves: AnyLeaf[], options: RenderOptions = {}): string {\n return LeafDocsPage(leaves, options);\n}\n\nexport type { RenderOptions, SerializableHistoryEntry } from \"./LeafDocsPage.js\";\nexport { createLeafDocsDocument } from \"./LeafDocsPage.js\";\nexport type { SerializablePreset, SerializablePresetOperation } from \"./presets.js\";\nexport type { LogFeedEntry } from \"../webhooks.js\";\n","import { z } from 'zod';\n\nexport type WebhookPage<T> = {\n items: T[];\n nextCursor?: string;\n prevCursor?: string;\n total?: number;\n};\n\nexport type WebhookPaths = {\n history: string;\n logs: string;\n};\n\nexport type HistoryFeedEntry = {\n id: string;\n requestId?: string;\n timestamp: number;\n method: string;\n path: string;\n fullUrl?: string;\n params?: Record<string, string>;\n query?: Record<string, string>;\n body?: string;\n output?: string;\n status?: number;\n durationMs: number;\n error?: string;\n};\n\nexport type HistoryFeedQuery = {\n cursor?: string;\n limit?: number;\n methods?: string[];\n path?: string;\n status?: string;\n from?: number;\n to?: number;\n text?: string;\n sortBy?: 'timestamp' | 'path' | 'duration';\n sortDir?: 'asc' | 'desc';\n};\n\nexport type LogType = 'debug' | 'info' | 'warn' | 'error' | 'system';\n\nexport type LogFeedEntry = {\n id: string;\n type: LogType;\n message: string;\n timestamp: number;\n requestId?: string;\n tags?: string[];\n metadata?: string;\n};\n\nexport type LogFeedQuery = {\n cursor?: string;\n limit?: number;\n types?: LogType[];\n tags?: string[];\n requestId?: string;\n text?: string;\n from?: number;\n to?: number;\n sortDir?: 'asc' | 'desc';\n};\n\nexport const logTypeSchema = z.enum(['debug', 'info', 'warn', 'error', 'system']);\n\nexport const historyFeedEntrySchema = z.object({\n id: z.string(),\n requestId: z.string().optional(),\n timestamp: z.number(),\n method: z.string(),\n path: z.string(),\n fullUrl: z.string().optional(),\n params: z.record(z.string(),z.string()).optional(),\n query: z.record(z.string(),z.string()).optional(),\n body: z.string().optional(),\n output: z.string().optional(),\n status: z.number().optional(),\n durationMs: z.number(),\n error: z.string().optional(),\n});\n\nexport const logFeedEntrySchema = z.object({\n id: z.string(),\n type: logTypeSchema,\n message: z.string(),\n timestamp: z.number(),\n requestId: z.string().optional(),\n tags: z.array(z.string()).optional(),\n metadata: z.string().optional(),\n});\n\nexport const historyFeedQuerySchema = z.object({\n cursor: z.string().optional(),\n limit: z.number().int().positive().optional(),\n methods: z.array(z.string()).optional(),\n path: z.string().optional(),\n status: z.string().optional(),\n text: z.string().optional(),\n from: z.number().optional(),\n to: z.number().optional(),\n sortBy: z.enum(['timestamp', 'path', 'duration']).optional(),\n sortDir: z.enum(['asc', 'desc']).optional(),\n});\n\nexport const logFeedQuerySchema = z.object({\n cursor: z.string().optional(),\n limit: z.number().int().positive().optional(),\n types: z.array(logTypeSchema).optional(),\n tags: z.array(z.string()).optional(),\n requestId: z.string().optional(),\n text: z.string().optional(),\n from: z.number().optional(),\n to: z.number().optional(),\n sortDir: z.enum(['asc', 'desc']).optional(),\n});\n\nexport const webhookPageSchema = <T extends z.ZodTypeAny>(itemSchema: T) =>\n z.object({\n items: z.array(itemSchema).default([]),\n nextCursor: z.string().optional(),\n prevCursor: z.string().optional(),\n total: z.number().optional(),\n });\n\nexport const historyWebhookResponseSchema = webhookPageSchema(historyFeedEntrySchema);\nexport const logWebhookResponseSchema = webhookPageSchema(logFeedEntrySchema);\n"],"mappings":"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","names":["renderLeafDocsHTML","z","filtered","renderLeafDocsHTML","path"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/docs/LeafDocsPage.tsx","../src/docs/serializer.ts","../src/docs/schemaIntrospection.ts","../src/docs/docs.ts","../src/web/utils/security.ts","../src/web/utils/types.ts","../src/web/v2/types/types.cacheLog.ts","../src/web/v2/types/types.base.ts","../src/web/v2/types/types.endpoint.ts","../src/web/v2/types/types.requestLog.ts","../src/web/v2/types/types.log.ts","../src/web/v2/types/types.preset.ts"],"sourcesContent":["// index.ts\n\nimport { randomBytes } from 'crypto'\nimport type { RequestHandler, Router } from 'express'\nimport { static as expressStatic } from 'express'\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { renderLeafDocsHTML } from './docs/docs.js'\nimport {\n applyDocsSecurityHeaders,\n createCookieGuard,\n createIpAllowListGuard,\n createMissingPasswordGuard,\n createPasswordGuard,\n} from './web/utils/security.js'\n\nexport type DocsAuthOptions = {\n /** Turn auth on/off. Enabled by default. */\n enabled?: boolean\n /** Password to require for docs access (HTTP Basic). */\n password?: string\n /** Realm used for the HTTP Basic challenge prompt. */\n realm?: string\n /**\n * Allow list of client IPs for docs access.\n * Supports:\n * - exact IPv4 or IPv6 strings (e.g. \"127.0.0.1\", \"::1\")\n * - IPv4 CIDR (e.g. \"10.0.0.0/8\", \"192.168.1.0/24\")\n */\n allowedIps?: string[]\n /**\n * Name of cookie used for cookie-based docs auth.\n * Requires `cookie-parser` or equivalent to populate `req.cookies`.\n */\n cookieName?: string\n /**\n * Optional exact value required for the cookie.\n * If omitted, the cookie only needs to exist (non-empty).\n */\n cookieSecret?: string\n /**\n * Fully custom guard middleware. If provided, it is used\n * instead of password/cookie auth (IP allow list still applies).\n */\n guardMiddleware?: RequestHandler\n /**\n * Whether to emit a CSP header + nonce. Defaults to true.\n */\n csp?: boolean\n}\n\nexport type MountDocsArgs = {\n router: Router\n auth: DocsAuthOptions\n}\n\nfunction resolvePublicDir() {\n const moduleDir =\n typeof __dirname !== 'undefined'\n ? __dirname\n : path.dirname(fileURLToPath(import.meta.url))\n const fromModule = path.resolve(moduleDir, '../public')\n if (fs.existsSync(fromModule)) return fromModule\n\n // When running from source (ts-node), fall back to the built output path.\n const fallback = path.resolve(moduleDir, '../dist/public')\n if (fs.existsSync(fallback)) return fallback\n\n return fromModule // fallback; express static will 404 if missing\n}\n\nexport function mountRRRoutesDocs({\n router,\n auth = {},\n}: MountDocsArgs): string {\n const docsPath = '/__rrroutes/docs'\n\n const publicDir = resolvePublicDir()\n const assetsDir = path.join(publicDir, 'assets')\n\n const cspEnabled = auth.csp !== false\n const authEnabled = auth.enabled !== false\n const docsPassword = auth.password\n const authRealm = auth.realm || 'RRRoutes Docs'\n const allowedIps = auth.allowedIps ?? []\n const cookieName = auth.cookieName\n const cookieSecret = auth?.cookieSecret\n const customGuard = auth?.guardMiddleware\n\n const ipGuard =\n allowedIps.length > 0 ? createIpAllowListGuard(allowedIps) : undefined\n\n const authGuard: RequestHandler = !authEnabled\n ? (_req, _res, next) => next()\n : customGuard\n ? customGuard\n : cookieName\n ? createCookieGuard(cookieName, cookieSecret)\n : docsPassword\n ? createPasswordGuard(docsPassword, authRealm)\n : createMissingPasswordGuard()\n\n // Protect docs HTML, static assets, and webhook feeds with IP guard (if any) + auth guard.\n ;[docsPath, `${docsPath}/assets`, `__rrroutes/`].forEach((p) => {\n if (ipGuard) router.use(p, ipGuard)\n router.use(p, authGuard)\n })\n\n router.use(\n `${docsPath}/assets`,\n expressStatic(assetsDir, { immutable: true, maxAge: '365d' }),\n )\n\n const docsRoutePaths = [docsPath, `${docsPath}/`, `${docsPath}/*id`]\n\n router.get(docsRoutePaths, (_req, res) => {\n const nonce = cspEnabled ? randomBytes(16).toString('base64') : undefined\n\n const html = renderLeafDocsHTML({\n cspNonce: nonce,\n assetBasePath: `${`${docsPath}/assets`}`,\n docsBasePath: `${docsPath}`,\n })\n\n applyDocsSecurityHeaders(res)\n\n if (cspEnabled && nonce) {\n res.setHeader(\n 'Content-Security-Policy',\n [\n \"default-src 'self'\",\n `script-src 'self' 'nonce-${nonce}'`,\n `style-src 'self' 'nonce-${nonce}'`,\n \"img-src 'self' data:\",\n \"connect-src 'self'\",\n \"font-src 'self'\",\n \"frame-ancestors 'self'\",\n \"object-src 'none'\",\n \"base-uri 'self'\",\n ].join('; '),\n )\n }\n\n res.send(html)\n })\n\n return docsPath\n}\n\nexport { renderLeafDocsHTML } from './docs/docs.js'\nexport { introspectSchema } from './docs/schemaIntrospection.js'\nexport { serializeLeaf } from './docs/serializer.js'\nexport type { SerializedLeaf as SerializableLeaf } from './docs/serializer.js'\nexport { leaves as requiredRoutes } from './web/utils/types.js'\n","// LeafDocsPage.tsx\n\nimport type { AnyLeafLowProfile } from '@emeryld/rrroutes-contract'\nimport type { ReactElement } from 'react'\nimport { renderToStaticMarkup } from 'react-dom/server'\nimport { serializeLeaf } from './serializer.js'\n\nexport interface RenderOptions {\n /** CSP nonce applied to data + script tags. */\n cspNonce?: string\n /** Base URL where static assets are served (e.g. `/__rrroutes/docs/assets`). */\n assetBasePath?: string\n /** Root path where the docs are mounted (e.g. `/__rrroutes/docs`). Used for client routing. */\n docsBasePath?: string\n}\n\nconst DEFAULT_ASSET_BASE = '/__rrroutes/docs/assets'\n\nfunction normalizeBase(base: string) {\n if (!base) return DEFAULT_ASSET_BASE\n return base.endsWith('/') ? base.slice(0, -1) : base\n}\n\nfunction normalizeDocsBase(base: string | undefined) {\n if (!base) return ''\n if (base === '/') return '/'\n return base.endsWith('/') && base.length > 1 ? base.slice(0, -1) : base\n}\n\nfunction normalizeBaseUrlSuffix(suffix: string | undefined) {\n if (!suffix) return ''\n const trimmed =\n suffix.endsWith('/') && suffix.length > 1 ? suffix.slice(0, -1) : suffix\n return trimmed.startsWith('/') ? trimmed : `/${trimmed}`\n}\n\ntype DocsDocumentProps = {\n assetBase: string\n docsBase: string\n cspNonce?: string\n}\n\nexport const DocsDocument = ({\n assetBase,\n docsBase,\n cspNonce,\n}: DocsDocumentProps) => {\n const cssHref = `${assetBase}/docs.css`\n const jsSrc = `${assetBase}/docs.js`\n const configJson = serializeConfig({\n docsBasePath: docsBase,\n cspNonce,\n })\n\n return (\n <html lang=\"en\">\n <head>\n <meta charSet=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>API Reference</title>\n <link rel=\"stylesheet\" href={cssHref} />\n </head>\n <body>\n <div id=\"docs-root\"></div>\n <script\n id=\"docs-config\"\n type=\"application/json\"\n nonce={cspNonce}\n dangerouslySetInnerHTML={{ __html: configJson }}\n />\n <script type=\"module\" src={jsSrc} nonce={cspNonce} />\n </body>\n </html>\n )\n}\n\nfunction serializeLeaves(leaves: AnyLeafLowProfile[]) {\n return JSON.stringify(leaves.map(serializeLeaf)).replace(/<\\//g, '<\\\\/')\n}\n\ntype DocsConfig = {\n docsBasePath: string\n baseUrlSuffix?: string\n cspNonce?: string\n}\n\nfunction serializeConfig(config: DocsConfig) {\n return JSON.stringify(config).replace(/<\\//g, '<\\\\/')\n}\n\nexport function createLeafDocsDocument(\n options: RenderOptions = {},\n): ReactElement {\n const assetBase = normalizeBase(options.assetBasePath ?? DEFAULT_ASSET_BASE)\n\n const docsBase = normalizeDocsBase(options.docsBasePath)\n\n return (\n <DocsDocument\n assetBase={assetBase}\n docsBase={docsBase}\n cspNonce={options.cspNonce}\n />\n )\n}\n\nexport function renderLeafDocsHTML(options: RenderOptions = {}): string {\n const doc = createLeafDocsDocument(options)\n const html = renderToStaticMarkup(doc)\n return `<!DOCTYPE html>${html}`\n}\n\nexport type SerializableHistoryEntry = {\n id?: string\n timestamp: number\n method: string\n path: string\n fullUrl: string\n params?: Record<string, string>\n query?: Record<string, string>\n body?: string\n output?: string\n status?: number\n durationMs: number\n error?: string\n}\n","// serializer.ts\nimport {\n MethodCfgLowProfile,\n routeSchemaParse,\n type AnyLeafLowProfile,\n} from '@emeryld/rrroutes-contract'\nimport { MethodType } from '../web/v2/types/types.base.js'\nimport type { Endpoint } from '../web/v2/types/types.endpoint.js'\nimport { introspectSchema } from './schemaIntrospection.js'\n\nexport type SerializedLeaf = Endpoint\n\nexport type { SerializableSchemaNode } from './schemaIntrospection.js'\n\nexport function serializeLeaf(leaf: AnyLeafLowProfile): Endpoint {\n const cfg = leaf.cfg\n\n const tags = Array.isArray(cfg.tags) ? cfg.tags.slice() : []\n const stability = (cfg.stability ?? 'experimental') as Endpoint['stability']\n const now = Date.now()\n\n return {\n id: buildLeafId(leaf),\n name: inferName(cfg, leaf.path),\n description: cfg.description,\n groupId: cfg.docsGroup,\n tags: tags.length > 0 ? tags : undefined,\n createdAt: now,\n updatedAt: now,\n method: leaf.method as MethodType,\n path: leaf.path,\n contract: {\n body: serializeContractSchema(cfg.bodySchema),\n query: serializeContractSchema(cfg.querySchema),\n params: serializeContractSchema(cfg.paramsSchema),\n output: serializeContractSchema(cfg.outputSchema),\n bodyFiles: serializeBodyFiles(cfg),\n },\n feed: cfg.feed ?? undefined,\n summary: cfg.summary,\n stability,\n hidden: cfg.docsHidden,\n meta: serializeMeta(cfg.docsMeta),\n }\n}\n\nfunction serializeContractSchema(schema: MethodCfgLowProfile['bodySchema']) {\n return schema ? introspectSchema(routeSchemaParse(schema)) : undefined\n}\n\nfunction serializeBodyFiles(cfg: MethodCfgLowProfile) {\n if (!Array.isArray(cfg.bodyFiles) || cfg.bodyFiles.length === 0)\n return undefined\n return cfg.bodyFiles.map(({ name, maxCount }) => ({ name, maxCount }))\n}\n\nfunction serializeMeta(meta?: Record<string, unknown>): Record<string, string> {\n if (!meta) return {}\n const entries = Object.entries(meta)\n .filter(([, value]) => value !== undefined && value !== null)\n .map(([key, value]) => [\n key,\n typeof value === 'string' ? value : JSON.stringify(value),\n ])\n return Object.fromEntries(entries)\n}\n\nfunction buildLeafId(leaf: AnyLeafLowProfile) {\n return `${leaf.method.toUpperCase()} ${leaf.path}`\n}\n\nfunction inferName(cfg: MethodCfgLowProfile, path: string) {\n return cfg.summary || cfg.description || path\n}\n","// schemaIntrospection.ts\nimport * as z from 'zod'\nimport type { SerializableSchema } from '../web/v2/types/types.endpoint.js'\n\nexport type SerializableSchemaNode = SerializableSchema\n\ntype ZodAny = z.ZodTypeAny\n\n/**\n * Zod 3 uses `schema._def`, Zod 4 uses `schema._zod.def`.\n */\nfunction getDef(schema: unknown): any | undefined {\n if (!schema || typeof schema !== 'object') return undefined\n const anySchema = schema as any\n return anySchema._zod?.def ?? anySchema._def\n}\n\n/**\n * Try to get a human-readable description.\n * Zod 4: use metadata/registry; fallback to internal def.description.\n * Zod 3: only internal def.description exists.\n */\nfunction getDescription(schema: ZodAny): string | undefined {\n const anyZ: any = z as any\n\n // Zod 4 global registry metadata, if present\n const registry = anyZ.globalRegistry?.get\n ? anyZ.globalRegistry.get(schema)\n : undefined\n if (registry && typeof registry.description === 'string') {\n return registry.description\n }\n\n // Legacy / internal description\n const def = getDef(schema)\n if (def && typeof def.description === 'string') {\n return def.description\n }\n\n return undefined\n}\n\n/**\n * Peel off wrappers (effects, optional, nullable, default) and\n * return the inner schema + flags.\n *\n * Supports:\n * - Zod 3: ZodEffects, ZodOptional, ZodNullable, ZodDefault\n * - Zod 4: ZodOptional, ZodNullable, ZodDefault\n */\nfunction unwrap(schema: ZodAny): {\n base: ZodAny\n optional: boolean\n nullable: boolean\n} {\n let s: ZodAny = schema\n let optional = false\n let nullable = false\n\n // Zod 3 only (undefined in Zod 4)\n const ZodEffectsCtor: any = (z as any).ZodEffects\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\n // Zod 3: ZodEffects wrapper\n if (ZodEffectsCtor && s instanceof ZodEffectsCtor) {\n const def = getDef(s) || {}\n const sourceType =\n typeof (s as any).sourceType === 'function'\n ? (s as any).sourceType()\n : def.schema\n if (!sourceType) break\n s = sourceType\n continue\n }\n\n // Zod 3 + 4: optional/nullable/default wrappers\n if (s instanceof z.ZodOptional) {\n optional = true\n const def = getDef(s)\n s = (def && def.innerType) || s // innerType exists in both 3 & 4\n continue\n }\n\n if (s instanceof z.ZodNullable) {\n nullable = true\n const def = getDef(s)\n s = (def && def.innerType) || s\n continue\n }\n\n if (s instanceof z.ZodDefault) {\n const def = getDef(s)\n s = (def && def.innerType) || s\n continue\n }\n\n break\n }\n\n return { base: s, optional, nullable }\n}\n\nexport function introspectSchema(\n schema: ZodAny | undefined,\n): SerializableSchema | undefined {\n if (!schema) return undefined\n\n const { base, optional, nullable } = unwrap(schema)\n const def = getDef(base)\n\n const node: SerializableSchema = {\n kind: inferKind(base),\n optional: optional || undefined,\n nullable: nullable || undefined,\n description: getDescription(base),\n }\n\n // OBJECT\n if (base instanceof z.ZodObject) {\n // Zod 3: _def.shape() (function)\n // Zod 4: .shape getter returns an object\n const rawShape: any =\n (base as any).shape ??\n (def && typeof def.shape === 'function' ? def.shape() : def?.shape)\n\n const shape = typeof rawShape === 'function' ? rawShape() : (rawShape ?? {})\n\n const props: Record<string, SerializableSchema> = {}\n for (const key of Object.keys(shape)) {\n const child = shape[key] as ZodAny\n const childNode = introspectSchema(child)\n if (childNode) props[key] = childNode\n }\n node.properties = props\n }\n\n // ARRAY\n if (base instanceof z.ZodArray) {\n // Zod 3: def.type is inner schema\n // Zod 4: def.element is inner schema\n const inner =\n (def && (def.element as ZodAny)) ||\n (def && (def.type as ZodAny)) ||\n undefined\n if (inner) {\n node.element = introspectSchema(inner)\n }\n }\n\n // UNION\n if (base instanceof z.ZodUnion) {\n const options: ZodAny[] = (def && def.options) || []\n node.union = options\n .map((opt) => introspectSchema(opt))\n .filter(Boolean) as SerializableSchema[]\n }\n\n // LITERAL\n if (base instanceof z.ZodLiteral) {\n if (def) {\n // Zod 4: def.values (multi-literal)\n if (Array.isArray(def.values)) {\n node.literal =\n def.values.length === 1 ? def.values[0] : def.values.slice()\n } else {\n // Zod 3: def.value\n node.literal = def.value\n }\n }\n }\n\n // ENUM\n if (base instanceof z.ZodEnum) {\n if (def) {\n if (Array.isArray(def.values)) {\n // Zod 3\n node.enumValues = def.values.slice()\n } else if (def.entries && typeof def.entries === 'object') {\n // Zod 4: entries is a { key: value } map\n node.enumValues = Object.values(def.entries).map((v: unknown) =>\n String(v),\n )\n }\n }\n }\n\n return node\n}\n\nfunction inferKind(schema: ZodAny): SerializableSchema['kind'] {\n // This path still uses instanceof; it works with Zod 4 Classic\n // (importing from \"zod\"). Anything unknown falls back to \"unknown\".\n if (schema instanceof z.ZodString) return 'string'\n if (schema instanceof z.ZodNumber) return 'number'\n if (schema instanceof z.ZodBoolean) return 'boolean'\n if (schema instanceof z.ZodBigInt) return 'bigint'\n if (schema instanceof z.ZodDate) return 'date'\n if (schema instanceof z.ZodArray) return 'array'\n if (schema instanceof z.ZodObject) return 'object'\n if (schema instanceof z.ZodUnion) return 'union'\n if (schema instanceof z.ZodLiteral) return 'literal'\n if (schema instanceof z.ZodEnum) return 'enum'\n if (schema instanceof z.ZodRecord) return 'record'\n if (schema instanceof z.ZodTuple) return 'tuple'\n if (schema instanceof z.ZodUnknown) return 'unknown'\n if (schema instanceof z.ZodAny) return 'any'\n\n return 'unknown'\n}\n","// renderLeafDocsHTML.ts\nimport {\n renderLeafDocsHTML as LeafDocsPage,\n RenderOptions,\n} from './LeafDocsPage.js'\n\nexport function renderLeafDocsHTML(options: RenderOptions = {}): string {\n return LeafDocsPage(options)\n}\n\nexport { createLeafDocsDocument } from './LeafDocsPage.js'\nexport type { RenderOptions } from './LeafDocsPage.js'\n","import type { Request, RequestHandler, Response } from 'express'\nimport net from 'node:net'\n\n/**\n * HTTP Basic password guard.\n */\nexport function createPasswordGuard(\n password: string,\n realm: string,\n): RequestHandler {\n const trimmed = password.trim()\n return (req: Request, res: Response, next: () => void) => {\n const provided = extractPassword(req.headers.authorization)\n if (provided && provided === trimmed) {\n return next()\n }\n applyDocsSecurityHeaders(res)\n res.setHeader('WWW-Authenticate', `Basic realm=\"${realm}\"`)\n res\n .status(401)\n .send(\n renderAuthErrorPage(\n 'Docs are password protected. Provide the configured password.',\n ),\n )\n }\n}\n/**\n * Cookie-based guard. Requires `req.cookies` to be populated\n * (e.g. via `cookie-parser`).\n */\nexport function createCookieGuard(\n cookieName: string,\n cookieSecret?: string,\n): RequestHandler {\n return (req: Request, res: Response, next: () => void) => {\n const cookies = (req as any).cookies as Record<string, string> | undefined\n const value = cookies?.[cookieName]\n\n const valid = cookieSecret ? value === cookieSecret : Boolean(value)\n\n if (valid) {\n return next()\n }\n\n applyDocsSecurityHeaders(res)\n res\n .status(401)\n .send(\n renderAuthErrorPage(\n 'Docs are protected. You must be authenticated to access this page.',\n ),\n )\n }\n}\n/**\n * When auth is enabled but no password/cookie/custom guard is provided,\n * fail closed.\n */\nexport function createMissingPasswordGuard(): RequestHandler {\n return (_req: Request, res: Response) => {\n applyDocsSecurityHeaders(res)\n res\n .status(500)\n .send(renderAuthErrorPage('Provide auth configuration to mounted docs'))\n }\n}\n/**\n * Extract password from HTTP Basic Authorization header.\n */\nfunction extractPassword(authHeader: string | string[] | undefined) {\n if (!authHeader) return undefined\n const header = Array.isArray(authHeader) ? authHeader[0] : authHeader\n if (typeof header !== 'string' || !header.startsWith('Basic '))\n return undefined\n const token = header.slice('Basic '.length)\n try {\n const decoded = Buffer.from(token, 'base64').toString('utf8')\n const parts = decoded.split(':')\n parts.shift() // username\n return parts.join(':')\n } catch {\n return undefined\n }\n}\n/**\n * Simple IP allow-list guard. For accurate client IPs behind proxies,\n * configure `app.set('trust proxy', true)` in your Express app.\n */\nexport function createIpAllowListGuard(allowed: string[]): RequestHandler {\n const ranges = allowed\n .map((raw) => raw.trim())\n .filter(Boolean)\n .map(parseIpPattern)\n .filter((r): r is IpRange => r !== null)\n\n return (req: Request, res: Response, next: () => void) => {\n const rawIp =\n req.ip || (req.connection && (req.connection as any).remoteAddress) || ''\n const ip = normalizeIp(rawIp)\n\n if (!ip || !isIpAllowed(ip, ranges)) {\n applyDocsSecurityHeaders(res)\n res\n .status(403)\n .send(\n renderAuthErrorPage(\n 'Access to docs is restricted from this IP address.',\n ),\n )\n return\n }\n\n next()\n }\n}\ntype IpRange =\n | { kind: 'exact'; value: string }\n | { kind: 'cidr'; base: number; mask: number }\n/**\n * Normalize typical Express IP formats, including IPv4-mapped IPv6.\n */\nfunction normalizeIp(ip: string): string {\n if (!ip) return ''\n if (ip.startsWith('::ffff:')) return ip.slice(7)\n if (ip === '::1') return '127.0.0.1'\n return ip\n}\nfunction parseIpPattern(raw: string): IpRange | null {\n if (raw.includes('/')) {\n const cidr = parseCidr(raw)\n if (!cidr) return null\n return { kind: 'cidr', base: cidr.base, mask: cidr.mask }\n }\n\n // Exact string match (IPv4 or IPv6).\n return { kind: 'exact', value: normalizeIp(raw) }\n}\nfunction parseCidr(raw: string): { base: number; mask: number } | null {\n const [baseIp, bitsStr] = raw.split('/')\n const bits = Number(bitsStr)\n if (!Number.isInteger(bits) || bits < 0 || bits > 32) return null\n if (net.isIP(baseIp) !== 4) return null // IPv4 CIDR only for simplicity\n\n const baseLong = ipToLong(baseIp)\n if (baseLong == null) return null\n\n const mask = bits === 0 ? 0 : (~0 << (32 - bits)) >>> 0\n return { base: (baseLong & mask) >>> 0, mask }\n}\nfunction ipToLong(ip: string): number | null {\n const parts = ip.split('.').map((n) => Number(n))\n if (parts.length !== 4) return null\n if (parts.some((n) => !Number.isInteger(n) || n < 0 || n > 255)) return null\n return (\n ((parts[0] << 24) >>> 0) +\n ((parts[1] << 16) >>> 0) +\n ((parts[2] << 8) >>> 0) +\n parts[3]\n )\n}\nfunction isIpAllowed(ip: string, ranges: IpRange[]): boolean {\n const ipv4 = net.isIP(ip) === 4 ? ipToLong(ip) : null\n\n for (const r of ranges) {\n if (r.kind === 'exact') {\n if (ip === r.value) return true\n } else if (r.kind === 'cidr' && ipv4 != null) {\n if ((ipv4 & r.mask) === r.base) return true\n }\n }\n\n return false\n}\nfunction renderAuthErrorPage(message: string) {\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>RRRoutes docs locked</title>\n <style>\n body { margin:0; font-family: system-ui, -apple-system, Segoe UI, sans-serif; background: #0f172a; color: #e2e8f0; display:flex; align-items:center; justify-content:center; min-height:100vh; }\n .card { padding:32px; border:1px solid #1e293b; border-radius:12px; max-width:420px; background: rgba(15,23,42,0.8); box-shadow:0 15px 45px rgba(0,0,0,0.35); }\n h1 { margin:0 0 12px; font-size:22px; }\n p { margin:0; line-height:1.5; color:#cbd5e1; }\n code { background: rgba(226,232,240,0.1); padding: 2px 4px; border-radius: 4px; }\n </style>\n</head>\n<body>\n <div class=\"card\">\n <h1>Docs locked</h1>\n <p>${message}</p>\n </div>\n</body>\n</html>`\n}\nexport function applyDocsSecurityHeaders(res: Response) {\n res.setHeader('X-Content-Type-Options', 'nosniff')\n res.setHeader('Referrer-Policy', 'same-origin')\n res.setHeader('X-Frame-Options', 'SAMEORIGIN')\n res.setHeader('Cache-Control', 'no-store')\n res.setHeader(\n 'Strict-Transport-Security',\n 'max-age=31536000; includeSubDomains',\n )\n}\n","import {\n AnyLeafLowProfile,\n AugmentLeaves,\n finalize,\n FinalizedRegistry,\n resource,\n} from '@emeryld/rrroutes-contract'\nimport { cacheLeaves } from '../v2/types/types.cacheLog'\nimport { endpointLeaves } from '../v2/types/types.endpoint'\nimport { logLeaves } from '../v2/types/types.log'\nimport { presetLeaves } from '../v2/types/types.preset'\nimport { requestLogLeaves } from '../v2/types/types.requestLog'\n\ntype MountedLeaves<Leaves extends readonly AnyLeafLowProfile[]> = AugmentLeaves<\n '/__rrroutes',\n undefined,\n Leaves\n>\ntype AllLeaves = readonly [\n ...MountedLeaves<typeof endpointLeaves>,\n ...MountedLeaves<typeof requestLogLeaves>,\n ...MountedLeaves<typeof logLeaves>,\n ...MountedLeaves<typeof cacheLeaves>,\n ...MountedLeaves<typeof presetLeaves>,\n]\n\nconst allLeaves: AllLeaves = resource()\n .sub(\n resource('/__rrroutes')\n .sub(\n endpointLeaves,\n requestLogLeaves,\n logLeaves,\n cacheLeaves,\n presetLeaves,\n )\n .done(),\n )\n .done()\n\nexport const leaves: FinalizedRegistry<typeof allLeaves> = finalize(allLeaves)\n","import { resource } from '@emeryld/rrroutes-contract'\nimport z from 'zod'\nimport { baseEntitySchema, baseQuerySchema } from './types.base'\n\nconst operationEnum = z.enum(['hit', 'miss', 'set', 'delete'])\nexport const cacheLogSchema = baseEntitySchema.extend({\n operation: operationEnum,\n // on hit, value = value retrieved\n // on miss, value = null\n // on set, value = value set\n // on delete, value = value deleted\n value: z.any().nullable(),\n size: z.number().optional(),\n})\n\nexport const cacheLogQuerySchema = baseQuerySchema.extend({\n operations: operationEnum.array().optional(),\n})\n\nexport const cacheLeaves = resource('cache')\n .get({\n feed: true,\n outputSchema: cacheLogSchema.array(),\n querySchema: cacheLogQuerySchema,\n outputMetaSchema: z.object({\n totalCount: z.number().optional(),\n }),\n })\n .post({\n querySchema: cacheLogQuerySchema,\n })\n .done()\n","import z from 'zod'\n\nexport const METHODS = ['get', 'post', 'put', 'patch', 'delete'] as const\nexport type MethodType = (typeof METHODS)[number]\n\nexport const baseEntitySchema = z.object({\n id: z.string(),\n name: z.string(),\n description: z.string().optional(),\n groupId: z.string().optional(),\n tags: z.string().array().optional(),\n createdAt: z.number(),\n updatedAt: z.number(),\n})\n\nexport const baseQuerySchema = z.object({\n beforeDate: z.string().optional(),\n afterDate: z.string().optional(),\n orderBy: z\n .enum(['timestamp', 'duration', 'level', 'path'])\n .default('timestamp'),\n orderDirection: z.enum(['asc', 'desc']).default('desc'),\n searchQuery: z.string().optional(),\n groups: z.string().array().optional(),\n tags: z.string().array().optional(),\n cursor: z.string().optional(),\n})\n","import { resource } from '@emeryld/rrroutes-contract'\nimport z, { ZodType } from 'zod'\nimport { baseEntitySchema, baseQuerySchema, METHODS } from './types.base'\nimport { requestSchema } from './types.requestLog'\n\nexport const nodeKind = [\n 'object',\n 'string',\n 'number',\n 'boolean',\n 'bigint',\n 'date',\n 'array',\n 'enum',\n 'literal',\n 'union',\n 'record',\n 'tuple',\n 'unknown',\n 'any',\n] as const\n\nexport type SerializableSchema = {\n kind: (typeof nodeKind)[number]\n optional?: boolean\n nullable?: boolean\n description?: string\n\n // object\n properties?: Record<string, SerializableSchema>\n // array\n element?: SerializableSchema\n // union\n union?: SerializableSchema[]\n // literal\n literal?: unknown\n // enum\n enumValues?: string[]\n}\n\n// The Zod schema\nexport const serializableSchemaSchema: ZodType<\n SerializableSchema,\n SerializableSchema\n> = z.lazy(() =>\n z.object({\n kind: z.enum(nodeKind),\n\n optional: z.boolean().optional(),\n nullable: z.boolean().optional(),\n description: z.string().optional(),\n\n // object\n properties: z\n .record(z.string(), serializableSchemaSchema) // Record<string, SerializableSchemaNode>\n .optional(),\n\n // array\n element: serializableSchemaSchema.optional(),\n\n // union\n union: z.array(serializableSchemaSchema).optional(),\n\n // literal\n literal: z.unknown().optional(),\n\n // enum\n enumValues: z.array(z.string()).optional(),\n }),\n)\n\nexport const STABILITIES = [\n 'experimental',\n 'beta',\n 'stable',\n 'deprecated',\n] as const\nconst stabilityEnum = z.enum(STABILITIES)\nexport const endpointSchema = baseEntitySchema.extend({\n method: z.enum(METHODS),\n path: z.string(),\n contract: z.object({\n body: serializableSchemaSchema.optional(),\n query: serializableSchemaSchema.optional(),\n output: serializableSchemaSchema.optional(),\n params: serializableSchemaSchema.optional(),\n bodyFiles: z\n .array(z.object({ name: z.string(), maxCount: z.number() }))\n .optional(),\n }),\n feed: z.boolean().optional(),\n summary: z.string().optional(),\n stability: stabilityEnum,\n hidden: z.boolean().optional(),\n meta: z.record(z.string(), z.string()),\n})\n\nexport type Endpoint = z.output<typeof endpointSchema>\n\nexport const endpointFilterSchema = baseQuerySchema.extend({\n methods: z.enum(METHODS).array().optional(),\n path: z.string().optional(),\n stability: stabilityEnum.array().optional(),\n})\n\nexport const endpointLeaves = resource('endpoints')\n .get({\n feed: true,\n querySchema: endpointFilterSchema,\n outputSchema: endpointSchema.array(),\n outputMetaSchema: z.object({\n totalCount: z.number().optional(),\n }),\n })\n .sub(\n resource(':endpointId', undefined, z.string())\n .get({\n outputSchema: endpointSchema.extend({\n // Related by groupId. Just use the existing feed endpoints with filter: groupId=?\n requests: z.array(requestSchema),\n // Summary stats: return with the feed?\n volumeTS: z.array(\n z.object({\n timestamp: z.string(),\n count: z.number(),\n }),\n ),\n averageDurationMs: z.number(),\n successRate: z.number(),\n // Add id as query param to the existing feed endpoints? This way \"requests\" field can also be only Ids\n latestErrorRequestIds: z.array(z.string()),\n }),\n })\n .done(),\n )\n .done()\n","import { resource } from '@emeryld/rrroutes-contract'\nimport z from 'zod'\nimport { baseEntitySchema, baseQuerySchema, METHODS } from './types.base'\nimport { cacheLogSchema } from './types.cacheLog'\nimport { logSchema } from './types.log'\n\nexport const requestSchema = baseEntitySchema.extend({\n status: z.number(),\n body: z.any().optional(),\n fullUrl: z.string(),\n path: z.string(),\n method: z.enum(METHODS),\n query: z.record(z.string(), z.any()).optional(),\n params: z.record(z.string(), z.any()).optional(),\n output: z.any().optional(),\n headers: z.record(z.string(), z.any()).optional(),\n error: z.string().optional(),\n durationMs: z.number(),\n})\n\nexport type RequestLogType = z.infer<typeof requestSchema>\n\nexport const requestQuerySchema = baseQuerySchema.extend({\n methods: z.enum(METHODS).array().default([]),\n statuses: z.number().array().default([]),\n path: z.string().optional(),\n})\n\nexport const requestLogLeaves = resource('requests')\n .get({\n feed: true,\n outputSchema: requestSchema.array(),\n querySchema: requestQuerySchema,\n outputMetaSchema: z.object({\n totalCount: z.number().optional(),\n }),\n })\n .sub(\n resource(':requestId', undefined, z.string())\n .get({\n outputSchema: requestSchema.extend({\n // Related by groupId\n // Do I just use the existing feed endpoints with filter: groupId=?\n logs: z.array(logSchema),\n caches: z.array(cacheLogSchema),\n }),\n })\n .done(),\n )\n .done()\n","import { resource } from '@emeryld/rrroutes-contract'\nimport z from 'zod'\nimport { baseEntitySchema, baseQuerySchema } from './types.base'\n\nconst levelSchema = z.enum(['info', 'warning', 'error', 'debug', 'trace'])\nexport const logSchema = baseEntitySchema.extend({\n level: levelSchema,\n meta: z.json(),\n})\n\nexport const logQuerySchema = baseQuerySchema.extend({\n level: levelSchema.array().optional(),\n})\n\nexport const logLeaves = resource('logs')\n .get({\n feed: true,\n outputSchema: logSchema.array(),\n querySchema: logQuerySchema,\n outputMetaSchema: z.object({\n totalCount: z.number().optional(),\n }),\n })\n .done()\n","import { resource } from '@emeryld/rrroutes-contract'\nimport z from 'zod'\nimport { baseEntitySchema, baseQuerySchema, METHODS } from './types.base'\n\nconst presetSchema = baseEntitySchema.extend({\n operations: z.array(\n z.object({\n endpointId: z.string().optional(),\n method: z.enum(METHODS),\n path: z.string(),\n body: z.json().optional(),\n extraHeaders: z.record(z.string(), z.any()).optional(),\n query: z.record(z.string(), z.any()).optional(),\n }),\n ),\n})\n\nconst presetQuerySchema = baseQuerySchema.extend({\n name: z.string().optional(),\n tags: z.string().array().optional(),\n group: z.string().optional(),\n})\n\nexport const presetLeaves = resource('presets')\n .get({\n feed: true,\n querySchema: presetQuerySchema.array(),\n outputMetaSchema: z.object({\n totalCount: z.number().optional(),\n }),\n outputSchema: presetSchema,\n })\n .post({\n bodySchema: presetSchema,\n outputSchema: presetSchema,\n })\n .put({\n bodySchema: presetSchema,\n outputSchema: presetSchema,\n })\n .done()\n"],"mappings":"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","names":["path","renderLeafDocsHTML","resource","z","z","z","resource","z","resource","z","resource","z","z","resource","z","resource","z","resource","resource","z","z","resource","resource","renderLeafDocsHTML"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
:root{--bg-root: #020617;--bg-card: rgba(15, 23, 42, .6);--bg-card-hover: rgba(30, 41, 59, .7);--bg-glass: rgba(15, 23, 42, .9);--bg-panel: #0f172a;--border-subtle: rgba(148, 163, 184, .2);--text-main: #f8fafc;--text-muted: #94a3b8;--text-accent: #c4b5fd;--accent-primary: #a855f7;--accent-glow: rgba(168, 85, 247, .25);--accent-success: #4ade80;--accent-error: #f87171;--method-get: #4ade80;--method-get-bg: rgba(34, 197, 94, .15);--method-post: #60a5fa;--method-post-bg: rgba(59, 130, 246, .15);--method-put: #facc15;--method-put-bg: rgba(234, 179, 8, .15);--method-patch: #2dd4bf;--method-patch-bg: rgba(45, 212, 191, .15);--method-delete: #f87171;--method-delete-bg: rgba(248, 113, 113, .15);--radius-card: 12px;--shadow-card: 0 4px 20px rgba(0, 0, 0, .4);--shadow-panel: -5px 0 30px rgba(0,0,0,.5);--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;--tag-0-bg: rgba(254, 202, 202, .2);--tag-0-fg: #fca5a5;--tag-1-bg: rgba(253, 230, 138, .2);--tag-1-fg: #fcd34d;--tag-2-bg: rgba(187, 247, 208, .2);--tag-2-fg: #86efac;--tag-3-bg: rgba(165, 243, 252, .2);--tag-3-fg: #67e8f9;--tag-4-bg: rgba(191, 219, 254, .2);--tag-4-fg: #93c5fd;--tag-5-bg: rgba(233, 213, 255, .2);--tag-5-fg: #d8b4fe;--tag-6-bg: rgba(251, 207, 232, .2);--tag-6-fg: #f9a8d4}*{box-sizing:border-box}html,body{height:100%;margin:0;padding:0;background-color:var(--bg-root);color:var(--text-main);font-family:system-ui,-apple-system,sans-serif}body{background-image:radial-gradient(circle at 15% 10%,rgba(88,28,135,.15),transparent 40%),radial-gradient(circle at 85% 80%,rgba(15,23,42,1),transparent 40%);background-attachment:fixed}.page{min-height:100vh;padding:20px 40px 60px;max-width:1600px;margin:0 auto;display:flex;flex-direction:column;gap:24px}.header{display:flex;justify-content:space-between;padding-bottom:10px;border-bottom:1px solid var(--border-subtle)}.header-title h1{font-size:28px;margin:0;font-weight:700;letter-spacing:-.02em;background:linear-gradient(to right,#e2e8f0,#a855f7);-webkit-background-clip:text;-webkit-text-fill-color:transparent}.header-actions{display:flex;align-items:center;gap:8px}.preset-nav-btn{background:#a855f71f;border:1px solid rgba(168,85,247,.5);color:var(--text-accent);padding:6px 12px;border-radius:6px;font-weight:700;cursor:pointer;font-size:12px;transition:all .2s ease}.preset-nav-btn:hover{box-shadow:0 0 0 1px var(--accent-glow);color:#fff}.preset-nav-btn:disabled{opacity:.4;cursor:not-allowed}.preset-nav-btn.ghost-btn{background:transparent;border-color:var(--border-subtle);color:var(--text-muted)}.preset-nav-btn.nav-pill{background:#ffffff0a;border-color:var(--border-subtle);color:var(--text-main)}.preset-nav-btn.nav-pill[data-active=true]{background:var(--accent-primary);color:#fff;border-color:var(--accent-primary);box-shadow:0 0 0 1px var(--accent-glow)}.link-button{background:none;border:none;color:var(--text-accent);cursor:pointer;padding:0;font-weight:700}.link-button:hover{color:#fff}.breadcrumb-sep{color:var(--text-muted)}.controls-container{background:var(--bg-glass);-webkit-backdrop-filter:blur(16px);backdrop-filter:blur(16px);border:1px solid var(--border-subtle);border-radius:var(--radius-card);padding:12px 16px;display:flex;flex-direction:column;gap:12px;box-shadow:0 10px 30px -10px #00000080}.filters-row{display:flex;align-items:flex-start;gap:16px;width:100%}.left-column{display:flex;flex-direction:column;gap:16px;flex-basis:300px;min-width:250px}.search-box{width:100%;position:relative}.search-input{width:100%;background:#02061799;border:1px solid var(--border-subtle);color:var(--text-main);padding:8px 12px 8px 32px;border-radius:6px;font-size:13px}.search-input:focus{outline:none;border-color:var(--accent-primary)}.search-icon{position:absolute;left:10px;top:50%;transform:translateY(-50%);color:var(--text-muted);font-size:12px}.filter-group{display:flex;flex-direction:column;gap:6px}.filter-label{font-size:10px;text-transform:uppercase;color:var(--text-muted);font-weight:700}.checkbox-group{display:flex;flex-wrap:wrap;gap:6px}.filters-shell{border:1px solid var(--border-subtle);border-radius:var(--radius-card);background:#ffffff1a;padding:14px;box-shadow:var(--shadow-card);display:flex;flex-direction:column;gap:12px;transition:background .15s ease,box-shadow .15s ease,border-color .15s ease;-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px)}.filters-shell:hover:not(:has(.filters-actions:hover,.filters-raw:hover,.filters-grid:hover)){cursor:pointer;background-color:#ffffff0d}.sticky-panel{position:sticky;top:12px;z-index:45;margin-top:4px;background:#060914b3}.sticky-panel[data-scrolled=true]{background:#060914e6;box-shadow:0 15px 30px -12px #0009;border-color:#ffffff14}.filters-header{display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap}.filters-heading{display:flex;flex-direction:column;gap:2px}.filters-title{font-size:16px;font-weight:800;color:var(--text-main)}.filters-subtitle{color:var(--text-muted);font-size:12px}.filters-actions{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.filters-collapse-btn{border:1px solid var(--border-subtle);background:#ffffff14;color:var(--text-muted);border-radius:6px;padding:4px 8px;cursor:pointer}.filters-collapse-btn:hover{border-color:var(--accent-primary);color:#fff}.filters-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px;margin:-15px;padding:15px}.filters-raw{display:flex;flex-direction:column;gap:12px;margin:-15px;padding:15px}.filter-block{border:1px solid var(--border-subtle);border-radius:10px;background:#00000040;padding:10px 12px;display:flex;flex-direction:column;gap:8px}.filter-block-header{display:flex;align-items:center;justify-content:space-between;gap:8px}.filter-hint{color:var(--text-muted);font-size:11px}.filter-block-body{display:flex;flex-direction:column;gap:8px}.filter-duo{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:8px}.text-muted{color:var(--text-muted)}.text-accent{color:var(--text-accent)}.helper-enum-input{display:flex;flex-direction:column;gap:8px}.helper-input-shell{position:relative}.helper-suggestions{position:absolute;top:calc(100% + 4px);left:0;right:0;z-index:12;display:flex;flex-wrap:wrap;gap:6px;padding:8px;border-radius:10px;border:1px solid var(--border-subtle);background:#0f172af2;box-shadow:0 10px 30px #00000080;max-height:240px;overflow-y:auto}.helper-suggestion{border:1px solid var(--border-subtle);background:#ffffff0a;color:var(--text-main);border-radius:999px;padding:4px 10px;font-size:12px;cursor:pointer}.helper-suggestion:hover{border-color:var(--accent-primary);color:#fff}.helper-tags{display:flex;flex-wrap:wrap;gap:6px}.helper-tag{display:inline-flex;align-items:center;gap:6px;padding:4px 10px;border-radius:999px;border:1px solid var(--border-subtle);background:#ffffff0f;color:var(--text-main);cursor:pointer;font-size:12px}.helper-tag:hover{border-color:var(--accent-primary);color:#fff}.helper-tag-close{color:var(--text-muted);font-weight:800}.pill-checkbox input{display:none}.pill-checkbox span{display:inline-block;padding:3px 8px;border-radius:4px;font-size:11px;font-weight:600;background:#1e293b80;color:var(--text-muted);border:1px solid transparent;cursor:pointer}.pill-checkbox input:checked+span{background:#a855f726;color:var(--accent-primary);border-color:var(--accent-primary)}.pill-checkbox.colored-tag input:checked+.tag-filter-pill{border-color:var(--accent-primary);box-shadow:0 0 0 1px var(--accent-glow)}.overview-row{display:flex;flex-wrap:wrap;gap:8px;padding-top:8px;border-top:1px solid var(--border-subtle);align-items:center}.overview-label{font-size:10px;text-transform:uppercase;color:var(--text-muted);font-weight:700}.group-chip{text-decoration:none}.preset-menu{display:flex;flex-direction:column;gap:16px}.preset-menu-header{display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap}.preset-menu-title{margin:0}.preset-menu-subtitle{margin:4px 0 0;color:var(--text-muted)}.preset-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:12px}.preset-card{background:var(--bg-card);border:1px solid var(--border-subtle);border-radius:var(--radius-card);padding:14px;display:flex;flex-direction:column;gap:8px;cursor:pointer;transition:border-color .2s ease,transform .2s ease}.preset-card:hover{border-color:#94a3b866;box-shadow:var(--shadow-card);transform:translateY(-2px)}.preset-card-title{font-weight:700;font-size:15px}.preset-card-desc{margin:0;color:var(--text-muted);line-height:1.4}.preset-card-meta{display:flex;gap:8px;align-items:center;font-size:11px;color:var(--text-muted)}.preset-tag-row{display:flex;gap:6px;flex-wrap:wrap}.preset-tag{background:#ffffff0f;border:1px solid var(--border-subtle);color:var(--text-muted);padding:3px 8px;border-radius:999px;font-size:11px}.preset-empty{padding:20px;border:1px dashed var(--border-subtle);border-radius:var(--radius-card);color:var(--text-muted);display:flex;gap:12px;align-items:center}.api-group{margin-bottom:40px;scroll-margin-top:180px}.group-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px;border-bottom:1px solid var(--border-subtle)}.group-title{font-size:20px;font-weight:600;margin:0;padding-bottom:8px}.group-actions button{background:transparent;border:1px solid var(--border-subtle);color:var(--text-muted);font-size:11px;padding:4px 10px;border-radius:4px;cursor:pointer;margin-left:8px}.endpoint-card{background:var(--bg-card);border:1px solid var(--border-subtle);border-radius:var(--radius-card);overflow:hidden;transition:all .2s ease;margin-bottom:12px}.endpoint-card:hover{border-color:#94a3b866;box-shadow:var(--shadow-card);transform:translateY(-2px)}.card-header{padding:12px 16px;display:flex;align-items:center;gap:12px;flex-wrap:wrap;cursor:pointer}.history-link-btn{background:transparent;border:1px solid var(--border-subtle);color:var(--text-muted);padding:4px 8px;border-radius:6px;cursor:pointer;font-size:11px}.history-link-btn:hover{color:#fff;border-color:var(--accent-primary)}.header-spacer{flex:1}.card-body{display:none;padding:0 16px 16px;border-top:1px solid var(--border-subtle);margin-top:4px}.endpoint-card[data-expanded=true] .card-body{display:block;animation:slideDown .2s ease-out}.endpoint-card[data-expanded=true] .expand-icon{transform:rotate(180deg);color:var(--text-main)}@keyframes slideDown{0%{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:translateY(0)}}.method-badge{font-size:11px;font-weight:800;text-transform:uppercase;padding:4px 8px;border-radius:4px;min-width:55px;text-align:center;transition:all .3s ease}.m-GET{background:var(--method-get-bg);color:var(--method-get);border:1px solid rgba(74,222,128,.3)}.m-GET:hover{background:var(--method-get-hover-bg);color:var(--method-get-hover);border:1px solid rgba(74,222,128,.5)}.m-GET:active{background:var(--method-get-click-bg);color:var(--method-get-click);border:1px solid rgba(74,222,128,.7)}.m-POST{background:var(--method-post-bg);color:var(--method-post);border:1px solid rgba(96,165,250,.3)}.m-POST:hover{background:var(--method-post-hover-bg);color:var(--method-post-hover);border:1px solid rgba(96,165,250,.5)}.m-POST:active{background:var(--method-post-click-bg);color:var(--method-post-click);border:1px solid rgba(96,165,250,.7)}.m-PUT{background:var(--method-put-bg);color:var(--method-put);border:1px solid rgba(250,204,21,.3)}.m-PUT:hover{background:var(--method-put-hover-bg);color:var(--method-put-hover);border:1px solid rgba(250,204,21,.5)}.m-PUT:active{background:var(--method-put-click-bg);color:var(--method-put-click);border:1px solid rgba(250,204,21,.7)}.m-PATCH{background:var(--method-patch-bg);color:var(--method-patch);border:1px solid rgba(45,212,191,.3)}.m-PATCH:hover{background:var(--method-patch-hover-bg);color:var(--method-patch-hover);border:1px solid rgba(45,212,191,.5)}.m-PATCH:active{background:var(--method-patch-click-bg);color:var(--method-patch-click);border:1px solid rgba(45,212,191,.7)}.m-DELETE{background:var(--method-delete-bg);color:var(--method-delete);border:1px solid rgba(248,113,113,.3)}.m-DELETE:hover{background:var(--method-delete-hover-bg);color:var(--method-delete-hover);border:1px solid rgba(248,113,113,.5)}.m-DELETE:active{background:var(--method-delete-click-bg);color:var(--method-delete-click);border:1px solid rgba(248,113,113,.7)}.path-container{font-family:var(--font-mono);font-size:13px;display:inline-flex;align-items:center;gap:8px;padding:2px 6px;border-radius:4px}.path-container:hover{background:#ffffff0d}.copy-icon{opacity:0;font-size:10px}.path-container:hover .copy-icon{opacity:1}.tags-container{display:flex;gap:6px}.status-badge{font-size:9px;text-transform:uppercase;padding:2px 6px;border-radius:3px;font-weight:600}.tag-0{background:var(--tag-0-bg);color:var(--tag-0-fg);border-color:var(--tag-0-fg)}.tag-1{background:var(--tag-1-bg);color:var(--tag-1-fg);border-color:var(--tag-1-fg)}.tag-2{background:var(--tag-2-bg);color:var(--tag-2-fg);border-color:var(--tag-2-fg)}.tag-3{background:var(--tag-3-bg);color:var(--tag-3-fg);border-color:var(--tag-3-fg)}.tag-4{background:var(--tag-4-bg);color:var(--tag-4-fg);border-color:var(--tag-4-fg)}.tag-5{background:var(--tag-5-bg);color:var(--tag-5-fg);border-color:var(--tag-5-fg)}.tag-6{background:var(--tag-6-bg);color:var(--tag-6-fg);border-color:var(--tag-6-fg)}.not-implemented{border-color:var(--method-delete);color:var(--method-delete);background:var(--method-delete-bg)}.btn-try-it{background:#a855f71a;border:1px solid rgba(168,85,247,.4);color:var(--text-accent);font-size:11px;font-weight:600;padding:4px 12px;border-radius:12px;cursor:pointer;transition:all .2s;margin-right:12px;display:flex;align-items:center;gap:6px}.btn-try-it:hover{background:#a855f740;color:#fff;box-shadow:0 0 10px var(--accent-glow)}.btn-try-it .play-icon{font-size:10px}.section-block{margin-top:18px}.section-title{font-size:11px;text-transform:uppercase;letter-spacing:.1em;color:var(--text-muted);margin-bottom:8px;border-bottom:1px solid var(--border-subtle);padding-bottom:4px}.schema-table{width:100%;border-collapse:collapse;font-size:12px}.schema-table th{text-align:left;color:var(--text-muted);font-weight:600;padding:6px 8px;border-bottom:1px solid var(--border-subtle);background:#0003}.schema-table td{padding:6px 8px;border-bottom:1px solid var(--border-subtle);vertical-align:top;color:var(--text-muted)}.col-name{font-family:var(--font-mono);color:var(--text-accent)!important;width:25%}.col-type{font-family:var(--font-mono);color:#93c5fd!important;width:15%}.req-badge{font-size:9px;text-transform:uppercase;padding:2px 4px;border-radius:2px}.req-true{color:#4ade80;background:#4ade801a}.req-false{color:#94a3b8;background:#94a3b81a}.schema-toggle{background:none;border:none;color:var(--text-muted);cursor:pointer;font-size:10px;padding:0 4px;margin-right:4px;width:16px;text-align:center}.schema-toggle:hover{color:var(--text-main)}tr[data-hidden=true]{display:none}.schema-name-cell{display:flex;align-items:center}.schema-name-text{opacity:.8}.schema-toggle-placeholder{width:20px;display:inline-block}.schema-depth-0{padding-left:0}.schema-depth-1{padding-left:16px}.schema-depth-2{padding-left:32px}.schema-depth-3{padding-left:48px}.schema-depth-4{padding-left:64px}.schema-depth-5{padding-left:80px}.schema-depth-6{padding-left:96px}.schema-depth-7{padding-left:112px}.schema-depth-8{padding-left:128px}.playground-overlay{position:fixed;top:0;right:0;bottom:0;width:740px;max-width:90vw;min-width:560px;background:var(--bg-panel);border-left:1px solid var(--border-subtle);box-shadow:var(--shadow-panel);z-index:100;transform:translate(100%);transition:transform .3s cubic-bezier(.16,1,.3,1);display:flex;flex-direction:column;overflow:hidden}.playground-overlay.open{transform:translate(0)}.pg-shell{display:grid;grid-template-columns:minmax(220px,1fr) minmax(440px,2.5fr);height:100%;min-height:0}.pg-sidebar{display:flex;flex-direction:column;gap:12px;padding:14px;background:#ffffff08;border-right:1px solid var(--border-subtle);min-width:0;min-height:0}.pg-main{min-width:0;height:100%;display:flex;min-height:0;overflow:hidden}.pg-main-pane{display:flex;flex-direction:column;width:100%;height:100%;background:var(--bg-panel);min-height:0;overflow:hidden}.pg-resize-handle{position:absolute;left:0;top:0;bottom:0;width:18px;cursor:ew-resize;z-index:5}.pg-resize-handle:hover{background:linear-gradient(90deg,transparent 0%,rgba(255,255,255,.08) 70%)}.pg-search .helper-enum-input{width:100%}.pg-tab-list{display:flex;flex-direction:column;gap:8px;overflow-y:auto;padding-right:4px;flex:1;min-height:0}.pg-tab{border:1px solid var(--border-subtle);background:#ffffff05;color:var(--text-main);border-radius:8px;padding:10px;text-align:left;display:flex;align-items:center;justify-content:space-between;gap:10px;cursor:pointer;min-height:52px}.pg-tab:hover{border-color:var(--accent-primary);background:#ffffff0d}.pg-tab[data-active=true]{border-color:var(--accent-primary);background:#3a81f61f;box-shadow:0 10px 30px #00000029}.pg-tab-text{flex:1;min-width:0}.pg-tab-label{display:block;font-weight:500;font-size:small;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pg-tab-sub{display:block;color:var(--text-muted);font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pg-tab-actions{display:flex;gap:6px}.pg-tab-btn{background:#ffffff0f;border:1px solid var(--border-subtle);color:var(--text-muted);border-radius:6px;width:28px;height:28px;cursor:pointer}.pg-tab-btn:hover{color:var(--text-main);border-color:var(--accent-primary)}.playground-inline{background:var(--bg-card);border:1px solid var(--border-subtle);border-radius:var(--radius-card);overflow:hidden;margin-top:8px}.playground-inline .pg-content{padding:16px}.playground-inline .pg-footer{padding:12px 16px}.pg-note{margin-left:8px;color:var(--text-muted);font-size:11px}.loading-placeholder{text-align:center;padding:40px;color:#64748b}.no-results{text-align:center;padding:40px;color:var(--text-muted)}.preset-detail{display:flex;flex-direction:column;gap:16px}.preset-detail-header{display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap;border-bottom:1px solid var(--border-subtle);padding-bottom:8px}.preset-breadcrumb{margin:0 0 4px;color:var(--text-muted);display:flex;align-items:center;gap:6px;font-size:12px}.preset-detail-title{margin:0}.preset-detail-desc{margin:4px 0 0;color:var(--text-muted)}.preset-detail-actions{display:flex;gap:8px;align-items:center}.preset-meta-row{display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap}.preset-tags{display:flex;gap:8px;flex-wrap:wrap}.preset-tag.ghost-tag{border-style:dashed}.preset-meta-count{color:var(--text-muted);font-size:12px}.preset-ops-list{display:flex;flex-direction:column;gap:14px}.preset-op-card{border:1px solid var(--border-subtle);border-radius:var(--radius-card);background:var(--bg-card);padding:12px;box-shadow:0 6px 20px #0000001f}.preset-op-card.preset-op-missing{border-style:dashed;opacity:.85}.preset-op-header{display:flex;justify-content:space-between;align-items:flex-start;gap:12px;margin-bottom:8px}.preset-op-label{font-size:11px;color:var(--text-muted);letter-spacing:.08em;text-transform:uppercase}.preset-op-title{display:flex;align-items:center;gap:8px;font-weight:700}.preset-op-path{font-family:var(--font-mono);color:var(--text-main)}.preset-op-summary{margin-top:4px;font-weight:600}.preset-op-desc{margin:4px 0 0;color:var(--text-muted)}.preset-run-all{display:flex;justify-content:flex-end;align-items:center;gap:10px}.preset-run-status{color:var(--text-muted);font-size:12px}.section-header-row{display:flex;justify-content:space-between;align-items:flex-end;border-bottom:1px solid var(--border-subtle);margin-bottom:8px}.section-title-no-border{border:none;margin:0}.schema-actions-inline{margin-bottom:4px;justify-content:flex-end;display:flex}.schema-actions-inline button.expand-all{background:none;border:none;color:var(--text-accent);cursor:pointer;font-size:10px}.schema-actions-inline button.collapse-all{background:none;border:none;color:var(--text-muted);cursor:pointer;font-size:10px}.endpoint-history-stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:8px}.endpoint-history-stat{border:1px solid var(--border-subtle);border-radius:8px;padding:8px 10px;background:#ffffff0a}.endpoint-history-label{font-size:10px;text-transform:uppercase;letter-spacing:.08em;color:var(--text-muted)}.endpoint-history-value{font-size:16px;font-weight:700;color:var(--text-main)}.history-mini-empty{color:var(--text-muted);font-size:12px}.pg-header{padding:16px;border-bottom:1px solid var(--border-subtle);display:flex;justify-content:space-between;align-items:center;background:var(--bg-glass)}.pg-title{font-size:16px;font-weight:700;color:var(--text-main)}.pg-close{background:transparent;border:none;color:var(--text-muted);font-size:20px;cursor:pointer}.pg-close:hover{color:var(--text-main)}.pg-content{flex:1;overflow-y:auto;padding:20px;display:flex;flex-direction:column;gap:24px}.pg-section{display:flex;flex-direction:column;gap:8px}.pg-label{font-size:11px;text-transform:uppercase;color:var(--text-muted);font-weight:700;letter-spacing:.05em}.pg-input,.pg-textarea{background:#02061766;border:1px solid var(--border-subtle);color:var(--text-main);padding:8px;border-radius:6px;font-family:var(--font-mono);font-size:12px}.pg-input:focus,.pg-textarea:focus{outline:none;border-color:var(--accent-primary)}.pg-textarea{min-height:150px;resize:vertical}.json-input{display:flex;flex-direction:column;gap:6px}.json-input-toolbar{display:flex;justify-content:space-between;align-items:center;gap:8px;flex-wrap:wrap}.json-input-status{font-size:11px;color:var(--text-muted)}.json-input-status.ok{color:var(--accent-success)}.json-input-status.error{color:var(--accent-error)}.json-input-actions{display:flex;gap:6px;flex-wrap:wrap;justify-content:flex-end}.json-input-shell{display:flex;border:1px solid var(--border-subtle);border-radius:8px;overflow:hidden;background:#02061766}.json-line-numbers{background:#ffffff0a;color:var(--text-muted);padding:8px;font-family:var(--font-mono);font-size:11px;min-width:36px;display:flex;flex-direction:column;align-items:flex-end;gap:2px;max-height:320px;overflow:hidden}.json-input-area{border:none;border-left:1px solid var(--border-subtle);margin:0;min-height:200px;flex:1}.json-input-area:focus{outline:none}.pg-input-disabled-label{opacity:.7}.param-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px}.param-row{display:contents}.param-grid-queries{grid-template-columns:1fr 1fr 40px;align-items:center}.param-grid-headers{grid-template-columns:28px 1fr 1fr 40px;align-items:center}.header-toggle{display:flex;align-items:center;justify-content:center}.header-toggle input[type=checkbox]{width:16px;height:16px;accent-color:var(--accent-primary);cursor:pointer}.btn-remove-param{background:transparent;border:1px solid var(--border-subtle);color:var(--text-muted);border-radius:6px;width:36px;height:36px;cursor:pointer}.btn-remove-param:hover{color:var(--accent-error);border-color:var(--accent-error)}.btn-remove-param:disabled{opacity:.5;cursor:not-allowed}.btn-add-query{font-size:11px;background:none;border:1px dashed var(--border-subtle);color:var(--text-muted);padding:4px;cursor:pointer}.pg-footer{padding:16px;border-top:1px solid var(--border-subtle);background:var(--bg-glass);display:flex;justify-content:flex-end;gap:12px}.btn-clear{background:transparent;border:1px solid var(--border-subtle);color:var(--text-muted);padding:8px 14px;border-radius:6px;font-weight:600;cursor:pointer;transition:color .2s,border-color .2s}.btn-clear:hover{color:var(--text-main);border-color:var(--text-muted)}.btn-clear:disabled{opacity:.6;cursor:not-allowed}.btn-send{background:var(--accent-primary);color:#fff;border:none;padding:8px 24px;border-radius:6px;font-weight:600;cursor:pointer;transition:opacity .2s}.btn-send:hover{opacity:.9}.btn-send:disabled{opacity:.5;cursor:not-allowed}.response-box{background:#0000004d;border-radius:8px;border:1px solid var(--border-subtle);overflow:hidden}.response-meta{background:#ffffff0d;padding:8px 70px 8px 12px;display:flex;gap:12px;font-size:11px;font-family:var(--font-mono);border-bottom:1px solid var(--border-subtle);position:relative}.response-box{position:relative}.meta-item{display:flex;align-items:center;gap:4px}.status-ok{color:var(--accent-success)}.status-err{color:var(--accent-error)}.response-body{padding:12px;overflow-x:auto;font-family:var(--font-mono);font-size:12px}.pg-response-hidden{display:none}.response-pre{margin:0}.pg-run-stack{display:flex;flex-direction:column;gap:16px}.pg-run-card{border:1px solid var(--border-subtle);border-radius:10px;background:#ffffff08;display:flex;flex-direction:column}.pg-run-card-header{background:transparent;border:none;display:flex;justify-content:space-between;align-items:center;gap:10px;padding:12px;cursor:pointer;width:100%;color:var(--text-main)}.pg-run-card-header:hover{background:#ffffff08}.pg-run-card-title{display:flex;justify-content:space-between;align-items:center;gap:12px;font-weight:700;color:var(--text-main)}.pg-run-tags{display:flex;gap:6px;flex-wrap:wrap;justify-content:flex-end}.pg-run-chip{background:#ffffff0f;border:1px solid var(--border-subtle);padding:4px 8px;border-radius:999px;font-size:11px;color:var(--text-muted)}.pg-run-card-body{padding:12px;display:flex;flex-direction:column;gap:8px;border-top:1px solid var(--border-subtle)}.pg-run-subtitle{font-size:12px;font-weight:600;color:var(--text-muted)}.pg-run-block{display:flex;flex-direction:column;gap:6px}.pg-run-meta-row{display:flex;flex-wrap:wrap;gap:6px}.json-tree{font-family:var(--font-mono);line-height:1.6}.jt-obj,.jt-arr{margin-left:14px}.jt-key{color:#93c5fd;margin-right:4px}.jt-str{color:#86efac}.jt-num{color:#fca5a5}.jt-bool{color:#fcd34d}.jt-null{color:#94a3b8}.jt-toggle{display:inline-block;width:12px;text-align:center;cursor:pointer;color:var(--text-muted);-webkit-user-select:none;user-select:none;margin-left:-14px}.jt-toggle:hover{color:var(--text-main)}.jt-collapsed .jt-content{display:none}.jt-collapsed:after{content:" ... ";color:var(--text-muted);font-size:10px}.json-tree-line{padding-left:16px}.history-view{display:flex;flex-direction:column;gap:16px}.history-toolbar{display:flex;flex-direction:column;gap:10px;padding:14px;background:var(--bg-card);border:1px solid var(--border-subtle);border-radius:var(--radius-card);box-shadow:var(--shadow-card)}.history-toolbar-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:12px}.history-path-filter{grid-column:span 2;min-width:280px}.history-search-filter{min-width:220px}@media(max-width:900px){.history-path-filter{grid-column:span 1;min-width:0}}.history-methods{min-height:36px}.history-duration .duration-inputs{display:flex;gap:8px}.history-date-range .duration-inputs{flex-wrap:wrap}.history-page-size{min-width:140px}.history-sort-row{display:flex;gap:8px;align-items:center}.sort-select{min-width:140px}.sort-direction-btn{height:32px;width:40px;border-radius:6px;border:1px solid var(--border-subtle);background:#ffffff08;color:var(--text-main);cursor:pointer}.sort-direction-btn:hover{border-color:var(--accent-primary);color:#fff}.history-toolbar-actions{display:flex;gap:8px;justify-content:flex-end;flex-wrap:wrap;width:100%;padding-top:6px;border-top:1px dashed var(--border-subtle)}.history-list{display:flex;flex-direction:column;gap:12px}.history-card{border:1px solid var(--border-subtle);border-radius:var(--radius-card);background:var(--bg-card);overflow:hidden}.highlightOnHover:hover{background:#ffffff0d;cursor:pointer;border-radius:6px;padding:6px;margin:12px -6px -6px}.history-card:hover{border-color:#94a3b866;box-shadow:var(--shadow-card);transform:translateY(-2px)}.history-card[data-expanded=true]{box-shadow:var(--shadow-card)}.history-card-header{display:flex;align-items:center;gap:12px;padding:12px 14px;cursor:pointer}.history-card .expand-icon{color:var(--text-muted)}.history-card[data-expanded=true] .expand-icon{color:var(--text-main);transform:rotate(180deg)}.history-title{display:flex;align-items:center;gap:8px;flex:1;min-width:0}.history-path{font-family:var(--font-mono);color:var(--text-main);overflow-wrap:anywhere}.history-meta-row{display:flex;align-items:center;gap:8px}.history-status{border:1px solid var(--border-subtle);padding:2px 8px;border-radius:6px;font-size:11px;color:var(--text-muted)}.history-status-error{border-color:var(--accent-error);color:var(--accent-error)}.history-status-warn{border-color:#facc15;color:#facc15}.history-status-good{border-color:var(--accent-success);color:var(--accent-success)}.history-chip{background:#ffffff0f;border:1px solid var(--border-subtle);color:var(--text-muted);padding:3px 8px;border-radius:6px;font-size:11px}.history-card-body{border-top:1px solid var(--border-subtle);padding:12px 14px;display:flex;flex-direction:column;gap:10px}.history-meta-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:8px}.history-detail{display:flex;flex-direction:column;gap:4px}.history-detail-label{font-size:10px;text-transform:uppercase;letter-spacing:.08em;color:var(--text-muted)}.history-detail-value{font-size:13px;color:var(--text-main);overflow-wrap:anywhere}.history-kv{display:flex;flex-direction:column;gap:4px}.history-kv-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.history-kv-key{font-family:var(--font-mono);color:var(--text-main);min-width:100px}.history-kv-value{font-family:var(--font-mono);color:var(--text-muted)}.history-empty{color:var(--text-muted);font-style:italic}.history-pre{margin:0;background:#00000040;border:1px solid var(--border-subtle);border-radius:8px;padding:8px;overflow-x:auto;font-family:var(--font-mono);font-size:12px;white-space:pre-wrap}.history-error{color:var(--accent-error);font-weight:700}.history-logs{display:flex;flex-direction:column;gap:8px}.history-log-summary{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:8px 10px;border-radius:10px;border:1px solid var(--border-subtle);background:#ffffff08;color:var(--text-main);cursor:pointer}.history-log-summary:hover{border-color:var(--accent-primary);background:#ffffff0d}.history-log-summary-main{display:flex;align-items:center;gap:10px}.history-log-summary-stats{display:flex;gap:6px;flex-wrap:wrap}.history-log-pill{border:1px solid var(--border-subtle);border-radius:999px;padding:3px 8px;font-size:11px;text-transform:capitalize;color:var(--text-muted)}.history-log-list{display:flex;flex-direction:column;gap:8px;padding:10px;border:1px solid var(--border-subtle);border-radius:8px;background:#00000040}.history-log-row{display:flex;flex-direction:column;gap:6px}.history-log-meta-row{background:#ffffff0d;border-radius:6px;padding:4px;margin:-4px}.history-log-meta-row:hover{background:#ffffff1a;cursor:pointer;border-radius:6px}.history-log-meta{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.history-log-tags{display:flex;gap:6px;flex-wrap:wrap}.history-log-message{font-family:var(--font-mono);color:var(--text-main)}.history-log-meta-toggle{display:flex;flex-direction:column;gap:6px}.history-stats-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:12px;background:#ffffff03;border-radius:var(--radius-card);padding:8px;margin:4px -8px -8px}.history-stats-grid[data-clickable=true]{cursor:pointer}.history-stats-grid:hover{background:#ffffff0d}.analytics-panel{display:flex;flex-direction:column;gap:12px}.analytics-expando{grid-column:1 / -1;text-align:right;color:var(--text-muted);font-size:12px;display:flex;justify-content:flex-end;align-items:center;gap:6px}.history-stat-card{border:1px solid var(--border-subtle);border-radius:var(--radius-card);background:#ffffff08;padding:10px 12px;margin-left:4px;margin-right:4px}.history-stats-grid[data-clickable=true] .history-stat-card{transition:border-color .15s ease,transform .15s ease}.history-stat-card[data-tone=good]{border-color:#4ade8066}.history-stat-card[data-tone=warn]{border-color:#eab30866}.history-stat-card[data-tone=bad]{border-color:#f8717166}.history-stat-label{font-size:11px;color:var(--text-muted);text-transform:uppercase;letter-spacing:.08em}.history-stat-value{font-size:22px;font-weight:800;margin-top:4px}.history-stat-hint{font-size:12px;color:var(--text-muted)}.history-graph-card{border:1px solid var(--border-subtle);border-radius:var(--radius-card);background:var(--bg-card);padding:10px 12px;display:flex;flex-direction:column;gap:10px;position:relative}.history-graph-header{display:flex;justify-content:space-between;align-items:center}.history-graph-title{font-weight:700}.history-graph-subtitle{color:var(--text-muted);font-size:12px}.history-graph-body{min-height:120px;display:flex;align-items:stretch}.history-graph-body>*{width:100%}.history-graph-empty{color:var(--text-muted);font-size:12px}.history-bar-chart{display:flex;flex-direction:column;gap:8px}.history-bar-row{display:grid;grid-template-columns:1fr 2fr auto;gap:8px;align-items:center}.history-bar-label{font-size:12px;color:var(--text-main)}.history-bar-track{height:10px;background:#ffffff0f;border-radius:999px;overflow:hidden}.history-bar-fill{height:100%;background:linear-gradient(90deg,var(--accent-primary),rgba(168,85,247,.3));border-radius:999px}.history-bar-fill.tone-good{background:linear-gradient(90deg,#4ade80,#4ade804d)}.history-bar-fill.tone-warn{background:linear-gradient(90deg,#facc15,#facc1540)}.history-bar-fill.tone-bad{background:linear-gradient(90deg,#f87171,#f8717140)}.history-bar-value{font-size:12px;color:var(--text-main);display:flex;flex-direction:column;align-items:flex-end}.history-bar-hint{color:var(--text-muted);font-size:11px}.history-line-chart{width:100%;height:100%;min-height:90px}.history-line-wrapper{position:relative;width:100%;height:100%}.history-line-path{fill:none;stroke:var(--accent-primary);stroke-width:.5}.history-line-dot{fill:#c4b5fd}.history-line-dot.dot-error{fill:var(--accent-error)}.history-line-grid{stroke:#94a3b84d;stroke-width:.6}.history-line-grid.vertical{opacity:.4}.history-line-axis{stroke:var(--border-subtle);stroke-width:1}.history-line-axis-label{fill:var(--text-muted);dominant-baseline:middle;font-size:4px}.history-line-axis-label.x-axis{text-anchor:middle}.history-graph-card.graph-timeline .history-graph-body{min-height:104px}.history-graphs-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:12px}.history-graph-card.graph-boxplot .history-graph-body{min-height:320px;flex:1}@media(min-width:1100px){.history-graphs-grid{grid-template-columns:repeat(4,minmax(0,1fr));grid-template-areas:"timeline timeline boxplot top" "status volume boxplot top";grid-auto-rows:minmax(140px,auto)}.history-graph-card.graph-timeline{grid-area:timeline}.history-graph-card.graph-status{grid-area:status}.history-graph-card.graph-volume{grid-area:volume}.history-graph-card.graph-boxplot{grid-area:boxplot}.history-graph-card.graph-top-paths{grid-area:top}}.history-boxplot-vertical{position:relative;padding-left:64px;padding-bottom:52px;min-height:240px;height:100%}.boxplot-scale{position:absolute;left:0;right:0;top:6px;bottom:52px;pointer-events:none}.scale-row{position:absolute;left:0;right:0;display:flex;align-items:center;gap:8px;font-size:11px;color:var(--text-muted)}.scale-label{width:60px;text-align:right}.scale-line{flex:1;height:1px;background:var(--border-subtle);opacity:.6}.boxplot-columns{display:flex;align-items:stretch;gap:14px;min-height:100%;height:100%;overflow-x:auto;padding-left:4px;padding-bottom:8px}.boxplot-column{display:flex;flex-direction:column;align-items:center;gap:6px;min-width:56px;flex:1 1 56px}.boxplot-vert-track{position:relative;width:32px;flex:1 1 auto;min-height:140px;background:#ffffff0a;border:1px solid var(--border-subtle);border-radius:10px;overflow:hidden}.boxplot-vert-whisker{position:absolute;left:13px;width:6px;background:#94a3b899;border-radius:6px}.boxplot-vert-box{position:absolute;left:7px;width:18px;background:#c4b5fd4d;border:1px solid var(--accent-primary);border-radius:8px}.boxplot-vert-median{position:absolute;left:4px;right:4px;height:2px;background:var(--accent-primary)}.boxplot-col-label{font-size:12px;color:var(--text-main);font-weight:700}.boxplot-col-meta{font-size:11px;color:var(--text-muted);margin-bottom:-4px}.copy-pre-wrapper{position:relative;display:flex;flex-direction:column;gap:6px}.copy-pre-actions{display:flex;align-items:center;justify-content:flex-end;gap:8px;position:absolute;right:6px;top:6px}.copy-pre-wrapper .history-pre{padding-right:12px}.copy-btn{position:relative;top:0;right:0;background:#ffffff14;border:1px solid var(--border-subtle);color:var(--text-main);border-radius:6px;padding:4px 8px;font-size:10px;cursor:pointer;z-index:2}.copy-btn:hover{border-color:var(--accent-primary);color:#fff}.history-error-banner{background:#fff1f0;border:1px solid #f5c2c0;color:#8a1f11;padding:8px 12px;border-radius:6px;margin:12px 0}.history-loading{margin:8px 0 4px;color:#555}.history-pagination{display:flex;align-items:center;justify-content:space-between;margin:12px 0}.m-error,.m-ERROR{background:#fef2f2;color:#b91c1c;border:1px solid #fecaca}.m-warn,.m-WARN{background:#fff7ed;color:#c05621;border:1px solid #fbd38d}.m-info,.m-INFO{background:#eff6ff;color:#2563eb;border:1px solid #bfdbfe}.m-debug,.m-DEBUG{background:#f7fafc;color:#4a5568;border:1px solid #e2e8f0}.m-system,.m-SYSTEM{background:#eef2ff;color:#4338ca;border:1px solid #cbd5ff}.hidden-template{display:none}
|
|
1
|
+
:root{color-scheme:light}html,body{margin:0;padding:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;background-color:#f6f8fa;min-height:100%}#docs-root{min-height:100vh}
|