{"_id":"als-browser","_rev":"2-c636e4728ac6df02efb4f6db0d2849ac","name":"als-browser","dist-tags":{"latest":"1.0.1"},"versions":{"1.0.0":{"name":"als-browser","version":"1.0.0","keywords":["async-local-storage","context","async-context","browser","polyfill"],"author":{"name":"Stephen Belanger","email":"admin@stephenbelanger.com"},"license":"MIT","_id":"als-browser@1.0.0","maintainers":[{"name":"qard","email":"admin@stephenbelanger.com"}],"dist":{"shasum":"85625d03d95dae72d2a9960d5f86adac0e99839e","tarball":"https://registry.npmjs.org/als-browser/-/als-browser-1.0.0.tgz","fileCount":26,"integrity":"sha512-fhUedkp8YYkD1E1+IUOYxQNk0ZQyCmpXeJRqqmQGG4fC0lTT6AJk0BtFDFV7yGLY1F3uMhu+fRL6TzELVBWq3w==","signatures":[{"sig":"MEUCIQCZEybDOON6Abi5J7yHo673iMy+QG3XJg/P7aHKuU08LwIgL9Dm6FWLC8tI8AtRRemfYzsIKVldDKuvDU4dCqaW+P8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":101141},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","module":"./dist/index.mjs","require":"./dist/index.js"},"./package.json":"./package.json"},"scripts":{"lint":"eslint src --ext .ts","test":"vitest run","build":"tsup","watch":"tsup --watch","typecheck":"tsc --noEmit"},"_npmUser":{"name":"qard","email":"admin@stephenbelanger.com"},"_npmVersion":"11.6.2","description":"Browser polyfill for Node.js AsyncLocalStorage","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","vitest":"^1.0.0","happy-dom":"^12.0.0","typescript":"^5.3.0","@types/node":"^20.0.0"},"_npmOperationalInternal":{"tmp":"tmp/als-browser_1.0.0_1769042220384_0.5228768959296475","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"als-browser","version":"1.0.1","description":"Browser polyfill for Node.js AsyncLocalStorage","author":{"name":"Stephen Belanger","email":"admin@stephenbelanger.com"},"license":"MIT","main":"./dist/index.js","module":"./dist/index.mjs","types":"./dist/index.d.ts","exports":{"./package.json":"./package.json",".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","module":"./dist/index.mjs","require":"./dist/index.js"}},"scripts":{"build":"tsup","lint":"eslint src --ext .ts","prepublishOnly":"npm run build && npm test","test":"vitest run","typecheck":"tsc --noEmit","watch":"tsup --watch"},"devDependencies":{"@types/node":"^20.0.0","happy-dom":"^12.0.0","tsup":"^8.0.0","typescript":"^5.3.0","vitest":"^1.0.0"},"keywords":["async-local-storage","context","async-context","browser","polyfill"],"_id":"als-browser@1.0.1","_nodeVersion":"24.12.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-DjavKf6zf4DFPdEmgsEM474MBjFcZG/1amv2/+WHGf61kVQWqf7XEn4jvpjFS4ssQbh/pkmYThaPfQK1ERC+3g==","shasum":"ddd9c2ac8ad2817e7d55f0d470b76aaa70f3d521","tarball":"https://registry.npmjs.org/als-browser/-/als-browser-1.0.1.tgz","fileCount":9,"unpackedSize":117603,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDNNbHicshbr77sLhyfXbN5boyCdEhObzG/2tBuaUocVgIgPqA6Yad9fyGwFncis7RfP0QtUhKVWpCfRm+twxikZH4="}]},"_npmUser":{"name":"qard","email":"admin@stephenbelanger.com"},"directories":{},"maintainers":[{"name":"qard","email":"admin@stephenbelanger.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/als-browser_1.0.1_1769042654860_0.08483974856056142"},"_hasShrinkwrap":false}},"time":{"created":"2026-01-22T00:37:00.383Z","modified":"2026-01-22T00:44:15.122Z","1.0.0":"2026-01-22T00:37:00.543Z","1.0.1":"2026-01-22T00:44:15.012Z"},"author":{"name":"Stephen Belanger","email":"admin@stephenbelanger.com"},"license":"MIT","keywords":["async-local-storage","context","async-context","browser","polyfill"],"description":"Browser polyfill for Node.js AsyncLocalStorage","maintainers":[{"name":"qard","email":"admin@stephenbelanger.com"}],"readme":"# als-browser\n\nBrowser-compatible polyfill for Node.js's `AsyncLocalStorage` API. This package\nenables async context propagation in browser environments by patching common\nasync browser APIs.\n\n## Features\n\n- Full `AsyncLocalStorage` API compatibility\n- Automatic patching of browser async APIs\n- Zero dependencies (dev dependencies only)\n- TypeScript support with full type definitions\n- ESM and CommonJS builds\n- Comprehensive test coverage\n\n## Installation\n\n```bash\nnpm install als-browser\n# or\npnpm add als-browser\n# or\nyarn add als-browser\n```\n\n## Usage\n\n```typescript\nimport { AsyncLocalStorage } from 'als-browser';\n\n// Create a storage instance\nconst requestContext = new AsyncLocalStorage<{ userId: string }>();\n\n// Use run() to execute code in a context\nrequestContext.run({ userId: '123' }, () => {\n  console.log(requestContext.getStore()); // { userId: '123' }\n\n  // Context is preserved through setTimeout\n  setTimeout(() => {\n    console.log(requestContext.getStore()); // { userId: '123' }\n  }, 100);\n});\n```\n\n## API\n\n### `AsyncLocalStorage<T>`\n\n#### `constructor(options?)`\n\n```typescript\nconst store = new AsyncLocalStorage<T>({\n  defaultValue?: T,  // Optional default value\n  name?: string      // Optional name for debugging\n});\n```\n\n#### `run(data, callback, ...args)`\n\nRun a function in a new async context with the given data.\n\n```typescript\nconst result = store.run(myData, () => {\n  // Your code here\n  return store.getStore(); // Returns myData\n});\n```\n\n#### `getStore()`\n\nGet the current value from this store.\n\n```typescript\nconst currentValue = store.getStore();\n```\n\n#### `enterWith(data)`\n\nEnter a new async context with the given data (no callback).\n\n```typescript\nstore.enterWith(myData);\nconsole.log(store.getStore()); // myData\n```\n\n#### `exit(callback, ...args)`\n\nRun a function with the store value set to undefined.\n\n```typescript\nstore.exit(() => {\n  console.log(store.getStore()); // undefined\n});\n```\n\n#### `disable()`\n\nRemove this store from the current async context.\n\n```typescript\nstore.disable();\n```\n\n#### Static: `bind(fn)`\n\nBind a function to the current async context.\n\n```typescript\nconst boundFn = AsyncLocalStorage.bind(() => {\n  return store.getStore();\n});\n```\n\n#### Static: `snapshot()`\n\nCapture the current async context and return a function that can restore it.\n\n```typescript\nconst snapshot = AsyncLocalStorage.snapshot();\nsnapshot(() => {\n  // Runs in captured context\n});\n```\n\n### Manual Context Propagation\n\nFor advanced use cases like code transformers or custom async instrumentation, you can manually capture and restore async context around `await` points.\n\n#### `capture(container, promise)`\n\nCapture the current async context frame before an await and store it in a container object.\n\n```typescript\nimport { capture, restore, SnapshotContainer } from 'als-browser';\n\nconst container: SnapshotContainer = {};\nconst result = restore(container, await capture(container, promise));\n```\n\n#### `restore(container, value)`\n\nRestore the async context frame after an await from the container object.\n\n```typescript\n// Transform: await foo()\n// Into: restore(container, await capture(container, foo()))\n\nconst container: SnapshotContainer = {};\nstore.run(myData, async () => {\n  // Manually preserve context across await\n  restore(container, await capture(container, asyncOperation()));\n  console.log(store.getStore()); // myData is preserved\n});\n```\n\nThese functions are primarily useful for:\n- Code transformers/compilers that automatically instrument async functions\n- Custom async context tracking systems\n- Debugging and understanding async context flow\n\n**Note**: For normal application code, prefer using the automatic patches or `AsyncLocalStorage.bind()`/`snapshot()`.\n\n## Patched Browser APIs\n\nThe following browser APIs are automatically patched to preserve async context:\n\n### Timers\n- `setTimeout`\n- `setInterval`\n- `setImmediate` (if available)\n\n### Animation\n- `requestAnimationFrame`\n- `requestIdleCallback`\n\n### Network\n- `XMLHttpRequest` event handlers (addEventListener and on* properties)\n\n## How It Works\n\nThis package implements Node.js's `AsyncContextFrame` model adapted for browsers:\n\n1. **AsyncContextFrame**: A Map-based storage for async context, stored in a module-level variable\n2. **AsyncLocalStorage**: The main API that stores and retrieves values from the current frame\n3. **Browser API Patches**: Automatically wraps callbacks to preserve context across async boundaries\n\nThe implementation replaces Node.js's V8 embedder data APIs with a simple module-level variable, making it work in any JavaScript environment.\n\n## Limitations\n\n- **Promise-based APIs**: This package does not automatically patch promise-based APIs like `fetch()`. For those, you need to manually propagate context using `AsyncLocalStorage.bind()` or `AsyncLocalStorage.snapshot()`.\n- **EventTarget.addEventListener**: Only `XMLHttpRequest` is patched. Other event targets may need manual context propagation.\n- **Module-level state**: The context is stored in a module-level variable, which means it's shared across all code in the same JavaScript realm.\n\n## Example: Request Tracing\n\n```typescript\nimport { AsyncLocalStorage } from 'als-browser';\n\nconst requestId = new AsyncLocalStorage<string>();\n\nfunction generateId() {\n  return Math.random().toString(36).slice(2);\n}\n\nfunction log(message: string) {\n  const id = requestId.getStore() || 'no-context';\n  console.log(`[${id}] ${message}`);\n}\n\n// Start a request\nrequestId.run(generateId(), async () => {\n  log('Request started');\n\n  // Context preserved through setTimeout\n  setTimeout(() => {\n    log('Async operation 1');\n  }, 100);\n\n  // Context preserved through requestAnimationFrame\n  requestAnimationFrame(() => {\n    log('Animation frame');\n  });\n\n  // For fetch, manually bind\n  const boundHandler = AsyncLocalStorage.bind(async () => {\n    const response = await fetch('/api/data');\n    log('Fetch completed');\n    return response.json();\n  });\n\n  await boundHandler();\n});\n```\n\n## Testing\n\n```bash\n# Run tests\npnpm test\n\n# Build\npnpm build\n\n# Type check\npnpm typecheck\n```\n\n## License\n\nMIT\n\n## Credits\n\nThis implementation is based on Node.js's `AsyncLocalStorage` and `AsyncContextFrame` APIs:\n- `lib/internal/async_context_frame.js`\n- `lib/internal/async_local_storage/async_context_frame.js`\n","readmeFilename":"README.md"}