@intlayer/config 8.9.0 → 8.9.1

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.
@@ -41,6 +41,21 @@ const loadExternalFileSync = (filePath, options) => {
41
41
  require_logger.logger([`Error: ${error.message} - `, JSON.stringify(error.stack, null, 2)], { level: "error" });
42
42
  }
43
43
  };
44
+ const withPreloadedGlobals = (globals, fn) => {
45
+ if (!globals) return fn();
46
+ const globalVars = globalThis;
47
+ const prev = {};
48
+ for (const [key, value] of Object.entries(globals)) {
49
+ prev[key] = globalVars[key];
50
+ globalVars[key] = value;
51
+ }
52
+ try {
53
+ return fn();
54
+ } finally {
55
+ for (const key of Object.keys(globals)) if (prev[key] !== void 0) globalVars[key] = prev[key];
56
+ else delete globalVars[key];
57
+ }
58
+ };
44
59
  /**
45
60
  * Load the content declaration from the given path
46
61
  *
@@ -55,13 +70,13 @@ const loadExternalFile = async (filePath, options) => {
55
70
  require_logger.logger("File could not be loaded.", { level: "error" });
56
71
  return;
57
72
  }
58
- const fileContent = require_loadExternalFile_parseFileContent.parseFileContent(moduleResultString, {
73
+ const fileContent = withPreloadedGlobals(options?.preloadGlobals, () => require_loadExternalFile_parseFileContent.parseFileContent(moduleResultString, {
59
74
  projectRequire: options?.projectRequire,
60
75
  envVarOptions: options?.envVarOptions,
61
76
  additionalEnvVars: options?.additionalEnvVars,
62
77
  mocks: options?.mocks,
63
78
  aliases: options?.aliases
64
- });
79
+ }));
65
80
  if (typeof fileContent === "undefined") {
66
81
  require_logger.logger(`File could not be loaded. Path : ${require_logger.colorizePath(filePath)}`);
67
82
  return;
@@ -1 +1 @@
1
- {"version":3,"file":"loadExternalFile.cjs","names":["JSON5","transpileTSToCJSSync","parseFileContent","transpileTSToCJS","colorizePath"],"sources":["../../../src/loadExternalFile/loadExternalFile.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { extname } from 'node:path';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport JSON5 from 'json5';\nimport { colorizePath, logger } from '../logger';\nimport {\n parseFileContent,\n type SandBoxContextOptions,\n} from './parseFileContent';\nimport {\n type TranspileOptions,\n transpileTSToCJS,\n transpileTSToCJSSync,\n} from './transpileTSToCJS';\n\n// CJS MJS cross usage\nconst parseJSON5 = JSON5.parse || (JSON5 as any).default?.parse;\n\nexport type LoadExternalFileOptions = {\n configuration?: IntlayerConfig;\n buildOptions?: TranspileOptions;\n logError?: boolean;\n} & SandBoxContextOptions;\n\n/**\n * Load the content declaration from the given path\n *\n * Accepts JSON, JS, MJS and TS files as configuration\n */\nexport const loadExternalFileSync = (\n filePath: string,\n options?: LoadExternalFileOptions\n): any | undefined => {\n const fileExtension = extname(filePath) || '.json';\n\n try {\n if (\n fileExtension === '.json' ||\n fileExtension === '.json5' ||\n fileExtension === '.jsonc'\n ) {\n // Assume JSON\n return parseJSON5(readFileSync(filePath, 'utf-8'));\n }\n\n // Rest is JS, MJS or TS\n const code = readFileSync(filePath, 'utf-8');\n\n const moduleResultString: string | undefined = transpileTSToCJSSync(\n code,\n filePath,\n options?.buildOptions\n );\n\n if (!moduleResultString) {\n logger('File could not be loaded.', { level: 'error' });\n return undefined;\n }\n\n const fileContent = parseFileContent(moduleResultString, {\n projectRequire: options?.projectRequire,\n envVarOptions: options?.envVarOptions,\n additionalEnvVars: options?.additionalEnvVars,\n mocks: options?.mocks,\n aliases: options?.aliases,\n });\n\n if (typeof fileContent === 'undefined') {\n logger(`File could not be loaded. Path : ${filePath}`);\n return undefined;\n }\n\n return fileContent;\n } catch (error) {\n logger(\n [\n `Error: ${(error as Error).message} - `,\n JSON.stringify((error as Error).stack, null, 2),\n ],\n {\n level: 'error',\n }\n );\n }\n};\n\n/**\n * Load the content declaration from the given path\n *\n * Accepts JSON, JS, MJS and TS files as configuration\n */\nexport const loadExternalFile = async (\n filePath: string,\n options?: LoadExternalFileOptions\n): Promise<any | undefined> => {\n const fileExtension = extname(filePath);\n\n try {\n if (\n fileExtension === '.json' ||\n fileExtension === '.json5' ||\n fileExtension === '.jsonc'\n ) {\n // Remove cache to force getting fresh content\n const fileContent = await readFile(filePath, 'utf-8');\n return parseJSON5(fileContent);\n }\n\n // Rest is JS, MJS or TS\n const code = await readFile(filePath, 'utf-8');\n\n const moduleResultString: string | undefined = await transpileTSToCJS(\n code,\n filePath,\n options?.buildOptions\n );\n\n if (!moduleResultString) {\n logger('File could not be loaded.', { level: 'error' });\n return undefined;\n }\n\n const fileContent = parseFileContent(moduleResultString, {\n projectRequire: options?.projectRequire,\n envVarOptions: options?.envVarOptions,\n additionalEnvVars: options?.additionalEnvVars,\n mocks: options?.mocks,\n aliases: options?.aliases,\n });\n\n if (typeof fileContent === 'undefined') {\n logger(`File could not be loaded. Path : ${colorizePath(filePath)}`);\n return undefined;\n }\n\n return fileContent;\n } catch (error) {\n if (options?.logError ?? true) {\n logger(\n [\n `Error: ${(error as Error).message} - `,\n JSON.stringify((error as Error).stack, null, 2),\n ],\n {\n level: 'error',\n }\n );\n }\n }\n};\n"],"mappings":";;;;;;;;;;;;AAiBA,MAAM,aAAaA,cAAM,SAAUA,cAAc,SAAS;;;;;;AAa1D,MAAa,wBACX,UACA,YACoB;CACpB,MAAM,uCAAwB,SAAS,IAAI;AAE3C,KAAI;AACF,MACE,kBAAkB,WAClB,kBAAkB,YAClB,kBAAkB,SAGlB,QAAO,qCAAwB,UAAU,QAAQ,CAAC;EAMpD,MAAM,qBAAyCC,yFAFrB,UAAU,QAG9B,EACJ,UACA,SAAS,aACV;AAED,MAAI,CAAC,oBAAoB;AACvB,yBAAO,6BAA6B,EAAE,OAAO,SAAS,CAAC;AACvD;;EAGF,MAAM,cAAcC,2DAAiB,oBAAoB;GACvD,gBAAgB,SAAS;GACzB,eAAe,SAAS;GACxB,mBAAmB,SAAS;GAC5B,OAAO,SAAS;GAChB,SAAS,SAAS;GACnB,CAAC;AAEF,MAAI,OAAO,gBAAgB,aAAa;AACtC,yBAAO,oCAAoC,WAAW;AACtD;;AAGF,SAAO;UACA,OAAO;AACd,wBACE,CACE,UAAW,MAAgB,QAAQ,MACnC,KAAK,UAAW,MAAgB,OAAO,MAAM,EAAE,CAChD,EACD,EACE,OAAO,SACR,CACF;;;;;;;;AASL,MAAa,mBAAmB,OAC9B,UACA,YAC6B;CAC7B,MAAM,uCAAwB,SAAS;AAEvC,KAAI;AACF,MACE,kBAAkB,WAClB,kBAAkB,YAClB,kBAAkB,SAIlB,QAAO,WAAW,qCADiB,UAAU,QAAQ,CACvB;EAMhC,MAAM,qBAAyC,MAAMC,2DACnD,qCAH0B,UAAU,QAAQ,EAI5C,UACA,SAAS,aACV;AAED,MAAI,CAAC,oBAAoB;AACvB,yBAAO,6BAA6B,EAAE,OAAO,SAAS,CAAC;AACvD;;EAGF,MAAM,cAAcD,2DAAiB,oBAAoB;GACvD,gBAAgB,SAAS;GACzB,eAAe,SAAS;GACxB,mBAAmB,SAAS;GAC5B,OAAO,SAAS;GAChB,SAAS,SAAS;GACnB,CAAC;AAEF,MAAI,OAAO,gBAAgB,aAAa;AACtC,yBAAO,oCAAoCE,4BAAa,SAAS,GAAG;AACpE;;AAGF,SAAO;UACA,OAAO;AACd,MAAI,SAAS,YAAY,KACvB,uBACE,CACE,UAAW,MAAgB,QAAQ,MACnC,KAAK,UAAW,MAAgB,OAAO,MAAM,EAAE,CAChD,EACD,EACE,OAAO,SACR,CACF"}
1
+ {"version":3,"file":"loadExternalFile.cjs","names":["JSON5","transpileTSToCJSSync","parseFileContent","transpileTSToCJS","colorizePath"],"sources":["../../../src/loadExternalFile/loadExternalFile.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { extname } from 'node:path';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport JSON5 from 'json5';\nimport { colorizePath, logger } from '../logger';\nimport {\n parseFileContent,\n type SandBoxContextOptions,\n} from './parseFileContent';\nimport {\n type TranspileOptions,\n transpileTSToCJS,\n transpileTSToCJSSync,\n} from './transpileTSToCJS';\n\n// CJS MJS cross usage\nconst parseJSON5 = JSON5.parse || (JSON5 as any).default?.parse;\n\nexport type LoadExternalFileOptions = {\n configuration?: IntlayerConfig;\n buildOptions?: TranspileOptions;\n logError?: boolean;\n /**\n * Key-value pairs to temporarily set on the main Node.js `globalThis` for the\n * synchronous duration of `parseFileContent` / `runInNewContext`. External modules\n * loaded via `require()` inside the VM (e.g. `@intlayer/core`'s `file()` helper)\n * run in the main context and read from the real `globalThis`, not the VM sandbox.\n * Values are restored (or deleted) after `runInNewContext` returns.\n */\n preloadGlobals?: Record<string, unknown>;\n} & SandBoxContextOptions;\n\n/**\n * Load the content declaration from the given path\n *\n * Accepts JSON, JS, MJS and TS files as configuration\n */\nexport const loadExternalFileSync = (\n filePath: string,\n options?: LoadExternalFileOptions\n): any | undefined => {\n const fileExtension = extname(filePath) || '.json';\n\n try {\n if (\n fileExtension === '.json' ||\n fileExtension === '.json5' ||\n fileExtension === '.jsonc'\n ) {\n // Assume JSON\n return parseJSON5(readFileSync(filePath, 'utf-8'));\n }\n\n // Rest is JS, MJS or TS\n const code = readFileSync(filePath, 'utf-8');\n\n const moduleResultString: string | undefined = transpileTSToCJSSync(\n code,\n filePath,\n options?.buildOptions\n );\n\n if (!moduleResultString) {\n logger('File could not be loaded.', { level: 'error' });\n return undefined;\n }\n\n const fileContent = parseFileContent(moduleResultString, {\n projectRequire: options?.projectRequire,\n envVarOptions: options?.envVarOptions,\n additionalEnvVars: options?.additionalEnvVars,\n mocks: options?.mocks,\n aliases: options?.aliases,\n });\n\n if (typeof fileContent === 'undefined') {\n logger(`File could not be loaded. Path : ${filePath}`);\n return undefined;\n }\n\n return fileContent;\n } catch (error) {\n logger(\n [\n `Error: ${(error as Error).message} - `,\n JSON.stringify((error as Error).stack, null, 2),\n ],\n {\n level: 'error',\n }\n );\n }\n};\n\nconst withPreloadedGlobals = <T>(\n globals: Record<string, unknown> | undefined,\n fn: () => T\n): T => {\n if (!globals) return fn();\n\n const globalVars = globalThis as Record<string, unknown>;\n const prev: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(globals)) {\n prev[key] = globalVars[key];\n globalVars[key] = value;\n }\n\n try {\n return fn();\n } finally {\n for (const key of Object.keys(globals)) {\n if (prev[key] !== undefined) {\n globalVars[key] = prev[key];\n } else {\n delete globalVars[key];\n }\n }\n }\n};\n\n/**\n * Load the content declaration from the given path\n *\n * Accepts JSON, JS, MJS and TS files as configuration\n */\nexport const loadExternalFile = async (\n filePath: string,\n options?: LoadExternalFileOptions\n): Promise<any | undefined> => {\n const fileExtension = extname(filePath);\n\n try {\n if (\n fileExtension === '.json' ||\n fileExtension === '.json5' ||\n fileExtension === '.jsonc'\n ) {\n // Remove cache to force getting fresh content\n const fileContent = await readFile(filePath, 'utf-8');\n return parseJSON5(fileContent);\n }\n\n // Rest is JS, MJS or TS\n const code = await readFile(filePath, 'utf-8');\n\n const moduleResultString: string | undefined = await transpileTSToCJS(\n code,\n filePath,\n options?.buildOptions\n );\n\n if (!moduleResultString) {\n logger('File could not be loaded.', { level: 'error' });\n return undefined;\n }\n\n // parseFileContent/runInNewContext is synchronous, so withPreloadedGlobals\n // has no interleaving risk even when multiple files are processed concurrently.\n const fileContent = withPreloadedGlobals(options?.preloadGlobals, () =>\n parseFileContent(moduleResultString, {\n projectRequire: options?.projectRequire,\n envVarOptions: options?.envVarOptions,\n additionalEnvVars: options?.additionalEnvVars,\n mocks: options?.mocks,\n aliases: options?.aliases,\n })\n );\n\n if (typeof fileContent === 'undefined') {\n logger(`File could not be loaded. Path : ${colorizePath(filePath)}`);\n return undefined;\n }\n\n return fileContent;\n } catch (error) {\n if (options?.logError ?? true) {\n logger(\n [\n `Error: ${(error as Error).message} - `,\n JSON.stringify((error as Error).stack, null, 2),\n ],\n {\n level: 'error',\n }\n );\n }\n }\n};\n"],"mappings":";;;;;;;;;;;;AAiBA,MAAM,aAAaA,cAAM,SAAUA,cAAc,SAAS;;;;;;AAqB1D,MAAa,wBACX,UACA,YACoB;CACpB,MAAM,uCAAwB,SAAS,IAAI;AAE3C,KAAI;AACF,MACE,kBAAkB,WAClB,kBAAkB,YAClB,kBAAkB,SAGlB,QAAO,qCAAwB,UAAU,QAAQ,CAAC;EAMpD,MAAM,qBAAyCC,yFAFrB,UAAU,QAG9B,EACJ,UACA,SAAS,aACV;AAED,MAAI,CAAC,oBAAoB;AACvB,yBAAO,6BAA6B,EAAE,OAAO,SAAS,CAAC;AACvD;;EAGF,MAAM,cAAcC,2DAAiB,oBAAoB;GACvD,gBAAgB,SAAS;GACzB,eAAe,SAAS;GACxB,mBAAmB,SAAS;GAC5B,OAAO,SAAS;GAChB,SAAS,SAAS;GACnB,CAAC;AAEF,MAAI,OAAO,gBAAgB,aAAa;AACtC,yBAAO,oCAAoC,WAAW;AACtD;;AAGF,SAAO;UACA,OAAO;AACd,wBACE,CACE,UAAW,MAAgB,QAAQ,MACnC,KAAK,UAAW,MAAgB,OAAO,MAAM,EAAE,CAChD,EACD,EACE,OAAO,SACR,CACF;;;AAIL,MAAM,wBACJ,SACA,OACM;AACN,KAAI,CAAC,QAAS,QAAO,IAAI;CAEzB,MAAM,aAAa;CACnB,MAAM,OAAgC,EAAE;AAExC,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,EAAE;AAClD,OAAK,OAAO,WAAW;AACvB,aAAW,OAAO;;AAGpB,KAAI;AACF,SAAO,IAAI;WACH;AACR,OAAK,MAAM,OAAO,OAAO,KAAK,QAAQ,CACpC,KAAI,KAAK,SAAS,OAChB,YAAW,OAAO,KAAK;MAEvB,QAAO,WAAW;;;;;;;;AAW1B,MAAa,mBAAmB,OAC9B,UACA,YAC6B;CAC7B,MAAM,uCAAwB,SAAS;AAEvC,KAAI;AACF,MACE,kBAAkB,WAClB,kBAAkB,YAClB,kBAAkB,SAIlB,QAAO,WAAW,qCADiB,UAAU,QAAQ,CACvB;EAMhC,MAAM,qBAAyC,MAAMC,2DACnD,qCAH0B,UAAU,QAAQ,EAI5C,UACA,SAAS,aACV;AAED,MAAI,CAAC,oBAAoB;AACvB,yBAAO,6BAA6B,EAAE,OAAO,SAAS,CAAC;AACvD;;EAKF,MAAM,cAAc,qBAAqB,SAAS,sBAChDD,2DAAiB,oBAAoB;GACnC,gBAAgB,SAAS;GACzB,eAAe,SAAS;GACxB,mBAAmB,SAAS;GAC5B,OAAO,SAAS;GAChB,SAAS,SAAS;GACnB,CAAC,CACH;AAED,MAAI,OAAO,gBAAgB,aAAa;AACtC,yBAAO,oCAAoCE,4BAAa,SAAS,GAAG;AACpE;;AAGF,SAAO;UACA,OAAO;AACd,MAAI,SAAS,YAAY,KACvB,uBACE,CACE,UAAW,MAAgB,QAAQ,MACnC,KAAK,UAAW,MAAgB,OAAO,MAAM,EAAE,CAChD,EACD,EACE,OAAO,SACR,CACF"}
@@ -7,6 +7,26 @@ let esbuild = require("esbuild");
7
7
  esbuild = require_runtime.__toESM(esbuild);
8
8
 
9
9
  //#region src/loadExternalFile/parseFileContent.ts
10
+ const NODE_GLOBALS = [
11
+ "Buffer",
12
+ "setTimeout",
13
+ "clearTimeout",
14
+ "setInterval",
15
+ "clearInterval",
16
+ "setImmediate",
17
+ "clearImmediate",
18
+ "queueMicrotask",
19
+ "URL",
20
+ "URLSearchParams",
21
+ "TextEncoder",
22
+ "TextDecoder",
23
+ "AbortController",
24
+ "AbortSignal",
25
+ "performance",
26
+ "fetch",
27
+ "crypto",
28
+ "structuredClone"
29
+ ];
10
30
  const getSandBoxContext = (options) => {
11
31
  const { envVarOptions, projectRequire, additionalEnvVars, mocks, aliases } = options ?? {};
12
32
  let additionalGlobalVar = {};
@@ -55,9 +75,7 @@ const getSandBoxContext = (options) => {
55
75
  require: mockedRequire,
56
76
  ...additionalGlobalVar
57
77
  };
58
- Object.getOwnPropertyNames(globalThis).forEach((key) => {
59
- if (!(key in sandboxContext)) sandboxContext[key] = globalThis[key];
60
- });
78
+ for (const key of NODE_GLOBALS) if (!(key in sandboxContext) && key in globalThis) sandboxContext[key] = globalThis[key];
61
79
  return sandboxContext;
62
80
  };
63
81
  const parseFileContent = (fileContentString, options) => {
@@ -69,7 +87,17 @@ const parseFileContent = (fileContentString, options) => {
69
87
  sandboxContext.module?.exports?.default,
70
88
  sandboxContext.module?.exports
71
89
  ];
72
- for (const candidate of candidates) if (candidate && typeof candidate === "object" && Object.keys(candidate).length > 0) return candidate;
90
+ let result;
91
+ for (const candidate of candidates) if (candidate && typeof candidate === "object" && Object.keys(candidate).length > 0) {
92
+ result = candidate;
93
+ break;
94
+ }
95
+ sandboxContext.require = void 0;
96
+ sandboxContext.process = void 0;
97
+ sandboxContext.React = void 0;
98
+ sandboxContext.module = void 0;
99
+ sandboxContext.exports = void 0;
100
+ return result;
73
101
  };
74
102
 
75
103
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"parseFileContent.cjs","names":["getProjectRequire","loadEnvFile"],"sources":["../../../src/loadExternalFile/parseFileContent.ts"],"sourcesContent":["import { type Context, runInNewContext } from 'node:vm';\nimport * as esbuild from 'esbuild';\nimport { type LoadEnvFileOptions, loadEnvFile } from '../loadEnvFile';\nimport { getProjectRequire } from '../utils/ESMxCJSHelpers';\n\nexport type SandBoxContextOptions = {\n envVarOptions?: LoadEnvFileOptions;\n projectRequire?: NodeJS.Require;\n additionalEnvVars?: Record<string, string>;\n /**\n * Map of specifier -> mocked export to be returned when code in the VM calls require(specifier).\n * Example:\n * mocks: {\n * '@intlayer/config/built': { getConfig: () => ({}), Locales: {} }\n * }\n */\n mocks?: Record<string, any>;\n /**\n * Optional alias map if you want to redirect specifiers.\n * Useful when user code imports a subpath you want to collapse.\n * Example:\n * aliases: { '@intlayer/config/built': '@intlayer/config' }\n */\n aliases?: Record<string, string>;\n};\n\nexport const getSandBoxContext = (options?: SandBoxContextOptions): Context => {\n const { envVarOptions, projectRequire, additionalEnvVars, mocks, aliases } =\n options ?? {};\n\n let additionalGlobalVar = {};\n\n const baseRequire: NodeJS.Require =\n typeof projectRequire === 'function' ? projectRequire : getProjectRequire();\n\n // Wrap require to honor mocks and aliases inside the VM\n const mockedRequire: NodeJS.Require = (() => {\n const mockTable = Object.assign(\n {\n esbuild,\n },\n mocks\n );\n const aliasTable = Object.assign({}, aliases);\n\n const wrappedRequire = function mockableRequire(id: string) {\n const target = aliasTable?.[id] ? aliasTable[id] : id;\n\n if (mockTable && Object.hasOwn(mockTable, target)) {\n return mockTable[target];\n }\n\n // If the original id was aliased, allow mocks to be defined on either key.\n if (target !== id && mockTable && Object.hasOwn(mockTable, id)) {\n return mockTable[id];\n }\n\n return baseRequire(target);\n } as NodeJS.Require;\n\n // Mirror NodeJS.Require properties\n wrappedRequire.resolve = baseRequire.resolve.bind(baseRequire);\n wrappedRequire.main = baseRequire.main;\n wrappedRequire.extensions = baseRequire.extensions;\n wrappedRequire.cache = baseRequire.cache;\n\n return wrappedRequire;\n })();\n\n try {\n // Dynamically try to require React if it's installed in the project\n additionalGlobalVar = {\n React: baseRequire('react'),\n };\n } catch (_err) {\n // React is not installed, so we inject a dummy React object to capture JSX elements\n // This allows using JSX in content declarations even if React is not installed (e.g. in Solid.js or Vue projects)\n // because esbuild's tsx loader defaults to React.createElement.\n additionalGlobalVar = {\n React: {\n createElement: (type: any, props: any, ...children: any[]) => ({\n type,\n props: {\n ...props,\n children: children.length <= 1 ? children[0] : children,\n },\n }),\n Fragment: Symbol.for('react.fragment'),\n },\n };\n }\n\n const sandboxContext: Context = {\n exports: {\n default: {},\n },\n module: {\n exports: {},\n },\n process: {\n ...process,\n env: {\n ...process.env,\n ...loadEnvFile(envVarOptions),\n ...additionalEnvVars,\n },\n },\n console,\n require: mockedRequire,\n ...additionalGlobalVar,\n };\n\n // Dynamically inject all global variables\n Object.getOwnPropertyNames(globalThis).forEach((key) => {\n if (!(key in sandboxContext)) {\n sandboxContext[key] = globalThis[key as keyof typeof globalThis];\n }\n });\n\n return sandboxContext;\n};\n\nexport const parseFileContent = <T>(\n fileContentString: string,\n options?: SandBoxContextOptions\n): T | undefined => {\n const sandboxContext = getSandBoxContext(options);\n\n // Force strict mode so illegal writes throw instead of silently failing.\n runInNewContext(`\"use strict\";\\n${fileContentString}`, sandboxContext);\n\n const candidates: unknown[] = [\n sandboxContext.exports?.default,\n sandboxContext.module?.exports?.defaults,\n sandboxContext.module?.exports?.default,\n sandboxContext.module?.exports,\n ];\n\n for (const candidate of candidates) {\n if (\n candidate &&\n typeof candidate === 'object' &&\n Object.keys(candidate as object).length > 0\n ) {\n return candidate as T;\n }\n }\n};\n"],"mappings":";;;;;;;;;AA0BA,MAAa,qBAAqB,YAA6C;CAC7E,MAAM,EAAE,eAAe,gBAAgB,mBAAmB,OAAO,YAC/D,WAAW,EAAE;CAEf,IAAI,sBAAsB,EAAE;CAE5B,MAAM,cACJ,OAAO,mBAAmB,aAAa,iBAAiBA,gDAAmB;CAG7E,MAAM,uBAAuC;EAC3C,MAAM,YAAY,OAAO,OACvB,EACE,SACD,EACD,MACD;EACD,MAAM,aAAa,OAAO,OAAO,EAAE,EAAE,QAAQ;EAE7C,MAAM,iBAAiB,SAAS,gBAAgB,IAAY;GAC1D,MAAM,SAAS,aAAa,MAAM,WAAW,MAAM;AAEnD,OAAI,aAAa,OAAO,OAAO,WAAW,OAAO,CAC/C,QAAO,UAAU;AAInB,OAAI,WAAW,MAAM,aAAa,OAAO,OAAO,WAAW,GAAG,CAC5D,QAAO,UAAU;AAGnB,UAAO,YAAY,OAAO;;AAI5B,iBAAe,UAAU,YAAY,QAAQ,KAAK,YAAY;AAC9D,iBAAe,OAAO,YAAY;AAClC,iBAAe,aAAa,YAAY;AACxC,iBAAe,QAAQ,YAAY;AAEnC,SAAO;KACL;AAEJ,KAAI;AAEF,wBAAsB,EACpB,OAAO,YAAY,QAAQ,EAC5B;UACM,MAAM;AAIb,wBAAsB,EACpB,OAAO;GACL,gBAAgB,MAAW,OAAY,GAAG,cAAqB;IAC7D;IACA,OAAO;KACL,GAAG;KACH,UAAU,SAAS,UAAU,IAAI,SAAS,KAAK;KAChD;IACF;GACD,UAAU,OAAO,IAAI,iBAAiB;GACvC,EACF;;CAGH,MAAM,iBAA0B;EAC9B,SAAS,EACP,SAAS,EAAE,EACZ;EACD,QAAQ,EACN,SAAS,EAAE,EACZ;EACD,SAAS;GACP,GAAG;GACH,KAAK;IACH,GAAG,QAAQ;IACX,GAAGC,gCAAY,cAAc;IAC7B,GAAG;IACJ;GACF;EACD;EACA,SAAS;EACT,GAAG;EACJ;AAGD,QAAO,oBAAoB,WAAW,CAAC,SAAS,QAAQ;AACtD,MAAI,EAAE,OAAO,gBACX,gBAAe,OAAO,WAAW;GAEnC;AAEF,QAAO;;AAGT,MAAa,oBACX,mBACA,YACkB;CAClB,MAAM,iBAAiB,kBAAkB,QAAQ;AAGjD,8BAAgB,kBAAkB,qBAAqB,eAAe;CAEtE,MAAM,aAAwB;EAC5B,eAAe,SAAS;EACxB,eAAe,QAAQ,SAAS;EAChC,eAAe,QAAQ,SAAS;EAChC,eAAe,QAAQ;EACxB;AAED,MAAK,MAAM,aAAa,WACtB,KACE,aACA,OAAO,cAAc,YACrB,OAAO,KAAK,UAAoB,CAAC,SAAS,EAE1C,QAAO"}
1
+ {"version":3,"file":"parseFileContent.cjs","names":["getProjectRequire","loadEnvFile"],"sources":["../../../src/loadExternalFile/parseFileContent.ts"],"sourcesContent":["import { type Context, runInNewContext } from 'node:vm';\nimport * as esbuild from 'esbuild';\nimport { type LoadEnvFileOptions, loadEnvFile } from '../loadEnvFile';\nimport { getProjectRequire } from '../utils/ESMxCJSHelpers';\n\nexport type SandBoxContextOptions = {\n envVarOptions?: LoadEnvFileOptions;\n projectRequire?: NodeJS.Require;\n additionalEnvVars?: Record<string, string>;\n /**\n * Map of specifier -> mocked export to be returned when code in the VM calls require(specifier).\n * Example:\n * mocks: {\n * '@intlayer/config/built': { getConfig: () => ({}), Locales: {} }\n * }\n */\n mocks?: Record<string, any>;\n /**\n * Optional alias map if you want to redirect specifiers.\n * Useful when user code imports a subpath you want to collapse.\n * Example:\n * aliases: { '@intlayer/config/built': '@intlayer/config' }\n */\n aliases?: Record<string, string>;\n};\n\n// Inject only Node.js-specific globals that are absent from a plain V8 context.\n// JS built-ins (Object, Array, Promise, Math, Date, JSON, Symbol, etc.) are\n// provided automatically by runInNewContext — no need to copy them.\n// Copying all of globalThis would retain hundreds of references (including the\n// full module cache via `global`) inside every sandbox, causing a memory leak.\nconst NODE_GLOBALS = [\n 'Buffer',\n 'setTimeout',\n 'clearTimeout',\n 'setInterval',\n 'clearInterval',\n 'setImmediate',\n 'clearImmediate',\n 'queueMicrotask',\n 'URL',\n 'URLSearchParams',\n 'TextEncoder',\n 'TextDecoder',\n 'AbortController',\n 'AbortSignal',\n 'performance',\n 'fetch',\n 'crypto',\n 'structuredClone',\n] as const;\n\nexport const getSandBoxContext = (options?: SandBoxContextOptions): Context => {\n const { envVarOptions, projectRequire, additionalEnvVars, mocks, aliases } =\n options ?? {};\n\n let additionalGlobalVar = {};\n\n const baseRequire: NodeJS.Require =\n typeof projectRequire === 'function' ? projectRequire : getProjectRequire();\n\n // Wrap require to honor mocks and aliases inside the VM\n const mockedRequire: NodeJS.Require = (() => {\n const mockTable = Object.assign(\n {\n esbuild,\n },\n mocks\n );\n const aliasTable = Object.assign({}, aliases);\n\n const wrappedRequire = function mockableRequire(id: string) {\n const target = aliasTable?.[id] ? aliasTable[id] : id;\n\n if (mockTable && Object.hasOwn(mockTable, target)) {\n return mockTable[target];\n }\n\n // If the original id was aliased, allow mocks to be defined on either key.\n if (target !== id && mockTable && Object.hasOwn(mockTable, id)) {\n return mockTable[id];\n }\n\n return baseRequire(target);\n } as NodeJS.Require;\n\n // Mirror NodeJS.Require properties\n wrappedRequire.resolve = baseRequire.resolve.bind(baseRequire);\n wrappedRequire.main = baseRequire.main;\n wrappedRequire.extensions = baseRequire.extensions;\n wrappedRequire.cache = baseRequire.cache;\n\n return wrappedRequire;\n })();\n\n try {\n // Dynamically try to require React if it's installed in the project\n additionalGlobalVar = {\n React: baseRequire('react'),\n };\n } catch (_err) {\n // React is not installed, so we inject a dummy React object to capture JSX elements\n // This allows using JSX in content declarations even if React is not installed (e.g. in Solid.js or Vue projects)\n // because esbuild's tsx loader defaults to React.createElement.\n additionalGlobalVar = {\n React: {\n createElement: (type: any, props: any, ...children: any[]) => ({\n type,\n props: {\n ...props,\n children: children.length <= 1 ? children[0] : children,\n },\n }),\n Fragment: Symbol.for('react.fragment'),\n },\n };\n }\n\n const sandboxContext: Context = {\n exports: {\n default: {},\n },\n module: {\n exports: {},\n },\n process: {\n ...process,\n env: {\n ...process.env,\n ...loadEnvFile(envVarOptions),\n ...additionalEnvVars,\n },\n },\n console,\n require: mockedRequire,\n ...additionalGlobalVar,\n };\n\n for (const key of NODE_GLOBALS) {\n if (!(key in sandboxContext) && key in globalThis) {\n (sandboxContext as Record<string, unknown>)[key] =\n globalThis[key as keyof typeof globalThis];\n }\n }\n\n return sandboxContext;\n};\n\nexport const parseFileContent = <T>(\n fileContentString: string,\n options?: SandBoxContextOptions\n): T | undefined => {\n const sandboxContext = getSandBoxContext(options);\n\n // Force strict mode so illegal writes throw instead of silently failing.\n runInNewContext(`\"use strict\";\\n${fileContentString}`, sandboxContext);\n\n const candidates: unknown[] = [\n sandboxContext.exports?.default,\n sandboxContext.module?.exports?.defaults,\n sandboxContext.module?.exports?.default,\n sandboxContext.module?.exports,\n ];\n\n let result: T | undefined;\n for (const candidate of candidates) {\n if (\n candidate &&\n typeof candidate === 'object' &&\n Object.keys(candidate as object).length > 0\n ) {\n result = candidate as T;\n break;\n }\n }\n\n // Drop heavy references so the V8 context created by runInNewContext can be\n // garbage-collected promptly. The extracted `result` is a plain data object\n // and does not retain the sandbox.\n (sandboxContext as Record<string, unknown>).require = undefined;\n (sandboxContext as Record<string, unknown>).process = undefined;\n (sandboxContext as Record<string, unknown>).React = undefined;\n (sandboxContext as Record<string, unknown>).module = undefined;\n (sandboxContext as Record<string, unknown>).exports = undefined;\n\n return result;\n};\n"],"mappings":";;;;;;;;;AA+BA,MAAM,eAAe;CACnB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAED,MAAa,qBAAqB,YAA6C;CAC7E,MAAM,EAAE,eAAe,gBAAgB,mBAAmB,OAAO,YAC/D,WAAW,EAAE;CAEf,IAAI,sBAAsB,EAAE;CAE5B,MAAM,cACJ,OAAO,mBAAmB,aAAa,iBAAiBA,gDAAmB;CAG7E,MAAM,uBAAuC;EAC3C,MAAM,YAAY,OAAO,OACvB,EACE,SACD,EACD,MACD;EACD,MAAM,aAAa,OAAO,OAAO,EAAE,EAAE,QAAQ;EAE7C,MAAM,iBAAiB,SAAS,gBAAgB,IAAY;GAC1D,MAAM,SAAS,aAAa,MAAM,WAAW,MAAM;AAEnD,OAAI,aAAa,OAAO,OAAO,WAAW,OAAO,CAC/C,QAAO,UAAU;AAInB,OAAI,WAAW,MAAM,aAAa,OAAO,OAAO,WAAW,GAAG,CAC5D,QAAO,UAAU;AAGnB,UAAO,YAAY,OAAO;;AAI5B,iBAAe,UAAU,YAAY,QAAQ,KAAK,YAAY;AAC9D,iBAAe,OAAO,YAAY;AAClC,iBAAe,aAAa,YAAY;AACxC,iBAAe,QAAQ,YAAY;AAEnC,SAAO;KACL;AAEJ,KAAI;AAEF,wBAAsB,EACpB,OAAO,YAAY,QAAQ,EAC5B;UACM,MAAM;AAIb,wBAAsB,EACpB,OAAO;GACL,gBAAgB,MAAW,OAAY,GAAG,cAAqB;IAC7D;IACA,OAAO;KACL,GAAG;KACH,UAAU,SAAS,UAAU,IAAI,SAAS,KAAK;KAChD;IACF;GACD,UAAU,OAAO,IAAI,iBAAiB;GACvC,EACF;;CAGH,MAAM,iBAA0B;EAC9B,SAAS,EACP,SAAS,EAAE,EACZ;EACD,QAAQ,EACN,SAAS,EAAE,EACZ;EACD,SAAS;GACP,GAAG;GACH,KAAK;IACH,GAAG,QAAQ;IACX,GAAGC,gCAAY,cAAc;IAC7B,GAAG;IACJ;GACF;EACD;EACA,SAAS;EACT,GAAG;EACJ;AAED,MAAK,MAAM,OAAO,aAChB,KAAI,EAAE,OAAO,mBAAmB,OAAO,WACrC,CAAC,eAA2C,OAC1C,WAAW;AAIjB,QAAO;;AAGT,MAAa,oBACX,mBACA,YACkB;CAClB,MAAM,iBAAiB,kBAAkB,QAAQ;AAGjD,8BAAgB,kBAAkB,qBAAqB,eAAe;CAEtE,MAAM,aAAwB;EAC5B,eAAe,SAAS;EACxB,eAAe,QAAQ,SAAS;EAChC,eAAe,QAAQ,SAAS;EAChC,eAAe,QAAQ;EACxB;CAED,IAAI;AACJ,MAAK,MAAM,aAAa,WACtB,KACE,aACA,OAAO,cAAc,YACrB,OAAO,KAAK,UAAoB,CAAC,SAAS,GAC1C;AACA,WAAS;AACT;;AAOJ,CAAC,eAA2C,UAAU;AACtD,CAAC,eAA2C,UAAU;AACtD,CAAC,eAA2C,QAAQ;AACpD,CAAC,eAA2C,SAAS;AACrD,CAAC,eAA2C,UAAU;AAEtD,QAAO"}
@@ -53,7 +53,7 @@ const transpileTSToCJSSync = (code, filePath, options) => {
53
53
  const transpileTSToCJS = async (code, filePath, options) => {
54
54
  const loader = require_loadExternalFile_bundleFile.getLoader((0, node_path.extname)(filePath));
55
55
  const { esbuildInstance, ...buildOptions } = options ?? {};
56
- return (await (esbuildInstance?.build ?? esbuild.build)({
56
+ const ctx = await (esbuildInstance?.context ?? esbuild.context)({
57
57
  stdin: {
58
58
  contents: code,
59
59
  loader,
@@ -62,7 +62,12 @@ const transpileTSToCJS = async (code, filePath, options) => {
62
62
  },
63
63
  ...getTransformationOptions(filePath),
64
64
  ...buildOptions
65
- })).outputFiles?.[0].text;
65
+ });
66
+ try {
67
+ return (await ctx.rebuild()).outputFiles?.[0].text;
68
+ } finally {
69
+ await ctx.dispose();
70
+ }
66
71
  };
67
72
 
68
73
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"transpileTSToCJS.cjs","names":["getPackageJsonPath","getLoader","buildSync","build"],"sources":["../../../src/loadExternalFile/transpileTSToCJS.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { dirname, extname, join } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport { type BuildOptions, type BuildResult, build, buildSync } from 'esbuild';\nimport { getPackageJsonPath } from '../utils/getPackageJsonPath';\nimport { getLoader } from './bundleFile';\n\nexport type TranspileOptions = BuildOptions & {\n /**\n * Optional custom esbuild instance to use for transpilation.\n * Useful in environments (e.g. VS Code extensions) where the bundled\n * esbuild binary may not match the host platform.\n * When provided, its `buildSync`/`build` methods are used instead of\n * the ones imported from the `esbuild` package.\n */\n esbuildInstance?: typeof import('esbuild');\n};\n\nconst getTsConfigPath = (filePath: string): string | undefined => {\n const tsconfigPath = join(\n getPackageJsonPath(dirname(filePath)).baseDir,\n 'tsconfig.json'\n );\n\n // Only return the tsconfig path if it exists\n return existsSync(tsconfigPath) ? tsconfigPath : undefined;\n};\n\nconst getTransformationOptions = (filePath: string): BuildOptions => ({\n loader: {\n '.js': 'js',\n '.jsx': 'jsx',\n '.mjs': 'js',\n '.ts': 'ts',\n '.tsx': 'tsx',\n '.cjs': 'js',\n '.json': 'json',\n '.md': 'text',\n '.mdx': 'text',\n },\n format: 'cjs',\n target: 'node20',\n platform: 'node',\n write: false,\n packages: 'external',\n bundle: true,\n tsconfig: getTsConfigPath(filePath),\n define: {\n 'import.meta.url': JSON.stringify(pathToFileURL(filePath).href),\n 'import.meta.env': 'process.env',\n },\n});\n\nexport const transpileTSToCJSSync = (\n code: string,\n filePath: string,\n options?: TranspileOptions\n): string | undefined => {\n const extension = extname(filePath);\n const loader = getLoader(extension);\n\n const { esbuildInstance, ...buildOptions } = options ?? {};\n const esbuildBuildSync = esbuildInstance?.buildSync ?? buildSync;\n\n const moduleResult: BuildResult = esbuildBuildSync({\n stdin: {\n contents: code,\n loader,\n resolveDir: dirname(filePath), // Add resolveDir to resolve imports relative to the file's location\n sourcefile: filePath, // Add sourcefile for better error messages\n },\n ...getTransformationOptions(filePath),\n ...buildOptions,\n });\n\n const moduleResultString = moduleResult.outputFiles?.[0].text;\n\n return moduleResultString;\n};\n\nexport const transpileTSToCJS = async (\n code: string,\n filePath: string,\n options?: TranspileOptions\n): Promise<string | undefined> => {\n const extension = extname(filePath);\n const loader = getLoader(extension);\n\n const { esbuildInstance, ...buildOptions } = options ?? {};\n const esbuildBuild = esbuildInstance?.build ?? build;\n\n const moduleResult: BuildResult = await esbuildBuild({\n stdin: {\n contents: code,\n loader,\n resolveDir: dirname(filePath), // Add resolveDir to resolve imports relative to the file's location\n sourcefile: filePath, // Add sourcefile for better error messages\n },\n ...getTransformationOptions(filePath),\n ...buildOptions,\n });\n\n const moduleResultString = moduleResult.outputFiles?.[0].text;\n\n return moduleResultString;\n};\n"],"mappings":";;;;;;;;;;AAkBA,MAAM,mBAAmB,aAAyC;CAChE,MAAM,mCACJA,2EAA2B,SAAS,CAAC,CAAC,SACtC,gBACD;AAGD,gCAAkB,aAAa,GAAG,eAAe;;AAGnD,MAAM,4BAA4B,cAAoC;CACpE,QAAQ;EACN,OAAO;EACP,QAAQ;EACR,QAAQ;EACR,OAAO;EACP,QAAQ;EACR,QAAQ;EACR,SAAS;EACT,OAAO;EACP,QAAQ;EACT;CACD,QAAQ;CACR,QAAQ;CACR,UAAU;CACV,OAAO;CACP,UAAU;CACV,QAAQ;CACR,UAAU,gBAAgB,SAAS;CACnC,QAAQ;EACN,mBAAmB,KAAK,sCAAwB,SAAS,CAAC,KAAK;EAC/D,mBAAmB;EACpB;CACF;AAED,MAAa,wBACX,MACA,UACA,YACuB;CAEvB,MAAM,SAASC,qEADW,SACQ,CAAC;CAEnC,MAAM,EAAE,iBAAiB,GAAG,iBAAiB,WAAW,EAAE;AAgB1D,SAfyB,iBAAiB,aAAaC,mBAEJ;EACjD,OAAO;GACL,UAAU;GACV;GACA,mCAAoB,SAAS;GAC7B,YAAY;GACb;EACD,GAAG,yBAAyB,SAAS;EACrC,GAAG;EACJ,CAEsC,CAAC,cAAc,GAAG;;AAK3D,MAAa,mBAAmB,OAC9B,MACA,UACA,YACgC;CAEhC,MAAM,SAASD,qEADW,SACQ,CAAC;CAEnC,MAAM,EAAE,iBAAiB,GAAG,iBAAiB,WAAW,EAAE;AAgB1D,SAF2B,OAbN,iBAAiB,SAASE,eAEM;EACnD,OAAO;GACL,UAAU;GACV;GACA,mCAAoB,SAAS;GAC7B,YAAY;GACb;EACD,GAAG,yBAAyB,SAAS;EACrC,GAAG;EACJ,CAAC,EAEsC,cAAc,GAAG"}
1
+ {"version":3,"file":"transpileTSToCJS.cjs","names":["getPackageJsonPath","getLoader","buildSync","context"],"sources":["../../../src/loadExternalFile/transpileTSToCJS.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { dirname, extname, join } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport {\n type BuildOptions,\n type BuildResult,\n buildSync,\n context,\n} from 'esbuild';\nimport { getPackageJsonPath } from '../utils/getPackageJsonPath';\nimport { getLoader } from './bundleFile';\n\nexport type TranspileOptions = BuildOptions & {\n /**\n * Optional custom esbuild instance to use for transpilation.\n * Useful in environments (e.g. VS Code extensions) where the bundled\n * esbuild binary may not match the host platform.\n * When provided, its `buildSync`/`build` methods are used instead of\n * the ones imported from the `esbuild` package.\n */\n esbuildInstance?: typeof import('esbuild');\n};\n\nconst getTsConfigPath = (filePath: string): string | undefined => {\n const tsconfigPath = join(\n getPackageJsonPath(dirname(filePath)).baseDir,\n 'tsconfig.json'\n );\n\n // Only return the tsconfig path if it exists\n return existsSync(tsconfigPath) ? tsconfigPath : undefined;\n};\n\nconst getTransformationOptions = (filePath: string): BuildOptions => ({\n loader: {\n '.js': 'js',\n '.jsx': 'jsx',\n '.mjs': 'js',\n '.ts': 'ts',\n '.tsx': 'tsx',\n '.cjs': 'js',\n '.json': 'json',\n '.md': 'text',\n '.mdx': 'text',\n },\n format: 'cjs',\n target: 'node20',\n platform: 'node',\n write: false,\n packages: 'external',\n bundle: true,\n tsconfig: getTsConfigPath(filePath),\n define: {\n 'import.meta.url': JSON.stringify(pathToFileURL(filePath).href),\n 'import.meta.env': 'process.env',\n },\n});\n\nexport const transpileTSToCJSSync = (\n code: string,\n filePath: string,\n options?: TranspileOptions\n): string | undefined => {\n const extension = extname(filePath);\n const loader = getLoader(extension);\n\n const { esbuildInstance, ...buildOptions } = options ?? {};\n const esbuildBuildSync = esbuildInstance?.buildSync ?? buildSync;\n\n const moduleResult: BuildResult = esbuildBuildSync({\n stdin: {\n contents: code,\n loader,\n resolveDir: dirname(filePath), // Add resolveDir to resolve imports relative to the file's location\n sourcefile: filePath, // Add sourcefile for better error messages\n },\n ...getTransformationOptions(filePath),\n ...buildOptions,\n });\n\n const moduleResultString = moduleResult.outputFiles?.[0].text;\n\n return moduleResultString;\n};\n\nexport const transpileTSToCJS = async (\n code: string,\n filePath: string,\n options?: TranspileOptions\n): Promise<string | undefined> => {\n const extension = extname(filePath);\n const loader = getLoader(extension);\n\n const { esbuildInstance, ...buildOptions } = options ?? {};\n // Use context() + rebuild() + dispose() so esbuild deterministically releases\n // Go-subprocess resources for each one-shot transpilation, preventing them\n // from accumulating between rapid HMR-driven file changes.\n const esbuildContext = esbuildInstance?.context ?? context;\n\n const ctx = await esbuildContext({\n stdin: {\n contents: code,\n loader,\n resolveDir: dirname(filePath),\n sourcefile: filePath,\n },\n ...getTransformationOptions(filePath),\n ...buildOptions,\n });\n\n try {\n const moduleResult = await ctx.rebuild();\n return moduleResult.outputFiles?.[0].text;\n } finally {\n await ctx.dispose();\n }\n};\n"],"mappings":";;;;;;;;;;AAuBA,MAAM,mBAAmB,aAAyC;CAChE,MAAM,mCACJA,2EAA2B,SAAS,CAAC,CAAC,SACtC,gBACD;AAGD,gCAAkB,aAAa,GAAG,eAAe;;AAGnD,MAAM,4BAA4B,cAAoC;CACpE,QAAQ;EACN,OAAO;EACP,QAAQ;EACR,QAAQ;EACR,OAAO;EACP,QAAQ;EACR,QAAQ;EACR,SAAS;EACT,OAAO;EACP,QAAQ;EACT;CACD,QAAQ;CACR,QAAQ;CACR,UAAU;CACV,OAAO;CACP,UAAU;CACV,QAAQ;CACR,UAAU,gBAAgB,SAAS;CACnC,QAAQ;EACN,mBAAmB,KAAK,sCAAwB,SAAS,CAAC,KAAK;EAC/D,mBAAmB;EACpB;CACF;AAED,MAAa,wBACX,MACA,UACA,YACuB;CAEvB,MAAM,SAASC,qEADW,SACQ,CAAC;CAEnC,MAAM,EAAE,iBAAiB,GAAG,iBAAiB,WAAW,EAAE;AAgB1D,SAfyB,iBAAiB,aAAaC,mBAEJ;EACjD,OAAO;GACL,UAAU;GACV;GACA,mCAAoB,SAAS;GAC7B,YAAY;GACb;EACD,GAAG,yBAAyB,SAAS;EACrC,GAAG;EACJ,CAEsC,CAAC,cAAc,GAAG;;AAK3D,MAAa,mBAAmB,OAC9B,MACA,UACA,YACgC;CAEhC,MAAM,SAASD,qEADW,SACQ,CAAC;CAEnC,MAAM,EAAE,iBAAiB,GAAG,iBAAiB,WAAW,EAAE;CAM1D,MAAM,MAAM,OAFW,iBAAiB,WAAWE,iBAElB;EAC/B,OAAO;GACL,UAAU;GACV;GACA,mCAAoB,SAAS;GAC7B,YAAY;GACb;EACD,GAAG,yBAAyB,SAAS;EACrC,GAAG;EACJ,CAAC;AAEF,KAAI;AAEF,UAAO,MADoB,IAAI,SAAS,EACpB,cAAc,GAAG;WAC7B;AACR,QAAM,IAAI,SAAS"}
@@ -4,7 +4,7 @@ import { getConfigEnvVars } from "../envVars/envVars.mjs";
4
4
  import { BundleLogger } from "./logBundle.mjs";
5
5
  import { isAbsolute, join, resolve } from "node:path";
6
6
  import { mkdir, rm, writeFile } from "node:fs/promises";
7
- import configPackageJson from "@intlayer/types/package.json" with { type: "json" };
7
+ import packageJSON from "@intlayer/types/package.json" with { type: "json" };
8
8
  import { build } from "esbuild";
9
9
  import { exec } from "node:child_process";
10
10
  import { promisify } from "node:util";
@@ -27,7 +27,7 @@ const packageList = [
27
27
  "vanilla-intlayer",
28
28
  "intlayer"
29
29
  ];
30
- const defaultVersion = configPackageJson.version;
30
+ const defaultVersion = packageJSON.version;
31
31
  /**
32
32
  * Bundle the application content using esbuild.
33
33
  * It uses the Intlayer configuration to set up aliases and other esbuild options.
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["packageJSON"],"sources":["../../../src/bundle/index.ts"],"sourcesContent":["import { exec } from 'node:child_process';\nimport { mkdir, rm, writeFile } from 'node:fs/promises';\nimport { isAbsolute, join, resolve } from 'node:path';\nimport { promisify } from 'node:util';\nimport packageJSON from '@intlayer/types/package.json' with { type: 'json' };\nimport { type BuildOptions, build, type Plugin } from 'esbuild';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n} from '../configFile/getConfiguration';\nimport { getConfigEnvVars } from '../envVars/envVars';\nimport { getAlias } from '../utils/alias';\nimport { BundleLogger } from './logBundle';\n\nconst execAsync = promisify(exec);\n\nexport const packageList = [\n 'next-intlayer',\n 'react-intlayer',\n 'vue-intlayer',\n 'svelte-intlayer',\n 'preact-intlayer',\n 'solid-intlayer',\n 'angular-intlayer',\n 'lit-intlayer',\n 'express-intlayer',\n 'hono-intlayer',\n 'fastify-intlayer',\n 'adonis-intlayer',\n 'vanilla-intlayer',\n 'intlayer',\n] as const;\n\nconst defaultVersion = packageJSON.version;\n\nexport type BundleIntlayerOptions = {\n outfile?: string;\n configOptions?: GetConfigurationOptions;\n bundlePackages?: string[];\n version?: string;\n} & BuildOptions;\n\n/**\n * Bundle the application content using esbuild.\n * It uses the Intlayer configuration to set up aliases and other esbuild options.\n *\n * @param options - Bundle options including entryPoint, outfile, and esbuild options.\n * @returns The build result.\n */\nexport const bundleIntlayer = async (options: BundleIntlayerOptions) => {\n const {\n outfile = 'intlayer-bundle.js',\n configOptions,\n bundlePackages = [...packageList],\n version = defaultVersion,\n ...esbuildOptions\n } = options;\n\n const intlayerConfig = getConfiguration(configOptions);\n\n const logger = new BundleLogger(intlayerConfig);\n\n const alias = getAlias({\n configuration: intlayerConfig,\n formatter: (value: string) => resolve(process.cwd(), value),\n });\n\n // Fetch dictionaries and calculate tree-shaking variables\n\n const treeShakingDefines = getConfigEnvVars(\n intlayerConfig,\n (key) => `process.env.${key}`,\n (value) => `\"${value}\"` // Properly wraps the string in quotes\n );\n\n const intlayerBundlePlugin: Plugin = {\n name: 'intlayer-bundle-plugin',\n setup(build) {\n // Create a regex that matches the provided packages\n // It matches both the package name and any sub-exports\n const packagesRegex = new RegExp(\n `^(${bundlePackages\n .map((packages) => packages.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'))\n .join('|')})(\\\\/.*)?$`\n );\n\n build.onResolve({ filter: packagesRegex }, () => ({\n external: false,\n }));\n\n // Also ensure @intlayer/ packages are bundled if not explicitly excluded\n build.onResolve({ filter: /^@intlayer\\// }, () => ({\n external: false,\n }));\n },\n };\n\n const tempDir = join(intlayerConfig.system.tempDir, 'intlayer-bundle-tmp');\n\n logger.setStatus('installing');\n\n try {\n // Clean and prepare temp directory\n await rm(tempDir, { recursive: true, force: true });\n await mkdir(tempDir, { recursive: true });\n\n // Write package.json to fetch packages via npm/bun\n const deps = Object.fromEntries(\n bundlePackages.map((pkg) => [pkg, version])\n );\n await writeFile(\n join(tempDir, 'package.json'),\n JSON.stringify({ dependencies: deps, type: 'module' })\n );\n\n // Determine package manager (prefer bun if available)\n let pm = 'npm install';\n try {\n await execAsync('bun --version');\n pm = 'bun install';\n } catch {}\n\n // Install the packages in the temp directory\n await execAsync(pm, { cwd: tempDir });\n\n const absoluteOutfile = isAbsolute(outfile)\n ? outfile\n : join(process.cwd(), outfile);\n\n const buildOptions: BuildOptions = {\n bundle: true,\n outfile: absoluteOutfile,\n absWorkingDir: tempDir,\n platform: 'browser',\n conditions: ['browser', 'module', 'import', 'default'],\n minify: true,\n minifyIdentifiers: true,\n treeShaking: true,\n format: 'iife',\n ignoreAnnotations: true,\n stdin: {\n contents: bundlePackages\n .map((packageName) => {\n // Convert package name to global name (e.g. vanilla-intlayer -> VanillaIntlayer)\n const globalName = packageName\n .split('-')\n .map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`)\n .join('');\n // Create a global variable for each package\n return `import * as ${globalName} from '${packageName}';\\nif (typeof window !== 'undefined') { window['${globalName}'] = ${globalName}; }`;\n })\n .join('\\n'),\n resolveDir: tempDir,\n },\n define: {\n 'process.env': '{}', // Fix ReferenceError: process is not defined\n // Inject generated environment variables\n ...treeShakingDefines,\n ...esbuildOptions.define,\n },\n alias: {\n ...alias,\n ...esbuildOptions.alias,\n },\n ...esbuildOptions,\n plugins: [intlayerBundlePlugin, ...(esbuildOptions.plugins || [])],\n };\n\n logger.setStatus('bundling');\n const result = await build(buildOptions);\n logger.setStatus('success');\n return result;\n } catch (error) {\n logger.setError(error);\n throw error;\n } finally {\n // Clean up temp directory\n await rm(tempDir, { recursive: true, force: true });\n }\n};\n"],"mappings":";;;;;;;;;;;;AAcA,MAAM,YAAY,UAAU,KAAK;AAEjC,MAAa,cAAc;CACzB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAED,MAAM,iBAAiBA,kBAAY;;;;;;;;AAgBnC,MAAa,iBAAiB,OAAO,YAAmC;CACtE,MAAM,EACJ,UAAU,sBACV,eACA,iBAAiB,CAAC,GAAG,YAAY,EACjC,UAAU,gBACV,GAAG,mBACD;CAEJ,MAAM,iBAAiB,iBAAiB,cAAc;CAEtD,MAAM,SAAS,IAAI,aAAa,eAAe;CAE/C,MAAM,QAAQ,SAAS;EACrB,eAAe;EACf,YAAY,UAAkB,QAAQ,QAAQ,KAAK,EAAE,MAAM;EAC5D,CAAC;CAIF,MAAM,qBAAqB,iBACzB,iBACC,QAAQ,eAAe,QACvB,UAAU,IAAI,MAAM,GACtB;CAED,MAAM,uBAA+B;EACnC,MAAM;EACN,MAAM,OAAO;GAGX,MAAM,gBAAgB,IAAI,OACxB,KAAK,eACF,KAAK,aAAa,SAAS,QAAQ,uBAAuB,OAAO,CAAC,CAClE,KAAK,IAAI,CAAC,YACd;AAED,SAAM,UAAU,EAAE,QAAQ,eAAe,SAAS,EAChD,UAAU,OACX,EAAE;AAGH,SAAM,UAAU,EAAE,QAAQ,gBAAgB,SAAS,EACjD,UAAU,OACX,EAAE;;EAEN;CAED,MAAM,UAAU,KAAK,eAAe,OAAO,SAAS,sBAAsB;AAE1E,QAAO,UAAU,aAAa;AAE9B,KAAI;AAEF,QAAM,GAAG,SAAS;GAAE,WAAW;GAAM,OAAO;GAAM,CAAC;AACnD,QAAM,MAAM,SAAS,EAAE,WAAW,MAAM,CAAC;EAGzC,MAAM,OAAO,OAAO,YAClB,eAAe,KAAK,QAAQ,CAAC,KAAK,QAAQ,CAAC,CAC5C;AACD,QAAM,UACJ,KAAK,SAAS,eAAe,EAC7B,KAAK,UAAU;GAAE,cAAc;GAAM,MAAM;GAAU,CAAC,CACvD;EAGD,IAAI,KAAK;AACT,MAAI;AACF,SAAM,UAAU,gBAAgB;AAChC,QAAK;UACC;AAGR,QAAM,UAAU,IAAI,EAAE,KAAK,SAAS,CAAC;EAMrC,MAAM,eAA6B;GACjC,QAAQ;GACR,SANsB,WAAW,QAAQ,GACvC,UACA,KAAK,QAAQ,KAAK,EAAE,QAAQ;GAK9B,eAAe;GACf,UAAU;GACV,YAAY;IAAC;IAAW;IAAU;IAAU;IAAU;GACtD,QAAQ;GACR,mBAAmB;GACnB,aAAa;GACb,QAAQ;GACR,mBAAmB;GACnB,OAAO;IACL,UAAU,eACP,KAAK,gBAAgB;KAEpB,MAAM,aAAa,YAChB,MAAM,IAAI,CACV,KAAK,SAAS,GAAG,KAAK,OAAO,EAAE,CAAC,aAAa,GAAG,KAAK,MAAM,EAAE,GAAG,CAChE,KAAK,GAAG;AAEX,YAAO,eAAe,WAAW,SAAS,YAAY,mDAAmD,WAAW,OAAO,WAAW;MACtI,CACD,KAAK,KAAK;IACb,YAAY;IACb;GACD,QAAQ;IACN,eAAe;IAEf,GAAG;IACH,GAAG,eAAe;IACnB;GACD,OAAO;IACL,GAAG;IACH,GAAG,eAAe;IACnB;GACD,GAAG;GACH,SAAS,CAAC,sBAAsB,GAAI,eAAe,WAAW,EAAE,CAAE;GACnE;AAED,SAAO,UAAU,WAAW;EAC5B,MAAM,SAAS,MAAM,MAAM,aAAa;AACxC,SAAO,UAAU,UAAU;AAC3B,SAAO;UACA,OAAO;AACd,SAAO,SAAS,MAAM;AACtB,QAAM;WACE;AAER,QAAM,GAAG,SAAS;GAAE,WAAW;GAAM,OAAO;GAAM,CAAC"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/bundle/index.ts"],"sourcesContent":["import { exec } from 'node:child_process';\nimport { mkdir, rm, writeFile } from 'node:fs/promises';\nimport { isAbsolute, join, resolve } from 'node:path';\nimport { promisify } from 'node:util';\nimport packageJSON from '@intlayer/types/package.json' with { type: 'json' };\nimport { type BuildOptions, build, type Plugin } from 'esbuild';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n} from '../configFile/getConfiguration';\nimport { getConfigEnvVars } from '../envVars/envVars';\nimport { getAlias } from '../utils/alias';\nimport { BundleLogger } from './logBundle';\n\nconst execAsync = promisify(exec);\n\nexport const packageList = [\n 'next-intlayer',\n 'react-intlayer',\n 'vue-intlayer',\n 'svelte-intlayer',\n 'preact-intlayer',\n 'solid-intlayer',\n 'angular-intlayer',\n 'lit-intlayer',\n 'express-intlayer',\n 'hono-intlayer',\n 'fastify-intlayer',\n 'adonis-intlayer',\n 'vanilla-intlayer',\n 'intlayer',\n] as const;\n\nconst defaultVersion = packageJSON.version;\n\nexport type BundleIntlayerOptions = {\n outfile?: string;\n configOptions?: GetConfigurationOptions;\n bundlePackages?: string[];\n version?: string;\n} & BuildOptions;\n\n/**\n * Bundle the application content using esbuild.\n * It uses the Intlayer configuration to set up aliases and other esbuild options.\n *\n * @param options - Bundle options including entryPoint, outfile, and esbuild options.\n * @returns The build result.\n */\nexport const bundleIntlayer = async (options: BundleIntlayerOptions) => {\n const {\n outfile = 'intlayer-bundle.js',\n configOptions,\n bundlePackages = [...packageList],\n version = defaultVersion,\n ...esbuildOptions\n } = options;\n\n const intlayerConfig = getConfiguration(configOptions);\n\n const logger = new BundleLogger(intlayerConfig);\n\n const alias = getAlias({\n configuration: intlayerConfig,\n formatter: (value: string) => resolve(process.cwd(), value),\n });\n\n // Fetch dictionaries and calculate tree-shaking variables\n\n const treeShakingDefines = getConfigEnvVars(\n intlayerConfig,\n (key) => `process.env.${key}`,\n (value) => `\"${value}\"` // Properly wraps the string in quotes\n );\n\n const intlayerBundlePlugin: Plugin = {\n name: 'intlayer-bundle-plugin',\n setup(build) {\n // Create a regex that matches the provided packages\n // It matches both the package name and any sub-exports\n const packagesRegex = new RegExp(\n `^(${bundlePackages\n .map((packages) => packages.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'))\n .join('|')})(\\\\/.*)?$`\n );\n\n build.onResolve({ filter: packagesRegex }, () => ({\n external: false,\n }));\n\n // Also ensure @intlayer/ packages are bundled if not explicitly excluded\n build.onResolve({ filter: /^@intlayer\\// }, () => ({\n external: false,\n }));\n },\n };\n\n const tempDir = join(intlayerConfig.system.tempDir, 'intlayer-bundle-tmp');\n\n logger.setStatus('installing');\n\n try {\n // Clean and prepare temp directory\n await rm(tempDir, { recursive: true, force: true });\n await mkdir(tempDir, { recursive: true });\n\n // Write package.json to fetch packages via npm/bun\n const deps = Object.fromEntries(\n bundlePackages.map((pkg) => [pkg, version])\n );\n await writeFile(\n join(tempDir, 'package.json'),\n JSON.stringify({ dependencies: deps, type: 'module' })\n );\n\n // Determine package manager (prefer bun if available)\n let pm = 'npm install';\n try {\n await execAsync('bun --version');\n pm = 'bun install';\n } catch {}\n\n // Install the packages in the temp directory\n await execAsync(pm, { cwd: tempDir });\n\n const absoluteOutfile = isAbsolute(outfile)\n ? outfile\n : join(process.cwd(), outfile);\n\n const buildOptions: BuildOptions = {\n bundle: true,\n outfile: absoluteOutfile,\n absWorkingDir: tempDir,\n platform: 'browser',\n conditions: ['browser', 'module', 'import', 'default'],\n minify: true,\n minifyIdentifiers: true,\n treeShaking: true,\n format: 'iife',\n ignoreAnnotations: true,\n stdin: {\n contents: bundlePackages\n .map((packageName) => {\n // Convert package name to global name (e.g. vanilla-intlayer -> VanillaIntlayer)\n const globalName = packageName\n .split('-')\n .map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`)\n .join('');\n // Create a global variable for each package\n return `import * as ${globalName} from '${packageName}';\\nif (typeof window !== 'undefined') { window['${globalName}'] = ${globalName}; }`;\n })\n .join('\\n'),\n resolveDir: tempDir,\n },\n define: {\n 'process.env': '{}', // Fix ReferenceError: process is not defined\n // Inject generated environment variables\n ...treeShakingDefines,\n ...esbuildOptions.define,\n },\n alias: {\n ...alias,\n ...esbuildOptions.alias,\n },\n ...esbuildOptions,\n plugins: [intlayerBundlePlugin, ...(esbuildOptions.plugins || [])],\n };\n\n logger.setStatus('bundling');\n const result = await build(buildOptions);\n logger.setStatus('success');\n return result;\n } catch (error) {\n logger.setError(error);\n throw error;\n } finally {\n // Clean up temp directory\n await rm(tempDir, { recursive: true, force: true });\n }\n};\n"],"mappings":";;;;;;;;;;;;AAcA,MAAM,YAAY,UAAU,KAAK;AAEjC,MAAa,cAAc;CACzB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAED,MAAM,iBAAiB,YAAY;;;;;;;;AAgBnC,MAAa,iBAAiB,OAAO,YAAmC;CACtE,MAAM,EACJ,UAAU,sBACV,eACA,iBAAiB,CAAC,GAAG,YAAY,EACjC,UAAU,gBACV,GAAG,mBACD;CAEJ,MAAM,iBAAiB,iBAAiB,cAAc;CAEtD,MAAM,SAAS,IAAI,aAAa,eAAe;CAE/C,MAAM,QAAQ,SAAS;EACrB,eAAe;EACf,YAAY,UAAkB,QAAQ,QAAQ,KAAK,EAAE,MAAM;EAC5D,CAAC;CAIF,MAAM,qBAAqB,iBACzB,iBACC,QAAQ,eAAe,QACvB,UAAU,IAAI,MAAM,GACtB;CAED,MAAM,uBAA+B;EACnC,MAAM;EACN,MAAM,OAAO;GAGX,MAAM,gBAAgB,IAAI,OACxB,KAAK,eACF,KAAK,aAAa,SAAS,QAAQ,uBAAuB,OAAO,CAAC,CAClE,KAAK,IAAI,CAAC,YACd;AAED,SAAM,UAAU,EAAE,QAAQ,eAAe,SAAS,EAChD,UAAU,OACX,EAAE;AAGH,SAAM,UAAU,EAAE,QAAQ,gBAAgB,SAAS,EACjD,UAAU,OACX,EAAE;;EAEN;CAED,MAAM,UAAU,KAAK,eAAe,OAAO,SAAS,sBAAsB;AAE1E,QAAO,UAAU,aAAa;AAE9B,KAAI;AAEF,QAAM,GAAG,SAAS;GAAE,WAAW;GAAM,OAAO;GAAM,CAAC;AACnD,QAAM,MAAM,SAAS,EAAE,WAAW,MAAM,CAAC;EAGzC,MAAM,OAAO,OAAO,YAClB,eAAe,KAAK,QAAQ,CAAC,KAAK,QAAQ,CAAC,CAC5C;AACD,QAAM,UACJ,KAAK,SAAS,eAAe,EAC7B,KAAK,UAAU;GAAE,cAAc;GAAM,MAAM;GAAU,CAAC,CACvD;EAGD,IAAI,KAAK;AACT,MAAI;AACF,SAAM,UAAU,gBAAgB;AAChC,QAAK;UACC;AAGR,QAAM,UAAU,IAAI,EAAE,KAAK,SAAS,CAAC;EAMrC,MAAM,eAA6B;GACjC,QAAQ;GACR,SANsB,WAAW,QAAQ,GACvC,UACA,KAAK,QAAQ,KAAK,EAAE,QAAQ;GAK9B,eAAe;GACf,UAAU;GACV,YAAY;IAAC;IAAW;IAAU;IAAU;IAAU;GACtD,QAAQ;GACR,mBAAmB;GACnB,aAAa;GACb,QAAQ;GACR,mBAAmB;GACnB,OAAO;IACL,UAAU,eACP,KAAK,gBAAgB;KAEpB,MAAM,aAAa,YAChB,MAAM,IAAI,CACV,KAAK,SAAS,GAAG,KAAK,OAAO,EAAE,CAAC,aAAa,GAAG,KAAK,MAAM,EAAE,GAAG,CAChE,KAAK,GAAG;AAEX,YAAO,eAAe,WAAW,SAAS,YAAY,mDAAmD,WAAW,OAAO,WAAW;MACtI,CACD,KAAK,KAAK;IACb,YAAY;IACb;GACD,QAAQ;IACN,eAAe;IAEf,GAAG;IACH,GAAG,eAAe;IACnB;GACD,OAAO;IACL,GAAG;IACH,GAAG,eAAe;IACnB;GACD,GAAG;GACH,SAAS,CAAC,sBAAsB,GAAI,eAAe,WAAW,EAAE,CAAE;GACnE;AAED,SAAO,UAAU,WAAW;EAC5B,MAAM,SAAS,MAAM,MAAM,aAAa;AACxC,SAAO,UAAU,UAAU;AAC3B,SAAO;UACA,OAAO;AACd,SAAO,SAAS,MAAM;AACtB,QAAM;WACE;AAER,QAAM,GAAG,SAAS;GAAE,WAAW;GAAM,OAAO;GAAM,CAAC"}
@@ -38,6 +38,21 @@ const loadExternalFileSync = (filePath, options) => {
38
38
  logger([`Error: ${error.message} - `, JSON.stringify(error.stack, null, 2)], { level: "error" });
39
39
  }
40
40
  };
41
+ const withPreloadedGlobals = (globals, fn) => {
42
+ if (!globals) return fn();
43
+ const globalVars = globalThis;
44
+ const prev = {};
45
+ for (const [key, value] of Object.entries(globals)) {
46
+ prev[key] = globalVars[key];
47
+ globalVars[key] = value;
48
+ }
49
+ try {
50
+ return fn();
51
+ } finally {
52
+ for (const key of Object.keys(globals)) if (prev[key] !== void 0) globalVars[key] = prev[key];
53
+ else delete globalVars[key];
54
+ }
55
+ };
41
56
  /**
42
57
  * Load the content declaration from the given path
43
58
  *
@@ -52,13 +67,13 @@ const loadExternalFile = async (filePath, options) => {
52
67
  logger("File could not be loaded.", { level: "error" });
53
68
  return;
54
69
  }
55
- const fileContent = parseFileContent(moduleResultString, {
70
+ const fileContent = withPreloadedGlobals(options?.preloadGlobals, () => parseFileContent(moduleResultString, {
56
71
  projectRequire: options?.projectRequire,
57
72
  envVarOptions: options?.envVarOptions,
58
73
  additionalEnvVars: options?.additionalEnvVars,
59
74
  mocks: options?.mocks,
60
75
  aliases: options?.aliases
61
- });
76
+ }));
62
77
  if (typeof fileContent === "undefined") {
63
78
  logger(`File could not be loaded. Path : ${colorizePath(filePath)}`);
64
79
  return;
@@ -1 +1 @@
1
- {"version":3,"file":"loadExternalFile.mjs","names":[],"sources":["../../../src/loadExternalFile/loadExternalFile.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { extname } from 'node:path';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport JSON5 from 'json5';\nimport { colorizePath, logger } from '../logger';\nimport {\n parseFileContent,\n type SandBoxContextOptions,\n} from './parseFileContent';\nimport {\n type TranspileOptions,\n transpileTSToCJS,\n transpileTSToCJSSync,\n} from './transpileTSToCJS';\n\n// CJS MJS cross usage\nconst parseJSON5 = JSON5.parse || (JSON5 as any).default?.parse;\n\nexport type LoadExternalFileOptions = {\n configuration?: IntlayerConfig;\n buildOptions?: TranspileOptions;\n logError?: boolean;\n} & SandBoxContextOptions;\n\n/**\n * Load the content declaration from the given path\n *\n * Accepts JSON, JS, MJS and TS files as configuration\n */\nexport const loadExternalFileSync = (\n filePath: string,\n options?: LoadExternalFileOptions\n): any | undefined => {\n const fileExtension = extname(filePath) || '.json';\n\n try {\n if (\n fileExtension === '.json' ||\n fileExtension === '.json5' ||\n fileExtension === '.jsonc'\n ) {\n // Assume JSON\n return parseJSON5(readFileSync(filePath, 'utf-8'));\n }\n\n // Rest is JS, MJS or TS\n const code = readFileSync(filePath, 'utf-8');\n\n const moduleResultString: string | undefined = transpileTSToCJSSync(\n code,\n filePath,\n options?.buildOptions\n );\n\n if (!moduleResultString) {\n logger('File could not be loaded.', { level: 'error' });\n return undefined;\n }\n\n const fileContent = parseFileContent(moduleResultString, {\n projectRequire: options?.projectRequire,\n envVarOptions: options?.envVarOptions,\n additionalEnvVars: options?.additionalEnvVars,\n mocks: options?.mocks,\n aliases: options?.aliases,\n });\n\n if (typeof fileContent === 'undefined') {\n logger(`File could not be loaded. Path : ${filePath}`);\n return undefined;\n }\n\n return fileContent;\n } catch (error) {\n logger(\n [\n `Error: ${(error as Error).message} - `,\n JSON.stringify((error as Error).stack, null, 2),\n ],\n {\n level: 'error',\n }\n );\n }\n};\n\n/**\n * Load the content declaration from the given path\n *\n * Accepts JSON, JS, MJS and TS files as configuration\n */\nexport const loadExternalFile = async (\n filePath: string,\n options?: LoadExternalFileOptions\n): Promise<any | undefined> => {\n const fileExtension = extname(filePath);\n\n try {\n if (\n fileExtension === '.json' ||\n fileExtension === '.json5' ||\n fileExtension === '.jsonc'\n ) {\n // Remove cache to force getting fresh content\n const fileContent = await readFile(filePath, 'utf-8');\n return parseJSON5(fileContent);\n }\n\n // Rest is JS, MJS or TS\n const code = await readFile(filePath, 'utf-8');\n\n const moduleResultString: string | undefined = await transpileTSToCJS(\n code,\n filePath,\n options?.buildOptions\n );\n\n if (!moduleResultString) {\n logger('File could not be loaded.', { level: 'error' });\n return undefined;\n }\n\n const fileContent = parseFileContent(moduleResultString, {\n projectRequire: options?.projectRequire,\n envVarOptions: options?.envVarOptions,\n additionalEnvVars: options?.additionalEnvVars,\n mocks: options?.mocks,\n aliases: options?.aliases,\n });\n\n if (typeof fileContent === 'undefined') {\n logger(`File could not be loaded. Path : ${colorizePath(filePath)}`);\n return undefined;\n }\n\n return fileContent;\n } catch (error) {\n if (options?.logError ?? true) {\n logger(\n [\n `Error: ${(error as Error).message} - `,\n JSON.stringify((error as Error).stack, null, 2),\n ],\n {\n level: 'error',\n }\n );\n }\n }\n};\n"],"mappings":";;;;;;;;;AAiBA,MAAM,aAAa,MAAM,SAAU,MAAc,SAAS;;;;;;AAa1D,MAAa,wBACX,UACA,YACoB;CACpB,MAAM,gBAAgB,QAAQ,SAAS,IAAI;AAE3C,KAAI;AACF,MACE,kBAAkB,WAClB,kBAAkB,YAClB,kBAAkB,SAGlB,QAAO,WAAW,aAAa,UAAU,QAAQ,CAAC;EAMpD,MAAM,qBAAyC,qBAFlC,aAAa,UAAU,QAG9B,EACJ,UACA,SAAS,aACV;AAED,MAAI,CAAC,oBAAoB;AACvB,UAAO,6BAA6B,EAAE,OAAO,SAAS,CAAC;AACvD;;EAGF,MAAM,cAAc,iBAAiB,oBAAoB;GACvD,gBAAgB,SAAS;GACzB,eAAe,SAAS;GACxB,mBAAmB,SAAS;GAC5B,OAAO,SAAS;GAChB,SAAS,SAAS;GACnB,CAAC;AAEF,MAAI,OAAO,gBAAgB,aAAa;AACtC,UAAO,oCAAoC,WAAW;AACtD;;AAGF,SAAO;UACA,OAAO;AACd,SACE,CACE,UAAW,MAAgB,QAAQ,MACnC,KAAK,UAAW,MAAgB,OAAO,MAAM,EAAE,CAChD,EACD,EACE,OAAO,SACR,CACF;;;;;;;;AASL,MAAa,mBAAmB,OAC9B,UACA,YAC6B;CAC7B,MAAM,gBAAgB,QAAQ,SAAS;AAEvC,KAAI;AACF,MACE,kBAAkB,WAClB,kBAAkB,YAClB,kBAAkB,SAIlB,QAAO,WAAW,MADQ,SAAS,UAAU,QAAQ,CACvB;EAMhC,MAAM,qBAAyC,MAAM,iBACnD,MAHiB,SAAS,UAAU,QAAQ,EAI5C,UACA,SAAS,aACV;AAED,MAAI,CAAC,oBAAoB;AACvB,UAAO,6BAA6B,EAAE,OAAO,SAAS,CAAC;AACvD;;EAGF,MAAM,cAAc,iBAAiB,oBAAoB;GACvD,gBAAgB,SAAS;GACzB,eAAe,SAAS;GACxB,mBAAmB,SAAS;GAC5B,OAAO,SAAS;GAChB,SAAS,SAAS;GACnB,CAAC;AAEF,MAAI,OAAO,gBAAgB,aAAa;AACtC,UAAO,oCAAoC,aAAa,SAAS,GAAG;AACpE;;AAGF,SAAO;UACA,OAAO;AACd,MAAI,SAAS,YAAY,KACvB,QACE,CACE,UAAW,MAAgB,QAAQ,MACnC,KAAK,UAAW,MAAgB,OAAO,MAAM,EAAE,CAChD,EACD,EACE,OAAO,SACR,CACF"}
1
+ {"version":3,"file":"loadExternalFile.mjs","names":[],"sources":["../../../src/loadExternalFile/loadExternalFile.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { extname } from 'node:path';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport JSON5 from 'json5';\nimport { colorizePath, logger } from '../logger';\nimport {\n parseFileContent,\n type SandBoxContextOptions,\n} from './parseFileContent';\nimport {\n type TranspileOptions,\n transpileTSToCJS,\n transpileTSToCJSSync,\n} from './transpileTSToCJS';\n\n// CJS MJS cross usage\nconst parseJSON5 = JSON5.parse || (JSON5 as any).default?.parse;\n\nexport type LoadExternalFileOptions = {\n configuration?: IntlayerConfig;\n buildOptions?: TranspileOptions;\n logError?: boolean;\n /**\n * Key-value pairs to temporarily set on the main Node.js `globalThis` for the\n * synchronous duration of `parseFileContent` / `runInNewContext`. External modules\n * loaded via `require()` inside the VM (e.g. `@intlayer/core`'s `file()` helper)\n * run in the main context and read from the real `globalThis`, not the VM sandbox.\n * Values are restored (or deleted) after `runInNewContext` returns.\n */\n preloadGlobals?: Record<string, unknown>;\n} & SandBoxContextOptions;\n\n/**\n * Load the content declaration from the given path\n *\n * Accepts JSON, JS, MJS and TS files as configuration\n */\nexport const loadExternalFileSync = (\n filePath: string,\n options?: LoadExternalFileOptions\n): any | undefined => {\n const fileExtension = extname(filePath) || '.json';\n\n try {\n if (\n fileExtension === '.json' ||\n fileExtension === '.json5' ||\n fileExtension === '.jsonc'\n ) {\n // Assume JSON\n return parseJSON5(readFileSync(filePath, 'utf-8'));\n }\n\n // Rest is JS, MJS or TS\n const code = readFileSync(filePath, 'utf-8');\n\n const moduleResultString: string | undefined = transpileTSToCJSSync(\n code,\n filePath,\n options?.buildOptions\n );\n\n if (!moduleResultString) {\n logger('File could not be loaded.', { level: 'error' });\n return undefined;\n }\n\n const fileContent = parseFileContent(moduleResultString, {\n projectRequire: options?.projectRequire,\n envVarOptions: options?.envVarOptions,\n additionalEnvVars: options?.additionalEnvVars,\n mocks: options?.mocks,\n aliases: options?.aliases,\n });\n\n if (typeof fileContent === 'undefined') {\n logger(`File could not be loaded. Path : ${filePath}`);\n return undefined;\n }\n\n return fileContent;\n } catch (error) {\n logger(\n [\n `Error: ${(error as Error).message} - `,\n JSON.stringify((error as Error).stack, null, 2),\n ],\n {\n level: 'error',\n }\n );\n }\n};\n\nconst withPreloadedGlobals = <T>(\n globals: Record<string, unknown> | undefined,\n fn: () => T\n): T => {\n if (!globals) return fn();\n\n const globalVars = globalThis as Record<string, unknown>;\n const prev: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(globals)) {\n prev[key] = globalVars[key];\n globalVars[key] = value;\n }\n\n try {\n return fn();\n } finally {\n for (const key of Object.keys(globals)) {\n if (prev[key] !== undefined) {\n globalVars[key] = prev[key];\n } else {\n delete globalVars[key];\n }\n }\n }\n};\n\n/**\n * Load the content declaration from the given path\n *\n * Accepts JSON, JS, MJS and TS files as configuration\n */\nexport const loadExternalFile = async (\n filePath: string,\n options?: LoadExternalFileOptions\n): Promise<any | undefined> => {\n const fileExtension = extname(filePath);\n\n try {\n if (\n fileExtension === '.json' ||\n fileExtension === '.json5' ||\n fileExtension === '.jsonc'\n ) {\n // Remove cache to force getting fresh content\n const fileContent = await readFile(filePath, 'utf-8');\n return parseJSON5(fileContent);\n }\n\n // Rest is JS, MJS or TS\n const code = await readFile(filePath, 'utf-8');\n\n const moduleResultString: string | undefined = await transpileTSToCJS(\n code,\n filePath,\n options?.buildOptions\n );\n\n if (!moduleResultString) {\n logger('File could not be loaded.', { level: 'error' });\n return undefined;\n }\n\n // parseFileContent/runInNewContext is synchronous, so withPreloadedGlobals\n // has no interleaving risk even when multiple files are processed concurrently.\n const fileContent = withPreloadedGlobals(options?.preloadGlobals, () =>\n parseFileContent(moduleResultString, {\n projectRequire: options?.projectRequire,\n envVarOptions: options?.envVarOptions,\n additionalEnvVars: options?.additionalEnvVars,\n mocks: options?.mocks,\n aliases: options?.aliases,\n })\n );\n\n if (typeof fileContent === 'undefined') {\n logger(`File could not be loaded. Path : ${colorizePath(filePath)}`);\n return undefined;\n }\n\n return fileContent;\n } catch (error) {\n if (options?.logError ?? true) {\n logger(\n [\n `Error: ${(error as Error).message} - `,\n JSON.stringify((error as Error).stack, null, 2),\n ],\n {\n level: 'error',\n }\n );\n }\n }\n};\n"],"mappings":";;;;;;;;;AAiBA,MAAM,aAAa,MAAM,SAAU,MAAc,SAAS;;;;;;AAqB1D,MAAa,wBACX,UACA,YACoB;CACpB,MAAM,gBAAgB,QAAQ,SAAS,IAAI;AAE3C,KAAI;AACF,MACE,kBAAkB,WAClB,kBAAkB,YAClB,kBAAkB,SAGlB,QAAO,WAAW,aAAa,UAAU,QAAQ,CAAC;EAMpD,MAAM,qBAAyC,qBAFlC,aAAa,UAAU,QAG9B,EACJ,UACA,SAAS,aACV;AAED,MAAI,CAAC,oBAAoB;AACvB,UAAO,6BAA6B,EAAE,OAAO,SAAS,CAAC;AACvD;;EAGF,MAAM,cAAc,iBAAiB,oBAAoB;GACvD,gBAAgB,SAAS;GACzB,eAAe,SAAS;GACxB,mBAAmB,SAAS;GAC5B,OAAO,SAAS;GAChB,SAAS,SAAS;GACnB,CAAC;AAEF,MAAI,OAAO,gBAAgB,aAAa;AACtC,UAAO,oCAAoC,WAAW;AACtD;;AAGF,SAAO;UACA,OAAO;AACd,SACE,CACE,UAAW,MAAgB,QAAQ,MACnC,KAAK,UAAW,MAAgB,OAAO,MAAM,EAAE,CAChD,EACD,EACE,OAAO,SACR,CACF;;;AAIL,MAAM,wBACJ,SACA,OACM;AACN,KAAI,CAAC,QAAS,QAAO,IAAI;CAEzB,MAAM,aAAa;CACnB,MAAM,OAAgC,EAAE;AAExC,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,EAAE;AAClD,OAAK,OAAO,WAAW;AACvB,aAAW,OAAO;;AAGpB,KAAI;AACF,SAAO,IAAI;WACH;AACR,OAAK,MAAM,OAAO,OAAO,KAAK,QAAQ,CACpC,KAAI,KAAK,SAAS,OAChB,YAAW,OAAO,KAAK;MAEvB,QAAO,WAAW;;;;;;;;AAW1B,MAAa,mBAAmB,OAC9B,UACA,YAC6B;CAC7B,MAAM,gBAAgB,QAAQ,SAAS;AAEvC,KAAI;AACF,MACE,kBAAkB,WAClB,kBAAkB,YAClB,kBAAkB,SAIlB,QAAO,WAAW,MADQ,SAAS,UAAU,QAAQ,CACvB;EAMhC,MAAM,qBAAyC,MAAM,iBACnD,MAHiB,SAAS,UAAU,QAAQ,EAI5C,UACA,SAAS,aACV;AAED,MAAI,CAAC,oBAAoB;AACvB,UAAO,6BAA6B,EAAE,OAAO,SAAS,CAAC;AACvD;;EAKF,MAAM,cAAc,qBAAqB,SAAS,sBAChD,iBAAiB,oBAAoB;GACnC,gBAAgB,SAAS;GACzB,eAAe,SAAS;GACxB,mBAAmB,SAAS;GAC5B,OAAO,SAAS;GAChB,SAAS,SAAS;GACnB,CAAC,CACH;AAED,MAAI,OAAO,gBAAgB,aAAa;AACtC,UAAO,oCAAoC,aAAa,SAAS,GAAG;AACpE;;AAGF,SAAO;UACA,OAAO;AACd,MAAI,SAAS,YAAY,KACvB,QACE,CACE,UAAW,MAAgB,QAAQ,MACnC,KAAK,UAAW,MAAgB,OAAO,MAAM,EAAE,CAChD,EACD,EACE,OAAO,SACR,CACF"}
@@ -4,6 +4,26 @@ import { runInNewContext } from "node:vm";
4
4
  import * as esbuild from "esbuild";
5
5
 
6
6
  //#region src/loadExternalFile/parseFileContent.ts
7
+ const NODE_GLOBALS = [
8
+ "Buffer",
9
+ "setTimeout",
10
+ "clearTimeout",
11
+ "setInterval",
12
+ "clearInterval",
13
+ "setImmediate",
14
+ "clearImmediate",
15
+ "queueMicrotask",
16
+ "URL",
17
+ "URLSearchParams",
18
+ "TextEncoder",
19
+ "TextDecoder",
20
+ "AbortController",
21
+ "AbortSignal",
22
+ "performance",
23
+ "fetch",
24
+ "crypto",
25
+ "structuredClone"
26
+ ];
7
27
  const getSandBoxContext = (options) => {
8
28
  const { envVarOptions, projectRequire, additionalEnvVars, mocks, aliases } = options ?? {};
9
29
  let additionalGlobalVar = {};
@@ -52,9 +72,7 @@ const getSandBoxContext = (options) => {
52
72
  require: mockedRequire,
53
73
  ...additionalGlobalVar
54
74
  };
55
- Object.getOwnPropertyNames(globalThis).forEach((key) => {
56
- if (!(key in sandboxContext)) sandboxContext[key] = globalThis[key];
57
- });
75
+ for (const key of NODE_GLOBALS) if (!(key in sandboxContext) && key in globalThis) sandboxContext[key] = globalThis[key];
58
76
  return sandboxContext;
59
77
  };
60
78
  const parseFileContent = (fileContentString, options) => {
@@ -66,7 +84,17 @@ const parseFileContent = (fileContentString, options) => {
66
84
  sandboxContext.module?.exports?.default,
67
85
  sandboxContext.module?.exports
68
86
  ];
69
- for (const candidate of candidates) if (candidate && typeof candidate === "object" && Object.keys(candidate).length > 0) return candidate;
87
+ let result;
88
+ for (const candidate of candidates) if (candidate && typeof candidate === "object" && Object.keys(candidate).length > 0) {
89
+ result = candidate;
90
+ break;
91
+ }
92
+ sandboxContext.require = void 0;
93
+ sandboxContext.process = void 0;
94
+ sandboxContext.React = void 0;
95
+ sandboxContext.module = void 0;
96
+ sandboxContext.exports = void 0;
97
+ return result;
70
98
  };
71
99
 
72
100
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"parseFileContent.mjs","names":[],"sources":["../../../src/loadExternalFile/parseFileContent.ts"],"sourcesContent":["import { type Context, runInNewContext } from 'node:vm';\nimport * as esbuild from 'esbuild';\nimport { type LoadEnvFileOptions, loadEnvFile } from '../loadEnvFile';\nimport { getProjectRequire } from '../utils/ESMxCJSHelpers';\n\nexport type SandBoxContextOptions = {\n envVarOptions?: LoadEnvFileOptions;\n projectRequire?: NodeJS.Require;\n additionalEnvVars?: Record<string, string>;\n /**\n * Map of specifier -> mocked export to be returned when code in the VM calls require(specifier).\n * Example:\n * mocks: {\n * '@intlayer/config/built': { getConfig: () => ({}), Locales: {} }\n * }\n */\n mocks?: Record<string, any>;\n /**\n * Optional alias map if you want to redirect specifiers.\n * Useful when user code imports a subpath you want to collapse.\n * Example:\n * aliases: { '@intlayer/config/built': '@intlayer/config' }\n */\n aliases?: Record<string, string>;\n};\n\nexport const getSandBoxContext = (options?: SandBoxContextOptions): Context => {\n const { envVarOptions, projectRequire, additionalEnvVars, mocks, aliases } =\n options ?? {};\n\n let additionalGlobalVar = {};\n\n const baseRequire: NodeJS.Require =\n typeof projectRequire === 'function' ? projectRequire : getProjectRequire();\n\n // Wrap require to honor mocks and aliases inside the VM\n const mockedRequire: NodeJS.Require = (() => {\n const mockTable = Object.assign(\n {\n esbuild,\n },\n mocks\n );\n const aliasTable = Object.assign({}, aliases);\n\n const wrappedRequire = function mockableRequire(id: string) {\n const target = aliasTable?.[id] ? aliasTable[id] : id;\n\n if (mockTable && Object.hasOwn(mockTable, target)) {\n return mockTable[target];\n }\n\n // If the original id was aliased, allow mocks to be defined on either key.\n if (target !== id && mockTable && Object.hasOwn(mockTable, id)) {\n return mockTable[id];\n }\n\n return baseRequire(target);\n } as NodeJS.Require;\n\n // Mirror NodeJS.Require properties\n wrappedRequire.resolve = baseRequire.resolve.bind(baseRequire);\n wrappedRequire.main = baseRequire.main;\n wrappedRequire.extensions = baseRequire.extensions;\n wrappedRequire.cache = baseRequire.cache;\n\n return wrappedRequire;\n })();\n\n try {\n // Dynamically try to require React if it's installed in the project\n additionalGlobalVar = {\n React: baseRequire('react'),\n };\n } catch (_err) {\n // React is not installed, so we inject a dummy React object to capture JSX elements\n // This allows using JSX in content declarations even if React is not installed (e.g. in Solid.js or Vue projects)\n // because esbuild's tsx loader defaults to React.createElement.\n additionalGlobalVar = {\n React: {\n createElement: (type: any, props: any, ...children: any[]) => ({\n type,\n props: {\n ...props,\n children: children.length <= 1 ? children[0] : children,\n },\n }),\n Fragment: Symbol.for('react.fragment'),\n },\n };\n }\n\n const sandboxContext: Context = {\n exports: {\n default: {},\n },\n module: {\n exports: {},\n },\n process: {\n ...process,\n env: {\n ...process.env,\n ...loadEnvFile(envVarOptions),\n ...additionalEnvVars,\n },\n },\n console,\n require: mockedRequire,\n ...additionalGlobalVar,\n };\n\n // Dynamically inject all global variables\n Object.getOwnPropertyNames(globalThis).forEach((key) => {\n if (!(key in sandboxContext)) {\n sandboxContext[key] = globalThis[key as keyof typeof globalThis];\n }\n });\n\n return sandboxContext;\n};\n\nexport const parseFileContent = <T>(\n fileContentString: string,\n options?: SandBoxContextOptions\n): T | undefined => {\n const sandboxContext = getSandBoxContext(options);\n\n // Force strict mode so illegal writes throw instead of silently failing.\n runInNewContext(`\"use strict\";\\n${fileContentString}`, sandboxContext);\n\n const candidates: unknown[] = [\n sandboxContext.exports?.default,\n sandboxContext.module?.exports?.defaults,\n sandboxContext.module?.exports?.default,\n sandboxContext.module?.exports,\n ];\n\n for (const candidate of candidates) {\n if (\n candidate &&\n typeof candidate === 'object' &&\n Object.keys(candidate as object).length > 0\n ) {\n return candidate as T;\n }\n }\n};\n"],"mappings":";;;;;;AA0BA,MAAa,qBAAqB,YAA6C;CAC7E,MAAM,EAAE,eAAe,gBAAgB,mBAAmB,OAAO,YAC/D,WAAW,EAAE;CAEf,IAAI,sBAAsB,EAAE;CAE5B,MAAM,cACJ,OAAO,mBAAmB,aAAa,iBAAiB,mBAAmB;CAG7E,MAAM,uBAAuC;EAC3C,MAAM,YAAY,OAAO,OACvB,EACE,SACD,EACD,MACD;EACD,MAAM,aAAa,OAAO,OAAO,EAAE,EAAE,QAAQ;EAE7C,MAAM,iBAAiB,SAAS,gBAAgB,IAAY;GAC1D,MAAM,SAAS,aAAa,MAAM,WAAW,MAAM;AAEnD,OAAI,aAAa,OAAO,OAAO,WAAW,OAAO,CAC/C,QAAO,UAAU;AAInB,OAAI,WAAW,MAAM,aAAa,OAAO,OAAO,WAAW,GAAG,CAC5D,QAAO,UAAU;AAGnB,UAAO,YAAY,OAAO;;AAI5B,iBAAe,UAAU,YAAY,QAAQ,KAAK,YAAY;AAC9D,iBAAe,OAAO,YAAY;AAClC,iBAAe,aAAa,YAAY;AACxC,iBAAe,QAAQ,YAAY;AAEnC,SAAO;KACL;AAEJ,KAAI;AAEF,wBAAsB,EACpB,OAAO,YAAY,QAAQ,EAC5B;UACM,MAAM;AAIb,wBAAsB,EACpB,OAAO;GACL,gBAAgB,MAAW,OAAY,GAAG,cAAqB;IAC7D;IACA,OAAO;KACL,GAAG;KACH,UAAU,SAAS,UAAU,IAAI,SAAS,KAAK;KAChD;IACF;GACD,UAAU,OAAO,IAAI,iBAAiB;GACvC,EACF;;CAGH,MAAM,iBAA0B;EAC9B,SAAS,EACP,SAAS,EAAE,EACZ;EACD,QAAQ,EACN,SAAS,EAAE,EACZ;EACD,SAAS;GACP,GAAG;GACH,KAAK;IACH,GAAG,QAAQ;IACX,GAAG,YAAY,cAAc;IAC7B,GAAG;IACJ;GACF;EACD;EACA,SAAS;EACT,GAAG;EACJ;AAGD,QAAO,oBAAoB,WAAW,CAAC,SAAS,QAAQ;AACtD,MAAI,EAAE,OAAO,gBACX,gBAAe,OAAO,WAAW;GAEnC;AAEF,QAAO;;AAGT,MAAa,oBACX,mBACA,YACkB;CAClB,MAAM,iBAAiB,kBAAkB,QAAQ;AAGjD,iBAAgB,kBAAkB,qBAAqB,eAAe;CAEtE,MAAM,aAAwB;EAC5B,eAAe,SAAS;EACxB,eAAe,QAAQ,SAAS;EAChC,eAAe,QAAQ,SAAS;EAChC,eAAe,QAAQ;EACxB;AAED,MAAK,MAAM,aAAa,WACtB,KACE,aACA,OAAO,cAAc,YACrB,OAAO,KAAK,UAAoB,CAAC,SAAS,EAE1C,QAAO"}
1
+ {"version":3,"file":"parseFileContent.mjs","names":[],"sources":["../../../src/loadExternalFile/parseFileContent.ts"],"sourcesContent":["import { type Context, runInNewContext } from 'node:vm';\nimport * as esbuild from 'esbuild';\nimport { type LoadEnvFileOptions, loadEnvFile } from '../loadEnvFile';\nimport { getProjectRequire } from '../utils/ESMxCJSHelpers';\n\nexport type SandBoxContextOptions = {\n envVarOptions?: LoadEnvFileOptions;\n projectRequire?: NodeJS.Require;\n additionalEnvVars?: Record<string, string>;\n /**\n * Map of specifier -> mocked export to be returned when code in the VM calls require(specifier).\n * Example:\n * mocks: {\n * '@intlayer/config/built': { getConfig: () => ({}), Locales: {} }\n * }\n */\n mocks?: Record<string, any>;\n /**\n * Optional alias map if you want to redirect specifiers.\n * Useful when user code imports a subpath you want to collapse.\n * Example:\n * aliases: { '@intlayer/config/built': '@intlayer/config' }\n */\n aliases?: Record<string, string>;\n};\n\n// Inject only Node.js-specific globals that are absent from a plain V8 context.\n// JS built-ins (Object, Array, Promise, Math, Date, JSON, Symbol, etc.) are\n// provided automatically by runInNewContext — no need to copy them.\n// Copying all of globalThis would retain hundreds of references (including the\n// full module cache via `global`) inside every sandbox, causing a memory leak.\nconst NODE_GLOBALS = [\n 'Buffer',\n 'setTimeout',\n 'clearTimeout',\n 'setInterval',\n 'clearInterval',\n 'setImmediate',\n 'clearImmediate',\n 'queueMicrotask',\n 'URL',\n 'URLSearchParams',\n 'TextEncoder',\n 'TextDecoder',\n 'AbortController',\n 'AbortSignal',\n 'performance',\n 'fetch',\n 'crypto',\n 'structuredClone',\n] as const;\n\nexport const getSandBoxContext = (options?: SandBoxContextOptions): Context => {\n const { envVarOptions, projectRequire, additionalEnvVars, mocks, aliases } =\n options ?? {};\n\n let additionalGlobalVar = {};\n\n const baseRequire: NodeJS.Require =\n typeof projectRequire === 'function' ? projectRequire : getProjectRequire();\n\n // Wrap require to honor mocks and aliases inside the VM\n const mockedRequire: NodeJS.Require = (() => {\n const mockTable = Object.assign(\n {\n esbuild,\n },\n mocks\n );\n const aliasTable = Object.assign({}, aliases);\n\n const wrappedRequire = function mockableRequire(id: string) {\n const target = aliasTable?.[id] ? aliasTable[id] : id;\n\n if (mockTable && Object.hasOwn(mockTable, target)) {\n return mockTable[target];\n }\n\n // If the original id was aliased, allow mocks to be defined on either key.\n if (target !== id && mockTable && Object.hasOwn(mockTable, id)) {\n return mockTable[id];\n }\n\n return baseRequire(target);\n } as NodeJS.Require;\n\n // Mirror NodeJS.Require properties\n wrappedRequire.resolve = baseRequire.resolve.bind(baseRequire);\n wrappedRequire.main = baseRequire.main;\n wrappedRequire.extensions = baseRequire.extensions;\n wrappedRequire.cache = baseRequire.cache;\n\n return wrappedRequire;\n })();\n\n try {\n // Dynamically try to require React if it's installed in the project\n additionalGlobalVar = {\n React: baseRequire('react'),\n };\n } catch (_err) {\n // React is not installed, so we inject a dummy React object to capture JSX elements\n // This allows using JSX in content declarations even if React is not installed (e.g. in Solid.js or Vue projects)\n // because esbuild's tsx loader defaults to React.createElement.\n additionalGlobalVar = {\n React: {\n createElement: (type: any, props: any, ...children: any[]) => ({\n type,\n props: {\n ...props,\n children: children.length <= 1 ? children[0] : children,\n },\n }),\n Fragment: Symbol.for('react.fragment'),\n },\n };\n }\n\n const sandboxContext: Context = {\n exports: {\n default: {},\n },\n module: {\n exports: {},\n },\n process: {\n ...process,\n env: {\n ...process.env,\n ...loadEnvFile(envVarOptions),\n ...additionalEnvVars,\n },\n },\n console,\n require: mockedRequire,\n ...additionalGlobalVar,\n };\n\n for (const key of NODE_GLOBALS) {\n if (!(key in sandboxContext) && key in globalThis) {\n (sandboxContext as Record<string, unknown>)[key] =\n globalThis[key as keyof typeof globalThis];\n }\n }\n\n return sandboxContext;\n};\n\nexport const parseFileContent = <T>(\n fileContentString: string,\n options?: SandBoxContextOptions\n): T | undefined => {\n const sandboxContext = getSandBoxContext(options);\n\n // Force strict mode so illegal writes throw instead of silently failing.\n runInNewContext(`\"use strict\";\\n${fileContentString}`, sandboxContext);\n\n const candidates: unknown[] = [\n sandboxContext.exports?.default,\n sandboxContext.module?.exports?.defaults,\n sandboxContext.module?.exports?.default,\n sandboxContext.module?.exports,\n ];\n\n let result: T | undefined;\n for (const candidate of candidates) {\n if (\n candidate &&\n typeof candidate === 'object' &&\n Object.keys(candidate as object).length > 0\n ) {\n result = candidate as T;\n break;\n }\n }\n\n // Drop heavy references so the V8 context created by runInNewContext can be\n // garbage-collected promptly. The extracted `result` is a plain data object\n // and does not retain the sandbox.\n (sandboxContext as Record<string, unknown>).require = undefined;\n (sandboxContext as Record<string, unknown>).process = undefined;\n (sandboxContext as Record<string, unknown>).React = undefined;\n (sandboxContext as Record<string, unknown>).module = undefined;\n (sandboxContext as Record<string, unknown>).exports = undefined;\n\n return result;\n};\n"],"mappings":";;;;;;AA+BA,MAAM,eAAe;CACnB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAED,MAAa,qBAAqB,YAA6C;CAC7E,MAAM,EAAE,eAAe,gBAAgB,mBAAmB,OAAO,YAC/D,WAAW,EAAE;CAEf,IAAI,sBAAsB,EAAE;CAE5B,MAAM,cACJ,OAAO,mBAAmB,aAAa,iBAAiB,mBAAmB;CAG7E,MAAM,uBAAuC;EAC3C,MAAM,YAAY,OAAO,OACvB,EACE,SACD,EACD,MACD;EACD,MAAM,aAAa,OAAO,OAAO,EAAE,EAAE,QAAQ;EAE7C,MAAM,iBAAiB,SAAS,gBAAgB,IAAY;GAC1D,MAAM,SAAS,aAAa,MAAM,WAAW,MAAM;AAEnD,OAAI,aAAa,OAAO,OAAO,WAAW,OAAO,CAC/C,QAAO,UAAU;AAInB,OAAI,WAAW,MAAM,aAAa,OAAO,OAAO,WAAW,GAAG,CAC5D,QAAO,UAAU;AAGnB,UAAO,YAAY,OAAO;;AAI5B,iBAAe,UAAU,YAAY,QAAQ,KAAK,YAAY;AAC9D,iBAAe,OAAO,YAAY;AAClC,iBAAe,aAAa,YAAY;AACxC,iBAAe,QAAQ,YAAY;AAEnC,SAAO;KACL;AAEJ,KAAI;AAEF,wBAAsB,EACpB,OAAO,YAAY,QAAQ,EAC5B;UACM,MAAM;AAIb,wBAAsB,EACpB,OAAO;GACL,gBAAgB,MAAW,OAAY,GAAG,cAAqB;IAC7D;IACA,OAAO;KACL,GAAG;KACH,UAAU,SAAS,UAAU,IAAI,SAAS,KAAK;KAChD;IACF;GACD,UAAU,OAAO,IAAI,iBAAiB;GACvC,EACF;;CAGH,MAAM,iBAA0B;EAC9B,SAAS,EACP,SAAS,EAAE,EACZ;EACD,QAAQ,EACN,SAAS,EAAE,EACZ;EACD,SAAS;GACP,GAAG;GACH,KAAK;IACH,GAAG,QAAQ;IACX,GAAG,YAAY,cAAc;IAC7B,GAAG;IACJ;GACF;EACD;EACA,SAAS;EACT,GAAG;EACJ;AAED,MAAK,MAAM,OAAO,aAChB,KAAI,EAAE,OAAO,mBAAmB,OAAO,WACrC,CAAC,eAA2C,OAC1C,WAAW;AAIjB,QAAO;;AAGT,MAAa,oBACX,mBACA,YACkB;CAClB,MAAM,iBAAiB,kBAAkB,QAAQ;AAGjD,iBAAgB,kBAAkB,qBAAqB,eAAe;CAEtE,MAAM,aAAwB;EAC5B,eAAe,SAAS;EACxB,eAAe,QAAQ,SAAS;EAChC,eAAe,QAAQ,SAAS;EAChC,eAAe,QAAQ;EACxB;CAED,IAAI;AACJ,MAAK,MAAM,aAAa,WACtB,KACE,aACA,OAAO,cAAc,YACrB,OAAO,KAAK,UAAoB,CAAC,SAAS,GAC1C;AACA,WAAS;AACT;;AAOJ,CAAC,eAA2C,UAAU;AACtD,CAAC,eAA2C,UAAU;AACtD,CAAC,eAA2C,QAAQ;AACpD,CAAC,eAA2C,SAAS;AACrD,CAAC,eAA2C,UAAU;AAEtD,QAAO"}
@@ -2,7 +2,7 @@ import { getPackageJsonPath } from "../utils/getPackageJsonPath.mjs";
2
2
  import { getLoader } from "./bundleFile.mjs";
3
3
  import { existsSync } from "node:fs";
4
4
  import { dirname, extname, join } from "node:path";
5
- import { build, buildSync } from "esbuild";
5
+ import { buildSync, context } from "esbuild";
6
6
  import { pathToFileURL } from "node:url";
7
7
 
8
8
  //#region src/loadExternalFile/transpileTSToCJS.ts
@@ -51,7 +51,7 @@ const transpileTSToCJSSync = (code, filePath, options) => {
51
51
  const transpileTSToCJS = async (code, filePath, options) => {
52
52
  const loader = getLoader(extname(filePath));
53
53
  const { esbuildInstance, ...buildOptions } = options ?? {};
54
- return (await (esbuildInstance?.build ?? build)({
54
+ const ctx = await (esbuildInstance?.context ?? context)({
55
55
  stdin: {
56
56
  contents: code,
57
57
  loader,
@@ -60,7 +60,12 @@ const transpileTSToCJS = async (code, filePath, options) => {
60
60
  },
61
61
  ...getTransformationOptions(filePath),
62
62
  ...buildOptions
63
- })).outputFiles?.[0].text;
63
+ });
64
+ try {
65
+ return (await ctx.rebuild()).outputFiles?.[0].text;
66
+ } finally {
67
+ await ctx.dispose();
68
+ }
64
69
  };
65
70
 
66
71
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"transpileTSToCJS.mjs","names":[],"sources":["../../../src/loadExternalFile/transpileTSToCJS.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { dirname, extname, join } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport { type BuildOptions, type BuildResult, build, buildSync } from 'esbuild';\nimport { getPackageJsonPath } from '../utils/getPackageJsonPath';\nimport { getLoader } from './bundleFile';\n\nexport type TranspileOptions = BuildOptions & {\n /**\n * Optional custom esbuild instance to use for transpilation.\n * Useful in environments (e.g. VS Code extensions) where the bundled\n * esbuild binary may not match the host platform.\n * When provided, its `buildSync`/`build` methods are used instead of\n * the ones imported from the `esbuild` package.\n */\n esbuildInstance?: typeof import('esbuild');\n};\n\nconst getTsConfigPath = (filePath: string): string | undefined => {\n const tsconfigPath = join(\n getPackageJsonPath(dirname(filePath)).baseDir,\n 'tsconfig.json'\n );\n\n // Only return the tsconfig path if it exists\n return existsSync(tsconfigPath) ? tsconfigPath : undefined;\n};\n\nconst getTransformationOptions = (filePath: string): BuildOptions => ({\n loader: {\n '.js': 'js',\n '.jsx': 'jsx',\n '.mjs': 'js',\n '.ts': 'ts',\n '.tsx': 'tsx',\n '.cjs': 'js',\n '.json': 'json',\n '.md': 'text',\n '.mdx': 'text',\n },\n format: 'cjs',\n target: 'node20',\n platform: 'node',\n write: false,\n packages: 'external',\n bundle: true,\n tsconfig: getTsConfigPath(filePath),\n define: {\n 'import.meta.url': JSON.stringify(pathToFileURL(filePath).href),\n 'import.meta.env': 'process.env',\n },\n});\n\nexport const transpileTSToCJSSync = (\n code: string,\n filePath: string,\n options?: TranspileOptions\n): string | undefined => {\n const extension = extname(filePath);\n const loader = getLoader(extension);\n\n const { esbuildInstance, ...buildOptions } = options ?? {};\n const esbuildBuildSync = esbuildInstance?.buildSync ?? buildSync;\n\n const moduleResult: BuildResult = esbuildBuildSync({\n stdin: {\n contents: code,\n loader,\n resolveDir: dirname(filePath), // Add resolveDir to resolve imports relative to the file's location\n sourcefile: filePath, // Add sourcefile for better error messages\n },\n ...getTransformationOptions(filePath),\n ...buildOptions,\n });\n\n const moduleResultString = moduleResult.outputFiles?.[0].text;\n\n return moduleResultString;\n};\n\nexport const transpileTSToCJS = async (\n code: string,\n filePath: string,\n options?: TranspileOptions\n): Promise<string | undefined> => {\n const extension = extname(filePath);\n const loader = getLoader(extension);\n\n const { esbuildInstance, ...buildOptions } = options ?? {};\n const esbuildBuild = esbuildInstance?.build ?? build;\n\n const moduleResult: BuildResult = await esbuildBuild({\n stdin: {\n contents: code,\n loader,\n resolveDir: dirname(filePath), // Add resolveDir to resolve imports relative to the file's location\n sourcefile: filePath, // Add sourcefile for better error messages\n },\n ...getTransformationOptions(filePath),\n ...buildOptions,\n });\n\n const moduleResultString = moduleResult.outputFiles?.[0].text;\n\n return moduleResultString;\n};\n"],"mappings":";;;;;;;;AAkBA,MAAM,mBAAmB,aAAyC;CAChE,MAAM,eAAe,KACnB,mBAAmB,QAAQ,SAAS,CAAC,CAAC,SACtC,gBACD;AAGD,QAAO,WAAW,aAAa,GAAG,eAAe;;AAGnD,MAAM,4BAA4B,cAAoC;CACpE,QAAQ;EACN,OAAO;EACP,QAAQ;EACR,QAAQ;EACR,OAAO;EACP,QAAQ;EACR,QAAQ;EACR,SAAS;EACT,OAAO;EACP,QAAQ;EACT;CACD,QAAQ;CACR,QAAQ;CACR,UAAU;CACV,OAAO;CACP,UAAU;CACV,QAAQ;CACR,UAAU,gBAAgB,SAAS;CACnC,QAAQ;EACN,mBAAmB,KAAK,UAAU,cAAc,SAAS,CAAC,KAAK;EAC/D,mBAAmB;EACpB;CACF;AAED,MAAa,wBACX,MACA,UACA,YACuB;CAEvB,MAAM,SAAS,UADG,QAAQ,SACQ,CAAC;CAEnC,MAAM,EAAE,iBAAiB,GAAG,iBAAiB,WAAW,EAAE;AAgB1D,SAfyB,iBAAiB,aAAa,WAEJ;EACjD,OAAO;GACL,UAAU;GACV;GACA,YAAY,QAAQ,SAAS;GAC7B,YAAY;GACb;EACD,GAAG,yBAAyB,SAAS;EACrC,GAAG;EACJ,CAEsC,CAAC,cAAc,GAAG;;AAK3D,MAAa,mBAAmB,OAC9B,MACA,UACA,YACgC;CAEhC,MAAM,SAAS,UADG,QAAQ,SACQ,CAAC;CAEnC,MAAM,EAAE,iBAAiB,GAAG,iBAAiB,WAAW,EAAE;AAgB1D,SAF2B,OAbN,iBAAiB,SAAS,OAEM;EACnD,OAAO;GACL,UAAU;GACV;GACA,YAAY,QAAQ,SAAS;GAC7B,YAAY;GACb;EACD,GAAG,yBAAyB,SAAS;EACrC,GAAG;EACJ,CAAC,EAEsC,cAAc,GAAG"}
1
+ {"version":3,"file":"transpileTSToCJS.mjs","names":[],"sources":["../../../src/loadExternalFile/transpileTSToCJS.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { dirname, extname, join } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport {\n type BuildOptions,\n type BuildResult,\n buildSync,\n context,\n} from 'esbuild';\nimport { getPackageJsonPath } from '../utils/getPackageJsonPath';\nimport { getLoader } from './bundleFile';\n\nexport type TranspileOptions = BuildOptions & {\n /**\n * Optional custom esbuild instance to use for transpilation.\n * Useful in environments (e.g. VS Code extensions) where the bundled\n * esbuild binary may not match the host platform.\n * When provided, its `buildSync`/`build` methods are used instead of\n * the ones imported from the `esbuild` package.\n */\n esbuildInstance?: typeof import('esbuild');\n};\n\nconst getTsConfigPath = (filePath: string): string | undefined => {\n const tsconfigPath = join(\n getPackageJsonPath(dirname(filePath)).baseDir,\n 'tsconfig.json'\n );\n\n // Only return the tsconfig path if it exists\n return existsSync(tsconfigPath) ? tsconfigPath : undefined;\n};\n\nconst getTransformationOptions = (filePath: string): BuildOptions => ({\n loader: {\n '.js': 'js',\n '.jsx': 'jsx',\n '.mjs': 'js',\n '.ts': 'ts',\n '.tsx': 'tsx',\n '.cjs': 'js',\n '.json': 'json',\n '.md': 'text',\n '.mdx': 'text',\n },\n format: 'cjs',\n target: 'node20',\n platform: 'node',\n write: false,\n packages: 'external',\n bundle: true,\n tsconfig: getTsConfigPath(filePath),\n define: {\n 'import.meta.url': JSON.stringify(pathToFileURL(filePath).href),\n 'import.meta.env': 'process.env',\n },\n});\n\nexport const transpileTSToCJSSync = (\n code: string,\n filePath: string,\n options?: TranspileOptions\n): string | undefined => {\n const extension = extname(filePath);\n const loader = getLoader(extension);\n\n const { esbuildInstance, ...buildOptions } = options ?? {};\n const esbuildBuildSync = esbuildInstance?.buildSync ?? buildSync;\n\n const moduleResult: BuildResult = esbuildBuildSync({\n stdin: {\n contents: code,\n loader,\n resolveDir: dirname(filePath), // Add resolveDir to resolve imports relative to the file's location\n sourcefile: filePath, // Add sourcefile for better error messages\n },\n ...getTransformationOptions(filePath),\n ...buildOptions,\n });\n\n const moduleResultString = moduleResult.outputFiles?.[0].text;\n\n return moduleResultString;\n};\n\nexport const transpileTSToCJS = async (\n code: string,\n filePath: string,\n options?: TranspileOptions\n): Promise<string | undefined> => {\n const extension = extname(filePath);\n const loader = getLoader(extension);\n\n const { esbuildInstance, ...buildOptions } = options ?? {};\n // Use context() + rebuild() + dispose() so esbuild deterministically releases\n // Go-subprocess resources for each one-shot transpilation, preventing them\n // from accumulating between rapid HMR-driven file changes.\n const esbuildContext = esbuildInstance?.context ?? context;\n\n const ctx = await esbuildContext({\n stdin: {\n contents: code,\n loader,\n resolveDir: dirname(filePath),\n sourcefile: filePath,\n },\n ...getTransformationOptions(filePath),\n ...buildOptions,\n });\n\n try {\n const moduleResult = await ctx.rebuild();\n return moduleResult.outputFiles?.[0].text;\n } finally {\n await ctx.dispose();\n }\n};\n"],"mappings":";;;;;;;;AAuBA,MAAM,mBAAmB,aAAyC;CAChE,MAAM,eAAe,KACnB,mBAAmB,QAAQ,SAAS,CAAC,CAAC,SACtC,gBACD;AAGD,QAAO,WAAW,aAAa,GAAG,eAAe;;AAGnD,MAAM,4BAA4B,cAAoC;CACpE,QAAQ;EACN,OAAO;EACP,QAAQ;EACR,QAAQ;EACR,OAAO;EACP,QAAQ;EACR,QAAQ;EACR,SAAS;EACT,OAAO;EACP,QAAQ;EACT;CACD,QAAQ;CACR,QAAQ;CACR,UAAU;CACV,OAAO;CACP,UAAU;CACV,QAAQ;CACR,UAAU,gBAAgB,SAAS;CACnC,QAAQ;EACN,mBAAmB,KAAK,UAAU,cAAc,SAAS,CAAC,KAAK;EAC/D,mBAAmB;EACpB;CACF;AAED,MAAa,wBACX,MACA,UACA,YACuB;CAEvB,MAAM,SAAS,UADG,QAAQ,SACQ,CAAC;CAEnC,MAAM,EAAE,iBAAiB,GAAG,iBAAiB,WAAW,EAAE;AAgB1D,SAfyB,iBAAiB,aAAa,WAEJ;EACjD,OAAO;GACL,UAAU;GACV;GACA,YAAY,QAAQ,SAAS;GAC7B,YAAY;GACb;EACD,GAAG,yBAAyB,SAAS;EACrC,GAAG;EACJ,CAEsC,CAAC,cAAc,GAAG;;AAK3D,MAAa,mBAAmB,OAC9B,MACA,UACA,YACgC;CAEhC,MAAM,SAAS,UADG,QAAQ,SACQ,CAAC;CAEnC,MAAM,EAAE,iBAAiB,GAAG,iBAAiB,WAAW,EAAE;CAM1D,MAAM,MAAM,OAFW,iBAAiB,WAAW,SAElB;EAC/B,OAAO;GACL,UAAU;GACV;GACA,YAAY,QAAQ,SAAS;GAC7B,YAAY;GACb;EACD,GAAG,yBAAyB,SAAS;EACrC,GAAG;EACJ,CAAC;AAEF,KAAI;AAEF,UAAO,MADoB,IAAI,SAAS,EACpB,cAAc,GAAG;WAC7B;AACR,QAAM,IAAI,SAAS"}
@@ -3,7 +3,7 @@ import { basename, dirname, join } from "node:path";
3
3
  import { mkdir, readFile, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
4
4
  import { deserialize, serialize } from "node:v8";
5
5
  import { gunzipSync, gzipSync } from "node:zlib";
6
- import configPackageJson from "@intlayer/types/package.json" with { type: "json" };
6
+ import packageJSON from "@intlayer/types/package.json" with { type: "json" };
7
7
 
8
8
  //#region src/utils/cacheDisk.ts
9
9
  const DEFAULTS = { compress: true };
@@ -60,7 +60,7 @@ const cacheDisk = (intlayerConfig, keys, options) => {
60
60
  const maybeObj = deserialized;
61
61
  if (!!maybeObj && typeof maybeObj === "object" && typeof maybeObj.version === "string" && typeof maybeObj.timestamp === "number" && Object.hasOwn(maybeObj, "data")) {
62
62
  const entry = maybeObj;
63
- if (entry.version !== configPackageJson.version) {
63
+ if (entry.version !== packageJSON.version) {
64
64
  try {
65
65
  await unlink(filePath);
66
66
  } catch {}
@@ -96,7 +96,7 @@ const cacheDisk = (intlayerConfig, keys, options) => {
96
96
  try {
97
97
  await ensureDir(dirname(filePath));
98
98
  const envelope = {
99
- version: configPackageJson.version,
99
+ version: packageJSON.version,
100
100
  timestamp: Date.now(),
101
101
  data: value
102
102
  };
@@ -156,7 +156,7 @@ const cacheDisk = (intlayerConfig, keys, options) => {
156
156
  const maybeObj = deserialize(flag === 1 ? gunzipSync(raw) : raw);
157
157
  if (!!maybeObj && typeof maybeObj === "object" && typeof maybeObj.version === "string" && typeof maybeObj.timestamp === "number" && Object.hasOwn(maybeObj, "data")) {
158
158
  const entry = maybeObj;
159
- if (entry.version !== configPackageJson.version) return false;
159
+ if (entry.version !== packageJSON.version) return false;
160
160
  if (typeof maxTimeMs === "number" && maxTimeMs > 0) {
161
161
  if (Date.now() - entry.timestamp > maxTimeMs) return false;
162
162
  }
@@ -1 +1 @@
1
- {"version":3,"file":"cacheDisk.mjs","names":[],"sources":["../../../src/utils/cacheDisk.ts"],"sourcesContent":["import {\n mkdir,\n readFile,\n rename,\n rm,\n stat,\n unlink,\n writeFile,\n} from 'node:fs/promises';\nimport { basename, dirname, join } from 'node:path';\nimport { deserialize, serialize } from 'node:v8';\nimport { gunzipSync, gzipSync } from 'node:zlib';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport configPackageJson from '@intlayer/types/package.json' with {\n type: 'json',\n};\nimport { type CacheKey, clearAllCache, computeKeyId } from './cacheMemory';\n\n/** ------------------------- Persistence layer ------------------------- **/\n\n/** Cache envelope structure stored on disk */\ntype CacheEnvelope = {\n /** Version of the config package (for cache invalidation) */\n version: string;\n /** Timestamp when the cache entry was created (in milliseconds) */\n timestamp: number;\n /** Data payload (the actual cached value) */\n data: unknown;\n};\n\ntype LocalCacheOptions = {\n /** Preferred new option name */\n persistent?: boolean;\n /** Time-to-live in ms; if expired, disk entry is ignored. */\n ttlMs?: number;\n /** Max age in ms based on stored creation timestamp; invalidates on exceed. */\n maxTimeMs?: number;\n /** Optional namespace to separate different logical caches. */\n namespace?: string;\n /** Gzip values on disk (on by default for blobs > 1KB). */\n compress?: boolean;\n};\n\nconst DEFAULTS: Required<Pick<LocalCacheOptions, 'compress'>> = {\n compress: true,\n};\n\nconst ensureDir = async (dir: string) => {\n await mkdir(dir, { recursive: true });\n};\n\nconst atomicWriteFile = async (\n file: string,\n data: Buffer,\n tempDir?: string\n) => {\n if (tempDir) {\n try {\n await ensureDir(tempDir);\n } catch {}\n }\n\n const tempFileName = `${basename(file)}.tmp-${process.pid}-${Math.random().toString(36).slice(2)}`;\n const tmp = tempDir\n ? join(tempDir, tempFileName)\n : `${file}.tmp-${process.pid}-${Math.random().toString(36).slice(2)}`;\n try {\n await writeFile(tmp, data);\n await rename(tmp, file);\n } catch (error) {\n try {\n await rm(tmp, { force: true });\n } catch {\n // Ignore\n }\n throw error;\n }\n};\n\nconst shouldUseCompression = (buf: Buffer, force?: boolean) =>\n force === true || (force !== false && buf.byteLength > 1024);\n\n/** Derive on-disk path from config dir + namespace + key id. */\nconst cachePath = (cacheDir: string, id: string, ns?: string) =>\n join(cacheDir, ns ? join(ns, id) : id);\n\n/** ------------------------- Local cache facade ------------------------- **/\n\nconst cacheMap = new Map<string, any>();\n\n/** Clears the in-memory portion of the disk cache without touching disk files. */\nexport const clearDiskCacheMemory = (): void => {\n cacheMap.clear();\n};\n\nexport const cacheDisk = (\n intlayerConfig: IntlayerConfig,\n keys: CacheKey[],\n options?: LocalCacheOptions\n) => {\n const { cacheDir, tempDir } = intlayerConfig.system;\n const buildCacheEnabled = intlayerConfig.build.cache ?? true;\n const persistent =\n options?.persistent === true ||\n (typeof options?.persistent === 'undefined' && buildCacheEnabled);\n\n const { compress, ttlMs, maxTimeMs, namespace } = {\n ...DEFAULTS,\n ...options,\n };\n\n // single stable id for this key tuple (works for both memory & disk)\n const id = computeKeyId(keys);\n const filePath = cachePath(cacheDir, id, namespace);\n\n const readFromDisk = async (): Promise<unknown | undefined> => {\n try {\n const statValue = await stat(filePath).catch(() => undefined);\n\n if (!statValue) return undefined;\n\n if (typeof ttlMs === 'number' && ttlMs > 0) {\n const age = Date.now() - statValue.mtimeMs;\n if (age > ttlMs) return undefined;\n }\n let raw = await readFile(filePath);\n // header: 1 byte flag (0x00 raw, 0x01 gzip)\n const flag = raw[0];\n\n raw = raw.subarray(1);\n\n const payload = flag === 0x01 ? gunzipSync(raw) : raw;\n const deserialized = deserialize(payload) as unknown;\n\n let value: unknown;\n const maybeObj = deserialized as Record<string, unknown> | null;\n const isEnvelope =\n !!maybeObj &&\n typeof maybeObj === 'object' &&\n typeof (maybeObj as any).version === 'string' &&\n typeof (maybeObj as any).timestamp === 'number' &&\n Object.hasOwn(maybeObj, 'data');\n\n if (isEnvelope) {\n const entry = maybeObj as CacheEnvelope;\n\n if (entry.version !== configPackageJson.version) {\n try {\n await unlink(filePath);\n } catch {}\n return undefined;\n }\n\n if (typeof maxTimeMs === 'number' && maxTimeMs > 0) {\n const age = Date.now() - entry.timestamp;\n if (age > maxTimeMs) {\n try {\n await unlink(filePath);\n } catch {}\n return undefined;\n }\n }\n\n value = entry.data;\n } else {\n // Backward compatibility: old entries had raw serialized value.\n if (typeof maxTimeMs === 'number' && maxTimeMs > 0) {\n const age = Date.now() - statValue.mtimeMs;\n if (age > maxTimeMs) {\n try {\n await unlink(filePath);\n } catch {}\n return undefined;\n }\n }\n value = deserialized;\n }\n\n // hydrate memory cache as well\n cacheMap.set(id, value);\n return value;\n } catch {\n return undefined;\n }\n };\n\n const writeToDisk = async (value: unknown) => {\n try {\n await ensureDir(dirname(filePath));\n const envelope: CacheEnvelope = {\n version: configPackageJson.version,\n timestamp: Date.now(),\n data: value,\n };\n const payload = Buffer.from(serialize(envelope));\n\n const gz = shouldUseCompression(payload, compress)\n ? gzipSync(payload)\n : payload;\n\n // prepend a 1-byte header indicating compression\n const buf = Buffer.concat([\n Buffer.from([gz === payload ? 0x00 : 0x01]),\n gz,\n ]);\n\n await atomicWriteFile(filePath, buf, tempDir);\n } catch {\n // swallow disk errors for cache writes\n }\n };\n\n return {\n /** In-memory first, then disk (if enabled), otherwise undefined. */\n get: async <T>(): Promise<T | undefined> => {\n const mem = cacheMap.get(id);\n\n if (mem !== undefined) return mem as T;\n\n if (persistent && buildCacheEnabled) {\n return (await readFromDisk()) as T | undefined;\n }\n return undefined;\n },\n /** Sets in-memory (always) and persists to disk if enabled. */\n set: async (value: unknown): Promise<void> => {\n cacheMap.set(id, value);\n\n if (persistent && buildCacheEnabled) {\n await writeToDisk(value);\n }\n },\n /** Clears only this entry from memory and disk. */\n clear: async (): Promise<void> => {\n cacheMap.delete(id);\n\n try {\n await unlink(filePath);\n } catch {}\n },\n /** Clears ALL cached entries (memory Map and entire cacheDir namespace if persistent). */\n clearAll: async (): Promise<void> => {\n clearAllCache();\n if (persistent && buildCacheEnabled) {\n // remove only the current namespace (if provided), else the root dir\n const base = namespace ? join(cacheDir, namespace) : cacheDir;\n\n try {\n await rm(base, { recursive: true, force: true });\n } catch {}\n\n try {\n await mkdir(base, { recursive: true });\n } catch {}\n }\n },\n /** Expose the computed id (useful if you want to key other structures). */\n isValid: async (): Promise<boolean> => {\n const cachedValue = cacheMap.get(id);\n if (cachedValue !== undefined) return true;\n\n // If persistence is disabled or build cache disabled, only memory can be valid\n if (!persistent || !buildCacheEnabled) return false;\n\n try {\n const statValue = await stat(filePath).catch(() => undefined);\n if (!statValue) return false;\n\n if (typeof ttlMs === 'number' && ttlMs > 0) {\n const age = Date.now() - statValue.mtimeMs;\n if (age > ttlMs) return false;\n }\n\n let raw = await readFile(filePath);\n const flag = raw[0];\n raw = raw.subarray(1);\n const payload = flag === 0x01 ? gunzipSync(raw) : raw;\n const deserialized = deserialize(payload) as unknown;\n\n const maybeObj = deserialized as Record<string, unknown> | null;\n const isEnvelope =\n !!maybeObj &&\n typeof maybeObj === 'object' &&\n typeof maybeObj.version === 'string' &&\n typeof maybeObj.timestamp === 'number' &&\n Object.hasOwn(maybeObj, 'data');\n\n if (isEnvelope) {\n const entry = maybeObj as CacheEnvelope;\n if (entry.version !== configPackageJson.version) return false;\n\n if (typeof maxTimeMs === 'number' && maxTimeMs > 0) {\n const age = Date.now() - entry.timestamp;\n if (age > maxTimeMs) return false;\n }\n return true;\n }\n\n if (typeof maxTimeMs === 'number' && maxTimeMs > 0) {\n const age = Date.now() - statValue.mtimeMs;\n if (age > maxTimeMs) return false;\n }\n return true;\n } catch {\n return false;\n }\n },\n /** Expose the computed id (useful if you want to key other structures). */\n id,\n /** Expose the absolute file path for debugging. */\n filePath,\n };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"cacheDisk.mjs","names":["configPackageJson"],"sources":["../../../src/utils/cacheDisk.ts"],"sourcesContent":["import {\n mkdir,\n readFile,\n rename,\n rm,\n stat,\n unlink,\n writeFile,\n} from 'node:fs/promises';\nimport { basename, dirname, join } from 'node:path';\nimport { deserialize, serialize } from 'node:v8';\nimport { gunzipSync, gzipSync } from 'node:zlib';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport configPackageJson from '@intlayer/types/package.json' with {\n type: 'json',\n};\nimport { type CacheKey, clearAllCache, computeKeyId } from './cacheMemory';\n\n/** ------------------------- Persistence layer ------------------------- **/\n\n/** Cache envelope structure stored on disk */\ntype CacheEnvelope = {\n /** Version of the config package (for cache invalidation) */\n version: string;\n /** Timestamp when the cache entry was created (in milliseconds) */\n timestamp: number;\n /** Data payload (the actual cached value) */\n data: unknown;\n};\n\ntype LocalCacheOptions = {\n /** Preferred new option name */\n persistent?: boolean;\n /** Time-to-live in ms; if expired, disk entry is ignored. */\n ttlMs?: number;\n /** Max age in ms based on stored creation timestamp; invalidates on exceed. */\n maxTimeMs?: number;\n /** Optional namespace to separate different logical caches. */\n namespace?: string;\n /** Gzip values on disk (on by default for blobs > 1KB). */\n compress?: boolean;\n};\n\nconst DEFAULTS: Required<Pick<LocalCacheOptions, 'compress'>> = {\n compress: true,\n};\n\nconst ensureDir = async (dir: string) => {\n await mkdir(dir, { recursive: true });\n};\n\nconst atomicWriteFile = async (\n file: string,\n data: Buffer,\n tempDir?: string\n) => {\n if (tempDir) {\n try {\n await ensureDir(tempDir);\n } catch {}\n }\n\n const tempFileName = `${basename(file)}.tmp-${process.pid}-${Math.random().toString(36).slice(2)}`;\n const tmp = tempDir\n ? join(tempDir, tempFileName)\n : `${file}.tmp-${process.pid}-${Math.random().toString(36).slice(2)}`;\n try {\n await writeFile(tmp, data);\n await rename(tmp, file);\n } catch (error) {\n try {\n await rm(tmp, { force: true });\n } catch {\n // Ignore\n }\n throw error;\n }\n};\n\nconst shouldUseCompression = (buf: Buffer, force?: boolean) =>\n force === true || (force !== false && buf.byteLength > 1024);\n\n/** Derive on-disk path from config dir + namespace + key id. */\nconst cachePath = (cacheDir: string, id: string, ns?: string) =>\n join(cacheDir, ns ? join(ns, id) : id);\n\n/** ------------------------- Local cache facade ------------------------- **/\n\nconst cacheMap = new Map<string, any>();\n\n/** Clears the in-memory portion of the disk cache without touching disk files. */\nexport const clearDiskCacheMemory = (): void => {\n cacheMap.clear();\n};\n\nexport const cacheDisk = (\n intlayerConfig: IntlayerConfig,\n keys: CacheKey[],\n options?: LocalCacheOptions\n) => {\n const { cacheDir, tempDir } = intlayerConfig.system;\n const buildCacheEnabled = intlayerConfig.build.cache ?? true;\n const persistent =\n options?.persistent === true ||\n (typeof options?.persistent === 'undefined' && buildCacheEnabled);\n\n const { compress, ttlMs, maxTimeMs, namespace } = {\n ...DEFAULTS,\n ...options,\n };\n\n // single stable id for this key tuple (works for both memory & disk)\n const id = computeKeyId(keys);\n const filePath = cachePath(cacheDir, id, namespace);\n\n const readFromDisk = async (): Promise<unknown | undefined> => {\n try {\n const statValue = await stat(filePath).catch(() => undefined);\n\n if (!statValue) return undefined;\n\n if (typeof ttlMs === 'number' && ttlMs > 0) {\n const age = Date.now() - statValue.mtimeMs;\n if (age > ttlMs) return undefined;\n }\n let raw = await readFile(filePath);\n // header: 1 byte flag (0x00 raw, 0x01 gzip)\n const flag = raw[0];\n\n raw = raw.subarray(1);\n\n const payload = flag === 0x01 ? gunzipSync(raw) : raw;\n const deserialized = deserialize(payload) as unknown;\n\n let value: unknown;\n const maybeObj = deserialized as Record<string, unknown> | null;\n const isEnvelope =\n !!maybeObj &&\n typeof maybeObj === 'object' &&\n typeof (maybeObj as any).version === 'string' &&\n typeof (maybeObj as any).timestamp === 'number' &&\n Object.hasOwn(maybeObj, 'data');\n\n if (isEnvelope) {\n const entry = maybeObj as CacheEnvelope;\n\n if (entry.version !== configPackageJson.version) {\n try {\n await unlink(filePath);\n } catch {}\n return undefined;\n }\n\n if (typeof maxTimeMs === 'number' && maxTimeMs > 0) {\n const age = Date.now() - entry.timestamp;\n if (age > maxTimeMs) {\n try {\n await unlink(filePath);\n } catch {}\n return undefined;\n }\n }\n\n value = entry.data;\n } else {\n // Backward compatibility: old entries had raw serialized value.\n if (typeof maxTimeMs === 'number' && maxTimeMs > 0) {\n const age = Date.now() - statValue.mtimeMs;\n if (age > maxTimeMs) {\n try {\n await unlink(filePath);\n } catch {}\n return undefined;\n }\n }\n value = deserialized;\n }\n\n // hydrate memory cache as well\n cacheMap.set(id, value);\n return value;\n } catch {\n return undefined;\n }\n };\n\n const writeToDisk = async (value: unknown) => {\n try {\n await ensureDir(dirname(filePath));\n const envelope: CacheEnvelope = {\n version: configPackageJson.version,\n timestamp: Date.now(),\n data: value,\n };\n const payload = Buffer.from(serialize(envelope));\n\n const gz = shouldUseCompression(payload, compress)\n ? gzipSync(payload)\n : payload;\n\n // prepend a 1-byte header indicating compression\n const buf = Buffer.concat([\n Buffer.from([gz === payload ? 0x00 : 0x01]),\n gz,\n ]);\n\n await atomicWriteFile(filePath, buf, tempDir);\n } catch {\n // swallow disk errors for cache writes\n }\n };\n\n return {\n /** In-memory first, then disk (if enabled), otherwise undefined. */\n get: async <T>(): Promise<T | undefined> => {\n const mem = cacheMap.get(id);\n\n if (mem !== undefined) return mem as T;\n\n if (persistent && buildCacheEnabled) {\n return (await readFromDisk()) as T | undefined;\n }\n return undefined;\n },\n /** Sets in-memory (always) and persists to disk if enabled. */\n set: async (value: unknown): Promise<void> => {\n cacheMap.set(id, value);\n\n if (persistent && buildCacheEnabled) {\n await writeToDisk(value);\n }\n },\n /** Clears only this entry from memory and disk. */\n clear: async (): Promise<void> => {\n cacheMap.delete(id);\n\n try {\n await unlink(filePath);\n } catch {}\n },\n /** Clears ALL cached entries (memory Map and entire cacheDir namespace if persistent). */\n clearAll: async (): Promise<void> => {\n clearAllCache();\n if (persistent && buildCacheEnabled) {\n // remove only the current namespace (if provided), else the root dir\n const base = namespace ? join(cacheDir, namespace) : cacheDir;\n\n try {\n await rm(base, { recursive: true, force: true });\n } catch {}\n\n try {\n await mkdir(base, { recursive: true });\n } catch {}\n }\n },\n /** Expose the computed id (useful if you want to key other structures). */\n isValid: async (): Promise<boolean> => {\n const cachedValue = cacheMap.get(id);\n if (cachedValue !== undefined) return true;\n\n // If persistence is disabled or build cache disabled, only memory can be valid\n if (!persistent || !buildCacheEnabled) return false;\n\n try {\n const statValue = await stat(filePath).catch(() => undefined);\n if (!statValue) return false;\n\n if (typeof ttlMs === 'number' && ttlMs > 0) {\n const age = Date.now() - statValue.mtimeMs;\n if (age > ttlMs) return false;\n }\n\n let raw = await readFile(filePath);\n const flag = raw[0];\n raw = raw.subarray(1);\n const payload = flag === 0x01 ? gunzipSync(raw) : raw;\n const deserialized = deserialize(payload) as unknown;\n\n const maybeObj = deserialized as Record<string, unknown> | null;\n const isEnvelope =\n !!maybeObj &&\n typeof maybeObj === 'object' &&\n typeof maybeObj.version === 'string' &&\n typeof maybeObj.timestamp === 'number' &&\n Object.hasOwn(maybeObj, 'data');\n\n if (isEnvelope) {\n const entry = maybeObj as CacheEnvelope;\n if (entry.version !== configPackageJson.version) return false;\n\n if (typeof maxTimeMs === 'number' && maxTimeMs > 0) {\n const age = Date.now() - entry.timestamp;\n if (age > maxTimeMs) return false;\n }\n return true;\n }\n\n if (typeof maxTimeMs === 'number' && maxTimeMs > 0) {\n const age = Date.now() - statValue.mtimeMs;\n if (age > maxTimeMs) return false;\n }\n return true;\n } catch {\n return false;\n }\n },\n /** Expose the computed id (useful if you want to key other structures). */\n id,\n /** Expose the absolute file path for debugging. */\n filePath,\n };\n};\n"],"mappings":"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"}
@@ -7,6 +7,14 @@ type LoadExternalFileOptions = {
7
7
  configuration?: IntlayerConfig;
8
8
  buildOptions?: TranspileOptions;
9
9
  logError?: boolean;
10
+ /**
11
+ * Key-value pairs to temporarily set on the main Node.js `globalThis` for the
12
+ * synchronous duration of `parseFileContent` / `runInNewContext`. External modules
13
+ * loaded via `require()` inside the VM (e.g. `@intlayer/core`'s `file()` helper)
14
+ * run in the main context and read from the real `globalThis`, not the VM sandbox.
15
+ * Values are restored (or deleted) after `runInNewContext` returns.
16
+ */
17
+ preloadGlobals?: Record<string, unknown>;
10
18
  } & SandBoxContextOptions;
11
19
  /**
12
20
  * Load the content declaration from the given path
@@ -1 +1 @@
1
- {"version":3,"file":"loadExternalFile.d.ts","names":[],"sources":["../../../src/loadExternalFile/loadExternalFile.ts"],"mappings":";;;;;KAmBY,uBAAA;EACV,aAAA,GAAgB,cAAA;EAChB,YAAA,GAAe,gBAAA;EACf,QAAA;AAAA,IACE,qBAAA;;;;;;cAOS,oBAAA,GACX,QAAA,UACA,OAAA,GAAU,uBAAA;;;;;;cA4DC,gBAAA,GACX,QAAA,UACA,OAAA,GAAU,uBAAA,KACT,OAAA"}
1
+ {"version":3,"file":"loadExternalFile.d.ts","names":[],"sources":["../../../src/loadExternalFile/loadExternalFile.ts"],"mappings":";;;;;KAmBY,uBAAA;EACV,aAAA,GAAgB,cAAA;EAChB,YAAA,GAAe,gBAAA;EACf,QAAA;;;;;;;;EAQA,cAAA,GAAiB,MAAA;AAAA,IACf,qBAAA;;;;;;cAOS,oBAAA,GACX,QAAA,UACA,OAAA,GAAU,uBAAA;;;AAFZ;;;cAyFa,gBAAA,GACX,QAAA,UACA,OAAA,GAAU,uBAAA,KACT,OAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"parseFileContent.d.ts","names":[],"sources":["../../../src/loadExternalFile/parseFileContent.ts"],"mappings":";;;;KAKY,qBAAA;EACV,aAAA,GAAgB,kBAAA;EAChB,cAAA,GAAiB,MAAA,CAAO,OAAA;EACxB,iBAAA,GAAoB,MAAA;;;;;;;;EAQpB,KAAA,GAAQ,MAAA;EAVR;;;;;;EAiBA,OAAA,GAAU,MAAA;AAAA;AAAA,cAGC,iBAAA,GAAqB,OAAA,GAAU,qBAAA,KAAwB,OAAA;AAAA,cAgGvD,gBAAA,MACX,iBAAA,UACA,OAAA,GAAU,qBAAA,KACT,CAAA"}
1
+ {"version":3,"file":"parseFileContent.d.ts","names":[],"sources":["../../../src/loadExternalFile/parseFileContent.ts"],"mappings":";;;;KAKY,qBAAA;EACV,aAAA,GAAgB,kBAAA;EAChB,cAAA,GAAiB,MAAA,CAAO,OAAA;EACxB,iBAAA,GAAoB,MAAA;;;;;;;;EAQpB,KAAA,GAAQ,MAAA;EAVR;;;;;;EAiBA,OAAA,GAAU,MAAA;AAAA;AAAA,cA6BC,iBAAA,GAAqB,OAAA,GAAU,qBAAA,KAAwB,OAAA;AAAA,cAgGvD,gBAAA,MACX,iBAAA,UACA,OAAA,GAAU,qBAAA,KACT,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"transpileTSToCJS.d.ts","names":[],"sources":["../../../src/loadExternalFile/transpileTSToCJS.ts"],"mappings":";;;;KAOY,gBAAA,GAAmB,YAAA;;;AAA/B;;;;;EAQE,eAAA,UARyC,SAAA;AAAA;AAAA,cA8C9B,oBAAA,GACX,IAAA,UACA,QAAA,UACA,OAAA,GAAU,gBAAA;AAAA,cAwBC,gBAAA,GACX,IAAA,UACA,QAAA,UACA,OAAA,GAAU,gBAAA,KACT,OAAA"}
1
+ {"version":3,"file":"transpileTSToCJS.d.ts","names":[],"sources":["../../../src/loadExternalFile/transpileTSToCJS.ts"],"mappings":";;;;KAYY,gBAAA,GAAmB,YAAA;;;AAA/B;;;;;EAQE,eAAA,UARyC,SAAA;AAAA;AAAA,cA8C9B,oBAAA,GACX,IAAA,UACA,QAAA,UACA,OAAA,GAAU,gBAAA;AAAA,cAwBC,gBAAA,GACX,IAAA,UACA,QAAA,UACA,OAAA,GAAU,gBAAA,KACT,OAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intlayer/config",
3
- "version": "8.9.0",
3
+ "version": "8.9.1",
4
4
  "private": false,
5
5
  "description": "Retrieve Intlayer configurations and manage environment variables for both server-side and client-side environments.",
6
6
  "keywords": [
@@ -160,7 +160,7 @@
160
160
  "typecheck": "tsc --noEmit --project tsconfig.types.json"
161
161
  },
162
162
  "dependencies": {
163
- "@intlayer/types": "8.9.0",
163
+ "@intlayer/types": "8.9.1",
164
164
  "defu": "6.1.7",
165
165
  "dotenv": "17.4.2",
166
166
  "esbuild": "0.28.0",