vector-framework 1.2.1 → 1.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +97 -11
- package/dist/core/server.d.ts +1 -0
- package/dist/core/server.d.ts.map +1 -1
- package/dist/core/server.js +13 -2
- package/dist/core/server.js.map +1 -1
- package/dist/errors/index.cjs +2 -0
- package/dist/index.cjs +1434 -0
- package/dist/index.js +12 -1433
- package/dist/index.mjs +20 -19
- package/dist/openapi/generator.d.ts.map +1 -1
- package/dist/openapi/generator.js +92 -9
- package/dist/openapi/generator.js.map +1 -1
- package/package.json +8 -14
- package/src/core/server.ts +15 -2
- package/src/openapi/generator.ts +115 -7
package/dist/index.mjs
CHANGED
|
@@ -1,33 +1,34 @@
|
|
|
1
|
-
|
|
1
|
+
// @bun
|
|
2
|
+
var E={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},L={PORT:3000,HOSTNAME:"localhost",ROUTES_DIR:"./routes",CACHE_TTL:0,CORS_MAX_AGE:86400},T={JSON:"application/json",TEXT:"text/plain",HTML:"text/html",FORM_URLENCODED:"application/x-www-form-urlencoded",MULTIPART:"multipart/form-data"};var j={NOT_FOUND:new Response(JSON.stringify({error:!0,message:"Not Found",statusCode:404}),{status:404,headers:{"content-type":"application/json"}})};class R{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.");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 U{cacheHandler=null;memoryCache=new Map;cleanupInterval=null;inflight=new Map;setCacheHandler(e){this.cacheHandler=e}clearCacheHandler(){this.cacheHandler=null}async get(e,t,d=L.CACHE_TTL){if(d<=0)return t();if(this.cacheHandler)return this.cacheHandler(e,t,d);return this.getFromMemoryCache(e,t,d)}async getFromMemoryCache(e,t,d){let n=Date.now(),r=this.memoryCache.get(e);if(this.isCacheValid(r,n))return r.value;if(this.inflight.has(e))return await this.inflight.get(e);let o=(async()=>{let i=await t();return this.setInMemoryCache(e,i,d),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,d){let n=Date.now()+d*1000;this.memoryCache.set(e,{value:t,expires:n}),this.scheduleCleanup()}scheduleCleanup(){if(this.cleanupInterval)return;this.cleanupInterval=setInterval(()=>{this.cleanupExpired()},60000)}cleanupExpired(){let e=Date.now();for(let[t,d]of this.memoryCache.entries())if(d.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,d=L.CACHE_TTL){if(d<=0)return;if(this.cacheHandler){await this.cacheHandler(e,async()=>t,d);return}this.setInMemoryCache(e,t,d)}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 d=e._parsedUrl??new URL(e.url),n=t?.authUser?.id!=null?String(t.authUser.id):"anonymous";return`${e.method}:${d.pathname}:${d.search}:${n}`}}import{promises as ee}from"fs";import{dirname as te,relative as je}from"path";class ${outputPath;constructor(e="./.vector/routes.generated.ts"){this.outputPath=e}async generate(e){let t=te(this.outputPath);await ee.mkdir(t,{recursive:!0});let d=[],n=new Map;for(let a of e){if(!n.has(a.path))n.set(a.path,[]);n.get(a.path).push(a)}let r=0,o=[];for(let[a,s]of n){let c=je(te(this.outputPath),a).replace(/\\/g,"/").replace(/\.(ts|js)$/,""),m=`route_${r++}`,b=s.filter((p)=>p.name!=="default").map((p)=>p.name);if(s.some((p)=>p.name==="default"))if(b.length>0)d.push(`import ${m}, { ${b.join(", ")} } from '${c}';`);else d.push(`import ${m} from '${c}';`);else if(b.length>0)d.push(`import { ${b.join(", ")} } from '${c}';`);for(let p of s){let x=p.name==="default"?m:p.name;o.push(` ${x},`)}}let i=`// This file is auto-generated. Do not edit manually.
|
|
2
3
|
// Generated at: ${new Date().toISOString()}
|
|
3
4
|
|
|
4
|
-
${
|
|
5
|
+
${d.join(`
|
|
5
6
|
`)}
|
|
6
7
|
|
|
7
8
|
export const routes = [
|
|
8
|
-
${
|
|
9
|
+
${o.join(`
|
|
9
10
|
`)}
|
|
10
11
|
];
|
|
11
12
|
|
|
12
13
|
export default routes;
|
|
13
|
-
`;await
|
|
14
|
-
...${
|
|
15
|
-
handler: m.${
|
|
14
|
+
`;await ee.writeFile(this.outputPath,i,"utf-8")}async generateDynamic(e){let t=[];for(let d of e){let n=JSON.stringify({method:d.method,path:d.options.path,options:d.options});t.push(` await import('${d.path}').then(m => ({
|
|
15
|
+
...${n},
|
|
16
|
+
handler: m.${d.name==="default"?"default":d.name}
|
|
16
17
|
}))`)}return`export const loadRoutes = async () => {
|
|
17
18
|
return Promise.all([
|
|
18
19
|
${t.join(`,
|
|
19
20
|
`)}
|
|
20
21
|
]);
|
|
21
|
-
};`}}var{existsSync:_e,promises:ie}=(()=>({}));class P{routesDir;excludePatterns;static DEFAULT_EXCLUDE_PATTERNS=["*.test.ts","*.test.js","*.test.tsx","*.test.jsx","*.spec.ts","*.spec.js","*.spec.tsx","*.spec.jsx","*.tests.ts","*.tests.js","**/__tests__/**","*.interface.ts","*.type.ts","*.d.ts"];constructor(e="./routes",t){this.routesDir=B(process.cwd(),e),this.excludePatterns=t||P.DEFAULT_EXCLUDE_PATTERNS}async scan(){let e=[];if(!_e(this.routesDir))return[];try{await this.scanDirectory(this.routesDir,e)}catch(t){if(t.code==="ENOENT")return console.warn(` ✗ Routes directory not accessible: ${this.routesDir}`),[];throw t}return e}isExcluded(e){let t=D(this.routesDir,e);for(let n of this.excludePatterns){let d=n.replace(/\./g,"\\.").replace(/\*\*/g,"__GLOBSTAR__").replace(/\*/g,"[^/]*").replace(/__GLOBSTAR__/g,".*").replace(/\?/g,"."),r=new RegExp(`^${d}$`),a=t.split(S).pop()||"";if(r.test(t)||r.test(a))return!0}return!1}async scanDirectory(e,t,n=""){let d=await ie.readdir(e);for(let r of d){let a=j(e,r);if((await ie.stat(a)).isDirectory()){let o=n?`${n}/${r}`:r;await this.scanDirectory(a,t,o)}else if(r.endsWith(".ts")||r.endsWith(".js")){if(this.isExcluded(a))continue;let o=D(this.routesDir,a).replace(/\.(ts|js)$/,"").split(S).join("/");try{let c=await import(process.platform==="win32"?`file:///${a.replace(/\\/g,"/")}`:a);if(c.default&&typeof c.default==="function")t.push({name:"default",path:a,method:"GET",options:{method:"GET",path:`/${o}`,expose:!0}});for(let[l,u]of Object.entries(c)){if(l==="default")continue;if(u&&typeof u==="object"&&"entry"in u&&"options"in u&&"handler"in u){let m=u;t.push({name:l,path:a,method:m.options.method,options:m.options})}else if(Array.isArray(u)&&u.length>=4){let[m,,,h]=u;t.push({name:l,path:a,method:m,options:{method:m,path:h,expose:!0}})}}}catch(s){console.error(`Failed to load route from ${a}:`,s)}}}}enableWatch(e){if(typeof Bun!=="undefined"&&Bun.env.NODE_ENV==="development")console.log(`Watching for route changes in ${this.routesDir}`),setInterval(async()=>{await e()},1000)}}class R{beforeHandlers=[];finallyHandlers=[];addBefore(...e){this.beforeHandlers.push(...e)}addFinally(...e){this.finallyHandlers.push(...e)}async executeBefore(e){if(this.beforeHandlers.length===0)return e;let t=e;for(let n of this.beforeHandlers){let d=await n(t);if(d instanceof Response)return d;t=d}return t}async executeFinally(e,t){if(this.finallyHandlers.length===0)return e;let n=e;for(let d of this.finallyHandlers)try{n=await d(n,t)}catch(r){console.error("After middleware error:",r)}return n}clone(){let e=new R;return e.beforeHandlers=[...this.beforeHandlers],e.finallyHandlers=[...this.finallyHandlers],e}clear(){this.beforeHandlers=[],this.finallyHandlers=[]}}function U(e){return process.platform==="win32"?`file:///${e.replace(/\\/g,"/")}`:e}function z(e){return RegExp(`^${e.replace(/\/+(\/|$)/g,"$1").replace(/(\/?\.?):(\w+)\+/g,"($1(?<$2>[\\s\\S]+))").replace(/(\/?\.?):(\w+)/g,"($1(?<$2>[^$1/]+?))").replace(/\./g,"\\.").replace(/(\/?)\*/g,"($1.*)?")}/*$`)}function se(e){let t=e?.["~standard"];return!!t&&typeof t==="object"&&typeof t.validate==="function"&&t.version===1}async function le(e,t){let n=await e["~standard"].validate(t),d=n?.issues;if(Array.isArray(d)&&d.length>0)return{success:!1,issues:d};return{success:!0,value:n?.value}}function ce(e){if(Array.isArray(e))return e;if(e&&typeof e==="object"&&Array.isArray(e.issues))return e.issues;if(e&&typeof e==="object"&&e.cause&&Array.isArray(e.cause.issues))return e.cause.issues;return null}function $e(e){if(!Array.isArray(e))return[];let t=[];for(let n=0;n<e.length;n++){let d=e[n],r=d;if(d&&typeof d==="object"&&"key"in d)r=d.key;if(typeof r==="string"||typeof r==="number")t.push(r);else if(typeof r==="symbol")t.push(String(r));else if(r!==void 0&&r!==null)t.push(String(r))}return t}function G(e,t){let n=[];for(let d=0;d<e.length;d++){let r=e[d],a=r,i={message:typeof a?.message==="string"&&a.message.length>0?a.message:"Invalid value",path:$e(a?.path)};if(typeof a?.code==="string")i.code=a.code;if(t)i.raw=r;n.push(i)}return n}function Q(e,t){return{error:!0,message:"Validation failed",statusCode:422,source:"validation",target:e,issues:t,timestamp:new Date().toISOString()}}class M{middlewareManager;authManager;cacheManager;routeBooleanDefaults={};developmentMode=void 0;routeDefinitions=[];routeTable=Object.create(null);routeMatchers=[];corsHeadersEntries=null;corsHandler=null;constructor(e,t,n){this.middlewareManager=e,this.authManager=t,this.cacheManager=n}setCorsHeaders(e){this.corsHeadersEntries=e}setCorsHandler(e){this.corsHandler=e}setRouteBooleanDefaults(e){this.routeBooleanDefaults={...e}}setDevelopmentMode(e){this.developmentMode=e}applyRouteBooleanDefaults(e){let t={...e},n=this.routeBooleanDefaults,d=["auth","expose","rawRequest","validate","rawResponse"];for(let r of d)if(t[r]===void 0&&n[r]!==void 0)t[r]=n[r];return t}route(e,t){let n=this.applyRouteBooleanDefaults(e),d=n.method.toUpperCase(),r=n.path,a=this.wrapHandler(n,t),i=this.getOrCreateMethodMap(r);i[d]=a,this.routeDefinitions.push({method:d,path:r,options:n})}addRoute(e){let[t,,n,d]=e;if(!d)return;let r=this.getOrCreateMethodMap(d);r[t.toUpperCase()]=n[0];let a=t.toUpperCase();this.routeDefinitions.push({method:a,path:d,options:{method:a,path:d,expose:!0}})}bulkAddRoutes(e){for(let t of e)this.addRoute(t)}addStaticRoute(e,t){let n=this.routeTable[e];if(n&&!(n instanceof Response))throw new Error(`Cannot register static route for path "${e}" because method routes already exist.`);this.routeTable[e]=t,this.removeRouteMatcher(e)}getRouteTable(){return this.routeTable}getRoutes(){let e=[];for(let t of this.routeMatchers){let n=this.routeTable[t.path];if(!n||n instanceof Response)continue;for(let[d,r]of Object.entries(n))e.push([d,t.regex,[r],t.path])}return e}getRouteDefinitions(){return[...this.routeDefinitions]}clearRoutes(){this.routeTable=Object.create(null),this.routeMatchers=[],this.routeDefinitions=[]}sortRoutes(){}async handle(e){let t;try{t=new URL(e.url)}catch{return w.badRequest("Malformed request URL")}e._parsedUrl=t;let n=t.pathname;for(let d of this.routeMatchers){let r=d.path,a=this.routeTable[r];if(!a)continue;if(a instanceof Response)continue;let i=a;if(e.method==="OPTIONS"||e.method in i){let o=n.match(d.regex);if(o){try{e.params=o.groups??{}}catch{}let s=i[e.method]??i.GET;if(s){let c=await s(e);if(c)return c}}}}return H.NOT_FOUND.clone()}prepareRequest(e,t){if(!e.context)e.context={};let n=!!e.params&&typeof e.params==="object"&&!Array.isArray(e.params)&&Object.keys(e.params).length===0;if(t?.params!==void 0&&(e.params===void 0||n))try{e.params=t.params}catch{}if(t?.route!==void 0)e.route=t.route;if(t?.metadata!==void 0)e.metadata=t.metadata;if(e.query==null&&e.url)try{Object.defineProperty(e,"query",{get(){let d=this._parsedUrl??new URL(this.url),r=M.parseQuery(d);return Object.defineProperty(this,"query",{value:r,writable:!0,configurable:!0,enumerable:!0}),r},set(d){Object.defineProperty(this,"query",{value:d,writable:!0,configurable:!0,enumerable:!0})},configurable:!0,enumerable:!0})}catch{let d=e._parsedUrl??new URL(e.url);try{e.query=M.parseQuery(d)}catch{}}if(!Object.getOwnPropertyDescriptor(e,"cookies"))Object.defineProperty(e,"cookies",{get(){let d=this.headers.get("cookie")??"",r={};if(d)for(let a of d.split(";")){let i=a.indexOf("=");if(i>0)r[a.slice(0,i).trim()]=a.slice(i+1).trim()}return Object.defineProperty(this,"cookies",{value:r,writable:!0,configurable:!0,enumerable:!0}),r},configurable:!0,enumerable:!0})}resolveFallbackParams(e,t){if(!t)return;let n=e.params;if(n&&typeof n==="object"&&!Array.isArray(n)&&Object.keys(n).length>0)return;let d;try{d=(e._parsedUrl??new URL(e.url)).pathname}catch{return}let r=d.match(t);if(!r?.groups)return;return r.groups}wrapHandler(e,t){let n=e.path,d=n.includes(":")?z(n):null;return async(r)=>{let a=r,i=this.resolveFallbackParams(r,d);this.prepareRequest(a,{params:i,route:n,metadata:e.metadata});try{if(e.expose===!1)return w.forbidden("Forbidden");let o=await this.middlewareManager.executeBefore(a);if(o instanceof Response)return o;let s=o;if(e.auth)try{await this.authManager.authenticate(s)}catch(f){return w.unauthorized(f instanceof Error?f.message:"Authentication failed",e.responseContentType)}if(!e.rawRequest&&s.method!=="GET"&&s.method!=="HEAD"){let f=null;try{let p=s.headers.get("content-type");if(p?.startsWith("application/json"))f=await s.json();else if(p?.startsWith("application/x-www-form-urlencoded"))f=Object.fromEntries(await s.formData());else if(p?.startsWith("multipart/form-data"))f=await s.formData();else f=await s.text()}catch{f=null}this.setContentAndBodyAlias(s,f)}let c=await this.validateInputSchema(s,e);if(c)return c;let l,u=e.cache;if(u&&typeof u==="number"&&u>0){let f=this.cacheManager.generateKey(s,{authUser:s.authUser});l=await this.cacheManager.get(f,async()=>{let p=await t(s);if(p instanceof Response)return{_isResponse:!0,body:await p.text(),status:p.status,headers:Object.fromEntries(p.headers.entries())};return p},u)}else if(u&&typeof u==="object"&&u.ttl){let f=u.key||this.cacheManager.generateKey(s,{authUser:s.authUser});l=await this.cacheManager.get(f,async()=>{let p=await t(s);if(p instanceof Response)return{_isResponse:!0,body:await p.text(),status:p.status,headers:Object.fromEntries(p.headers.entries())};return p},u.ttl)}else l=await t(s);if(l&&typeof l==="object"&&l._isResponse===!0)l=new Response(l.body,{status:l.status,headers:l.headers});let m;if(e.rawResponse||l instanceof Response)m=l instanceof Response?l:new Response(l);else m=N(200,l,e.responseContentType);m=await this.middlewareManager.executeFinally(m,s);let h=this.corsHeadersEntries;if(h)for(let[f,p]of h)m.headers.set(f,p);else{let f=this.corsHandler;if(f)m=f(m,s)}return m}catch(o){if(o instanceof Response)return o;return console.error("Route handler error:",o),w.internalServerError(o instanceof Error?o.message:String(o),e.responseContentType)}}}isDevelopmentMode(){if(this.developmentMode!==void 0)return this.developmentMode;return(typeof Bun!=="undefined"?Bun.env.NODE_ENV:"development")!=="production"}async buildInputValidationPayload(e,t){let n=e.content;if(t.rawRequest&&e.method!=="GET"&&e.method!=="HEAD")try{n=await e.clone().text()}catch{n=null}return{params:e.params??{},query:e.query??{},headers:Object.fromEntries(e.headers.entries()),cookies:e.cookies??{},body:n}}applyValidatedInput(e,t){if(e.validatedInput=t,!t||typeof t!=="object")return;let n=t;if("params"in n)try{e.params=n.params}catch{}if("query"in n)try{e.query=n.query}catch{}if("cookies"in n)try{e.cookies=n.cookies}catch{}if("body"in n)this.setContentAndBodyAlias(e,n.body)}setContentAndBodyAlias(e,t){try{e.content=t}catch{return}this.setBodyAlias(e,t)}setBodyAlias(e,t){try{e.body=t}catch{}}async validateInputSchema(e,t){let n=t.schema?.input;if(!n)return null;if(t.validate===!1)return null;if(!se(n))return w.internalServerError("Invalid route schema configuration",t.responseContentType);let d=this.isDevelopmentMode(),r=await this.buildInputValidationPayload(e,t);try{let a=await le(n,r);if(a.success===!1){let i=G(a.issues,d);return N(422,Q("input",i),t.responseContentType)}return this.applyValidatedInput(e,a.value),null}catch(a){let i=ce(a);if(i){let o=G(i,d);return N(422,Q("input",o),t.responseContentType)}return w.internalServerError(a instanceof Error?a.message:"Validation failed",t.responseContentType)}}getOrCreateMethodMap(e){let t=this.routeTable[e];if(t instanceof Response)throw new Error(`Cannot register method route for path "${e}" because a static route already exists.`);if(t)return t;let n=Object.create(null);return this.routeTable[e]=n,this.addRouteMatcher(e),n}addRouteMatcher(e){if(this.routeMatchers.some((t)=>t.path===e))return;this.routeMatchers.push({path:e,regex:z(e),specificity:this.routeSpecificityScore(e)}),this.routeMatchers.sort((t,n)=>{if(t.specificity!==n.specificity)return n.specificity-t.specificity;return t.path.localeCompare(n.path)})}removeRouteMatcher(e){this.routeMatchers=this.routeMatchers.filter((t)=>t.path!==e)}static parseQuery(e){let t={};for(let[n,d]of e.searchParams)if(n in t){let r=t[n];if(Array.isArray(r))r.push(d);else t[n]=[r,d]}else t[n]=d;return t}routeSpecificityScore(e){let a=e.split("/").filter(Boolean),i=0;for(let o of a)if(o.includes("*"))i+=1;else if(o.startsWith(":"))i+=10;else i+=1000;if(i+=e.length,!e.includes(":")&&!e.includes("*"))i+=1e4;return i}}var{existsSync:Ee}=(()=>({}));function be(e,t){if(!e){if(typeof t.origin==="string"){if(t.origin==="*"&&t.credentials)return null;return t.origin}return null}if(typeof t.origin==="string"){if(t.origin==="*")return t.credentials?e:"*";return t.origin===e?e:null}if(Array.isArray(t.origin))return t.origin.includes(e)?e:null;if(typeof t.origin==="function")return t.origin(e)?e:null;return null}function ue(e){return typeof e.origin==="string"&&e.origin==="*"&&e.credentials||Array.isArray(e.origin)||typeof e.origin==="function"}function me(e,t,n){let d={};if(e){if(d["access-control-allow-origin"]=e,d["access-control-allow-methods"]=t.allowMethods,d["access-control-allow-headers"]=t.allowHeaders,d["access-control-expose-headers"]=t.exposeHeaders,d["access-control-max-age"]=String(t.maxAge),t.credentials)d["access-control-allow-credentials"]="true";if(n)d.vary="Origin"}return d}function Je(e,t){if(!e)return t;let n=e.split(",").map((r)=>r.trim()).filter(Boolean);if(!n.map((r)=>r.toLowerCase()).includes(t.toLowerCase()))n.push(t);return n.join(", ")}function fe(e){return{preflight(t){let n=t.headers.get("origin")??void 0,d=be(n,e),r=Boolean(n&&d&&ue(e));return new Response(null,{status:204,headers:me(d,e,r)})},corsify(t,n){let d=n.headers.get("origin")??void 0,r=be(d,e);if(!r)return t;let a=Boolean(d&&ue(e)),i=me(r,e,a);for(let[o,s]of Object.entries(i)){if(o==="vary"){t.headers.set("vary",Je(t.headers.get("vary"),s));continue}t.headers.set(o,s)}return t}}}function pe(e,t,n,d,r,a,i,o,s){let c=JSON.stringify(e).replace(/<\/script/gi,"<\\/script"),l=JSON.stringify(t),u=JSON.stringify(n),m=JSON.stringify(d),h=JSON.stringify(r),f=JSON.stringify(a),p=JSON.stringify(i),je=JSON.stringify(o),Me=JSON.stringify(s);return`<!DOCTYPE html>
|
|
22
|
+
};`}}import{existsSync as Me,promises as de}from"fs";import{join as Ce,relative as ne,resolve as He,sep as re}from"path";class M{routesDir;excludePatterns;static DEFAULT_EXCLUDE_PATTERNS=["*.test.ts","*.test.js","*.test.tsx","*.test.jsx","*.spec.ts","*.spec.js","*.spec.tsx","*.spec.jsx","*.tests.ts","*.tests.js","**/__tests__/**","*.interface.ts","*.type.ts","*.d.ts"];constructor(e="./routes",t){this.routesDir=He(process.cwd(),e),this.excludePatterns=t||M.DEFAULT_EXCLUDE_PATTERNS}async scan(){let e=[];if(!Me(this.routesDir))return[];try{await this.scanDirectory(this.routesDir,e)}catch(t){if(t.code==="ENOENT")return console.warn(` \u2717 Routes directory not accessible: ${this.routesDir}`),[];throw t}return e}isExcluded(e){let t=ne(this.routesDir,e);for(let d of this.excludePatterns){let n=d.replace(/\./g,"\\.").replace(/\*\*/g,"__GLOBSTAR__").replace(/\*/g,"[^/]*").replace(/__GLOBSTAR__/g,".*").replace(/\?/g,"."),r=new RegExp(`^${n}$`),o=t.split(re).pop()||"";if(r.test(t)||r.test(o))return!0}return!1}async scanDirectory(e,t,d=""){let n=await de.readdir(e);for(let r of n){let o=Ce(e,r);if((await de.stat(o)).isDirectory()){let a=d?`${d}/${r}`:r;await this.scanDirectory(o,t,a)}else if(r.endsWith(".ts")||r.endsWith(".js")){if(this.isExcluded(o))continue;let a=ne(this.routesDir,o).replace(/\.(ts|js)$/,"").split(re).join("/");try{let c=await import(process.platform==="win32"?`file:///${o.replace(/\\/g,"/")}`:o);if(c.default&&typeof c.default==="function")t.push({name:"default",path:o,method:"GET",options:{method:"GET",path:`/${a}`,expose:!0}});for(let[m,b]of Object.entries(c)){if(m==="default")continue;if(b&&typeof b==="object"&&"entry"in b&&"options"in b&&"handler"in b){let p=b;t.push({name:m,path:o,method:p.options.method,options:p.options})}else if(Array.isArray(b)&&b.length>=4){let[p,,,x]=b;t.push({name:m,path:o,method:p,options:{method:p,path:x,expose:!0}})}}}catch(s){console.error(`Failed to load route from ${o}:`,s)}}}}enableWatch(e){if(typeof Bun!=="undefined"&&Bun.env.NODE_ENV==="development")console.log(`Watching for route changes in ${this.routesDir}`),setInterval(async()=>{await e()},1000)}}class C{beforeHandlers=[];finallyHandlers=[];addBefore(...e){this.beforeHandlers.push(...e)}addFinally(...e){this.finallyHandlers.push(...e)}async executeBefore(e){if(this.beforeHandlers.length===0)return e;let t=e;for(let d of this.beforeHandlers){let n=await d(t);if(n instanceof Response)return n;t=n}return t}async executeFinally(e,t){if(this.finallyHandlers.length===0)return e;let d=e;for(let n of this.finallyHandlers)try{d=await n(d,t)}catch(r){console.error("After middleware error:",r)}return d}clone(){let e=new C;return e.beforeHandlers=[...this.beforeHandlers],e.finallyHandlers=[...this.finallyHandlers],e}clear(){this.beforeHandlers=[],this.finallyHandlers=[]}}function H(e){return process.platform==="win32"?`file:///${e.replace(/\\/g,"/")}`:e}function P(e){return RegExp(`^${e.replace(/\/+(\/|$)/g,"$1").replace(/(\/?\.?):(\w+)\+/g,"($1(?<$2>[\\s\\S]+))").replace(/(\/?\.?):(\w+)/g,"($1(?<$2>[^$1/]+?))").replace(/\./g,"\\.").replace(/(\/?)\*/g,"($1.*)?")}/*$`)}function oe(e){let t=e?.["~standard"];return!!t&&typeof t==="object"&&typeof t.validate==="function"&&t.version===1}async function ae(e,t){let d=await e["~standard"].validate(t),n=d?.issues;if(Array.isArray(n)&&n.length>0)return{success:!1,issues:n};return{success:!0,value:d?.value}}function ie(e){if(Array.isArray(e))return e;if(e&&typeof e==="object"&&Array.isArray(e.issues))return e.issues;if(e&&typeof e==="object"&&e.cause&&Array.isArray(e.cause.issues))return e.cause.issues;return null}function Oe(e){if(!Array.isArray(e))return[];let t=[];for(let d=0;d<e.length;d++){let n=e[d],r=n;if(n&&typeof n==="object"&&"key"in n)r=n.key;if(typeof r==="string"||typeof r==="number")t.push(r);else if(typeof r==="symbol")t.push(String(r));else if(r!==void 0&&r!==null)t.push(String(r))}return t}function _(e,t){let d=[];for(let n=0;n<e.length;n++){let r=e[n],o=r,i={message:typeof o?.message==="string"&&o.message.length>0?o.message:"Invalid value",path:Oe(o?.path)};if(typeof o?.code==="string")i.code=o.code;if(t)i.raw=r;d.push(i)}return d}function J(e,t){return{error:!0,message:"Validation failed",statusCode:422,source:"validation",target:e,issues:t,timestamp:new Date().toISOString()}}class N{middlewareManager;authManager;cacheManager;routeBooleanDefaults={};developmentMode=void 0;routeDefinitions=[];routeTable=Object.create(null);routeMatchers=[];corsHeadersEntries=null;corsHandler=null;constructor(e,t,d){this.middlewareManager=e,this.authManager=t,this.cacheManager=d}setCorsHeaders(e){this.corsHeadersEntries=e}setCorsHandler(e){this.corsHandler=e}setRouteBooleanDefaults(e){this.routeBooleanDefaults={...e}}setDevelopmentMode(e){this.developmentMode=e}applyRouteBooleanDefaults(e){let t={...e},d=this.routeBooleanDefaults,n=["auth","expose","rawRequest","validate","rawResponse"];for(let r of n)if(t[r]===void 0&&d[r]!==void 0)t[r]=d[r];return t}route(e,t){let d=this.applyRouteBooleanDefaults(e),n=d.method.toUpperCase(),r=d.path,o=this.wrapHandler(d,t),i=this.getOrCreateMethodMap(r);i[n]=o,this.routeDefinitions.push({method:n,path:r,options:d})}addRoute(e){let[t,,d,n]=e;if(!n)return;let r=this.getOrCreateMethodMap(n);r[t.toUpperCase()]=d[0];let o=t.toUpperCase();this.routeDefinitions.push({method:o,path:n,options:{method:o,path:n,expose:!0}})}bulkAddRoutes(e){for(let t of e)this.addRoute(t)}addStaticRoute(e,t){let d=this.routeTable[e];if(d&&!(d instanceof Response))throw new Error(`Cannot register static route for path "${e}" because method routes already exist.`);this.routeTable[e]=t,this.removeRouteMatcher(e)}getRouteTable(){return this.routeTable}getRoutes(){let e=[];for(let t of this.routeMatchers){let d=this.routeTable[t.path];if(!d||d instanceof Response)continue;for(let[n,r]of Object.entries(d))e.push([n,t.regex,[r],t.path])}return e}getRouteDefinitions(){return[...this.routeDefinitions]}clearRoutes(){this.routeTable=Object.create(null),this.routeMatchers=[],this.routeDefinitions=[]}sortRoutes(){}async handle(e){let t;try{t=new URL(e.url)}catch{return v.badRequest("Malformed request URL")}e._parsedUrl=t;let d=t.pathname;for(let n of this.routeMatchers){let r=n.path,o=this.routeTable[r];if(!o)continue;if(o instanceof Response)continue;let i=o;if(e.method==="OPTIONS"||e.method in i){let a=d.match(n.regex);if(a){try{e.params=a.groups??{}}catch{}let s=i[e.method]??i.GET;if(s){let c=await s(e);if(c)return c}}}}return j.NOT_FOUND.clone()}prepareRequest(e,t){if(!e.context)e.context={};let d=!!e.params&&typeof e.params==="object"&&!Array.isArray(e.params)&&Object.keys(e.params).length===0;if(t?.params!==void 0&&(e.params===void 0||d))try{e.params=t.params}catch{}if(t?.route!==void 0)e.route=t.route;if(t?.metadata!==void 0)e.metadata=t.metadata;if(e.query==null&&e.url)try{Object.defineProperty(e,"query",{get(){let n=this._parsedUrl??new URL(this.url),r=N.parseQuery(n);return Object.defineProperty(this,"query",{value:r,writable:!0,configurable:!0,enumerable:!0}),r},set(n){Object.defineProperty(this,"query",{value:n,writable:!0,configurable:!0,enumerable:!0})},configurable:!0,enumerable:!0})}catch{let n=e._parsedUrl??new URL(e.url);try{e.query=N.parseQuery(n)}catch{}}if(!Object.getOwnPropertyDescriptor(e,"cookies"))Object.defineProperty(e,"cookies",{get(){let n=this.headers.get("cookie")??"",r={};if(n)for(let o of n.split(";")){let i=o.indexOf("=");if(i>0)r[o.slice(0,i).trim()]=o.slice(i+1).trim()}return Object.defineProperty(this,"cookies",{value:r,writable:!0,configurable:!0,enumerable:!0}),r},configurable:!0,enumerable:!0})}resolveFallbackParams(e,t){if(!t)return;let d=e.params;if(d&&typeof d==="object"&&!Array.isArray(d)&&Object.keys(d).length>0)return;let n;try{n=(e._parsedUrl??new URL(e.url)).pathname}catch{return}let r=n.match(t);if(!r?.groups)return;return r.groups}wrapHandler(e,t){let d=e.path,n=d.includes(":")?P(d):null;return async(r)=>{let o=r,i=this.resolveFallbackParams(r,n);this.prepareRequest(o,{params:i,route:d,metadata:e.metadata});try{if(e.expose===!1)return v.forbidden("Forbidden");let a=await this.middlewareManager.executeBefore(o);if(a instanceof Response)return a;let s=a;if(e.auth)try{await this.authManager.authenticate(s)}catch(u){return v.unauthorized(u instanceof Error?u.message:"Authentication failed",e.responseContentType)}if(!e.rawRequest&&s.method!=="GET"&&s.method!=="HEAD"){let u=null;try{let f=s.headers.get("content-type");if(f?.startsWith("application/json"))u=await s.json();else if(f?.startsWith("application/x-www-form-urlencoded"))u=Object.fromEntries(await s.formData());else if(f?.startsWith("multipart/form-data"))u=await s.formData();else u=await s.text()}catch{u=null}this.setContentAndBodyAlias(s,u)}let c=await this.validateInputSchema(s,e);if(c)return c;let m,b=e.cache;if(b&&typeof b==="number"&&b>0){let u=this.cacheManager.generateKey(s,{authUser:s.authUser});m=await this.cacheManager.get(u,async()=>{let f=await t(s);if(f instanceof Response)return{_isResponse:!0,body:await f.text(),status:f.status,headers:Object.fromEntries(f.headers.entries())};return f},b)}else if(b&&typeof b==="object"&&b.ttl){let u=b.key||this.cacheManager.generateKey(s,{authUser:s.authUser});m=await this.cacheManager.get(u,async()=>{let f=await t(s);if(f instanceof Response)return{_isResponse:!0,body:await f.text(),status:f.status,headers:Object.fromEntries(f.headers.entries())};return f},b.ttl)}else m=await t(s);if(m&&typeof m==="object"&&m._isResponse===!0)m=new Response(m.body,{status:m.status,headers:m.headers});let p;if(e.rawResponse||m instanceof Response)p=m instanceof Response?m:new Response(m);else p=D(200,m,e.responseContentType);p=await this.middlewareManager.executeFinally(p,s);let x=this.corsHeadersEntries;if(x)for(let[u,f]of x)p.headers.set(u,f);else{let u=this.corsHandler;if(u)p=u(p,s)}return p}catch(a){if(a instanceof Response)return a;return console.error("Route handler error:",a),v.internalServerError(a instanceof Error?a.message:String(a),e.responseContentType)}}}isDevelopmentMode(){if(this.developmentMode!==void 0)return this.developmentMode;return(typeof Bun!=="undefined"?Bun.env.NODE_ENV:"development")!=="production"}async buildInputValidationPayload(e,t){let d=e.content;if(t.rawRequest&&e.method!=="GET"&&e.method!=="HEAD")try{d=await e.clone().text()}catch{d=null}return{params:e.params??{},query:e.query??{},headers:Object.fromEntries(e.headers.entries()),cookies:e.cookies??{},body:d}}applyValidatedInput(e,t){if(e.validatedInput=t,!t||typeof t!=="object")return;let d=t;if("params"in d)try{e.params=d.params}catch{}if("query"in d)try{e.query=d.query}catch{}if("cookies"in d)try{e.cookies=d.cookies}catch{}if("body"in d)this.setContentAndBodyAlias(e,d.body)}setContentAndBodyAlias(e,t){try{e.content=t}catch{return}this.setBodyAlias(e,t)}setBodyAlias(e,t){try{e.body=t}catch{}}async validateInputSchema(e,t){let d=t.schema?.input;if(!d)return null;if(t.validate===!1)return null;if(!oe(d))return v.internalServerError("Invalid route schema configuration",t.responseContentType);let n=this.isDevelopmentMode(),r=await this.buildInputValidationPayload(e,t);try{let o=await ae(d,r);if(o.success===!1){let i=_(o.issues,n);return D(422,J("input",i),t.responseContentType)}return this.applyValidatedInput(e,o.value),null}catch(o){let i=ie(o);if(i){let a=_(i,n);return D(422,J("input",a),t.responseContentType)}return v.internalServerError(o instanceof Error?o.message:"Validation failed",t.responseContentType)}}getOrCreateMethodMap(e){let t=this.routeTable[e];if(t instanceof Response)throw new Error(`Cannot register method route for path "${e}" because a static route already exists.`);if(t)return t;let d=Object.create(null);return this.routeTable[e]=d,this.addRouteMatcher(e),d}addRouteMatcher(e){if(this.routeMatchers.some((t)=>t.path===e))return;this.routeMatchers.push({path:e,regex:P(e),specificity:this.routeSpecificityScore(e)}),this.routeMatchers.sort((t,d)=>{if(t.specificity!==d.specificity)return d.specificity-t.specificity;return t.path.localeCompare(d.path)})}removeRouteMatcher(e){this.routeMatchers=this.routeMatchers.filter((t)=>t.path!==e)}static parseQuery(e){let t={};for(let[d,n]of e.searchParams)if(d in t){let r=t[d];if(Array.isArray(r))r.push(n);else t[d]=[r,n]}else t[d]=n;return t}routeSpecificityScore(e){let o=e.split("/").filter(Boolean),i=0;for(let a of o)if(a.includes("*"))i+=1;else if(a.startsWith(":"))i+=10;else i+=1000;if(i+=e.length,!e.includes(":")&&!e.includes("*"))i+=1e4;return i}}import{existsSync as ge}from"fs";import{join as Ke}from"path";function se(e,t){if(!e){if(typeof t.origin==="string"){if(t.origin==="*"&&t.credentials)return null;return t.origin}return null}if(typeof t.origin==="string"){if(t.origin==="*")return t.credentials?e:"*";return t.origin===e?e:null}if(Array.isArray(t.origin))return t.origin.includes(e)?e:null;if(typeof t.origin==="function")return t.origin(e)?e:null;return null}function le(e){return typeof e.origin==="string"&&e.origin==="*"&&e.credentials||Array.isArray(e.origin)||typeof e.origin==="function"}function ce(e,t,d){let n={};if(e){if(n["access-control-allow-origin"]=e,n["access-control-allow-methods"]=t.allowMethods,n["access-control-allow-headers"]=t.allowHeaders,n["access-control-expose-headers"]=t.exposeHeaders,n["access-control-max-age"]=String(t.maxAge),t.credentials)n["access-control-allow-credentials"]="true";if(d)n.vary="Origin"}return n}function Te(e,t){if(!e)return t;let d=e.split(",").map((r)=>r.trim()).filter(Boolean);if(!d.map((r)=>r.toLowerCase()).includes(t.toLowerCase()))d.push(t);return d.join(", ")}function be(e){return{preflight(t){let d=t.headers.get("origin")??void 0,n=se(d,e),r=Boolean(d&&n&&le(e));return new Response(null,{status:204,headers:ce(n,e,r)})},corsify(t,d){let n=d.headers.get("origin")??void 0,r=se(n,e);if(!r)return t;let o=Boolean(n&&le(e)),i=ce(r,e,o);for(let[a,s]of Object.entries(i)){if(a==="vary"){t.headers.set("vary",Te(t.headers.get("vary"),s));continue}t.headers.set(a,s)}return t}}}function me(e,t,d,n,r,o,i,a,s){let c=JSON.stringify(e).replace(/<\/script/gi,"<\\/script"),m=JSON.stringify(t),b=JSON.stringify(d),p=JSON.stringify(n),x=JSON.stringify(r),u=JSON.stringify(o),f=JSON.stringify(i),Ne=JSON.stringify(a),Ae=JSON.stringify(s);return`<!DOCTYPE html>
|
|
22
23
|
<html lang="en">
|
|
23
24
|
<head>
|
|
24
25
|
<meta charset="UTF-8">
|
|
25
26
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
26
27
|
<title>Vector API Documentation</title>
|
|
27
|
-
<link rel="apple-touch-icon" sizes="180x180" href=${
|
|
28
|
-
<link rel="icon" type="image/png" sizes="32x32" href=${
|
|
29
|
-
<link rel="icon" type="image/png" sizes="16x16" href=${
|
|
30
|
-
<link rel="manifest" href=${
|
|
28
|
+
<link rel="apple-touch-icon" sizes="180x180" href=${u}>
|
|
29
|
+
<link rel="icon" type="image/png" sizes="32x32" href=${f}>
|
|
30
|
+
<link rel="icon" type="image/png" sizes="16x16" href=${Ne}>
|
|
31
|
+
<link rel="manifest" href=${Ae}>
|
|
31
32
|
<script>
|
|
32
33
|
if (localStorage.getItem('theme') === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
|
|
33
34
|
document.documentElement.classList.add('dark');
|
|
@@ -35,7 +36,7 @@ ${t.join(`,
|
|
|
35
36
|
document.documentElement.classList.remove('dark');
|
|
36
37
|
}
|
|
37
38
|
</script>
|
|
38
|
-
<script src=${
|
|
39
|
+
<script src=${b}></script>
|
|
39
40
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
|
40
41
|
<script>
|
|
41
42
|
tailwind.config = {
|
|
@@ -150,8 +151,8 @@ ${t.join(`,
|
|
|
150
151
|
<aside id="docs-sidebar" class="fixed inset-y-0 left-0 z-40 w-72 md:w-64 border-r border-light-border dark:border-dark-border bg-light-surface dark:bg-dark-surface flex flex-col flex-shrink-0 transition-transform duration-300 ease-out -translate-x-full md:translate-x-0 md:static md:z-auto transition-colors duration-150">
|
|
151
152
|
<div class="h-14 flex items-center px-5 border-b border-light-border dark:border-dark-border">
|
|
152
153
|
<div class="flex items-center">
|
|
153
|
-
<img src=${
|
|
154
|
-
<img src=${
|
|
154
|
+
<img src=${p} alt="Vector" class="h-6 w-auto block dark:hidden" />
|
|
155
|
+
<img src=${x} alt="Vector" class="h-6 w-auto hidden dark:block" />
|
|
155
156
|
</div>
|
|
156
157
|
<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">
|
|
157
158
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
@@ -183,8 +184,8 @@ ${t.join(`,
|
|
|
183
184
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path>
|
|
184
185
|
</svg>
|
|
185
186
|
</button>
|
|
186
|
-
<img src=${
|
|
187
|
-
<img src=${
|
|
187
|
+
<img src=${p} alt="Vector" class="h-5 w-auto block dark:hidden" />
|
|
188
|
+
<img src=${x} alt="Vector" class="h-5 w-auto hidden dark:block" />
|
|
188
189
|
</div>
|
|
189
190
|
<div class="flex-1"></div>
|
|
190
191
|
<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">
|
|
@@ -303,7 +304,7 @@ ${t.join(`,
|
|
|
303
304
|
|
|
304
305
|
<script>
|
|
305
306
|
const spec = ${c};
|
|
306
|
-
const openapiPath = ${
|
|
307
|
+
const openapiPath = ${m};
|
|
307
308
|
const methodBadgeDefault = "bg-black/5 text-light-text/80 dark:bg-white/10 dark:text-dark-text/80";
|
|
308
309
|
const methodBadge = {
|
|
309
310
|
GET: "bg-brand-soft text-brand-deep dark:bg-brand/20 dark:text-brand",
|
|
@@ -701,7 +702,7 @@ ${t.join(`,
|
|
|
701
702
|
'<details class="border-b border-light-border/50 dark:border-dark-border/50" open>' +
|
|
702
703
|
'<summary class="list-none cursor-pointer py-2 flex justify-between items-center" style="padding-left:' +
|
|
703
704
|
padding +
|
|
704
|
-
'px"><div class="flex items-center gap-2"><span class="text-xs opacity-70"
|
|
705
|
+
'px"><div class="flex items-center gap-2"><span class="text-xs opacity-70">\u25BE</span><code class="text-sm font-mono">' +
|
|
705
706
|
name +
|
|
706
707
|
'</code><span class="text-xs text-brand">' +
|
|
707
708
|
requiredLabel +
|
|
@@ -1430,4 +1431,4 @@ ${t.join(`,
|
|
|
1430
1431
|
renderEndpoint();
|
|
1431
1432
|
</script>
|
|
1432
1433
|
</body>
|
|
1433
|
-
</html>`}function ye(e){let t=e?.["~standard"],n=t?.jsonSchema;return!!t&&typeof t==="object"&&t.version===1&&!!n&&typeof n.input==="function"&&typeof n.output==="function"}function ge(e){let t=0,n=[];return{openapiPath:e.split("/").map((r)=>{let a=/^:([A-Za-z0-9_]+)\+$/.exec(r);if(a?.[1])return n.push(a[1]),`{${a[1]}}`;let i=/^:([A-Za-z0-9_]+)$/.exec(r);if(i?.[1])return n.push(i[1]),`{${i[1]}}`;if(r==="*"){t+=1;let o=t===1?"wildcard":`wildcard${t}`;return n.push(o),`{${o}}`}return r}).join("/"),pathParamNames:n}}function Ve(e){return ge(e).openapiPath}function Fe(e,t){return`${e.toLowerCase()}_${t}`.replace(/[:{}]/g,"").replace(/[^A-Za-z0-9_]+/g,"_").replace(/^_+|_+$/g,"")||`${e.toLowerCase()}_operation`}function ze(e){let t=e.split("/").filter(Boolean);for(let n of t)if(!n.startsWith(":")&&n!=="*")return n.toLowerCase();return"default"}function Ge(e){return ge(e).pathParamNames}function Qe(e,t){let n=new Set((e.parameters||[]).filter((d)=>d.in==="path").map((d)=>String(d.name)));for(let d of Ge(t)){if(n.has(d))continue;(e.parameters||=[]).push({name:d,in:"path",required:!0,schema:{type:"string"}})}}function Ye(e){let t=Number(e);if(!Number.isInteger(t))return!1;return t>=100&&t<200||t===204||t===205||t===304}function Xe(e){if(e==="204")return"No Content";if(e==="205")return"Reset Content";if(e==="304")return"Not Modified";let t=Number(e);if(Number.isInteger(t)&&t>=100&&t<200)return"Informational";return"OK"}function We(e,t,n,d){if(!ye(t))return null;try{return t["~standard"].jsonSchema.input({target:n})}catch(r){d.push(`[OpenAPI] Failed input schema conversion for ${e}: ${r instanceof Error?r.message:String(r)}. Falling back to a permissive JSON Schema.`);let a=ve(t);return Ke(a)?null:a}}function he(e,t,n,d,r){if(!ye(n))return null;try{return n["~standard"].jsonSchema.output({target:d})}catch(a){return r.push(`[OpenAPI] Failed output schema conversion for ${e} (${t}): ${a instanceof Error?a.message:String(a)}. Falling back to a permissive JSON Schema.`),ve(n)}}function g(e){return!!e&&typeof e==="object"&&!Array.isArray(e)}function Ke(e){return g(e)&&Object.keys(e).length===0}function X(e){if(!e||typeof e!=="object")return null;let t=e;if(g(t._def))return t._def;if(g(t._zod)&&g(t._zod.def))return t._zod.def;return null}function xe(e){if(!e)return null;let t=e.typeName;if(typeof t==="string")return t;let n=e.type;if(typeof n==="string")return n;return null}function Y(e){let t=["innerType","schema","type","out","in","left","right"];for(let n of t)if(n in e)return e[n];return}function Ze(e,t){for(let n of t){let d=e[n];if(d&&typeof d==="object"&&!Array.isArray(d))return d}return}function qe(e){if(!e)return!1;let t=e.toLowerCase();return t.includes("optional")||t.includes("default")||t.includes("catch")}function et(e){let t=e,n=!1,d=0;while(d<8){d+=1;let r=X(t),a=xe(r);if(!r||!qe(a))break;n=!0;let i=Y(r);if(!i)break;t=i}return{schema:t,optional:n}}function tt(e){let t=e.shape;if(typeof t==="function")try{let n=t();return g(n)?n:{}}catch{return{}}return g(t)?t:{}}function nt(e){let t=e.toLowerCase();if(t.includes("string"))return{type:"string"};if(t.includes("number"))return{type:"number"};if(t.includes("boolean"))return{type:"boolean"};if(t.includes("bigint"))return{type:"string"};if(t.includes("null"))return{type:"null"};if(t.includes("any")||t.includes("unknown")||t.includes("never"))return{};if(t.includes("date"))return{type:"string",format:"date-time"};if(t.includes("custom"))return{type:"object",additionalProperties:!0};return null}function x(e,t=new WeakSet){if(!e||typeof e!=="object")return{};if(t.has(e))return{};t.add(e);let n=X(e),d=xe(n);if(!n||!d)return{};let r=nt(d);if(r)return r;let a=d.toLowerCase();if(a.includes("object")){let o=tt(n),s={},c=[];for(let[u,m]of Object.entries(o)){let h=et(m);if(s[u]=x(h.schema,t),!h.optional)c.push(u)}let l={type:"object",properties:s,additionalProperties:!0};if(c.length>0)l.required=c;return l}if(a.includes("array")){let o=Ze(n,["element","items","innerType","type"])??{};return{type:"array",items:x(o,t)}}if(a.includes("record")){let o=n.valueType??n.valueSchema;return{type:"object",additionalProperties:o?x(o,t):!0}}if(a.includes("tuple")){let s=(Array.isArray(n.items)?n.items:[]).map((c)=>x(c,t));return{type:"array",prefixItems:s,minItems:s.length,maxItems:s.length}}if(a.includes("union")){let o=n.options??n.schemas??[];if(!Array.isArray(o)||o.length===0)return{};return{anyOf:o.map((s)=>x(s,t))}}if(a.includes("intersection")){let{left:o,right:s}=n;if(!o||!s)return{};return{allOf:[x(o,t),x(s,t)]}}if(a.includes("enum")){let o=n.values;if(Array.isArray(o))return{enum:o};if(o&&typeof o==="object")return{enum:Object.values(o)};return{}}if(a.includes("literal")){let o=n.value;if(o===void 0)return{};let s=o===null?"null":typeof o;if(s==="string"||s==="number"||s==="boolean"||s==="null")return{type:s,const:o};return{const:o}}if(a.includes("nullable")){let o=Y(n);if(!o)return{};return{anyOf:[x(o,t),{type:"null"}]}}if(a.includes("lazy")){let o=n.getter;if(typeof o!=="function")return{};try{return x(o(),t)}catch{return{}}}let i=Y(n);if(i)return x(i,t);return{}}function ve(e){if(!X(e))return{};return x(e)}function dt(e,t){if(!g(t))return;if(t.type!=="object"||!g(t.properties)){e.requestBody={required:!0,content:{"application/json":{schema:t}}};return}let n=new Set(Array.isArray(t.required)?t.required:[]),d=t.properties,r=Array.isArray(e.parameters)?e.parameters:[],a=[{key:"params",in:"path"},{key:"query",in:"query"},{key:"headers",in:"header"},{key:"cookies",in:"cookie"}];for(let o of a){let s=d[o.key];if(!g(s))continue;if(s.type!=="object"||!g(s.properties))continue;let c=new Set(Array.isArray(s.required)?s.required:[]);for(let[l,u]of Object.entries(s.properties))r.push({name:l,in:o.in,required:o.in==="path"?!0:c.has(l),schema:g(u)?u:{}})}if(r.length>0){let o=new Map;for(let s of r)o.set(`${s.in}:${s.name}`,s);e.parameters=[...o.values()]}let i=d.body;if(i)e.requestBody={required:n.has("body"),content:{"application/json":{schema:g(i)?i:{}}}}}function rt(e,t,n,d,r){let a=n.output;if(!a){e.responses={200:{description:"OK"}};return}let i={};if(typeof a==="object"&&a!==null&&"~standard"in a){let o=he(t,"200",a,d,r);if(o)i["200"]={description:"OK",content:{"application/json":{schema:o}}};else i["200"]={description:"OK"}}else for(let[o,s]of Object.entries(a)){let c=String(o),l=he(t,c,s,d,r),u=Xe(c);if(l&&!Ye(c))i[c]={description:u,content:{"application/json":{schema:l}}};else i[c]={description:u}}if(Object.keys(i).length===0)i["200"]={description:"OK"};e.responses=i}function ke(e,t){let n=[],d={};for(let i of e){if(i.options.expose===!1)continue;if(!i.method||!i.path)continue;let o=i.method.toLowerCase();if(o==="options")continue;let s=Ve(i.path),c={operationId:Fe(o,s),tags:[i.options.schema?.tag||ze(i.path)]},l=We(i.path,i.options.schema?.input,t.target,n);if(l)dt(c,l);Qe(c,i.path),rt(c,i.path,i.options.schema||{},t.target,n),d[s]||={},d[s][o]=c}return{document:{openapi:t.target==="openapi-3.0"?"3.0.3":"3.1.0",info:{title:t.info?.title||"Vector API",version:t.info?.version||"1.0.0",...t.info?.description?{description:t.info.description}:{}},paths:d},warnings:n}}var W="/_vector/openapi/tailwindcdn.js",K="/_vector/openapi/logo_dark.svg",Z="/_vector/openapi/logo_white.svg",Ae="/_vector/openapi/favicon/apple-touch-icon.png",Ce="/_vector/openapi/favicon/favicon-32x32.png",De="/_vector/openapi/favicon/favicon-16x16.png",at="/_vector/openapi/favicon/favicon.ico",Ne="/_vector/openapi/favicon/site.webmanifest",ot="/_vector/openapi/favicon/android-chrome-192x192.png",it="/_vector/openapi/favicon/android-chrome-512x512.png",st=["../openapi/assets/tailwindcdn.js","../src/openapi/assets/tailwindcdn.js","../../src/openapi/assets/tailwindcdn.js"],lt=["../openapi/assets/logo_dark.svg","../src/openapi/assets/logo_dark.svg","../../src/openapi/assets/logo_dark.svg"],ct=["../openapi/assets/logo_white.svg","../src/openapi/assets/logo_white.svg","../../src/openapi/assets/logo_white.svg"],bt=["src/openapi/assets/tailwindcdn.js","openapi/assets/tailwindcdn.js","dist/openapi/assets/tailwindcdn.js"],ut=["src/openapi/assets/logo_dark.svg","openapi/assets/logo_dark.svg","dist/openapi/assets/logo_dark.svg"],mt=["src/openapi/assets/logo_white.svg","openapi/assets/logo_white.svg","dist/openapi/assets/logo_white.svg"],I=["../openapi/assets/favicon","../src/openapi/assets/favicon","../../src/openapi/assets/favicon"],L=["src/openapi/assets/favicon","openapi/assets/favicon","dist/openapi/assets/favicon"],ft="/* OpenAPI docs runtime asset missing: tailwind disabled */";function y(e,t){return e.map((n)=>`${n}/${t}`)}function k(e,t){for(let d of e)try{let r=new URL(d,import.meta.url);if(Ee(r))return Bun.file(r)}catch{}let n=process.cwd();for(let d of t){let r=j(n,d);if(Ee(r))return Bun.file(r)}return null}var we=k(st,bt),Be=k(lt,ut),Ie=k(ct,mt),pt=k(y(I,"apple-touch-icon.png"),y(L,"apple-touch-icon.png")),ht=k(y(I,"favicon-32x32.png"),y(L,"favicon-32x32.png")),yt=k(y(I,"favicon-16x16.png"),y(L,"favicon-16x16.png")),gt=k(y(I,"favicon.ico"),y(L,"favicon.ico")),xt=k(y(I,"site.webmanifest"),y(L,"site.webmanifest")),vt=k(y(I,"android-chrome-192x192.png"),y(L,"android-chrome-192x192.png")),kt=k(y(I,"android-chrome-512x512.png"),y(L,"android-chrome-512x512.png")),Le=[{path:Ae,file:pt,contentType:"image/png",filename:"apple-touch-icon.png"},{path:Ce,file:ht,contentType:"image/png",filename:"favicon-32x32.png"},{path:De,file:yt,contentType:"image/png",filename:"favicon-16x16.png"},{path:at,file:gt,contentType:"image/x-icon",filename:"favicon.ico"},{path:Ne,file:xt,contentType:"application/manifest+json; charset=utf-8",filename:"site.webmanifest"},{path:ot,file:vt,contentType:"image/png",filename:"android-chrome-192x192.png"},{path:it,file:kt,contentType:"image/png",filename:"android-chrome-512x512.png"}],q="public, max-age=0, must-revalidate",O="public, max-age=31536000, immutable",ee="no-store";function Et(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function wt(e){let t="^";for(let n of e){if(n==="*"){t+=".*";continue}t+=Et(n)}return t+="$",new RegExp(t)}function Bt(e,t){if(!t.includes("*"))return e===t;return wt(t).test(e)}class te{server=null;router;config;openapiConfig;openapiDocCache=null;openapiDocsHtmlCache=null;openapiWarningsLogged=!1;openapiTailwindMissingLogged=!1;openapiLogoDarkMissingLogged=!1;openapiLogoWhiteMissingLogged=!1;corsHandler=null;corsHeadersEntries=null;constructor(e,t){if(this.router=e,this.config=t,this.openapiConfig=this.normalizeOpenAPIConfig(t.openapi,t.development),t.cors){let n=this.normalizeCorsOptions(t.cors),{preflight:d,corsify:r}=fe(n);if(this.corsHandler={preflight:d,corsify:r},typeof n.origin==="string"&&(n.origin!=="*"||!n.credentials)){let i={"access-control-allow-origin":n.origin,"access-control-allow-methods":n.allowMethods,"access-control-allow-headers":n.allowHeaders,"access-control-expose-headers":n.exposeHeaders,"access-control-max-age":String(n.maxAge)};if(n.credentials)i["access-control-allow-credentials"]="true";this.corsHeadersEntries=Object.entries(i)}this.router.setCorsHeaders(this.corsHeadersEntries),this.router.setCorsHandler(this.corsHeadersEntries?null:this.corsHandler.corsify)}}normalizeOpenAPIConfig(e,t){let d=t!==!1&&!0;if(e===!1)return{enabled:!1,path:"/openapi.json",target:"openapi-3.0",docs:{enabled:!1,path:"/docs"}};if(e===!0)return{enabled:!0,path:"/openapi.json",target:"openapi-3.0",docs:{enabled:!1,path:"/docs"}};let r=e||{},a=r.docs,i=typeof a==="boolean"?{enabled:a,path:"/docs",exposePaths:void 0}:{enabled:a?.enabled===!0,path:a?.path||"/docs",exposePaths:Array.isArray(a?.exposePaths)?a.exposePaths.map((o)=>typeof o==="string"?o.trim():"").filter((o)=>o.length>0):void 0};return{enabled:r.enabled??d,path:r.path||"/openapi.json",target:r.target||"openapi-3.0",docs:i,info:r.info}}isDocsReservedPath(e){return e===this.openapiConfig.path||this.openapiConfig.docs.enabled&&e===this.openapiConfig.docs.path}getOpenAPIDocument(){if(this.openapiDocCache)return this.openapiDocCache;let e=this.router.getRouteDefinitions().filter((n)=>!this.isDocsReservedPath(n.path)),t=ke(e,{target:this.openapiConfig.target,info:this.openapiConfig.info});if(!this.openapiWarningsLogged&&t.warnings.length>0){for(let n of t.warnings)console.warn(n);this.openapiWarningsLogged=!0}return this.openapiDocCache=t.document,this.openapiDocCache}getOpenAPIDocumentForDocs(){let e=this.openapiConfig.docs.exposePaths,t=this.getOpenAPIDocument();if(!Array.isArray(e)||e.length===0)return t;let n=t.paths&&typeof t.paths==="object"&&!Array.isArray(t.paths)?t.paths:{},d={};for(let[r,a]of Object.entries(n))if(e.some((i)=>Bt(r,i)))d[r]=a;return{...t,paths:d}}getOpenAPIDocsHtmlCacheEntry(){if(this.openapiDocsHtmlCache)return this.openapiDocsHtmlCache;let e=pe(this.getOpenAPIDocumentForDocs(),this.openapiConfig.path,W,K,Z,Ae,Ce,De,Ne),t=Bun.gzipSync(e),n=`"${Bun.hash(e).toString(16)}"`;return this.openapiDocsHtmlCache={html:e,gzip:t,etag:n},this.openapiDocsHtmlCache}requestAcceptsGzip(e){let t=e.headers.get("accept-encoding");return Boolean(t&&/\bgzip\b/i.test(t))}validateReservedOpenAPIPaths(){if(!this.openapiConfig.enabled)return;let e=new Set([this.openapiConfig.path]);if(this.openapiConfig.docs.enabled){e.add(this.openapiConfig.docs.path),e.add(W),e.add(K),e.add(Z);for(let r of Le)e.add(r.path)}let t=this.router.getRouteDefinitions().filter((r)=>e.has(r.path)).map((r)=>`${r.method} ${r.path}`),n=Object.entries(this.router.getRouteTable()).filter(([r,a])=>e.has(r)&&a instanceof Response).map(([r])=>`STATIC ${r}`),d=[...t,...n];if(d.length>0)throw new Error(`OpenAPI reserved path conflict: ${d.join(", ")}. Change your route path(s) or reconfigure openapi.path/docs.path.`)}tryHandleOpenAPIRequest(e){if(!this.openapiConfig.enabled||e.method!=="GET")return null;let t=new URL(e.url).pathname;if(t===this.openapiConfig.path)return Response.json(this.getOpenAPIDocument());if(this.openapiConfig.docs.enabled&&t===this.openapiConfig.docs.path){let{html:n,gzip:d,etag:r}=this.getOpenAPIDocsHtmlCacheEntry();if(e.headers.get("if-none-match")===r)return new Response(null,{status:304,headers:{etag:r,"cache-control":q,vary:"accept-encoding"}});if(this.requestAcceptsGzip(e))return new Response(d,{status:200,headers:{"content-type":"text/html; charset=utf-8","content-encoding":"gzip",etag:r,"cache-control":q,vary:"accept-encoding"}});return new Response(n,{status:200,headers:{"content-type":"text/html; charset=utf-8",etag:r,"cache-control":q,vary:"accept-encoding"}})}if(this.openapiConfig.docs.enabled&&t===W){if(!we){if(!this.openapiTailwindMissingLogged)this.openapiTailwindMissingLogged=!0,console.warn('[OpenAPI] Missing docs runtime asset "tailwindcdn.js". Serving inline fallback script instead.');return new Response(ft,{status:200,headers:{"content-type":"application/javascript; charset=utf-8","cache-control":O}})}return new Response(we,{status:200,headers:{"content-type":"application/javascript; charset=utf-8","cache-control":O}})}if(this.openapiConfig.docs.enabled&&t===K){if(!Be){if(!this.openapiLogoDarkMissingLogged)this.openapiLogoDarkMissingLogged=!0,console.warn('[OpenAPI] Missing docs runtime asset "logo_dark.svg".');return new Response("OpenAPI docs runtime asset missing: logo_dark.svg",{status:404,headers:{"content-type":"text/plain; charset=utf-8","cache-control":ee}})}return new Response(Be,{status:200,headers:{"content-type":"image/svg+xml; charset=utf-8","cache-control":O}})}if(this.openapiConfig.docs.enabled&&t===Z){if(!Ie){if(!this.openapiLogoWhiteMissingLogged)this.openapiLogoWhiteMissingLogged=!0,console.warn('[OpenAPI] Missing docs runtime asset "logo_white.svg".');return new Response("OpenAPI docs runtime asset missing: logo_white.svg",{status:404,headers:{"content-type":"text/plain; charset=utf-8","cache-control":ee}})}return new Response(Ie,{status:200,headers:{"content-type":"image/svg+xml; charset=utf-8","cache-control":O}})}if(this.openapiConfig.docs.enabled){let n=Le.find((d)=>d.path===t);if(n){if(!n.file)return new Response(`OpenAPI docs runtime asset missing: ${n.filename}`,{status:404,headers:{"content-type":"text/plain; charset=utf-8","cache-control":ee}});return new Response(n.file,{status:200,headers:{"content-type":n.contentType,"cache-control":O}})}}return null}normalizeCorsOptions(e){return{origin:e.origin||"*",credentials:e.credentials!==!1,allowHeaders:Array.isArray(e.allowHeaders)?e.allowHeaders.join(", "):e.allowHeaders||"Content-Type, Authorization",allowMethods:Array.isArray(e.allowMethods)?e.allowMethods.join(", "):e.allowMethods||"GET, POST, PUT, PATCH, DELETE, OPTIONS",exposeHeaders:Array.isArray(e.exposeHeaders)?e.exposeHeaders.join(", "):e.exposeHeaders||"Authorization",maxAge:e.maxAge||86400}}applyCors(e,t){if(this.corsHeadersEntries){for(let[n,d]of this.corsHeadersEntries)e.headers.set(n,d);return e}if(this.corsHandler&&t)return this.corsHandler.corsify(e,t);return e}async start(){let e=this.config.port??3000,t=this.config.hostname||"localhost";this.validateReservedOpenAPIPaths();let n=async(d)=>{try{if(this.corsHandler&&d.method==="OPTIONS")return this.corsHandler.preflight(d);let r=this.tryHandleOpenAPIRequest(d);if(r)return this.applyCors(r,d);return this.applyCors(H.NOT_FOUND.clone(),d)}catch(r){return console.error("Server error:",r),this.applyCors(new Response("Internal Server Error",{status:500}),d)}};try{if(this.server=Bun.serve({port:e,hostname:t,reusePort:this.config.reusePort!==!1,routes:this.router.getRouteTable(),fetch:n,idleTimeout:this.config.idleTimeout??60,error:(d,r)=>{return console.error("[ERROR] Server error:",d),this.applyCors(new Response("Internal Server Error",{status:500}),r)}}),!this.server||!this.server.port)throw new Error(`Failed to start server on ${t}:${e} - server object is invalid`);return this.server}catch(d){if(d.code==="EADDRINUSE"||d.message?.includes("address already in use"))d.message=`Port ${e} is already in use`,d.port=e;else if(d.code==="EACCES"||d.message?.includes("permission denied"))d.message=`Permission denied to bind to port ${e}`,d.port=e;else if(d.message?.includes("EADDRNOTAVAIL"))d.message=`Cannot bind to hostname ${t}`,d.hostname=t;throw d}}stop(){if(this.server)this.server.stop(),this.server=null,this.openapiDocCache=null,this.openapiDocsHtmlCache=null,this.openapiWarningsLogged=!1,console.log("Server stopped")}getServer(){return this.server}getPort(){return this.server?.port??this.config.port??3000}getHostname(){return this.server?.hostname||this.config.hostname||"localhost"}getUrl(){let e=this.getPort();return`http://${this.getHostname()}:${e}`}}class A{static instance;router;server=null;middlewareManager;authManager;cacheManager;config={};routeScanner=null;routeGenerator=null;_protectedHandler=null;_cacheHandler=null;shutdownPromise=null;constructor(){this.middlewareManager=new R,this.authManager=new $,this.cacheManager=new J,this.router=new M(this.middlewareManager,this.authManager,this.cacheManager)}static getInstance(){if(!A.instance)A.instance=new A;return A.instance}setProtectedHandler(e){if(this._protectedHandler=e,e){this.authManager.setProtectedHandler(e);return}this.authManager.clearProtectedHandler()}getProtectedHandler(){return this._protectedHandler}setCacheHandler(e){if(this._cacheHandler=e,e){this.cacheManager.setCacheHandler(e);return}this.cacheManager.clearCacheHandler()}getCacheHandler(){return this._cacheHandler}addRoute(e,t){this.router.route(e,t)}async startServer(e){this.config={...this.config,...e};let t={...this.config.defaults?.route};if(this.router.setRouteBooleanDefaults(t),this.router.setDevelopmentMode(this.config.development),this.middlewareManager.clear(),this.config.autoDiscover!==!1)this.router.clearRoutes();if(e?.before)this.middlewareManager.addBefore(...e.before);if(e?.finally)this.middlewareManager.addFinally(...e.finally);if(typeof this.config.startup==="function")await this.config.startup();if(this.config.autoDiscover!==!1)await this.discoverRoutes();return this.server=new te(this.router,this.config),await this.server.start()}async discoverRoutes(){let e=this.config.routesDir||"./routes",t=this.config.routeExcludePatterns;if(this.routeScanner=new P(e,t),!this.routeGenerator)this.routeGenerator=new F;try{let n=await this.routeScanner.scan();if(n.length>0){if(this.config.development)await this.routeGenerator.generate(n);for(let d of n)try{let a=await import(U(d.path)),i=d.name==="default"?a.default:a[d.name];if(i){if(this.isRouteDefinition(i))this.router.route(i.options,i.handler),this.logRouteLoaded(i.options);else if(this.isRouteEntry(i))this.router.addRoute(i),this.logRouteLoaded(i);else if(typeof i==="function")this.router.route(d.options,i),this.logRouteLoaded(d.options)}}catch(r){console.error(`Failed to load route ${d.name} from ${d.path}:`,r)}}}catch(n){if(n.code!=="ENOENT"&&n.code!=="ENOTDIR")console.error("Failed to discover routes:",n)}}async loadRoute(e){if(typeof e==="function"){let t=e();if(this.isRouteEntry(t))this.router.addRoute(t)}else if(e&&typeof e==="object"){for(let[,t]of Object.entries(e))if(typeof t==="function"){let n=t();if(this.isRouteEntry(n))this.router.addRoute(n)}}}isRouteEntry(e){if(!Array.isArray(e)||e.length<3)return!1;let[t,n,d,r]=e;return typeof t==="string"&&n instanceof RegExp&&Array.isArray(d)&&d.length>0&&d.every((a)=>typeof a==="function")&&(r===void 0||typeof r==="string")}isRouteDefinition(e){return e!==null&&typeof e==="object"&&"entry"in e&&"options"in e&&"handler"in e&&typeof e.handler==="function"}logRouteLoaded(e){}stop(){if(this.server)this.server.stop(),this.server=null}async shutdown(){if(this.shutdownPromise)return this.shutdownPromise;this.shutdownPromise=(async()=>{if(this.stop(),typeof this.config.shutdown==="function")await this.config.shutdown()})();try{await this.shutdownPromise}finally{this.shutdownPromise=null}}getServer(){return this.server}getRouter(){return this.router}getCacheManager(){return this.cacheManager}getAuthManager(){return this.authManager}static resetInstance(){A.instance=null}}var ne=A.getInstance;function It(e,t){return{entry:{method:e.method.toUpperCase(),path:e.path},options:e,handler:t}}function Lt(e){let t=e??null;try{return JSON.stringify(t)}catch(n){if(n instanceof TypeError&&/\bbigint\b/i.test(n.message))return JSON.stringify(t,(d,r)=>typeof r==="bigint"?r.toString():r);throw n}}function b(e,t,n){let d={error:!0,message:t,statusCode:e,timestamp:new Date().toISOString()};return N(e,d,n)}var w={badRequest:(e="Bad Request",t)=>b(E.BAD_REQUEST,e,t),unauthorized:(e="Unauthorized",t)=>b(E.UNAUTHORIZED,e,t),paymentRequired:(e="Payment Required",t)=>b(402,e,t),forbidden:(e="Forbidden",t)=>b(E.FORBIDDEN,e,t),notFound:(e="Not Found",t)=>b(E.NOT_FOUND,e,t),methodNotAllowed:(e="Method Not Allowed",t)=>b(405,e,t),notAcceptable:(e="Not Acceptable",t)=>b(406,e,t),requestTimeout:(e="Request Timeout",t)=>b(408,e,t),conflict:(e="Conflict",t)=>b(E.CONFLICT,e,t),gone:(e="Gone",t)=>b(410,e,t),lengthRequired:(e="Length Required",t)=>b(411,e,t),preconditionFailed:(e="Precondition Failed",t)=>b(412,e,t),payloadTooLarge:(e="Payload Too Large",t)=>b(413,e,t),uriTooLong:(e="URI Too Long",t)=>b(414,e,t),unsupportedMediaType:(e="Unsupported Media Type",t)=>b(415,e,t),rangeNotSatisfiable:(e="Range Not Satisfiable",t)=>b(416,e,t),expectationFailed:(e="Expectation Failed",t)=>b(417,e,t),imATeapot:(e="I'm a teapot",t)=>b(418,e,t),misdirectedRequest:(e="Misdirected Request",t)=>b(421,e,t),unprocessableEntity:(e="Unprocessable Entity",t)=>b(E.UNPROCESSABLE_ENTITY,e,t),locked:(e="Locked",t)=>b(423,e,t),failedDependency:(e="Failed Dependency",t)=>b(424,e,t),tooEarly:(e="Too Early",t)=>b(425,e,t),upgradeRequired:(e="Upgrade Required",t)=>b(426,e,t),preconditionRequired:(e="Precondition Required",t)=>b(428,e,t),tooManyRequests:(e="Too Many Requests",t)=>b(429,e,t),requestHeaderFieldsTooLarge:(e="Request Header Fields Too Large",t)=>b(431,e,t),unavailableForLegalReasons:(e="Unavailable For Legal Reasons",t)=>b(451,e,t),internalServerError:(e="Internal Server Error",t)=>b(E.INTERNAL_SERVER_ERROR,e,t),notImplemented:(e="Not Implemented",t)=>b(501,e,t),badGateway:(e="Bad Gateway",t)=>b(502,e,t),serviceUnavailable:(e="Service Unavailable",t)=>b(503,e,t),gatewayTimeout:(e="Gateway Timeout",t)=>b(504,e,t),httpVersionNotSupported:(e="HTTP Version Not Supported",t)=>b(505,e,t),variantAlsoNegotiates:(e="Variant Also Negotiates",t)=>b(506,e,t),insufficientStorage:(e="Insufficient Storage",t)=>b(507,e,t),loopDetected:(e="Loop Detected",t)=>b(508,e,t),notExtended:(e="Not Extended",t)=>b(510,e,t),networkAuthenticationRequired:(e="Network Authentication Required",t)=>b(511,e,t),invalidArgument:(e="Invalid Argument",t)=>b(E.UNPROCESSABLE_ENTITY,e,t),rateLimitExceeded:(e="Rate Limit Exceeded",t)=>b(429,e,t),maintenance:(e="Service Under Maintenance",t)=>b(503,e,t),custom:(e,t,n)=>b(e,t,n)};function N(e,t,n=_.JSON){let d=n===_.JSON?Lt(t):t;return new Response(d,{status:e,headers:{"content-type":n}})}var{existsSync:At}=(()=>({}));class de{configPath;config=null;configSource="default";constructor(e){let t=e||"vector.config.ts";this.configPath=V(t)?t:B(process.cwd(),t)}async load(){if(At(this.configPath))try{let t=await import(U(this.configPath));this.config=t.default||t,this.configSource="user"}catch(e){let t=e instanceof Error?e.message:String(e);console.error(`[vector] Failed to load config from ${this.configPath}: ${t}`),console.error("[vector] Server is using default configuration. Fix your config file and restart."),this.config={}}else this.config={};return await this.buildLegacyConfig()}getConfigSource(){return this.configSource}async buildLegacyConfig(){let e={};if(this.config)e.port=this.config.port,e.hostname=this.config.hostname,e.reusePort=this.config.reusePort,e.development=this.config.development,e.routesDir=this.config.routesDir||"./routes",e.routeExcludePatterns=this.config.routeExcludePatterns,e.idleTimeout=this.config.idleTimeout,e.defaults=this.config.defaults,e.openapi=this.config.openapi,e.startup=this.config.startup,e.shutdown=this.config.shutdown;if(e.autoDiscover=!0,this.config?.cors)if(typeof this.config.cors==="boolean")e.cors=this.config.cors?{origin:"*",credentials:!0,allowHeaders:"Content-Type, Authorization",allowMethods:"GET, POST, PUT, PATCH, DELETE, OPTIONS",exposeHeaders:"Authorization",maxAge:86400}:void 0;else e.cors=this.config.cors;if(this.config?.before)e.before=this.config.before;if(this.config?.after)e.finally=this.config.after;return e}async loadAuthHandler(){return this.config?.auth||null}async loadCacheHandler(){return this.config?.cache||null}getConfig(){return this.config}}async function Ct(e={}){let t=new de(e.configPath),n=await t.load(),d=t.getConfigSource(),r={...n};if(e.mutateConfig)r=await e.mutateConfig(r,{configSource:d});if(e.config)r={...r,...e.config};if(e.autoDiscover!==void 0)r.autoDiscover=e.autoDiscover;let a=ne(),i=e.protectedHandler!==void 0?e.protectedHandler:await t.loadAuthHandler(),o=e.cacheHandler!==void 0?e.cacheHandler:await t.loadCacheHandler();a.setProtectedHandler(i??null),a.setCacheHandler(o??null);let s=await a.startServer(r),c={...r,port:s.port??r.port??C.PORT,hostname:s.hostname||r.hostname||C.HOSTNAME,reusePort:r.reusePort!==!1,idleTimeout:r.idleTimeout??60};return{server:s,config:c,stop:()=>a.stop(),shutdown:()=>a.shutdown()}}export{Ct as startVector,It as route,N as createResponse,w as APIError};
|
|
1434
|
+
</html>`}function z(e){let t=e?.["~standard"],d=t?.jsonSchema;return!!t&&typeof t==="object"&&t.version===1&&!!d&&typeof d.input==="function"&&typeof d.output==="function"}function fe(e){let t=0,d=[];return{openapiPath:e.split("/").map((r)=>{let o=/^:([A-Za-z0-9_]+)\+$/.exec(r);if(o?.[1])return d.push(o[1]),`{${o[1]}}`;let i=/^:([A-Za-z0-9_]+)$/.exec(r);if(i?.[1])return d.push(i[1]),`{${i[1]}}`;if(r==="*"){t+=1;let a=t===1?"wildcard":`wildcard${t}`;return d.push(a),`{${a}}`}return r}).join("/"),pathParamNames:d}}function Re(e){return fe(e).openapiPath}function Ue(e,t){return`${e.toLowerCase()}_${t}`.replace(/[:{}]/g,"").replace(/[^A-Za-z0-9_]+/g,"_").replace(/^_+|_+$/g,"")||`${e.toLowerCase()}_operation`}function $e(e){let t=e.split("/").filter(Boolean);for(let d of t)if(!d.startsWith(":")&&d!=="*")return d.toLowerCase();return"default"}function Pe(e){return fe(e).pathParamNames}function _e(e,t){let d=new Set((e.parameters||[]).filter((n)=>n.in==="path").map((n)=>String(n.name)));for(let n of Pe(t)){if(d.has(n))continue;(e.parameters||=[]).push({name:n,in:"path",required:!0,schema:{type:"string"}})}}function Je(e){let t=Number(e);if(!Number.isInteger(t))return!1;return t>=100&&t<200||t===204||t===205||t===304}function Se(e){if(e==="204")return"No Content";if(e==="205")return"Reset Content";if(e==="304")return"Not Modified";let t=Number(e);if(Number.isInteger(t)&&t>=100&&t<200)return"Informational";return"OK"}function Fe(e,t,d,n){if(!z(t)){let r=O(t);return S(r)?null:r}try{return t["~standard"].jsonSchema.input({target:d})}catch(r){let o=he(t,"input",d,r,e,void 0,n);if(o)return o;n.push(`[OpenAPI] Failed input schema conversion for ${e}: ${r instanceof Error?r.message:String(r)}. Falling back to a permissive JSON Schema.`);let i=O(t);return S(i)?null:i}}function pe(e,t,d,n,r){if(!z(d)){let o=O(d);return S(o)?null:o}try{return d["~standard"].jsonSchema.output({target:n})}catch(o){let i=he(d,"output",n,o,e,t,r);if(i)return i;return r.push(`[OpenAPI] Failed output schema conversion for ${e} (${t}): ${o instanceof Error?o.message:String(o)}. Falling back to a permissive JSON Schema.`),O(d)}}function y(e){return!!e&&typeof e==="object"&&!Array.isArray(e)}function S(e){return y(e)&&Object.keys(e).length===0}function he(e,t,d,n,r,o,i){if(!z(e))return null;let a=n instanceof Error?n.message:String(n);if(!(d==="openapi-3.0"&&a.includes("target 'openapi-3.0' is not supported")&&a.includes("draft-2020-12")&&a.includes("draft-07")))return null;try{let c=e["~standard"].jsonSchema[t]({target:"draft-07"});return i.push(t==="input"?`[OpenAPI] ${r} converter does not support openapi-3.0 target; using draft-07 conversion output.`:`[OpenAPI] ${r} (${o}) converter does not support openapi-3.0 target; using draft-07 conversion output.`),c}catch{return null}}function G(e){if(!e||typeof e!=="object")return null;let t=e;if(y(t._def))return t._def;if(y(t._zod)&&y(t._zod.def))return t._zod.def;if(t.kind==="schema"&&typeof t.type==="string")return t;return null}function ye(e){if(!e)return null;let t=e.typeName;if(typeof t==="string")return t;let d=e.type;if(typeof d==="string")return d;return null}function F(e){let t=["innerType","schema","type","out","in","left","right","wrapped","element"];for(let d of t)if(d in e)return e[d];return}function ze(e,t){for(let d of t){let n=e[d];if(n&&typeof n==="object"&&!Array.isArray(n))return n}return}function Ge(e){if(!e)return!1;let t=e.toLowerCase();return t.includes("optional")||t.includes("default")||t.includes("catch")}function Ve(e){let t=e,d=!1,n=0;while(n<8){n+=1;let r=G(t),o=ye(r);if(!r||!Ge(o))break;d=!0;let i=F(r);if(!i)break;t=i}return{schema:t,optional:d}}function Qe(e){let t=e.entries;if(y(t))return t;let d=e.shape;if(typeof d==="function")try{let n=d();return y(n)?n:{}}catch{return{}}return y(d)?d:{}}function ue(e){let t=e.values;if(Array.isArray(t))return t;if(t&&typeof t==="object")return Object.values(t);let d=e.entries;if(d&&typeof d==="object")return Object.values(d);let n=e.enum;if(n&&typeof n==="object")return Object.values(n);let r=e.options;if(Array.isArray(r))return r.map((o)=>{if(o&&typeof o==="object"&&"unit"in o)return o.unit;return o}).filter((o)=>o!==void 0);return[]}function Ye(e){let t=e.toLowerCase();if(t.includes("string"))return{type:"string"};if(t.includes("number"))return{type:"number"};if(t.includes("boolean"))return{type:"boolean"};if(t.includes("bigint"))return{type:"string"};if(t==="null"||t.includes("zodnull"))return{type:"null"};if(t.includes("any")||t.includes("unknown")||t.includes("never"))return{};if(t.includes("date"))return{type:"string",format:"date-time"};if(t.includes("custom"))return{type:"object",additionalProperties:!0};return null}function g(e,t=new WeakSet){if(!e||typeof e!=="object")return{};if(t.has(e))return{};t.add(e);let d=G(e),n=ye(d);if(!d||!n)return{};let r=Ye(n);if(r)return r;let o=n.toLowerCase();if(o.includes("object")){let a=Qe(d),s={},c=[];for(let[b,p]of Object.entries(a)){let x=Ve(p);if(s[b]=g(x.schema,t),!x.optional)c.push(b)}let m={type:"object",properties:s,additionalProperties:!0};if(c.length>0)m.required=c;return m}if(o.includes("array")){let a=ze(d,["element","items","innerType","type"])??{};return{type:"array",items:g(a,t)}}if(o.includes("record")){let a=d.valueType??d.valueSchema;return{type:"object",additionalProperties:a?g(a,t):!0}}if(o.includes("tuple")){let s=(Array.isArray(d.items)?d.items:[]).map((c)=>g(c,t));return{type:"array",prefixItems:s,minItems:s.length,maxItems:s.length}}if(o.includes("union")){let a=d.options??d.schemas??[];if(!Array.isArray(a)||a.length===0)return{};return{anyOf:a.map((s)=>g(s,t))}}if(o.includes("intersection")){let{left:a,right:s}=d;if(!a||!s)return{};return{allOf:[g(a,t),g(s,t)]}}if(o.includes("enum")){let a=ue(d);if(a.length>0){let s=a.every((b)=>typeof b==="string"),c=a.every((b)=>typeof b==="number"),m=a.every((b)=>typeof b==="boolean");if(s)return{type:"string",enum:a};if(c)return{type:"number",enum:a};if(m)return{type:"boolean",enum:a};return{enum:a}}return{}}if(o.includes("picklist")){let a=ue(d);if(a.length>0){if(a.every((c)=>typeof c==="string"))return{type:"string",enum:a};return{enum:a}}return{}}if(o.includes("literal")){let a=d.value;if(a===void 0)return{};let s=a===null?"null":typeof a;if(s==="string"||s==="number"||s==="boolean"||s==="null")return{type:s,const:a};return{const:a}}if(o.includes("nullable")){let a=F(d);if(!a)return{};return{anyOf:[g(a,t),{type:"null"}]}}if(o.includes("lazy")){let a=d.getter;if(typeof a!=="function")return{};try{return g(a(),t)}catch{return{}}}let i=F(d);if(i)return g(i,t);return{}}function O(e){if(!G(e))return{};return g(e)}function Xe(e,t){if(!y(t))return;if(t.type!=="object"||!y(t.properties)){e.requestBody={required:!0,content:{"application/json":{schema:t}}};return}let d=new Set(Array.isArray(t.required)?t.required:[]),n=t.properties,r=Array.isArray(e.parameters)?e.parameters:[],o=[{key:"params",in:"path"},{key:"query",in:"query"},{key:"headers",in:"header"},{key:"cookies",in:"cookie"}];for(let a of o){let s=n[a.key];if(!y(s))continue;if(s.type!=="object"||!y(s.properties))continue;let c=new Set(Array.isArray(s.required)?s.required:[]);for(let[m,b]of Object.entries(s.properties))r.push({name:m,in:a.in,required:a.in==="path"?!0:c.has(m),schema:y(b)?b:{}})}if(r.length>0){let a=new Map;for(let s of r)a.set(`${s.in}:${s.name}`,s);e.parameters=[...a.values()]}let i=n.body;if(i)e.requestBody={required:d.has("body"),content:{"application/json":{schema:y(i)?i:{}}}}}function We(e,t,d,n,r){let o=d.output;if(!o){e.responses={200:{description:"OK"}};return}let i={};if(typeof o==="object"&&o!==null&&"~standard"in o){let a=pe(t,"200",o,n,r);if(a)i["200"]={description:"OK",content:{"application/json":{schema:a}}};else i["200"]={description:"OK"}}else for(let[a,s]of Object.entries(o)){let c=String(a),m=pe(t,c,s,n,r),b=Se(c);if(m&&!Je(c))i[c]={description:b,content:{"application/json":{schema:m}}};else i[c]={description:b}}if(Object.keys(i).length===0)i["200"]={description:"OK"};e.responses=i}function xe(e,t){let d=[],n={};for(let i of e){if(i.options.expose===!1)continue;if(!i.method||!i.path)continue;let a=i.method.toLowerCase();if(a==="options")continue;let s=Re(i.path),c={operationId:Ue(a,s),tags:[i.options.schema?.tag||$e(i.path)]},m=Fe(i.path,i.options.schema?.input,t.target,d);if(m)Xe(c,m);_e(c,i.path),We(c,i.path,i.options.schema||{},t.target,d),n[s]||={},n[s][a]=c}return{document:{openapi:t.target==="openapi-3.0"?"3.0.3":"3.1.0",info:{title:t.info?.title||"Vector API",version:t.info?.version||"1.0.0",...t.info?.description?{description:t.info.description}:{}},paths:n},warnings:d}}var V="/_vector/openapi/tailwindcdn.js",Q="/_vector/openapi/logo_dark.svg",Y="/_vector/openapi/logo_white.svg",Ie="/_vector/openapi/favicon/apple-touch-icon.png",we="/_vector/openapi/favicon/favicon-32x32.png",Le="/_vector/openapi/favicon/favicon-16x16.png",Ze="/_vector/openapi/favicon/favicon.ico",De="/_vector/openapi/favicon/site.webmanifest",qe="/_vector/openapi/favicon/android-chrome-192x192.png",et="/_vector/openapi/favicon/android-chrome-512x512.png",tt=["../openapi/assets/tailwindcdn.js","../src/openapi/assets/tailwindcdn.js","../../src/openapi/assets/tailwindcdn.js"],dt=["../openapi/assets/logo_dark.svg","../src/openapi/assets/logo_dark.svg","../../src/openapi/assets/logo_dark.svg"],nt=["../openapi/assets/logo_white.svg","../src/openapi/assets/logo_white.svg","../../src/openapi/assets/logo_white.svg"],rt=["src/openapi/assets/tailwindcdn.js","openapi/assets/tailwindcdn.js","dist/openapi/assets/tailwindcdn.js"],ot=["src/openapi/assets/logo_dark.svg","openapi/assets/logo_dark.svg","dist/openapi/assets/logo_dark.svg"],at=["src/openapi/assets/logo_white.svg","openapi/assets/logo_white.svg","dist/openapi/assets/logo_white.svg"],B=["../openapi/assets/favicon","../src/openapi/assets/favicon","../../src/openapi/assets/favicon"],I=["src/openapi/assets/favicon","openapi/assets/favicon","dist/openapi/assets/favicon"],it="/* OpenAPI docs runtime asset missing: tailwind disabled */";function h(e,t){return e.map((d)=>`${d}/${t}`)}function k(e,t){for(let n of e)try{let r=new URL(n,import.meta.url);if(ge(r))return Bun.file(r)}catch{}let d=process.cwd();for(let n of t){let r=Ke(d,n);if(ge(r))return Bun.file(r)}return null}var ke=k(tt,rt),Ee=k(dt,ot),ve=k(nt,at),st=k(h(B,"apple-touch-icon.png"),h(I,"apple-touch-icon.png")),lt=k(h(B,"favicon-32x32.png"),h(I,"favicon-32x32.png")),ct=k(h(B,"favicon-16x16.png"),h(I,"favicon-16x16.png")),bt=k(h(B,"favicon.ico"),h(I,"favicon.ico")),mt=k(h(B,"site.webmanifest"),h(I,"site.webmanifest")),pt=k(h(B,"android-chrome-192x192.png"),h(I,"android-chrome-192x192.png")),ut=k(h(B,"android-chrome-512x512.png"),h(I,"android-chrome-512x512.png")),Be=[{path:Ie,file:st,contentType:"image/png",filename:"apple-touch-icon.png"},{path:we,file:lt,contentType:"image/png",filename:"favicon-32x32.png"},{path:Le,file:ct,contentType:"image/png",filename:"favicon-16x16.png"},{path:Ze,file:bt,contentType:"image/x-icon",filename:"favicon.ico"},{path:De,file:mt,contentType:"application/manifest+json; charset=utf-8",filename:"site.webmanifest"},{path:qe,file:pt,contentType:"image/png",filename:"android-chrome-192x192.png"},{path:et,file:ut,contentType:"image/png",filename:"android-chrome-512x512.png"}],X="public, max-age=0, must-revalidate",A="public, max-age=31536000, immutable",W="no-store";function ft(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function ht(e){let t="^";for(let d of e){if(d==="*"){t+=".*";continue}t+=ft(d)}return t+="$",new RegExp(t)}function yt(e,t){if(!t.includes("*"))return e===t;return ht(t).test(e)}class K{server=null;router;config;openapiConfig;openapiDocCache=null;openapiDocsHtmlCache=null;openapiWarningsLogged=!1;openapiTailwindMissingLogged=!1;openapiLogoDarkMissingLogged=!1;openapiLogoWhiteMissingLogged=!1;corsHandler=null;corsHeadersEntries=null;constructor(e,t){if(this.router=e,this.config=t,this.openapiConfig=this.normalizeOpenAPIConfig(t.openapi,t.development),t.cors){let d=this.normalizeCorsOptions(t.cors),{preflight:n,corsify:r}=be(d);if(this.corsHandler={preflight:n,corsify:r},typeof d.origin==="string"&&(d.origin!=="*"||!d.credentials)){let i={"access-control-allow-origin":d.origin,"access-control-allow-methods":d.allowMethods,"access-control-allow-headers":d.allowHeaders,"access-control-expose-headers":d.exposeHeaders,"access-control-max-age":String(d.maxAge)};if(d.credentials)i["access-control-allow-credentials"]="true";this.corsHeadersEntries=Object.entries(i)}this.router.setCorsHeaders(this.corsHeadersEntries),this.router.setCorsHandler(this.corsHeadersEntries?null:this.corsHandler.corsify)}}normalizeOpenAPIConfig(e,t){let n=t!==!1&&!0;if(e===!1)return{enabled:!1,path:"/openapi.json",target:"openapi-3.0",docs:{enabled:!1,path:"/docs"}};if(e===!0)return{enabled:!0,path:"/openapi.json",target:"openapi-3.0",docs:{enabled:!1,path:"/docs"}};let r=e||{},o=r.docs,i=typeof o==="boolean"?{enabled:o,path:"/docs",exposePaths:void 0}:{enabled:o?.enabled===!0,path:o?.path||"/docs",exposePaths:Array.isArray(o?.exposePaths)?o.exposePaths.map((a)=>typeof a==="string"?a.trim():"").filter((a)=>a.length>0):void 0};return{enabled:r.enabled??n,path:r.path||"/openapi.json",target:r.target||"openapi-3.0",docs:i,info:r.info}}isDocsReservedPath(e){return e===this.openapiConfig.path||this.openapiConfig.docs.enabled&&e===this.openapiConfig.docs.path}shouldLogOpenAPIConversionWarnings(){if(this.config.development===!1)return!1;let d=process.env.LOG_LEVEL;return typeof d==="string"&&d.toLowerCase()==="debug"}getOpenAPIDocument(){if(this.openapiDocCache)return this.openapiDocCache;let e=this.router.getRouteDefinitions().filter((d)=>!this.isDocsReservedPath(d.path)),t=xe(e,{target:this.openapiConfig.target,info:this.openapiConfig.info});if(!this.openapiWarningsLogged&&t.warnings.length>0){if(this.shouldLogOpenAPIConversionWarnings())for(let d of t.warnings)console.warn(d);this.openapiWarningsLogged=!0}return this.openapiDocCache=t.document,this.openapiDocCache}getOpenAPIDocumentForDocs(){let e=this.openapiConfig.docs.exposePaths,t=this.getOpenAPIDocument();if(!Array.isArray(e)||e.length===0)return t;let d=t.paths&&typeof t.paths==="object"&&!Array.isArray(t.paths)?t.paths:{},n={};for(let[r,o]of Object.entries(d))if(e.some((i)=>yt(r,i)))n[r]=o;return{...t,paths:n}}getOpenAPIDocsHtmlCacheEntry(){if(this.openapiDocsHtmlCache)return this.openapiDocsHtmlCache;let e=me(this.getOpenAPIDocumentForDocs(),this.openapiConfig.path,V,Q,Y,Ie,we,Le,De),t=Bun.gzipSync(e),d=`"${Bun.hash(e).toString(16)}"`;return this.openapiDocsHtmlCache={html:e,gzip:t,etag:d},this.openapiDocsHtmlCache}requestAcceptsGzip(e){let t=e.headers.get("accept-encoding");return Boolean(t&&/\bgzip\b/i.test(t))}validateReservedOpenAPIPaths(){if(!this.openapiConfig.enabled)return;let e=new Set([this.openapiConfig.path]);if(this.openapiConfig.docs.enabled){e.add(this.openapiConfig.docs.path),e.add(V),e.add(Q),e.add(Y);for(let r of Be)e.add(r.path)}let t=this.router.getRouteDefinitions().filter((r)=>e.has(r.path)).map((r)=>`${r.method} ${r.path}`),d=Object.entries(this.router.getRouteTable()).filter(([r,o])=>e.has(r)&&o instanceof Response).map(([r])=>`STATIC ${r}`),n=[...t,...d];if(n.length>0)throw new Error(`OpenAPI reserved path conflict: ${n.join(", ")}. Change your route path(s) or reconfigure openapi.path/docs.path.`)}tryHandleOpenAPIRequest(e){if(!this.openapiConfig.enabled||e.method!=="GET")return null;let t=new URL(e.url).pathname;if(t===this.openapiConfig.path)return Response.json(this.getOpenAPIDocument());if(this.openapiConfig.docs.enabled&&t===this.openapiConfig.docs.path){let{html:d,gzip:n,etag:r}=this.getOpenAPIDocsHtmlCacheEntry();if(e.headers.get("if-none-match")===r)return new Response(null,{status:304,headers:{etag:r,"cache-control":X,vary:"accept-encoding"}});if(this.requestAcceptsGzip(e))return new Response(n,{status:200,headers:{"content-type":"text/html; charset=utf-8","content-encoding":"gzip",etag:r,"cache-control":X,vary:"accept-encoding"}});return new Response(d,{status:200,headers:{"content-type":"text/html; charset=utf-8",etag:r,"cache-control":X,vary:"accept-encoding"}})}if(this.openapiConfig.docs.enabled&&t===V){if(!ke){if(!this.openapiTailwindMissingLogged)this.openapiTailwindMissingLogged=!0,console.warn('[OpenAPI] Missing docs runtime asset "tailwindcdn.js". Serving inline fallback script instead.');return new Response(it,{status:200,headers:{"content-type":"application/javascript; charset=utf-8","cache-control":A}})}return new Response(ke,{status:200,headers:{"content-type":"application/javascript; charset=utf-8","cache-control":A}})}if(this.openapiConfig.docs.enabled&&t===Q){if(!Ee){if(!this.openapiLogoDarkMissingLogged)this.openapiLogoDarkMissingLogged=!0,console.warn('[OpenAPI] Missing docs runtime asset "logo_dark.svg".');return new Response("OpenAPI docs runtime asset missing: logo_dark.svg",{status:404,headers:{"content-type":"text/plain; charset=utf-8","cache-control":W}})}return new Response(Ee,{status:200,headers:{"content-type":"image/svg+xml; charset=utf-8","cache-control":A}})}if(this.openapiConfig.docs.enabled&&t===Y){if(!ve){if(!this.openapiLogoWhiteMissingLogged)this.openapiLogoWhiteMissingLogged=!0,console.warn('[OpenAPI] Missing docs runtime asset "logo_white.svg".');return new Response("OpenAPI docs runtime asset missing: logo_white.svg",{status:404,headers:{"content-type":"text/plain; charset=utf-8","cache-control":W}})}return new Response(ve,{status:200,headers:{"content-type":"image/svg+xml; charset=utf-8","cache-control":A}})}if(this.openapiConfig.docs.enabled){let d=Be.find((n)=>n.path===t);if(d){if(!d.file)return new Response(`OpenAPI docs runtime asset missing: ${d.filename}`,{status:404,headers:{"content-type":"text/plain; charset=utf-8","cache-control":W}});return new Response(d.file,{status:200,headers:{"content-type":d.contentType,"cache-control":A}})}}return null}normalizeCorsOptions(e){return{origin:e.origin||"*",credentials:e.credentials!==!1,allowHeaders:Array.isArray(e.allowHeaders)?e.allowHeaders.join(", "):e.allowHeaders||"Content-Type, Authorization",allowMethods:Array.isArray(e.allowMethods)?e.allowMethods.join(", "):e.allowMethods||"GET, POST, PUT, PATCH, DELETE, OPTIONS",exposeHeaders:Array.isArray(e.exposeHeaders)?e.exposeHeaders.join(", "):e.exposeHeaders||"Authorization",maxAge:e.maxAge||86400}}applyCors(e,t){if(this.corsHeadersEntries){for(let[d,n]of this.corsHeadersEntries)e.headers.set(d,n);return e}if(this.corsHandler&&t)return this.corsHandler.corsify(e,t);return e}async start(){let e=this.config.port??3000,t=this.config.hostname||"localhost";this.validateReservedOpenAPIPaths();let d=async(n)=>{try{if(this.corsHandler&&n.method==="OPTIONS")return this.corsHandler.preflight(n);let r=this.tryHandleOpenAPIRequest(n);if(r)return this.applyCors(r,n);return this.applyCors(j.NOT_FOUND.clone(),n)}catch(r){return console.error("Server error:",r),this.applyCors(new Response("Internal Server Error",{status:500}),n)}};try{if(this.server=Bun.serve({port:e,hostname:t,reusePort:this.config.reusePort!==!1,routes:this.router.getRouteTable(),fetch:d,idleTimeout:this.config.idleTimeout??60,error:(n,r)=>{return console.error("[ERROR] Server error:",n),this.applyCors(new Response("Internal Server Error",{status:500}),r)}}),!this.server||!this.server.port)throw new Error(`Failed to start server on ${t}:${e} - server object is invalid`);return this.server}catch(n){if(n.code==="EADDRINUSE"||n.message?.includes("address already in use"))n.message=`Port ${e} is already in use`,n.port=e;else if(n.code==="EACCES"||n.message?.includes("permission denied"))n.message=`Permission denied to bind to port ${e}`,n.port=e;else if(n.message?.includes("EADDRNOTAVAIL"))n.message=`Cannot bind to hostname ${t}`,n.hostname=t;throw n}}stop(){if(this.server)this.server.stop(),this.server=null,this.openapiDocCache=null,this.openapiDocsHtmlCache=null,this.openapiWarningsLogged=!1,console.log("Server stopped")}getServer(){return this.server}getPort(){return this.server?.port??this.config.port??3000}getHostname(){return this.server?.hostname||this.config.hostname||"localhost"}getUrl(){let e=this.getPort();return`http://${this.getHostname()}:${e}`}}class w{static instance;router;server=null;middlewareManager;authManager;cacheManager;config={};routeScanner=null;routeGenerator=null;_protectedHandler=null;_cacheHandler=null;shutdownPromise=null;constructor(){this.middlewareManager=new C,this.authManager=new R,this.cacheManager=new U,this.router=new N(this.middlewareManager,this.authManager,this.cacheManager)}static getInstance(){if(!w.instance)w.instance=new w;return w.instance}setProtectedHandler(e){if(this._protectedHandler=e,e){this.authManager.setProtectedHandler(e);return}this.authManager.clearProtectedHandler()}getProtectedHandler(){return this._protectedHandler}setCacheHandler(e){if(this._cacheHandler=e,e){this.cacheManager.setCacheHandler(e);return}this.cacheManager.clearCacheHandler()}getCacheHandler(){return this._cacheHandler}addRoute(e,t){this.router.route(e,t)}async startServer(e){this.config={...this.config,...e};let t={...this.config.defaults?.route};if(this.router.setRouteBooleanDefaults(t),this.router.setDevelopmentMode(this.config.development),this.middlewareManager.clear(),this.config.autoDiscover!==!1)this.router.clearRoutes();if(e?.before)this.middlewareManager.addBefore(...e.before);if(e?.finally)this.middlewareManager.addFinally(...e.finally);if(typeof this.config.startup==="function")await this.config.startup();if(this.config.autoDiscover!==!1)await this.discoverRoutes();return this.server=new K(this.router,this.config),await this.server.start()}async discoverRoutes(){let e=this.config.routesDir||"./routes",t=this.config.routeExcludePatterns;if(this.routeScanner=new M(e,t),!this.routeGenerator)this.routeGenerator=new $;try{let d=await this.routeScanner.scan();if(d.length>0){if(this.config.development)await this.routeGenerator.generate(d);for(let n of d)try{let o=await import(H(n.path)),i=n.name==="default"?o.default:o[n.name];if(i){if(this.isRouteDefinition(i))this.router.route(i.options,i.handler),this.logRouteLoaded(i.options);else if(this.isRouteEntry(i))this.router.addRoute(i),this.logRouteLoaded(i);else if(typeof i==="function")this.router.route(n.options,i),this.logRouteLoaded(n.options)}}catch(r){console.error(`Failed to load route ${n.name} from ${n.path}:`,r)}}}catch(d){if(d.code!=="ENOENT"&&d.code!=="ENOTDIR")console.error("Failed to discover routes:",d)}}async loadRoute(e){if(typeof e==="function"){let t=e();if(this.isRouteEntry(t))this.router.addRoute(t)}else if(e&&typeof e==="object"){for(let[,t]of Object.entries(e))if(typeof t==="function"){let d=t();if(this.isRouteEntry(d))this.router.addRoute(d)}}}isRouteEntry(e){if(!Array.isArray(e)||e.length<3)return!1;let[t,d,n,r]=e;return typeof t==="string"&&d instanceof RegExp&&Array.isArray(n)&&n.length>0&&n.every((o)=>typeof o==="function")&&(r===void 0||typeof r==="string")}isRouteDefinition(e){return e!==null&&typeof e==="object"&&"entry"in e&&"options"in e&&"handler"in e&&typeof e.handler==="function"}logRouteLoaded(e){}stop(){if(this.server)this.server.stop(),this.server=null}async shutdown(){if(this.shutdownPromise)return this.shutdownPromise;this.shutdownPromise=(async()=>{if(this.stop(),typeof this.config.shutdown==="function")await this.config.shutdown()})();try{await this.shutdownPromise}finally{this.shutdownPromise=null}}getServer(){return this.server}getRouter(){return this.router}getCacheManager(){return this.cacheManager}getAuthManager(){return this.authManager}static resetInstance(){w.instance=null}}var Z=w.getInstance;function xt(e,t){return{entry:{method:e.method.toUpperCase(),path:e.path},options:e,handler:t}}function gt(e){let t=e??null;try{return JSON.stringify(t)}catch(d){if(d instanceof TypeError&&/\bbigint\b/i.test(d.message))return JSON.stringify(t,(n,r)=>typeof r==="bigint"?r.toString():r);throw d}}function l(e,t,d){let n={error:!0,message:t,statusCode:e,timestamp:new Date().toISOString()};return D(e,n,d)}var v={badRequest:(e="Bad Request",t)=>l(E.BAD_REQUEST,e,t),unauthorized:(e="Unauthorized",t)=>l(E.UNAUTHORIZED,e,t),paymentRequired:(e="Payment Required",t)=>l(402,e,t),forbidden:(e="Forbidden",t)=>l(E.FORBIDDEN,e,t),notFound:(e="Not Found",t)=>l(E.NOT_FOUND,e,t),methodNotAllowed:(e="Method Not Allowed",t)=>l(405,e,t),notAcceptable:(e="Not Acceptable",t)=>l(406,e,t),requestTimeout:(e="Request Timeout",t)=>l(408,e,t),conflict:(e="Conflict",t)=>l(E.CONFLICT,e,t),gone:(e="Gone",t)=>l(410,e,t),lengthRequired:(e="Length Required",t)=>l(411,e,t),preconditionFailed:(e="Precondition Failed",t)=>l(412,e,t),payloadTooLarge:(e="Payload Too Large",t)=>l(413,e,t),uriTooLong:(e="URI Too Long",t)=>l(414,e,t),unsupportedMediaType:(e="Unsupported Media Type",t)=>l(415,e,t),rangeNotSatisfiable:(e="Range Not Satisfiable",t)=>l(416,e,t),expectationFailed:(e="Expectation Failed",t)=>l(417,e,t),imATeapot:(e="I'm a teapot",t)=>l(418,e,t),misdirectedRequest:(e="Misdirected Request",t)=>l(421,e,t),unprocessableEntity:(e="Unprocessable Entity",t)=>l(E.UNPROCESSABLE_ENTITY,e,t),locked:(e="Locked",t)=>l(423,e,t),failedDependency:(e="Failed Dependency",t)=>l(424,e,t),tooEarly:(e="Too Early",t)=>l(425,e,t),upgradeRequired:(e="Upgrade Required",t)=>l(426,e,t),preconditionRequired:(e="Precondition Required",t)=>l(428,e,t),tooManyRequests:(e="Too Many Requests",t)=>l(429,e,t),requestHeaderFieldsTooLarge:(e="Request Header Fields Too Large",t)=>l(431,e,t),unavailableForLegalReasons:(e="Unavailable For Legal Reasons",t)=>l(451,e,t),internalServerError:(e="Internal Server Error",t)=>l(E.INTERNAL_SERVER_ERROR,e,t),notImplemented:(e="Not Implemented",t)=>l(501,e,t),badGateway:(e="Bad Gateway",t)=>l(502,e,t),serviceUnavailable:(e="Service Unavailable",t)=>l(503,e,t),gatewayTimeout:(e="Gateway Timeout",t)=>l(504,e,t),httpVersionNotSupported:(e="HTTP Version Not Supported",t)=>l(505,e,t),variantAlsoNegotiates:(e="Variant Also Negotiates",t)=>l(506,e,t),insufficientStorage:(e="Insufficient Storage",t)=>l(507,e,t),loopDetected:(e="Loop Detected",t)=>l(508,e,t),notExtended:(e="Not Extended",t)=>l(510,e,t),networkAuthenticationRequired:(e="Network Authentication Required",t)=>l(511,e,t),invalidArgument:(e="Invalid Argument",t)=>l(E.UNPROCESSABLE_ENTITY,e,t),rateLimitExceeded:(e="Rate Limit Exceeded",t)=>l(429,e,t),maintenance:(e="Service Under Maintenance",t)=>l(503,e,t),custom:(e,t,d)=>l(e,t,d)};function D(e,t,d=T.JSON){let n=d===T.JSON?gt(t):t;return new Response(n,{status:e,headers:{"content-type":d}})}import{existsSync as kt}from"fs";import{resolve as Et,isAbsolute as vt}from"path";class q{configPath;config=null;configSource="default";constructor(e){let t=e||"vector.config.ts";this.configPath=vt(t)?t:Et(process.cwd(),t)}async load(){if(kt(this.configPath))try{let t=await import(H(this.configPath));this.config=t.default||t,this.configSource="user"}catch(e){let t=e instanceof Error?e.message:String(e);console.error(`[vector] Failed to load config from ${this.configPath}: ${t}`),console.error("[vector] Server is using default configuration. Fix your config file and restart."),this.config={}}else this.config={};return await this.buildLegacyConfig()}getConfigSource(){return this.configSource}async buildLegacyConfig(){let e={};if(this.config)e.port=this.config.port,e.hostname=this.config.hostname,e.reusePort=this.config.reusePort,e.development=this.config.development,e.routesDir=this.config.routesDir||"./routes",e.routeExcludePatterns=this.config.routeExcludePatterns,e.idleTimeout=this.config.idleTimeout,e.defaults=this.config.defaults,e.openapi=this.config.openapi,e.startup=this.config.startup,e.shutdown=this.config.shutdown;if(e.autoDiscover=!0,this.config?.cors)if(typeof this.config.cors==="boolean")e.cors=this.config.cors?{origin:"*",credentials:!0,allowHeaders:"Content-Type, Authorization",allowMethods:"GET, POST, PUT, PATCH, DELETE, OPTIONS",exposeHeaders:"Authorization",maxAge:86400}:void 0;else e.cors=this.config.cors;if(this.config?.before)e.before=this.config.before;if(this.config?.after)e.finally=this.config.after;return e}async loadAuthHandler(){return this.config?.auth||null}async loadCacheHandler(){return this.config?.cache||null}getConfig(){return this.config}}async function Bt(e={}){let t=new q(e.configPath),d=await t.load(),n=t.getConfigSource(),r={...d};if(e.mutateConfig)r=await e.mutateConfig(r,{configSource:n});if(e.config)r={...r,...e.config};if(e.autoDiscover!==void 0)r.autoDiscover=e.autoDiscover;let o=Z(),i=e.protectedHandler!==void 0?e.protectedHandler:await t.loadAuthHandler(),a=e.cacheHandler!==void 0?e.cacheHandler:await t.loadCacheHandler();o.setProtectedHandler(i??null),o.setCacheHandler(a??null);let s=await o.startServer(r),c={...r,port:s.port??r.port??L.PORT,hostname:s.hostname||r.hostname||L.HOSTNAME,reusePort:r.reusePort!==!1,idleTimeout:r.idleTimeout??60};return{server:s,config:c,stop:()=>o.stop(),shutdown:()=>o.shutdown()}}export{Bt as startVector,xt as route,D as createResponse,v as APIError};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/openapi/generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,KAAK,EAAE,kBAAkB,EAAoD,MAAM,UAAU,CAAC;AAIrG,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,kBAAkB,CAAC;CAC3B;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;
|
|
1
|
+
{"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/openapi/generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,KAAK,EAAE,kBAAkB,EAAoD,MAAM,UAAU,CAAC;AAIrG,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,kBAAkB,CAAC;CAC3B;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAunBD,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,yBAAyB,EAAE,EACnC,OAAO,EAAE,wBAAwB,GAChC,uBAAuB,CA8CzB"}
|
|
@@ -94,12 +94,17 @@ function getResponseDescription(status) {
|
|
|
94
94
|
}
|
|
95
95
|
function convertInputSchema(routePath, inputSchema, target, warnings) {
|
|
96
96
|
if (!isJSONSchemaCapable(inputSchema)) {
|
|
97
|
-
|
|
97
|
+
const fallback = buildFallbackJSONSchema(inputSchema);
|
|
98
|
+
return isEmptyObjectSchema(fallback) ? null : fallback;
|
|
98
99
|
}
|
|
99
100
|
try {
|
|
100
101
|
return inputSchema['~standard'].jsonSchema.input({ target });
|
|
101
102
|
}
|
|
102
103
|
catch (error) {
|
|
104
|
+
const alternate = tryAlternateTargetConversion(inputSchema, 'input', target, error, routePath, undefined, warnings);
|
|
105
|
+
if (alternate) {
|
|
106
|
+
return alternate;
|
|
107
|
+
}
|
|
103
108
|
warnings.push(`[OpenAPI] Failed input schema conversion for ${routePath}: ${error instanceof Error ? error.message : String(error)}. Falling back to a permissive JSON Schema.`);
|
|
104
109
|
const fallback = buildFallbackJSONSchema(inputSchema);
|
|
105
110
|
return isEmptyObjectSchema(fallback) ? null : fallback;
|
|
@@ -107,12 +112,17 @@ function convertInputSchema(routePath, inputSchema, target, warnings) {
|
|
|
107
112
|
}
|
|
108
113
|
function convertOutputSchema(routePath, statusCode, outputSchema, target, warnings) {
|
|
109
114
|
if (!isJSONSchemaCapable(outputSchema)) {
|
|
110
|
-
|
|
115
|
+
const fallback = buildFallbackJSONSchema(outputSchema);
|
|
116
|
+
return isEmptyObjectSchema(fallback) ? null : fallback;
|
|
111
117
|
}
|
|
112
118
|
try {
|
|
113
119
|
return outputSchema['~standard'].jsonSchema.output({ target });
|
|
114
120
|
}
|
|
115
121
|
catch (error) {
|
|
122
|
+
const alternate = tryAlternateTargetConversion(outputSchema, 'output', target, error, routePath, statusCode, warnings);
|
|
123
|
+
if (alternate) {
|
|
124
|
+
return alternate;
|
|
125
|
+
}
|
|
116
126
|
warnings.push(`[OpenAPI] Failed output schema conversion for ${routePath} (${statusCode}): ${error instanceof Error ? error.message : String(error)}. Falling back to a permissive JSON Schema.`);
|
|
117
127
|
return buildFallbackJSONSchema(outputSchema);
|
|
118
128
|
}
|
|
@@ -123,6 +133,29 @@ function isRecord(value) {
|
|
|
123
133
|
function isEmptyObjectSchema(value) {
|
|
124
134
|
return isRecord(value) && Object.keys(value).length === 0;
|
|
125
135
|
}
|
|
136
|
+
function tryAlternateTargetConversion(schema, kind, target, originalError, routePath, statusCode, warnings) {
|
|
137
|
+
if (!isJSONSchemaCapable(schema)) {
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
const message = originalError instanceof Error ? originalError.message : String(originalError);
|
|
141
|
+
const unsupportedOpenAPITarget = target === 'openapi-3.0' &&
|
|
142
|
+
message.includes("target 'openapi-3.0' is not supported") &&
|
|
143
|
+
message.includes('draft-2020-12') &&
|
|
144
|
+
message.includes('draft-07');
|
|
145
|
+
if (!unsupportedOpenAPITarget) {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
try {
|
|
149
|
+
const converted = schema['~standard'].jsonSchema[kind]({ target: 'draft-07' });
|
|
150
|
+
warnings.push(kind === 'input'
|
|
151
|
+
? `[OpenAPI] ${routePath} converter does not support openapi-3.0 target; using draft-07 conversion output.`
|
|
152
|
+
: `[OpenAPI] ${routePath} (${statusCode}) converter does not support openapi-3.0 target; using draft-07 conversion output.`);
|
|
153
|
+
return converted;
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
126
159
|
// Best-effort extraction of internal schema definition metadata from common
|
|
127
160
|
// standards-compatible validators. If unavailable, callers should fall back to {}.
|
|
128
161
|
function getValidatorSchemaDef(schema) {
|
|
@@ -134,6 +167,9 @@ function getValidatorSchemaDef(schema) {
|
|
|
134
167
|
if (isRecord(value._zod) && isRecord(value._zod.def)) {
|
|
135
168
|
return value._zod.def;
|
|
136
169
|
}
|
|
170
|
+
if (value.kind === 'schema' && typeof value.type === 'string') {
|
|
171
|
+
return value;
|
|
172
|
+
}
|
|
137
173
|
return null;
|
|
138
174
|
}
|
|
139
175
|
function getSchemaKind(def) {
|
|
@@ -148,7 +184,7 @@ function getSchemaKind(def) {
|
|
|
148
184
|
return null;
|
|
149
185
|
}
|
|
150
186
|
function pickSchemaChild(def) {
|
|
151
|
-
const candidates = ['innerType', 'schema', 'type', 'out', 'in', 'left', 'right'];
|
|
187
|
+
const candidates = ['innerType', 'schema', 'type', 'out', 'in', 'left', 'right', 'wrapped', 'element'];
|
|
152
188
|
for (const key of candidates) {
|
|
153
189
|
if (key in def)
|
|
154
190
|
return def[key];
|
|
@@ -189,6 +225,10 @@ function unwrapOptionalForRequired(schema) {
|
|
|
189
225
|
return { schema: current, optional };
|
|
190
226
|
}
|
|
191
227
|
function getObjectShape(def) {
|
|
228
|
+
const entries = def.entries;
|
|
229
|
+
if (isRecord(entries)) {
|
|
230
|
+
return entries;
|
|
231
|
+
}
|
|
192
232
|
const rawShape = def.shape;
|
|
193
233
|
if (typeof rawShape === 'function') {
|
|
194
234
|
try {
|
|
@@ -201,6 +241,31 @@ function getObjectShape(def) {
|
|
|
201
241
|
}
|
|
202
242
|
return isRecord(rawShape) ? rawShape : {};
|
|
203
243
|
}
|
|
244
|
+
function extractEnumValues(def) {
|
|
245
|
+
const values = def.values;
|
|
246
|
+
if (Array.isArray(values))
|
|
247
|
+
return values;
|
|
248
|
+
if (values && typeof values === 'object')
|
|
249
|
+
return Object.values(values);
|
|
250
|
+
const entries = def.entries;
|
|
251
|
+
if (entries && typeof entries === 'object')
|
|
252
|
+
return Object.values(entries);
|
|
253
|
+
const enumObject = def.enum;
|
|
254
|
+
if (enumObject && typeof enumObject === 'object')
|
|
255
|
+
return Object.values(enumObject);
|
|
256
|
+
const options = def.options;
|
|
257
|
+
if (Array.isArray(options)) {
|
|
258
|
+
return options
|
|
259
|
+
.map((item) => {
|
|
260
|
+
if (item && typeof item === 'object' && 'unit' in item) {
|
|
261
|
+
return item.unit;
|
|
262
|
+
}
|
|
263
|
+
return item;
|
|
264
|
+
})
|
|
265
|
+
.filter((item) => item !== undefined);
|
|
266
|
+
}
|
|
267
|
+
return [];
|
|
268
|
+
}
|
|
204
269
|
function mapPrimitiveKind(kind) {
|
|
205
270
|
const lower = kind.toLowerCase();
|
|
206
271
|
if (lower.includes('string'))
|
|
@@ -211,7 +276,7 @@ function mapPrimitiveKind(kind) {
|
|
|
211
276
|
return { type: 'boolean' };
|
|
212
277
|
if (lower.includes('bigint'))
|
|
213
278
|
return { type: 'string' };
|
|
214
|
-
if (lower.includes('
|
|
279
|
+
if (lower === 'null' || lower.includes('zodnull'))
|
|
215
280
|
return { type: 'null' };
|
|
216
281
|
if (lower.includes('any') || lower.includes('unknown') || lower.includes('never'))
|
|
217
282
|
return {};
|
|
@@ -301,11 +366,29 @@ function buildIntrospectedFallbackJSONSchema(schema, seen = new WeakSet()) {
|
|
|
301
366
|
};
|
|
302
367
|
}
|
|
303
368
|
if (lower.includes('enum')) {
|
|
304
|
-
const
|
|
305
|
-
if (
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
369
|
+
const enumValues = extractEnumValues(def);
|
|
370
|
+
if (enumValues.length > 0) {
|
|
371
|
+
const allString = enumValues.every((v) => typeof v === 'string');
|
|
372
|
+
const allNumber = enumValues.every((v) => typeof v === 'number');
|
|
373
|
+
const allBoolean = enumValues.every((v) => typeof v === 'boolean');
|
|
374
|
+
if (allString)
|
|
375
|
+
return { type: 'string', enum: enumValues };
|
|
376
|
+
if (allNumber)
|
|
377
|
+
return { type: 'number', enum: enumValues };
|
|
378
|
+
if (allBoolean)
|
|
379
|
+
return { type: 'boolean', enum: enumValues };
|
|
380
|
+
return { enum: enumValues };
|
|
381
|
+
}
|
|
382
|
+
return {};
|
|
383
|
+
}
|
|
384
|
+
if (lower.includes('picklist')) {
|
|
385
|
+
const enumValues = extractEnumValues(def);
|
|
386
|
+
if (enumValues.length > 0) {
|
|
387
|
+
const allString = enumValues.every((v) => typeof v === 'string');
|
|
388
|
+
if (allString)
|
|
389
|
+
return { type: 'string', enum: enumValues };
|
|
390
|
+
return { enum: enumValues };
|
|
391
|
+
}
|
|
309
392
|
return {};
|
|
310
393
|
}
|
|
311
394
|
if (lower.includes('literal')) {
|