vector-framework 1.2.0 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) 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 +967 -222
  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 +4 -0
  21. package/dist/core/server.d.ts.map +1 -1
  22. package/dist/core/server.js +240 -9
  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/errors/index.cjs +2 -0
  29. package/dist/index.cjs +1434 -0
  30. package/dist/index.d.ts +2 -0
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +12 -1327
  33. package/dist/index.js.map +1 -1
  34. package/dist/index.mjs +153 -46
  35. package/dist/openapi/docs-ui.d.ts +1 -1
  36. package/dist/openapi/docs-ui.d.ts.map +1 -1
  37. package/dist/openapi/docs-ui.js +147 -35
  38. package/dist/openapi/docs-ui.js.map +1 -1
  39. package/dist/openapi/generator.d.ts.map +1 -1
  40. package/dist/openapi/generator.js +318 -6
  41. package/dist/openapi/generator.js.map +1 -1
  42. package/dist/start-vector.d.ts +3 -0
  43. package/dist/start-vector.d.ts.map +1 -0
  44. package/dist/start-vector.js +38 -0
  45. package/dist/start-vector.js.map +1 -0
  46. package/dist/types/index.d.ts +25 -0
  47. package/dist/types/index.d.ts.map +1 -1
  48. package/dist/utils/logger.js +1 -1
  49. package/dist/utils/validation.d.ts.map +1 -1
  50. package/dist/utils/validation.js +2 -0
  51. package/dist/utils/validation.js.map +1 -1
  52. package/package.json +10 -14
  53. package/src/auth/protected.ts +4 -0
  54. package/src/cache/manager.ts +4 -0
  55. package/src/cli/graceful-shutdown.ts +60 -0
  56. package/src/cli/index.ts +42 -49
  57. package/src/core/config-loader.ts +5 -2
  58. package/src/core/server.ts +304 -9
  59. package/src/core/vector.ts +38 -4
  60. package/src/index.ts +4 -3
  61. package/src/openapi/assets/favicon/android-chrome-192x192.png +0 -0
  62. package/src/openapi/assets/favicon/android-chrome-512x512.png +0 -0
  63. package/src/openapi/assets/favicon/apple-touch-icon.png +0 -0
  64. package/src/openapi/assets/favicon/favicon-16x16.png +0 -0
  65. package/src/openapi/assets/favicon/favicon-32x32.png +0 -0
  66. package/src/openapi/assets/favicon/favicon.ico +0 -0
  67. package/src/openapi/assets/favicon/site.webmanifest +11 -0
  68. package/src/openapi/assets/logo.svg +12 -0
  69. package/src/openapi/assets/logo_dark.svg +6 -0
  70. package/src/openapi/assets/logo_icon.png +0 -0
  71. package/src/openapi/assets/logo_white.svg +6 -0
  72. package/src/openapi/docs-ui.ts +153 -35
  73. package/src/openapi/generator.ts +341 -6
  74. package/src/start-vector.ts +50 -0
  75. package/src/types/index.ts +34 -0
  76. package/src/utils/logger.ts +1 -1
  77. package/src/utils/validation.ts +2 -0
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAC5C,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAE/B,4CAA4C;AAC5C,OAAO,EAAE,KAAK,EAAE,CAAC;AAEjB,sCAAsC;AACtC,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAElD,oCAAoC;AACpC,cAAc,SAAS,CAAC;AAExB,+DAA+D;AAC/D,wEAAwE"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAC/B,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,4CAA4C;AAC5C,OAAO,EAAE,KAAK,EAAE,CAAC;AACjB,OAAO,EAAE,WAAW,EAAE,CAAC;AAEvB,sCAAsC;AACtC,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAElD,oCAAoC;AACpC,cAAc,SAAS,CAAC;AAExB,gFAAgF"}
package/dist/index.mjs CHANGED
@@ -1,29 +1,34 @@
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
+ // @bun
2
+ var E={OK:200,CREATED:201,ACCEPTED:202,NON_AUTHORITATIVE_INFORMATION:203,NO_CONTENT:204,RESET_CONTENT:205,PARTIAL_CONTENT:206,MULTI_STATUS:207,ALREADY_REPORTED:208,IM_USED:226,MULTIPLE_CHOICES:300,MOVED_PERMANENTLY:301,FOUND:302,SEE_OTHER:303,NOT_MODIFIED:304,USE_PROXY:305,TEMPORARY_REDIRECT:307,PERMANENT_REDIRECT:308,BAD_REQUEST:400,UNAUTHORIZED:401,PAYMENT_REQUIRED:402,FORBIDDEN:403,NOT_FOUND:404,METHOD_NOT_ALLOWED:405,NOT_ACCEPTABLE:406,PROXY_AUTHENTICATION_REQUIRED:407,REQUEST_TIMEOUT:408,CONFLICT:409,GONE:410,LENGTH_REQUIRED:411,PRECONDITION_FAILED:412,PAYLOAD_TOO_LARGE:413,URI_TOO_LONG:414,UNSUPPORTED_MEDIA_TYPE:415,RANGE_NOT_SATISFIABLE:416,EXPECTATION_FAILED:417,IM_A_TEAPOT:418,MISDIRECTED_REQUEST:421,UNPROCESSABLE_ENTITY:422,LOCKED:423,FAILED_DEPENDENCY:424,TOO_EARLY:425,UPGRADE_REQUIRED:426,PRECONDITION_REQUIRED:428,TOO_MANY_REQUESTS:429,REQUEST_HEADER_FIELDS_TOO_LARGE:431,UNAVAILABLE_FOR_LEGAL_REASONS:451,INTERNAL_SERVER_ERROR:500,NOT_IMPLEMENTED:501,BAD_GATEWAY:502,SERVICE_UNAVAILABLE:503,GATEWAY_TIMEOUT:504,HTTP_VERSION_NOT_SUPPORTED:505,VARIANT_ALSO_NEGOTIATES:506,INSUFFICIENT_STORAGE:507,LOOP_DETECTED:508,NOT_EXTENDED:510,NETWORK_AUTHENTICATION_REQUIRED:511},L={PORT:3000,HOSTNAME:"localhost",ROUTES_DIR:"./routes",CACHE_TTL:0,CORS_MAX_AGE:86400},T={JSON:"application/json",TEXT:"text/plain",HTML:"text/html",FORM_URLENCODED:"application/x-www-form-urlencoded",MULTIPART:"multipart/form-data"};var j={NOT_FOUND:new Response(JSON.stringify({error:!0,message:"Not Found",statusCode:404}),{status:404,headers:{"content-type":"application/json"}})};class R{protectedHandler=null;setProtectedHandler(e){this.protectedHandler=e}clearProtectedHandler(){this.protectedHandler=null}async authenticate(e){if(!this.protectedHandler)throw new Error("Protected handler not configured. Use vector.protected() to set authentication handler.");try{let t=await this.protectedHandler(e);return e.authUser=t,t}catch(t){throw new Error(`Authentication failed: ${t instanceof Error?t.message:String(t)}`)}}isAuthenticated(e){return!!e.authUser}getUser(e){return e.authUser||null}}class U{cacheHandler=null;memoryCache=new Map;cleanupInterval=null;inflight=new Map;setCacheHandler(e){this.cacheHandler=e}clearCacheHandler(){this.cacheHandler=null}async get(e,t,d=L.CACHE_TTL){if(d<=0)return t();if(this.cacheHandler)return this.cacheHandler(e,t,d);return this.getFromMemoryCache(e,t,d)}async getFromMemoryCache(e,t,d){let n=Date.now(),r=this.memoryCache.get(e);if(this.isCacheValid(r,n))return r.value;if(this.inflight.has(e))return await this.inflight.get(e);let o=(async()=>{let i=await t();return this.setInMemoryCache(e,i,d),i})();this.inflight.set(e,o);try{return await o}finally{this.inflight.delete(e)}}isCacheValid(e,t){return e!==void 0&&e.expires>t}setInMemoryCache(e,t,d){let n=Date.now()+d*1000;this.memoryCache.set(e,{value:t,expires:n}),this.scheduleCleanup()}scheduleCleanup(){if(this.cleanupInterval)return;this.cleanupInterval=setInterval(()=>{this.cleanupExpired()},60000)}cleanupExpired(){let e=Date.now();for(let[t,d]of this.memoryCache.entries())if(d.expires<=e)this.memoryCache.delete(t);if(this.memoryCache.size===0&&this.cleanupInterval)clearInterval(this.cleanupInterval),this.cleanupInterval=null}clear(){if(this.memoryCache.clear(),this.cleanupInterval)clearInterval(this.cleanupInterval),this.cleanupInterval=null}async set(e,t,d=L.CACHE_TTL){if(d<=0)return;if(this.cacheHandler){await this.cacheHandler(e,async()=>t,d);return}this.setInMemoryCache(e,t,d)}delete(e){return this.memoryCache.delete(e)}has(e){let t=this.memoryCache.get(e);if(!t)return!1;if(t.expires<=Date.now())return this.memoryCache.delete(e),!1;return!0}generateKey(e,t){let d=e._parsedUrl??new URL(e.url),n=t?.authUser?.id!=null?String(t.authUser.id):"anonymous";return`${e.method}:${d.pathname}:${d.search}:${n}`}}import{promises as ee}from"fs";import{dirname as te,relative as je}from"path";class ${outputPath;constructor(e="./.vector/routes.generated.ts"){this.outputPath=e}async generate(e){let t=te(this.outputPath);await ee.mkdir(t,{recursive:!0});let d=[],n=new Map;for(let a of e){if(!n.has(a.path))n.set(a.path,[]);n.get(a.path).push(a)}let r=0,o=[];for(let[a,s]of n){let c=je(te(this.outputPath),a).replace(/\\/g,"/").replace(/\.(ts|js)$/,""),m=`route_${r++}`,b=s.filter((p)=>p.name!=="default").map((p)=>p.name);if(s.some((p)=>p.name==="default"))if(b.length>0)d.push(`import ${m}, { ${b.join(", ")} } from '${c}';`);else d.push(`import ${m} from '${c}';`);else if(b.length>0)d.push(`import { ${b.join(", ")} } from '${c}';`);for(let p of s){let x=p.name==="default"?m:p.name;o.push(` ${x},`)}}let i=`// This file is auto-generated. Do not edit manually.
2
3
  // Generated at: ${new Date().toISOString()}
3
4
 
4
- ${n.join(`
5
+ ${d.join(`
5
6
  `)}
6
7
 
7
8
  export const routes = [
8
- ${a.join(`
9
+ ${o.join(`
9
10
  `)}
10
11
  ];
11
12
 
12
13
  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 => ({
14
- ...${d},
15
- handler: m.${n.name==="default"?"default":n.name}
14
+ `;await ee.writeFile(this.outputPath,i,"utf-8")}async generateDynamic(e){let t=[];for(let d of e){let n=JSON.stringify({method:d.method,path:d.options.path,options:d.options});t.push(` await import('${d.path}').then(m => ({
15
+ ...${n},
16
+ handler: m.${d.name==="default"?"default":d.name}
16
17
  }))`)}return`export const loadRoutes = async () => {
17
18
  return Promise.all([
18
19
  ${t.join(`,
19
20
  `)}
20
21
  ]);
21
- };`}}var{existsSync: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>
22
+ };`}}import{existsSync as Me,promises as de}from"fs";import{join as Ce,relative as ne,resolve as He,sep as re}from"path";class M{routesDir;excludePatterns;static DEFAULT_EXCLUDE_PATTERNS=["*.test.ts","*.test.js","*.test.tsx","*.test.jsx","*.spec.ts","*.spec.js","*.spec.tsx","*.spec.jsx","*.tests.ts","*.tests.js","**/__tests__/**","*.interface.ts","*.type.ts","*.d.ts"];constructor(e="./routes",t){this.routesDir=He(process.cwd(),e),this.excludePatterns=t||M.DEFAULT_EXCLUDE_PATTERNS}async scan(){let e=[];if(!Me(this.routesDir))return[];try{await this.scanDirectory(this.routesDir,e)}catch(t){if(t.code==="ENOENT")return console.warn(` \u2717 Routes directory not accessible: ${this.routesDir}`),[];throw t}return e}isExcluded(e){let t=ne(this.routesDir,e);for(let d of this.excludePatterns){let n=d.replace(/\./g,"\\.").replace(/\*\*/g,"__GLOBSTAR__").replace(/\*/g,"[^/]*").replace(/__GLOBSTAR__/g,".*").replace(/\?/g,"."),r=new RegExp(`^${n}$`),o=t.split(re).pop()||"";if(r.test(t)||r.test(o))return!0}return!1}async scanDirectory(e,t,d=""){let n=await de.readdir(e);for(let r of n){let o=Ce(e,r);if((await de.stat(o)).isDirectory()){let a=d?`${d}/${r}`:r;await this.scanDirectory(o,t,a)}else if(r.endsWith(".ts")||r.endsWith(".js")){if(this.isExcluded(o))continue;let a=ne(this.routesDir,o).replace(/\.(ts|js)$/,"").split(re).join("/");try{let c=await import(process.platform==="win32"?`file:///${o.replace(/\\/g,"/")}`:o);if(c.default&&typeof c.default==="function")t.push({name:"default",path:o,method:"GET",options:{method:"GET",path:`/${a}`,expose:!0}});for(let[m,b]of Object.entries(c)){if(m==="default")continue;if(b&&typeof b==="object"&&"entry"in b&&"options"in b&&"handler"in b){let p=b;t.push({name:m,path:o,method:p.options.method,options:p.options})}else if(Array.isArray(b)&&b.length>=4){let[p,,,x]=b;t.push({name:m,path:o,method:p,options:{method:p,path:x,expose:!0}})}}}catch(s){console.error(`Failed to load route from ${o}:`,s)}}}}enableWatch(e){if(typeof Bun!=="undefined"&&Bun.env.NODE_ENV==="development")console.log(`Watching for route changes in ${this.routesDir}`),setInterval(async()=>{await e()},1000)}}class C{beforeHandlers=[];finallyHandlers=[];addBefore(...e){this.beforeHandlers.push(...e)}addFinally(...e){this.finallyHandlers.push(...e)}async executeBefore(e){if(this.beforeHandlers.length===0)return e;let t=e;for(let d of this.beforeHandlers){let n=await d(t);if(n instanceof Response)return n;t=n}return t}async executeFinally(e,t){if(this.finallyHandlers.length===0)return e;let d=e;for(let n of this.finallyHandlers)try{d=await n(d,t)}catch(r){console.error("After middleware error:",r)}return d}clone(){let e=new C;return e.beforeHandlers=[...this.beforeHandlers],e.finallyHandlers=[...this.finallyHandlers],e}clear(){this.beforeHandlers=[],this.finallyHandlers=[]}}function H(e){return process.platform==="win32"?`file:///${e.replace(/\\/g,"/")}`:e}function P(e){return RegExp(`^${e.replace(/\/+(\/|$)/g,"$1").replace(/(\/?\.?):(\w+)\+/g,"($1(?<$2>[\\s\\S]+))").replace(/(\/?\.?):(\w+)/g,"($1(?<$2>[^$1/]+?))").replace(/\./g,"\\.").replace(/(\/?)\*/g,"($1.*)?")}/*$`)}function oe(e){let t=e?.["~standard"];return!!t&&typeof t==="object"&&typeof t.validate==="function"&&t.version===1}async function ae(e,t){let d=await e["~standard"].validate(t),n=d?.issues;if(Array.isArray(n)&&n.length>0)return{success:!1,issues:n};return{success:!0,value:d?.value}}function ie(e){if(Array.isArray(e))return e;if(e&&typeof e==="object"&&Array.isArray(e.issues))return e.issues;if(e&&typeof e==="object"&&e.cause&&Array.isArray(e.cause.issues))return e.cause.issues;return null}function Oe(e){if(!Array.isArray(e))return[];let t=[];for(let d=0;d<e.length;d++){let n=e[d],r=n;if(n&&typeof n==="object"&&"key"in n)r=n.key;if(typeof r==="string"||typeof r==="number")t.push(r);else if(typeof r==="symbol")t.push(String(r));else if(r!==void 0&&r!==null)t.push(String(r))}return t}function _(e,t){let d=[];for(let n=0;n<e.length;n++){let r=e[n],o=r,i={message:typeof o?.message==="string"&&o.message.length>0?o.message:"Invalid value",path:Oe(o?.path)};if(typeof o?.code==="string")i.code=o.code;if(t)i.raw=r;d.push(i)}return d}function J(e,t){return{error:!0,message:"Validation failed",statusCode:422,source:"validation",target:e,issues:t,timestamp:new Date().toISOString()}}class N{middlewareManager;authManager;cacheManager;routeBooleanDefaults={};developmentMode=void 0;routeDefinitions=[];routeTable=Object.create(null);routeMatchers=[];corsHeadersEntries=null;corsHandler=null;constructor(e,t,d){this.middlewareManager=e,this.authManager=t,this.cacheManager=d}setCorsHeaders(e){this.corsHeadersEntries=e}setCorsHandler(e){this.corsHandler=e}setRouteBooleanDefaults(e){this.routeBooleanDefaults={...e}}setDevelopmentMode(e){this.developmentMode=e}applyRouteBooleanDefaults(e){let t={...e},d=this.routeBooleanDefaults,n=["auth","expose","rawRequest","validate","rawResponse"];for(let r of n)if(t[r]===void 0&&d[r]!==void 0)t[r]=d[r];return t}route(e,t){let d=this.applyRouteBooleanDefaults(e),n=d.method.toUpperCase(),r=d.path,o=this.wrapHandler(d,t),i=this.getOrCreateMethodMap(r);i[n]=o,this.routeDefinitions.push({method:n,path:r,options:d})}addRoute(e){let[t,,d,n]=e;if(!n)return;let r=this.getOrCreateMethodMap(n);r[t.toUpperCase()]=d[0];let o=t.toUpperCase();this.routeDefinitions.push({method:o,path:n,options:{method:o,path:n,expose:!0}})}bulkAddRoutes(e){for(let t of e)this.addRoute(t)}addStaticRoute(e,t){let d=this.routeTable[e];if(d&&!(d instanceof Response))throw new Error(`Cannot register static route for path "${e}" because method routes already exist.`);this.routeTable[e]=t,this.removeRouteMatcher(e)}getRouteTable(){return this.routeTable}getRoutes(){let e=[];for(let t of this.routeMatchers){let d=this.routeTable[t.path];if(!d||d instanceof Response)continue;for(let[n,r]of Object.entries(d))e.push([n,t.regex,[r],t.path])}return e}getRouteDefinitions(){return[...this.routeDefinitions]}clearRoutes(){this.routeTable=Object.create(null),this.routeMatchers=[],this.routeDefinitions=[]}sortRoutes(){}async handle(e){let t;try{t=new URL(e.url)}catch{return v.badRequest("Malformed request URL")}e._parsedUrl=t;let d=t.pathname;for(let n of this.routeMatchers){let r=n.path,o=this.routeTable[r];if(!o)continue;if(o instanceof Response)continue;let i=o;if(e.method==="OPTIONS"||e.method in i){let a=d.match(n.regex);if(a){try{e.params=a.groups??{}}catch{}let s=i[e.method]??i.GET;if(s){let c=await s(e);if(c)return c}}}}return j.NOT_FOUND.clone()}prepareRequest(e,t){if(!e.context)e.context={};let d=!!e.params&&typeof e.params==="object"&&!Array.isArray(e.params)&&Object.keys(e.params).length===0;if(t?.params!==void 0&&(e.params===void 0||d))try{e.params=t.params}catch{}if(t?.route!==void 0)e.route=t.route;if(t?.metadata!==void 0)e.metadata=t.metadata;if(e.query==null&&e.url)try{Object.defineProperty(e,"query",{get(){let n=this._parsedUrl??new URL(this.url),r=N.parseQuery(n);return Object.defineProperty(this,"query",{value:r,writable:!0,configurable:!0,enumerable:!0}),r},set(n){Object.defineProperty(this,"query",{value:n,writable:!0,configurable:!0,enumerable:!0})},configurable:!0,enumerable:!0})}catch{let n=e._parsedUrl??new URL(e.url);try{e.query=N.parseQuery(n)}catch{}}if(!Object.getOwnPropertyDescriptor(e,"cookies"))Object.defineProperty(e,"cookies",{get(){let n=this.headers.get("cookie")??"",r={};if(n)for(let o of n.split(";")){let i=o.indexOf("=");if(i>0)r[o.slice(0,i).trim()]=o.slice(i+1).trim()}return Object.defineProperty(this,"cookies",{value:r,writable:!0,configurable:!0,enumerable:!0}),r},configurable:!0,enumerable:!0})}resolveFallbackParams(e,t){if(!t)return;let d=e.params;if(d&&typeof d==="object"&&!Array.isArray(d)&&Object.keys(d).length>0)return;let n;try{n=(e._parsedUrl??new URL(e.url)).pathname}catch{return}let r=n.match(t);if(!r?.groups)return;return r.groups}wrapHandler(e,t){let d=e.path,n=d.includes(":")?P(d):null;return async(r)=>{let o=r,i=this.resolveFallbackParams(r,n);this.prepareRequest(o,{params:i,route:d,metadata:e.metadata});try{if(e.expose===!1)return v.forbidden("Forbidden");let a=await this.middlewareManager.executeBefore(o);if(a instanceof Response)return a;let s=a;if(e.auth)try{await this.authManager.authenticate(s)}catch(u){return v.unauthorized(u instanceof Error?u.message:"Authentication failed",e.responseContentType)}if(!e.rawRequest&&s.method!=="GET"&&s.method!=="HEAD"){let u=null;try{let f=s.headers.get("content-type");if(f?.startsWith("application/json"))u=await s.json();else if(f?.startsWith("application/x-www-form-urlencoded"))u=Object.fromEntries(await s.formData());else if(f?.startsWith("multipart/form-data"))u=await s.formData();else u=await s.text()}catch{u=null}this.setContentAndBodyAlias(s,u)}let c=await this.validateInputSchema(s,e);if(c)return c;let m,b=e.cache;if(b&&typeof b==="number"&&b>0){let u=this.cacheManager.generateKey(s,{authUser:s.authUser});m=await this.cacheManager.get(u,async()=>{let f=await t(s);if(f instanceof Response)return{_isResponse:!0,body:await f.text(),status:f.status,headers:Object.fromEntries(f.headers.entries())};return f},b)}else if(b&&typeof b==="object"&&b.ttl){let u=b.key||this.cacheManager.generateKey(s,{authUser:s.authUser});m=await this.cacheManager.get(u,async()=>{let f=await t(s);if(f instanceof Response)return{_isResponse:!0,body:await f.text(),status:f.status,headers:Object.fromEntries(f.headers.entries())};return f},b.ttl)}else m=await t(s);if(m&&typeof m==="object"&&m._isResponse===!0)m=new Response(m.body,{status:m.status,headers:m.headers});let p;if(e.rawResponse||m instanceof Response)p=m instanceof Response?m:new Response(m);else p=D(200,m,e.responseContentType);p=await this.middlewareManager.executeFinally(p,s);let x=this.corsHeadersEntries;if(x)for(let[u,f]of x)p.headers.set(u,f);else{let u=this.corsHandler;if(u)p=u(p,s)}return p}catch(a){if(a instanceof Response)return a;return console.error("Route handler error:",a),v.internalServerError(a instanceof Error?a.message:String(a),e.responseContentType)}}}isDevelopmentMode(){if(this.developmentMode!==void 0)return this.developmentMode;return(typeof Bun!=="undefined"?Bun.env.NODE_ENV:"development")!=="production"}async buildInputValidationPayload(e,t){let d=e.content;if(t.rawRequest&&e.method!=="GET"&&e.method!=="HEAD")try{d=await e.clone().text()}catch{d=null}return{params:e.params??{},query:e.query??{},headers:Object.fromEntries(e.headers.entries()),cookies:e.cookies??{},body:d}}applyValidatedInput(e,t){if(e.validatedInput=t,!t||typeof t!=="object")return;let d=t;if("params"in d)try{e.params=d.params}catch{}if("query"in d)try{e.query=d.query}catch{}if("cookies"in d)try{e.cookies=d.cookies}catch{}if("body"in d)this.setContentAndBodyAlias(e,d.body)}setContentAndBodyAlias(e,t){try{e.content=t}catch{return}this.setBodyAlias(e,t)}setBodyAlias(e,t){try{e.body=t}catch{}}async validateInputSchema(e,t){let d=t.schema?.input;if(!d)return null;if(t.validate===!1)return null;if(!oe(d))return v.internalServerError("Invalid route schema configuration",t.responseContentType);let n=this.isDevelopmentMode(),r=await this.buildInputValidationPayload(e,t);try{let o=await ae(d,r);if(o.success===!1){let i=_(o.issues,n);return D(422,J("input",i),t.responseContentType)}return this.applyValidatedInput(e,o.value),null}catch(o){let i=ie(o);if(i){let a=_(i,n);return D(422,J("input",a),t.responseContentType)}return v.internalServerError(o instanceof Error?o.message:"Validation failed",t.responseContentType)}}getOrCreateMethodMap(e){let t=this.routeTable[e];if(t instanceof Response)throw new Error(`Cannot register method route for path "${e}" because a static route already exists.`);if(t)return t;let d=Object.create(null);return this.routeTable[e]=d,this.addRouteMatcher(e),d}addRouteMatcher(e){if(this.routeMatchers.some((t)=>t.path===e))return;this.routeMatchers.push({path:e,regex:P(e),specificity:this.routeSpecificityScore(e)}),this.routeMatchers.sort((t,d)=>{if(t.specificity!==d.specificity)return d.specificity-t.specificity;return t.path.localeCompare(d.path)})}removeRouteMatcher(e){this.routeMatchers=this.routeMatchers.filter((t)=>t.path!==e)}static parseQuery(e){let t={};for(let[d,n]of e.searchParams)if(d in t){let r=t[d];if(Array.isArray(r))r.push(n);else t[d]=[r,n]}else t[d]=n;return t}routeSpecificityScore(e){let o=e.split("/").filter(Boolean),i=0;for(let a of o)if(a.includes("*"))i+=1;else if(a.startsWith(":"))i+=10;else i+=1000;if(i+=e.length,!e.includes(":")&&!e.includes("*"))i+=1e4;return i}}import{existsSync as ge}from"fs";import{join as Ke}from"path";function se(e,t){if(!e){if(typeof t.origin==="string"){if(t.origin==="*"&&t.credentials)return null;return t.origin}return null}if(typeof t.origin==="string"){if(t.origin==="*")return t.credentials?e:"*";return t.origin===e?e:null}if(Array.isArray(t.origin))return t.origin.includes(e)?e:null;if(typeof t.origin==="function")return t.origin(e)?e:null;return null}function le(e){return typeof e.origin==="string"&&e.origin==="*"&&e.credentials||Array.isArray(e.origin)||typeof e.origin==="function"}function ce(e,t,d){let n={};if(e){if(n["access-control-allow-origin"]=e,n["access-control-allow-methods"]=t.allowMethods,n["access-control-allow-headers"]=t.allowHeaders,n["access-control-expose-headers"]=t.exposeHeaders,n["access-control-max-age"]=String(t.maxAge),t.credentials)n["access-control-allow-credentials"]="true";if(d)n.vary="Origin"}return n}function Te(e,t){if(!e)return t;let d=e.split(",").map((r)=>r.trim()).filter(Boolean);if(!d.map((r)=>r.toLowerCase()).includes(t.toLowerCase()))d.push(t);return d.join(", ")}function be(e){return{preflight(t){let d=t.headers.get("origin")??void 0,n=se(d,e),r=Boolean(d&&n&&le(e));return new Response(null,{status:204,headers:ce(n,e,r)})},corsify(t,d){let n=d.headers.get("origin")??void 0,r=se(n,e);if(!r)return t;let o=Boolean(n&&le(e)),i=ce(r,e,o);for(let[a,s]of Object.entries(i)){if(a==="vary"){t.headers.set("vary",Te(t.headers.get("vary"),s));continue}t.headers.set(a,s)}return t}}}function me(e,t,d,n,r,o,i,a,s){let c=JSON.stringify(e).replace(/<\/script/gi,"<\\/script"),m=JSON.stringify(t),b=JSON.stringify(d),p=JSON.stringify(n),x=JSON.stringify(r),u=JSON.stringify(o),f=JSON.stringify(i),Ne=JSON.stringify(a),Ae=JSON.stringify(s);return`<!DOCTYPE html>
22
23
  <html lang="en">
23
24
  <head>
24
25
  <meta charset="UTF-8">
25
26
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
26
27
  <title>Vector API Documentation</title>
28
+ <link rel="apple-touch-icon" sizes="180x180" href=${u}>
29
+ <link rel="icon" type="image/png" sizes="32x32" href=${f}>
30
+ <link rel="icon" type="image/png" sizes="16x16" href=${Ne}>
31
+ <link rel="manifest" href=${Ae}>
27
32
  <script>
28
33
  if (localStorage.getItem('theme') === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
29
34
  document.documentElement.classList.add('dark');
@@ -31,7 +36,7 @@ ${t.join(`,
31
36
  document.documentElement.classList.remove('dark');
32
37
  }
33
38
  </script>
34
- <script src=${JSON.stringify(n)}></script>
39
+ <script src=${b}></script>
35
40
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
36
41
  <script>
37
42
  tailwind.config = {
@@ -39,7 +44,12 @@ ${t.join(`,
39
44
  theme: {
40
45
  extend: {
41
46
  colors: {
42
- brand: '#6366F1',
47
+ brand: {
48
+ DEFAULT: '#00A1FF',
49
+ mint: '#00FF8F',
50
+ soft: '#E4F5FF',
51
+ deep: '#007BC5',
52
+ },
43
53
  dark: { bg: '#0A0A0A', surface: '#111111', border: '#1F1F1F', text: '#EDEDED' },
44
54
  light: { bg: '#FFFFFF', surface: '#F9F9F9', border: '#E5E5E5', text: '#111111' }
45
55
  },
@@ -106,32 +116,44 @@ ${t.join(`,
106
116
  from { opacity: 0; transform: translateX(-6px); }
107
117
  to { opacity: 1; transform: translateX(0); }
108
118
  }
119
+ @keyframes spin {
120
+ to { transform: rotate(360deg); }
121
+ }
122
+ .button-spinner {
123
+ display: inline-block;
124
+ width: 0.875rem;
125
+ height: 0.875rem;
126
+ border: 2px solid currentColor;
127
+ border-right-color: transparent;
128
+ border-radius: 9999px;
129
+ animation: spin 700ms linear infinite;
130
+ }
109
131
  @media (prefers-reduced-motion: reduce) {
110
132
  *, *::before, *::after {
111
133
  animation: none !important;
112
134
  transition: none !important;
113
135
  }
114
136
  }
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; }
137
+ .json-key { color: #007bc5; }
138
+ .json-string { color: #334155; }
139
+ .json-number { color: #00a1ff; }
140
+ .json-boolean { color: #475569; }
141
+ .json-null { color: #64748b; }
142
+ .dark .json-key { color: #7dc9ff; }
143
+ .dark .json-string { color: #d1d9e6; }
144
+ .dark .json-number { color: #7dc9ff; }
145
+ .dark .json-boolean { color: #93a4bf; }
146
+ .dark .json-null { color: #7c8ba3; }
125
147
  </style>
126
148
  </head>
127
149
  <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
150
  <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
151
  <aside id="docs-sidebar" class="fixed inset-y-0 left-0 z-40 w-72 md:w-64 border-r border-light-border dark:border-dark-border bg-light-surface dark:bg-dark-surface flex flex-col flex-shrink-0 transition-transform duration-300 ease-out -translate-x-full md:translate-x-0 md:static md:z-auto transition-colors duration-150">
130
152
  <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>
153
+ <div class="flex items-center">
154
+ <img src=${p} alt="Vector" class="h-6 w-auto block dark:hidden" />
155
+ <img src=${x} alt="Vector" class="h-6 w-auto hidden dark:block" />
156
+ </div>
135
157
  <button id="sidebar-close" class="ml-auto p-1.5 rounded-full border border-light-border dark:border-dark-border bg-light-bg/90 dark:bg-dark-bg/90 opacity-90 hover:opacity-100 transition md:hidden" aria-label="Close Menu" title="Close Menu">
136
158
  <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
137
159
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
@@ -162,8 +184,8 @@ ${t.join(`,
162
184
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path>
163
185
  </svg>
164
186
  </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>
187
+ <img src=${p} alt="Vector" class="h-5 w-auto block dark:hidden" />
188
+ <img src=${x} alt="Vector" class="h-5 w-auto hidden dark:block" />
167
189
  </div>
168
190
  <div class="flex-1"></div>
169
191
  <button id="theme-toggle" class="p-2 rounded-md hover:bg-black/5 dark:hover:bg-white/5 transition-colors" aria-label="Toggle Dark Mode">
@@ -188,17 +210,22 @@ ${t.join(`,
188
210
  <div class="grid grid-cols-1 lg:grid-cols-12 gap-10">
189
211
  <div class="lg:col-span-5 space-y-8" id="params-column"></div>
190
212
  <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>
213
+ <div class="rounded-lg border border-light-border dark:border-dark-border bg-light-bg dark:bg-dark-bg overflow-hidden group">
214
+ <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">
215
+ <span class="text-xs font-mono text-light-text/70 dark:text-dark-text/70">cURL</span>
216
+ <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
217
  </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>
218
+ <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
219
  </div>
198
220
  <div class="mt-4 p-4 rounded-lg border border-light-border dark:border-dark-border bg-light-surface dark:bg-dark-surface">
199
221
  <div class="flex items-center justify-between mb-3">
200
222
  <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>
223
+ <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">
224
+ <span class="inline-flex items-center gap-2">
225
+ <span id="send-btn-spinner" class="button-spinner hidden" aria-hidden="true"></span>
226
+ <span id="send-btn-label">Submit</span>
227
+ </span>
228
+ </button>
202
229
  </div>
203
230
  <div class="space-y-4">
204
231
  <div>
@@ -232,7 +259,7 @@ ${t.join(`,
232
259
  </div>
233
260
  </div>
234
261
 
235
- <div>
262
+ <div id="response-section">
236
263
  <div class="flex items-center justify-between mb-2">
237
264
  <p class="text-xs font-semibold uppercase tracking-wider opacity-60">Response</p>
238
265
  </div>
@@ -259,7 +286,7 @@ ${t.join(`,
259
286
  <div class="flex items-center justify-between mb-3">
260
287
  <h3 id="expand-modal-title" class="text-sm font-semibold">Expanded View</h3>
261
288
  <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>
289
+ <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
290
  <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
291
  <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
265
292
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
@@ -276,14 +303,15 @@ ${t.join(`,
276
303
  </div>
277
304
 
278
305
  <script>
279
- const spec = ${d};
280
- const openapiPath = ${r};
306
+ const spec = ${c};
307
+ const openapiPath = ${m};
308
+ const methodBadgeDefault = "bg-black/5 text-light-text/80 dark:bg-white/10 dark:text-dark-text/80";
281
309
  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",
310
+ GET: "bg-brand-soft text-brand-deep dark:bg-brand/20 dark:text-brand",
311
+ POST: "bg-brand-soft text-brand-deep dark:bg-brand/20 dark:text-brand",
312
+ PUT: "bg-brand-soft text-brand-deep dark:bg-brand/20 dark:text-brand",
313
+ PATCH: "bg-brand-soft text-brand-deep dark:bg-brand/20 dark:text-brand",
314
+ DELETE: "bg-brand-soft text-brand-deep dark:bg-brand/20 dark:text-brand",
287
315
  };
288
316
 
289
317
  function getOperations() {
@@ -537,6 +565,16 @@ ${t.join(`,
537
565
  return;
538
566
  }
539
567
  for (const [tag, ops] of groups.entries()) {
568
+ ops.sort((a, b) => {
569
+ const byName = a.name.localeCompare(b.name, undefined, { sensitivity: "base" });
570
+ if (byName !== 0) return byName;
571
+
572
+ const byPath = a.path.localeCompare(b.path, undefined, { sensitivity: "base" });
573
+ if (byPath !== 0) return byPath;
574
+
575
+ return a.method.localeCompare(b.method, undefined, { sensitivity: "base" });
576
+ });
577
+
540
578
  const block = document.createElement("div");
541
579
  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
580
  block.querySelector("h3").textContent = tag;
@@ -548,14 +586,14 @@ ${t.join(`,
548
586
  const a = document.createElement("a");
549
587
  a.href = "#";
550
588
  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"
589
+ ? "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
590
  : "block px-2 py-1.5 rounded-md hover:bg-black/5 dark:hover:bg-white/5 transition-colors";
553
591
 
554
592
  const row = document.createElement("span");
555
593
  row.className = "flex items-center gap-2";
556
594
 
557
595
  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");
596
+ method.className = "px-1.5 py-0.5 rounded text-[10px] font-mono font-semibold " + (methodBadge[op.method] || methodBadgeDefault);
559
597
  method.textContent = op.method;
560
598
 
561
599
  const name = document.createElement("span");
@@ -664,7 +702,7 @@ ${t.join(`,
664
702
  '<details class="border-b border-light-border/50 dark:border-dark-border/50" open>' +
665
703
  '<summary class="list-none cursor-pointer py-2 flex justify-between items-center" style="padding-left:' +
666
704
  padding +
667
- 'px"><div class="flex items-center gap-2"><span class="text-xs opacity-70">▾</span><code class="text-sm font-mono">' +
705
+ 'px"><div class="flex items-center gap-2"><span class="text-xs opacity-70">\u25BE</span><code class="text-sm font-mono">' +
668
706
  name +
669
707
  '</code><span class="text-xs text-brand">' +
670
708
  requiredLabel +
@@ -694,6 +732,55 @@ ${t.join(`,
694
732
  );
695
733
  }
696
734
 
735
+ function renderResponseSchemasSection(responses) {
736
+ if (!responses || typeof responses !== "object") return "";
737
+
738
+ const statusCodes = Object.keys(responses).sort((a, b) => {
739
+ const aNum = Number(a);
740
+ const bNum = Number(b);
741
+ if (Number.isInteger(aNum) && Number.isInteger(bNum)) return aNum - bNum;
742
+ if (Number.isInteger(aNum)) return -1;
743
+ if (Number.isInteger(bNum)) return 1;
744
+ return a.localeCompare(b);
745
+ });
746
+
747
+ let sections = "";
748
+ for (const statusCode of statusCodes) {
749
+ const responseDef = responses[statusCode];
750
+ if (!responseDef || typeof responseDef !== "object") continue;
751
+
752
+ const jsonSchema =
753
+ responseDef.content &&
754
+ responseDef.content["application/json"] &&
755
+ responseDef.content["application/json"].schema;
756
+
757
+ if (!jsonSchema || typeof jsonSchema !== "object") continue;
758
+
759
+ const rootChildren = buildSchemaChildren(jsonSchema);
760
+ if (!rootChildren.length) continue;
761
+
762
+ let rows = "";
763
+ for (const child of rootChildren) {
764
+ rows += renderSchemaFieldNode(child, 0);
765
+ }
766
+
767
+ sections +=
768
+ '<div class="mb-4"><h4 class="text-xs font-mono uppercase tracking-wider opacity-70 mb-2">Status ' +
769
+ escapeHtml(statusCode) +
770
+ "</h4>" +
771
+ rows +
772
+ "</div>";
773
+ }
774
+
775
+ if (!sections) return "";
776
+
777
+ return (
778
+ '<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>' +
779
+ sections +
780
+ "</div>"
781
+ );
782
+ }
783
+
697
784
  function renderTryItParameterInputs(pathParams, queryParams) {
698
785
  const container = document.getElementById("request-param-inputs");
699
786
  if (!container || !selected) return;
@@ -977,6 +1064,19 @@ ${t.join(`,
977
1064
  }
978
1065
  }
979
1066
 
1067
+ function setSubmitLoading(isLoading) {
1068
+ const sendButton = document.getElementById("send-btn");
1069
+ const spinner = document.getElementById("send-btn-spinner");
1070
+ const label = document.getElementById("send-btn-label");
1071
+ if (!sendButton) return;
1072
+
1073
+ sendButton.disabled = isLoading;
1074
+ sendButton.classList.toggle("opacity-80", isLoading);
1075
+ sendButton.classList.toggle("cursor-wait", isLoading);
1076
+ if (spinner) spinner.classList.toggle("hidden", !isLoading);
1077
+ if (label) label.textContent = isLoading ? "Sending..." : "Submit";
1078
+ }
1079
+
980
1080
  function updateRequestPreview() {
981
1081
  if (!selected) return;
982
1082
 
@@ -1040,7 +1140,7 @@ ${t.join(`,
1040
1140
  document.getElementById("tag-description").textContent = op.description || "Interactive API documentation.";
1041
1141
  const methodNode = document.getElementById("endpoint-method");
1042
1142
  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");
1143
+ methodNode.className = "px-2.5 py-0.5 rounded-full text-xs font-mono font-medium " + (methodBadge[selected.method] || methodBadgeDefault);
1044
1144
  document.getElementById("endpoint-title").textContent = selected.name;
1045
1145
  document.getElementById("endpoint-path").textContent = selected.path;
1046
1146
 
@@ -1053,6 +1153,7 @@ ${t.join(`,
1053
1153
  html += renderParamSection("Header Parameters", headers);
1054
1154
 
1055
1155
  html += renderRequestBodySchemaSection(reqSchema);
1156
+ html += renderResponseSchemasSection(op.responses);
1056
1157
  document.getElementById("params-column").innerHTML = html || '<div class="text-sm opacity-70">No parameters</div>';
1057
1158
  renderTryItParameterInputs(path, query);
1058
1159
  renderHeaderInputs();
@@ -1103,14 +1204,18 @@ ${t.join(`,
1103
1204
  headers["Content-Type"] = "application/json";
1104
1205
  }
1105
1206
 
1207
+ setSubmitLoading(true);
1106
1208
  try {
1209
+ const requestStart = performance.now();
1107
1210
  const response = await fetch(requestPath, { method: selected.method, headers, body: body || undefined });
1108
1211
  const text = await response.text();
1212
+ const responseTimeMs = Math.round(performance.now() - requestStart);
1109
1213
  const contentType = response.headers.get("content-type") || "unknown";
1110
1214
  const formattedResponse = formatResponseText(text);
1111
1215
  const headerText =
1112
1216
  "Status: " + response.status + " " + response.statusText + "\\n" +
1113
- "Content-Type: " + contentType + "\\n\\n";
1217
+ "Content-Type: " + contentType + "\\n" +
1218
+ "Response Time: " + responseTimeMs + " ms\\n\\n";
1114
1219
  setResponseContent(
1115
1220
  headerText,
1116
1221
  formattedResponse.text,
@@ -1118,6 +1223,8 @@ ${t.join(`,
1118
1223
  );
1119
1224
  } catch (error) {
1120
1225
  setResponseContent("", "Request failed: " + String(error), false);
1226
+ } finally {
1227
+ setSubmitLoading(false);
1121
1228
  }
1122
1229
  });
1123
1230
 
@@ -1324,4 +1431,4 @@ ${t.join(`,
1324
1431
  renderEndpoint();
1325
1432
  </script>
1326
1433
  </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};
1434
+ </html>`}function z(e){let t=e?.["~standard"],d=t?.jsonSchema;return!!t&&typeof t==="object"&&t.version===1&&!!d&&typeof d.input==="function"&&typeof d.output==="function"}function fe(e){let t=0,d=[];return{openapiPath:e.split("/").map((r)=>{let o=/^:([A-Za-z0-9_]+)\+$/.exec(r);if(o?.[1])return d.push(o[1]),`{${o[1]}}`;let i=/^:([A-Za-z0-9_]+)$/.exec(r);if(i?.[1])return d.push(i[1]),`{${i[1]}}`;if(r==="*"){t+=1;let a=t===1?"wildcard":`wildcard${t}`;return d.push(a),`{${a}}`}return r}).join("/"),pathParamNames:d}}function Re(e){return fe(e).openapiPath}function Ue(e,t){return`${e.toLowerCase()}_${t}`.replace(/[:{}]/g,"").replace(/[^A-Za-z0-9_]+/g,"_").replace(/^_+|_+$/g,"")||`${e.toLowerCase()}_operation`}function $e(e){let t=e.split("/").filter(Boolean);for(let d of t)if(!d.startsWith(":")&&d!=="*")return d.toLowerCase();return"default"}function Pe(e){return fe(e).pathParamNames}function _e(e,t){let d=new Set((e.parameters||[]).filter((n)=>n.in==="path").map((n)=>String(n.name)));for(let n of Pe(t)){if(d.has(n))continue;(e.parameters||=[]).push({name:n,in:"path",required:!0,schema:{type:"string"}})}}function Je(e){let t=Number(e);if(!Number.isInteger(t))return!1;return t>=100&&t<200||t===204||t===205||t===304}function Se(e){if(e==="204")return"No Content";if(e==="205")return"Reset Content";if(e==="304")return"Not Modified";let t=Number(e);if(Number.isInteger(t)&&t>=100&&t<200)return"Informational";return"OK"}function Fe(e,t,d,n){if(!z(t)){let r=O(t);return S(r)?null:r}try{return t["~standard"].jsonSchema.input({target:d})}catch(r){let o=he(t,"input",d,r,e,void 0,n);if(o)return o;n.push(`[OpenAPI] Failed input schema conversion for ${e}: ${r instanceof Error?r.message:String(r)}. Falling back to a permissive JSON Schema.`);let i=O(t);return S(i)?null:i}}function pe(e,t,d,n,r){if(!z(d)){let o=O(d);return S(o)?null:o}try{return d["~standard"].jsonSchema.output({target:n})}catch(o){let i=he(d,"output",n,o,e,t,r);if(i)return i;return r.push(`[OpenAPI] Failed output schema conversion for ${e} (${t}): ${o instanceof Error?o.message:String(o)}. Falling back to a permissive JSON Schema.`),O(d)}}function y(e){return!!e&&typeof e==="object"&&!Array.isArray(e)}function S(e){return y(e)&&Object.keys(e).length===0}function he(e,t,d,n,r,o,i){if(!z(e))return null;let a=n instanceof Error?n.message:String(n);if(!(d==="openapi-3.0"&&a.includes("target 'openapi-3.0' is not supported")&&a.includes("draft-2020-12")&&a.includes("draft-07")))return null;try{let c=e["~standard"].jsonSchema[t]({target:"draft-07"});return i.push(t==="input"?`[OpenAPI] ${r} converter does not support openapi-3.0 target; using draft-07 conversion output.`:`[OpenAPI] ${r} (${o}) converter does not support openapi-3.0 target; using draft-07 conversion output.`),c}catch{return null}}function G(e){if(!e||typeof e!=="object")return null;let t=e;if(y(t._def))return t._def;if(y(t._zod)&&y(t._zod.def))return t._zod.def;if(t.kind==="schema"&&typeof t.type==="string")return t;return null}function ye(e){if(!e)return null;let t=e.typeName;if(typeof t==="string")return t;let d=e.type;if(typeof d==="string")return d;return null}function F(e){let t=["innerType","schema","type","out","in","left","right","wrapped","element"];for(let d of t)if(d in e)return e[d];return}function ze(e,t){for(let d of t){let n=e[d];if(n&&typeof n==="object"&&!Array.isArray(n))return n}return}function Ge(e){if(!e)return!1;let t=e.toLowerCase();return t.includes("optional")||t.includes("default")||t.includes("catch")}function Ve(e){let t=e,d=!1,n=0;while(n<8){n+=1;let r=G(t),o=ye(r);if(!r||!Ge(o))break;d=!0;let i=F(r);if(!i)break;t=i}return{schema:t,optional:d}}function Qe(e){let t=e.entries;if(y(t))return t;let d=e.shape;if(typeof d==="function")try{let n=d();return y(n)?n:{}}catch{return{}}return y(d)?d:{}}function ue(e){let t=e.values;if(Array.isArray(t))return t;if(t&&typeof t==="object")return Object.values(t);let d=e.entries;if(d&&typeof d==="object")return Object.values(d);let n=e.enum;if(n&&typeof n==="object")return Object.values(n);let r=e.options;if(Array.isArray(r))return r.map((o)=>{if(o&&typeof o==="object"&&"unit"in o)return o.unit;return o}).filter((o)=>o!==void 0);return[]}function Ye(e){let t=e.toLowerCase();if(t.includes("string"))return{type:"string"};if(t.includes("number"))return{type:"number"};if(t.includes("boolean"))return{type:"boolean"};if(t.includes("bigint"))return{type:"string"};if(t==="null"||t.includes("zodnull"))return{type:"null"};if(t.includes("any")||t.includes("unknown")||t.includes("never"))return{};if(t.includes("date"))return{type:"string",format:"date-time"};if(t.includes("custom"))return{type:"object",additionalProperties:!0};return null}function g(e,t=new WeakSet){if(!e||typeof e!=="object")return{};if(t.has(e))return{};t.add(e);let d=G(e),n=ye(d);if(!d||!n)return{};let r=Ye(n);if(r)return r;let o=n.toLowerCase();if(o.includes("object")){let a=Qe(d),s={},c=[];for(let[b,p]of Object.entries(a)){let x=Ve(p);if(s[b]=g(x.schema,t),!x.optional)c.push(b)}let m={type:"object",properties:s,additionalProperties:!0};if(c.length>0)m.required=c;return m}if(o.includes("array")){let a=ze(d,["element","items","innerType","type"])??{};return{type:"array",items:g(a,t)}}if(o.includes("record")){let a=d.valueType??d.valueSchema;return{type:"object",additionalProperties:a?g(a,t):!0}}if(o.includes("tuple")){let s=(Array.isArray(d.items)?d.items:[]).map((c)=>g(c,t));return{type:"array",prefixItems:s,minItems:s.length,maxItems:s.length}}if(o.includes("union")){let a=d.options??d.schemas??[];if(!Array.isArray(a)||a.length===0)return{};return{anyOf:a.map((s)=>g(s,t))}}if(o.includes("intersection")){let{left:a,right:s}=d;if(!a||!s)return{};return{allOf:[g(a,t),g(s,t)]}}if(o.includes("enum")){let a=ue(d);if(a.length>0){let s=a.every((b)=>typeof b==="string"),c=a.every((b)=>typeof b==="number"),m=a.every((b)=>typeof b==="boolean");if(s)return{type:"string",enum:a};if(c)return{type:"number",enum:a};if(m)return{type:"boolean",enum:a};return{enum:a}}return{}}if(o.includes("picklist")){let a=ue(d);if(a.length>0){if(a.every((c)=>typeof c==="string"))return{type:"string",enum:a};return{enum:a}}return{}}if(o.includes("literal")){let a=d.value;if(a===void 0)return{};let s=a===null?"null":typeof a;if(s==="string"||s==="number"||s==="boolean"||s==="null")return{type:s,const:a};return{const:a}}if(o.includes("nullable")){let a=F(d);if(!a)return{};return{anyOf:[g(a,t),{type:"null"}]}}if(o.includes("lazy")){let a=d.getter;if(typeof a!=="function")return{};try{return g(a(),t)}catch{return{}}}let i=F(d);if(i)return g(i,t);return{}}function O(e){if(!G(e))return{};return g(e)}function Xe(e,t){if(!y(t))return;if(t.type!=="object"||!y(t.properties)){e.requestBody={required:!0,content:{"application/json":{schema:t}}};return}let d=new Set(Array.isArray(t.required)?t.required:[]),n=t.properties,r=Array.isArray(e.parameters)?e.parameters:[],o=[{key:"params",in:"path"},{key:"query",in:"query"},{key:"headers",in:"header"},{key:"cookies",in:"cookie"}];for(let a of o){let s=n[a.key];if(!y(s))continue;if(s.type!=="object"||!y(s.properties))continue;let c=new Set(Array.isArray(s.required)?s.required:[]);for(let[m,b]of Object.entries(s.properties))r.push({name:m,in:a.in,required:a.in==="path"?!0:c.has(m),schema:y(b)?b:{}})}if(r.length>0){let a=new Map;for(let s of r)a.set(`${s.in}:${s.name}`,s);e.parameters=[...a.values()]}let i=n.body;if(i)e.requestBody={required:d.has("body"),content:{"application/json":{schema:y(i)?i:{}}}}}function We(e,t,d,n,r){let o=d.output;if(!o){e.responses={200:{description:"OK"}};return}let i={};if(typeof o==="object"&&o!==null&&"~standard"in o){let a=pe(t,"200",o,n,r);if(a)i["200"]={description:"OK",content:{"application/json":{schema:a}}};else i["200"]={description:"OK"}}else for(let[a,s]of Object.entries(o)){let c=String(a),m=pe(t,c,s,n,r),b=Se(c);if(m&&!Je(c))i[c]={description:b,content:{"application/json":{schema:m}}};else i[c]={description:b}}if(Object.keys(i).length===0)i["200"]={description:"OK"};e.responses=i}function xe(e,t){let d=[],n={};for(let i of e){if(i.options.expose===!1)continue;if(!i.method||!i.path)continue;let a=i.method.toLowerCase();if(a==="options")continue;let s=Re(i.path),c={operationId:Ue(a,s),tags:[i.options.schema?.tag||$e(i.path)]},m=Fe(i.path,i.options.schema?.input,t.target,d);if(m)Xe(c,m);_e(c,i.path),We(c,i.path,i.options.schema||{},t.target,d),n[s]||={},n[s][a]=c}return{document:{openapi:t.target==="openapi-3.0"?"3.0.3":"3.1.0",info:{title:t.info?.title||"Vector API",version:t.info?.version||"1.0.0",...t.info?.description?{description:t.info.description}:{}},paths:n},warnings:d}}var V="/_vector/openapi/tailwindcdn.js",Q="/_vector/openapi/logo_dark.svg",Y="/_vector/openapi/logo_white.svg",Ie="/_vector/openapi/favicon/apple-touch-icon.png",we="/_vector/openapi/favicon/favicon-32x32.png",Le="/_vector/openapi/favicon/favicon-16x16.png",Ze="/_vector/openapi/favicon/favicon.ico",De="/_vector/openapi/favicon/site.webmanifest",qe="/_vector/openapi/favicon/android-chrome-192x192.png",et="/_vector/openapi/favicon/android-chrome-512x512.png",tt=["../openapi/assets/tailwindcdn.js","../src/openapi/assets/tailwindcdn.js","../../src/openapi/assets/tailwindcdn.js"],dt=["../openapi/assets/logo_dark.svg","../src/openapi/assets/logo_dark.svg","../../src/openapi/assets/logo_dark.svg"],nt=["../openapi/assets/logo_white.svg","../src/openapi/assets/logo_white.svg","../../src/openapi/assets/logo_white.svg"],rt=["src/openapi/assets/tailwindcdn.js","openapi/assets/tailwindcdn.js","dist/openapi/assets/tailwindcdn.js"],ot=["src/openapi/assets/logo_dark.svg","openapi/assets/logo_dark.svg","dist/openapi/assets/logo_dark.svg"],at=["src/openapi/assets/logo_white.svg","openapi/assets/logo_white.svg","dist/openapi/assets/logo_white.svg"],B=["../openapi/assets/favicon","../src/openapi/assets/favicon","../../src/openapi/assets/favicon"],I=["src/openapi/assets/favicon","openapi/assets/favicon","dist/openapi/assets/favicon"],it="/* OpenAPI docs runtime asset missing: tailwind disabled */";function h(e,t){return e.map((d)=>`${d}/${t}`)}function k(e,t){for(let n of e)try{let r=new URL(n,import.meta.url);if(ge(r))return Bun.file(r)}catch{}let d=process.cwd();for(let n of t){let r=Ke(d,n);if(ge(r))return Bun.file(r)}return null}var ke=k(tt,rt),Ee=k(dt,ot),ve=k(nt,at),st=k(h(B,"apple-touch-icon.png"),h(I,"apple-touch-icon.png")),lt=k(h(B,"favicon-32x32.png"),h(I,"favicon-32x32.png")),ct=k(h(B,"favicon-16x16.png"),h(I,"favicon-16x16.png")),bt=k(h(B,"favicon.ico"),h(I,"favicon.ico")),mt=k(h(B,"site.webmanifest"),h(I,"site.webmanifest")),pt=k(h(B,"android-chrome-192x192.png"),h(I,"android-chrome-192x192.png")),ut=k(h(B,"android-chrome-512x512.png"),h(I,"android-chrome-512x512.png")),Be=[{path:Ie,file:st,contentType:"image/png",filename:"apple-touch-icon.png"},{path:we,file:lt,contentType:"image/png",filename:"favicon-32x32.png"},{path:Le,file:ct,contentType:"image/png",filename:"favicon-16x16.png"},{path:Ze,file:bt,contentType:"image/x-icon",filename:"favicon.ico"},{path:De,file:mt,contentType:"application/manifest+json; charset=utf-8",filename:"site.webmanifest"},{path:qe,file:pt,contentType:"image/png",filename:"android-chrome-192x192.png"},{path:et,file:ut,contentType:"image/png",filename:"android-chrome-512x512.png"}],X="public, max-age=0, must-revalidate",A="public, max-age=31536000, immutable",W="no-store";function ft(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function ht(e){let t="^";for(let d of e){if(d==="*"){t+=".*";continue}t+=ft(d)}return t+="$",new RegExp(t)}function yt(e,t){if(!t.includes("*"))return e===t;return ht(t).test(e)}class K{server=null;router;config;openapiConfig;openapiDocCache=null;openapiDocsHtmlCache=null;openapiWarningsLogged=!1;openapiTailwindMissingLogged=!1;openapiLogoDarkMissingLogged=!1;openapiLogoWhiteMissingLogged=!1;corsHandler=null;corsHeadersEntries=null;constructor(e,t){if(this.router=e,this.config=t,this.openapiConfig=this.normalizeOpenAPIConfig(t.openapi,t.development),t.cors){let d=this.normalizeCorsOptions(t.cors),{preflight:n,corsify:r}=be(d);if(this.corsHandler={preflight:n,corsify:r},typeof d.origin==="string"&&(d.origin!=="*"||!d.credentials)){let i={"access-control-allow-origin":d.origin,"access-control-allow-methods":d.allowMethods,"access-control-allow-headers":d.allowHeaders,"access-control-expose-headers":d.exposeHeaders,"access-control-max-age":String(d.maxAge)};if(d.credentials)i["access-control-allow-credentials"]="true";this.corsHeadersEntries=Object.entries(i)}this.router.setCorsHeaders(this.corsHeadersEntries),this.router.setCorsHandler(this.corsHeadersEntries?null:this.corsHandler.corsify)}}normalizeOpenAPIConfig(e,t){let n=t!==!1&&!0;if(e===!1)return{enabled:!1,path:"/openapi.json",target:"openapi-3.0",docs:{enabled:!1,path:"/docs"}};if(e===!0)return{enabled:!0,path:"/openapi.json",target:"openapi-3.0",docs:{enabled:!1,path:"/docs"}};let r=e||{},o=r.docs,i=typeof o==="boolean"?{enabled:o,path:"/docs",exposePaths:void 0}:{enabled:o?.enabled===!0,path:o?.path||"/docs",exposePaths:Array.isArray(o?.exposePaths)?o.exposePaths.map((a)=>typeof a==="string"?a.trim():"").filter((a)=>a.length>0):void 0};return{enabled:r.enabled??n,path:r.path||"/openapi.json",target:r.target||"openapi-3.0",docs:i,info:r.info}}isDocsReservedPath(e){return e===this.openapiConfig.path||this.openapiConfig.docs.enabled&&e===this.openapiConfig.docs.path}shouldLogOpenAPIConversionWarnings(){if(this.config.development===!1)return!1;let d=process.env.LOG_LEVEL;return typeof d==="string"&&d.toLowerCase()==="debug"}getOpenAPIDocument(){if(this.openapiDocCache)return this.openapiDocCache;let e=this.router.getRouteDefinitions().filter((d)=>!this.isDocsReservedPath(d.path)),t=xe(e,{target:this.openapiConfig.target,info:this.openapiConfig.info});if(!this.openapiWarningsLogged&&t.warnings.length>0){if(this.shouldLogOpenAPIConversionWarnings())for(let d of t.warnings)console.warn(d);this.openapiWarningsLogged=!0}return this.openapiDocCache=t.document,this.openapiDocCache}getOpenAPIDocumentForDocs(){let e=this.openapiConfig.docs.exposePaths,t=this.getOpenAPIDocument();if(!Array.isArray(e)||e.length===0)return t;let d=t.paths&&typeof t.paths==="object"&&!Array.isArray(t.paths)?t.paths:{},n={};for(let[r,o]of Object.entries(d))if(e.some((i)=>yt(r,i)))n[r]=o;return{...t,paths:n}}getOpenAPIDocsHtmlCacheEntry(){if(this.openapiDocsHtmlCache)return this.openapiDocsHtmlCache;let e=me(this.getOpenAPIDocumentForDocs(),this.openapiConfig.path,V,Q,Y,Ie,we,Le,De),t=Bun.gzipSync(e),d=`"${Bun.hash(e).toString(16)}"`;return this.openapiDocsHtmlCache={html:e,gzip:t,etag:d},this.openapiDocsHtmlCache}requestAcceptsGzip(e){let t=e.headers.get("accept-encoding");return Boolean(t&&/\bgzip\b/i.test(t))}validateReservedOpenAPIPaths(){if(!this.openapiConfig.enabled)return;let e=new Set([this.openapiConfig.path]);if(this.openapiConfig.docs.enabled){e.add(this.openapiConfig.docs.path),e.add(V),e.add(Q),e.add(Y);for(let r of Be)e.add(r.path)}let t=this.router.getRouteDefinitions().filter((r)=>e.has(r.path)).map((r)=>`${r.method} ${r.path}`),d=Object.entries(this.router.getRouteTable()).filter(([r,o])=>e.has(r)&&o instanceof Response).map(([r])=>`STATIC ${r}`),n=[...t,...d];if(n.length>0)throw new Error(`OpenAPI reserved path conflict: ${n.join(", ")}. Change your route path(s) or reconfigure openapi.path/docs.path.`)}tryHandleOpenAPIRequest(e){if(!this.openapiConfig.enabled||e.method!=="GET")return null;let t=new URL(e.url).pathname;if(t===this.openapiConfig.path)return Response.json(this.getOpenAPIDocument());if(this.openapiConfig.docs.enabled&&t===this.openapiConfig.docs.path){let{html:d,gzip:n,etag:r}=this.getOpenAPIDocsHtmlCacheEntry();if(e.headers.get("if-none-match")===r)return new Response(null,{status:304,headers:{etag:r,"cache-control":X,vary:"accept-encoding"}});if(this.requestAcceptsGzip(e))return new Response(n,{status:200,headers:{"content-type":"text/html; charset=utf-8","content-encoding":"gzip",etag:r,"cache-control":X,vary:"accept-encoding"}});return new Response(d,{status:200,headers:{"content-type":"text/html; charset=utf-8",etag:r,"cache-control":X,vary:"accept-encoding"}})}if(this.openapiConfig.docs.enabled&&t===V){if(!ke){if(!this.openapiTailwindMissingLogged)this.openapiTailwindMissingLogged=!0,console.warn('[OpenAPI] Missing docs runtime asset "tailwindcdn.js". Serving inline fallback script instead.');return new Response(it,{status:200,headers:{"content-type":"application/javascript; charset=utf-8","cache-control":A}})}return new Response(ke,{status:200,headers:{"content-type":"application/javascript; charset=utf-8","cache-control":A}})}if(this.openapiConfig.docs.enabled&&t===Q){if(!Ee){if(!this.openapiLogoDarkMissingLogged)this.openapiLogoDarkMissingLogged=!0,console.warn('[OpenAPI] Missing docs runtime asset "logo_dark.svg".');return new Response("OpenAPI docs runtime asset missing: logo_dark.svg",{status:404,headers:{"content-type":"text/plain; charset=utf-8","cache-control":W}})}return new Response(Ee,{status:200,headers:{"content-type":"image/svg+xml; charset=utf-8","cache-control":A}})}if(this.openapiConfig.docs.enabled&&t===Y){if(!ve){if(!this.openapiLogoWhiteMissingLogged)this.openapiLogoWhiteMissingLogged=!0,console.warn('[OpenAPI] Missing docs runtime asset "logo_white.svg".');return new Response("OpenAPI docs runtime asset missing: logo_white.svg",{status:404,headers:{"content-type":"text/plain; charset=utf-8","cache-control":W}})}return new Response(ve,{status:200,headers:{"content-type":"image/svg+xml; charset=utf-8","cache-control":A}})}if(this.openapiConfig.docs.enabled){let d=Be.find((n)=>n.path===t);if(d){if(!d.file)return new Response(`OpenAPI docs runtime asset missing: ${d.filename}`,{status:404,headers:{"content-type":"text/plain; charset=utf-8","cache-control":W}});return new Response(d.file,{status:200,headers:{"content-type":d.contentType,"cache-control":A}})}}return null}normalizeCorsOptions(e){return{origin:e.origin||"*",credentials:e.credentials!==!1,allowHeaders:Array.isArray(e.allowHeaders)?e.allowHeaders.join(", "):e.allowHeaders||"Content-Type, Authorization",allowMethods:Array.isArray(e.allowMethods)?e.allowMethods.join(", "):e.allowMethods||"GET, POST, PUT, PATCH, DELETE, OPTIONS",exposeHeaders:Array.isArray(e.exposeHeaders)?e.exposeHeaders.join(", "):e.exposeHeaders||"Authorization",maxAge:e.maxAge||86400}}applyCors(e,t){if(this.corsHeadersEntries){for(let[d,n]of this.corsHeadersEntries)e.headers.set(d,n);return e}if(this.corsHandler&&t)return this.corsHandler.corsify(e,t);return e}async start(){let e=this.config.port??3000,t=this.config.hostname||"localhost";this.validateReservedOpenAPIPaths();let d=async(n)=>{try{if(this.corsHandler&&n.method==="OPTIONS")return this.corsHandler.preflight(n);let r=this.tryHandleOpenAPIRequest(n);if(r)return this.applyCors(r,n);return this.applyCors(j.NOT_FOUND.clone(),n)}catch(r){return console.error("Server error:",r),this.applyCors(new Response("Internal Server Error",{status:500}),n)}};try{if(this.server=Bun.serve({port:e,hostname:t,reusePort:this.config.reusePort!==!1,routes:this.router.getRouteTable(),fetch:d,idleTimeout:this.config.idleTimeout??60,error:(n,r)=>{return console.error("[ERROR] Server error:",n),this.applyCors(new Response("Internal Server Error",{status:500}),r)}}),!this.server||!this.server.port)throw new Error(`Failed to start server on ${t}:${e} - server object is invalid`);return this.server}catch(n){if(n.code==="EADDRINUSE"||n.message?.includes("address already in use"))n.message=`Port ${e} is already in use`,n.port=e;else if(n.code==="EACCES"||n.message?.includes("permission denied"))n.message=`Permission denied to bind to port ${e}`,n.port=e;else if(n.message?.includes("EADDRNOTAVAIL"))n.message=`Cannot bind to hostname ${t}`,n.hostname=t;throw n}}stop(){if(this.server)this.server.stop(),this.server=null,this.openapiDocCache=null,this.openapiDocsHtmlCache=null,this.openapiWarningsLogged=!1,console.log("Server stopped")}getServer(){return this.server}getPort(){return this.server?.port??this.config.port??3000}getHostname(){return this.server?.hostname||this.config.hostname||"localhost"}getUrl(){let e=this.getPort();return`http://${this.getHostname()}:${e}`}}class w{static instance;router;server=null;middlewareManager;authManager;cacheManager;config={};routeScanner=null;routeGenerator=null;_protectedHandler=null;_cacheHandler=null;shutdownPromise=null;constructor(){this.middlewareManager=new C,this.authManager=new R,this.cacheManager=new U,this.router=new N(this.middlewareManager,this.authManager,this.cacheManager)}static getInstance(){if(!w.instance)w.instance=new w;return w.instance}setProtectedHandler(e){if(this._protectedHandler=e,e){this.authManager.setProtectedHandler(e);return}this.authManager.clearProtectedHandler()}getProtectedHandler(){return this._protectedHandler}setCacheHandler(e){if(this._cacheHandler=e,e){this.cacheManager.setCacheHandler(e);return}this.cacheManager.clearCacheHandler()}getCacheHandler(){return this._cacheHandler}addRoute(e,t){this.router.route(e,t)}async startServer(e){this.config={...this.config,...e};let t={...this.config.defaults?.route};if(this.router.setRouteBooleanDefaults(t),this.router.setDevelopmentMode(this.config.development),this.middlewareManager.clear(),this.config.autoDiscover!==!1)this.router.clearRoutes();if(e?.before)this.middlewareManager.addBefore(...e.before);if(e?.finally)this.middlewareManager.addFinally(...e.finally);if(typeof this.config.startup==="function")await this.config.startup();if(this.config.autoDiscover!==!1)await this.discoverRoutes();return this.server=new K(this.router,this.config),await this.server.start()}async discoverRoutes(){let e=this.config.routesDir||"./routes",t=this.config.routeExcludePatterns;if(this.routeScanner=new M(e,t),!this.routeGenerator)this.routeGenerator=new $;try{let d=await this.routeScanner.scan();if(d.length>0){if(this.config.development)await this.routeGenerator.generate(d);for(let n of d)try{let o=await import(H(n.path)),i=n.name==="default"?o.default:o[n.name];if(i){if(this.isRouteDefinition(i))this.router.route(i.options,i.handler),this.logRouteLoaded(i.options);else if(this.isRouteEntry(i))this.router.addRoute(i),this.logRouteLoaded(i);else if(typeof i==="function")this.router.route(n.options,i),this.logRouteLoaded(n.options)}}catch(r){console.error(`Failed to load route ${n.name} from ${n.path}:`,r)}}}catch(d){if(d.code!=="ENOENT"&&d.code!=="ENOTDIR")console.error("Failed to discover routes:",d)}}async loadRoute(e){if(typeof e==="function"){let t=e();if(this.isRouteEntry(t))this.router.addRoute(t)}else if(e&&typeof e==="object"){for(let[,t]of Object.entries(e))if(typeof t==="function"){let d=t();if(this.isRouteEntry(d))this.router.addRoute(d)}}}isRouteEntry(e){if(!Array.isArray(e)||e.length<3)return!1;let[t,d,n,r]=e;return typeof t==="string"&&d instanceof RegExp&&Array.isArray(n)&&n.length>0&&n.every((o)=>typeof o==="function")&&(r===void 0||typeof r==="string")}isRouteDefinition(e){return e!==null&&typeof e==="object"&&"entry"in e&&"options"in e&&"handler"in e&&typeof e.handler==="function"}logRouteLoaded(e){}stop(){if(this.server)this.server.stop(),this.server=null}async shutdown(){if(this.shutdownPromise)return this.shutdownPromise;this.shutdownPromise=(async()=>{if(this.stop(),typeof this.config.shutdown==="function")await this.config.shutdown()})();try{await this.shutdownPromise}finally{this.shutdownPromise=null}}getServer(){return this.server}getRouter(){return this.router}getCacheManager(){return this.cacheManager}getAuthManager(){return this.authManager}static resetInstance(){w.instance=null}}var Z=w.getInstance;function xt(e,t){return{entry:{method:e.method.toUpperCase(),path:e.path},options:e,handler:t}}function gt(e){let t=e??null;try{return JSON.stringify(t)}catch(d){if(d instanceof TypeError&&/\bbigint\b/i.test(d.message))return JSON.stringify(t,(n,r)=>typeof r==="bigint"?r.toString():r);throw d}}function l(e,t,d){let n={error:!0,message:t,statusCode:e,timestamp:new Date().toISOString()};return D(e,n,d)}var v={badRequest:(e="Bad Request",t)=>l(E.BAD_REQUEST,e,t),unauthorized:(e="Unauthorized",t)=>l(E.UNAUTHORIZED,e,t),paymentRequired:(e="Payment Required",t)=>l(402,e,t),forbidden:(e="Forbidden",t)=>l(E.FORBIDDEN,e,t),notFound:(e="Not Found",t)=>l(E.NOT_FOUND,e,t),methodNotAllowed:(e="Method Not Allowed",t)=>l(405,e,t),notAcceptable:(e="Not Acceptable",t)=>l(406,e,t),requestTimeout:(e="Request Timeout",t)=>l(408,e,t),conflict:(e="Conflict",t)=>l(E.CONFLICT,e,t),gone:(e="Gone",t)=>l(410,e,t),lengthRequired:(e="Length Required",t)=>l(411,e,t),preconditionFailed:(e="Precondition Failed",t)=>l(412,e,t),payloadTooLarge:(e="Payload Too Large",t)=>l(413,e,t),uriTooLong:(e="URI Too Long",t)=>l(414,e,t),unsupportedMediaType:(e="Unsupported Media Type",t)=>l(415,e,t),rangeNotSatisfiable:(e="Range Not Satisfiable",t)=>l(416,e,t),expectationFailed:(e="Expectation Failed",t)=>l(417,e,t),imATeapot:(e="I'm a teapot",t)=>l(418,e,t),misdirectedRequest:(e="Misdirected Request",t)=>l(421,e,t),unprocessableEntity:(e="Unprocessable Entity",t)=>l(E.UNPROCESSABLE_ENTITY,e,t),locked:(e="Locked",t)=>l(423,e,t),failedDependency:(e="Failed Dependency",t)=>l(424,e,t),tooEarly:(e="Too Early",t)=>l(425,e,t),upgradeRequired:(e="Upgrade Required",t)=>l(426,e,t),preconditionRequired:(e="Precondition Required",t)=>l(428,e,t),tooManyRequests:(e="Too Many Requests",t)=>l(429,e,t),requestHeaderFieldsTooLarge:(e="Request Header Fields Too Large",t)=>l(431,e,t),unavailableForLegalReasons:(e="Unavailable For Legal Reasons",t)=>l(451,e,t),internalServerError:(e="Internal Server Error",t)=>l(E.INTERNAL_SERVER_ERROR,e,t),notImplemented:(e="Not Implemented",t)=>l(501,e,t),badGateway:(e="Bad Gateway",t)=>l(502,e,t),serviceUnavailable:(e="Service Unavailable",t)=>l(503,e,t),gatewayTimeout:(e="Gateway Timeout",t)=>l(504,e,t),httpVersionNotSupported:(e="HTTP Version Not Supported",t)=>l(505,e,t),variantAlsoNegotiates:(e="Variant Also Negotiates",t)=>l(506,e,t),insufficientStorage:(e="Insufficient Storage",t)=>l(507,e,t),loopDetected:(e="Loop Detected",t)=>l(508,e,t),notExtended:(e="Not Extended",t)=>l(510,e,t),networkAuthenticationRequired:(e="Network Authentication Required",t)=>l(511,e,t),invalidArgument:(e="Invalid Argument",t)=>l(E.UNPROCESSABLE_ENTITY,e,t),rateLimitExceeded:(e="Rate Limit Exceeded",t)=>l(429,e,t),maintenance:(e="Service Under Maintenance",t)=>l(503,e,t),custom:(e,t,d)=>l(e,t,d)};function D(e,t,d=T.JSON){let n=d===T.JSON?gt(t):t;return new Response(n,{status:e,headers:{"content-type":d}})}import{existsSync as kt}from"fs";import{resolve as Et,isAbsolute as vt}from"path";class q{configPath;config=null;configSource="default";constructor(e){let t=e||"vector.config.ts";this.configPath=vt(t)?t:Et(process.cwd(),t)}async load(){if(kt(this.configPath))try{let t=await import(H(this.configPath));this.config=t.default||t,this.configSource="user"}catch(e){let t=e instanceof Error?e.message:String(e);console.error(`[vector] Failed to load config from ${this.configPath}: ${t}`),console.error("[vector] Server is using default configuration. Fix your config file and restart."),this.config={}}else this.config={};return await this.buildLegacyConfig()}getConfigSource(){return this.configSource}async buildLegacyConfig(){let e={};if(this.config)e.port=this.config.port,e.hostname=this.config.hostname,e.reusePort=this.config.reusePort,e.development=this.config.development,e.routesDir=this.config.routesDir||"./routes",e.routeExcludePatterns=this.config.routeExcludePatterns,e.idleTimeout=this.config.idleTimeout,e.defaults=this.config.defaults,e.openapi=this.config.openapi,e.startup=this.config.startup,e.shutdown=this.config.shutdown;if(e.autoDiscover=!0,this.config?.cors)if(typeof this.config.cors==="boolean")e.cors=this.config.cors?{origin:"*",credentials:!0,allowHeaders:"Content-Type, Authorization",allowMethods:"GET, POST, PUT, PATCH, DELETE, OPTIONS",exposeHeaders:"Authorization",maxAge:86400}:void 0;else e.cors=this.config.cors;if(this.config?.before)e.before=this.config.before;if(this.config?.after)e.finally=this.config.after;return e}async loadAuthHandler(){return this.config?.auth||null}async loadCacheHandler(){return this.config?.cache||null}getConfig(){return this.config}}async function Bt(e={}){let t=new q(e.configPath),d=await t.load(),n=t.getConfigSource(),r={...d};if(e.mutateConfig)r=await e.mutateConfig(r,{configSource:n});if(e.config)r={...r,...e.config};if(e.autoDiscover!==void 0)r.autoDiscover=e.autoDiscover;let o=Z(),i=e.protectedHandler!==void 0?e.protectedHandler:await t.loadAuthHandler(),a=e.cacheHandler!==void 0?e.cacheHandler:await t.loadCacheHandler();o.setProtectedHandler(i??null),o.setCacheHandler(a??null);let s=await o.startServer(r),c={...r,port:s.port??r.port??L.PORT,hostname:s.hostname||r.hostname||L.HOSTNAME,reusePort:r.reusePort!==!1,idleTimeout:r.idleTimeout??60};return{server:s,config:c,stop:()=>o.stop(),shutdown:()=>o.shutdown()}}export{Bt as startVector,xt as route,D as createResponse,v as APIError};
@@ -1,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"}