{"version":3,"file":"setup.mjs","names":[],"sources":["../../src/vitest/setup.ts"],"sourcesContent":["/**\n * Vitest setup file that removes Node.js globals which Vitest depends on\n * but are not available in the Tailor Platform runtime.\n *\n * These globals cannot be removed in the environment's setup() because\n * Vitest's runner needs them during initialization. By using beforeEach/afterEach,\n * they are only removed during user test code execution.\n *\n * This file is auto-injected by tailorRuntime() but only activates when\n * the tailor-runtime environment is active (detected via __tailorRuntimeActive,\n * a flag set by injectMocks() during environment setup).\n */\nimport { pathToFileURL } from \"node:url\";\nimport { afterEach, beforeAll, beforeEach } from \"vitest\";\nimport { RUNTIME_FLAG_KEY, mockSecretmanager } from \"./mock\";\n\n// Globals that Vitest internals depend on but don't exist in the platform runtime.\n// Removed before each test, restored after.\nconst BLOCKED_GLOBALS = [\"performance\"] as const;\n\ntype SavedGlobals = Record<string, PropertyDescriptor | undefined>;\n\n/**\n * Reference-counted lifecycle for blocked globals.\n *\n * Concurrent tests in the same Vitest worker (`test.concurrent`) interleave\n * their beforeEach/afterEach hooks: a naive `let saved` shared across hooks\n * would let one test's `afterEach` restore `performance` mid-execution of\n * another test. Reference counting keeps the globals removed for the union\n * of all overlapping test scopes — the property is removed on first entry\n * and restored only when the last test exits.\n * @returns Lifecycle hooks\n */\nexport function createBlockedGlobalsLifecycle(): {\n  enter: (globalObj: Record<string, unknown>, keys: readonly string[]) => void;\n  exit: (globalObj: Record<string, unknown>) => void;\n  readonly active: number;\n} {\n  let active = 0;\n  let saved: SavedGlobals = {};\n  return {\n    get active() {\n      return active;\n    },\n    enter(globalObj, keys) {\n      if (active === 0) saved = removeBlockedGlobals(globalObj, keys);\n      active++;\n    },\n    exit(globalObj) {\n      // Defensive guard — in practice every `enter` is paired with `exit`,\n      // but a hook crash could desync the counter.\n      if (active === 0) return;\n      active--;\n      if (active === 0) {\n        restoreBlockedGlobals(globalObj, saved);\n        saved = {};\n      }\n    },\n  };\n}\n\nconst lifecycle = createBlockedGlobalsLifecycle();\n\nfunction isTailorRuntime(): boolean {\n  return RUNTIME_FLAG_KEY in globalThis;\n}\n\n/**\n * Extract a vault store from a secrets-shaped value.\n *\n * `defineSecretManager()` returns `{ vaults, options, get, getAll }` (get/getAll\n * are non-enumerable). When that shape is present, the actual vaults live\n * under `.vaults`. Otherwise fall back to treating the object itself as the\n * vault map (for plain object configs).\n * @param secrets - Value from `appConfig.secrets` or `config.secrets`\n * @returns Vault store, or null if the value is unusable\n */\nexport function extractVaultStore(secrets: unknown): Record<string, Record<string, string>> | null {\n  if (!secrets || typeof secrets !== \"object\") return null;\n\n  const source =\n    \"vaults\" in secrets &&\n    typeof (secrets as { vaults?: unknown }).vaults === \"object\" &&\n    (secrets as { vaults?: unknown }).vaults !== null\n      ? ((secrets as { vaults: Record<string, unknown> }).vaults as Record<string, unknown>)\n      : (secrets as Record<string, unknown>);\n\n  const store: Record<string, Record<string, string>> = {};\n  for (const [vaultName, vaultData] of Object.entries(source)) {\n    if (typeof vaultData === \"object\" && vaultData !== null) {\n      store[vaultName] = { ...(vaultData as Record<string, string>) };\n    }\n  }\n  return Object.keys(store).length > 0 ? store : null;\n}\n\n/**\n * Load and parse secrets from a tailor.config.ts file.\n *\n * Returns a vault store on success, or `null` on any failure (missing config,\n * import failure, missing/invalid secrets shape). Errors are swallowed so a\n * misconfigured project still boots — the user can set secrets manually via\n * `mockSecretmanager().setSecrets()`.\n * @param configPath - Absolute path to tailor.config.ts\n * @returns Vault store keyed by vault name, or null if unavailable\n */\nexport async function loadSecretsFromConfig(\n  configPath: string,\n): Promise<Record<string, Record<string, string>> | null> {\n  try {\n    // Convert to file URL so absolute Windows paths (e.g. \"C:\\...\") parse as\n    // valid ESM specifiers.\n    const config = await import(pathToFileURL(configPath).href);\n    const appConfig = config.default;\n    const secrets = appConfig?.secrets ?? config.secrets;\n    return extractVaultStore(secrets);\n  } catch {\n    return null;\n  }\n}\n\n// Load secrets from tailor.config.ts if config path is provided via env var\nbeforeAll(async () => {\n  if (!isTailorRuntime()) return;\n  const configPath = process.env.__TAILOR_RUNTIME_CONFIG;\n  if (!configPath) return;\n\n  const store = await loadSecretsFromConfig(configPath);\n  if (store) {\n    // Acquire without `using`: this is a one-time global seed that must persist\n    // across tests, so we deliberately do not dispose (which would reset it).\n    mockSecretmanager().setSecrets(store);\n  }\n});\n\n/**\n * Remove the given globals from `globalObj`, returning the descriptors that\n * were actually deleted so `restoreBlockedGlobals` can put them back.\n *\n * Mirrors environment.ts: non-configurable properties are skipped instead of\n * deleted, so `delete` never throws in strict-mode runtimes that lock them\n * down. Only properties whose deletion actually happened are returned, so the\n * caller restores nothing for the skipped case.\n * @param globalObj - Target object (typically `globalThis`)\n * @param keys - Property names to remove\n * @returns Map of removed descriptors keyed by property name\n */\nexport function removeBlockedGlobals(\n  globalObj: Record<string, unknown>,\n  keys: readonly string[],\n): SavedGlobals {\n  const removed: SavedGlobals = {};\n  for (const key of keys) {\n    const descriptor = Object.getOwnPropertyDescriptor(globalObj, key);\n    if (descriptor?.configurable) {\n      removed[key] = descriptor;\n      delete globalObj[key];\n    }\n  }\n  return removed;\n}\n\n/**\n * Restore previously-removed globals onto `globalObj` from a `SavedGlobals`\n * map produced by `removeBlockedGlobals`.\n * @param globalObj - Target object (typically `globalThis`)\n * @param saved - Descriptors to re-define\n */\nexport function restoreBlockedGlobals(\n  globalObj: Record<string, unknown>,\n  saved: SavedGlobals,\n): void {\n  for (const [key, descriptor] of Object.entries(saved)) {\n    if (descriptor) {\n      Object.defineProperty(globalObj, key, descriptor);\n    }\n  }\n}\n\nbeforeEach(() => {\n  if (!isTailorRuntime()) return;\n  lifecycle.enter(globalThis as Record<string, unknown>, BLOCKED_GLOBALS);\n});\n\nafterEach(() => {\n  if (!isTailorRuntime()) return;\n  lifecycle.exit(globalThis as Record<string, unknown>);\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;AAkBA,MAAM,kBAAkB,CAAC,aAAa;;;;;;;;;;;;AAetC,SAAgB,gCAId;CACA,IAAI,SAAS;CACb,IAAI,QAAsB,CAAC;CAC3B,OAAO;EACL,IAAI,SAAS;GACX,OAAO;EACT;EACA,MAAM,WAAW,MAAM;GACrB,IAAI,WAAW,GAAG,QAAQ,qBAAqB,WAAW,IAAI;GAC9D;EACF;EACA,KAAK,WAAW;GAGd,IAAI,WAAW,GAAG;GAClB;GACA,IAAI,WAAW,GAAG;IAChB,sBAAsB,WAAW,KAAK;IACtC,QAAQ,CAAC;GACX;EACF;CACF;AACF;AAEA,MAAM,YAAY,8BAA8B;AAEhD,SAAS,kBAA2B;CAClC,OAAO,oBAAoB;AAC7B;;;;;;;;;;;AAYA,SAAgB,kBAAkB,SAAiE;CACjG,IAAI,CAAC,WAAW,OAAO,YAAY,UAAU,OAAO;CAEpD,MAAM,SACJ,YAAY,WACZ,OAAQ,QAAiC,WAAW,YACnD,QAAiC,WAAW,OACvC,QAAgD,SACjD;CAEP,MAAM,QAAgD,CAAC;CACvD,KAAK,MAAM,CAAC,WAAW,cAAc,OAAO,QAAQ,MAAM,GACxD,IAAI,OAAO,cAAc,YAAY,cAAc,MACjD,MAAM,aAAa,EAAE,GAAI,UAAqC;CAGlE,OAAO,OAAO,KAAK,KAAK,CAAC,CAAC,SAAS,IAAI,QAAQ;AACjD;;;;;;;;;;;AAYA,eAAsB,sBACpB,YACwD;CACxD,IAAI;EAGF,MAAM,SAAS,MAAM,OAAO,cAAc,UAAU,CAAC,CAAC;EAGtD,OAAO,kBAFW,OAAO,SACE,WAAW,OAAO,OACb;CAClC,QAAQ;EACN,OAAO;CACT;AACF;AAGA,UAAU,YAAY;CACpB,IAAI,CAAC,gBAAgB,GAAG;CACxB,MAAM,aAAa,QAAQ,IAAI;CAC/B,IAAI,CAAC,YAAY;CAEjB,MAAM,QAAQ,MAAM,sBAAsB,UAAU;CACpD,IAAI,OAGF,kBAAkB,CAAC,CAAC,WAAW,KAAK;AAExC,CAAC;;;;;;;;;;;;;AAcD,SAAgB,qBACd,WACA,MACc;CACd,MAAM,UAAwB,CAAC;CAC/B,KAAK,MAAM,OAAO,MAAM;EACtB,MAAM,aAAa,OAAO,yBAAyB,WAAW,GAAG;EACjE,IAAI,YAAY,cAAc;GAC5B,QAAQ,OAAO;GACf,OAAO,UAAU;EACnB;CACF;CACA,OAAO;AACT;;;;;;;AAQA,SAAgB,sBACd,WACA,OACM;CACN,KAAK,MAAM,CAAC,KAAK,eAAe,OAAO,QAAQ,KAAK,GAClD,IAAI,YACF,OAAO,eAAe,WAAW,KAAK,UAAU;AAGtD;AAEA,iBAAiB;CACf,IAAI,CAAC,gBAAgB,GAAG;CACxB,UAAU,MAAM,YAAuC,eAAe;AACxE,CAAC;AAED,gBAAgB;CACd,IAAI,CAAC,gBAAgB,GAAG;CACxB,UAAU,KAAK,UAAqC;AACtD,CAAC"}