🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

@fluojs/http

Package Overview
Dependencies
Maintainers
1
Versions
15
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@fluojs/http - npm Package Compare versions

Comparing version
1.1.0
to
1.1.1
+14
-0
dist/context/request-context-node-store.d.ts

@@ -17,2 +17,9 @@ import type { RequestContextStore } from './request-context-store.js';

/**
* Resolves host-provided `AsyncLocalStorage` without async imports or throwing host probes.
*
* @param host Host global-like object to inspect for synchronous async-context support.
* @returns The resolved `AsyncLocalStorage` constructor, or `undefined` when unavailable.
*/
export declare function resolveImmediateAsyncLocalStorageConstructor(host?: AsyncLocalStorageResolutionHost): AsyncLocalStorageConstructor | undefined;
/**
* Resolves the host `AsyncLocalStorage` constructor without eagerly importing Node built-ins.

@@ -25,3 +32,10 @@ *

export declare function resolveAsyncLocalStorageConstructor(host?: AsyncLocalStorageResolutionHost, loadNodeAsyncHooks?: NodeAsyncHooksLoader): Promise<AsyncLocalStorageConstructor | undefined>;
/**
* Reports whether the host can still resolve Node async-context storage asynchronously.
*
* @param host Host global-like object to inspect for Node runtime markers.
* @returns `true` when the host is Node.js and can use a lazy `node:async_hooks` import.
*/
export declare function canResolveAsyncLocalStorageDynamically(host?: AsyncLocalStorageResolutionHost): boolean;
export {};
//# sourceMappingURL=request-context-node-store.d.ts.map
+1
-1

@@ -1,1 +0,1 @@

{"version":3,"file":"request-context-node-store.d.ts","sourceRoot":"","sources":["../../src/context/request-context-node-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAEtE,KAAK,4BAA4B,GAAG,UAAU,mBAAmB,CAAC;AAElE,KAAK,oBAAoB,GAAG;IAC1B,iBAAiB,CAAC,EAAE,4BAA4B,CAAC;CAClD,CAAC;AAEF,KAAK,+BAA+B,GAAG;IACrC,iBAAiB,CAAC,EAAE,4BAA4B,CAAC;IACjD,OAAO,CAAC,EAAE;QACR,gBAAgB,CAAC,CAAC,EAAE,EAAE,kBAAkB,GAAG,oBAAoB,CAAC;QAChE,QAAQ,CAAC,EAAE;YACT,IAAI,CAAC,EAAE,MAAM,CAAC;SACf,CAAC;KACH,CAAC;CACH,CAAC;AAEF,KAAK,oBAAoB,GAAG,MAAM,OAAO,CAAC,oBAAoB,CAAC,CAAC;AAEhE;;;;;;GAMG;AACH,wBAAsB,mCAAmC,CACvD,IAAI,GAAE,+BAA4C,EAClD,kBAAkB,GAAE,oBAA2C,GAC9D,OAAO,CAAC,4BAA4B,GAAG,SAAS,CAAC,CAsBnD"}
{"version":3,"file":"request-context-node-store.d.ts","sourceRoot":"","sources":["../../src/context/request-context-node-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAEtE,KAAK,4BAA4B,GAAG,UAAU,mBAAmB,CAAC;AAElE,KAAK,oBAAoB,GAAG;IAC1B,iBAAiB,CAAC,EAAE,4BAA4B,CAAC;CAClD,CAAC;AAEF,KAAK,+BAA+B,GAAG;IACrC,iBAAiB,CAAC,EAAE,4BAA4B,CAAC;IACjD,OAAO,CAAC,EAAE;QACR,gBAAgB,CAAC,CAAC,EAAE,EAAE,kBAAkB,GAAG,oBAAoB,CAAC;QAChE,QAAQ,CAAC,EAAE;YACT,IAAI,CAAC,EAAE,MAAM,CAAC;SACf,CAAC;KACH,CAAC;CACH,CAAC;AAEF,KAAK,oBAAoB,GAAG,MAAM,OAAO,CAAC,oBAAoB,CAAC,CAAC;AAEhE;;;;;GAKG;AACH,wBAAgB,4CAA4C,CAC1D,IAAI,GAAE,+BAA4C,GACjD,4BAA4B,GAAG,SAAS,CAsB1C;AAED;;;;;;GAMG;AACH,wBAAsB,mCAAmC,CACvD,IAAI,GAAE,+BAA4C,EAClD,kBAAkB,GAAE,oBAA2C,GAC9D,OAAO,CAAC,4BAA4B,GAAG,SAAS,CAAC,CAkBnD;AAED;;;;;GAKG;AACH,wBAAgB,sCAAsC,CACpD,IAAI,GAAE,+BAA4C,GACjD,OAAO,CAET"}
/**
* Resolves host-provided `AsyncLocalStorage` without async imports or throwing host probes.
*
* @param host Host global-like object to inspect for synchronous async-context support.
* @returns The resolved `AsyncLocalStorage` constructor, or `undefined` when unavailable.
*/
export function resolveImmediateAsyncLocalStorageConstructor(host = globalThis) {
if (typeof host.AsyncLocalStorage === 'function') {
return host.AsyncLocalStorage;
}
const getBuiltinModule = host.process?.getBuiltinModule;
if (typeof getBuiltinModule !== 'function') {
return undefined;
}
try {
const builtinAsyncLocalStorage = getBuiltinModule('node:async_hooks')?.AsyncLocalStorage;
if (typeof builtinAsyncLocalStorage === 'function') {
return builtinAsyncLocalStorage;
}
} catch {
return undefined;
}
return undefined;
}
/**
* Resolves the host `AsyncLocalStorage` constructor without eagerly importing Node built-ins.

@@ -9,9 +34,6 @@ *

export async function resolveAsyncLocalStorageConstructor(host = globalThis, loadNodeAsyncHooks = importNodeAsyncHooks) {
if (typeof host.AsyncLocalStorage === 'function') {
return host.AsyncLocalStorage;
const immediateAsyncLocalStorage = resolveImmediateAsyncLocalStorageConstructor(host);
if (typeof immediateAsyncLocalStorage === 'function') {
return immediateAsyncLocalStorage;
}
const builtinAsyncLocalStorage = host.process?.getBuiltinModule?.('node:async_hooks').AsyncLocalStorage;
if (typeof builtinAsyncLocalStorage === 'function') {
return builtinAsyncLocalStorage;
}
if (!isNodeHost(host)) {

@@ -27,2 +49,12 @@ return undefined;

}
/**
* Reports whether the host can still resolve Node async-context storage asynchronously.
*
* @param host Host global-like object to inspect for Node runtime markers.
* @returns `true` when the host is Node.js and can use a lazy `node:async_hooks` import.
*/
export function canResolveAsyncLocalStorageDynamically(host = globalThis) {
return isNodeHost(host);
}
function isNodeHost(host) {

@@ -29,0 +61,0 @@ return typeof host.process?.versions?.node === 'string';

@@ -1,1 +0,1 @@

{"version":3,"file":"request-context.d.ts","sourceRoot":"","sources":["../../src/context/request-context.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAO9D;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAC,CAEtF;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,IAAI,cAAc,GAAG,SAAS,CAErE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,IAAI,cAAc,CAUrD;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,cAAc,GAAG,cAAc,CAK5E;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,CAKtE;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,OAAO,EAAE,cAAc,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,SAAS,CAE7F;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,OAAO,EAAE,cAAc,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,CAE9F"}
{"version":3,"file":"request-context.d.ts","sourceRoot":"","sources":["../../src/context/request-context.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAc9D;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAC,CAgBtF;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,IAAI,cAAc,GAAG,SAAS,CAErE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,IAAI,cAAc,CAUrD;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,cAAc,GAAG,cAAc,CAK5E;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,CAKtE;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,OAAO,EAAE,cAAc,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,SAAS,CAE7F;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,OAAO,EAAE,cAAc,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,CAE9F"}
import { FluoError } from '@fluojs/core';
import { resolveAsyncLocalStorageConstructor } from './request-context-node-store.js';
import { canResolveAsyncLocalStorageDynamically, resolveAsyncLocalStorageConstructor, resolveImmediateAsyncLocalStorageConstructor } from './request-context-node-store.js';
import { createStackRequestContextStore } from './request-context-stack-store.js';
const requestContextStore = await createRequestContextStore();
let requestContextStore;
let requestContextStoreResolution;
let fallbackRequestContextStore;
const dynamicResolutionFallbackStack = [];

@@ -18,3 +21,13 @@ /**

export function runWithRequestContext(context, callback) {
return requestContextStore.run(context, callback);
const store = getResolvedRequestContextStore();
if (store) {
return store.run(context, callback);
}
if (!canResolveAsyncLocalStorageDynamically()) {
return getFallbackRequestContextStore().run(context, callback);
}
if (!isAsyncCallback(callback)) {
return runWithDynamicResolutionFallbackContext(context, callback);
}
return runWithResolvedRequestContextStore(context, callback);
}

@@ -28,3 +41,3 @@

export function getCurrentRequestContext() {
return requestContextStore.getStore();
return getRequestContextStore().getStore() ?? getDynamicResolutionFallbackContext();
}

@@ -97,8 +110,72 @@

}
function getRequestContextStore() {
return getResolvedRequestContextStore() ?? getFallbackRequestContextStore();
}
function getResolvedRequestContextStore() {
if (requestContextStore) {
return requestContextStore;
}
const AsyncLocalStorage = resolveImmediateAsyncLocalStorageConstructor();
if (typeof AsyncLocalStorage === 'function') {
requestContextStore = new AsyncLocalStorage();
return requestContextStore;
}
void resolveRequestContextStore();
return undefined;
}
async function runWithResolvedRequestContextStore(context, callback) {
const store = await resolveRequestContextStore();
return store.run(context, callback);
}
async function resolveRequestContextStore() {
requestContextStoreResolution ??= createRequestContextStore();
return requestContextStoreResolution;
}
async function createRequestContextStore() {
const AsyncLocalStorage = await resolveAsyncLocalStorageConstructor();
if (typeof AsyncLocalStorage === 'function') {
return new AsyncLocalStorage();
requestContextStore = new AsyncLocalStorage();
return requestContextStore;
}
return createStackRequestContextStore();
requestContextStore = getFallbackRequestContextStore();
return requestContextStore;
}
function getFallbackRequestContextStore() {
fallbackRequestContextStore ??= createStackRequestContextStore();
return fallbackRequestContextStore;
}
function runWithDynamicResolutionFallbackContext(context, callback) {
dynamicResolutionFallbackStack.push(context);
try {
const result = callback();
void resolveRequestContextStore();
if (isPromiseLike(result)) {
return result.finally(() => {
removeDynamicResolutionFallbackContext(context);
});
}
removeDynamicResolutionFallbackContext(context);
return result;
} catch (error) {
removeDynamicResolutionFallbackContext(context);
throw error;
}
}
function getDynamicResolutionFallbackContext() {
if (dynamicResolutionFallbackStack.length !== 1) {
return undefined;
}
return dynamicResolutionFallbackStack[0];
}
function removeDynamicResolutionFallbackContext(context) {
const index = dynamicResolutionFallbackStack.lastIndexOf(context);
if (index >= 0) {
dynamicResolutionFallbackStack.splice(index, 1);
}
}
function isPromiseLike(value) {
return typeof value === 'object' && value !== null && 'then' in value && 'finally' in value;
}
function isAsyncCallback(callback) {
return callback.constructor.name === 'AsyncFunction';
}

@@ -13,3 +13,3 @@ {

],
"version": "1.1.0",
"version": "1.1.1",
"private": false,

@@ -46,4 +46,4 @@ "license": "MIT",

"@fluojs/core": "^1.0.3",
"@fluojs/validation": "^1.0.4",
"@fluojs/di": "^1.0.3"
"@fluojs/validation": "^1.0.5",
"@fluojs/di": "^1.1.0"
},

@@ -50,0 +50,0 @@ "devDependencies": {

@@ -99,3 +99,3 @@ # @fluojs/http

`runWithRequestContext(...)`는 호스트가 `globalThis.AsyncLocalStorage` 또는 Node 내장 `node:async_hooks` 모듈로 `AsyncLocalStorage`를 제공할 때 활성 컨텍스트를 `await` 이후까지 보존합니다. 선언된 `>=20.0.0` 지원 범위의 Node 런타임은 `process.getBuiltinModule(...)`이 없어도 `node:async_hooks`를 동적으로 해석해 ALS 의미론을 유지합니다. 비동기 컨텍스트 primitive가 없는 비 Node 호스트에서는 동기 stack fallback을 사용하며, 겹치는 비동기 요청이 서로의 컨텍스트를 관찰하지 않도록 awaited continuation이 재개되기 전에 컨텍스트를 비웁니다.
`runWithRequestContext(...)`는 호스트가 `globalThis.AsyncLocalStorage` 또는 Node 내장 `node:async_hooks` 모듈로 `AsyncLocalStorage`를 제공할 때 활성 컨텍스트를 `await` 이후까지 보존합니다. 루트 `@fluojs/http` import는 async-context storage를 probe하거나 instantiate하지 않습니다. Helper가 처음 사용될 때 storage를 lazy하게 해석하고, `process.getBuiltinModule(...)` 실패를 guard하며, 동기 probe를 노출하지 않는 Node host에서는 계속 `node:async_hooks`를 동적으로 해석할 수 있습니다. 비동기 컨텍스트 primitive가 없는 비 Node 호스트에서는 동기 stack fallback을 사용하며, 겹치는 비동기 요청이 서로의 컨텍스트를 관찰하지 않도록 awaited continuation이 재개되기 전에 컨텍스트를 비웁니다.

@@ -102,0 +102,0 @@ ### 프록시 뒤의 속도 제한

@@ -101,3 +101,3 @@ # @fluojs/http

`runWithRequestContext(...)` preserves the active context across awaited work when the host provides `AsyncLocalStorage` through `globalThis.AsyncLocalStorage` or Node's built-in `node:async_hooks` module. Node runtimes in the declared `>=20.0.0` support range keep ALS semantics even when `process.getBuiltinModule(...)` is unavailable by resolving `node:async_hooks` dynamically. Non-Node hosts without an async-context primitive use a synchronous stack fallback that clears the context before awaited continuations resume, avoiding cross-request leaks instead of pretending to isolate overlapping async work.
`runWithRequestContext(...)` preserves the active context across awaited work when the host provides `AsyncLocalStorage` through `globalThis.AsyncLocalStorage` or Node's built-in `node:async_hooks` module. The root `@fluojs/http` import does not probe or instantiate async-context storage; helpers resolve storage lazily on first use, guard `process.getBuiltinModule(...)` failures, and can still resolve `node:async_hooks` dynamically for Node hosts that do not expose the synchronous probe. Non-Node hosts without an async-context primitive use a synchronous stack fallback that clears the context before awaited continuations resume, avoiding cross-request leaks instead of pretending to isolate overlapping async work.

@@ -104,0 +104,0 @@ ### Rate limiting behind proxies