vector-framework 1.2.2 → 1.2.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 +18 -6
- package/dist/auth/protected.d.ts +4 -4
- package/dist/auth/protected.d.ts.map +1 -1
- package/dist/auth/protected.js +10 -7
- package/dist/auth/protected.js.map +1 -1
- package/dist/cache/manager.d.ts +2 -0
- package/dist/cache/manager.d.ts.map +1 -1
- package/dist/cache/manager.js +21 -4
- package/dist/cache/manager.js.map +1 -1
- package/dist/checkpoint/artifacts/compressor.d.ts +5 -0
- package/dist/checkpoint/artifacts/compressor.d.ts.map +1 -0
- package/dist/checkpoint/artifacts/compressor.js +24 -0
- package/dist/checkpoint/artifacts/compressor.js.map +1 -0
- package/dist/checkpoint/artifacts/decompress-worker.d.ts +2 -0
- package/dist/checkpoint/artifacts/decompress-worker.d.ts.map +1 -0
- package/dist/checkpoint/artifacts/decompress-worker.js +31 -0
- package/dist/checkpoint/artifacts/decompress-worker.js.map +1 -0
- package/dist/checkpoint/artifacts/hasher.d.ts +2 -0
- package/dist/checkpoint/artifacts/hasher.d.ts.map +1 -0
- package/dist/checkpoint/artifacts/hasher.js +7 -0
- package/dist/checkpoint/artifacts/hasher.js.map +1 -0
- package/dist/checkpoint/artifacts/manifest.d.ts +6 -0
- package/dist/checkpoint/artifacts/manifest.d.ts.map +1 -0
- package/dist/checkpoint/artifacts/manifest.js +55 -0
- package/dist/checkpoint/artifacts/manifest.js.map +1 -0
- package/dist/checkpoint/artifacts/materializer.d.ts +16 -0
- package/dist/checkpoint/artifacts/materializer.d.ts.map +1 -0
- package/dist/checkpoint/artifacts/materializer.js +168 -0
- package/dist/checkpoint/artifacts/materializer.js.map +1 -0
- package/dist/checkpoint/artifacts/packager.d.ts +12 -0
- package/dist/checkpoint/artifacts/packager.d.ts.map +1 -0
- package/dist/checkpoint/artifacts/packager.js +82 -0
- package/dist/checkpoint/artifacts/packager.js.map +1 -0
- package/dist/checkpoint/artifacts/repository.d.ts +11 -0
- package/dist/checkpoint/artifacts/repository.d.ts.map +1 -0
- package/dist/checkpoint/artifacts/repository.js +29 -0
- package/dist/checkpoint/artifacts/repository.js.map +1 -0
- package/dist/checkpoint/artifacts/store.d.ts +13 -0
- package/dist/checkpoint/artifacts/store.d.ts.map +1 -0
- package/dist/checkpoint/artifacts/store.js +85 -0
- package/dist/checkpoint/artifacts/store.js.map +1 -0
- package/dist/checkpoint/artifacts/types.d.ts +21 -0
- package/dist/checkpoint/artifacts/types.d.ts.map +1 -0
- package/dist/checkpoint/artifacts/types.js +2 -0
- package/dist/checkpoint/artifacts/types.js.map +1 -0
- package/dist/checkpoint/artifacts/worker-decompressor.d.ts +17 -0
- package/dist/checkpoint/artifacts/worker-decompressor.d.ts.map +1 -0
- package/dist/checkpoint/artifacts/worker-decompressor.js +148 -0
- package/dist/checkpoint/artifacts/worker-decompressor.js.map +1 -0
- package/dist/checkpoint/asset-store.d.ts +10 -0
- package/dist/checkpoint/asset-store.d.ts.map +1 -0
- package/dist/checkpoint/asset-store.js +46 -0
- package/dist/checkpoint/asset-store.js.map +1 -0
- package/dist/checkpoint/bundler.d.ts +15 -0
- package/dist/checkpoint/bundler.d.ts.map +1 -0
- package/dist/checkpoint/bundler.js +45 -0
- package/dist/checkpoint/bundler.js.map +1 -0
- package/dist/checkpoint/cli.d.ts +2 -0
- package/dist/checkpoint/cli.d.ts.map +1 -0
- package/dist/checkpoint/cli.js +157 -0
- package/dist/checkpoint/cli.js.map +1 -0
- package/dist/checkpoint/entrypoint-generator.d.ts +17 -0
- package/dist/checkpoint/entrypoint-generator.d.ts.map +1 -0
- package/dist/checkpoint/entrypoint-generator.js +251 -0
- package/dist/checkpoint/entrypoint-generator.js.map +1 -0
- package/dist/checkpoint/forwarder.d.ts +6 -0
- package/dist/checkpoint/forwarder.d.ts.map +1 -0
- package/dist/checkpoint/forwarder.js +74 -0
- package/dist/checkpoint/forwarder.js.map +1 -0
- package/dist/checkpoint/gateway.d.ts +11 -0
- package/dist/checkpoint/gateway.d.ts.map +1 -0
- package/dist/checkpoint/gateway.js +30 -0
- package/dist/checkpoint/gateway.js.map +1 -0
- package/dist/checkpoint/ipc.d.ts +12 -0
- package/dist/checkpoint/ipc.d.ts.map +1 -0
- package/dist/checkpoint/ipc.js +96 -0
- package/dist/checkpoint/ipc.js.map +1 -0
- package/dist/checkpoint/manager.d.ts +20 -0
- package/dist/checkpoint/manager.d.ts.map +1 -0
- package/dist/checkpoint/manager.js +214 -0
- package/dist/checkpoint/manager.js.map +1 -0
- package/dist/checkpoint/process-manager.d.ts +35 -0
- package/dist/checkpoint/process-manager.d.ts.map +1 -0
- package/dist/checkpoint/process-manager.js +203 -0
- package/dist/checkpoint/process-manager.js.map +1 -0
- package/dist/checkpoint/resolver.d.ts +25 -0
- package/dist/checkpoint/resolver.d.ts.map +1 -0
- package/dist/checkpoint/resolver.js +95 -0
- package/dist/checkpoint/resolver.js.map +1 -0
- package/dist/checkpoint/socket-path.d.ts +2 -0
- package/dist/checkpoint/socket-path.d.ts.map +1 -0
- package/dist/checkpoint/socket-path.js +51 -0
- package/dist/checkpoint/socket-path.js.map +1 -0
- package/dist/checkpoint/types.d.ts +54 -0
- package/dist/checkpoint/types.d.ts.map +1 -0
- package/dist/checkpoint/types.js +2 -0
- package/dist/checkpoint/types.js.map +1 -0
- package/dist/cli/index.js +10 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/option-resolution.d.ts +1 -1
- package/dist/cli/option-resolution.d.ts.map +1 -1
- package/dist/cli/option-resolution.js.map +1 -1
- package/dist/cli.js +3709 -328
- package/dist/core/config-loader.d.ts +1 -0
- package/dist/core/config-loader.d.ts.map +1 -1
- package/dist/core/config-loader.js +10 -2
- package/dist/core/config-loader.js.map +1 -1
- package/dist/core/router.d.ts +24 -3
- package/dist/core/router.d.ts.map +1 -1
- package/dist/core/router.js +398 -249
- package/dist/core/router.js.map +1 -1
- package/dist/core/server.d.ts +2 -0
- package/dist/core/server.d.ts.map +1 -1
- package/dist/core/server.js +22 -8
- package/dist/core/server.js.map +1 -1
- package/dist/core/vector.d.ts +3 -0
- package/dist/core/vector.d.ts.map +1 -1
- package/dist/core/vector.js +51 -1
- package/dist/core/vector.js.map +1 -1
- package/dist/dev/route-scanner.d.ts.map +1 -1
- package/dist/dev/route-scanner.js +2 -1
- package/dist/dev/route-scanner.js.map +1 -1
- package/dist/http.d.ts +32 -7
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +144 -13
- package/dist/http.js.map +1 -1
- package/dist/index.cjs +1297 -74
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1296 -73
- package/dist/middleware/manager.d.ts +3 -3
- package/dist/middleware/manager.d.ts.map +1 -1
- package/dist/middleware/manager.js +9 -8
- package/dist/middleware/manager.js.map +1 -1
- package/dist/openapi/docs-ui.d.ts.map +1 -1
- package/dist/openapi/docs-ui.js +1097 -61
- package/dist/openapi/docs-ui.js.map +1 -1
- package/dist/openapi/generator.d.ts +2 -1
- package/dist/openapi/generator.d.ts.map +1 -1
- package/dist/openapi/generator.js +240 -7
- package/dist/openapi/generator.js.map +1 -1
- package/dist/types/index.d.ts +71 -28
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +24 -1
- package/dist/types/index.js.map +1 -1
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js +3 -2
- package/dist/utils/validation.js.map +1 -1
- package/package.json +2 -1
- package/src/auth/protected.ts +11 -8
- package/src/cache/manager.ts +23 -4
- package/src/checkpoint/artifacts/compressor.ts +30 -0
- package/src/checkpoint/artifacts/decompress-worker.ts +49 -0
- package/src/checkpoint/artifacts/hasher.ts +6 -0
- package/src/checkpoint/artifacts/manifest.ts +72 -0
- package/src/checkpoint/artifacts/materializer.ts +211 -0
- package/src/checkpoint/artifacts/packager.ts +100 -0
- package/src/checkpoint/artifacts/repository.ts +36 -0
- package/src/checkpoint/artifacts/store.ts +102 -0
- package/src/checkpoint/artifacts/types.ts +24 -0
- package/src/checkpoint/artifacts/worker-decompressor.ts +192 -0
- package/src/checkpoint/asset-store.ts +61 -0
- package/src/checkpoint/bundler.ts +64 -0
- package/src/checkpoint/cli.ts +177 -0
- package/src/checkpoint/entrypoint-generator.ts +275 -0
- package/src/checkpoint/forwarder.ts +84 -0
- package/src/checkpoint/gateway.ts +40 -0
- package/src/checkpoint/ipc.ts +107 -0
- package/src/checkpoint/manager.ts +254 -0
- package/src/checkpoint/process-manager.ts +250 -0
- package/src/checkpoint/resolver.ts +124 -0
- package/src/checkpoint/socket-path.ts +61 -0
- package/src/checkpoint/types.ts +63 -0
- package/src/cli/index.ts +11 -2
- package/src/cli/option-resolution.ts +5 -1
- package/src/core/config-loader.ts +11 -2
- package/src/core/router.ts +505 -264
- package/src/core/server.ts +36 -9
- package/src/core/vector.ts +60 -1
- package/src/dev/route-scanner.ts +2 -1
- package/src/http.ts +219 -19
- package/src/index.ts +3 -2
- package/src/middleware/manager.ts +10 -10
- package/src/openapi/docs-ui.ts +1097 -61
- package/src/openapi/generator.ts +265 -6
- package/src/types/index.ts +83 -30
- package/src/utils/validation.ts +5 -3
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,195 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var
|
|
2
|
+
var ir=Object.defineProperty;var P=(e,t)=>{for(var r in t)ir(e,r,{get:t[r],enumerable:!0,configurable:!0,set:(a)=>t[r]=()=>a})};var E=(e,t)=>()=>(e&&(t=e(e=0)),t);var ge=1;function ft(e,t="gzip"){let r=new Uint8Array(e);switch(t){case"none":return r;case"gzip":return Bun.gzipSync(r);default:throw new Error(`Unsupported compression codec: ${t}`)}}var ht="gzip";function T(e){let t=e instanceof Uint8Array?e:new Uint8Array(e),r=Bun.SHA256.hash(t),a=new Uint8Array(r.buffer,r.byteOffset,r.byteLength);return Buffer.from(a).toString("hex")}import{basename as oa,isAbsolute as da,relative as ia}from"path";function Y(e){let t=U(e).trim(),n=(ye(t)?la(t):t).split("/").filter((i)=>i.length>0&&i!=="."&&i!=="..").join("/").replace(gt,"_").replace(/^\/+/,"");if(n.length>0)return n;let o=oa(t).replace(gt,"_");return o.length>0?`external/${o}`:"external/asset.bin"}function xt(e){return U(e).replace(/^\/+/,"")}function ye(e){let t=U(e).trim();return da(t)||yt.test(t)||wt.test(e)}function vt(e){let t=e.map((r)=>({type:r.type,logicalPath:r.logicalPath,contentHash:r.contentHash??r.hash,blobHash:r.blobHash??"",blobPath:r.blobPath??r.storedPath,codec:r.codec??"none",size:r.contentSize??r.size})).sort((r,a)=>`${r.type}:${r.logicalPath}:${r.contentHash}:${r.blobHash}`.localeCompare(`${a.type}:${a.logicalPath}:${a.contentHash}:${a.blobHash}`));return JSON.stringify(t)}function U(e){return e.replace(/\\/g,"/")}function la(e){let t=U(e);if(yt.test(t))return t.replace(/^[a-zA-Z]:/,"").replace(/^\/+/,"");if(wt.test(e))return U(e).replace(/^\\\\[^\\]+\\[^\\]+/,"").replace(/^\/+/,"");return U(ia(process.cwd(),t))}var gt,yt,wt;var we=E(()=>{gt=/[^a-zA-Z0-9._/-]/g,yt=/^[a-zA-Z]:[\\/]/,wt=/^\\\\[^\\]+\\[^\\]+/});import{existsSync as sa,promises as O}from"fs";import{join as xe}from"path";class ve{storageDir;codec;constructor(e,t={}){this.storageDir=e,this.codec=t.assetCodec??ht}async addEmbedded(e,t){return this.addAsset("embedded",e,t)}async addSidecar(e,t){return this.addAsset("sidecar",e,t)}async collect(e,t){let r=[];for(let a of e)r.push(await this.addEmbedded(a,a));for(let a of t)r.push(await this.addSidecar(a,a));return r}async addAsset(e,t,r){let a=await O.readFile(r),n=new Uint8Array(a.buffer,a.byteOffset,a.byteLength),o=T(n),i=ft(n,this.codec),d=T(i),l=xt(xe(Et,`${d}${this.codec==="gzip"?".gz":""}`)),c=xe(this.storageDir,l);if(await O.mkdir(xe(this.storageDir,Et),{recursive:!0}),!sa(c))await this.writeAtomically(c,i);else{let m=await O.readFile(c),s=new Uint8Array(m.buffer,m.byteOffset,m.byteLength);if(T(s)!==d)await this.writeAtomically(c,i)}return{type:e,logicalPath:Y(t),storedPath:c,hash:o,size:a.byteLength,contentHash:o,contentSize:a.byteLength,blobHash:d,blobSize:i.byteLength,blobPath:l,codec:this.codec}}async writeAtomically(e,t){let r=`${e}.tmp.${process.pid}.${Date.now()}`;await O.writeFile(r,t);try{await O.rename(r,e)}catch(a){if(!ca(a))throw a;await O.rm(e,{force:!0}),await O.rename(r,e)}}}function ca(e){if(typeof e!=="object"||e===null||!("code"in e))return!1;let t=e.code;return t==="EEXIST"||t==="EPERM"}var Et="_assets/blobs";var kt=E(()=>{we()});import{promises as pa}from"fs";class Ee{artifactStore;constructor(e){this.artifactStore=new ve(e)}async addEmbedded(e,t){let r=await pa.readFile(t);if(r.byteLength>Bt)throw new Error(`Embedded asset "${e}" is ${q(r.byteLength)} \u2014 exceeds ${q(Bt)} per-file budget. Use sidecar instead.`);return await this.artifactStore.addEmbedded(e,t)}async addSidecar(e,t){return await this.artifactStore.addSidecar(e,t)}async collect(e,t){let r=[];for(let a of e)r.push(await this.addEmbedded(a,a));for(let a of t)r.push(await this.addSidecar(a,a));return r}validateBudgets(e){let t=e.filter((r)=>r.type==="embedded").reduce((r,a)=>r+(a.contentSize??a.size),0);if(t>It)throw new Error(`Total embedded asset size ${q(t)} exceeds ${q(It)} budget.`)}}function q(e){if(e<1024)return`${e} B`;if(e<1048576)return`${(e/1024).toFixed(1)} KB`;return`${(e/1048576).toFixed(1)} MB`}var Bt=65536,It=524288;var Tt=E(()=>{kt()});import{existsSync as Ct}from"fs";import{join as ma}from"path";class ke{async bundle(e){let t=e.outputFile??"checkpoint.js",r=await Bun.build({entrypoints:[e.entrypointPath],outdir:e.outputDir,target:"bun",format:"esm",minify:!0,naming:{entry:t}});if(!r.success){let n=r.logs.map((o)=>o.message??String(o)).join(`
|
|
3
|
+
`);throw new Error(`Checkpoint bundle failed:
|
|
4
|
+
${n}`)}let a=ma(e.outputDir,t);if(!Ct(a)){let n=r.outputs.find((o)=>o.kind==="entry-point");if(n){let o=n.path;if(Ct(o))return this.hashFile(o)}throw new Error(`Bundle output not found at expected path: ${a}`)}return this.hashFile(a)}async hashFile(e){let r=await Bun.file(e).arrayBuffer(),a=Bun.SHA256.hash(new Uint8Array(r)),n=new Uint8Array(a.buffer,a.byteOffset,a.byteLength),o=Buffer.from(n).toString("hex");return{outputPath:e,hash:o,size:r.byteLength}}}var Lt=()=>{};import{existsSync as ba,promises as Be}from"fs";import{join as Nt,relative as At,sep as St}from"path";class Ie{discoveredRoutes=[];async generate(e){let t=await this.scanRouteFiles(e.routesDir),r=this.buildSource(t,e),a=Nt(e.outputDir,"entrypoint.ts");return await Be.writeFile(a,r,"utf-8"),a}getDiscoveredRoutes(){return this.discoveredRoutes}async scanRouteFiles(e){if(!ba(e))return[];let t=[];return await this.walkDir(e,t),t}async walkDir(e,t){let r=await Be.readdir(e);for(let a of r){let n=Nt(e,a);if((await Be.stat(n)).isDirectory())await this.walkDir(n,t);else if((a.endsWith(".ts")||a.endsWith(".js"))&&!a.endsWith(".test.ts")&&!a.endsWith(".test.js")&&!a.endsWith(".spec.ts")&&!a.endsWith(".spec.js")&&!a.endsWith(".d.ts"))t.push(n)}}buildSource(e,t){this.discoveredRoutes=[];let r=[],a=[];for(let[n,o]of e.entries()){let i=`routeModule_${n}`,d=this.toImportSpecifier(o,t.outputDir);r.push(`import * as ${i} from ${JSON.stringify(d)};`),a.push(` registerModule(${i});`);let l=At(t.routesDir,o).replace(/\.(ts|js)$/,"").split(St).join("/");this.discoveredRoutes.push({method:"*",path:`/${l}`})}return`// Checkpoint entrypoint \u2014 auto-generated for version ${t.version}
|
|
5
|
+
// DO NOT EDIT: This file is generated by Vector checkpoint publish.
|
|
6
|
+
|
|
7
|
+
${r.join(`
|
|
8
|
+
`)}
|
|
9
|
+
|
|
10
|
+
const socketPath = process.env.VECTOR_CHECKPOINT_SOCKET ?? '${t.socketPath}';
|
|
11
|
+
const checkpointContextHeader = 'x-vector-checkpoint-context';
|
|
12
|
+
|
|
13
|
+
// Route registration helper
|
|
14
|
+
type RouteDefinition = {
|
|
15
|
+
entry: { method: string; path: string };
|
|
16
|
+
options: { method: string; path: string; [key: string]: any };
|
|
17
|
+
handler: (ctx: any) => any;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
function isRouteDefinition(value: unknown): value is RouteDefinition {
|
|
21
|
+
return (
|
|
22
|
+
value !== null &&
|
|
23
|
+
typeof value === 'object' &&
|
|
24
|
+
'entry' in value &&
|
|
25
|
+
'options' in value &&
|
|
26
|
+
'handler' in value &&
|
|
27
|
+
typeof (value as any).handler === 'function'
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const routeTable: Record<string, Record<string, (req: Request) => Response | Promise<Response>>> = {};
|
|
32
|
+
|
|
33
|
+
function parseCheckpointContext(req: Request): Record<string, unknown> {
|
|
34
|
+
const encoded = req.headers.get(checkpointContextHeader);
|
|
35
|
+
if (!encoded) {
|
|
36
|
+
return {};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
const json = Buffer.from(encoded, 'base64url').toString('utf-8');
|
|
41
|
+
const parsed = JSON.parse(json);
|
|
42
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
43
|
+
return {};
|
|
44
|
+
}
|
|
45
|
+
return parsed as Record<string, unknown>;
|
|
46
|
+
} catch {
|
|
47
|
+
return {};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function parseQuery(url: URL): Record<string, string | string[]> {
|
|
52
|
+
const query: Record<string, string | string[]> = {};
|
|
53
|
+
for (const [key, value] of url.searchParams) {
|
|
54
|
+
if (key in query) {
|
|
55
|
+
const existing = query[key];
|
|
56
|
+
if (Array.isArray(existing)) {
|
|
57
|
+
existing.push(value);
|
|
58
|
+
} else {
|
|
59
|
+
query[key] = [existing as string, value];
|
|
60
|
+
}
|
|
61
|
+
} else {
|
|
62
|
+
query[key] = value;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return query;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function parseCookies(cookieHeader: string | null): Record<string, string> {
|
|
69
|
+
const cookies: Record<string, string> = {};
|
|
70
|
+
if (!cookieHeader) {
|
|
71
|
+
return cookies;
|
|
72
|
+
}
|
|
73
|
+
for (const pair of cookieHeader.split(';')) {
|
|
74
|
+
const idx = pair.indexOf('=');
|
|
75
|
+
if (idx > 0) {
|
|
76
|
+
cookies[pair.slice(0, idx).trim()] = pair.slice(idx + 1).trim();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return cookies;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function extractRouteParams(req: Request): Record<string, string> {
|
|
83
|
+
const nativeParams = (req as Request & { params?: Record<string, string> }).params;
|
|
84
|
+
if (nativeParams && typeof nativeParams === 'object' && !Array.isArray(nativeParams)) {
|
|
85
|
+
return nativeParams;
|
|
86
|
+
}
|
|
87
|
+
return {};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function createContext(req: Request): Record<string, unknown> {
|
|
91
|
+
const ctx: Record<string, unknown> = Object.create(null);
|
|
92
|
+
setContextField(ctx, 'request', req);
|
|
93
|
+
|
|
94
|
+
// Initialize always-present VectorContext fields with defaults derived from the request
|
|
95
|
+
setContextField(ctx, 'params', extractRouteParams(req));
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
setContextField(ctx, 'query', parseQuery(new URL(req.url)));
|
|
99
|
+
} catch {
|
|
100
|
+
setContextField(ctx, 'query', {});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
setContextField(ctx, 'cookies', parseCookies(req.headers.get('cookie')));
|
|
104
|
+
setContextField(ctx, 'metadata', {});
|
|
105
|
+
|
|
106
|
+
const checkpointContext = parseCheckpointContext(req);
|
|
107
|
+
const allowedCheckpointKeys = ['metadata', 'content', 'validatedInput', 'authUser'] as const;
|
|
108
|
+
for (const key of allowedCheckpointKeys) {
|
|
109
|
+
if (!Object.prototype.hasOwnProperty.call(checkpointContext, key)) {
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
const value = checkpointContext[key];
|
|
113
|
+
setContextField(ctx, key, value);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return ctx;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function setContextField(target: Record<string, unknown>, key: string, value: unknown) {
|
|
120
|
+
const ownDescriptor = Object.getOwnPropertyDescriptor(target as object, key);
|
|
121
|
+
if (ownDescriptor && ownDescriptor.writable === false && typeof ownDescriptor.set !== 'function') {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
try {
|
|
126
|
+
target[key] = value;
|
|
127
|
+
return;
|
|
128
|
+
} catch {
|
|
129
|
+
// Fall back to own-property define when inherited Request field is readonly.
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
try {
|
|
133
|
+
Object.defineProperty(target, key, {
|
|
134
|
+
value,
|
|
135
|
+
writable: true,
|
|
136
|
+
configurable: true,
|
|
137
|
+
enumerable: true,
|
|
138
|
+
});
|
|
139
|
+
} catch {
|
|
140
|
+
// Ignore non-extensible context edge cases.
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function addToRouteTable(method: string, path: string, handler: (ctx: any) => any) {
|
|
145
|
+
if (!routeTable[path]) {
|
|
146
|
+
routeTable[path] = Object.create(null);
|
|
147
|
+
}
|
|
148
|
+
routeTable[path][method.toUpperCase()] = async (req: Request) => {
|
|
149
|
+
const ctx = createContext(req);
|
|
150
|
+
const result = await handler(ctx);
|
|
151
|
+
if (result instanceof Response) return result;
|
|
152
|
+
return Response.json(result);
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function registerModule(mod: Record<string, unknown>) {
|
|
157
|
+
for (const [name, value] of Object.entries(mod)) {
|
|
158
|
+
if (isRouteDefinition(value)) {
|
|
159
|
+
addToRouteTable(value.options.method, value.options.path, value.handler);
|
|
160
|
+
} else if (name === 'default' && typeof value === 'function') {
|
|
161
|
+
// Default export functions need path context \u2014 skip for now
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
${a.join(`
|
|
167
|
+
`)}
|
|
168
|
+
|
|
169
|
+
// Health check endpoint for parent process
|
|
170
|
+
routeTable['/_vector/health'] = {
|
|
171
|
+
GET: () => Response.json({ status: 'ok', version: '${t.version}' }),
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
const server = Bun.serve({
|
|
175
|
+
unix: socketPath,
|
|
176
|
+
routes: routeTable,
|
|
177
|
+
fetch(req: Request) {
|
|
178
|
+
return Response.json(
|
|
179
|
+
{ error: true, message: 'Not Found', statusCode: 404 },
|
|
180
|
+
{ status: 404 }
|
|
181
|
+
);
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
// Signal readiness to parent process
|
|
186
|
+
process.stdout.write('READY\\n');
|
|
187
|
+
`}toImportSpecifier(e,t){let r=At(t,e).split(St).join("/");if(r.startsWith(".")||r.startsWith("/"))return r;return`./${r}`}}var Rt=()=>{};import{promises as Te}from"fs";import{join as Q,relative as Ce}from"path";class Le{storageDir;codec;constructor(e,t="gzip"){this.storageDir=e,this.codec=t}async packageVersion(e){let t=Q(this.storageDir,e),r=Q(Ht,`${e}${this.archiveSuffix()}`).replace(/\\/g,"/"),a=Q(this.storageDir,r);await Te.mkdir(Q(this.storageDir,Ht),{recursive:!0});let n=await ua(t),o=await this.buildArchiveBytes(t,a,n);return{archivePath:r,archiveHash:T(o),archiveSize:o.byteLength,codec:this.codec}}async buildArchiveBytes(e,t,r){let a=Bun.Archive;if(typeof a==="function"){let o=Object.fromEntries(r.map((c)=>{return[Ce(e,c).replace(/\\/g,"/"),Bun.file(c)]})),i=new a(o),d=new Uint8Array(await i.bytes()),l=this.codec==="gzip"?Bun.gzipSync(d):d;return await Bun.write(t,l),l}await this.buildArchiveWithTar(e,t,r);let n=await Te.readFile(t);return new Uint8Array(n.buffer,n.byteOffset,n.byteLength)}async buildArchiveWithTar(e,t,r){let a=r.map((l)=>Ce(e,l));if(a.length===0)throw new Error(`Cannot package checkpoint: no files found in "${e}"`);let n=this.codec==="gzip"?["-czf",t]:["-cf",t],o=Bun.spawn(["tar",...n,"-C",e,...a],{stdout:"pipe",stderr:"pipe"}),i=await o.exited;if(i===0)return;let d=await new Response(o.stderr).text();throw new Error(`Failed to package checkpoint archive with tar (exit ${i}): ${d.trim()}`)}archiveSuffix(){return this.codec==="gzip"?".tar.gz":".tar"}}async function ua(e){let t=[];return await Ot(e,t),t.filter((r)=>Ce(e,r).replace(/\\/g,"/")!=="manifest.json")}async function Ot(e,t){let r=await Te.readdir(e,{withFileTypes:!0});for(let a of r){let n=Q(e,a.name);if(a.isDirectory()){await Ot(n,t);continue}if(a.isFile())t.push(n)}}var Ht="_archives";var Dt=()=>{};import{createHash as ha}from"crypto";import{tmpdir as fa}from"os";import{isAbsolute as ga,join as Ne,resolve as ya}from"path";function jt(e){return ga(e)?e:ya(e)}function $t(e){return Buffer.byteLength(e,"utf8")<=xa}function va(e,t){let r=t.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/(^-+|-+$)/g,"").slice(0,12),a=ha("sha256").update(e).update("\x00").update(t).digest("hex").slice(0,16);return`vector-${r.length>0?`${r}-`:""}${a}.sock`}function Ea(){let e=new Set,t=process.env.VECTOR_CHECKPOINT_SOCKET_DIR?.trim();if(t)e.add(jt(t));if(process.platform!=="win32")e.add("/tmp"),e.add("/private/tmp");return e.add(jt(fa())),[...e]}function K(e,t){let r=Ne(e,t,wa);if(process.platform==="win32"||$t(r))return r;let a=va(e,t);for(let n of Ea()){let o=Ne(n,a);if($t(o))return o}return Ne("/tmp",a)}var wa="run.sock",xa=103;var Ae=()=>{};var Pt={};P(Pt,{CheckpointManager:()=>Mt});import{existsSync as M,promises as B}from"fs";import{join as D,resolve as _t}from"path";function Ba(e){if(e.codec)return e.codec;return(e.blobPath??e.storedPath??"").trim().toLowerCase().endsWith(".gz")?"gzip":"none"}class Mt{storageDir;maxCheckpoints;constructor(e={}){this.storageDir=_t(process.cwd(),e.storageDir??ka),this.maxCheckpoints=e.maxCheckpoints??10}getStorageDir(){return this.storageDir}versionDir(e){return D(this.storageDir,e)}socketPath(e){return K(this.storageDir,e)}async ensureStorageDir(){await B.mkdir(this.storageDir,{recursive:!0})}async publish(e){await this.ensureStorageDir();let t=this.versionDir(e.version);await B.mkdir(t,{recursive:!0});let r=new Ie,a=await r.generate({version:e.version,outputDir:t,routesDir:_t(process.cwd(),e.routesDir),socketPath:this.socketPath(e.version)}),o=await new ke().bundle({entrypointPath:a,outputDir:t}),i=new Ee(this.storageDir),d=await i.collect(e.embeddedAssetPaths??[],e.sidecarAssetPaths??[]);i.validateBudgets(d);let l={formatVersion:ge,version:e.version,createdAt:new Date().toISOString(),entrypoint:"checkpoint.js",routes:r.getDiscoveredRoutes(),assets:d,bundleHash:o.hash,bundleSize:o.size,checkpointArchivePath:void 0,checkpointArchiveHash:void 0,checkpointArchiveSize:void 0,checkpointArchiveCodec:void 0};await this.writeManifest(e.version,l);try{await B.unlink(a)}catch{}let m=await new Le(this.storageDir).packageVersion(e.version);return l.checkpointArchivePath=m.archivePath,l.checkpointArchiveHash=m.archiveHash,l.checkpointArchiveSize=m.archiveSize,l.checkpointArchiveCodec=m.codec,await this.writeManifest(e.version,l),await this.pruneOld(),l}async readManifest(e){let t=D(this.versionDir(e),"manifest.json"),r=await B.readFile(t,"utf-8");return this.normalizeManifest(JSON.parse(r))}async writeManifest(e,t){let r=D(this.versionDir(e),"manifest.json");await B.writeFile(r,JSON.stringify(t,null,2),"utf-8")}async listVersions(){if(!M(this.storageDir))return[];let e=await B.readdir(this.storageDir),t=[];for(let r of e){let a=D(this.storageDir,r,"manifest.json");if(M(a))try{let n=await B.readFile(a,"utf-8");t.push(this.normalizeManifest(JSON.parse(n)))}catch{}}return t.sort((r,a)=>new Date(a.createdAt).getTime()-new Date(r.createdAt).getTime()),t}async getActive(){let e=D(this.storageDir,Ut);if(!M(e))return null;try{let t=await B.readFile(e,"utf-8");return JSON.parse(t)}catch{return null}}async setActive(e){let t=this.versionDir(e);if(!M(t))throw new Error(`Checkpoint version ${e} does not exist`);let r=D(t,"manifest.json");if(!M(r))throw new Error(`Checkpoint version ${e} has no manifest`);await this.ensureStorageDir();let a={version:e,activatedAt:new Date().toISOString()},n=D(this.storageDir,Ut);await B.writeFile(n,JSON.stringify(a,null,2),"utf-8")}async remove(e){if((await this.getActive())?.version===e)throw new Error(`Cannot remove active checkpoint version ${e}. Rollback to a different version first.`);let r=this.versionDir(e);if(!M(r))throw new Error(`Checkpoint version ${e} does not exist`);await B.rm(r,{recursive:!0,force:!0})}async pruneOld(){if(this.maxCheckpoints<=0)return;let e=await this.listVersions();if(e.length<=this.maxCheckpoints)return;let t=await this.getActive(),r=e.slice(this.maxCheckpoints);for(let a of r){if(t?.version===a.version)continue;try{let n=this.versionDir(a.version);await B.rm(n,{recursive:!0,force:!0})}catch{}}}normalizeManifest(e){let t=(e.assets??[]).map((r)=>({...r,contentHash:r.contentHash??r.hash,contentSize:r.contentSize??r.size,blobPath:r.blobPath??r.storedPath,blobHash:r.blobHash,blobSize:r.blobSize,codec:Ba(r)}));return{formatVersion:e.formatVersion??ge,version:e.version??"unknown",createdAt:e.createdAt??new Date(0).toISOString(),entrypoint:e.entrypoint??"checkpoint.js",routes:e.routes??[],assets:t,bundleHash:e.bundleHash??"",bundleSize:e.bundleSize??0,checkpointArchivePath:e.checkpointArchivePath,checkpointArchiveHash:e.checkpointArchiveHash,checkpointArchiveSize:e.checkpointArchiveSize,checkpointArchiveCodec:e.checkpointArchiveCodec}}}var ka=".vector/checkpoints",Ut="active.json";var zt=E(()=>{Tt();Lt();Rt();Dt();Ae()});function Ia(e){let t=e.trim();if(!t)return null;if(t==="READY")return{type:"ready"};try{return JSON.parse(t)}catch{return null}}async function Jt(e,t=1e4){return new Promise((r,a)=>{let n=!1,o=e.getReader(),i=new TextDecoder,d="";function l(p){if(n)return;n=!0,clearTimeout(c);try{o.releaseLock()}catch{}p()}let c=setTimeout(()=>{l(()=>a(new Error(`Checkpoint process did not become ready within ${t}ms`)))},t),m=(p)=>{let h=Ia(p);if(h?.type==="ready")return l(()=>r()),"ready";if(h?.type==="error")return l(()=>a(new Error(`Checkpoint process error: ${h.message}`))),"error";return"continue"},s=()=>{let p=d.indexOf(`
|
|
188
|
+
`);while(p!==-1){let h=d.slice(0,p);d=d.slice(p+1);let u=m(h);if(u!=="continue")return u;p=d.indexOf(`
|
|
189
|
+
`)}return"continue"};(async()=>{try{while(!0){let{done:p,value:h}=await o.read();if(p){d+=i.decode();let f=d.trim();if(f.length>0){if(m(f)!=="continue")return}l(()=>a(new Error("Checkpoint process stdout closed before READY signal")));return}if(d+=i.decode(h,{stream:!0}),d.length>1048576){l(()=>a(new Error("Checkpoint process stdout exceeded 1048576 chars before READY")));return}if(s()!=="continue")return}}catch(p){l(()=>a(p))}})()})}import{availableParallelism as Ta,cpus as Ca}from"os";class Se{workers=[];idleWorkers=[];queue=[];activeJobsByWorker=new Map;nextJobId=1;disposed=!1;constructor(e=Na()){let t=Sa(e),r=Ra();for(let a=0;a<t;a++){let n=new Worker(r.href);n.onmessage=(o)=>this.handleWorkerMessage(n,o),n.onerror=(o)=>this.handleWorkerError(n,o),this.workers.push(n),this.idleWorkers.push(n)}}async decompress(e,t){if(t==="none")return new Uint8Array(e);if(this.disposed)throw new Error("Checkpoint worker decompressor is disposed");let r=new Uint8Array(e);return await new Promise((a,n)=>{let o=this.nextJobId++;this.queue.push({id:o,request:{id:o,codec:t,input:r.buffer},resolve:a,reject:n}),this.pump()})}async dispose(){if(this.disposed)return;this.disposed=!0;let e=new Error("Checkpoint worker decompressor disposed");this.failAll(e);for(let t of this.workers)try{t.terminate()}catch{}this.workers=[],this.idleWorkers=[],this.activeJobsByWorker.clear()}pump(){while(this.idleWorkers.length>0&&this.queue.length>0){let e=this.idleWorkers.pop(),t=this.queue.shift();this.activeJobsByWorker.set(e,t),e.postMessage(t.request,[t.request.input])}}handleWorkerMessage(e,t){let r=this.activeJobsByWorker.get(e);if(this.activeJobsByWorker.delete(e),!this.disposed)this.idleWorkers.push(e);if(!r){this.pump();return}let a=t.data;if(a.error)r.reject(new Error(a.error));else if(a.output instanceof ArrayBuffer)r.resolve(new Uint8Array(a.output));else r.reject(new Error("Worker returned no output"));this.pump()}handleWorkerError(e,t){let r=this.activeJobsByWorker.get(e);this.activeJobsByWorker.delete(e),this.idleWorkers=this.idleWorkers.filter((o)=>o!==e);let a=t.message?.trim()||"Checkpoint decompression worker crashed",n=new Error(a);if(r)r.reject(n);this.failAll(n),this.dispose().catch(()=>{})}failAll(e){let t=this.queue.splice(0,this.queue.length);for(let r of t)r.reject(e);for(let r of this.activeJobsByWorker.values())r.reject(e);this.activeJobsByWorker.clear()}}function Na(){let e=Aa(),t=Math.max(1,e-1);return Math.max(1,Math.min(La,t))}function Aa(){try{let t=Ta();if(Number.isFinite(t)&&t>0)return t}catch{}let e=Ca().length;return Number.isFinite(e)&&e>0?e:1}function Sa(e){if(!Number.isFinite(e)||e<=0)return 1;return Math.max(1,Math.floor(e))}function Ra(){if(import.meta.url.endsWith(".ts"))return new URL("./decompress-worker.ts",import.meta.url);return new URL("./decompress-worker.js",import.meta.url)}var La=4;var Ft=()=>{};import{existsSync as ee,promises as g}from"fs";import{dirname as Gt,extname as Ha,join as C,relative as Oa}from"path";class Re{verifyChecksums;materializedDirName;lockTimeoutMs;constructor(e={}){this.verifyChecksums=e.verifyChecksums??!0,this.materializedDirName=e.materializedDirName??Da,this.lockTimeoutMs=e.lockTimeoutMs??ja}async materialize(e,t){let r=C(t,e.version),a=C(r,".assets.ready.json"),n=C(r,".assets.lock"),o=vt(e.assets);if(await this.isReady(a,o,e.assets,C(r,this.materializedDirName)))return;await this.acquireLock(n);try{if(await this.isReady(a,o,e.assets,C(r,this.materializedDirName)))return;let i=C(r,this.materializedDirName);await g.rm(i,{recursive:!0,force:!0}),await g.mkdir(i,{recursive:!0});let d=new Se;try{for(let c of e.assets){let m=await this.materializeAsset(c,t,r,i,d);c.materializedPath=m}}finally{await d.dispose()}let l={fingerprint:o,createdAt:new Date().toISOString()};await g.writeFile(a,JSON.stringify(l,null,2),"utf-8")}finally{await g.rm(n,{recursive:!0,force:!0})}}async materializeAsset(e,t,r,a,n){let o=this.resolveSourcePath(e,t);if(!ee(o))throw new Error(`Checkpoint asset blob not found: ${o}`);let i=await g.readFile(o),d=new Uint8Array(i.buffer,i.byteOffset,i.byteLength),l=e.blobHash;if(this.verifyChecksums&&l&&T(d)!==l)throw new Error(`Checkpoint asset blob checksum mismatch for ${e.logicalPath}`);let c=e.codec??(e.blobHash?"gzip":"none"),m=await n.decompress(d,c),s=e.contentHash??e.hash;if(this.verifyChecksums&&s&&T(m)!==s)throw new Error(`Checkpoint asset content checksum mismatch for ${e.logicalPath}`);let p=await this.writeDecompressedCache(e,t,m),h=Y(e.logicalPath),u=C(a,h);return await g.mkdir(Gt(u),{recursive:!0}),await g.rm(u,{force:!0}),await this.linkWithFallback(p,u),_a(Oa(r,u))}async writeDecompressedCache(e,t,r){let a=e.contentHash??e.hash,n=Ha(e.logicalPath)||".bin",o=C(t,"_assets/cache",`${a}${n}`);if(await g.mkdir(Gt(o),{recursive:!0}),ee(o)){if(!this.verifyChecksums)return o;let i=await g.readFile(o),d=new Uint8Array(i.buffer,i.byteOffset,i.byteLength);if(T(d)===a)return o}return await g.writeFile(o,r),o}resolveSourcePath(e,t){let r=e.blobPath??e.storedPath;if(ye(r))return r;return C(t,r)}async linkWithFallback(e,t){try{await g.link(e,t);return}catch{}try{await g.symlink(e,t);return}catch{}await g.copyFile(e,t)}async acquireLock(e){let t=Date.now()+this.lockTimeoutMs;while(Date.now()<t){try{await g.mkdir(e);return}catch(r){if(!Ua(r))throw r}await Ma($a)}throw new Error(`Timed out waiting for checkpoint asset lock: ${e}`)}async isReady(e,t,r,a){if(!ee(e))return!1;try{if(JSON.parse(await g.readFile(e,"utf-8")).fingerprint!==t)return!1;for(let o of r){let i=C(a,Y(o.logicalPath));if(!ee(i))return!1}return!0}catch{return!1}}}function _a(e){return e.replace(/\\/g,"/")}function Ua(e){return typeof e==="object"&&e!==null&&"code"in e&&e.code==="EEXIST"}function Ma(e){return new Promise((t)=>setTimeout(t,e))}var Da="_materialized",ja=15000,$a=50;var Yt=E(()=>{we();Ft()});var qt={};P(qt,{CheckpointProcessManager:()=>Zt});import{existsSync as Qt,promises as Pa,unlinkSync as za}from"fs";import{dirname as Ja,join as Vt}from"path";class Zt{running=new Map;pending=new Map;readyTimeoutMs;idleTimeoutMs;idleTimers=new Map;lastUsedAt=new Map;materializer;constructor(e=Wt){if(typeof e==="number")this.readyTimeoutMs=e,this.idleTimeoutMs=Xt;else this.readyTimeoutMs=e.readyTimeoutMs??Wt,this.idleTimeoutMs=e.idleTimeoutMs??Xt;this.materializer=new Re}async spawn(e,t){if(this.running.has(e.version))return this.running.get(e.version);if(this.pending.has(e.version))return this.pending.get(e.version);let r=this.doSpawn(e,t);this.pending.set(e.version,r);try{return await r}finally{this.pending.delete(e.version)}}async doSpawn(e,t){let r=Vt(t,e.version),a=Vt(r,e.entrypoint),n=K(t,e.version);if(!Qt(a))throw new Error(`Checkpoint bundle not found: ${a}`);await this.materializer.materialize(e,t),await Pa.mkdir(Ja(n),{recursive:!0}),this.tryUnlinkSocket(n);let o=Bun.spawn(["bun","run",a],{env:{...process.env,VECTOR_CHECKPOINT_SOCKET:n,VECTOR_CHECKPOINT_VERSION:e.version},stdout:"pipe",stderr:"inherit"});if(!o.stdout)throw o.kill("SIGTERM"),new Error(`Checkpoint process for ${e.version} did not provide stdout`);try{await Jt(o.stdout,this.readyTimeoutMs)}catch(d){throw o.kill("SIGTERM"),d}let i={version:e.version,socketPath:n,process:o,pid:o.pid};return this.running.set(e.version,i),this.lastUsedAt.set(e.version,Date.now()),this.scheduleIdleCheck(e.version),i}markUsed(e){if(!this.running.has(e))return;this.lastUsedAt.set(e,Date.now())}async stop(e){let t=this.running.get(e);if(!t)return;if(this.running.delete(e),this.clearIdleTimer(e),this.lastUsedAt.delete(e),t.process.kill("SIGTERM"),!await Promise.race([t.process.exited.then(()=>!0),new Promise((a)=>setTimeout(()=>a(!1),Fa))]))try{t.process.kill("SIGKILL"),await t.process.exited}catch{}this.tryUnlinkSocket(t.socketPath)}async stopAll(){let e=[...this.running.keys()];for(let t of e)await this.stop(t)}isRunning(e){return this.running.has(e)}getRunning(e){return this.running.get(e)}async health(e){let t=this.running.get(e);if(!t)return!1;try{return(await fetch("http://localhost/_vector/health",{unix:t.socketPath,signal:AbortSignal.timeout(2000)})).ok}catch{return!1}}getRunningVersions(){return[...this.running.keys()]}scheduleIdleCheck(e,t=this.idleTimeoutMs){if(this.clearIdleTimer(e),this.idleTimeoutMs<=0)return;let r=setTimeout(()=>{this.handleIdleCheck(e)},Math.max(1,t));if(typeof r.unref==="function")r.unref();this.idleTimers.set(e,r)}async handleIdleCheck(e){if(!this.running.has(e))return;let t=this.lastUsedAt.get(e)??0,r=Date.now()-t,a=this.idleTimeoutMs-r;if(a>0){this.scheduleIdleCheck(e,a);return}try{await this.stop(e)}catch(n){console.error(`[CheckpointProcessManager] Failed to stop idle checkpoint ${e}:`,n)}}clearIdleTimer(e){let t=this.idleTimers.get(e);if(!t)return;clearTimeout(t),this.idleTimers.delete(e)}tryUnlinkSocket(e){try{if(Qt(e))za(e)}catch{}}}var Wt=1e4,Xt=600000,Fa=5000;var Kt=E(()=>{Yt();Ae()});var tr={};P(tr,{CheckpointResolver:()=>er});class er{manager;processManager;versionHeader;cacheKeyOverride;allowFallbackVersionHeader;pendingVersionResolves=new Map;constructor(e,t,r={}){this.manager=e,this.processManager=t,this.versionHeader=Ga(r.versionHeader??"x-vector-checkpoint-version"),this.cacheKeyOverride=r.cacheKeyOverride===!0,this.allowFallbackVersionHeader=r.versionHeader===void 0}async resolve(e){let t=this.getRequestedVersion(e);if(!t)return null;return await this.resolveVersion(t)}getRequestedVersion(e){return this.getRequestedHeader(e)?.value??null}getCacheKeyOverrideValue(e){if(!this.cacheKeyOverride)return null;let t=this.getRequestedHeader(e);if(!t)return null;return`${t.name}:${t.value}`}getRequestedHeader(e){let t=e.headers.get(this.versionHeader);if(t&&t.trim().length>0)return{name:this.versionHeader,value:t.trim()};if(this.allowFallbackVersionHeader&&this.versionHeader!=="x-vector-checkpoint"){let r=e.headers.get("x-vector-checkpoint");if(r&&r.trim().length>0)return{name:"x-vector-checkpoint",value:r.trim()}}return null}async resolveVersion(e){let t=this.processManager.getRunning(e);if(!t){let r=this.pendingVersionResolves.get(e);if(r){let o=await r;if(!o)return null;return this.processManager.markUsed(e),o}let a=(async()=>{try{let o=await this.manager.readManifest(e);return(await this.processManager.spawn(o,this.manager.getStorageDir())).socketPath}catch{return null}})();this.pendingVersionResolves.set(e,a);let n=await a;if(this.pendingVersionResolves.delete(e),!n)return null;return this.processManager.markUsed(e),n}return this.processManager.markUsed(e),t.socketPath}invalidateCache(){}}function Ga(e){let t=e.trim().toLowerCase();return t.length>0?t:"x-vector-checkpoint-version"}var ar={};P(ar,{CheckpointForwarder:()=>rr,CHECKPOINT_CONTEXT_HEADER:()=>Ya});class rr{async forward(e,t,r){try{let a=Wa(r),n=Qa(e.headers,a),o=await fetch(e.url,{method:e.method,headers:n,body:e.body,unix:t,duplex:e.body?"half":void 0});return new Response(o.body,{status:o.status,statusText:o.statusText,headers:new Headers(o.headers)})}catch(a){return console.error("[CheckpointForwarder] Forward failed:",a),new Response(JSON.stringify({error:!0,message:"Checkpoint unavailable",statusCode:503}),{status:503,headers:{"content-type":"application/json"}})}}}function Qa(e,t){let r=new Headers(e);if(Va(r),t)r.set("x-vector-checkpoint-context",t);return r}function Va(e){let t=e.get("connection");if(t)for(let r of t.split(",")){let a=r.trim().toLowerCase();if(a)e.delete(a)}e.delete("connection"),e.delete("keep-alive"),e.delete("proxy-authenticate"),e.delete("proxy-authorization"),e.delete("te"),e.delete("trailer"),e.delete("transfer-encoding"),e.delete("upgrade")}function Wa(e){if(!e)return null;if(Object.keys(e).length===0)return null;try{return Buffer.from(JSON.stringify(e),"utf-8").toString("base64url")}catch{return null}}var Ya="x-vector-checkpoint-context";var or={};P(or,{CheckpointGateway:()=>nr});class nr{resolver;forwarder;constructor(e,t){this.resolver=e,this.forwarder=t}getRequestedVersion(e){return this.resolver.getRequestedVersion(e)}getCacheKeyOverrideValue(e){return this.resolver.getCacheKeyOverrideValue(e)}async handle(e,t){let r=this.getRequestedVersion(e),a=await this.resolver.resolve(e);if(!a){if(r)return new Response(JSON.stringify({error:!0,message:`Requested checkpoint version "${r}" is unavailable`,statusCode:503}),{status:503,headers:{"content-type":"application/json"}});return null}return await this.forwarder.forward(e,a,t)}}var A={OK:200,CREATED:201,ACCEPTED:202,NON_AUTHORITATIVE_INFORMATION:203,NO_CONTENT:204,RESET_CONTENT:205,PARTIAL_CONTENT:206,MULTI_STATUS:207,ALREADY_REPORTED:208,IM_USED:226,MULTIPLE_CHOICES:300,MOVED_PERMANENTLY:301,FOUND:302,SEE_OTHER:303,NOT_MODIFIED:304,USE_PROXY:305,TEMPORARY_REDIRECT:307,PERMANENT_REDIRECT:308,BAD_REQUEST:400,UNAUTHORIZED:401,PAYMENT_REQUIRED:402,FORBIDDEN:403,NOT_FOUND:404,METHOD_NOT_ALLOWED:405,NOT_ACCEPTABLE:406,PROXY_AUTHENTICATION_REQUIRED:407,REQUEST_TIMEOUT:408,CONFLICT:409,GONE:410,LENGTH_REQUIRED:411,PRECONDITION_FAILED:412,PAYLOAD_TOO_LARGE:413,URI_TOO_LONG:414,UNSUPPORTED_MEDIA_TYPE:415,RANGE_NOT_SATISFIABLE:416,EXPECTATION_FAILED:417,IM_A_TEAPOT:418,MISDIRECTED_REQUEST:421,UNPROCESSABLE_ENTITY:422,LOCKED:423,FAILED_DEPENDENCY:424,TOO_EARLY:425,UPGRADE_REQUIRED:426,PRECONDITION_REQUIRED:428,TOO_MANY_REQUESTS:429,REQUEST_HEADER_FIELDS_TOO_LARGE:431,UNAVAILABLE_FOR_LEGAL_REASONS:451,INTERNAL_SERVER_ERROR:500,NOT_IMPLEMENTED:501,BAD_GATEWAY:502,SERVICE_UNAVAILABLE:503,GATEWAY_TIMEOUT:504,HTTP_VERSION_NOT_SUPPORTED:505,VARIANT_ALSO_NEGOTIATES:506,INSUFFICIENT_STORAGE:507,LOOP_DETECTED:508,NOT_EXTENDED:510,NETWORK_AUTHENTICATION_REQUIRED:511},$={PORT:3000,HOSTNAME:"localhost",ROUTES_DIR:"./routes",CACHE_TTL:0,CORS_MAX_AGE:86400},z={JSON:"application/json",TEXT:"text/plain",HTML:"text/html",FORM_URLENCODED:"application/x-www-form-urlencoded",MULTIPART:"multipart/form-data"};var je={NOT_FOUND:new Response(JSON.stringify({error:!0,message:"Not Found",statusCode:404}),{status:404,headers:{"content-type":"application/json"}})};class te{protectedHandler=null;setProtectedHandler(e){this.protectedHandler=e}clearProtectedHandler(){this.protectedHandler=null}async authenticate(e){if(!this.protectedHandler)throw new Error("Protected handler not configured. Use vector.protected() to set authentication handler.");if(!e||typeof e!=="object"||!e.request)throw new Error("Authentication context is invalid: missing request");try{let t=await this.protectedHandler(e);return e.authUser=t,t}catch(t){throw new Error(`Authentication failed: ${t instanceof Error?t.message:String(t)}`)}}isAuthenticated(e){return!!e.authUser}getUser(e){return e.authUser||null}}class re{cacheHandler=null;memoryCache=new Map;cleanupInterval=null;inflight=new Map;setCacheHandler(e){this.cacheHandler=e}clearCacheHandler(){this.cacheHandler=null}async get(e,t,r=$.CACHE_TTL){if(r<=0)return t();if(this.cacheHandler)return this.cacheHandler(e,t,r);return this.getFromMemoryCache(e,t,r)}async getFromMemoryCache(e,t,r){let a=Date.now(),n=this.memoryCache.get(e);if(this.isCacheValid(n,a))return this.cloneCachedValue(n.value);if(this.inflight.has(e)){let i=await this.inflight.get(e);return this.cloneCachedValue(i)}let o=(async()=>{let i=await t();return this.setInMemoryCache(e,i,r),i})();this.inflight.set(e,o);try{return await o}finally{this.inflight.delete(e)}}isCacheValid(e,t){return e!==void 0&&e.expires>t}setInMemoryCache(e,t,r){let a=Date.now()+r*1000;this.memoryCache.set(e,{value:this.cloneForStore(t),expires:a}),this.scheduleCleanup()}cloneForStore(e){if(e instanceof Response)return e.clone();return e}cloneCachedValue(e){if(e instanceof Response)return e.clone();return e}scheduleCleanup(){if(this.cleanupInterval)return;let e=setInterval(()=>{this.cleanupExpired()},60000);if(typeof e.unref==="function")e.unref();this.cleanupInterval=e}cleanupExpired(){let e=Date.now();for(let[t,r]of this.memoryCache.entries())if(r.expires<=e)this.memoryCache.delete(t);if(this.memoryCache.size===0&&this.cleanupInterval)clearInterval(this.cleanupInterval),this.cleanupInterval=null}clear(){if(this.memoryCache.clear(),this.cleanupInterval)clearInterval(this.cleanupInterval),this.cleanupInterval=null}async set(e,t,r=$.CACHE_TTL){if(r<=0)return;if(this.cacheHandler){await this.cacheHandler(e,async()=>t,r);return}this.setInMemoryCache(e,t,r)}delete(e){return this.memoryCache.delete(e)}has(e){let t=this.memoryCache.get(e);if(!t)return!1;if(t.expires<=Date.now())return this.memoryCache.delete(e),!1;return!0}generateKey(e,t){let r=e._parsedUrl??new URL(e.url),a=t?.authUser?.id!=null?String(t.authUser.id):"anonymous";return`${e.method}:${r.pathname}:${r.search}:${a}`}}import{promises as $e}from"fs";import{dirname as _e,relative as lr}from"path";class ae{outputPath;constructor(e="./.vector/routes.generated.ts"){this.outputPath=e}async generate(e){let t=_e(this.outputPath);await $e.mkdir(t,{recursive:!0});let r=[],a=new Map;for(let d of e){if(!a.has(d.path))a.set(d.path,[]);a.get(d.path).push(d)}let n=0,o=[];for(let[d,l]of a){let c=lr(_e(this.outputPath),d).replace(/\\/g,"/").replace(/\.(ts|js)$/,""),m=`route_${n++}`,s=l.filter((p)=>p.name!=="default").map((p)=>p.name);if(l.some((p)=>p.name==="default"))if(s.length>0)r.push(`import ${m}, { ${s.join(", ")} } from '${c}';`);else r.push(`import ${m} from '${c}';`);else if(s.length>0)r.push(`import { ${s.join(", ")} } from '${c}';`);for(let p of l){let h=p.name==="default"?m:p.name;o.push(` ${h},`)}}let i=`// This file is auto-generated. Do not edit manually.
|
|
3
190
|
// Generated at: ${new Date().toISOString()}
|
|
4
191
|
|
|
5
|
-
${
|
|
192
|
+
${r.join(`
|
|
6
193
|
`)}
|
|
7
194
|
|
|
8
195
|
export const routes = [
|
|
@@ -11,15 +198,15 @@ ${o.join(`
|
|
|
11
198
|
];
|
|
12
199
|
|
|
13
200
|
export default routes;
|
|
14
|
-
`;await
|
|
15
|
-
...${
|
|
16
|
-
handler: m.${
|
|
201
|
+
`;await $e.writeFile(this.outputPath,i,"utf-8")}async generateDynamic(e){let t=[];for(let r of e){let a=JSON.stringify({method:r.method,path:r.options.path,options:r.options});t.push(` await import('${r.path}').then(m => ({
|
|
202
|
+
...${a},
|
|
203
|
+
handler: m.${r.name==="default"?"default":r.name}
|
|
17
204
|
}))`)}return`export const loadRoutes = async () => {
|
|
18
205
|
return Promise.all([
|
|
19
206
|
${t.join(`,
|
|
20
207
|
`)}
|
|
21
208
|
]);
|
|
22
|
-
};`}}import{existsSync as Me,promises as de}from"fs";import{join as Ce,relative as ne,resolve as He,sep as re}from"path";class M{routesDir;excludePatterns;static DEFAULT_EXCLUDE_PATTERNS=["*.test.ts","*.test.js","*.test.tsx","*.test.jsx","*.spec.ts","*.spec.js","*.spec.tsx","*.spec.jsx","*.tests.ts","*.tests.js","**/__tests__/**","*.interface.ts","*.type.ts","*.d.ts"];constructor(e="./routes",t){this.routesDir=He(process.cwd(),e),this.excludePatterns=t||M.DEFAULT_EXCLUDE_PATTERNS}async scan(){let e=[];if(!Me(this.routesDir))return[];try{await this.scanDirectory(this.routesDir,e)}catch(t){if(t.code==="ENOENT")return console.warn(` \u2717 Routes directory not accessible: ${this.routesDir}`),[];throw t}return e}isExcluded(e){let t=ne(this.routesDir,e);for(let d of this.excludePatterns){let n=d.replace(/\./g,"\\.").replace(/\*\*/g,"__GLOBSTAR__").replace(/\*/g,"[^/]*").replace(/__GLOBSTAR__/g,".*").replace(/\?/g,"."),r=new RegExp(`^${n}$`),o=t.split(re).pop()||"";if(r.test(t)||r.test(o))return!0}return!1}async scanDirectory(e,t,d=""){let n=await de.readdir(e);for(let r of n){let o=Ce(e,r);if((await de.stat(o)).isDirectory()){let a=d?`${d}/${r}`:r;await this.scanDirectory(o,t,a)}else if(r.endsWith(".ts")||r.endsWith(".js")){if(this.isExcluded(o))continue;let a=ne(this.routesDir,o).replace(/\.(ts|js)$/,"").split(re).join("/");try{let c=await import(process.platform==="win32"?`file:///${o.replace(/\\/g,"/")}`:o);if(c.default&&typeof c.default==="function")t.push({name:"default",path:o,method:"GET",options:{method:"GET",path:`/${a}`,expose:!0}});for(let[m,b]of Object.entries(c)){if(m==="default")continue;if(b&&typeof b==="object"&&"entry"in b&&"options"in b&&"handler"in b){let p=b;t.push({name:m,path:o,method:p.options.method,options:p.options})}else if(Array.isArray(b)&&b.length>=4){let[p,,,x]=b;t.push({name:m,path:o,method:p,options:{method:p,path:x,expose:!0}})}}}catch(s){console.error(`Failed to load route from ${o}:`,s)}}}}enableWatch(e){if(typeof Bun!=="undefined"&&Bun.env.NODE_ENV==="development")console.log(`Watching for route changes in ${this.routesDir}`),setInterval(async()=>{await e()},1000)}}class C{beforeHandlers=[];finallyHandlers=[];addBefore(...e){this.beforeHandlers.push(...e)}addFinally(...e){this.finallyHandlers.push(...e)}async executeBefore(e){if(this.beforeHandlers.length===0)return e;let t=e;for(let d of this.beforeHandlers){let n=await d(t);if(n instanceof Response)return n;t=n}return t}async executeFinally(e,t){if(this.finallyHandlers.length===0)return e;let d=e;for(let n of this.finallyHandlers)try{d=await n(d,t)}catch(r){console.error("After middleware error:",r)}return d}clone(){let e=new C;return e.beforeHandlers=[...this.beforeHandlers],e.finallyHandlers=[...this.finallyHandlers],e}clear(){this.beforeHandlers=[],this.finallyHandlers=[]}}function H(e){return process.platform==="win32"?`file:///${e.replace(/\\/g,"/")}`:e}function P(e){return RegExp(`^${e.replace(/\/+(\/|$)/g,"$1").replace(/(\/?\.?):(\w+)\+/g,"($1(?<$2>[\\s\\S]+))").replace(/(\/?\.?):(\w+)/g,"($1(?<$2>[^$1/]+?))").replace(/\./g,"\\.").replace(/(\/?)\*/g,"($1.*)?")}/*$`)}function oe(e){let t=e?.["~standard"];return!!t&&typeof t==="object"&&typeof t.validate==="function"&&t.version===1}async function ae(e,t){let d=await e["~standard"].validate(t),n=d?.issues;if(Array.isArray(n)&&n.length>0)return{success:!1,issues:n};return{success:!0,value:d?.value}}function ie(e){if(Array.isArray(e))return e;if(e&&typeof e==="object"&&Array.isArray(e.issues))return e.issues;if(e&&typeof e==="object"&&e.cause&&Array.isArray(e.cause.issues))return e.cause.issues;return null}function Oe(e){if(!Array.isArray(e))return[];let t=[];for(let d=0;d<e.length;d++){let n=e[d],r=n;if(n&&typeof n==="object"&&"key"in n)r=n.key;if(typeof r==="string"||typeof r==="number")t.push(r);else if(typeof r==="symbol")t.push(String(r));else if(r!==void 0&&r!==null)t.push(String(r))}return t}function _(e,t){let d=[];for(let n=0;n<e.length;n++){let r=e[n],o=r,i={message:typeof o?.message==="string"&&o.message.length>0?o.message:"Invalid value",path:Oe(o?.path)};if(typeof o?.code==="string")i.code=o.code;if(t)i.raw=r;d.push(i)}return d}function J(e,t){return{error:!0,message:"Validation failed",statusCode:422,source:"validation",target:e,issues:t,timestamp:new Date().toISOString()}}class N{middlewareManager;authManager;cacheManager;routeBooleanDefaults={};developmentMode=void 0;routeDefinitions=[];routeTable=Object.create(null);routeMatchers=[];corsHeadersEntries=null;corsHandler=null;constructor(e,t,d){this.middlewareManager=e,this.authManager=t,this.cacheManager=d}setCorsHeaders(e){this.corsHeadersEntries=e}setCorsHandler(e){this.corsHandler=e}setRouteBooleanDefaults(e){this.routeBooleanDefaults={...e}}setDevelopmentMode(e){this.developmentMode=e}applyRouteBooleanDefaults(e){let t={...e},d=this.routeBooleanDefaults,n=["auth","expose","rawRequest","validate","rawResponse"];for(let r of n)if(t[r]===void 0&&d[r]!==void 0)t[r]=d[r];return t}route(e,t){let d=this.applyRouteBooleanDefaults(e),n=d.method.toUpperCase(),r=d.path,o=this.wrapHandler(d,t),i=this.getOrCreateMethodMap(r);i[n]=o,this.routeDefinitions.push({method:n,path:r,options:d})}addRoute(e){let[t,,d,n]=e;if(!n)return;let r=this.getOrCreateMethodMap(n);r[t.toUpperCase()]=d[0];let o=t.toUpperCase();this.routeDefinitions.push({method:o,path:n,options:{method:o,path:n,expose:!0}})}bulkAddRoutes(e){for(let t of e)this.addRoute(t)}addStaticRoute(e,t){let d=this.routeTable[e];if(d&&!(d instanceof Response))throw new Error(`Cannot register static route for path "${e}" because method routes already exist.`);this.routeTable[e]=t,this.removeRouteMatcher(e)}getRouteTable(){return this.routeTable}getRoutes(){let e=[];for(let t of this.routeMatchers){let d=this.routeTable[t.path];if(!d||d instanceof Response)continue;for(let[n,r]of Object.entries(d))e.push([n,t.regex,[r],t.path])}return e}getRouteDefinitions(){return[...this.routeDefinitions]}clearRoutes(){this.routeTable=Object.create(null),this.routeMatchers=[],this.routeDefinitions=[]}sortRoutes(){}async handle(e){let t;try{t=new URL(e.url)}catch{return v.badRequest("Malformed request URL")}e._parsedUrl=t;let d=t.pathname;for(let n of this.routeMatchers){let r=n.path,o=this.routeTable[r];if(!o)continue;if(o instanceof Response)continue;let i=o;if(e.method==="OPTIONS"||e.method in i){let a=d.match(n.regex);if(a){try{e.params=a.groups??{}}catch{}let s=i[e.method]??i.GET;if(s){let c=await s(e);if(c)return c}}}}return j.NOT_FOUND.clone()}prepareRequest(e,t){if(!e.context)e.context={};let d=!!e.params&&typeof e.params==="object"&&!Array.isArray(e.params)&&Object.keys(e.params).length===0;if(t?.params!==void 0&&(e.params===void 0||d))try{e.params=t.params}catch{}if(t?.route!==void 0)e.route=t.route;if(t?.metadata!==void 0)e.metadata=t.metadata;if(e.query==null&&e.url)try{Object.defineProperty(e,"query",{get(){let n=this._parsedUrl??new URL(this.url),r=N.parseQuery(n);return Object.defineProperty(this,"query",{value:r,writable:!0,configurable:!0,enumerable:!0}),r},set(n){Object.defineProperty(this,"query",{value:n,writable:!0,configurable:!0,enumerable:!0})},configurable:!0,enumerable:!0})}catch{let n=e._parsedUrl??new URL(e.url);try{e.query=N.parseQuery(n)}catch{}}if(!Object.getOwnPropertyDescriptor(e,"cookies"))Object.defineProperty(e,"cookies",{get(){let n=this.headers.get("cookie")??"",r={};if(n)for(let o of n.split(";")){let i=o.indexOf("=");if(i>0)r[o.slice(0,i).trim()]=o.slice(i+1).trim()}return Object.defineProperty(this,"cookies",{value:r,writable:!0,configurable:!0,enumerable:!0}),r},configurable:!0,enumerable:!0})}resolveFallbackParams(e,t){if(!t)return;let d=e.params;if(d&&typeof d==="object"&&!Array.isArray(d)&&Object.keys(d).length>0)return;let n;try{n=(e._parsedUrl??new URL(e.url)).pathname}catch{return}let r=n.match(t);if(!r?.groups)return;return r.groups}wrapHandler(e,t){let d=e.path,n=d.includes(":")?P(d):null;return async(r)=>{let o=r,i=this.resolveFallbackParams(r,n);this.prepareRequest(o,{params:i,route:d,metadata:e.metadata});try{if(e.expose===!1)return v.forbidden("Forbidden");let a=await this.middlewareManager.executeBefore(o);if(a instanceof Response)return a;let s=a;if(e.auth)try{await this.authManager.authenticate(s)}catch(u){return v.unauthorized(u instanceof Error?u.message:"Authentication failed",e.responseContentType)}if(!e.rawRequest&&s.method!=="GET"&&s.method!=="HEAD"){let u=null;try{let f=s.headers.get("content-type");if(f?.startsWith("application/json"))u=await s.json();else if(f?.startsWith("application/x-www-form-urlencoded"))u=Object.fromEntries(await s.formData());else if(f?.startsWith("multipart/form-data"))u=await s.formData();else u=await s.text()}catch{u=null}this.setContentAndBodyAlias(s,u)}let c=await this.validateInputSchema(s,e);if(c)return c;let m,b=e.cache;if(b&&typeof b==="number"&&b>0){let u=this.cacheManager.generateKey(s,{authUser:s.authUser});m=await this.cacheManager.get(u,async()=>{let f=await t(s);if(f instanceof Response)return{_isResponse:!0,body:await f.text(),status:f.status,headers:Object.fromEntries(f.headers.entries())};return f},b)}else if(b&&typeof b==="object"&&b.ttl){let u=b.key||this.cacheManager.generateKey(s,{authUser:s.authUser});m=await this.cacheManager.get(u,async()=>{let f=await t(s);if(f instanceof Response)return{_isResponse:!0,body:await f.text(),status:f.status,headers:Object.fromEntries(f.headers.entries())};return f},b.ttl)}else m=await t(s);if(m&&typeof m==="object"&&m._isResponse===!0)m=new Response(m.body,{status:m.status,headers:m.headers});let p;if(e.rawResponse||m instanceof Response)p=m instanceof Response?m:new Response(m);else p=D(200,m,e.responseContentType);p=await this.middlewareManager.executeFinally(p,s);let x=this.corsHeadersEntries;if(x)for(let[u,f]of x)p.headers.set(u,f);else{let u=this.corsHandler;if(u)p=u(p,s)}return p}catch(a){if(a instanceof Response)return a;return console.error("Route handler error:",a),v.internalServerError(a instanceof Error?a.message:String(a),e.responseContentType)}}}isDevelopmentMode(){if(this.developmentMode!==void 0)return this.developmentMode;return(typeof Bun!=="undefined"?Bun.env.NODE_ENV:"development")!=="production"}async buildInputValidationPayload(e,t){let d=e.content;if(t.rawRequest&&e.method!=="GET"&&e.method!=="HEAD")try{d=await e.clone().text()}catch{d=null}return{params:e.params??{},query:e.query??{},headers:Object.fromEntries(e.headers.entries()),cookies:e.cookies??{},body:d}}applyValidatedInput(e,t){if(e.validatedInput=t,!t||typeof t!=="object")return;let d=t;if("params"in d)try{e.params=d.params}catch{}if("query"in d)try{e.query=d.query}catch{}if("cookies"in d)try{e.cookies=d.cookies}catch{}if("body"in d)this.setContentAndBodyAlias(e,d.body)}setContentAndBodyAlias(e,t){try{e.content=t}catch{return}this.setBodyAlias(e,t)}setBodyAlias(e,t){try{e.body=t}catch{}}async validateInputSchema(e,t){let d=t.schema?.input;if(!d)return null;if(t.validate===!1)return null;if(!oe(d))return v.internalServerError("Invalid route schema configuration",t.responseContentType);let n=this.isDevelopmentMode(),r=await this.buildInputValidationPayload(e,t);try{let o=await ae(d,r);if(o.success===!1){let i=_(o.issues,n);return D(422,J("input",i),t.responseContentType)}return this.applyValidatedInput(e,o.value),null}catch(o){let i=ie(o);if(i){let a=_(i,n);return D(422,J("input",a),t.responseContentType)}return v.internalServerError(o instanceof Error?o.message:"Validation failed",t.responseContentType)}}getOrCreateMethodMap(e){let t=this.routeTable[e];if(t instanceof Response)throw new Error(`Cannot register method route for path "${e}" because a static route already exists.`);if(t)return t;let d=Object.create(null);return this.routeTable[e]=d,this.addRouteMatcher(e),d}addRouteMatcher(e){if(this.routeMatchers.some((t)=>t.path===e))return;this.routeMatchers.push({path:e,regex:P(e),specificity:this.routeSpecificityScore(e)}),this.routeMatchers.sort((t,d)=>{if(t.specificity!==d.specificity)return d.specificity-t.specificity;return t.path.localeCompare(d.path)})}removeRouteMatcher(e){this.routeMatchers=this.routeMatchers.filter((t)=>t.path!==e)}static parseQuery(e){let t={};for(let[d,n]of e.searchParams)if(d in t){let r=t[d];if(Array.isArray(r))r.push(n);else t[d]=[r,n]}else t[d]=n;return t}routeSpecificityScore(e){let o=e.split("/").filter(Boolean),i=0;for(let a of o)if(a.includes("*"))i+=1;else if(a.startsWith(":"))i+=10;else i+=1000;if(i+=e.length,!e.includes(":")&&!e.includes("*"))i+=1e4;return i}}import{existsSync as ge}from"fs";import{join as Ke}from"path";function se(e,t){if(!e){if(typeof t.origin==="string"){if(t.origin==="*"&&t.credentials)return null;return t.origin}return null}if(typeof t.origin==="string"){if(t.origin==="*")return t.credentials?e:"*";return t.origin===e?e:null}if(Array.isArray(t.origin))return t.origin.includes(e)?e:null;if(typeof t.origin==="function")return t.origin(e)?e:null;return null}function le(e){return typeof e.origin==="string"&&e.origin==="*"&&e.credentials||Array.isArray(e.origin)||typeof e.origin==="function"}function ce(e,t,d){let n={};if(e){if(n["access-control-allow-origin"]=e,n["access-control-allow-methods"]=t.allowMethods,n["access-control-allow-headers"]=t.allowHeaders,n["access-control-expose-headers"]=t.exposeHeaders,n["access-control-max-age"]=String(t.maxAge),t.credentials)n["access-control-allow-credentials"]="true";if(d)n.vary="Origin"}return n}function Te(e,t){if(!e)return t;let d=e.split(",").map((r)=>r.trim()).filter(Boolean);if(!d.map((r)=>r.toLowerCase()).includes(t.toLowerCase()))d.push(t);return d.join(", ")}function be(e){return{preflight(t){let d=t.headers.get("origin")??void 0,n=se(d,e),r=Boolean(d&&n&&le(e));return new Response(null,{status:204,headers:ce(n,e,r)})},corsify(t,d){let n=d.headers.get("origin")??void 0,r=se(n,e);if(!r)return t;let o=Boolean(n&&le(e)),i=ce(r,e,o);for(let[a,s]of Object.entries(i)){if(a==="vary"){t.headers.set("vary",Te(t.headers.get("vary"),s));continue}t.headers.set(a,s)}return t}}}function me(e,t,d,n,r,o,i,a,s){let c=JSON.stringify(e).replace(/<\/script/gi,"<\\/script"),m=JSON.stringify(t),b=JSON.stringify(d),p=JSON.stringify(n),x=JSON.stringify(r),u=JSON.stringify(o),f=JSON.stringify(i),Ne=JSON.stringify(a),Ae=JSON.stringify(s);return`<!DOCTYPE html>
|
|
209
|
+
};`}}import{existsSync as sr,promises as Ue}from"fs";import{join as cr,relative as Me,resolve as pr,sep as Pe}from"path";class V{routesDir;excludePatterns;static DEFAULT_EXCLUDE_PATTERNS=["*.test.ts","*.test.js","*.test.tsx","*.test.jsx","*.spec.ts","*.spec.js","*.spec.tsx","*.spec.jsx","*.tests.ts","*.tests.js","**/__tests__/**","*.interface.ts","*.type.ts","*.d.ts"];constructor(e="./routes",t){this.routesDir=pr(process.cwd(),e),this.excludePatterns=t||V.DEFAULT_EXCLUDE_PATTERNS}async scan(){let e=[];if(!sr(this.routesDir))return[];try{await this.scanDirectory(this.routesDir,e)}catch(t){if(t.code==="ENOENT")return console.warn(` \u2717 Routes directory not accessible: ${this.routesDir}`),[];throw t}return e}isExcluded(e){let t=Me(this.routesDir,e);for(let r of this.excludePatterns){let a=r.replace(/\./g,"\\.").replace(/\*\*/g,"__GLOBSTAR__").replace(/\*/g,"[^/]*").replace(/__GLOBSTAR__/g,".*").replace(/\?/g,"."),n=new RegExp(`^${a}$`),o=t.split(Pe).pop()||"";if(n.test(t)||n.test(o))return!0}return!1}async scanDirectory(e,t,r=""){let a=await Ue.readdir(e);for(let n of a){let o=cr(e,n);if((await Ue.stat(o)).isDirectory()){let d=r?`${r}/${n}`:n;await this.scanDirectory(o,t,d)}else if(n.endsWith(".ts")||n.endsWith(".js")){if(this.isExcluded(o))continue;let d=Me(this.routesDir,o).replace(/\.(ts|js)$/,"").split(Pe).join("/");try{let c=await import(`${process.platform==="win32"?`file:///${o.replace(/\\/g,"/")}`:o}?t=${Date.now()}`);if(c.default&&typeof c.default==="function")t.push({name:"default",path:o,method:"GET",options:{method:"GET",path:`/${d}`,expose:!0}});for(let[m,s]of Object.entries(c)){if(m==="default")continue;if(s&&typeof s==="object"&&"entry"in s&&"options"in s&&"handler"in s){let p=s;t.push({name:m,path:o,method:p.options.method,options:p.options})}else if(Array.isArray(s)&&s.length>=4){let[p,,,h]=s;t.push({name:m,path:o,method:p,options:{method:p,path:h,expose:!0}})}}}catch(l){console.error(`Failed to load route from ${o}:`,l)}}}}enableWatch(e){if(typeof Bun!=="undefined"&&Bun.env.NODE_ENV==="development")console.log(`Watching for route changes in ${this.routesDir}`),setInterval(async()=>{await e()},1000)}}class W{beforeHandlers=[];finallyHandlers=[];addBefore(...e){this.beforeHandlers.push(...e)}addFinally(...e){this.finallyHandlers.push(...e)}async executeBefore(e){if(this.beforeHandlers.length===0)return null;for(let t of this.beforeHandlers){let r=await t(e);if(r instanceof Response)return r;if(r!==void 0)throw new TypeError("Before middleware must return void or Response")}return null}async executeFinally(e,t){if(this.finallyHandlers.length===0)return e;let r=e;for(let a of this.finallyHandlers)try{r=await a(r,t)}catch(n){console.error("After middleware error:",n)}return r}clone(){let e=new W;return e.beforeHandlers=[...this.beforeHandlers],e.finallyHandlers=[...this.finallyHandlers],e}clear(){this.beforeHandlers=[],this.finallyHandlers=[]}}function X(e){return process.platform==="win32"?`file:///${e.replace(/\\/g,"/")}`:e}function ne(e){return RegExp(`^${e.replace(/\/+(\/|$)/g,"$1").replace(/(\/?\.?):(\w+)\+/g,"($1(?<$2>[\\s\\S]+))").replace(/(\/?\.?):(\w+)/g,"($1(?<$2>[^$1/]+?))").replace(/\./g,"\\.").replace(/(\/?)\*/g,"($1.*)?")}/*$`)}var ze;((o)=>{o.ApiKey="apiKey";o.Http="http";o.MutualTls="mutualTLS";o.OAuth2="oauth2";o.OpenIdConnect="openIdConnect"})(ze||={});var Je;((a)=>{a.Basic="basic";a.Bearer="bearer";a.Digest="digest"})(Je||={});var J;((d)=>{d.ApiKey="ApiKey";d.HttpBasic="HttpBasic";d.HttpBearer="HttpBearer";d.HttpDigest="HttpDigest";d.OAuth2="OAuth2";d.OpenIdConnect="OpenIdConnect";d.MutualTls="MutualTls"})(J||={});function Fe(e){let t=e?.["~standard"];return!!t&&typeof t==="object"&&typeof t.validate==="function"&&t.version===1}async function Ge(e,t){let r=await e["~standard"].validate(t),a=r?.issues;if(Array.isArray(a)&&a.length>0)return{success:!1,issues:a};return{success:!0,value:r?.value}}function Ye(e){if(Array.isArray(e))return e;if(e&&typeof e==="object"&&Array.isArray(e.issues))return e.issues;if(e&&typeof e==="object"&&e.cause&&Array.isArray(e.cause.issues))return e.cause.issues;return null}function mr(e){if(!Array.isArray(e))return[];let t=[];for(let r=0;r<e.length;r++){let a=e[r],n=a;if(a&&typeof a==="object"&&"key"in a)n=a.key;if(typeof n==="string"||typeof n==="number")t.push(n);else if(typeof n==="symbol")t.push(String(n));else if(n!==void 0&&n!==null)t.push(String(n))}return t}function oe(e,t){let r=[];for(let a=0;a<e.length;a++){let n=e[a],o=n,i={message:typeof o?.message==="string"&&o.message.length>0?o.message:"Invalid value",path:mr(o?.path)};if(typeof o?.code==="string")i.code=o.code;if(t)i.raw=n;r.push(i)}return r}function de(e,t){return{error:!0,message:"Validation failed",statusCode:422,source:"validation",target:e,issues:t,timestamp:new Date().toISOString()}}var br=new Set(Object.values(J));function ur(e){return typeof e==="string"&&br.has(e)}class F{middlewareManager;authManager;cacheManager;routeBooleanDefaults={};developmentMode=void 0;routeDefinitions=[];routeTable=Object.create(null);routeMatchers=[];corsHeadersEntries=null;corsHandler=null;checkpointGateway=null;constructor(e,t,r){this.middlewareManager=e,this.authManager=t,this.cacheManager=r}setCorsHeaders(e){this.corsHeadersEntries=e}setCorsHandler(e){this.corsHandler=e}setCheckpointGateway(e){this.checkpointGateway=e}setRouteBooleanDefaults(e){this.routeBooleanDefaults={...e}}setDevelopmentMode(e){this.developmentMode=e}applyRouteBooleanDefaults(e){let t={...e},r=this.routeBooleanDefaults,a=["auth","expose","rawRequest","validate","rawResponse"];for(let n of a)if(t[n]===void 0&&r[n]!==void 0)t[n]=r[n];if(t.auth===!0&&ur(r.auth))t.auth=r.auth;return t}route(e,t){let r=this.applyRouteBooleanDefaults(e),a=r.method.toUpperCase(),n=r.path,o=this.wrapHandler(r,t),i=this.getOrCreateMethodMap(n);i[a]=o,this.routeDefinitions.push({method:a,path:n,options:r})}addRoute(e){let[t,,r,a]=e;if(!a)return;let n=this.getOrCreateMethodMap(a);n[t.toUpperCase()]=r[0];let o=t.toUpperCase();this.routeDefinitions.push({method:o,path:a,options:{method:o,path:a,expose:!0}})}bulkAddRoutes(e){for(let t of e)this.addRoute(t)}addStaticRoute(e,t){let r=this.routeTable[e];if(r&&!(r instanceof Response))throw new Error(`Cannot register static route for path "${e}" because method routes already exist.`);this.routeTable[e]=t,this.removeRouteMatcher(e)}getRouteTable(){return this.routeTable}getRoutes(){let e=[];for(let t of this.routeMatchers){let r=this.routeTable[t.path];if(!r||r instanceof Response)continue;for(let[a,n]of Object.entries(r))e.push([a,t.regex,[n],t.path])}return e}getRouteDefinitions(){return[...this.routeDefinitions]}clearRoutes(){this.routeTable=Object.create(null),this.routeMatchers=[],this.routeDefinitions=[]}sortRoutes(){}async handle(e){let t;try{t=new URL(e.url)}catch{return S.badRequest("Malformed request URL")}let r=t.pathname,a=this.routeTable[r];if(a){if(a instanceof Response)return this.applyCorsResponse(a.clone(),e);let n=a,o=n[e.method]??(e.method==="HEAD"?n.GET:void 0);if(o){let i=await o(e);if(i)return i}}for(let n of this.routeMatchers){let o=n.path,i=this.routeTable[o];if(!i)continue;if(i instanceof Response){if(r===o)return this.applyCorsResponse(i.clone(),e);continue}let d=i,l=d[e.method]??(e.method==="HEAD"?d.GET:void 0);if(!l)continue;if(!r.match(n.regex))continue;let m=await l(e);if(m)return m}return this.applyCorsResponse(je.NOT_FOUND.clone(),e)}cloneMetadata(e){if(Array.isArray(e))return[...e];if(e&&typeof e==="object")return{...e};return e}createContext(e,t){let r={request:e};return this.setContextField(r,"metadata",t?.metadata!==void 0?this.cloneMetadata(t.metadata):{}),this.setContextField(r,"params",t?.params??{}),this.setContextField(r,"query",t?.query??{}),this.setContextField(r,"cookies",t?.cookies??{}),r}setContextField(e,t,r){e[t]=r}hasOwnContextField(e,t){return Object.prototype.hasOwnProperty.call(e,t)}buildCheckpointContextPayload(e){let t={},r=["metadata","content","validatedInput","authUser"];for(let a of r){if(!this.hasOwnContextField(e,a))continue;let n=e[a];if(typeof n==="function"||typeof n==="symbol"||n===void 0)continue;t[a]=n}return t}resolveFallbackParams(e,t){if(!t)return;let r=e.match(t);if(!r?.groups)return;return r.groups}getRequestedCheckpointVersion(e){if(!this.checkpointGateway)return null;let t=this.checkpointGateway;if(t?.getRequestedVersion)return t.getRequestedVersion(e);let r=e.headers.get("x-vector-checkpoint-version");if(r&&r.trim().length>0)return r.trim();let a=e.headers.get("x-vector-checkpoint");if(a&&a.trim().length>0)return a.trim();return null}getCheckpointCacheKeyOverrideValue(e){if(!this.checkpointGateway)return null;let t=this.checkpointGateway;if(t?.getCacheKeyOverrideValue)return t.getCacheKeyOverrideValue(e);let r=e.headers.get("x-vector-checkpoint-version");if(r&&r.trim().length>0)return`x-vector-checkpoint-version:${r.trim()}`;let a=e.headers.get("x-vector-checkpoint");if(a&&a.trim().length>0)return`x-vector-checkpoint:${a.trim()}`;return null}applyCheckpointCacheNamespace(e,t){let r=this.getRequestedCheckpointVersion(t);if(!r)return e;return`${e}:checkpoint=${r}`}applyCheckpointRouteKeyOverride(e,t){let r=this.getCheckpointCacheKeyOverrideValue(t);if(!r)return e;return r}async parseRequestBodyForContext(e,t,r){let a=null;try{let n=r?t.clone():t,o=n.headers.get("content-type");if(o?.startsWith("application/json"))a=await n.json();else if(o?.startsWith("application/x-www-form-urlencoded"))a=Object.fromEntries(await n.formData());else if(o?.startsWith("multipart/form-data"))a=await n.formData();else a=await n.text()}catch{a=null}this.setContextField(e,"content",a)}isLikelyStreamingBodyRequest(e){if(e.method==="GET"||e.method==="HEAD")return!1;if(!e.body)return!1;if(e.duplex==="half")return!0;let t=e.headers.get("transfer-encoding");if(t){if(t.split(",").some((a)=>a.trim().toLowerCase()==="chunked"))return!0}return!1}wrapHandler(e,t){let r=e.path,a=r.includes(":")?ne(r):null;return async(n)=>{let o=n,i="";try{i=new URL(n.url).pathname}catch{}let d=this.resolveFallbackParams(i,a),l=this.createContext(o,{metadata:e.metadata,params:this.getRequestParams(n,d),query:this.getRequestQuery(n),cookies:this.getRequestCookies(n)});try{if(e.expose===!1)return S.forbidden("Forbidden");let c=await this.middlewareManager.executeBefore(l);if(c instanceof Response)return c;if(e.auth)try{await this.authManager.authenticate(l)}catch(u){return S.unauthorized(u instanceof Error?u.message:"Authentication failed",e.responseContentType)}let m=async()=>{let u=l.request,f=u,L=this.getRequestedCheckpointVersion(f)!==null,x=this.isLikelyStreamingBodyRequest(f)&&e.schema?.input!==void 0&&e.validate!==!1;if(!e.rawRequest&&u.method!=="GET"&&u.method!=="HEAD"&&!x)await this.parseRequestBodyForContext(l,f,L);if(x){let N=await this.validateInputSchema(l,e,d,{includeBody:!1,allowBodyDeferral:!0});if(N.response)return N.response;if(N.requiresBody){if(!e.rawRequest&&u.method!=="GET"&&u.method!=="HEAD")await this.parseRequestBodyForContext(l,f,L);let De=await this.validateInputSchema(l,e,d);if(De.response)return De.response}}else{let N=await this.validateInputSchema(l,e,d);if(N.response)return N.response}if(this.checkpointGateway){let N=await this.checkpointGateway.handle(u,this.buildCheckpointContextPayload(l));if(N)return N}return await t(l)},s,p=e.cache;if(p&&typeof p==="number"&&p>0){let u=this.applyCheckpointCacheNamespace(this.cacheManager.generateKey(l.request,{authUser:l.authUser}),l.request);s=await this.cacheManager.get(u,async()=>await m(),p)}else if(p&&typeof p==="object"&&p.ttl){let u=typeof p.key==="string"&&p.key.length>0,f;if(u)f=this.applyCheckpointRouteKeyOverride(p.key,l.request);else{let L=this.cacheManager.generateKey(l.request,{authUser:l.authUser});f=this.applyCheckpointCacheNamespace(L,l.request)}s=await this.cacheManager.get(f,async()=>await m(),p.ttl)}else s=await m();if(s instanceof Response&&!!p)s=s.clone();let h;if(e.rawResponse||s instanceof Response)h=s instanceof Response?s:new Response(s);else h=_(200,s,e.responseContentType);return h=await this.middlewareManager.executeFinally(h,l),this.applyCorsResponse(h,l.request)}catch(c){if(c instanceof Response)return c;return console.error("Route handler error:",c),S.internalServerError(c instanceof Error?c.message:String(c),e.responseContentType)}}}isDevelopmentMode(){if(this.developmentMode!==void 0)return this.developmentMode;return(typeof Bun!=="undefined"?Bun.env.NODE_ENV:"development")!=="production"}async buildInputValidationPayload(e,t,r,a){let n=e.request,o=a?.includeBody!==!1,i=o&&this.hasOwnContextField(e,"content")?e.content:void 0;if(o&&t.rawRequest&&n.method!=="GET"&&n.method!=="HEAD")try{i=await n.clone().text()}catch{i=null}return{params:this.getRequestParams(n,r),query:this.getRequestQuery(n),headers:Object.fromEntries(n.headers.entries()),cookies:this.getRequestCookies(n),body:i}}getRequestParams(e,t){let r=this.readRequestObjectField(e,"params");if(r&&Object.keys(r).length>0)return r;return t??{}}getRequestQuery(e){let t=this.readRequestObjectField(e,"query");if(t)return t;try{return F.parseQuery(new URL(e.url))}catch{return{}}}getRequestCookies(e){let t=this.readRequestObjectField(e,"cookies");if(t)return t;return F.parseCookies(e.headers.get("cookie"))}readRequestObjectField(e,t){let r=e[t];if(!r||typeof r!=="object"||Array.isArray(r))return;return r}applyValidatedInput(e,t){this.setContextField(e,"validatedInput",t)}issueHasBodyPath(e){if(!e||typeof e!=="object"||!("path"in e))return!1;let t=e.path;if(!Array.isArray(t)||t.length===0)return!1;let r=t[0];if(r&&typeof r==="object"&&"key"in r)return r.key==="body";return r==="body"}issueHasExplicitNonBodyPath(e){if(!e||typeof e!=="object"||!("path"in e))return!1;let t=e.path;if(!Array.isArray(t)||t.length===0)return!1;let r=t[0];if(r&&typeof r==="object"&&"key"in r)return r.key!=="body";return r!=="body"}issueHasUnknownPath(e){if(!e||typeof e!=="object"||!("path"in e))return!0;let t=e.path;if(!Array.isArray(t))return!0;return t.length===0}shouldDeferBodyValidation(e,t,r){if(!(r?.allowBodyDeferral===!0&&r?.includeBody===!1))return!1;let a=t.request;if(!(a.method!=="GET"&&a.method!=="HEAD"&&a.body!==null)||e.length===0)return!1;if(e.some((d)=>this.issueHasBodyPath(d)))return!0;let o=e.some((d)=>this.issueHasExplicitNonBodyPath(d)),i=e.some((d)=>this.issueHasUnknownPath(d));return!o&&i}async validateInputSchema(e,t,r,a){let n=t.schema?.input;if(!n)return{response:null,requiresBody:!1};if(t.validate===!1)return{response:null,requiresBody:!1};if(!Fe(n))return{response:S.internalServerError("Invalid route schema configuration",t.responseContentType),requiresBody:!1};let o=this.isDevelopmentMode(),i=await this.buildInputValidationPayload(e,t,r,{includeBody:a?.includeBody});try{let d=await Ge(n,i);if(d.success===!1){if(this.shouldDeferBodyValidation(d.issues,e,a))return{response:null,requiresBody:!0};let l=oe(d.issues,o);return{response:_(422,de("input",l),t.responseContentType),requiresBody:!1}}return this.applyValidatedInput(e,d.value),{response:null,requiresBody:!1}}catch(d){let l=Ye(d);if(l){if(this.shouldDeferBodyValidation(l,e,a))return{response:null,requiresBody:!0};let c=oe(l,o);return{response:_(422,de("input",c),t.responseContentType),requiresBody:!1}}return{response:S.internalServerError(d instanceof Error?d.message:"Validation failed",t.responseContentType),requiresBody:!1}}}getOrCreateMethodMap(e){let t=this.routeTable[e];if(t instanceof Response)throw new Error(`Cannot register method route for path "${e}" because a static route already exists.`);if(t)return t;let r=Object.create(null);return this.routeTable[e]=r,this.addRouteMatcher(e),r}addRouteMatcher(e){if(this.routeMatchers.some((t)=>t.path===e))return;this.routeMatchers.push({path:e,regex:ne(e),specificity:this.routeSpecificityScore(e)}),this.routeMatchers.sort((t,r)=>{if(t.specificity!==r.specificity)return r.specificity-t.specificity;return t.path.localeCompare(r.path)})}removeRouteMatcher(e){this.routeMatchers=this.routeMatchers.filter((t)=>t.path!==e)}static parseQuery(e){let t={};for(let[r,a]of e.searchParams)if(r in t){let n=t[r];if(Array.isArray(n))n.push(a);else t[r]=[n,a]}else t[r]=a;return t}static parseCookies(e){let t={};if(!e)return t;for(let r of e.split(";")){let a=r.indexOf("=");if(a>0)t[r.slice(0,a).trim()]=r.slice(a+1).trim()}return t}routeSpecificityScore(e){let o=e.split("/").filter(Boolean),i=0;for(let d of o)if(d.includes("*"))i+=1;else if(d.startsWith(":"))i+=10;else i+=1000;if(i+=e.length,!e.includes(":")&&!e.includes("*"))i+=1e4;return i}applyCorsResponse(e,t){let r=this.corsHeadersEntries;if(r){for(let[n,o]of r)e.headers.set(n,o);return e}let a=this.corsHandler;if(a)return a(e,t);return e}}import{existsSync as ot}from"fs";import{join as $r}from"path";function Qe(e,t){if(!e){if(typeof t.origin==="string"){if(t.origin==="*"&&t.credentials)return null;return t.origin}return null}if(typeof t.origin==="string"){if(t.origin==="*")return t.credentials?e:"*";return t.origin===e?e:null}if(Array.isArray(t.origin))return t.origin.includes(e)?e:null;if(typeof t.origin==="function")return t.origin(e)?e:null;return null}function Ve(e){return typeof e.origin==="string"&&e.origin==="*"&&e.credentials||Array.isArray(e.origin)||typeof e.origin==="function"}function We(e,t,r){let a={};if(e){if(a["access-control-allow-origin"]=e,a["access-control-allow-methods"]=t.allowMethods,a["access-control-allow-headers"]=t.allowHeaders,a["access-control-expose-headers"]=t.exposeHeaders,a["access-control-max-age"]=String(t.maxAge),t.credentials)a["access-control-allow-credentials"]="true";if(r)a.vary="Origin"}return a}function hr(e,t){if(!e)return t;let r=e.split(",").map((n)=>n.trim()).filter(Boolean);if(!r.map((n)=>n.toLowerCase()).includes(t.toLowerCase()))r.push(t);return r.join(", ")}function Xe(e){return{preflight(t){let r=t.headers.get("origin")??void 0,a=Qe(r,e),n=Boolean(r&&a&&Ve(e));return new Response(null,{status:204,headers:We(a,e,n)})},corsify(t,r){let a=r.headers.get("origin")??void 0,n=Qe(a,e);if(!n)return t;let o=Boolean(a&&Ve(e)),i=We(n,e,o);for(let[d,l]of Object.entries(i)){if(d==="vary"){t.headers.set("vary",hr(t.headers.get("vary"),l));continue}t.headers.set(d,l)}return t}}}function Ze(e,t,r,a,n,o,i,d,l){let c=JSON.stringify(e).replace(/<\/script/gi,"<\\/script"),m=JSON.stringify(t),s=JSON.stringify(r),p=JSON.stringify(a),h=JSON.stringify(n),u=JSON.stringify(o),f=JSON.stringify(i),L=JSON.stringify(d),x=JSON.stringify(l);return`<!DOCTYPE html>
|
|
23
210
|
<html lang="en">
|
|
24
211
|
<head>
|
|
25
212
|
<meta charset="UTF-8">
|
|
@@ -27,8 +214,8 @@ ${t.join(`,
|
|
|
27
214
|
<title>Vector API Documentation</title>
|
|
28
215
|
<link rel="apple-touch-icon" sizes="180x180" href=${u}>
|
|
29
216
|
<link rel="icon" type="image/png" sizes="32x32" href=${f}>
|
|
30
|
-
<link rel="icon" type="image/png" sizes="16x16" href=${
|
|
31
|
-
<link rel="manifest" href=${
|
|
217
|
+
<link rel="icon" type="image/png" sizes="16x16" href=${L}>
|
|
218
|
+
<link rel="manifest" href=${x}>
|
|
32
219
|
<script>
|
|
33
220
|
if (localStorage.getItem('theme') === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
|
|
34
221
|
document.documentElement.classList.add('dark');
|
|
@@ -36,7 +223,7 @@ ${t.join(`,
|
|
|
36
223
|
document.documentElement.classList.remove('dark');
|
|
37
224
|
}
|
|
38
225
|
</script>
|
|
39
|
-
<script src=${
|
|
226
|
+
<script src=${s}></script>
|
|
40
227
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
|
41
228
|
<script>
|
|
42
229
|
tailwind.config = {
|
|
@@ -144,6 +331,124 @@ ${t.join(`,
|
|
|
144
331
|
.dark .json-number { color: #7dc9ff; }
|
|
145
332
|
.dark .json-boolean { color: #93a4bf; }
|
|
146
333
|
.dark .json-null { color: #7c8ba3; }
|
|
334
|
+
.param-row {
|
|
335
|
+
--param-row-bg-rgb: 255 255 255;
|
|
336
|
+
}
|
|
337
|
+
.dark .param-row {
|
|
338
|
+
--param-row-bg-rgb: 10 10 10;
|
|
339
|
+
}
|
|
340
|
+
.param-row-head {
|
|
341
|
+
display: grid;
|
|
342
|
+
grid-template-columns: minmax(0, 1fr) auto;
|
|
343
|
+
align-items: center;
|
|
344
|
+
gap: 0.5rem;
|
|
345
|
+
min-width: 0;
|
|
346
|
+
width: 100%;
|
|
347
|
+
}
|
|
348
|
+
.param-row-main {
|
|
349
|
+
min-width: 0;
|
|
350
|
+
display: flex;
|
|
351
|
+
align-items: center;
|
|
352
|
+
gap: 0.4rem;
|
|
353
|
+
overflow: hidden;
|
|
354
|
+
}
|
|
355
|
+
.param-tooltip-trigger {
|
|
356
|
+
border: 0;
|
|
357
|
+
margin: 0;
|
|
358
|
+
padding: 0;
|
|
359
|
+
background: transparent;
|
|
360
|
+
color: inherit;
|
|
361
|
+
cursor: pointer;
|
|
362
|
+
font: inherit;
|
|
363
|
+
text-align: left;
|
|
364
|
+
min-width: 0;
|
|
365
|
+
}
|
|
366
|
+
.param-tooltip-trigger:focus-visible {
|
|
367
|
+
outline: 2px solid rgba(0, 161, 255, 0.65);
|
|
368
|
+
outline-offset: 2px;
|
|
369
|
+
border-radius: 0.375rem;
|
|
370
|
+
}
|
|
371
|
+
.param-name-trigger {
|
|
372
|
+
min-width: 0;
|
|
373
|
+
flex: 1 1 auto;
|
|
374
|
+
overflow: hidden;
|
|
375
|
+
}
|
|
376
|
+
.param-name-text {
|
|
377
|
+
display: block;
|
|
378
|
+
max-width: 100%;
|
|
379
|
+
overflow: hidden;
|
|
380
|
+
text-overflow: ellipsis;
|
|
381
|
+
white-space: nowrap;
|
|
382
|
+
mask-image: linear-gradient(to right, #000 0%, #000 calc(100% - 18px), transparent 100%);
|
|
383
|
+
-webkit-mask-image: linear-gradient(to right, #000 0%, #000 calc(100% - 18px), transparent 100%);
|
|
384
|
+
}
|
|
385
|
+
.param-type-fade {
|
|
386
|
+
position: relative;
|
|
387
|
+
z-index: 1;
|
|
388
|
+
display: block;
|
|
389
|
+
max-width: none;
|
|
390
|
+
overflow: visible;
|
|
391
|
+
text-overflow: clip;
|
|
392
|
+
padding-left: 1.25rem;
|
|
393
|
+
white-space: nowrap;
|
|
394
|
+
text-align: left;
|
|
395
|
+
justify-self: end;
|
|
396
|
+
background: linear-gradient(
|
|
397
|
+
90deg,
|
|
398
|
+
rgba(var(--param-row-bg-rgb), 0) 0%,
|
|
399
|
+
rgba(var(--param-row-bg-rgb), 0.76) 36%,
|
|
400
|
+
rgba(var(--param-row-bg-rgb), 0.94) 68%,
|
|
401
|
+
rgba(var(--param-row-bg-rgb), 1) 100%
|
|
402
|
+
);
|
|
403
|
+
}
|
|
404
|
+
#param-value-tooltip {
|
|
405
|
+
position: fixed;
|
|
406
|
+
top: 0;
|
|
407
|
+
left: 0;
|
|
408
|
+
z-index: 70;
|
|
409
|
+
width: min(42rem, calc(100vw - 0.75rem));
|
|
410
|
+
border-radius: 0.5rem;
|
|
411
|
+
border: 1px solid rgba(15, 23, 42, 0.12);
|
|
412
|
+
background: rgba(255, 255, 255, 0.92);
|
|
413
|
+
color: #111111;
|
|
414
|
+
box-shadow: 0 10px 20px rgba(15, 23, 42, 0.14);
|
|
415
|
+
backdrop-filter: blur(12px) saturate(145%);
|
|
416
|
+
-webkit-backdrop-filter: blur(12px) saturate(145%);
|
|
417
|
+
padding: 0.4rem 0.6rem;
|
|
418
|
+
opacity: 0;
|
|
419
|
+
pointer-events: none;
|
|
420
|
+
transform: translateY(6px) scale(0.98);
|
|
421
|
+
transition:
|
|
422
|
+
opacity var(--motion-fast) var(--motion-ease),
|
|
423
|
+
transform var(--motion-fast) var(--motion-ease);
|
|
424
|
+
}
|
|
425
|
+
#param-value-tooltip.is-visible {
|
|
426
|
+
opacity: 1;
|
|
427
|
+
pointer-events: auto;
|
|
428
|
+
transform: translateY(0) scale(1);
|
|
429
|
+
}
|
|
430
|
+
.dark #param-value-tooltip {
|
|
431
|
+
border-color: rgba(148, 163, 184, 0.24);
|
|
432
|
+
background: rgba(17, 17, 17, 0.9);
|
|
433
|
+
color: #ededed;
|
|
434
|
+
box-shadow: 0 14px 30px rgba(0, 0, 0, 0.45);
|
|
435
|
+
}
|
|
436
|
+
#param-tooltip-line {
|
|
437
|
+
margin: 0;
|
|
438
|
+
font-size: 11px;
|
|
439
|
+
line-height: 1.3;
|
|
440
|
+
font-family: "JetBrains Mono", monospace;
|
|
441
|
+
white-space: normal;
|
|
442
|
+
word-break: break-word;
|
|
443
|
+
}
|
|
444
|
+
#param-tooltip-description {
|
|
445
|
+
margin: 0.2rem 0 0;
|
|
446
|
+
font-size: 11px;
|
|
447
|
+
line-height: 1.3;
|
|
448
|
+
opacity: 0.8;
|
|
449
|
+
white-space: normal;
|
|
450
|
+
word-break: break-word;
|
|
451
|
+
}
|
|
147
452
|
</style>
|
|
148
453
|
</head>
|
|
149
454
|
<body class="bg-light-bg text-light-text dark:bg-dark-bg dark:text-dark-text font-sans antialiased flex h-screen overflow-hidden">
|
|
@@ -152,7 +457,7 @@ ${t.join(`,
|
|
|
152
457
|
<div class="h-14 flex items-center px-5 border-b border-light-border dark:border-dark-border">
|
|
153
458
|
<div class="flex items-center">
|
|
154
459
|
<img src=${p} alt="Vector" class="h-6 w-auto block dark:hidden" />
|
|
155
|
-
<img src=${
|
|
460
|
+
<img src=${h} alt="Vector" class="h-6 w-auto hidden dark:block" />
|
|
156
461
|
</div>
|
|
157
462
|
<button id="sidebar-close" class="ml-auto p-1.5 rounded-full border border-light-border dark:border-dark-border bg-light-bg/90 dark:bg-dark-bg/90 opacity-90 hover:opacity-100 transition md:hidden" aria-label="Close Menu" title="Close Menu">
|
|
158
463
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
@@ -173,6 +478,16 @@ ${t.join(`,
|
|
|
173
478
|
/>
|
|
174
479
|
</div>
|
|
175
480
|
</div>
|
|
481
|
+
<div id="auth-panel" class="border-b border-light-border dark:border-dark-border">
|
|
482
|
+
<button id="auth-toggle" class="w-full flex items-center justify-between px-4 py-2.5 text-xs font-semibold uppercase tracking-wider opacity-60 hover:opacity-100 transition-opacity">
|
|
483
|
+
<span class="flex items-center gap-1.5">
|
|
484
|
+
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"></path></svg>
|
|
485
|
+
Auth
|
|
486
|
+
</span>
|
|
487
|
+
<svg id="auth-chevron" class="w-3.5 h-3.5 transition-transform duration-200" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path></svg>
|
|
488
|
+
</button>
|
|
489
|
+
<div id="auth-fields" class="px-4 pb-3 space-y-2"></div>
|
|
490
|
+
</div>
|
|
176
491
|
<nav class="flex-1 overflow-y-auto px-3 py-2 space-y-6 text-sm" id="sidebar-nav"></nav>
|
|
177
492
|
</aside>
|
|
178
493
|
|
|
@@ -185,7 +500,7 @@ ${t.join(`,
|
|
|
185
500
|
</svg>
|
|
186
501
|
</button>
|
|
187
502
|
<img src=${p} alt="Vector" class="h-5 w-auto block dark:hidden" />
|
|
188
|
-
<img src=${
|
|
503
|
+
<img src=${h} alt="Vector" class="h-5 w-auto hidden dark:block" />
|
|
189
504
|
</div>
|
|
190
505
|
<div class="flex-1"></div>
|
|
191
506
|
<button id="theme-toggle" class="p-2 rounded-md hover:bg-black/5 dark:hover:bg-white/5 transition-colors" aria-label="Toggle Dark Mode">
|
|
@@ -206,6 +521,9 @@ ${t.join(`,
|
|
|
206
521
|
<span id="endpoint-method" class="px-2.5 py-0.5 rounded-full text-xs font-mono font-medium"></span>
|
|
207
522
|
<h2 class="text-xl font-semibold tracking-tight" id="endpoint-title">Operation</h2>
|
|
208
523
|
</div>
|
|
524
|
+
<div id="deprecated-banner" class="hidden mb-4 px-3 py-2 rounded border border-amber-300 dark:border-amber-700 bg-amber-50 dark:bg-amber-900/20 text-amber-700 dark:text-amber-400 text-xs font-medium">
|
|
525
|
+
! This operation is deprecated
|
|
526
|
+
</div>
|
|
209
527
|
<p class="text-sm opacity-80 mb-8 font-mono" id="endpoint-path">/</p>
|
|
210
528
|
<div class="grid grid-cols-1 lg:grid-cols-12 gap-10">
|
|
211
529
|
<div class="lg:col-span-5 space-y-8" id="params-column"></div>
|
|
@@ -301,6 +619,10 @@ ${t.join(`,
|
|
|
301
619
|
<pre id="expand-viewer" class="hidden w-full h-[70vh] text-sm p-3 rounded border border-light-border dark:border-dark-border bg-light-bg dark:bg-dark-bg overflow-auto font-mono"></pre>
|
|
302
620
|
</div>
|
|
303
621
|
</div>
|
|
622
|
+
<div id="param-value-tooltip" aria-hidden="true" role="tooltip">
|
|
623
|
+
<p id="param-tooltip-line"></p>
|
|
624
|
+
<p id="param-tooltip-description" class="hidden"></p>
|
|
625
|
+
</div>
|
|
304
626
|
|
|
305
627
|
<script>
|
|
306
628
|
const spec = ${c};
|
|
@@ -371,14 +693,71 @@ ${t.join(`,
|
|
|
371
693
|
return ops;
|
|
372
694
|
}
|
|
373
695
|
|
|
696
|
+
const AUTH_STATE_KEY = "vector-docs-auth-v1";
|
|
697
|
+
const AUTH_SELECTION_KEY = "vector-docs-auth-selection-v1";
|
|
698
|
+
const HEADERS_STATE_KEY = "vector-docs-headers-v1";
|
|
699
|
+
|
|
700
|
+
function loadSavedHeaders() {
|
|
701
|
+
try {
|
|
702
|
+
const raw = localStorage.getItem(HEADERS_STATE_KEY);
|
|
703
|
+
if (raw) {
|
|
704
|
+
const parsed = JSON.parse(raw);
|
|
705
|
+
if (Array.isArray(parsed) && parsed.length > 0) return parsed;
|
|
706
|
+
}
|
|
707
|
+
} catch {}
|
|
708
|
+
return [{ key: "", value: "" }];
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
function saveHeaders() {
|
|
712
|
+
try { localStorage.setItem(HEADERS_STATE_KEY, JSON.stringify(requestHeaders)); } catch {}
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
function loadAuthState() {
|
|
716
|
+
try {
|
|
717
|
+
const raw = localStorage.getItem(AUTH_STATE_KEY);
|
|
718
|
+
if (raw) return JSON.parse(raw);
|
|
719
|
+
} catch {}
|
|
720
|
+
return {};
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
function saveAuthState() {
|
|
724
|
+
try { localStorage.setItem(AUTH_STATE_KEY, JSON.stringify(authState)); } catch {}
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
function loadAuthSelectionState() {
|
|
728
|
+
try {
|
|
729
|
+
const raw = localStorage.getItem(AUTH_SELECTION_KEY);
|
|
730
|
+
if (raw) {
|
|
731
|
+
const parsed = JSON.parse(raw);
|
|
732
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
733
|
+
return parsed;
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
} catch {}
|
|
737
|
+
return {};
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
function saveAuthSelectionState() {
|
|
741
|
+
try { localStorage.setItem(AUTH_SELECTION_KEY, JSON.stringify(authSelectionState)); } catch {}
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
const authSchemes = (spec.components && spec.components.securitySchemes) || {};
|
|
745
|
+
let authState = loadAuthState();
|
|
746
|
+
let authSelectionState = loadAuthSelectionState();
|
|
747
|
+
|
|
374
748
|
const operations = getOperations();
|
|
375
749
|
let selected = operations[0] || null;
|
|
376
750
|
const operationParamValues = new Map();
|
|
377
751
|
const operationBodyDrafts = new Map();
|
|
378
|
-
const requestHeaders =
|
|
752
|
+
const requestHeaders = loadSavedHeaders();
|
|
379
753
|
let expandModalMode = null;
|
|
380
754
|
let isMobileSidebarOpen = false;
|
|
381
755
|
let sidebarSearchQuery = "";
|
|
756
|
+
const paramTooltipRoot = document.getElementById("param-value-tooltip");
|
|
757
|
+
const paramTooltipLine = document.getElementById("param-tooltip-line");
|
|
758
|
+
const paramTooltipDescription = document.getElementById("param-tooltip-description");
|
|
759
|
+
let activeParamTooltipTrigger = null;
|
|
760
|
+
let paramTooltipHideTimer = null;
|
|
382
761
|
|
|
383
762
|
function setMobileSidebarOpen(open) {
|
|
384
763
|
const sidebar = document.getElementById("docs-sidebar");
|
|
@@ -398,6 +777,29 @@ ${t.join(`,
|
|
|
398
777
|
return op.method + " " + op.path;
|
|
399
778
|
}
|
|
400
779
|
|
|
780
|
+
function getOpHash(op) {
|
|
781
|
+
var tag = op.tag || "default";
|
|
782
|
+
var id = (op.operation && op.operation.operationId)
|
|
783
|
+
? op.operation.operationId
|
|
784
|
+
: op.method.toLowerCase() + "_" + op.path.split("/").filter(Boolean).join("_").replace(/[{}]/g, "");
|
|
785
|
+
return "#/" + encodeURIComponent(tag) + "/" + encodeURIComponent(id);
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
function findOpByHash(hash) {
|
|
789
|
+
if (!hash || hash.length <= 1) return null;
|
|
790
|
+
var parts = hash.slice(1).split("/").filter(Boolean);
|
|
791
|
+
if (parts.length < 2) return null;
|
|
792
|
+
var hashTag = decodeURIComponent(parts[0]);
|
|
793
|
+
var hashId = decodeURIComponent(parts[1]);
|
|
794
|
+
return operations.find(function(op) {
|
|
795
|
+
if (op.tag !== hashTag) return false;
|
|
796
|
+
var id = (op.operation && op.operation.operationId)
|
|
797
|
+
? op.operation.operationId
|
|
798
|
+
: op.method.toLowerCase() + "_" + op.path.split("/").filter(Boolean).join("_").replace(/[{}]/g, "");
|
|
799
|
+
return id === hashId;
|
|
800
|
+
}) || null;
|
|
801
|
+
}
|
|
802
|
+
|
|
401
803
|
function getOperationParameterGroups(op) {
|
|
402
804
|
const params =
|
|
403
805
|
op &&
|
|
@@ -447,7 +849,7 @@ ${t.join(`,
|
|
|
447
849
|
return resolved;
|
|
448
850
|
}
|
|
449
851
|
|
|
450
|
-
function buildRequestPath(op, pathParams, queryParams, values) {
|
|
852
|
+
function buildRequestPath(op, pathParams, queryParams, values, extraQuery) {
|
|
451
853
|
const resolvedPath = resolvePath(op.path, pathParams, values);
|
|
452
854
|
const query = new URLSearchParams();
|
|
453
855
|
|
|
@@ -459,6 +861,13 @@ ${t.join(`,
|
|
|
459
861
|
query.append(param.name, String(rawValue));
|
|
460
862
|
}
|
|
461
863
|
|
|
864
|
+
if (extraQuery) {
|
|
865
|
+
for (const key of Object.keys(extraQuery)) {
|
|
866
|
+
const val = extraQuery[key];
|
|
867
|
+
if (val) query.set(key, String(val));
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
|
|
462
871
|
const queryString = query.toString();
|
|
463
872
|
return queryString ? resolvedPath + "?" + queryString : resolvedPath;
|
|
464
873
|
}
|
|
@@ -598,14 +1007,25 @@ ${t.join(`,
|
|
|
598
1007
|
|
|
599
1008
|
const name = document.createElement("span");
|
|
600
1009
|
name.textContent = op.name;
|
|
1010
|
+
if (op.operation && op.operation.deprecated) {
|
|
1011
|
+
name.style.textDecoration = "line-through";
|
|
1012
|
+
name.style.opacity = "0.5";
|
|
1013
|
+
}
|
|
601
1014
|
|
|
602
1015
|
row.appendChild(method);
|
|
603
1016
|
row.appendChild(name);
|
|
1017
|
+
if (op.operation && op.operation.deprecated) {
|
|
1018
|
+
const badge = document.createElement("span");
|
|
1019
|
+
badge.className = "text-[9px] px-1 py-0.5 rounded bg-amber-100 dark:bg-amber-900/30 text-amber-700 dark:text-amber-500 font-semibold shrink-0";
|
|
1020
|
+
badge.textContent = "deprecated";
|
|
1021
|
+
row.appendChild(badge);
|
|
1022
|
+
}
|
|
604
1023
|
a.appendChild(row);
|
|
605
1024
|
|
|
606
1025
|
a.onclick = (e) => {
|
|
607
1026
|
e.preventDefault();
|
|
608
1027
|
selected = op;
|
|
1028
|
+
history.pushState(null, "", getOpHash(op));
|
|
609
1029
|
renderSidebar();
|
|
610
1030
|
renderEndpoint();
|
|
611
1031
|
if (window.innerWidth < 768) {
|
|
@@ -619,51 +1039,257 @@ ${t.join(`,
|
|
|
619
1039
|
}
|
|
620
1040
|
}
|
|
621
1041
|
|
|
1042
|
+
function hideParamTooltip() {
|
|
1043
|
+
if (!paramTooltipRoot) return;
|
|
1044
|
+
if (paramTooltipHideTimer) {
|
|
1045
|
+
window.clearTimeout(paramTooltipHideTimer);
|
|
1046
|
+
paramTooltipHideTimer = null;
|
|
1047
|
+
}
|
|
1048
|
+
paramTooltipRoot.classList.remove("is-visible");
|
|
1049
|
+
paramTooltipRoot.setAttribute("aria-hidden", "true");
|
|
1050
|
+
if (activeParamTooltipTrigger) {
|
|
1051
|
+
activeParamTooltipTrigger.setAttribute("aria-expanded", "false");
|
|
1052
|
+
}
|
|
1053
|
+
activeParamTooltipTrigger = null;
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
function scheduleParamTooltipHide() {
|
|
1057
|
+
if (paramTooltipHideTimer) {
|
|
1058
|
+
window.clearTimeout(paramTooltipHideTimer);
|
|
1059
|
+
}
|
|
1060
|
+
paramTooltipHideTimer = window.setTimeout(() => {
|
|
1061
|
+
hideParamTooltip();
|
|
1062
|
+
}, 95);
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
function positionParamTooltip(trigger) {
|
|
1066
|
+
if (!paramTooltipRoot || !trigger) return;
|
|
1067
|
+
const viewportPadding = 8;
|
|
1068
|
+
const spacing = 10;
|
|
1069
|
+
const triggerRect = trigger.getBoundingClientRect();
|
|
1070
|
+
const tooltipRect = paramTooltipRoot.getBoundingClientRect();
|
|
1071
|
+
let left = triggerRect.left + (triggerRect.width / 2) - (tooltipRect.width / 2);
|
|
1072
|
+
left = Math.max(viewportPadding, Math.min(left, window.innerWidth - tooltipRect.width - viewportPadding));
|
|
1073
|
+
let top = triggerRect.top - tooltipRect.height - spacing;
|
|
1074
|
+
if (top < viewportPadding) {
|
|
1075
|
+
top = triggerRect.bottom + spacing;
|
|
1076
|
+
}
|
|
1077
|
+
if (top + tooltipRect.height > window.innerHeight - viewportPadding) {
|
|
1078
|
+
top = window.innerHeight - tooltipRect.height - viewportPadding;
|
|
1079
|
+
}
|
|
1080
|
+
paramTooltipRoot.style.left = Math.round(left) + "px";
|
|
1081
|
+
paramTooltipRoot.style.top = Math.round(top) + "px";
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
function showParamTooltip(trigger) {
|
|
1085
|
+
if (
|
|
1086
|
+
!paramTooltipRoot ||
|
|
1087
|
+
!paramTooltipLine ||
|
|
1088
|
+
!paramTooltipDescription ||
|
|
1089
|
+
!trigger
|
|
1090
|
+
) {
|
|
1091
|
+
return;
|
|
1092
|
+
}
|
|
1093
|
+
if (paramTooltipHideTimer) {
|
|
1094
|
+
window.clearTimeout(paramTooltipHideTimer);
|
|
1095
|
+
paramTooltipHideTimer = null;
|
|
1096
|
+
}
|
|
1097
|
+
const label = trigger.getAttribute("data-param-tooltip-label") || "Value";
|
|
1098
|
+
const value = trigger.getAttribute("data-param-tooltip-value") || "";
|
|
1099
|
+
const related = trigger.getAttribute("data-param-tooltip-related") || "";
|
|
1100
|
+
const description = trigger.getAttribute("data-param-tooltip-description") || "";
|
|
1101
|
+
if (activeParamTooltipTrigger && activeParamTooltipTrigger !== trigger) {
|
|
1102
|
+
activeParamTooltipTrigger.setAttribute("aria-expanded", "false");
|
|
1103
|
+
}
|
|
1104
|
+
activeParamTooltipTrigger = trigger;
|
|
1105
|
+
activeParamTooltipTrigger.setAttribute("aria-expanded", "true");
|
|
1106
|
+
const pathLabel = related ? " | path: " + related : "";
|
|
1107
|
+
paramTooltipLine.textContent = label + ": " + value + pathLabel;
|
|
1108
|
+
if (description.trim()) {
|
|
1109
|
+
paramTooltipDescription.textContent = description;
|
|
1110
|
+
paramTooltipDescription.classList.remove("hidden");
|
|
1111
|
+
} else {
|
|
1112
|
+
paramTooltipDescription.textContent = "";
|
|
1113
|
+
paramTooltipDescription.classList.add("hidden");
|
|
1114
|
+
}
|
|
1115
|
+
paramTooltipRoot.classList.add("is-visible");
|
|
1116
|
+
paramTooltipRoot.setAttribute("aria-hidden", "false");
|
|
1117
|
+
positionParamTooltip(trigger);
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
function registerParamTooltipTargets(scope) {
|
|
1121
|
+
if (!scope) return;
|
|
1122
|
+
const targets = scope.querySelectorAll("[data-param-tooltip-value]");
|
|
1123
|
+
for (const target of targets) {
|
|
1124
|
+
target.addEventListener("click", (event) => {
|
|
1125
|
+
event.preventDefault();
|
|
1126
|
+
if (
|
|
1127
|
+
activeParamTooltipTrigger === target &&
|
|
1128
|
+
paramTooltipRoot &&
|
|
1129
|
+
paramTooltipRoot.classList.contains("is-visible")
|
|
1130
|
+
) {
|
|
1131
|
+
hideParamTooltip();
|
|
1132
|
+
return;
|
|
1133
|
+
}
|
|
1134
|
+
showParamTooltip(target);
|
|
1135
|
+
});
|
|
1136
|
+
target.addEventListener("mouseenter", () => {
|
|
1137
|
+
showParamTooltip(target);
|
|
1138
|
+
});
|
|
1139
|
+
target.addEventListener("mouseleave", (event) => {
|
|
1140
|
+
const related = event.relatedTarget;
|
|
1141
|
+
if (paramTooltipRoot && related && paramTooltipRoot.contains(related)) return;
|
|
1142
|
+
scheduleParamTooltipHide();
|
|
1143
|
+
});
|
|
1144
|
+
target.addEventListener("focus", () => {
|
|
1145
|
+
showParamTooltip(target);
|
|
1146
|
+
});
|
|
1147
|
+
target.addEventListener("blur", (event) => {
|
|
1148
|
+
const related = event.relatedTarget;
|
|
1149
|
+
if (paramTooltipRoot && related && paramTooltipRoot.contains(related)) return;
|
|
1150
|
+
scheduleParamTooltipHide();
|
|
1151
|
+
});
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
|
|
622
1155
|
function renderParamSection(title, params) {
|
|
623
1156
|
if (!params.length) return "";
|
|
624
1157
|
let rows = "";
|
|
625
1158
|
for (const p of params) {
|
|
626
|
-
const
|
|
627
|
-
const
|
|
628
|
-
|
|
1159
|
+
const schema = resolveSchemaRef(p.schema || {});
|
|
1160
|
+
const typeRaw = getSchemaTypeLabel(schema);
|
|
1161
|
+
const type = escapeHtml(typeRaw);
|
|
1162
|
+
const nameRaw = p.name || "";
|
|
1163
|
+
const name = escapeHtml(nameRaw);
|
|
1164
|
+
const tooltipName = escapeHtmlAttribute(nameRaw);
|
|
1165
|
+
const tooltipType = escapeHtmlAttribute(typeRaw);
|
|
1166
|
+
const tooltipDescription = (typeof p.description === "string" && p.description.trim())
|
|
1167
|
+
? escapeHtmlAttribute(p.description.trim())
|
|
1168
|
+
: (typeof schema.description === "string" && schema.description.trim())
|
|
1169
|
+
? escapeHtmlAttribute(schema.description.trim())
|
|
1170
|
+
: "";
|
|
1171
|
+
const desc = (typeof p.description === "string" && p.description.trim())
|
|
1172
|
+
? '<p class="text-xs opacity-60 mt-0.5 leading-snug">' + renderMarkdown(p.description.trim()) + '</p>'
|
|
1173
|
+
: "";
|
|
1174
|
+
const extra = buildSchemaExtra(schema);
|
|
1175
|
+
rows +=
|
|
1176
|
+
'<div class="param-row py-2 border-b border-light-border/50 dark:border-dark-border/50">' +
|
|
1177
|
+
'<div class="param-row-head">' +
|
|
1178
|
+
'<div class="param-row-main">' +
|
|
1179
|
+
'<button type="button" class="param-tooltip-trigger param-name-trigger" data-param-tooltip-label="Parameter" data-param-tooltip-value="' +
|
|
1180
|
+
tooltipName +
|
|
1181
|
+
'" data-param-tooltip-description="' +
|
|
1182
|
+
tooltipDescription +
|
|
1183
|
+
'" aria-expanded="false">' +
|
|
1184
|
+
'<code class="text-sm font-mono param-name-text">' +
|
|
1185
|
+
name +
|
|
1186
|
+
"</code></button>" +
|
|
1187
|
+
'<span class="text-xs text-brand shrink-0">' +
|
|
1188
|
+
(p.required ? "required" : "optional") +
|
|
1189
|
+
"</span></div>" +
|
|
1190
|
+
'<button type="button" class="param-tooltip-trigger param-type-fade text-xs font-mono opacity-60" data-param-tooltip-label="Type" data-param-tooltip-value="' +
|
|
1191
|
+
tooltipType +
|
|
1192
|
+
'" data-param-tooltip-description="' +
|
|
1193
|
+
tooltipDescription +
|
|
1194
|
+
'" aria-expanded="false">' +
|
|
1195
|
+
type +
|
|
1196
|
+
"</button></div>" +
|
|
1197
|
+
desc +
|
|
1198
|
+
extra +
|
|
1199
|
+
"</div>";
|
|
629
1200
|
}
|
|
630
1201
|
return '<div><h3 class="text-sm font-semibold mb-3 flex items-center border-b border-light-border dark:border-dark-border pb-2">' + escapeHtml(title) + "</h3>" + rows + "</div>";
|
|
631
1202
|
}
|
|
632
1203
|
|
|
633
1204
|
function getSchemaTypeLabel(schema) {
|
|
634
|
-
|
|
635
|
-
if (
|
|
636
|
-
if (
|
|
637
|
-
if (
|
|
638
|
-
if (
|
|
639
|
-
if (
|
|
640
|
-
if (Array.isArray(
|
|
641
|
-
if (Array.isArray(
|
|
1205
|
+
const resolved = resolveSchemaRef(schema);
|
|
1206
|
+
if (!resolved || typeof resolved !== "object") return "unknown";
|
|
1207
|
+
if (Array.isArray(resolved.type)) return resolved.type.join(" | ");
|
|
1208
|
+
if (resolved.type) return String(resolved.type);
|
|
1209
|
+
if (resolved.properties) return "object";
|
|
1210
|
+
if (resolved.items) return "array";
|
|
1211
|
+
if (Array.isArray(resolved.oneOf)) return "oneOf";
|
|
1212
|
+
if (Array.isArray(resolved.anyOf)) return "anyOf";
|
|
1213
|
+
if (Array.isArray(resolved.allOf)) return "allOf";
|
|
642
1214
|
return "unknown";
|
|
643
1215
|
}
|
|
644
1216
|
|
|
1217
|
+
function buildSchemaExtra(schema) {
|
|
1218
|
+
const resolved = resolveSchemaRef(schema);
|
|
1219
|
+
if (!resolved || typeof resolved !== "object") return "";
|
|
1220
|
+
const chips = [];
|
|
1221
|
+
if (resolved.format) chips.push(escapeHtml(String(resolved.format)));
|
|
1222
|
+
if (Array.isArray(resolved.enum) && resolved.enum.length > 0) {
|
|
1223
|
+
const shown = resolved.enum.slice(0, 5).map(function(v) { return escapeHtml(JSON.stringify(v)); });
|
|
1224
|
+
chips.push(shown.join(" | ") + (resolved.enum.length > 5 ? " \u2026" : ""));
|
|
1225
|
+
}
|
|
1226
|
+
if (resolved.minimum !== undefined) chips.push("min: " + resolved.minimum);
|
|
1227
|
+
if (resolved.maximum !== undefined) chips.push("max: " + resolved.maximum);
|
|
1228
|
+
if (typeof resolved.exclusiveMinimum === "number") chips.push(">" + resolved.exclusiveMinimum);
|
|
1229
|
+
if (typeof resolved.exclusiveMaximum === "number") chips.push("<" + resolved.exclusiveMaximum);
|
|
1230
|
+
if (resolved.minLength !== undefined) chips.push("minLen: " + resolved.minLength);
|
|
1231
|
+
if (resolved.maxLength !== undefined) chips.push("maxLen: " + resolved.maxLength);
|
|
1232
|
+
if (resolved.minItems !== undefined) chips.push("minItems: " + resolved.minItems);
|
|
1233
|
+
if (resolved.maxItems !== undefined) chips.push("maxItems: " + resolved.maxItems);
|
|
1234
|
+
if (resolved.uniqueItems) chips.push("unique");
|
|
1235
|
+
if (resolved.pattern) chips.push("/" + escapeHtml(String(resolved.pattern)) + "/");
|
|
1236
|
+
if (!chips.length) return "";
|
|
1237
|
+
return '<div class="flex flex-wrap gap-1 mt-1.5">' +
|
|
1238
|
+
chips.map(function(c) {
|
|
1239
|
+
return '<span class="text-[10px] px-1.5 py-0.5 rounded bg-black/5 dark:bg-white/5 font-mono opacity-80">' + c + '</span>';
|
|
1240
|
+
}).join("") +
|
|
1241
|
+
'</div>';
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
function resolveSchemaRef(schema, visitedRefs) {
|
|
1245
|
+
if (!schema || typeof schema !== "object") return schema;
|
|
1246
|
+
const ref = typeof schema.$ref === "string" ? schema.$ref : "";
|
|
1247
|
+
if (!ref || !ref.startsWith("#/components/schemas/")) {
|
|
1248
|
+
return schema;
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
const seen = visitedRefs || new Set();
|
|
1252
|
+
if (seen.has(ref)) return schema;
|
|
1253
|
+
seen.add(ref);
|
|
1254
|
+
|
|
1255
|
+
const parts = ref.split("/");
|
|
1256
|
+
const schemaName = parts[parts.length - 1];
|
|
1257
|
+
const referenced = spec && spec.components && spec.components.schemas && spec.components.schemas[schemaName];
|
|
1258
|
+
if (!referenced || typeof referenced !== "object") return schema;
|
|
1259
|
+
|
|
1260
|
+
const merged = Object.assign({}, referenced, schema);
|
|
1261
|
+
delete merged.$ref;
|
|
1262
|
+
return resolveSchemaRef(merged, seen);
|
|
1263
|
+
}
|
|
1264
|
+
|
|
645
1265
|
function buildSchemaChildren(schema) {
|
|
646
|
-
|
|
1266
|
+
const resolved = resolveSchemaRef(schema);
|
|
1267
|
+
if (!resolved || typeof resolved !== "object") return [];
|
|
647
1268
|
|
|
648
1269
|
const children = [];
|
|
649
1270
|
|
|
650
|
-
if (
|
|
1271
|
+
if (resolved.properties && typeof resolved.properties === "object") {
|
|
651
1272
|
const requiredSet = new Set(
|
|
652
|
-
Array.isArray(
|
|
1273
|
+
Array.isArray(resolved.required) ? resolved.required : [],
|
|
653
1274
|
);
|
|
654
|
-
for (const [name, childSchema] of Object.entries(
|
|
1275
|
+
for (const [name, childSchema] of Object.entries(resolved.properties)) {
|
|
1276
|
+
const childDef = childSchema || {};
|
|
1277
|
+
const isArrayType = Array.isArray(childDef.type)
|
|
1278
|
+
? childDef.type.includes("array")
|
|
1279
|
+
: childDef.type === "array";
|
|
1280
|
+
const isArrayLike = isArrayType || childDef.items !== undefined;
|
|
655
1281
|
children.push({
|
|
656
|
-
name,
|
|
657
|
-
schema:
|
|
1282
|
+
name: isArrayLike ? (name + "[]") : name,
|
|
1283
|
+
schema: childDef,
|
|
658
1284
|
required: requiredSet.has(name),
|
|
659
1285
|
});
|
|
660
1286
|
}
|
|
661
1287
|
}
|
|
662
1288
|
|
|
663
|
-
if (
|
|
1289
|
+
if (resolved.items) {
|
|
664
1290
|
children.push({
|
|
665
|
-
name:
|
|
666
|
-
schema:
|
|
1291
|
+
name: getArrayItemNodeName(resolved.items),
|
|
1292
|
+
schema: resolved.items,
|
|
667
1293
|
required: true,
|
|
668
1294
|
});
|
|
669
1295
|
}
|
|
@@ -671,45 +1297,100 @@ ${t.join(`,
|
|
|
671
1297
|
return children;
|
|
672
1298
|
}
|
|
673
1299
|
|
|
674
|
-
function
|
|
675
|
-
|
|
676
|
-
const
|
|
1300
|
+
function getArrayItemNodeName(itemSchema) {
|
|
1301
|
+
if (!itemSchema || typeof itemSchema !== "object") return "item";
|
|
1302
|
+
const title =
|
|
1303
|
+
typeof itemSchema.title === "string" && itemSchema.title.trim()
|
|
1304
|
+
? itemSchema.title.trim()
|
|
1305
|
+
: "";
|
|
1306
|
+
if (title) return title;
|
|
1307
|
+
|
|
1308
|
+
const ref =
|
|
1309
|
+
typeof itemSchema.$ref === "string" && itemSchema.$ref.trim()
|
|
1310
|
+
? itemSchema.$ref.trim()
|
|
1311
|
+
: "";
|
|
1312
|
+
if (ref) {
|
|
1313
|
+
const parts = ref.split("/").filter(Boolean);
|
|
1314
|
+
const last = parts[parts.length - 1];
|
|
1315
|
+
if (last) return last;
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
const typeLabel = getSchemaTypeLabel(itemSchema);
|
|
1319
|
+
if (typeLabel && typeLabel !== "unknown") return typeLabel;
|
|
1320
|
+
return "type";
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
function renderSchemaFieldNode(field, depth, parentPath) {
|
|
1324
|
+
const schema = resolveSchemaRef(field.schema || {});
|
|
1325
|
+
const nameRaw = field.name || "field";
|
|
1326
|
+
const name = escapeHtml(nameRaw);
|
|
677
1327
|
const requiredLabel = field.required ? "required" : "optional";
|
|
678
|
-
const
|
|
1328
|
+
const typeRaw = getSchemaTypeLabel(schema);
|
|
1329
|
+
const type = escapeHtml(typeRaw);
|
|
1330
|
+
const tooltipName = escapeHtmlAttribute(nameRaw);
|
|
1331
|
+
const tooltipType = escapeHtmlAttribute(typeRaw);
|
|
1332
|
+
const fieldPath = parentPath ? (parentPath + "." + nameRaw) : nameRaw;
|
|
1333
|
+
const tooltipPath = escapeHtmlAttribute(fieldPath);
|
|
1334
|
+
const tooltipDescription = (typeof schema.description === "string" && schema.description.trim())
|
|
1335
|
+
? escapeHtmlAttribute(schema.description.trim())
|
|
1336
|
+
: "";
|
|
679
1337
|
const children = buildSchemaChildren(schema);
|
|
680
1338
|
const padding = depth * 14;
|
|
1339
|
+
const extra = buildSchemaExtra(schema);
|
|
681
1340
|
|
|
682
1341
|
if (!children.length) {
|
|
683
1342
|
return (
|
|
684
|
-
'<div class="py-2 border-b border-light-border/50 dark:border-dark-border/50" style="padding-left:' +
|
|
1343
|
+
'<div class="param-row py-2 border-b border-light-border/50 dark:border-dark-border/50" style="padding-left:' +
|
|
685
1344
|
padding +
|
|
686
|
-
'px"><div class="
|
|
1345
|
+
'px"><div class="param-row-head"><div class="param-row-main">' +
|
|
1346
|
+
'<button type="button" class="param-tooltip-trigger param-name-trigger" data-param-tooltip-label="Field" data-param-tooltip-value="' +
|
|
1347
|
+
tooltipName +
|
|
1348
|
+
'" data-param-tooltip-related="' +
|
|
1349
|
+
tooltipPath +
|
|
1350
|
+
'" data-param-tooltip-description="' +
|
|
1351
|
+
tooltipDescription +
|
|
1352
|
+
'" aria-expanded="false"><code class="text-sm font-mono param-name-text">' +
|
|
687
1353
|
name +
|
|
688
|
-
'</code><span class="text-xs text-brand
|
|
1354
|
+
'</code></button><span class="text-xs text-brand shrink-0">' +
|
|
689
1355
|
requiredLabel +
|
|
690
|
-
'</span></div><
|
|
1356
|
+
'</span></div><button type="button" class="param-tooltip-trigger param-type-fade text-xs font-mono opacity-60" data-param-tooltip-label="Type" data-param-tooltip-value="' +
|
|
1357
|
+
tooltipType +
|
|
1358
|
+
'" data-param-tooltip-description="' +
|
|
1359
|
+
tooltipDescription +
|
|
1360
|
+
'" aria-expanded="false">' +
|
|
691
1361
|
type +
|
|
692
|
-
"</
|
|
1362
|
+
"</button></div>" + extra + "</div>"
|
|
693
1363
|
);
|
|
694
1364
|
}
|
|
695
1365
|
|
|
696
1366
|
let nested = "";
|
|
697
1367
|
for (const child of children) {
|
|
698
|
-
nested += renderSchemaFieldNode(child, depth + 1);
|
|
1368
|
+
nested += renderSchemaFieldNode(child, depth + 1, fieldPath);
|
|
699
1369
|
}
|
|
700
1370
|
|
|
701
1371
|
return (
|
|
702
|
-
'<details
|
|
703
|
-
'<summary class="list-none cursor-pointer py-2
|
|
1372
|
+
'<details open>' +
|
|
1373
|
+
'<summary class="list-none cursor-pointer py-2 border-b border-light-border/50 dark:border-dark-border/50" style="padding-left:' +
|
|
704
1374
|
padding +
|
|
705
|
-
'px"><div class="
|
|
1375
|
+
'px"><div class="param-row-head"><div class="param-row-main"><span class="text-xs opacity-70 shrink-0">\u25BE</span>' +
|
|
1376
|
+
'<button type="button" class="param-tooltip-trigger param-name-trigger" data-param-tooltip-label="Field" data-param-tooltip-value="' +
|
|
1377
|
+
tooltipName +
|
|
1378
|
+
'" data-param-tooltip-related="' +
|
|
1379
|
+
tooltipPath +
|
|
1380
|
+
'" data-param-tooltip-description="' +
|
|
1381
|
+
tooltipDescription +
|
|
1382
|
+
'" aria-expanded="false"><code class="text-sm font-mono param-name-text">' +
|
|
706
1383
|
name +
|
|
707
|
-
'</code><span class="text-xs text-brand">' +
|
|
1384
|
+
'</code></button><span class="text-xs text-brand shrink-0">' +
|
|
708
1385
|
requiredLabel +
|
|
709
|
-
'</span></div><
|
|
1386
|
+
'</span></div><button type="button" class="param-tooltip-trigger param-type-fade text-xs font-mono opacity-60" data-param-tooltip-label="Type" data-param-tooltip-value="' +
|
|
1387
|
+
tooltipType +
|
|
1388
|
+
'" data-param-tooltip-description="' +
|
|
1389
|
+
tooltipDescription +
|
|
1390
|
+
'" aria-expanded="false">' +
|
|
710
1391
|
type +
|
|
711
|
-
"</
|
|
712
|
-
|
|
1392
|
+
"</button></div>" + extra + "</summary>" +
|
|
1393
|
+
"<div>" +
|
|
713
1394
|
nested +
|
|
714
1395
|
"</div></details>"
|
|
715
1396
|
);
|
|
@@ -722,7 +1403,7 @@ ${t.join(`,
|
|
|
722
1403
|
|
|
723
1404
|
let rows = "";
|
|
724
1405
|
for (const child of rootChildren) {
|
|
725
|
-
rows += renderSchemaFieldNode(child, 0);
|
|
1406
|
+
rows += renderSchemaFieldNode(child, 0, "");
|
|
726
1407
|
}
|
|
727
1408
|
|
|
728
1409
|
return (
|
|
@@ -749,27 +1430,40 @@ ${t.join(`,
|
|
|
749
1430
|
const responseDef = responses[statusCode];
|
|
750
1431
|
if (!responseDef || typeof responseDef !== "object") continue;
|
|
751
1432
|
|
|
1433
|
+
const responseDesc = (typeof responseDef.description === "string" && responseDef.description.trim())
|
|
1434
|
+
? responseDef.description.trim()
|
|
1435
|
+
: "";
|
|
1436
|
+
|
|
752
1437
|
const jsonSchema =
|
|
753
1438
|
responseDef.content &&
|
|
754
1439
|
responseDef.content["application/json"] &&
|
|
755
1440
|
responseDef.content["application/json"].schema;
|
|
756
1441
|
|
|
757
|
-
if (!jsonSchema || typeof jsonSchema !== "object") continue;
|
|
758
|
-
|
|
759
|
-
const rootChildren = buildSchemaChildren(jsonSchema);
|
|
760
|
-
if (!rootChildren.length) continue;
|
|
761
|
-
|
|
762
1442
|
let rows = "";
|
|
763
|
-
|
|
764
|
-
|
|
1443
|
+
if (jsonSchema && typeof jsonSchema === "object") {
|
|
1444
|
+
const rootChildren = buildSchemaChildren(jsonSchema);
|
|
1445
|
+
for (const child of rootChildren) {
|
|
1446
|
+
rows += renderSchemaFieldNode(child, 0, "");
|
|
1447
|
+
}
|
|
765
1448
|
}
|
|
766
1449
|
|
|
1450
|
+
if (!responseDesc && !rows) continue;
|
|
1451
|
+
|
|
1452
|
+
const descHtml = responseDesc
|
|
1453
|
+
? ' <span class="normal-case font-sans opacity-70 ml-1">\u2014 ' + escapeHtml(responseDesc) + '</span>'
|
|
1454
|
+
: "";
|
|
1455
|
+
const contentHtml = rows || '<p class="text-xs opacity-60 mt-1">No schema fields</p>';
|
|
1456
|
+
|
|
767
1457
|
sections +=
|
|
768
|
-
'<
|
|
1458
|
+
'<details class="mb-4">' +
|
|
1459
|
+
'<summary class="list-none cursor-pointer">' +
|
|
1460
|
+
'<h4 class="text-xs font-mono uppercase tracking-wider opacity-70 mb-2">Status ' +
|
|
769
1461
|
escapeHtml(statusCode) +
|
|
1462
|
+
descHtml +
|
|
770
1463
|
"</h4>" +
|
|
771
|
-
|
|
772
|
-
|
|
1464
|
+
"</summary>" +
|
|
1465
|
+
contentHtml +
|
|
1466
|
+
"</details>";
|
|
773
1467
|
}
|
|
774
1468
|
|
|
775
1469
|
if (!sections) return "";
|
|
@@ -861,6 +1555,7 @@ ${t.join(`,
|
|
|
861
1555
|
"w-full text-xs px-2.5 py-2 rounded border border-light-border dark:border-dark-border bg-light-bg dark:bg-dark-bg focus:outline-none focus:border-brand dark:focus:border-brand transition-colors font-mono";
|
|
862
1556
|
keyInput.addEventListener("input", () => {
|
|
863
1557
|
entry.key = keyInput.value;
|
|
1558
|
+
saveHeaders();
|
|
864
1559
|
updateRequestPreview();
|
|
865
1560
|
});
|
|
866
1561
|
|
|
@@ -875,6 +1570,7 @@ ${t.join(`,
|
|
|
875
1570
|
"w-full text-xs px-2.5 py-2 rounded border border-light-border dark:border-dark-border bg-light-bg dark:bg-dark-bg focus:outline-none focus:border-brand dark:focus:border-brand transition-colors font-mono";
|
|
876
1571
|
valueInput.addEventListener("input", () => {
|
|
877
1572
|
entry.value = valueInput.value;
|
|
1573
|
+
saveHeaders();
|
|
878
1574
|
updateRequestPreview();
|
|
879
1575
|
});
|
|
880
1576
|
|
|
@@ -888,6 +1584,7 @@ ${t.join(`,
|
|
|
888
1584
|
'<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 12h12"></path></svg>';
|
|
889
1585
|
removeButton.addEventListener("click", () => {
|
|
890
1586
|
requestHeaders.splice(index, 1);
|
|
1587
|
+
saveHeaders();
|
|
891
1588
|
renderHeaderInputs();
|
|
892
1589
|
updateRequestPreview();
|
|
893
1590
|
});
|
|
@@ -904,15 +1601,32 @@ ${t.join(`,
|
|
|
904
1601
|
return Object.keys(headers).some((key) => key.toLowerCase() === target);
|
|
905
1602
|
}
|
|
906
1603
|
|
|
907
|
-
function
|
|
908
|
-
const
|
|
1604
|
+
function buildCookieHeaderValue(cookieValues) {
|
|
1605
|
+
const entries = Object.entries(cookieValues);
|
|
1606
|
+
if (!entries.length) return "";
|
|
1607
|
+
return entries
|
|
1608
|
+
.map(([name, value]) => String(name) + "=" + encodeURIComponent(String(value)))
|
|
1609
|
+
.join("; ");
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1612
|
+
function getRequestHeadersObject(op) {
|
|
1613
|
+
const auth = getAuthHeaders(op);
|
|
1614
|
+
const authCookies = getAuthCookieParams(op);
|
|
1615
|
+
if (Object.keys(authCookies).length > 0) {
|
|
1616
|
+
const cookieHeader = buildCookieHeaderValue(authCookies);
|
|
1617
|
+
if (cookieHeader) {
|
|
1618
|
+
auth["Cookie"] = cookieHeader;
|
|
1619
|
+
}
|
|
1620
|
+
}
|
|
1621
|
+
const manual = {};
|
|
909
1622
|
for (const entry of requestHeaders) {
|
|
910
1623
|
const key = String(entry.key || "").trim();
|
|
911
1624
|
const value = String(entry.value || "").trim();
|
|
912
1625
|
if (!key || !value) continue;
|
|
913
|
-
|
|
1626
|
+
manual[key] = value;
|
|
914
1627
|
}
|
|
915
|
-
|
|
1628
|
+
// Auth provides defaults; manual headers win on conflict
|
|
1629
|
+
return Object.assign({}, auth, manual);
|
|
916
1630
|
}
|
|
917
1631
|
|
|
918
1632
|
function buildCurl(op, headers, body, requestPath) {
|
|
@@ -949,6 +1663,33 @@ ${t.join(`,
|
|
|
949
1663
|
.replace(/>/g, ">");
|
|
950
1664
|
}
|
|
951
1665
|
|
|
1666
|
+
function escapeHtmlAttribute(value) {
|
|
1667
|
+
return String(value)
|
|
1668
|
+
.replace(/&/g, "&")
|
|
1669
|
+
.replace(/</g, "<")
|
|
1670
|
+
.replace(/>/g, ">")
|
|
1671
|
+
.replace(/"/g, """)
|
|
1672
|
+
.replace(/'/g, "'");
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
function renderMarkdown(text) {
|
|
1676
|
+
if (!text || typeof text !== "string") return "";
|
|
1677
|
+
var s = escapeHtml(text);
|
|
1678
|
+
// inline code \u2014 process first to protect content inside backticks
|
|
1679
|
+
s = s.replace(/\`([^\`\\n]+)\`/g, '<code class="text-xs font-mono bg-black/5 dark:bg-white/5 px-1 py-0.5 rounded">$1</code>');
|
|
1680
|
+
// bold **text**
|
|
1681
|
+
s = s.replace(/\\*\\*([^*\\n]+)\\*\\*/g, '<strong>$1</strong>');
|
|
1682
|
+
// italic *text*
|
|
1683
|
+
s = s.replace(/\\*([^*\\n]+)\\*/g, '<em>$1</em>');
|
|
1684
|
+
// links [text](url)
|
|
1685
|
+
s = s.replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, function(m, txt, url) {
|
|
1686
|
+
var lc = url.toLowerCase().replace(/\\s/g, "");
|
|
1687
|
+
if (lc.indexOf("javascript:") === 0 || lc.indexOf("data:") === 0 || lc.indexOf("vbscript:") === 0) return txt;
|
|
1688
|
+
return '<a href="' + url.replace(/"/g, '"') + '" target="_blank" rel="noopener noreferrer" class="text-brand hover:underline">' + txt + '</a>';
|
|
1689
|
+
});
|
|
1690
|
+
return s;
|
|
1691
|
+
}
|
|
1692
|
+
|
|
952
1693
|
function toPrettyJson(value) {
|
|
953
1694
|
const trimmed = (value || "").trim();
|
|
954
1695
|
if (!trimmed) return null;
|
|
@@ -1082,10 +1823,10 @@ ${t.join(`,
|
|
|
1082
1823
|
|
|
1083
1824
|
const { path, query } = getOperationParameterGroups(selected);
|
|
1084
1825
|
const values = getParameterValues(selected);
|
|
1085
|
-
const requestPath = buildRequestPath(selected, path, query, values);
|
|
1826
|
+
const requestPath = buildRequestPath(selected, path, query, values, getAuthQueryParams(selected));
|
|
1086
1827
|
const bodyInput = document.getElementById("body-input");
|
|
1087
1828
|
const body = bodyInput ? bodyInput.value.trim() : "";
|
|
1088
|
-
const headers = getRequestHeadersObject();
|
|
1829
|
+
const headers = getRequestHeadersObject(selected);
|
|
1089
1830
|
if (body && !hasHeaderName(headers, "Content-Type")) {
|
|
1090
1831
|
headers["Content-Type"] = "application/json";
|
|
1091
1832
|
}
|
|
@@ -1136,8 +1877,13 @@ ${t.join(`,
|
|
|
1136
1877
|
}
|
|
1137
1878
|
setResponseContent("", "", false);
|
|
1138
1879
|
|
|
1880
|
+
const deprecatedBanner = document.getElementById("deprecated-banner");
|
|
1881
|
+
if (deprecatedBanner) {
|
|
1882
|
+
deprecatedBanner.classList.toggle("hidden", !op.deprecated);
|
|
1883
|
+
}
|
|
1884
|
+
|
|
1139
1885
|
document.getElementById("tag-title").textContent = selected.tag;
|
|
1140
|
-
document.getElementById("tag-description").
|
|
1886
|
+
document.getElementById("tag-description").innerHTML = op.description ? renderMarkdown(op.description) : "Interactive API documentation.";
|
|
1141
1887
|
const methodNode = document.getElementById("endpoint-method");
|
|
1142
1888
|
methodNode.textContent = selected.method;
|
|
1143
1889
|
methodNode.className = "px-2.5 py-0.5 rounded-full text-xs font-mono font-medium " + (methodBadge[selected.method] || methodBadgeDefault);
|
|
@@ -1154,7 +1900,13 @@ ${t.join(`,
|
|
|
1154
1900
|
|
|
1155
1901
|
html += renderRequestBodySchemaSection(reqSchema);
|
|
1156
1902
|
html += renderResponseSchemasSection(op.responses);
|
|
1157
|
-
document.getElementById("params-column")
|
|
1903
|
+
const paramsColumn = document.getElementById("params-column");
|
|
1904
|
+
if (paramsColumn) {
|
|
1905
|
+
hideParamTooltip();
|
|
1906
|
+
paramsColumn.innerHTML = html || '<div class="text-sm opacity-70">No parameters</div>';
|
|
1907
|
+
registerParamTooltipTargets(paramsColumn);
|
|
1908
|
+
}
|
|
1909
|
+
renderAuthPanel();
|
|
1158
1910
|
renderTryItParameterInputs(path, query);
|
|
1159
1911
|
renderHeaderInputs();
|
|
1160
1912
|
updateRequestPreview();
|
|
@@ -1165,6 +1917,24 @@ ${t.join(`,
|
|
|
1165
1917
|
document.getElementById("copy-curl").addEventListener("click", async () => {
|
|
1166
1918
|
try { await navigator.clipboard.writeText(document.getElementById("curl-code").textContent || ""); } catch {}
|
|
1167
1919
|
});
|
|
1920
|
+
if (paramTooltipRoot) {
|
|
1921
|
+
paramTooltipRoot.addEventListener("mouseenter", () => {
|
|
1922
|
+
if (paramTooltipHideTimer) {
|
|
1923
|
+
window.clearTimeout(paramTooltipHideTimer);
|
|
1924
|
+
paramTooltipHideTimer = null;
|
|
1925
|
+
}
|
|
1926
|
+
});
|
|
1927
|
+
paramTooltipRoot.addEventListener("mouseleave", () => {
|
|
1928
|
+
scheduleParamTooltipHide();
|
|
1929
|
+
});
|
|
1930
|
+
}
|
|
1931
|
+
document.addEventListener("pointerdown", (event) => {
|
|
1932
|
+
if (!paramTooltipRoot) return;
|
|
1933
|
+
const target = event.target;
|
|
1934
|
+
if (target && paramTooltipRoot.contains(target)) return;
|
|
1935
|
+
if (target && target.closest && target.closest("[data-param-tooltip-value]")) return;
|
|
1936
|
+
hideParamTooltip();
|
|
1937
|
+
});
|
|
1168
1938
|
document.getElementById("sidebar-search").addEventListener("input", (event) => {
|
|
1169
1939
|
sidebarSearchQuery = event.currentTarget.value || "";
|
|
1170
1940
|
renderSidebar();
|
|
@@ -1190,7 +1960,7 @@ ${t.join(`,
|
|
|
1190
1960
|
return;
|
|
1191
1961
|
}
|
|
1192
1962
|
|
|
1193
|
-
const requestPath = buildRequestPath(selected, path, query, values);
|
|
1963
|
+
const requestPath = buildRequestPath(selected, path, query, values, getAuthQueryParams(selected));
|
|
1194
1964
|
formatBodyJsonInput();
|
|
1195
1965
|
updateBodyJsonPresentation();
|
|
1196
1966
|
const op = selected.operation || {};
|
|
@@ -1199,7 +1969,7 @@ ${t.join(`,
|
|
|
1199
1969
|
const bodyInput = document.getElementById("body-input");
|
|
1200
1970
|
const body =
|
|
1201
1971
|
supportsBody && bodyInput ? bodyInput.value.trim() : "";
|
|
1202
|
-
const headers = getRequestHeadersObject();
|
|
1972
|
+
const headers = getRequestHeadersObject(selected);
|
|
1203
1973
|
if (body && !hasHeaderName(headers, "Content-Type")) {
|
|
1204
1974
|
headers["Content-Type"] = "application/json";
|
|
1205
1975
|
}
|
|
@@ -1207,7 +1977,13 @@ ${t.join(`,
|
|
|
1207
1977
|
setSubmitLoading(true);
|
|
1208
1978
|
try {
|
|
1209
1979
|
const requestStart = performance.now();
|
|
1210
|
-
|
|
1980
|
+
applyAuthCookies(selected);
|
|
1981
|
+
const response = await fetch(requestPath, {
|
|
1982
|
+
method: selected.method,
|
|
1983
|
+
headers,
|
|
1984
|
+
body: body || undefined,
|
|
1985
|
+
credentials: "same-origin",
|
|
1986
|
+
});
|
|
1211
1987
|
const text = await response.text();
|
|
1212
1988
|
const responseTimeMs = Math.round(performance.now() - requestStart);
|
|
1213
1989
|
const contentType = response.headers.get("content-type") || "unknown";
|
|
@@ -1283,6 +2059,7 @@ ${t.join(`,
|
|
|
1283
2059
|
|
|
1284
2060
|
document.getElementById("add-header-btn").addEventListener("click", () => {
|
|
1285
2061
|
requestHeaders.push({ key: "", value: "" });
|
|
2062
|
+
saveHeaders();
|
|
1286
2063
|
renderHeaderInputs();
|
|
1287
2064
|
updateRequestPreview();
|
|
1288
2065
|
});
|
|
@@ -1396,12 +2173,21 @@ ${t.join(`,
|
|
|
1396
2173
|
setMobileSidebarOpen(false);
|
|
1397
2174
|
});
|
|
1398
2175
|
window.addEventListener("resize", () => {
|
|
2176
|
+
if (activeParamTooltipTrigger) {
|
|
2177
|
+
positionParamTooltip(activeParamTooltipTrigger);
|
|
2178
|
+
}
|
|
1399
2179
|
if (window.innerWidth >= 768 && isMobileSidebarOpen) {
|
|
1400
2180
|
setMobileSidebarOpen(false);
|
|
1401
2181
|
}
|
|
1402
2182
|
});
|
|
2183
|
+
window.addEventListener("scroll", () => {
|
|
2184
|
+
if (activeParamTooltipTrigger) {
|
|
2185
|
+
positionParamTooltip(activeParamTooltipTrigger);
|
|
2186
|
+
}
|
|
2187
|
+
}, true);
|
|
1403
2188
|
document.addEventListener("keydown", (event) => {
|
|
1404
2189
|
if (event.key === "Escape") {
|
|
2190
|
+
hideParamTooltip();
|
|
1405
2191
|
if (isMobileSidebarOpen) {
|
|
1406
2192
|
setMobileSidebarOpen(false);
|
|
1407
2193
|
}
|
|
@@ -1426,9 +2212,446 @@ ${t.join(`,
|
|
|
1426
2212
|
}
|
|
1427
2213
|
});
|
|
1428
2214
|
|
|
2215
|
+
function getOperationSecurityRequirements(op) {
|
|
2216
|
+
const operationSecurity = op && op.operation && Array.isArray(op.operation.security)
|
|
2217
|
+
? op.operation.security
|
|
2218
|
+
: null;
|
|
2219
|
+
if (operationSecurity) {
|
|
2220
|
+
return operationSecurity;
|
|
2221
|
+
}
|
|
2222
|
+
return Array.isArray(spec.security) ? spec.security : [];
|
|
2223
|
+
}
|
|
2224
|
+
|
|
2225
|
+
function getAuthSelectionKeyForOperation(op) {
|
|
2226
|
+
if (!op) return "";
|
|
2227
|
+
return getOperationKey(op);
|
|
2228
|
+
}
|
|
2229
|
+
|
|
2230
|
+
function getAuthSchemeOptionsForOperation(op) {
|
|
2231
|
+
const requirements = getOperationSecurityRequirements(op).filter((requirement) =>
|
|
2232
|
+
requirement && typeof requirement === "object" && !Array.isArray(requirement)
|
|
2233
|
+
);
|
|
2234
|
+
if (!requirements.length) return [];
|
|
2235
|
+
|
|
2236
|
+
const seen = new Set();
|
|
2237
|
+
const options = [];
|
|
2238
|
+
for (const requirement of requirements) {
|
|
2239
|
+
for (const schemeName of Object.keys(requirement)) {
|
|
2240
|
+
if (!Object.prototype.hasOwnProperty.call(authSchemes, schemeName)) continue;
|
|
2241
|
+
if (seen.has(schemeName)) continue;
|
|
2242
|
+
seen.add(schemeName);
|
|
2243
|
+
options.push(schemeName);
|
|
2244
|
+
}
|
|
2245
|
+
}
|
|
2246
|
+
return options;
|
|
2247
|
+
}
|
|
2248
|
+
|
|
2249
|
+
function getSelectedAuthSchemeForOperation(op) {
|
|
2250
|
+
const selectionKey = getAuthSelectionKeyForOperation(op);
|
|
2251
|
+
if (!selectionKey) return null;
|
|
2252
|
+
|
|
2253
|
+
const selectedScheme = authSelectionState[selectionKey];
|
|
2254
|
+
if (!selectedScheme || typeof selectedScheme !== "string") return null;
|
|
2255
|
+
|
|
2256
|
+
const options = Object.keys(authSchemes);
|
|
2257
|
+
if (!options.includes(selectedScheme)) {
|
|
2258
|
+
delete authSelectionState[selectionKey];
|
|
2259
|
+
saveAuthSelectionState();
|
|
2260
|
+
return null;
|
|
2261
|
+
}
|
|
2262
|
+
|
|
2263
|
+
return selectedScheme;
|
|
2264
|
+
}
|
|
2265
|
+
|
|
2266
|
+
function setSelectedAuthSchemeForOperation(op, schemeName) {
|
|
2267
|
+
const selectionKey = getAuthSelectionKeyForOperation(op);
|
|
2268
|
+
if (!selectionKey) return;
|
|
2269
|
+
|
|
2270
|
+
if (!schemeName) {
|
|
2271
|
+
delete authSelectionState[selectionKey];
|
|
2272
|
+
} else {
|
|
2273
|
+
authSelectionState[selectionKey] = schemeName;
|
|
2274
|
+
}
|
|
2275
|
+
saveAuthSelectionState();
|
|
2276
|
+
}
|
|
2277
|
+
|
|
2278
|
+
function hasAuthStateForScheme(schemeName) {
|
|
2279
|
+
const scheme = authSchemes[schemeName];
|
|
2280
|
+
if (!scheme) return false;
|
|
2281
|
+
|
|
2282
|
+
const state = authState[schemeName] || {};
|
|
2283
|
+
const type = (scheme.type || "").toLowerCase();
|
|
2284
|
+
const httpScheme = (scheme.scheme || "").toLowerCase();
|
|
2285
|
+
|
|
2286
|
+
if (type === "http" && httpScheme === "basic") {
|
|
2287
|
+
return Boolean(state.username && state.password);
|
|
2288
|
+
}
|
|
2289
|
+
if (type === "http") {
|
|
2290
|
+
return Boolean(state.token);
|
|
2291
|
+
}
|
|
2292
|
+
if (type === "apikey") {
|
|
2293
|
+
return Boolean(state.value);
|
|
2294
|
+
}
|
|
2295
|
+
if (type === "oauth2" || type === "openidconnect") {
|
|
2296
|
+
return Boolean(state.token);
|
|
2297
|
+
}
|
|
2298
|
+
|
|
2299
|
+
return false;
|
|
2300
|
+
}
|
|
2301
|
+
|
|
2302
|
+
function chooseOperationSecurityRequirement(op) {
|
|
2303
|
+
const requirements = getOperationSecurityRequirements(op).filter((requirement) =>
|
|
2304
|
+
requirement && typeof requirement === "object" && !Array.isArray(requirement)
|
|
2305
|
+
);
|
|
2306
|
+
if (!requirements.length) return null;
|
|
2307
|
+
|
|
2308
|
+
const selectedScheme = getSelectedAuthSchemeForOperation(op);
|
|
2309
|
+
if (selectedScheme) {
|
|
2310
|
+
const selectedRequirement = requirements.find((requirement) =>
|
|
2311
|
+
Object.prototype.hasOwnProperty.call(requirement, selectedScheme)
|
|
2312
|
+
);
|
|
2313
|
+
if (selectedRequirement) return selectedRequirement;
|
|
2314
|
+
}
|
|
2315
|
+
|
|
2316
|
+
let bestRequirement = null;
|
|
2317
|
+
let bestScore = -1;
|
|
2318
|
+
|
|
2319
|
+
for (const requirement of requirements) {
|
|
2320
|
+
const schemeNames = Object.keys(requirement).filter((schemeName) =>
|
|
2321
|
+
Object.prototype.hasOwnProperty.call(authSchemes, schemeName)
|
|
2322
|
+
);
|
|
2323
|
+
if (!schemeNames.length) continue;
|
|
2324
|
+
|
|
2325
|
+
const providedCount = schemeNames.filter((schemeName) => hasAuthStateForScheme(schemeName)).length;
|
|
2326
|
+
const isComplete = providedCount === schemeNames.length;
|
|
2327
|
+
const score = isComplete ? 1000 + providedCount : providedCount;
|
|
2328
|
+
|
|
2329
|
+
if (score > bestScore) {
|
|
2330
|
+
bestScore = score;
|
|
2331
|
+
bestRequirement = requirement;
|
|
2332
|
+
}
|
|
2333
|
+
}
|
|
2334
|
+
|
|
2335
|
+
return bestRequirement || requirements[0];
|
|
2336
|
+
}
|
|
2337
|
+
|
|
2338
|
+
function getAuthSchemeNamesForOperation(op) {
|
|
2339
|
+
const schemeNames = Object.keys(authSchemes);
|
|
2340
|
+
if (!schemeNames.length) return [];
|
|
2341
|
+
|
|
2342
|
+
const selectedScheme = getSelectedAuthSchemeForOperation(op);
|
|
2343
|
+
if (selectedScheme) {
|
|
2344
|
+
const requirement = chooseOperationSecurityRequirement(op);
|
|
2345
|
+
if (requirement && Object.prototype.hasOwnProperty.call(requirement, selectedScheme)) {
|
|
2346
|
+
return Object.keys(requirement).filter((schemeName) =>
|
|
2347
|
+
Object.prototype.hasOwnProperty.call(authSchemes, schemeName)
|
|
2348
|
+
);
|
|
2349
|
+
}
|
|
2350
|
+
return [selectedScheme];
|
|
2351
|
+
}
|
|
2352
|
+
|
|
2353
|
+
const requirement = chooseOperationSecurityRequirement(op);
|
|
2354
|
+
if (!requirement) return [];
|
|
2355
|
+
|
|
2356
|
+
return Object.keys(requirement).filter((schemeName) =>
|
|
2357
|
+
Object.prototype.hasOwnProperty.call(authSchemes, schemeName)
|
|
2358
|
+
);
|
|
2359
|
+
}
|
|
2360
|
+
|
|
2361
|
+
function getAuthHeaders(op) {
|
|
2362
|
+
const headers = {};
|
|
2363
|
+
const schemeNames = getAuthSchemeNamesForOperation(op);
|
|
2364
|
+
const allSchemeNames = Object.keys(authSchemes);
|
|
2365
|
+
|
|
2366
|
+
if (!allSchemeNames.length) {
|
|
2367
|
+
const state = authState["__default__"] || {};
|
|
2368
|
+
if (state.token) headers["Authorization"] = "Bearer " + state.token;
|
|
2369
|
+
return headers;
|
|
2370
|
+
}
|
|
2371
|
+
if (!schemeNames.length) return headers;
|
|
2372
|
+
|
|
2373
|
+
for (const schemeName of schemeNames) {
|
|
2374
|
+
const scheme = authSchemes[schemeName];
|
|
2375
|
+
const state = authState[schemeName] || {};
|
|
2376
|
+
const type = (scheme.type || "").toLowerCase();
|
|
2377
|
+
const httpScheme = (scheme.scheme || "").toLowerCase();
|
|
2378
|
+
|
|
2379
|
+
if (type === "http" && httpScheme === "basic") {
|
|
2380
|
+
if (state.username && state.password) {
|
|
2381
|
+
try {
|
|
2382
|
+
headers["Authorization"] = "Basic " + btoa(state.username + ":" + state.password);
|
|
2383
|
+
} catch {}
|
|
2384
|
+
}
|
|
2385
|
+
} else if (type === "http") {
|
|
2386
|
+
if (state.token) headers["Authorization"] = "Bearer " + state.token;
|
|
2387
|
+
} else if (type === "apikey" && (scheme.in || "").toLowerCase() === "header") {
|
|
2388
|
+
if (state.value && scheme.name) headers[scheme.name] = state.value;
|
|
2389
|
+
} else if (type === "oauth2" || type === "openidconnect") {
|
|
2390
|
+
if (state.token) headers["Authorization"] = "Bearer " + state.token;
|
|
2391
|
+
}
|
|
2392
|
+
}
|
|
2393
|
+
return headers;
|
|
2394
|
+
}
|
|
2395
|
+
|
|
2396
|
+
function getAuthQueryParams(op) {
|
|
2397
|
+
const params = {};
|
|
2398
|
+
for (const schemeName of getAuthSchemeNamesForOperation(op)) {
|
|
2399
|
+
const scheme = authSchemes[schemeName];
|
|
2400
|
+
if ((scheme.type || "").toLowerCase() === "apikey" && (scheme.in || "").toLowerCase() === "query") {
|
|
2401
|
+
const state = authState[schemeName] || {};
|
|
2402
|
+
if (state.value && scheme.name) params[scheme.name] = state.value;
|
|
2403
|
+
}
|
|
2404
|
+
}
|
|
2405
|
+
return params;
|
|
2406
|
+
}
|
|
2407
|
+
|
|
2408
|
+
function getAuthCookieParams(op) {
|
|
2409
|
+
const cookies = {};
|
|
2410
|
+
for (const schemeName of getAuthSchemeNamesForOperation(op)) {
|
|
2411
|
+
const scheme = authSchemes[schemeName];
|
|
2412
|
+
if ((scheme.type || "").toLowerCase() !== "apikey") continue;
|
|
2413
|
+
if ((scheme.in || "").toLowerCase() !== "cookie") continue;
|
|
2414
|
+
const state = authState[schemeName] || {};
|
|
2415
|
+
if (state.value && scheme.name) {
|
|
2416
|
+
cookies[scheme.name] = state.value;
|
|
2417
|
+
}
|
|
2418
|
+
}
|
|
2419
|
+
return cookies;
|
|
2420
|
+
}
|
|
2421
|
+
|
|
2422
|
+
function applyAuthCookies(op) {
|
|
2423
|
+
const cookies = getAuthCookieParams(op);
|
|
2424
|
+
for (const [name, value] of Object.entries(cookies)) {
|
|
2425
|
+
try {
|
|
2426
|
+
document.cookie = encodeURIComponent(String(name)) + "=" + encodeURIComponent(String(value)) + "; path=/";
|
|
2427
|
+
} catch {}
|
|
2428
|
+
}
|
|
2429
|
+
}
|
|
2430
|
+
|
|
2431
|
+
function renderAuthPanel() {
|
|
2432
|
+
const fields = document.getElementById("auth-fields");
|
|
2433
|
+
if (!fields) return;
|
|
2434
|
+
fields.innerHTML = "";
|
|
2435
|
+
|
|
2436
|
+
const schemeNames = Object.keys(authSchemes);
|
|
2437
|
+
const op = selected;
|
|
2438
|
+
const operationSchemeOptions = op ? getAuthSchemeOptionsForOperation(op) : [];
|
|
2439
|
+
const availableSchemeOptions = Object.keys(authSchemes);
|
|
2440
|
+
const selectedScheme = op ? getSelectedAuthSchemeForOperation(op) : null;
|
|
2441
|
+
|
|
2442
|
+
function getAuthSchemeDisplayLabel(schemeName) {
|
|
2443
|
+
const scheme = authSchemes[schemeName] || {};
|
|
2444
|
+
const type = (scheme.type || "").toLowerCase();
|
|
2445
|
+
const httpScheme = (scheme.scheme || "").toLowerCase();
|
|
2446
|
+
const location = (scheme.in || "").toLowerCase();
|
|
2447
|
+
|
|
2448
|
+
if (type === "http" && httpScheme === "basic") return "HTTP Basic";
|
|
2449
|
+
if (type === "http" && httpScheme === "bearer") return "HTTP Bearer";
|
|
2450
|
+
if (type === "http" && httpScheme === "digest") return "HTTP Digest";
|
|
2451
|
+
if (type === "http") return "HTTP " + (httpScheme || "Token");
|
|
2452
|
+
if (type === "apikey") return "API Key" + (location ? " (" + location + ")" : "");
|
|
2453
|
+
if (type === "oauth2") return "OAuth 2.0";
|
|
2454
|
+
if (type === "openidconnect") return "OpenID Connect";
|
|
2455
|
+
if (type === "mutualtls") return "Mutual TLS";
|
|
2456
|
+
return schemeName;
|
|
2457
|
+
}
|
|
2458
|
+
|
|
2459
|
+
function makeInput(placeholder, value, onInput, type) {
|
|
2460
|
+
const inp = document.createElement("input");
|
|
2461
|
+
inp.type = type || "text";
|
|
2462
|
+
inp.value = value || "";
|
|
2463
|
+
inp.placeholder = placeholder;
|
|
2464
|
+
inp.className = "w-full text-xs px-2.5 py-2 rounded-md border border-light-border dark:border-dark-border bg-light-bg dark:bg-dark-bg focus:outline-none focus:border-brand dark:focus:border-brand transition-colors font-mono";
|
|
2465
|
+
inp.addEventListener("input", onInput);
|
|
2466
|
+
return inp;
|
|
2467
|
+
}
|
|
2468
|
+
|
|
2469
|
+
function makeLabel(text, small) {
|
|
2470
|
+
const el = document.createElement("p");
|
|
2471
|
+
el.className = small
|
|
2472
|
+
? "text-[10px] font-medium uppercase tracking-wider opacity-55"
|
|
2473
|
+
: "text-[10px] font-semibold uppercase tracking-wider opacity-55";
|
|
2474
|
+
el.textContent = text;
|
|
2475
|
+
return el;
|
|
2476
|
+
}
|
|
2477
|
+
|
|
2478
|
+
function makeField(label, input) {
|
|
2479
|
+
const wrapper = document.createElement("div");
|
|
2480
|
+
wrapper.className = "space-y-1";
|
|
2481
|
+
wrapper.appendChild(makeLabel(label, true));
|
|
2482
|
+
wrapper.appendChild(input);
|
|
2483
|
+
return wrapper;
|
|
2484
|
+
}
|
|
2485
|
+
|
|
2486
|
+
function makeSchemeCard(title, subtitle) {
|
|
2487
|
+
const card = document.createElement("div");
|
|
2488
|
+
card.className = "space-y-2 rounded-md border border-light-border dark:border-dark-border bg-light-bg/40 dark:bg-dark-bg/40 p-2.5";
|
|
2489
|
+
|
|
2490
|
+
const titleRow = document.createElement("div");
|
|
2491
|
+
titleRow.className = "flex items-center justify-between gap-2";
|
|
2492
|
+
|
|
2493
|
+
const heading = document.createElement("p");
|
|
2494
|
+
heading.className = "text-[11px] font-semibold tracking-wide";
|
|
2495
|
+
heading.textContent = title;
|
|
2496
|
+
titleRow.appendChild(heading);
|
|
2497
|
+
|
|
2498
|
+
if (subtitle) {
|
|
2499
|
+
const note = document.createElement("span");
|
|
2500
|
+
note.className = "text-[10px] opacity-60 font-mono";
|
|
2501
|
+
note.textContent = subtitle;
|
|
2502
|
+
titleRow.appendChild(note);
|
|
2503
|
+
}
|
|
2504
|
+
|
|
2505
|
+
card.appendChild(titleRow);
|
|
2506
|
+
return card;
|
|
2507
|
+
}
|
|
2508
|
+
|
|
2509
|
+
if (!schemeNames.length) {
|
|
2510
|
+
if (!authState["__default__"]) authState["__default__"] = {};
|
|
2511
|
+
const defaultCard = makeSchemeCard("Default Auth", "bearer");
|
|
2512
|
+
defaultCard.appendChild(makeField("Token", makeInput("Enter token\u2026", authState["__default__"].token, function(e) {
|
|
2513
|
+
authState["__default__"].token = e.target.value;
|
|
2514
|
+
saveAuthState();
|
|
2515
|
+
updateRequestPreview();
|
|
2516
|
+
})));
|
|
2517
|
+
fields.appendChild(defaultCard);
|
|
2518
|
+
return;
|
|
2519
|
+
}
|
|
2520
|
+
|
|
2521
|
+
if (op && availableSchemeOptions.length > 0) {
|
|
2522
|
+
const selectorWrap = document.createElement("div");
|
|
2523
|
+
selectorWrap.className = "space-y-1";
|
|
2524
|
+
selectorWrap.appendChild(makeLabel("Auth Type"));
|
|
2525
|
+
const select = document.createElement("select");
|
|
2526
|
+
select.className = "w-full text-xs px-2.5 py-2 rounded-md border border-light-border dark:border-dark-border bg-light-bg dark:bg-dark-bg focus:outline-none focus:border-brand dark:focus:border-brand transition-colors font-mono";
|
|
2527
|
+
|
|
2528
|
+
const autoOption = document.createElement("option");
|
|
2529
|
+
autoOption.value = "";
|
|
2530
|
+
autoOption.textContent = "Auto";
|
|
2531
|
+
select.appendChild(autoOption);
|
|
2532
|
+
|
|
2533
|
+
for (const schemeName of availableSchemeOptions) {
|
|
2534
|
+
const option = document.createElement("option");
|
|
2535
|
+
option.value = schemeName;
|
|
2536
|
+
const isOperationScheme = operationSchemeOptions.includes(schemeName);
|
|
2537
|
+
const label = getAuthSchemeDisplayLabel(schemeName);
|
|
2538
|
+
option.textContent = isOperationScheme
|
|
2539
|
+
? label
|
|
2540
|
+
: (label + " \u2022 override");
|
|
2541
|
+
select.appendChild(option);
|
|
2542
|
+
}
|
|
2543
|
+
|
|
2544
|
+
select.value = selectedScheme || "";
|
|
2545
|
+
select.addEventListener("change", function(e) {
|
|
2546
|
+
setSelectedAuthSchemeForOperation(op, e.target.value || "");
|
|
2547
|
+
renderAuthPanel();
|
|
2548
|
+
updateRequestPreview();
|
|
2549
|
+
});
|
|
2550
|
+
selectorWrap.appendChild(select);
|
|
2551
|
+
fields.appendChild(selectorWrap);
|
|
2552
|
+
}
|
|
2553
|
+
|
|
2554
|
+
const schemesToRender = selectedScheme
|
|
2555
|
+
? [selectedScheme]
|
|
2556
|
+
: (operationSchemeOptions.length ? operationSchemeOptions : schemeNames);
|
|
2557
|
+
|
|
2558
|
+
for (const schemeName of schemesToRender) {
|
|
2559
|
+
const scheme = authSchemes[schemeName];
|
|
2560
|
+
if (!authState[schemeName]) authState[schemeName] = {};
|
|
2561
|
+
const state = authState[schemeName];
|
|
2562
|
+
const type = (scheme.type || "").toLowerCase();
|
|
2563
|
+
const httpScheme = (scheme.scheme || "").toLowerCase();
|
|
2564
|
+
const card = makeSchemeCard(getAuthSchemeDisplayLabel(schemeName), schemeName);
|
|
2565
|
+
|
|
2566
|
+
if (type === "http" && httpScheme === "basic") {
|
|
2567
|
+
card.appendChild(makeField("Username", makeInput("Username", state.username, function(e) {
|
|
2568
|
+
authState[schemeName].username = e.target.value;
|
|
2569
|
+
saveAuthState();
|
|
2570
|
+
updateRequestPreview();
|
|
2571
|
+
})));
|
|
2572
|
+
card.appendChild(makeField("Password", makeInput("Password", state.password, function(e) {
|
|
2573
|
+
authState[schemeName].password = e.target.value;
|
|
2574
|
+
saveAuthState();
|
|
2575
|
+
updateRequestPreview();
|
|
2576
|
+
}, "password")));
|
|
2577
|
+
} else if (type === "apikey") {
|
|
2578
|
+
const paramName = scheme.name || "key";
|
|
2579
|
+
const location = (scheme.in || "header").toLowerCase();
|
|
2580
|
+
card.appendChild(makeField("API Key", makeInput(paramName + " (" + location + ")", state.value, function(e) {
|
|
2581
|
+
authState[schemeName].value = e.target.value;
|
|
2582
|
+
saveAuthState();
|
|
2583
|
+
updateRequestPreview();
|
|
2584
|
+
})));
|
|
2585
|
+
} else if (type === "oauth2") {
|
|
2586
|
+
card.appendChild(makeField("Access Token", makeInput("OAuth2 access token\u2026", state.token, function(e) {
|
|
2587
|
+
authState[schemeName].token = e.target.value;
|
|
2588
|
+
saveAuthState();
|
|
2589
|
+
updateRequestPreview();
|
|
2590
|
+
})));
|
|
2591
|
+
} else if (type === "openidconnect") {
|
|
2592
|
+
card.appendChild(makeField("ID Token / Access Token", makeInput("OpenID Connect token\u2026", state.token, function(e) {
|
|
2593
|
+
authState[schemeName].token = e.target.value;
|
|
2594
|
+
saveAuthState();
|
|
2595
|
+
updateRequestPreview();
|
|
2596
|
+
})));
|
|
2597
|
+
} else if (type === "http" && httpScheme === "digest") {
|
|
2598
|
+
card.appendChild(makeField("Digest Credential", makeInput("Digest token\u2026", state.token, function(e) {
|
|
2599
|
+
authState[schemeName].token = e.target.value;
|
|
2600
|
+
saveAuthState();
|
|
2601
|
+
updateRequestPreview();
|
|
2602
|
+
})));
|
|
2603
|
+
} else if (type === "http" && httpScheme === "bearer") {
|
|
2604
|
+
card.appendChild(makeField("Bearer Token", makeInput("Bearer token\u2026", state.token, function(e) {
|
|
2605
|
+
authState[schemeName].token = e.target.value;
|
|
2606
|
+
saveAuthState();
|
|
2607
|
+
updateRequestPreview();
|
|
2608
|
+
})));
|
|
2609
|
+
} else if (type === "mutualtls") {
|
|
2610
|
+
const hint = document.createElement("p");
|
|
2611
|
+
hint.className = "text-xs opacity-70 leading-relaxed";
|
|
2612
|
+
hint.textContent = "Configured by your client certificate. No token input required.";
|
|
2613
|
+
card.appendChild(hint);
|
|
2614
|
+
} else {
|
|
2615
|
+
card.appendChild(makeField("Token", makeInput("Token\u2026", state.token, function(e) {
|
|
2616
|
+
authState[schemeName].token = e.target.value;
|
|
2617
|
+
saveAuthState();
|
|
2618
|
+
updateRequestPreview();
|
|
2619
|
+
})));
|
|
2620
|
+
}
|
|
2621
|
+
fields.appendChild(card);
|
|
2622
|
+
}
|
|
2623
|
+
}
|
|
2624
|
+
|
|
2625
|
+
let authPanelOpen = true;
|
|
2626
|
+
document.getElementById("auth-toggle").addEventListener("click", function() {
|
|
2627
|
+
authPanelOpen = !authPanelOpen;
|
|
2628
|
+
const fieldsEl = document.getElementById("auth-fields");
|
|
2629
|
+
const chevron = document.getElementById("auth-chevron");
|
|
2630
|
+
if (fieldsEl) fieldsEl.classList.toggle("hidden", !authPanelOpen);
|
|
2631
|
+
if (chevron) chevron.style.transform = authPanelOpen ? "" : "rotate(-90deg)";
|
|
2632
|
+
});
|
|
2633
|
+
|
|
2634
|
+
// Restore selected operation from URL hash, or set hash for the default selection
|
|
2635
|
+
var initMatch = findOpByHash(window.location.hash);
|
|
2636
|
+
if (initMatch) {
|
|
2637
|
+
selected = initMatch;
|
|
2638
|
+
} else if (selected) {
|
|
2639
|
+
history.replaceState(null, "", getOpHash(selected));
|
|
2640
|
+
}
|
|
2641
|
+
|
|
2642
|
+
window.addEventListener("popstate", function() {
|
|
2643
|
+
var match = findOpByHash(window.location.hash);
|
|
2644
|
+
if (match) {
|
|
2645
|
+
selected = match;
|
|
2646
|
+
renderSidebar();
|
|
2647
|
+
renderEndpoint();
|
|
2648
|
+
}
|
|
2649
|
+
});
|
|
2650
|
+
|
|
1429
2651
|
setMobileSidebarOpen(false);
|
|
2652
|
+
renderAuthPanel();
|
|
1430
2653
|
renderSidebar();
|
|
1431
2654
|
renderEndpoint();
|
|
1432
2655
|
</script>
|
|
1433
2656
|
</body>
|
|
1434
|
-
</html>`}function z(e){let t=e?.["~standard"],d=t?.jsonSchema;return!!t&&typeof t==="object"&&t.version===1&&!!d&&typeof d.input==="function"&&typeof d.output==="function"}function fe(e){let t=0,d=[];return{openapiPath:e.split("/").map((r)=>{let o=/^:([A-Za-z0-9_]+)\+$/.exec(r);if(o?.[1])return d.push(o[1]),`{${o[1]}}`;let i=/^:([A-Za-z0-9_]+)$/.exec(r);if(i?.[1])return d.push(i[1]),`{${i[1]}}`;if(r==="*"){t+=1;let a=t===1?"wildcard":`wildcard${t}`;return d.push(a),`{${a}}`}return r}).join("/"),pathParamNames:d}}function Re(e){return fe(e).openapiPath}function Ue(e,t){return`${e.toLowerCase()}_${t}`.replace(/[:{}]/g,"").replace(/[^A-Za-z0-9_]+/g,"_").replace(/^_+|_+$/g,"")||`${e.toLowerCase()}_operation`}function $e(e){let t=e.split("/").filter(Boolean);for(let d of t)if(!d.startsWith(":")&&d!=="*")return d.toLowerCase();return"default"}function Pe(e){return fe(e).pathParamNames}function _e(e,t){let d=new Set((e.parameters||[]).filter((n)=>n.in==="path").map((n)=>String(n.name)));for(let n of Pe(t)){if(d.has(n))continue;(e.parameters||=[]).push({name:n,in:"path",required:!0,schema:{type:"string"}})}}function Je(e){let t=Number(e);if(!Number.isInteger(t))return!1;return t>=100&&t<200||t===204||t===205||t===304}function Se(e){if(e==="204")return"No Content";if(e==="205")return"Reset Content";if(e==="304")return"Not Modified";let t=Number(e);if(Number.isInteger(t)&&t>=100&&t<200)return"Informational";return"OK"}function Fe(e,t,d,n){if(!z(t)){let r=O(t);return S(r)?null:r}try{return t["~standard"].jsonSchema.input({target:d})}catch(r){let o=he(t,"input",d,r,e,void 0,n);if(o)return o;n.push(`[OpenAPI] Failed input schema conversion for ${e}: ${r instanceof Error?r.message:String(r)}. Falling back to a permissive JSON Schema.`);let i=O(t);return S(i)?null:i}}function pe(e,t,d,n,r){if(!z(d)){let o=O(d);return S(o)?null:o}try{return d["~standard"].jsonSchema.output({target:n})}catch(o){let i=he(d,"output",n,o,e,t,r);if(i)return i;return r.push(`[OpenAPI] Failed output schema conversion for ${e} (${t}): ${o instanceof Error?o.message:String(o)}. Falling back to a permissive JSON Schema.`),O(d)}}function y(e){return!!e&&typeof e==="object"&&!Array.isArray(e)}function S(e){return y(e)&&Object.keys(e).length===0}function he(e,t,d,n,r,o,i){if(!z(e))return null;let a=n instanceof Error?n.message:String(n);if(!(d==="openapi-3.0"&&a.includes("target 'openapi-3.0' is not supported")&&a.includes("draft-2020-12")&&a.includes("draft-07")))return null;try{let c=e["~standard"].jsonSchema[t]({target:"draft-07"});return i.push(t==="input"?`[OpenAPI] ${r} converter does not support openapi-3.0 target; using draft-07 conversion output.`:`[OpenAPI] ${r} (${o}) converter does not support openapi-3.0 target; using draft-07 conversion output.`),c}catch{return null}}function G(e){if(!e||typeof e!=="object")return null;let t=e;if(y(t._def))return t._def;if(y(t._zod)&&y(t._zod.def))return t._zod.def;if(t.kind==="schema"&&typeof t.type==="string")return t;return null}function ye(e){if(!e)return null;let t=e.typeName;if(typeof t==="string")return t;let d=e.type;if(typeof d==="string")return d;return null}function F(e){let t=["innerType","schema","type","out","in","left","right","wrapped","element"];for(let d of t)if(d in e)return e[d];return}function ze(e,t){for(let d of t){let n=e[d];if(n&&typeof n==="object"&&!Array.isArray(n))return n}return}function Ge(e){if(!e)return!1;let t=e.toLowerCase();return t.includes("optional")||t.includes("default")||t.includes("catch")}function Ve(e){let t=e,d=!1,n=0;while(n<8){n+=1;let r=G(t),o=ye(r);if(!r||!Ge(o))break;d=!0;let i=F(r);if(!i)break;t=i}return{schema:t,optional:d}}function Qe(e){let t=e.entries;if(y(t))return t;let d=e.shape;if(typeof d==="function")try{let n=d();return y(n)?n:{}}catch{return{}}return y(d)?d:{}}function ue(e){let t=e.values;if(Array.isArray(t))return t;if(t&&typeof t==="object")return Object.values(t);let d=e.entries;if(d&&typeof d==="object")return Object.values(d);let n=e.enum;if(n&&typeof n==="object")return Object.values(n);let r=e.options;if(Array.isArray(r))return r.map((o)=>{if(o&&typeof o==="object"&&"unit"in o)return o.unit;return o}).filter((o)=>o!==void 0);return[]}function Ye(e){let t=e.toLowerCase();if(t.includes("string"))return{type:"string"};if(t.includes("number"))return{type:"number"};if(t.includes("boolean"))return{type:"boolean"};if(t.includes("bigint"))return{type:"string"};if(t==="null"||t.includes("zodnull"))return{type:"null"};if(t.includes("any")||t.includes("unknown")||t.includes("never"))return{};if(t.includes("date"))return{type:"string",format:"date-time"};if(t.includes("custom"))return{type:"object",additionalProperties:!0};return null}function g(e,t=new WeakSet){if(!e||typeof e!=="object")return{};if(t.has(e))return{};t.add(e);let d=G(e),n=ye(d);if(!d||!n)return{};let r=Ye(n);if(r)return r;let o=n.toLowerCase();if(o.includes("object")){let a=Qe(d),s={},c=[];for(let[b,p]of Object.entries(a)){let x=Ve(p);if(s[b]=g(x.schema,t),!x.optional)c.push(b)}let m={type:"object",properties:s,additionalProperties:!0};if(c.length>0)m.required=c;return m}if(o.includes("array")){let a=ze(d,["element","items","innerType","type"])??{};return{type:"array",items:g(a,t)}}if(o.includes("record")){let a=d.valueType??d.valueSchema;return{type:"object",additionalProperties:a?g(a,t):!0}}if(o.includes("tuple")){let s=(Array.isArray(d.items)?d.items:[]).map((c)=>g(c,t));return{type:"array",prefixItems:s,minItems:s.length,maxItems:s.length}}if(o.includes("union")){let a=d.options??d.schemas??[];if(!Array.isArray(a)||a.length===0)return{};return{anyOf:a.map((s)=>g(s,t))}}if(o.includes("intersection")){let{left:a,right:s}=d;if(!a||!s)return{};return{allOf:[g(a,t),g(s,t)]}}if(o.includes("enum")){let a=ue(d);if(a.length>0){let s=a.every((b)=>typeof b==="string"),c=a.every((b)=>typeof b==="number"),m=a.every((b)=>typeof b==="boolean");if(s)return{type:"string",enum:a};if(c)return{type:"number",enum:a};if(m)return{type:"boolean",enum:a};return{enum:a}}return{}}if(o.includes("picklist")){let a=ue(d);if(a.length>0){if(a.every((c)=>typeof c==="string"))return{type:"string",enum:a};return{enum:a}}return{}}if(o.includes("literal")){let a=d.value;if(a===void 0)return{};let s=a===null?"null":typeof a;if(s==="string"||s==="number"||s==="boolean"||s==="null")return{type:s,const:a};return{const:a}}if(o.includes("nullable")){let a=F(d);if(!a)return{};return{anyOf:[g(a,t),{type:"null"}]}}if(o.includes("lazy")){let a=d.getter;if(typeof a!=="function")return{};try{return g(a(),t)}catch{return{}}}let i=F(d);if(i)return g(i,t);return{}}function O(e){if(!G(e))return{};return g(e)}function Xe(e,t){if(!y(t))return;if(t.type!=="object"||!y(t.properties)){e.requestBody={required:!0,content:{"application/json":{schema:t}}};return}let d=new Set(Array.isArray(t.required)?t.required:[]),n=t.properties,r=Array.isArray(e.parameters)?e.parameters:[],o=[{key:"params",in:"path"},{key:"query",in:"query"},{key:"headers",in:"header"},{key:"cookies",in:"cookie"}];for(let a of o){let s=n[a.key];if(!y(s))continue;if(s.type!=="object"||!y(s.properties))continue;let c=new Set(Array.isArray(s.required)?s.required:[]);for(let[m,b]of Object.entries(s.properties))r.push({name:m,in:a.in,required:a.in==="path"?!0:c.has(m),schema:y(b)?b:{}})}if(r.length>0){let a=new Map;for(let s of r)a.set(`${s.in}:${s.name}`,s);e.parameters=[...a.values()]}let i=n.body;if(i)e.requestBody={required:d.has("body"),content:{"application/json":{schema:y(i)?i:{}}}}}function We(e,t,d,n,r){let o=d.output;if(!o){e.responses={200:{description:"OK"}};return}let i={};if(typeof o==="object"&&o!==null&&"~standard"in o){let a=pe(t,"200",o,n,r);if(a)i["200"]={description:"OK",content:{"application/json":{schema:a}}};else i["200"]={description:"OK"}}else for(let[a,s]of Object.entries(o)){let c=String(a),m=pe(t,c,s,n,r),b=Se(c);if(m&&!Je(c))i[c]={description:b,content:{"application/json":{schema:m}}};else i[c]={description:b}}if(Object.keys(i).length===0)i["200"]={description:"OK"};e.responses=i}function xe(e,t){let d=[],n={};for(let i of e){if(i.options.expose===!1)continue;if(!i.method||!i.path)continue;let a=i.method.toLowerCase();if(a==="options")continue;let s=Re(i.path),c={operationId:Ue(a,s),tags:[i.options.schema?.tag||$e(i.path)]},m=Fe(i.path,i.options.schema?.input,t.target,d);if(m)Xe(c,m);_e(c,i.path),We(c,i.path,i.options.schema||{},t.target,d),n[s]||={},n[s][a]=c}return{document:{openapi:t.target==="openapi-3.0"?"3.0.3":"3.1.0",info:{title:t.info?.title||"Vector API",version:t.info?.version||"1.0.0",...t.info?.description?{description:t.info.description}:{}},paths:n},warnings:d}}var V="/_vector/openapi/tailwindcdn.js",Q="/_vector/openapi/logo_dark.svg",Y="/_vector/openapi/logo_white.svg",Ie="/_vector/openapi/favicon/apple-touch-icon.png",we="/_vector/openapi/favicon/favicon-32x32.png",Le="/_vector/openapi/favicon/favicon-16x16.png",Ze="/_vector/openapi/favicon/favicon.ico",De="/_vector/openapi/favicon/site.webmanifest",qe="/_vector/openapi/favicon/android-chrome-192x192.png",et="/_vector/openapi/favicon/android-chrome-512x512.png",tt=["../openapi/assets/tailwindcdn.js","../src/openapi/assets/tailwindcdn.js","../../src/openapi/assets/tailwindcdn.js"],dt=["../openapi/assets/logo_dark.svg","../src/openapi/assets/logo_dark.svg","../../src/openapi/assets/logo_dark.svg"],nt=["../openapi/assets/logo_white.svg","../src/openapi/assets/logo_white.svg","../../src/openapi/assets/logo_white.svg"],rt=["src/openapi/assets/tailwindcdn.js","openapi/assets/tailwindcdn.js","dist/openapi/assets/tailwindcdn.js"],ot=["src/openapi/assets/logo_dark.svg","openapi/assets/logo_dark.svg","dist/openapi/assets/logo_dark.svg"],at=["src/openapi/assets/logo_white.svg","openapi/assets/logo_white.svg","dist/openapi/assets/logo_white.svg"],B=["../openapi/assets/favicon","../src/openapi/assets/favicon","../../src/openapi/assets/favicon"],I=["src/openapi/assets/favicon","openapi/assets/favicon","dist/openapi/assets/favicon"],it="/* OpenAPI docs runtime asset missing: tailwind disabled */";function h(e,t){return e.map((d)=>`${d}/${t}`)}function k(e,t){for(let n of e)try{let r=new URL(n,import.meta.url);if(ge(r))return Bun.file(r)}catch{}let d=process.cwd();for(let n of t){let r=Ke(d,n);if(ge(r))return Bun.file(r)}return null}var ke=k(tt,rt),Ee=k(dt,ot),ve=k(nt,at),st=k(h(B,"apple-touch-icon.png"),h(I,"apple-touch-icon.png")),lt=k(h(B,"favicon-32x32.png"),h(I,"favicon-32x32.png")),ct=k(h(B,"favicon-16x16.png"),h(I,"favicon-16x16.png")),bt=k(h(B,"favicon.ico"),h(I,"favicon.ico")),mt=k(h(B,"site.webmanifest"),h(I,"site.webmanifest")),pt=k(h(B,"android-chrome-192x192.png"),h(I,"android-chrome-192x192.png")),ut=k(h(B,"android-chrome-512x512.png"),h(I,"android-chrome-512x512.png")),Be=[{path:Ie,file:st,contentType:"image/png",filename:"apple-touch-icon.png"},{path:we,file:lt,contentType:"image/png",filename:"favicon-32x32.png"},{path:Le,file:ct,contentType:"image/png",filename:"favicon-16x16.png"},{path:Ze,file:bt,contentType:"image/x-icon",filename:"favicon.ico"},{path:De,file:mt,contentType:"application/manifest+json; charset=utf-8",filename:"site.webmanifest"},{path:qe,file:pt,contentType:"image/png",filename:"android-chrome-192x192.png"},{path:et,file:ut,contentType:"image/png",filename:"android-chrome-512x512.png"}],X="public, max-age=0, must-revalidate",A="public, max-age=31536000, immutable",W="no-store";function ft(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function ht(e){let t="^";for(let d of e){if(d==="*"){t+=".*";continue}t+=ft(d)}return t+="$",new RegExp(t)}function yt(e,t){if(!t.includes("*"))return e===t;return ht(t).test(e)}class K{server=null;router;config;openapiConfig;openapiDocCache=null;openapiDocsHtmlCache=null;openapiWarningsLogged=!1;openapiTailwindMissingLogged=!1;openapiLogoDarkMissingLogged=!1;openapiLogoWhiteMissingLogged=!1;corsHandler=null;corsHeadersEntries=null;constructor(e,t){if(this.router=e,this.config=t,this.openapiConfig=this.normalizeOpenAPIConfig(t.openapi,t.development),t.cors){let d=this.normalizeCorsOptions(t.cors),{preflight:n,corsify:r}=be(d);if(this.corsHandler={preflight:n,corsify:r},typeof d.origin==="string"&&(d.origin!=="*"||!d.credentials)){let i={"access-control-allow-origin":d.origin,"access-control-allow-methods":d.allowMethods,"access-control-allow-headers":d.allowHeaders,"access-control-expose-headers":d.exposeHeaders,"access-control-max-age":String(d.maxAge)};if(d.credentials)i["access-control-allow-credentials"]="true";this.corsHeadersEntries=Object.entries(i)}this.router.setCorsHeaders(this.corsHeadersEntries),this.router.setCorsHandler(this.corsHeadersEntries?null:this.corsHandler.corsify)}}normalizeOpenAPIConfig(e,t){let n=t!==!1&&!0;if(e===!1)return{enabled:!1,path:"/openapi.json",target:"openapi-3.0",docs:{enabled:!1,path:"/docs"}};if(e===!0)return{enabled:!0,path:"/openapi.json",target:"openapi-3.0",docs:{enabled:!1,path:"/docs"}};let r=e||{},o=r.docs,i=typeof o==="boolean"?{enabled:o,path:"/docs",exposePaths:void 0}:{enabled:o?.enabled===!0,path:o?.path||"/docs",exposePaths:Array.isArray(o?.exposePaths)?o.exposePaths.map((a)=>typeof a==="string"?a.trim():"").filter((a)=>a.length>0):void 0};return{enabled:r.enabled??n,path:r.path||"/openapi.json",target:r.target||"openapi-3.0",docs:i,info:r.info}}isDocsReservedPath(e){return e===this.openapiConfig.path||this.openapiConfig.docs.enabled&&e===this.openapiConfig.docs.path}shouldLogOpenAPIConversionWarnings(){if(this.config.development===!1)return!1;let d=process.env.LOG_LEVEL;return typeof d==="string"&&d.toLowerCase()==="debug"}getOpenAPIDocument(){if(this.openapiDocCache)return this.openapiDocCache;let e=this.router.getRouteDefinitions().filter((d)=>!this.isDocsReservedPath(d.path)),t=xe(e,{target:this.openapiConfig.target,info:this.openapiConfig.info});if(!this.openapiWarningsLogged&&t.warnings.length>0){if(this.shouldLogOpenAPIConversionWarnings())for(let d of t.warnings)console.warn(d);this.openapiWarningsLogged=!0}return this.openapiDocCache=t.document,this.openapiDocCache}getOpenAPIDocumentForDocs(){let e=this.openapiConfig.docs.exposePaths,t=this.getOpenAPIDocument();if(!Array.isArray(e)||e.length===0)return t;let d=t.paths&&typeof t.paths==="object"&&!Array.isArray(t.paths)?t.paths:{},n={};for(let[r,o]of Object.entries(d))if(e.some((i)=>yt(r,i)))n[r]=o;return{...t,paths:n}}getOpenAPIDocsHtmlCacheEntry(){if(this.openapiDocsHtmlCache)return this.openapiDocsHtmlCache;let e=me(this.getOpenAPIDocumentForDocs(),this.openapiConfig.path,V,Q,Y,Ie,we,Le,De),t=Bun.gzipSync(e),d=`"${Bun.hash(e).toString(16)}"`;return this.openapiDocsHtmlCache={html:e,gzip:t,etag:d},this.openapiDocsHtmlCache}requestAcceptsGzip(e){let t=e.headers.get("accept-encoding");return Boolean(t&&/\bgzip\b/i.test(t))}validateReservedOpenAPIPaths(){if(!this.openapiConfig.enabled)return;let e=new Set([this.openapiConfig.path]);if(this.openapiConfig.docs.enabled){e.add(this.openapiConfig.docs.path),e.add(V),e.add(Q),e.add(Y);for(let r of Be)e.add(r.path)}let t=this.router.getRouteDefinitions().filter((r)=>e.has(r.path)).map((r)=>`${r.method} ${r.path}`),d=Object.entries(this.router.getRouteTable()).filter(([r,o])=>e.has(r)&&o instanceof Response).map(([r])=>`STATIC ${r}`),n=[...t,...d];if(n.length>0)throw new Error(`OpenAPI reserved path conflict: ${n.join(", ")}. Change your route path(s) or reconfigure openapi.path/docs.path.`)}tryHandleOpenAPIRequest(e){if(!this.openapiConfig.enabled||e.method!=="GET")return null;let t=new URL(e.url).pathname;if(t===this.openapiConfig.path)return Response.json(this.getOpenAPIDocument());if(this.openapiConfig.docs.enabled&&t===this.openapiConfig.docs.path){let{html:d,gzip:n,etag:r}=this.getOpenAPIDocsHtmlCacheEntry();if(e.headers.get("if-none-match")===r)return new Response(null,{status:304,headers:{etag:r,"cache-control":X,vary:"accept-encoding"}});if(this.requestAcceptsGzip(e))return new Response(n,{status:200,headers:{"content-type":"text/html; charset=utf-8","content-encoding":"gzip",etag:r,"cache-control":X,vary:"accept-encoding"}});return new Response(d,{status:200,headers:{"content-type":"text/html; charset=utf-8",etag:r,"cache-control":X,vary:"accept-encoding"}})}if(this.openapiConfig.docs.enabled&&t===V){if(!ke){if(!this.openapiTailwindMissingLogged)this.openapiTailwindMissingLogged=!0,console.warn('[OpenAPI] Missing docs runtime asset "tailwindcdn.js". Serving inline fallback script instead.');return new Response(it,{status:200,headers:{"content-type":"application/javascript; charset=utf-8","cache-control":A}})}return new Response(ke,{status:200,headers:{"content-type":"application/javascript; charset=utf-8","cache-control":A}})}if(this.openapiConfig.docs.enabled&&t===Q){if(!Ee){if(!this.openapiLogoDarkMissingLogged)this.openapiLogoDarkMissingLogged=!0,console.warn('[OpenAPI] Missing docs runtime asset "logo_dark.svg".');return new Response("OpenAPI docs runtime asset missing: logo_dark.svg",{status:404,headers:{"content-type":"text/plain; charset=utf-8","cache-control":W}})}return new Response(Ee,{status:200,headers:{"content-type":"image/svg+xml; charset=utf-8","cache-control":A}})}if(this.openapiConfig.docs.enabled&&t===Y){if(!ve){if(!this.openapiLogoWhiteMissingLogged)this.openapiLogoWhiteMissingLogged=!0,console.warn('[OpenAPI] Missing docs runtime asset "logo_white.svg".');return new Response("OpenAPI docs runtime asset missing: logo_white.svg",{status:404,headers:{"content-type":"text/plain; charset=utf-8","cache-control":W}})}return new Response(ve,{status:200,headers:{"content-type":"image/svg+xml; charset=utf-8","cache-control":A}})}if(this.openapiConfig.docs.enabled){let d=Be.find((n)=>n.path===t);if(d){if(!d.file)return new Response(`OpenAPI docs runtime asset missing: ${d.filename}`,{status:404,headers:{"content-type":"text/plain; charset=utf-8","cache-control":W}});return new Response(d.file,{status:200,headers:{"content-type":d.contentType,"cache-control":A}})}}return null}normalizeCorsOptions(e){return{origin:e.origin||"*",credentials:e.credentials!==!1,allowHeaders:Array.isArray(e.allowHeaders)?e.allowHeaders.join(", "):e.allowHeaders||"Content-Type, Authorization",allowMethods:Array.isArray(e.allowMethods)?e.allowMethods.join(", "):e.allowMethods||"GET, POST, PUT, PATCH, DELETE, OPTIONS",exposeHeaders:Array.isArray(e.exposeHeaders)?e.exposeHeaders.join(", "):e.exposeHeaders||"Authorization",maxAge:e.maxAge||86400}}applyCors(e,t){if(this.corsHeadersEntries){for(let[d,n]of this.corsHeadersEntries)e.headers.set(d,n);return e}if(this.corsHandler&&t)return this.corsHandler.corsify(e,t);return e}async start(){let e=this.config.port??3000,t=this.config.hostname||"localhost";this.validateReservedOpenAPIPaths();let d=async(n)=>{try{if(this.corsHandler&&n.method==="OPTIONS")return this.corsHandler.preflight(n);let r=this.tryHandleOpenAPIRequest(n);if(r)return this.applyCors(r,n);return this.applyCors(j.NOT_FOUND.clone(),n)}catch(r){return console.error("Server error:",r),this.applyCors(new Response("Internal Server Error",{status:500}),n)}};try{if(this.server=Bun.serve({port:e,hostname:t,reusePort:this.config.reusePort!==!1,routes:this.router.getRouteTable(),fetch:d,idleTimeout:this.config.idleTimeout??60,error:(n,r)=>{return console.error("[ERROR] Server error:",n),this.applyCors(new Response("Internal Server Error",{status:500}),r)}}),!this.server||!this.server.port)throw new Error(`Failed to start server on ${t}:${e} - server object is invalid`);return this.server}catch(n){if(n.code==="EADDRINUSE"||n.message?.includes("address already in use"))n.message=`Port ${e} is already in use`,n.port=e;else if(n.code==="EACCES"||n.message?.includes("permission denied"))n.message=`Permission denied to bind to port ${e}`,n.port=e;else if(n.message?.includes("EADDRNOTAVAIL"))n.message=`Cannot bind to hostname ${t}`,n.hostname=t;throw n}}stop(){if(this.server)this.server.stop(),this.server=null,this.openapiDocCache=null,this.openapiDocsHtmlCache=null,this.openapiWarningsLogged=!1,console.log("Server stopped")}getServer(){return this.server}getPort(){return this.server?.port??this.config.port??3000}getHostname(){return this.server?.hostname||this.config.hostname||"localhost"}getUrl(){let e=this.getPort();return`http://${this.getHostname()}:${e}`}}class w{static instance;router;server=null;middlewareManager;authManager;cacheManager;config={};routeScanner=null;routeGenerator=null;_protectedHandler=null;_cacheHandler=null;shutdownPromise=null;constructor(){this.middlewareManager=new C,this.authManager=new R,this.cacheManager=new U,this.router=new N(this.middlewareManager,this.authManager,this.cacheManager)}static getInstance(){if(!w.instance)w.instance=new w;return w.instance}setProtectedHandler(e){if(this._protectedHandler=e,e){this.authManager.setProtectedHandler(e);return}this.authManager.clearProtectedHandler()}getProtectedHandler(){return this._protectedHandler}setCacheHandler(e){if(this._cacheHandler=e,e){this.cacheManager.setCacheHandler(e);return}this.cacheManager.clearCacheHandler()}getCacheHandler(){return this._cacheHandler}addRoute(e,t){this.router.route(e,t)}async startServer(e){this.config={...this.config,...e};let t={...this.config.defaults?.route};if(this.router.setRouteBooleanDefaults(t),this.router.setDevelopmentMode(this.config.development),this.middlewareManager.clear(),this.config.autoDiscover!==!1)this.router.clearRoutes();if(e?.before)this.middlewareManager.addBefore(...e.before);if(e?.finally)this.middlewareManager.addFinally(...e.finally);if(typeof this.config.startup==="function")await this.config.startup();if(this.config.autoDiscover!==!1)await this.discoverRoutes();return this.server=new K(this.router,this.config),await this.server.start()}async discoverRoutes(){let e=this.config.routesDir||"./routes",t=this.config.routeExcludePatterns;if(this.routeScanner=new M(e,t),!this.routeGenerator)this.routeGenerator=new $;try{let d=await this.routeScanner.scan();if(d.length>0){if(this.config.development)await this.routeGenerator.generate(d);for(let n of d)try{let o=await import(H(n.path)),i=n.name==="default"?o.default:o[n.name];if(i){if(this.isRouteDefinition(i))this.router.route(i.options,i.handler),this.logRouteLoaded(i.options);else if(this.isRouteEntry(i))this.router.addRoute(i),this.logRouteLoaded(i);else if(typeof i==="function")this.router.route(n.options,i),this.logRouteLoaded(n.options)}}catch(r){console.error(`Failed to load route ${n.name} from ${n.path}:`,r)}}}catch(d){if(d.code!=="ENOENT"&&d.code!=="ENOTDIR")console.error("Failed to discover routes:",d)}}async loadRoute(e){if(typeof e==="function"){let t=e();if(this.isRouteEntry(t))this.router.addRoute(t)}else if(e&&typeof e==="object"){for(let[,t]of Object.entries(e))if(typeof t==="function"){let d=t();if(this.isRouteEntry(d))this.router.addRoute(d)}}}isRouteEntry(e){if(!Array.isArray(e)||e.length<3)return!1;let[t,d,n,r]=e;return typeof t==="string"&&d instanceof RegExp&&Array.isArray(n)&&n.length>0&&n.every((o)=>typeof o==="function")&&(r===void 0||typeof r==="string")}isRouteDefinition(e){return e!==null&&typeof e==="object"&&"entry"in e&&"options"in e&&"handler"in e&&typeof e.handler==="function"}logRouteLoaded(e){}stop(){if(this.server)this.server.stop(),this.server=null}async shutdown(){if(this.shutdownPromise)return this.shutdownPromise;this.shutdownPromise=(async()=>{if(this.stop(),typeof this.config.shutdown==="function")await this.config.shutdown()})();try{await this.shutdownPromise}finally{this.shutdownPromise=null}}getServer(){return this.server}getRouter(){return this.router}getCacheManager(){return this.cacheManager}getAuthManager(){return this.authManager}static resetInstance(){w.instance=null}}var Z=w.getInstance;function xt(e,t){return{entry:{method:e.method.toUpperCase(),path:e.path},options:e,handler:t}}function gt(e){let t=e??null;try{return JSON.stringify(t)}catch(d){if(d instanceof TypeError&&/\bbigint\b/i.test(d.message))return JSON.stringify(t,(n,r)=>typeof r==="bigint"?r.toString():r);throw d}}function l(e,t,d){let n={error:!0,message:t,statusCode:e,timestamp:new Date().toISOString()};return D(e,n,d)}var v={badRequest:(e="Bad Request",t)=>l(E.BAD_REQUEST,e,t),unauthorized:(e="Unauthorized",t)=>l(E.UNAUTHORIZED,e,t),paymentRequired:(e="Payment Required",t)=>l(402,e,t),forbidden:(e="Forbidden",t)=>l(E.FORBIDDEN,e,t),notFound:(e="Not Found",t)=>l(E.NOT_FOUND,e,t),methodNotAllowed:(e="Method Not Allowed",t)=>l(405,e,t),notAcceptable:(e="Not Acceptable",t)=>l(406,e,t),requestTimeout:(e="Request Timeout",t)=>l(408,e,t),conflict:(e="Conflict",t)=>l(E.CONFLICT,e,t),gone:(e="Gone",t)=>l(410,e,t),lengthRequired:(e="Length Required",t)=>l(411,e,t),preconditionFailed:(e="Precondition Failed",t)=>l(412,e,t),payloadTooLarge:(e="Payload Too Large",t)=>l(413,e,t),uriTooLong:(e="URI Too Long",t)=>l(414,e,t),unsupportedMediaType:(e="Unsupported Media Type",t)=>l(415,e,t),rangeNotSatisfiable:(e="Range Not Satisfiable",t)=>l(416,e,t),expectationFailed:(e="Expectation Failed",t)=>l(417,e,t),imATeapot:(e="I'm a teapot",t)=>l(418,e,t),misdirectedRequest:(e="Misdirected Request",t)=>l(421,e,t),unprocessableEntity:(e="Unprocessable Entity",t)=>l(E.UNPROCESSABLE_ENTITY,e,t),locked:(e="Locked",t)=>l(423,e,t),failedDependency:(e="Failed Dependency",t)=>l(424,e,t),tooEarly:(e="Too Early",t)=>l(425,e,t),upgradeRequired:(e="Upgrade Required",t)=>l(426,e,t),preconditionRequired:(e="Precondition Required",t)=>l(428,e,t),tooManyRequests:(e="Too Many Requests",t)=>l(429,e,t),requestHeaderFieldsTooLarge:(e="Request Header Fields Too Large",t)=>l(431,e,t),unavailableForLegalReasons:(e="Unavailable For Legal Reasons",t)=>l(451,e,t),internalServerError:(e="Internal Server Error",t)=>l(E.INTERNAL_SERVER_ERROR,e,t),notImplemented:(e="Not Implemented",t)=>l(501,e,t),badGateway:(e="Bad Gateway",t)=>l(502,e,t),serviceUnavailable:(e="Service Unavailable",t)=>l(503,e,t),gatewayTimeout:(e="Gateway Timeout",t)=>l(504,e,t),httpVersionNotSupported:(e="HTTP Version Not Supported",t)=>l(505,e,t),variantAlsoNegotiates:(e="Variant Also Negotiates",t)=>l(506,e,t),insufficientStorage:(e="Insufficient Storage",t)=>l(507,e,t),loopDetected:(e="Loop Detected",t)=>l(508,e,t),notExtended:(e="Not Extended",t)=>l(510,e,t),networkAuthenticationRequired:(e="Network Authentication Required",t)=>l(511,e,t),invalidArgument:(e="Invalid Argument",t)=>l(E.UNPROCESSABLE_ENTITY,e,t),rateLimitExceeded:(e="Rate Limit Exceeded",t)=>l(429,e,t),maintenance:(e="Service Under Maintenance",t)=>l(503,e,t),custom:(e,t,d)=>l(e,t,d)};function D(e,t,d=T.JSON){let n=d===T.JSON?gt(t):t;return new Response(n,{status:e,headers:{"content-type":d}})}import{existsSync as kt}from"fs";import{resolve as Et,isAbsolute as vt}from"path";class q{configPath;config=null;configSource="default";constructor(e){let t=e||"vector.config.ts";this.configPath=vt(t)?t:Et(process.cwd(),t)}async load(){if(kt(this.configPath))try{let t=await import(H(this.configPath));this.config=t.default||t,this.configSource="user"}catch(e){let t=e instanceof Error?e.message:String(e);console.error(`[vector] Failed to load config from ${this.configPath}: ${t}`),console.error("[vector] Server is using default configuration. Fix your config file and restart."),this.config={}}else this.config={};return await this.buildLegacyConfig()}getConfigSource(){return this.configSource}async buildLegacyConfig(){let e={};if(this.config)e.port=this.config.port,e.hostname=this.config.hostname,e.reusePort=this.config.reusePort,e.development=this.config.development,e.routesDir=this.config.routesDir||"./routes",e.routeExcludePatterns=this.config.routeExcludePatterns,e.idleTimeout=this.config.idleTimeout,e.defaults=this.config.defaults,e.openapi=this.config.openapi,e.startup=this.config.startup,e.shutdown=this.config.shutdown;if(e.autoDiscover=!0,this.config?.cors)if(typeof this.config.cors==="boolean")e.cors=this.config.cors?{origin:"*",credentials:!0,allowHeaders:"Content-Type, Authorization",allowMethods:"GET, POST, PUT, PATCH, DELETE, OPTIONS",exposeHeaders:"Authorization",maxAge:86400}:void 0;else e.cors=this.config.cors;if(this.config?.before)e.before=this.config.before;if(this.config?.after)e.finally=this.config.after;return e}async loadAuthHandler(){return this.config?.auth||null}async loadCacheHandler(){return this.config?.cache||null}getConfig(){return this.config}}async function Bt(e={}){let t=new q(e.configPath),d=await t.load(),n=t.getConfigSource(),r={...d};if(e.mutateConfig)r=await e.mutateConfig(r,{configSource:n});if(e.config)r={...r,...e.config};if(e.autoDiscover!==void 0)r.autoDiscover=e.autoDiscover;let o=Z(),i=e.protectedHandler!==void 0?e.protectedHandler:await t.loadAuthHandler(),a=e.cacheHandler!==void 0?e.cacheHandler:await t.loadCacheHandler();o.setProtectedHandler(i??null),o.setCacheHandler(a??null);let s=await o.startServer(r),c={...r,port:s.port??r.port??L.PORT,hostname:s.hostname||r.hostname||L.HOSTNAME,reusePort:r.reusePort!==!1,idleTimeout:r.idleTimeout??60};return{server:s,config:c,stop:()=>o.stop(),shutdown:()=>o.shutdown()}}export{Bt as startVector,xt as route,D as createResponse,v as APIError};
|
|
2657
|
+
</html>`}var fr=new Set(Object.values(J)),gr={ApiKey:"apiKeyAuth",HttpBasic:"basicAuth",HttpBearer:"bearerAuth",HttpDigest:"digestAuth",OAuth2:"oauth2Auth",OpenIdConnect:"openIdConnectAuth",MutualTls:"mutualTlsAuth"};function yr(e){return typeof e==="string"&&fr.has(e)}function wr(e,t){if(e===void 0||e===!1||e===null)return null;if(e===!0)return t;if(yr(e))return e;return t}function qe(e,t){let r=t?.securitySchemeNames?.[e];if(typeof r==="string"&&r.trim().length>0)return r.trim();return gr[e]}function xr(e){switch(e){case"ApiKey":return{type:"apiKey",name:"X-API-Key",in:"header"};case"HttpBasic":return{type:"http",scheme:"basic"};case"HttpBearer":return{type:"http",scheme:"bearer",bearerFormat:"JWT"};case"HttpDigest":return{type:"http",scheme:"digest"};case"OAuth2":return{type:"oauth2",flows:{authorizationCode:{authorizationUrl:"https://example.com/oauth/authorize",tokenUrl:"https://example.com/oauth/token",scopes:{}}}};case"OpenIdConnect":return{type:"openIdConnect",openIdConnectUrl:"https://example.com/.well-known/openid-configuration"};case"MutualTls":return{type:"mutualTLS"};default:return e}}function vr(e,t){let r=xr(e),a=t?.securitySchemes?.[e];if(!a)return r;let n={...r,...a};if(y(r.flows)&&y(a.flows))n.flows={...r.flows,...a.flows};return n}function se(e){let t=e?.["~standard"],r=t?.jsonSchema;return!!t&&typeof t==="object"&&t.version===1&&!!r&&typeof r.input==="function"&&typeof r.output==="function"}function tt(e){let t=0,r=[];return{openapiPath:e.split("/").map((n)=>{let o=/^:([A-Za-z0-9_]+)\+$/.exec(n);if(o?.[1])return r.push(o[1]),`{${o[1]}}`;let i=/^:([A-Za-z0-9_]+)$/.exec(n);if(i?.[1])return r.push(i[1]),`{${i[1]}}`;if(n==="*"){t+=1;let d=t===1?"wildcard":`wildcard${t}`;return r.push(d),`{${d}}`}return n}).join("/"),pathParamNames:r}}function Er(e){return tt(e).openapiPath}function kr(e,t){return`${e.toLowerCase()}_${t}`.replace(/[:{}]/g,"").replace(/[^A-Za-z0-9_]+/g,"_").replace(/^_+|_+$/g,"")||`${e.toLowerCase()}_operation`}function Br(e){let t=e.split("/").filter(Boolean);for(let r of t)if(!r.startsWith(":")&&r!=="*")return r.toLowerCase();return"default"}function Ir(e){return tt(e).pathParamNames}function Tr(e,t){let r=new Set((e.parameters||[]).filter((a)=>a.in==="path").map((a)=>String(a.name)));for(let a of Ir(t)){if(r.has(a))continue;(e.parameters||=[]).push({name:a,in:"path",required:!0,schema:{type:"string"}})}}function Cr(e){let t=Number(e);if(!Number.isInteger(t))return!1;return t>=100&&t<200||t===204||t===205||t===304}function Lr(e){let t={"100":"Continue","101":"Switching Protocols","102":"Processing","103":"Early Hints","200":"OK","201":"Created","202":"Accepted","203":"Non-Authoritative Information","204":"No Content","205":"Reset Content","206":"Partial Content","207":"Multi-Status","208":"Already Reported","226":"IM Used","300":"Multiple Choices","301":"Moved Permanently","302":"Found","303":"See Other","304":"Not Modified","305":"Use Proxy","307":"Temporary Redirect","308":"Permanent Redirect","400":"Bad Request","401":"Unauthorized","402":"Payment Required","403":"Forbidden","404":"Not Found","405":"Method Not Allowed","406":"Not Acceptable","407":"Proxy Authentication Required","408":"Request Timeout","409":"Conflict","410":"Gone","411":"Length Required","412":"Precondition Failed","413":"Payload Too Large","414":"URI Too Long","415":"Unsupported Media Type","416":"Range Not Satisfiable","417":"Expectation Failed","418":"I'm a teapot","421":"Misdirected Request","422":"Unprocessable Content","423":"Locked","424":"Failed Dependency","425":"Too Early","426":"Upgrade Required","428":"Precondition Required","429":"Too Many Requests","431":"Request Header Fields Too Large","451":"Unavailable For Legal Reasons","500":"Internal Server Error","501":"Not Implemented","502":"Bad Gateway","503":"Service Unavailable","504":"Gateway Timeout","505":"HTTP Version Not Supported","506":"Variant Also Negotiates","507":"Insufficient Storage","508":"Loop Detected","510":"Not Extended","511":"Network Authentication Required"};if(t[e])return t[e];let r=Number(e);if(Number.isInteger(r)&&r>=100&&r<200)return"Informational Response";if(Number.isInteger(r)&&r>=200&&r<300)return"Successful Response";if(Number.isInteger(r)&&r>=300&&r<400)return"Redirection";if(Number.isInteger(r)&&r>=400&&r<500)return"Client Error";if(Number.isInteger(r)&&r>=500&&r<600)return"Server Error";return"OK"}function Nr(e,t,r,a){if(!se(t)){let n=Z(t);return ie(n)?null:n}try{return t["~standard"].jsonSchema.input({target:r})}catch(n){let o=rt(t,"input",r,n,e,void 0,a);if(o)return o;a.push(`[OpenAPI] Failed input schema conversion for ${e}: ${n instanceof Error?n.message:String(n)}. Falling back to a permissive JSON Schema.`);let i=Z(t);return ie(i)?null:i}}function Ke(e,t,r,a,n){if(!se(r)){let o=Z(r);return ie(o)?null:o}try{return r["~standard"].jsonSchema.output({target:a})}catch(o){let i=rt(r,"output",a,o,e,t,n);if(i)return i;return n.push(`[OpenAPI] Failed output schema conversion for ${e} (${t}): ${o instanceof Error?o.message:String(o)}. Falling back to a permissive JSON Schema.`),Z(r)}}function y(e){return!!e&&typeof e==="object"&&!Array.isArray(e)}function ie(e){return y(e)&&Object.keys(e).length===0}function rt(e,t,r,a,n,o,i){if(!se(e))return null;let d=a instanceof Error?a.message:String(a);if(!(r==="openapi-3.0"&&d.includes("target 'openapi-3.0' is not supported")&&d.includes("draft-2020-12")&&d.includes("draft-07")))return null;try{let c=e["~standard"].jsonSchema[t]({target:"draft-07"});return i.push(t==="input"?`[OpenAPI] ${n} converter does not support openapi-3.0 target; using draft-07 conversion output.`:`[OpenAPI] ${n} (${o}) converter does not support openapi-3.0 target; using draft-07 conversion output.`),c}catch{return null}}function ce(e){if(!e||typeof e!=="object")return null;let t=e;if(y(t._def))return t._def;if(y(t._zod)&&y(t._zod.def))return t._zod.def;if(t.kind==="schema"&&typeof t.type==="string")return t;return null}function at(e){if(!e)return null;let t=e.typeName;if(typeof t==="string")return t;let r=e.type;if(typeof r==="string")return r;return null}function le(e){let t=["innerType","schema","type","out","in","left","right","wrapped","element"];for(let r of t)if(r in e)return e[r];return}function Ar(e,t){for(let r of t){let a=e[r];if(a&&typeof a==="object"&&!Array.isArray(a))return a}return}function Sr(e){if(!e)return!1;let t=e.toLowerCase();return t.includes("optional")||t.includes("default")||t.includes("catch")}function Rr(e){let t=e,r=!1,a=0;while(a<8){a+=1;let n=ce(t),o=at(n);if(!n||!Sr(o))break;r=!0;let i=le(n);if(!i)break;t=i}return{schema:t,optional:r}}function Hr(e){let t=e.entries;if(y(t))return t;let r=e.shape;if(typeof r==="function")try{let a=r();return y(a)?a:{}}catch{return{}}return y(r)?r:{}}function et(e){let t=e.values;if(Array.isArray(t))return t;if(t&&typeof t==="object")return Object.values(t);let r=e.entries;if(r&&typeof r==="object")return Object.values(r);let a=e.enum;if(a&&typeof a==="object")return Object.values(a);let n=e.options;if(Array.isArray(n))return n.map((o)=>{if(o&&typeof o==="object"&&"unit"in o)return o.unit;return o}).filter((o)=>o!==void 0);return[]}function Or(e){let t=e.toLowerCase();if(t.includes("string"))return{type:"string"};if(t.includes("number"))return{type:"number"};if(t.includes("boolean"))return{type:"boolean"};if(t.includes("bigint"))return{type:"string"};if(t==="null"||t.includes("zodnull"))return{type:"null"};if(t.includes("any")||t.includes("unknown")||t.includes("never"))return{};if(t.includes("date"))return{type:"string",format:"date-time"};if(t.includes("custom"))return{type:"object",additionalProperties:!0};return null}function k(e,t=new WeakSet){if(!e||typeof e!=="object")return{};if(t.has(e))return{};t.add(e);let r=ce(e),a=at(r);if(!r||!a)return{};let n=Or(a);if(n)return n;let o=a.toLowerCase();if(o.includes("object")){let d=Hr(r),l={},c=[];for(let[s,p]of Object.entries(d)){let h=Rr(p);if(l[s]=k(h.schema,t),!h.optional)c.push(s)}let m={type:"object",properties:l,additionalProperties:!0};if(c.length>0)m.required=c;return m}if(o.includes("array")){let d=Ar(r,["element","items","innerType","type"])??{};return{type:"array",items:k(d,t)}}if(o.includes("record")){let d=r.valueType??r.valueSchema;return{type:"object",additionalProperties:d?k(d,t):!0}}if(o.includes("tuple")){let l=(Array.isArray(r.items)?r.items:[]).map((c)=>k(c,t));return{type:"array",prefixItems:l,minItems:l.length,maxItems:l.length}}if(o.includes("union")){let d=r.options??r.schemas??[];if(!Array.isArray(d)||d.length===0)return{};return{anyOf:d.map((l)=>k(l,t))}}if(o.includes("intersection")){let{left:d,right:l}=r;if(!d||!l)return{};return{allOf:[k(d,t),k(l,t)]}}if(o.includes("enum")){let d=et(r);if(d.length>0){let l=d.every((s)=>typeof s==="string"),c=d.every((s)=>typeof s==="number"),m=d.every((s)=>typeof s==="boolean");if(l)return{type:"string",enum:d};if(c)return{type:"number",enum:d};if(m)return{type:"boolean",enum:d};return{enum:d}}return{}}if(o.includes("picklist")){let d=et(r);if(d.length>0){if(d.every((c)=>typeof c==="string"))return{type:"string",enum:d};return{enum:d}}return{}}if(o.includes("literal")){let d=r.value;if(d===void 0)return{};let l=d===null?"null":typeof d;if(l==="string"||l==="number"||l==="boolean"||l==="null")return{type:l,const:d};return{const:d}}if(o.includes("nullable")){let d=le(r);if(!d)return{};return{anyOf:[k(d,t),{type:"null"}]}}if(o.includes("lazy")){let d=r.getter;if(typeof d!=="function")return{};try{return k(d(),t)}catch{return{}}}let i=le(r);if(i)return k(i,t);return{}}function Z(e){if(!ce(e))return{};return k(e)}function Dr(e,t){if(!y(t))return;if(t.type!=="object"||!y(t.properties)){e.requestBody={required:!0,content:{"application/json":{schema:t}}};return}let r=new Set(Array.isArray(t.required)?t.required:[]),a=t.properties,n=Array.isArray(e.parameters)?e.parameters:[],o=[{key:"params",in:"path"},{key:"query",in:"query"},{key:"headers",in:"header"},{key:"cookies",in:"cookie"}];for(let d of o){let l=a[d.key];if(!y(l))continue;if(l.type!=="object"||!y(l.properties))continue;let c=new Set(Array.isArray(l.required)?l.required:[]);for(let[m,s]of Object.entries(l.properties))n.push({name:m,in:d.in,required:d.in==="path"?!0:c.has(m),schema:y(s)?s:{}})}if(n.length>0){let d=new Map;for(let l of n)d.set(`${l.in}:${l.name}`,l);e.parameters=[...d.values()]}let i=a.body;if(i)e.requestBody={required:r.has("body"),content:{"application/json":{schema:y(i)?i:{}}}}}function jr(e,t,r,a,n){let o=r.output;if(!o){e.responses={200:{description:"OK"}};return}let i={};if(typeof o==="object"&&o!==null&&"~standard"in o){let d=Ke(t,"200",o,a,n);if(d)i["200"]={description:"OK",content:{"application/json":{schema:d}}};else i["200"]={description:"OK"}}else for(let[d,l]of Object.entries(o)){let c=String(d),m=Ke(t,c,l,a,n),s=Lr(c);if(m&&!Cr(c))i[c]={description:s,content:{"application/json":{schema:m}}};else i[c]={description:s}}if(Object.keys(i).length===0)i["200"]={description:"OK"};e.responses=i}function nt(e,t){let r=[],a={},n="HttpBearer",o=new Set;for(let l of e){if(l.options.expose===!1)continue;if(!l.method||!l.path)continue;let c=l.method.toLowerCase();if(c==="options")continue;let m=Er(l.path),s={operationId:kr(c,m),tags:[l.options.schema?.tag||Br(l.path)]};if(typeof l.options.schema?.summary==="string"&&l.options.schema.summary.trim())s.summary=l.options.schema.summary.trim();let p=typeof l.options.schema?.description==="string"&&l.options.schema.description.trim()?l.options.schema.description.trim():typeof l.options.schema?.descrition==="string"&&l.options.schema.descrition.trim()?l.options.schema.descrition.trim():void 0;if(p)s.description=p;if(l.options.deprecated===!0)s.deprecated=!0;let h=wr(l.options.auth,n);if(h){o.add(h);let f=qe(h,t.auth);s.security=[{[f]:[]}]}let u=Nr(l.path,l.options.schema?.input,t.target,r);if(u){if(!s.summary&&typeof u.title==="string"&&u.title.trim())s.summary=u.title.trim();if(!s.description&&typeof u.description==="string"&&u.description.trim())s.description=u.description.trim();Dr(s,u)}if(Tr(s,l.path),jr(s,l.path,l.options.schema||{},t.target,r),!s.summary||!s.description){let f=Object.values(s.responses||{});for(let L of f){let x=L?.content?.["application/json"]?.schema;if(!x||typeof x!=="object")continue;if(!s.summary&&typeof x.title==="string"&&x.title.trim())s.summary=x.title.trim();if(!s.description&&typeof x.description==="string"&&x.description.trim())s.description=x.description.trim();if(s.summary&&s.description)break}}a[m]||={},a[m][c]=s}let d={openapi:t.target==="openapi-3.0"?"3.0.3":"3.1.0",info:{title:t.info?.title||"Vector API",version:t.info?.version||"1.0.0",...t.info?.description?{description:t.info.description}:{}},paths:a};if(o.size>0){let l={};for(let c of o){let m=qe(c,t.auth);l[m]=vr(c,t.auth)}d.components={securitySchemes:l}}return{document:d,warnings:r}}var pe="/_vector/openapi/tailwindcdn.js",me="/_vector/openapi/logo_dark.svg",be="/_vector/openapi/logo_white.svg",pt="/_vector/openapi/favicon/apple-touch-icon.png",mt="/_vector/openapi/favicon/favicon-32x32.png",bt="/_vector/openapi/favicon/favicon-16x16.png",_r="/_vector/openapi/favicon/favicon.ico",ut="/_vector/openapi/favicon/site.webmanifest",Ur="/_vector/openapi/favicon/android-chrome-192x192.png",Mr="/_vector/openapi/favicon/android-chrome-512x512.png",Pr=["../openapi/assets/tailwindcdn.js","../src/openapi/assets/tailwindcdn.js","../../src/openapi/assets/tailwindcdn.js"],zr=["../openapi/assets/logo_dark.svg","../src/openapi/assets/logo_dark.svg","../../src/openapi/assets/logo_dark.svg"],Jr=["../openapi/assets/logo_white.svg","../src/openapi/assets/logo_white.svg","../../src/openapi/assets/logo_white.svg"],Fr=["src/openapi/assets/tailwindcdn.js","openapi/assets/tailwindcdn.js","dist/openapi/assets/tailwindcdn.js"],Gr=["src/openapi/assets/logo_dark.svg","openapi/assets/logo_dark.svg","dist/openapi/assets/logo_dark.svg"],Yr=["src/openapi/assets/logo_white.svg","openapi/assets/logo_white.svg","dist/openapi/assets/logo_white.svg"],R=["../openapi/assets/favicon","../src/openapi/assets/favicon","../../src/openapi/assets/favicon"],H=["src/openapi/assets/favicon","openapi/assets/favicon","dist/openapi/assets/favicon"],Qr="/* OpenAPI docs runtime asset missing: tailwind disabled */";function w(e,t){return e.map((r)=>`${r}/${t}`)}function I(e,t){for(let a of e)try{let n=new URL(a,import.meta.url);if(ot(n))return Bun.file(n)}catch{}let r=process.cwd();for(let a of t){let n=$r(r,a);if(ot(n))return Bun.file(n)}return null}var dt=I(Pr,Fr),it=I(zr,Gr),lt=I(Jr,Yr),Vr=I(w(R,"apple-touch-icon.png"),w(H,"apple-touch-icon.png")),Wr=I(w(R,"favicon-32x32.png"),w(H,"favicon-32x32.png")),Xr=I(w(R,"favicon-16x16.png"),w(H,"favicon-16x16.png")),Zr=I(w(R,"favicon.ico"),w(H,"favicon.ico")),qr=I(w(R,"site.webmanifest"),w(H,"site.webmanifest")),Kr=I(w(R,"android-chrome-192x192.png"),w(H,"android-chrome-192x192.png")),ea=I(w(R,"android-chrome-512x512.png"),w(H,"android-chrome-512x512.png")),st=[{path:pt,file:Vr,contentType:"image/png",filename:"apple-touch-icon.png"},{path:mt,file:Wr,contentType:"image/png",filename:"favicon-32x32.png"},{path:bt,file:Xr,contentType:"image/png",filename:"favicon-16x16.png"},{path:_r,file:Zr,contentType:"image/x-icon",filename:"favicon.ico"},{path:ut,file:qr,contentType:"application/manifest+json; charset=utf-8",filename:"site.webmanifest"},{path:Ur,file:Kr,contentType:"image/png",filename:"android-chrome-192x192.png"},{path:Mr,file:ea,contentType:"image/png",filename:"android-chrome-512x512.png"}],ue="public, max-age=0, must-revalidate",G="public, max-age=31536000, immutable",he="no-store",ta=3000;function ct(e){if(e===void 0)return ta;let t=Number(e);if(!Number.isInteger(t)||t<0||t>65535)throw new Error(`Invalid port: ${String(e)}. Port must be an integer between 0 and 65535.`);return t}function ra(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function aa(e){let t="^";for(let r of e){if(r==="*"){t+=".*";continue}t+=ra(r)}return t+="$",new RegExp(t)}function na(e,t){if(!t.includes("*"))return e===t;return aa(t).test(e)}class fe{server=null;router;config;openapiConfig;openapiDocCache=null;openapiDocsHtmlCache=null;openapiWarningsLogged=!1;openapiTailwindMissingLogged=!1;openapiLogoDarkMissingLogged=!1;openapiLogoWhiteMissingLogged=!1;corsHandler=null;corsHeadersEntries=null;constructor(e,t){if(this.router=e,this.config=t,this.openapiConfig=this.normalizeOpenAPIConfig(t.openapi,t.development),t.cors){let r=this.normalizeCorsOptions(t.cors),{preflight:a,corsify:n}=Xe(r);if(this.corsHandler={preflight:a,corsify:n},typeof r.origin==="string"&&(r.origin!=="*"||!r.credentials)){let i={"access-control-allow-origin":r.origin,"access-control-allow-methods":r.allowMethods,"access-control-allow-headers":r.allowHeaders,"access-control-expose-headers":r.exposeHeaders,"access-control-max-age":String(r.maxAge)};if(r.credentials)i["access-control-allow-credentials"]="true";this.corsHeadersEntries=Object.entries(i)}this.router.setCorsHeaders(this.corsHeadersEntries),this.router.setCorsHandler(this.corsHeadersEntries?null:this.corsHandler.corsify)}}setCheckpointGateway(e){this.router.setCheckpointGateway(e)}normalizeOpenAPIConfig(e,t){let a=t!==!1&&!0;if(e===!1)return{enabled:!1,path:"/openapi.json",target:"openapi-3.0",docs:{enabled:!1,path:"/docs"}};if(e===!0)return{enabled:!0,path:"/openapi.json",target:"openapi-3.0",docs:{enabled:!1,path:"/docs"}};let n=e||{},o=n.docs,i=typeof o==="boolean"?{enabled:o,path:"/docs",exposePaths:void 0}:{enabled:o?.enabled===!0,path:o?.path||"/docs",exposePaths:Array.isArray(o?.exposePaths)?o.exposePaths.map((d)=>typeof d==="string"?d.trim():"").filter((d)=>d.length>0):void 0};return{enabled:n.enabled??a,path:n.path||"/openapi.json",target:n.target||"openapi-3.0",docs:i,info:n.info,auth:n.auth}}isDocsReservedPath(e){return e===this.openapiConfig.path||this.openapiConfig.docs.enabled&&e===this.openapiConfig.docs.path}shouldLogOpenAPIConversionWarnings(){if(this.config.development===!1)return!1;let r=process.env.LOG_LEVEL;return typeof r==="string"&&r.toLowerCase()==="debug"}getOpenAPIDocument(){if(this.openapiDocCache)return this.openapiDocCache;let e=this.router.getRouteDefinitions().filter((r)=>!this.isDocsReservedPath(r.path)),t=nt(e,{target:this.openapiConfig.target,info:this.openapiConfig.info,auth:this.openapiConfig.auth});if(!this.openapiWarningsLogged&&t.warnings.length>0){if(this.shouldLogOpenAPIConversionWarnings())for(let r of t.warnings)console.warn(r);this.openapiWarningsLogged=!0}return this.openapiDocCache=t.document,this.openapiDocCache}getOpenAPIDocumentForDocs(){let e=this.openapiConfig.docs.exposePaths,t=this.getOpenAPIDocument();if(!Array.isArray(e)||e.length===0)return t;let r=t.paths&&typeof t.paths==="object"&&!Array.isArray(t.paths)?t.paths:{},a={};for(let[n,o]of Object.entries(r))if(e.some((i)=>na(n,i)))a[n]=o;return{...t,paths:a}}getOpenAPIDocsHtmlCacheEntry(){if(this.openapiDocsHtmlCache)return this.openapiDocsHtmlCache;let e=Ze(this.getOpenAPIDocumentForDocs(),this.openapiConfig.path,pe,me,be,pt,mt,bt,ut),t=Bun.gzipSync(e),r=`"${Bun.hash(e).toString(16)}"`;return this.openapiDocsHtmlCache={html:e,gzip:t,etag:r},this.openapiDocsHtmlCache}requestAcceptsGzip(e){let t=e.headers.get("accept-encoding");return Boolean(t&&/\bgzip\b/i.test(t))}validateReservedOpenAPIPaths(){if(!this.openapiConfig.enabled)return;let e=new Set([this.openapiConfig.path]);if(this.openapiConfig.docs.enabled){e.add(this.openapiConfig.docs.path),e.add(pe),e.add(me),e.add(be);for(let n of st)e.add(n.path)}let t=this.router.getRouteDefinitions().filter((n)=>e.has(n.path)).map((n)=>`${n.method} ${n.path}`),r=Object.entries(this.router.getRouteTable()).filter(([n,o])=>e.has(n)&&o instanceof Response).map(([n])=>`STATIC ${n}`),a=[...t,...r];if(a.length>0)throw new Error(`OpenAPI reserved path conflict: ${a.join(", ")}. Change your route path(s) or reconfigure openapi.path/docs.path.`)}tryHandleOpenAPIRequest(e){if(!this.openapiConfig.enabled||e.method!=="GET")return null;let t=new URL(e.url).pathname;if(t===this.openapiConfig.path)return Response.json(this.getOpenAPIDocument());if(this.openapiConfig.docs.enabled&&t===this.openapiConfig.docs.path){let{html:r,gzip:a,etag:n}=this.getOpenAPIDocsHtmlCacheEntry();if(e.headers.get("if-none-match")===n)return new Response(null,{status:304,headers:{etag:n,"cache-control":ue,vary:"accept-encoding"}});if(this.requestAcceptsGzip(e))return new Response(a,{status:200,headers:{"content-type":"text/html; charset=utf-8","content-encoding":"gzip",etag:n,"cache-control":ue,vary:"accept-encoding"}});return new Response(r,{status:200,headers:{"content-type":"text/html; charset=utf-8",etag:n,"cache-control":ue,vary:"accept-encoding"}})}if(this.openapiConfig.docs.enabled&&t===pe){if(!dt){if(!this.openapiTailwindMissingLogged)this.openapiTailwindMissingLogged=!0,console.warn('[OpenAPI] Missing docs runtime asset "tailwindcdn.js". Serving inline fallback script instead.');return new Response(Qr,{status:200,headers:{"content-type":"application/javascript; charset=utf-8","cache-control":G}})}return new Response(dt,{status:200,headers:{"content-type":"application/javascript; charset=utf-8","cache-control":G}})}if(this.openapiConfig.docs.enabled&&t===me){if(!it){if(!this.openapiLogoDarkMissingLogged)this.openapiLogoDarkMissingLogged=!0,console.warn('[OpenAPI] Missing docs runtime asset "logo_dark.svg".');return new Response("OpenAPI docs runtime asset missing: logo_dark.svg",{status:404,headers:{"content-type":"text/plain; charset=utf-8","cache-control":he}})}return new Response(it,{status:200,headers:{"content-type":"image/svg+xml; charset=utf-8","cache-control":G}})}if(this.openapiConfig.docs.enabled&&t===be){if(!lt){if(!this.openapiLogoWhiteMissingLogged)this.openapiLogoWhiteMissingLogged=!0,console.warn('[OpenAPI] Missing docs runtime asset "logo_white.svg".');return new Response("OpenAPI docs runtime asset missing: logo_white.svg",{status:404,headers:{"content-type":"text/plain; charset=utf-8","cache-control":he}})}return new Response(lt,{status:200,headers:{"content-type":"image/svg+xml; charset=utf-8","cache-control":G}})}if(this.openapiConfig.docs.enabled){let r=st.find((a)=>a.path===t);if(r){if(!r.file)return new Response(`OpenAPI docs runtime asset missing: ${r.filename}`,{status:404,headers:{"content-type":"text/plain; charset=utf-8","cache-control":he}});return new Response(r.file,{status:200,headers:{"content-type":r.contentType,"cache-control":G}})}}return null}normalizeCorsOptions(e){return{origin:e.origin||"*",credentials:e.credentials!==!1,allowHeaders:Array.isArray(e.allowHeaders)?e.allowHeaders.join(", "):e.allowHeaders||"Content-Type, Authorization",allowMethods:Array.isArray(e.allowMethods)?e.allowMethods.join(", "):e.allowMethods||"GET, POST, PUT, PATCH, DELETE, OPTIONS",exposeHeaders:Array.isArray(e.exposeHeaders)?e.exposeHeaders.join(", "):e.exposeHeaders||"Authorization",maxAge:e.maxAge||86400}}applyCors(e,t){if(this.corsHeadersEntries){for(let[r,a]of this.corsHeadersEntries)e.headers.set(r,a);return e}if(this.corsHandler&&t)return this.corsHandler.corsify(e,t);return e}async start(){let e=ct(this.config.port),t=this.config.hostname||"localhost";this.validateReservedOpenAPIPaths();let r=async(a)=>{try{if(this.corsHandler&&a.method==="OPTIONS")return this.corsHandler.preflight(a);let n=this.tryHandleOpenAPIRequest(a);if(n)return this.applyCors(n,a);return await this.router.handle(a)}catch(n){return console.error("Server error:",n),this.applyCors(new Response("Internal Server Error",{status:500}),a)}};try{if(this.server=Bun.serve({port:e,hostname:t,reusePort:this.config.reusePort!==!1,fetch:r,idleTimeout:this.config.idleTimeout??60,error:(a,n)=>{return console.error("[ERROR] Server error:",a),this.applyCors(new Response("Internal Server Error",{status:500}),n)}}),!this.server||!this.server.port)throw new Error(`Failed to start server on ${t}:${e} - server object is invalid`);return this.server}catch(a){if(a.code==="EADDRINUSE"||a.message?.includes("address already in use"))a.message=`Port ${e} is already in use`,a.port=e;else if(a.code==="EACCES"||a.message?.includes("permission denied"))a.message=`Permission denied to bind to port ${e}`,a.port=e;else if(a.message?.includes("EADDRNOTAVAIL"))a.message=`Cannot bind to hostname ${t}`,a.hostname=t;throw a}}stop(){if(this.server)this.server.stop(),this.server=null,this.openapiDocCache=null,this.openapiDocsHtmlCache=null,this.openapiWarningsLogged=!1,console.log("Server stopped")}getServer(){return this.server}getPort(){return this.server?.port??ct(this.config.port)}getHostname(){return this.server?.hostname||this.config.hostname||"localhost"}getUrl(){let e=this.getPort();return`http://${this.getHostname()}:${e}`}}class j{static instance;router;server=null;middlewareManager;authManager;cacheManager;config={};routeScanner=null;routeGenerator=null;_protectedHandler=null;_cacheHandler=null;shutdownPromise=null;checkpointProcessManager=null;constructor(){this.middlewareManager=new W,this.authManager=new te,this.cacheManager=new re,this.router=new F(this.middlewareManager,this.authManager,this.cacheManager)}static getInstance(){if(!j.instance)j.instance=new j;return j.instance}setProtectedHandler(e){if(this._protectedHandler=e,e){this.authManager.setProtectedHandler(e);return}this.authManager.clearProtectedHandler()}getProtectedHandler(){return this._protectedHandler}setCacheHandler(e){if(this._cacheHandler=e,e){this.cacheManager.setCacheHandler(e);return}this.cacheManager.clearCacheHandler()}getCacheHandler(){return this._cacheHandler}addRoute(e,t){this.router.route(e,t)}async startServer(e){if(this.checkpointProcessManager)await this.checkpointProcessManager.stopAll(),this.checkpointProcessManager=null;this.config={...this.config,...e};let t={...this.config.defaults?.route};if(this.router.setRouteBooleanDefaults(t),this.router.setDevelopmentMode(this.config.development),this.middlewareManager.clear(),this.config.autoDiscover!==!1)this.router.clearRoutes();if(e?.before)this.middlewareManager.addBefore(...e.before);if(e?.finally)this.middlewareManager.addFinally(...e.finally);if(typeof this.config.startup==="function")await this.config.startup();if(this.config.autoDiscover!==!1)await this.discoverRoutes();this.server=new fe(this.router,this.config);let r=await this.server.start();if(this.config.checkpoint&&this.config.checkpoint.enabled!==!1)await this.enableCheckpointGateway(this.config.checkpoint);return r}async discoverRoutes(){let e=this.config.routesDir||"./routes",t=this.config.routeExcludePatterns;if(this.routeScanner=new V(e,t),!this.routeGenerator)this.routeGenerator=new ae;try{let r=await this.routeScanner.scan();if(r.length>0){if(this.config.development)await this.routeGenerator.generate(r);for(let a of r)try{let o=await import(`${X(a.path)}?t=${Date.now()}`),i=a.name==="default"?o.default:o[a.name];if(i){if(this.isRouteDefinition(i))this.router.route(i.options,i.handler),this.logRouteLoaded(i.options);else if(this.isRouteEntry(i))this.router.addRoute(i),this.logRouteLoaded(i);else if(typeof i==="function")this.router.route(a.options,i),this.logRouteLoaded(a.options)}}catch(n){console.error(`Failed to load route ${a.name} from ${a.path}:`,n)}}}catch(r){if(r.code!=="ENOENT"&&r.code!=="ENOTDIR")console.error("Failed to discover routes:",r)}}async loadRoute(e){if(typeof e==="function"){let t=e();if(this.isRouteEntry(t))this.router.addRoute(t)}else if(e&&typeof e==="object"){for(let[,t]of Object.entries(e))if(typeof t==="function"){let r=t();if(this.isRouteEntry(r))this.router.addRoute(r)}}}isRouteEntry(e){if(!Array.isArray(e)||e.length<3)return!1;let[t,r,a,n]=e;return typeof t==="string"&&r instanceof RegExp&&Array.isArray(a)&&a.length>0&&a.every((o)=>typeof o==="function")&&(n===void 0||typeof n==="string")}isRouteDefinition(e){return e!==null&&typeof e==="object"&&"entry"in e&&"options"in e&&"handler"in e&&typeof e.handler==="function"}logRouteLoaded(e){}async enableCheckpointGateway(e){if(!this.server)throw new Error("Cannot enable checkpoint gateway before server is started. Call startServer() first.");let{CheckpointManager:t}=await Promise.resolve().then(() => (zt(),Pt)),{CheckpointProcessManager:r}=await Promise.resolve().then(() => (Kt(),qt)),{CheckpointResolver:a}=await Promise.resolve().then(() => tr),{CheckpointForwarder:n}=await Promise.resolve().then(() => ar),{CheckpointGateway:o}=await Promise.resolve().then(() => or);if(this.checkpointProcessManager)await this.checkpointProcessManager.stopAll(),this.checkpointProcessManager=null;let i=new t(e),d=new r({idleTimeoutMs:e?.idleTimeoutMs});this.checkpointProcessManager=d;let l=new a(i,d,{versionHeader:e?.versionHeader,cacheKeyOverride:e?.cacheKeyOverride}),c=new n,m=new o(l,c);this.server.setCheckpointGateway(m);let s=await i.getActive();if(s)try{let p=await i.readManifest(s.version);await d.spawn(p,i.getStorageDir())}catch(p){console.error(`[Checkpoint] Failed to start active checkpoint ${s.version}:`,p)}}stop(){if(this.server)this.server.stop(),this.server=null}async shutdown(){if(this.shutdownPromise)return this.shutdownPromise;this.shutdownPromise=(async()=>{if(this.stop(),this.checkpointProcessManager)await this.checkpointProcessManager.stopAll(),this.checkpointProcessManager=null;if(typeof this.config.shutdown==="function")await this.config.shutdown()})();try{await this.shutdownPromise}finally{this.shutdownPromise=null}}getServer(){return this.server}getRouter(){return this.router}getCacheManager(){return this.cacheManager}getAuthManager(){return this.authManager}static resetInstance(){j.instance=null}}var He=j.getInstance;function dr(e,t){return{entry:{method:e.method.toUpperCase(),path:e.path},options:e,handler:t}}function Xa(e,t){return dr({...e,deprecated:!0},t)}function Za(e){let t=e??null;try{return JSON.stringify(t)}catch(r){if(r instanceof TypeError&&/\bbigint\b/i.test(r.message))return JSON.stringify(t,(a,n)=>typeof n==="bigint"?n.toString():n);throw r}}function qa(e){return(e.split(";",1)[0]??e).trim().toLowerCase()===z.JSON}function Ka(e){let t=[`${e.name}=${e.value}`];if(e.maxAge!==void 0&&Number.isFinite(e.maxAge))t.push(`Max-Age=${Math.trunc(e.maxAge)}`);if(e.domain)t.push(`Domain=${e.domain}`);if(e.path)t.push(`Path=${e.path}`);if(e.expires!==void 0){let r=e.expires instanceof Date?e.expires:new Date(e.expires);if(!Number.isNaN(r.getTime()))t.push(`Expires=${r.toUTCString()}`)}if(e.httpOnly)t.push("HttpOnly");if(e.secure)t.push("Secure");if(e.sameSite)t.push(`SameSite=${e.sameSite}`);if(e.partitioned)t.push("Partitioned");if(e.priority)t.push(`Priority=${e.priority}`);return t.join("; ")}function en(e,t){if(!t||t.length===0)return;for(let r of t)e.append("set-cookie",typeof r==="string"?r:Ka(r))}function b(e,t,r){let a={error:!0,message:t,statusCode:e,timestamp:new Date().toISOString()};return _(e,a,r)}var S={badRequest:(e="Bad Request",t)=>b(A.BAD_REQUEST,e,t),unauthorized:(e="Unauthorized",t)=>b(A.UNAUTHORIZED,e,t),paymentRequired:(e="Payment Required",t)=>b(402,e,t),forbidden:(e="Forbidden",t)=>b(A.FORBIDDEN,e,t),notFound:(e="Not Found",t)=>b(A.NOT_FOUND,e,t),methodNotAllowed:(e="Method Not Allowed",t)=>b(405,e,t),notAcceptable:(e="Not Acceptable",t)=>b(406,e,t),requestTimeout:(e="Request Timeout",t)=>b(408,e,t),conflict:(e="Conflict",t)=>b(A.CONFLICT,e,t),gone:(e="Gone",t)=>b(410,e,t),lengthRequired:(e="Length Required",t)=>b(411,e,t),preconditionFailed:(e="Precondition Failed",t)=>b(412,e,t),payloadTooLarge:(e="Payload Too Large",t)=>b(413,e,t),uriTooLong:(e="URI Too Long",t)=>b(414,e,t),unsupportedMediaType:(e="Unsupported Media Type",t)=>b(415,e,t),rangeNotSatisfiable:(e="Range Not Satisfiable",t)=>b(416,e,t),expectationFailed:(e="Expectation Failed",t)=>b(417,e,t),imATeapot:(e="I'm a teapot",t)=>b(418,e,t),misdirectedRequest:(e="Misdirected Request",t)=>b(421,e,t),unprocessableEntity:(e="Unprocessable Entity",t)=>b(A.UNPROCESSABLE_ENTITY,e,t),locked:(e="Locked",t)=>b(423,e,t),failedDependency:(e="Failed Dependency",t)=>b(424,e,t),tooEarly:(e="Too Early",t)=>b(425,e,t),upgradeRequired:(e="Upgrade Required",t)=>b(426,e,t),preconditionRequired:(e="Precondition Required",t)=>b(428,e,t),tooManyRequests:(e="Too Many Requests",t)=>b(429,e,t),requestHeaderFieldsTooLarge:(e="Request Header Fields Too Large",t)=>b(431,e,t),unavailableForLegalReasons:(e="Unavailable For Legal Reasons",t)=>b(451,e,t),internalServerError:(e="Internal Server Error",t)=>b(A.INTERNAL_SERVER_ERROR,e,t),notImplemented:(e="Not Implemented",t)=>b(501,e,t),badGateway:(e="Bad Gateway",t)=>b(502,e,t),serviceUnavailable:(e="Service Unavailable",t)=>b(503,e,t),gatewayTimeout:(e="Gateway Timeout",t)=>b(504,e,t),httpVersionNotSupported:(e="HTTP Version Not Supported",t)=>b(505,e,t),variantAlsoNegotiates:(e="Variant Also Negotiates",t)=>b(506,e,t),insufficientStorage:(e="Insufficient Storage",t)=>b(507,e,t),loopDetected:(e="Loop Detected",t)=>b(508,e,t),notExtended:(e="Not Extended",t)=>b(510,e,t),networkAuthenticationRequired:(e="Network Authentication Required",t)=>b(511,e,t),invalidArgument:(e="Invalid Argument",t)=>b(A.UNPROCESSABLE_ENTITY,e,t),rateLimitExceeded:(e="Rate Limit Exceeded",t)=>b(429,e,t),maintenance:(e="Service Under Maintenance",t)=>b(503,e,t),custom:(e,t,r)=>b(e,t,r)};function _(e,t,r=z.JSON){let a=typeof r==="string"?{contentType:r}:r??{},n=new Headers(a.headers),o=a.contentType??n.get("content-type")??z.JSON;if(a.contentType||!n.has("content-type"))n.set("content-type",o);en(n,a.cookies);let i=qa(o)?Za(t):t;return new Response(i,{status:e,statusText:a.statusText,headers:n})}import{existsSync as tn}from"fs";import{resolve as rn,isAbsolute as an}from"path";class Oe{configPath;config=null;configSource="default";constructor(e){let t=e||"vector.config.ts";this.configPath=an(t)?t:rn(process.cwd(),t)}async load(){if(tn(this.configPath))try{let t=await import(`${X(this.configPath)}?t=${Date.now()}`);this.config=t.default||t,this.configSource="user"}catch(e){let t=e instanceof Error?e.message:String(e);console.error(`[vector] Failed to load config from ${this.configPath}: ${t}`),console.error("[vector] Server is using default configuration. Fix your config file and restart."),this.config={}}else this.config={};return await this.buildLegacyConfig()}getConfigSource(){return this.configSource}async buildLegacyConfig(){let e={};if(this.config)e.port=this.normalizePort(this.config.port),e.hostname=this.config.hostname,e.reusePort=this.config.reusePort,e.development=this.config.development,e.routesDir=this.config.routesDir||"./routes",e.routeExcludePatterns=this.config.routeExcludePatterns,e.idleTimeout=this.config.idleTimeout,e.defaults=this.config.defaults,e.openapi=this.config.openapi,e.startup=this.config.startup,e.shutdown=this.config.shutdown,e.checkpoint=this.config.checkpoint;if(e.autoDiscover=!0,this.config?.cors)if(typeof this.config.cors==="boolean")e.cors=this.config.cors?{origin:"*",credentials:!0,allowHeaders:"Content-Type, Authorization",allowMethods:"GET, POST, PUT, PATCH, DELETE, OPTIONS",exposeHeaders:"Authorization",maxAge:86400}:void 0;else e.cors=this.config.cors;if(this.config?.before)e.before=this.config.before;if(this.config?.after)e.finally=this.config.after;return e}normalizePort(e){if(e===void 0)return;return Number(e)}async loadAuthHandler(){return this.config?.auth||null}async loadCacheHandler(){return this.config?.cache||null}getConfig(){return this.config}}async function nn(e={}){let t=new Oe(e.configPath),r=await t.load(),a=t.getConfigSource(),n={...r};if(e.mutateConfig)n=await e.mutateConfig(n,{configSource:a});if(e.config)n={...n,...e.config};if(e.autoDiscover!==void 0)n.autoDiscover=e.autoDiscover;let o=He(),i=e.protectedHandler!==void 0?e.protectedHandler:await t.loadAuthHandler(),d=e.cacheHandler!==void 0?e.cacheHandler:await t.loadCacheHandler();o.setProtectedHandler(i??null),o.setCacheHandler(d??null);let l=await o.startServer(n),c={...n,port:l.port??n.port??$.PORT,hostname:l.hostname||n.hostname||$.HOSTNAME,reusePort:n.reusePort!==!1,idleTimeout:n.idleTimeout??60};return{server:l,config:c,stop:()=>o.stop(),shutdown:()=>o.shutdown()}}export{nn as startVector,dr as route,Xa as depRoute,_ as createResponse,ze as OpenApiSecuritySchemeType,Je as HttpAuthScheme,J as AuthKind,S as APIError};
|