vector-framework 1.2.1 → 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 +3817 -350
- 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 +3 -0
- package/dist/core/server.d.ts.map +1 -1
- package/dist/core/server.js +35 -10
- 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/errors/index.cjs +2 -0
- 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 +2657 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -1433
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1301 -77
- 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 +332 -16
- 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 +9 -14
- 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 +51 -11
- 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 +380 -13
- package/src/types/index.ts +83 -30
- package/src/utils/validation.ts +5 -3
package/dist/index.mjs
CHANGED
|
@@ -1,33 +1,221 @@
|
|
|
1
|
-
|
|
1
|
+
// @bun
|
|
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.
|
|
2
190
|
// Generated at: ${new Date().toISOString()}
|
|
3
191
|
|
|
4
|
-
${
|
|
192
|
+
${r.join(`
|
|
5
193
|
`)}
|
|
6
194
|
|
|
7
195
|
export const routes = [
|
|
8
|
-
${
|
|
196
|
+
${o.join(`
|
|
9
197
|
`)}
|
|
10
198
|
];
|
|
11
199
|
|
|
12
200
|
export default routes;
|
|
13
|
-
`;await
|
|
14
|
-
...${
|
|
15
|
-
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}
|
|
16
204
|
}))`)}return`export const loadRoutes = async () => {
|
|
17
205
|
return Promise.all([
|
|
18
206
|
${t.join(`,
|
|
19
207
|
`)}
|
|
20
208
|
]);
|
|
21
|
-
};`}}var{existsSync:_e,promises:ie}=(()=>({}));class P{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=B(process.cwd(),e),this.excludePatterns=t||P.DEFAULT_EXCLUDE_PATTERNS}async scan(){let e=[];if(!_e(this.routesDir))return[];try{await this.scanDirectory(this.routesDir,e)}catch(t){if(t.code==="ENOENT")return console.warn(` ✗ Routes directory not accessible: ${this.routesDir}`),[];throw t}return e}isExcluded(e){let t=D(this.routesDir,e);for(let n of this.excludePatterns){let d=n.replace(/\./g,"\\.").replace(/\*\*/g,"__GLOBSTAR__").replace(/\*/g,"[^/]*").replace(/__GLOBSTAR__/g,".*").replace(/\?/g,"."),r=new RegExp(`^${d}$`),a=t.split(S).pop()||"";if(r.test(t)||r.test(a))return!0}return!1}async scanDirectory(e,t,n=""){let d=await ie.readdir(e);for(let r of d){let a=j(e,r);if((await ie.stat(a)).isDirectory()){let o=n?`${n}/${r}`:r;await this.scanDirectory(a,t,o)}else if(r.endsWith(".ts")||r.endsWith(".js")){if(this.isExcluded(a))continue;let o=D(this.routesDir,a).replace(/\.(ts|js)$/,"").split(S).join("/");try{let c=await import(process.platform==="win32"?`file:///${a.replace(/\\/g,"/")}`:a);if(c.default&&typeof c.default==="function")t.push({name:"default",path:a,method:"GET",options:{method:"GET",path:`/${o}`,expose:!0}});for(let[l,u]of Object.entries(c)){if(l==="default")continue;if(u&&typeof u==="object"&&"entry"in u&&"options"in u&&"handler"in u){let m=u;t.push({name:l,path:a,method:m.options.method,options:m.options})}else if(Array.isArray(u)&&u.length>=4){let[m,,,h]=u;t.push({name:l,path:a,method:m,options:{method:m,path:h,expose:!0}})}}}catch(s){console.error(`Failed to load route from ${a}:`,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 R{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 n of this.beforeHandlers){let d=await n(t);if(d instanceof Response)return d;t=d}return t}async executeFinally(e,t){if(this.finallyHandlers.length===0)return e;let n=e;for(let d of this.finallyHandlers)try{n=await d(n,t)}catch(r){console.error("After middleware error:",r)}return n}clone(){let e=new R;return e.beforeHandlers=[...this.beforeHandlers],e.finallyHandlers=[...this.finallyHandlers],e}clear(){this.beforeHandlers=[],this.finallyHandlers=[]}}function U(e){return process.platform==="win32"?`file:///${e.replace(/\\/g,"/")}`:e}function z(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 se(e){let t=e?.["~standard"];return!!t&&typeof t==="object"&&typeof t.validate==="function"&&t.version===1}async function le(e,t){let n=await e["~standard"].validate(t),d=n?.issues;if(Array.isArray(d)&&d.length>0)return{success:!1,issues:d};return{success:!0,value:n?.value}}function ce(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 $e(e){if(!Array.isArray(e))return[];let t=[];for(let n=0;n<e.length;n++){let d=e[n],r=d;if(d&&typeof d==="object"&&"key"in d)r=d.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 G(e,t){let n=[];for(let d=0;d<e.length;d++){let r=e[d],a=r,i={message:typeof a?.message==="string"&&a.message.length>0?a.message:"Invalid value",path:$e(a?.path)};if(typeof a?.code==="string")i.code=a.code;if(t)i.raw=r;n.push(i)}return n}function Q(e,t){return{error:!0,message:"Validation failed",statusCode:422,source:"validation",target:e,issues:t,timestamp:new Date().toISOString()}}class M{middlewareManager;authManager;cacheManager;routeBooleanDefaults={};developmentMode=void 0;routeDefinitions=[];routeTable=Object.create(null);routeMatchers=[];corsHeadersEntries=null;corsHandler=null;constructor(e,t,n){this.middlewareManager=e,this.authManager=t,this.cacheManager=n}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},n=this.routeBooleanDefaults,d=["auth","expose","rawRequest","validate","rawResponse"];for(let r of d)if(t[r]===void 0&&n[r]!==void 0)t[r]=n[r];return t}route(e,t){let n=this.applyRouteBooleanDefaults(e),d=n.method.toUpperCase(),r=n.path,a=this.wrapHandler(n,t),i=this.getOrCreateMethodMap(r);i[d]=a,this.routeDefinitions.push({method:d,path:r,options:n})}addRoute(e){let[t,,n,d]=e;if(!d)return;let r=this.getOrCreateMethodMap(d);r[t.toUpperCase()]=n[0];let a=t.toUpperCase();this.routeDefinitions.push({method:a,path:d,options:{method:a,path:d,expose:!0}})}bulkAddRoutes(e){for(let t of e)this.addRoute(t)}addStaticRoute(e,t){let n=this.routeTable[e];if(n&&!(n 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 n=this.routeTable[t.path];if(!n||n instanceof Response)continue;for(let[d,r]of Object.entries(n))e.push([d,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 w.badRequest("Malformed request URL")}e._parsedUrl=t;let n=t.pathname;for(let d of this.routeMatchers){let r=d.path,a=this.routeTable[r];if(!a)continue;if(a instanceof Response)continue;let i=a;if(e.method==="OPTIONS"||e.method in i){let o=n.match(d.regex);if(o){try{e.params=o.groups??{}}catch{}let s=i[e.method]??i.GET;if(s){let c=await s(e);if(c)return c}}}}return H.NOT_FOUND.clone()}prepareRequest(e,t){if(!e.context)e.context={};let n=!!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||n))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 d=this._parsedUrl??new URL(this.url),r=M.parseQuery(d);return Object.defineProperty(this,"query",{value:r,writable:!0,configurable:!0,enumerable:!0}),r},set(d){Object.defineProperty(this,"query",{value:d,writable:!0,configurable:!0,enumerable:!0})},configurable:!0,enumerable:!0})}catch{let d=e._parsedUrl??new URL(e.url);try{e.query=M.parseQuery(d)}catch{}}if(!Object.getOwnPropertyDescriptor(e,"cookies"))Object.defineProperty(e,"cookies",{get(){let d=this.headers.get("cookie")??"",r={};if(d)for(let a of d.split(";")){let i=a.indexOf("=");if(i>0)r[a.slice(0,i).trim()]=a.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 n=e.params;if(n&&typeof n==="object"&&!Array.isArray(n)&&Object.keys(n).length>0)return;let d;try{d=(e._parsedUrl??new URL(e.url)).pathname}catch{return}let r=d.match(t);if(!r?.groups)return;return r.groups}wrapHandler(e,t){let n=e.path,d=n.includes(":")?z(n):null;return async(r)=>{let a=r,i=this.resolveFallbackParams(r,d);this.prepareRequest(a,{params:i,route:n,metadata:e.metadata});try{if(e.expose===!1)return w.forbidden("Forbidden");let o=await this.middlewareManager.executeBefore(a);if(o instanceof Response)return o;let s=o;if(e.auth)try{await this.authManager.authenticate(s)}catch(f){return w.unauthorized(f instanceof Error?f.message:"Authentication failed",e.responseContentType)}if(!e.rawRequest&&s.method!=="GET"&&s.method!=="HEAD"){let f=null;try{let p=s.headers.get("content-type");if(p?.startsWith("application/json"))f=await s.json();else if(p?.startsWith("application/x-www-form-urlencoded"))f=Object.fromEntries(await s.formData());else if(p?.startsWith("multipart/form-data"))f=await s.formData();else f=await s.text()}catch{f=null}this.setContentAndBodyAlias(s,f)}let c=await this.validateInputSchema(s,e);if(c)return c;let l,u=e.cache;if(u&&typeof u==="number"&&u>0){let f=this.cacheManager.generateKey(s,{authUser:s.authUser});l=await this.cacheManager.get(f,async()=>{let p=await t(s);if(p instanceof Response)return{_isResponse:!0,body:await p.text(),status:p.status,headers:Object.fromEntries(p.headers.entries())};return p},u)}else if(u&&typeof u==="object"&&u.ttl){let f=u.key||this.cacheManager.generateKey(s,{authUser:s.authUser});l=await this.cacheManager.get(f,async()=>{let p=await t(s);if(p instanceof Response)return{_isResponse:!0,body:await p.text(),status:p.status,headers:Object.fromEntries(p.headers.entries())};return p},u.ttl)}else l=await t(s);if(l&&typeof l==="object"&&l._isResponse===!0)l=new Response(l.body,{status:l.status,headers:l.headers});let m;if(e.rawResponse||l instanceof Response)m=l instanceof Response?l:new Response(l);else m=N(200,l,e.responseContentType);m=await this.middlewareManager.executeFinally(m,s);let h=this.corsHeadersEntries;if(h)for(let[f,p]of h)m.headers.set(f,p);else{let f=this.corsHandler;if(f)m=f(m,s)}return m}catch(o){if(o instanceof Response)return o;return console.error("Route handler error:",o),w.internalServerError(o instanceof Error?o.message:String(o),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 n=e.content;if(t.rawRequest&&e.method!=="GET"&&e.method!=="HEAD")try{n=await e.clone().text()}catch{n=null}return{params:e.params??{},query:e.query??{},headers:Object.fromEntries(e.headers.entries()),cookies:e.cookies??{},body:n}}applyValidatedInput(e,t){if(e.validatedInput=t,!t||typeof t!=="object")return;let n=t;if("params"in n)try{e.params=n.params}catch{}if("query"in n)try{e.query=n.query}catch{}if("cookies"in n)try{e.cookies=n.cookies}catch{}if("body"in n)this.setContentAndBodyAlias(e,n.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 n=t.schema?.input;if(!n)return null;if(t.validate===!1)return null;if(!se(n))return w.internalServerError("Invalid route schema configuration",t.responseContentType);let d=this.isDevelopmentMode(),r=await this.buildInputValidationPayload(e,t);try{let a=await le(n,r);if(a.success===!1){let i=G(a.issues,d);return N(422,Q("input",i),t.responseContentType)}return this.applyValidatedInput(e,a.value),null}catch(a){let i=ce(a);if(i){let o=G(i,d);return N(422,Q("input",o),t.responseContentType)}return w.internalServerError(a instanceof Error?a.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 n=Object.create(null);return this.routeTable[e]=n,this.addRouteMatcher(e),n}addRouteMatcher(e){if(this.routeMatchers.some((t)=>t.path===e))return;this.routeMatchers.push({path:e,regex:z(e),specificity:this.routeSpecificityScore(e)}),this.routeMatchers.sort((t,n)=>{if(t.specificity!==n.specificity)return n.specificity-t.specificity;return t.path.localeCompare(n.path)})}removeRouteMatcher(e){this.routeMatchers=this.routeMatchers.filter((t)=>t.path!==e)}static parseQuery(e){let t={};for(let[n,d]of e.searchParams)if(n in t){let r=t[n];if(Array.isArray(r))r.push(d);else t[n]=[r,d]}else t[n]=d;return t}routeSpecificityScore(e){let a=e.split("/").filter(Boolean),i=0;for(let o of a)if(o.includes("*"))i+=1;else if(o.startsWith(":"))i+=10;else i+=1000;if(i+=e.length,!e.includes(":")&&!e.includes("*"))i+=1e4;return i}}var{existsSync:Ee}=(()=>({}));function be(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 ue(e){return typeof e.origin==="string"&&e.origin==="*"&&e.credentials||Array.isArray(e.origin)||typeof e.origin==="function"}function me(e,t,n){let d={};if(e){if(d["access-control-allow-origin"]=e,d["access-control-allow-methods"]=t.allowMethods,d["access-control-allow-headers"]=t.allowHeaders,d["access-control-expose-headers"]=t.exposeHeaders,d["access-control-max-age"]=String(t.maxAge),t.credentials)d["access-control-allow-credentials"]="true";if(n)d.vary="Origin"}return d}function Je(e,t){if(!e)return t;let n=e.split(",").map((r)=>r.trim()).filter(Boolean);if(!n.map((r)=>r.toLowerCase()).includes(t.toLowerCase()))n.push(t);return n.join(", ")}function fe(e){return{preflight(t){let n=t.headers.get("origin")??void 0,d=be(n,e),r=Boolean(n&&d&&ue(e));return new Response(null,{status:204,headers:me(d,e,r)})},corsify(t,n){let d=n.headers.get("origin")??void 0,r=be(d,e);if(!r)return t;let a=Boolean(d&&ue(e)),i=me(r,e,a);for(let[o,s]of Object.entries(i)){if(o==="vary"){t.headers.set("vary",Je(t.headers.get("vary"),s));continue}t.headers.set(o,s)}return t}}}function pe(e,t,n,d,r,a,i,o,s){let c=JSON.stringify(e).replace(/<\/script/gi,"<\\/script"),l=JSON.stringify(t),u=JSON.stringify(n),m=JSON.stringify(d),h=JSON.stringify(r),f=JSON.stringify(a),p=JSON.stringify(i),je=JSON.stringify(o),Me=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>
|
|
22
210
|
<html lang="en">
|
|
23
211
|
<head>
|
|
24
212
|
<meta charset="UTF-8">
|
|
25
213
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
26
214
|
<title>Vector API Documentation</title>
|
|
27
|
-
<link rel="apple-touch-icon" sizes="180x180" href=${
|
|
28
|
-
<link rel="icon" type="image/png" sizes="32x32" href=${
|
|
29
|
-
<link rel="icon" type="image/png" sizes="16x16" href=${
|
|
30
|
-
<link rel="manifest" href=${
|
|
215
|
+
<link rel="apple-touch-icon" sizes="180x180" href=${u}>
|
|
216
|
+
<link rel="icon" type="image/png" sizes="32x32" href=${f}>
|
|
217
|
+
<link rel="icon" type="image/png" sizes="16x16" href=${L}>
|
|
218
|
+
<link rel="manifest" href=${x}>
|
|
31
219
|
<script>
|
|
32
220
|
if (localStorage.getItem('theme') === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
|
|
33
221
|
document.documentElement.classList.add('dark');
|
|
@@ -35,7 +223,7 @@ ${t.join(`,
|
|
|
35
223
|
document.documentElement.classList.remove('dark');
|
|
36
224
|
}
|
|
37
225
|
</script>
|
|
38
|
-
<script src=${
|
|
226
|
+
<script src=${s}></script>
|
|
39
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">
|
|
40
228
|
<script>
|
|
41
229
|
tailwind.config = {
|
|
@@ -143,6 +331,124 @@ ${t.join(`,
|
|
|
143
331
|
.dark .json-number { color: #7dc9ff; }
|
|
144
332
|
.dark .json-boolean { color: #93a4bf; }
|
|
145
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
|
+
}
|
|
146
452
|
</style>
|
|
147
453
|
</head>
|
|
148
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">
|
|
@@ -150,7 +456,7 @@ ${t.join(`,
|
|
|
150
456
|
<aside id="docs-sidebar" class="fixed inset-y-0 left-0 z-40 w-72 md:w-64 border-r border-light-border dark:border-dark-border bg-light-surface dark:bg-dark-surface flex flex-col flex-shrink-0 transition-transform duration-300 ease-out -translate-x-full md:translate-x-0 md:static md:z-auto transition-colors duration-150">
|
|
151
457
|
<div class="h-14 flex items-center px-5 border-b border-light-border dark:border-dark-border">
|
|
152
458
|
<div class="flex items-center">
|
|
153
|
-
<img src=${
|
|
459
|
+
<img src=${p} alt="Vector" class="h-6 w-auto block dark:hidden" />
|
|
154
460
|
<img src=${h} alt="Vector" class="h-6 w-auto hidden dark:block" />
|
|
155
461
|
</div>
|
|
156
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">
|
|
@@ -172,6 +478,16 @@ ${t.join(`,
|
|
|
172
478
|
/>
|
|
173
479
|
</div>
|
|
174
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>
|
|
175
491
|
<nav class="flex-1 overflow-y-auto px-3 py-2 space-y-6 text-sm" id="sidebar-nav"></nav>
|
|
176
492
|
</aside>
|
|
177
493
|
|
|
@@ -183,7 +499,7 @@ ${t.join(`,
|
|
|
183
499
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path>
|
|
184
500
|
</svg>
|
|
185
501
|
</button>
|
|
186
|
-
<img src=${
|
|
502
|
+
<img src=${p} alt="Vector" class="h-5 w-auto block dark:hidden" />
|
|
187
503
|
<img src=${h} alt="Vector" class="h-5 w-auto hidden dark:block" />
|
|
188
504
|
</div>
|
|
189
505
|
<div class="flex-1"></div>
|
|
@@ -205,6 +521,9 @@ ${t.join(`,
|
|
|
205
521
|
<span id="endpoint-method" class="px-2.5 py-0.5 rounded-full text-xs font-mono font-medium"></span>
|
|
206
522
|
<h2 class="text-xl font-semibold tracking-tight" id="endpoint-title">Operation</h2>
|
|
207
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>
|
|
208
527
|
<p class="text-sm opacity-80 mb-8 font-mono" id="endpoint-path">/</p>
|
|
209
528
|
<div class="grid grid-cols-1 lg:grid-cols-12 gap-10">
|
|
210
529
|
<div class="lg:col-span-5 space-y-8" id="params-column"></div>
|
|
@@ -300,10 +619,14 @@ ${t.join(`,
|
|
|
300
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>
|
|
301
620
|
</div>
|
|
302
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>
|
|
303
626
|
|
|
304
627
|
<script>
|
|
305
628
|
const spec = ${c};
|
|
306
|
-
const openapiPath = ${
|
|
629
|
+
const openapiPath = ${m};
|
|
307
630
|
const methodBadgeDefault = "bg-black/5 text-light-text/80 dark:bg-white/10 dark:text-dark-text/80";
|
|
308
631
|
const methodBadge = {
|
|
309
632
|
GET: "bg-brand-soft text-brand-deep dark:bg-brand/20 dark:text-brand",
|
|
@@ -370,14 +693,71 @@ ${t.join(`,
|
|
|
370
693
|
return ops;
|
|
371
694
|
}
|
|
372
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
|
+
|
|
373
748
|
const operations = getOperations();
|
|
374
749
|
let selected = operations[0] || null;
|
|
375
750
|
const operationParamValues = new Map();
|
|
376
751
|
const operationBodyDrafts = new Map();
|
|
377
|
-
const requestHeaders =
|
|
752
|
+
const requestHeaders = loadSavedHeaders();
|
|
378
753
|
let expandModalMode = null;
|
|
379
754
|
let isMobileSidebarOpen = false;
|
|
380
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;
|
|
381
761
|
|
|
382
762
|
function setMobileSidebarOpen(open) {
|
|
383
763
|
const sidebar = document.getElementById("docs-sidebar");
|
|
@@ -397,6 +777,29 @@ ${t.join(`,
|
|
|
397
777
|
return op.method + " " + op.path;
|
|
398
778
|
}
|
|
399
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
|
+
|
|
400
803
|
function getOperationParameterGroups(op) {
|
|
401
804
|
const params =
|
|
402
805
|
op &&
|
|
@@ -446,7 +849,7 @@ ${t.join(`,
|
|
|
446
849
|
return resolved;
|
|
447
850
|
}
|
|
448
851
|
|
|
449
|
-
function buildRequestPath(op, pathParams, queryParams, values) {
|
|
852
|
+
function buildRequestPath(op, pathParams, queryParams, values, extraQuery) {
|
|
450
853
|
const resolvedPath = resolvePath(op.path, pathParams, values);
|
|
451
854
|
const query = new URLSearchParams();
|
|
452
855
|
|
|
@@ -458,6 +861,13 @@ ${t.join(`,
|
|
|
458
861
|
query.append(param.name, String(rawValue));
|
|
459
862
|
}
|
|
460
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
|
+
|
|
461
871
|
const queryString = query.toString();
|
|
462
872
|
return queryString ? resolvedPath + "?" + queryString : resolvedPath;
|
|
463
873
|
}
|
|
@@ -597,14 +1007,25 @@ ${t.join(`,
|
|
|
597
1007
|
|
|
598
1008
|
const name = document.createElement("span");
|
|
599
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
|
+
}
|
|
600
1014
|
|
|
601
1015
|
row.appendChild(method);
|
|
602
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
|
+
}
|
|
603
1023
|
a.appendChild(row);
|
|
604
1024
|
|
|
605
1025
|
a.onclick = (e) => {
|
|
606
1026
|
e.preventDefault();
|
|
607
1027
|
selected = op;
|
|
1028
|
+
history.pushState(null, "", getOpHash(op));
|
|
608
1029
|
renderSidebar();
|
|
609
1030
|
renderEndpoint();
|
|
610
1031
|
if (window.innerWidth < 768) {
|
|
@@ -618,51 +1039,257 @@ ${t.join(`,
|
|
|
618
1039
|
}
|
|
619
1040
|
}
|
|
620
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
|
+
|
|
621
1155
|
function renderParamSection(title, params) {
|
|
622
1156
|
if (!params.length) return "";
|
|
623
1157
|
let rows = "";
|
|
624
1158
|
for (const p of params) {
|
|
625
|
-
const
|
|
626
|
-
const
|
|
627
|
-
|
|
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>";
|
|
628
1200
|
}
|
|
629
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>";
|
|
630
1202
|
}
|
|
631
1203
|
|
|
632
1204
|
function getSchemaTypeLabel(schema) {
|
|
633
|
-
|
|
634
|
-
if (
|
|
635
|
-
if (
|
|
636
|
-
if (
|
|
637
|
-
if (
|
|
638
|
-
if (
|
|
639
|
-
if (Array.isArray(
|
|
640
|
-
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";
|
|
641
1214
|
return "unknown";
|
|
642
1215
|
}
|
|
643
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
|
+
|
|
644
1265
|
function buildSchemaChildren(schema) {
|
|
645
|
-
|
|
1266
|
+
const resolved = resolveSchemaRef(schema);
|
|
1267
|
+
if (!resolved || typeof resolved !== "object") return [];
|
|
646
1268
|
|
|
647
1269
|
const children = [];
|
|
648
1270
|
|
|
649
|
-
if (
|
|
1271
|
+
if (resolved.properties && typeof resolved.properties === "object") {
|
|
650
1272
|
const requiredSet = new Set(
|
|
651
|
-
Array.isArray(
|
|
1273
|
+
Array.isArray(resolved.required) ? resolved.required : [],
|
|
652
1274
|
);
|
|
653
|
-
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;
|
|
654
1281
|
children.push({
|
|
655
|
-
name,
|
|
656
|
-
schema:
|
|
1282
|
+
name: isArrayLike ? (name + "[]") : name,
|
|
1283
|
+
schema: childDef,
|
|
657
1284
|
required: requiredSet.has(name),
|
|
658
1285
|
});
|
|
659
1286
|
}
|
|
660
1287
|
}
|
|
661
1288
|
|
|
662
|
-
if (
|
|
1289
|
+
if (resolved.items) {
|
|
663
1290
|
children.push({
|
|
664
|
-
name:
|
|
665
|
-
schema:
|
|
1291
|
+
name: getArrayItemNodeName(resolved.items),
|
|
1292
|
+
schema: resolved.items,
|
|
666
1293
|
required: true,
|
|
667
1294
|
});
|
|
668
1295
|
}
|
|
@@ -670,45 +1297,100 @@ ${t.join(`,
|
|
|
670
1297
|
return children;
|
|
671
1298
|
}
|
|
672
1299
|
|
|
673
|
-
function
|
|
674
|
-
|
|
675
|
-
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);
|
|
676
1327
|
const requiredLabel = field.required ? "required" : "optional";
|
|
677
|
-
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
|
+
: "";
|
|
678
1337
|
const children = buildSchemaChildren(schema);
|
|
679
1338
|
const padding = depth * 14;
|
|
1339
|
+
const extra = buildSchemaExtra(schema);
|
|
680
1340
|
|
|
681
1341
|
if (!children.length) {
|
|
682
1342
|
return (
|
|
683
|
-
'<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:' +
|
|
684
1344
|
padding +
|
|
685
|
-
'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">' +
|
|
686
1353
|
name +
|
|
687
|
-
'</code><span class="text-xs text-brand
|
|
1354
|
+
'</code></button><span class="text-xs text-brand shrink-0">' +
|
|
688
1355
|
requiredLabel +
|
|
689
|
-
'</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">' +
|
|
690
1361
|
type +
|
|
691
|
-
"</
|
|
1362
|
+
"</button></div>" + extra + "</div>"
|
|
692
1363
|
);
|
|
693
1364
|
}
|
|
694
1365
|
|
|
695
1366
|
let nested = "";
|
|
696
1367
|
for (const child of children) {
|
|
697
|
-
nested += renderSchemaFieldNode(child, depth + 1);
|
|
1368
|
+
nested += renderSchemaFieldNode(child, depth + 1, fieldPath);
|
|
698
1369
|
}
|
|
699
1370
|
|
|
700
1371
|
return (
|
|
701
|
-
'<details
|
|
702
|
-
'<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:' +
|
|
703
1374
|
padding +
|
|
704
|
-
'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">' +
|
|
705
1383
|
name +
|
|
706
|
-
'</code><span class="text-xs text-brand">' +
|
|
1384
|
+
'</code></button><span class="text-xs text-brand shrink-0">' +
|
|
707
1385
|
requiredLabel +
|
|
708
|
-
'</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">' +
|
|
709
1391
|
type +
|
|
710
|
-
"</
|
|
711
|
-
|
|
1392
|
+
"</button></div>" + extra + "</summary>" +
|
|
1393
|
+
"<div>" +
|
|
712
1394
|
nested +
|
|
713
1395
|
"</div></details>"
|
|
714
1396
|
);
|
|
@@ -721,7 +1403,7 @@ ${t.join(`,
|
|
|
721
1403
|
|
|
722
1404
|
let rows = "";
|
|
723
1405
|
for (const child of rootChildren) {
|
|
724
|
-
rows += renderSchemaFieldNode(child, 0);
|
|
1406
|
+
rows += renderSchemaFieldNode(child, 0, "");
|
|
725
1407
|
}
|
|
726
1408
|
|
|
727
1409
|
return (
|
|
@@ -748,27 +1430,40 @@ ${t.join(`,
|
|
|
748
1430
|
const responseDef = responses[statusCode];
|
|
749
1431
|
if (!responseDef || typeof responseDef !== "object") continue;
|
|
750
1432
|
|
|
1433
|
+
const responseDesc = (typeof responseDef.description === "string" && responseDef.description.trim())
|
|
1434
|
+
? responseDef.description.trim()
|
|
1435
|
+
: "";
|
|
1436
|
+
|
|
751
1437
|
const jsonSchema =
|
|
752
1438
|
responseDef.content &&
|
|
753
1439
|
responseDef.content["application/json"] &&
|
|
754
1440
|
responseDef.content["application/json"].schema;
|
|
755
1441
|
|
|
756
|
-
if (!jsonSchema || typeof jsonSchema !== "object") continue;
|
|
757
|
-
|
|
758
|
-
const rootChildren = buildSchemaChildren(jsonSchema);
|
|
759
|
-
if (!rootChildren.length) continue;
|
|
760
|
-
|
|
761
1442
|
let rows = "";
|
|
762
|
-
|
|
763
|
-
|
|
1443
|
+
if (jsonSchema && typeof jsonSchema === "object") {
|
|
1444
|
+
const rootChildren = buildSchemaChildren(jsonSchema);
|
|
1445
|
+
for (const child of rootChildren) {
|
|
1446
|
+
rows += renderSchemaFieldNode(child, 0, "");
|
|
1447
|
+
}
|
|
764
1448
|
}
|
|
765
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
|
+
|
|
766
1457
|
sections +=
|
|
767
|
-
'<
|
|
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 ' +
|
|
768
1461
|
escapeHtml(statusCode) +
|
|
1462
|
+
descHtml +
|
|
769
1463
|
"</h4>" +
|
|
770
|
-
|
|
771
|
-
|
|
1464
|
+
"</summary>" +
|
|
1465
|
+
contentHtml +
|
|
1466
|
+
"</details>";
|
|
772
1467
|
}
|
|
773
1468
|
|
|
774
1469
|
if (!sections) return "";
|
|
@@ -860,6 +1555,7 @@ ${t.join(`,
|
|
|
860
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";
|
|
861
1556
|
keyInput.addEventListener("input", () => {
|
|
862
1557
|
entry.key = keyInput.value;
|
|
1558
|
+
saveHeaders();
|
|
863
1559
|
updateRequestPreview();
|
|
864
1560
|
});
|
|
865
1561
|
|
|
@@ -874,6 +1570,7 @@ ${t.join(`,
|
|
|
874
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";
|
|
875
1571
|
valueInput.addEventListener("input", () => {
|
|
876
1572
|
entry.value = valueInput.value;
|
|
1573
|
+
saveHeaders();
|
|
877
1574
|
updateRequestPreview();
|
|
878
1575
|
});
|
|
879
1576
|
|
|
@@ -887,6 +1584,7 @@ ${t.join(`,
|
|
|
887
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>';
|
|
888
1585
|
removeButton.addEventListener("click", () => {
|
|
889
1586
|
requestHeaders.splice(index, 1);
|
|
1587
|
+
saveHeaders();
|
|
890
1588
|
renderHeaderInputs();
|
|
891
1589
|
updateRequestPreview();
|
|
892
1590
|
});
|
|
@@ -903,15 +1601,32 @@ ${t.join(`,
|
|
|
903
1601
|
return Object.keys(headers).some((key) => key.toLowerCase() === target);
|
|
904
1602
|
}
|
|
905
1603
|
|
|
906
|
-
function
|
|
907
|
-
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 = {};
|
|
908
1622
|
for (const entry of requestHeaders) {
|
|
909
1623
|
const key = String(entry.key || "").trim();
|
|
910
1624
|
const value = String(entry.value || "").trim();
|
|
911
1625
|
if (!key || !value) continue;
|
|
912
|
-
|
|
1626
|
+
manual[key] = value;
|
|
913
1627
|
}
|
|
914
|
-
|
|
1628
|
+
// Auth provides defaults; manual headers win on conflict
|
|
1629
|
+
return Object.assign({}, auth, manual);
|
|
915
1630
|
}
|
|
916
1631
|
|
|
917
1632
|
function buildCurl(op, headers, body, requestPath) {
|
|
@@ -948,6 +1663,33 @@ ${t.join(`,
|
|
|
948
1663
|
.replace(/>/g, ">");
|
|
949
1664
|
}
|
|
950
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
|
+
|
|
951
1693
|
function toPrettyJson(value) {
|
|
952
1694
|
const trimmed = (value || "").trim();
|
|
953
1695
|
if (!trimmed) return null;
|
|
@@ -1081,10 +1823,10 @@ ${t.join(`,
|
|
|
1081
1823
|
|
|
1082
1824
|
const { path, query } = getOperationParameterGroups(selected);
|
|
1083
1825
|
const values = getParameterValues(selected);
|
|
1084
|
-
const requestPath = buildRequestPath(selected, path, query, values);
|
|
1826
|
+
const requestPath = buildRequestPath(selected, path, query, values, getAuthQueryParams(selected));
|
|
1085
1827
|
const bodyInput = document.getElementById("body-input");
|
|
1086
1828
|
const body = bodyInput ? bodyInput.value.trim() : "";
|
|
1087
|
-
const headers = getRequestHeadersObject();
|
|
1829
|
+
const headers = getRequestHeadersObject(selected);
|
|
1088
1830
|
if (body && !hasHeaderName(headers, "Content-Type")) {
|
|
1089
1831
|
headers["Content-Type"] = "application/json";
|
|
1090
1832
|
}
|
|
@@ -1135,8 +1877,13 @@ ${t.join(`,
|
|
|
1135
1877
|
}
|
|
1136
1878
|
setResponseContent("", "", false);
|
|
1137
1879
|
|
|
1880
|
+
const deprecatedBanner = document.getElementById("deprecated-banner");
|
|
1881
|
+
if (deprecatedBanner) {
|
|
1882
|
+
deprecatedBanner.classList.toggle("hidden", !op.deprecated);
|
|
1883
|
+
}
|
|
1884
|
+
|
|
1138
1885
|
document.getElementById("tag-title").textContent = selected.tag;
|
|
1139
|
-
document.getElementById("tag-description").
|
|
1886
|
+
document.getElementById("tag-description").innerHTML = op.description ? renderMarkdown(op.description) : "Interactive API documentation.";
|
|
1140
1887
|
const methodNode = document.getElementById("endpoint-method");
|
|
1141
1888
|
methodNode.textContent = selected.method;
|
|
1142
1889
|
methodNode.className = "px-2.5 py-0.5 rounded-full text-xs font-mono font-medium " + (methodBadge[selected.method] || methodBadgeDefault);
|
|
@@ -1153,7 +1900,13 @@ ${t.join(`,
|
|
|
1153
1900
|
|
|
1154
1901
|
html += renderRequestBodySchemaSection(reqSchema);
|
|
1155
1902
|
html += renderResponseSchemasSection(op.responses);
|
|
1156
|
-
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();
|
|
1157
1910
|
renderTryItParameterInputs(path, query);
|
|
1158
1911
|
renderHeaderInputs();
|
|
1159
1912
|
updateRequestPreview();
|
|
@@ -1164,6 +1917,24 @@ ${t.join(`,
|
|
|
1164
1917
|
document.getElementById("copy-curl").addEventListener("click", async () => {
|
|
1165
1918
|
try { await navigator.clipboard.writeText(document.getElementById("curl-code").textContent || ""); } catch {}
|
|
1166
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
|
+
});
|
|
1167
1938
|
document.getElementById("sidebar-search").addEventListener("input", (event) => {
|
|
1168
1939
|
sidebarSearchQuery = event.currentTarget.value || "";
|
|
1169
1940
|
renderSidebar();
|
|
@@ -1189,7 +1960,7 @@ ${t.join(`,
|
|
|
1189
1960
|
return;
|
|
1190
1961
|
}
|
|
1191
1962
|
|
|
1192
|
-
const requestPath = buildRequestPath(selected, path, query, values);
|
|
1963
|
+
const requestPath = buildRequestPath(selected, path, query, values, getAuthQueryParams(selected));
|
|
1193
1964
|
formatBodyJsonInput();
|
|
1194
1965
|
updateBodyJsonPresentation();
|
|
1195
1966
|
const op = selected.operation || {};
|
|
@@ -1198,7 +1969,7 @@ ${t.join(`,
|
|
|
1198
1969
|
const bodyInput = document.getElementById("body-input");
|
|
1199
1970
|
const body =
|
|
1200
1971
|
supportsBody && bodyInput ? bodyInput.value.trim() : "";
|
|
1201
|
-
const headers = getRequestHeadersObject();
|
|
1972
|
+
const headers = getRequestHeadersObject(selected);
|
|
1202
1973
|
if (body && !hasHeaderName(headers, "Content-Type")) {
|
|
1203
1974
|
headers["Content-Type"] = "application/json";
|
|
1204
1975
|
}
|
|
@@ -1206,7 +1977,13 @@ ${t.join(`,
|
|
|
1206
1977
|
setSubmitLoading(true);
|
|
1207
1978
|
try {
|
|
1208
1979
|
const requestStart = performance.now();
|
|
1209
|
-
|
|
1980
|
+
applyAuthCookies(selected);
|
|
1981
|
+
const response = await fetch(requestPath, {
|
|
1982
|
+
method: selected.method,
|
|
1983
|
+
headers,
|
|
1984
|
+
body: body || undefined,
|
|
1985
|
+
credentials: "same-origin",
|
|
1986
|
+
});
|
|
1210
1987
|
const text = await response.text();
|
|
1211
1988
|
const responseTimeMs = Math.round(performance.now() - requestStart);
|
|
1212
1989
|
const contentType = response.headers.get("content-type") || "unknown";
|
|
@@ -1282,6 +2059,7 @@ ${t.join(`,
|
|
|
1282
2059
|
|
|
1283
2060
|
document.getElementById("add-header-btn").addEventListener("click", () => {
|
|
1284
2061
|
requestHeaders.push({ key: "", value: "" });
|
|
2062
|
+
saveHeaders();
|
|
1285
2063
|
renderHeaderInputs();
|
|
1286
2064
|
updateRequestPreview();
|
|
1287
2065
|
});
|
|
@@ -1395,12 +2173,21 @@ ${t.join(`,
|
|
|
1395
2173
|
setMobileSidebarOpen(false);
|
|
1396
2174
|
});
|
|
1397
2175
|
window.addEventListener("resize", () => {
|
|
2176
|
+
if (activeParamTooltipTrigger) {
|
|
2177
|
+
positionParamTooltip(activeParamTooltipTrigger);
|
|
2178
|
+
}
|
|
1398
2179
|
if (window.innerWidth >= 768 && isMobileSidebarOpen) {
|
|
1399
2180
|
setMobileSidebarOpen(false);
|
|
1400
2181
|
}
|
|
1401
2182
|
});
|
|
2183
|
+
window.addEventListener("scroll", () => {
|
|
2184
|
+
if (activeParamTooltipTrigger) {
|
|
2185
|
+
positionParamTooltip(activeParamTooltipTrigger);
|
|
2186
|
+
}
|
|
2187
|
+
}, true);
|
|
1402
2188
|
document.addEventListener("keydown", (event) => {
|
|
1403
2189
|
if (event.key === "Escape") {
|
|
2190
|
+
hideParamTooltip();
|
|
1404
2191
|
if (isMobileSidebarOpen) {
|
|
1405
2192
|
setMobileSidebarOpen(false);
|
|
1406
2193
|
}
|
|
@@ -1425,9 +2212,446 @@ ${t.join(`,
|
|
|
1425
2212
|
}
|
|
1426
2213
|
});
|
|
1427
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
|
+
|
|
1428
2651
|
setMobileSidebarOpen(false);
|
|
2652
|
+
renderAuthPanel();
|
|
1429
2653
|
renderSidebar();
|
|
1430
2654
|
renderEndpoint();
|
|
1431
2655
|
</script>
|
|
1432
2656
|
</body>
|
|
1433
|
-
</html>`}function ye(e){let t=e?.["~standard"],n=t?.jsonSchema;return!!t&&typeof t==="object"&&t.version===1&&!!n&&typeof n.input==="function"&&typeof n.output==="function"}function ge(e){let t=0,n=[];return{openapiPath:e.split("/").map((r)=>{let a=/^:([A-Za-z0-9_]+)\+$/.exec(r);if(a?.[1])return n.push(a[1]),`{${a[1]}}`;let i=/^:([A-Za-z0-9_]+)$/.exec(r);if(i?.[1])return n.push(i[1]),`{${i[1]}}`;if(r==="*"){t+=1;let o=t===1?"wildcard":`wildcard${t}`;return n.push(o),`{${o}}`}return r}).join("/"),pathParamNames:n}}function Ve(e){return ge(e).openapiPath}function Fe(e,t){return`${e.toLowerCase()}_${t}`.replace(/[:{}]/g,"").replace(/[^A-Za-z0-9_]+/g,"_").replace(/^_+|_+$/g,"")||`${e.toLowerCase()}_operation`}function ze(e){let t=e.split("/").filter(Boolean);for(let n of t)if(!n.startsWith(":")&&n!=="*")return n.toLowerCase();return"default"}function Ge(e){return ge(e).pathParamNames}function Qe(e,t){let n=new Set((e.parameters||[]).filter((d)=>d.in==="path").map((d)=>String(d.name)));for(let d of Ge(t)){if(n.has(d))continue;(e.parameters||=[]).push({name:d,in:"path",required:!0,schema:{type:"string"}})}}function Ye(e){let t=Number(e);if(!Number.isInteger(t))return!1;return t>=100&&t<200||t===204||t===205||t===304}function Xe(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 We(e,t,n,d){if(!ye(t))return null;try{return t["~standard"].jsonSchema.input({target:n})}catch(r){d.push(`[OpenAPI] Failed input schema conversion for ${e}: ${r instanceof Error?r.message:String(r)}. Falling back to a permissive JSON Schema.`);let a=ve(t);return Ke(a)?null:a}}function he(e,t,n,d,r){if(!ye(n))return null;try{return n["~standard"].jsonSchema.output({target:d})}catch(a){return r.push(`[OpenAPI] Failed output schema conversion for ${e} (${t}): ${a instanceof Error?a.message:String(a)}. Falling back to a permissive JSON Schema.`),ve(n)}}function g(e){return!!e&&typeof e==="object"&&!Array.isArray(e)}function Ke(e){return g(e)&&Object.keys(e).length===0}function X(e){if(!e||typeof e!=="object")return null;let t=e;if(g(t._def))return t._def;if(g(t._zod)&&g(t._zod.def))return t._zod.def;return null}function xe(e){if(!e)return null;let t=e.typeName;if(typeof t==="string")return t;let n=e.type;if(typeof n==="string")return n;return null}function Y(e){let t=["innerType","schema","type","out","in","left","right"];for(let n of t)if(n in e)return e[n];return}function Ze(e,t){for(let n of t){let d=e[n];if(d&&typeof d==="object"&&!Array.isArray(d))return d}return}function qe(e){if(!e)return!1;let t=e.toLowerCase();return t.includes("optional")||t.includes("default")||t.includes("catch")}function et(e){let t=e,n=!1,d=0;while(d<8){d+=1;let r=X(t),a=xe(r);if(!r||!qe(a))break;n=!0;let i=Y(r);if(!i)break;t=i}return{schema:t,optional:n}}function tt(e){let t=e.shape;if(typeof t==="function")try{let n=t();return g(n)?n:{}}catch{return{}}return g(t)?t:{}}function nt(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.includes("null"))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 x(e,t=new WeakSet){if(!e||typeof e!=="object")return{};if(t.has(e))return{};t.add(e);let n=X(e),d=xe(n);if(!n||!d)return{};let r=nt(d);if(r)return r;let a=d.toLowerCase();if(a.includes("object")){let o=tt(n),s={},c=[];for(let[u,m]of Object.entries(o)){let h=et(m);if(s[u]=x(h.schema,t),!h.optional)c.push(u)}let l={type:"object",properties:s,additionalProperties:!0};if(c.length>0)l.required=c;return l}if(a.includes("array")){let o=Ze(n,["element","items","innerType","type"])??{};return{type:"array",items:x(o,t)}}if(a.includes("record")){let o=n.valueType??n.valueSchema;return{type:"object",additionalProperties:o?x(o,t):!0}}if(a.includes("tuple")){let s=(Array.isArray(n.items)?n.items:[]).map((c)=>x(c,t));return{type:"array",prefixItems:s,minItems:s.length,maxItems:s.length}}if(a.includes("union")){let o=n.options??n.schemas??[];if(!Array.isArray(o)||o.length===0)return{};return{anyOf:o.map((s)=>x(s,t))}}if(a.includes("intersection")){let{left:o,right:s}=n;if(!o||!s)return{};return{allOf:[x(o,t),x(s,t)]}}if(a.includes("enum")){let o=n.values;if(Array.isArray(o))return{enum:o};if(o&&typeof o==="object")return{enum:Object.values(o)};return{}}if(a.includes("literal")){let o=n.value;if(o===void 0)return{};let s=o===null?"null":typeof o;if(s==="string"||s==="number"||s==="boolean"||s==="null")return{type:s,const:o};return{const:o}}if(a.includes("nullable")){let o=Y(n);if(!o)return{};return{anyOf:[x(o,t),{type:"null"}]}}if(a.includes("lazy")){let o=n.getter;if(typeof o!=="function")return{};try{return x(o(),t)}catch{return{}}}let i=Y(n);if(i)return x(i,t);return{}}function ve(e){if(!X(e))return{};return x(e)}function dt(e,t){if(!g(t))return;if(t.type!=="object"||!g(t.properties)){e.requestBody={required:!0,content:{"application/json":{schema:t}}};return}let n=new Set(Array.isArray(t.required)?t.required:[]),d=t.properties,r=Array.isArray(e.parameters)?e.parameters:[],a=[{key:"params",in:"path"},{key:"query",in:"query"},{key:"headers",in:"header"},{key:"cookies",in:"cookie"}];for(let o of a){let s=d[o.key];if(!g(s))continue;if(s.type!=="object"||!g(s.properties))continue;let c=new Set(Array.isArray(s.required)?s.required:[]);for(let[l,u]of Object.entries(s.properties))r.push({name:l,in:o.in,required:o.in==="path"?!0:c.has(l),schema:g(u)?u:{}})}if(r.length>0){let o=new Map;for(let s of r)o.set(`${s.in}:${s.name}`,s);e.parameters=[...o.values()]}let i=d.body;if(i)e.requestBody={required:n.has("body"),content:{"application/json":{schema:g(i)?i:{}}}}}function rt(e,t,n,d,r){let a=n.output;if(!a){e.responses={200:{description:"OK"}};return}let i={};if(typeof a==="object"&&a!==null&&"~standard"in a){let o=he(t,"200",a,d,r);if(o)i["200"]={description:"OK",content:{"application/json":{schema:o}}};else i["200"]={description:"OK"}}else for(let[o,s]of Object.entries(a)){let c=String(o),l=he(t,c,s,d,r),u=Xe(c);if(l&&!Ye(c))i[c]={description:u,content:{"application/json":{schema:l}}};else i[c]={description:u}}if(Object.keys(i).length===0)i["200"]={description:"OK"};e.responses=i}function ke(e,t){let n=[],d={};for(let i of e){if(i.options.expose===!1)continue;if(!i.method||!i.path)continue;let o=i.method.toLowerCase();if(o==="options")continue;let s=Ve(i.path),c={operationId:Fe(o,s),tags:[i.options.schema?.tag||ze(i.path)]},l=We(i.path,i.options.schema?.input,t.target,n);if(l)dt(c,l);Qe(c,i.path),rt(c,i.path,i.options.schema||{},t.target,n),d[s]||={},d[s][o]=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:d},warnings:n}}var W="/_vector/openapi/tailwindcdn.js",K="/_vector/openapi/logo_dark.svg",Z="/_vector/openapi/logo_white.svg",Ae="/_vector/openapi/favicon/apple-touch-icon.png",Ce="/_vector/openapi/favicon/favicon-32x32.png",De="/_vector/openapi/favicon/favicon-16x16.png",at="/_vector/openapi/favicon/favicon.ico",Ne="/_vector/openapi/favicon/site.webmanifest",ot="/_vector/openapi/favicon/android-chrome-192x192.png",it="/_vector/openapi/favicon/android-chrome-512x512.png",st=["../openapi/assets/tailwindcdn.js","../src/openapi/assets/tailwindcdn.js","../../src/openapi/assets/tailwindcdn.js"],lt=["../openapi/assets/logo_dark.svg","../src/openapi/assets/logo_dark.svg","../../src/openapi/assets/logo_dark.svg"],ct=["../openapi/assets/logo_white.svg","../src/openapi/assets/logo_white.svg","../../src/openapi/assets/logo_white.svg"],bt=["src/openapi/assets/tailwindcdn.js","openapi/assets/tailwindcdn.js","dist/openapi/assets/tailwindcdn.js"],ut=["src/openapi/assets/logo_dark.svg","openapi/assets/logo_dark.svg","dist/openapi/assets/logo_dark.svg"],mt=["src/openapi/assets/logo_white.svg","openapi/assets/logo_white.svg","dist/openapi/assets/logo_white.svg"],I=["../openapi/assets/favicon","../src/openapi/assets/favicon","../../src/openapi/assets/favicon"],L=["src/openapi/assets/favicon","openapi/assets/favicon","dist/openapi/assets/favicon"],ft="/* OpenAPI docs runtime asset missing: tailwind disabled */";function y(e,t){return e.map((n)=>`${n}/${t}`)}function k(e,t){for(let d of e)try{let r=new URL(d,import.meta.url);if(Ee(r))return Bun.file(r)}catch{}let n=process.cwd();for(let d of t){let r=j(n,d);if(Ee(r))return Bun.file(r)}return null}var we=k(st,bt),Be=k(lt,ut),Ie=k(ct,mt),pt=k(y(I,"apple-touch-icon.png"),y(L,"apple-touch-icon.png")),ht=k(y(I,"favicon-32x32.png"),y(L,"favicon-32x32.png")),yt=k(y(I,"favicon-16x16.png"),y(L,"favicon-16x16.png")),gt=k(y(I,"favicon.ico"),y(L,"favicon.ico")),xt=k(y(I,"site.webmanifest"),y(L,"site.webmanifest")),vt=k(y(I,"android-chrome-192x192.png"),y(L,"android-chrome-192x192.png")),kt=k(y(I,"android-chrome-512x512.png"),y(L,"android-chrome-512x512.png")),Le=[{path:Ae,file:pt,contentType:"image/png",filename:"apple-touch-icon.png"},{path:Ce,file:ht,contentType:"image/png",filename:"favicon-32x32.png"},{path:De,file:yt,contentType:"image/png",filename:"favicon-16x16.png"},{path:at,file:gt,contentType:"image/x-icon",filename:"favicon.ico"},{path:Ne,file:xt,contentType:"application/manifest+json; charset=utf-8",filename:"site.webmanifest"},{path:ot,file:vt,contentType:"image/png",filename:"android-chrome-192x192.png"},{path:it,file:kt,contentType:"image/png",filename:"android-chrome-512x512.png"}],q="public, max-age=0, must-revalidate",O="public, max-age=31536000, immutable",ee="no-store";function Et(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function wt(e){let t="^";for(let n of e){if(n==="*"){t+=".*";continue}t+=Et(n)}return t+="$",new RegExp(t)}function Bt(e,t){if(!t.includes("*"))return e===t;return wt(t).test(e)}class te{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 n=this.normalizeCorsOptions(t.cors),{preflight:d,corsify:r}=fe(n);if(this.corsHandler={preflight:d,corsify:r},typeof n.origin==="string"&&(n.origin!=="*"||!n.credentials)){let i={"access-control-allow-origin":n.origin,"access-control-allow-methods":n.allowMethods,"access-control-allow-headers":n.allowHeaders,"access-control-expose-headers":n.exposeHeaders,"access-control-max-age":String(n.maxAge)};if(n.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 d=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||{},a=r.docs,i=typeof a==="boolean"?{enabled:a,path:"/docs",exposePaths:void 0}:{enabled:a?.enabled===!0,path:a?.path||"/docs",exposePaths:Array.isArray(a?.exposePaths)?a.exposePaths.map((o)=>typeof o==="string"?o.trim():"").filter((o)=>o.length>0):void 0};return{enabled:r.enabled??d,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}getOpenAPIDocument(){if(this.openapiDocCache)return this.openapiDocCache;let e=this.router.getRouteDefinitions().filter((n)=>!this.isDocsReservedPath(n.path)),t=ke(e,{target:this.openapiConfig.target,info:this.openapiConfig.info});if(!this.openapiWarningsLogged&&t.warnings.length>0){for(let n of t.warnings)console.warn(n);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 n=t.paths&&typeof t.paths==="object"&&!Array.isArray(t.paths)?t.paths:{},d={};for(let[r,a]of Object.entries(n))if(e.some((i)=>Bt(r,i)))d[r]=a;return{...t,paths:d}}getOpenAPIDocsHtmlCacheEntry(){if(this.openapiDocsHtmlCache)return this.openapiDocsHtmlCache;let e=pe(this.getOpenAPIDocumentForDocs(),this.openapiConfig.path,W,K,Z,Ae,Ce,De,Ne),t=Bun.gzipSync(e),n=`"${Bun.hash(e).toString(16)}"`;return this.openapiDocsHtmlCache={html:e,gzip:t,etag:n},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(W),e.add(K),e.add(Z);for(let r of Le)e.add(r.path)}let t=this.router.getRouteDefinitions().filter((r)=>e.has(r.path)).map((r)=>`${r.method} ${r.path}`),n=Object.entries(this.router.getRouteTable()).filter(([r,a])=>e.has(r)&&a instanceof Response).map(([r])=>`STATIC ${r}`),d=[...t,...n];if(d.length>0)throw new Error(`OpenAPI reserved path conflict: ${d.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:n,gzip:d,etag:r}=this.getOpenAPIDocsHtmlCacheEntry();if(e.headers.get("if-none-match")===r)return new Response(null,{status:304,headers:{etag:r,"cache-control":q,vary:"accept-encoding"}});if(this.requestAcceptsGzip(e))return new Response(d,{status:200,headers:{"content-type":"text/html; charset=utf-8","content-encoding":"gzip",etag:r,"cache-control":q,vary:"accept-encoding"}});return new Response(n,{status:200,headers:{"content-type":"text/html; charset=utf-8",etag:r,"cache-control":q,vary:"accept-encoding"}})}if(this.openapiConfig.docs.enabled&&t===W){if(!we){if(!this.openapiTailwindMissingLogged)this.openapiTailwindMissingLogged=!0,console.warn('[OpenAPI] Missing docs runtime asset "tailwindcdn.js". Serving inline fallback script instead.');return new Response(ft,{status:200,headers:{"content-type":"application/javascript; charset=utf-8","cache-control":O}})}return new Response(we,{status:200,headers:{"content-type":"application/javascript; charset=utf-8","cache-control":O}})}if(this.openapiConfig.docs.enabled&&t===K){if(!Be){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":ee}})}return new Response(Be,{status:200,headers:{"content-type":"image/svg+xml; charset=utf-8","cache-control":O}})}if(this.openapiConfig.docs.enabled&&t===Z){if(!Ie){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":ee}})}return new Response(Ie,{status:200,headers:{"content-type":"image/svg+xml; charset=utf-8","cache-control":O}})}if(this.openapiConfig.docs.enabled){let n=Le.find((d)=>d.path===t);if(n){if(!n.file)return new Response(`OpenAPI docs runtime asset missing: ${n.filename}`,{status:404,headers:{"content-type":"text/plain; charset=utf-8","cache-control":ee}});return new Response(n.file,{status:200,headers:{"content-type":n.contentType,"cache-control":O}})}}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[n,d]of this.corsHeadersEntries)e.headers.set(n,d);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 n=async(d)=>{try{if(this.corsHandler&&d.method==="OPTIONS")return this.corsHandler.preflight(d);let r=this.tryHandleOpenAPIRequest(d);if(r)return this.applyCors(r,d);return this.applyCors(H.NOT_FOUND.clone(),d)}catch(r){return console.error("Server error:",r),this.applyCors(new Response("Internal Server Error",{status:500}),d)}};try{if(this.server=Bun.serve({port:e,hostname:t,reusePort:this.config.reusePort!==!1,routes:this.router.getRouteTable(),fetch:n,idleTimeout:this.config.idleTimeout??60,error:(d,r)=>{return console.error("[ERROR] Server error:",d),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(d){if(d.code==="EADDRINUSE"||d.message?.includes("address already in use"))d.message=`Port ${e} is already in use`,d.port=e;else if(d.code==="EACCES"||d.message?.includes("permission denied"))d.message=`Permission denied to bind to port ${e}`,d.port=e;else if(d.message?.includes("EADDRNOTAVAIL"))d.message=`Cannot bind to hostname ${t}`,d.hostname=t;throw d}}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 A{static instance;router;server=null;middlewareManager;authManager;cacheManager;config={};routeScanner=null;routeGenerator=null;_protectedHandler=null;_cacheHandler=null;shutdownPromise=null;constructor(){this.middlewareManager=new R,this.authManager=new $,this.cacheManager=new J,this.router=new M(this.middlewareManager,this.authManager,this.cacheManager)}static getInstance(){if(!A.instance)A.instance=new A;return A.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 te(this.router,this.config),await this.server.start()}async discoverRoutes(){let e=this.config.routesDir||"./routes",t=this.config.routeExcludePatterns;if(this.routeScanner=new P(e,t),!this.routeGenerator)this.routeGenerator=new F;try{let n=await this.routeScanner.scan();if(n.length>0){if(this.config.development)await this.routeGenerator.generate(n);for(let d of n)try{let a=await import(U(d.path)),i=d.name==="default"?a.default:a[d.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(d.options,i),this.logRouteLoaded(d.options)}}catch(r){console.error(`Failed to load route ${d.name} from ${d.path}:`,r)}}}catch(n){if(n.code!=="ENOENT"&&n.code!=="ENOTDIR")console.error("Failed to discover routes:",n)}}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 n=t();if(this.isRouteEntry(n))this.router.addRoute(n)}}}isRouteEntry(e){if(!Array.isArray(e)||e.length<3)return!1;let[t,n,d,r]=e;return typeof t==="string"&&n instanceof RegExp&&Array.isArray(d)&&d.length>0&&d.every((a)=>typeof a==="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(){A.instance=null}}var ne=A.getInstance;function It(e,t){return{entry:{method:e.method.toUpperCase(),path:e.path},options:e,handler:t}}function Lt(e){let t=e??null;try{return JSON.stringify(t)}catch(n){if(n instanceof TypeError&&/\bbigint\b/i.test(n.message))return JSON.stringify(t,(d,r)=>typeof r==="bigint"?r.toString():r);throw n}}function b(e,t,n){let d={error:!0,message:t,statusCode:e,timestamp:new Date().toISOString()};return N(e,d,n)}var w={badRequest:(e="Bad Request",t)=>b(E.BAD_REQUEST,e,t),unauthorized:(e="Unauthorized",t)=>b(E.UNAUTHORIZED,e,t),paymentRequired:(e="Payment Required",t)=>b(402,e,t),forbidden:(e="Forbidden",t)=>b(E.FORBIDDEN,e,t),notFound:(e="Not Found",t)=>b(E.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(E.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(E.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(E.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(E.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,n)=>b(e,t,n)};function N(e,t,n=_.JSON){let d=n===_.JSON?Lt(t):t;return new Response(d,{status:e,headers:{"content-type":n}})}var{existsSync:At}=(()=>({}));class de{configPath;config=null;configSource="default";constructor(e){let t=e||"vector.config.ts";this.configPath=V(t)?t:B(process.cwd(),t)}async load(){if(At(this.configPath))try{let t=await import(U(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 Ct(e={}){let t=new de(e.configPath),n=await t.load(),d=t.getConfigSource(),r={...n};if(e.mutateConfig)r=await e.mutateConfig(r,{configSource:d});if(e.config)r={...r,...e.config};if(e.autoDiscover!==void 0)r.autoDiscover=e.autoDiscover;let a=ne(),i=e.protectedHandler!==void 0?e.protectedHandler:await t.loadAuthHandler(),o=e.cacheHandler!==void 0?e.cacheHandler:await t.loadCacheHandler();a.setProtectedHandler(i??null),a.setCacheHandler(o??null);let s=await a.startServer(r),c={...r,port:s.port??r.port??C.PORT,hostname:s.hostname||r.hostname||C.HOSTNAME,reusePort:r.reusePort!==!1,idleTimeout:r.idleTimeout??60};return{server:s,config:c,stop:()=>a.stop(),shutdown:()=>a.shutdown()}}export{Ct as startVector,It as route,N as createResponse,w 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};
|