nucleus-core-ts 0.10.9 → 0.10.10

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/.build-ok CHANGED
@@ -1 +1 @@
1
- 0.10.9
1
+ 0.10.10
package/dist/server.js CHANGED
@@ -606,4 +606,4 @@ ${content}
606
606
  <script id="api-reference" data-url="${forHtml(documentUrl)}"></script>
607
607
  <script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"></script>
608
608
  </body>
609
- </html>`}function chainGuards(...guards){return async(context)=>{for(let guard5 of guards){let early=await guard5(context);if(early!==void 0)return early}return}}function docsGroup(groups,config){let swagger=config.swagger;if(swagger?.enabled===!1)return null;let base=swagger?.path??"/swagger",info=swagger?.documentation?.info,title=info?.title??"Nucleus API",description=info?.description??"Auto-generated API documentation",document=buildOpenApiDocument(groups,swagger),page=viewerHtml(`${base}/json`,title,description);return{prefix:base,routes:[defineRoute({method:"GET",path:"/",detail:{summary:"API documentation",tags:["Documentation"]},handler:()=>new Response(page,{headers:{"content-type":"text/html; charset=utf8"}})}),defineRoute({method:"GET",path:"/json",detail:{summary:"OpenAPI document",tags:["Documentation"]},handler:()=>document})]}}async function createNucleusServer(options){await buildNucleus(options.config);let groups=getMountedRouteGroups();if(groups.length===0)throw Error("createNucleusServer: the plugin mounted no route groups. That is a wiring "+"fault, not an empty install \u2014 refusing to serve rather than answering 404 to everything.");let resolved=getResolvedOptions2(),rawOptions=options.config.options,securityOf=(candidate)=>typeof candidate==="object"&&candidate!==null?candidate.security?.maxRequestBodyBytes:void 0,maxRequestBodyBytes=securityOf(resolved)??securityOf(rawOptions),storageCeiling=requiredBodyCeiling({storageEnabled:resolved?.storage?.enabled,maxFileSizeBytes:resolved?.storage?.maxFileSizeBytes,maxFiles:resolved?.storage?.formData?.maxFiles}),bunBodyCeiling=bunBodyCeilingFor({storageRequired:storageCeiling,guardCeiling:maxRequestBodyBytes});for(let step of getBootSteps())await step({config:{serve:{maxRequestBodySize:bunBodyCeiling}}});let hostRoutes=options.routes??[],resolvedSwagger=resolved?.swagger,outerSwagger=options.config.swagger,docs=docsGroup([...groups,...hostRoutes],{swagger:outerSwagger??resolvedSwagger});return serve({groups:[...groups,...docs?[docs]:[],...hostRoutes],maxRequestBodyBytes:bunBodyCeiling,onStop:[...getShutdownSteps(),...options.onStop??[]],socket:options.socket??getMountedSocket()??void 0,staticAssets:(()=>{let directory=getMountedStaticAssets();return directory?{prefix:"/nucleus-core",directory}:void 0})(),onRequest:chainGuards(...options.onRequest?[options.onRequest]:[],createInboundGuard({maxRequestBodyBytes}),getAuthMiddleware()),onError:getErrorHandler(),onAfter:getAfterHandler()??void 0,context:(()=>{let runtime=getMountedRuntime2();return runtime?{nucleus:runtime}:void 0})(),port:options.port,hostname:options.hostname})}init_routeCollector();init_response();function compile(pattern2){let names2=[],source=pattern2.split("/").map((segment)=>{if(segment.startsWith(":"))return names2.push(segment.slice(1)),"([^/]+)";if(segment==="*")return names2.push("*"),"(.*)";return segment.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}).join("/");return{regex:new RegExp(`^${source}/?$`),names:names2}}var DEFAULT_ERROR_RESPONDER=({set:set2,error:error3})=>{let carried=error3?.status,status=typeof carried==="number"&&carried>=100&&carried<=599?carried:500;set2.status=status;let message=status<500?String(error3?.message??""):"Internal Server Error";return Response.json(withEnvelopeFlags({isSuccess:!1,message,status,errors:[{message}],data:null}))};class NucleusTestApp{mountConfig;recorded=[];sockets=[];globalGuard;beforeHandlers=[];listening=null;errorResponder;afterResponder;table=null;constructor(mountConfig={}){this.mountConfig=mountConfig;for(let method of["get","post","put","patch","delete","head","options"]){let register=(path8,handler,schema3)=>{return this.add(method.toUpperCase(),path8,handler,schema3),this};this[method]=register}}add(method,path8,handler,schema3={}){let prefix=this.mountConfig.prefix??"",joined=path8==="/"?prefix||"/":`${prefix}${path8}`;this.recorded.push({method,path:joined,route:{method,path:joined,handler,body:schema3.body,query:schema3.query,params:schema3.params,detail:schema3.detail,type:schema3.type}}),this.table=null}ws(path8,definition){return this.sockets.push({path:path8,...definition}),this}use(plugin){if(plugin instanceof NucleusTestApp){for(let one of plugin.recorded)this.recorded.push(one);for(let socket of plugin.sockets)this.sockets.push(socket);return this.table=null,this}let group=plugin;if(group&&Array.isArray(group.routes)){let prefix=typeof group.prefix==="string"?group.prefix:"";for(let route of group.routes){let declared=route.path==="/"?"":route.path,path8=`${prefix}${declared}`||"/";this.recorded.push({method:route.method,path:path8,route:{...route,path:path8}})}this.table=null}return this}onRequest(guard5){return this.globalGuard=guard5,this.table=null,this}onError(responder){return this.errorResponder=responder,this.table=null,this}onAfterHandle(responder){return this.afterResponder=responder,this.table=null,this}onBeforeHandle(guard5){return this.beforeHandlers.push(guard5),this.table=null,this}decorate(key2,value2){let entries=typeof key2==="string"?{[key2]:value2}:key2;return Object.assign(this,entries),this}listen(port=0){return this.listening=serve({groups:[{routes:this.recorded.map((one)=>one.route)}],socket:this.sockets[0],port:Number(port)||0,reusePort:!1,onRequest:this.globalGuard,onError:this.errorResponder??DEFAULT_ERROR_RESPONDER,onAfter:this.afterResponder}),this}get server(){return this.listening??void 0}stop(closeActiveConnections){return this.listening?.stop(closeActiveConnections)}get socketRoutes(){return this.sockets}get routes(){return this.recorded.map((one)=>`${one.method} ${one.path}`)}build(){if(this.table)return this.table;let groups=[{guards:this.beforeHandlers,routes:this.recorded.map((one)=>one.route)}];return this.table=buildRoutes(groups,{onRequest:this.globalGuard,onError:this.errorResponder??DEFAULT_ERROR_RESPONDER,onAfter:this.afterResponder}),this.table}async handle(request){let table=this.build(),{pathname}=new URL(request.url),method=request.method.toUpperCase(),exact=table[pathname]??table[pathname.replace(/\/$/,"")];if(exact?.[method])return exact[method](request);for(let[pattern2,byMethod]of Object.entries(table)){if(!byMethod[method])continue;if(!pattern2.includes(":")&&!pattern2.includes("*"))continue;let{regex,names:names2}=compile(pattern2),matched=regex.exec(pathname);if(!matched)continue;let params={};return names2.forEach((name2,index)=>{params[name2]=decodeURIComponent(matched[index+1]??"")}),request.params=params,byMethod[method](request)}return new Response("NOT_FOUND",{status:404})}}init_websocket();export{serve,defineWebSocketRoute,defineRoute,decodeHeaderList,createNucleusServer,collectRoutes,buildOpenApiDocument,buildNucleus,NucleusTestApp};
609
+ </html>`}function chainGuards(...guards){return async(context)=>{for(let guard5 of guards){let early=await guard5(context);if(early!==void 0)return early}return}}function docsGroup(groups,config){let swagger=config.swagger;if(swagger?.enabled===!1)return null;let base=swagger?.path??"/swagger",info=swagger?.documentation?.info,title=info?.title??"Nucleus API",description=info?.description??"Auto-generated API documentation",document=buildOpenApiDocument(groups,swagger),page=viewerHtml(`${base}/json`,title,description);return{prefix:base,routes:[defineRoute({method:"GET",path:"/",detail:{summary:"API documentation",tags:["Documentation"]},handler:()=>new Response(page,{headers:{"content-type":"text/html; charset=utf8"}})}),defineRoute({method:"GET",path:"/json",detail:{summary:"OpenAPI document",tags:["Documentation"]},handler:()=>document})]}}async function createNucleusServer(options){await buildNucleus(options.config);let groups=getMountedRouteGroups();if(groups.length===0)throw Error("createNucleusServer: the plugin mounted no route groups. That is a wiring "+"fault, not an empty install \u2014 refusing to serve rather than answering 404 to everything.");let resolved=getResolvedOptions2(),rawOptions=options.config.options,securityOf=(candidate)=>typeof candidate==="object"&&candidate!==null?candidate.security?.maxRequestBodyBytes:void 0,maxRequestBodyBytes=securityOf(resolved)??securityOf(rawOptions),storageCeiling=requiredBodyCeiling({storageEnabled:resolved?.storage?.enabled,maxFileSizeBytes:resolved?.storage?.maxFileSizeBytes,maxFiles:resolved?.storage?.formData?.maxFiles}),bunBodyCeiling=bunBodyCeilingFor({storageRequired:storageCeiling,guardCeiling:maxRequestBodyBytes});for(let step of getBootSteps())await step({config:{serve:{maxRequestBodySize:bunBodyCeiling}}});let hostRoutes=options.routes??[],resolvedSwagger=resolved?.swagger,outerSwagger=options.config.swagger,docs=docsGroup([...groups,...hostRoutes],{swagger:outerSwagger??resolvedSwagger});return serve({groups:[...groups,...docs?[docs]:[],...hostRoutes],maxRequestBodyBytes:bunBodyCeiling,onStop:[...getShutdownSteps(),...options.onStop??[]],socket:options.socket??getMountedSocket()??void 0,staticAssets:(()=>{let directory=getMountedStaticAssets();return directory?{prefix:"/nucleus-core",directory}:void 0})(),onRequest:chainGuards(...options.onRequest?[options.onRequest]:[],createInboundGuard({maxRequestBodyBytes}),getAuthMiddleware()),onError:getErrorHandler(),onAfter:getAfterHandler()??void 0,context:(()=>{let runtime=getMountedRuntime2();return runtime?{nucleus:runtime}:void 0})(),port:options.port,hostname:options.hostname})}init_routeCollector();init_response();function compile(pattern2){let names2=[],source=pattern2.split("/").map((segment)=>{if(segment.startsWith(":"))return names2.push(segment.slice(1)),"([^/]+)";if(segment==="*")return names2.push("*"),"(.*)";return segment.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}).join("/");return{regex:new RegExp(`^${source}/?$`),names:names2}}var DEFAULT_ERROR_RESPONDER=({set:set2,error:error3})=>{let carried=error3?.status,status=typeof carried==="number"&&carried>=100&&carried<=599?carried:500;set2.status=status;let message=status<500?String(error3?.message??""):"Internal Server Error";return Response.json(withEnvelopeFlags({isSuccess:!1,message,status,errors:[{message}],data:null}))};class NucleusTestApp{mountConfig;recorded=[];decorations={};sockets=[];globalGuard;beforeHandlers=[];listening=null;errorResponder;afterResponder;table=null;constructor(mountConfig={}){this.mountConfig=mountConfig;for(let method of["get","post","put","patch","delete","head","options"]){let register=(path8,handler,schema3)=>{return this.add(method.toUpperCase(),path8,handler,schema3),this};this[method]=register}}add(method,path8,handler,schema3={}){let prefix=this.mountConfig.prefix??"",joined=path8==="/"?prefix||"/":`${prefix}${path8}`;this.recorded.push({method,path:joined,route:{method,path:joined,handler,body:schema3.body,query:schema3.query,params:schema3.params,detail:schema3.detail,type:schema3.type}}),this.table=null}ws(path8,definition){return this.sockets.push({path:path8,...definition}),this}use(plugin){if(plugin instanceof NucleusTestApp){for(let one of plugin.recorded)this.recorded.push(one);for(let socket of plugin.sockets)this.sockets.push(socket);return this.table=null,this}let group=plugin;if(group&&Array.isArray(group.routes)){let prefix=typeof group.prefix==="string"?group.prefix:"";for(let route of group.routes){let declared=route.path==="/"?"":route.path,path8=`${prefix}${declared}`||"/";this.recorded.push({method:route.method,path:path8,route:{...route,path:path8}})}this.table=null}return this}onRequest(guard5){return this.globalGuard=guard5,this.table=null,this}onError(responder){return this.errorResponder=responder,this.table=null,this}onAfterHandle(responder){return this.afterResponder=responder,this.table=null,this}onBeforeHandle(guard5){return this.beforeHandlers.push(guard5),this.table=null,this}decorate(key2,value2){let entries=typeof key2==="string"?{[key2]:value2}:key2;return Object.assign(this,entries),Object.assign(this.decorations,entries),this.table=null,this}listen(port=0){return this.listening=serve({groups:[{routes:this.recorded.map((one)=>one.route)}],socket:this.sockets[0],port:Number(port)||0,reusePort:!1,onRequest:this.globalGuard,onError:this.errorResponder??DEFAULT_ERROR_RESPONDER,onAfter:this.afterResponder}),this}get server(){return this.listening??void 0}stop(closeActiveConnections){return this.listening?.stop(closeActiveConnections)}get socketRoutes(){return this.sockets}get routes(){return this.recorded.map((one)=>`${one.method} ${one.path}`)}build(){if(this.table)return this.table;let groups=[{guards:this.beforeHandlers,routes:this.recorded.map((one)=>one.route)}];return this.table=buildRoutes(groups,{context:this.decorations,onRequest:this.globalGuard,onError:this.errorResponder??DEFAULT_ERROR_RESPONDER,onAfter:this.afterResponder}),this.table}async handle(request){let table=this.build(),{pathname}=new URL(request.url),method=request.method.toUpperCase(),exact=table[pathname]??table[pathname.replace(/\/$/,"")];if(exact?.[method])return exact[method](request);for(let[pattern2,byMethod]of Object.entries(table)){if(!byMethod[method])continue;if(!pattern2.includes(":")&&!pattern2.includes("*"))continue;let{regex,names:names2}=compile(pattern2),matched=regex.exec(pathname);if(!matched)continue;let params={};return names2.forEach((name2,index)=>{params[name2]=decodeURIComponent(matched[index+1]??"")}),request.params=params,byMethod[method](request)}return new Response("NOT_FOUND",{status:404})}}init_websocket();export{serve,defineWebSocketRoute,defineRoute,decodeHeaderList,createNucleusServer,collectRoutes,buildOpenApiDocument,buildNucleus,NucleusTestApp};
@@ -25,6 +25,8 @@ type Handler = (context: any) => unknown;
25
25
  export declare class NucleusTestApp {
26
26
  private readonly mountConfig;
27
27
  private readonly recorded;
28
+ /** What `.decorate()` put on every handler's context. */
29
+ private readonly decorations;
28
30
  private readonly sockets;
29
31
  private globalGuard;
30
32
  private beforeHandlers;
@@ -69,7 +71,18 @@ export declare class NucleusTestApp {
69
71
  * fail both refuses here with the guard's answer rather than a 422.
70
72
  */
71
73
  onBeforeHandle(guard: Handler): this;
72
- /** Elysia's `.decorate`; accepted and kept so a factory can read it back. */
74
+ /**
75
+ * Elysia's `.decorate`, including the half that matters to a handler.
76
+ *
77
+ * This used to assign onto the INSTANCE only, so a factory could read it
78
+ * back — and `ctx.nucleus` stayed undefined inside the handler, which is
79
+ * where Elysia puts it. A converted consumer test that decorated `nucleus`
80
+ * and called an endpoint got `undefined is not an object (evaluating
81
+ * 'nucleus.logger')`: the decoration was accepted, kept, and never delivered.
82
+ *
83
+ * Both now: on the instance for whoever reads it back, and on every handler's
84
+ * context, which is what `.decorate` is for.
85
+ */
73
86
  decorate(key: string | Record<string, unknown>, value?: unknown): this;
74
87
  /** Binds a port for real, because a test that reads `.server.port` needs one. */
75
88
  listen(port?: number | string): this;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nucleus-core-ts",
3
- "version": "0.10.9",
3
+ "version": "0.10.10",
4
4
  "description": "Production-ready, enterprise-grade TypeScript framework for building multi-tenant APIs",
5
5
  "author": "Hidayet Can Özcan <hidayetcan@gmail.com>",
6
6
  "license": "SEE LICENSE IN LICENSE",