@lowerdeck/execution-context 1.0.0

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.
@@ -0,0 +1,11 @@
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
@@ -0,0 +1,26 @@
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/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@lowerdeck/execution-context",
3
+ "version": "1.0.0",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "author": "Tobias Herber",
8
+ "license": "Apache 2",
9
+ "type": "module",
10
+ "source": "src/index.ts",
11
+ "exports": {
12
+ "types": "./dist/index.d.ts",
13
+ "require": "./dist/index.cjs",
14
+ "import": "./dist/index.module.js",
15
+ "default": "./dist/index.module.js"
16
+ },
17
+ "main": "./dist/index.cjs",
18
+ "module": "./dist/index.module.js",
19
+ "types": "dist/index.d.ts",
20
+ "unpkg": "./dist/index.umd.js",
21
+ "scripts": {
22
+ "test": "vitest run --passWithNoTests",
23
+ "lint": "prettier src/**/*.ts --check",
24
+ "build": "microbundle"
25
+ },
26
+ "dependencies": {
27
+ "@lowerdeck/id": "^1.0.0",
28
+ "@lowerdeck/sentry": "^1.0.0"
29
+ },
30
+ "devDependencies": {
31
+ "microbundle": "^0.15.1",
32
+ "@lowerdeck/tsconfig": "^1.0.0",
33
+ "typescript": "^5.8.3",
34
+ "vitest": "^3.1.2"
35
+ }
36
+ }
@@ -0,0 +1,27 @@
1
+ import { generateId } from '@lowerdeck/id';
2
+
3
+ export type ExecutionContext = {
4
+ contextId: string;
5
+ parent?: ExecutionContext;
6
+ } & (
7
+ | {
8
+ type: 'request';
9
+ userId?: string;
10
+ memberId?: string;
11
+ apiKeyId?: string;
12
+ machineAccessId?: string;
13
+ ip: string;
14
+ userAgent: string;
15
+ }
16
+ | { type: 'scheduled'; cron: string; name: string }
17
+ | { type: 'job'; queue: string }
18
+ | { type: 'unknown' }
19
+ );
20
+
21
+ export let createExecutionContext = (
22
+ input: ExecutionContext & { contextId?: string | undefined }
23
+ ) => {
24
+ if (!input.contextId) input.contextId = generateId('ctx_');
25
+
26
+ return input as ExecutionContext;
27
+ };
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from './execution-context';
2
+ export * from './with-execution-context';
@@ -0,0 +1,93 @@
1
+ import { getSentry } from '@lowerdeck/sentry';
2
+ import { AsyncLocalStorage } from 'async_hooks';
3
+ import { ExecutionContext } from './execution-context';
4
+
5
+ let Sentry = getSentry();
6
+
7
+ export let ctxStorage = new AsyncLocalStorage<{
8
+ context: ExecutionContext;
9
+ afterHooks?: Array<() => Promise<void | any>>;
10
+ }>();
11
+
12
+ export let withExecutionContext = async <T>(
13
+ cb: (ctx: ExecutionContext) => Promise<T>
14
+ ): Promise<T> => {
15
+ let ctx = ctxStorage.getStore();
16
+ if (!ctx) {
17
+ throw new Error('No execution context found');
18
+ }
19
+
20
+ return await cb(ctx.context);
21
+ };
22
+
23
+ export let withExecutionContextOptional = async <T>(
24
+ cb: (ctx: ExecutionContext | null) => Promise<T>
25
+ ): Promise<T> => {
26
+ let ctx = ctxStorage.getStore();
27
+ return await cb(ctx?.context ?? null);
28
+ };
29
+
30
+ export let addAfterHook = async (hook: () => Promise<void | any>) => {
31
+ let ctx = ctxStorage.getStore();
32
+ if (!ctx) {
33
+ throw new Error('No execution context found');
34
+ }
35
+
36
+ if (!ctx.afterHooks) {
37
+ throw new Error('After hooks not enabled for this execution context');
38
+ }
39
+
40
+ ctx.afterHooks.push(hook);
41
+ };
42
+
43
+ export let provideExecutionContext = async <T>(
44
+ ctx: ExecutionContext,
45
+ cb: () => Promise<T>
46
+ ): Promise<T> => {
47
+ let afterHooks: Array<() => Promise<void | any>> = [];
48
+
49
+ Sentry.setContext('executionContext', ctx);
50
+
51
+ let res = await ctxStorage.run(
52
+ {
53
+ context: ctx,
54
+ afterHooks
55
+ },
56
+ async () => await cb()
57
+ );
58
+
59
+ for (let hook of afterHooks) {
60
+ hook().catch(err => {
61
+ Sentry.captureException(err);
62
+
63
+ console.error('Error in after hook', {
64
+ err,
65
+ context: ctx
66
+ });
67
+ });
68
+ }
69
+
70
+ return res;
71
+ };
72
+
73
+ export let setExecutionContextSync = (ctx: ExecutionContext) => {
74
+ ctxStorage.enterWith({
75
+ context: ctx
76
+ });
77
+ };
78
+
79
+ export let updateExecutionContext = (ctx: Partial<ExecutionContext>) => {
80
+ let currentCtx = getExecutionContext();
81
+
82
+ Object.assign(currentCtx, ctx);
83
+
84
+ return currentCtx;
85
+ };
86
+
87
+ export let getExecutionContext = () => {
88
+ let ctx = ctxStorage.getStore();
89
+ if (!ctx) {
90
+ throw new Error('No execution context found');
91
+ }
92
+ return ctx.context;
93
+ };
package/tsconfig.json ADDED
@@ -0,0 +1,13 @@
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
+ }