-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathtest-env-key.ts
More file actions
95 lines (84 loc) · 3.14 KB
/
Copy pathtest-env-key.ts
File metadata and controls
95 lines (84 loc) · 3.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/**
* Typed accessors for the test-time globalThis slot used to pass `env` from
* `mockWorkflow().setEnv()` (in `@tailor-platform/sdk/vitest`) to
* `runWorkflowLocally()` job bodies. The slot key is private to this
* module; callers go through the get/set/clear functions below so both sides
* share the same access path.
*
* Lives in its own file (with no `@/` imports) so `vitest/mock.ts` can load
* it from nested Vitest configs that do not resolve `@/` aliases.
* @internal
*/
import { AsyncLocalStorage } from "node:async_hooks";
import type { TailorEnv, TailorPrincipal } from "../../../runtime/types";
const SLOT_KEY = "__tailorWorkflowTestEnv";
type AsyncLocalStorageLike<T> = {
getStore(): T | undefined;
run<R>(store: T, callback: () => R): R;
};
let invokerStorage: AsyncLocalStorageLike<TailorPrincipal | null> | undefined;
function workflowInvokerStorage(): AsyncLocalStorageLike<TailorPrincipal | null> {
if (!invokerStorage) {
invokerStorage = new AsyncLocalStorage<TailorPrincipal | null>();
}
return invokerStorage;
}
/**
* Read the test-time env slot.
* @returns Current env, or `undefined` when unset.
* @internal
*/
export function readWorkflowTestEnv(): TailorEnv | undefined {
return (globalThis as unknown as Record<string, TailorEnv | undefined>)[SLOT_KEY];
}
/**
* Write the test-time env slot.
* @param env - Env value to expose to `runWorkflowLocally()` job bodies.
* @internal
*/
export function writeWorkflowTestEnv(env: TailorEnv): void {
(globalThis as unknown as Record<string, TailorEnv>)[SLOT_KEY] = env;
}
/**
* Clear the test-time env slot.
* @internal
*/
export function clearWorkflowTestEnv(): void {
delete (globalThis as unknown as Record<string, unknown>)[SLOT_KEY];
}
export function withWorkflowTestInvoker<T>(invoker: TailorPrincipal | null, run: () => T): T {
return workflowInvokerStorage().run(invoker, run);
}
type RuntimeInvoker = {
id: string;
type: "user" | "machine_user";
workspaceId: string;
attributes?: string[] | TailorPrincipal["attributes"];
attributeMap?: TailorPrincipal["attributes"];
attributeList?: TailorPrincipal["attributeList"];
};
function readRuntimeInvoker(): TailorPrincipal | null {
const runtime = (
globalThis as unknown as {
tailor?: { context?: { getInvoker?: () => RuntimeInvoker | null } };
}
).tailor?.context?.getInvoker;
const raw = runtime?.();
if (!raw) return null;
return {
id: raw.id,
type: raw.type,
workspaceId: raw.workspaceId,
attributes: raw.attributeMap ?? (Array.isArray(raw.attributes) ? {} : (raw.attributes ?? {})),
attributeList: (raw.attributeList ??
(Array.isArray(raw.attributes) ? raw.attributes : [])) as TailorPrincipal["attributeList"],
};
}
// Shallow-copied to isolate against cross-trigger mutation.
export function buildJobContext(): { env: TailorEnv; invoker: TailorPrincipal | null } {
const storedInvoker = invokerStorage?.getStore();
const invoker = storedInvoker === undefined ? readRuntimeInvoker() : storedInvoker;
const fromGlobal = readWorkflowTestEnv();
if (fromGlobal !== undefined) return { env: { ...fromGlobal }, invoker };
return { env: {} as TailorEnv, invoker };
}