@lowerdeck/execution-context 1.0.0 → 1.0.2

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/README.md ADDED
@@ -0,0 +1,56 @@
1
+ # `@lowerdeck/execution-context`
2
+
3
+ Track and manage execution context for requests, scheduled jobs, and background tasks. Provides type-safe context objects for different execution environments with support for parent-child relationships.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @lowerdeck/execution-context
9
+ yarn add @lowerdeck/execution-context
10
+ bun add @lowerdeck/execution-context
11
+ pnpm add @lowerdeck/execution-context
12
+ ```
13
+
14
+ ## Usage
15
+
16
+ ```typescript
17
+ import { createExecutionContext, ExecutionContext } from '@lowerdeck/execution-context';
18
+
19
+ // Create context for an HTTP request
20
+ const requestContext = createExecutionContext({
21
+ type: 'request',
22
+ userId: 'user_123',
23
+ ip: '192.168.1.1',
24
+ userAgent: 'Mozilla/5.0...'
25
+ });
26
+
27
+ // Create context for a scheduled job
28
+ const cronContext = createExecutionContext({
29
+ type: 'scheduled',
30
+ cron: '0 0 * * *',
31
+ name: 'daily-cleanup'
32
+ });
33
+
34
+ // Create context for a queue job
35
+ const jobContext = createExecutionContext({
36
+ type: 'job',
37
+ queue: 'emails'
38
+ });
39
+
40
+ // Nest contexts with parent relationships
41
+ const childContext = createExecutionContext({
42
+ type: 'job',
43
+ queue: 'notifications',
44
+ parent: requestContext
45
+ });
46
+
47
+ console.log(childContext.contextId); // Auto-generated ID
48
+ ```
49
+
50
+ ## License
51
+
52
+ This project is licensed under the Apache License 2.0.
53
+
54
+ <div align="center">
55
+ <sub>Built with ❤️ by <a href="https://metorial.com">Metorial</a></sub>
56
+ </div>
@@ -0,0 +1,25 @@
1
+ export type ExecutionContext = {
2
+ contextId: string;
3
+ parent?: ExecutionContext;
4
+ } & ({
5
+ type: 'request';
6
+ userId?: string;
7
+ memberId?: string;
8
+ apiKeyId?: string;
9
+ machineAccessId?: string;
10
+ ip: string;
11
+ userAgent: string;
12
+ } | {
13
+ type: 'scheduled';
14
+ cron: string;
15
+ name: string;
16
+ } | {
17
+ type: 'job';
18
+ queue: string;
19
+ } | {
20
+ type: 'unknown';
21
+ });
22
+ export declare let createExecutionContext: (input: ExecutionContext & {
23
+ contextId?: string | undefined;
24
+ }) => ExecutionContext;
25
+ //# sourceMappingURL=execution-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"execution-context.d.ts","sourceRoot":"","sources":["../src/execution-context.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,gBAAgB,CAAC;CAC3B,GAAG,CACA;IACE,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;CACnB,GACD;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACjD;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CACtB,CAAC;AAEF,eAAO,IAAI,sBAAsB,GAC/B,OAAO,gBAAgB,GAAG;IAAE,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,KAI5C,gBACjB,CAAC"}
package/dist/index.cjs ADDED
@@ -0,0 +1,2 @@
1
+ var e=require("@lowerdeck/id"),t=require("@lowerdeck/sentry"),r=require("async_hooks"),o=t.getSentry(),n=new r.AsyncLocalStorage,c=function(){var e=n.getStore();if(!e)throw new Error("No execution context found");return e.context};exports.addAfterHook=function(e){try{var t=n.getStore();if(!t)throw new Error("No execution context found");if(!t.afterHooks)throw new Error("After hooks not enabled for this execution context");return t.afterHooks.push(e),Promise.resolve()}catch(e){return Promise.reject(e)}},exports.createExecutionContext=function(t){return t.contextId||(t.contextId=e.generateId("ctx_")),t},exports.ctxStorage=n,exports.getExecutionContext=c,exports.provideExecutionContext=function(e,t){try{var r=[];return o.setContext("executionContext",e),Promise.resolve(n.run({context:e,afterHooks:r},function(){try{return Promise.resolve(t())}catch(e){return Promise.reject(e)}})).then(function(t){for(var n=0,c=r;n<c.length;n++)(0,c[n])().catch(function(t){o.captureException(t),console.error("Error in after hook",{err:t,context:e})});return t})}catch(e){return Promise.reject(e)}},exports.setExecutionContextSync=function(e){n.enterWith({context:e})},exports.updateExecutionContext=function(e){var t=c();return Object.assign(t,e),t},exports.withExecutionContext=function(e){try{var t=n.getStore();if(!t)throw new Error("No execution context found");return Promise.resolve(e(t.context))}catch(e){return Promise.reject(e)}},exports.withExecutionContextOptional=function(e){try{var t,r=n.getStore();return Promise.resolve(e(null!=(t=null==r?void 0:r.context)?t:null))}catch(e){return Promise.reject(e)}};
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sources":["../src/with-execution-context.ts","../src/execution-context.ts"],"sourcesContent":["import { getSentry } from '@lowerdeck/sentry';\nimport { AsyncLocalStorage } from 'async_hooks';\nimport { ExecutionContext } from './execution-context';\n\nlet Sentry = getSentry();\n\nexport let ctxStorage = new AsyncLocalStorage<{\n context: ExecutionContext;\n afterHooks?: Array<() => Promise<void | any>>;\n}>();\n\nexport let withExecutionContext = async <T>(\n cb: (ctx: ExecutionContext) => Promise<T>\n): Promise<T> => {\n let ctx = ctxStorage.getStore();\n if (!ctx) {\n throw new Error('No execution context found');\n }\n\n return await cb(ctx.context);\n};\n\nexport let withExecutionContextOptional = async <T>(\n cb: (ctx: ExecutionContext | null) => Promise<T>\n): Promise<T> => {\n let ctx = ctxStorage.getStore();\n return await cb(ctx?.context ?? null);\n};\n\nexport let addAfterHook = async (hook: () => Promise<void | any>) => {\n let ctx = ctxStorage.getStore();\n if (!ctx) {\n throw new Error('No execution context found');\n }\n\n if (!ctx.afterHooks) {\n throw new Error('After hooks not enabled for this execution context');\n }\n\n ctx.afterHooks.push(hook);\n};\n\nexport let provideExecutionContext = async <T>(\n ctx: ExecutionContext,\n cb: () => Promise<T>\n): Promise<T> => {\n let afterHooks: Array<() => Promise<void | any>> = [];\n\n Sentry.setContext('executionContext', ctx);\n\n let res = await ctxStorage.run(\n {\n context: ctx,\n afterHooks\n },\n async () => await cb()\n );\n\n for (let hook of afterHooks) {\n hook().catch(err => {\n Sentry.captureException(err);\n\n console.error('Error in after hook', {\n err,\n context: ctx\n });\n });\n }\n\n return res;\n};\n\nexport let setExecutionContextSync = (ctx: ExecutionContext) => {\n ctxStorage.enterWith({\n context: ctx\n });\n};\n\nexport let updateExecutionContext = (ctx: Partial<ExecutionContext>) => {\n let currentCtx = getExecutionContext();\n\n Object.assign(currentCtx, ctx);\n\n return currentCtx;\n};\n\nexport let getExecutionContext = () => {\n let ctx = ctxStorage.getStore();\n if (!ctx) {\n throw new Error('No execution context found');\n }\n return ctx.context;\n};\n","import { generateId } from '@lowerdeck/id';\n\nexport type ExecutionContext = {\n contextId: string;\n parent?: ExecutionContext;\n} & (\n | {\n type: 'request';\n userId?: string;\n memberId?: string;\n apiKeyId?: string;\n machineAccessId?: string;\n ip: string;\n userAgent: string;\n }\n | { type: 'scheduled'; cron: string; name: string }\n | { type: 'job'; queue: string }\n | { type: 'unknown' }\n);\n\nexport let createExecutionContext = (\n input: ExecutionContext & { contextId?: string | undefined }\n) => {\n if (!input.contextId) input.contextId = generateId('ctx_');\n\n return input as ExecutionContext;\n};\n"],"names":["Sentry","getSentry","ctxStorage","AsyncLocalStorage","getExecutionContext","ctx","getStore","Error","context","hook","afterHooks","push","Promise","resolve","e","reject","input","contextId","generateId","cb","setContext","run","then","res","_i","_afterHooks","length","err","captureException","console","error","enterWith","currentCtx","Object","assign","_ctx$context"],"mappings":"uFAIIA,EAASC,EAAAA,YAEFC,EAAa,IAAIC,EAAAA,kBAgFjBC,EAAsB,WAC/B,IAAIC,EAAMH,EAAWI,WACrB,IAAKD,EACH,MAAU,IAAAE,MAAM,8BAElB,OAAOF,EAAIG,OACb,uBA/DW,SAAsBC,GAA+B,IAC9D,IAAIJ,EAAMH,EAAWI,WACrB,IAAKD,EACH,MAAU,IAAAE,MAAM,8BAGlB,IAAKF,EAAIK,WACP,MAAM,IAAIH,MAAM,sDAGQ,OAA1BF,EAAIK,WAAWC,KAAKF,GAAMG,QAAAC,SAC5B,CAAC,MAAAC,UAAAF,QAAAG,OAAAD,EAAA,CAAA,iCCpBmC,SAClCE,GAIA,OAFKA,EAAMC,YAAWD,EAAMC,UAAYC,EAAAA,WAAW,SAE5CF,CACT,qFDgBkC,SAChCX,EACAc,GACc,IACd,IAAIT,EAA+C,GAER,OAA3CV,EAAOoB,WAAW,mBAAoBf,GAAKO,QAAAC,QAE3BX,EAAWmB,IACzB,CACEb,QAASH,EACTK,WAAAA,GACDE,WAAAA,IAAAA,OAAAA,QAAAC,QACiBM,IAAI,CAAA,MAAAL,GAAA,OAAAF,QAAAG,OAAAD,EACvB,CAAA,IAAAQ,KANGC,SAAAA,GAQJ,IAAA,IAAAC,EAAA,EAAAC,EAAiBf,EAAUc,EAAAC,EAAAC,OAAAF,KACzBf,EADWgB,EAAAD,MACC,MAAC,SAAAG,GACX3B,EAAO4B,iBAAiBD,GAExBE,QAAQC,MAAM,sBAAuB,CACnCH,IAAAA,EACAnB,QAASH,GAEb,GAGF,OAAOkB,CAAI,EACb,CAAC,MAAAT,UAAAF,QAAAG,OAAAD,EAAA,CAAA,kCAEoC,SAACT,GACpCH,EAAW6B,UAAU,CACnBvB,QAASH,GAEb,iCAEoC,SAACA,GACnC,IAAI2B,EAAa5B,IAIjB,OAFA6B,OAAOC,OAAOF,EAAY3B,GAEnB2B,CACT,+BAzE+B,SAC7Bb,GAAyC,IAEzC,IAAId,EAAMH,EAAWI,WACrB,IAAKD,EACH,MAAM,IAAIE,MAAM,8BACjB,OAAAK,QAAAC,QAEYM,EAAGd,EAAIG,SACtB,CAAC,MAAAM,UAAAF,QAAAG,OAAAD,EAAA,CAAA,uCAEsC,SACrCK,GAAgD,IAClCgB,IAAAA,EACV9B,EAAMH,EAAWI,WAAW,OAAAM,QAAAC,QACnBM,EAAe,OAAbgB,EAAC9B,MAAAA,OAAAA,EAAAA,EAAKG,SAAO2B,EAAI,MAClC,CAAC,MAAArB,GAAA,OAAAF,QAAAG,OAAAD,EAED,CAAA"}
@@ -0,0 +1,3 @@
1
+ export * from './execution-context';
2
+ export * from './with-execution-context';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,0BAA0B,CAAC"}
@@ -0,0 +1,2 @@
1
+ import{generateId as r}from"@lowerdeck/id";import{getSentry as t}from"@lowerdeck/sentry";import{AsyncLocalStorage as e}from"async_hooks";var o=function(t){return t.contextId||(t.contextId=r("ctx_")),t},n=t(),c=new e,i=function(r){try{var t=c.getStore();if(!t)throw new Error("No execution context found");return Promise.resolve(r(t.context))}catch(r){return Promise.reject(r)}},u=function(r){try{var t,e=c.getStore();return Promise.resolve(r(null!=(t=null==e?void 0:e.context)?t:null))}catch(r){return Promise.reject(r)}},f=function(r){try{var t=c.getStore();if(!t)throw new Error("No execution context found");if(!t.afterHooks)throw new Error("After hooks not enabled for this execution context");return t.afterHooks.push(r),Promise.resolve()}catch(r){return Promise.reject(r)}},s=function(r,t){try{var e=[];return n.setContext("executionContext",r),Promise.resolve(c.run({context:r,afterHooks:e},function(){try{return Promise.resolve(t())}catch(r){return Promise.reject(r)}})).then(function(t){for(var o=0,c=e;o<c.length;o++)(0,c[o])().catch(function(t){n.captureException(t),console.error("Error in after hook",{err:t,context:r})});return t})}catch(r){return Promise.reject(r)}},a=function(r){c.enterWith({context:r})},x=function(r){var t=h();return Object.assign(t,r),t},h=function(){var r=c.getStore();if(!r)throw new Error("No execution context found");return r.context};export{f as addAfterHook,o as createExecutionContext,c as ctxStorage,h as getExecutionContext,s as provideExecutionContext,a as setExecutionContextSync,x as updateExecutionContext,i as withExecutionContext,u as withExecutionContextOptional};
2
+ //# sourceMappingURL=index.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.module.js","sources":["../src/execution-context.ts","../src/with-execution-context.ts"],"sourcesContent":["import { generateId } from '@lowerdeck/id';\n\nexport type ExecutionContext = {\n contextId: string;\n parent?: ExecutionContext;\n} & (\n | {\n type: 'request';\n userId?: string;\n memberId?: string;\n apiKeyId?: string;\n machineAccessId?: string;\n ip: string;\n userAgent: string;\n }\n | { type: 'scheduled'; cron: string; name: string }\n | { type: 'job'; queue: string }\n | { type: 'unknown' }\n);\n\nexport let createExecutionContext = (\n input: ExecutionContext & { contextId?: string | undefined }\n) => {\n if (!input.contextId) input.contextId = generateId('ctx_');\n\n return input as ExecutionContext;\n};\n","import { getSentry } from '@lowerdeck/sentry';\nimport { AsyncLocalStorage } from 'async_hooks';\nimport { ExecutionContext } from './execution-context';\n\nlet Sentry = getSentry();\n\nexport let ctxStorage = new AsyncLocalStorage<{\n context: ExecutionContext;\n afterHooks?: Array<() => Promise<void | any>>;\n}>();\n\nexport let withExecutionContext = async <T>(\n cb: (ctx: ExecutionContext) => Promise<T>\n): Promise<T> => {\n let ctx = ctxStorage.getStore();\n if (!ctx) {\n throw new Error('No execution context found');\n }\n\n return await cb(ctx.context);\n};\n\nexport let withExecutionContextOptional = async <T>(\n cb: (ctx: ExecutionContext | null) => Promise<T>\n): Promise<T> => {\n let ctx = ctxStorage.getStore();\n return await cb(ctx?.context ?? null);\n};\n\nexport let addAfterHook = async (hook: () => Promise<void | any>) => {\n let ctx = ctxStorage.getStore();\n if (!ctx) {\n throw new Error('No execution context found');\n }\n\n if (!ctx.afterHooks) {\n throw new Error('After hooks not enabled for this execution context');\n }\n\n ctx.afterHooks.push(hook);\n};\n\nexport let provideExecutionContext = async <T>(\n ctx: ExecutionContext,\n cb: () => Promise<T>\n): Promise<T> => {\n let afterHooks: Array<() => Promise<void | any>> = [];\n\n Sentry.setContext('executionContext', ctx);\n\n let res = await ctxStorage.run(\n {\n context: ctx,\n afterHooks\n },\n async () => await cb()\n );\n\n for (let hook of afterHooks) {\n hook().catch(err => {\n Sentry.captureException(err);\n\n console.error('Error in after hook', {\n err,\n context: ctx\n });\n });\n }\n\n return res;\n};\n\nexport let setExecutionContextSync = (ctx: ExecutionContext) => {\n ctxStorage.enterWith({\n context: ctx\n });\n};\n\nexport let updateExecutionContext = (ctx: Partial<ExecutionContext>) => {\n let currentCtx = getExecutionContext();\n\n Object.assign(currentCtx, ctx);\n\n return currentCtx;\n};\n\nexport let getExecutionContext = () => {\n let ctx = ctxStorage.getStore();\n if (!ctx) {\n throw new Error('No execution context found');\n }\n return ctx.context;\n};\n"],"names":["createExecutionContext","input","contextId","generateId","Sentry","getSentry","ctxStorage","AsyncLocalStorage","withExecutionContext","cb","ctx","getStore","Error","Promise","resolve","context","e","reject","withExecutionContextOptional","_ctx$context","addAfterHook","hook","afterHooks","push","provideExecutionContext","setContext","run","then","res","_i","_afterHooks","length","err","captureException","console","error","setExecutionContextSync","enterWith","updateExecutionContext","currentCtx","getExecutionContext","Object","assign"],"mappings":"yIAoBW,IAAAA,EAAyB,SAClCC,GAIA,OAFKA,EAAMC,YAAWD,EAAMC,UAAYC,EAAW,SAE5CF,CACT,ECtBIG,EAASC,IAEFC,EAAa,IAAIC,EAKjBC,EAAoB,SAC7BC,GAAyC,IAEzC,IAAIC,EAAMJ,EAAWK,WACrB,IAAKD,EACH,MAAM,IAAIE,MAAM,8BACjB,OAAAC,QAAAC,QAEYL,EAAGC,EAAIK,SACtB,CAAC,MAAAC,UAAAH,QAAAI,OAAAD,EAAA,CAAA,EAEUE,EAA4B,SACrCT,GAAgD,IAClCU,IAAAA,EACVT,EAAMJ,EAAWK,WAAW,OAAAE,QAAAC,QACnBL,EAAe,OAAbU,EAACT,MAAAA,OAAAA,EAAAA,EAAKK,SAAOI,EAAI,MAClC,CAAC,MAAAH,GAAA,OAAAH,QAAAI,OAAAD,EAED,CAAA,EAAWI,EAAA,SAAsBC,GAA+B,IAC9D,IAAIX,EAAMJ,EAAWK,WACrB,IAAKD,EACH,MAAU,IAAAE,MAAM,8BAGlB,IAAKF,EAAIY,WACP,MAAM,IAAIV,MAAM,sDAGQ,OAA1BF,EAAIY,WAAWC,KAAKF,GAAMR,QAAAC,SAC5B,CAAC,MAAAE,UAAAH,QAAAI,OAAAD,EAAA,CAAA,EAEUQ,EAAuB,SAChCd,EACAD,GACc,IACd,IAAIa,EAA+C,GAER,OAA3ClB,EAAOqB,WAAW,mBAAoBf,GAAKG,QAAAC,QAE3BR,EAAWoB,IACzB,CACEX,QAASL,EACTY,WAAAA,GACDT,WAAAA,IAAAA,OAAAA,QAAAC,QACiBL,IAAI,CAAA,MAAAO,GAAA,OAAAH,QAAAI,OAAAD,EACvB,CAAA,IAAAW,KANGC,SAAAA,GAQJ,IAAA,IAAAC,EAAA,EAAAC,EAAiBR,EAAUO,EAAAC,EAAAC,OAAAF,KACzBR,EADWS,EAAAD,MACC,MAAC,SAAAG,GACX5B,EAAO6B,iBAAiBD,GAExBE,QAAQC,MAAM,sBAAuB,CACnCH,IAAAA,EACAjB,QAASL,GAEb,GAGF,OAAOkB,CAAI,EACb,CAAC,MAAAZ,UAAAH,QAAAI,OAAAD,EAAA,CAAA,EAEUoB,EAA0B,SAAC1B,GACpCJ,EAAW+B,UAAU,CACnBtB,QAASL,GAEb,EAEW4B,EAAyB,SAAC5B,GACnC,IAAI6B,EAAaC,IAIjB,OAFAC,OAAOC,OAAOH,EAAY7B,GAEnB6B,CACT,EAEWC,EAAsB,WAC/B,IAAI9B,EAAMJ,EAAWK,WACrB,IAAKD,EACH,MAAU,IAAAE,MAAM,8BAElB,OAAOF,EAAIK,OACb"}
@@ -0,0 +1,2 @@
1
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("@lowerdeck/id"),require("@lowerdeck/sentry"),require("async_hooks")):"function"==typeof define&&define.amd?define(["exports","@lowerdeck/id","@lowerdeck/sentry","async_hooks"],t):t((e||self).executionContext={},e.id,e.sentry,e.async_hooks)}(this,function(e,t,o,r){var n=o.getSentry(),c=new r.AsyncLocalStorage,i=function(){var e=c.getStore();if(!e)throw new Error("No execution context found");return e.context};e.addAfterHook=function(e){try{var t=c.getStore();if(!t)throw new Error("No execution context found");if(!t.afterHooks)throw new Error("After hooks not enabled for this execution context");return t.afterHooks.push(e),Promise.resolve()}catch(e){return Promise.reject(e)}},e.createExecutionContext=function(e){return e.contextId||(e.contextId=t.generateId("ctx_")),e},e.ctxStorage=c,e.getExecutionContext=i,e.provideExecutionContext=function(e,t){try{var o=[];return n.setContext("executionContext",e),Promise.resolve(c.run({context:e,afterHooks:o},function(){try{return Promise.resolve(t())}catch(e){return Promise.reject(e)}})).then(function(t){for(var r=0,c=o;r<c.length;r++)(0,c[r])().catch(function(t){n.captureException(t),console.error("Error in after hook",{err:t,context:e})});return t})}catch(e){return Promise.reject(e)}},e.setExecutionContextSync=function(e){c.enterWith({context:e})},e.updateExecutionContext=function(e){var t=i();return Object.assign(t,e),t},e.withExecutionContext=function(e){try{var t=c.getStore();if(!t)throw new Error("No execution context found");return Promise.resolve(e(t.context))}catch(e){return Promise.reject(e)}},e.withExecutionContextOptional=function(e){try{var t,o=c.getStore();return Promise.resolve(e(null!=(t=null==o?void 0:o.context)?t:null))}catch(e){return Promise.reject(e)}}});
2
+ //# sourceMappingURL=index.umd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.umd.js","sources":["../src/execution-context.ts","../src/with-execution-context.ts"],"sourcesContent":["import { generateId } from '@lowerdeck/id';\n\nexport type ExecutionContext = {\n contextId: string;\n parent?: ExecutionContext;\n} & (\n | {\n type: 'request';\n userId?: string;\n memberId?: string;\n apiKeyId?: string;\n machineAccessId?: string;\n ip: string;\n userAgent: string;\n }\n | { type: 'scheduled'; cron: string; name: string }\n | { type: 'job'; queue: string }\n | { type: 'unknown' }\n);\n\nexport let createExecutionContext = (\n input: ExecutionContext & { contextId?: string | undefined }\n) => {\n if (!input.contextId) input.contextId = generateId('ctx_');\n\n return input as ExecutionContext;\n};\n","import { getSentry } from '@lowerdeck/sentry';\nimport { AsyncLocalStorage } from 'async_hooks';\nimport { ExecutionContext } from './execution-context';\n\nlet Sentry = getSentry();\n\nexport let ctxStorage = new AsyncLocalStorage<{\n context: ExecutionContext;\n afterHooks?: Array<() => Promise<void | any>>;\n}>();\n\nexport let withExecutionContext = async <T>(\n cb: (ctx: ExecutionContext) => Promise<T>\n): Promise<T> => {\n let ctx = ctxStorage.getStore();\n if (!ctx) {\n throw new Error('No execution context found');\n }\n\n return await cb(ctx.context);\n};\n\nexport let withExecutionContextOptional = async <T>(\n cb: (ctx: ExecutionContext | null) => Promise<T>\n): Promise<T> => {\n let ctx = ctxStorage.getStore();\n return await cb(ctx?.context ?? null);\n};\n\nexport let addAfterHook = async (hook: () => Promise<void | any>) => {\n let ctx = ctxStorage.getStore();\n if (!ctx) {\n throw new Error('No execution context found');\n }\n\n if (!ctx.afterHooks) {\n throw new Error('After hooks not enabled for this execution context');\n }\n\n ctx.afterHooks.push(hook);\n};\n\nexport let provideExecutionContext = async <T>(\n ctx: ExecutionContext,\n cb: () => Promise<T>\n): Promise<T> => {\n let afterHooks: Array<() => Promise<void | any>> = [];\n\n Sentry.setContext('executionContext', ctx);\n\n let res = await ctxStorage.run(\n {\n context: ctx,\n afterHooks\n },\n async () => await cb()\n );\n\n for (let hook of afterHooks) {\n hook().catch(err => {\n Sentry.captureException(err);\n\n console.error('Error in after hook', {\n err,\n context: ctx\n });\n });\n }\n\n return res;\n};\n\nexport let setExecutionContextSync = (ctx: ExecutionContext) => {\n ctxStorage.enterWith({\n context: ctx\n });\n};\n\nexport let updateExecutionContext = (ctx: Partial<ExecutionContext>) => {\n let currentCtx = getExecutionContext();\n\n Object.assign(currentCtx, ctx);\n\n return currentCtx;\n};\n\nexport let getExecutionContext = () => {\n let ctx = ctxStorage.getStore();\n if (!ctx) {\n throw new Error('No execution context found');\n }\n return ctx.context;\n};\n"],"names":["createExecutionContext","Sentry","getSentry","ctxStorage","AsyncLocalStorage","getExecutionContext","ctx","getStore","Error","context","hook","afterHooks","push","Promise","resolve","e","reject","input","contextId","generateId","cb","setContext","run","then","res","_i","_afterHooks","length","err","captureException","console","error","enterWith","currentCtx","Object","assign","_ctx$context"],"mappings":"2YAoBWA,IChBPC,EAASC,EAAAA,YAEFC,EAAa,IAAIC,EAAAA,kBAgFjBC,EAAsB,WAC/B,IAAIC,EAAMH,EAAWI,WACrB,IAAKD,EACH,MAAU,IAAAE,MAAM,8BAElB,OAAOF,EAAIG,OACb,iBA/DW,SAAsBC,GAA+B,IAC9D,IAAIJ,EAAMH,EAAWI,WACrB,IAAKD,EACH,MAAU,IAAAE,MAAM,8BAGlB,IAAKF,EAAIK,WACP,MAAM,IAAIH,MAAM,sDAGQ,OAA1BF,EAAIK,WAAWC,KAAKF,GAAMG,QAAAC,SAC5B,CAAC,MAAAC,UAAAF,QAAAG,OAAAD,EAAA,CAAA,2BDpBmC,SAClCE,GAIA,OAFKA,EAAMC,YAAWD,EAAMC,UAAYC,EAAAA,WAAW,SAE5CF,CACT,mECgBkC,SAChCX,EACAc,GACc,IACd,IAAIT,EAA+C,GAER,OAA3CV,EAAOoB,WAAW,mBAAoBf,GAAKO,QAAAC,QAE3BX,EAAWmB,IACzB,CACEb,QAASH,EACTK,WAAAA,GACDE,WAAAA,IAAAA,OAAAA,QAAAC,QACiBM,IAAI,CAAA,MAAAL,GAAA,OAAAF,QAAAG,OAAAD,EACvB,CAAA,IAAAQ,KANGC,SAAAA,GAQJ,IAAA,IAAAC,EAAA,EAAAC,EAAiBf,EAAUc,EAAAC,EAAAC,OAAAF,KACzBf,EADWgB,EAAAD,MACC,MAAC,SAAAG,GACX3B,EAAO4B,iBAAiBD,GAExBE,QAAQC,MAAM,sBAAuB,CACnCH,IAAAA,EACAnB,QAASH,GAEb,GAGF,OAAOkB,CAAI,EACb,CAAC,MAAAT,UAAAF,QAAAG,OAAAD,EAAA,CAAA,4BAEoC,SAACT,GACpCH,EAAW6B,UAAU,CACnBvB,QAASH,GAEb,2BAEoC,SAACA,GACnC,IAAI2B,EAAa5B,IAIjB,OAFA6B,OAAOC,OAAOF,EAAY3B,GAEnB2B,CACT,yBAzE+B,SAC7Bb,GAAyC,IAEzC,IAAId,EAAMH,EAAWI,WACrB,IAAKD,EACH,MAAM,IAAIE,MAAM,8BACjB,OAAAK,QAAAC,QAEYM,EAAGd,EAAIG,SACtB,CAAC,MAAAM,UAAAF,QAAAG,OAAAD,EAAA,CAAA,iCAEsC,SACrCK,GAAgD,IAClCgB,IAAAA,EACV9B,EAAMH,EAAWI,WAAW,OAAAM,QAAAC,QACnBM,EAAe,OAAbgB,EAAC9B,MAAAA,OAAAA,EAAAA,EAAKG,SAAO2B,EAAI,MAClC,CAAC,MAAArB,GAAA,OAAAF,QAAAG,OAAAD,EAED,CAAA"}
@@ -0,0 +1,14 @@
1
+ import { AsyncLocalStorage } from 'async_hooks';
2
+ import { ExecutionContext } from './execution-context';
3
+ export declare let ctxStorage: AsyncLocalStorage<{
4
+ context: ExecutionContext;
5
+ afterHooks?: Array<() => Promise<void | any>>;
6
+ }>;
7
+ export declare let withExecutionContext: <T>(cb: (ctx: ExecutionContext) => Promise<T>) => Promise<T>;
8
+ export declare let withExecutionContextOptional: <T>(cb: (ctx: ExecutionContext | null) => Promise<T>) => Promise<T>;
9
+ export declare let addAfterHook: (hook: () => Promise<void | any>) => Promise<void>;
10
+ export declare let provideExecutionContext: <T>(ctx: ExecutionContext, cb: () => Promise<T>) => Promise<T>;
11
+ export declare let setExecutionContextSync: (ctx: ExecutionContext) => void;
12
+ export declare let updateExecutionContext: (ctx: Partial<ExecutionContext>) => ExecutionContext;
13
+ export declare let getExecutionContext: () => ExecutionContext;
14
+ //# sourceMappingURL=with-execution-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"with-execution-context.d.ts","sourceRoot":"","sources":["../src/with-execution-context.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAIvD,eAAO,IAAI,UAAU;aACV,gBAAgB;iBACZ,KAAK,CAAC,MAAM,OAAO,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC;EAC3C,CAAC;AAEL,eAAO,IAAI,oBAAoB,GAAU,CAAC,EACxC,IAAI,CAAC,GAAG,EAAE,gBAAgB,KAAK,OAAO,CAAC,CAAC,CAAC,KACxC,OAAO,CAAC,CAAC,CAOX,CAAC;AAEF,eAAO,IAAI,4BAA4B,GAAU,CAAC,EAChD,IAAI,CAAC,GAAG,EAAE,gBAAgB,GAAG,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,KAC/C,OAAO,CAAC,CAAC,CAGX,CAAC;AAEF,eAAO,IAAI,YAAY,GAAU,MAAM,MAAM,OAAO,CAAC,IAAI,GAAG,GAAG,CAAC,kBAW/D,CAAC;AAEF,eAAO,IAAI,uBAAuB,GAAU,CAAC,EAC3C,KAAK,gBAAgB,EACrB,IAAI,MAAM,OAAO,CAAC,CAAC,CAAC,KACnB,OAAO,CAAC,CAAC,CAyBX,CAAC;AAEF,eAAO,IAAI,uBAAuB,GAAI,KAAK,gBAAgB,SAI1D,CAAC;AAEF,eAAO,IAAI,sBAAsB,GAAI,KAAK,OAAO,CAAC,gBAAgB,CAAC,qBAMlE,CAAC;AAEF,eAAO,IAAI,mBAAmB,wBAM7B,CAAC"}
package/package.json CHANGED
@@ -1,9 +1,15 @@
1
1
  {
2
2
  "name": "@lowerdeck/execution-context",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
+ "files": [
8
+ "src/**",
9
+ "dist/**",
10
+ "README.md",
11
+ "package.json"
12
+ ],
7
13
  "author": "Tobias Herber",
8
14
  "license": "Apache 2",
9
15
  "type": "module",
@@ -21,15 +27,15 @@
21
27
  "scripts": {
22
28
  "test": "vitest run --passWithNoTests",
23
29
  "lint": "prettier src/**/*.ts --check",
24
- "build": "microbundle"
30
+ "build": "rm -rf ./dist && microbundle"
25
31
  },
26
32
  "dependencies": {
27
- "@lowerdeck/id": "^1.0.0",
28
- "@lowerdeck/sentry": "^1.0.0"
33
+ "@lowerdeck/id": "^1.0.5",
34
+ "@lowerdeck/sentry": "^1.0.2"
29
35
  },
30
36
  "devDependencies": {
31
37
  "microbundle": "^0.15.1",
32
- "@lowerdeck/tsconfig": "^1.0.0",
38
+ "@lowerdeck/tsconfig": "^1.0.1",
33
39
  "typescript": "^5.8.3",
34
40
  "vitest": "^3.1.2"
35
41
  }
@@ -1,11 +0,0 @@
1
-
2
- $ microbundle
3
- Build "@lowerdeck/unique" to dist:
4
- 77 B: index.cjs.gz
5
- 58 B: index.cjs.br
6
- 66 B: index.module.js.gz
7
- 50 B: index.module.js.br
8
- 88 B: index.module.js.gz
9
- 72 B: index.module.js.br
10
- 170 B: index.umd.js.gz
11
- 137 B: index.umd.js.br
@@ -1,26 +0,0 @@
1
-
2
- $ vitest run --passWithNoTests
3
- [?25l
4
-  RUN  v3.2.4 /Users/tobias/code/metorial/metorial-enterprise/oss/src/packages/shared/unique
5
-
6
- [?2026h
7
-  ❯ src/index.test.ts [queued]
8
-
9
-  Test Files 0 passed (1)
10
-  Tests 0 passed (0)
11
-  Start at 10:23:39
12
-  Duration 101ms
13
- [?2026l ✓ src/index.test.ts (6 tests) 2ms
14
- ✓ unique > should return an array with unique elements 1ms
15
- ✓ unique > should handle an empty array 0ms
16
- ✓ unique > should handle an array with all unique elements 0ms
17
- ✓ unique > should handle an array with all duplicate elements 0ms
18
- ✓ unique > should work with strings 0ms
19
- ✓ unique > should work with mixed types 0ms
20
-
21
-  Test Files  1 passed (1)
22
-  Tests  6 passed (6)
23
-  Start at  10:23:39
24
-  Duration  218ms (transform 29ms, setup 0ms, collect 28ms, tests 2ms, environment 0ms, prepare 40ms)
25
-
26
- [?25h
package/tsconfig.json DELETED
@@ -1,13 +0,0 @@
1
- {
2
- "$schema": "https://json.schemastore.org/tsconfig",
3
- "extends": "@lowerdeck/tsconfig/base.json",
4
- "exclude": [
5
- "dist"
6
- ],
7
- "include": [
8
- "src"
9
- ],
10
- "compilerOptions": {
11
- "outDir": "dist"
12
- }
13
- }