@514labs/moose-lib 0.6.445 → 0.6.446
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.
- package/dist/moose-tspc.js +7 -56
- package/dist/moose-tspc.js.map +1 -1
- package/dist/moose-tspc.mjs +7 -56
- package/dist/moose-tspc.mjs.map +1 -1
- package/package.json +1 -1
package/dist/moose-tspc.js
CHANGED
|
@@ -245,9 +245,8 @@ function createBuildTsconfig(moduleOptions) {
|
|
|
245
245
|
skipDefaultLibCheck: true,
|
|
246
246
|
// Additional settings to handle module resolution conflicts
|
|
247
247
|
allowSyntheticDefaultImports: true,
|
|
248
|
-
//
|
|
249
|
-
|
|
250
|
-
noEmitOnError: watchMode,
|
|
248
|
+
// Block emission on errors so build and dev behave consistently
|
|
249
|
+
noEmitOnError: true,
|
|
251
250
|
// Enable incremental compilation for faster rebuilds
|
|
252
251
|
incremental: true,
|
|
253
252
|
tsBuildInfoFile: import_path3.default.join(outDir, ".tsbuildinfo")
|
|
@@ -257,7 +256,6 @@ function createBuildTsconfig(moduleOptions) {
|
|
|
257
256
|
function runSingleCompilation(moduleSystem) {
|
|
258
257
|
const moduleOptions = getModuleOptions(moduleSystem);
|
|
259
258
|
const buildTsconfig = createBuildTsconfig(moduleOptions);
|
|
260
|
-
buildTsconfig.compilerOptions.noEmitOnError = false;
|
|
261
259
|
(0, import_fs3.writeFileSync)(tempTsconfigPath, JSON.stringify(buildTsconfig, null, 2));
|
|
262
260
|
console.log("Created temporary tsconfig with moose plugins...");
|
|
263
261
|
const tspcArgs = [
|
|
@@ -272,58 +270,11 @@ function runSingleCompilation(moduleSystem) {
|
|
|
272
270
|
if (shouldAddOutDir) {
|
|
273
271
|
tspcArgs.push("--outDir", outDir);
|
|
274
272
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
console.log("TypeScript compilation complete.");
|
|
281
|
-
} catch (compileError) {
|
|
282
|
-
const sourceDir = getSourceDir();
|
|
283
|
-
const outputIndexPath = import_path3.default.join(
|
|
284
|
-
projectRoot2,
|
|
285
|
-
outDir,
|
|
286
|
-
sourceDir,
|
|
287
|
-
"index.js"
|
|
288
|
-
);
|
|
289
|
-
if ((0, import_fs3.existsSync)(outputIndexPath)) {
|
|
290
|
-
console.warn("");
|
|
291
|
-
console.warn("BUILD SAFETY WARNING");
|
|
292
|
-
console.warn(
|
|
293
|
-
"==============================================================="
|
|
294
|
-
);
|
|
295
|
-
console.warn(
|
|
296
|
-
"TypeScript detected type errors but JavaScript was still emitted."
|
|
297
|
-
);
|
|
298
|
-
console.warn("");
|
|
299
|
-
console.warn(
|
|
300
|
-
"IMPORTANT: Type errors can indicate code that will fail at runtime."
|
|
301
|
-
);
|
|
302
|
-
console.warn(
|
|
303
|
-
"While this build will succeed, the resulting code may crash when:"
|
|
304
|
-
);
|
|
305
|
-
console.warn(" - Functions receive unexpected argument types");
|
|
306
|
-
console.warn(
|
|
307
|
-
" - Properties are accessed on potentially null/undefined values"
|
|
308
|
-
);
|
|
309
|
-
console.warn(" - Incorrect types flow through your application logic");
|
|
310
|
-
console.warn("");
|
|
311
|
-
console.warn(
|
|
312
|
-
"RECOMMENDATION: Run `npx tsc --noEmit` to review type errors before"
|
|
313
|
-
);
|
|
314
|
-
console.warn(
|
|
315
|
-
"deploying to production. Fix any errors that could cause runtime issues."
|
|
316
|
-
);
|
|
317
|
-
console.warn(
|
|
318
|
-
"==============================================================="
|
|
319
|
-
);
|
|
320
|
-
console.warn("");
|
|
321
|
-
console.log("TypeScript compilation complete (with type warnings).");
|
|
322
|
-
} else {
|
|
323
|
-
console.error("Compilation failed - no output files generated.");
|
|
324
|
-
throw compileError;
|
|
325
|
-
}
|
|
326
|
-
}
|
|
273
|
+
(0, import_child_process.execFileSync)("npx", tspcArgs, {
|
|
274
|
+
stdio: "inherit",
|
|
275
|
+
cwd: projectRoot2
|
|
276
|
+
});
|
|
277
|
+
console.log("TypeScript compilation complete.");
|
|
327
278
|
if (moduleSystem === "esm") {
|
|
328
279
|
console.log("Post-processing ESM imports to add .js extensions...");
|
|
329
280
|
const fullOutDir = import_path3.default.join(projectRoot2, outDir);
|
package/dist/moose-tspc.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/moose-tspc.ts","../src/compiler-config.ts","../src/commons.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * Pre-compiles TypeScript app code with moose compiler plugins and typia transforms.\n *\n * Usage: moose-tspc [outDir] [--watch]\n * outDir: Output directory for compiled files (optional, overrides tsconfig)\n * --watch: Enable watch mode for incremental compilation (outputs JSON events)\n *\n * Output directory is determined by (in priority order):\n * 1. CLI argument (if provided) - used by Docker builds\n * 2. User's tsconfig.json outDir setting (if specified)\n * 3. Default: .moose/compiled\n *\n * This script creates a temporary tsconfig that extends the user's config and adds\n * the required moose compiler plugins, then runs tspc to compile with transforms.\n *\n * In watch mode, outputs JSON events to stdout for the Rust CLI to parse:\n * {\"event\": \"compile_start\"}\n * {\"event\": \"compile_complete\", \"errors\": 0, \"warnings\": 2}\n * {\"event\": \"compile_error\", \"errors\": 3, \"diagnostics\": [...]}\n */\nimport { execFileSync, spawn } from \"child_process\";\nimport { existsSync, writeFileSync, unlinkSync, mkdirSync } from \"fs\";\nimport path from \"path\";\nimport {\n MOOSE_COMPILER_PLUGINS,\n MOOSE_COMPILER_OPTIONS,\n detectModuleSystem,\n getModuleOptions,\n getSourceDir,\n readUserOutDir,\n DEFAULT_OUT_DIR,\n type ModuleSystem,\n} from \"./compiler-config\";\nimport { rewriteImportExtensions } from \"./commons\";\n\n// Parse command line arguments\nconst args = process.argv.slice(2);\nconst watchMode = args.includes(\"--watch\");\n// CLI argument takes priority (for Docker builds), then tsconfig, then default\nconst cliOutDir = args.find((arg) => !arg.startsWith(\"--\"));\n\nconst projectRoot = process.cwd();\nconst tsconfigPath = path.join(projectRoot, \"tsconfig.json\");\nconst tempTsconfigPath = path.join(projectRoot, \"tsconfig.moose-build.json\");\n\n// Determine outDir - CLI arg > tsconfig > default\nconst userOutDir = readUserOutDir(projectRoot);\nconst outDir = cliOutDir || userOutDir || DEFAULT_OUT_DIR;\n// add --outDir flag if user hasn't specified in tsconfig\n// (if CLI arg is provided, we always pass it explicitly)\nconst shouldAddOutDir = cliOutDir !== undefined || !userOutDir;\n\n/**\n * JSON event protocol for watch mode communication with Rust CLI.\n */\ninterface CompileEvent {\n event: \"compile_start\" | \"compile_complete\" | \"compile_error\";\n errors?: number;\n warnings?: number;\n diagnostics?: string[];\n}\n\n/**\n * Emit a JSON event to stdout for the Rust CLI to parse.\n */\nfunction emitEvent(event: CompileEvent): void {\n console.log(JSON.stringify(event));\n}\n\n/**\n * Create the build tsconfig with moose plugins.\n */\nfunction createBuildTsconfig(\n moduleOptions: ReturnType<typeof getModuleOptions>,\n) {\n return {\n extends: \"./tsconfig.json\",\n compilerOptions: {\n ...MOOSE_COMPILER_OPTIONS,\n ...moduleOptions,\n plugins: [...MOOSE_COMPILER_PLUGINS],\n // Skip type checking of declaration files to avoid dual-package conflicts\n skipLibCheck: true,\n skipDefaultLibCheck: true,\n // Additional settings to handle module resolution conflicts\n allowSyntheticDefaultImports: true,\n // In watch mode, we want to block on errors (noEmitOnError: true)\n // In build mode, we allow emission with errors for Docker builds\n noEmitOnError: watchMode,\n // Enable incremental compilation for faster rebuilds\n incremental: true,\n tsBuildInfoFile: path.join(outDir, \".tsbuildinfo\"),\n },\n };\n}\n\n/**\n * Run a single compilation (non-watch mode).\n */\nfunction runSingleCompilation(moduleSystem: ModuleSystem): void {\n const moduleOptions = getModuleOptions(moduleSystem);\n const buildTsconfig = createBuildTsconfig(moduleOptions);\n // Override noEmitOnError for single compilation (allow errors)\n buildTsconfig.compilerOptions.noEmitOnError = false;\n\n writeFileSync(tempTsconfigPath, JSON.stringify(buildTsconfig, null, 2));\n console.log(\"Created temporary tsconfig with moose plugins...\");\n\n // Build tspc arguments - only add --outDir if user hasn't specified one in tsconfig\n const tspcArgs = [\n \"tspc\",\n \"-p\",\n tempTsconfigPath,\n \"--rootDir\",\n \".\",\n \"--sourceMap\",\n \"--inlineSources\",\n ];\n if (shouldAddOutDir) {\n tspcArgs.push(\"--outDir\", outDir);\n }\n\n try {\n execFileSync(\"npx\", tspcArgs, {\n stdio: \"inherit\",\n cwd: projectRoot,\n });\n console.log(\"TypeScript compilation complete.\");\n } catch (compileError: any) {\n // TypeScript might exit with non-zero code even when noEmitOnError: false\n // Check if output files were actually created\n const sourceDir = getSourceDir();\n const outputIndexPath = path.join(\n projectRoot,\n outDir,\n sourceDir,\n \"index.js\",\n );\n\n if (existsSync(outputIndexPath)) {\n console.warn(\"\");\n console.warn(\"BUILD SAFETY WARNING\");\n console.warn(\n \"===============================================================\",\n );\n console.warn(\n \"TypeScript detected type errors but JavaScript was still emitted.\",\n );\n console.warn(\"\");\n console.warn(\n \"IMPORTANT: Type errors can indicate code that will fail at runtime.\",\n );\n console.warn(\n \"While this build will succeed, the resulting code may crash when:\",\n );\n console.warn(\" - Functions receive unexpected argument types\");\n console.warn(\n \" - Properties are accessed on potentially null/undefined values\",\n );\n console.warn(\" - Incorrect types flow through your application logic\");\n console.warn(\"\");\n console.warn(\n \"RECOMMENDATION: Run `npx tsc --noEmit` to review type errors before\",\n );\n console.warn(\n \"deploying to production. Fix any errors that could cause runtime issues.\",\n );\n console.warn(\n \"===============================================================\",\n );\n console.warn(\"\");\n console.log(\"TypeScript compilation complete (with type warnings).\");\n } else {\n console.error(\"Compilation failed - no output files generated.\");\n throw compileError;\n }\n }\n\n // Post-process ESM output to add .js extensions to relative imports\n if (moduleSystem === \"esm\") {\n console.log(\"Post-processing ESM imports to add .js extensions...\");\n const fullOutDir = path.join(projectRoot, outDir);\n rewriteImportExtensions(fullOutDir);\n console.log(\"ESM import rewriting complete.\");\n }\n}\n\n/**\n * Run watch mode compilation with JSON event output.\n * Uses tspc --watch and parses its output to emit structured events.\n */\nfunction runWatchCompilation(moduleSystem: ModuleSystem): void {\n const moduleOptions = getModuleOptions(moduleSystem);\n const buildTsconfig = createBuildTsconfig(moduleOptions);\n\n // Write the tsconfig (it stays for the duration of watch mode)\n writeFileSync(tempTsconfigPath, JSON.stringify(buildTsconfig, null, 2));\n\n // Ensure output directory exists for incremental build info\n const fullOutDir = path.join(projectRoot, outDir);\n if (!existsSync(fullOutDir)) {\n mkdirSync(fullOutDir, { recursive: true });\n }\n\n // Track diagnostics between compilation cycles\n let currentDiagnostics: string[] = [];\n let errorCount = 0;\n let warningCount = 0;\n\n // Build tspc arguments - only add --outDir if user hasn't specified one in tsconfig\n const tspcArgs = [\n \"tspc\",\n \"-p\",\n tempTsconfigPath,\n \"--rootDir\",\n \".\",\n \"--sourceMap\",\n \"--inlineSources\",\n \"--watch\",\n \"--preserveWatchOutput\",\n ];\n if (shouldAddOutDir) {\n // Insert --outDir after --rootDir and \".\" so rootDir is not clobbered\n tspcArgs.splice(6, 0, \"--outDir\", outDir);\n }\n\n // Spawn tspc in watch mode\n const tspcProcess = spawn(\"npx\", tspcArgs, {\n cwd: projectRoot,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n\n // Handle process termination\n const cleanup = () => {\n if (existsSync(tempTsconfigPath)) {\n unlinkSync(tempTsconfigPath);\n }\n tspcProcess.kill();\n };\n\n process.on(\"SIGINT\", () => {\n cleanup();\n process.exit(0);\n });\n\n process.on(\"SIGTERM\", () => {\n cleanup();\n process.exit(0);\n });\n\n // Parse tspc output line by line\n // Pattern matching approach inspired by tsc-watch (github.com/gilamran/tsc-watch)\n // which also parses tsc stdout to detect compilation events\n let buffer = \"\";\n\n // Strip ANSI escape codes for reliable pattern matching (standard regex pattern)\n const stripAnsi = (str: string) =>\n str.replace(\n /[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d/#&.:=?%@~_]*)*)?[\\u0007])|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))/g,\n \"\",\n );\n\n // tsc watch mode patterns (with timestamp prefix like \"12:00:00 AM - \")\n const compilationStartedRegex =\n /Starting compilation in watch mode|Starting incremental compilation/;\n const compilationCompleteRegex =\n /Found\\s+(\\d+)\\s+error(?:s)?\\..*Watching for file changes/;\n const diagnosticRegex = /\\(\\d+,\\d+\\):\\s*(error|warning)\\s+TS\\d+:/;\n\n const processLine = (line: string) => {\n const cleanLine = stripAnsi(line);\n\n if (compilationStartedRegex.test(cleanLine)) {\n // New compilation cycle starting\n currentDiagnostics = [];\n errorCount = 0;\n warningCount = 0;\n emitEvent({ event: \"compile_start\" });\n } else if (compilationCompleteRegex.test(cleanLine)) {\n // Compilation complete - parse error count from tsc summary line\n // Format: \"12:00:00 AM - Found 0 errors. Watching for file changes.\"\n const match = cleanLine.match(/Found\\s+(\\d+)\\s+error(?:s)?\\./);\n if (match) {\n errorCount = parseInt(match[1], 10);\n }\n\n // Post-process ESM if successful\n if (errorCount === 0 && moduleSystem === \"esm\") {\n try {\n rewriteImportExtensions(fullOutDir);\n } catch (e) {\n // Log but don't fail - import rewriting is best-effort\n console.error(\"Warning: ESM import rewriting failed:\", e);\n }\n }\n\n if (errorCount > 0) {\n emitEvent({\n event: \"compile_error\",\n errors: errorCount,\n warnings: warningCount,\n diagnostics: currentDiagnostics,\n });\n } else {\n emitEvent({\n event: \"compile_complete\",\n errors: 0,\n warnings: warningCount,\n diagnostics: warningCount > 0 ? currentDiagnostics : undefined,\n });\n }\n } else if (diagnosticRegex.test(cleanLine)) {\n // This is a diagnostic line (error or warning)\n currentDiagnostics.push(cleanLine.trim());\n if (cleanLine.includes(\": error \")) {\n errorCount++;\n } else if (cleanLine.includes(\": warning \")) {\n warningCount++;\n }\n }\n };\n\n tspcProcess.stdout.on(\"data\", (data: Buffer) => {\n buffer += data.toString();\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() || \"\"; // Keep incomplete line in buffer\n for (const line of lines) {\n if (line.trim()) {\n processLine(line);\n }\n }\n });\n\n tspcProcess.stderr.on(\"data\", (data: Buffer) => {\n // Forward stderr for debugging but don't parse it\n process.stderr.write(data.toString());\n });\n\n tspcProcess.on(\"error\", (err) => {\n console.error(\"Failed to start tspc:\", err);\n cleanup();\n process.exit(1);\n });\n\n tspcProcess.on(\"exit\", (code) => {\n cleanup();\n if (code !== 0) {\n process.exit(code || 1);\n }\n });\n}\n\n/**\n * Write compile metadata to .moose/.compile-config.json\n * This allows Rust CLI to know where compiled output is without duplicating logic\n */\nfunction writeCompileConfig() {\n const mooseDir = path.join(projectRoot, \".moose\");\n if (!existsSync(mooseDir)) {\n mkdirSync(mooseDir, { recursive: true });\n }\n const configPath = path.join(mooseDir, \".compile-config.json\");\n writeFileSync(configPath, JSON.stringify({ outDir }, null, 2));\n}\n\n// Main execution\nif (!existsSync(tsconfigPath)) {\n console.error(\"Error: tsconfig.json not found in\", projectRoot);\n process.exit(1);\n}\n\ntry {\n // Write compile config so Rust CLI knows where output is\n writeCompileConfig();\n\n // Auto-detect module system from package.json\n const moduleSystem = detectModuleSystem(projectRoot);\n\n if (watchMode) {\n // Watch mode - run indefinitely with JSON event output\n runWatchCompilation(moduleSystem);\n } else {\n // Single compilation mode\n console.log(`Compiling TypeScript to ${outDir}...`);\n console.log(\n `Using ${moduleSystem.toUpperCase()} module output (detected from package.json)...`,\n );\n runSingleCompilation(moduleSystem);\n console.log(\"Compilation complete.\");\n\n // Clean up the temporary tsconfig\n if (existsSync(tempTsconfigPath)) {\n unlinkSync(tempTsconfigPath);\n }\n }\n} catch (error) {\n console.error(\"Build process failed:\", error);\n // Clean up the temporary tsconfig\n if (existsSync(tempTsconfigPath)) {\n unlinkSync(tempTsconfigPath);\n }\n process.exit(1);\n}\n","import { existsSync, readFileSync } from \"fs\";\nimport path from \"path\";\n\n/**\n * Shared TypeScript compiler configuration for moose projects.\n * Used by both moose-runner.ts (runtime) and moose-tspc.ts (pre-compilation).\n *\n * Moose now always uses pre-compiled JavaScript - no ts-node fallback.\n */\n\nexport const MOOSE_COMPILER_PLUGINS = [\n {\n transform: \"./node_modules/@514labs/moose-lib/dist/compilerPlugin.js\",\n // No longer using transformProgram - direct typia integration eliminates\n // the need for program replacement and the associated incremental compilation issues\n },\n {\n // Keep typia plugin for users who use typia directly (not through Moose resources)\n transform: \"typia/lib/transform\",\n },\n] as const;\n\n// Options required for moose compilation\n// Note: We only set what's absolutely necessary to avoid conflicts with user projects\nexport const MOOSE_COMPILER_OPTIONS = {\n experimentalDecorators: true,\n esModuleInterop: true,\n // Disable strict module syntax checking to avoid dual-package type conflicts\n // This prevents errors where the same type imported with different resolution\n // modes (CJS vs ESM) is treated as incompatible\n verbatimModuleSyntax: false,\n} as const;\n\n// Module resolution options - only applied if not already set in user's tsconfig\n// These help with ESM/CJS interop but can be overridden by user config\nexport const MOOSE_MODULE_OPTIONS = {\n module: \"NodeNext\",\n moduleResolution: \"NodeNext\",\n} as const;\n\n/**\n * Default source directory for user code.\n * Can be overridden via MOOSE_SOURCE_DIR environment variable.\n */\nexport function getSourceDir(): string {\n return process.env.MOOSE_SOURCE_DIR || \"app\";\n}\n\n/**\n * Default output directory for compiled code.\n */\nexport const DEFAULT_OUT_DIR = \".moose/compiled\";\n\n/**\n * Read the user's tsconfig.json and extract the outDir setting.\n * Supports JSONC (JSON with Comments) by evaluating as JavaScript\n * (JSON with comments is valid JS in ES2019+).\n *\n * Security note: This uses eval-like behavior (new Function), which means\n * malicious code in tsconfig.json would execute. This is acceptable because:\n * - The user controls their own tsconfig.json\n * - Same trust model as running `tsc` or any other tool that processes the file\n * - If you clone and run untrusted code, you're already at risk\n *\n * Returns the outDir if specified, or null if not.\n */\nexport function readUserOutDir(\n projectRoot: string = process.cwd(),\n): string | null {\n try {\n let content = readFileSync(\n path.join(projectRoot, \"tsconfig.json\"),\n \"utf-8\",\n );\n // Strip UTF-8 BOM if present\n if (content.charCodeAt(0) === 0xfeff) {\n content = content.slice(1);\n }\n // eslint-disable-next-line no-eval\n const tsconfig = eval(`(${content})`);\n return tsconfig.compilerOptions?.outDir || null;\n } catch {\n return null;\n }\n}\n\n/**\n * Get the output directory for compiled code.\n * Uses user's tsconfig outDir if specified, otherwise defaults to .moose/compiled\n */\nexport function getOutDir(projectRoot: string = process.cwd()): string {\n const userOutDir = readUserOutDir(projectRoot);\n return userOutDir || DEFAULT_OUT_DIR;\n}\n\n/**\n * Get the path to the compiled index.js file.\n */\nexport function getCompiledIndexPath(\n projectRoot: string = process.cwd(),\n): string {\n const outDir = getOutDir(projectRoot);\n const sourceDir = getSourceDir();\n // Resolve so that absolute outDir from tsconfig is handled correctly\n return path.resolve(projectRoot, outDir, sourceDir, \"index.js\");\n}\n\n/**\n * Check if pre-compiled artifacts exist for the current project.\n */\nexport function hasCompiledArtifacts(\n projectRoot: string = process.cwd(),\n): boolean {\n return existsSync(getCompiledIndexPath(projectRoot));\n}\n\n/**\n * Module system type for compilation output.\n */\nexport type ModuleSystem = \"esm\" | \"cjs\";\n\n/**\n * Detects the module system from the user's package.json.\n * Returns 'esm' if package.json has \"type\": \"module\", otherwise 'cjs'.\n *\n * @param projectRoot - Root directory containing package.json (defaults to cwd)\n * @returns The detected module system\n */\nexport function detectModuleSystem(\n projectRoot: string = process.cwd(),\n): ModuleSystem {\n const pkgPath = path.join(projectRoot, \"package.json\");\n\n if (existsSync(pkgPath)) {\n try {\n const pkgContent = readFileSync(pkgPath, \"utf-8\");\n const pkg = JSON.parse(pkgContent);\n if (pkg.type === \"module\") {\n return \"esm\";\n }\n } catch (e) {\n // If parsing fails, default to CJS\n console.debug(\n `[moose] Failed to parse package.json at ${pkgPath}, defaulting to CJS:`,\n e,\n );\n }\n }\n\n return \"cjs\";\n}\n\n/**\n * Get compiler module options based on detected module system.\n *\n * @param moduleSystem - The module system to get options for\n * @returns Compiler options for module and moduleResolution\n */\nexport function getModuleOptions(moduleSystem: ModuleSystem): {\n module: string;\n moduleResolution: string;\n} {\n if (moduleSystem === \"esm\") {\n return {\n module: \"ES2022\",\n moduleResolution: \"bundler\",\n };\n }\n return {\n module: \"CommonJS\",\n moduleResolution: \"Node\",\n };\n}\n\n/**\n * Dynamic module loader that works with both CJS and ESM.\n * Uses detected module system to determine loading strategy.\n *\n * @param modulePath - Path to the module to load\n * @param projectRoot - Root directory for module system detection\n * @returns The loaded module\n */\nexport async function loadModule<T = any>(\n modulePath: string,\n projectRoot: string = process.cwd(),\n): Promise<T> {\n const moduleSystem = detectModuleSystem(projectRoot);\n\n if (moduleSystem === \"esm\") {\n // Use dynamic import for ESM\n // pathToFileURL is needed for Windows compatibility with absolute paths\n const { pathToFileURL } = await import(\"url\");\n const fileUrl = pathToFileURL(modulePath).href;\n return await import(fileUrl);\n }\n\n // Use require for CJS\n // Note: In ESM builds (compiled by tsup), this code path is replaced with\n // the appropriate ESM imports. The dual-package build ensures compatibility.\n return require(modulePath);\n}\n","import {\n existsSync,\n readdirSync,\n readFileSync,\n statSync,\n writeFileSync,\n} from \"fs\";\nimport nodePath from \"path\";\nimport { createClient } from \"@clickhouse/client\";\nimport { KafkaJS } from \"@514labs/kafka-javascript\";\nimport { SASLOptions } from \"@514labs/kafka-javascript/types/kafkajs\";\nconst { Kafka } = KafkaJS;\ntype Kafka = KafkaJS.Kafka;\ntype Consumer = KafkaJS.Consumer;\nexport type Producer = KafkaJS.Producer;\n\n/**\n * Utility function for compiler-related logging that can be disabled via environment variable.\n * Set MOOSE_DISABLE_COMPILER_LOGS=true to suppress these logs (useful for testing environments).\n */\n\n/**\n * Returns true if the value is a common truthy string: \"1\", \"true\", \"yes\", \"on\" (case-insensitive).\n */\nfunction isTruthy(value: string | undefined): boolean {\n if (!value) return false;\n switch (value.trim().toLowerCase()) {\n case \"1\":\n case \"true\":\n case \"yes\":\n case \"on\":\n return true;\n default:\n return false;\n }\n}\n\nexport const compilerLog = (message: string) => {\n if (!isTruthy(process.env.MOOSE_DISABLE_COMPILER_LOGS)) {\n console.log(message);\n }\n};\n\nexport const antiCachePath = (path: string) =>\n `${path}?num=${Math.random().toString()}&time=${Date.now()}`;\n\nexport const getFileName = (filePath: string) => {\n const regex = /\\/([^\\/]+)\\.ts/;\n const matches = filePath.match(regex);\n if (matches && matches.length > 1) {\n return matches[1];\n }\n return \"\";\n};\n\ninterface ClientConfig {\n username: string;\n password: string;\n database: string;\n useSSL: string;\n host: string;\n port: string;\n}\n\nexport const getClickhouseClient = ({\n username,\n password,\n database,\n useSSL,\n host,\n port,\n}: ClientConfig) => {\n const protocol =\n useSSL === \"1\" || useSSL.toLowerCase() === \"true\" ? \"https\" : \"http\";\n console.log(`Connecting to Clickhouse at ${protocol}://${host}:${port}`);\n return createClient({\n url: `${protocol}://${host}:${port}`,\n username: username,\n password: password,\n database: database,\n application: \"moose\",\n // Note: wait_end_of_query is configured per operation type, not globally\n // to preserve SELECT query performance while ensuring INSERT/DDL reliability\n });\n};\n\nexport type CliLogData = {\n message_type?: \"Info\" | \"Success\" | \"Warning\" | \"Error\" | \"Highlight\";\n action: string;\n message: string;\n};\n\nexport const cliLog: (log: CliLogData) => void = (log) => {\n const level =\n log.message_type === \"Error\" ? \"error\"\n : log.message_type === \"Warning\" ? \"warn\"\n : \"info\";\n\n const structuredLog = {\n __moose_structured_log__: true,\n level,\n message: log.message,\n resource_type: \"runtime\",\n cli_action: log.action,\n cli_message_type: log.message_type ?? \"Info\",\n timestamp: new Date().toISOString(),\n };\n\n process.stderr.write(JSON.stringify(structuredLog) + \"\\n\");\n};\n\n/**\n * Method to change .ts, .cts, and .mts to .js, .cjs, and .mjs\n * This is needed because 'import' does not support .ts, .cts, and .mts\n */\nexport function mapTstoJs(filePath: string): string {\n return filePath\n .replace(/\\.ts$/, \".js\")\n .replace(/\\.cts$/, \".cjs\")\n .replace(/\\.mts$/, \".mjs\");\n}\n\n/**\n * Walks a directory recursively and returns all files matching the given extensions.\n * Skips node_modules directories.\n *\n * @param dir - Directory to walk\n * @param extensions - File extensions to include (e.g., [\".js\", \".mjs\"])\n * @returns Array of file paths\n */\nfunction walkDirectory(dir: string, extensions: string[]): string[] {\n const results: string[] = [];\n\n if (!existsSync(dir)) {\n return results;\n }\n\n try {\n const entries = readdirSync(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = nodePath.join(dir, entry.name);\n\n if (entry.isDirectory()) {\n // Skip node_modules\n if (entry.name !== \"node_modules\") {\n results.push(...walkDirectory(fullPath, extensions));\n }\n } else if (entry.isFile()) {\n const ext = nodePath.extname(entry.name);\n if (extensions.includes(ext)) {\n results.push(fullPath);\n }\n }\n }\n } catch (e) {\n // Log error in case it is something the user can/should act on\n console.debug(`[moose] Failed to read directory ${dir}:`, e);\n }\n\n return results;\n}\n\n/**\n * Adds .js extension to relative import paths that don't have an extension.\n * Handles import/export from statements and dynamic imports.\n *\n * @param content - JavaScript file content\n * @param fileDir - Directory containing the file being processed (for resolving paths)\n * @returns Content with .js extensions added to relative imports\n */\nfunction addJsExtensionToImports(content: string, fileDir?: string): string {\n // Pattern for 'from' statements with relative paths\n // Matches: from './foo', from \"../bar\", from './utils/helper'\n const fromPattern = /(from\\s+['\"])(\\.\\.?\\/[^'\"]*?)(['\"])/g;\n\n // Pattern for side-effect-only imports with relative paths\n // Matches: import './foo', import \"../bar\" (no 'from' keyword, just importing for side effects)\n const bareImportPattern = /(import\\s+['\"])(\\.\\.?\\/[^'\"]*?)(['\"])/g;\n\n // Pattern for dynamic imports with relative paths\n // Matches: import('./foo'), import(\"../bar\")\n const dynamicPattern = /(import\\s*\\(\\s*['\"])(\\.\\.?\\/[^'\"]*?)(['\"])/g;\n\n let result = content;\n\n // Process 'from' statements\n result = result.replace(fromPattern, (match, prefix, importPath, quote) => {\n return rewriteImportPath(match, prefix, importPath, quote, fileDir);\n });\n\n // Process side-effect-only imports\n result = result.replace(\n bareImportPattern,\n (match, prefix, importPath, quote) => {\n return rewriteImportPath(match, prefix, importPath, quote, fileDir);\n },\n );\n\n // Process dynamic imports\n result = result.replace(\n dynamicPattern,\n (match, prefix, importPath, quote) => {\n return rewriteImportPath(match, prefix, importPath, quote, fileDir);\n },\n );\n\n return result;\n}\n\n/**\n * Rewrites a single import path to add .js extension if needed.\n * Handles directory imports with index files correctly.\n *\n * @param match - The full matched string\n * @param prefix - The prefix (from ' or import(')\n * @param importPath - The import path\n * @param quote - The closing quote\n * @param fileDir - Directory containing the file being processed (for resolving paths)\n * @returns The rewritten import or original if no change needed\n */\nfunction rewriteImportPath(\n match: string,\n prefix: string,\n importPath: string,\n quote: string,\n fileDir?: string,\n): string {\n // Skip if already has a JavaScript extension\n if (/\\.[cm]?js$/.test(importPath)) {\n return match;\n }\n\n // Skip if importing a JSON file\n if (/\\.json$/.test(importPath)) {\n return match;\n }\n\n // If we have the file directory, check if the import target is a directory with index.js\n if (fileDir) {\n const resolvedPath = nodePath.resolve(fileDir, importPath);\n\n // Check if path.js exists (regular file import)\n if (existsSync(`${resolvedPath}.js`)) {\n return `${prefix}${importPath}.js${quote}`;\n }\n\n // Check if path/index.js exists (directory import)\n if (existsSync(nodePath.join(resolvedPath, \"index.js\"))) {\n // For directory imports, rewrite to include /index.js\n return `${prefix}${importPath}/index.js${quote}`;\n }\n\n // Check for .mjs variants\n if (existsSync(`${resolvedPath}.mjs`)) {\n return `${prefix}${importPath}.mjs${quote}`;\n }\n if (existsSync(nodePath.join(resolvedPath, \"index.mjs\"))) {\n return `${prefix}${importPath}/index.mjs${quote}`;\n }\n\n // Check for .cjs variants\n if (existsSync(`${resolvedPath}.cjs`)) {\n return `${prefix}${importPath}.cjs${quote}`;\n }\n if (existsSync(nodePath.join(resolvedPath, \"index.cjs\"))) {\n return `${prefix}${importPath}/index.cjs${quote}`;\n }\n }\n\n // Default: add .js extension (fallback when no fileDir or file not found)\n return `${prefix}${importPath}.js${quote}`;\n}\n\n/**\n * Rewrites relative import paths in JavaScript files to include .js extensions.\n * This is required for Node.js ESM which requires explicit extensions.\n *\n * Handles:\n * - import statements: import { foo } from './bar' -> import { foo } from './bar.js'\n * - dynamic imports: import('./bar') -> import('./bar.js')\n * - re-exports: export { foo } from './bar' -> export { foo } from './bar.js'\n *\n * Does NOT modify:\n * - Package imports (no leading . or ..)\n * - Imports that already have extensions\n * - Imports from node_modules\n *\n * @param outDir - Directory containing compiled JavaScript files\n */\nexport function rewriteImportExtensions(outDir: string): void {\n const files = walkDirectory(outDir, [\".js\", \".mjs\"]);\n\n for (const filePath of files) {\n const content = readFileSync(filePath, \"utf-8\");\n const fileDir = nodePath.dirname(filePath);\n const rewritten = addJsExtensionToImports(content, fileDir);\n\n if (content !== rewritten) {\n writeFileSync(filePath, rewritten, \"utf-8\");\n }\n }\n}\n\nexport const MAX_RETRIES = 150;\nexport const MAX_RETRY_TIME_MS = 1000;\nexport const RETRY_INITIAL_TIME_MS = 100;\n\nexport const MAX_RETRIES_PRODUCER = 150;\nexport const RETRY_FACTOR_PRODUCER = 0.2;\n// Means all replicas need to acknowledge the message\nexport const ACKs = -1;\n\n/**\n * Creates the base producer configuration for Kafka.\n * Used by both the SDK stream publishing and streaming function workers.\n *\n * @param maxMessageBytes - Optional max message size in bytes (synced with topic config)\n * @returns Producer configuration object for the Confluent Kafka client\n */\nexport function createProducerConfig(maxMessageBytes?: number) {\n return {\n kafkaJS: {\n idempotent: false, // Not needed for at-least-once delivery\n acks: ACKs,\n retry: {\n retries: MAX_RETRIES_PRODUCER,\n maxRetryTime: MAX_RETRY_TIME_MS,\n },\n },\n \"linger.ms\": 0, // This is to make sure at least once delivery with immediate feedback on the send\n ...(maxMessageBytes && { \"message.max.bytes\": maxMessageBytes }),\n };\n}\n\n/**\n * Parses a comma-separated broker string into an array of valid broker addresses.\n * Handles whitespace trimming and filters out empty elements.\n *\n * @param brokerString - Comma-separated broker addresses (e.g., \"broker1:9092, broker2:9092, , broker3:9092\")\n * @returns Array of trimmed, non-empty broker addresses\n */\nconst parseBrokerString = (brokerString: string): string[] =>\n brokerString\n .split(\",\")\n .map((b) => b.trim())\n .filter((b) => b.length > 0);\n\nexport type KafkaClientConfig = {\n clientId: string;\n broker: string;\n securityProtocol?: string; // e.g. \"SASL_SSL\" or \"PLAINTEXT\"\n saslUsername?: string;\n saslPassword?: string;\n saslMechanism?: string; // e.g. \"scram-sha-256\", \"plain\"\n};\n\n/**\n * Dynamically creates and connects a KafkaJS producer using the provided configuration.\n * Returns a connected producer instance.\n *\n * @param cfg - Kafka client configuration\n * @param logger - Logger instance\n * @param maxMessageBytes - Optional max message size in bytes (synced with topic config)\n */\nexport async function getKafkaProducer(\n cfg: KafkaClientConfig,\n logger: Logger,\n maxMessageBytes?: number,\n): Promise<Producer> {\n const kafka = await getKafkaClient(cfg, logger);\n\n const producer = kafka.producer(createProducerConfig(maxMessageBytes));\n await producer.connect();\n return producer;\n}\n\n/**\n * Interface for logging functionality\n */\nexport interface Logger {\n logPrefix: string;\n log: (message: string) => void;\n error: (message: string) => void;\n warn: (message: string) => void;\n}\n\nexport const logError = (logger: Logger, e: Error): void => {\n logger.error(e.message);\n const stack = e.stack;\n if (stack) {\n logger.error(stack);\n }\n};\n\n/**\n * Builds SASL configuration for Kafka client authentication\n */\nconst buildSaslConfig = (\n logger: Logger,\n args: KafkaClientConfig,\n): SASLOptions | undefined => {\n const mechanism = args.saslMechanism ? args.saslMechanism.toLowerCase() : \"\";\n switch (mechanism) {\n case \"plain\":\n case \"scram-sha-256\":\n case \"scram-sha-512\":\n return {\n mechanism: mechanism,\n username: args.saslUsername || \"\",\n password: args.saslPassword || \"\",\n };\n default:\n logger.warn(`Unsupported SASL mechanism: ${args.saslMechanism}`);\n return undefined;\n }\n};\n\n/**\n * Dynamically creates a KafkaJS client configured with provided settings.\n * Use this to construct producers/consumers with custom options.\n */\nexport const getKafkaClient = async (\n cfg: KafkaClientConfig,\n logger: Logger,\n): Promise<Kafka> => {\n const brokers = parseBrokerString(cfg.broker || \"\");\n if (brokers.length === 0) {\n throw new Error(`No valid broker addresses found in: \"${cfg.broker}\"`);\n }\n\n logger.log(`Creating Kafka client with brokers: ${brokers.join(\", \")}`);\n logger.log(`Security protocol: ${cfg.securityProtocol || \"plaintext\"}`);\n logger.log(`Client ID: ${cfg.clientId}`);\n\n const saslConfig = buildSaslConfig(logger, cfg);\n\n return new Kafka({\n kafkaJS: {\n clientId: cfg.clientId,\n brokers,\n ssl: cfg.securityProtocol === \"SASL_SSL\",\n ...(saslConfig && { sasl: saslConfig }),\n retry: {\n initialRetryTime: RETRY_INITIAL_TIME_MS,\n maxRetryTime: MAX_RETRY_TIME_MS,\n retries: MAX_RETRIES,\n },\n },\n });\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAqBA,2BAAoC;AACpC,IAAAA,aAAiE;AACjE,IAAAC,eAAiB;;;ACvBjB,gBAAyC;AACzC,kBAAiB;AASV,IAAM,yBAAyB;AAAA,EACpC;AAAA,IACE,WAAW;AAAA;AAAA;AAAA,EAGb;AAAA,EACA;AAAA;AAAA,IAEE,WAAW;AAAA,EACb;AACF;AAIO,IAAM,yBAAyB;AAAA,EACpC,wBAAwB;AAAA,EACxB,iBAAiB;AAAA;AAAA;AAAA;AAAA,EAIjB,sBAAsB;AACxB;AAIO,IAAM,uBAAuB;AAAA,EAClC,QAAQ;AAAA,EACR,kBAAkB;AACpB;AAMO,SAAS,eAAuB;AACrC,SAAO,QAAQ,IAAI,oBAAoB;AACzC;AAKO,IAAM,kBAAkB;AAexB,SAAS,eACd,cAAsB,QAAQ,IAAI,GACnB;AACf,MAAI;AACF,QAAI,cAAU;AAAA,MACZ,YAAAC,QAAK,KAAK,aAAa,eAAe;AAAA,MACtC;AAAA,IACF;AAEA,QAAI,QAAQ,WAAW,CAAC,MAAM,OAAQ;AACpC,gBAAU,QAAQ,MAAM,CAAC;AAAA,IAC3B;AAEA,UAAM,WAAW,KAAK,IAAI,OAAO,GAAG;AACpC,WAAO,SAAS,iBAAiB,UAAU;AAAA,EAC7C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAMO,SAAS,UAAUC,eAAsB,QAAQ,IAAI,GAAW;AACrE,QAAMC,cAAa,eAAeD,YAAW;AAC7C,SAAOC,eAAc;AACvB;AAKO,SAAS,qBACdD,eAAsB,QAAQ,IAAI,GAC1B;AACR,QAAME,UAAS,UAAUF,YAAW;AACpC,QAAM,YAAY,aAAa;AAE/B,SAAO,YAAAD,QAAK,QAAQC,cAAaE,SAAQ,WAAW,UAAU;AAChE;AAKO,SAAS,qBACdF,eAAsB,QAAQ,IAAI,GACzB;AACT,aAAO,sBAAW,qBAAqBA,YAAW,CAAC;AACrD;AAcO,SAAS,mBACdA,eAAsB,QAAQ,IAAI,GACpB;AACd,QAAM,UAAU,YAAAD,QAAK,KAAKC,cAAa,cAAc;AAErD,UAAI,sBAAW,OAAO,GAAG;AACvB,QAAI;AACF,YAAM,iBAAa,wBAAa,SAAS,OAAO;AAChD,YAAM,MAAM,KAAK,MAAM,UAAU;AACjC,UAAI,IAAI,SAAS,UAAU;AACzB,eAAO;AAAA,MACT;AAAA,IACF,SAAS,GAAG;AAEV,cAAQ;AAAA,QACN,2CAA2C,OAAO;AAAA,QAClD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAQO,SAAS,iBAAiB,cAG/B;AACA,MAAI,iBAAiB,OAAO;AAC1B,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,kBAAkB;AAAA,IACpB;AAAA,EACF;AACA,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,kBAAkB;AAAA,EACpB;AACF;AAUA,eAAsB,WACpB,YACAA,eAAsB,QAAQ,IAAI,GACtB;AACZ,QAAM,eAAe,mBAAmBA,YAAW;AAEnD,MAAI,iBAAiB,OAAO;AAG1B,UAAM,EAAE,cAAc,IAAI,MAAM,OAAO,KAAK;AAC5C,UAAM,UAAU,cAAc,UAAU,EAAE;AAC1C,WAAO,MAAM,OAAO;AAAA,EACtB;AAKA,SAAO,QAAQ,UAAU;AAC3B;;;ACxMA,IAAAG,aAMO;AACP,IAAAC,eAAqB;AACrB,oBAA6B;AAC7B,8BAAwB;AAExB,IAAM,EAAE,MAAM,IAAI;AAuHlB,SAAS,cAAc,KAAa,YAAgC;AAClE,QAAM,UAAoB,CAAC;AAE3B,MAAI,KAAC,uBAAW,GAAG,GAAG;AACpB,WAAO;AAAA,EACT;AAEA,MAAI;AACF,UAAM,cAAU,wBAAY,KAAK,EAAE,eAAe,KAAK,CAAC;AAExD,eAAW,SAAS,SAAS;AAC3B,YAAM,WAAW,aAAAC,QAAS,KAAK,KAAK,MAAM,IAAI;AAE9C,UAAI,MAAM,YAAY,GAAG;AAEvB,YAAI,MAAM,SAAS,gBAAgB;AACjC,kBAAQ,KAAK,GAAG,cAAc,UAAU,UAAU,CAAC;AAAA,QACrD;AAAA,MACF,WAAW,MAAM,OAAO,GAAG;AACzB,cAAM,MAAM,aAAAA,QAAS,QAAQ,MAAM,IAAI;AACvC,YAAI,WAAW,SAAS,GAAG,GAAG;AAC5B,kBAAQ,KAAK,QAAQ;AAAA,QACvB;AAAA,MACF;AAAA,IACF;AAAA,EACF,SAAS,GAAG;AAEV,YAAQ,MAAM,oCAAoC,GAAG,KAAK,CAAC;AAAA,EAC7D;AAEA,SAAO;AACT;AAUA,SAAS,wBAAwBC,UAAiB,SAA0B;AAG1E,QAAM,cAAc;AAIpB,QAAM,oBAAoB;AAI1B,QAAM,iBAAiB;AAEvB,MAAI,SAASA;AAGb,WAAS,OAAO,QAAQ,aAAa,CAAC,OAAO,QAAQ,YAAY,UAAU;AACzE,WAAO,kBAAkB,OAAO,QAAQ,YAAY,OAAO,OAAO;AAAA,EACpE,CAAC;AAGD,WAAS,OAAO;AAAA,IACd;AAAA,IACA,CAAC,OAAO,QAAQ,YAAY,UAAU;AACpC,aAAO,kBAAkB,OAAO,QAAQ,YAAY,OAAO,OAAO;AAAA,IACpE;AAAA,EACF;AAGA,WAAS,OAAO;AAAA,IACd;AAAA,IACA,CAAC,OAAO,QAAQ,YAAY,UAAU;AACpC,aAAO,kBAAkB,OAAO,QAAQ,YAAY,OAAO,OAAO;AAAA,IACpE;AAAA,EACF;AAEA,SAAO;AACT;AAaA,SAAS,kBACP,OACA,QACA,YACA,OACA,SACQ;AAER,MAAI,aAAa,KAAK,UAAU,GAAG;AACjC,WAAO;AAAA,EACT;AAGA,MAAI,UAAU,KAAK,UAAU,GAAG;AAC9B,WAAO;AAAA,EACT;AAGA,MAAI,SAAS;AACX,UAAM,eAAe,aAAAD,QAAS,QAAQ,SAAS,UAAU;AAGzD,YAAI,uBAAW,GAAG,YAAY,KAAK,GAAG;AACpC,aAAO,GAAG,MAAM,GAAG,UAAU,MAAM,KAAK;AAAA,IAC1C;AAGA,YAAI,uBAAW,aAAAA,QAAS,KAAK,cAAc,UAAU,CAAC,GAAG;AAEvD,aAAO,GAAG,MAAM,GAAG,UAAU,YAAY,KAAK;AAAA,IAChD;AAGA,YAAI,uBAAW,GAAG,YAAY,MAAM,GAAG;AACrC,aAAO,GAAG,MAAM,GAAG,UAAU,OAAO,KAAK;AAAA,IAC3C;AACA,YAAI,uBAAW,aAAAA,QAAS,KAAK,cAAc,WAAW,CAAC,GAAG;AACxD,aAAO,GAAG,MAAM,GAAG,UAAU,aAAa,KAAK;AAAA,IACjD;AAGA,YAAI,uBAAW,GAAG,YAAY,MAAM,GAAG;AACrC,aAAO,GAAG,MAAM,GAAG,UAAU,OAAO,KAAK;AAAA,IAC3C;AACA,YAAI,uBAAW,aAAAA,QAAS,KAAK,cAAc,WAAW,CAAC,GAAG;AACxD,aAAO,GAAG,MAAM,GAAG,UAAU,aAAa,KAAK;AAAA,IACjD;AAAA,EACF;AAGA,SAAO,GAAG,MAAM,GAAG,UAAU,MAAM,KAAK;AAC1C;AAkBO,SAAS,wBAAwBE,SAAsB;AAC5D,QAAM,QAAQ,cAAcA,SAAQ,CAAC,OAAO,MAAM,CAAC;AAEnD,aAAW,YAAY,OAAO;AAC5B,UAAMD,eAAU,yBAAa,UAAU,OAAO;AAC9C,UAAM,UAAU,aAAAD,QAAS,QAAQ,QAAQ;AACzC,UAAM,YAAY,wBAAwBC,UAAS,OAAO;AAE1D,QAAIA,aAAY,WAAW;AACzB,oCAAc,UAAU,WAAW,OAAO;AAAA,IAC5C;AAAA,EACF;AACF;;;AFzQA,IAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AACjC,IAAM,YAAY,KAAK,SAAS,SAAS;AAEzC,IAAM,YAAY,KAAK,KAAK,CAAC,QAAQ,CAAC,IAAI,WAAW,IAAI,CAAC;AAE1D,IAAME,eAAc,QAAQ,IAAI;AAChC,IAAM,eAAe,aAAAC,QAAK,KAAKD,cAAa,eAAe;AAC3D,IAAM,mBAAmB,aAAAC,QAAK,KAAKD,cAAa,2BAA2B;AAG3E,IAAM,aAAa,eAAeA,YAAW;AAC7C,IAAM,SAAS,aAAa,cAAc;AAG1C,IAAM,kBAAkB,cAAc,UAAa,CAAC;AAepD,SAAS,UAAU,OAA2B;AAC5C,UAAQ,IAAI,KAAK,UAAU,KAAK,CAAC;AACnC;AAKA,SAAS,oBACP,eACA;AACA,SAAO;AAAA,IACL,SAAS;AAAA,IACT,iBAAiB;AAAA,MACf,GAAG;AAAA,MACH,GAAG;AAAA,MACH,SAAS,CAAC,GAAG,sBAAsB;AAAA;AAAA,MAEnC,cAAc;AAAA,MACd,qBAAqB;AAAA;AAAA,MAErB,8BAA8B;AAAA;AAAA;AAAA,MAG9B,eAAe;AAAA;AAAA,MAEf,aAAa;AAAA,MACb,iBAAiB,aAAAC,QAAK,KAAK,QAAQ,cAAc;AAAA,IACnD;AAAA,EACF;AACF;AAKA,SAAS,qBAAqB,cAAkC;AAC9D,QAAM,gBAAgB,iBAAiB,YAAY;AACnD,QAAM,gBAAgB,oBAAoB,aAAa;AAEvD,gBAAc,gBAAgB,gBAAgB;AAE9C,gCAAc,kBAAkB,KAAK,UAAU,eAAe,MAAM,CAAC,CAAC;AACtE,UAAQ,IAAI,kDAAkD;AAG9D,QAAM,WAAW;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,MAAI,iBAAiB;AACnB,aAAS,KAAK,YAAY,MAAM;AAAA,EAClC;AAEA,MAAI;AACF,2CAAa,OAAO,UAAU;AAAA,MAC5B,OAAO;AAAA,MACP,KAAKD;AAAA,IACP,CAAC;AACD,YAAQ,IAAI,kCAAkC;AAAA,EAChD,SAAS,cAAmB;AAG1B,UAAM,YAAY,aAAa;AAC/B,UAAM,kBAAkB,aAAAC,QAAK;AAAA,MAC3BD;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,YAAI,uBAAW,eAAe,GAAG;AAC/B,cAAQ,KAAK,EAAE;AACf,cAAQ,KAAK,sBAAsB;AACnC,cAAQ;AAAA,QACN;AAAA,MACF;AACA,cAAQ;AAAA,QACN;AAAA,MACF;AACA,cAAQ,KAAK,EAAE;AACf,cAAQ;AAAA,QACN;AAAA,MACF;AACA,cAAQ;AAAA,QACN;AAAA,MACF;AACA,cAAQ,KAAK,iDAAiD;AAC9D,cAAQ;AAAA,QACN;AAAA,MACF;AACA,cAAQ,KAAK,yDAAyD;AACtE,cAAQ,KAAK,EAAE;AACf,cAAQ;AAAA,QACN;AAAA,MACF;AACA,cAAQ;AAAA,QACN;AAAA,MACF;AACA,cAAQ;AAAA,QACN;AAAA,MACF;AACA,cAAQ,KAAK,EAAE;AACf,cAAQ,IAAI,uDAAuD;AAAA,IACrE,OAAO;AACL,cAAQ,MAAM,iDAAiD;AAC/D,YAAM;AAAA,IACR;AAAA,EACF;AAGA,MAAI,iBAAiB,OAAO;AAC1B,YAAQ,IAAI,sDAAsD;AAClE,UAAM,aAAa,aAAAC,QAAK,KAAKD,cAAa,MAAM;AAChD,4BAAwB,UAAU;AAClC,YAAQ,IAAI,gCAAgC;AAAA,EAC9C;AACF;AAMA,SAAS,oBAAoB,cAAkC;AAC7D,QAAM,gBAAgB,iBAAiB,YAAY;AACnD,QAAM,gBAAgB,oBAAoB,aAAa;AAGvD,gCAAc,kBAAkB,KAAK,UAAU,eAAe,MAAM,CAAC,CAAC;AAGtE,QAAM,aAAa,aAAAC,QAAK,KAAKD,cAAa,MAAM;AAChD,MAAI,KAAC,uBAAW,UAAU,GAAG;AAC3B,8BAAU,YAAY,EAAE,WAAW,KAAK,CAAC;AAAA,EAC3C;AAGA,MAAI,qBAA+B,CAAC;AACpC,MAAI,aAAa;AACjB,MAAI,eAAe;AAGnB,QAAM,WAAW;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,MAAI,iBAAiB;AAEnB,aAAS,OAAO,GAAG,GAAG,YAAY,MAAM;AAAA,EAC1C;AAGA,QAAM,kBAAc,4BAAM,OAAO,UAAU;AAAA,IACzC,KAAKA;AAAA,IACL,OAAO,CAAC,UAAU,QAAQ,MAAM;AAAA,EAClC,CAAC;AAGD,QAAM,UAAU,MAAM;AACpB,YAAI,uBAAW,gBAAgB,GAAG;AAChC,iCAAW,gBAAgB;AAAA,IAC7B;AACA,gBAAY,KAAK;AAAA,EACnB;AAEA,UAAQ,GAAG,UAAU,MAAM;AACzB,YAAQ;AACR,YAAQ,KAAK,CAAC;AAAA,EAChB,CAAC;AAED,UAAQ,GAAG,WAAW,MAAM;AAC1B,YAAQ;AACR,YAAQ,KAAK,CAAC;AAAA,EAChB,CAAC;AAKD,MAAI,SAAS;AAGb,QAAM,YAAY,CAAC,QACjB,IAAI;AAAA,IACF;AAAA,IACA;AAAA,EACF;AAGF,QAAM,0BACJ;AACF,QAAM,2BACJ;AACF,QAAM,kBAAkB;AAExB,QAAM,cAAc,CAAC,SAAiB;AACpC,UAAM,YAAY,UAAU,IAAI;AAEhC,QAAI,wBAAwB,KAAK,SAAS,GAAG;AAE3C,2BAAqB,CAAC;AACtB,mBAAa;AACb,qBAAe;AACf,gBAAU,EAAE,OAAO,gBAAgB,CAAC;AAAA,IACtC,WAAW,yBAAyB,KAAK,SAAS,GAAG;AAGnD,YAAM,QAAQ,UAAU,MAAM,+BAA+B;AAC7D,UAAI,OAAO;AACT,qBAAa,SAAS,MAAM,CAAC,GAAG,EAAE;AAAA,MACpC;AAGA,UAAI,eAAe,KAAK,iBAAiB,OAAO;AAC9C,YAAI;AACF,kCAAwB,UAAU;AAAA,QACpC,SAAS,GAAG;AAEV,kBAAQ,MAAM,yCAAyC,CAAC;AAAA,QAC1D;AAAA,MACF;AAEA,UAAI,aAAa,GAAG;AAClB,kBAAU;AAAA,UACR,OAAO;AAAA,UACP,QAAQ;AAAA,UACR,UAAU;AAAA,UACV,aAAa;AAAA,QACf,CAAC;AAAA,MACH,OAAO;AACL,kBAAU;AAAA,UACR,OAAO;AAAA,UACP,QAAQ;AAAA,UACR,UAAU;AAAA,UACV,aAAa,eAAe,IAAI,qBAAqB;AAAA,QACvD,CAAC;AAAA,MACH;AAAA,IACF,WAAW,gBAAgB,KAAK,SAAS,GAAG;AAE1C,yBAAmB,KAAK,UAAU,KAAK,CAAC;AACxC,UAAI,UAAU,SAAS,UAAU,GAAG;AAClC;AAAA,MACF,WAAW,UAAU,SAAS,YAAY,GAAG;AAC3C;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,cAAY,OAAO,GAAG,QAAQ,CAAC,SAAiB;AAC9C,cAAU,KAAK,SAAS;AACxB,UAAM,QAAQ,OAAO,MAAM,IAAI;AAC/B,aAAS,MAAM,IAAI,KAAK;AACxB,eAAW,QAAQ,OAAO;AACxB,UAAI,KAAK,KAAK,GAAG;AACf,oBAAY,IAAI;AAAA,MAClB;AAAA,IACF;AAAA,EACF,CAAC;AAED,cAAY,OAAO,GAAG,QAAQ,CAAC,SAAiB;AAE9C,YAAQ,OAAO,MAAM,KAAK,SAAS,CAAC;AAAA,EACtC,CAAC;AAED,cAAY,GAAG,SAAS,CAAC,QAAQ;AAC/B,YAAQ,MAAM,yBAAyB,GAAG;AAC1C,YAAQ;AACR,YAAQ,KAAK,CAAC;AAAA,EAChB,CAAC;AAED,cAAY,GAAG,QAAQ,CAAC,SAAS;AAC/B,YAAQ;AACR,QAAI,SAAS,GAAG;AACd,cAAQ,KAAK,QAAQ,CAAC;AAAA,IACxB;AAAA,EACF,CAAC;AACH;AAMA,SAAS,qBAAqB;AAC5B,QAAM,WAAW,aAAAC,QAAK,KAAKD,cAAa,QAAQ;AAChD,MAAI,KAAC,uBAAW,QAAQ,GAAG;AACzB,8BAAU,UAAU,EAAE,WAAW,KAAK,CAAC;AAAA,EACzC;AACA,QAAM,aAAa,aAAAC,QAAK,KAAK,UAAU,sBAAsB;AAC7D,gCAAc,YAAY,KAAK,UAAU,EAAE,OAAO,GAAG,MAAM,CAAC,CAAC;AAC/D;AAGA,IAAI,KAAC,uBAAW,YAAY,GAAG;AAC7B,UAAQ,MAAM,qCAAqCD,YAAW;AAC9D,UAAQ,KAAK,CAAC;AAChB;AAEA,IAAI;AAEF,qBAAmB;AAGnB,QAAM,eAAe,mBAAmBA,YAAW;AAEnD,MAAI,WAAW;AAEb,wBAAoB,YAAY;AAAA,EAClC,OAAO;AAEL,YAAQ,IAAI,2BAA2B,MAAM,KAAK;AAClD,YAAQ;AAAA,MACN,SAAS,aAAa,YAAY,CAAC;AAAA,IACrC;AACA,yBAAqB,YAAY;AACjC,YAAQ,IAAI,uBAAuB;AAGnC,YAAI,uBAAW,gBAAgB,GAAG;AAChC,iCAAW,gBAAgB;AAAA,IAC7B;AAAA,EACF;AACF,SAAS,OAAO;AACd,UAAQ,MAAM,yBAAyB,KAAK;AAE5C,UAAI,uBAAW,gBAAgB,GAAG;AAChC,+BAAW,gBAAgB;AAAA,EAC7B;AACA,UAAQ,KAAK,CAAC;AAChB;","names":["import_fs","import_path","path","projectRoot","userOutDir","outDir","import_fs","import_path","nodePath","content","outDir","projectRoot","path"]}
|
|
1
|
+
{"version":3,"sources":["../src/moose-tspc.ts","../src/compiler-config.ts","../src/commons.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * Pre-compiles TypeScript app code with moose compiler plugins and typia transforms.\n *\n * Usage: moose-tspc [outDir] [--watch]\n * outDir: Output directory for compiled files (optional, overrides tsconfig)\n * --watch: Enable watch mode for incremental compilation (outputs JSON events)\n *\n * Output directory is determined by (in priority order):\n * 1. CLI argument (if provided) - used by Docker builds\n * 2. User's tsconfig.json outDir setting (if specified)\n * 3. Default: .moose/compiled\n *\n * This script creates a temporary tsconfig that extends the user's config and adds\n * the required moose compiler plugins, then runs tspc to compile with transforms.\n *\n * In watch mode, outputs JSON events to stdout for the Rust CLI to parse:\n * {\"event\": \"compile_start\"}\n * {\"event\": \"compile_complete\", \"errors\": 0, \"warnings\": 2}\n * {\"event\": \"compile_error\", \"errors\": 3, \"diagnostics\": [...]}\n */\nimport { execFileSync, spawn } from \"child_process\";\nimport { existsSync, writeFileSync, unlinkSync, mkdirSync } from \"fs\";\nimport path from \"path\";\nimport {\n MOOSE_COMPILER_PLUGINS,\n MOOSE_COMPILER_OPTIONS,\n detectModuleSystem,\n getModuleOptions,\n getSourceDir,\n readUserOutDir,\n DEFAULT_OUT_DIR,\n type ModuleSystem,\n} from \"./compiler-config\";\nimport { rewriteImportExtensions } from \"./commons\";\n\n// Parse command line arguments\nconst args = process.argv.slice(2);\nconst watchMode = args.includes(\"--watch\");\n// CLI argument takes priority (for Docker builds), then tsconfig, then default\nconst cliOutDir = args.find((arg) => !arg.startsWith(\"--\"));\n\nconst projectRoot = process.cwd();\nconst tsconfigPath = path.join(projectRoot, \"tsconfig.json\");\nconst tempTsconfigPath = path.join(projectRoot, \"tsconfig.moose-build.json\");\n\n// Determine outDir - CLI arg > tsconfig > default\nconst userOutDir = readUserOutDir(projectRoot);\nconst outDir = cliOutDir || userOutDir || DEFAULT_OUT_DIR;\n// add --outDir flag if user hasn't specified in tsconfig\n// (if CLI arg is provided, we always pass it explicitly)\nconst shouldAddOutDir = cliOutDir !== undefined || !userOutDir;\n\n/**\n * JSON event protocol for watch mode communication with Rust CLI.\n */\ninterface CompileEvent {\n event: \"compile_start\" | \"compile_complete\" | \"compile_error\";\n errors?: number;\n warnings?: number;\n diagnostics?: string[];\n}\n\n/**\n * Emit a JSON event to stdout for the Rust CLI to parse.\n */\nfunction emitEvent(event: CompileEvent): void {\n console.log(JSON.stringify(event));\n}\n\n/**\n * Create the build tsconfig with moose plugins.\n */\nfunction createBuildTsconfig(\n moduleOptions: ReturnType<typeof getModuleOptions>,\n) {\n return {\n extends: \"./tsconfig.json\",\n compilerOptions: {\n ...MOOSE_COMPILER_OPTIONS,\n ...moduleOptions,\n plugins: [...MOOSE_COMPILER_PLUGINS],\n // Skip type checking of declaration files to avoid dual-package conflicts\n skipLibCheck: true,\n skipDefaultLibCheck: true,\n // Additional settings to handle module resolution conflicts\n allowSyntheticDefaultImports: true,\n // Block emission on errors so build and dev behave consistently\n noEmitOnError: true,\n // Enable incremental compilation for faster rebuilds\n incremental: true,\n tsBuildInfoFile: path.join(outDir, \".tsbuildinfo\"),\n },\n };\n}\n\n/**\n * Run a single compilation (non-watch mode).\n */\nfunction runSingleCompilation(moduleSystem: ModuleSystem): void {\n const moduleOptions = getModuleOptions(moduleSystem);\n const buildTsconfig = createBuildTsconfig(moduleOptions);\n\n writeFileSync(tempTsconfigPath, JSON.stringify(buildTsconfig, null, 2));\n console.log(\"Created temporary tsconfig with moose plugins...\");\n\n // Build tspc arguments - only add --outDir if user hasn't specified one in tsconfig\n const tspcArgs = [\n \"tspc\",\n \"-p\",\n tempTsconfigPath,\n \"--rootDir\",\n \".\",\n \"--sourceMap\",\n \"--inlineSources\",\n ];\n if (shouldAddOutDir) {\n tspcArgs.push(\"--outDir\", outDir);\n }\n\n execFileSync(\"npx\", tspcArgs, {\n stdio: \"inherit\",\n cwd: projectRoot,\n });\n console.log(\"TypeScript compilation complete.\");\n\n // Post-process ESM output to add .js extensions to relative imports\n if (moduleSystem === \"esm\") {\n console.log(\"Post-processing ESM imports to add .js extensions...\");\n const fullOutDir = path.join(projectRoot, outDir);\n rewriteImportExtensions(fullOutDir);\n console.log(\"ESM import rewriting complete.\");\n }\n}\n\n/**\n * Run watch mode compilation with JSON event output.\n * Uses tspc --watch and parses its output to emit structured events.\n */\nfunction runWatchCompilation(moduleSystem: ModuleSystem): void {\n const moduleOptions = getModuleOptions(moduleSystem);\n const buildTsconfig = createBuildTsconfig(moduleOptions);\n\n // Write the tsconfig (it stays for the duration of watch mode)\n writeFileSync(tempTsconfigPath, JSON.stringify(buildTsconfig, null, 2));\n\n // Ensure output directory exists for incremental build info\n const fullOutDir = path.join(projectRoot, outDir);\n if (!existsSync(fullOutDir)) {\n mkdirSync(fullOutDir, { recursive: true });\n }\n\n // Track diagnostics between compilation cycles\n let currentDiagnostics: string[] = [];\n let errorCount = 0;\n let warningCount = 0;\n\n // Build tspc arguments - only add --outDir if user hasn't specified one in tsconfig\n const tspcArgs = [\n \"tspc\",\n \"-p\",\n tempTsconfigPath,\n \"--rootDir\",\n \".\",\n \"--sourceMap\",\n \"--inlineSources\",\n \"--watch\",\n \"--preserveWatchOutput\",\n ];\n if (shouldAddOutDir) {\n // Insert --outDir after --rootDir and \".\" so rootDir is not clobbered\n tspcArgs.splice(6, 0, \"--outDir\", outDir);\n }\n\n // Spawn tspc in watch mode\n const tspcProcess = spawn(\"npx\", tspcArgs, {\n cwd: projectRoot,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n\n // Handle process termination\n const cleanup = () => {\n if (existsSync(tempTsconfigPath)) {\n unlinkSync(tempTsconfigPath);\n }\n tspcProcess.kill();\n };\n\n process.on(\"SIGINT\", () => {\n cleanup();\n process.exit(0);\n });\n\n process.on(\"SIGTERM\", () => {\n cleanup();\n process.exit(0);\n });\n\n // Parse tspc output line by line\n // Pattern matching approach inspired by tsc-watch (github.com/gilamran/tsc-watch)\n // which also parses tsc stdout to detect compilation events\n let buffer = \"\";\n\n // Strip ANSI escape codes for reliable pattern matching (standard regex pattern)\n const stripAnsi = (str: string) =>\n str.replace(\n /[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d/#&.:=?%@~_]*)*)?[\\u0007])|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))/g,\n \"\",\n );\n\n // tsc watch mode patterns (with timestamp prefix like \"12:00:00 AM - \")\n const compilationStartedRegex =\n /Starting compilation in watch mode|Starting incremental compilation/;\n const compilationCompleteRegex =\n /Found\\s+(\\d+)\\s+error(?:s)?\\..*Watching for file changes/;\n const diagnosticRegex = /\\(\\d+,\\d+\\):\\s*(error|warning)\\s+TS\\d+:/;\n\n const processLine = (line: string) => {\n const cleanLine = stripAnsi(line);\n\n if (compilationStartedRegex.test(cleanLine)) {\n // New compilation cycle starting\n currentDiagnostics = [];\n errorCount = 0;\n warningCount = 0;\n emitEvent({ event: \"compile_start\" });\n } else if (compilationCompleteRegex.test(cleanLine)) {\n // Compilation complete - parse error count from tsc summary line\n // Format: \"12:00:00 AM - Found 0 errors. Watching for file changes.\"\n const match = cleanLine.match(/Found\\s+(\\d+)\\s+error(?:s)?\\./);\n if (match) {\n errorCount = parseInt(match[1], 10);\n }\n\n // Post-process ESM if successful\n if (errorCount === 0 && moduleSystem === \"esm\") {\n try {\n rewriteImportExtensions(fullOutDir);\n } catch (e) {\n // Log but don't fail - import rewriting is best-effort\n console.error(\"Warning: ESM import rewriting failed:\", e);\n }\n }\n\n if (errorCount > 0) {\n emitEvent({\n event: \"compile_error\",\n errors: errorCount,\n warnings: warningCount,\n diagnostics: currentDiagnostics,\n });\n } else {\n emitEvent({\n event: \"compile_complete\",\n errors: 0,\n warnings: warningCount,\n diagnostics: warningCount > 0 ? currentDiagnostics : undefined,\n });\n }\n } else if (diagnosticRegex.test(cleanLine)) {\n // This is a diagnostic line (error or warning)\n currentDiagnostics.push(cleanLine.trim());\n if (cleanLine.includes(\": error \")) {\n errorCount++;\n } else if (cleanLine.includes(\": warning \")) {\n warningCount++;\n }\n }\n };\n\n tspcProcess.stdout.on(\"data\", (data: Buffer) => {\n buffer += data.toString();\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() || \"\"; // Keep incomplete line in buffer\n for (const line of lines) {\n if (line.trim()) {\n processLine(line);\n }\n }\n });\n\n tspcProcess.stderr.on(\"data\", (data: Buffer) => {\n // Forward stderr for debugging but don't parse it\n process.stderr.write(data.toString());\n });\n\n tspcProcess.on(\"error\", (err) => {\n console.error(\"Failed to start tspc:\", err);\n cleanup();\n process.exit(1);\n });\n\n tspcProcess.on(\"exit\", (code) => {\n cleanup();\n if (code !== 0) {\n process.exit(code || 1);\n }\n });\n}\n\n/**\n * Write compile metadata to .moose/.compile-config.json\n * This allows Rust CLI to know where compiled output is without duplicating logic\n */\nfunction writeCompileConfig() {\n const mooseDir = path.join(projectRoot, \".moose\");\n if (!existsSync(mooseDir)) {\n mkdirSync(mooseDir, { recursive: true });\n }\n const configPath = path.join(mooseDir, \".compile-config.json\");\n writeFileSync(configPath, JSON.stringify({ outDir }, null, 2));\n}\n\n// Main execution\nif (!existsSync(tsconfigPath)) {\n console.error(\"Error: tsconfig.json not found in\", projectRoot);\n process.exit(1);\n}\n\ntry {\n // Write compile config so Rust CLI knows where output is\n writeCompileConfig();\n\n // Auto-detect module system from package.json\n const moduleSystem = detectModuleSystem(projectRoot);\n\n if (watchMode) {\n // Watch mode - run indefinitely with JSON event output\n runWatchCompilation(moduleSystem);\n } else {\n // Single compilation mode\n console.log(`Compiling TypeScript to ${outDir}...`);\n console.log(\n `Using ${moduleSystem.toUpperCase()} module output (detected from package.json)...`,\n );\n runSingleCompilation(moduleSystem);\n console.log(\"Compilation complete.\");\n\n // Clean up the temporary tsconfig\n if (existsSync(tempTsconfigPath)) {\n unlinkSync(tempTsconfigPath);\n }\n }\n} catch (error) {\n console.error(\"Build process failed:\", error);\n // Clean up the temporary tsconfig\n if (existsSync(tempTsconfigPath)) {\n unlinkSync(tempTsconfigPath);\n }\n process.exit(1);\n}\n","import { existsSync, readFileSync } from \"fs\";\nimport path from \"path\";\n\n/**\n * Shared TypeScript compiler configuration for moose projects.\n * Used by both moose-runner.ts (runtime) and moose-tspc.ts (pre-compilation).\n *\n * Moose now always uses pre-compiled JavaScript - no ts-node fallback.\n */\n\nexport const MOOSE_COMPILER_PLUGINS = [\n {\n transform: \"./node_modules/@514labs/moose-lib/dist/compilerPlugin.js\",\n // No longer using transformProgram - direct typia integration eliminates\n // the need for program replacement and the associated incremental compilation issues\n },\n {\n // Keep typia plugin for users who use typia directly (not through Moose resources)\n transform: \"typia/lib/transform\",\n },\n] as const;\n\n// Options required for moose compilation\n// Note: We only set what's absolutely necessary to avoid conflicts with user projects\nexport const MOOSE_COMPILER_OPTIONS = {\n experimentalDecorators: true,\n esModuleInterop: true,\n // Disable strict module syntax checking to avoid dual-package type conflicts\n // This prevents errors where the same type imported with different resolution\n // modes (CJS vs ESM) is treated as incompatible\n verbatimModuleSyntax: false,\n} as const;\n\n// Module resolution options - only applied if not already set in user's tsconfig\n// These help with ESM/CJS interop but can be overridden by user config\nexport const MOOSE_MODULE_OPTIONS = {\n module: \"NodeNext\",\n moduleResolution: \"NodeNext\",\n} as const;\n\n/**\n * Default source directory for user code.\n * Can be overridden via MOOSE_SOURCE_DIR environment variable.\n */\nexport function getSourceDir(): string {\n return process.env.MOOSE_SOURCE_DIR || \"app\";\n}\n\n/**\n * Default output directory for compiled code.\n */\nexport const DEFAULT_OUT_DIR = \".moose/compiled\";\n\n/**\n * Read the user's tsconfig.json and extract the outDir setting.\n * Supports JSONC (JSON with Comments) by evaluating as JavaScript\n * (JSON with comments is valid JS in ES2019+).\n *\n * Security note: This uses eval-like behavior (new Function), which means\n * malicious code in tsconfig.json would execute. This is acceptable because:\n * - The user controls their own tsconfig.json\n * - Same trust model as running `tsc` or any other tool that processes the file\n * - If you clone and run untrusted code, you're already at risk\n *\n * Returns the outDir if specified, or null if not.\n */\nexport function readUserOutDir(\n projectRoot: string = process.cwd(),\n): string | null {\n try {\n let content = readFileSync(\n path.join(projectRoot, \"tsconfig.json\"),\n \"utf-8\",\n );\n // Strip UTF-8 BOM if present\n if (content.charCodeAt(0) === 0xfeff) {\n content = content.slice(1);\n }\n // eslint-disable-next-line no-eval\n const tsconfig = eval(`(${content})`);\n return tsconfig.compilerOptions?.outDir || null;\n } catch {\n return null;\n }\n}\n\n/**\n * Get the output directory for compiled code.\n * Uses user's tsconfig outDir if specified, otherwise defaults to .moose/compiled\n */\nexport function getOutDir(projectRoot: string = process.cwd()): string {\n const userOutDir = readUserOutDir(projectRoot);\n return userOutDir || DEFAULT_OUT_DIR;\n}\n\n/**\n * Get the path to the compiled index.js file.\n */\nexport function getCompiledIndexPath(\n projectRoot: string = process.cwd(),\n): string {\n const outDir = getOutDir(projectRoot);\n const sourceDir = getSourceDir();\n // Resolve so that absolute outDir from tsconfig is handled correctly\n return path.resolve(projectRoot, outDir, sourceDir, \"index.js\");\n}\n\n/**\n * Check if pre-compiled artifacts exist for the current project.\n */\nexport function hasCompiledArtifacts(\n projectRoot: string = process.cwd(),\n): boolean {\n return existsSync(getCompiledIndexPath(projectRoot));\n}\n\n/**\n * Module system type for compilation output.\n */\nexport type ModuleSystem = \"esm\" | \"cjs\";\n\n/**\n * Detects the module system from the user's package.json.\n * Returns 'esm' if package.json has \"type\": \"module\", otherwise 'cjs'.\n *\n * @param projectRoot - Root directory containing package.json (defaults to cwd)\n * @returns The detected module system\n */\nexport function detectModuleSystem(\n projectRoot: string = process.cwd(),\n): ModuleSystem {\n const pkgPath = path.join(projectRoot, \"package.json\");\n\n if (existsSync(pkgPath)) {\n try {\n const pkgContent = readFileSync(pkgPath, \"utf-8\");\n const pkg = JSON.parse(pkgContent);\n if (pkg.type === \"module\") {\n return \"esm\";\n }\n } catch (e) {\n // If parsing fails, default to CJS\n console.debug(\n `[moose] Failed to parse package.json at ${pkgPath}, defaulting to CJS:`,\n e,\n );\n }\n }\n\n return \"cjs\";\n}\n\n/**\n * Get compiler module options based on detected module system.\n *\n * @param moduleSystem - The module system to get options for\n * @returns Compiler options for module and moduleResolution\n */\nexport function getModuleOptions(moduleSystem: ModuleSystem): {\n module: string;\n moduleResolution: string;\n} {\n if (moduleSystem === \"esm\") {\n return {\n module: \"ES2022\",\n moduleResolution: \"bundler\",\n };\n }\n return {\n module: \"CommonJS\",\n moduleResolution: \"Node\",\n };\n}\n\n/**\n * Dynamic module loader that works with both CJS and ESM.\n * Uses detected module system to determine loading strategy.\n *\n * @param modulePath - Path to the module to load\n * @param projectRoot - Root directory for module system detection\n * @returns The loaded module\n */\nexport async function loadModule<T = any>(\n modulePath: string,\n projectRoot: string = process.cwd(),\n): Promise<T> {\n const moduleSystem = detectModuleSystem(projectRoot);\n\n if (moduleSystem === \"esm\") {\n // Use dynamic import for ESM\n // pathToFileURL is needed for Windows compatibility with absolute paths\n const { pathToFileURL } = await import(\"url\");\n const fileUrl = pathToFileURL(modulePath).href;\n return await import(fileUrl);\n }\n\n // Use require for CJS\n // Note: In ESM builds (compiled by tsup), this code path is replaced with\n // the appropriate ESM imports. The dual-package build ensures compatibility.\n return require(modulePath);\n}\n","import {\n existsSync,\n readdirSync,\n readFileSync,\n statSync,\n writeFileSync,\n} from \"fs\";\nimport nodePath from \"path\";\nimport { createClient } from \"@clickhouse/client\";\nimport { KafkaJS } from \"@514labs/kafka-javascript\";\nimport { SASLOptions } from \"@514labs/kafka-javascript/types/kafkajs\";\nconst { Kafka } = KafkaJS;\ntype Kafka = KafkaJS.Kafka;\ntype Consumer = KafkaJS.Consumer;\nexport type Producer = KafkaJS.Producer;\n\n/**\n * Utility function for compiler-related logging that can be disabled via environment variable.\n * Set MOOSE_DISABLE_COMPILER_LOGS=true to suppress these logs (useful for testing environments).\n */\n\n/**\n * Returns true if the value is a common truthy string: \"1\", \"true\", \"yes\", \"on\" (case-insensitive).\n */\nfunction isTruthy(value: string | undefined): boolean {\n if (!value) return false;\n switch (value.trim().toLowerCase()) {\n case \"1\":\n case \"true\":\n case \"yes\":\n case \"on\":\n return true;\n default:\n return false;\n }\n}\n\nexport const compilerLog = (message: string) => {\n if (!isTruthy(process.env.MOOSE_DISABLE_COMPILER_LOGS)) {\n console.log(message);\n }\n};\n\nexport const antiCachePath = (path: string) =>\n `${path}?num=${Math.random().toString()}&time=${Date.now()}`;\n\nexport const getFileName = (filePath: string) => {\n const regex = /\\/([^\\/]+)\\.ts/;\n const matches = filePath.match(regex);\n if (matches && matches.length > 1) {\n return matches[1];\n }\n return \"\";\n};\n\ninterface ClientConfig {\n username: string;\n password: string;\n database: string;\n useSSL: string;\n host: string;\n port: string;\n}\n\nexport const getClickhouseClient = ({\n username,\n password,\n database,\n useSSL,\n host,\n port,\n}: ClientConfig) => {\n const protocol =\n useSSL === \"1\" || useSSL.toLowerCase() === \"true\" ? \"https\" : \"http\";\n console.log(`Connecting to Clickhouse at ${protocol}://${host}:${port}`);\n return createClient({\n url: `${protocol}://${host}:${port}`,\n username: username,\n password: password,\n database: database,\n application: \"moose\",\n // Note: wait_end_of_query is configured per operation type, not globally\n // to preserve SELECT query performance while ensuring INSERT/DDL reliability\n });\n};\n\nexport type CliLogData = {\n message_type?: \"Info\" | \"Success\" | \"Warning\" | \"Error\" | \"Highlight\";\n action: string;\n message: string;\n};\n\nexport const cliLog: (log: CliLogData) => void = (log) => {\n const level =\n log.message_type === \"Error\" ? \"error\"\n : log.message_type === \"Warning\" ? \"warn\"\n : \"info\";\n\n const structuredLog = {\n __moose_structured_log__: true,\n level,\n message: log.message,\n resource_type: \"runtime\",\n cli_action: log.action,\n cli_message_type: log.message_type ?? \"Info\",\n timestamp: new Date().toISOString(),\n };\n\n process.stderr.write(JSON.stringify(structuredLog) + \"\\n\");\n};\n\n/**\n * Method to change .ts, .cts, and .mts to .js, .cjs, and .mjs\n * This is needed because 'import' does not support .ts, .cts, and .mts\n */\nexport function mapTstoJs(filePath: string): string {\n return filePath\n .replace(/\\.ts$/, \".js\")\n .replace(/\\.cts$/, \".cjs\")\n .replace(/\\.mts$/, \".mjs\");\n}\n\n/**\n * Walks a directory recursively and returns all files matching the given extensions.\n * Skips node_modules directories.\n *\n * @param dir - Directory to walk\n * @param extensions - File extensions to include (e.g., [\".js\", \".mjs\"])\n * @returns Array of file paths\n */\nfunction walkDirectory(dir: string, extensions: string[]): string[] {\n const results: string[] = [];\n\n if (!existsSync(dir)) {\n return results;\n }\n\n try {\n const entries = readdirSync(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = nodePath.join(dir, entry.name);\n\n if (entry.isDirectory()) {\n // Skip node_modules\n if (entry.name !== \"node_modules\") {\n results.push(...walkDirectory(fullPath, extensions));\n }\n } else if (entry.isFile()) {\n const ext = nodePath.extname(entry.name);\n if (extensions.includes(ext)) {\n results.push(fullPath);\n }\n }\n }\n } catch (e) {\n // Log error in case it is something the user can/should act on\n console.debug(`[moose] Failed to read directory ${dir}:`, e);\n }\n\n return results;\n}\n\n/**\n * Adds .js extension to relative import paths that don't have an extension.\n * Handles import/export from statements and dynamic imports.\n *\n * @param content - JavaScript file content\n * @param fileDir - Directory containing the file being processed (for resolving paths)\n * @returns Content with .js extensions added to relative imports\n */\nfunction addJsExtensionToImports(content: string, fileDir?: string): string {\n // Pattern for 'from' statements with relative paths\n // Matches: from './foo', from \"../bar\", from './utils/helper'\n const fromPattern = /(from\\s+['\"])(\\.\\.?\\/[^'\"]*?)(['\"])/g;\n\n // Pattern for side-effect-only imports with relative paths\n // Matches: import './foo', import \"../bar\" (no 'from' keyword, just importing for side effects)\n const bareImportPattern = /(import\\s+['\"])(\\.\\.?\\/[^'\"]*?)(['\"])/g;\n\n // Pattern for dynamic imports with relative paths\n // Matches: import('./foo'), import(\"../bar\")\n const dynamicPattern = /(import\\s*\\(\\s*['\"])(\\.\\.?\\/[^'\"]*?)(['\"])/g;\n\n let result = content;\n\n // Process 'from' statements\n result = result.replace(fromPattern, (match, prefix, importPath, quote) => {\n return rewriteImportPath(match, prefix, importPath, quote, fileDir);\n });\n\n // Process side-effect-only imports\n result = result.replace(\n bareImportPattern,\n (match, prefix, importPath, quote) => {\n return rewriteImportPath(match, prefix, importPath, quote, fileDir);\n },\n );\n\n // Process dynamic imports\n result = result.replace(\n dynamicPattern,\n (match, prefix, importPath, quote) => {\n return rewriteImportPath(match, prefix, importPath, quote, fileDir);\n },\n );\n\n return result;\n}\n\n/**\n * Rewrites a single import path to add .js extension if needed.\n * Handles directory imports with index files correctly.\n *\n * @param match - The full matched string\n * @param prefix - The prefix (from ' or import(')\n * @param importPath - The import path\n * @param quote - The closing quote\n * @param fileDir - Directory containing the file being processed (for resolving paths)\n * @returns The rewritten import or original if no change needed\n */\nfunction rewriteImportPath(\n match: string,\n prefix: string,\n importPath: string,\n quote: string,\n fileDir?: string,\n): string {\n // Skip if already has a JavaScript extension\n if (/\\.[cm]?js$/.test(importPath)) {\n return match;\n }\n\n // Skip if importing a JSON file\n if (/\\.json$/.test(importPath)) {\n return match;\n }\n\n // If we have the file directory, check if the import target is a directory with index.js\n if (fileDir) {\n const resolvedPath = nodePath.resolve(fileDir, importPath);\n\n // Check if path.js exists (regular file import)\n if (existsSync(`${resolvedPath}.js`)) {\n return `${prefix}${importPath}.js${quote}`;\n }\n\n // Check if path/index.js exists (directory import)\n if (existsSync(nodePath.join(resolvedPath, \"index.js\"))) {\n // For directory imports, rewrite to include /index.js\n return `${prefix}${importPath}/index.js${quote}`;\n }\n\n // Check for .mjs variants\n if (existsSync(`${resolvedPath}.mjs`)) {\n return `${prefix}${importPath}.mjs${quote}`;\n }\n if (existsSync(nodePath.join(resolvedPath, \"index.mjs\"))) {\n return `${prefix}${importPath}/index.mjs${quote}`;\n }\n\n // Check for .cjs variants\n if (existsSync(`${resolvedPath}.cjs`)) {\n return `${prefix}${importPath}.cjs${quote}`;\n }\n if (existsSync(nodePath.join(resolvedPath, \"index.cjs\"))) {\n return `${prefix}${importPath}/index.cjs${quote}`;\n }\n }\n\n // Default: add .js extension (fallback when no fileDir or file not found)\n return `${prefix}${importPath}.js${quote}`;\n}\n\n/**\n * Rewrites relative import paths in JavaScript files to include .js extensions.\n * This is required for Node.js ESM which requires explicit extensions.\n *\n * Handles:\n * - import statements: import { foo } from './bar' -> import { foo } from './bar.js'\n * - dynamic imports: import('./bar') -> import('./bar.js')\n * - re-exports: export { foo } from './bar' -> export { foo } from './bar.js'\n *\n * Does NOT modify:\n * - Package imports (no leading . or ..)\n * - Imports that already have extensions\n * - Imports from node_modules\n *\n * @param outDir - Directory containing compiled JavaScript files\n */\nexport function rewriteImportExtensions(outDir: string): void {\n const files = walkDirectory(outDir, [\".js\", \".mjs\"]);\n\n for (const filePath of files) {\n const content = readFileSync(filePath, \"utf-8\");\n const fileDir = nodePath.dirname(filePath);\n const rewritten = addJsExtensionToImports(content, fileDir);\n\n if (content !== rewritten) {\n writeFileSync(filePath, rewritten, \"utf-8\");\n }\n }\n}\n\nexport const MAX_RETRIES = 150;\nexport const MAX_RETRY_TIME_MS = 1000;\nexport const RETRY_INITIAL_TIME_MS = 100;\n\nexport const MAX_RETRIES_PRODUCER = 150;\nexport const RETRY_FACTOR_PRODUCER = 0.2;\n// Means all replicas need to acknowledge the message\nexport const ACKs = -1;\n\n/**\n * Creates the base producer configuration for Kafka.\n * Used by both the SDK stream publishing and streaming function workers.\n *\n * @param maxMessageBytes - Optional max message size in bytes (synced with topic config)\n * @returns Producer configuration object for the Confluent Kafka client\n */\nexport function createProducerConfig(maxMessageBytes?: number) {\n return {\n kafkaJS: {\n idempotent: false, // Not needed for at-least-once delivery\n acks: ACKs,\n retry: {\n retries: MAX_RETRIES_PRODUCER,\n maxRetryTime: MAX_RETRY_TIME_MS,\n },\n },\n \"linger.ms\": 0, // This is to make sure at least once delivery with immediate feedback on the send\n ...(maxMessageBytes && { \"message.max.bytes\": maxMessageBytes }),\n };\n}\n\n/**\n * Parses a comma-separated broker string into an array of valid broker addresses.\n * Handles whitespace trimming and filters out empty elements.\n *\n * @param brokerString - Comma-separated broker addresses (e.g., \"broker1:9092, broker2:9092, , broker3:9092\")\n * @returns Array of trimmed, non-empty broker addresses\n */\nconst parseBrokerString = (brokerString: string): string[] =>\n brokerString\n .split(\",\")\n .map((b) => b.trim())\n .filter((b) => b.length > 0);\n\nexport type KafkaClientConfig = {\n clientId: string;\n broker: string;\n securityProtocol?: string; // e.g. \"SASL_SSL\" or \"PLAINTEXT\"\n saslUsername?: string;\n saslPassword?: string;\n saslMechanism?: string; // e.g. \"scram-sha-256\", \"plain\"\n};\n\n/**\n * Dynamically creates and connects a KafkaJS producer using the provided configuration.\n * Returns a connected producer instance.\n *\n * @param cfg - Kafka client configuration\n * @param logger - Logger instance\n * @param maxMessageBytes - Optional max message size in bytes (synced with topic config)\n */\nexport async function getKafkaProducer(\n cfg: KafkaClientConfig,\n logger: Logger,\n maxMessageBytes?: number,\n): Promise<Producer> {\n const kafka = await getKafkaClient(cfg, logger);\n\n const producer = kafka.producer(createProducerConfig(maxMessageBytes));\n await producer.connect();\n return producer;\n}\n\n/**\n * Interface for logging functionality\n */\nexport interface Logger {\n logPrefix: string;\n log: (message: string) => void;\n error: (message: string) => void;\n warn: (message: string) => void;\n}\n\nexport const logError = (logger: Logger, e: Error): void => {\n logger.error(e.message);\n const stack = e.stack;\n if (stack) {\n logger.error(stack);\n }\n};\n\n/**\n * Builds SASL configuration for Kafka client authentication\n */\nconst buildSaslConfig = (\n logger: Logger,\n args: KafkaClientConfig,\n): SASLOptions | undefined => {\n const mechanism = args.saslMechanism ? args.saslMechanism.toLowerCase() : \"\";\n switch (mechanism) {\n case \"plain\":\n case \"scram-sha-256\":\n case \"scram-sha-512\":\n return {\n mechanism: mechanism,\n username: args.saslUsername || \"\",\n password: args.saslPassword || \"\",\n };\n default:\n logger.warn(`Unsupported SASL mechanism: ${args.saslMechanism}`);\n return undefined;\n }\n};\n\n/**\n * Dynamically creates a KafkaJS client configured with provided settings.\n * Use this to construct producers/consumers with custom options.\n */\nexport const getKafkaClient = async (\n cfg: KafkaClientConfig,\n logger: Logger,\n): Promise<Kafka> => {\n const brokers = parseBrokerString(cfg.broker || \"\");\n if (brokers.length === 0) {\n throw new Error(`No valid broker addresses found in: \"${cfg.broker}\"`);\n }\n\n logger.log(`Creating Kafka client with brokers: ${brokers.join(\", \")}`);\n logger.log(`Security protocol: ${cfg.securityProtocol || \"plaintext\"}`);\n logger.log(`Client ID: ${cfg.clientId}`);\n\n const saslConfig = buildSaslConfig(logger, cfg);\n\n return new Kafka({\n kafkaJS: {\n clientId: cfg.clientId,\n brokers,\n ssl: cfg.securityProtocol === \"SASL_SSL\",\n ...(saslConfig && { sasl: saslConfig }),\n retry: {\n initialRetryTime: RETRY_INITIAL_TIME_MS,\n maxRetryTime: MAX_RETRY_TIME_MS,\n retries: MAX_RETRIES,\n },\n },\n });\n};\n"],"mappings":"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","names":["import_fs","import_path","path","projectRoot","userOutDir","outDir","import_fs","import_path","nodePath","content","outDir","projectRoot","path"]}
|
package/dist/moose-tspc.mjs
CHANGED
|
@@ -233,9 +233,8 @@ function createBuildTsconfig(moduleOptions) {
|
|
|
233
233
|
skipDefaultLibCheck: true,
|
|
234
234
|
// Additional settings to handle module resolution conflicts
|
|
235
235
|
allowSyntheticDefaultImports: true,
|
|
236
|
-
//
|
|
237
|
-
|
|
238
|
-
noEmitOnError: watchMode,
|
|
236
|
+
// Block emission on errors so build and dev behave consistently
|
|
237
|
+
noEmitOnError: true,
|
|
239
238
|
// Enable incremental compilation for faster rebuilds
|
|
240
239
|
incremental: true,
|
|
241
240
|
tsBuildInfoFile: path2.join(outDir, ".tsbuildinfo")
|
|
@@ -245,7 +244,6 @@ function createBuildTsconfig(moduleOptions) {
|
|
|
245
244
|
function runSingleCompilation(moduleSystem) {
|
|
246
245
|
const moduleOptions = getModuleOptions(moduleSystem);
|
|
247
246
|
const buildTsconfig = createBuildTsconfig(moduleOptions);
|
|
248
|
-
buildTsconfig.compilerOptions.noEmitOnError = false;
|
|
249
247
|
writeFileSync2(tempTsconfigPath, JSON.stringify(buildTsconfig, null, 2));
|
|
250
248
|
console.log("Created temporary tsconfig with moose plugins...");
|
|
251
249
|
const tspcArgs = [
|
|
@@ -260,58 +258,11 @@ function runSingleCompilation(moduleSystem) {
|
|
|
260
258
|
if (shouldAddOutDir) {
|
|
261
259
|
tspcArgs.push("--outDir", outDir);
|
|
262
260
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
console.log("TypeScript compilation complete.");
|
|
269
|
-
} catch (compileError) {
|
|
270
|
-
const sourceDir = getSourceDir();
|
|
271
|
-
const outputIndexPath = path2.join(
|
|
272
|
-
projectRoot2,
|
|
273
|
-
outDir,
|
|
274
|
-
sourceDir,
|
|
275
|
-
"index.js"
|
|
276
|
-
);
|
|
277
|
-
if (existsSync3(outputIndexPath)) {
|
|
278
|
-
console.warn("");
|
|
279
|
-
console.warn("BUILD SAFETY WARNING");
|
|
280
|
-
console.warn(
|
|
281
|
-
"==============================================================="
|
|
282
|
-
);
|
|
283
|
-
console.warn(
|
|
284
|
-
"TypeScript detected type errors but JavaScript was still emitted."
|
|
285
|
-
);
|
|
286
|
-
console.warn("");
|
|
287
|
-
console.warn(
|
|
288
|
-
"IMPORTANT: Type errors can indicate code that will fail at runtime."
|
|
289
|
-
);
|
|
290
|
-
console.warn(
|
|
291
|
-
"While this build will succeed, the resulting code may crash when:"
|
|
292
|
-
);
|
|
293
|
-
console.warn(" - Functions receive unexpected argument types");
|
|
294
|
-
console.warn(
|
|
295
|
-
" - Properties are accessed on potentially null/undefined values"
|
|
296
|
-
);
|
|
297
|
-
console.warn(" - Incorrect types flow through your application logic");
|
|
298
|
-
console.warn("");
|
|
299
|
-
console.warn(
|
|
300
|
-
"RECOMMENDATION: Run `npx tsc --noEmit` to review type errors before"
|
|
301
|
-
);
|
|
302
|
-
console.warn(
|
|
303
|
-
"deploying to production. Fix any errors that could cause runtime issues."
|
|
304
|
-
);
|
|
305
|
-
console.warn(
|
|
306
|
-
"==============================================================="
|
|
307
|
-
);
|
|
308
|
-
console.warn("");
|
|
309
|
-
console.log("TypeScript compilation complete (with type warnings).");
|
|
310
|
-
} else {
|
|
311
|
-
console.error("Compilation failed - no output files generated.");
|
|
312
|
-
throw compileError;
|
|
313
|
-
}
|
|
314
|
-
}
|
|
261
|
+
execFileSync("npx", tspcArgs, {
|
|
262
|
+
stdio: "inherit",
|
|
263
|
+
cwd: projectRoot2
|
|
264
|
+
});
|
|
265
|
+
console.log("TypeScript compilation complete.");
|
|
315
266
|
if (moduleSystem === "esm") {
|
|
316
267
|
console.log("Post-processing ESM imports to add .js extensions...");
|
|
317
268
|
const fullOutDir = path2.join(projectRoot2, outDir);
|
package/dist/moose-tspc.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/moose-tspc.ts","../src/compiler-config.ts","../src/commons.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * Pre-compiles TypeScript app code with moose compiler plugins and typia transforms.\n *\n * Usage: moose-tspc [outDir] [--watch]\n * outDir: Output directory for compiled files (optional, overrides tsconfig)\n * --watch: Enable watch mode for incremental compilation (outputs JSON events)\n *\n * Output directory is determined by (in priority order):\n * 1. CLI argument (if provided) - used by Docker builds\n * 2. User's tsconfig.json outDir setting (if specified)\n * 3. Default: .moose/compiled\n *\n * This script creates a temporary tsconfig that extends the user's config and adds\n * the required moose compiler plugins, then runs tspc to compile with transforms.\n *\n * In watch mode, outputs JSON events to stdout for the Rust CLI to parse:\n * {\"event\": \"compile_start\"}\n * {\"event\": \"compile_complete\", \"errors\": 0, \"warnings\": 2}\n * {\"event\": \"compile_error\", \"errors\": 3, \"diagnostics\": [...]}\n */\nimport { execFileSync, spawn } from \"child_process\";\nimport { existsSync, writeFileSync, unlinkSync, mkdirSync } from \"fs\";\nimport path from \"path\";\nimport {\n MOOSE_COMPILER_PLUGINS,\n MOOSE_COMPILER_OPTIONS,\n detectModuleSystem,\n getModuleOptions,\n getSourceDir,\n readUserOutDir,\n DEFAULT_OUT_DIR,\n type ModuleSystem,\n} from \"./compiler-config\";\nimport { rewriteImportExtensions } from \"./commons\";\n\n// Parse command line arguments\nconst args = process.argv.slice(2);\nconst watchMode = args.includes(\"--watch\");\n// CLI argument takes priority (for Docker builds), then tsconfig, then default\nconst cliOutDir = args.find((arg) => !arg.startsWith(\"--\"));\n\nconst projectRoot = process.cwd();\nconst tsconfigPath = path.join(projectRoot, \"tsconfig.json\");\nconst tempTsconfigPath = path.join(projectRoot, \"tsconfig.moose-build.json\");\n\n// Determine outDir - CLI arg > tsconfig > default\nconst userOutDir = readUserOutDir(projectRoot);\nconst outDir = cliOutDir || userOutDir || DEFAULT_OUT_DIR;\n// add --outDir flag if user hasn't specified in tsconfig\n// (if CLI arg is provided, we always pass it explicitly)\nconst shouldAddOutDir = cliOutDir !== undefined || !userOutDir;\n\n/**\n * JSON event protocol for watch mode communication with Rust CLI.\n */\ninterface CompileEvent {\n event: \"compile_start\" | \"compile_complete\" | \"compile_error\";\n errors?: number;\n warnings?: number;\n diagnostics?: string[];\n}\n\n/**\n * Emit a JSON event to stdout for the Rust CLI to parse.\n */\nfunction emitEvent(event: CompileEvent): void {\n console.log(JSON.stringify(event));\n}\n\n/**\n * Create the build tsconfig with moose plugins.\n */\nfunction createBuildTsconfig(\n moduleOptions: ReturnType<typeof getModuleOptions>,\n) {\n return {\n extends: \"./tsconfig.json\",\n compilerOptions: {\n ...MOOSE_COMPILER_OPTIONS,\n ...moduleOptions,\n plugins: [...MOOSE_COMPILER_PLUGINS],\n // Skip type checking of declaration files to avoid dual-package conflicts\n skipLibCheck: true,\n skipDefaultLibCheck: true,\n // Additional settings to handle module resolution conflicts\n allowSyntheticDefaultImports: true,\n // In watch mode, we want to block on errors (noEmitOnError: true)\n // In build mode, we allow emission with errors for Docker builds\n noEmitOnError: watchMode,\n // Enable incremental compilation for faster rebuilds\n incremental: true,\n tsBuildInfoFile: path.join(outDir, \".tsbuildinfo\"),\n },\n };\n}\n\n/**\n * Run a single compilation (non-watch mode).\n */\nfunction runSingleCompilation(moduleSystem: ModuleSystem): void {\n const moduleOptions = getModuleOptions(moduleSystem);\n const buildTsconfig = createBuildTsconfig(moduleOptions);\n // Override noEmitOnError for single compilation (allow errors)\n buildTsconfig.compilerOptions.noEmitOnError = false;\n\n writeFileSync(tempTsconfigPath, JSON.stringify(buildTsconfig, null, 2));\n console.log(\"Created temporary tsconfig with moose plugins...\");\n\n // Build tspc arguments - only add --outDir if user hasn't specified one in tsconfig\n const tspcArgs = [\n \"tspc\",\n \"-p\",\n tempTsconfigPath,\n \"--rootDir\",\n \".\",\n \"--sourceMap\",\n \"--inlineSources\",\n ];\n if (shouldAddOutDir) {\n tspcArgs.push(\"--outDir\", outDir);\n }\n\n try {\n execFileSync(\"npx\", tspcArgs, {\n stdio: \"inherit\",\n cwd: projectRoot,\n });\n console.log(\"TypeScript compilation complete.\");\n } catch (compileError: any) {\n // TypeScript might exit with non-zero code even when noEmitOnError: false\n // Check if output files were actually created\n const sourceDir = getSourceDir();\n const outputIndexPath = path.join(\n projectRoot,\n outDir,\n sourceDir,\n \"index.js\",\n );\n\n if (existsSync(outputIndexPath)) {\n console.warn(\"\");\n console.warn(\"BUILD SAFETY WARNING\");\n console.warn(\n \"===============================================================\",\n );\n console.warn(\n \"TypeScript detected type errors but JavaScript was still emitted.\",\n );\n console.warn(\"\");\n console.warn(\n \"IMPORTANT: Type errors can indicate code that will fail at runtime.\",\n );\n console.warn(\n \"While this build will succeed, the resulting code may crash when:\",\n );\n console.warn(\" - Functions receive unexpected argument types\");\n console.warn(\n \" - Properties are accessed on potentially null/undefined values\",\n );\n console.warn(\" - Incorrect types flow through your application logic\");\n console.warn(\"\");\n console.warn(\n \"RECOMMENDATION: Run `npx tsc --noEmit` to review type errors before\",\n );\n console.warn(\n \"deploying to production. Fix any errors that could cause runtime issues.\",\n );\n console.warn(\n \"===============================================================\",\n );\n console.warn(\"\");\n console.log(\"TypeScript compilation complete (with type warnings).\");\n } else {\n console.error(\"Compilation failed - no output files generated.\");\n throw compileError;\n }\n }\n\n // Post-process ESM output to add .js extensions to relative imports\n if (moduleSystem === \"esm\") {\n console.log(\"Post-processing ESM imports to add .js extensions...\");\n const fullOutDir = path.join(projectRoot, outDir);\n rewriteImportExtensions(fullOutDir);\n console.log(\"ESM import rewriting complete.\");\n }\n}\n\n/**\n * Run watch mode compilation with JSON event output.\n * Uses tspc --watch and parses its output to emit structured events.\n */\nfunction runWatchCompilation(moduleSystem: ModuleSystem): void {\n const moduleOptions = getModuleOptions(moduleSystem);\n const buildTsconfig = createBuildTsconfig(moduleOptions);\n\n // Write the tsconfig (it stays for the duration of watch mode)\n writeFileSync(tempTsconfigPath, JSON.stringify(buildTsconfig, null, 2));\n\n // Ensure output directory exists for incremental build info\n const fullOutDir = path.join(projectRoot, outDir);\n if (!existsSync(fullOutDir)) {\n mkdirSync(fullOutDir, { recursive: true });\n }\n\n // Track diagnostics between compilation cycles\n let currentDiagnostics: string[] = [];\n let errorCount = 0;\n let warningCount = 0;\n\n // Build tspc arguments - only add --outDir if user hasn't specified one in tsconfig\n const tspcArgs = [\n \"tspc\",\n \"-p\",\n tempTsconfigPath,\n \"--rootDir\",\n \".\",\n \"--sourceMap\",\n \"--inlineSources\",\n \"--watch\",\n \"--preserveWatchOutput\",\n ];\n if (shouldAddOutDir) {\n // Insert --outDir after --rootDir and \".\" so rootDir is not clobbered\n tspcArgs.splice(6, 0, \"--outDir\", outDir);\n }\n\n // Spawn tspc in watch mode\n const tspcProcess = spawn(\"npx\", tspcArgs, {\n cwd: projectRoot,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n\n // Handle process termination\n const cleanup = () => {\n if (existsSync(tempTsconfigPath)) {\n unlinkSync(tempTsconfigPath);\n }\n tspcProcess.kill();\n };\n\n process.on(\"SIGINT\", () => {\n cleanup();\n process.exit(0);\n });\n\n process.on(\"SIGTERM\", () => {\n cleanup();\n process.exit(0);\n });\n\n // Parse tspc output line by line\n // Pattern matching approach inspired by tsc-watch (github.com/gilamran/tsc-watch)\n // which also parses tsc stdout to detect compilation events\n let buffer = \"\";\n\n // Strip ANSI escape codes for reliable pattern matching (standard regex pattern)\n const stripAnsi = (str: string) =>\n str.replace(\n /[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d/#&.:=?%@~_]*)*)?[\\u0007])|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))/g,\n \"\",\n );\n\n // tsc watch mode patterns (with timestamp prefix like \"12:00:00 AM - \")\n const compilationStartedRegex =\n /Starting compilation in watch mode|Starting incremental compilation/;\n const compilationCompleteRegex =\n /Found\\s+(\\d+)\\s+error(?:s)?\\..*Watching for file changes/;\n const diagnosticRegex = /\\(\\d+,\\d+\\):\\s*(error|warning)\\s+TS\\d+:/;\n\n const processLine = (line: string) => {\n const cleanLine = stripAnsi(line);\n\n if (compilationStartedRegex.test(cleanLine)) {\n // New compilation cycle starting\n currentDiagnostics = [];\n errorCount = 0;\n warningCount = 0;\n emitEvent({ event: \"compile_start\" });\n } else if (compilationCompleteRegex.test(cleanLine)) {\n // Compilation complete - parse error count from tsc summary line\n // Format: \"12:00:00 AM - Found 0 errors. Watching for file changes.\"\n const match = cleanLine.match(/Found\\s+(\\d+)\\s+error(?:s)?\\./);\n if (match) {\n errorCount = parseInt(match[1], 10);\n }\n\n // Post-process ESM if successful\n if (errorCount === 0 && moduleSystem === \"esm\") {\n try {\n rewriteImportExtensions(fullOutDir);\n } catch (e) {\n // Log but don't fail - import rewriting is best-effort\n console.error(\"Warning: ESM import rewriting failed:\", e);\n }\n }\n\n if (errorCount > 0) {\n emitEvent({\n event: \"compile_error\",\n errors: errorCount,\n warnings: warningCount,\n diagnostics: currentDiagnostics,\n });\n } else {\n emitEvent({\n event: \"compile_complete\",\n errors: 0,\n warnings: warningCount,\n diagnostics: warningCount > 0 ? currentDiagnostics : undefined,\n });\n }\n } else if (diagnosticRegex.test(cleanLine)) {\n // This is a diagnostic line (error or warning)\n currentDiagnostics.push(cleanLine.trim());\n if (cleanLine.includes(\": error \")) {\n errorCount++;\n } else if (cleanLine.includes(\": warning \")) {\n warningCount++;\n }\n }\n };\n\n tspcProcess.stdout.on(\"data\", (data: Buffer) => {\n buffer += data.toString();\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() || \"\"; // Keep incomplete line in buffer\n for (const line of lines) {\n if (line.trim()) {\n processLine(line);\n }\n }\n });\n\n tspcProcess.stderr.on(\"data\", (data: Buffer) => {\n // Forward stderr for debugging but don't parse it\n process.stderr.write(data.toString());\n });\n\n tspcProcess.on(\"error\", (err) => {\n console.error(\"Failed to start tspc:\", err);\n cleanup();\n process.exit(1);\n });\n\n tspcProcess.on(\"exit\", (code) => {\n cleanup();\n if (code !== 0) {\n process.exit(code || 1);\n }\n });\n}\n\n/**\n * Write compile metadata to .moose/.compile-config.json\n * This allows Rust CLI to know where compiled output is without duplicating logic\n */\nfunction writeCompileConfig() {\n const mooseDir = path.join(projectRoot, \".moose\");\n if (!existsSync(mooseDir)) {\n mkdirSync(mooseDir, { recursive: true });\n }\n const configPath = path.join(mooseDir, \".compile-config.json\");\n writeFileSync(configPath, JSON.stringify({ outDir }, null, 2));\n}\n\n// Main execution\nif (!existsSync(tsconfigPath)) {\n console.error(\"Error: tsconfig.json not found in\", projectRoot);\n process.exit(1);\n}\n\ntry {\n // Write compile config so Rust CLI knows where output is\n writeCompileConfig();\n\n // Auto-detect module system from package.json\n const moduleSystem = detectModuleSystem(projectRoot);\n\n if (watchMode) {\n // Watch mode - run indefinitely with JSON event output\n runWatchCompilation(moduleSystem);\n } else {\n // Single compilation mode\n console.log(`Compiling TypeScript to ${outDir}...`);\n console.log(\n `Using ${moduleSystem.toUpperCase()} module output (detected from package.json)...`,\n );\n runSingleCompilation(moduleSystem);\n console.log(\"Compilation complete.\");\n\n // Clean up the temporary tsconfig\n if (existsSync(tempTsconfigPath)) {\n unlinkSync(tempTsconfigPath);\n }\n }\n} catch (error) {\n console.error(\"Build process failed:\", error);\n // Clean up the temporary tsconfig\n if (existsSync(tempTsconfigPath)) {\n unlinkSync(tempTsconfigPath);\n }\n process.exit(1);\n}\n","import { existsSync, readFileSync } from \"fs\";\nimport path from \"path\";\n\n/**\n * Shared TypeScript compiler configuration for moose projects.\n * Used by both moose-runner.ts (runtime) and moose-tspc.ts (pre-compilation).\n *\n * Moose now always uses pre-compiled JavaScript - no ts-node fallback.\n */\n\nexport const MOOSE_COMPILER_PLUGINS = [\n {\n transform: \"./node_modules/@514labs/moose-lib/dist/compilerPlugin.js\",\n // No longer using transformProgram - direct typia integration eliminates\n // the need for program replacement and the associated incremental compilation issues\n },\n {\n // Keep typia plugin for users who use typia directly (not through Moose resources)\n transform: \"typia/lib/transform\",\n },\n] as const;\n\n// Options required for moose compilation\n// Note: We only set what's absolutely necessary to avoid conflicts with user projects\nexport const MOOSE_COMPILER_OPTIONS = {\n experimentalDecorators: true,\n esModuleInterop: true,\n // Disable strict module syntax checking to avoid dual-package type conflicts\n // This prevents errors where the same type imported with different resolution\n // modes (CJS vs ESM) is treated as incompatible\n verbatimModuleSyntax: false,\n} as const;\n\n// Module resolution options - only applied if not already set in user's tsconfig\n// These help with ESM/CJS interop but can be overridden by user config\nexport const MOOSE_MODULE_OPTIONS = {\n module: \"NodeNext\",\n moduleResolution: \"NodeNext\",\n} as const;\n\n/**\n * Default source directory for user code.\n * Can be overridden via MOOSE_SOURCE_DIR environment variable.\n */\nexport function getSourceDir(): string {\n return process.env.MOOSE_SOURCE_DIR || \"app\";\n}\n\n/**\n * Default output directory for compiled code.\n */\nexport const DEFAULT_OUT_DIR = \".moose/compiled\";\n\n/**\n * Read the user's tsconfig.json and extract the outDir setting.\n * Supports JSONC (JSON with Comments) by evaluating as JavaScript\n * (JSON with comments is valid JS in ES2019+).\n *\n * Security note: This uses eval-like behavior (new Function), which means\n * malicious code in tsconfig.json would execute. This is acceptable because:\n * - The user controls their own tsconfig.json\n * - Same trust model as running `tsc` or any other tool that processes the file\n * - If you clone and run untrusted code, you're already at risk\n *\n * Returns the outDir if specified, or null if not.\n */\nexport function readUserOutDir(\n projectRoot: string = process.cwd(),\n): string | null {\n try {\n let content = readFileSync(\n path.join(projectRoot, \"tsconfig.json\"),\n \"utf-8\",\n );\n // Strip UTF-8 BOM if present\n if (content.charCodeAt(0) === 0xfeff) {\n content = content.slice(1);\n }\n // eslint-disable-next-line no-eval\n const tsconfig = eval(`(${content})`);\n return tsconfig.compilerOptions?.outDir || null;\n } catch {\n return null;\n }\n}\n\n/**\n * Get the output directory for compiled code.\n * Uses user's tsconfig outDir if specified, otherwise defaults to .moose/compiled\n */\nexport function getOutDir(projectRoot: string = process.cwd()): string {\n const userOutDir = readUserOutDir(projectRoot);\n return userOutDir || DEFAULT_OUT_DIR;\n}\n\n/**\n * Get the path to the compiled index.js file.\n */\nexport function getCompiledIndexPath(\n projectRoot: string = process.cwd(),\n): string {\n const outDir = getOutDir(projectRoot);\n const sourceDir = getSourceDir();\n // Resolve so that absolute outDir from tsconfig is handled correctly\n return path.resolve(projectRoot, outDir, sourceDir, \"index.js\");\n}\n\n/**\n * Check if pre-compiled artifacts exist for the current project.\n */\nexport function hasCompiledArtifacts(\n projectRoot: string = process.cwd(),\n): boolean {\n return existsSync(getCompiledIndexPath(projectRoot));\n}\n\n/**\n * Module system type for compilation output.\n */\nexport type ModuleSystem = \"esm\" | \"cjs\";\n\n/**\n * Detects the module system from the user's package.json.\n * Returns 'esm' if package.json has \"type\": \"module\", otherwise 'cjs'.\n *\n * @param projectRoot - Root directory containing package.json (defaults to cwd)\n * @returns The detected module system\n */\nexport function detectModuleSystem(\n projectRoot: string = process.cwd(),\n): ModuleSystem {\n const pkgPath = path.join(projectRoot, \"package.json\");\n\n if (existsSync(pkgPath)) {\n try {\n const pkgContent = readFileSync(pkgPath, \"utf-8\");\n const pkg = JSON.parse(pkgContent);\n if (pkg.type === \"module\") {\n return \"esm\";\n }\n } catch (e) {\n // If parsing fails, default to CJS\n console.debug(\n `[moose] Failed to parse package.json at ${pkgPath}, defaulting to CJS:`,\n e,\n );\n }\n }\n\n return \"cjs\";\n}\n\n/**\n * Get compiler module options based on detected module system.\n *\n * @param moduleSystem - The module system to get options for\n * @returns Compiler options for module and moduleResolution\n */\nexport function getModuleOptions(moduleSystem: ModuleSystem): {\n module: string;\n moduleResolution: string;\n} {\n if (moduleSystem === \"esm\") {\n return {\n module: \"ES2022\",\n moduleResolution: \"bundler\",\n };\n }\n return {\n module: \"CommonJS\",\n moduleResolution: \"Node\",\n };\n}\n\n/**\n * Dynamic module loader that works with both CJS and ESM.\n * Uses detected module system to determine loading strategy.\n *\n * @param modulePath - Path to the module to load\n * @param projectRoot - Root directory for module system detection\n * @returns The loaded module\n */\nexport async function loadModule<T = any>(\n modulePath: string,\n projectRoot: string = process.cwd(),\n): Promise<T> {\n const moduleSystem = detectModuleSystem(projectRoot);\n\n if (moduleSystem === \"esm\") {\n // Use dynamic import for ESM\n // pathToFileURL is needed for Windows compatibility with absolute paths\n const { pathToFileURL } = await import(\"url\");\n const fileUrl = pathToFileURL(modulePath).href;\n return await import(fileUrl);\n }\n\n // Use require for CJS\n // Note: In ESM builds (compiled by tsup), this code path is replaced with\n // the appropriate ESM imports. The dual-package build ensures compatibility.\n return require(modulePath);\n}\n","import {\n existsSync,\n readdirSync,\n readFileSync,\n statSync,\n writeFileSync,\n} from \"fs\";\nimport nodePath from \"path\";\nimport { createClient } from \"@clickhouse/client\";\nimport { KafkaJS } from \"@514labs/kafka-javascript\";\nimport { SASLOptions } from \"@514labs/kafka-javascript/types/kafkajs\";\nconst { Kafka } = KafkaJS;\ntype Kafka = KafkaJS.Kafka;\ntype Consumer = KafkaJS.Consumer;\nexport type Producer = KafkaJS.Producer;\n\n/**\n * Utility function for compiler-related logging that can be disabled via environment variable.\n * Set MOOSE_DISABLE_COMPILER_LOGS=true to suppress these logs (useful for testing environments).\n */\n\n/**\n * Returns true if the value is a common truthy string: \"1\", \"true\", \"yes\", \"on\" (case-insensitive).\n */\nfunction isTruthy(value: string | undefined): boolean {\n if (!value) return false;\n switch (value.trim().toLowerCase()) {\n case \"1\":\n case \"true\":\n case \"yes\":\n case \"on\":\n return true;\n default:\n return false;\n }\n}\n\nexport const compilerLog = (message: string) => {\n if (!isTruthy(process.env.MOOSE_DISABLE_COMPILER_LOGS)) {\n console.log(message);\n }\n};\n\nexport const antiCachePath = (path: string) =>\n `${path}?num=${Math.random().toString()}&time=${Date.now()}`;\n\nexport const getFileName = (filePath: string) => {\n const regex = /\\/([^\\/]+)\\.ts/;\n const matches = filePath.match(regex);\n if (matches && matches.length > 1) {\n return matches[1];\n }\n return \"\";\n};\n\ninterface ClientConfig {\n username: string;\n password: string;\n database: string;\n useSSL: string;\n host: string;\n port: string;\n}\n\nexport const getClickhouseClient = ({\n username,\n password,\n database,\n useSSL,\n host,\n port,\n}: ClientConfig) => {\n const protocol =\n useSSL === \"1\" || useSSL.toLowerCase() === \"true\" ? \"https\" : \"http\";\n console.log(`Connecting to Clickhouse at ${protocol}://${host}:${port}`);\n return createClient({\n url: `${protocol}://${host}:${port}`,\n username: username,\n password: password,\n database: database,\n application: \"moose\",\n // Note: wait_end_of_query is configured per operation type, not globally\n // to preserve SELECT query performance while ensuring INSERT/DDL reliability\n });\n};\n\nexport type CliLogData = {\n message_type?: \"Info\" | \"Success\" | \"Warning\" | \"Error\" | \"Highlight\";\n action: string;\n message: string;\n};\n\nexport const cliLog: (log: CliLogData) => void = (log) => {\n const level =\n log.message_type === \"Error\" ? \"error\"\n : log.message_type === \"Warning\" ? \"warn\"\n : \"info\";\n\n const structuredLog = {\n __moose_structured_log__: true,\n level,\n message: log.message,\n resource_type: \"runtime\",\n cli_action: log.action,\n cli_message_type: log.message_type ?? \"Info\",\n timestamp: new Date().toISOString(),\n };\n\n process.stderr.write(JSON.stringify(structuredLog) + \"\\n\");\n};\n\n/**\n * Method to change .ts, .cts, and .mts to .js, .cjs, and .mjs\n * This is needed because 'import' does not support .ts, .cts, and .mts\n */\nexport function mapTstoJs(filePath: string): string {\n return filePath\n .replace(/\\.ts$/, \".js\")\n .replace(/\\.cts$/, \".cjs\")\n .replace(/\\.mts$/, \".mjs\");\n}\n\n/**\n * Walks a directory recursively and returns all files matching the given extensions.\n * Skips node_modules directories.\n *\n * @param dir - Directory to walk\n * @param extensions - File extensions to include (e.g., [\".js\", \".mjs\"])\n * @returns Array of file paths\n */\nfunction walkDirectory(dir: string, extensions: string[]): string[] {\n const results: string[] = [];\n\n if (!existsSync(dir)) {\n return results;\n }\n\n try {\n const entries = readdirSync(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = nodePath.join(dir, entry.name);\n\n if (entry.isDirectory()) {\n // Skip node_modules\n if (entry.name !== \"node_modules\") {\n results.push(...walkDirectory(fullPath, extensions));\n }\n } else if (entry.isFile()) {\n const ext = nodePath.extname(entry.name);\n if (extensions.includes(ext)) {\n results.push(fullPath);\n }\n }\n }\n } catch (e) {\n // Log error in case it is something the user can/should act on\n console.debug(`[moose] Failed to read directory ${dir}:`, e);\n }\n\n return results;\n}\n\n/**\n * Adds .js extension to relative import paths that don't have an extension.\n * Handles import/export from statements and dynamic imports.\n *\n * @param content - JavaScript file content\n * @param fileDir - Directory containing the file being processed (for resolving paths)\n * @returns Content with .js extensions added to relative imports\n */\nfunction addJsExtensionToImports(content: string, fileDir?: string): string {\n // Pattern for 'from' statements with relative paths\n // Matches: from './foo', from \"../bar\", from './utils/helper'\n const fromPattern = /(from\\s+['\"])(\\.\\.?\\/[^'\"]*?)(['\"])/g;\n\n // Pattern for side-effect-only imports with relative paths\n // Matches: import './foo', import \"../bar\" (no 'from' keyword, just importing for side effects)\n const bareImportPattern = /(import\\s+['\"])(\\.\\.?\\/[^'\"]*?)(['\"])/g;\n\n // Pattern for dynamic imports with relative paths\n // Matches: import('./foo'), import(\"../bar\")\n const dynamicPattern = /(import\\s*\\(\\s*['\"])(\\.\\.?\\/[^'\"]*?)(['\"])/g;\n\n let result = content;\n\n // Process 'from' statements\n result = result.replace(fromPattern, (match, prefix, importPath, quote) => {\n return rewriteImportPath(match, prefix, importPath, quote, fileDir);\n });\n\n // Process side-effect-only imports\n result = result.replace(\n bareImportPattern,\n (match, prefix, importPath, quote) => {\n return rewriteImportPath(match, prefix, importPath, quote, fileDir);\n },\n );\n\n // Process dynamic imports\n result = result.replace(\n dynamicPattern,\n (match, prefix, importPath, quote) => {\n return rewriteImportPath(match, prefix, importPath, quote, fileDir);\n },\n );\n\n return result;\n}\n\n/**\n * Rewrites a single import path to add .js extension if needed.\n * Handles directory imports with index files correctly.\n *\n * @param match - The full matched string\n * @param prefix - The prefix (from ' or import(')\n * @param importPath - The import path\n * @param quote - The closing quote\n * @param fileDir - Directory containing the file being processed (for resolving paths)\n * @returns The rewritten import or original if no change needed\n */\nfunction rewriteImportPath(\n match: string,\n prefix: string,\n importPath: string,\n quote: string,\n fileDir?: string,\n): string {\n // Skip if already has a JavaScript extension\n if (/\\.[cm]?js$/.test(importPath)) {\n return match;\n }\n\n // Skip if importing a JSON file\n if (/\\.json$/.test(importPath)) {\n return match;\n }\n\n // If we have the file directory, check if the import target is a directory with index.js\n if (fileDir) {\n const resolvedPath = nodePath.resolve(fileDir, importPath);\n\n // Check if path.js exists (regular file import)\n if (existsSync(`${resolvedPath}.js`)) {\n return `${prefix}${importPath}.js${quote}`;\n }\n\n // Check if path/index.js exists (directory import)\n if (existsSync(nodePath.join(resolvedPath, \"index.js\"))) {\n // For directory imports, rewrite to include /index.js\n return `${prefix}${importPath}/index.js${quote}`;\n }\n\n // Check for .mjs variants\n if (existsSync(`${resolvedPath}.mjs`)) {\n return `${prefix}${importPath}.mjs${quote}`;\n }\n if (existsSync(nodePath.join(resolvedPath, \"index.mjs\"))) {\n return `${prefix}${importPath}/index.mjs${quote}`;\n }\n\n // Check for .cjs variants\n if (existsSync(`${resolvedPath}.cjs`)) {\n return `${prefix}${importPath}.cjs${quote}`;\n }\n if (existsSync(nodePath.join(resolvedPath, \"index.cjs\"))) {\n return `${prefix}${importPath}/index.cjs${quote}`;\n }\n }\n\n // Default: add .js extension (fallback when no fileDir or file not found)\n return `${prefix}${importPath}.js${quote}`;\n}\n\n/**\n * Rewrites relative import paths in JavaScript files to include .js extensions.\n * This is required for Node.js ESM which requires explicit extensions.\n *\n * Handles:\n * - import statements: import { foo } from './bar' -> import { foo } from './bar.js'\n * - dynamic imports: import('./bar') -> import('./bar.js')\n * - re-exports: export { foo } from './bar' -> export { foo } from './bar.js'\n *\n * Does NOT modify:\n * - Package imports (no leading . or ..)\n * - Imports that already have extensions\n * - Imports from node_modules\n *\n * @param outDir - Directory containing compiled JavaScript files\n */\nexport function rewriteImportExtensions(outDir: string): void {\n const files = walkDirectory(outDir, [\".js\", \".mjs\"]);\n\n for (const filePath of files) {\n const content = readFileSync(filePath, \"utf-8\");\n const fileDir = nodePath.dirname(filePath);\n const rewritten = addJsExtensionToImports(content, fileDir);\n\n if (content !== rewritten) {\n writeFileSync(filePath, rewritten, \"utf-8\");\n }\n }\n}\n\nexport const MAX_RETRIES = 150;\nexport const MAX_RETRY_TIME_MS = 1000;\nexport const RETRY_INITIAL_TIME_MS = 100;\n\nexport const MAX_RETRIES_PRODUCER = 150;\nexport const RETRY_FACTOR_PRODUCER = 0.2;\n// Means all replicas need to acknowledge the message\nexport const ACKs = -1;\n\n/**\n * Creates the base producer configuration for Kafka.\n * Used by both the SDK stream publishing and streaming function workers.\n *\n * @param maxMessageBytes - Optional max message size in bytes (synced with topic config)\n * @returns Producer configuration object for the Confluent Kafka client\n */\nexport function createProducerConfig(maxMessageBytes?: number) {\n return {\n kafkaJS: {\n idempotent: false, // Not needed for at-least-once delivery\n acks: ACKs,\n retry: {\n retries: MAX_RETRIES_PRODUCER,\n maxRetryTime: MAX_RETRY_TIME_MS,\n },\n },\n \"linger.ms\": 0, // This is to make sure at least once delivery with immediate feedback on the send\n ...(maxMessageBytes && { \"message.max.bytes\": maxMessageBytes }),\n };\n}\n\n/**\n * Parses a comma-separated broker string into an array of valid broker addresses.\n * Handles whitespace trimming and filters out empty elements.\n *\n * @param brokerString - Comma-separated broker addresses (e.g., \"broker1:9092, broker2:9092, , broker3:9092\")\n * @returns Array of trimmed, non-empty broker addresses\n */\nconst parseBrokerString = (brokerString: string): string[] =>\n brokerString\n .split(\",\")\n .map((b) => b.trim())\n .filter((b) => b.length > 0);\n\nexport type KafkaClientConfig = {\n clientId: string;\n broker: string;\n securityProtocol?: string; // e.g. \"SASL_SSL\" or \"PLAINTEXT\"\n saslUsername?: string;\n saslPassword?: string;\n saslMechanism?: string; // e.g. \"scram-sha-256\", \"plain\"\n};\n\n/**\n * Dynamically creates and connects a KafkaJS producer using the provided configuration.\n * Returns a connected producer instance.\n *\n * @param cfg - Kafka client configuration\n * @param logger - Logger instance\n * @param maxMessageBytes - Optional max message size in bytes (synced with topic config)\n */\nexport async function getKafkaProducer(\n cfg: KafkaClientConfig,\n logger: Logger,\n maxMessageBytes?: number,\n): Promise<Producer> {\n const kafka = await getKafkaClient(cfg, logger);\n\n const producer = kafka.producer(createProducerConfig(maxMessageBytes));\n await producer.connect();\n return producer;\n}\n\n/**\n * Interface for logging functionality\n */\nexport interface Logger {\n logPrefix: string;\n log: (message: string) => void;\n error: (message: string) => void;\n warn: (message: string) => void;\n}\n\nexport const logError = (logger: Logger, e: Error): void => {\n logger.error(e.message);\n const stack = e.stack;\n if (stack) {\n logger.error(stack);\n }\n};\n\n/**\n * Builds SASL configuration for Kafka client authentication\n */\nconst buildSaslConfig = (\n logger: Logger,\n args: KafkaClientConfig,\n): SASLOptions | undefined => {\n const mechanism = args.saslMechanism ? args.saslMechanism.toLowerCase() : \"\";\n switch (mechanism) {\n case \"plain\":\n case \"scram-sha-256\":\n case \"scram-sha-512\":\n return {\n mechanism: mechanism,\n username: args.saslUsername || \"\",\n password: args.saslPassword || \"\",\n };\n default:\n logger.warn(`Unsupported SASL mechanism: ${args.saslMechanism}`);\n return undefined;\n }\n};\n\n/**\n * Dynamically creates a KafkaJS client configured with provided settings.\n * Use this to construct producers/consumers with custom options.\n */\nexport const getKafkaClient = async (\n cfg: KafkaClientConfig,\n logger: Logger,\n): Promise<Kafka> => {\n const brokers = parseBrokerString(cfg.broker || \"\");\n if (brokers.length === 0) {\n throw new Error(`No valid broker addresses found in: \"${cfg.broker}\"`);\n }\n\n logger.log(`Creating Kafka client with brokers: ${brokers.join(\", \")}`);\n logger.log(`Security protocol: ${cfg.securityProtocol || \"plaintext\"}`);\n logger.log(`Client ID: ${cfg.clientId}`);\n\n const saslConfig = buildSaslConfig(logger, cfg);\n\n return new Kafka({\n kafkaJS: {\n clientId: cfg.clientId,\n brokers,\n ssl: cfg.securityProtocol === \"SASL_SSL\",\n ...(saslConfig && { sasl: saslConfig }),\n retry: {\n initialRetryTime: RETRY_INITIAL_TIME_MS,\n maxRetryTime: MAX_RETRY_TIME_MS,\n retries: MAX_RETRIES,\n },\n },\n });\n};\n"],"mappings":";;;;;;;;;AAqBA,SAAS,cAAc,aAAa;AACpC,SAAS,cAAAA,aAAY,iBAAAC,gBAAe,YAAY,iBAAiB;AACjE,OAAOC,WAAU;;;ACvBjB,SAAS,YAAY,oBAAoB;AACzC,OAAO,UAAU;AASV,IAAM,yBAAyB;AAAA,EACpC;AAAA,IACE,WAAW;AAAA;AAAA;AAAA,EAGb;AAAA,EACA;AAAA;AAAA,IAEE,WAAW;AAAA,EACb;AACF;AAIO,IAAM,yBAAyB;AAAA,EACpC,wBAAwB;AAAA,EACxB,iBAAiB;AAAA;AAAA;AAAA;AAAA,EAIjB,sBAAsB;AACxB;AAIO,IAAM,uBAAuB;AAAA,EAClC,QAAQ;AAAA,EACR,kBAAkB;AACpB;AAMO,SAAS,eAAuB;AACrC,SAAO,QAAQ,IAAI,oBAAoB;AACzC;AAKO,IAAM,kBAAkB;AAexB,SAAS,eACd,cAAsB,QAAQ,IAAI,GACnB;AACf,MAAI;AACF,QAAI,UAAU;AAAA,MACZ,KAAK,KAAK,aAAa,eAAe;AAAA,MACtC;AAAA,IACF;AAEA,QAAI,QAAQ,WAAW,CAAC,MAAM,OAAQ;AACpC,gBAAU,QAAQ,MAAM,CAAC;AAAA,IAC3B;AAEA,UAAM,WAAW,KAAK,IAAI,OAAO,GAAG;AACpC,WAAO,SAAS,iBAAiB,UAAU;AAAA,EAC7C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAMO,SAAS,UAAUC,eAAsB,QAAQ,IAAI,GAAW;AACrE,QAAMC,cAAa,eAAeD,YAAW;AAC7C,SAAOC,eAAc;AACvB;AAKO,SAAS,qBACdD,eAAsB,QAAQ,IAAI,GAC1B;AACR,QAAME,UAAS,UAAUF,YAAW;AACpC,QAAM,YAAY,aAAa;AAE/B,SAAO,KAAK,QAAQA,cAAaE,SAAQ,WAAW,UAAU;AAChE;AAKO,SAAS,qBACdF,eAAsB,QAAQ,IAAI,GACzB;AACT,SAAO,WAAW,qBAAqBA,YAAW,CAAC;AACrD;AAcO,SAAS,mBACdA,eAAsB,QAAQ,IAAI,GACpB;AACd,QAAM,UAAU,KAAK,KAAKA,cAAa,cAAc;AAErD,MAAI,WAAW,OAAO,GAAG;AACvB,QAAI;AACF,YAAM,aAAa,aAAa,SAAS,OAAO;AAChD,YAAM,MAAM,KAAK,MAAM,UAAU;AACjC,UAAI,IAAI,SAAS,UAAU;AACzB,eAAO;AAAA,MACT;AAAA,IACF,SAAS,GAAG;AAEV,cAAQ;AAAA,QACN,2CAA2C,OAAO;AAAA,QAClD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAQO,SAAS,iBAAiB,cAG/B;AACA,MAAI,iBAAiB,OAAO;AAC1B,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,kBAAkB;AAAA,IACpB;AAAA,EACF;AACA,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,kBAAkB;AAAA,EACpB;AACF;AAUA,eAAsB,WACpB,YACAA,eAAsB,QAAQ,IAAI,GACtB;AACZ,QAAM,eAAe,mBAAmBA,YAAW;AAEnD,MAAI,iBAAiB,OAAO;AAG1B,UAAM,EAAE,cAAc,IAAI,MAAM,OAAO,KAAK;AAC5C,UAAM,UAAU,cAAc,UAAU,EAAE;AAC1C,WAAO,MAAM,OAAO;AAAA,EACtB;AAKA,SAAO,UAAQ,UAAU;AAC3B;;;ACxMA;AAAA,EACE,cAAAG;AAAA,EACA;AAAA,EACA,gBAAAC;AAAA,EAEA;AAAA,OACK;AACP,OAAO,cAAc;AACrB,SAAS,oBAAoB;AAC7B,SAAS,eAAe;AAExB,IAAM,EAAE,MAAM,IAAI;AAuHlB,SAAS,cAAc,KAAa,YAAgC;AAClE,QAAM,UAAoB,CAAC;AAE3B,MAAI,CAACC,YAAW,GAAG,GAAG;AACpB,WAAO;AAAA,EACT;AAEA,MAAI;AACF,UAAM,UAAU,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC;AAExD,eAAW,SAAS,SAAS;AAC3B,YAAM,WAAW,SAAS,KAAK,KAAK,MAAM,IAAI;AAE9C,UAAI,MAAM,YAAY,GAAG;AAEvB,YAAI,MAAM,SAAS,gBAAgB;AACjC,kBAAQ,KAAK,GAAG,cAAc,UAAU,UAAU,CAAC;AAAA,QACrD;AAAA,MACF,WAAW,MAAM,OAAO,GAAG;AACzB,cAAM,MAAM,SAAS,QAAQ,MAAM,IAAI;AACvC,YAAI,WAAW,SAAS,GAAG,GAAG;AAC5B,kBAAQ,KAAK,QAAQ;AAAA,QACvB;AAAA,MACF;AAAA,IACF;AAAA,EACF,SAAS,GAAG;AAEV,YAAQ,MAAM,oCAAoC,GAAG,KAAK,CAAC;AAAA,EAC7D;AAEA,SAAO;AACT;AAUA,SAAS,wBAAwBC,UAAiB,SAA0B;AAG1E,QAAM,cAAc;AAIpB,QAAM,oBAAoB;AAI1B,QAAM,iBAAiB;AAEvB,MAAI,SAASA;AAGb,WAAS,OAAO,QAAQ,aAAa,CAAC,OAAO,QAAQ,YAAY,UAAU;AACzE,WAAO,kBAAkB,OAAO,QAAQ,YAAY,OAAO,OAAO;AAAA,EACpE,CAAC;AAGD,WAAS,OAAO;AAAA,IACd;AAAA,IACA,CAAC,OAAO,QAAQ,YAAY,UAAU;AACpC,aAAO,kBAAkB,OAAO,QAAQ,YAAY,OAAO,OAAO;AAAA,IACpE;AAAA,EACF;AAGA,WAAS,OAAO;AAAA,IACd;AAAA,IACA,CAAC,OAAO,QAAQ,YAAY,UAAU;AACpC,aAAO,kBAAkB,OAAO,QAAQ,YAAY,OAAO,OAAO;AAAA,IACpE;AAAA,EACF;AAEA,SAAO;AACT;AAaA,SAAS,kBACP,OACA,QACA,YACA,OACA,SACQ;AAER,MAAI,aAAa,KAAK,UAAU,GAAG;AACjC,WAAO;AAAA,EACT;AAGA,MAAI,UAAU,KAAK,UAAU,GAAG;AAC9B,WAAO;AAAA,EACT;AAGA,MAAI,SAAS;AACX,UAAM,eAAe,SAAS,QAAQ,SAAS,UAAU;AAGzD,QAAID,YAAW,GAAG,YAAY,KAAK,GAAG;AACpC,aAAO,GAAG,MAAM,GAAG,UAAU,MAAM,KAAK;AAAA,IAC1C;AAGA,QAAIA,YAAW,SAAS,KAAK,cAAc,UAAU,CAAC,GAAG;AAEvD,aAAO,GAAG,MAAM,GAAG,UAAU,YAAY,KAAK;AAAA,IAChD;AAGA,QAAIA,YAAW,GAAG,YAAY,MAAM,GAAG;AACrC,aAAO,GAAG,MAAM,GAAG,UAAU,OAAO,KAAK;AAAA,IAC3C;AACA,QAAIA,YAAW,SAAS,KAAK,cAAc,WAAW,CAAC,GAAG;AACxD,aAAO,GAAG,MAAM,GAAG,UAAU,aAAa,KAAK;AAAA,IACjD;AAGA,QAAIA,YAAW,GAAG,YAAY,MAAM,GAAG;AACrC,aAAO,GAAG,MAAM,GAAG,UAAU,OAAO,KAAK;AAAA,IAC3C;AACA,QAAIA,YAAW,SAAS,KAAK,cAAc,WAAW,CAAC,GAAG;AACxD,aAAO,GAAG,MAAM,GAAG,UAAU,aAAa,KAAK;AAAA,IACjD;AAAA,EACF;AAGA,SAAO,GAAG,MAAM,GAAG,UAAU,MAAM,KAAK;AAC1C;AAkBO,SAAS,wBAAwBE,SAAsB;AAC5D,QAAM,QAAQ,cAAcA,SAAQ,CAAC,OAAO,MAAM,CAAC;AAEnD,aAAW,YAAY,OAAO;AAC5B,UAAMD,WAAUE,cAAa,UAAU,OAAO;AAC9C,UAAM,UAAU,SAAS,QAAQ,QAAQ;AACzC,UAAM,YAAY,wBAAwBF,UAAS,OAAO;AAE1D,QAAIA,aAAY,WAAW;AACzB,oBAAc,UAAU,WAAW,OAAO;AAAA,IAC5C;AAAA,EACF;AACF;;;AFzQA,IAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AACjC,IAAM,YAAY,KAAK,SAAS,SAAS;AAEzC,IAAM,YAAY,KAAK,KAAK,CAAC,QAAQ,CAAC,IAAI,WAAW,IAAI,CAAC;AAE1D,IAAMG,eAAc,QAAQ,IAAI;AAChC,IAAM,eAAeC,MAAK,KAAKD,cAAa,eAAe;AAC3D,IAAM,mBAAmBC,MAAK,KAAKD,cAAa,2BAA2B;AAG3E,IAAM,aAAa,eAAeA,YAAW;AAC7C,IAAM,SAAS,aAAa,cAAc;AAG1C,IAAM,kBAAkB,cAAc,UAAa,CAAC;AAepD,SAAS,UAAU,OAA2B;AAC5C,UAAQ,IAAI,KAAK,UAAU,KAAK,CAAC;AACnC;AAKA,SAAS,oBACP,eACA;AACA,SAAO;AAAA,IACL,SAAS;AAAA,IACT,iBAAiB;AAAA,MACf,GAAG;AAAA,MACH,GAAG;AAAA,MACH,SAAS,CAAC,GAAG,sBAAsB;AAAA;AAAA,MAEnC,cAAc;AAAA,MACd,qBAAqB;AAAA;AAAA,MAErB,8BAA8B;AAAA;AAAA;AAAA,MAG9B,eAAe;AAAA;AAAA,MAEf,aAAa;AAAA,MACb,iBAAiBC,MAAK,KAAK,QAAQ,cAAc;AAAA,IACnD;AAAA,EACF;AACF;AAKA,SAAS,qBAAqB,cAAkC;AAC9D,QAAM,gBAAgB,iBAAiB,YAAY;AACnD,QAAM,gBAAgB,oBAAoB,aAAa;AAEvD,gBAAc,gBAAgB,gBAAgB;AAE9C,EAAAC,eAAc,kBAAkB,KAAK,UAAU,eAAe,MAAM,CAAC,CAAC;AACtE,UAAQ,IAAI,kDAAkD;AAG9D,QAAM,WAAW;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,MAAI,iBAAiB;AACnB,aAAS,KAAK,YAAY,MAAM;AAAA,EAClC;AAEA,MAAI;AACF,iBAAa,OAAO,UAAU;AAAA,MAC5B,OAAO;AAAA,MACP,KAAKF;AAAA,IACP,CAAC;AACD,YAAQ,IAAI,kCAAkC;AAAA,EAChD,SAAS,cAAmB;AAG1B,UAAM,YAAY,aAAa;AAC/B,UAAM,kBAAkBC,MAAK;AAAA,MAC3BD;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,QAAIG,YAAW,eAAe,GAAG;AAC/B,cAAQ,KAAK,EAAE;AACf,cAAQ,KAAK,sBAAsB;AACnC,cAAQ;AAAA,QACN;AAAA,MACF;AACA,cAAQ;AAAA,QACN;AAAA,MACF;AACA,cAAQ,KAAK,EAAE;AACf,cAAQ;AAAA,QACN;AAAA,MACF;AACA,cAAQ;AAAA,QACN;AAAA,MACF;AACA,cAAQ,KAAK,iDAAiD;AAC9D,cAAQ;AAAA,QACN;AAAA,MACF;AACA,cAAQ,KAAK,yDAAyD;AACtE,cAAQ,KAAK,EAAE;AACf,cAAQ;AAAA,QACN;AAAA,MACF;AACA,cAAQ;AAAA,QACN;AAAA,MACF;AACA,cAAQ;AAAA,QACN;AAAA,MACF;AACA,cAAQ,KAAK,EAAE;AACf,cAAQ,IAAI,uDAAuD;AAAA,IACrE,OAAO;AACL,cAAQ,MAAM,iDAAiD;AAC/D,YAAM;AAAA,IACR;AAAA,EACF;AAGA,MAAI,iBAAiB,OAAO;AAC1B,YAAQ,IAAI,sDAAsD;AAClE,UAAM,aAAaF,MAAK,KAAKD,cAAa,MAAM;AAChD,4BAAwB,UAAU;AAClC,YAAQ,IAAI,gCAAgC;AAAA,EAC9C;AACF;AAMA,SAAS,oBAAoB,cAAkC;AAC7D,QAAM,gBAAgB,iBAAiB,YAAY;AACnD,QAAM,gBAAgB,oBAAoB,aAAa;AAGvD,EAAAE,eAAc,kBAAkB,KAAK,UAAU,eAAe,MAAM,CAAC,CAAC;AAGtE,QAAM,aAAaD,MAAK,KAAKD,cAAa,MAAM;AAChD,MAAI,CAACG,YAAW,UAAU,GAAG;AAC3B,cAAU,YAAY,EAAE,WAAW,KAAK,CAAC;AAAA,EAC3C;AAGA,MAAI,qBAA+B,CAAC;AACpC,MAAI,aAAa;AACjB,MAAI,eAAe;AAGnB,QAAM,WAAW;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,MAAI,iBAAiB;AAEnB,aAAS,OAAO,GAAG,GAAG,YAAY,MAAM;AAAA,EAC1C;AAGA,QAAM,cAAc,MAAM,OAAO,UAAU;AAAA,IACzC,KAAKH;AAAA,IACL,OAAO,CAAC,UAAU,QAAQ,MAAM;AAAA,EAClC,CAAC;AAGD,QAAM,UAAU,MAAM;AACpB,QAAIG,YAAW,gBAAgB,GAAG;AAChC,iBAAW,gBAAgB;AAAA,IAC7B;AACA,gBAAY,KAAK;AAAA,EACnB;AAEA,UAAQ,GAAG,UAAU,MAAM;AACzB,YAAQ;AACR,YAAQ,KAAK,CAAC;AAAA,EAChB,CAAC;AAED,UAAQ,GAAG,WAAW,MAAM;AAC1B,YAAQ;AACR,YAAQ,KAAK,CAAC;AAAA,EAChB,CAAC;AAKD,MAAI,SAAS;AAGb,QAAM,YAAY,CAAC,QACjB,IAAI;AAAA,IACF;AAAA,IACA;AAAA,EACF;AAGF,QAAM,0BACJ;AACF,QAAM,2BACJ;AACF,QAAM,kBAAkB;AAExB,QAAM,cAAc,CAAC,SAAiB;AACpC,UAAM,YAAY,UAAU,IAAI;AAEhC,QAAI,wBAAwB,KAAK,SAAS,GAAG;AAE3C,2BAAqB,CAAC;AACtB,mBAAa;AACb,qBAAe;AACf,gBAAU,EAAE,OAAO,gBAAgB,CAAC;AAAA,IACtC,WAAW,yBAAyB,KAAK,SAAS,GAAG;AAGnD,YAAM,QAAQ,UAAU,MAAM,+BAA+B;AAC7D,UAAI,OAAO;AACT,qBAAa,SAAS,MAAM,CAAC,GAAG,EAAE;AAAA,MACpC;AAGA,UAAI,eAAe,KAAK,iBAAiB,OAAO;AAC9C,YAAI;AACF,kCAAwB,UAAU;AAAA,QACpC,SAAS,GAAG;AAEV,kBAAQ,MAAM,yCAAyC,CAAC;AAAA,QAC1D;AAAA,MACF;AAEA,UAAI,aAAa,GAAG;AAClB,kBAAU;AAAA,UACR,OAAO;AAAA,UACP,QAAQ;AAAA,UACR,UAAU;AAAA,UACV,aAAa;AAAA,QACf,CAAC;AAAA,MACH,OAAO;AACL,kBAAU;AAAA,UACR,OAAO;AAAA,UACP,QAAQ;AAAA,UACR,UAAU;AAAA,UACV,aAAa,eAAe,IAAI,qBAAqB;AAAA,QACvD,CAAC;AAAA,MACH;AAAA,IACF,WAAW,gBAAgB,KAAK,SAAS,GAAG;AAE1C,yBAAmB,KAAK,UAAU,KAAK,CAAC;AACxC,UAAI,UAAU,SAAS,UAAU,GAAG;AAClC;AAAA,MACF,WAAW,UAAU,SAAS,YAAY,GAAG;AAC3C;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,cAAY,OAAO,GAAG,QAAQ,CAAC,SAAiB;AAC9C,cAAU,KAAK,SAAS;AACxB,UAAM,QAAQ,OAAO,MAAM,IAAI;AAC/B,aAAS,MAAM,IAAI,KAAK;AACxB,eAAW,QAAQ,OAAO;AACxB,UAAI,KAAK,KAAK,GAAG;AACf,oBAAY,IAAI;AAAA,MAClB;AAAA,IACF;AAAA,EACF,CAAC;AAED,cAAY,OAAO,GAAG,QAAQ,CAAC,SAAiB;AAE9C,YAAQ,OAAO,MAAM,KAAK,SAAS,CAAC;AAAA,EACtC,CAAC;AAED,cAAY,GAAG,SAAS,CAAC,QAAQ;AAC/B,YAAQ,MAAM,yBAAyB,GAAG;AAC1C,YAAQ;AACR,YAAQ,KAAK,CAAC;AAAA,EAChB,CAAC;AAED,cAAY,GAAG,QAAQ,CAAC,SAAS;AAC/B,YAAQ;AACR,QAAI,SAAS,GAAG;AACd,cAAQ,KAAK,QAAQ,CAAC;AAAA,IACxB;AAAA,EACF,CAAC;AACH;AAMA,SAAS,qBAAqB;AAC5B,QAAM,WAAWF,MAAK,KAAKD,cAAa,QAAQ;AAChD,MAAI,CAACG,YAAW,QAAQ,GAAG;AACzB,cAAU,UAAU,EAAE,WAAW,KAAK,CAAC;AAAA,EACzC;AACA,QAAM,aAAaF,MAAK,KAAK,UAAU,sBAAsB;AAC7D,EAAAC,eAAc,YAAY,KAAK,UAAU,EAAE,OAAO,GAAG,MAAM,CAAC,CAAC;AAC/D;AAGA,IAAI,CAACC,YAAW,YAAY,GAAG;AAC7B,UAAQ,MAAM,qCAAqCH,YAAW;AAC9D,UAAQ,KAAK,CAAC;AAChB;AAEA,IAAI;AAEF,qBAAmB;AAGnB,QAAM,eAAe,mBAAmBA,YAAW;AAEnD,MAAI,WAAW;AAEb,wBAAoB,YAAY;AAAA,EAClC,OAAO;AAEL,YAAQ,IAAI,2BAA2B,MAAM,KAAK;AAClD,YAAQ;AAAA,MACN,SAAS,aAAa,YAAY,CAAC;AAAA,IACrC;AACA,yBAAqB,YAAY;AACjC,YAAQ,IAAI,uBAAuB;AAGnC,QAAIG,YAAW,gBAAgB,GAAG;AAChC,iBAAW,gBAAgB;AAAA,IAC7B;AAAA,EACF;AACF,SAAS,OAAO;AACd,UAAQ,MAAM,yBAAyB,KAAK;AAE5C,MAAIA,YAAW,gBAAgB,GAAG;AAChC,eAAW,gBAAgB;AAAA,EAC7B;AACA,UAAQ,KAAK,CAAC;AAChB;","names":["existsSync","writeFileSync","path","projectRoot","userOutDir","outDir","existsSync","readFileSync","existsSync","content","outDir","readFileSync","projectRoot","path","writeFileSync","existsSync"]}
|
|
1
|
+
{"version":3,"sources":["../src/moose-tspc.ts","../src/compiler-config.ts","../src/commons.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * Pre-compiles TypeScript app code with moose compiler plugins and typia transforms.\n *\n * Usage: moose-tspc [outDir] [--watch]\n * outDir: Output directory for compiled files (optional, overrides tsconfig)\n * --watch: Enable watch mode for incremental compilation (outputs JSON events)\n *\n * Output directory is determined by (in priority order):\n * 1. CLI argument (if provided) - used by Docker builds\n * 2. User's tsconfig.json outDir setting (if specified)\n * 3. Default: .moose/compiled\n *\n * This script creates a temporary tsconfig that extends the user's config and adds\n * the required moose compiler plugins, then runs tspc to compile with transforms.\n *\n * In watch mode, outputs JSON events to stdout for the Rust CLI to parse:\n * {\"event\": \"compile_start\"}\n * {\"event\": \"compile_complete\", \"errors\": 0, \"warnings\": 2}\n * {\"event\": \"compile_error\", \"errors\": 3, \"diagnostics\": [...]}\n */\nimport { execFileSync, spawn } from \"child_process\";\nimport { existsSync, writeFileSync, unlinkSync, mkdirSync } from \"fs\";\nimport path from \"path\";\nimport {\n MOOSE_COMPILER_PLUGINS,\n MOOSE_COMPILER_OPTIONS,\n detectModuleSystem,\n getModuleOptions,\n getSourceDir,\n readUserOutDir,\n DEFAULT_OUT_DIR,\n type ModuleSystem,\n} from \"./compiler-config\";\nimport { rewriteImportExtensions } from \"./commons\";\n\n// Parse command line arguments\nconst args = process.argv.slice(2);\nconst watchMode = args.includes(\"--watch\");\n// CLI argument takes priority (for Docker builds), then tsconfig, then default\nconst cliOutDir = args.find((arg) => !arg.startsWith(\"--\"));\n\nconst projectRoot = process.cwd();\nconst tsconfigPath = path.join(projectRoot, \"tsconfig.json\");\nconst tempTsconfigPath = path.join(projectRoot, \"tsconfig.moose-build.json\");\n\n// Determine outDir - CLI arg > tsconfig > default\nconst userOutDir = readUserOutDir(projectRoot);\nconst outDir = cliOutDir || userOutDir || DEFAULT_OUT_DIR;\n// add --outDir flag if user hasn't specified in tsconfig\n// (if CLI arg is provided, we always pass it explicitly)\nconst shouldAddOutDir = cliOutDir !== undefined || !userOutDir;\n\n/**\n * JSON event protocol for watch mode communication with Rust CLI.\n */\ninterface CompileEvent {\n event: \"compile_start\" | \"compile_complete\" | \"compile_error\";\n errors?: number;\n warnings?: number;\n diagnostics?: string[];\n}\n\n/**\n * Emit a JSON event to stdout for the Rust CLI to parse.\n */\nfunction emitEvent(event: CompileEvent): void {\n console.log(JSON.stringify(event));\n}\n\n/**\n * Create the build tsconfig with moose plugins.\n */\nfunction createBuildTsconfig(\n moduleOptions: ReturnType<typeof getModuleOptions>,\n) {\n return {\n extends: \"./tsconfig.json\",\n compilerOptions: {\n ...MOOSE_COMPILER_OPTIONS,\n ...moduleOptions,\n plugins: [...MOOSE_COMPILER_PLUGINS],\n // Skip type checking of declaration files to avoid dual-package conflicts\n skipLibCheck: true,\n skipDefaultLibCheck: true,\n // Additional settings to handle module resolution conflicts\n allowSyntheticDefaultImports: true,\n // Block emission on errors so build and dev behave consistently\n noEmitOnError: true,\n // Enable incremental compilation for faster rebuilds\n incremental: true,\n tsBuildInfoFile: path.join(outDir, \".tsbuildinfo\"),\n },\n };\n}\n\n/**\n * Run a single compilation (non-watch mode).\n */\nfunction runSingleCompilation(moduleSystem: ModuleSystem): void {\n const moduleOptions = getModuleOptions(moduleSystem);\n const buildTsconfig = createBuildTsconfig(moduleOptions);\n\n writeFileSync(tempTsconfigPath, JSON.stringify(buildTsconfig, null, 2));\n console.log(\"Created temporary tsconfig with moose plugins...\");\n\n // Build tspc arguments - only add --outDir if user hasn't specified one in tsconfig\n const tspcArgs = [\n \"tspc\",\n \"-p\",\n tempTsconfigPath,\n \"--rootDir\",\n \".\",\n \"--sourceMap\",\n \"--inlineSources\",\n ];\n if (shouldAddOutDir) {\n tspcArgs.push(\"--outDir\", outDir);\n }\n\n execFileSync(\"npx\", tspcArgs, {\n stdio: \"inherit\",\n cwd: projectRoot,\n });\n console.log(\"TypeScript compilation complete.\");\n\n // Post-process ESM output to add .js extensions to relative imports\n if (moduleSystem === \"esm\") {\n console.log(\"Post-processing ESM imports to add .js extensions...\");\n const fullOutDir = path.join(projectRoot, outDir);\n rewriteImportExtensions(fullOutDir);\n console.log(\"ESM import rewriting complete.\");\n }\n}\n\n/**\n * Run watch mode compilation with JSON event output.\n * Uses tspc --watch and parses its output to emit structured events.\n */\nfunction runWatchCompilation(moduleSystem: ModuleSystem): void {\n const moduleOptions = getModuleOptions(moduleSystem);\n const buildTsconfig = createBuildTsconfig(moduleOptions);\n\n // Write the tsconfig (it stays for the duration of watch mode)\n writeFileSync(tempTsconfigPath, JSON.stringify(buildTsconfig, null, 2));\n\n // Ensure output directory exists for incremental build info\n const fullOutDir = path.join(projectRoot, outDir);\n if (!existsSync(fullOutDir)) {\n mkdirSync(fullOutDir, { recursive: true });\n }\n\n // Track diagnostics between compilation cycles\n let currentDiagnostics: string[] = [];\n let errorCount = 0;\n let warningCount = 0;\n\n // Build tspc arguments - only add --outDir if user hasn't specified one in tsconfig\n const tspcArgs = [\n \"tspc\",\n \"-p\",\n tempTsconfigPath,\n \"--rootDir\",\n \".\",\n \"--sourceMap\",\n \"--inlineSources\",\n \"--watch\",\n \"--preserveWatchOutput\",\n ];\n if (shouldAddOutDir) {\n // Insert --outDir after --rootDir and \".\" so rootDir is not clobbered\n tspcArgs.splice(6, 0, \"--outDir\", outDir);\n }\n\n // Spawn tspc in watch mode\n const tspcProcess = spawn(\"npx\", tspcArgs, {\n cwd: projectRoot,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n\n // Handle process termination\n const cleanup = () => {\n if (existsSync(tempTsconfigPath)) {\n unlinkSync(tempTsconfigPath);\n }\n tspcProcess.kill();\n };\n\n process.on(\"SIGINT\", () => {\n cleanup();\n process.exit(0);\n });\n\n process.on(\"SIGTERM\", () => {\n cleanup();\n process.exit(0);\n });\n\n // Parse tspc output line by line\n // Pattern matching approach inspired by tsc-watch (github.com/gilamran/tsc-watch)\n // which also parses tsc stdout to detect compilation events\n let buffer = \"\";\n\n // Strip ANSI escape codes for reliable pattern matching (standard regex pattern)\n const stripAnsi = (str: string) =>\n str.replace(\n /[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d/#&.:=?%@~_]*)*)?[\\u0007])|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))/g,\n \"\",\n );\n\n // tsc watch mode patterns (with timestamp prefix like \"12:00:00 AM - \")\n const compilationStartedRegex =\n /Starting compilation in watch mode|Starting incremental compilation/;\n const compilationCompleteRegex =\n /Found\\s+(\\d+)\\s+error(?:s)?\\..*Watching for file changes/;\n const diagnosticRegex = /\\(\\d+,\\d+\\):\\s*(error|warning)\\s+TS\\d+:/;\n\n const processLine = (line: string) => {\n const cleanLine = stripAnsi(line);\n\n if (compilationStartedRegex.test(cleanLine)) {\n // New compilation cycle starting\n currentDiagnostics = [];\n errorCount = 0;\n warningCount = 0;\n emitEvent({ event: \"compile_start\" });\n } else if (compilationCompleteRegex.test(cleanLine)) {\n // Compilation complete - parse error count from tsc summary line\n // Format: \"12:00:00 AM - Found 0 errors. Watching for file changes.\"\n const match = cleanLine.match(/Found\\s+(\\d+)\\s+error(?:s)?\\./);\n if (match) {\n errorCount = parseInt(match[1], 10);\n }\n\n // Post-process ESM if successful\n if (errorCount === 0 && moduleSystem === \"esm\") {\n try {\n rewriteImportExtensions(fullOutDir);\n } catch (e) {\n // Log but don't fail - import rewriting is best-effort\n console.error(\"Warning: ESM import rewriting failed:\", e);\n }\n }\n\n if (errorCount > 0) {\n emitEvent({\n event: \"compile_error\",\n errors: errorCount,\n warnings: warningCount,\n diagnostics: currentDiagnostics,\n });\n } else {\n emitEvent({\n event: \"compile_complete\",\n errors: 0,\n warnings: warningCount,\n diagnostics: warningCount > 0 ? currentDiagnostics : undefined,\n });\n }\n } else if (diagnosticRegex.test(cleanLine)) {\n // This is a diagnostic line (error or warning)\n currentDiagnostics.push(cleanLine.trim());\n if (cleanLine.includes(\": error \")) {\n errorCount++;\n } else if (cleanLine.includes(\": warning \")) {\n warningCount++;\n }\n }\n };\n\n tspcProcess.stdout.on(\"data\", (data: Buffer) => {\n buffer += data.toString();\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() || \"\"; // Keep incomplete line in buffer\n for (const line of lines) {\n if (line.trim()) {\n processLine(line);\n }\n }\n });\n\n tspcProcess.stderr.on(\"data\", (data: Buffer) => {\n // Forward stderr for debugging but don't parse it\n process.stderr.write(data.toString());\n });\n\n tspcProcess.on(\"error\", (err) => {\n console.error(\"Failed to start tspc:\", err);\n cleanup();\n process.exit(1);\n });\n\n tspcProcess.on(\"exit\", (code) => {\n cleanup();\n if (code !== 0) {\n process.exit(code || 1);\n }\n });\n}\n\n/**\n * Write compile metadata to .moose/.compile-config.json\n * This allows Rust CLI to know where compiled output is without duplicating logic\n */\nfunction writeCompileConfig() {\n const mooseDir = path.join(projectRoot, \".moose\");\n if (!existsSync(mooseDir)) {\n mkdirSync(mooseDir, { recursive: true });\n }\n const configPath = path.join(mooseDir, \".compile-config.json\");\n writeFileSync(configPath, JSON.stringify({ outDir }, null, 2));\n}\n\n// Main execution\nif (!existsSync(tsconfigPath)) {\n console.error(\"Error: tsconfig.json not found in\", projectRoot);\n process.exit(1);\n}\n\ntry {\n // Write compile config so Rust CLI knows where output is\n writeCompileConfig();\n\n // Auto-detect module system from package.json\n const moduleSystem = detectModuleSystem(projectRoot);\n\n if (watchMode) {\n // Watch mode - run indefinitely with JSON event output\n runWatchCompilation(moduleSystem);\n } else {\n // Single compilation mode\n console.log(`Compiling TypeScript to ${outDir}...`);\n console.log(\n `Using ${moduleSystem.toUpperCase()} module output (detected from package.json)...`,\n );\n runSingleCompilation(moduleSystem);\n console.log(\"Compilation complete.\");\n\n // Clean up the temporary tsconfig\n if (existsSync(tempTsconfigPath)) {\n unlinkSync(tempTsconfigPath);\n }\n }\n} catch (error) {\n console.error(\"Build process failed:\", error);\n // Clean up the temporary tsconfig\n if (existsSync(tempTsconfigPath)) {\n unlinkSync(tempTsconfigPath);\n }\n process.exit(1);\n}\n","import { existsSync, readFileSync } from \"fs\";\nimport path from \"path\";\n\n/**\n * Shared TypeScript compiler configuration for moose projects.\n * Used by both moose-runner.ts (runtime) and moose-tspc.ts (pre-compilation).\n *\n * Moose now always uses pre-compiled JavaScript - no ts-node fallback.\n */\n\nexport const MOOSE_COMPILER_PLUGINS = [\n {\n transform: \"./node_modules/@514labs/moose-lib/dist/compilerPlugin.js\",\n // No longer using transformProgram - direct typia integration eliminates\n // the need for program replacement and the associated incremental compilation issues\n },\n {\n // Keep typia plugin for users who use typia directly (not through Moose resources)\n transform: \"typia/lib/transform\",\n },\n] as const;\n\n// Options required for moose compilation\n// Note: We only set what's absolutely necessary to avoid conflicts with user projects\nexport const MOOSE_COMPILER_OPTIONS = {\n experimentalDecorators: true,\n esModuleInterop: true,\n // Disable strict module syntax checking to avoid dual-package type conflicts\n // This prevents errors where the same type imported with different resolution\n // modes (CJS vs ESM) is treated as incompatible\n verbatimModuleSyntax: false,\n} as const;\n\n// Module resolution options - only applied if not already set in user's tsconfig\n// These help with ESM/CJS interop but can be overridden by user config\nexport const MOOSE_MODULE_OPTIONS = {\n module: \"NodeNext\",\n moduleResolution: \"NodeNext\",\n} as const;\n\n/**\n * Default source directory for user code.\n * Can be overridden via MOOSE_SOURCE_DIR environment variable.\n */\nexport function getSourceDir(): string {\n return process.env.MOOSE_SOURCE_DIR || \"app\";\n}\n\n/**\n * Default output directory for compiled code.\n */\nexport const DEFAULT_OUT_DIR = \".moose/compiled\";\n\n/**\n * Read the user's tsconfig.json and extract the outDir setting.\n * Supports JSONC (JSON with Comments) by evaluating as JavaScript\n * (JSON with comments is valid JS in ES2019+).\n *\n * Security note: This uses eval-like behavior (new Function), which means\n * malicious code in tsconfig.json would execute. This is acceptable because:\n * - The user controls their own tsconfig.json\n * - Same trust model as running `tsc` or any other tool that processes the file\n * - If you clone and run untrusted code, you're already at risk\n *\n * Returns the outDir if specified, or null if not.\n */\nexport function readUserOutDir(\n projectRoot: string = process.cwd(),\n): string | null {\n try {\n let content = readFileSync(\n path.join(projectRoot, \"tsconfig.json\"),\n \"utf-8\",\n );\n // Strip UTF-8 BOM if present\n if (content.charCodeAt(0) === 0xfeff) {\n content = content.slice(1);\n }\n // eslint-disable-next-line no-eval\n const tsconfig = eval(`(${content})`);\n return tsconfig.compilerOptions?.outDir || null;\n } catch {\n return null;\n }\n}\n\n/**\n * Get the output directory for compiled code.\n * Uses user's tsconfig outDir if specified, otherwise defaults to .moose/compiled\n */\nexport function getOutDir(projectRoot: string = process.cwd()): string {\n const userOutDir = readUserOutDir(projectRoot);\n return userOutDir || DEFAULT_OUT_DIR;\n}\n\n/**\n * Get the path to the compiled index.js file.\n */\nexport function getCompiledIndexPath(\n projectRoot: string = process.cwd(),\n): string {\n const outDir = getOutDir(projectRoot);\n const sourceDir = getSourceDir();\n // Resolve so that absolute outDir from tsconfig is handled correctly\n return path.resolve(projectRoot, outDir, sourceDir, \"index.js\");\n}\n\n/**\n * Check if pre-compiled artifacts exist for the current project.\n */\nexport function hasCompiledArtifacts(\n projectRoot: string = process.cwd(),\n): boolean {\n return existsSync(getCompiledIndexPath(projectRoot));\n}\n\n/**\n * Module system type for compilation output.\n */\nexport type ModuleSystem = \"esm\" | \"cjs\";\n\n/**\n * Detects the module system from the user's package.json.\n * Returns 'esm' if package.json has \"type\": \"module\", otherwise 'cjs'.\n *\n * @param projectRoot - Root directory containing package.json (defaults to cwd)\n * @returns The detected module system\n */\nexport function detectModuleSystem(\n projectRoot: string = process.cwd(),\n): ModuleSystem {\n const pkgPath = path.join(projectRoot, \"package.json\");\n\n if (existsSync(pkgPath)) {\n try {\n const pkgContent = readFileSync(pkgPath, \"utf-8\");\n const pkg = JSON.parse(pkgContent);\n if (pkg.type === \"module\") {\n return \"esm\";\n }\n } catch (e) {\n // If parsing fails, default to CJS\n console.debug(\n `[moose] Failed to parse package.json at ${pkgPath}, defaulting to CJS:`,\n e,\n );\n }\n }\n\n return \"cjs\";\n}\n\n/**\n * Get compiler module options based on detected module system.\n *\n * @param moduleSystem - The module system to get options for\n * @returns Compiler options for module and moduleResolution\n */\nexport function getModuleOptions(moduleSystem: ModuleSystem): {\n module: string;\n moduleResolution: string;\n} {\n if (moduleSystem === \"esm\") {\n return {\n module: \"ES2022\",\n moduleResolution: \"bundler\",\n };\n }\n return {\n module: \"CommonJS\",\n moduleResolution: \"Node\",\n };\n}\n\n/**\n * Dynamic module loader that works with both CJS and ESM.\n * Uses detected module system to determine loading strategy.\n *\n * @param modulePath - Path to the module to load\n * @param projectRoot - Root directory for module system detection\n * @returns The loaded module\n */\nexport async function loadModule<T = any>(\n modulePath: string,\n projectRoot: string = process.cwd(),\n): Promise<T> {\n const moduleSystem = detectModuleSystem(projectRoot);\n\n if (moduleSystem === \"esm\") {\n // Use dynamic import for ESM\n // pathToFileURL is needed for Windows compatibility with absolute paths\n const { pathToFileURL } = await import(\"url\");\n const fileUrl = pathToFileURL(modulePath).href;\n return await import(fileUrl);\n }\n\n // Use require for CJS\n // Note: In ESM builds (compiled by tsup), this code path is replaced with\n // the appropriate ESM imports. The dual-package build ensures compatibility.\n return require(modulePath);\n}\n","import {\n existsSync,\n readdirSync,\n readFileSync,\n statSync,\n writeFileSync,\n} from \"fs\";\nimport nodePath from \"path\";\nimport { createClient } from \"@clickhouse/client\";\nimport { KafkaJS } from \"@514labs/kafka-javascript\";\nimport { SASLOptions } from \"@514labs/kafka-javascript/types/kafkajs\";\nconst { Kafka } = KafkaJS;\ntype Kafka = KafkaJS.Kafka;\ntype Consumer = KafkaJS.Consumer;\nexport type Producer = KafkaJS.Producer;\n\n/**\n * Utility function for compiler-related logging that can be disabled via environment variable.\n * Set MOOSE_DISABLE_COMPILER_LOGS=true to suppress these logs (useful for testing environments).\n */\n\n/**\n * Returns true if the value is a common truthy string: \"1\", \"true\", \"yes\", \"on\" (case-insensitive).\n */\nfunction isTruthy(value: string | undefined): boolean {\n if (!value) return false;\n switch (value.trim().toLowerCase()) {\n case \"1\":\n case \"true\":\n case \"yes\":\n case \"on\":\n return true;\n default:\n return false;\n }\n}\n\nexport const compilerLog = (message: string) => {\n if (!isTruthy(process.env.MOOSE_DISABLE_COMPILER_LOGS)) {\n console.log(message);\n }\n};\n\nexport const antiCachePath = (path: string) =>\n `${path}?num=${Math.random().toString()}&time=${Date.now()}`;\n\nexport const getFileName = (filePath: string) => {\n const regex = /\\/([^\\/]+)\\.ts/;\n const matches = filePath.match(regex);\n if (matches && matches.length > 1) {\n return matches[1];\n }\n return \"\";\n};\n\ninterface ClientConfig {\n username: string;\n password: string;\n database: string;\n useSSL: string;\n host: string;\n port: string;\n}\n\nexport const getClickhouseClient = ({\n username,\n password,\n database,\n useSSL,\n host,\n port,\n}: ClientConfig) => {\n const protocol =\n useSSL === \"1\" || useSSL.toLowerCase() === \"true\" ? \"https\" : \"http\";\n console.log(`Connecting to Clickhouse at ${protocol}://${host}:${port}`);\n return createClient({\n url: `${protocol}://${host}:${port}`,\n username: username,\n password: password,\n database: database,\n application: \"moose\",\n // Note: wait_end_of_query is configured per operation type, not globally\n // to preserve SELECT query performance while ensuring INSERT/DDL reliability\n });\n};\n\nexport type CliLogData = {\n message_type?: \"Info\" | \"Success\" | \"Warning\" | \"Error\" | \"Highlight\";\n action: string;\n message: string;\n};\n\nexport const cliLog: (log: CliLogData) => void = (log) => {\n const level =\n log.message_type === \"Error\" ? \"error\"\n : log.message_type === \"Warning\" ? \"warn\"\n : \"info\";\n\n const structuredLog = {\n __moose_structured_log__: true,\n level,\n message: log.message,\n resource_type: \"runtime\",\n cli_action: log.action,\n cli_message_type: log.message_type ?? \"Info\",\n timestamp: new Date().toISOString(),\n };\n\n process.stderr.write(JSON.stringify(structuredLog) + \"\\n\");\n};\n\n/**\n * Method to change .ts, .cts, and .mts to .js, .cjs, and .mjs\n * This is needed because 'import' does not support .ts, .cts, and .mts\n */\nexport function mapTstoJs(filePath: string): string {\n return filePath\n .replace(/\\.ts$/, \".js\")\n .replace(/\\.cts$/, \".cjs\")\n .replace(/\\.mts$/, \".mjs\");\n}\n\n/**\n * Walks a directory recursively and returns all files matching the given extensions.\n * Skips node_modules directories.\n *\n * @param dir - Directory to walk\n * @param extensions - File extensions to include (e.g., [\".js\", \".mjs\"])\n * @returns Array of file paths\n */\nfunction walkDirectory(dir: string, extensions: string[]): string[] {\n const results: string[] = [];\n\n if (!existsSync(dir)) {\n return results;\n }\n\n try {\n const entries = readdirSync(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = nodePath.join(dir, entry.name);\n\n if (entry.isDirectory()) {\n // Skip node_modules\n if (entry.name !== \"node_modules\") {\n results.push(...walkDirectory(fullPath, extensions));\n }\n } else if (entry.isFile()) {\n const ext = nodePath.extname(entry.name);\n if (extensions.includes(ext)) {\n results.push(fullPath);\n }\n }\n }\n } catch (e) {\n // Log error in case it is something the user can/should act on\n console.debug(`[moose] Failed to read directory ${dir}:`, e);\n }\n\n return results;\n}\n\n/**\n * Adds .js extension to relative import paths that don't have an extension.\n * Handles import/export from statements and dynamic imports.\n *\n * @param content - JavaScript file content\n * @param fileDir - Directory containing the file being processed (for resolving paths)\n * @returns Content with .js extensions added to relative imports\n */\nfunction addJsExtensionToImports(content: string, fileDir?: string): string {\n // Pattern for 'from' statements with relative paths\n // Matches: from './foo', from \"../bar\", from './utils/helper'\n const fromPattern = /(from\\s+['\"])(\\.\\.?\\/[^'\"]*?)(['\"])/g;\n\n // Pattern for side-effect-only imports with relative paths\n // Matches: import './foo', import \"../bar\" (no 'from' keyword, just importing for side effects)\n const bareImportPattern = /(import\\s+['\"])(\\.\\.?\\/[^'\"]*?)(['\"])/g;\n\n // Pattern for dynamic imports with relative paths\n // Matches: import('./foo'), import(\"../bar\")\n const dynamicPattern = /(import\\s*\\(\\s*['\"])(\\.\\.?\\/[^'\"]*?)(['\"])/g;\n\n let result = content;\n\n // Process 'from' statements\n result = result.replace(fromPattern, (match, prefix, importPath, quote) => {\n return rewriteImportPath(match, prefix, importPath, quote, fileDir);\n });\n\n // Process side-effect-only imports\n result = result.replace(\n bareImportPattern,\n (match, prefix, importPath, quote) => {\n return rewriteImportPath(match, prefix, importPath, quote, fileDir);\n },\n );\n\n // Process dynamic imports\n result = result.replace(\n dynamicPattern,\n (match, prefix, importPath, quote) => {\n return rewriteImportPath(match, prefix, importPath, quote, fileDir);\n },\n );\n\n return result;\n}\n\n/**\n * Rewrites a single import path to add .js extension if needed.\n * Handles directory imports with index files correctly.\n *\n * @param match - The full matched string\n * @param prefix - The prefix (from ' or import(')\n * @param importPath - The import path\n * @param quote - The closing quote\n * @param fileDir - Directory containing the file being processed (for resolving paths)\n * @returns The rewritten import or original if no change needed\n */\nfunction rewriteImportPath(\n match: string,\n prefix: string,\n importPath: string,\n quote: string,\n fileDir?: string,\n): string {\n // Skip if already has a JavaScript extension\n if (/\\.[cm]?js$/.test(importPath)) {\n return match;\n }\n\n // Skip if importing a JSON file\n if (/\\.json$/.test(importPath)) {\n return match;\n }\n\n // If we have the file directory, check if the import target is a directory with index.js\n if (fileDir) {\n const resolvedPath = nodePath.resolve(fileDir, importPath);\n\n // Check if path.js exists (regular file import)\n if (existsSync(`${resolvedPath}.js`)) {\n return `${prefix}${importPath}.js${quote}`;\n }\n\n // Check if path/index.js exists (directory import)\n if (existsSync(nodePath.join(resolvedPath, \"index.js\"))) {\n // For directory imports, rewrite to include /index.js\n return `${prefix}${importPath}/index.js${quote}`;\n }\n\n // Check for .mjs variants\n if (existsSync(`${resolvedPath}.mjs`)) {\n return `${prefix}${importPath}.mjs${quote}`;\n }\n if (existsSync(nodePath.join(resolvedPath, \"index.mjs\"))) {\n return `${prefix}${importPath}/index.mjs${quote}`;\n }\n\n // Check for .cjs variants\n if (existsSync(`${resolvedPath}.cjs`)) {\n return `${prefix}${importPath}.cjs${quote}`;\n }\n if (existsSync(nodePath.join(resolvedPath, \"index.cjs\"))) {\n return `${prefix}${importPath}/index.cjs${quote}`;\n }\n }\n\n // Default: add .js extension (fallback when no fileDir or file not found)\n return `${prefix}${importPath}.js${quote}`;\n}\n\n/**\n * Rewrites relative import paths in JavaScript files to include .js extensions.\n * This is required for Node.js ESM which requires explicit extensions.\n *\n * Handles:\n * - import statements: import { foo } from './bar' -> import { foo } from './bar.js'\n * - dynamic imports: import('./bar') -> import('./bar.js')\n * - re-exports: export { foo } from './bar' -> export { foo } from './bar.js'\n *\n * Does NOT modify:\n * - Package imports (no leading . or ..)\n * - Imports that already have extensions\n * - Imports from node_modules\n *\n * @param outDir - Directory containing compiled JavaScript files\n */\nexport function rewriteImportExtensions(outDir: string): void {\n const files = walkDirectory(outDir, [\".js\", \".mjs\"]);\n\n for (const filePath of files) {\n const content = readFileSync(filePath, \"utf-8\");\n const fileDir = nodePath.dirname(filePath);\n const rewritten = addJsExtensionToImports(content, fileDir);\n\n if (content !== rewritten) {\n writeFileSync(filePath, rewritten, \"utf-8\");\n }\n }\n}\n\nexport const MAX_RETRIES = 150;\nexport const MAX_RETRY_TIME_MS = 1000;\nexport const RETRY_INITIAL_TIME_MS = 100;\n\nexport const MAX_RETRIES_PRODUCER = 150;\nexport const RETRY_FACTOR_PRODUCER = 0.2;\n// Means all replicas need to acknowledge the message\nexport const ACKs = -1;\n\n/**\n * Creates the base producer configuration for Kafka.\n * Used by both the SDK stream publishing and streaming function workers.\n *\n * @param maxMessageBytes - Optional max message size in bytes (synced with topic config)\n * @returns Producer configuration object for the Confluent Kafka client\n */\nexport function createProducerConfig(maxMessageBytes?: number) {\n return {\n kafkaJS: {\n idempotent: false, // Not needed for at-least-once delivery\n acks: ACKs,\n retry: {\n retries: MAX_RETRIES_PRODUCER,\n maxRetryTime: MAX_RETRY_TIME_MS,\n },\n },\n \"linger.ms\": 0, // This is to make sure at least once delivery with immediate feedback on the send\n ...(maxMessageBytes && { \"message.max.bytes\": maxMessageBytes }),\n };\n}\n\n/**\n * Parses a comma-separated broker string into an array of valid broker addresses.\n * Handles whitespace trimming and filters out empty elements.\n *\n * @param brokerString - Comma-separated broker addresses (e.g., \"broker1:9092, broker2:9092, , broker3:9092\")\n * @returns Array of trimmed, non-empty broker addresses\n */\nconst parseBrokerString = (brokerString: string): string[] =>\n brokerString\n .split(\",\")\n .map((b) => b.trim())\n .filter((b) => b.length > 0);\n\nexport type KafkaClientConfig = {\n clientId: string;\n broker: string;\n securityProtocol?: string; // e.g. \"SASL_SSL\" or \"PLAINTEXT\"\n saslUsername?: string;\n saslPassword?: string;\n saslMechanism?: string; // e.g. \"scram-sha-256\", \"plain\"\n};\n\n/**\n * Dynamically creates and connects a KafkaJS producer using the provided configuration.\n * Returns a connected producer instance.\n *\n * @param cfg - Kafka client configuration\n * @param logger - Logger instance\n * @param maxMessageBytes - Optional max message size in bytes (synced with topic config)\n */\nexport async function getKafkaProducer(\n cfg: KafkaClientConfig,\n logger: Logger,\n maxMessageBytes?: number,\n): Promise<Producer> {\n const kafka = await getKafkaClient(cfg, logger);\n\n const producer = kafka.producer(createProducerConfig(maxMessageBytes));\n await producer.connect();\n return producer;\n}\n\n/**\n * Interface for logging functionality\n */\nexport interface Logger {\n logPrefix: string;\n log: (message: string) => void;\n error: (message: string) => void;\n warn: (message: string) => void;\n}\n\nexport const logError = (logger: Logger, e: Error): void => {\n logger.error(e.message);\n const stack = e.stack;\n if (stack) {\n logger.error(stack);\n }\n};\n\n/**\n * Builds SASL configuration for Kafka client authentication\n */\nconst buildSaslConfig = (\n logger: Logger,\n args: KafkaClientConfig,\n): SASLOptions | undefined => {\n const mechanism = args.saslMechanism ? args.saslMechanism.toLowerCase() : \"\";\n switch (mechanism) {\n case \"plain\":\n case \"scram-sha-256\":\n case \"scram-sha-512\":\n return {\n mechanism: mechanism,\n username: args.saslUsername || \"\",\n password: args.saslPassword || \"\",\n };\n default:\n logger.warn(`Unsupported SASL mechanism: ${args.saslMechanism}`);\n return undefined;\n }\n};\n\n/**\n * Dynamically creates a KafkaJS client configured with provided settings.\n * Use this to construct producers/consumers with custom options.\n */\nexport const getKafkaClient = async (\n cfg: KafkaClientConfig,\n logger: Logger,\n): Promise<Kafka> => {\n const brokers = parseBrokerString(cfg.broker || \"\");\n if (brokers.length === 0) {\n throw new Error(`No valid broker addresses found in: \"${cfg.broker}\"`);\n }\n\n logger.log(`Creating Kafka client with brokers: ${brokers.join(\", \")}`);\n logger.log(`Security protocol: ${cfg.securityProtocol || \"plaintext\"}`);\n logger.log(`Client ID: ${cfg.clientId}`);\n\n const saslConfig = buildSaslConfig(logger, cfg);\n\n return new Kafka({\n kafkaJS: {\n clientId: cfg.clientId,\n brokers,\n ssl: cfg.securityProtocol === \"SASL_SSL\",\n ...(saslConfig && { sasl: saslConfig }),\n retry: {\n initialRetryTime: RETRY_INITIAL_TIME_MS,\n maxRetryTime: MAX_RETRY_TIME_MS,\n retries: MAX_RETRIES,\n },\n },\n });\n};\n"],"mappings":"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","names":["existsSync","writeFileSync","path","projectRoot","userOutDir","outDir","existsSync","readFileSync","existsSync","content","outDir","readFileSync","projectRoot","path","writeFileSync","existsSync"]}
|