vector-framework 1.2.0 → 1.2.1

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.
Files changed (75) hide show
  1. package/README.md +19 -0
  2. package/dist/auth/protected.d.ts +1 -0
  3. package/dist/auth/protected.d.ts.map +1 -1
  4. package/dist/auth/protected.js +3 -0
  5. package/dist/auth/protected.js.map +1 -1
  6. package/dist/cache/manager.d.ts +1 -0
  7. package/dist/cache/manager.d.ts.map +1 -1
  8. package/dist/cache/manager.js +3 -0
  9. package/dist/cache/manager.js.map +1 -1
  10. package/dist/cli/graceful-shutdown.d.ts +15 -0
  11. package/dist/cli/graceful-shutdown.d.ts.map +1 -0
  12. package/dist/cli/graceful-shutdown.js +42 -0
  13. package/dist/cli/graceful-shutdown.js.map +1 -0
  14. package/dist/cli/index.js +37 -43
  15. package/dist/cli/index.js.map +1 -1
  16. package/dist/cli.js +877 -218
  17. package/dist/core/config-loader.d.ts.map +1 -1
  18. package/dist/core/config-loader.js +5 -2
  19. package/dist/core/config-loader.js.map +1 -1
  20. package/dist/core/server.d.ts +3 -0
  21. package/dist/core/server.d.ts.map +1 -1
  22. package/dist/core/server.js +227 -7
  23. package/dist/core/server.js.map +1 -1
  24. package/dist/core/vector.d.ts +4 -2
  25. package/dist/core/vector.d.ts.map +1 -1
  26. package/dist/core/vector.js +32 -2
  27. package/dist/core/vector.js.map +1 -1
  28. package/dist/index.d.ts +2 -0
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +147 -41
  31. package/dist/index.js.map +1 -1
  32. package/dist/index.mjs +147 -41
  33. package/dist/openapi/docs-ui.d.ts +1 -1
  34. package/dist/openapi/docs-ui.d.ts.map +1 -1
  35. package/dist/openapi/docs-ui.js +147 -35
  36. package/dist/openapi/docs-ui.js.map +1 -1
  37. package/dist/openapi/generator.d.ts.map +1 -1
  38. package/dist/openapi/generator.js +233 -4
  39. package/dist/openapi/generator.js.map +1 -1
  40. package/dist/start-vector.d.ts +3 -0
  41. package/dist/start-vector.d.ts.map +1 -0
  42. package/dist/start-vector.js +38 -0
  43. package/dist/start-vector.js.map +1 -0
  44. package/dist/types/index.d.ts +25 -0
  45. package/dist/types/index.d.ts.map +1 -1
  46. package/dist/utils/logger.js +1 -1
  47. package/dist/utils/validation.d.ts.map +1 -1
  48. package/dist/utils/validation.js +2 -0
  49. package/dist/utils/validation.js.map +1 -1
  50. package/package.json +3 -1
  51. package/src/auth/protected.ts +4 -0
  52. package/src/cache/manager.ts +4 -0
  53. package/src/cli/graceful-shutdown.ts +60 -0
  54. package/src/cli/index.ts +42 -49
  55. package/src/core/config-loader.ts +5 -2
  56. package/src/core/server.ts +289 -7
  57. package/src/core/vector.ts +38 -4
  58. package/src/index.ts +4 -3
  59. package/src/openapi/assets/favicon/android-chrome-192x192.png +0 -0
  60. package/src/openapi/assets/favicon/android-chrome-512x512.png +0 -0
  61. package/src/openapi/assets/favicon/apple-touch-icon.png +0 -0
  62. package/src/openapi/assets/favicon/favicon-16x16.png +0 -0
  63. package/src/openapi/assets/favicon/favicon-32x32.png +0 -0
  64. package/src/openapi/assets/favicon/favicon.ico +0 -0
  65. package/src/openapi/assets/favicon/site.webmanifest +11 -0
  66. package/src/openapi/assets/logo.svg +12 -0
  67. package/src/openapi/assets/logo_dark.svg +6 -0
  68. package/src/openapi/assets/logo_icon.png +0 -0
  69. package/src/openapi/assets/logo_white.svg +6 -0
  70. package/src/openapi/docs-ui.ts +153 -35
  71. package/src/openapi/generator.ts +231 -4
  72. package/src/start-vector.ts +50 -0
  73. package/src/types/index.ts +34 -0
  74. package/src/utils/logger.ts +1 -1
  75. package/src/utils/validation.ts +2 -0
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- var g={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},S={PORT:3000,HOSTNAME:"localhost",ROUTES_DIR:"./routes",CACHE_TTL:0,CORS_MAX_AGE:86400},j={JSON:"application/json",TEXT:"text/plain",HTML:"text/html",FORM_URLENCODED:"application/x-www-form-urlencoded",MULTIPART:"multipart/form-data"};var L={NOT_FOUND:new Response(JSON.stringify({error:!0,message:"Not Found",statusCode:404}),{status:404,headers:{"content-type":"application/json"}})};class M{protectedHandler=null;setProtectedHandler(e){this.protectedHandler=e}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 P{cacheHandler=null;memoryCache=new Map;cleanupInterval=null;inflight=new Map;setCacheHandler(e){this.cacheHandler=e}async get(e,t,n=S.CACHE_TTL){if(n<=0)return t();if(this.cacheHandler)return this.cacheHandler(e,t,n);return this.getFromMemoryCache(e,t,n)}async getFromMemoryCache(e,t,n){let d=Date.now(),r=this.memoryCache.get(e);if(this.isCacheValid(r,d))return r.value;if(this.inflight.has(e))return await this.inflight.get(e);let a=(async()=>{let o=await t();return this.setInMemoryCache(e,o,n),o})();this.inflight.set(e,a);try{return await a}finally{this.inflight.delete(e)}}isCacheValid(e,t){return e!==void 0&&e.expires>t}setInMemoryCache(e,t,n){let d=Date.now()+n*1000;this.memoryCache.set(e,{value:t,expires:d}),this.scheduleCleanup()}scheduleCleanup(){if(this.cleanupInterval)return;this.cleanupInterval=setInterval(()=>{this.cleanupExpired()},60000)}cleanupExpired(){let e=Date.now();for(let[t,n]of this.memoryCache.entries())if(n.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,n=S.CACHE_TTL){if(n<=0)return;if(this.cacheHandler){await this.cacheHandler(e,async()=>t,n);return}this.setInMemoryCache(e,t,n)}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 n=e._parsedUrl??new URL(e.url),d=t?.authUser?.id!=null?String(t.authUser.id):"anonymous";return`${e.method}:${n.pathname}:${n.search}:${d}`}}var{promises:V}=(()=>({}));function y(e){if(typeof e!=="string")throw new TypeError("Path must be a string. Received "+JSON.stringify(e))}function z(e,t){var n="",d=0,r=-1,a=0,o;for(var l=0;l<=e.length;++l){if(l<e.length)o=e.charCodeAt(l);else if(o===47)break;else o=47;if(o===47){if(r===l-1||a===1);else if(r!==l-1&&a===2){if(n.length<2||d!==2||n.charCodeAt(n.length-1)!==46||n.charCodeAt(n.length-2)!==46){if(n.length>2){var i=n.lastIndexOf("/");if(i!==n.length-1){if(i===-1)n="",d=0;else n=n.slice(0,i),d=n.length-1-n.lastIndexOf("/");r=l,a=0;continue}}else if(n.length===2||n.length===1){n="",d=0,r=l,a=0;continue}}if(t){if(n.length>0)n+="/..";else n="..";d=2}}else{if(n.length>0)n+="/"+e.slice(r+1,l);else n=e.slice(r+1,l);d=l-r-1}r=l,a=0}else if(o===46&&a!==-1)++a;else a=-1}return n}function se(e,t){var n=t.dir||t.root,d=t.base||(t.name||"")+(t.ext||"");if(!n)return d;if(n===t.root)return n+d;return n+e+d}function I(){var e="",t=!1,n;for(var d=arguments.length-1;d>=-1&&!t;d--){var r;if(d>=0)r=arguments[d];else{if(n===void 0)n=process.cwd();r=n}if(y(r),r.length===0)continue;e=r+"/"+e,t=r.charCodeAt(0)===47}if(e=z(e,!t),t)if(e.length>0)return"/"+e;else return"/";else if(e.length>0)return e;else return"."}function $(e){if(y(e),e.length===0)return".";var t=e.charCodeAt(0)===47,n=e.charCodeAt(e.length-1)===47;if(e=z(e,!t),e.length===0&&!t)e=".";if(e.length>0&&n)e+="/";if(t)return"/"+e;return e}function ce(e){return y(e),e.length>0&&e.charCodeAt(0)===47}function B(){if(arguments.length===0)return".";var e;for(var t=0;t<arguments.length;++t){var n=arguments[t];if(y(n),n.length>0)if(e===void 0)e=n;else e+="/"+n}if(e===void 0)return".";return $(e)}function k(e,t){if(y(e),y(t),e===t)return"";if(e=I(e),t=I(t),e===t)return"";var n=1;for(;n<e.length;++n)if(e.charCodeAt(n)!==47)break;var d=e.length,r=d-n,a=1;for(;a<t.length;++a)if(t.charCodeAt(a)!==47)break;var o=t.length,l=o-a,i=r<l?r:l,b=-1,s=0;for(;s<=i;++s){if(s===i){if(l>i){if(t.charCodeAt(a+s)===47)return t.slice(a+s+1);else if(s===0)return t.slice(a+s)}else if(r>i){if(e.charCodeAt(n+s)===47)b=s;else if(s===0)b=0}break}var u=e.charCodeAt(n+s),m=t.charCodeAt(a+s);if(u!==m)break;else if(u===47)b=s}var h="";for(s=n+b+1;s<=d;++s)if(s===d||e.charCodeAt(s)===47)if(h.length===0)h+="..";else h+="/..";if(h.length>0)return h+t.slice(a+b);else{if(a+=b,t.charCodeAt(a)===47)++a;return t.slice(a)}}function be(e){return e}function C(e){if(y(e),e.length===0)return".";var t=e.charCodeAt(0),n=t===47,d=-1,r=!0;for(var a=e.length-1;a>=1;--a)if(t=e.charCodeAt(a),t===47){if(!r){d=a;break}}else r=!1;if(d===-1)return n?"/":".";if(n&&d===1)return"//";return e.slice(0,d)}function ue(e,t){if(t!==void 0&&typeof t!=="string")throw new TypeError('"ext" argument must be a string');y(e);var n=0,d=-1,r=!0,a;if(t!==void 0&&t.length>0&&t.length<=e.length){if(t.length===e.length&&t===e)return"";var o=t.length-1,l=-1;for(a=e.length-1;a>=0;--a){var i=e.charCodeAt(a);if(i===47){if(!r){n=a+1;break}}else{if(l===-1)r=!1,l=a+1;if(o>=0)if(i===t.charCodeAt(o)){if(--o===-1)d=a}else o=-1,d=l}}if(n===d)d=l;else if(d===-1)d=e.length;return e.slice(n,d)}else{for(a=e.length-1;a>=0;--a)if(e.charCodeAt(a)===47){if(!r){n=a+1;break}}else if(d===-1)r=!1,d=a+1;if(d===-1)return"";return e.slice(n,d)}}function me(e){y(e);var t=-1,n=0,d=-1,r=!0,a=0;for(var o=e.length-1;o>=0;--o){var l=e.charCodeAt(o);if(l===47){if(!r){n=o+1;break}continue}if(d===-1)r=!1,d=o+1;if(l===46){if(t===-1)t=o;else if(a!==1)a=1}else if(t!==-1)a=-1}if(t===-1||d===-1||a===0||a===1&&t===d-1&&t===n+1)return"";return e.slice(t,d)}function fe(e){if(e===null||typeof e!=="object")throw new TypeError('The "pathObject" argument must be of type Object. Received type '+typeof e);return se("/",e)}function pe(e){y(e);var t={root:"",dir:"",base:"",ext:"",name:""};if(e.length===0)return t;var n=e.charCodeAt(0),d=n===47,r;if(d)t.root="/",r=1;else r=0;var a=-1,o=0,l=-1,i=!0,b=e.length-1,s=0;for(;b>=r;--b){if(n=e.charCodeAt(b),n===47){if(!i){o=b+1;break}continue}if(l===-1)i=!1,l=b+1;if(n===46){if(a===-1)a=b;else if(s!==1)s=1}else if(a!==-1)s=-1}if(a===-1||l===-1||s===0||s===1&&a===l-1&&a===o+1){if(l!==-1)if(o===0&&d)t.base=t.name=e.slice(1,l);else t.base=t.name=e.slice(o,l)}else{if(o===0&&d)t.name=e.slice(1,a),t.base=e.slice(1,l);else t.name=e.slice(o,a),t.base=e.slice(o,l);t.ext=e.slice(a,l)}if(o>0)t.dir=e.slice(0,o-1);else if(d)t.dir="/";return t}var O="/",he=":",Fe=((e)=>(e.posix=e,e))({resolve:I,normalize:$,isAbsolute:ce,join:B,relative:k,_makeLong:be,dirname:C,basename:ue,extname:me,format:fe,parse:pe,sep:O,delimiter:he,win32:null,posix:null});class _{outputPath;constructor(e="./.vector/routes.generated.ts"){this.outputPath=e}async generate(e){let t=C(this.outputPath);await V.mkdir(t,{recursive:!0});let n=[],d=new Map;for(let l of e){if(!d.has(l.path))d.set(l.path,[]);d.get(l.path).push(l)}let r=0,a=[];for(let[l,i]of d){let b=k(C(this.outputPath),l).replace(/\\/g,"/").replace(/\.(ts|js)$/,""),s=`route_${r++}`,u=i.filter((m)=>m.name!=="default").map((m)=>m.name);if(i.some((m)=>m.name==="default"))if(u.length>0)n.push(`import ${s}, { ${u.join(", ")} } from '${b}';`);else n.push(`import ${s} from '${b}';`);else if(u.length>0)n.push(`import { ${u.join(", ")} } from '${b}';`);for(let m of i){let h=m.name==="default"?s:m.name;a.push(` ${h},`)}}let o=`// This file is auto-generated. Do not edit manually.
1
+ 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},C={PORT:3000,HOSTNAME:"localhost",ROUTES_DIR:"./routes",CACHE_TTL:0,CORS_MAX_AGE:86400},_={JSON:"application/json",TEXT:"text/plain",HTML:"text/html",FORM_URLENCODED:"application/x-www-form-urlencoded",MULTIPART:"multipart/form-data"};var H={NOT_FOUND:new Response(JSON.stringify({error:!0,message:"Not Found",statusCode:404}),{status:404,headers:{"content-type":"application/json"}})};class ${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 J{cacheHandler=null;memoryCache=new Map;cleanupInterval=null;inflight=new Map;setCacheHandler(e){this.cacheHandler=e}clearCacheHandler(){this.cacheHandler=null}async get(e,t,n=C.CACHE_TTL){if(n<=0)return t();if(this.cacheHandler)return this.cacheHandler(e,t,n);return this.getFromMemoryCache(e,t,n)}async getFromMemoryCache(e,t,n){let d=Date.now(),r=this.memoryCache.get(e);if(this.isCacheValid(r,d))return r.value;if(this.inflight.has(e))return await this.inflight.get(e);let a=(async()=>{let i=await t();return this.setInMemoryCache(e,i,n),i})();this.inflight.set(e,a);try{return await a}finally{this.inflight.delete(e)}}isCacheValid(e,t){return e!==void 0&&e.expires>t}setInMemoryCache(e,t,n){let d=Date.now()+n*1000;this.memoryCache.set(e,{value:t,expires:d}),this.scheduleCleanup()}scheduleCleanup(){if(this.cleanupInterval)return;this.cleanupInterval=setInterval(()=>{this.cleanupExpired()},60000)}cleanupExpired(){let e=Date.now();for(let[t,n]of this.memoryCache.entries())if(n.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,n=C.CACHE_TTL){if(n<=0)return;if(this.cacheHandler){await this.cacheHandler(e,async()=>t,n);return}this.setInMemoryCache(e,t,n)}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 n=e._parsedUrl??new URL(e.url),d=t?.authUser?.id!=null?String(t.authUser.id):"anonymous";return`${e.method}:${n.pathname}:${n.search}:${d}`}}var{promises:oe}=(()=>({}));function v(e){if(typeof e!=="string")throw new TypeError("Path must be a string. Received "+JSON.stringify(e))}function re(e,t){var n="",d=0,r=-1,a=0,i;for(var o=0;o<=e.length;++o){if(o<e.length)i=e.charCodeAt(o);else if(i===47)break;else i=47;if(i===47){if(r===o-1||a===1);else if(r!==o-1&&a===2){if(n.length<2||d!==2||n.charCodeAt(n.length-1)!==46||n.charCodeAt(n.length-2)!==46){if(n.length>2){var s=n.lastIndexOf("/");if(s!==n.length-1){if(s===-1)n="",d=0;else n=n.slice(0,s),d=n.length-1-n.lastIndexOf("/");r=o,a=0;continue}}else if(n.length===2||n.length===1){n="",d=0,r=o,a=0;continue}}if(t){if(n.length>0)n+="/..";else n="..";d=2}}else{if(n.length>0)n+="/"+e.slice(r+1,o);else n=e.slice(r+1,o);d=o-r-1}r=o,a=0}else if(i===46&&a!==-1)++a;else a=-1}return n}function Oe(e,t){var n=t.dir||t.root,d=t.base||(t.name||"")+(t.ext||"");if(!n)return d;if(n===t.root)return n+d;return n+e+d}function B(){var e="",t=!1,n;for(var d=arguments.length-1;d>=-1&&!t;d--){var r;if(d>=0)r=arguments[d];else{if(n===void 0)n=process.cwd();r=n}if(v(r),r.length===0)continue;e=r+"/"+e,t=r.charCodeAt(0)===47}if(e=re(e,!t),t)if(e.length>0)return"/"+e;else return"/";else if(e.length>0)return e;else return"."}function ae(e){if(v(e),e.length===0)return".";var t=e.charCodeAt(0)===47,n=e.charCodeAt(e.length-1)===47;if(e=re(e,!t),e.length===0&&!t)e=".";if(e.length>0&&n)e+="/";if(t)return"/"+e;return e}function V(e){return v(e),e.length>0&&e.charCodeAt(0)===47}function j(){if(arguments.length===0)return".";var e;for(var t=0;t<arguments.length;++t){var n=arguments[t];if(v(n),n.length>0)if(e===void 0)e=n;else e+="/"+n}if(e===void 0)return".";return ae(e)}function D(e,t){if(v(e),v(t),e===t)return"";if(e=B(e),t=B(t),e===t)return"";var n=1;for(;n<e.length;++n)if(e.charCodeAt(n)!==47)break;var d=e.length,r=d-n,a=1;for(;a<t.length;++a)if(t.charCodeAt(a)!==47)break;var i=t.length,o=i-a,s=r<o?r:o,c=-1,l=0;for(;l<=s;++l){if(l===s){if(o>s){if(t.charCodeAt(a+l)===47)return t.slice(a+l+1);else if(l===0)return t.slice(a+l)}else if(r>s){if(e.charCodeAt(n+l)===47)c=l;else if(l===0)c=0}break}var u=e.charCodeAt(n+l),m=t.charCodeAt(a+l);if(u!==m)break;else if(u===47)c=l}var h="";for(l=n+c+1;l<=d;++l)if(l===d||e.charCodeAt(l)===47)if(h.length===0)h+="..";else h+="/..";if(h.length>0)return h+t.slice(a+c);else{if(a+=c,t.charCodeAt(a)===47)++a;return t.slice(a)}}function He(e){return e}function T(e){if(v(e),e.length===0)return".";var t=e.charCodeAt(0),n=t===47,d=-1,r=!0;for(var a=e.length-1;a>=1;--a)if(t=e.charCodeAt(a),t===47){if(!r){d=a;break}}else r=!1;if(d===-1)return n?"/":".";if(n&&d===1)return"//";return e.slice(0,d)}function Te(e,t){if(t!==void 0&&typeof t!=="string")throw new TypeError('"ext" argument must be a string');v(e);var n=0,d=-1,r=!0,a;if(t!==void 0&&t.length>0&&t.length<=e.length){if(t.length===e.length&&t===e)return"";var i=t.length-1,o=-1;for(a=e.length-1;a>=0;--a){var s=e.charCodeAt(a);if(s===47){if(!r){n=a+1;break}}else{if(o===-1)r=!1,o=a+1;if(i>=0)if(s===t.charCodeAt(i)){if(--i===-1)d=a}else i=-1,d=o}}if(n===d)d=o;else if(d===-1)d=e.length;return e.slice(n,d)}else{for(a=e.length-1;a>=0;--a)if(e.charCodeAt(a)===47){if(!r){n=a+1;break}}else if(d===-1)r=!1,d=a+1;if(d===-1)return"";return e.slice(n,d)}}function Se(e){v(e);var t=-1,n=0,d=-1,r=!0,a=0;for(var i=e.length-1;i>=0;--i){var o=e.charCodeAt(i);if(o===47){if(!r){n=i+1;break}continue}if(d===-1)r=!1,d=i+1;if(o===46){if(t===-1)t=i;else if(a!==1)a=1}else if(t!==-1)a=-1}if(t===-1||d===-1||a===0||a===1&&t===d-1&&t===n+1)return"";return e.slice(t,d)}function Pe(e){if(e===null||typeof e!=="object")throw new TypeError('The "pathObject" argument must be of type Object. Received type '+typeof e);return Oe("/",e)}function Re(e){v(e);var t={root:"",dir:"",base:"",ext:"",name:""};if(e.length===0)return t;var n=e.charCodeAt(0),d=n===47,r;if(d)t.root="/",r=1;else r=0;var a=-1,i=0,o=-1,s=!0,c=e.length-1,l=0;for(;c>=r;--c){if(n=e.charCodeAt(c),n===47){if(!s){i=c+1;break}continue}if(o===-1)s=!1,o=c+1;if(n===46){if(a===-1)a=c;else if(l!==1)l=1}else if(a!==-1)l=-1}if(a===-1||o===-1||l===0||l===1&&a===o-1&&a===i+1){if(o!==-1)if(i===0&&d)t.base=t.name=e.slice(1,o);else t.base=t.name=e.slice(i,o)}else{if(i===0&&d)t.name=e.slice(1,a),t.base=e.slice(1,o);else t.name=e.slice(i,a),t.base=e.slice(i,o);t.ext=e.slice(a,o)}if(i>0)t.dir=e.slice(0,i-1);else if(d)t.dir="/";return t}var S="/",Ue=":",Ot=((e)=>(e.posix=e,e))({resolve:B,normalize:ae,isAbsolute:V,join:j,relative:D,_makeLong:He,dirname:T,basename:Te,extname:Se,format:Pe,parse:Re,sep:S,delimiter:Ue,win32:null,posix:null});class F{outputPath;constructor(e="./.vector/routes.generated.ts"){this.outputPath=e}async generate(e){let t=T(this.outputPath);await oe.mkdir(t,{recursive:!0});let n=[],d=new Map;for(let o of e){if(!d.has(o.path))d.set(o.path,[]);d.get(o.path).push(o)}let r=0,a=[];for(let[o,s]of d){let c=D(T(this.outputPath),o).replace(/\\/g,"/").replace(/\.(ts|js)$/,""),l=`route_${r++}`,u=s.filter((m)=>m.name!=="default").map((m)=>m.name);if(s.some((m)=>m.name==="default"))if(u.length>0)n.push(`import ${l}, { ${u.join(", ")} } from '${c}';`);else n.push(`import ${l} from '${c}';`);else if(u.length>0)n.push(`import { ${u.join(", ")} } from '${c}';`);for(let m of s){let h=m.name==="default"?l:m.name;a.push(` ${h},`)}}let i=`// This file is auto-generated. Do not edit manually.
2
2
  // Generated at: ${new Date().toISOString()}
3
3
 
4
4
  ${n.join(`
@@ -10,7 +10,7 @@ ${a.join(`
10
10
  ];
11
11
 
12
12
  export default routes;
13
- `;await V.writeFile(this.outputPath,o,"utf-8")}async generateDynamic(e){let t=[];for(let n of e){let d=JSON.stringify({method:n.method,path:n.options.path,options:n.options});t.push(` await import('${n.path}').then(m => ({
13
+ `;await oe.writeFile(this.outputPath,i,"utf-8")}async generateDynamic(e){let t=[];for(let n of e){let d=JSON.stringify({method:n.method,path:n.options.path,options:n.options});t.push(` await import('${n.path}').then(m => ({
14
14
  ...${d},
15
15
  handler: m.${n.name==="default"?"default":n.name}
16
16
  }))`)}return`export const loadRoutes = async () => {
@@ -18,12 +18,16 @@ export default routes;
18
18
  ${t.join(`,
19
19
  `)}
20
20
  ]);
21
- };`}}var{existsSync:ye,promises:G}=(()=>({}));class D{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=I(process.cwd(),e),this.excludePatterns=t||D.DEFAULT_EXCLUDE_PATTERNS}async scan(){let e=[];if(!ye(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=k(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(O).pop()||"";if(r.test(t)||r.test(a))return!0}return!1}async scanDirectory(e,t,n=""){let d=await G.readdir(e);for(let r of d){let a=B(e,r);if((await G.stat(a)).isDirectory()){let l=n?`${n}/${r}`:r;await this.scanDirectory(a,t,l)}else if(r.endsWith(".ts")||r.endsWith(".js")){if(this.isExcluded(a))continue;let l=k(this.routesDir,a).replace(/\.(ts|js)$/,"").split(O).join("/");try{let b=await import(process.platform==="win32"?`file:///${a.replace(/\\/g,"/")}`:a);if(b.default&&typeof b.default==="function")t.push({name:"default",path:a,method:"GET",options:{method:"GET",path:`/${l}`,expose:!0}});for(let[s,u]of Object.entries(b)){if(s==="default")continue;if(u&&typeof u==="object"&&"entry"in u&&"options"in u&&"handler"in u){let m=u;t.push({name:s,path:a,method:m.options.method,options:m.options})}else if(Array.isArray(u)&&u.length>=4){let[m,,,h]=u;t.push({name:s,path:a,method:m,options:{method:m,path:h,expose:!0}})}}}catch(i){console.error(`Failed to load route from ${a}:`,i)}}}}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 N{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 N;return e.beforeHandlers=[...this.beforeHandlers],e.finallyHandlers=[...this.finallyHandlers],e}clear(){this.beforeHandlers=[],this.finallyHandlers=[]}}function Q(e){return process.platform==="win32"?`file:///${e.replace(/\\/g,"/")}`:e}function H(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 Y(e){let t=e?.["~standard"];return!!t&&typeof t==="object"&&typeof t.validate==="function"&&t.version===1}async function X(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 W(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 ge(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 R(e,t){let n=[];for(let d=0;d<e.length;d++){let r=e[d],a=r,o={message:typeof a?.message==="string"&&a.message.length>0?a.message:"Invalid value",path:ge(a?.path)};if(typeof a?.code==="string")o.code=a.code;if(t)o.raw=r;n.push(o)}return n}function T(e,t){return{error:!0,message:"Validation failed",statusCode:422,source:"validation",target:e,issues:t,timestamp:new Date().toISOString()}}class A{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),o=this.getOrCreateMethodMap(r);o[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 x.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 o=a;if(e.method==="OPTIONS"||e.method in o){let l=n.match(d.regex);if(l){try{e.params=l.groups??{}}catch{}let i=o[e.method]??o.GET;if(i){let b=await i(e);if(b)return b}}}}return L.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=A.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=A.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 o=a.indexOf("=");if(o>0)r[a.slice(0,o).trim()]=a.slice(o+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(":")?H(n):null;return async(r)=>{let a=r,o=this.resolveFallbackParams(r,d);this.prepareRequest(a,{params:o,route:n,metadata:e.metadata});try{if(e.expose===!1)return x.forbidden("Forbidden");let l=await this.middlewareManager.executeBefore(a);if(l instanceof Response)return l;let i=l;if(e.auth)try{await this.authManager.authenticate(i)}catch(f){return x.unauthorized(f instanceof Error?f.message:"Authentication failed",e.responseContentType)}if(!e.rawRequest&&i.method!=="GET"&&i.method!=="HEAD"){let f=null;try{let p=i.headers.get("content-type");if(p?.startsWith("application/json"))f=await i.json();else if(p?.startsWith("application/x-www-form-urlencoded"))f=Object.fromEntries(await i.formData());else if(p?.startsWith("multipart/form-data"))f=await i.formData();else f=await i.text()}catch{f=null}this.setContentAndBodyAlias(i,f)}let b=await this.validateInputSchema(i,e);if(b)return b;let s,u=e.cache;if(u&&typeof u==="number"&&u>0){let f=this.cacheManager.generateKey(i,{authUser:i.authUser});s=await this.cacheManager.get(f,async()=>{let p=await t(i);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(i,{authUser:i.authUser});s=await this.cacheManager.get(f,async()=>{let p=await t(i);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 s=await t(i);if(s&&typeof s==="object"&&s._isResponse===!0)s=new Response(s.body,{status:s.status,headers:s.headers});let m;if(e.rawResponse||s instanceof Response)m=s instanceof Response?s:new Response(s);else m=E(200,s,e.responseContentType);m=await this.middlewareManager.executeFinally(m,i);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,i)}return m}catch(l){if(l instanceof Response)return l;return console.error("Route handler error:",l),x.internalServerError(l instanceof Error?l.message:String(l),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(!Y(n))return x.internalServerError("Invalid route schema configuration",t.responseContentType);let d=this.isDevelopmentMode(),r=await this.buildInputValidationPayload(e,t);try{let a=await X(n,r);if(a.success===!1){let o=R(a.issues,d);return E(422,T("input",o),t.responseContentType)}return this.applyValidatedInput(e,a.value),null}catch(a){let o=W(a);if(o){let l=R(o,d);return E(422,T("input",l),t.responseContentType)}return x.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:H(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),o=0;for(let l of a)if(l.includes("*"))o+=1;else if(l.startsWith(":"))o+=10;else o+=1000;if(o+=e.length,!e.includes(":")&&!e.includes("*"))o+=1e4;return o}}var{existsSync:oe}=(()=>({}));function K(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 Z(e){return typeof e.origin==="string"&&e.origin==="*"&&e.credentials||Array.isArray(e.origin)||typeof e.origin==="function"}function q(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 xe(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 ee(e){return{preflight(t){let n=t.headers.get("origin")??void 0,d=K(n,e),r=Boolean(n&&d&&Z(e));return new Response(null,{status:204,headers:q(d,e,r)})},corsify(t,n){let d=n.headers.get("origin")??void 0,r=K(d,e);if(!r)return t;let a=Boolean(d&&Z(e)),o=q(r,e,a);for(let[l,i]of Object.entries(o)){if(l==="vary"){t.headers.set("vary",xe(t.headers.get("vary"),i));continue}t.headers.set(l,i)}return t}}}function te(e,t,n){let d=JSON.stringify(e).replace(/<\/script/gi,"<\\/script"),r=JSON.stringify(t);return`<!DOCTYPE html>
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
22
  <html lang="en">
23
23
  <head>
24
24
  <meta charset="UTF-8">
25
25
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
26
26
  <title>Vector API Documentation</title>
27
+ <link rel="apple-touch-icon" sizes="180x180" href=${f}>
28
+ <link rel="icon" type="image/png" sizes="32x32" href=${p}>
29
+ <link rel="icon" type="image/png" sizes="16x16" href=${je}>
30
+ <link rel="manifest" href=${Me}>
27
31
  <script>
28
32
  if (localStorage.getItem('theme') === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
29
33
  document.documentElement.classList.add('dark');
@@ -31,7 +35,7 @@ ${t.join(`,
31
35
  document.documentElement.classList.remove('dark');
32
36
  }
33
37
  </script>
34
- <script src=${JSON.stringify(n)}></script>
38
+ <script src=${u}></script>
35
39
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
36
40
  <script>
37
41
  tailwind.config = {
@@ -39,7 +43,12 @@ ${t.join(`,
39
43
  theme: {
40
44
  extend: {
41
45
  colors: {
42
- brand: '#6366F1',
46
+ brand: {
47
+ DEFAULT: '#00A1FF',
48
+ mint: '#00FF8F',
49
+ soft: '#E4F5FF',
50
+ deep: '#007BC5',
51
+ },
43
52
  dark: { bg: '#0A0A0A', surface: '#111111', border: '#1F1F1F', text: '#EDEDED' },
44
53
  light: { bg: '#FFFFFF', surface: '#F9F9F9', border: '#E5E5E5', text: '#111111' }
45
54
  },
@@ -106,32 +115,44 @@ ${t.join(`,
106
115
  from { opacity: 0; transform: translateX(-6px); }
107
116
  to { opacity: 1; transform: translateX(0); }
108
117
  }
118
+ @keyframes spin {
119
+ to { transform: rotate(360deg); }
120
+ }
121
+ .button-spinner {
122
+ display: inline-block;
123
+ width: 0.875rem;
124
+ height: 0.875rem;
125
+ border: 2px solid currentColor;
126
+ border-right-color: transparent;
127
+ border-radius: 9999px;
128
+ animation: spin 700ms linear infinite;
129
+ }
109
130
  @media (prefers-reduced-motion: reduce) {
110
131
  *, *::before, *::after {
111
132
  animation: none !important;
112
133
  transition: none !important;
113
134
  }
114
135
  }
115
- .json-key { color: #0f766e; }
116
- .json-string { color: #0369a1; }
117
- .json-number { color: #7c3aed; }
118
- .json-boolean { color: #b45309; }
119
- .json-null { color: #be123c; }
120
- .dark .json-key { color: #5eead4; }
121
- .dark .json-string { color: #7dd3fc; }
122
- .dark .json-number { color: #c4b5fd; }
123
- .dark .json-boolean { color: #fcd34d; }
124
- .dark .json-null { color: #fda4af; }
136
+ .json-key { color: #007bc5; }
137
+ .json-string { color: #334155; }
138
+ .json-number { color: #00a1ff; }
139
+ .json-boolean { color: #475569; }
140
+ .json-null { color: #64748b; }
141
+ .dark .json-key { color: #7dc9ff; }
142
+ .dark .json-string { color: #d1d9e6; }
143
+ .dark .json-number { color: #7dc9ff; }
144
+ .dark .json-boolean { color: #93a4bf; }
145
+ .dark .json-null { color: #7c8ba3; }
125
146
  </style>
126
147
  </head>
127
148
  <body class="bg-light-bg text-light-text dark:bg-dark-bg dark:text-dark-text font-sans antialiased flex h-screen overflow-hidden">
128
149
  <div id="mobile-backdrop" class="fixed inset-0 z-30 bg-black/40 opacity-0 pointer-events-none transition-opacity duration-300 md:hidden"></div>
129
150
  <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">
130
151
  <div class="h-14 flex items-center px-5 border-b border-light-border dark:border-dark-border">
131
- <svg class="w-5 h-5 text-brand" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
132
- <polygon points="3 21 12 2 21 21 12 15 3 21"></polygon>
133
- </svg>
134
- <span class="ml-2.5 font-bold tracking-tight text-lg">Vector</span>
152
+ <div class="flex items-center">
153
+ <img src=${m} alt="Vector" class="h-6 w-auto block dark:hidden" />
154
+ <img src=${h} alt="Vector" class="h-6 w-auto hidden dark:block" />
155
+ </div>
135
156
  <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">
136
157
  <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
137
158
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
@@ -162,8 +183,8 @@ ${t.join(`,
162
183
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path>
163
184
  </svg>
164
185
  </button>
165
- <svg class="w-5 h-5 text-brand" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="3 21 12 2 21 21 12 15 3 21"></polygon></svg>
166
- <span class="font-bold tracking-tight">Vector</span>
186
+ <img src=${m} alt="Vector" class="h-5 w-auto block dark:hidden" />
187
+ <img src=${h} alt="Vector" class="h-5 w-auto hidden dark:block" />
167
188
  </div>
168
189
  <div class="flex-1"></div>
169
190
  <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">
@@ -188,17 +209,22 @@ ${t.join(`,
188
209
  <div class="grid grid-cols-1 lg:grid-cols-12 gap-10">
189
210
  <div class="lg:col-span-5 space-y-8" id="params-column"></div>
190
211
  <div class="lg:col-span-7">
191
- <div class="rounded-lg border border-light-border dark:border-[#1F1F1F] bg-light-bg dark:bg-[#111111] overflow-hidden group">
192
- <div class="flex items-center justify-between px-4 py-2 border-b border-light-border dark:border-[#1F1F1F] bg-light-surface dark:bg-[#0A0A0A]">
193
- <span class="text-xs font-mono text-light-text/70 dark:text-[#EDEDED]/70">cURL</span>
194
- <button class="text-xs text-light-text/50 hover:text-light-text dark:text-[#EDEDED]/50 dark:hover:text-[#EDEDED] transition-colors" id="copy-curl">Copy</button>
212
+ <div class="rounded-lg border border-light-border dark:border-dark-border bg-light-bg dark:bg-dark-bg overflow-hidden group">
213
+ <div class="flex items-center justify-between px-4 py-2 border-b border-light-border dark:border-dark-border bg-light-surface dark:bg-dark-surface">
214
+ <span class="text-xs font-mono text-light-text/70 dark:text-dark-text/70">cURL</span>
215
+ <button class="text-xs text-light-text/50 hover:text-light-text dark:text-dark-text/50 dark:hover:text-dark-text transition-colors" id="copy-curl">Copy</button>
195
216
  </div>
196
- <pre class="p-4 text-sm font-mono text-light-text dark:text-[#EDEDED] overflow-x-auto leading-relaxed"><code id="curl-code"></code></pre>
217
+ <pre class="p-4 text-sm font-mono text-light-text dark:text-dark-text overflow-x-auto leading-relaxed"><code id="curl-code"></code></pre>
197
218
  </div>
198
219
  <div class="mt-4 p-4 rounded-lg border border-light-border dark:border-dark-border bg-light-surface dark:bg-dark-surface">
199
220
  <div class="flex items-center justify-between mb-3">
200
221
  <h4 class="text-sm font-medium">Try it out</h4>
201
- <button id="send-btn" class="px-4 py-1.5 bg-teal-600 text-white text-sm font-semibold rounded hover:bg-teal-500 transition-colors">Submit</button>
222
+ <button id="send-btn" class="px-4 py-1.5 bg-brand text-white text-sm font-semibold rounded hover:bg-brand-deep transition-colors">
223
+ <span class="inline-flex items-center gap-2">
224
+ <span id="send-btn-spinner" class="button-spinner hidden" aria-hidden="true"></span>
225
+ <span id="send-btn-label">Submit</span>
226
+ </span>
227
+ </button>
202
228
  </div>
203
229
  <div class="space-y-4">
204
230
  <div>
@@ -232,7 +258,7 @@ ${t.join(`,
232
258
  </div>
233
259
  </div>
234
260
 
235
- <div>
261
+ <div id="response-section">
236
262
  <div class="flex items-center justify-between mb-2">
237
263
  <p class="text-xs font-semibold uppercase tracking-wider opacity-60">Response</p>
238
264
  </div>
@@ -259,7 +285,7 @@ ${t.join(`,
259
285
  <div class="flex items-center justify-between mb-3">
260
286
  <h3 id="expand-modal-title" class="text-sm font-semibold">Expanded View</h3>
261
287
  <div class="flex items-center gap-2">
262
- <button id="expand-apply" class="hidden text-sm px-3 py-1.5 rounded bg-teal-600 text-white font-semibold hover:bg-teal-500 transition-colors">Apply</button>
288
+ <button id="expand-apply" class="hidden text-sm px-3 py-1.5 rounded bg-brand text-white font-semibold hover:bg-brand-deep transition-colors">Apply</button>
263
289
  <button id="expand-close" class="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 hover:border-brand/60 transition-colors" aria-label="Close Modal" title="Close Modal">
264
290
  <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
265
291
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
@@ -276,14 +302,15 @@ ${t.join(`,
276
302
  </div>
277
303
 
278
304
  <script>
279
- const spec = ${d};
280
- const openapiPath = ${r};
305
+ const spec = ${c};
306
+ const openapiPath = ${l};
307
+ const methodBadgeDefault = "bg-black/5 text-light-text/80 dark:bg-white/10 dark:text-dark-text/80";
281
308
  const methodBadge = {
282
- GET: "bg-green-100 text-green-700 dark:bg-green-500/10 dark:text-green-400",
283
- POST: "bg-blue-100 text-blue-700 dark:bg-blue-500/10 dark:text-blue-400",
284
- PUT: "bg-amber-100 text-amber-700 dark:bg-amber-500/10 dark:text-amber-400",
285
- PATCH: "bg-amber-100 text-amber-700 dark:bg-amber-500/10 dark:text-amber-400",
286
- DELETE: "bg-red-100 text-red-700 dark:bg-red-500/10 dark:text-red-400",
309
+ GET: "bg-brand-soft text-brand-deep dark:bg-brand/20 dark:text-brand",
310
+ POST: "bg-brand-soft text-brand-deep dark:bg-brand/20 dark:text-brand",
311
+ PUT: "bg-brand-soft text-brand-deep dark:bg-brand/20 dark:text-brand",
312
+ PATCH: "bg-brand-soft text-brand-deep dark:bg-brand/20 dark:text-brand",
313
+ DELETE: "bg-brand-soft text-brand-deep dark:bg-brand/20 dark:text-brand",
287
314
  };
288
315
 
289
316
  function getOperations() {
@@ -537,6 +564,16 @@ ${t.join(`,
537
564
  return;
538
565
  }
539
566
  for (const [tag, ops] of groups.entries()) {
567
+ ops.sort((a, b) => {
568
+ const byName = a.name.localeCompare(b.name, undefined, { sensitivity: "base" });
569
+ if (byName !== 0) return byName;
570
+
571
+ const byPath = a.path.localeCompare(b.path, undefined, { sensitivity: "base" });
572
+ if (byPath !== 0) return byPath;
573
+
574
+ return a.method.localeCompare(b.method, undefined, { sensitivity: "base" });
575
+ });
576
+
540
577
  const block = document.createElement("div");
541
578
  block.innerHTML = '<h3 class="px-2 mb-2 font-semibold text-xs uppercase tracking-wider opacity-50"></h3><ul class="space-y-0.5"></ul>';
542
579
  block.querySelector("h3").textContent = tag;
@@ -548,14 +585,14 @@ ${t.join(`,
548
585
  const a = document.createElement("a");
549
586
  a.href = "#";
550
587
  a.className = op === selected
551
- ? "block px-2 py-1.5 rounded-md bg-black/5 dark:bg-white/5 text-brand font-medium transition-colors"
588
+ ? "block px-2 py-1.5 rounded-md bg-brand-soft/70 dark:bg-brand/20 text-brand-deep dark:text-brand font-medium transition-colors"
552
589
  : "block px-2 py-1.5 rounded-md hover:bg-black/5 dark:hover:bg-white/5 transition-colors";
553
590
 
554
591
  const row = document.createElement("span");
555
592
  row.className = "flex items-center gap-2";
556
593
 
557
594
  const method = document.createElement("span");
558
- method.className = "px-1.5 py-0.5 rounded text-[10px] font-mono font-semibold " + (methodBadge[op.method] || "bg-zinc-100 text-zinc-700 dark:bg-zinc-500/10 dark:text-zinc-400");
595
+ method.className = "px-1.5 py-0.5 rounded text-[10px] font-mono font-semibold " + (methodBadge[op.method] || methodBadgeDefault);
559
596
  method.textContent = op.method;
560
597
 
561
598
  const name = document.createElement("span");
@@ -694,6 +731,55 @@ ${t.join(`,
694
731
  );
695
732
  }
696
733
 
734
+ function renderResponseSchemasSection(responses) {
735
+ if (!responses || typeof responses !== "object") return "";
736
+
737
+ const statusCodes = Object.keys(responses).sort((a, b) => {
738
+ const aNum = Number(a);
739
+ const bNum = Number(b);
740
+ if (Number.isInteger(aNum) && Number.isInteger(bNum)) return aNum - bNum;
741
+ if (Number.isInteger(aNum)) return -1;
742
+ if (Number.isInteger(bNum)) return 1;
743
+ return a.localeCompare(b);
744
+ });
745
+
746
+ let sections = "";
747
+ for (const statusCode of statusCodes) {
748
+ const responseDef = responses[statusCode];
749
+ if (!responseDef || typeof responseDef !== "object") continue;
750
+
751
+ const jsonSchema =
752
+ responseDef.content &&
753
+ responseDef.content["application/json"] &&
754
+ responseDef.content["application/json"].schema;
755
+
756
+ if (!jsonSchema || typeof jsonSchema !== "object") continue;
757
+
758
+ const rootChildren = buildSchemaChildren(jsonSchema);
759
+ if (!rootChildren.length) continue;
760
+
761
+ let rows = "";
762
+ for (const child of rootChildren) {
763
+ rows += renderSchemaFieldNode(child, 0);
764
+ }
765
+
766
+ sections +=
767
+ '<div class="mb-4"><h4 class="text-xs font-mono uppercase tracking-wider opacity-70 mb-2">Status ' +
768
+ escapeHtml(statusCode) +
769
+ "</h4>" +
770
+ rows +
771
+ "</div>";
772
+ }
773
+
774
+ if (!sections) return "";
775
+
776
+ return (
777
+ '<div><h3 class="text-sm font-semibold mb-3 flex items-center border-b border-light-border dark:border-dark-border pb-2">Response Schemas</h3>' +
778
+ sections +
779
+ "</div>"
780
+ );
781
+ }
782
+
697
783
  function renderTryItParameterInputs(pathParams, queryParams) {
698
784
  const container = document.getElementById("request-param-inputs");
699
785
  if (!container || !selected) return;
@@ -977,6 +1063,19 @@ ${t.join(`,
977
1063
  }
978
1064
  }
979
1065
 
1066
+ function setSubmitLoading(isLoading) {
1067
+ const sendButton = document.getElementById("send-btn");
1068
+ const spinner = document.getElementById("send-btn-spinner");
1069
+ const label = document.getElementById("send-btn-label");
1070
+ if (!sendButton) return;
1071
+
1072
+ sendButton.disabled = isLoading;
1073
+ sendButton.classList.toggle("opacity-80", isLoading);
1074
+ sendButton.classList.toggle("cursor-wait", isLoading);
1075
+ if (spinner) spinner.classList.toggle("hidden", !isLoading);
1076
+ if (label) label.textContent = isLoading ? "Sending..." : "Submit";
1077
+ }
1078
+
980
1079
  function updateRequestPreview() {
981
1080
  if (!selected) return;
982
1081
 
@@ -1040,7 +1139,7 @@ ${t.join(`,
1040
1139
  document.getElementById("tag-description").textContent = op.description || "Interactive API documentation.";
1041
1140
  const methodNode = document.getElementById("endpoint-method");
1042
1141
  methodNode.textContent = selected.method;
1043
- methodNode.className = "px-2.5 py-0.5 rounded-full text-xs font-mono font-medium " + (methodBadge[selected.method] || "bg-zinc-100 text-zinc-700 dark:bg-zinc-500/10 dark:text-zinc-400");
1142
+ methodNode.className = "px-2.5 py-0.5 rounded-full text-xs font-mono font-medium " + (methodBadge[selected.method] || methodBadgeDefault);
1044
1143
  document.getElementById("endpoint-title").textContent = selected.name;
1045
1144
  document.getElementById("endpoint-path").textContent = selected.path;
1046
1145
 
@@ -1053,6 +1152,7 @@ ${t.join(`,
1053
1152
  html += renderParamSection("Header Parameters", headers);
1054
1153
 
1055
1154
  html += renderRequestBodySchemaSection(reqSchema);
1155
+ html += renderResponseSchemasSection(op.responses);
1056
1156
  document.getElementById("params-column").innerHTML = html || '<div class="text-sm opacity-70">No parameters</div>';
1057
1157
  renderTryItParameterInputs(path, query);
1058
1158
  renderHeaderInputs();
@@ -1103,14 +1203,18 @@ ${t.join(`,
1103
1203
  headers["Content-Type"] = "application/json";
1104
1204
  }
1105
1205
 
1206
+ setSubmitLoading(true);
1106
1207
  try {
1208
+ const requestStart = performance.now();
1107
1209
  const response = await fetch(requestPath, { method: selected.method, headers, body: body || undefined });
1108
1210
  const text = await response.text();
1211
+ const responseTimeMs = Math.round(performance.now() - requestStart);
1109
1212
  const contentType = response.headers.get("content-type") || "unknown";
1110
1213
  const formattedResponse = formatResponseText(text);
1111
1214
  const headerText =
1112
1215
  "Status: " + response.status + " " + response.statusText + "\\n" +
1113
- "Content-Type: " + contentType + "\\n\\n";
1216
+ "Content-Type: " + contentType + "\\n" +
1217
+ "Response Time: " + responseTimeMs + " ms\\n\\n";
1114
1218
  setResponseContent(
1115
1219
  headerText,
1116
1220
  formattedResponse.text,
@@ -1118,6 +1222,8 @@ ${t.join(`,
1118
1222
  );
1119
1223
  } catch (error) {
1120
1224
  setResponseContent("", "Request failed: " + String(error), false);
1225
+ } finally {
1226
+ setSubmitLoading(false);
1121
1227
  }
1122
1228
  });
1123
1229
 
@@ -1324,4 +1430,4 @@ ${t.join(`,
1324
1430
  renderEndpoint();
1325
1431
  </script>
1326
1432
  </body>
1327
- </html>`}function de(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 re(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 o=/^:([A-Za-z0-9_]+)$/.exec(r);if(o?.[1])return n.push(o[1]),`{${o[1]}}`;if(r==="*"){t+=1;let l=t===1?"wildcard":`wildcard${t}`;return n.push(l),`{${l}}`}return r}).join("/"),pathParamNames:n}}function ve(e){return re(e).openapiPath}function ke(e,t){return`${e.toLowerCase()}_${t}`.replace(/[:{}]/g,"").replace(/[^A-Za-z0-9_]+/g,"_").replace(/^_+|_+$/g,"")||`${e.toLowerCase()}_operation`}function Ee(e){let t=e.split("/").filter(Boolean);for(let n of t)if(!n.startsWith(":")&&n!=="*")return n.toLowerCase();return"default"}function we(e){return re(e).pathParamNames}function Ie(e,t){let n=new Set((e.parameters||[]).filter((d)=>d.in==="path").map((d)=>String(d.name)));for(let d of we(t)){if(n.has(d))continue;(e.parameters||=[]).push({name:d,in:"path",required:!0,schema:{type:"string"}})}}function Be(e){let t=Number(e);if(!Number.isInteger(t))return!1;return t>=100&&t<200||t===204||t===205||t===304}function Ae(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 Le(e,t,n,d){if(!de(t))return null;try{return t["~standard"].jsonSchema.input({target:n})}catch(r){return d.push(`[OpenAPI] Failed input schema conversion for ${e}: ${r instanceof Error?r.message:String(r)}`),null}}function ne(e,t,n,d,r){if(!de(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)}`),null}}function w(e){return!!e&&typeof e==="object"&&!Array.isArray(e)}function Ce(e,t){if(!w(t))return;if(t.type!=="object"||!w(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 l of a){let i=d[l.key];if(!w(i))continue;if(i.type!=="object"||!w(i.properties))continue;let b=new Set(Array.isArray(i.required)?i.required:[]);for(let[s,u]of Object.entries(i.properties))r.push({name:s,in:l.in,required:l.in==="path"?!0:b.has(s),schema:w(u)?u:{}})}if(r.length>0){let l=new Map;for(let i of r)l.set(`${i.in}:${i.name}`,i);e.parameters=[...l.values()]}let o=d.body;if(o)e.requestBody={required:n.has("body"),content:{"application/json":{schema:w(o)?o:{}}}}}function Oe(e,t,n,d,r){let a=n.output;if(!a){e.responses={200:{description:"OK"}};return}let o={};if(typeof a==="object"&&a!==null&&"~standard"in a){let l=ne(t,"200",a,d,r);if(l)o["200"]={description:"OK",content:{"application/json":{schema:l}}};else o["200"]={description:"OK"}}else for(let[l,i]of Object.entries(a)){let b=String(l),s=ne(t,b,i,d,r),u=Ae(b);if(s&&!Be(b))o[b]={description:u,content:{"application/json":{schema:s}}};else o[b]={description:u}}if(Object.keys(o).length===0)o["200"]={description:"OK"};e.responses=o}function ae(e,t){let n=[],d={};for(let o of e){if(o.options.expose===!1)continue;if(!o.method||!o.path)continue;let l=o.method.toLowerCase();if(l==="options")continue;let i=ve(o.path),b={operationId:ke(l,i),tags:[o.options.schema?.tag||Ee(o.path)]},s=Le(o.path,o.options.schema?.input,t.target,n);if(s)Ce(b,s);Ie(b,o.path),Oe(b,o.path,o.options.schema||{},t.target,n),d[i]||={},d[i][l]=b}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 U="/_vector/openapi/tailwindcdn.js",De=["../openapi/assets/tailwindcdn.js","../src/openapi/assets/tailwindcdn.js","../../src/openapi/assets/tailwindcdn.js"],Ne=["src/openapi/assets/tailwindcdn.js","openapi/assets/tailwindcdn.js","dist/openapi/assets/tailwindcdn.js"],Se="/* OpenAPI docs runtime asset missing: tailwind disabled */";function je(){for(let t of De)try{let n=new URL(t,import.meta.url);if(oe(n))return Bun.file(n)}catch{}let e=process.cwd();for(let t of Ne){let n=B(e,t);if(oe(n))return Bun.file(n)}return null}var le=je(),F="public, max-age=0, must-revalidate",ie="public, max-age=31536000, immutable";class J{server=null;router;config;openapiConfig;openapiDocCache=null;openapiDocsHtmlCache=null;openapiWarningsLogged=!1;openapiTailwindMissingLogged=!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}=ee(n);if(this.corsHandler={preflight:d,corsify:r},typeof n.origin==="string"&&(n.origin!=="*"||!n.credentials)){let o={"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)o["access-control-allow-credentials"]="true";this.corsHeadersEntries=Object.entries(o)}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,o=typeof a==="boolean"?{enabled:a,path:"/docs"}:{enabled:a?.enabled===!0,path:a?.path||"/docs"};return{enabled:r.enabled??d,path:r.path||"/openapi.json",target:r.target||"openapi-3.0",docs:o,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=ae(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}getOpenAPIDocsHtmlCacheEntry(){if(this.openapiDocsHtmlCache)return this.openapiDocsHtmlCache;let e=te(this.getOpenAPIDocument(),this.openapiConfig.path,U),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(U);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":F,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":F,vary:"accept-encoding"}});return new Response(n,{status:200,headers:{"content-type":"text/html; charset=utf-8",etag:r,"cache-control":F,vary:"accept-encoding"}})}if(this.openapiConfig.docs.enabled&&t===U){if(!le){if(!this.openapiTailwindMissingLogged)this.openapiTailwindMissingLogged=!0,console.warn('[OpenAPI] Missing docs runtime asset "tailwindcdn.js". Serving inline fallback script instead.');return new Response(Se,{status:200,headers:{"content-type":"application/javascript; charset=utf-8","cache-control":ie}})}return new Response(le,{status:200,headers:{"content-type":"application/javascript; charset=utf-8","cache-control":ie}})}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(L.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 v{static instance;router;server=null;middlewareManager;authManager;cacheManager;config={};routeScanner=null;routeGenerator=null;_protectedHandler=null;_cacheHandler=null;constructor(){this.middlewareManager=new N,this.authManager=new M,this.cacheManager=new P,this.router=new A(this.middlewareManager,this.authManager,this.cacheManager)}static getInstance(){if(!v.instance)v.instance=new v;return v.instance}setProtectedHandler(e){this._protectedHandler=e,this.authManager.setProtectedHandler(e)}getProtectedHandler(){return this._protectedHandler}setCacheHandler(e){this._cacheHandler=e,this.cacheManager.setCacheHandler(e)}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(this.config.autoDiscover!==!1)await this.discoverRoutes();return this.server=new J(this.router,this.config),await this.server.start()}async discoverRoutes(){let e=this.config.routesDir||"./routes",t=this.config.routeExcludePatterns;if(this.routeScanner=new D(e,t),!this.routeGenerator)this.routeGenerator=new _;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(Q(d.path)),o=d.name==="default"?a.default:a[d.name];if(o){if(this.isRouteDefinition(o))this.router.route(o.options,o.handler),this.logRouteLoaded(o.options);else if(this.isRouteEntry(o))this.router.addRoute(o),this.logRouteLoaded(o);else if(typeof o==="function")this.router.route(d.options,o),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}getServer(){return this.server}getRouter(){return this.router}getCacheManager(){return this.cacheManager}getAuthManager(){return this.authManager}static resetInstance(){v.instance=null}}var Me=v.getInstance;function Pe(e,t){return{entry:{method:e.method.toUpperCase(),path:e.path},options:e,handler:t}}function _e(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 c(e,t,n){let d={error:!0,message:t,statusCode:e,timestamp:new Date().toISOString()};return E(e,d,n)}var x={badRequest:(e="Bad Request",t)=>c(g.BAD_REQUEST,e,t),unauthorized:(e="Unauthorized",t)=>c(g.UNAUTHORIZED,e,t),paymentRequired:(e="Payment Required",t)=>c(402,e,t),forbidden:(e="Forbidden",t)=>c(g.FORBIDDEN,e,t),notFound:(e="Not Found",t)=>c(g.NOT_FOUND,e,t),methodNotAllowed:(e="Method Not Allowed",t)=>c(405,e,t),notAcceptable:(e="Not Acceptable",t)=>c(406,e,t),requestTimeout:(e="Request Timeout",t)=>c(408,e,t),conflict:(e="Conflict",t)=>c(g.CONFLICT,e,t),gone:(e="Gone",t)=>c(410,e,t),lengthRequired:(e="Length Required",t)=>c(411,e,t),preconditionFailed:(e="Precondition Failed",t)=>c(412,e,t),payloadTooLarge:(e="Payload Too Large",t)=>c(413,e,t),uriTooLong:(e="URI Too Long",t)=>c(414,e,t),unsupportedMediaType:(e="Unsupported Media Type",t)=>c(415,e,t),rangeNotSatisfiable:(e="Range Not Satisfiable",t)=>c(416,e,t),expectationFailed:(e="Expectation Failed",t)=>c(417,e,t),imATeapot:(e="I'm a teapot",t)=>c(418,e,t),misdirectedRequest:(e="Misdirected Request",t)=>c(421,e,t),unprocessableEntity:(e="Unprocessable Entity",t)=>c(g.UNPROCESSABLE_ENTITY,e,t),locked:(e="Locked",t)=>c(423,e,t),failedDependency:(e="Failed Dependency",t)=>c(424,e,t),tooEarly:(e="Too Early",t)=>c(425,e,t),upgradeRequired:(e="Upgrade Required",t)=>c(426,e,t),preconditionRequired:(e="Precondition Required",t)=>c(428,e,t),tooManyRequests:(e="Too Many Requests",t)=>c(429,e,t),requestHeaderFieldsTooLarge:(e="Request Header Fields Too Large",t)=>c(431,e,t),unavailableForLegalReasons:(e="Unavailable For Legal Reasons",t)=>c(451,e,t),internalServerError:(e="Internal Server Error",t)=>c(g.INTERNAL_SERVER_ERROR,e,t),notImplemented:(e="Not Implemented",t)=>c(501,e,t),badGateway:(e="Bad Gateway",t)=>c(502,e,t),serviceUnavailable:(e="Service Unavailable",t)=>c(503,e,t),gatewayTimeout:(e="Gateway Timeout",t)=>c(504,e,t),httpVersionNotSupported:(e="HTTP Version Not Supported",t)=>c(505,e,t),variantAlsoNegotiates:(e="Variant Also Negotiates",t)=>c(506,e,t),insufficientStorage:(e="Insufficient Storage",t)=>c(507,e,t),loopDetected:(e="Loop Detected",t)=>c(508,e,t),notExtended:(e="Not Extended",t)=>c(510,e,t),networkAuthenticationRequired:(e="Network Authentication Required",t)=>c(511,e,t),invalidArgument:(e="Invalid Argument",t)=>c(g.UNPROCESSABLE_ENTITY,e,t),rateLimitExceeded:(e="Rate Limit Exceeded",t)=>c(429,e,t),maintenance:(e="Service Under Maintenance",t)=>c(503,e,t),custom:(e,t,n)=>c(e,t,n)};function E(e,t,n=j.JSON){let d=n===j.JSON?_e(t):t;return new Response(d,{status:e,headers:{"content-type":n}})}export{Pe as route,E as createResponse,x as APIError};
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};
@@ -1,2 +1,2 @@
1
- export declare function renderOpenAPIDocsHtml(spec: Record<string, unknown>, openapiPath: string, tailwindScriptPath: string): string;
1
+ export declare function renderOpenAPIDocsHtml(spec: Record<string, unknown>, openapiPath: string, tailwindScriptPath: string, logoDarkPath: string, logoWhitePath: string, appleTouchIconPath: string, favicon32Path: string, favicon16Path: string, webManifestPath: string): string;
2
2
  //# sourceMappingURL=docs-ui.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"docs-ui.d.ts","sourceRoot":"","sources":["../../src/openapi/docs-ui.ts"],"names":[],"mappings":"AAAA,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,WAAW,EAAE,MAAM,EACnB,kBAAkB,EAAE,MAAM,GACzB,MAAM,CAgyCR"}
1
+ {"version":3,"file":"docs-ui.d.ts","sourceRoot":"","sources":["../../src/openapi/docs-ui.ts"],"names":[],"mappings":"AAAA,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,WAAW,EAAE,MAAM,EACnB,kBAAkB,EAAE,MAAM,EAC1B,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,EACrB,kBAAkB,EAAE,MAAM,EAC1B,aAAa,EAAE,MAAM,EACrB,aAAa,EAAE,MAAM,EACrB,eAAe,EAAE,MAAM,GACtB,MAAM,CAg5CR"}