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