@stacksjs/router 0.70.332 → 0.70.335

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/index.d.ts CHANGED
@@ -25,7 +25,7 @@ export * from '@stacksjs/bun-router';
25
25
  export { assertRouteMiddlewareResolvable,
26
26
  configureViewDirectories, clearMiddlewareCache, createStacksRouter, findUnresolvableRouteMiddleware, installMiddlewareHotReload, route, serve, serverResponse, url, warnOnMultipleRouterInstances } from './stacks-router';
27
27
  // Export request context helpers
28
- export { cacheRequestQuery, getCurrentRequest, getTraceId, request, runWithRequest, setCurrentRequest, withTraceId } from './request-context';
28
+ export { cacheRequestQuery, clearCurrentRequest, getCurrentRequest, getTraceId, request, runWithRequest, setCurrentRequest, withTraceId } from './request-context';
29
29
  // Export Middleware class for defining route middleware
30
30
  export { Middleware } from './middleware';
31
31
  // Export route loader
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- var {require}=import.meta;import"./request-augmentation";export*from"@stacksjs/bun-router";export{assertRouteMiddlewareResolvable,configureViewDirectories,clearMiddlewareCache,createStacksRouter,findUnresolvableRouteMiddleware,installMiddlewareHotReload,route,serve,serverResponse,url,warnOnMultipleRouterInstances}from"./stacks-router";export{cacheRequestQuery,getCurrentRequest,getTraceId,request,runWithRequest,setCurrentRequest,withTraceId}from"./request-context";export{Middleware}from"./middleware";export{loadRoutes}from"./route-loader";export{clearTrackedQueries,createErrorResponse,createMiddlewareErrorResponse,createNotFoundResponse,createValidationErrorResponse,getQueryShapeCounts,trackQuery}from"./error-handler";export{listRegisteredRoutes,routeParams}from"./stacks-router";export{clearRouteModelBindings,defineRouteModelBinding,resolveRouteModel,routeModelBindings,setRouteModelFallback}from"./route-model-binding";export{isApiRequest,JSON_CONTENT_TYPE}from"./api-shape";export{rateLimit,rateLimitStatus,clearRateLimit}from"./rate-limit";export{PathParamError,safePathParam,sanitizePathParam}from"./path-sanitize";export{checkApplicationHealth,runHealthProbes}from"./health";export{stream}from"./stacks-router";export{signedUrl,signUrl,verifySignedUrl,verifySignedUrlMiddleware}from"./signed-url";export{EncryptedSessionStore}from"./encrypted-session-store";export{createSessionStore,createStacksSessionStore,DatabaseSessionStore,FileSessionStore,MemorySessionStore,RedisSessionStore}from"./session-factory";import("@stacksjs/database").then(({setQueryTracker})=>{if(typeof setQueryTracker==="function"){const{trackQuery}=require("./error-handler");setQueryTracker(trackQuery)}}).catch(()=>{});
1
+ var {require}=import.meta;import"./request-augmentation";export*from"@stacksjs/bun-router";export{assertRouteMiddlewareResolvable,configureViewDirectories,clearMiddlewareCache,createStacksRouter,findUnresolvableRouteMiddleware,installMiddlewareHotReload,route,serve,serverResponse,url,warnOnMultipleRouterInstances}from"./stacks-router";export{cacheRequestQuery,clearCurrentRequest,getCurrentRequest,getTraceId,request,runWithRequest,setCurrentRequest,withTraceId}from"./request-context";export{Middleware}from"./middleware";export{loadRoutes}from"./route-loader";export{clearTrackedQueries,createErrorResponse,createMiddlewareErrorResponse,createNotFoundResponse,createValidationErrorResponse,getQueryShapeCounts,trackQuery}from"./error-handler";export{listRegisteredRoutes,routeParams}from"./stacks-router";export{clearRouteModelBindings,defineRouteModelBinding,resolveRouteModel,routeModelBindings,setRouteModelFallback}from"./route-model-binding";export{isApiRequest,JSON_CONTENT_TYPE}from"./api-shape";export{rateLimit,rateLimitStatus,clearRateLimit}from"./rate-limit";export{PathParamError,safePathParam,sanitizePathParam}from"./path-sanitize";export{checkApplicationHealth,runHealthProbes}from"./health";export{stream}from"./stacks-router";export{signedUrl,signUrl,verifySignedUrl,verifySignedUrlMiddleware}from"./signed-url";export{EncryptedSessionStore}from"./encrypted-session-store";export{createSessionStore,createStacksSessionStore,DatabaseSessionStore,FileSessionStore,MemorySessionStore,RedisSessionStore}from"./session-factory";import("@stacksjs/database").then(({setQueryTracker})=>{if(typeof setQueryTracker==="function"){const{trackQuery}=require("./error-handler");setQueryTracker(trackQuery)}}).catch(()=>{});
@@ -42,9 +42,21 @@ export declare function setCurrentRequest(req: EnhancedRequest): void;
42
42
  *
43
43
  * `setCurrentRequest` uses `AsyncLocalStorage.enterWith`, which mutates the
44
44
  * caller's async scope and never restores it. Call this in test teardown
45
- * (`afterEach`) whenever a test body calls `setCurrentRequest`, so the leaked
46
- * frame doesn't poison subsequently-collected test files (bun's runner
47
- * mis-registers tests when collected on a foreign async frame).
45
+ * (`afterEach`) whenever a test body calls `setCurrentRequest`.
46
+ *
47
+ * `enterWith(undefined)`, not `disable()`. The two look interchangeable and
48
+ * are not: `enterWith` clears the value for this async scope, while `disable`
49
+ * turns the whole storage instance off — and `requestStorage` is process-wide,
50
+ * keyed on a `Symbol.for` so every copy of this module shares it. So one call
51
+ * to `disable()` clears the request context for the entire process, including
52
+ * requests already in flight and every other module holding the same storage.
53
+ *
54
+ * That is not theoretical. This function used to call `disable()`, and it cost
55
+ * the router suite about seven minutes a run: `bun test` puts every file in one
56
+ * process, so the first `afterEach` here disabled the storage for all thirty-
57
+ * three files, and sixty-one tests in eleven unrelated files then died on the
58
+ * hook timeout. The suite passed in any subset that excluded this one file,
59
+ * which is what made it look like accumulation rather than a single bad call.
48
60
  */
49
61
  export declare function clearCurrentRequest(): void;
50
62
  /**
@@ -1 +1 @@
1
- import process from"node:process";import{AsyncLocalStorage}from"node:async_hooks";import{log}from"@stacksjs/logging";const REQUEST_STORAGE_KEY=Symbol.for("stacks.router.requestStorage"),requestStorage=globalThis[REQUEST_STORAGE_KEY]??=new AsyncLocalStorage,TRACE_STORAGE_KEY=Symbol.for("stacks.router.traceStorage"),traceStorage=globalThis[TRACE_STORAGE_KEY]??=new AsyncLocalStorage;export function getTraceId(){const explicit=traceStorage.getStore();if(explicit)return explicit;return requestStorage.getStore()?._requestId}export function withTraceId(id,fn){return traceStorage.run(id,fn)}const REQUEST_QUERY_CACHE_KEY=Symbol.for("stacks.requestQueryCache");function getRequestCache(){const req=requestStorage.getStore();if(!req)return;let cache=req[REQUEST_QUERY_CACHE_KEY];if(!cache){cache={map:new Map};req[REQUEST_QUERY_CACHE_KEY]=cache}return cache}export async function cacheRequestQuery(key,fetcher){const cache=getRequestCache();if(!cache)return fetcher();const existing=cache.map.get(key);if(existing)return existing;const promise=Promise.resolve().then(()=>fetcher());cache.map.set(key,promise);promise.catch(()=>cache.map.delete(key));return promise}export function setCurrentRequest(req){log.debug(`[request] ${req.method} ${new URL(req.url).pathname}`);requestStorage.enterWith(req)}export function clearCurrentRequest(){requestStorage.disable()}export function runWithRequest(req,fn){return requestStorage.run(req,fn)}export function getCurrentRequest(){return requestStorage.getStore()}export const request=new Proxy({},{get(_target,prop){const currentRequest=getCurrentRequest();if(!currentRequest){if(process.env.NODE_ENV!=="production")console.warn(`[RequestContext] Accessing request.${String(prop)} outside of request context`);if(prop==="bearerToken")return()=>null;if(prop==="user"||prop==="userToken")return async()=>{return};if(prop==="tokenCan"||prop==="tokenCant")return async()=>!1;if(prop==="headers")return new Headers;if(prop==="url")return"";if(prop==="method")return"GET";return}const value=currentRequest[prop];if(typeof value==="function")return value.bind(currentRequest);return value}});
1
+ import process from"node:process";import{AsyncLocalStorage}from"node:async_hooks";import{log}from"@stacksjs/logging";const REQUEST_STORAGE_KEY=Symbol.for("stacks.router.requestStorage"),requestStorage=globalThis[REQUEST_STORAGE_KEY]??=new AsyncLocalStorage,TRACE_STORAGE_KEY=Symbol.for("stacks.router.traceStorage"),traceStorage=globalThis[TRACE_STORAGE_KEY]??=new AsyncLocalStorage;export function getTraceId(){const explicit=traceStorage.getStore();if(explicit)return explicit;return requestStorage.getStore()?._requestId}export function withTraceId(id,fn){return traceStorage.run(id,fn)}const REQUEST_QUERY_CACHE_KEY=Symbol.for("stacks.requestQueryCache");function getRequestCache(){const req=requestStorage.getStore();if(!req)return;let cache=req[REQUEST_QUERY_CACHE_KEY];if(!cache){cache={map:new Map};req[REQUEST_QUERY_CACHE_KEY]=cache}return cache}export async function cacheRequestQuery(key,fetcher){const cache=getRequestCache();if(!cache)return fetcher();const existing=cache.map.get(key);if(existing)return existing;const promise=Promise.resolve().then(()=>fetcher());cache.map.set(key,promise);promise.catch(()=>cache.map.delete(key));return promise}export function setCurrentRequest(req){log.debug(`[request] ${req.method} ${new URL(req.url).pathname}`);requestStorage.enterWith(req)}export function clearCurrentRequest(){requestStorage.enterWith(void 0)}export function runWithRequest(req,fn){return requestStorage.run(req,fn)}export function getCurrentRequest(){return requestStorage.getStore()}export const request=new Proxy({},{get(_target,prop){const currentRequest=getCurrentRequest();if(!currentRequest){if(process.env.NODE_ENV!=="production")console.warn(`[RequestContext] Accessing request.${String(prop)} outside of request context`);if(prop==="bearerToken")return()=>null;if(prop==="user"||prop==="userToken")return async()=>{return};if(prop==="tokenCan"||prop==="tokenCant")return async()=>!1;if(prop==="headers")return new Headers;if(prop==="url")return"";if(prop==="method")return"GET";return}const value=currentRequest[prop];if(typeof value==="function")return value.bind(currentRequest);return value}});
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/router",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.70.332",
5
+ "version": "0.70.335",
6
6
  "description": "The Stacks framework router.",
7
7
  "author": "Chris Breuer",
8
8
  "contributors": [
@@ -60,19 +60,19 @@
60
60
  },
61
61
  "dependencies": {
62
62
  "@stacksjs/bun-router": "^0.0.21",
63
- "@stacksjs/collections": "0.70.332",
63
+ "@stacksjs/collections": "0.70.335",
64
64
  "ts-rate-limiter": "^0.4.2"
65
65
  },
66
66
  "devDependencies": {
67
- "@stacksjs/actions": "0.70.332",
68
- "@stacksjs/config": "0.70.332",
67
+ "@stacksjs/actions": "0.70.335",
68
+ "@stacksjs/config": "0.70.335",
69
69
  "better-dx": "^0.2.17",
70
- "@stacksjs/error-handling": "0.70.332",
71
- "@stacksjs/logging": "0.70.332",
72
- "@stacksjs/orm": "0.70.332",
73
- "@stacksjs/path": "0.70.332",
74
- "@stacksjs/storage": "0.70.332",
75
- "@stacksjs/types": "0.70.332",
76
- "@stacksjs/validation": "0.70.332"
70
+ "@stacksjs/error-handling": "0.70.335",
71
+ "@stacksjs/logging": "0.70.335",
72
+ "@stacksjs/orm": "0.70.335",
73
+ "@stacksjs/path": "0.70.335",
74
+ "@stacksjs/storage": "0.70.335",
75
+ "@stacksjs/types": "0.70.335",
76
+ "@stacksjs/validation": "0.70.335"
77
77
  }
78
78
  }