@514labs/moose-lib 0.6.348 → 0.6.349
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/browserCompatible.js +2225 -2521
- package/dist/browserCompatible.js.map +1 -1
- package/dist/browserCompatible.mjs +2179 -2473
- package/dist/browserCompatible.mjs.map +1 -1
- package/dist/compilerPlugin.d.mts +2 -6
- package/dist/compilerPlugin.d.ts +2 -6
- package/dist/compilerPlugin.js +464 -647
- package/dist/compilerPlugin.js.map +1 -1
- package/dist/compilerPlugin.mjs +464 -643
- package/dist/compilerPlugin.mjs.map +1 -1
- package/dist/dataModels/toDataModels.js.map +1 -1
- package/dist/dataModels/toDataModels.mjs.map +1 -1
- package/dist/dmv2/index.js +2186 -2482
- package/dist/dmv2/index.js.map +1 -1
- package/dist/dmv2/index.mjs +2137 -2431
- package/dist/dmv2/index.mjs.map +1 -1
- package/dist/index.d.mts +3 -7
- package/dist/index.d.ts +3 -7
- package/dist/index.js +2836 -3133
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2735 -3030
- package/dist/index.mjs.map +1 -1
- package/dist/moose-runner.js +522 -534
- package/dist/moose-runner.js.map +1 -1
- package/dist/moose-runner.mjs +523 -535
- package/dist/moose-runner.mjs.map +1 -1
- package/dist/moose-tspc.js +4 -2
- package/dist/moose-tspc.js.map +1 -1
- package/dist/moose-tspc.mjs +4 -2
- package/dist/moose-tspc.mjs.map +1 -1
- package/package.json +1 -1
package/dist/moose-tspc.js
CHANGED
|
@@ -33,10 +33,12 @@ var import_fs = require("fs");
|
|
|
33
33
|
var import_path = __toESM(require("path"));
|
|
34
34
|
var MOOSE_COMPILER_PLUGINS = [
|
|
35
35
|
{
|
|
36
|
-
transform: "./node_modules/@514labs/moose-lib/dist/compilerPlugin.js"
|
|
37
|
-
transformProgram
|
|
36
|
+
transform: "./node_modules/@514labs/moose-lib/dist/compilerPlugin.js"
|
|
37
|
+
// No longer using transformProgram - direct typia integration eliminates
|
|
38
|
+
// the need for program replacement and the associated incremental compilation issues
|
|
38
39
|
},
|
|
39
40
|
{
|
|
41
|
+
// Keep typia plugin for users who use typia directly (not through Moose resources)
|
|
40
42
|
transform: "typia/lib/transform"
|
|
41
43
|
}
|
|
42
44
|
];
|
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 * Used during Docker build to eliminate ts-node overhead at runtime.\n *\n * Usage: moose-tspc [outDir]\n * outDir: Output directory for compiled files (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 */\nimport { execFileSync } from \"child_process\";\nimport { existsSync, writeFileSync, unlinkSync } from \"fs\";\nimport path from \"path\";\nimport {\n MOOSE_COMPILER_PLUGINS,\n MOOSE_COMPILER_OPTIONS,\n detectModuleSystem,\n getModuleOptions,\n getSourceDir,\n} from \"./compiler-config\";\nimport { rewriteImportExtensions } from \"./commons\";\n\nconst outDir = process.argv[2] || \".moose/compiled\";\nconst projectRoot = process.cwd();\nconst tsconfigPath = path.join(projectRoot, \"tsconfig.json\");\nconst tempTsconfigPath = path.join(projectRoot, \"tsconfig.moose-build.json\");\n\nif (!existsSync(tsconfigPath)) {\n console.error(\"Error: tsconfig.json not found in\", projectRoot);\n process.exit(1);\n}\n\nconsole.log(`Compiling TypeScript to ${outDir}...`);\n\ntry {\n // Auto-detect module system from package.json\n const moduleSystem = detectModuleSystem(projectRoot);\n const moduleOptions = getModuleOptions(moduleSystem);\n\n console.log(\n `Using ${moduleSystem.toUpperCase()} module output (detected from package.json)...`,\n );\n\n // Create a temporary tsconfig that extends the user's config and adds plugins.\n // We use extends (not spread) to properly inherit all user settings.\n // Only override what's needed for moose compilation.\n const buildTsconfig = {\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 // This must be in compilerOptions (not just CLI flag) to fully work\n skipLibCheck: true,\n skipDefaultLibCheck: true,\n // Additional settings to handle module resolution conflicts\n allowSyntheticDefaultImports: true,\n // IMPORTANT: Build Safety Trade-off\n // noEmitOnError: false allows JavaScript emission even with type errors.\n // This is intentional for Docker builds to succeed even when TypeScript\n // finds type issues. The trade-off is that type errors that could cause\n // runtime failures will not block the build - they will be logged as\n // warnings below. For strict type safety, users should run `npx tsc --noEmit`\n // before building to catch type errors that could indicate runtime issues.\n noEmitOnError: false,\n },\n };\n\n // Write the temporary tsconfig\n writeFileSync(tempTsconfigPath, JSON.stringify(buildTsconfig, null, 2));\n console.log(\"Created temporary tsconfig with moose plugins...\");\n\n // Use tspc (ts-patch compiler CLI) with the temporary tsconfig\n // Include source maps for better error messages in production\n // --rootDir . preserves directory structure (e.g., app/index.ts -> outDir/app/index.js)\n // Note: skipLibCheck and noEmitOnError are in compilerOptions\n try {\n execFileSync(\n \"npx\",\n [\n \"tspc\",\n \"-p\",\n tempTsconfigPath,\n \"--outDir\",\n outDir,\n \"--rootDir\",\n \".\",\n \"--sourceMap\",\n \"--inlineSources\",\n ],\n {\n stdio: \"inherit\",\n cwd: projectRoot,\n },\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 // Node.js ESM requires explicit extensions which TypeScript doesn't add\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 console.log(\"Compilation complete.\");\n} catch (error) {\n console.error(\"Build process failed:\", error);\n process.exit(1);\n} finally {\n // Clean up the temporary tsconfig\n if (existsSync(tempTsconfigPath)) {\n unlinkSync(tempTsconfigPath);\n }\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 * This ensures identical compilation behavior between:\n * - Development: ts-node with plugins (dynamic compilation)\n * - Production: Pre-compiled JavaScript (via moose-tspc)\n */\n\nexport const MOOSE_COMPILER_PLUGINS = [\n {\n transform: \"./node_modules/@514labs/moose-lib/dist/compilerPlugin.js\",\n transformProgram: true,\n },\n {\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// Commands that require full plugin compilation (moose transforms + typia)\nexport const COMMANDS_REQUIRING_PLUGINS = [\n \"consumption-apis\",\n \"consumption-type-serializer\",\n \"dmv2-serializer\",\n \"streaming-functions\",\n \"scripts\",\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 * Check if pre-compiled artifacts exist for the current project.\n * Used to determine whether to use compiled code or fall back to ts-node.\n */\nexport function hasCompiledArtifacts(\n projectRoot: string = process.cwd(),\n): boolean {\n const sourceDir = getSourceDir();\n const compiledIndexPath = path.join(\n projectRoot,\n \".moose\",\n \"compiled\",\n sourceDir,\n \"index.js\",\n );\n return existsSync(compiledIndexPath);\n}\n\n/**\n * Determine if we should use pre-compiled code.\n * Returns true if MOOSE_USE_COMPILED=true AND compiled artifacts exist.\n * This provides automatic fallback to ts-node if compilation wasn't run.\n */\nexport function shouldUseCompiled(\n projectRoot: string = process.cwd(),\n): boolean {\n const envSaysCompiled = process.env.MOOSE_USE_COMPILED === \"true\";\n if (!envSaysCompiled) {\n return false;\n }\n\n const hasArtifacts = hasCompiledArtifacts(projectRoot);\n if (!hasArtifacts) {\n console.warn(\n \"[moose] MOOSE_USE_COMPILED=true but no compiled artifacts found at \" +\n `.moose/compiled/${getSourceDir()}/index.js. Falling back to ts-node.`,\n );\n }\n return hasArtifacts;\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 http from \"http\";\nimport {\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\" | \"Error\" | \"Highlight\";\n action: string;\n message: string;\n};\n\nexport const cliLog: (log: CliLogData) => void = (log) => {\n const req = http.request({\n port: parseInt(process.env.MOOSE_MANAGEMENT_PORT ?? \"5001\"),\n method: \"POST\",\n path: \"/logs\",\n });\n\n req.on(\"error\", (err: Error) => {\n console.log(`Error ${err.name} sending CLI log.`, err.message);\n });\n\n req.write(JSON.stringify({ message_type: \"Info\", ...log }));\n req.end();\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","projectRoot","path","import_fs","import_path","nodePath","outDir","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 * Used during Docker build to eliminate ts-node overhead at runtime.\n *\n * Usage: moose-tspc [outDir]\n * outDir: Output directory for compiled files (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 */\nimport { execFileSync } from \"child_process\";\nimport { existsSync, writeFileSync, unlinkSync } from \"fs\";\nimport path from \"path\";\nimport {\n MOOSE_COMPILER_PLUGINS,\n MOOSE_COMPILER_OPTIONS,\n detectModuleSystem,\n getModuleOptions,\n getSourceDir,\n} from \"./compiler-config\";\nimport { rewriteImportExtensions } from \"./commons\";\n\nconst outDir = process.argv[2] || \".moose/compiled\";\nconst projectRoot = process.cwd();\nconst tsconfigPath = path.join(projectRoot, \"tsconfig.json\");\nconst tempTsconfigPath = path.join(projectRoot, \"tsconfig.moose-build.json\");\n\nif (!existsSync(tsconfigPath)) {\n console.error(\"Error: tsconfig.json not found in\", projectRoot);\n process.exit(1);\n}\n\nconsole.log(`Compiling TypeScript to ${outDir}...`);\n\ntry {\n // Auto-detect module system from package.json\n const moduleSystem = detectModuleSystem(projectRoot);\n const moduleOptions = getModuleOptions(moduleSystem);\n\n console.log(\n `Using ${moduleSystem.toUpperCase()} module output (detected from package.json)...`,\n );\n\n // Create a temporary tsconfig that extends the user's config and adds plugins.\n // We use extends (not spread) to properly inherit all user settings.\n // Only override what's needed for moose compilation.\n const buildTsconfig = {\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 // This must be in compilerOptions (not just CLI flag) to fully work\n skipLibCheck: true,\n skipDefaultLibCheck: true,\n // Additional settings to handle module resolution conflicts\n allowSyntheticDefaultImports: true,\n // IMPORTANT: Build Safety Trade-off\n // noEmitOnError: false allows JavaScript emission even with type errors.\n // This is intentional for Docker builds to succeed even when TypeScript\n // finds type issues. The trade-off is that type errors that could cause\n // runtime failures will not block the build - they will be logged as\n // warnings below. For strict type safety, users should run `npx tsc --noEmit`\n // before building to catch type errors that could indicate runtime issues.\n noEmitOnError: false,\n },\n };\n\n // Write the temporary tsconfig\n writeFileSync(tempTsconfigPath, JSON.stringify(buildTsconfig, null, 2));\n console.log(\"Created temporary tsconfig with moose plugins...\");\n\n // Use tspc (ts-patch compiler CLI) with the temporary tsconfig\n // Include source maps for better error messages in production\n // --rootDir . preserves directory structure (e.g., app/index.ts -> outDir/app/index.js)\n // Note: skipLibCheck and noEmitOnError are in compilerOptions\n try {\n execFileSync(\n \"npx\",\n [\n \"tspc\",\n \"-p\",\n tempTsconfigPath,\n \"--outDir\",\n outDir,\n \"--rootDir\",\n \".\",\n \"--sourceMap\",\n \"--inlineSources\",\n ],\n {\n stdio: \"inherit\",\n cwd: projectRoot,\n },\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 // Node.js ESM requires explicit extensions which TypeScript doesn't add\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 console.log(\"Compilation complete.\");\n} catch (error) {\n console.error(\"Build process failed:\", error);\n process.exit(1);\n} finally {\n // Clean up the temporary tsconfig\n if (existsSync(tempTsconfigPath)) {\n unlinkSync(tempTsconfigPath);\n }\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 * This ensures identical compilation behavior between:\n * - Development: ts-node with plugins (dynamic compilation)\n * - Production: Pre-compiled JavaScript (via moose-tspc)\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// Commands that require full plugin compilation (moose transforms + typia)\nexport const COMMANDS_REQUIRING_PLUGINS = [\n \"consumption-apis\",\n \"consumption-type-serializer\",\n \"dmv2-serializer\",\n \"streaming-functions\",\n \"scripts\",\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 * Check if pre-compiled artifacts exist for the current project.\n * Used to determine whether to use compiled code or fall back to ts-node.\n */\nexport function hasCompiledArtifacts(\n projectRoot: string = process.cwd(),\n): boolean {\n const sourceDir = getSourceDir();\n const compiledIndexPath = path.join(\n projectRoot,\n \".moose\",\n \"compiled\",\n sourceDir,\n \"index.js\",\n );\n return existsSync(compiledIndexPath);\n}\n\n/**\n * Determine if we should use pre-compiled code.\n * Returns true if MOOSE_USE_COMPILED=true AND compiled artifacts exist.\n * This provides automatic fallback to ts-node if compilation wasn't run.\n */\nexport function shouldUseCompiled(\n projectRoot: string = process.cwd(),\n): boolean {\n const envSaysCompiled = process.env.MOOSE_USE_COMPILED === \"true\";\n if (!envSaysCompiled) {\n return false;\n }\n\n const hasArtifacts = hasCompiledArtifacts(projectRoot);\n if (!hasArtifacts) {\n console.warn(\n \"[moose] MOOSE_USE_COMPILED=true but no compiled artifacts found at \" +\n `.moose/compiled/${getSourceDir()}/index.js. Falling back to ts-node.`,\n );\n }\n return hasArtifacts;\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 http from \"http\";\nimport {\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\" | \"Error\" | \"Highlight\";\n action: string;\n message: string;\n};\n\nexport const cliLog: (log: CliLogData) => void = (log) => {\n const req = http.request({\n port: parseInt(process.env.MOOSE_MANAGEMENT_PORT ?? \"5001\"),\n method: \"POST\",\n path: \"/logs\",\n });\n\n req.on(\"error\", (err: Error) => {\n console.log(`Error ${err.name} sending CLI log.`, err.message);\n });\n\n req.write(JSON.stringify({ message_type: \"Info\", ...log }));\n req.end();\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","projectRoot","path","import_fs","import_path","nodePath","outDir","path"]}
|
package/dist/moose-tspc.mjs
CHANGED
|
@@ -10,10 +10,12 @@ import { existsSync, readFileSync } from "fs";
|
|
|
10
10
|
import path from "path";
|
|
11
11
|
var MOOSE_COMPILER_PLUGINS = [
|
|
12
12
|
{
|
|
13
|
-
transform: "./node_modules/@514labs/moose-lib/dist/compilerPlugin.js"
|
|
14
|
-
transformProgram
|
|
13
|
+
transform: "./node_modules/@514labs/moose-lib/dist/compilerPlugin.js"
|
|
14
|
+
// No longer using transformProgram - direct typia integration eliminates
|
|
15
|
+
// the need for program replacement and the associated incremental compilation issues
|
|
15
16
|
},
|
|
16
17
|
{
|
|
18
|
+
// Keep typia plugin for users who use typia directly (not through Moose resources)
|
|
17
19
|
transform: "typia/lib/transform"
|
|
18
20
|
}
|
|
19
21
|
];
|
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 * Used during Docker build to eliminate ts-node overhead at runtime.\n *\n * Usage: moose-tspc [outDir]\n * outDir: Output directory for compiled files (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 */\nimport { execFileSync } from \"child_process\";\nimport { existsSync, writeFileSync, unlinkSync } from \"fs\";\nimport path from \"path\";\nimport {\n MOOSE_COMPILER_PLUGINS,\n MOOSE_COMPILER_OPTIONS,\n detectModuleSystem,\n getModuleOptions,\n getSourceDir,\n} from \"./compiler-config\";\nimport { rewriteImportExtensions } from \"./commons\";\n\nconst outDir = process.argv[2] || \".moose/compiled\";\nconst projectRoot = process.cwd();\nconst tsconfigPath = path.join(projectRoot, \"tsconfig.json\");\nconst tempTsconfigPath = path.join(projectRoot, \"tsconfig.moose-build.json\");\n\nif (!existsSync(tsconfigPath)) {\n console.error(\"Error: tsconfig.json not found in\", projectRoot);\n process.exit(1);\n}\n\nconsole.log(`Compiling TypeScript to ${outDir}...`);\n\ntry {\n // Auto-detect module system from package.json\n const moduleSystem = detectModuleSystem(projectRoot);\n const moduleOptions = getModuleOptions(moduleSystem);\n\n console.log(\n `Using ${moduleSystem.toUpperCase()} module output (detected from package.json)...`,\n );\n\n // Create a temporary tsconfig that extends the user's config and adds plugins.\n // We use extends (not spread) to properly inherit all user settings.\n // Only override what's needed for moose compilation.\n const buildTsconfig = {\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 // This must be in compilerOptions (not just CLI flag) to fully work\n skipLibCheck: true,\n skipDefaultLibCheck: true,\n // Additional settings to handle module resolution conflicts\n allowSyntheticDefaultImports: true,\n // IMPORTANT: Build Safety Trade-off\n // noEmitOnError: false allows JavaScript emission even with type errors.\n // This is intentional for Docker builds to succeed even when TypeScript\n // finds type issues. The trade-off is that type errors that could cause\n // runtime failures will not block the build - they will be logged as\n // warnings below. For strict type safety, users should run `npx tsc --noEmit`\n // before building to catch type errors that could indicate runtime issues.\n noEmitOnError: false,\n },\n };\n\n // Write the temporary tsconfig\n writeFileSync(tempTsconfigPath, JSON.stringify(buildTsconfig, null, 2));\n console.log(\"Created temporary tsconfig with moose plugins...\");\n\n // Use tspc (ts-patch compiler CLI) with the temporary tsconfig\n // Include source maps for better error messages in production\n // --rootDir . preserves directory structure (e.g., app/index.ts -> outDir/app/index.js)\n // Note: skipLibCheck and noEmitOnError are in compilerOptions\n try {\n execFileSync(\n \"npx\",\n [\n \"tspc\",\n \"-p\",\n tempTsconfigPath,\n \"--outDir\",\n outDir,\n \"--rootDir\",\n \".\",\n \"--sourceMap\",\n \"--inlineSources\",\n ],\n {\n stdio: \"inherit\",\n cwd: projectRoot,\n },\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 // Node.js ESM requires explicit extensions which TypeScript doesn't add\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 console.log(\"Compilation complete.\");\n} catch (error) {\n console.error(\"Build process failed:\", error);\n process.exit(1);\n} finally {\n // Clean up the temporary tsconfig\n if (existsSync(tempTsconfigPath)) {\n unlinkSync(tempTsconfigPath);\n }\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 * This ensures identical compilation behavior between:\n * - Development: ts-node with plugins (dynamic compilation)\n * - Production: Pre-compiled JavaScript (via moose-tspc)\n */\n\nexport const MOOSE_COMPILER_PLUGINS = [\n {\n transform: \"./node_modules/@514labs/moose-lib/dist/compilerPlugin.js\",\n transformProgram: true,\n },\n {\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// Commands that require full plugin compilation (moose transforms + typia)\nexport const COMMANDS_REQUIRING_PLUGINS = [\n \"consumption-apis\",\n \"consumption-type-serializer\",\n \"dmv2-serializer\",\n \"streaming-functions\",\n \"scripts\",\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 * Check if pre-compiled artifacts exist for the current project.\n * Used to determine whether to use compiled code or fall back to ts-node.\n */\nexport function hasCompiledArtifacts(\n projectRoot: string = process.cwd(),\n): boolean {\n const sourceDir = getSourceDir();\n const compiledIndexPath = path.join(\n projectRoot,\n \".moose\",\n \"compiled\",\n sourceDir,\n \"index.js\",\n );\n return existsSync(compiledIndexPath);\n}\n\n/**\n * Determine if we should use pre-compiled code.\n * Returns true if MOOSE_USE_COMPILED=true AND compiled artifacts exist.\n * This provides automatic fallback to ts-node if compilation wasn't run.\n */\nexport function shouldUseCompiled(\n projectRoot: string = process.cwd(),\n): boolean {\n const envSaysCompiled = process.env.MOOSE_USE_COMPILED === \"true\";\n if (!envSaysCompiled) {\n return false;\n }\n\n const hasArtifacts = hasCompiledArtifacts(projectRoot);\n if (!hasArtifacts) {\n console.warn(\n \"[moose] MOOSE_USE_COMPILED=true but no compiled artifacts found at \" +\n `.moose/compiled/${getSourceDir()}/index.js. Falling back to ts-node.`,\n );\n }\n return hasArtifacts;\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 http from \"http\";\nimport {\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\" | \"Error\" | \"Highlight\";\n action: string;\n message: string;\n};\n\nexport const cliLog: (log: CliLogData) => void = (log) => {\n const req = http.request({\n port: parseInt(process.env.MOOSE_MANAGEMENT_PORT ?? \"5001\"),\n method: \"POST\",\n path: \"/logs\",\n });\n\n req.on(\"error\", (err: Error) => {\n console.log(`Error ${err.name} sending CLI log.`, err.message);\n });\n\n req.write(JSON.stringify({ message_type: \"Info\", ...log }));\n req.end();\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","existsSync","readFileSync","existsSync","outDir","readFileSync","path","existsSync","writeFileSync"]}
|
|
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 * Used during Docker build to eliminate ts-node overhead at runtime.\n *\n * Usage: moose-tspc [outDir]\n * outDir: Output directory for compiled files (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 */\nimport { execFileSync } from \"child_process\";\nimport { existsSync, writeFileSync, unlinkSync } from \"fs\";\nimport path from \"path\";\nimport {\n MOOSE_COMPILER_PLUGINS,\n MOOSE_COMPILER_OPTIONS,\n detectModuleSystem,\n getModuleOptions,\n getSourceDir,\n} from \"./compiler-config\";\nimport { rewriteImportExtensions } from \"./commons\";\n\nconst outDir = process.argv[2] || \".moose/compiled\";\nconst projectRoot = process.cwd();\nconst tsconfigPath = path.join(projectRoot, \"tsconfig.json\");\nconst tempTsconfigPath = path.join(projectRoot, \"tsconfig.moose-build.json\");\n\nif (!existsSync(tsconfigPath)) {\n console.error(\"Error: tsconfig.json not found in\", projectRoot);\n process.exit(1);\n}\n\nconsole.log(`Compiling TypeScript to ${outDir}...`);\n\ntry {\n // Auto-detect module system from package.json\n const moduleSystem = detectModuleSystem(projectRoot);\n const moduleOptions = getModuleOptions(moduleSystem);\n\n console.log(\n `Using ${moduleSystem.toUpperCase()} module output (detected from package.json)...`,\n );\n\n // Create a temporary tsconfig that extends the user's config and adds plugins.\n // We use extends (not spread) to properly inherit all user settings.\n // Only override what's needed for moose compilation.\n const buildTsconfig = {\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 // This must be in compilerOptions (not just CLI flag) to fully work\n skipLibCheck: true,\n skipDefaultLibCheck: true,\n // Additional settings to handle module resolution conflicts\n allowSyntheticDefaultImports: true,\n // IMPORTANT: Build Safety Trade-off\n // noEmitOnError: false allows JavaScript emission even with type errors.\n // This is intentional for Docker builds to succeed even when TypeScript\n // finds type issues. The trade-off is that type errors that could cause\n // runtime failures will not block the build - they will be logged as\n // warnings below. For strict type safety, users should run `npx tsc --noEmit`\n // before building to catch type errors that could indicate runtime issues.\n noEmitOnError: false,\n },\n };\n\n // Write the temporary tsconfig\n writeFileSync(tempTsconfigPath, JSON.stringify(buildTsconfig, null, 2));\n console.log(\"Created temporary tsconfig with moose plugins...\");\n\n // Use tspc (ts-patch compiler CLI) with the temporary tsconfig\n // Include source maps for better error messages in production\n // --rootDir . preserves directory structure (e.g., app/index.ts -> outDir/app/index.js)\n // Note: skipLibCheck and noEmitOnError are in compilerOptions\n try {\n execFileSync(\n \"npx\",\n [\n \"tspc\",\n \"-p\",\n tempTsconfigPath,\n \"--outDir\",\n outDir,\n \"--rootDir\",\n \".\",\n \"--sourceMap\",\n \"--inlineSources\",\n ],\n {\n stdio: \"inherit\",\n cwd: projectRoot,\n },\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 // Node.js ESM requires explicit extensions which TypeScript doesn't add\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 console.log(\"Compilation complete.\");\n} catch (error) {\n console.error(\"Build process failed:\", error);\n process.exit(1);\n} finally {\n // Clean up the temporary tsconfig\n if (existsSync(tempTsconfigPath)) {\n unlinkSync(tempTsconfigPath);\n }\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 * This ensures identical compilation behavior between:\n * - Development: ts-node with plugins (dynamic compilation)\n * - Production: Pre-compiled JavaScript (via moose-tspc)\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// Commands that require full plugin compilation (moose transforms + typia)\nexport const COMMANDS_REQUIRING_PLUGINS = [\n \"consumption-apis\",\n \"consumption-type-serializer\",\n \"dmv2-serializer\",\n \"streaming-functions\",\n \"scripts\",\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 * Check if pre-compiled artifacts exist for the current project.\n * Used to determine whether to use compiled code or fall back to ts-node.\n */\nexport function hasCompiledArtifacts(\n projectRoot: string = process.cwd(),\n): boolean {\n const sourceDir = getSourceDir();\n const compiledIndexPath = path.join(\n projectRoot,\n \".moose\",\n \"compiled\",\n sourceDir,\n \"index.js\",\n );\n return existsSync(compiledIndexPath);\n}\n\n/**\n * Determine if we should use pre-compiled code.\n * Returns true if MOOSE_USE_COMPILED=true AND compiled artifacts exist.\n * This provides automatic fallback to ts-node if compilation wasn't run.\n */\nexport function shouldUseCompiled(\n projectRoot: string = process.cwd(),\n): boolean {\n const envSaysCompiled = process.env.MOOSE_USE_COMPILED === \"true\";\n if (!envSaysCompiled) {\n return false;\n }\n\n const hasArtifacts = hasCompiledArtifacts(projectRoot);\n if (!hasArtifacts) {\n console.warn(\n \"[moose] MOOSE_USE_COMPILED=true but no compiled artifacts found at \" +\n `.moose/compiled/${getSourceDir()}/index.js. Falling back to ts-node.`,\n );\n }\n return hasArtifacts;\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 http from \"http\";\nimport {\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\" | \"Error\" | \"Highlight\";\n action: string;\n message: string;\n};\n\nexport const cliLog: (log: CliLogData) => void = (log) => {\n const req = http.request({\n port: parseInt(process.env.MOOSE_MANAGEMENT_PORT ?? \"5001\"),\n method: \"POST\",\n path: \"/logs\",\n });\n\n req.on(\"error\", (err: Error) => {\n console.log(`Error ${err.name} sending CLI log.`, err.message);\n });\n\n req.write(JSON.stringify({ message_type: \"Info\", ...log }));\n req.end();\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","existsSync","readFileSync","existsSync","outDir","readFileSync","path","existsSync","writeFileSync"]}
|