@emeryld/rrroutes-openapi 2.2.27 → 2.2.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/docs/LeafDocsPage.d.ts +9 -1
- package/dist/docs/docs.d.ts +1 -0
- package/dist/index.cjs +241 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +40 -1
- package/dist/index.mjs +241 -3
- package/dist/index.mjs.map +1 -1
- package/dist/public/assets/docs.css +1 -1
- package/dist/public/assets/docs.js +18 -12
- package/dist/web/components/FiltersBar.d.ts +25 -0
- package/dist/web/components/HistoryView.d.ts +2 -1
- package/dist/web/components/LogsView.d.ts +1 -0
- package/dist/web/components/PlaygroundOverlay.d.ts +2 -2
- package/dist/web/historyStore.d.ts +20 -17
- package/dist/web/logsStore.d.ts +50 -0
- package/dist/webhooks.d.ts +181 -0
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -184,12 +184,14 @@ var DocsDocument = ({
|
|
|
184
184
|
assetBase,
|
|
185
185
|
docsBase,
|
|
186
186
|
historyJson,
|
|
187
|
+
logsJson,
|
|
187
188
|
baseUrlSuffix,
|
|
189
|
+
webhooks,
|
|
188
190
|
cspNonce
|
|
189
191
|
}) => {
|
|
190
192
|
const cssHref = `${assetBase}/docs.css`;
|
|
191
193
|
const jsSrc = `${assetBase}/docs.js`;
|
|
192
|
-
const configJson = serializeConfig({ docsBasePath: docsBase, baseUrlSuffix });
|
|
194
|
+
const configJson = serializeConfig({ docsBasePath: docsBase, baseUrlSuffix, webhooks });
|
|
193
195
|
return /* @__PURE__ */ jsxs("html", { lang: "en", children: [
|
|
194
196
|
/* @__PURE__ */ jsxs("head", { children: [
|
|
195
197
|
/* @__PURE__ */ jsx("meta", { charSet: "UTF-8" }),
|
|
@@ -226,6 +228,15 @@ var DocsDocument = ({
|
|
|
226
228
|
dangerouslySetInnerHTML: { __html: historyJson }
|
|
227
229
|
}
|
|
228
230
|
),
|
|
231
|
+
/* @__PURE__ */ jsx(
|
|
232
|
+
"script",
|
|
233
|
+
{
|
|
234
|
+
id: "logs-data",
|
|
235
|
+
type: "application/json",
|
|
236
|
+
nonce: cspNonce,
|
|
237
|
+
dangerouslySetInnerHTML: { __html: logsJson }
|
|
238
|
+
}
|
|
239
|
+
),
|
|
229
240
|
/* @__PURE__ */ jsx(
|
|
230
241
|
"script",
|
|
231
242
|
{
|
|
@@ -248,6 +259,9 @@ function serializePresets(presets) {
|
|
|
248
259
|
function serializeHistorySeeds(historySeeds) {
|
|
249
260
|
return JSON.stringify(Array.isArray(historySeeds) ? historySeeds : []).replace(/<\//g, "<\\/");
|
|
250
261
|
}
|
|
262
|
+
function serializeLogSeeds(logSeeds) {
|
|
263
|
+
return JSON.stringify(Array.isArray(logSeeds) ? logSeeds : []).replace(/<\//g, "<\\/");
|
|
264
|
+
}
|
|
251
265
|
function serializeConfig(config) {
|
|
252
266
|
return JSON.stringify(config).replace(/<\//g, "<\\/");
|
|
253
267
|
}
|
|
@@ -257,7 +271,9 @@ function createLeafDocsDocument(leaves, options = {}) {
|
|
|
257
271
|
const presetsJson = serializePresets(options.presets);
|
|
258
272
|
const docsBase = normalizeDocsBase(options.docsBasePath);
|
|
259
273
|
const historyJson = serializeHistorySeeds(options.historySeeds);
|
|
274
|
+
const logsJson = serializeLogSeeds(options.logSeeds);
|
|
260
275
|
const baseUrlSuffix = normalizeBaseUrlSuffix(options.baseUrlSuffix);
|
|
276
|
+
const webhooks = options.webhooks;
|
|
261
277
|
return /* @__PURE__ */ jsx(
|
|
262
278
|
DocsDocument,
|
|
263
279
|
{
|
|
@@ -266,7 +282,9 @@ function createLeafDocsDocument(leaves, options = {}) {
|
|
|
266
282
|
assetBase,
|
|
267
283
|
docsBase,
|
|
268
284
|
historyJson,
|
|
285
|
+
logsJson,
|
|
269
286
|
baseUrlSuffix,
|
|
287
|
+
webhooks,
|
|
270
288
|
cspNonce: options.cspNonce
|
|
271
289
|
}
|
|
272
290
|
);
|
|
@@ -282,6 +300,65 @@ function renderLeafDocsHTML2(leaves, options = {}) {
|
|
|
282
300
|
return renderLeafDocsHTML(leaves, options);
|
|
283
301
|
}
|
|
284
302
|
|
|
303
|
+
// src/webhooks.ts
|
|
304
|
+
import { z as z2 } from "zod";
|
|
305
|
+
var logTypeSchema = z2.enum(["debug", "info", "warn", "error", "system"]);
|
|
306
|
+
var historyFeedEntrySchema = z2.object({
|
|
307
|
+
id: z2.string(),
|
|
308
|
+
requestId: z2.string().optional(),
|
|
309
|
+
timestamp: z2.number(),
|
|
310
|
+
method: z2.string(),
|
|
311
|
+
path: z2.string(),
|
|
312
|
+
fullUrl: z2.string().optional(),
|
|
313
|
+
params: z2.record(z2.string(), z2.string()).optional(),
|
|
314
|
+
query: z2.record(z2.string(), z2.string()).optional(),
|
|
315
|
+
body: z2.string().optional(),
|
|
316
|
+
output: z2.string().optional(),
|
|
317
|
+
status: z2.number().optional(),
|
|
318
|
+
durationMs: z2.number(),
|
|
319
|
+
error: z2.string().optional()
|
|
320
|
+
});
|
|
321
|
+
var logFeedEntrySchema = z2.object({
|
|
322
|
+
id: z2.string(),
|
|
323
|
+
type: logTypeSchema,
|
|
324
|
+
message: z2.string(),
|
|
325
|
+
timestamp: z2.number(),
|
|
326
|
+
requestId: z2.string().optional(),
|
|
327
|
+
tags: z2.array(z2.string()).optional(),
|
|
328
|
+
metadata: z2.record(z2.string(), z2.unknown()).optional()
|
|
329
|
+
});
|
|
330
|
+
var historyFeedQuerySchema = z2.object({
|
|
331
|
+
cursor: z2.string().optional(),
|
|
332
|
+
limit: z2.number().int().positive().optional(),
|
|
333
|
+
methods: z2.array(z2.string()).optional(),
|
|
334
|
+
path: z2.string().optional(),
|
|
335
|
+
status: z2.string().optional(),
|
|
336
|
+
text: z2.string().optional(),
|
|
337
|
+
from: z2.number().optional(),
|
|
338
|
+
to: z2.number().optional(),
|
|
339
|
+
sortBy: z2.enum(["timestamp", "path", "duration"]).optional(),
|
|
340
|
+
sortDir: z2.enum(["asc", "desc"]).optional()
|
|
341
|
+
});
|
|
342
|
+
var logFeedQuerySchema = z2.object({
|
|
343
|
+
cursor: z2.string().optional(),
|
|
344
|
+
limit: z2.number().int().positive().optional(),
|
|
345
|
+
types: z2.array(logTypeSchema).optional(),
|
|
346
|
+
tags: z2.array(z2.string()).optional(),
|
|
347
|
+
requestId: z2.string().optional(),
|
|
348
|
+
text: z2.string().optional(),
|
|
349
|
+
from: z2.number().optional(),
|
|
350
|
+
to: z2.number().optional(),
|
|
351
|
+
sortDir: z2.enum(["asc", "desc"]).optional()
|
|
352
|
+
});
|
|
353
|
+
var webhookPageSchema = (itemSchema) => z2.object({
|
|
354
|
+
items: z2.array(itemSchema).default([]),
|
|
355
|
+
nextCursor: z2.string().optional(),
|
|
356
|
+
prevCursor: z2.string().optional(),
|
|
357
|
+
total: z2.number().optional()
|
|
358
|
+
});
|
|
359
|
+
var historyWebhookResponseSchema = webhookPageSchema(historyFeedEntrySchema);
|
|
360
|
+
var logWebhookResponseSchema = webhookPageSchema(logFeedEntrySchema);
|
|
361
|
+
|
|
285
362
|
// src/index.ts
|
|
286
363
|
var trimTrailingSlash = (value) => value.endsWith("/") && value.length > 1 ? value.slice(0, -1) : value;
|
|
287
364
|
function mountRRRoutesDocs({
|
|
@@ -296,6 +373,50 @@ function mountRRRoutesDocs({
|
|
|
296
373
|
const assetsMountPath = trimTrailingSlash(
|
|
297
374
|
options.assetBasePath ?? `${normalizedDocsPath}/assets`
|
|
298
375
|
);
|
|
376
|
+
const webhookBaseInput = options.logWebhook?.basePath ?? `${normalizedDocsPath}/webhooks`;
|
|
377
|
+
const webhookBasePath = trimTrailingSlash(
|
|
378
|
+
webhookBaseInput.startsWith("/") ? webhookBaseInput : `/${webhookBaseInput}`
|
|
379
|
+
);
|
|
380
|
+
const webhookPaths = {
|
|
381
|
+
history: `${webhookBasePath}/history`,
|
|
382
|
+
logs: `${webhookBasePath}/logs`
|
|
383
|
+
};
|
|
384
|
+
const webhookSchemas = {
|
|
385
|
+
history: {
|
|
386
|
+
query: historyFeedQuerySchema,
|
|
387
|
+
response: historyWebhookResponseSchema,
|
|
388
|
+
entry: historyFeedEntrySchema
|
|
389
|
+
},
|
|
390
|
+
logs: {
|
|
391
|
+
query: logFeedQuerySchema,
|
|
392
|
+
response: logWebhookResponseSchema,
|
|
393
|
+
entry: logFeedEntrySchema
|
|
394
|
+
}
|
|
395
|
+
};
|
|
396
|
+
const webhookLeaves = {
|
|
397
|
+
history: {
|
|
398
|
+
method: "get",
|
|
399
|
+
path: webhookPaths.history,
|
|
400
|
+
cfg: {
|
|
401
|
+
summary: "RRRoutes docs history feed",
|
|
402
|
+
description: "Returns request history for the docs UI.",
|
|
403
|
+
querySchema: historyFeedQuerySchema,
|
|
404
|
+
outputSchema: historyWebhookResponseSchema,
|
|
405
|
+
tags: ["rrroutes", "docs"]
|
|
406
|
+
}
|
|
407
|
+
},
|
|
408
|
+
logs: {
|
|
409
|
+
method: "get",
|
|
410
|
+
path: webhookPaths.logs,
|
|
411
|
+
cfg: {
|
|
412
|
+
summary: "RRRoutes docs request logs",
|
|
413
|
+
description: "Returns request logs for the docs UI.",
|
|
414
|
+
querySchema: logFeedQuerySchema,
|
|
415
|
+
outputSchema: logWebhookResponseSchema,
|
|
416
|
+
tags: ["rrroutes", "docs"]
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
};
|
|
299
420
|
const publicDir = resolvePublicDir();
|
|
300
421
|
const assetsDir = path.join(publicDir, "assets");
|
|
301
422
|
const cspEnabled = options.csp !== false;
|
|
@@ -318,7 +439,12 @@ function mountRRRoutesDocs({
|
|
|
318
439
|
docsBasePath: `${prefix}${normalizedDocsPath}`,
|
|
319
440
|
baseUrlSuffix: prefix,
|
|
320
441
|
historySeeds: options.historySeeds,
|
|
321
|
-
|
|
442
|
+
logSeeds: options.logSeeds,
|
|
443
|
+
presets: normalizePresets(finalPresets),
|
|
444
|
+
webhooks: {
|
|
445
|
+
history: `${prefix}${webhookPaths.history}`,
|
|
446
|
+
logs: `${prefix}${webhookPaths.logs}`
|
|
447
|
+
}
|
|
322
448
|
});
|
|
323
449
|
if (cspEnabled && nonce) {
|
|
324
450
|
res.setHeader(
|
|
@@ -336,7 +462,37 @@ function mountRRRoutesDocs({
|
|
|
336
462
|
}
|
|
337
463
|
res.send(html);
|
|
338
464
|
});
|
|
339
|
-
|
|
465
|
+
router.get(webhookPaths.history, async (req, res) => {
|
|
466
|
+
const handler = options.logWebhook?.history;
|
|
467
|
+
if (!handler) {
|
|
468
|
+
res.status(501).json({ items: [], total: 0 });
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
try {
|
|
472
|
+
const query = parseHistoryWebhookQuery(req);
|
|
473
|
+
const result = await handler({ query, req, res });
|
|
474
|
+
res.json(normalizeWebhookPage(result));
|
|
475
|
+
} catch (err) {
|
|
476
|
+
console.error("Failed to serve history webhook", err);
|
|
477
|
+
res.status(500).json({ error: "Failed to load history feed" });
|
|
478
|
+
}
|
|
479
|
+
});
|
|
480
|
+
router.get(webhookPaths.logs, async (req, res) => {
|
|
481
|
+
const handler = options.logWebhook?.logs;
|
|
482
|
+
if (!handler) {
|
|
483
|
+
res.status(501).json({ items: [], total: 0 });
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
try {
|
|
487
|
+
const query = parseLogWebhookQuery(req);
|
|
488
|
+
const result = await handler({ query, req, res });
|
|
489
|
+
res.json(normalizeWebhookPage(result));
|
|
490
|
+
} catch (err) {
|
|
491
|
+
console.error("Failed to serve log webhook", err);
|
|
492
|
+
res.status(500).json({ error: "Failed to load logs feed" });
|
|
493
|
+
}
|
|
494
|
+
});
|
|
495
|
+
return { path: docsPath, webhooks: webhookPaths, webhookLeaves, webhookSchemas };
|
|
340
496
|
}
|
|
341
497
|
function resolvePublicDir() {
|
|
342
498
|
const moduleDir = typeof __dirname !== "undefined" ? __dirname : path.dirname(fileURLToPath(import.meta.url));
|
|
@@ -362,6 +518,88 @@ function normalizePresets(presets) {
|
|
|
362
518
|
})) : []
|
|
363
519
|
}));
|
|
364
520
|
}
|
|
521
|
+
function parseHistoryWebhookQuery(req) {
|
|
522
|
+
const query = req.query || {};
|
|
523
|
+
const methods = parseStringList(query.methods);
|
|
524
|
+
const path2 = typeof query.path === "string" ? query.path : void 0;
|
|
525
|
+
const status = typeof query.status === "string" ? query.status : void 0;
|
|
526
|
+
const text = typeof query.text === "string" ? query.text : void 0;
|
|
527
|
+
const cursor = typeof query.cursor === "string" ? query.cursor : void 0;
|
|
528
|
+
const sortBy = isSortKey(query.sortBy) ? query.sortBy : void 0;
|
|
529
|
+
const sortDir = isSortDir(query.sortDir) ? query.sortDir : void 0;
|
|
530
|
+
const limit = parseLimit(query.limit);
|
|
531
|
+
const from = parseDateInput(query.from);
|
|
532
|
+
const to = parseDateInput(query.to);
|
|
533
|
+
return {
|
|
534
|
+
cursor,
|
|
535
|
+
methods,
|
|
536
|
+
path: path2,
|
|
537
|
+
status,
|
|
538
|
+
text,
|
|
539
|
+
limit,
|
|
540
|
+
from,
|
|
541
|
+
to,
|
|
542
|
+
sortBy,
|
|
543
|
+
sortDir
|
|
544
|
+
};
|
|
545
|
+
}
|
|
546
|
+
function parseLogWebhookQuery(req) {
|
|
547
|
+
const query = req.query || {};
|
|
548
|
+
const types = parseStringList(query.types);
|
|
549
|
+
const tags = parseStringList(query.tags);
|
|
550
|
+
const requestId = typeof query.requestId === "string" ? query.requestId : void 0;
|
|
551
|
+
const text = typeof query.text === "string" ? query.text : void 0;
|
|
552
|
+
const cursor = typeof query.cursor === "string" ? query.cursor : void 0;
|
|
553
|
+
const limit = parseLimit(query.limit);
|
|
554
|
+
const from = parseDateInput(query.from);
|
|
555
|
+
const to = parseDateInput(query.to);
|
|
556
|
+
const sortDir = isSortDir(query.sortDir) ? query.sortDir : void 0;
|
|
557
|
+
return {
|
|
558
|
+
cursor,
|
|
559
|
+
types,
|
|
560
|
+
tags,
|
|
561
|
+
requestId,
|
|
562
|
+
text,
|
|
563
|
+
limit,
|
|
564
|
+
from,
|
|
565
|
+
to,
|
|
566
|
+
sortDir
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
function parseStringList(value) {
|
|
570
|
+
if (typeof value !== "string") return void 0;
|
|
571
|
+
const parts = value.split(",").map((p) => p.trim()).filter(Boolean);
|
|
572
|
+
return parts.length ? parts : void 0;
|
|
573
|
+
}
|
|
574
|
+
function parseLimit(value) {
|
|
575
|
+
if (value === void 0) return void 0;
|
|
576
|
+
const num = Number(value);
|
|
577
|
+
if (!Number.isFinite(num) || num <= 0) return void 0;
|
|
578
|
+
return num;
|
|
579
|
+
}
|
|
580
|
+
function parseDateInput(value) {
|
|
581
|
+
if (typeof value !== "string") return void 0;
|
|
582
|
+
const numeric = Number(value);
|
|
583
|
+
if (Number.isFinite(numeric)) return numeric;
|
|
584
|
+
const timestamp = Date.parse(value);
|
|
585
|
+
if (Number.isNaN(timestamp)) return void 0;
|
|
586
|
+
return timestamp;
|
|
587
|
+
}
|
|
588
|
+
function isSortKey(value) {
|
|
589
|
+
return value === "timestamp" || value === "path" || value === "duration";
|
|
590
|
+
}
|
|
591
|
+
function isSortDir(value) {
|
|
592
|
+
return value === "asc" || value === "desc";
|
|
593
|
+
}
|
|
594
|
+
function normalizeWebhookPage(page) {
|
|
595
|
+
if (!page || typeof page !== "object") return { items: [] };
|
|
596
|
+
return {
|
|
597
|
+
items: Array.isArray(page.items) ? page.items : [],
|
|
598
|
+
nextCursor: page.nextCursor,
|
|
599
|
+
prevCursor: page.prevCursor,
|
|
600
|
+
total: page.total
|
|
601
|
+
};
|
|
602
|
+
}
|
|
365
603
|
export {
|
|
366
604
|
mountRRRoutesDocs,
|
|
367
605
|
renderLeafDocsHTML2 as renderLeafDocsHTML,
|
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"],"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';\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 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 /**\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\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>) {\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 publicDir = resolvePublicDir();\n const assetsDir = path.join(publicDir, 'assets');\n const cspEnabled = options.csp !== false;\n\n router.use(assetsMountPath, expressStatic(assetsDir, { immutable: true, maxAge: '365d' }));\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: options.historySeeds,\n presets: normalizePresets(finalPresets),\n });\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 ].join('; '),\n );\n }\n\n res.send(html);\n });\n\n return { path: docsPath };\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\nexport { renderLeafDocsHTML } from './docs/docs.js';\nexport { serializeLeaf } from './docs/serializer.js';\nexport type { SerializableLeaf } from './docs/serializer.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';\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}\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 baseUrlSuffix?: string;\n cspNonce?: string;\n};\n\nexport const DocsDocument = ({\n leavesJson,\n presetsJson,\n assetBase,\n docsBase,\n historyJson,\n baseUrlSuffix,\n cspNonce,\n}: DocsDocumentProps) => {\n const cssHref = `${assetBase}/docs.css`;\n const jsSrc = `${assetBase}/docs.js`;\n const configJson = serializeConfig({ docsBasePath: docsBase, baseUrlSuffix });\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=\"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\ntype DocsConfig = { docsBasePath: string; baseUrlSuffix?: string };\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 baseUrlSuffix = normalizeBaseUrlSuffix(options.baseUrlSuffix);\n\n return (\n <DocsDocument\n leavesJson={leavesJson}\n presetsJson={presetsJson}\n assetBase={assetBase}\n docsBase={docsBase}\n historyJson={historyJson}\n baseUrlSuffix={baseUrlSuffix}\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\";\n"],"mappings":"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","names":["renderLeafDocsHTML","renderLeafDocsHTML"]}
|
|
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 logTypeSchema,\n webhookPageSchema,\n type HistoryFeedEntry,\n type HistoryFeedQuery,\n type LogFeedEntry,\n type LogFeedQuery,\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 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 * 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 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\n router.use(assetsMountPath, expressStatic(assetsDir, { immutable: true, maxAge: '365d' }));\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: options.historySeeds,\n logSeeds: options.logSeeds,\n presets: normalizePresets(finalPresets),\n webhooks: {\n history: `${prefix}${webhookPaths.history}`,\n logs: `${prefix}${webhookPaths.logs}`,\n },\n });\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 ].join('; '),\n );\n }\n\n res.send(html);\n });\n\n router.get(webhookPaths.history, async (req, res) => {\n const handler = options.logWebhook?.history;\n if (!handler) {\n res.status(501).json({ items: [], total: 0 });\n return;\n }\n try {\n const query = parseHistoryWebhookQuery(req);\n const result = await handler({ query, req, res });\n res.json(normalizeWebhookPage(result));\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 if (!handler) {\n res.status(501).json({ items: [], total: 0 });\n return;\n }\n try {\n const query = parseLogWebhookQuery(req);\n const result = await handler({ query, req, res });\n res.json(normalizeWebhookPage(result));\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 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\nexport { renderLeafDocsHTML } from './docs/docs.js';\nexport { serializeLeaf } from './docs/serializer.js';\nexport type { SerializableLeaf } from './docs/serializer.js';\nexport type {\n HistoryFeedEntry,\n HistoryFeedQuery,\n LogFeedEntry,\n LogFeedQuery,\n LogType,\n WebhookPage,\n WebhookPaths,\n historyFeedEntrySchema,\n historyFeedQuerySchema,\n historyWebhookResponseSchema,\n logFeedEntrySchema,\n logFeedQuerySchema,\n logWebhookResponseSchema,\n logTypeSchema,\n webhookPageSchema,\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?: Record<string, unknown>;\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.record(z.string(),z.unknown()).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","renderLeafDocsHTML","path"]}
|