Skip to content

Commit dc6e659

Browse files
committed
new locals API
1 parent e34e520 commit dc6e659

File tree

17 files changed

+188
-38
lines changed

17 files changed

+188
-38
lines changed

packages/cli-v3/src/entryPoints/dev-run-worker.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
runTimelineMetrics,
2121
lifecycleHooks,
2222
lifecycleHooksAdapters,
23+
localsAPI,
2324
} from "@trigger.dev/core/v3";
2425
import { TriggerTracer } from "@trigger.dev/core/v3/tracer";
2526
import {
@@ -41,6 +42,7 @@ import {
4142
UsageTimeoutManager,
4243
StandardRunTimelineMetricsManager,
4344
StandardLifecycleHooksManager,
45+
StandardLocalsManager,
4446
} from "@trigger.dev/core/v3/workers";
4547
import { ZodIpcConnection } from "@trigger.dev/core/v3/zodIpc";
4648
import { readFile } from "node:fs/promises";
@@ -92,6 +94,9 @@ process.on("uncaughtException", function (error, origin) {
9294

9395
const heartbeatIntervalMs = getEnvVar("HEARTBEAT_INTERVAL_MS");
9496

97+
const standardLocalsManager = new StandardLocalsManager();
98+
localsAPI.setGlobalLocalsManager(standardLocalsManager);
99+
95100
const standardRunTimelineMetricsManager = new StandardRunTimelineMetricsManager();
96101
runTimelineMetrics.setGlobalManager(standardRunTimelineMetricsManager);
97102
standardRunTimelineMetricsManager.seedMetricsFromEnvironment();

packages/cli-v3/src/entryPoints/managed-run-worker.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
waitUntil,
1919
apiClientManager,
2020
runTimelineMetrics,
21+
localsAPI,
2122
} from "@trigger.dev/core/v3";
2223
import { TriggerTracer } from "@trigger.dev/core/v3/tracer";
2324
import {
@@ -39,6 +40,7 @@ import {
3940
StandardWaitUntilManager,
4041
ManagedRuntimeManager,
4142
StandardRunTimelineMetricsManager,
43+
StandardLocalsManager,
4244
} from "@trigger.dev/core/v3/workers";
4345
import { ZodIpcConnection } from "@trigger.dev/core/v3/zodIpc";
4446
import { readFile } from "node:fs/promises";
@@ -93,6 +95,9 @@ const usageEventUrl = getEnvVar("USAGE_EVENT_URL");
9395
const triggerJWT = getEnvVar("TRIGGER_JWT");
9496
const heartbeatIntervalMs = getEnvVar("HEARTBEAT_INTERVAL_MS");
9597

98+
const standardLocalsManager = new StandardLocalsManager();
99+
localsAPI.setGlobalLocalsManager(standardLocalsManager);
100+
96101
const standardRunTimelineMetricsManager = new StandardRunTimelineMetricsManager();
97102
runTimelineMetrics.setGlobalManager(standardRunTimelineMetricsManager);
98103
standardRunTimelineMetricsManager.seedMetricsFromEnvironment();

packages/core/src/v3/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export * from "./wait-until-api.js";
1616
export * from "./timeout-api.js";
1717
export * from "./run-timeline-metrics-api.js";
1818
export * from "./lifecycle-hooks-api.js";
19+
export * from "./locals-api.js";
1920
export * from "./schemas/index.js";
2021
export { SemanticInternalAttributes } from "./semanticInternalAttributes.js";
2122
export * from "./resource-catalog-api.js";

packages/core/src/v3/locals-api.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Split module-level variable definition into separate files to allow
2+
// tree-shaking on each api instance.
3+
import { LocalsAPI } from "./locals/index.js";
4+
import type { LocalsKey } from "./locals/types.js";
5+
/** Entrypoint for runtime API */
6+
export const localsAPI = LocalsAPI.getInstance();
7+
8+
export const locals = {
9+
create<T>(id: string): LocalsKey<T> {
10+
return localsAPI.createLocal(id);
11+
},
12+
get<T>(key: LocalsKey<T>): T | undefined {
13+
return localsAPI.getLocal(key);
14+
},
15+
getOrThrow<T>(key: LocalsKey<T>): T {
16+
const value = localsAPI.getLocal(key);
17+
if (!value) {
18+
throw new Error(`Local with id ${key.id} not found`);
19+
}
20+
return value;
21+
},
22+
set<T>(key: LocalsKey<T>, value: T): void {
23+
localsAPI.setLocal(key, value);
24+
},
25+
};
26+
27+
export type Locals = typeof locals;
28+
export type { LocalsKey };
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
const API_NAME = "locals";
2+
3+
import { getGlobal, registerGlobal, unregisterGlobal } from "../utils/globals.js";
4+
import { NoopLocalsManager } from "./manager.js";
5+
import { LocalsKey, type LocalsManager } from "./types.js";
6+
7+
const NOOP_LOCALS_MANAGER = new NoopLocalsManager();
8+
9+
export class LocalsAPI implements LocalsManager {
10+
private static _instance?: LocalsAPI;
11+
12+
private constructor() {}
13+
14+
public static getInstance(): LocalsAPI {
15+
if (!this._instance) {
16+
this._instance = new LocalsAPI();
17+
}
18+
19+
return this._instance;
20+
}
21+
22+
public setGlobalLocalsManager(localsManager: LocalsManager): boolean {
23+
return registerGlobal(API_NAME, localsManager);
24+
}
25+
26+
public disable() {
27+
unregisterGlobal(API_NAME);
28+
}
29+
30+
public createLocal<T>(id: string): LocalsKey<T> {
31+
return this.#getManager().createLocal(id);
32+
}
33+
34+
public getLocal<T>(key: LocalsKey<T>): T | undefined {
35+
return this.#getManager().getLocal(key);
36+
}
37+
38+
public setLocal<T>(key: LocalsKey<T>, value: T): void {
39+
return this.#getManager().setLocal(key, value);
40+
}
41+
42+
#getManager(): LocalsManager {
43+
return getGlobal(API_NAME) ?? NOOP_LOCALS_MANAGER;
44+
}
45+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { LocalsKey, LocalsManager } from "./types.js";
2+
3+
export class NoopLocalsManager implements LocalsManager {
4+
createLocal<T>(id: string): LocalsKey<T> {
5+
return {
6+
__type: Symbol(),
7+
id,
8+
} as unknown as LocalsKey<T>;
9+
}
10+
11+
getLocal<T>(key: LocalsKey<T>): T | undefined {
12+
return undefined;
13+
}
14+
15+
setLocal<T>(key: LocalsKey<T>, value: T): void {}
16+
}
17+
18+
export class StandardLocalsManager implements LocalsManager {
19+
private store: Map<symbol, unknown> = new Map();
20+
21+
createLocal<T>(id: string): LocalsKey<T> {
22+
const key = Symbol.for(id);
23+
return {
24+
__type: key,
25+
id,
26+
} as unknown as LocalsKey<T>;
27+
}
28+
29+
getLocal<T>(key: LocalsKey<T>): T | undefined {
30+
return this.store.get(key.__type) as T | undefined;
31+
}
32+
33+
setLocal<T>(key: LocalsKey<T>, value: T): void {
34+
this.store.set(key.__type, value);
35+
}
36+
}
37+
0;
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
declare const __local: unique symbol;
2+
type BrandLocal<T> = { [__local]: T };
3+
4+
// Create a type-safe store for your locals
5+
export type LocalsKey<T> = BrandLocal<T> & {
6+
readonly id: string;
7+
readonly __type: unique symbol;
8+
};
9+
10+
export interface LocalsManager {
11+
createLocal<T>(id: string): LocalsKey<T>;
12+
getLocal<T>(key: LocalsKey<T>): T | undefined;
13+
setLocal<T>(key: LocalsKey<T>, value: T): void;
14+
}

packages/core/src/v3/types/tasks.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,11 +264,15 @@ type CommonTaskOptions<
264264

265265
/**
266266
* init is called before the run function is called. It's useful for setting up any global state.
267+
*
268+
* @deprecated Use locals and middleware instead
267269
*/
268270
init?: (payload: TPayload, params: InitFnParams) => Promise<TInitOutput>;
269271

270272
/**
271273
* cleanup is called after the run function has completed.
274+
*
275+
* @deprecated Use middleware instead
272276
*/
273277
cleanup?: (payload: TPayload, params: RunFnParams<TInitOutput>) => Promise<void>;
274278

packages/core/src/v3/utils/globals.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { ApiClientConfiguration } from "../apiClientManager/types.js";
22
import { Clock } from "../clock/clock.js";
33
import { LifecycleHooksManager } from "../lifecycleHooks/types.js";
4+
import { LocalsManager } from "../locals/types.js";
45
import { ResourceCatalog } from "../resource-catalog/catalog.js";
56
import { RunMetadataManager } from "../runMetadata/types.js";
67
import type { RuntimeManager } from "../runtime/manager.js";
@@ -64,4 +65,5 @@ type TriggerDotDevGlobalAPI = {
6465
["wait-until"]?: WaitUntilManager;
6566
["run-timeline-metrics"]?: RunTimelineMetricsManager;
6667
["lifecycle-hooks"]?: LifecycleHooksManager;
68+
["locals"]?: LocalsManager;
6769
};

packages/core/src/v3/workers/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@ export * from "../runEngineWorker/index.js";
2121
export { StandardRunTimelineMetricsManager } from "../runTimelineMetrics/runTimelineMetricsManager.js";
2222
export { WarmStartClient, type WarmStartClientOptions } from "../workers/warmStartClient.js";
2323
export { StandardLifecycleHooksManager } from "../lifecycleHooks/manager.js";
24+
export { StandardLocalsManager } from "../locals/manager.js";

0 commit comments

Comments
 (0)