@danielgl/steampunk 0.0.4 → 0.0.5

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 CHANGED
@@ -1 +1 @@
1
- "use strict";var D=Object.defineProperty;var he=Object.getOwnPropertyDescriptor;var me=Object.getOwnPropertyNames;var ye=Object.prototype.hasOwnProperty;var a=(t,e)=>D(t,"name",{value:e,configurable:!0});var R=(t,e)=>()=>(t&&(e=t(t=0)),e);var k=(t,e)=>{for(var n in e)D(t,n,{get:e[n],enumerable:!0})},ge=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of me(e))!ye.call(t,s)&&s!==n&&D(t,s,{get:()=>e[s],enumerable:!(r=he(e,s))||r.enumerable});return t};var J=t=>ge(D({},"__esModule",{value:!0}),t);function T(){return t=>{Reflect.defineMetadata(we,!0,t)}}function G(t){return(e,n,r)=>{let s=Reflect.getMetadata(H,e)||[];s.push({index:r,token:t}),Reflect.defineMetadata(H,s,e)}}var Ee,we,H,I=R(()=>{"use strict";Ee=require("reflect-metadata"),we=Symbol("INJECTABLE_WATERMARK"),H=Symbol("INJECT_METADATA");a(T,"Injectable");a(G,"Inject")});function X(t){return(e,n)=>{let r={required:!0,roles:t};n!==void 0?Reflect.defineMetadata(O,r,e.constructor,n):Reflect.defineMetadata(O,r,e)}}var $e,O,L=R(()=>{"use strict";$e=require("reflect-metadata"),O=Symbol("AUTHORIZE_METADATA");a(X,"Authorize")});var g,q=R(()=>{"use strict";g=class t{static{a(this,"HttpResult")}status;body;headers;constructor(e,n,r={}){this.status=e,this.body=n!==void 0&&typeof n!="string"?JSON.stringify(n):n,this.headers=r}static ok(e){return new t(200,e)}static created(e,n){let r={};return n&&(r.Location=n),new t(201,e,r)}static noContent(){return new t(204)}static badRequest(e="Bad Request",n){let r=typeof e=="string"?{message:e,errors:n}:e;return new t(400,r)}static unauthorized(e="Unauthorized"){let n=typeof e=="string"?{message:e}:e;return new t(401,n)}static forbidden(e="Forbidden"){let n=typeof e=="string"?{message:e}:e;return new t(403,n)}static notFound(e="Not Found"){let n=typeof e=="string"?{message:e}:e;return new t(404,n)}static conflict(e="Conflict"){let n=typeof e=="string"?{message:e}:e;return new t(409,n)}static unprocessableEntity(e="Unprocessable Entity",n){let r=typeof e=="string"?{message:e,errors:n}:e;return new t(422,r)}static internalServerError(e="Internal Server Error"){let n=typeof e=="string"?{message:e}:e;return new t(500,n)}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})}}});function Q(t=""){return e=>{Reflect.defineMetadata(U,t,e),T()(e)}}function ne(t,e){return(n,r,s)=>{$(n,r,{type:0,index:s,name:t,schema:e})}}function re(t,e){return(n,r,s)=>{$(n,r,{type:1,index:s,name:t,schema:e})}}function se(t){return(e,n,r)=>{$(e,n,{type:2,index:r,schema:t})}}function $(t,e,n){let r=`${B.toString()}_${e.toString()}`;Reflect.hasMetadata(r,t.constructor)||Reflect.defineMetadata(r,[],t.constructor);let s=Reflect.getMetadata(r,t.constructor);s.push(n),Reflect.defineMetadata(r,s,t.constructor)}var ze,U,b,B,j,Z,V,Y,ee,te,w,W=R(()=>{"use strict";ze=require("reflect-metadata");I();U=Symbol("CONTROLLER_WATERMARK"),b=Symbol("ROUTE_METADATA"),B=Symbol("PARAM_METADATA");a(Q,"Controller");j=a(t=>(e="")=>(n,r)=>{Reflect.hasMetadata(b,n.constructor)||Reflect.defineMetadata(b,[],n.constructor);let s=Reflect.getMetadata(b,n.constructor);s.push({method:t,path:e,methodName:r.toString()}),Reflect.defineMetadata(b,s,n.constructor)},"createRouteDecorator"),Z=j("GET"),V=j("POST"),Y=j("PUT"),ee=j("DELETE"),te=j("PATCH"),w=(function(t){return t[t.Route=0]="Route",t[t.Query=1]="Query",t[t.Body=2]="Body",t[t.Context=3]="Context",t})({});a(ne,"FromRoute");a(re,"FromQuery");a(se,"FromBody");a($,"addParamMetadata")});var ae={};k(ae,{JwtAuthService:()=>A});function Ae(t,e,n,r){var s=arguments.length,o=s<3?e:r===null?r=Object.getOwnPropertyDescriptor(e,n):r,i;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")o=Reflect.decorate(t,e,n,r);else for(var c=t.length-1;c>=0;c--)(i=t[c])&&(o=(s<3?i(o):s>3?i(e,n,o):i(e,n))||o);return s>3&&o&&Object.defineProperty(e,n,o),o}function oe(t,e){if(typeof Reflect=="object"&&typeof Reflect.metadata=="function")return Reflect.metadata(t,e)}function F(t){return btoa(t).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function ie(t){let e=t+"==".slice(2-t.length*3&3);return atob(e.replace(/-/g,"+").replace(/_/g,"/"))}var A,_=R(()=>{"use strict";I();a(Ae,"_ts_decorate");a(oe,"_ts_metadata");a(F,"base64UrlEncode");a(ie,"base64UrlDecode");A=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 n={alg:"HS256",typ:"JWT"},r=Math.floor(Date.now()/1e3),s={...e,iat:r,exp:r+this.expiresIn},o=F(JSON.stringify(n)),i=F(JSON.stringify(s)),c=`${o}.${i}`,l=await this.getKey(),u=new TextEncoder,h=await crypto.subtle.sign("HMAC",l,u.encode(c)),f=F(String.fromCharCode(...new Uint8Array(h)));return`${c}.${f}`}async verify(e){let n=e.split(".");if(n.length!==3)throw new Error("Invalid JWT format");let r=n[0],s=n[1],o=n[2],i=`${r}.${s}`,c=await this.getKey(),l=new TextEncoder,u=Uint8Array.from(ie(o),N=>N.charCodeAt(0));if(!await crypto.subtle.verify("HMAC",c,u,l.encode(i)))throw new Error("Invalid JWT signature");let f=JSON.parse(ie(s)),C=Math.floor(Date.now()/1e3);if(f.exp!==void 0&&f.exp<C)throw new Error("JWT expired");return f}};A=Ae([T(),oe("design:type",Function),oe("design:paramtypes",[typeof JwtOptions>"u"?Object:JwtOptions])],A)});var ce={};k(ce,{Router:()=>K});async function Re(t,e,n){if(!n.required)return null;let r=t.request.headers.get("authorization");if(!r||!r.startsWith("Bearer "))return new Response(JSON.stringify({message:"Unauthorized"}),{status:401,headers:{"Content-Type":"application/json"}});let s=r.slice(7),o;try{let{JwtAuthService:c}=(_(),J(ae));o=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 o.verify(s)}catch{return new Response(JSON.stringify({message:"Unauthorized: invalid or expired token"}),{status:401,headers:{"Content-Type":"application/json"}})}if(n.roles&&n.roles.length>0){let c=i.roles??[];if(!n.roles.some(u=>c.includes(u)))return new Response(JSON.stringify({message:"Forbidden: insufficient permissions"}),{status:403,headers:{"Content-Type":"application/json"}})}return t.items.set("user",i),null}var K,le=R(()=>{"use strict";L();q();W();a(Re,"checkAuth");K=class{static{a(this,"Router")}routes=[];registerControllers(e){for(let n of e){let r=Reflect.getMetadata(U,n);if(r===void 0)continue;let s=Reflect.getMetadata(b,n)||[];for(let o of s){let i=`/${r}/${o.path}`.replace(/\/+/g,"/");i!=="/"&&i.endsWith("/")&&(i=i.slice(0,-1));let c=new URLPattern({pathname:i});this.routes.push({method:o.method,pattern:c,controller:n,methodName:o.methodName})}}}middleware(){return async(e,n)=>{for(let r of this.routes){if(r.method!==e.method)continue;let s=r.pattern.exec({pathname:e.path});if(s){let o=e.items.get("scope");if(!o)throw new Error("DI Scope not found in HttpContext");let i=Reflect.getMetadata(O,r.controller,r.methodName),c=Reflect.getMetadata(O,r.controller),l=i??c;if(l){let d=await Re(e,o,l);if(d)return d}let u=await o.resolve(r.controller),h=`${B.toString()}_${r.methodName}`,f=Reflect.getMetadata(h,r.controller)||[],C=u[r.methodName].length,N=new Array(C).fill(void 0),fe=f.some(d=>d.type===w.Body),z;fe&&(z=await e.request.json().catch(()=>({})));let pe=new URL(e.request.url);for(let d of f){let y;if(d.type===w.Route&&d.name?y=s.pathname.groups[d.name]:d.type===w.Query&&d.name?y=pe.searchParams.get(d.name):d.type===w.Body?y=z:d.type===w.Context&&(y=e),d.schema){let P=d.schema.safeParse(y);if(!P.success)return g.unprocessableEntity("Validation failed",{errors:P.error.errors,target:w[d.type].toLowerCase(),name:d.name}).toResponse();y=P.data}N[d.index]=y}let m=await u[r.methodName](...N);return m instanceof Response?m:m instanceof g?m.toResponse():typeof m=="object"?Response.json(m):new Response(String(m))}}return n()}}}});var Te={};k(Te,{Authorize:()=>X,Controller:()=>Q,Delete:()=>ee,FromBody:()=>se,FromQuery:()=>re,FromRoute:()=>ne,Get:()=>Z,HttpContext:()=>M,HttpResult:()=>g,Inject:()=>G,Injectable:()=>T,JwtAuthService:()=>A,Patch:()=>te,Post:()=>V,Put:()=>Y,ServiceCollection:()=>E,ServiceProvider:()=>x,WebApplication:()=>v,WebApplicationBuilder:()=>S,cors:()=>de,throttle:()=>ue});module.exports=J(Te);var be=require("reflect-metadata");I();var p=(function(t){return t[t.Singleton=0]="Singleton",t[t.Transient=1]="Transient",t[t.Scoped=2]="Scoped",t})({});var x=class t{static{a(this,"ServiceProvider")}descriptors;parent;singletonInstances=new Map;scopedInstances=new Map;trackedInstances=new Set;constructor(e,n){this.descriptors=e,this.parent=n}createScope(){return new t(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 n=this.descriptors.find(r=>r.token===e);if(!n){if(this.parent)return this.parent.resolve(e);throw new Error(`Service not registered for token: ${e.toString()}`)}switch(n.lifetime){case p.Singleton:return this.resolveSingleton(n);case p.Scoped:return this.resolveScoped(n);case p.Transient:return this.resolveTransient(n)}}async resolveSingleton(e){let n=this.getRoot();if(n.singletonInstances.has(e.token))return n.singletonInstances.get(e.token);let r=await this.createInstance(n,e);return n.singletonInstances.set(e.token,r),r}async resolveScoped(e){if(this.scopedInstances.has(e.token))return this.scopedInstances.get(e.token);let n=await this.createInstance(this,e);return this.scopedInstances.set(e.token,n),n}async resolveTransient(e){return this.createInstance(this,e)}async createInstance(e,n){let r;if(n.implementationInstance!==void 0)r=n.implementationInstance;else if(n.implementationFactory)r=await n.implementationFactory(this);else if(n.implementationType)r=await this.instantiateClass(n.implementationType);else throw new Error(`Invalid service descriptor for token: ${n.token.toString()}`);let s=Symbol.for("steampunk:initialized");return typeof r.onInit=="function"&&!r[s]&&(await r.onInit(),r[s]=!0),typeof r.onDestroy=="function"&&n.lifetime!==p.Transient&&e.trackedInstances.add(r),r}getRoot(){return this.parent?this.parent.getRoot():this}async instantiateClass(e){let n=Reflect.getMetadata("design:paramtypes",e)||[],r=Reflect.getMetadata(H,e)||[],s=await Promise.all(n.map(async(o,i)=>{let c=r.find(u=>u.index===i),l=c?c.token:o;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(...s)}};var E=class{static{a(this,"ServiceCollection")}descriptors=[];add(e){return this.descriptors.push(e),this}addSingleton(e,n){return this.add({token:e,implementationType:n||e,lifetime:p.Singleton})}addSingletonInstance(e,n){return this.add({token:e,implementationInstance:n,lifetime:p.Singleton})}addTransient(e,n){return this.add({token:e,implementationType:n||e,lifetime:p.Transient})}addScoped(e,n){return this.add({token:e,implementationType:n||e,lifetime:p.Scoped})}buildServiceProvider(){return new x(this.descriptors)}addControllers(e){return e.forEach(n=>this.addTransient(n)),this}};var M=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 S=class{static{a(this,"WebApplicationBuilder")}services;constructor(){this.services=new E}build(){let e=this.services.buildServiceProvider();return new v(e)}};var v=class{static{a(this,"WebApplication")}services;middlewares=[];controllersToMap=[];constructor(e){this.services=e}static createBuilder(){return new S}use(e){return this.middlewares.push(e),this}mapControllers(e){return this.controllersToMap.push(...e),this}async executePipeline(e){let n=-1,r=a(async o=>{if(o<=n)throw new Error("next() called multiple times");n=o;let i=this.middlewares[o];if(o===this.middlewares.length)return new Response(JSON.stringify({message:"Not found"}),{status:404});if(i)return i(e,r.bind(null,o+1))},"dispatch");return await r(0)||new Response(JSON.stringify({message:"Internal Server Error"}),{status:500})}run(e=3e3){let n=this;if(this.controllersToMap.length>0){let{Router:r}=(le(),J(ce)),s=new r;s.registerControllers(this.controllersToMap),this.use(s.middleware())}Bun.serve({port:e,async fetch(r){let s=n.services.createScope();try{let o=new M(r);return o.items.set("scope",s),await n.executePipeline(o)}finally{await s.dispose()}}}),console.log(`\u{1F680} Steampunk application is running on http://localhost:${e}`)}};q();I();W();L();_();function de(t={}){return async(e,n)=>{let{request:r}=e,s=r.headers.get("origin"),o=await n();o||(o=new Response);let i=new Response(o.body,o);if(t.origin?typeof t.origin=="string"?i.headers.set("Access-Control-Allow-Origin",t.origin):Array.isArray(t.origin)&&s?t.origin.includes(s)&&i.headers.set("Access-Control-Allow-Origin",s):typeof t.origin=="function"&&s&&t.origin(s)&&i.headers.set("Access-Control-Allow-Origin",s):i.headers.set("Access-Control-Allow-Origin","*"),t.methods){let c=Array.isArray(t.methods)?t.methods.join(", "):t.methods;i.headers.set("Access-Control-Allow-Methods",c)}else i.headers.set("Access-Control-Allow-Methods","GET,HEAD,PUT,PATCH,POST,DELETE");if(t.allowedHeaders){let c=Array.isArray(t.allowedHeaders)?t.allowedHeaders.join(", "):t.allowedHeaders;i.headers.set("Access-Control-Allow-Headers",c)}else{let c=r.headers.get("access-control-request-headers");c&&i.headers.set("Access-Control-Allow-Headers",c)}if(t.exposedHeaders){let c=Array.isArray(t.exposedHeaders)?t.exposedHeaders.join(", "):t.exposedHeaders;i.headers.set("Access-Control-Expose-Headers",c)}return t.credentials&&i.headers.set("Access-Control-Allow-Credentials","true"),t.maxAge!==void 0&&i.headers.set("Access-Control-Max-Age",t.maxAge.toString()),r.method==="OPTIONS"?new Response(null,{headers:i.headers,status:204}):i}}a(de,"cors");function ue(t){let e=a(s=>{let o=s.request?.headers?.get("x-forwarded-for");return o?o.split(",")[0].trim():"global"},"defaultKeyGenerator"),n=t.keyGenerator||e,r=new Map;return async(s,o)=>{let i=n(s),c=Date.now(),l=r.get(i);if(l?c>l.resetTime?(l.count=1,l.resetTime=c+t.windowMs):l.count++:(l={count:1,resetTime:c+t.windowMs},r.set(i,l)),Math.random()<.05)for(let[f,C]of r.entries())Date.now()>C.resetTime&&r.delete(f);if(l.count>t.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":t.limit.toString(),"X-RateLimit-Remaining":"0","X-RateLimit-Reset":Math.ceil(l.resetTime/1e3).toString()}})}let u=await o();u||(u=new Response);let h=new Response(u.body,u);return h.headers.set("X-RateLimit-Limit",t.limit.toString()),h.headers.set("X-RateLimit-Remaining",Math.max(0,t.limit-l.count).toString()),h.headers.set("X-RateLimit-Reset",Math.ceil(l.resetTime/1e3).toString()),h}}a(ue,"throttle");0&&(module.exports={Authorize,Controller,Delete,FromBody,FromQuery,FromRoute,Get,HttpContext,HttpResult,Inject,Injectable,JwtAuthService,Patch,Post,Put,ServiceCollection,ServiceProvider,WebApplication,WebApplicationBuilder,cors,throttle});
1
+ "use strict";var P=Object.defineProperty;var ue=Object.getOwnPropertyDescriptor;var fe=Object.getOwnPropertyNames;var pe=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 _=(r,e)=>{for(var t in e)P(r,t,{get:e[t],enumerable:!0})},he=(r,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of fe(e))!pe.call(r,s)&&s!==t&&P(r,s,{get:()=>e[s],enumerable:!(n=ue(e,s))||n.enumerable});return r};var F=r=>he(P({},"__esModule",{value:!0}),r);function R(){return r=>{Reflect.defineMetadata(me,!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 Re,me,j,v=B(()=>{"use strict";Re=require("reflect-metadata"),me=Symbol("INJECTABLE_WATERMARK"),j=Symbol("INJECT_METADATA");a(R,"Injectable");a(K,"Inject")});var oe={};_(oe,{JwtAuthService:()=>w});function ye(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 ne(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 se(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(ye,"_ts_decorate");a(ne,"_ts_metadata");a(J,"base64UrlEncode");a(se,"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(se(i),D=>D.charCodeAt(0));if(!await crypto.subtle.verify("HMAC",c,u,l.encode(o)))throw new Error("Invalid JWT signature");let f=JSON.parse(se(s)),A=Math.floor(Date.now()/1e3);if(f.exp!==void 0&&f.exp<A)throw new Error("JWT expired");return f}};w=ye([R(),ne("design:type",Function),ne("design:paramtypes",[typeof JwtOptions>"u"?Object:JwtOptions])],w)});var we={};_(we,{Authorize:()=>z,Controller:()=>G,Delete:()=>V,FromBody:()=>re,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:()=>ae,throttle:()=>ce});module.exports=F(we);var Me=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 He=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 We=require("reflect-metadata");v();var I=Symbol("CONTROLLER_WATERMARK"),M=Symbol("ROUTE_METADATA"),k=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)=>{L(t,n,{type:0,index:s,name:r,schema:e})}}a(ee,"FromRoute");function te(r,e){return(t,n,s)=>{L(t,n,{type:1,index:s,name:r,schema:e})}}a(te,"FromQuery");function re(r){return(e,t,n)=>{L(e,t,{type:2,index:n,schema:r})}}a(re,"FromBody");function L(r,e,t){let n=`${k.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(L,"addParamMetadata");async function ge(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(),F(oe));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(ge,"checkAuth");var N=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 ge(e,i,u);if(d)return d}let p=await i.resolve(n.controller),f=`${k.toString()}_${n.methodName}`,A=Reflect.getMetadata(f,n.controller)||[],D=p[n.methodName].length,$=new Array(D).fill(void 0),le=A.some(d=>d.type===g.Body),q;le&&(q=await e.request.json().catch(()=>({})));let de=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=de.searchParams.get(d.name):d.type===g.Body?m=q:d.type===g.Context&&(m=e),d.schema){let H=d.schema.safeParse(m);if(!H.success)return y.unprocessableEntity("Validation failed",{errors:H.error.errors,target:g[d.type].toLowerCase(),name:d.name}).toResponse();m=H.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 ie=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,ie.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 N}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 ae(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(ae,"cors");function ce(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(ce,"throttle");0&&(module.exports={Authorize,Controller,Delete,FromBody,FromQuery,FromRoute,Get,HttpContext,HttpResult,Inject,Injectable,JwtAuthService,Patch,Post,Put,ServiceCollection,ServiceProvider,WebApplication,WebApplicationBuilder,cors,throttle});
package/dist/main.d.cts CHANGED
@@ -62,7 +62,9 @@ declare class HttpContext {
62
62
 
63
63
  declare class WebApplicationBuilder {
64
64
  services: ServiceCollection;
65
+ private controllers;
65
66
  constructor();
67
+ addControllers(path?: string): Promise<this>;
66
68
  build(): WebApplication;
67
69
  }
68
70
 
@@ -71,10 +73,16 @@ declare class WebApplication {
71
73
  services: ServiceProvider;
72
74
  private middlewares;
73
75
  private controllersToMap;
74
- constructor(services: ServiceProvider);
76
+ private router;
77
+ constructor(services: ServiceProvider, controllers?: Array<any>);
75
78
  static createBuilder(): WebApplicationBuilder;
76
79
  use(middleware: Middleware): this;
77
80
  mapControllers(controllers: Array<any>): this;
81
+ mapGet(path: string, handler: (context: HttpContext) => any): this;
82
+ mapPost(path: string, handler: (context: HttpContext) => any): this;
83
+ mapPut(path: string, handler: (context: HttpContext) => any): this;
84
+ mapDelete(path: string, handler: (context: HttpContext) => any): this;
85
+ mapPatch(path: string, handler: (context: HttpContext) => any): this;
78
86
  private executePipeline;
79
87
  run(port?: number): void;
80
88
  }
package/dist/main.d.ts CHANGED
@@ -62,7 +62,9 @@ declare class HttpContext {
62
62
 
63
63
  declare class WebApplicationBuilder {
64
64
  services: ServiceCollection;
65
+ private controllers;
65
66
  constructor();
67
+ addControllers(path?: string): Promise<this>;
66
68
  build(): WebApplication;
67
69
  }
68
70
 
@@ -71,10 +73,16 @@ declare class WebApplication {
71
73
  services: ServiceProvider;
72
74
  private middlewares;
73
75
  private controllersToMap;
74
- constructor(services: ServiceProvider);
76
+ private router;
77
+ constructor(services: ServiceProvider, controllers?: Array<any>);
75
78
  static createBuilder(): WebApplicationBuilder;
76
79
  use(middleware: Middleware): this;
77
80
  mapControllers(controllers: Array<any>): this;
81
+ mapGet(path: string, handler: (context: HttpContext) => any): this;
82
+ mapPost(path: string, handler: (context: HttpContext) => any): this;
83
+ mapPut(path: string, handler: (context: HttpContext) => any): this;
84
+ mapDelete(path: string, handler: (context: HttpContext) => any): this;
85
+ mapPatch(path: string, handler: (context: HttpContext) => any): this;
78
86
  private executePipeline;
79
87
  run(port?: number): void;
80
88
  }
package/dist/main.js CHANGED
@@ -1 +1 @@
1
- var D=Object.defineProperty;var te=Object.getOwnPropertyDescriptor;var ne=Object.getOwnPropertyNames;var re=Object.prototype.hasOwnProperty;var a=(t,e)=>D(t,"name",{value:e,configurable:!0});var w=(t,e)=>()=>(t&&(e=t(t=0)),e);var K=(t,e)=>{for(var n in e)D(t,n,{get:e[n],enumerable:!0})},se=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of ne(e))!re.call(t,s)&&s!==n&&D(t,s,{get:()=>e[s],enumerable:!(r=te(e,s))||r.enumerable});return t};var z=t=>se(D({},"__esModule",{value:!0}),t);import"reflect-metadata";function E(){return t=>{Reflect.defineMetadata(oe,!0,t)}}function ie(t){return(e,n,r)=>{let s=Reflect.getMetadata(H,e)||[];s.push({index:r,token:t}),Reflect.defineMetadata(H,s,e)}}var oe,H,M=w(()=>{"use strict";oe=Symbol("INJECTABLE_WATERMARK"),H=Symbol("INJECT_METADATA");a(E,"Injectable");a(ie,"Inject")});import"reflect-metadata";function ae(t){return(e,n)=>{let r={required:!0,roles:t};n!==void 0?Reflect.defineMetadata(O,r,e.constructor,n):Reflect.defineMetadata(O,r,e)}}var O,k=w(()=>{"use strict";O=Symbol("AUTHORIZE_METADATA");a(ae,"Authorize")});var A,J=w(()=>{"use strict";A=class t{static{a(this,"HttpResult")}status;body;headers;constructor(e,n,r={}){this.status=e,this.body=n!==void 0&&typeof n!="string"?JSON.stringify(n):n,this.headers=r}static ok(e){return new t(200,e)}static created(e,n){let r={};return n&&(r.Location=n),new t(201,e,r)}static noContent(){return new t(204)}static badRequest(e="Bad Request",n){let r=typeof e=="string"?{message:e,errors:n}:e;return new t(400,r)}static unauthorized(e="Unauthorized"){let n=typeof e=="string"?{message:e}:e;return new t(401,n)}static forbidden(e="Forbidden"){let n=typeof e=="string"?{message:e}:e;return new t(403,n)}static notFound(e="Not Found"){let n=typeof e=="string"?{message:e}:e;return new t(404,n)}static conflict(e="Conflict"){let n=typeof e=="string"?{message:e}:e;return new t(409,n)}static unprocessableEntity(e="Unprocessable Entity",n){let r=typeof e=="string"?{message:e,errors:n}:e;return new t(422,r)}static internalServerError(e="Internal Server Error"){let n=typeof e=="string"?{message:e}:e;return new t(500,n)}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})}}});import"reflect-metadata";function ce(t=""){return e=>{Reflect.defineMetadata(L,t,e),E()(e)}}function he(t,e){return(n,r,s)=>{U(n,r,{type:0,index:s,name:t,schema:e})}}function me(t,e){return(n,r,s)=>{U(n,r,{type:1,index:s,name:t,schema:e})}}function ye(t){return(e,n,r)=>{U(e,n,{type:2,index:r,schema:t})}}function U(t,e,n){let r=`${q.toString()}_${e.toString()}`;Reflect.hasMetadata(r,t.constructor)||Reflect.defineMetadata(r,[],t.constructor);let s=Reflect.getMetadata(r,t.constructor);s.push(n),Reflect.defineMetadata(r,s,t.constructor)}var L,R,q,j,le,de,ue,fe,pe,g,B=w(()=>{"use strict";M();L=Symbol("CONTROLLER_WATERMARK"),R=Symbol("ROUTE_METADATA"),q=Symbol("PARAM_METADATA");a(ce,"Controller");j=a(t=>(e="")=>(n,r)=>{Reflect.hasMetadata(R,n.constructor)||Reflect.defineMetadata(R,[],n.constructor);let s=Reflect.getMetadata(R,n.constructor);s.push({method:t,path:e,methodName:r.toString()}),Reflect.defineMetadata(R,s,n.constructor)},"createRouteDecorator"),le=j("GET"),de=j("POST"),ue=j("PUT"),fe=j("DELETE"),pe=j("PATCH"),g=(function(t){return t[t.Route=0]="Route",t[t.Query=1]="Query",t[t.Body=2]="Body",t[t.Context=3]="Context",t})({});a(he,"FromRoute");a(me,"FromQuery");a(ye,"FromBody");a(U,"addParamMetadata")});var Q={};K(Q,{JwtAuthService:()=>T});function ge(t,e,n,r){var s=arguments.length,o=s<3?e:r===null?r=Object.getOwnPropertyDescriptor(e,n):r,i;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")o=Reflect.decorate(t,e,n,r);else for(var c=t.length-1;c>=0;c--)(i=t[c])&&(o=(s<3?i(o):s>3?i(e,n,o):i(e,n))||o);return s>3&&o&&Object.defineProperty(e,n,o),o}function G(t,e){if(typeof Reflect=="object"&&typeof Reflect.metadata=="function")return Reflect.metadata(t,e)}function $(t){return btoa(t).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function X(t){let e=t+"==".slice(2-t.length*3&3);return atob(e.replace(/-/g,"+").replace(/_/g,"/"))}var T,W=w(()=>{"use strict";M();a(ge,"_ts_decorate");a(G,"_ts_metadata");a($,"base64UrlEncode");a(X,"base64UrlDecode");T=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 n={alg:"HS256",typ:"JWT"},r=Math.floor(Date.now()/1e3),s={...e,iat:r,exp:r+this.expiresIn},o=$(JSON.stringify(n)),i=$(JSON.stringify(s)),c=`${o}.${i}`,l=await this.getKey(),u=new TextEncoder,h=await crypto.subtle.sign("HMAC",l,u.encode(c)),f=$(String.fromCharCode(...new Uint8Array(h)));return`${c}.${f}`}async verify(e){let n=e.split(".");if(n.length!==3)throw new Error("Invalid JWT format");let r=n[0],s=n[1],o=n[2],i=`${r}.${s}`,c=await this.getKey(),l=new TextEncoder,u=Uint8Array.from(X(o),N=>N.charCodeAt(0));if(!await crypto.subtle.verify("HMAC",c,u,l.encode(i)))throw new Error("Invalid JWT signature");let f=JSON.parse(X(s)),x=Math.floor(Date.now()/1e3);if(f.exp!==void 0&&f.exp<x)throw new Error("JWT expired");return f}};T=ge([E(),G("design:type",Function),G("design:paramtypes",[typeof JwtOptions>"u"?Object:JwtOptions])],T)});var Z={};K(Z,{Router:()=>F});async function we(t,e,n){if(!n.required)return null;let r=t.request.headers.get("authorization");if(!r||!r.startsWith("Bearer "))return new Response(JSON.stringify({message:"Unauthorized"}),{status:401,headers:{"Content-Type":"application/json"}});let s=r.slice(7),o;try{let{JwtAuthService:c}=(W(),z(Q));o=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 o.verify(s)}catch{return new Response(JSON.stringify({message:"Unauthorized: invalid or expired token"}),{status:401,headers:{"Content-Type":"application/json"}})}if(n.roles&&n.roles.length>0){let c=i.roles??[];if(!n.roles.some(u=>c.includes(u)))return new Response(JSON.stringify({message:"Forbidden: insufficient permissions"}),{status:403,headers:{"Content-Type":"application/json"}})}return t.items.set("user",i),null}var F,V=w(()=>{"use strict";k();J();B();a(we,"checkAuth");F=class{static{a(this,"Router")}routes=[];registerControllers(e){for(let n of e){let r=Reflect.getMetadata(L,n);if(r===void 0)continue;let s=Reflect.getMetadata(R,n)||[];for(let o of s){let i=`/${r}/${o.path}`.replace(/\/+/g,"/");i!=="/"&&i.endsWith("/")&&(i=i.slice(0,-1));let c=new URLPattern({pathname:i});this.routes.push({method:o.method,pattern:c,controller:n,methodName:o.methodName})}}}middleware(){return async(e,n)=>{for(let r of this.routes){if(r.method!==e.method)continue;let s=r.pattern.exec({pathname:e.path});if(s){let o=e.items.get("scope");if(!o)throw new Error("DI Scope not found in HttpContext");let i=Reflect.getMetadata(O,r.controller,r.methodName),c=Reflect.getMetadata(O,r.controller),l=i??c;if(l){let d=await we(e,o,l);if(d)return d}let u=await o.resolve(r.controller),h=`${q.toString()}_${r.methodName}`,f=Reflect.getMetadata(h,r.controller)||[],x=u[r.methodName].length,N=new Array(x).fill(void 0),Y=f.some(d=>d.type===g.Body),_;Y&&(_=await e.request.json().catch(()=>({})));let ee=new URL(e.request.url);for(let d of f){let y;if(d.type===g.Route&&d.name?y=s.pathname.groups[d.name]:d.type===g.Query&&d.name?y=ee.searchParams.get(d.name):d.type===g.Body?y=_:d.type===g.Context&&(y=e),d.schema){let P=d.schema.safeParse(y);if(!P.success)return A.unprocessableEntity("Validation failed",{errors:P.error.errors,target:g[d.type].toLowerCase(),name:d.name}).toResponse();y=P.data}N[d.index]=y}let m=await u[r.methodName](...N);return m instanceof Response?m:m instanceof A?m.toResponse():typeof m=="object"?Response.json(m):new Response(String(m))}}return n()}}}});M();import"reflect-metadata";var p=(function(t){return t[t.Singleton=0]="Singleton",t[t.Transient=1]="Transient",t[t.Scoped=2]="Scoped",t})({});var S=class t{static{a(this,"ServiceProvider")}descriptors;parent;singletonInstances=new Map;scopedInstances=new Map;trackedInstances=new Set;constructor(e,n){this.descriptors=e,this.parent=n}createScope(){return new t(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 n=this.descriptors.find(r=>r.token===e);if(!n){if(this.parent)return this.parent.resolve(e);throw new Error(`Service not registered for token: ${e.toString()}`)}switch(n.lifetime){case p.Singleton:return this.resolveSingleton(n);case p.Scoped:return this.resolveScoped(n);case p.Transient:return this.resolveTransient(n)}}async resolveSingleton(e){let n=this.getRoot();if(n.singletonInstances.has(e.token))return n.singletonInstances.get(e.token);let r=await this.createInstance(n,e);return n.singletonInstances.set(e.token,r),r}async resolveScoped(e){if(this.scopedInstances.has(e.token))return this.scopedInstances.get(e.token);let n=await this.createInstance(this,e);return this.scopedInstances.set(e.token,n),n}async resolveTransient(e){return this.createInstance(this,e)}async createInstance(e,n){let r;if(n.implementationInstance!==void 0)r=n.implementationInstance;else if(n.implementationFactory)r=await n.implementationFactory(this);else if(n.implementationType)r=await this.instantiateClass(n.implementationType);else throw new Error(`Invalid service descriptor for token: ${n.token.toString()}`);let s=Symbol.for("steampunk:initialized");return typeof r.onInit=="function"&&!r[s]&&(await r.onInit(),r[s]=!0),typeof r.onDestroy=="function"&&n.lifetime!==p.Transient&&e.trackedInstances.add(r),r}getRoot(){return this.parent?this.parent.getRoot():this}async instantiateClass(e){let n=Reflect.getMetadata("design:paramtypes",e)||[],r=Reflect.getMetadata(H,e)||[],s=await Promise.all(n.map(async(o,i)=>{let c=r.find(u=>u.index===i),l=c?c.token:o;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(...s)}};var v=class{static{a(this,"ServiceCollection")}descriptors=[];add(e){return this.descriptors.push(e),this}addSingleton(e,n){return this.add({token:e,implementationType:n||e,lifetime:p.Singleton})}addSingletonInstance(e,n){return this.add({token:e,implementationInstance:n,lifetime:p.Singleton})}addTransient(e,n){return this.add({token:e,implementationType:n||e,lifetime:p.Transient})}addScoped(e,n){return this.add({token:e,implementationType:n||e,lifetime:p.Scoped})}buildServiceProvider(){return new S(this.descriptors)}addControllers(e){return e.forEach(n=>this.addTransient(n)),this}};var b=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 C=class{static{a(this,"WebApplicationBuilder")}services;constructor(){this.services=new v}build(){let e=this.services.buildServiceProvider();return new I(e)}};var I=class{static{a(this,"WebApplication")}services;middlewares=[];controllersToMap=[];constructor(e){this.services=e}static createBuilder(){return new C}use(e){return this.middlewares.push(e),this}mapControllers(e){return this.controllersToMap.push(...e),this}async executePipeline(e){let n=-1,r=a(async o=>{if(o<=n)throw new Error("next() called multiple times");n=o;let i=this.middlewares[o];if(o===this.middlewares.length)return new Response(JSON.stringify({message:"Not found"}),{status:404});if(i)return i(e,r.bind(null,o+1))},"dispatch");return await r(0)||new Response(JSON.stringify({message:"Internal Server Error"}),{status:500})}run(e=3e3){let n=this;if(this.controllersToMap.length>0){let{Router:r}=(V(),z(Z)),s=new r;s.registerControllers(this.controllersToMap),this.use(s.middleware())}Bun.serve({port:e,async fetch(r){let s=n.services.createScope();try{let o=new b(r);return o.items.set("scope",s),await n.executePipeline(o)}finally{await s.dispose()}}}),console.log(`\u{1F680} Steampunk application is running on http://localhost:${e}`)}};J();M();B();k();W();function Ae(t={}){return async(e,n)=>{let{request:r}=e,s=r.headers.get("origin"),o=await n();o||(o=new Response);let i=new Response(o.body,o);if(t.origin?typeof t.origin=="string"?i.headers.set("Access-Control-Allow-Origin",t.origin):Array.isArray(t.origin)&&s?t.origin.includes(s)&&i.headers.set("Access-Control-Allow-Origin",s):typeof t.origin=="function"&&s&&t.origin(s)&&i.headers.set("Access-Control-Allow-Origin",s):i.headers.set("Access-Control-Allow-Origin","*"),t.methods){let c=Array.isArray(t.methods)?t.methods.join(", "):t.methods;i.headers.set("Access-Control-Allow-Methods",c)}else i.headers.set("Access-Control-Allow-Methods","GET,HEAD,PUT,PATCH,POST,DELETE");if(t.allowedHeaders){let c=Array.isArray(t.allowedHeaders)?t.allowedHeaders.join(", "):t.allowedHeaders;i.headers.set("Access-Control-Allow-Headers",c)}else{let c=r.headers.get("access-control-request-headers");c&&i.headers.set("Access-Control-Allow-Headers",c)}if(t.exposedHeaders){let c=Array.isArray(t.exposedHeaders)?t.exposedHeaders.join(", "):t.exposedHeaders;i.headers.set("Access-Control-Expose-Headers",c)}return t.credentials&&i.headers.set("Access-Control-Allow-Credentials","true"),t.maxAge!==void 0&&i.headers.set("Access-Control-Max-Age",t.maxAge.toString()),r.method==="OPTIONS"?new Response(null,{headers:i.headers,status:204}):i}}a(Ae,"cors");function Re(t){let e=a(s=>{let o=s.request?.headers?.get("x-forwarded-for");return o?o.split(",")[0].trim():"global"},"defaultKeyGenerator"),n=t.keyGenerator||e,r=new Map;return async(s,o)=>{let i=n(s),c=Date.now(),l=r.get(i);if(l?c>l.resetTime?(l.count=1,l.resetTime=c+t.windowMs):l.count++:(l={count:1,resetTime:c+t.windowMs},r.set(i,l)),Math.random()<.05)for(let[f,x]of r.entries())Date.now()>x.resetTime&&r.delete(f);if(l.count>t.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":t.limit.toString(),"X-RateLimit-Remaining":"0","X-RateLimit-Reset":Math.ceil(l.resetTime/1e3).toString()}})}let u=await o();u||(u=new Response);let h=new Response(u.body,u);return h.headers.set("X-RateLimit-Limit",t.limit.toString()),h.headers.set("X-RateLimit-Remaining",Math.max(0,t.limit-l.count).toString()),h.headers.set("X-RateLimit-Reset",Math.ceil(l.resetTime/1e3).toString()),h}}a(Re,"throttle");export{ae as Authorize,ce as Controller,fe as Delete,ye as FromBody,me as FromQuery,he as FromRoute,le as Get,b as HttpContext,A as HttpResult,ie as Inject,E as Injectable,T as JwtAuthService,pe as Patch,de as Post,ue as Put,v as ServiceCollection,S as ServiceProvider,I as WebApplication,C as WebApplicationBuilder,Ae as cors,Re as throttle};
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 F={};V(F,{JwtAuthService:()=>R});function pe(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 _(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(pe,"_ts_decorate");a(B,"_ts_metadata");a(J,"base64UrlEncode");a(_,"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(_(i),D=>D.charCodeAt(0));if(!await crypto.subtle.verify("HMAC",c,u,l.encode(o)))throw new Error("Invalid JWT signature");let f=JSON.parse(_(s)),g=Math.floor(Date.now()/1e3);if(f.exp!==void 0&&f.exp<g)throw new Error("JWT expired");return f}};R=pe([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"),k=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)=>{L(t,n,{type:0,index:s,name:r,schema:e})}}a(de,"FromRoute");function ue(r,e){return(t,n,s)=>{L(t,n,{type:1,index:s,name:r,schema:e})}}a(ue,"FromQuery");function fe(r){return(e,t,n)=>{L(e,t,{type:2,index:n,schema:r})}}a(fe,"FromBody");function L(r,e,t){let n=`${k.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(L,"addParamMetadata");async function he(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(F));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(he,"checkAuth");var N=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 he(e,i,u);if(d)return d}let p=await i.resolve(n.controller),f=`${k.toString()}_${n.methodName}`,g=Reflect.getMetadata(f,n.controller)||[],D=p[n.methodName].length,W=new Array(D).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 H=d.schema.safeParse(m);if(!H.success)return w.unprocessableEntity("Validation failed",{errors:H.error.errors,target:y[d.type].toLowerCase(),name:d.name}).toResponse();m=H.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 me}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 me(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 N}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 ye(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(ye,"cors");function ge(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(ge,"throttle");export{ne as Authorize,se as Controller,ce as Delete,fe as FromBody,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,ye as cors,ge as throttle};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danielgl/steampunk",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "type": "module",
5
5
  "description": "A high-performance, DX-focused web framework for Bun, inspired by ASP.NET Core.",
6
6
  "main": "./dist/main.cjs",
@@ -23,6 +23,7 @@
23
23
  "build": "tsup src/main.ts --format cjs,esm --dts --clean --minify",
24
24
  "lint": "eslint \"{src,tests,example}/**/*.ts\"",
25
25
  "lint:fix": "eslint \"{src,tests,example}/**/*.ts\" --fix",
26
+ "format:check": "prettier --check \"{src,tests,example}/**/*.ts\"",
26
27
  "format": "prettier --write \"{src,tests,example}/**/*.ts\"",
27
28
  "test": "bun test",
28
29
  "prepare": "husky",
@@ -51,6 +52,7 @@
51
52
  "eslint-config-prettier": "^10.1.8",
52
53
  "eslint-plugin-prettier": "^5.5.5",
53
54
  "husky": "^9.1.7",
55
+ "lint-staged": "^16.3.1",
54
56
  "prettier": "^3.8.1",
55
57
  "tsup": "^8.5.1",
56
58
  "typescript-eslint": "^8.56.1"
@@ -61,5 +63,11 @@
61
63
  "dependencies": {
62
64
  "reflect-metadata": "^0.2.2",
63
65
  "zod": "^4.3.6"
66
+ },
67
+ "lint-staged": {
68
+ "{src,tests,example}/**/*.ts": [
69
+ "prettier --write",
70
+ "eslint --fix"
71
+ ]
64
72
  }
65
73
  }