@danielgl/steampunk 0.0.6 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.cjs +16 -1
- package/dist/main.d.cts +124 -1
- package/dist/main.d.ts +124 -1
- package/dist/main.js +16 -1
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -1 +1,16 @@
|
|
|
1
|
-
"use strict";var P=Object.defineProperty;var fe=Object.getOwnPropertyDescriptor;var pe=Object.getOwnPropertyNames;var he=Object.prototype.hasOwnProperty;var a=(r,e)=>P(r,"name",{value:e,configurable:!0});var B=(r,e)=>()=>(r&&(e=r(r=0)),e);var F=(r,e)=>{for(var t in e)P(r,t,{get:e[t],enumerable:!0})},me=(r,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of pe(e))!he.call(r,s)&&s!==t&&P(r,s,{get:()=>e[s],enumerable:!(n=fe(e,s))||n.enumerable});return r};var _=r=>me(P({},"__esModule",{value:!0}),r);function R(){return r=>{Reflect.defineMetadata(ye,!0,r)}}function K(r){return(e,t,n)=>{let s=Reflect.getMetadata(j,e)||[];s.push({index:n,token:r}),Reflect.defineMetadata(j,s,e)}}var Te,ye,j,v=B(()=>{"use strict";Te=require("reflect-metadata"),ye=Symbol("INJECTABLE_WATERMARK"),j=Symbol("INJECT_METADATA");a(R,"Injectable");a(K,"Inject")});var ie={};F(ie,{JwtAuthService:()=>w});function ge(r,e,t,n){var s=arguments.length,i=s<3?e:n===null?n=Object.getOwnPropertyDescriptor(e,t):n,o;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")i=Reflect.decorate(r,e,t,n);else for(var c=r.length-1;c>=0;c--)(o=r[c])&&(i=(s<3?o(i):s>3?o(e,t,i):o(e,t))||i);return s>3&&i&&Object.defineProperty(e,t,i),i}function se(r,e){if(typeof Reflect=="object"&&typeof Reflect.metadata=="function")return Reflect.metadata(r,e)}function J(r){return btoa(r).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function oe(r){let e=r+"==".slice(2-r.length*3&3);return atob(e.replace(/-/g,"+").replace(/_/g,"/"))}var w,U=B(()=>{"use strict";v();a(ge,"_ts_decorate");a(se,"_ts_metadata");a(J,"base64UrlEncode");a(oe,"base64UrlDecode");w=class{static{a(this,"JwtAuthService")}secret;expiresIn;constructor(e){this.secret=e.secret,this.expiresIn=e.expiresIn??3600}async getKey(){let e=new TextEncoder;return crypto.subtle.importKey("raw",e.encode(this.secret),{name:"HMAC",hash:"SHA-256"},!1,["sign","verify"])}async sign(e){let t={alg:"HS256",typ:"JWT"},n=Math.floor(Date.now()/1e3),s={...e,iat:n,exp:n+this.expiresIn},i=J(JSON.stringify(t)),o=J(JSON.stringify(s)),c=`${i}.${o}`,l=await this.getKey(),u=new TextEncoder,p=await crypto.subtle.sign("HMAC",l,u.encode(c)),f=J(String.fromCharCode(...new Uint8Array(p)));return`${c}.${f}`}async verify(e){let t=e.split(".");if(t.length!==3)throw new Error("Invalid JWT format");let n=t[0],s=t[1],i=t[2],o=`${n}.${s}`,c=await this.getKey(),l=new TextEncoder,u=Uint8Array.from(oe(i),H=>H.charCodeAt(0));if(!await crypto.subtle.verify("HMAC",c,u,l.encode(o)))throw new Error("Invalid JWT signature");let f=JSON.parse(oe(s)),A=Math.floor(Date.now()/1e3);if(f.exp!==void 0&&f.exp<A)throw new Error("JWT expired");return f}};w=ge([R(),se("design:type",Function),se("design:paramtypes",[typeof JwtOptions>"u"?Object:JwtOptions])],w)});var Ae={};F(Ae,{Authorize:()=>z,Controller:()=>G,Delete:()=>V,FromBody:()=>re,FromContext:()=>ne,FromQuery:()=>te,FromRoute:()=>ee,Get:()=>X,HttpContext:()=>E,HttpResult:()=>y,Inject:()=>K,Injectable:()=>R,JwtAuthService:()=>w,Patch:()=>Y,Post:()=>Q,Put:()=>Z,ServiceCollection:()=>x,ServiceProvider:()=>T,WebApplication:()=>C,WebApplicationBuilder:()=>S,cors:()=>ce,throttle:()=>le});module.exports=_(Ae);var Se=require("reflect-metadata");v();var h=(function(r){return r[r.Singleton=0]="Singleton",r[r.Transient=1]="Transient",r[r.Scoped=2]="Scoped",r})({});var T=class r{static{a(this,"ServiceProvider")}descriptors;parent;singletonInstances=new Map;scopedInstances=new Map;trackedInstances=new Set;constructor(e,t){this.descriptors=e,this.parent=t}createScope(){return new r(this.descriptors,this.parent||this)}async dispose(){for(let e of this.trackedInstances)typeof e.onDestroy=="function"&&await e.onDestroy();this.trackedInstances.clear(),this.scopedInstances.clear(),this.singletonInstances.clear()}async resolve(e){let t=this.descriptors.find(n=>n.token===e);if(!t){if(this.parent)return this.parent.resolve(e);throw new Error(`Service not registered for token: ${e.toString()}`)}switch(t.lifetime){case h.Singleton:return this.resolveSingleton(t);case h.Scoped:return this.resolveScoped(t);case h.Transient:return this.resolveTransient(t)}}async resolveSingleton(e){let t=this.getRoot();if(t.singletonInstances.has(e.token))return t.singletonInstances.get(e.token);let n=await this.createInstance(t,e);return t.singletonInstances.set(e.token,n),n}async resolveScoped(e){if(this.scopedInstances.has(e.token))return this.scopedInstances.get(e.token);let t=await this.createInstance(this,e);return this.scopedInstances.set(e.token,t),t}async resolveTransient(e){return this.createInstance(this,e)}async createInstance(e,t){let n;if(t.implementationInstance!==void 0)n=t.implementationInstance;else if(t.implementationFactory)n=await t.implementationFactory(this);else if(t.implementationType)n=await this.instantiateClass(t.implementationType);else throw new Error(`Invalid service descriptor for token: ${t.token.toString()}`);let s=Symbol.for("steampunk:initialized");return typeof n.onInit=="function"&&!n[s]&&(await n.onInit(),n[s]=!0),typeof n.onDestroy=="function"&&t.lifetime!==h.Transient&&e.trackedInstances.add(n),n}getRoot(){return this.parent?this.parent.getRoot():this}async instantiateClass(e){let t=Reflect.getMetadata("design:paramtypes",e)||[],n=Reflect.getMetadata(j,e)||[],s=await Promise.all(t.map(async(i,o)=>{let c=n.find(u=>u.index===o),l=c?c.token:i;if(!l||l===Object||l===String||l===Number||l===Boolean)throw new Error(`Cannot resolve parameter at index ${o} for ${e.name}. Token could not be determined or is primitive. Cannot inject primitive types directly without @Inject().`);return this.resolve(l)}));return new e(...s)}};var x=class{static{a(this,"ServiceCollection")}descriptors=[];add(e){return this.descriptors.push(e),this}addSingleton(e,t){return this.add({token:e,implementationType:t||e,lifetime:h.Singleton})}addSingletonInstance(e,t){return this.add({token:e,implementationInstance:t,lifetime:h.Singleton})}addTransient(e,t){return this.add({token:e,implementationType:t||e,lifetime:h.Transient})}addScoped(e,t){return this.add({token:e,implementationType:t||e,lifetime:h.Scoped})}buildServiceProvider(){return new T(this.descriptors)}addControllers(e){return e.forEach(t=>this.addTransient(t)),this}};var E=class{static{a(this,"HttpContext")}request;items=new Map;constructor(e){this.request=e}get method(){return this.request.method}get url(){return this.request.url}get path(){return new URL(this.request.url).pathname}};var ke=require("reflect-metadata");var b=Symbol("AUTHORIZE_METADATA");function z(r){return(e,t)=>{let n={required:!0,roles:r};t!==void 0?Reflect.defineMetadata(b,n,e.constructor,t):Reflect.defineMetadata(b,n,e)}}a(z,"Authorize");var y=class r{static{a(this,"HttpResult")}status;body;headers;constructor(e,t,n={}){this.status=e,this.body=t!==void 0&&typeof t!="string"?JSON.stringify(t):t,this.headers=n}static ok(e){return new r(200,e)}static created(e,t){let n={};return t&&(n.Location=t),new r(201,e,n)}static noContent(){return new r(204)}static badRequest(e="Bad Request",t){let n=typeof e=="string"?{message:e,errors:t}:e;return new r(400,n)}static unauthorized(e="Unauthorized"){let t=typeof e=="string"?{message:e}:e;return new r(401,t)}static forbidden(e="Forbidden"){let t=typeof e=="string"?{message:e}:e;return new r(403,t)}static notFound(e="Not Found"){let t=typeof e=="string"?{message:e}:e;return new r(404,t)}static conflict(e="Conflict"){let t=typeof e=="string"?{message:e}:e;return new r(409,t)}static unprocessableEntity(e="Unprocessable Entity",t){let n=typeof e=="string"?{message:e,errors:t}:e;return new r(422,n)}static internalServerError(e="Internal Server Error"){let t=typeof e=="string"?{message:e}:e;return new r(500,t)}toResponse(){if(this.status===204||this.body===void 0)return new Response(null,{status:this.status,headers:this.headers});let e={"Content-Type":"application/json",...this.headers};return new Response(this.body,{status:this.status,headers:e})}};var $e=require("reflect-metadata");v();var I=Symbol("CONTROLLER_WATERMARK"),M=Symbol("ROUTE_METADATA"),L=Symbol("PARAM_METADATA");function G(r=""){return e=>{Reflect.defineMetadata(I,r,e),R()(e)}}a(G,"Controller");var O=a(r=>(e="")=>(t,n)=>{Reflect.hasMetadata(M,t.constructor)||Reflect.defineMetadata(M,[],t.constructor);let s=Reflect.getMetadata(M,t.constructor);s.push({method:r,path:e,methodName:n.toString()}),Reflect.defineMetadata(M,s,t.constructor)},"createRouteDecorator"),X=O("GET"),Q=O("POST"),Z=O("PUT"),V=O("DELETE"),Y=O("PATCH"),g=(function(r){return r[r.Route=0]="Route",r[r.Query=1]="Query",r[r.Body=2]="Body",r[r.Context=3]="Context",r})({});function ee(r,e){return(t,n,s)=>{N(t,n,{type:0,index:s,name:r,schema:e})}}a(ee,"FromRoute");function te(r,e){return(t,n,s)=>{N(t,n,{type:1,index:s,name:r,schema:e})}}a(te,"FromQuery");function re(r){return(e,t,n)=>{N(e,t,{type:2,index:n,schema:r})}}a(re,"FromBody");function ne(){return(r,e,t)=>{N(r,e,{type:3,index:t})}}a(ne,"FromContext");function N(r,e,t){let n=`${L.toString()}_${e.toString()}`;Reflect.hasMetadata(n,r.constructor)||Reflect.defineMetadata(n,[],r.constructor);let s=Reflect.getMetadata(n,r.constructor);s.push(t),Reflect.defineMetadata(n,s,r.constructor)}a(N,"addParamMetadata");async function we(r,e,t){if(!t.required)return null;let n=r.request.headers.get("authorization");if(!n||!n.startsWith("Bearer "))return new Response(JSON.stringify({message:"Unauthorized"}),{status:401,headers:{"Content-Type":"application/json"}});let s=n.slice(7),i;try{let{JwtAuthService:c}=(U(),_(ie));i=await e.resolve(c)}catch{return new Response(JSON.stringify({message:"JWT service not configured"}),{status:500,headers:{"Content-Type":"application/json"}})}let o;try{o=await i.verify(s)}catch{return new Response(JSON.stringify({message:"Unauthorized: invalid or expired token"}),{status:401,headers:{"Content-Type":"application/json"}})}if(t.roles&&t.roles.length>0){let c=o.roles??[];if(!t.roles.some(u=>c.includes(u)))return new Response(JSON.stringify({message:"Forbidden: insufficient permissions"}),{status:403,headers:{"Content-Type":"application/json"}})}return r.items.set("user",o),null}a(we,"checkAuth");var D=class{static{a(this,"Router")}routes=[];registerControllers(e){for(let t of e){let n=Reflect.getMetadata(I,t);if(n===void 0)continue;let s=Reflect.getMetadata(M,t)||[];for(let i of s){let o=`/${n}/${i.path}`.replace(/\/+/g,"/");o!=="/"&&o.endsWith("/")&&(o=o.slice(0,-1));let c=new URLPattern({pathname:o});this.routes.push({method:i.method,pattern:c,controller:t,methodName:i.methodName})}}}map(e,t,n){let s=t.startsWith("/")?t:`/${t}`;s!=="/"&&s.endsWith("/")&&(s=s.slice(0,-1));let i=new URLPattern({pathname:s});this.routes.push({method:e.toUpperCase(),pattern:i,handler:n})}middleware(){return async(e,t)=>{for(let n of this.routes){if(n.method!==e.method)continue;let s=n.pattern.exec({pathname:e.path});if(s){let i=e.items.get("scope");if(!i)throw new Error("DI Scope not found in HttpContext");let o;if(n.handler)o=await n.handler(e);else if(n.controller&&n.methodName){let c=Reflect.getMetadata(b,n.controller,n.methodName),l=Reflect.getMetadata(b,n.controller),u=c??l;if(u){let d=await we(e,i,u);if(d)return d}let p=await i.resolve(n.controller),f=`${L.toString()}_${n.methodName}`,A=Reflect.getMetadata(f,n.controller)||[],H=p[n.methodName].length,$=new Array(H).fill(void 0),de=A.some(d=>d.type===g.Body),q;de&&(q=await e.request.json().catch(()=>({})));let ue=new URL(e.request.url);for(let d of A){let m;if(d.type===g.Route&&d.name?m=s.pathname.groups[d.name]:d.type===g.Query&&d.name?m=ue.searchParams.get(d.name):d.type===g.Body?m=q:d.type===g.Context&&(m=e),d.schema){let k=d.schema.safeParse(m);if(!k.success)return y.unprocessableEntity("Validation failed",{errors:k.error.errors,target:g[d.type].toLowerCase(),name:d.name}).toResponse();m=k.data}$[d.index]=m}o=await p[n.methodName](...$)}return o instanceof Response?o:o instanceof y?o.toResponse():typeof o=="object"?Response.json(o):new Response(String(o))}}return t()}}};var ae=require("fs/promises"),W=require("path");var S=class{static{a(this,"WebApplicationBuilder")}services;controllers=[];constructor(){this.services=new x}async addControllers(e="controllers"){let t=(0,W.join)(process.cwd(),e);try{let n=await(0,ae.readdir)(t,{recursive:!0});for(let s of n)if(typeof s=="string"&&(s.endsWith(".ts")||s.endsWith(".js"))&&!s.endsWith(".d.ts")){let o=await import((0,W.join)(t,s));for(let c in o){let l=o[c];typeof l=="function"&&Reflect.hasMetadata(I,l)&&this.controllers.push(l)}}this.controllers.length>0&&this.services.addControllers(this.controllers)}catch(n){console.warn(`Could not discover controllers at ${t}:`,n)}return this}build(){let e=this.services.buildServiceProvider();return new C(e,this.controllers)}};var C=class{static{a(this,"WebApplication")}services;middlewares=[];controllersToMap=[];router;constructor(e,t=[]){this.services=e,this.controllersToMap.push(...t),this.router=new D}static createBuilder(){return new S}use(e){return this.middlewares.push(e),this}mapControllers(e){return this.controllersToMap.push(...e),this}mapGet(e,t){return this.router.map("GET",e,t),this}mapPost(e,t){return this.router.map("POST",e,t),this}mapPut(e,t){return this.router.map("PUT",e,t),this}mapDelete(e,t){return this.router.map("DELETE",e,t),this}mapPatch(e,t){return this.router.map("PATCH",e,t),this}async executePipeline(e){let t=-1,n=a(async i=>{if(i<=t)throw new Error("next() called multiple times");t=i;let o=this.middlewares[i];if(i===this.middlewares.length)return new Response(JSON.stringify({message:"Not found"}),{status:404});if(o)return o(e,n.bind(null,i+1))},"dispatch");return await n(0)||new Response(JSON.stringify({message:"Internal Server Error"}),{status:500})}run(e=3e3){let t=this;this.controllersToMap.length>0&&this.router.registerControllers(this.controllersToMap),this.use(this.router.middleware()),Bun.serve({port:e,async fetch(n){let s=t.services.createScope();try{let i=new E(n);return i.items.set("scope",s),await t.executePipeline(i)}finally{await s.dispose()}}}),console.log(`\u{1F680} Steampunk application is running on http://localhost:${e}`)}};v();U();function ce(r={}){return async(e,t)=>{let{request:n}=e,s=n.headers.get("origin"),i=await t();i||(i=new Response);let o=new Response(i.body,i);if(r.origin?typeof r.origin=="string"?o.headers.set("Access-Control-Allow-Origin",r.origin):Array.isArray(r.origin)&&s?r.origin.includes(s)&&o.headers.set("Access-Control-Allow-Origin",s):typeof r.origin=="function"&&s&&r.origin(s)&&o.headers.set("Access-Control-Allow-Origin",s):o.headers.set("Access-Control-Allow-Origin","*"),r.methods){let c=Array.isArray(r.methods)?r.methods.join(", "):r.methods;o.headers.set("Access-Control-Allow-Methods",c)}else o.headers.set("Access-Control-Allow-Methods","GET,HEAD,PUT,PATCH,POST,DELETE");if(r.allowedHeaders){let c=Array.isArray(r.allowedHeaders)?r.allowedHeaders.join(", "):r.allowedHeaders;o.headers.set("Access-Control-Allow-Headers",c)}else{let c=n.headers.get("access-control-request-headers");c&&o.headers.set("Access-Control-Allow-Headers",c)}if(r.exposedHeaders){let c=Array.isArray(r.exposedHeaders)?r.exposedHeaders.join(", "):r.exposedHeaders;o.headers.set("Access-Control-Expose-Headers",c)}return r.credentials&&o.headers.set("Access-Control-Allow-Credentials","true"),r.maxAge!==void 0&&o.headers.set("Access-Control-Max-Age",r.maxAge.toString()),n.method==="OPTIONS"?new Response(null,{headers:o.headers,status:204}):o}}a(ce,"cors");function le(r){let e=a(s=>{let i=s.request?.headers?.get("x-forwarded-for");return i?i.split(",")[0].trim():"global"},"defaultKeyGenerator"),t=r.keyGenerator||e,n=new Map;return async(s,i)=>{let o=t(s),c=Date.now(),l=n.get(o);if(l?c>l.resetTime?(l.count=1,l.resetTime=c+r.windowMs):l.count++:(l={count:1,resetTime:c+r.windowMs},n.set(o,l)),Math.random()<.05)for(let[f,A]of n.entries())Date.now()>A.resetTime&&n.delete(f);if(l.count>r.limit){let f=Math.ceil((l.resetTime-c)/1e3);return new Response("Too Many Requests",{status:429,headers:{"Retry-After":f.toString(),"X-RateLimit-Limit":r.limit.toString(),"X-RateLimit-Remaining":"0","X-RateLimit-Reset":Math.ceil(l.resetTime/1e3).toString()}})}let u=await i();u||(u=new Response);let p=new Response(u.body,u);return p.headers.set("X-RateLimit-Limit",r.limit.toString()),p.headers.set("X-RateLimit-Remaining",Math.max(0,r.limit-l.count).toString()),p.headers.set("X-RateLimit-Reset",Math.ceil(l.resetTime/1e3).toString()),p}}a(le,"throttle");0&&(module.exports={Authorize,Controller,Delete,FromBody,FromContext,FromQuery,FromRoute,Get,HttpContext,HttpResult,Inject,Injectable,JwtAuthService,Patch,Post,Put,ServiceCollection,ServiceProvider,WebApplication,WebApplicationBuilder,cors,throttle});
|
|
1
|
+
"use strict";var H=Object.defineProperty;var De=Object.getOwnPropertyDescriptor;var Ne=Object.getOwnPropertyNames;var qe=Object.prototype.hasOwnProperty;var a=(r,e)=>H(r,"name",{value:e,configurable:!0});var te=(r,e)=>()=>(r&&(e=r(r=0)),e);var re=(r,e)=>{for(var t in e)H(r,t,{get:e[t],enumerable:!0})},$e=(r,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of Ne(e))!qe.call(r,o)&&o!==t&&H(r,o,{get:()=>e[o],enumerable:!(n=De(e,o))||n.enumerable});return r};var ne=r=>$e(H({},"__esModule",{value:!0}),r);function C(){return r=>{Reflect.defineMetadata(ke,!0,r)}}function se(r){return(e,t,n)=>{let o=Reflect.getMetadata(L,e)||[];o.push({index:n,token:r}),Reflect.defineMetadata(L,o,e)}}var We,ke,L,D=te(()=>{"use strict";We=require("reflect-metadata"),ke=Symbol("INJECTABLE_WATERMARK"),L=Symbol("INJECT_METADATA");a(C,"Injectable");a(se,"Inject")});var Ie={};re(Ie,{JwtAuthService:()=>S});function Le(r,e,t,n){var o=arguments.length,s=o<3?e:n===null?n=Object.getOwnPropertyDescriptor(e,t):n,i;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")s=Reflect.decorate(r,e,t,n);else for(var c=r.length-1;c>=0;c--)(i=r[c])&&(s=(o<3?i(s):o>3?i(e,t,s):i(e,t))||s);return o>3&&s&&Object.defineProperty(e,t,s),s}function Se(r,e){if(typeof Reflect=="object"&&typeof Reflect.metadata=="function")return Reflect.metadata(r,e)}function Z(r){return btoa(r).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function be(r){let e=r+"==".slice(2-r.length*3&3);return atob(e.replace(/-/g,"+").replace(/_/g,"/"))}var S,V=te(()=>{"use strict";D();a(Le,"_ts_decorate");a(Se,"_ts_metadata");a(Z,"base64UrlEncode");a(be,"base64UrlDecode");S=class{static{a(this,"JwtAuthService")}secret;expiresIn;constructor(e){this.secret=e.secret,this.expiresIn=e.expiresIn??3600}async getKey(){let e=new TextEncoder;return crypto.subtle.importKey("raw",e.encode(this.secret),{name:"HMAC",hash:"SHA-256"},!1,["sign","verify"])}async sign(e){let t={alg:"HS256",typ:"JWT"},n=Math.floor(Date.now()/1e3),o={...e,iat:n,exp:n+this.expiresIn},s=Z(JSON.stringify(t)),i=Z(JSON.stringify(o)),c=`${s}.${i}`,l=await this.getKey(),p=new TextEncoder,f=await crypto.subtle.sign("HMAC",l,p.encode(c)),m=Z(String.fromCharCode(...new Uint8Array(f)));return`${c}.${m}`}async verify(e){let t=e.split(".");if(t.length!==3)throw new Error("Invalid JWT format");let n=t[0],o=t[1],s=t[2],i=`${n}.${o}`,c=await this.getKey(),l=new TextEncoder,p=Uint8Array.from(be(s),b=>b.charCodeAt(0));if(!await crypto.subtle.verify("HMAC",c,p,l.encode(i)))throw new Error("Invalid JWT signature");let m=JSON.parse(be(o)),w=Math.floor(Date.now()/1e3);if(m.exp!==void 0&&m.exp<w)throw new Error("JWT expired");return m}};S=Le([C(),Se("design:type",Function),Se("design:paramtypes",[typeof JwtOptions>"u"?Object:JwtOptions])],S)});var Je={};re(Je,{ApiBody:()=>xe,ApiOperation:()=>we,ApiProperty:()=>ye,ApiQuery:()=>Me,ApiResponse:()=>Te,ApiTags:()=>Re,Authorize:()=>Ee,Controller:()=>oe,Delete:()=>le,FromBody:()=>fe,FromContext:()=>me,FromQuery:()=>ue,FromRoute:()=>de,Get:()=>ie,HttpContext:()=>O,HttpResult:()=>E,Inject:()=>se,Injectable:()=>C,JwtAuthService:()=>S,Patch:()=>pe,Post:()=>ae,Put:()=>ce,ServiceCollection:()=>P,ServiceProvider:()=>v,WebApplication:()=>_,WebApplicationBuilder:()=>j,cors:()=>ve,scalar:()=>K,throttle:()=>Pe});module.exports=ne(Je);var ze=require("reflect-metadata");D();var A=(function(r){return r[r.Singleton=0]="Singleton",r[r.Transient=1]="Transient",r[r.Scoped=2]="Scoped",r})({});var v=class r{static{a(this,"ServiceProvider")}descriptors;parent;singletonInstances=new Map;scopedInstances=new Map;trackedInstances=new Set;constructor(e,t){this.descriptors=e,this.parent=t}createScope(){return new r(this.descriptors,this.parent||this)}async dispose(){for(let e of this.trackedInstances)typeof e.onDestroy=="function"&&await e.onDestroy();this.trackedInstances.clear(),this.scopedInstances.clear(),this.singletonInstances.clear()}async resolve(e){let t=this.descriptors.find(n=>n.token===e);if(!t){if(this.parent)return this.parent.resolve(e);throw new Error(`Service not registered for token: ${e.toString()}`)}switch(t.lifetime){case A.Singleton:return this.resolveSingleton(t);case A.Scoped:return this.resolveScoped(t);case A.Transient:return this.resolveTransient(t)}}async resolveSingleton(e){let t=this.getRoot();if(t.singletonInstances.has(e.token))return t.singletonInstances.get(e.token);let n=await this.createInstance(t,e);return t.singletonInstances.set(e.token,n),n}async resolveScoped(e){if(this.scopedInstances.has(e.token))return this.scopedInstances.get(e.token);let t=await this.createInstance(this,e);return this.scopedInstances.set(e.token,t),t}async resolveTransient(e){return this.createInstance(this,e)}async createInstance(e,t){let n;if(t.implementationInstance!==void 0)n=t.implementationInstance;else if(t.implementationFactory)n=await t.implementationFactory(this);else if(t.implementationType)n=await this.instantiateClass(t.implementationType);else throw new Error(`Invalid service descriptor for token: ${t.token.toString()}`);let o=Symbol.for("steampunk:initialized");return typeof n.onInit=="function"&&!n[o]&&(await n.onInit(),n[o]=!0),typeof n.onDestroy=="function"&&t.lifetime!==A.Transient&&e.trackedInstances.add(n),n}getRoot(){return this.parent?this.parent.getRoot():this}async instantiateClass(e){let t=Reflect.getMetadata("design:paramtypes",e)||[],n=Reflect.getMetadata(L,e)||[],o=await Promise.all(t.map(async(s,i)=>{let c=n.find(p=>p.index===i),l=c?c.token:s;if(!l||l===Object||l===String||l===Number||l===Boolean)throw new Error(`Cannot resolve parameter at index ${i} for ${e.name}. Token could not be determined or is primitive. Cannot inject primitive types directly without @Inject().`);return this.resolve(l)}));return new e(...o)}};var P=class{static{a(this,"ServiceCollection")}descriptors=[];add(e){return this.descriptors.push(e),this}addSingleton(e,t){return this.add({token:e,implementationType:t||e,lifetime:A.Singleton})}addSingletonInstance(e,t){return this.add({token:e,implementationInstance:t,lifetime:A.Singleton})}addTransient(e,t){return this.add({token:e,implementationType:t||e,lifetime:A.Transient})}addScoped(e,t){return this.add({token:e,implementationType:t||e,lifetime:A.Scoped})}buildServiceProvider(){return new v(this.descriptors)}addControllers(e){return e.forEach(t=>this.addTransient(t)),this}};var O=class{static{a(this,"HttpContext")}request;items=new Map;constructor(e){this.request=e}get method(){return this.request.method}get url(){return this.request.url}get path(){return new URL(this.request.url).pathname}};var ot=require("reflect-metadata");D();var M=Symbol("CONTROLLER_WATERMARK"),T=Symbol("ROUTE_METADATA"),N=Symbol("PARAM_METADATA");function oe(r=""){return e=>{Reflect.defineMetadata(M,r,e),C()(e)}}a(oe,"Controller");var q=a(r=>(e="")=>(t,n)=>{Reflect.hasMetadata(T,t.constructor)||Reflect.defineMetadata(T,[],t.constructor);let o=Reflect.getMetadata(T,t.constructor);o.push({method:r,path:e,methodName:n.toString()}),Reflect.defineMetadata(T,o,t.constructor)},"createRouteDecorator"),ie=q("GET"),ae=q("POST"),ce=q("PUT"),le=q("DELETE"),pe=q("PATCH"),h=(function(r){return r[r.Route=0]="Route",r[r.Query=1]="Query",r[r.Body=2]="Body",r[r.Context=3]="Context",r})({});function de(r,e){return(t,n,o)=>{B(t,n,{type:0,index:o,name:r,schema:e})}}a(de,"FromRoute");function ue(r,e){return(t,n,o)=>{B(t,n,{type:1,index:o,name:r,schema:e})}}a(ue,"FromQuery");function fe(r){return(e,t,n)=>{B(e,t,{type:2,index:n,schema:r})}}a(fe,"FromBody");function me(){return(r,e,t)=>{B(r,e,{type:3,index:t})}}a(me,"FromContext");function B(r,e,t){let n=`${N.toString()}_${e.toString()}`;Reflect.hasMetadata(n,r.constructor)||Reflect.defineMetadata(n,[],r.constructor);let o=Reflect.getMetadata(n,r.constructor);o.push(t),Reflect.defineMetadata(n,o,r.constructor)}a(B,"addParamMetadata");var lt=require("reflect-metadata");var J="steampunk:api_property";function ye(r={}){return(e,t)=>{let n=Reflect.getOwnMetadata(J,e.constructor)||[],o=Reflect.getMetadata("design:type",e,t),s;o&&(o===String?s="string":o===Number?s="number":o===Boolean?s="boolean":o===Array?s="array":o===Object&&(s="object")),n.push({propertyKey:t.toString(),type:r.type??s,...r}),Reflect.defineMetadata(J,n,e.constructor)}}a(ye,"ApiProperty");function ge(r){let e=Reflect.getOwnMetadata(J,r)||[],t=[],n={};for(let s of e){if(s.required!==!1&&t.push(s.propertyKey),s.schema){n[s.propertyKey]=s.schema;continue}let i={};s.type!==void 0&&(typeof s.type=="string"?i.type=s.type:typeof s.type=="object"&&"type"in s.type&&(i.type=s.type.type,s.type.items&&(i.items=he(s.type.items)))),s.type==="array"&&s.items&&(i.items=he(s.items)),s.description&&(i.description=s.description),s.example!==void 0&&(i.example=s.example),s.nullable&&(i.nullable=!0),s.enum&&(i.enum=s.enum),s.default!==void 0&&(i.default=s.default),n[s.propertyKey]=i}let o={type:"object"};return Object.keys(n).length>0&&(o.properties=n),t.length>0&&(o.required=t),o}a(ge,"buildSchemaFromClass");function he(r){return typeof r=="string"?{type:r}:typeof r=="object"&&"$ref"in r||typeof r=="object"&&"type"in r?r:{}}a(he,"buildItemsSchema");function Ae(r){return typeof r=="function"&&Reflect.hasOwnMetadata(J,r)}a(Ae,"isDto");var ut=require("reflect-metadata");var Q="steampunk:api_tags",X="steampunk:api_operation",U="steampunk:api_response",Y="steampunk:api_body",W="steampunk:api_query";function Re(...r){return e=>{Reflect.defineMetadata(Q,r,e)}}a(Re,"ApiTags");function we(r){return(e,t)=>{Reflect.defineMetadata(X,r,e.constructor,t)}}a(we,"ApiOperation");function Te(r){return(e,t)=>{let n=Reflect.getMetadata(U,e.constructor,t)||[];n.push(r),Reflect.defineMetadata(U,n,e.constructor,t)}}a(Te,"ApiResponse");function xe(r){return(e,t)=>{Reflect.defineMetadata(Y,r,e.constructor,t)}}a(xe,"ApiBody");function Me(r){return(e,t)=>{let n=Reflect.getMetadata(W,e.constructor,t)||[];n.push(r),Reflect.defineMetadata(W,n,e.constructor,t)}}a(Me,"ApiQuery");var F=class{static{a(this,"OpenApiGenerator")}controllers;options;schemaRegistry=new Map;constructor(e,t){this.controllers=e,this.options=t}refFromClass(e){let t=e.name;return this.schemaRegistry.has(t)||this.schemaRegistry.set(t,ge(e)),{$ref:`#/components/schemas/${t}`}}resolveSchema(e,t){if(t)return t;if(e&&Ae(e))return this.refFromClass(e);if(e)return{type:"object",description:e.name}}generate(){let e={},t=[],n=new Set;for(let s of this.controllers){let i=Reflect.getMetadata(M,s);if(i===void 0)continue;let c=Reflect.getMetadata(Q,s)||[];for(let p of c)n.has(p)||(n.add(p),t.push({name:p}));let l=Reflect.getMetadata(T,s)||[];for(let p of l){let f=`/${i}/${p.path}`.replace(/\/+/g,"/");f!=="/"&&f.endsWith("/")&&(f=f.slice(0,-1));let m=f.replace(/:([^/]+)/g,"{$1}");e[m]||(e[m]={});let w=`${N.toString()}_${p.methodName}`,b=Reflect.getMetadata(w,s)||[],y=Reflect.getMetadata(X,s,p.methodName),k=Reflect.getMetadata(U,s,p.methodName)||[],g=Reflect.getMetadata(Y,s,p.methodName),z=Reflect.getMetadata(W,s,p.methodName)||[],u=[];for(let d of b)d.type===h.Route&&d.name?u.push({name:d.name,in:"path",required:!0,schema:d.schema??{type:"string"}}):d.type===h.Query&&d.name&&u.push({name:d.name,in:"query",required:!1,schema:d.schema??{type:"string"}});for(let d of z)u.find(_e=>_e.name===d.name)||u.push({name:d.name,in:"query",required:d.required??!1,description:d.description,schema:d.schema??{type:"string"},...d.example!==void 0?{example:d.example}:{}});let R=b.some(d=>d.type===h.Body),x;if(R||g){let d=this.resolveSchema(g?.type,g?.schema),I=g?.example;x={...g?.description?{description:g.description}:{},required:g?.required??!0,content:{"application/json":{...d?{schema:d}:{},...I!==void 0?{example:I}:{}}}}}let Oe=k.length>0?Object.fromEntries(k.map(d=>{let I=this.resolveSchema(d.type,d.schema);return[String(d.status),{description:d.description,...I?{content:{"application/json":{schema:I,...d.example!==void 0?{example:d.example}:{}}}}:{}}]})):{200:{description:"Success"}},je={...c.length>0?{tags:c}:{},...y?.summary?{summary:y.summary}:{},...y?.description?{description:y.description}:{},...y?.operationId?{operationId:y.operationId}:{operationId:`${s.name}_${p.methodName}`},...y?.deprecated?{deprecated:!0}:{},...u.length>0?{parameters:u}:{},...x?{requestBody:x}:{},responses:Oe};e[m][p.method.toLowerCase()]=je}}let o=this.schemaRegistry.size>0?{schemas:Object.fromEntries(this.schemaRegistry)}:void 0;return{openapi:"3.1.0",info:this.options.info,...this.options.servers?{servers:this.options.servers}:{},...t.length>0?{tags:t}:{},paths:e,...o?{components:o}:{}}}};var He=a((r,e)=>`<!doctype html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>${e} - API Docs</title>
|
|
5
|
+
<meta charset="utf-8" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<script
|
|
10
|
+
id="api-reference"
|
|
11
|
+
data-url="${r}"
|
|
12
|
+
data-configuration='{"theme":"purple"}'
|
|
13
|
+
></script>
|
|
14
|
+
<script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"></script>
|
|
15
|
+
</body>
|
|
16
|
+
</html>`,"SCALAR_HTML");function K(r,e,t={}){let n=t.docsPath??"/docs",o=t.specPath??"/openapi.json",s=null;return async(i,c)=>{let{path:l}=i;if(l===o){if(!s){let p=new F(r,e);s=JSON.stringify(p.generate(),null,2)}return new Response(s,{headers:{"Content-Type":"application/json"}})}return l===n||l===`${n}/`?new Response(He(o,e.info.title),{headers:{"Content-Type":"text/html; charset=utf-8"}}):c()}}a(K,"scalar");var Mt=require("reflect-metadata");var $=Symbol("AUTHORIZE_METADATA");function Ee(r){return(e,t)=>{let n={required:!0,roles:r};t!==void 0?Reflect.defineMetadata($,n,e.constructor,t):Reflect.defineMetadata($,n,e)}}a(Ee,"Authorize");var E=class r{static{a(this,"HttpResult")}status;body;headers;constructor(e,t,n={}){this.status=e,this.body=t!==void 0&&typeof t!="string"?JSON.stringify(t):t,this.headers=n}static ok(e){return new r(200,e)}static created(e,t){let n={};return t&&(n.Location=t),new r(201,e,n)}static noContent(){return new r(204)}static badRequest(e="Bad Request",t){let n=typeof e=="string"?{message:e,errors:t}:e;return new r(400,n)}static unauthorized(e="Unauthorized"){let t=typeof e=="string"?{message:e}:e;return new r(401,t)}static forbidden(e="Forbidden"){let t=typeof e=="string"?{message:e}:e;return new r(403,t)}static notFound(e="Not Found"){let t=typeof e=="string"?{message:e}:e;return new r(404,t)}static conflict(e="Conflict"){let t=typeof e=="string"?{message:e}:e;return new r(409,t)}static unprocessableEntity(e="Unprocessable Entity",t){let n=typeof e=="string"?{message:e,errors:t}:e;return new r(422,n)}static internalServerError(e="Internal Server Error"){let t=typeof e=="string"?{message:e}:e;return new r(500,t)}toResponse(){if(this.status===204||this.body===void 0)return new Response(null,{status:this.status,headers:this.headers});let e={"Content-Type":"application/json",...this.headers};return new Response(this.body,{status:this.status,headers:e})}};async function Be(r,e,t){if(!t.required)return null;let n=r.request.headers.get("authorization");if(!n||!n.startsWith("Bearer "))return new Response(JSON.stringify({message:"Unauthorized"}),{status:401,headers:{"Content-Type":"application/json"}});let o=n.slice(7),s;try{let{JwtAuthService:c}=(V(),ne(Ie));s=await e.resolve(c)}catch{return new Response(JSON.stringify({message:"JWT service not configured"}),{status:500,headers:{"Content-Type":"application/json"}})}let i;try{i=await s.verify(o)}catch{return new Response(JSON.stringify({message:"Unauthorized: invalid or expired token"}),{status:401,headers:{"Content-Type":"application/json"}})}if(t.roles&&t.roles.length>0){let c=i.roles??[];if(!t.roles.some(p=>c.includes(p)))return new Response(JSON.stringify({message:"Forbidden: insufficient permissions"}),{status:403,headers:{"Content-Type":"application/json"}})}return r.items.set("user",i),null}a(Be,"checkAuth");var G=class{static{a(this,"Router")}routes=[];registerControllers(e){for(let t of e){let n=Reflect.getMetadata(M,t);if(n===void 0)continue;let o=Reflect.getMetadata(T,t)||[];for(let s of o){let i=`/${n}/${s.path}`.replace(/\/+/g,"/");i!=="/"&&i.endsWith("/")&&(i=i.slice(0,-1));let c=new URLPattern({pathname:i});this.routes.push({method:s.method,pattern:c,controller:t,methodName:s.methodName})}}}map(e,t,n){let o=t.startsWith("/")?t:`/${t}`;o!=="/"&&o.endsWith("/")&&(o=o.slice(0,-1));let s=new URLPattern({pathname:o});this.routes.push({method:e.toUpperCase(),pattern:s,handler:n})}middleware(){return async(e,t)=>{for(let n of this.routes){if(n.method!==e.method)continue;let o=n.pattern.exec({pathname:e.path});if(o){let s=e.items.get("scope");if(!s)throw new Error("DI Scope not found in HttpContext");let i;if(n.handler)i=await n.handler(e);else if(n.controller&&n.methodName){let c=Reflect.getMetadata($,n.controller,n.methodName),l=Reflect.getMetadata($,n.controller),p=c??l;if(p){let u=await Be(e,s,p);if(u)return u}let f=await s.resolve(n.controller),m=`${N.toString()}_${n.methodName}`,w=Reflect.getMetadata(m,n.controller)||[],b=f[n.methodName].length,y=new Array(b).fill(void 0),k=w.some(u=>u.type===h.Body),g;k&&(g=await e.request.json().catch(()=>({})));let z=new URL(e.request.url);for(let u of w){let R;if(u.type===h.Route&&u.name?R=o.pathname.groups[u.name]:u.type===h.Query&&u.name?R=z.searchParams.get(u.name):u.type===h.Body?R=g:u.type===h.Context&&(R=e),u.schema){let x=u.schema.safeParse(R);if(!x.success)return E.unprocessableEntity("Validation failed",{errors:x.error.errors,target:h[u.type].toLowerCase(),name:u.name}).toResponse();R=x.data}y[u.index]=R}i=await f[n.methodName](...y)}return i instanceof Response?i:i instanceof E?i.toResponse():typeof i=="object"?Response.json(i):new Response(String(i))}}return t()}}};var Ce=require("fs/promises"),ee=require("path");var j=class{static{a(this,"WebApplicationBuilder")}services;controllers=[];constructor(){this.services=new P}async addControllers(e="controllers"){let t=(0,ee.join)(process.cwd(),e);try{let n=await(0,Ce.readdir)(t,{recursive:!0});for(let o of n)if(typeof o=="string"&&(o.endsWith(".ts")||o.endsWith(".js"))&&!o.endsWith(".d.ts")){let i=await import((0,ee.join)(t,o));for(let c in i){let l=i[c];typeof l=="function"&&Reflect.hasMetadata(M,l)&&this.controllers.push(l)}}this.controllers.length>0&&this.services.addControllers(this.controllers)}catch(n){console.warn(`Could not discover controllers at ${t}:`,n)}return this}build(){let e=this.services.buildServiceProvider();return new _(e,this.controllers)}};var _=class{static{a(this,"WebApplication")}services;middlewares=[];controllersToMap=[];router;constructor(e,t=[]){this.services=e,this.controllersToMap.push(...t),this.router=new G}static createBuilder(){return new j}use(e){return this.middlewares.push(e),this}mapControllers(e){return this.controllersToMap.push(...e),this}useOpenApi(e,t){let n=K(this.controllersToMap,e,t);return this.middlewares.push(n),this}mapGet(e,t){return this.router.map("GET",e,t),this}mapPost(e,t){return this.router.map("POST",e,t),this}mapPut(e,t){return this.router.map("PUT",e,t),this}mapDelete(e,t){return this.router.map("DELETE",e,t),this}mapPatch(e,t){return this.router.map("PATCH",e,t),this}async executePipeline(e){let t=-1,n=a(async s=>{if(s<=t)throw new Error("next() called multiple times");t=s;let i=this.middlewares[s];if(s===this.middlewares.length)return new Response(JSON.stringify({message:"Not found"}),{status:404});if(i)return i(e,n.bind(null,s+1))},"dispatch");return await n(0)||new Response(JSON.stringify({message:"Internal Server Error"}),{status:500})}run(e=3e3){let t=this;this.controllersToMap.length>0&&this.router.registerControllers(this.controllersToMap),this.use(this.router.middleware()),Bun.serve({port:e,async fetch(n){let o=t.services.createScope();try{let s=new O(n);return s.items.set("scope",o),await t.executePipeline(s)}finally{await o.dispose()}}}),console.log(`\u{1F680} Steampunk application is running on http://localhost:${e}`)}};D();V();function ve(r={}){return async(e,t)=>{let{request:n}=e,o=n.headers.get("origin"),s=await t();s||(s=new Response);let i=new Response(s.body,s);if(r.origin?typeof r.origin=="string"?i.headers.set("Access-Control-Allow-Origin",r.origin):Array.isArray(r.origin)&&o?r.origin.includes(o)&&i.headers.set("Access-Control-Allow-Origin",o):typeof r.origin=="function"&&o&&r.origin(o)&&i.headers.set("Access-Control-Allow-Origin",o):i.headers.set("Access-Control-Allow-Origin","*"),r.methods){let c=Array.isArray(r.methods)?r.methods.join(", "):r.methods;i.headers.set("Access-Control-Allow-Methods",c)}else i.headers.set("Access-Control-Allow-Methods","GET,HEAD,PUT,PATCH,POST,DELETE");if(r.allowedHeaders){let c=Array.isArray(r.allowedHeaders)?r.allowedHeaders.join(", "):r.allowedHeaders;i.headers.set("Access-Control-Allow-Headers",c)}else{let c=n.headers.get("access-control-request-headers");c&&i.headers.set("Access-Control-Allow-Headers",c)}if(r.exposedHeaders){let c=Array.isArray(r.exposedHeaders)?r.exposedHeaders.join(", "):r.exposedHeaders;i.headers.set("Access-Control-Expose-Headers",c)}return r.credentials&&i.headers.set("Access-Control-Allow-Credentials","true"),r.maxAge!==void 0&&i.headers.set("Access-Control-Max-Age",r.maxAge.toString()),n.method==="OPTIONS"?new Response(null,{headers:i.headers,status:204}):i}}a(ve,"cors");function Pe(r){let e=a(o=>{let s=o.request?.headers?.get("x-forwarded-for");return s?s.split(",")[0].trim():"global"},"defaultKeyGenerator"),t=r.keyGenerator||e,n=new Map;return async(o,s)=>{let i=t(o),c=Date.now(),l=n.get(i);if(l?c>l.resetTime?(l.count=1,l.resetTime=c+r.windowMs):l.count++:(l={count:1,resetTime:c+r.windowMs},n.set(i,l)),Math.random()<.05)for(let[m,w]of n.entries())Date.now()>w.resetTime&&n.delete(m);if(l.count>r.limit){let m=Math.ceil((l.resetTime-c)/1e3);return new Response("Too Many Requests",{status:429,headers:{"Retry-After":m.toString(),"X-RateLimit-Limit":r.limit.toString(),"X-RateLimit-Remaining":"0","X-RateLimit-Reset":Math.ceil(l.resetTime/1e3).toString()}})}let p=await s();p||(p=new Response);let f=new Response(p.body,p);return f.headers.set("X-RateLimit-Limit",r.limit.toString()),f.headers.set("X-RateLimit-Remaining",Math.max(0,r.limit-l.count).toString()),f.headers.set("X-RateLimit-Reset",Math.ceil(l.resetTime/1e3).toString()),f}}a(Pe,"throttle");0&&(module.exports={ApiBody,ApiOperation,ApiProperty,ApiQuery,ApiResponse,ApiTags,Authorize,Controller,Delete,FromBody,FromContext,FromQuery,FromRoute,Get,HttpContext,HttpResult,Inject,Injectable,JwtAuthService,Patch,Post,Put,ServiceCollection,ServiceProvider,WebApplication,WebApplicationBuilder,cors,scalar,throttle});
|
package/dist/main.d.cts
CHANGED
|
@@ -60,6 +60,36 @@ declare class HttpContext {
|
|
|
60
60
|
get path(): string;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
interface ApiInfo {
|
|
64
|
+
title: string;
|
|
65
|
+
version: string;
|
|
66
|
+
description?: string;
|
|
67
|
+
contact?: {
|
|
68
|
+
name?: string;
|
|
69
|
+
email?: string;
|
|
70
|
+
url?: string;
|
|
71
|
+
};
|
|
72
|
+
license?: {
|
|
73
|
+
name: string;
|
|
74
|
+
url?: string;
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
interface OpenApiOptions {
|
|
78
|
+
info: ApiInfo;
|
|
79
|
+
servers?: Array<{
|
|
80
|
+
url: string;
|
|
81
|
+
description?: string;
|
|
82
|
+
}>;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
interface ScalarOptions {
|
|
86
|
+
/** Path to serve the Scalar UI at. Default: "/docs" */
|
|
87
|
+
docsPath?: string;
|
|
88
|
+
/** Path to serve the OpenAPI JSON spec at. Default: "/openapi.json" */
|
|
89
|
+
specPath?: string;
|
|
90
|
+
}
|
|
91
|
+
declare function scalar(controllers: Array<any>, apiOptions: OpenApiOptions, scalarOptions?: ScalarOptions): Middleware;
|
|
92
|
+
|
|
63
93
|
declare class WebApplicationBuilder {
|
|
64
94
|
services: ServiceCollection;
|
|
65
95
|
private controllers;
|
|
@@ -78,6 +108,8 @@ declare class WebApplication {
|
|
|
78
108
|
static createBuilder(): WebApplicationBuilder;
|
|
79
109
|
use(middleware: Middleware): this;
|
|
80
110
|
mapControllers(controllers: Array<any>): this;
|
|
111
|
+
/** Mount the Scalar UI and OpenAPI spec automatically using the registered controllers. */
|
|
112
|
+
useOpenApi(apiOptions: OpenApiOptions, scalarOptions?: ScalarOptions): this;
|
|
81
113
|
mapGet(path: string, handler: (context: HttpContext) => any): this;
|
|
82
114
|
mapPost(path: string, handler: (context: HttpContext) => any): this;
|
|
83
115
|
mapPut(path: string, handler: (context: HttpContext) => any): this;
|
|
@@ -177,4 +209,95 @@ interface ThrottleOptions {
|
|
|
177
209
|
}
|
|
178
210
|
declare function throttle(options: ThrottleOptions): Middleware;
|
|
179
211
|
|
|
180
|
-
|
|
212
|
+
type ApiPropertyType = "string" | "number" | "integer" | "boolean" | "object" | "array" | {
|
|
213
|
+
type: "array";
|
|
214
|
+
items: string | Record<string, unknown>;
|
|
215
|
+
} | {
|
|
216
|
+
$ref: string;
|
|
217
|
+
};
|
|
218
|
+
interface ApiPropertyOptions {
|
|
219
|
+
description?: string;
|
|
220
|
+
example?: unknown;
|
|
221
|
+
required?: boolean;
|
|
222
|
+
type?: ApiPropertyType | string;
|
|
223
|
+
/** For array types, define the item type */
|
|
224
|
+
items?: ApiPropertyType | Record<string, unknown>;
|
|
225
|
+
/** Override with a raw JSON Schema fragment */
|
|
226
|
+
schema?: Record<string, unknown>;
|
|
227
|
+
/** Whether the property can be null */
|
|
228
|
+
nullable?: boolean;
|
|
229
|
+
/** Enum values */
|
|
230
|
+
enum?: Array<unknown>;
|
|
231
|
+
/** Default value */
|
|
232
|
+
default?: unknown;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Documents a class property for OpenAPI schema generation.
|
|
236
|
+
* Use this on DTO classes to enable automatic JSON Schema generation.
|
|
237
|
+
*
|
|
238
|
+
* @example
|
|
239
|
+
* class LoginDto {
|
|
240
|
+
* @ApiProperty({ description: 'Username', example: 'admin' })
|
|
241
|
+
* username: string;
|
|
242
|
+
*
|
|
243
|
+
* @ApiProperty({ description: 'Password', example: '1234' })
|
|
244
|
+
* password: string;
|
|
245
|
+
* }
|
|
246
|
+
*/
|
|
247
|
+
declare function ApiProperty(options?: ApiPropertyOptions): PropertyDecorator;
|
|
248
|
+
|
|
249
|
+
interface ApiOperationOptions {
|
|
250
|
+
summary?: string;
|
|
251
|
+
description?: string;
|
|
252
|
+
operationId?: string;
|
|
253
|
+
deprecated?: boolean;
|
|
254
|
+
}
|
|
255
|
+
interface ApiResponseOptions {
|
|
256
|
+
status: number;
|
|
257
|
+
description: string;
|
|
258
|
+
/** Pass a DTO class decorated with @ApiProperty to auto-generate the schema */
|
|
259
|
+
type?: new (...args: Array<any>) => any;
|
|
260
|
+
/** Raw JSON Schema override (takes precedence over type) */
|
|
261
|
+
schema?: Record<string, unknown>;
|
|
262
|
+
example?: unknown;
|
|
263
|
+
}
|
|
264
|
+
interface ApiBodyOptions {
|
|
265
|
+
description?: string;
|
|
266
|
+
required?: boolean;
|
|
267
|
+
/** Pass a DTO class decorated with @ApiProperty to auto-generate the schema */
|
|
268
|
+
type?: new (...args: Array<any>) => any;
|
|
269
|
+
/** Raw JSON Schema override (takes precedence over type) */
|
|
270
|
+
schema?: Record<string, unknown>;
|
|
271
|
+
example?: unknown;
|
|
272
|
+
}
|
|
273
|
+
interface ApiQueryParamOptions {
|
|
274
|
+
name: string;
|
|
275
|
+
description?: string;
|
|
276
|
+
required?: boolean;
|
|
277
|
+
schema?: Record<string, unknown>;
|
|
278
|
+
example?: unknown;
|
|
279
|
+
}
|
|
280
|
+
/** Groups routes under tags in the Scalar/Swagger UI */
|
|
281
|
+
declare function ApiTags(...tags: Array<string>): ClassDecorator;
|
|
282
|
+
/** Documents the operation with summary, description, operationId, deprecated */
|
|
283
|
+
declare function ApiOperation(options: ApiOperationOptions): MethodDecorator;
|
|
284
|
+
/**
|
|
285
|
+
* Documents a possible response for the route.
|
|
286
|
+
* Can be stacked multiple times for different status codes.
|
|
287
|
+
*
|
|
288
|
+
* @example
|
|
289
|
+
* @ApiResponse({ status: 200, type: UserDto })
|
|
290
|
+
* @ApiResponse({ status: 404, description: 'Not found' })
|
|
291
|
+
*/
|
|
292
|
+
declare function ApiResponse(options: ApiResponseOptions): MethodDecorator;
|
|
293
|
+
/**
|
|
294
|
+
* Documents the request body.
|
|
295
|
+
*
|
|
296
|
+
* @example
|
|
297
|
+
* @ApiBody({ type: CreateUserDto })
|
|
298
|
+
*/
|
|
299
|
+
declare function ApiBody(options: ApiBodyOptions): MethodDecorator;
|
|
300
|
+
/** Documents an additional query parameter (alongside or instead of @FromQuery) */
|
|
301
|
+
declare function ApiQuery(options: ApiQueryParamOptions): MethodDecorator;
|
|
302
|
+
|
|
303
|
+
export { ApiBody, type ApiBodyOptions, type ApiInfo, ApiOperation, type ApiOperationOptions, ApiProperty, type ApiPropertyOptions, ApiQuery, type ApiQueryParamOptions, ApiResponse, type ApiResponseOptions, ApiTags, Authorize, type AuthorizeOptions, Controller, type CorsOptions, Delete, FromBody, FromContext, FromQuery, FromRoute, Get, HttpContext, HttpResult, Inject, Injectable, JwtAuthService, type JwtOptions, type JwtPayload, type OnDestroy, type OnInit, type OpenApiOptions, Patch, Post, Put, type ScalarOptions, ServiceCollection, ServiceProvider, type ThrottleOptions, WebApplication, WebApplicationBuilder, cors, scalar, throttle };
|
package/dist/main.d.ts
CHANGED
|
@@ -60,6 +60,36 @@ declare class HttpContext {
|
|
|
60
60
|
get path(): string;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
interface ApiInfo {
|
|
64
|
+
title: string;
|
|
65
|
+
version: string;
|
|
66
|
+
description?: string;
|
|
67
|
+
contact?: {
|
|
68
|
+
name?: string;
|
|
69
|
+
email?: string;
|
|
70
|
+
url?: string;
|
|
71
|
+
};
|
|
72
|
+
license?: {
|
|
73
|
+
name: string;
|
|
74
|
+
url?: string;
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
interface OpenApiOptions {
|
|
78
|
+
info: ApiInfo;
|
|
79
|
+
servers?: Array<{
|
|
80
|
+
url: string;
|
|
81
|
+
description?: string;
|
|
82
|
+
}>;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
interface ScalarOptions {
|
|
86
|
+
/** Path to serve the Scalar UI at. Default: "/docs" */
|
|
87
|
+
docsPath?: string;
|
|
88
|
+
/** Path to serve the OpenAPI JSON spec at. Default: "/openapi.json" */
|
|
89
|
+
specPath?: string;
|
|
90
|
+
}
|
|
91
|
+
declare function scalar(controllers: Array<any>, apiOptions: OpenApiOptions, scalarOptions?: ScalarOptions): Middleware;
|
|
92
|
+
|
|
63
93
|
declare class WebApplicationBuilder {
|
|
64
94
|
services: ServiceCollection;
|
|
65
95
|
private controllers;
|
|
@@ -78,6 +108,8 @@ declare class WebApplication {
|
|
|
78
108
|
static createBuilder(): WebApplicationBuilder;
|
|
79
109
|
use(middleware: Middleware): this;
|
|
80
110
|
mapControllers(controllers: Array<any>): this;
|
|
111
|
+
/** Mount the Scalar UI and OpenAPI spec automatically using the registered controllers. */
|
|
112
|
+
useOpenApi(apiOptions: OpenApiOptions, scalarOptions?: ScalarOptions): this;
|
|
81
113
|
mapGet(path: string, handler: (context: HttpContext) => any): this;
|
|
82
114
|
mapPost(path: string, handler: (context: HttpContext) => any): this;
|
|
83
115
|
mapPut(path: string, handler: (context: HttpContext) => any): this;
|
|
@@ -177,4 +209,95 @@ interface ThrottleOptions {
|
|
|
177
209
|
}
|
|
178
210
|
declare function throttle(options: ThrottleOptions): Middleware;
|
|
179
211
|
|
|
180
|
-
|
|
212
|
+
type ApiPropertyType = "string" | "number" | "integer" | "boolean" | "object" | "array" | {
|
|
213
|
+
type: "array";
|
|
214
|
+
items: string | Record<string, unknown>;
|
|
215
|
+
} | {
|
|
216
|
+
$ref: string;
|
|
217
|
+
};
|
|
218
|
+
interface ApiPropertyOptions {
|
|
219
|
+
description?: string;
|
|
220
|
+
example?: unknown;
|
|
221
|
+
required?: boolean;
|
|
222
|
+
type?: ApiPropertyType | string;
|
|
223
|
+
/** For array types, define the item type */
|
|
224
|
+
items?: ApiPropertyType | Record<string, unknown>;
|
|
225
|
+
/** Override with a raw JSON Schema fragment */
|
|
226
|
+
schema?: Record<string, unknown>;
|
|
227
|
+
/** Whether the property can be null */
|
|
228
|
+
nullable?: boolean;
|
|
229
|
+
/** Enum values */
|
|
230
|
+
enum?: Array<unknown>;
|
|
231
|
+
/** Default value */
|
|
232
|
+
default?: unknown;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Documents a class property for OpenAPI schema generation.
|
|
236
|
+
* Use this on DTO classes to enable automatic JSON Schema generation.
|
|
237
|
+
*
|
|
238
|
+
* @example
|
|
239
|
+
* class LoginDto {
|
|
240
|
+
* @ApiProperty({ description: 'Username', example: 'admin' })
|
|
241
|
+
* username: string;
|
|
242
|
+
*
|
|
243
|
+
* @ApiProperty({ description: 'Password', example: '1234' })
|
|
244
|
+
* password: string;
|
|
245
|
+
* }
|
|
246
|
+
*/
|
|
247
|
+
declare function ApiProperty(options?: ApiPropertyOptions): PropertyDecorator;
|
|
248
|
+
|
|
249
|
+
interface ApiOperationOptions {
|
|
250
|
+
summary?: string;
|
|
251
|
+
description?: string;
|
|
252
|
+
operationId?: string;
|
|
253
|
+
deprecated?: boolean;
|
|
254
|
+
}
|
|
255
|
+
interface ApiResponseOptions {
|
|
256
|
+
status: number;
|
|
257
|
+
description: string;
|
|
258
|
+
/** Pass a DTO class decorated with @ApiProperty to auto-generate the schema */
|
|
259
|
+
type?: new (...args: Array<any>) => any;
|
|
260
|
+
/** Raw JSON Schema override (takes precedence over type) */
|
|
261
|
+
schema?: Record<string, unknown>;
|
|
262
|
+
example?: unknown;
|
|
263
|
+
}
|
|
264
|
+
interface ApiBodyOptions {
|
|
265
|
+
description?: string;
|
|
266
|
+
required?: boolean;
|
|
267
|
+
/** Pass a DTO class decorated with @ApiProperty to auto-generate the schema */
|
|
268
|
+
type?: new (...args: Array<any>) => any;
|
|
269
|
+
/** Raw JSON Schema override (takes precedence over type) */
|
|
270
|
+
schema?: Record<string, unknown>;
|
|
271
|
+
example?: unknown;
|
|
272
|
+
}
|
|
273
|
+
interface ApiQueryParamOptions {
|
|
274
|
+
name: string;
|
|
275
|
+
description?: string;
|
|
276
|
+
required?: boolean;
|
|
277
|
+
schema?: Record<string, unknown>;
|
|
278
|
+
example?: unknown;
|
|
279
|
+
}
|
|
280
|
+
/** Groups routes under tags in the Scalar/Swagger UI */
|
|
281
|
+
declare function ApiTags(...tags: Array<string>): ClassDecorator;
|
|
282
|
+
/** Documents the operation with summary, description, operationId, deprecated */
|
|
283
|
+
declare function ApiOperation(options: ApiOperationOptions): MethodDecorator;
|
|
284
|
+
/**
|
|
285
|
+
* Documents a possible response for the route.
|
|
286
|
+
* Can be stacked multiple times for different status codes.
|
|
287
|
+
*
|
|
288
|
+
* @example
|
|
289
|
+
* @ApiResponse({ status: 200, type: UserDto })
|
|
290
|
+
* @ApiResponse({ status: 404, description: 'Not found' })
|
|
291
|
+
*/
|
|
292
|
+
declare function ApiResponse(options: ApiResponseOptions): MethodDecorator;
|
|
293
|
+
/**
|
|
294
|
+
* Documents the request body.
|
|
295
|
+
*
|
|
296
|
+
* @example
|
|
297
|
+
* @ApiBody({ type: CreateUserDto })
|
|
298
|
+
*/
|
|
299
|
+
declare function ApiBody(options: ApiBodyOptions): MethodDecorator;
|
|
300
|
+
/** Documents an additional query parameter (alongside or instead of @FromQuery) */
|
|
301
|
+
declare function ApiQuery(options: ApiQueryParamOptions): MethodDecorator;
|
|
302
|
+
|
|
303
|
+
export { ApiBody, type ApiBodyOptions, type ApiInfo, ApiOperation, type ApiOperationOptions, ApiProperty, type ApiPropertyOptions, ApiQuery, type ApiQueryParamOptions, ApiResponse, type ApiResponseOptions, ApiTags, Authorize, type AuthorizeOptions, Controller, type CorsOptions, Delete, FromBody, FromContext, FromQuery, FromRoute, Get, HttpContext, HttpResult, Inject, Injectable, JwtAuthService, type JwtOptions, type JwtPayload, type OnDestroy, type OnInit, type OpenApiOptions, Patch, Post, Put, type ScalarOptions, ServiceCollection, ServiceProvider, type ThrottleOptions, WebApplication, WebApplicationBuilder, cors, scalar, throttle };
|
package/dist/main.js
CHANGED
|
@@ -1 +1,16 @@
|
|
|
1
|
-
var P=Object.defineProperty;var X=Object.getOwnPropertyDescriptor;var Q=Object.getOwnPropertyNames;var Z=Object.prototype.hasOwnProperty;var a=(r,e)=>P(r,"name",{value:e,configurable:!0});var q=(r,e)=>()=>(r&&(e=r(r=0)),e);var V=(r,e)=>{for(var t in e)P(r,t,{get:e[t],enumerable:!0})},Y=(r,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of Q(e))!Z.call(r,s)&&s!==t&&P(r,s,{get:()=>e[s],enumerable:!(n=X(e,s))||n.enumerable});return r};var ee=r=>Y(P({},"__esModule",{value:!0}),r);import"reflect-metadata";function T(){return r=>{Reflect.defineMetadata(te,!0,r)}}function re(r){return(e,t,n)=>{let s=Reflect.getMetadata(j,e)||[];s.push({index:n,token:r}),Reflect.defineMetadata(j,s,e)}}var te,j,x=q(()=>{"use strict";te=Symbol("INJECTABLE_WATERMARK"),j=Symbol("INJECT_METADATA");a(T,"Injectable");a(re,"Inject")});var _={};V(_,{JwtAuthService:()=>R});function he(r,e,t,n){var s=arguments.length,i=s<3?e:n===null?n=Object.getOwnPropertyDescriptor(e,t):n,o;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")i=Reflect.decorate(r,e,t,n);else for(var c=r.length-1;c>=0;c--)(o=r[c])&&(i=(s<3?o(i):s>3?o(e,t,i):o(e,t))||i);return s>3&&i&&Object.defineProperty(e,t,i),i}function B(r,e){if(typeof Reflect=="object"&&typeof Reflect.metadata=="function")return Reflect.metadata(r,e)}function J(r){return btoa(r).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function F(r){let e=r+"==".slice(2-r.length*3&3);return atob(e.replace(/-/g,"+").replace(/_/g,"/"))}var R,U=q(()=>{"use strict";x();a(he,"_ts_decorate");a(B,"_ts_metadata");a(J,"base64UrlEncode");a(F,"base64UrlDecode");R=class{static{a(this,"JwtAuthService")}secret;expiresIn;constructor(e){this.secret=e.secret,this.expiresIn=e.expiresIn??3600}async getKey(){let e=new TextEncoder;return crypto.subtle.importKey("raw",e.encode(this.secret),{name:"HMAC",hash:"SHA-256"},!1,["sign","verify"])}async sign(e){let t={alg:"HS256",typ:"JWT"},n=Math.floor(Date.now()/1e3),s={...e,iat:n,exp:n+this.expiresIn},i=J(JSON.stringify(t)),o=J(JSON.stringify(s)),c=`${i}.${o}`,l=await this.getKey(),u=new TextEncoder,p=await crypto.subtle.sign("HMAC",l,u.encode(c)),f=J(String.fromCharCode(...new Uint8Array(p)));return`${c}.${f}`}async verify(e){let t=e.split(".");if(t.length!==3)throw new Error("Invalid JWT format");let n=t[0],s=t[1],i=t[2],o=`${n}.${s}`,c=await this.getKey(),l=new TextEncoder,u=Uint8Array.from(F(i),H=>H.charCodeAt(0));if(!await crypto.subtle.verify("HMAC",c,u,l.encode(o)))throw new Error("Invalid JWT signature");let f=JSON.parse(F(s)),g=Math.floor(Date.now()/1e3);if(f.exp!==void 0&&f.exp<g)throw new Error("JWT expired");return f}};R=he([T(),B("design:type",Function),B("design:paramtypes",[typeof JwtOptions>"u"?Object:JwtOptions])],R)});x();import"reflect-metadata";var h=(function(r){return r[r.Singleton=0]="Singleton",r[r.Transient=1]="Transient",r[r.Scoped=2]="Scoped",r})({});var E=class r{static{a(this,"ServiceProvider")}descriptors;parent;singletonInstances=new Map;scopedInstances=new Map;trackedInstances=new Set;constructor(e,t){this.descriptors=e,this.parent=t}createScope(){return new r(this.descriptors,this.parent||this)}async dispose(){for(let e of this.trackedInstances)typeof e.onDestroy=="function"&&await e.onDestroy();this.trackedInstances.clear(),this.scopedInstances.clear(),this.singletonInstances.clear()}async resolve(e){let t=this.descriptors.find(n=>n.token===e);if(!t){if(this.parent)return this.parent.resolve(e);throw new Error(`Service not registered for token: ${e.toString()}`)}switch(t.lifetime){case h.Singleton:return this.resolveSingleton(t);case h.Scoped:return this.resolveScoped(t);case h.Transient:return this.resolveTransient(t)}}async resolveSingleton(e){let t=this.getRoot();if(t.singletonInstances.has(e.token))return t.singletonInstances.get(e.token);let n=await this.createInstance(t,e);return t.singletonInstances.set(e.token,n),n}async resolveScoped(e){if(this.scopedInstances.has(e.token))return this.scopedInstances.get(e.token);let t=await this.createInstance(this,e);return this.scopedInstances.set(e.token,t),t}async resolveTransient(e){return this.createInstance(this,e)}async createInstance(e,t){let n;if(t.implementationInstance!==void 0)n=t.implementationInstance;else if(t.implementationFactory)n=await t.implementationFactory(this);else if(t.implementationType)n=await this.instantiateClass(t.implementationType);else throw new Error(`Invalid service descriptor for token: ${t.token.toString()}`);let s=Symbol.for("steampunk:initialized");return typeof n.onInit=="function"&&!n[s]&&(await n.onInit(),n[s]=!0),typeof n.onDestroy=="function"&&t.lifetime!==h.Transient&&e.trackedInstances.add(n),n}getRoot(){return this.parent?this.parent.getRoot():this}async instantiateClass(e){let t=Reflect.getMetadata("design:paramtypes",e)||[],n=Reflect.getMetadata(j,e)||[],s=await Promise.all(t.map(async(i,o)=>{let c=n.find(u=>u.index===o),l=c?c.token:i;if(!l||l===Object||l===String||l===Number||l===Boolean)throw new Error(`Cannot resolve parameter at index ${o} for ${e.name}. Token could not be determined or is primitive. Cannot inject primitive types directly without @Inject().`);return this.resolve(l)}));return new e(...s)}};var M=class{static{a(this,"ServiceCollection")}descriptors=[];add(e){return this.descriptors.push(e),this}addSingleton(e,t){return this.add({token:e,implementationType:t||e,lifetime:h.Singleton})}addSingletonInstance(e,t){return this.add({token:e,implementationInstance:t,lifetime:h.Singleton})}addTransient(e,t){return this.add({token:e,implementationType:t||e,lifetime:h.Transient})}addScoped(e,t){return this.add({token:e,implementationType:t||e,lifetime:h.Scoped})}buildServiceProvider(){return new E(this.descriptors)}addControllers(e){return e.forEach(t=>this.addTransient(t)),this}};var S=class{static{a(this,"HttpContext")}request;items=new Map;constructor(e){this.request=e}get method(){return this.request.method}get url(){return this.request.url}get path(){return new URL(this.request.url).pathname}};import"reflect-metadata";var C=Symbol("AUTHORIZE_METADATA");function ne(r){return(e,t)=>{let n={required:!0,roles:r};t!==void 0?Reflect.defineMetadata(C,n,e.constructor,t):Reflect.defineMetadata(C,n,e)}}a(ne,"Authorize");var w=class r{static{a(this,"HttpResult")}status;body;headers;constructor(e,t,n={}){this.status=e,this.body=t!==void 0&&typeof t!="string"?JSON.stringify(t):t,this.headers=n}static ok(e){return new r(200,e)}static created(e,t){let n={};return t&&(n.Location=t),new r(201,e,n)}static noContent(){return new r(204)}static badRequest(e="Bad Request",t){let n=typeof e=="string"?{message:e,errors:t}:e;return new r(400,n)}static unauthorized(e="Unauthorized"){let t=typeof e=="string"?{message:e}:e;return new r(401,t)}static forbidden(e="Forbidden"){let t=typeof e=="string"?{message:e}:e;return new r(403,t)}static notFound(e="Not Found"){let t=typeof e=="string"?{message:e}:e;return new r(404,t)}static conflict(e="Conflict"){let t=typeof e=="string"?{message:e}:e;return new r(409,t)}static unprocessableEntity(e="Unprocessable Entity",t){let n=typeof e=="string"?{message:e,errors:t}:e;return new r(422,n)}static internalServerError(e="Internal Server Error"){let t=typeof e=="string"?{message:e}:e;return new r(500,t)}toResponse(){if(this.status===204||this.body===void 0)return new Response(null,{status:this.status,headers:this.headers});let e={"Content-Type":"application/json",...this.headers};return new Response(this.body,{status:this.status,headers:e})}};x();import"reflect-metadata";var v=Symbol("CONTROLLER_WATERMARK"),A=Symbol("ROUTE_METADATA"),L=Symbol("PARAM_METADATA");function se(r=""){return e=>{Reflect.defineMetadata(v,r,e),T()(e)}}a(se,"Controller");var b=a(r=>(e="")=>(t,n)=>{Reflect.hasMetadata(A,t.constructor)||Reflect.defineMetadata(A,[],t.constructor);let s=Reflect.getMetadata(A,t.constructor);s.push({method:r,path:e,methodName:n.toString()}),Reflect.defineMetadata(A,s,t.constructor)},"createRouteDecorator"),oe=b("GET"),ie=b("POST"),ae=b("PUT"),ce=b("DELETE"),le=b("PATCH"),y=(function(r){return r[r.Route=0]="Route",r[r.Query=1]="Query",r[r.Body=2]="Body",r[r.Context=3]="Context",r})({});function de(r,e){return(t,n,s)=>{N(t,n,{type:0,index:s,name:r,schema:e})}}a(de,"FromRoute");function ue(r,e){return(t,n,s)=>{N(t,n,{type:1,index:s,name:r,schema:e})}}a(ue,"FromQuery");function fe(r){return(e,t,n)=>{N(e,t,{type:2,index:n,schema:r})}}a(fe,"FromBody");function pe(){return(r,e,t)=>{N(r,e,{type:3,index:t})}}a(pe,"FromContext");function N(r,e,t){let n=`${L.toString()}_${e.toString()}`;Reflect.hasMetadata(n,r.constructor)||Reflect.defineMetadata(n,[],r.constructor);let s=Reflect.getMetadata(n,r.constructor);s.push(t),Reflect.defineMetadata(n,s,r.constructor)}a(N,"addParamMetadata");async function me(r,e,t){if(!t.required)return null;let n=r.request.headers.get("authorization");if(!n||!n.startsWith("Bearer "))return new Response(JSON.stringify({message:"Unauthorized"}),{status:401,headers:{"Content-Type":"application/json"}});let s=n.slice(7),i;try{let{JwtAuthService:c}=(U(),ee(_));i=await e.resolve(c)}catch{return new Response(JSON.stringify({message:"JWT service not configured"}),{status:500,headers:{"Content-Type":"application/json"}})}let o;try{o=await i.verify(s)}catch{return new Response(JSON.stringify({message:"Unauthorized: invalid or expired token"}),{status:401,headers:{"Content-Type":"application/json"}})}if(t.roles&&t.roles.length>0){let c=o.roles??[];if(!t.roles.some(u=>c.includes(u)))return new Response(JSON.stringify({message:"Forbidden: insufficient permissions"}),{status:403,headers:{"Content-Type":"application/json"}})}return r.items.set("user",o),null}a(me,"checkAuth");var D=class{static{a(this,"Router")}routes=[];registerControllers(e){for(let t of e){let n=Reflect.getMetadata(v,t);if(n===void 0)continue;let s=Reflect.getMetadata(A,t)||[];for(let i of s){let o=`/${n}/${i.path}`.replace(/\/+/g,"/");o!=="/"&&o.endsWith("/")&&(o=o.slice(0,-1));let c=new URLPattern({pathname:o});this.routes.push({method:i.method,pattern:c,controller:t,methodName:i.methodName})}}}map(e,t,n){let s=t.startsWith("/")?t:`/${t}`;s!=="/"&&s.endsWith("/")&&(s=s.slice(0,-1));let i=new URLPattern({pathname:s});this.routes.push({method:e.toUpperCase(),pattern:i,handler:n})}middleware(){return async(e,t)=>{for(let n of this.routes){if(n.method!==e.method)continue;let s=n.pattern.exec({pathname:e.path});if(s){let i=e.items.get("scope");if(!i)throw new Error("DI Scope not found in HttpContext");let o;if(n.handler)o=await n.handler(e);else if(n.controller&&n.methodName){let c=Reflect.getMetadata(C,n.controller,n.methodName),l=Reflect.getMetadata(C,n.controller),u=c??l;if(u){let d=await me(e,i,u);if(d)return d}let p=await i.resolve(n.controller),f=`${L.toString()}_${n.methodName}`,g=Reflect.getMetadata(f,n.controller)||[],H=p[n.methodName].length,W=new Array(H).fill(void 0),z=g.some(d=>d.type===y.Body),$;z&&($=await e.request.json().catch(()=>({})));let G=new URL(e.request.url);for(let d of g){let m;if(d.type===y.Route&&d.name?m=s.pathname.groups[d.name]:d.type===y.Query&&d.name?m=G.searchParams.get(d.name):d.type===y.Body?m=$:d.type===y.Context&&(m=e),d.schema){let k=d.schema.safeParse(m);if(!k.success)return w.unprocessableEntity("Validation failed",{errors:k.error.errors,target:y[d.type].toLowerCase(),name:d.name}).toResponse();m=k.data}W[d.index]=m}o=await p[n.methodName](...W)}return o instanceof Response?o:o instanceof w?o.toResponse():typeof o=="object"?Response.json(o):new Response(String(o))}}return t()}}};import{readdir as ye}from"fs/promises";import{join as K}from"path";var I=class{static{a(this,"WebApplicationBuilder")}services;controllers=[];constructor(){this.services=new M}async addControllers(e="controllers"){let t=K(process.cwd(),e);try{let n=await ye(t,{recursive:!0});for(let s of n)if(typeof s=="string"&&(s.endsWith(".ts")||s.endsWith(".js"))&&!s.endsWith(".d.ts")){let o=await import(K(t,s));for(let c in o){let l=o[c];typeof l=="function"&&Reflect.hasMetadata(v,l)&&this.controllers.push(l)}}this.controllers.length>0&&this.services.addControllers(this.controllers)}catch(n){console.warn(`Could not discover controllers at ${t}:`,n)}return this}build(){let e=this.services.buildServiceProvider();return new O(e,this.controllers)}};var O=class{static{a(this,"WebApplication")}services;middlewares=[];controllersToMap=[];router;constructor(e,t=[]){this.services=e,this.controllersToMap.push(...t),this.router=new D}static createBuilder(){return new I}use(e){return this.middlewares.push(e),this}mapControllers(e){return this.controllersToMap.push(...e),this}mapGet(e,t){return this.router.map("GET",e,t),this}mapPost(e,t){return this.router.map("POST",e,t),this}mapPut(e,t){return this.router.map("PUT",e,t),this}mapDelete(e,t){return this.router.map("DELETE",e,t),this}mapPatch(e,t){return this.router.map("PATCH",e,t),this}async executePipeline(e){let t=-1,n=a(async i=>{if(i<=t)throw new Error("next() called multiple times");t=i;let o=this.middlewares[i];if(i===this.middlewares.length)return new Response(JSON.stringify({message:"Not found"}),{status:404});if(o)return o(e,n.bind(null,i+1))},"dispatch");return await n(0)||new Response(JSON.stringify({message:"Internal Server Error"}),{status:500})}run(e=3e3){let t=this;this.controllersToMap.length>0&&this.router.registerControllers(this.controllersToMap),this.use(this.router.middleware()),Bun.serve({port:e,async fetch(n){let s=t.services.createScope();try{let i=new S(n);return i.items.set("scope",s),await t.executePipeline(i)}finally{await s.dispose()}}}),console.log(`\u{1F680} Steampunk application is running on http://localhost:${e}`)}};x();U();function ge(r={}){return async(e,t)=>{let{request:n}=e,s=n.headers.get("origin"),i=await t();i||(i=new Response);let o=new Response(i.body,i);if(r.origin?typeof r.origin=="string"?o.headers.set("Access-Control-Allow-Origin",r.origin):Array.isArray(r.origin)&&s?r.origin.includes(s)&&o.headers.set("Access-Control-Allow-Origin",s):typeof r.origin=="function"&&s&&r.origin(s)&&o.headers.set("Access-Control-Allow-Origin",s):o.headers.set("Access-Control-Allow-Origin","*"),r.methods){let c=Array.isArray(r.methods)?r.methods.join(", "):r.methods;o.headers.set("Access-Control-Allow-Methods",c)}else o.headers.set("Access-Control-Allow-Methods","GET,HEAD,PUT,PATCH,POST,DELETE");if(r.allowedHeaders){let c=Array.isArray(r.allowedHeaders)?r.allowedHeaders.join(", "):r.allowedHeaders;o.headers.set("Access-Control-Allow-Headers",c)}else{let c=n.headers.get("access-control-request-headers");c&&o.headers.set("Access-Control-Allow-Headers",c)}if(r.exposedHeaders){let c=Array.isArray(r.exposedHeaders)?r.exposedHeaders.join(", "):r.exposedHeaders;o.headers.set("Access-Control-Expose-Headers",c)}return r.credentials&&o.headers.set("Access-Control-Allow-Credentials","true"),r.maxAge!==void 0&&o.headers.set("Access-Control-Max-Age",r.maxAge.toString()),n.method==="OPTIONS"?new Response(null,{headers:o.headers,status:204}):o}}a(ge,"cors");function we(r){let e=a(s=>{let i=s.request?.headers?.get("x-forwarded-for");return i?i.split(",")[0].trim():"global"},"defaultKeyGenerator"),t=r.keyGenerator||e,n=new Map;return async(s,i)=>{let o=t(s),c=Date.now(),l=n.get(o);if(l?c>l.resetTime?(l.count=1,l.resetTime=c+r.windowMs):l.count++:(l={count:1,resetTime:c+r.windowMs},n.set(o,l)),Math.random()<.05)for(let[f,g]of n.entries())Date.now()>g.resetTime&&n.delete(f);if(l.count>r.limit){let f=Math.ceil((l.resetTime-c)/1e3);return new Response("Too Many Requests",{status:429,headers:{"Retry-After":f.toString(),"X-RateLimit-Limit":r.limit.toString(),"X-RateLimit-Remaining":"0","X-RateLimit-Reset":Math.ceil(l.resetTime/1e3).toString()}})}let u=await i();u||(u=new Response);let p=new Response(u.body,u);return p.headers.set("X-RateLimit-Limit",r.limit.toString()),p.headers.set("X-RateLimit-Remaining",Math.max(0,r.limit-l.count).toString()),p.headers.set("X-RateLimit-Reset",Math.ceil(l.resetTime/1e3).toString()),p}}a(we,"throttle");export{ne as Authorize,se as Controller,ce as Delete,fe as FromBody,pe as FromContext,ue as FromQuery,de as FromRoute,oe as Get,S as HttpContext,w as HttpResult,re as Inject,T as Injectable,R as JwtAuthService,le as Patch,ie as Post,ae as Put,M as ServiceCollection,E as ServiceProvider,O as WebApplication,I as WebApplicationBuilder,ge as cors,we as throttle};
|
|
1
|
+
var H=Object.defineProperty;var de=Object.getOwnPropertyDescriptor;var ue=Object.getOwnPropertyNames;var fe=Object.prototype.hasOwnProperty;var a=(r,e)=>H(r,"name",{value:e,configurable:!0});var ee=(r,e)=>()=>(r&&(e=r(r=0)),e);var me=(r,e)=>{for(var t in e)H(r,t,{get:e[t],enumerable:!0})},he=(r,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of ue(e))!fe.call(r,o)&&o!==t&&H(r,o,{get:()=>e[o],enumerable:!(n=de(e,o))||n.enumerable});return r};var ye=r=>he(H({},"__esModule",{value:!0}),r);import"reflect-metadata";function C(){return r=>{Reflect.defineMetadata(ge,!0,r)}}function Ae(r){return(e,t,n)=>{let o=Reflect.getMetadata(L,e)||[];o.push({index:n,token:r}),Reflect.defineMetadata(L,o,e)}}var ge,L,v=ee(()=>{"use strict";ge=Symbol("INJECTABLE_WATERMARK"),L=Symbol("INJECT_METADATA");a(C,"Injectable");a(Ae,"Inject")});var ie={};me(ie,{JwtAuthService:()=>I});function $e(r,e,t,n){var o=arguments.length,s=o<3?e:n===null?n=Object.getOwnPropertyDescriptor(e,t):n,i;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")s=Reflect.decorate(r,e,t,n);else for(var c=r.length-1;c>=0;c--)(i=r[c])&&(s=(o<3?i(s):o>3?i(e,t,s):i(e,t))||s);return o>3&&s&&Object.defineProperty(e,t,s),s}function se(r,e){if(typeof Reflect=="object"&&typeof Reflect.metadata=="function")return Reflect.metadata(r,e)}function Z(r){return btoa(r).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function oe(r){let e=r+"==".slice(2-r.length*3&3);return atob(e.replace(/-/g,"+").replace(/_/g,"/"))}var I,V=ee(()=>{"use strict";v();a($e,"_ts_decorate");a(se,"_ts_metadata");a(Z,"base64UrlEncode");a(oe,"base64UrlDecode");I=class{static{a(this,"JwtAuthService")}secret;expiresIn;constructor(e){this.secret=e.secret,this.expiresIn=e.expiresIn??3600}async getKey(){let e=new TextEncoder;return crypto.subtle.importKey("raw",e.encode(this.secret),{name:"HMAC",hash:"SHA-256"},!1,["sign","verify"])}async sign(e){let t={alg:"HS256",typ:"JWT"},n=Math.floor(Date.now()/1e3),o={...e,iat:n,exp:n+this.expiresIn},s=Z(JSON.stringify(t)),i=Z(JSON.stringify(o)),c=`${s}.${i}`,l=await this.getKey(),p=new TextEncoder,f=await crypto.subtle.sign("HMAC",l,p.encode(c)),m=Z(String.fromCharCode(...new Uint8Array(f)));return`${c}.${m}`}async verify(e){let t=e.split(".");if(t.length!==3)throw new Error("Invalid JWT format");let n=t[0],o=t[1],s=t[2],i=`${n}.${o}`,c=await this.getKey(),l=new TextEncoder,p=Uint8Array.from(oe(s),E=>E.charCodeAt(0));if(!await crypto.subtle.verify("HMAC",c,p,l.encode(i)))throw new Error("Invalid JWT signature");let m=JSON.parse(oe(o)),w=Math.floor(Date.now()/1e3);if(m.exp!==void 0&&m.exp<w)throw new Error("JWT expired");return m}};I=$e([C(),se("design:type",Function),se("design:paramtypes",[typeof JwtOptions>"u"?Object:JwtOptions])],I)});v();import"reflect-metadata";var A=(function(r){return r[r.Singleton=0]="Singleton",r[r.Transient=1]="Transient",r[r.Scoped=2]="Scoped",r})({});var P=class r{static{a(this,"ServiceProvider")}descriptors;parent;singletonInstances=new Map;scopedInstances=new Map;trackedInstances=new Set;constructor(e,t){this.descriptors=e,this.parent=t}createScope(){return new r(this.descriptors,this.parent||this)}async dispose(){for(let e of this.trackedInstances)typeof e.onDestroy=="function"&&await e.onDestroy();this.trackedInstances.clear(),this.scopedInstances.clear(),this.singletonInstances.clear()}async resolve(e){let t=this.descriptors.find(n=>n.token===e);if(!t){if(this.parent)return this.parent.resolve(e);throw new Error(`Service not registered for token: ${e.toString()}`)}switch(t.lifetime){case A.Singleton:return this.resolveSingleton(t);case A.Scoped:return this.resolveScoped(t);case A.Transient:return this.resolveTransient(t)}}async resolveSingleton(e){let t=this.getRoot();if(t.singletonInstances.has(e.token))return t.singletonInstances.get(e.token);let n=await this.createInstance(t,e);return t.singletonInstances.set(e.token,n),n}async resolveScoped(e){if(this.scopedInstances.has(e.token))return this.scopedInstances.get(e.token);let t=await this.createInstance(this,e);return this.scopedInstances.set(e.token,t),t}async resolveTransient(e){return this.createInstance(this,e)}async createInstance(e,t){let n;if(t.implementationInstance!==void 0)n=t.implementationInstance;else if(t.implementationFactory)n=await t.implementationFactory(this);else if(t.implementationType)n=await this.instantiateClass(t.implementationType);else throw new Error(`Invalid service descriptor for token: ${t.token.toString()}`);let o=Symbol.for("steampunk:initialized");return typeof n.onInit=="function"&&!n[o]&&(await n.onInit(),n[o]=!0),typeof n.onDestroy=="function"&&t.lifetime!==A.Transient&&e.trackedInstances.add(n),n}getRoot(){return this.parent?this.parent.getRoot():this}async instantiateClass(e){let t=Reflect.getMetadata("design:paramtypes",e)||[],n=Reflect.getMetadata(L,e)||[],o=await Promise.all(t.map(async(s,i)=>{let c=n.find(p=>p.index===i),l=c?c.token:s;if(!l||l===Object||l===String||l===Number||l===Boolean)throw new Error(`Cannot resolve parameter at index ${i} for ${e.name}. Token could not be determined or is primitive. Cannot inject primitive types directly without @Inject().`);return this.resolve(l)}));return new e(...o)}};var O=class{static{a(this,"ServiceCollection")}descriptors=[];add(e){return this.descriptors.push(e),this}addSingleton(e,t){return this.add({token:e,implementationType:t||e,lifetime:A.Singleton})}addSingletonInstance(e,t){return this.add({token:e,implementationInstance:t,lifetime:A.Singleton})}addTransient(e,t){return this.add({token:e,implementationType:t||e,lifetime:A.Transient})}addScoped(e,t){return this.add({token:e,implementationType:t||e,lifetime:A.Scoped})}buildServiceProvider(){return new P(this.descriptors)}addControllers(e){return e.forEach(t=>this.addTransient(t)),this}};var j=class{static{a(this,"HttpContext")}request;items=new Map;constructor(e){this.request=e}get method(){return this.request.method}get url(){return this.request.url}get path(){return new URL(this.request.url).pathname}};v();import"reflect-metadata";var M=Symbol("CONTROLLER_WATERMARK"),T=Symbol("ROUTE_METADATA"),_=Symbol("PARAM_METADATA");function Re(r=""){return e=>{Reflect.defineMetadata(M,r,e),C()(e)}}a(Re,"Controller");var D=a(r=>(e="")=>(t,n)=>{Reflect.hasMetadata(T,t.constructor)||Reflect.defineMetadata(T,[],t.constructor);let o=Reflect.getMetadata(T,t.constructor);o.push({method:r,path:e,methodName:n.toString()}),Reflect.defineMetadata(T,o,t.constructor)},"createRouteDecorator"),we=D("GET"),Te=D("POST"),xe=D("PUT"),Me=D("DELETE"),Ee=D("PATCH"),h=(function(r){return r[r.Route=0]="Route",r[r.Query=1]="Query",r[r.Body=2]="Body",r[r.Context=3]="Context",r})({});function Se(r,e){return(t,n,o)=>{B(t,n,{type:0,index:o,name:r,schema:e})}}a(Se,"FromRoute");function be(r,e){return(t,n,o)=>{B(t,n,{type:1,index:o,name:r,schema:e})}}a(be,"FromQuery");function Ie(r){return(e,t,n)=>{B(e,t,{type:2,index:n,schema:r})}}a(Ie,"FromBody");function Ce(){return(r,e,t)=>{B(r,e,{type:3,index:t})}}a(Ce,"FromContext");function B(r,e,t){let n=`${_.toString()}_${e.toString()}`;Reflect.hasMetadata(n,r.constructor)||Reflect.defineMetadata(n,[],r.constructor);let o=Reflect.getMetadata(n,r.constructor);o.push(t),Reflect.defineMetadata(n,o,r.constructor)}a(B,"addParamMetadata");import"reflect-metadata";var J="steampunk:api_property";function ve(r={}){return(e,t)=>{let n=Reflect.getOwnMetadata(J,e.constructor)||[],o=Reflect.getMetadata("design:type",e,t),s;o&&(o===String?s="string":o===Number?s="number":o===Boolean?s="boolean":o===Array?s="array":o===Object&&(s="object")),n.push({propertyKey:t.toString(),type:r.type??s,...r}),Reflect.defineMetadata(J,n,e.constructor)}}a(ve,"ApiProperty");function re(r){let e=Reflect.getOwnMetadata(J,r)||[],t=[],n={};for(let s of e){if(s.required!==!1&&t.push(s.propertyKey),s.schema){n[s.propertyKey]=s.schema;continue}let i={};s.type!==void 0&&(typeof s.type=="string"?i.type=s.type:typeof s.type=="object"&&"type"in s.type&&(i.type=s.type.type,s.type.items&&(i.items=te(s.type.items)))),s.type==="array"&&s.items&&(i.items=te(s.items)),s.description&&(i.description=s.description),s.example!==void 0&&(i.example=s.example),s.nullable&&(i.nullable=!0),s.enum&&(i.enum=s.enum),s.default!==void 0&&(i.default=s.default),n[s.propertyKey]=i}let o={type:"object"};return Object.keys(n).length>0&&(o.properties=n),t.length>0&&(o.required=t),o}a(re,"buildSchemaFromClass");function te(r){return typeof r=="string"?{type:r}:typeof r=="object"&&"$ref"in r||typeof r=="object"&&"type"in r?r:{}}a(te,"buildItemsSchema");function ne(r){return typeof r=="function"&&Reflect.hasOwnMetadata(J,r)}a(ne,"isDto");import"reflect-metadata";var z="steampunk:api_tags",Q="steampunk:api_operation",U="steampunk:api_response",X="steampunk:api_body",W="steampunk:api_query";function Pe(...r){return e=>{Reflect.defineMetadata(z,r,e)}}a(Pe,"ApiTags");function Oe(r){return(e,t)=>{Reflect.defineMetadata(Q,r,e.constructor,t)}}a(Oe,"ApiOperation");function je(r){return(e,t)=>{let n=Reflect.getMetadata(U,e.constructor,t)||[];n.push(r),Reflect.defineMetadata(U,n,e.constructor,t)}}a(je,"ApiResponse");function _e(r){return(e,t)=>{Reflect.defineMetadata(X,r,e.constructor,t)}}a(_e,"ApiBody");function De(r){return(e,t)=>{let n=Reflect.getMetadata(W,e.constructor,t)||[];n.push(r),Reflect.defineMetadata(W,n,e.constructor,t)}}a(De,"ApiQuery");var F=class{static{a(this,"OpenApiGenerator")}controllers;options;schemaRegistry=new Map;constructor(e,t){this.controllers=e,this.options=t}refFromClass(e){let t=e.name;return this.schemaRegistry.has(t)||this.schemaRegistry.set(t,re(e)),{$ref:`#/components/schemas/${t}`}}resolveSchema(e,t){if(t)return t;if(e&&ne(e))return this.refFromClass(e);if(e)return{type:"object",description:e.name}}generate(){let e={},t=[],n=new Set;for(let s of this.controllers){let i=Reflect.getMetadata(M,s);if(i===void 0)continue;let c=Reflect.getMetadata(z,s)||[];for(let p of c)n.has(p)||(n.add(p),t.push({name:p}));let l=Reflect.getMetadata(T,s)||[];for(let p of l){let f=`/${i}/${p.path}`.replace(/\/+/g,"/");f!=="/"&&f.endsWith("/")&&(f=f.slice(0,-1));let m=f.replace(/:([^/]+)/g,"{$1}");e[m]||(e[m]={});let w=`${_.toString()}_${p.methodName}`,E=Reflect.getMetadata(w,s)||[],y=Reflect.getMetadata(Q,s,p.methodName),k=Reflect.getMetadata(U,s,p.methodName)||[],g=Reflect.getMetadata(X,s,p.methodName),G=Reflect.getMetadata(W,s,p.methodName)||[],u=[];for(let d of E)d.type===h.Route&&d.name?u.push({name:d.name,in:"path",required:!0,schema:d.schema??{type:"string"}}):d.type===h.Query&&d.name&&u.push({name:d.name,in:"query",required:!1,schema:d.schema??{type:"string"}});for(let d of G)u.find(pe=>pe.name===d.name)||u.push({name:d.name,in:"query",required:d.required??!1,description:d.description,schema:d.schema??{type:"string"},...d.example!==void 0?{example:d.example}:{}});let R=E.some(d=>d.type===h.Body),x;if(R||g){let d=this.resolveSchema(g?.type,g?.schema),S=g?.example;x={...g?.description?{description:g.description}:{},required:g?.required??!0,content:{"application/json":{...d?{schema:d}:{},...S!==void 0?{example:S}:{}}}}}let ce=k.length>0?Object.fromEntries(k.map(d=>{let S=this.resolveSchema(d.type,d.schema);return[String(d.status),{description:d.description,...S?{content:{"application/json":{schema:S,...d.example!==void 0?{example:d.example}:{}}}}:{}}]})):{200:{description:"Success"}},le={...c.length>0?{tags:c}:{},...y?.summary?{summary:y.summary}:{},...y?.description?{description:y.description}:{},...y?.operationId?{operationId:y.operationId}:{operationId:`${s.name}_${p.methodName}`},...y?.deprecated?{deprecated:!0}:{},...u.length>0?{parameters:u}:{},...x?{requestBody:x}:{},responses:ce};e[m][p.method.toLowerCase()]=le}}let o=this.schemaRegistry.size>0?{schemas:Object.fromEntries(this.schemaRegistry)}:void 0;return{openapi:"3.1.0",info:this.options.info,...this.options.servers?{servers:this.options.servers}:{},...t.length>0?{tags:t}:{},paths:e,...o?{components:o}:{}}}};var Ne=a((r,e)=>`<!doctype html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>${e} - API Docs</title>
|
|
5
|
+
<meta charset="utf-8" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<script
|
|
10
|
+
id="api-reference"
|
|
11
|
+
data-url="${r}"
|
|
12
|
+
data-configuration='{"theme":"purple"}'
|
|
13
|
+
></script>
|
|
14
|
+
<script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"></script>
|
|
15
|
+
</body>
|
|
16
|
+
</html>`,"SCALAR_HTML");function Y(r,e,t={}){let n=t.docsPath??"/docs",o=t.specPath??"/openapi.json",s=null;return async(i,c)=>{let{path:l}=i;if(l===o){if(!s){let p=new F(r,e);s=JSON.stringify(p.generate(),null,2)}return new Response(s,{headers:{"Content-Type":"application/json"}})}return l===n||l===`${n}/`?new Response(Ne(o,e.info.title),{headers:{"Content-Type":"text/html; charset=utf-8"}}):c()}}a(Y,"scalar");import"reflect-metadata";var N=Symbol("AUTHORIZE_METADATA");function qe(r){return(e,t)=>{let n={required:!0,roles:r};t!==void 0?Reflect.defineMetadata(N,n,e.constructor,t):Reflect.defineMetadata(N,n,e)}}a(qe,"Authorize");var b=class r{static{a(this,"HttpResult")}status;body;headers;constructor(e,t,n={}){this.status=e,this.body=t!==void 0&&typeof t!="string"?JSON.stringify(t):t,this.headers=n}static ok(e){return new r(200,e)}static created(e,t){let n={};return t&&(n.Location=t),new r(201,e,n)}static noContent(){return new r(204)}static badRequest(e="Bad Request",t){let n=typeof e=="string"?{message:e,errors:t}:e;return new r(400,n)}static unauthorized(e="Unauthorized"){let t=typeof e=="string"?{message:e}:e;return new r(401,t)}static forbidden(e="Forbidden"){let t=typeof e=="string"?{message:e}:e;return new r(403,t)}static notFound(e="Not Found"){let t=typeof e=="string"?{message:e}:e;return new r(404,t)}static conflict(e="Conflict"){let t=typeof e=="string"?{message:e}:e;return new r(409,t)}static unprocessableEntity(e="Unprocessable Entity",t){let n=typeof e=="string"?{message:e,errors:t}:e;return new r(422,n)}static internalServerError(e="Internal Server Error"){let t=typeof e=="string"?{message:e}:e;return new r(500,t)}toResponse(){if(this.status===204||this.body===void 0)return new Response(null,{status:this.status,headers:this.headers});let e={"Content-Type":"application/json",...this.headers};return new Response(this.body,{status:this.status,headers:e})}};async function ke(r,e,t){if(!t.required)return null;let n=r.request.headers.get("authorization");if(!n||!n.startsWith("Bearer "))return new Response(JSON.stringify({message:"Unauthorized"}),{status:401,headers:{"Content-Type":"application/json"}});let o=n.slice(7),s;try{let{JwtAuthService:c}=(V(),ye(ie));s=await e.resolve(c)}catch{return new Response(JSON.stringify({message:"JWT service not configured"}),{status:500,headers:{"Content-Type":"application/json"}})}let i;try{i=await s.verify(o)}catch{return new Response(JSON.stringify({message:"Unauthorized: invalid or expired token"}),{status:401,headers:{"Content-Type":"application/json"}})}if(t.roles&&t.roles.length>0){let c=i.roles??[];if(!t.roles.some(p=>c.includes(p)))return new Response(JSON.stringify({message:"Forbidden: insufficient permissions"}),{status:403,headers:{"Content-Type":"application/json"}})}return r.items.set("user",i),null}a(ke,"checkAuth");var K=class{static{a(this,"Router")}routes=[];registerControllers(e){for(let t of e){let n=Reflect.getMetadata(M,t);if(n===void 0)continue;let o=Reflect.getMetadata(T,t)||[];for(let s of o){let i=`/${n}/${s.path}`.replace(/\/+/g,"/");i!=="/"&&i.endsWith("/")&&(i=i.slice(0,-1));let c=new URLPattern({pathname:i});this.routes.push({method:s.method,pattern:c,controller:t,methodName:s.methodName})}}}map(e,t,n){let o=t.startsWith("/")?t:`/${t}`;o!=="/"&&o.endsWith("/")&&(o=o.slice(0,-1));let s=new URLPattern({pathname:o});this.routes.push({method:e.toUpperCase(),pattern:s,handler:n})}middleware(){return async(e,t)=>{for(let n of this.routes){if(n.method!==e.method)continue;let o=n.pattern.exec({pathname:e.path});if(o){let s=e.items.get("scope");if(!s)throw new Error("DI Scope not found in HttpContext");let i;if(n.handler)i=await n.handler(e);else if(n.controller&&n.methodName){let c=Reflect.getMetadata(N,n.controller,n.methodName),l=Reflect.getMetadata(N,n.controller),p=c??l;if(p){let u=await ke(e,s,p);if(u)return u}let f=await s.resolve(n.controller),m=`${_.toString()}_${n.methodName}`,w=Reflect.getMetadata(m,n.controller)||[],E=f[n.methodName].length,y=new Array(E).fill(void 0),k=w.some(u=>u.type===h.Body),g;k&&(g=await e.request.json().catch(()=>({})));let G=new URL(e.request.url);for(let u of w){let R;if(u.type===h.Route&&u.name?R=o.pathname.groups[u.name]:u.type===h.Query&&u.name?R=G.searchParams.get(u.name):u.type===h.Body?R=g:u.type===h.Context&&(R=e),u.schema){let x=u.schema.safeParse(R);if(!x.success)return b.unprocessableEntity("Validation failed",{errors:x.error.errors,target:h[u.type].toLowerCase(),name:u.name}).toResponse();R=x.data}y[u.index]=R}i=await f[n.methodName](...y)}return i instanceof Response?i:i instanceof b?i.toResponse():typeof i=="object"?Response.json(i):new Response(String(i))}}return t()}}};import{readdir as He}from"fs/promises";import{join as ae}from"path";var q=class{static{a(this,"WebApplicationBuilder")}services;controllers=[];constructor(){this.services=new O}async addControllers(e="controllers"){let t=ae(process.cwd(),e);try{let n=await He(t,{recursive:!0});for(let o of n)if(typeof o=="string"&&(o.endsWith(".ts")||o.endsWith(".js"))&&!o.endsWith(".d.ts")){let i=await import(ae(t,o));for(let c in i){let l=i[c];typeof l=="function"&&Reflect.hasMetadata(M,l)&&this.controllers.push(l)}}this.controllers.length>0&&this.services.addControllers(this.controllers)}catch(n){console.warn(`Could not discover controllers at ${t}:`,n)}return this}build(){let e=this.services.buildServiceProvider();return new $(e,this.controllers)}};var $=class{static{a(this,"WebApplication")}services;middlewares=[];controllersToMap=[];router;constructor(e,t=[]){this.services=e,this.controllersToMap.push(...t),this.router=new K}static createBuilder(){return new q}use(e){return this.middlewares.push(e),this}mapControllers(e){return this.controllersToMap.push(...e),this}useOpenApi(e,t){let n=Y(this.controllersToMap,e,t);return this.middlewares.push(n),this}mapGet(e,t){return this.router.map("GET",e,t),this}mapPost(e,t){return this.router.map("POST",e,t),this}mapPut(e,t){return this.router.map("PUT",e,t),this}mapDelete(e,t){return this.router.map("DELETE",e,t),this}mapPatch(e,t){return this.router.map("PATCH",e,t),this}async executePipeline(e){let t=-1,n=a(async s=>{if(s<=t)throw new Error("next() called multiple times");t=s;let i=this.middlewares[s];if(s===this.middlewares.length)return new Response(JSON.stringify({message:"Not found"}),{status:404});if(i)return i(e,n.bind(null,s+1))},"dispatch");return await n(0)||new Response(JSON.stringify({message:"Internal Server Error"}),{status:500})}run(e=3e3){let t=this;this.controllersToMap.length>0&&this.router.registerControllers(this.controllersToMap),this.use(this.router.middleware()),Bun.serve({port:e,async fetch(n){let o=t.services.createScope();try{let s=new j(n);return s.items.set("scope",o),await t.executePipeline(s)}finally{await o.dispose()}}}),console.log(`\u{1F680} Steampunk application is running on http://localhost:${e}`)}};v();V();function Le(r={}){return async(e,t)=>{let{request:n}=e,o=n.headers.get("origin"),s=await t();s||(s=new Response);let i=new Response(s.body,s);if(r.origin?typeof r.origin=="string"?i.headers.set("Access-Control-Allow-Origin",r.origin):Array.isArray(r.origin)&&o?r.origin.includes(o)&&i.headers.set("Access-Control-Allow-Origin",o):typeof r.origin=="function"&&o&&r.origin(o)&&i.headers.set("Access-Control-Allow-Origin",o):i.headers.set("Access-Control-Allow-Origin","*"),r.methods){let c=Array.isArray(r.methods)?r.methods.join(", "):r.methods;i.headers.set("Access-Control-Allow-Methods",c)}else i.headers.set("Access-Control-Allow-Methods","GET,HEAD,PUT,PATCH,POST,DELETE");if(r.allowedHeaders){let c=Array.isArray(r.allowedHeaders)?r.allowedHeaders.join(", "):r.allowedHeaders;i.headers.set("Access-Control-Allow-Headers",c)}else{let c=n.headers.get("access-control-request-headers");c&&i.headers.set("Access-Control-Allow-Headers",c)}if(r.exposedHeaders){let c=Array.isArray(r.exposedHeaders)?r.exposedHeaders.join(", "):r.exposedHeaders;i.headers.set("Access-Control-Expose-Headers",c)}return r.credentials&&i.headers.set("Access-Control-Allow-Credentials","true"),r.maxAge!==void 0&&i.headers.set("Access-Control-Max-Age",r.maxAge.toString()),n.method==="OPTIONS"?new Response(null,{headers:i.headers,status:204}):i}}a(Le,"cors");function Be(r){let e=a(o=>{let s=o.request?.headers?.get("x-forwarded-for");return s?s.split(",")[0].trim():"global"},"defaultKeyGenerator"),t=r.keyGenerator||e,n=new Map;return async(o,s)=>{let i=t(o),c=Date.now(),l=n.get(i);if(l?c>l.resetTime?(l.count=1,l.resetTime=c+r.windowMs):l.count++:(l={count:1,resetTime:c+r.windowMs},n.set(i,l)),Math.random()<.05)for(let[m,w]of n.entries())Date.now()>w.resetTime&&n.delete(m);if(l.count>r.limit){let m=Math.ceil((l.resetTime-c)/1e3);return new Response("Too Many Requests",{status:429,headers:{"Retry-After":m.toString(),"X-RateLimit-Limit":r.limit.toString(),"X-RateLimit-Remaining":"0","X-RateLimit-Reset":Math.ceil(l.resetTime/1e3).toString()}})}let p=await s();p||(p=new Response);let f=new Response(p.body,p);return f.headers.set("X-RateLimit-Limit",r.limit.toString()),f.headers.set("X-RateLimit-Remaining",Math.max(0,r.limit-l.count).toString()),f.headers.set("X-RateLimit-Reset",Math.ceil(l.resetTime/1e3).toString()),f}}a(Be,"throttle");export{_e as ApiBody,Oe as ApiOperation,ve as ApiProperty,De as ApiQuery,je as ApiResponse,Pe as ApiTags,qe as Authorize,Re as Controller,Me as Delete,Ie as FromBody,Ce as FromContext,be as FromQuery,Se as FromRoute,we as Get,j as HttpContext,b as HttpResult,Ae as Inject,C as Injectable,I as JwtAuthService,Ee as Patch,Te as Post,xe as Put,O as ServiceCollection,P as ServiceProvider,$ as WebApplication,q as WebApplicationBuilder,Le as cors,Y as scalar,Be as throttle};
|