@tailor-platform/sdk 1.39.0 → 1.39.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/{env-CgI46oPS.d.mts → actor-Bb4OVq1j.d.mts} +9 -9
- package/dist/{application-DhQrXEld.mjs → application-BHu8YE-g.mjs} +148 -148
- package/dist/application-BHu8YE-g.mjs.map +1 -0
- package/dist/application-C8Lr37AM.mjs +4 -0
- package/dist/{brand-D-d15jx3.mjs → brand-Ll48SMXe.mjs} +1 -1
- package/dist/{brand-D-d15jx3.mjs.map → brand-Ll48SMXe.mjs.map} +1 -1
- package/dist/cli/index.mjs +15 -15
- package/dist/cli/lib.d.mts +9 -9
- package/dist/cli/lib.mjs +4 -4
- package/dist/{client-xzPXtc_e.mjs → client-B2K45RvK.mjs} +77 -47
- package/dist/client-B2K45RvK.mjs.map +1 -0
- package/dist/{client-BWAbbA1C.mjs → client-CEVmv94H.mjs} +1 -1
- package/dist/configure/index.d.mts +4 -4
- package/dist/configure/index.mjs +55 -4
- package/dist/configure/index.mjs.map +1 -1
- package/dist/{crash-report-DXhPL8Ue.mjs → crash-report-CACiemAr.mjs} +4 -4
- package/dist/{crash-report-DXhPL8Ue.mjs.map → crash-report-CACiemAr.mjs.map} +1 -1
- package/dist/{crash-report-BEAiCSCl.mjs → crash-report-CPUF3T5d.mjs} +1 -1
- package/dist/{errors-D9f2UJpT.mjs → errors-ChWX5ZG8.mjs} +1 -1
- package/dist/{errors-D9f2UJpT.mjs.map → errors-ChWX5ZG8.mjs.map} +1 -1
- package/dist/field-BY2vbJ8f.mjs +23 -0
- package/dist/field-BY2vbJ8f.mjs.map +1 -0
- package/dist/{index-31hm0Fq7.d.mts → index-BYmdVno1.d.mts} +133 -30
- package/dist/{index-y5790SX_.d.mts → index-CeFwhUkX.d.mts} +2 -2
- package/dist/{index-B2tsEXdh.d.mts → index-Ch8Em3nz.d.mts} +2 -2
- package/dist/{index-DbzopC7M.d.mts → index-Cx1RYDbu.d.mts} +2 -2
- package/dist/{index-DeBFa7oc.d.mts → index-DLO_XvLi.d.mts} +2 -2
- package/dist/{interceptor-CzaH2Ur6.mjs → interceptor-B5bKVwgq.mjs} +1 -1
- package/dist/{interceptor-CzaH2Ur6.mjs.map → interceptor-B5bKVwgq.mjs.map} +1 -1
- package/dist/{job-DkAklmE4.mjs → job-p6zf8Qpg.mjs} +2 -2
- package/dist/job-p6zf8Qpg.mjs.map +1 -0
- package/dist/{logger-5_JMzHmw.mjs → logger-DTNAMYGy.mjs} +1 -1
- package/dist/{logger-5_JMzHmw.mjs.map → logger-DTNAMYGy.mjs.map} +1 -1
- package/dist/package-json-CPR7s5hf.mjs +4 -0
- package/dist/{package-json-BHViVisJ.mjs → package-json-CWp8s9dE.mjs} +1 -1
- package/dist/{package-json-BHViVisJ.mjs.map → package-json-CWp8s9dE.mjs.map} +1 -1
- package/dist/plugin/builtin/enum-constants/index.d.mts +1 -1
- package/dist/plugin/builtin/file-utils/index.d.mts +1 -1
- package/dist/plugin/builtin/kysely-type/index.d.mts +1 -1
- package/dist/plugin/builtin/seed/index.d.mts +1 -1
- package/dist/plugin/builtin/seed/index.mjs +1 -1
- package/dist/plugin/index.d.mts +2 -2
- package/dist/{runtime-DtSOnOHh.mjs → runtime-2xqzvkQv.mjs} +86 -15
- package/dist/runtime-2xqzvkQv.mjs.map +1 -0
- package/dist/{schema-CnwUqPyM.mjs → schema-CEcfEyPN.mjs} +4 -44
- package/dist/schema-CEcfEyPN.mjs.map +1 -0
- package/dist/{seed-DrbB1VXd.mjs → seed-CyYPhvNL.mjs} +12 -12
- package/dist/seed-CyYPhvNL.mjs.map +1 -0
- package/dist/{service-Bcp6JB3w.mjs → service-SrG26B9T.mjs} +3 -3
- package/dist/{service-Bcp6JB3w.mjs.map → service-SrG26B9T.mjs.map} +1 -1
- package/dist/{plugin-_K3ZfP8B.d.mts → tailor-db-field-B99RnR2N.d.mts} +695 -1187
- package/dist/{telemetry-DwHuiNiR.mjs → telemetry-BuDto_2q.mjs} +2 -2
- package/dist/{telemetry-DwHuiNiR.mjs.map → telemetry-BuDto_2q.mjs.map} +1 -1
- package/dist/telemetry-C1hzFaiV.mjs +4 -0
- package/dist/types-BnphjkIJ.mjs +5 -0
- package/dist/{types-B9ZMosul.mjs → types-Duhhsx3R.mjs} +3 -32
- package/dist/types-Duhhsx3R.mjs.map +1 -0
- package/dist/utils/test/index.d.mts +2 -2
- package/dist/utils/test/index.mjs +1 -1
- package/dist/workflow.generated-DSwr-k57.d.mts +1207 -0
- package/docs/cli/application.md +21 -5
- package/docs/services/idp.md +4 -4
- package/package.json +2 -2
- package/dist/application-C1ipG5Q6.mjs +0 -4
- package/dist/application-DhQrXEld.mjs.map +0 -1
- package/dist/client-xzPXtc_e.mjs.map +0 -1
- package/dist/job-DkAklmE4.mjs.map +0 -1
- package/dist/package-json--6dmp6-h.mjs +0 -4
- package/dist/runtime-DtSOnOHh.mjs.map +0 -1
- package/dist/schema-CnwUqPyM.mjs.map +0 -1
- package/dist/seed-DrbB1VXd.mjs.map +0 -1
- package/dist/telemetry-4IOPW6wE.mjs +0 -4
- package/dist/types-B9ZMosul.mjs.map +0 -1
- package/dist/types-C45jRrCM.mjs +0 -4
- package/dist/workflow.generated-BxbnuzAE.d.mts +0 -414
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crash-report-DXhPL8Ue.mjs","names":[],"sources":["../src/cli/crash-report/config.ts","../src/cli/crash-report/writer.ts","../src/cli/crash-report/sender.ts","../src/cli/crash-report/sanitize.ts","../src/cli/crash-report/report.ts","../src/cli/crash-report/index.ts"],"sourcesContent":["import * as path from \"pathe\";\nimport { isCI } from \"std-env\";\nimport { xdgConfig } from \"xdg-basedir\";\n\nexport interface CrashReportConfig {\n readonly localEnabled: boolean;\n readonly remoteEnabled: boolean;\n readonly localDir: string;\n}\n\n/**\n * Parse crash report configuration from environment variables.\n * Local crash log writing is enabled by default (opt-out via TAILOR_CRASH_REPORTS_LOCAL=off).\n * Remote sending is disabled by default (opt-in via TAILOR_CRASH_REPORTS_REMOTE=on).\n * Both are auto-disabled in CI environments.\n * @returns Crash report configuration\n */\nexport function parseCrashReportConfig(): CrashReportConfig {\n if (isCI) {\n return {\n localEnabled: false,\n remoteEnabled: false,\n localDir: \"\",\n };\n }\n\n const localEnabled = (process.env.TAILOR_CRASH_REPORTS_LOCAL ?? \"on\").toLowerCase() !== \"off\";\n const remoteEnabled = (process.env.TAILOR_CRASH_REPORTS_REMOTE ?? \"off\").toLowerCase() === \"on\";\n const localDir = xdgConfig ? path.join(xdgConfig, \"tailor-platform\", \"crash-reports\") : \"\";\n\n return {\n localEnabled: localEnabled && localDir !== \"\",\n remoteEnabled,\n localDir,\n };\n}\n","import * as fs from \"node:fs\";\nimport * as path from \"pathe\";\nimport type { CrashReport } from \"./report\";\n\nconst MAX_CRASH_FILES = 10;\n\n/** Marker line that separates human-readable content from the JSON footer. */\nexport const JSON_FOOTER_MARKER = \"--- JSON ---\";\n\n/** File extension for crash log files. */\nexport const CRASH_LOG_EXTENSION = \".crash.log\";\n\n/**\n * Format a CrashReport as human-readable text for local crash log files.\n * @param report - Crash report to format\n * @returns Formatted text content\n */\nexport function formatCrashReport(report: CrashReport): string {\n const lines = [\n `Crash Report: ${report.id}`,\n `Timestamp: ${report.timestamp}`,\n `Error Type: ${report.errorType}`,\n \"\",\n \"--- Environment ---\",\n `SDK Version: ${report.sdkVersion}`,\n `Node Version: ${report.nodeVersion}`,\n `OS: ${report.osPlatform} ${report.osRelease}`,\n `Arch: ${report.arch}`,\n \"\",\n \"--- Command ---\",\n `Command: ${report.command}`,\n `Arguments: ${JSON.stringify(report.argv)}`,\n \"\",\n \"--- Error ---\",\n `Name: ${report.errorName}`,\n `Message: ${report.errorMessage}`,\n \"\",\n \"--- Stack Trace ---\",\n report.stackTrace || \"(no stack trace available)\",\n \"\",\n JSON_FOOTER_MARKER,\n JSON.stringify(report),\n \"\",\n ];\n return lines.join(\"\\n\");\n}\n\n/**\n * Generate a filename for a crash log file.\n * Format: {timestamp}-{shortId}.crash.log\n * @param report - Crash report to generate filename for\n * @returns Filename string\n */\nfunction generateFilename(report: CrashReport): string {\n const safeTimestamp = report.timestamp.replace(/[:.]/g, \"-\");\n const shortId = report.id.slice(0, 8);\n return `${safeTimestamp}-${shortId}${CRASH_LOG_EXTENSION}`;\n}\n\n/**\n * Remove old crash log files, keeping only the most recent ones.\n * @param dir - Crash log directory\n */\nfunction cleanupOldFiles(dir: string): void {\n try {\n const files = fs\n .readdirSync(dir)\n .filter((f) => f.endsWith(CRASH_LOG_EXTENSION))\n .sort()\n .reverse();\n\n for (const file of files.slice(MAX_CRASH_FILES)) {\n fs.unlinkSync(path.join(dir, file));\n }\n } catch {\n // Best-effort cleanup, ignore errors\n }\n}\n\n/**\n * Write a crash report to a local file.\n * Creates the directory if it doesn't exist. Keeps only the last 10 crash files.\n * Never throws - returns the file path on success or undefined on failure.\n * @param report - Crash report to write\n * @param dir - Directory to write the crash log file to\n * @returns File path on success, undefined on failure\n */\nexport function writeCrashReport(report: CrashReport, dir: string): string | undefined {\n try {\n fs.mkdirSync(dir, { recursive: true });\n\n const filename = generateFilename(report);\n const filePath = path.join(dir, filename);\n const content = formatCrashReport(report);\n\n fs.writeFileSync(filePath, content, \"utf-8\");\n cleanupOldFiles(dir);\n\n return filePath;\n } catch {\n return undefined;\n }\n}\n","import type { CrashReport } from \"./report\";\n\nconst SEND_TIMEOUT_MS = 5000;\nconst PRODUCTION_ENDPOINT = \"https://sdk-error-tracking-926vh9t4cl.erp.dev/query\";\n\nconst SUBMIT_MUTATION = `\nmutation SubmitCrashReport(\n $id: String!\n $timestamp: String!\n $sdkVersion: String!\n $nodeVersion: String!\n $osPlatform: String!\n $osRelease: String!\n $arch: String!\n $command: String!\n $argv: [String]\n $errorName: String!\n $errorMessage: String!\n $stackTrace: String\n $errorType: String!\n $userId: String\n $userEmail: String\n) {\n submitCrashReport(\n id: $id\n timestamp: $timestamp\n sdkVersion: $sdkVersion\n nodeVersion: $nodeVersion\n osPlatform: $osPlatform\n osRelease: $osRelease\n arch: $arch\n command: $command\n argv: $argv\n errorName: $errorName\n errorMessage: $errorMessage\n stackTrace: $stackTrace\n errorType: $errorType\n userId: $userId\n userEmail: $userEmail\n ) {\n success\n }\n}`;\n\n/**\n * Send a crash report to the remote endpoint via GraphQL mutation.\n * Best-effort: never throws, returns boolean success.\n * @param report - Crash report to send\n * @param ua - User-Agent header value\n * @returns true if the request succeeded, false otherwise\n */\nexport async function sendCrashReport(report: CrashReport, ua: string): Promise<boolean> {\n try {\n const endpoint = process.env.TAILOR_CRASH_REPORT_ENDPOINT || PRODUCTION_ENDPOINT;\n const response = await fetch(endpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"User-Agent\": ua,\n },\n body: JSON.stringify({\n query: SUBMIT_MUTATION,\n variables: report,\n }),\n signal: AbortSignal.timeout(SEND_TIMEOUT_MS),\n });\n\n if (!response.ok) return false;\n\n const data = (await response.json()) as {\n errors?: unknown[];\n data?: { submitCrashReport: { success: boolean } };\n };\n if (data.errors?.length) return false;\n return data.data?.submitCrashReport.success === true;\n } catch {\n return false;\n }\n}\n","import * as os from \"node:os\";\n\nconst HOME_DIR = os.homedir();\n\n// Patterns for sanitization (global variants for use with .replace())\nconst UUID_PATTERN = /\\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\\b/gi;\nconst LONG_HEX_PATTERN = /\\b[0-9a-fA-F]{32,}\\b/g;\nconst EMAIL_PATTERN = /\\b[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}\\b/g;\nconst ABSOLUTE_PATH_PATTERN = /(?:\\/(?:[\\w.@\\- ]+\\/)+[\\w.@\\- ]+)/g;\nconst WINDOWS_PATH_PATTERN = /(?:[A-Za-z]:\\\\(?:[\\w.@\\- ]+\\\\)+[\\w.@\\- ]+)/g;\nconst URL_QUERY_PATTERN = /[?&][^?\\s]*/g;\n\n// Non-global variants for single-match .test() calls (avoids lastIndex state issues)\nconst EMAIL_TEST_PATTERN = /\\b[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}\\b/;\nconst WINDOWS_DRIVE_TEST_PATTERN = /^[A-Za-z]:\\\\/;\n\n// SDK package path marker for relative paths\nconst SDK_PACKAGE_MARKER = \"packages/sdk/\";\n\nfunction lastSegment(filePath: string, separator: string): string {\n return filePath.split(separator).pop() ?? filePath;\n}\n\n/**\n * Sanitize a stack trace by replacing absolute paths with relative SDK paths.\n * External paths are replaced with `<external>/filename.ext`.\n * Home directories are replaced with `~/<redacted>/`.\n * @param stack - Raw stack trace string\n * @returns Sanitized stack trace\n */\nexport function sanitizeStackTrace(stack: string): string {\n // V8 stack traces start with \"ErrorType: message\\n at ...\".\n // The error message may span multiple lines before the first \" at \" frame.\n // Apply message sanitization to all message lines so secrets embedded in\n // multiline error messages are redacted consistently with errorMessage.\n const firstFrameIndex = stack.search(/\\n\\s+at /);\n let result: string;\n if (firstFrameIndex !== -1) {\n result = sanitizeMessage(stack.slice(0, firstFrameIndex)) + stack.slice(firstFrameIndex);\n } else {\n result = sanitizeMessage(stack);\n }\n\n result = result.replace(ABSOLUTE_PATH_PATTERN, (match) => {\n const sdkIndex = match.indexOf(SDK_PACKAGE_MARKER);\n if (sdkIndex !== -1) {\n return match.slice(sdkIndex);\n }\n\n if (match.startsWith(HOME_DIR)) {\n return `~/<redacted>/${lastSegment(match, \"/\")}`;\n }\n\n return `<external>/${lastSegment(match, \"/\")}`;\n });\n result = result.replace(WINDOWS_PATH_PATTERN, (match) => {\n const normalized = match.replace(/\\\\/g, \"/\");\n const sdkIndex = normalized.indexOf(SDK_PACKAGE_MARKER);\n if (sdkIndex !== -1) {\n return normalized.slice(sdkIndex);\n }\n return `<external>/${lastSegment(match, \"\\\\\")}`;\n });\n return result;\n}\n\n/**\n * Sanitize an error message by redacting sensitive information.\n * Redacts: UUIDs, long hex tokens, email addresses, absolute paths, URL query strings.\n * @param message - Raw error message\n * @returns Sanitized error message\n */\nexport function sanitizeMessage(message: string): string {\n let result = message;\n // Strip serialized request/response bodies that may contain secrets\n result = result.replace(/\\nRequest:\\s*[\\s\\S]*$/, \"\\nRequest: <redacted>\");\n result = result.replace(UUID_PATTERN, \"<uuid>\");\n result = result.replace(LONG_HEX_PATTERN, \"<redacted>\");\n result = result.replace(EMAIL_PATTERN, \"<email>\");\n result = result.replace(URL_QUERY_PATTERN, \"?<redacted>\");\n result = result.replace(ABSOLUTE_PATH_PATTERN, (match) => `<path>/${lastSegment(match, \"/\")}`);\n result = result.replace(WINDOWS_PATH_PATTERN, (match) => `<path>/${lastSegment(match, \"\\\\\")}`);\n\n return result;\n}\n\n/**\n * Sanitize process.argv by keeping command/subcommand names and redacting\n * values of sensitive flags.\n * @param argv - Raw process.argv array\n * @returns Sanitized argv array\n */\nexport function sanitizeArgv(argv: string[]): string[] {\n const result: string[] = [];\n let redactNext = false;\n\n for (const arg of argv) {\n if (redactNext) {\n // If the next token is itself a flag, treat it as a new flag rather\n // than consuming it as the previous flag's value. This avoids leaking\n // the *next* flag's value (e.g., `--verbose --workspace-id secret`\n // would otherwise expose `secret`).\n if (!arg.startsWith(\"-\")) {\n result.push(\"<redacted>\");\n redactNext = false;\n continue;\n }\n redactNext = false;\n }\n\n if (arg.startsWith(\"-\")) {\n // --flag=value: keep flag name, redact value\n const eqIndex = arg.indexOf(\"=\");\n if (eqIndex !== -1) {\n result.push(`${arg.slice(0, eqIndex)}=<redacted>`);\n continue;\n }\n\n // --flag / -f: keep flag name, redact next arg as its value\n result.push(arg);\n redactNext = true;\n continue;\n }\n\n // Redact absolute paths\n if (arg.startsWith(\"/\") && arg.includes(\"/\", 1)) {\n result.push(\"<path>\");\n continue;\n }\n\n // Redact Windows-style absolute paths\n if (WINDOWS_DRIVE_TEST_PATTERN.test(arg)) {\n result.push(\"<path>\");\n continue;\n }\n\n // Redact email addresses\n if (EMAIL_TEST_PATTERN.test(arg)) {\n result.push(\"<email>\");\n continue;\n }\n\n result.push(arg);\n }\n\n return result;\n}\n","import * as crypto from \"node:crypto\";\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport { parseYAML } from \"confbox\";\nimport * as path from \"pathe\";\nimport { xdgConfig } from \"xdg-basedir\";\nimport { sanitizeArgv, sanitizeMessage, sanitizeStackTrace } from \"./sanitize\";\n\nexport type ErrorType = \"uncaughtException\" | \"unhandledRejection\" | \"handledError\";\n\nexport interface CrashReport {\n id: string;\n timestamp: string;\n sdkVersion: string;\n nodeVersion: string;\n osPlatform: string;\n osRelease: string;\n arch: string;\n command: string;\n argv: string[];\n errorName: string;\n errorMessage: string;\n stackTrace: string;\n errorType: ErrorType;\n userId: string | null;\n userEmail: string | null;\n}\n\ninterface BuildCrashReportOptions {\n error: unknown;\n sdkVersion: string;\n errorType: ErrorType;\n}\n\n// Maximum subcommand depth to keep (e.g., \"tailordb migrate generate\" = 3 tokens).\n// Positional arguments beyond this are potentially sensitive user input.\n// Accepted trade-off: plain-text positional args that don't match known patterns\n// (UUIDs, hex tokens, emails, paths) pass through to `command` and `argv`.\n// Full redaction would require embedding the CLI command tree here, which is fragile.\nconst MAX_COMMAND_TOKENS = 3;\n\n/**\n * Parse the command name from process.argv.\n * Extracts up to MAX_COMMAND_TOKENS non-flag arguments after the script name.\n * @returns Parsed command string\n */\nfunction parseCommand(): string {\n const args = process.argv.slice(2);\n const commandParts: string[] = [];\n for (const arg of args) {\n if (arg.startsWith(\"-\") || commandParts.length >= MAX_COMMAND_TOKENS) break;\n commandParts.push(arg);\n }\n return commandParts.join(\" \") || \"<unknown>\";\n}\n\n/**\n * Build a CrashReport data structure from an error and context.\n * All sensitive data is sanitized before inclusion.\n * @param options - Error, SDK version, and crash type\n * @returns Sanitized crash report\n */\nexport function buildCrashReport(options: BuildCrashReportOptions): CrashReport {\n const { error, sdkVersion, errorType } = options;\n\n const isError = error instanceof Error;\n const rawMessage = isError ? error.message : String(error);\n const rawStack = isError && error.stack ? error.stack : \"\";\n const errorName = isError ? error.name : \"UnknownError\";\n\n const currentUser = readCurrentUser();\n\n return {\n id: crypto.randomUUID(),\n timestamp: new Date().toISOString(),\n sdkVersion,\n nodeVersion: process.version,\n osPlatform: process.platform,\n osRelease: os.release(),\n arch: process.arch,\n command: sanitizeMessage(parseCommand()),\n argv: sanitizeArgv(process.argv),\n errorName,\n errorMessage: sanitizeMessage(rawMessage),\n stackTrace: sanitizeStackTrace(rawStack),\n errorType,\n userId: currentUser,\n userEmail: currentUser,\n };\n}\n\n/**\n * Read current_user from Tailor Platform config without side effects.\n * Unlike readPlatformConfig(), this never triggers migration or logs warnings.\n * @returns The current user email, or null if unavailable\n */\nfunction readCurrentUser(): string | null {\n try {\n if (!xdgConfig) return null;\n const configPath = path.join(xdgConfig, \"tailor-platform\", \"config.yaml\");\n if (!fs.existsSync(configPath)) return null;\n const raw = parseYAML(fs.readFileSync(configPath, \"utf-8\")) as { current_user?: string | null };\n return raw?.current_user ?? null;\n } catch {\n return null;\n }\n}\n","import { logger } from \"@/cli/shared/logger\";\nimport { readPackageJson } from \"@/cli/shared/package-json\";\nimport { parseCrashReportConfig } from \"./config\";\nimport { buildCrashReport, type ErrorType } from \"./report\";\nimport { sendCrashReport } from \"./sender\";\nimport { writeCrashReport } from \"./writer\";\n\n/**\n * Report an unexpected crash. Writes a local crash log file and optionally\n * sends the report to a remote endpoint. Displays a user-facing message\n * with the crash log path and a command to submit the report.\n *\n * Never throws - all errors are silently caught.\n * @param error - The error that caused the crash\n * @param errorType - How the error was caught\n */\nexport async function reportCrash(error: unknown, errorType: ErrorType): Promise<void> {\n try {\n const config = parseCrashReportConfig();\n if (!config.localEnabled && !config.remoteEnabled) return;\n\n const packageJson = await readPackageJson();\n const sdkVersion = packageJson.version ?? \"unknown\";\n\n const report = buildCrashReport({ error, sdkVersion, errorType });\n\n if (config.localEnabled) {\n const filePath = writeCrashReport(report, config.localDir);\n if (filePath) {\n logger.log(\n [\n \"\",\n \"An unexpected error occurred. A crash report has been saved to:\",\n ` ${filePath}`,\n \"\",\n \"To submit this report:\",\n ` tailor-sdk crash-report send --file \"${filePath}\"`,\n ].join(\"\\n\"),\n );\n }\n }\n\n if (config.remoteEnabled) {\n // Lazy import: client.ts pulls in heavy dependencies (OAuth2, Connect, Protobuf)\n // that should not be loaded on the startup critical path via initCrashReporting().\n const { userAgent } = await import(\"@/cli/shared/client\");\n const ua = await userAgent();\n await sendCrashReport(report, ua);\n }\n } catch {\n // Never throw from crash reporting\n }\n}\n\n/**\n * Register global uncaughtException and unhandledRejection handlers.\n * These catch errors outside the normal cleanup flow (e.g., during\n * argument parsing). Should be called once at CLI startup before runMain.\n */\nexport function initCrashReporting(): void {\n const config = parseCrashReportConfig();\n if (!config.localEnabled && !config.remoteEnabled) return;\n\n const handleFatal = (error: unknown, errorType: ErrorType) => {\n const message = error instanceof Error ? error.message : String(error);\n logger.error(message);\n void reportCrash(error, errorType).finally(() => {\n process.exit(1);\n });\n };\n\n process.on(\"uncaughtException\", (error) => handleFatal(error, \"uncaughtException\"));\n process.on(\"unhandledRejection\", (reason) => handleFatal(reason, \"unhandledRejection\"));\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"crash-report-CACiemAr.mjs","names":[],"sources":["../src/cli/crash-report/config.ts","../src/cli/crash-report/writer.ts","../src/cli/crash-report/sender.ts","../src/cli/crash-report/sanitize.ts","../src/cli/crash-report/report.ts","../src/cli/crash-report/index.ts"],"sourcesContent":["import * as path from \"pathe\";\nimport { isCI } from \"std-env\";\nimport { xdgConfig } from \"xdg-basedir\";\n\nexport interface CrashReportConfig {\n readonly localEnabled: boolean;\n readonly remoteEnabled: boolean;\n readonly localDir: string;\n}\n\n/**\n * Parse crash report configuration from environment variables.\n * Local crash log writing is enabled by default (opt-out via TAILOR_CRASH_REPORTS_LOCAL=off).\n * Remote sending is disabled by default (opt-in via TAILOR_CRASH_REPORTS_REMOTE=on).\n * Both are auto-disabled in CI environments.\n * @returns Crash report configuration\n */\nexport function parseCrashReportConfig(): CrashReportConfig {\n if (isCI) {\n return {\n localEnabled: false,\n remoteEnabled: false,\n localDir: \"\",\n };\n }\n\n const localEnabled = (process.env.TAILOR_CRASH_REPORTS_LOCAL ?? \"on\").toLowerCase() !== \"off\";\n const remoteEnabled = (process.env.TAILOR_CRASH_REPORTS_REMOTE ?? \"off\").toLowerCase() === \"on\";\n const localDir = xdgConfig ? path.join(xdgConfig, \"tailor-platform\", \"crash-reports\") : \"\";\n\n return {\n localEnabled: localEnabled && localDir !== \"\",\n remoteEnabled,\n localDir,\n };\n}\n","import * as fs from \"node:fs\";\nimport * as path from \"pathe\";\nimport type { CrashReport } from \"./report\";\n\nconst MAX_CRASH_FILES = 10;\n\n/** Marker line that separates human-readable content from the JSON footer. */\nexport const JSON_FOOTER_MARKER = \"--- JSON ---\";\n\n/** File extension for crash log files. */\nexport const CRASH_LOG_EXTENSION = \".crash.log\";\n\n/**\n * Format a CrashReport as human-readable text for local crash log files.\n * @param report - Crash report to format\n * @returns Formatted text content\n */\nexport function formatCrashReport(report: CrashReport): string {\n const lines = [\n `Crash Report: ${report.id}`,\n `Timestamp: ${report.timestamp}`,\n `Error Type: ${report.errorType}`,\n \"\",\n \"--- Environment ---\",\n `SDK Version: ${report.sdkVersion}`,\n `Node Version: ${report.nodeVersion}`,\n `OS: ${report.osPlatform} ${report.osRelease}`,\n `Arch: ${report.arch}`,\n \"\",\n \"--- Command ---\",\n `Command: ${report.command}`,\n `Arguments: ${JSON.stringify(report.argv)}`,\n \"\",\n \"--- Error ---\",\n `Name: ${report.errorName}`,\n `Message: ${report.errorMessage}`,\n \"\",\n \"--- Stack Trace ---\",\n report.stackTrace || \"(no stack trace available)\",\n \"\",\n JSON_FOOTER_MARKER,\n JSON.stringify(report),\n \"\",\n ];\n return lines.join(\"\\n\");\n}\n\n/**\n * Generate a filename for a crash log file.\n * Format: {timestamp}-{shortId}.crash.log\n * @param report - Crash report to generate filename for\n * @returns Filename string\n */\nfunction generateFilename(report: CrashReport): string {\n const safeTimestamp = report.timestamp.replace(/[:.]/g, \"-\");\n const shortId = report.id.slice(0, 8);\n return `${safeTimestamp}-${shortId}${CRASH_LOG_EXTENSION}`;\n}\n\n/**\n * Remove old crash log files, keeping only the most recent ones.\n * @param dir - Crash log directory\n */\nfunction cleanupOldFiles(dir: string): void {\n try {\n const files = fs\n .readdirSync(dir)\n .filter((f) => f.endsWith(CRASH_LOG_EXTENSION))\n .sort()\n .reverse();\n\n for (const file of files.slice(MAX_CRASH_FILES)) {\n fs.unlinkSync(path.join(dir, file));\n }\n } catch {\n // Best-effort cleanup, ignore errors\n }\n}\n\n/**\n * Write a crash report to a local file.\n * Creates the directory if it doesn't exist. Keeps only the last 10 crash files.\n * Never throws - returns the file path on success or undefined on failure.\n * @param report - Crash report to write\n * @param dir - Directory to write the crash log file to\n * @returns File path on success, undefined on failure\n */\nexport function writeCrashReport(report: CrashReport, dir: string): string | undefined {\n try {\n fs.mkdirSync(dir, { recursive: true });\n\n const filename = generateFilename(report);\n const filePath = path.join(dir, filename);\n const content = formatCrashReport(report);\n\n fs.writeFileSync(filePath, content, \"utf-8\");\n cleanupOldFiles(dir);\n\n return filePath;\n } catch {\n return undefined;\n }\n}\n","import type { CrashReport } from \"./report\";\n\nconst SEND_TIMEOUT_MS = 5000;\nconst PRODUCTION_ENDPOINT = \"https://sdk-error-tracking-926vh9t4cl.erp.dev/query\";\n\nconst SUBMIT_MUTATION = `\nmutation SubmitCrashReport(\n $id: String!\n $timestamp: String!\n $sdkVersion: String!\n $nodeVersion: String!\n $osPlatform: String!\n $osRelease: String!\n $arch: String!\n $command: String!\n $argv: [String]\n $errorName: String!\n $errorMessage: String!\n $stackTrace: String\n $errorType: String!\n $userId: String\n $userEmail: String\n) {\n submitCrashReport(\n id: $id\n timestamp: $timestamp\n sdkVersion: $sdkVersion\n nodeVersion: $nodeVersion\n osPlatform: $osPlatform\n osRelease: $osRelease\n arch: $arch\n command: $command\n argv: $argv\n errorName: $errorName\n errorMessage: $errorMessage\n stackTrace: $stackTrace\n errorType: $errorType\n userId: $userId\n userEmail: $userEmail\n ) {\n success\n }\n}`;\n\n/**\n * Send a crash report to the remote endpoint via GraphQL mutation.\n * Best-effort: never throws, returns boolean success.\n * @param report - Crash report to send\n * @param ua - User-Agent header value\n * @returns true if the request succeeded, false otherwise\n */\nexport async function sendCrashReport(report: CrashReport, ua: string): Promise<boolean> {\n try {\n const endpoint = process.env.TAILOR_CRASH_REPORT_ENDPOINT || PRODUCTION_ENDPOINT;\n const response = await fetch(endpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"User-Agent\": ua,\n },\n body: JSON.stringify({\n query: SUBMIT_MUTATION,\n variables: report,\n }),\n signal: AbortSignal.timeout(SEND_TIMEOUT_MS),\n });\n\n if (!response.ok) return false;\n\n const data = (await response.json()) as {\n errors?: unknown[];\n data?: { submitCrashReport: { success: boolean } };\n };\n if (data.errors?.length) return false;\n return data.data?.submitCrashReport.success === true;\n } catch {\n return false;\n }\n}\n","import * as os from \"node:os\";\n\nconst HOME_DIR = os.homedir();\n\n// Patterns for sanitization (global variants for use with .replace())\nconst UUID_PATTERN = /\\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\\b/gi;\nconst LONG_HEX_PATTERN = /\\b[0-9a-fA-F]{32,}\\b/g;\nconst EMAIL_PATTERN = /\\b[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}\\b/g;\nconst ABSOLUTE_PATH_PATTERN = /(?:\\/(?:[\\w.@\\- ]+\\/)+[\\w.@\\- ]+)/g;\nconst WINDOWS_PATH_PATTERN = /(?:[A-Za-z]:\\\\(?:[\\w.@\\- ]+\\\\)+[\\w.@\\- ]+)/g;\nconst URL_QUERY_PATTERN = /[?&][^?\\s]*/g;\n\n// Non-global variants for single-match .test() calls (avoids lastIndex state issues)\nconst EMAIL_TEST_PATTERN = /\\b[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}\\b/;\nconst WINDOWS_DRIVE_TEST_PATTERN = /^[A-Za-z]:\\\\/;\n\n// SDK package path marker for relative paths\nconst SDK_PACKAGE_MARKER = \"packages/sdk/\";\n\nfunction lastSegment(filePath: string, separator: string): string {\n return filePath.split(separator).pop() ?? filePath;\n}\n\n/**\n * Sanitize a stack trace by replacing absolute paths with relative SDK paths.\n * External paths are replaced with `<external>/filename.ext`.\n * Home directories are replaced with `~/<redacted>/`.\n * @param stack - Raw stack trace string\n * @returns Sanitized stack trace\n */\nexport function sanitizeStackTrace(stack: string): string {\n // V8 stack traces start with \"ErrorType: message\\n at ...\".\n // The error message may span multiple lines before the first \" at \" frame.\n // Apply message sanitization to all message lines so secrets embedded in\n // multiline error messages are redacted consistently with errorMessage.\n const firstFrameIndex = stack.search(/\\n\\s+at /);\n let result: string;\n if (firstFrameIndex !== -1) {\n result = sanitizeMessage(stack.slice(0, firstFrameIndex)) + stack.slice(firstFrameIndex);\n } else {\n result = sanitizeMessage(stack);\n }\n\n result = result.replace(ABSOLUTE_PATH_PATTERN, (match) => {\n const sdkIndex = match.indexOf(SDK_PACKAGE_MARKER);\n if (sdkIndex !== -1) {\n return match.slice(sdkIndex);\n }\n\n if (match.startsWith(HOME_DIR)) {\n return `~/<redacted>/${lastSegment(match, \"/\")}`;\n }\n\n return `<external>/${lastSegment(match, \"/\")}`;\n });\n result = result.replace(WINDOWS_PATH_PATTERN, (match) => {\n const normalized = match.replace(/\\\\/g, \"/\");\n const sdkIndex = normalized.indexOf(SDK_PACKAGE_MARKER);\n if (sdkIndex !== -1) {\n return normalized.slice(sdkIndex);\n }\n return `<external>/${lastSegment(match, \"\\\\\")}`;\n });\n return result;\n}\n\n/**\n * Sanitize an error message by redacting sensitive information.\n * Redacts: UUIDs, long hex tokens, email addresses, absolute paths, URL query strings.\n * @param message - Raw error message\n * @returns Sanitized error message\n */\nexport function sanitizeMessage(message: string): string {\n let result = message;\n // Strip serialized request/response bodies that may contain secrets\n result = result.replace(/\\nRequest:\\s*[\\s\\S]*$/, \"\\nRequest: <redacted>\");\n result = result.replace(UUID_PATTERN, \"<uuid>\");\n result = result.replace(LONG_HEX_PATTERN, \"<redacted>\");\n result = result.replace(EMAIL_PATTERN, \"<email>\");\n result = result.replace(URL_QUERY_PATTERN, \"?<redacted>\");\n result = result.replace(ABSOLUTE_PATH_PATTERN, (match) => `<path>/${lastSegment(match, \"/\")}`);\n result = result.replace(WINDOWS_PATH_PATTERN, (match) => `<path>/${lastSegment(match, \"\\\\\")}`);\n\n return result;\n}\n\n/**\n * Sanitize process.argv by keeping command/subcommand names and redacting\n * values of sensitive flags.\n * @param argv - Raw process.argv array\n * @returns Sanitized argv array\n */\nexport function sanitizeArgv(argv: string[]): string[] {\n const result: string[] = [];\n let redactNext = false;\n\n for (const arg of argv) {\n if (redactNext) {\n // If the next token is itself a flag, treat it as a new flag rather\n // than consuming it as the previous flag's value. This avoids leaking\n // the *next* flag's value (e.g., `--verbose --workspace-id secret`\n // would otherwise expose `secret`).\n if (!arg.startsWith(\"-\")) {\n result.push(\"<redacted>\");\n redactNext = false;\n continue;\n }\n redactNext = false;\n }\n\n if (arg.startsWith(\"-\")) {\n // --flag=value: keep flag name, redact value\n const eqIndex = arg.indexOf(\"=\");\n if (eqIndex !== -1) {\n result.push(`${arg.slice(0, eqIndex)}=<redacted>`);\n continue;\n }\n\n // --flag / -f: keep flag name, redact next arg as its value\n result.push(arg);\n redactNext = true;\n continue;\n }\n\n // Redact absolute paths\n if (arg.startsWith(\"/\") && arg.includes(\"/\", 1)) {\n result.push(\"<path>\");\n continue;\n }\n\n // Redact Windows-style absolute paths\n if (WINDOWS_DRIVE_TEST_PATTERN.test(arg)) {\n result.push(\"<path>\");\n continue;\n }\n\n // Redact email addresses\n if (EMAIL_TEST_PATTERN.test(arg)) {\n result.push(\"<email>\");\n continue;\n }\n\n result.push(arg);\n }\n\n return result;\n}\n","import * as crypto from \"node:crypto\";\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport { parseYAML } from \"confbox\";\nimport * as path from \"pathe\";\nimport { xdgConfig } from \"xdg-basedir\";\nimport { sanitizeArgv, sanitizeMessage, sanitizeStackTrace } from \"./sanitize\";\n\nexport type ErrorType = \"uncaughtException\" | \"unhandledRejection\" | \"handledError\";\n\nexport interface CrashReport {\n id: string;\n timestamp: string;\n sdkVersion: string;\n nodeVersion: string;\n osPlatform: string;\n osRelease: string;\n arch: string;\n command: string;\n argv: string[];\n errorName: string;\n errorMessage: string;\n stackTrace: string;\n errorType: ErrorType;\n userId: string | null;\n userEmail: string | null;\n}\n\ninterface BuildCrashReportOptions {\n error: unknown;\n sdkVersion: string;\n errorType: ErrorType;\n}\n\n// Maximum subcommand depth to keep (e.g., \"tailordb migrate generate\" = 3 tokens).\n// Positional arguments beyond this are potentially sensitive user input.\n// Accepted trade-off: plain-text positional args that don't match known patterns\n// (UUIDs, hex tokens, emails, paths) pass through to `command` and `argv`.\n// Full redaction would require embedding the CLI command tree here, which is fragile.\nconst MAX_COMMAND_TOKENS = 3;\n\n/**\n * Parse the command name from process.argv.\n * Extracts up to MAX_COMMAND_TOKENS non-flag arguments after the script name.\n * @returns Parsed command string\n */\nfunction parseCommand(): string {\n const args = process.argv.slice(2);\n const commandParts: string[] = [];\n for (const arg of args) {\n if (arg.startsWith(\"-\") || commandParts.length >= MAX_COMMAND_TOKENS) break;\n commandParts.push(arg);\n }\n return commandParts.join(\" \") || \"<unknown>\";\n}\n\n/**\n * Build a CrashReport data structure from an error and context.\n * All sensitive data is sanitized before inclusion.\n * @param options - Error, SDK version, and crash type\n * @returns Sanitized crash report\n */\nexport function buildCrashReport(options: BuildCrashReportOptions): CrashReport {\n const { error, sdkVersion, errorType } = options;\n\n const isError = error instanceof Error;\n const rawMessage = isError ? error.message : String(error);\n const rawStack = isError && error.stack ? error.stack : \"\";\n const errorName = isError ? error.name : \"UnknownError\";\n\n const currentUser = readCurrentUser();\n\n return {\n id: crypto.randomUUID(),\n timestamp: new Date().toISOString(),\n sdkVersion,\n nodeVersion: process.version,\n osPlatform: process.platform,\n osRelease: os.release(),\n arch: process.arch,\n command: sanitizeMessage(parseCommand()),\n argv: sanitizeArgv(process.argv),\n errorName,\n errorMessage: sanitizeMessage(rawMessage),\n stackTrace: sanitizeStackTrace(rawStack),\n errorType,\n userId: currentUser,\n userEmail: currentUser,\n };\n}\n\n/**\n * Read current_user from Tailor Platform config without side effects.\n * Unlike readPlatformConfig(), this never triggers migration or logs warnings.\n * @returns The current user email, or null if unavailable\n */\nfunction readCurrentUser(): string | null {\n try {\n if (!xdgConfig) return null;\n const configPath = path.join(xdgConfig, \"tailor-platform\", \"config.yaml\");\n if (!fs.existsSync(configPath)) return null;\n const raw = parseYAML(fs.readFileSync(configPath, \"utf-8\")) as { current_user?: string | null };\n return raw?.current_user ?? null;\n } catch {\n return null;\n }\n}\n","import { logger } from \"@/cli/shared/logger\";\nimport { readPackageJson } from \"@/cli/shared/package-json\";\nimport { parseCrashReportConfig } from \"./config\";\nimport { buildCrashReport, type ErrorType } from \"./report\";\nimport { sendCrashReport } from \"./sender\";\nimport { writeCrashReport } from \"./writer\";\n\n/**\n * Report an unexpected crash. Writes a local crash log file and optionally\n * sends the report to a remote endpoint. Displays a user-facing message\n * with the crash log path and a command to submit the report.\n *\n * Never throws - all errors are silently caught.\n * @param error - The error that caused the crash\n * @param errorType - How the error was caught\n */\nexport async function reportCrash(error: unknown, errorType: ErrorType): Promise<void> {\n try {\n const config = parseCrashReportConfig();\n if (!config.localEnabled && !config.remoteEnabled) return;\n\n const packageJson = await readPackageJson();\n const sdkVersion = packageJson.version ?? \"unknown\";\n\n const report = buildCrashReport({ error, sdkVersion, errorType });\n\n if (config.localEnabled) {\n const filePath = writeCrashReport(report, config.localDir);\n if (filePath) {\n logger.log(\n [\n \"\",\n \"An unexpected error occurred. A crash report has been saved to:\",\n ` ${filePath}`,\n \"\",\n \"To submit this report:\",\n ` tailor-sdk crash-report send --file \"${filePath}\"`,\n ].join(\"\\n\"),\n );\n }\n }\n\n if (config.remoteEnabled) {\n // Lazy import: client.ts pulls in heavy dependencies (OAuth2, Connect, Protobuf)\n // that should not be loaded on the startup critical path via initCrashReporting().\n const { userAgent } = await import(\"@/cli/shared/client\");\n const ua = await userAgent();\n await sendCrashReport(report, ua);\n }\n } catch {\n // Never throw from crash reporting\n }\n}\n\n/**\n * Register global uncaughtException and unhandledRejection handlers.\n * These catch errors outside the normal cleanup flow (e.g., during\n * argument parsing). Should be called once at CLI startup before runMain.\n */\nexport function initCrashReporting(): void {\n const config = parseCrashReportConfig();\n if (!config.localEnabled && !config.remoteEnabled) return;\n\n const handleFatal = (error: unknown, errorType: ErrorType) => {\n const message = error instanceof Error ? error.message : String(error);\n logger.error(message);\n void reportCrash(error, errorType).finally(() => {\n process.exit(1);\n });\n };\n\n process.on(\"uncaughtException\", (error) => handleFatal(error, \"uncaughtException\"));\n process.on(\"unhandledRejection\", (reason) => handleFatal(reason, \"unhandledRejection\"));\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAiBA,SAAgB,yBAA4C;AAC1D,KAAI,KACF,QAAO;EACL,cAAc;EACd,eAAe;EACf,UAAU;EACX;CAGH,MAAM,gBAAgB,QAAQ,IAAI,8BAA8B,MAAM,aAAa,KAAK;CACxF,MAAM,iBAAiB,QAAQ,IAAI,+BAA+B,OAAO,aAAa,KAAK;CAC3F,MAAM,WAAW,YAAY,KAAK,KAAK,WAAW,mBAAmB,gBAAgB,GAAG;AAExF,QAAO;EACL,cAAc,gBAAgB,aAAa;EAC3C;EACA;EACD;;;;;AC9BH,MAAM,kBAAkB;;AAGxB,MAAa,qBAAqB;;AAGlC,MAAa,sBAAsB;;;;;;AAOnC,SAAgB,kBAAkB,QAA6B;AA2B7D,QA1Bc;EACZ,iBAAiB,OAAO;EACxB,cAAc,OAAO;EACrB,eAAe,OAAO;EACtB;EACA;EACA,gBAAgB,OAAO;EACvB,iBAAiB,OAAO;EACxB,OAAO,OAAO,WAAW,GAAG,OAAO;EACnC,SAAS,OAAO;EAChB;EACA;EACA,YAAY,OAAO;EACnB,cAAc,KAAK,UAAU,OAAO,KAAK;EACzC;EACA;EACA,SAAS,OAAO;EAChB,YAAY,OAAO;EACnB;EACA;EACA,OAAO,cAAc;EACrB;EACA;EACA,KAAK,UAAU,OAAO;EACtB;EACD,CACY,KAAK,KAAK;;;;;;;;AASzB,SAAS,iBAAiB,QAA6B;AAGrD,QAAO,GAFe,OAAO,UAAU,QAAQ,SAAS,IAAI,CAEpC,GADR,OAAO,GAAG,MAAM,GAAG,EAAE,GACA;;;;;;AAOvC,SAAS,gBAAgB,KAAmB;AAC1C,KAAI;EACF,MAAM,QAAQ,GACX,YAAY,IAAI,CAChB,QAAQ,MAAM,EAAE,SAAS,oBAAoB,CAAC,CAC9C,MAAM,CACN,SAAS;AAEZ,OAAK,MAAM,QAAQ,MAAM,MAAM,gBAAgB,CAC7C,IAAG,WAAW,KAAK,KAAK,KAAK,KAAK,CAAC;SAE/B;;;;;;;;;;AAaV,SAAgB,iBAAiB,QAAqB,KAAiC;AACrF,KAAI;AACF,KAAG,UAAU,KAAK,EAAE,WAAW,MAAM,CAAC;EAEtC,MAAM,WAAW,iBAAiB,OAAO;EACzC,MAAM,WAAW,KAAK,KAAK,KAAK,SAAS;EACzC,MAAM,UAAU,kBAAkB,OAAO;AAEzC,KAAG,cAAc,UAAU,SAAS,QAAQ;AAC5C,kBAAgB,IAAI;AAEpB,SAAO;SACD;AACN;;;;;;AClGJ,MAAM,kBAAkB;AACxB,MAAM,sBAAsB;AAE5B,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8CxB,eAAsB,gBAAgB,QAAqB,IAA8B;AACvF,KAAI;EACF,MAAM,WAAW,QAAQ,IAAI,gCAAgC;EAC7D,MAAM,WAAW,MAAM,MAAM,UAAU;GACrC,QAAQ;GACR,SAAS;IACP,gBAAgB;IAChB,cAAc;IACf;GACD,MAAM,KAAK,UAAU;IACnB,OAAO;IACP,WAAW;IACZ,CAAC;GACF,QAAQ,YAAY,QAAQ,gBAAgB;GAC7C,CAAC;AAEF,MAAI,CAAC,SAAS,GAAI,QAAO;EAEzB,MAAM,OAAQ,MAAM,SAAS,MAAM;AAInC,MAAI,KAAK,QAAQ,OAAQ,QAAO;AAChC,SAAO,KAAK,MAAM,kBAAkB,YAAY;SAC1C;AACN,SAAO;;;;;;AC1EX,MAAM,WAAW,GAAG,SAAS;AAG7B,MAAM,eAAe;AACrB,MAAM,mBAAmB;AACzB,MAAM,gBAAgB;AACtB,MAAM,wBAAwB;AAC9B,MAAM,uBAAuB;AAC7B,MAAM,oBAAoB;AAG1B,MAAM,qBAAqB;AAC3B,MAAM,6BAA6B;AAGnC,MAAM,qBAAqB;AAE3B,SAAS,YAAY,UAAkB,WAA2B;AAChE,QAAO,SAAS,MAAM,UAAU,CAAC,KAAK,IAAI;;;;;;;;;AAU5C,SAAgB,mBAAmB,OAAuB;CAKxD,MAAM,kBAAkB,MAAM,OAAO,WAAW;CAChD,IAAI;AACJ,KAAI,oBAAoB,GACtB,UAAS,gBAAgB,MAAM,MAAM,GAAG,gBAAgB,CAAC,GAAG,MAAM,MAAM,gBAAgB;KAExF,UAAS,gBAAgB,MAAM;AAGjC,UAAS,OAAO,QAAQ,wBAAwB,UAAU;EACxD,MAAM,WAAW,MAAM,QAAQ,mBAAmB;AAClD,MAAI,aAAa,GACf,QAAO,MAAM,MAAM,SAAS;AAG9B,MAAI,MAAM,WAAW,SAAS,CAC5B,QAAO,gBAAgB,YAAY,OAAO,IAAI;AAGhD,SAAO,cAAc,YAAY,OAAO,IAAI;GAC5C;AACF,UAAS,OAAO,QAAQ,uBAAuB,UAAU;EACvD,MAAM,aAAa,MAAM,QAAQ,OAAO,IAAI;EAC5C,MAAM,WAAW,WAAW,QAAQ,mBAAmB;AACvD,MAAI,aAAa,GACf,QAAO,WAAW,MAAM,SAAS;AAEnC,SAAO,cAAc,YAAY,OAAO,KAAK;GAC7C;AACF,QAAO;;;;;;;;AAST,SAAgB,gBAAgB,SAAyB;CACvD,IAAI,SAAS;AAEb,UAAS,OAAO,QAAQ,yBAAyB,wBAAwB;AACzE,UAAS,OAAO,QAAQ,cAAc,SAAS;AAC/C,UAAS,OAAO,QAAQ,kBAAkB,aAAa;AACvD,UAAS,OAAO,QAAQ,eAAe,UAAU;AACjD,UAAS,OAAO,QAAQ,mBAAmB,cAAc;AACzD,UAAS,OAAO,QAAQ,wBAAwB,UAAU,UAAU,YAAY,OAAO,IAAI,GAAG;AAC9F,UAAS,OAAO,QAAQ,uBAAuB,UAAU,UAAU,YAAY,OAAO,KAAK,GAAG;AAE9F,QAAO;;;;;;;;AAST,SAAgB,aAAa,MAA0B;CACrD,MAAM,SAAmB,EAAE;CAC3B,IAAI,aAAa;AAEjB,MAAK,MAAM,OAAO,MAAM;AACtB,MAAI,YAAY;AAKd,OAAI,CAAC,IAAI,WAAW,IAAI,EAAE;AACxB,WAAO,KAAK,aAAa;AACzB,iBAAa;AACb;;AAEF,gBAAa;;AAGf,MAAI,IAAI,WAAW,IAAI,EAAE;GAEvB,MAAM,UAAU,IAAI,QAAQ,IAAI;AAChC,OAAI,YAAY,IAAI;AAClB,WAAO,KAAK,GAAG,IAAI,MAAM,GAAG,QAAQ,CAAC,aAAa;AAClD;;AAIF,UAAO,KAAK,IAAI;AAChB,gBAAa;AACb;;AAIF,MAAI,IAAI,WAAW,IAAI,IAAI,IAAI,SAAS,KAAK,EAAE,EAAE;AAC/C,UAAO,KAAK,SAAS;AACrB;;AAIF,MAAI,2BAA2B,KAAK,IAAI,EAAE;AACxC,UAAO,KAAK,SAAS;AACrB;;AAIF,MAAI,mBAAmB,KAAK,IAAI,EAAE;AAChC,UAAO,KAAK,UAAU;AACtB;;AAGF,SAAO,KAAK,IAAI;;AAGlB,QAAO;;;;;AC1GT,MAAM,qBAAqB;;;;;;AAO3B,SAAS,eAAuB;CAC9B,MAAM,OAAO,QAAQ,KAAK,MAAM,EAAE;CAClC,MAAM,eAAyB,EAAE;AACjC,MAAK,MAAM,OAAO,MAAM;AACtB,MAAI,IAAI,WAAW,IAAI,IAAI,aAAa,UAAU,mBAAoB;AACtE,eAAa,KAAK,IAAI;;AAExB,QAAO,aAAa,KAAK,IAAI,IAAI;;;;;;;;AASnC,SAAgB,iBAAiB,SAA+C;CAC9E,MAAM,EAAE,OAAO,YAAY,cAAc;CAEzC,MAAM,UAAU,iBAAiB;CACjC,MAAM,aAAa,UAAU,MAAM,UAAU,OAAO,MAAM;CAC1D,MAAM,WAAW,WAAW,MAAM,QAAQ,MAAM,QAAQ;CACxD,MAAM,YAAY,UAAU,MAAM,OAAO;CAEzC,MAAM,cAAc,iBAAiB;AAErC,QAAO;EACL,IAAI,OAAO,YAAY;EACvB,4BAAW,IAAI,MAAM,EAAC,aAAa;EACnC;EACA,aAAa,QAAQ;EACrB,YAAY,QAAQ;EACpB,WAAW,GAAG,SAAS;EACvB,MAAM,QAAQ;EACd,SAAS,gBAAgB,cAAc,CAAC;EACxC,MAAM,aAAa,QAAQ,KAAK;EAChC;EACA,cAAc,gBAAgB,WAAW;EACzC,YAAY,mBAAmB,SAAS;EACxC;EACA,QAAQ;EACR,WAAW;EACZ;;;;;;;AAQH,SAAS,kBAAiC;AACxC,KAAI;AACF,MAAI,CAAC,UAAW,QAAO;EACvB,MAAM,aAAa,KAAK,KAAK,WAAW,mBAAmB,cAAc;AACzE,MAAI,CAAC,GAAG,WAAW,WAAW,CAAE,QAAO;AAEvC,SADY,UAAU,GAAG,aAAa,YAAY,QAAQ,CAAC,EAC/C,gBAAgB;SACtB;AACN,SAAO;;;;;;;;;;;;;;;ACxFX,eAAsB,YAAY,OAAgB,WAAqC;AACrF,KAAI;EACF,MAAM,SAAS,wBAAwB;AACvC,MAAI,CAAC,OAAO,gBAAgB,CAAC,OAAO,cAAe;EAKnD,MAAM,SAAS,iBAAiB;GAAE;GAAO,aAHrB,MAAM,iBAAiB,EACZ,WAAW;GAEW;GAAW,CAAC;AAEjE,MAAI,OAAO,cAAc;GACvB,MAAM,WAAW,iBAAiB,QAAQ,OAAO,SAAS;AAC1D,OAAI,SACF,QAAO,IACL;IACE;IACA;IACA,KAAK;IACL;IACA;IACA,0CAA0C,SAAS;IACpD,CAAC,KAAK,KAAK,CACb;;AAIL,MAAI,OAAO,eAAe;GAGxB,MAAM,EAAE,cAAc,MAAM,OAAO;AAEnC,SAAM,gBAAgB,QADX,MAAM,WAAW,CACK;;SAE7B;;;;;;;AAUV,SAAgB,qBAA2B;CACzC,MAAM,SAAS,wBAAwB;AACvC,KAAI,CAAC,OAAO,gBAAgB,CAAC,OAAO,cAAe;CAEnD,MAAM,eAAe,OAAgB,cAAyB;EAC5D,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AACtE,SAAO,MAAM,QAAQ;AACrB,EAAK,YAAY,OAAO,UAAU,CAAC,cAAc;AAC/C,WAAQ,KAAK,EAAE;IACf;;AAGJ,SAAQ,GAAG,sBAAsB,UAAU,YAAY,OAAO,oBAAoB,CAAC;AACnF,SAAQ,GAAG,uBAAuB,WAAW,YAAY,QAAQ,qBAAqB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors-
|
|
1
|
+
{"version":3,"file":"errors-ChWX5ZG8.mjs","names":[],"sources":["../src/cli/shared/errors.ts"],"sourcesContent":["import chalk from \"chalk\";\n\n/**\n * Options for creating a CLI error\n */\nexport interface CLIErrorOptions {\n message: string;\n details?: string;\n suggestion?: string;\n command?: string;\n code?: string;\n}\n\n/**\n * CLI error interface with formatted output\n */\nexport interface CLIError extends Error {\n readonly code?: string;\n readonly details?: string;\n readonly suggestion?: string;\n readonly command?: string;\n format(): string;\n}\n\ntype CLIErrorInternal = Error & {\n code?: string;\n details?: string;\n suggestion?: string;\n command?: string;\n format(): string;\n};\n\n/**\n * Format CLI error for output\n * @param error - CLIError instance to format\n * @returns Formatted error message\n */\nfunction formatError(error: CLIError): string {\n const parts: string[] = [\n chalk.red(`Error${error.code ? ` [${error.code}]` : \"\"}: ${error.message}`),\n ];\n\n if (error.details) {\n parts.push(`\\n ${chalk.gray(\"Details:\")} ${error.details}`);\n }\n\n if (error.suggestion) {\n parts.push(`\\n ${chalk.cyan(\"Suggestion:\")} ${error.suggestion}`);\n }\n\n if (error.command) {\n parts.push(\n `\\n ${chalk.gray(\"Help:\")} Run \\`tailor-sdk ${error.command} --help\\` for usage information.`,\n );\n }\n\n return parts.join(\"\");\n}\n\n/**\n * Create a CLI error with formatted output\n * @param options - Options to construct a CLIError\n * @returns Constructed CLIError instance\n */\nfunction createCLIError(options: CLIErrorOptions): CLIError {\n const error = new Error(options.message) as CLIErrorInternal;\n error.name = \"CLIError\";\n error.code = options.code;\n error.details = options.details;\n error.suggestion = options.suggestion;\n error.command = options.command;\n error.format = () => formatError(error);\n return error;\n}\n\n/**\n * Type guard to check if an error is a CLIError\n * @param error - Error to check\n * @returns True if the error is a CLIError\n */\nexport function isCLIError(error: unknown): error is CLIError {\n return error instanceof Error && error.name === \"CLIError\";\n}\n\n// Re-export createCLIError as CLIError for backward compatibility\nexport { createCLIError as CLIError };\n"],"mappings":";;;;;;;;;AAqCA,SAAS,YAAY,OAAyB;CAC5C,MAAM,QAAkB,CACtB,MAAM,IAAI,QAAQ,MAAM,OAAO,KAAK,MAAM,KAAK,KAAK,GAAG,IAAI,MAAM,UAAU,CAC5E;AAED,KAAI,MAAM,QACR,OAAM,KAAK,OAAO,MAAM,KAAK,WAAW,CAAC,GAAG,MAAM,UAAU;AAG9D,KAAI,MAAM,WACR,OAAM,KAAK,OAAO,MAAM,KAAK,cAAc,CAAC,GAAG,MAAM,aAAa;AAGpE,KAAI,MAAM,QACR,OAAM,KACJ,OAAO,MAAM,KAAK,QAAQ,CAAC,oBAAoB,MAAM,QAAQ,kCAC9D;AAGH,QAAO,MAAM,KAAK,GAAG;;;;;;;AAQvB,SAAS,eAAe,SAAoC;CAC1D,MAAM,QAAQ,IAAI,MAAM,QAAQ,QAAQ;AACxC,OAAM,OAAO;AACb,OAAM,OAAO,QAAQ;AACrB,OAAM,UAAU,QAAQ;AACxB,OAAM,aAAa,QAAQ;AAC3B,OAAM,UAAU,QAAQ;AACxB,OAAM,eAAe,YAAY,MAAM;AACvC,QAAO;;;;;;;AAQT,SAAgB,WAAW,OAAmC;AAC5D,QAAO,iBAAiB,SAAS,MAAM,SAAS"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/configure/types/field.ts
|
|
3
|
+
/**
|
|
4
|
+
* Normalize allowed values into EnumValue objects with descriptions.
|
|
5
|
+
* @param values - Allowed values as strings or EnumValue objects
|
|
6
|
+
* @returns Normalized allowed values
|
|
7
|
+
*/
|
|
8
|
+
function mapAllowedValues(values) {
|
|
9
|
+
return values.map((value) => {
|
|
10
|
+
if (typeof value === "string") return {
|
|
11
|
+
value,
|
|
12
|
+
description: ""
|
|
13
|
+
};
|
|
14
|
+
return {
|
|
15
|
+
...value,
|
|
16
|
+
description: value.description ?? ""
|
|
17
|
+
};
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
//#endregion
|
|
22
|
+
export { mapAllowedValues as t };
|
|
23
|
+
//# sourceMappingURL=field-BY2vbJ8f.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"field-BY2vbJ8f.mjs","names":[],"sources":["../src/configure/types/field.ts"],"sourcesContent":["import type { EnumValue } from \"@/types/field-types\";\n\nexport type AllowedValues = readonly [string | EnumValue, ...(string | EnumValue)[]];\n\n/**\n * Normalize allowed values into EnumValue objects with descriptions.\n * @param values - Allowed values as strings or EnumValue objects\n * @returns Normalized allowed values\n */\nexport function mapAllowedValues(values: AllowedValues): EnumValue[] {\n return values.map((value) => {\n if (typeof value === \"string\") {\n return { value, description: \"\" };\n }\n return { ...value, description: value.description ?? \"\" };\n });\n}\n\nexport type AllowedValuesOutput<V extends AllowedValues> = V[number] extends infer T\n ? T extends string\n ? T\n : T extends { value: infer K }\n ? K\n : never\n : never;\n"],"mappings":";;;;;;;AASA,SAAgB,iBAAiB,QAAoC;AACnE,QAAO,OAAO,KAAK,UAAU;AAC3B,MAAI,OAAO,UAAU,SACnB,QAAO;GAAE;GAAO,aAAa;GAAI;AAEnC,SAAO;GAAE,GAAG;GAAO,aAAa,MAAM,eAAe;GAAI;GACzD"}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
/// <reference types="@tailor-platform/function-types" />
|
|
2
|
-
import { $ as
|
|
3
|
-
import { n as
|
|
4
|
-
import {
|
|
5
|
-
import * as _$zod from "zod";
|
|
2
|
+
import { $ as ResolverInput, At as FieldMetadata, Bt as InferredAttributeMap, Dt as ArrayFieldOutput, Ft as FieldValidateInput, G as UserAttributeListKey, Gt as JsonValue, K as UserAttributeMap, Kt as Prettify, Mt as FieldOutput, Nt as TailorFieldType, Ot as DefinedFieldMetadata, Q as Resolver, Ut as InferFieldsOutput, V as DefinedAuth, Vt as TailorUser, Wt as JsonCompatible, Y as TailorField$1, at as FunctionOperation$1, ct as IncomingWebhookTrigger$1, dt as TailorDBTrigger$1, et as GeneratorConfig, ft as WebhookOperation$1, it as ExecutorInput, jt as FieldOptions, lt as ResolverExecutedTrigger$1, mt as AuthInvoker$1, nt as AuthAccessTokenTrigger$1, o as Plugin, ot as GqlOperation$1, pt as WorkflowOperation$1, qt as output$1, st as IdpUserTrigger$1, tt as BaseGeneratorConfig, ut as ScheduleTriggerInput, z as AuthServiceInput } from "./tailor-db-field-B99RnR2N.mjs";
|
|
3
|
+
import { D as TailorDBType, E as TailorDBInstance, F as AllowedValuesOutput, P as AllowedValues, S as IdPInput, _ as IdPUserField, d as StaticWebsiteDefinitionBrand, f as StaticWebsiteInput, m as SecretsDefinitionBrand, n as AppConfig, t as RetryPolicy, v as IdpDefinitionBrand } from "./workflow.generated-DSwr-k57.mjs";
|
|
4
|
+
import { r as TailorEnv, t as TailorActor } from "./actor-Bb4OVq1j.mjs";
|
|
6
5
|
import { JsonPrimitive, Jsonifiable, Jsonify } from "type-fest";
|
|
6
|
+
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
7
7
|
import { Client } from "@urql/core";
|
|
8
8
|
import { StandardCRON } from "ts-cron-validator";
|
|
9
|
-
import * as _$zod_v4_core0 from "zod/v4/core";
|
|
10
9
|
|
|
11
10
|
//#region src/configure/types/machine-user.d.ts
|
|
12
11
|
interface MachineUserNameRegistry {}
|
|
@@ -19,8 +18,82 @@ interface MachineUserNameRegistry {}
|
|
|
19
18
|
*/
|
|
20
19
|
type MachineUserName = keyof MachineUserNameRegistry extends never ? string : keyof MachineUserNameRegistry & string;
|
|
21
20
|
//#endregion
|
|
21
|
+
//#region src/configure/types/type.d.ts
|
|
22
|
+
type TailorAnyField = TailorField<any>;
|
|
23
|
+
/**
|
|
24
|
+
* Full TailorField interface with builder methods.
|
|
25
|
+
* Extends the minimal structural interface from types/ with fluent API methods.
|
|
26
|
+
*/
|
|
27
|
+
interface TailorField<Defined extends DefinedFieldMetadata = DefinedFieldMetadata, Output = any, M extends FieldMetadata = FieldMetadata, T extends TailorFieldType = TailorFieldType> extends TailorField$1<Defined, Output, M, T> {
|
|
28
|
+
readonly fields: Record<string, TailorAnyField>;
|
|
29
|
+
_metadata: M;
|
|
30
|
+
/**
|
|
31
|
+
* Set a description for the field
|
|
32
|
+
* @param description - The description text
|
|
33
|
+
* @returns The field with updated metadata
|
|
34
|
+
*/
|
|
35
|
+
description<CurrentDefined extends Defined>(this: CurrentDefined extends {
|
|
36
|
+
description: unknown;
|
|
37
|
+
} ? never : TailorField<CurrentDefined, Output>, description: string): TailorField<Prettify<CurrentDefined & {
|
|
38
|
+
description: true;
|
|
39
|
+
}>, Output>;
|
|
40
|
+
/**
|
|
41
|
+
* Set a custom type name for enum or nested types
|
|
42
|
+
* @param typeName - The custom type name
|
|
43
|
+
* @returns The field with updated metadata
|
|
44
|
+
*/
|
|
45
|
+
typeName<CurrentDefined extends Defined>(this: CurrentDefined extends {
|
|
46
|
+
typeName: unknown;
|
|
47
|
+
} ? never : CurrentDefined extends {
|
|
48
|
+
type: "enum" | "nested";
|
|
49
|
+
} ? TailorField<CurrentDefined, Output> : never, typeName: string): TailorField<Prettify<CurrentDefined & {
|
|
50
|
+
typeName: true;
|
|
51
|
+
}>, Output>;
|
|
52
|
+
/**
|
|
53
|
+
* Add validation functions to the field
|
|
54
|
+
* @param validate - One or more validation functions
|
|
55
|
+
* @returns The field with updated metadata
|
|
56
|
+
*/
|
|
57
|
+
validate<CurrentDefined extends Defined>(this: CurrentDefined extends {
|
|
58
|
+
validate: unknown;
|
|
59
|
+
} ? never : TailorField<CurrentDefined, Output>, ...validate: FieldValidateInput<Output>[]): TailorField<Prettify<CurrentDefined & {
|
|
60
|
+
validate: true;
|
|
61
|
+
}>, Output>;
|
|
62
|
+
/**
|
|
63
|
+
* Parse and validate a value against this field's validation rules
|
|
64
|
+
* Returns StandardSchema Result type with success or failure
|
|
65
|
+
* @param args - Value, context data, and user
|
|
66
|
+
* @returns Validation result
|
|
67
|
+
*/
|
|
68
|
+
parse(args: FieldParseArgs): StandardSchemaV1.Result<Output>;
|
|
69
|
+
/**
|
|
70
|
+
* Internal parse method that tracks field path for nested validation
|
|
71
|
+
* @private
|
|
72
|
+
* @param args - Parse arguments
|
|
73
|
+
* @returns Validation result
|
|
74
|
+
*/
|
|
75
|
+
_parseInternal(args: FieldParseInternalArgs): StandardSchemaV1.Result<Output>;
|
|
76
|
+
}
|
|
77
|
+
type FieldParseArgs = {
|
|
78
|
+
value: unknown;
|
|
79
|
+
data: unknown;
|
|
80
|
+
user: TailorUser;
|
|
81
|
+
};
|
|
82
|
+
type FieldParseInternalArgs = {
|
|
83
|
+
value: any;
|
|
84
|
+
data: unknown;
|
|
85
|
+
user: TailorUser;
|
|
86
|
+
pathArray: string[];
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* Create a UUID field for resolver input/output.
|
|
90
|
+
* @param options - Field configuration options
|
|
91
|
+
* @returns A UUID field
|
|
92
|
+
* @example t.uuid()
|
|
93
|
+
*/
|
|
94
|
+
//#endregion
|
|
22
95
|
//#region src/configure/services/auth/index.d.ts
|
|
23
|
-
type MachineUserAttributeFields = Record<string, TailorField<DefinedFieldMetadata, unknown, FieldMetadata, TailorFieldType>>;
|
|
96
|
+
type MachineUserAttributeFields = Record<string, TailorField$1<DefinedFieldMetadata, unknown, FieldMetadata, TailorFieldType>>;
|
|
24
97
|
type PlaceholderUser = TailorDBInstance<Record<string, never>, Record<string, never>>;
|
|
25
98
|
type PlaceholderAttributeMap = UserAttributeMap<PlaceholderUser>;
|
|
26
99
|
type PlaceholderAttributeList = UserAttributeListKey<PlaceholderUser>[];
|
|
@@ -730,6 +803,20 @@ declare function createExecutor<Args, O extends Operation<Args> | {
|
|
|
730
803
|
workflow: Workflow;
|
|
731
804
|
}>(config: Executor<Trigger<Args>, O>): Executor<Trigger<Args>, O>;
|
|
732
805
|
//#endregion
|
|
806
|
+
//#region src/configure/services/staticwebsite/index.d.ts
|
|
807
|
+
/**
|
|
808
|
+
* Define a static website configuration for the Tailor SDK.
|
|
809
|
+
* @param name - Static website name
|
|
810
|
+
* @param config - Static website configuration
|
|
811
|
+
* @returns Defined static website
|
|
812
|
+
*/
|
|
813
|
+
declare function defineStaticWebSite(name: string, config: Omit<StaticWebsiteInput, "name">): {
|
|
814
|
+
readonly name: string;
|
|
815
|
+
readonly url: `${string}:url`;
|
|
816
|
+
readonly description?: string | undefined;
|
|
817
|
+
readonly allowedIpAddresses?: string[] | undefined;
|
|
818
|
+
} & StaticWebsiteDefinitionBrand;
|
|
819
|
+
//#endregion
|
|
733
820
|
//#region src/configure/services/idp/permission.d.ts
|
|
734
821
|
type EqualityOperator = "=" | "!=";
|
|
735
822
|
type ContainsOperator = "in" | "not in";
|
|
@@ -817,9 +904,9 @@ declare function defineIdp<const TClients extends string[]>(name: string, config
|
|
|
817
904
|
readonly namespace: string;
|
|
818
905
|
readonly clientName: TClients[number];
|
|
819
906
|
};
|
|
820
|
-
readonly authorization
|
|
907
|
+
readonly authorization?: "insecure" | "loggedIn" | {
|
|
821
908
|
cel: string;
|
|
822
|
-
};
|
|
909
|
+
} | undefined;
|
|
823
910
|
readonly lang?: "en" | "ja" | undefined;
|
|
824
911
|
readonly userAuthPolicy?: {
|
|
825
912
|
useNonEmailIdentifier?: boolean | undefined;
|
|
@@ -851,6 +938,41 @@ declare function defineIdp<const TClients extends string[]>(name: string, config
|
|
|
851
938
|
readonly permission?: IdPPermission;
|
|
852
939
|
} & IdpDefinitionBrand;
|
|
853
940
|
//#endregion
|
|
941
|
+
//#region src/configure/services/secrets/index.d.ts
|
|
942
|
+
type SecretsVaultInput = Record<string, string>;
|
|
943
|
+
type SecretsVaultInputNullish = Record<string, string | undefined | null>;
|
|
944
|
+
type SecretsInput = Record<string, SecretsVaultInput>;
|
|
945
|
+
type SecretsInputNullish = Record<string, SecretsVaultInputNullish>;
|
|
946
|
+
type SecretsOptions = {
|
|
947
|
+
readonly ignoreNullishValues: boolean;
|
|
948
|
+
};
|
|
949
|
+
type DefinedSecrets<T extends SecretsInputNullish> = {
|
|
950
|
+
readonly vaults: T;
|
|
951
|
+
readonly options: SecretsOptions;
|
|
952
|
+
get<V extends Extract<keyof T, string>, S extends Extract<keyof T[V], string>>(vault: V, secret: S): Promise<string | undefined>;
|
|
953
|
+
getAll<V extends Extract<keyof T, string>, S extends Extract<keyof T[V], string>>(vault: V, secrets: readonly S[]): Promise<(string | undefined)[]>;
|
|
954
|
+
} & SecretsDefinitionBrand;
|
|
955
|
+
/**
|
|
956
|
+
* Define secrets configuration for the Tailor SDK.
|
|
957
|
+
* Each key is a vault name, and its value is a record of secret name to secret value.
|
|
958
|
+
* @param config - Secrets configuration mapping vault names to their secrets
|
|
959
|
+
* @returns Defined secrets with typed runtime access methods
|
|
960
|
+
*/
|
|
961
|
+
declare function defineSecretManager<const T extends SecretsInput>(config: T): DefinedSecrets<T>;
|
|
962
|
+
/**
|
|
963
|
+
* Define secrets configuration for the Tailor SDK with ignoreNullishValues option.
|
|
964
|
+
* When `ignoreNullishValues` is true, secrets with nullish values are skipped during deploy
|
|
965
|
+
* instead of causing an error. This is useful for CI environments where not all
|
|
966
|
+
* secret values are available.
|
|
967
|
+
* @param config - Secrets configuration mapping vault names to their secrets
|
|
968
|
+
* @param options - Options for secret management behavior
|
|
969
|
+
* @param options.ignoreNullishValues - When true, secrets with nullish values are skipped during deploy
|
|
970
|
+
* @returns Defined secrets with typed runtime access methods
|
|
971
|
+
*/
|
|
972
|
+
declare function defineSecretManager<const T extends SecretsInputNullish>(config: T, options: {
|
|
973
|
+
ignoreNullishValues: true;
|
|
974
|
+
}): DefinedSecrets<T>;
|
|
975
|
+
//#endregion
|
|
854
976
|
//#region src/configure/config.d.ts
|
|
855
977
|
/**
|
|
856
978
|
* Define a Tailor SDK application configuration with shallow exactness.
|
|
@@ -865,26 +987,7 @@ declare function defineConfig<const Config extends AppConfig & Record<Exclude<ke
|
|
|
865
987
|
* @param configs - Generator configurations
|
|
866
988
|
* @returns Generator configurations as given
|
|
867
989
|
*/
|
|
868
|
-
declare function defineGenerators(...configs: GeneratorConfig[]):
|
|
869
|
-
distPath: string;
|
|
870
|
-
}] | ["@tailor-platform/seed", {
|
|
871
|
-
distPath: string;
|
|
872
|
-
machineUserName?: string | undefined;
|
|
873
|
-
}] | ["@tailor-platform/enum-constants", {
|
|
874
|
-
distPath: string;
|
|
875
|
-
}] | ["@tailor-platform/file-utils", {
|
|
876
|
-
distPath: string;
|
|
877
|
-
}] | {
|
|
878
|
-
id: string;
|
|
879
|
-
description: string;
|
|
880
|
-
dependencies: ("executor" | "tailordb" | "resolver")[];
|
|
881
|
-
aggregate: _$zod_v4_core0.$InferInnerFunctionType<_$zod_v4_core0.$ZodFunctionArgs, _$zod.ZodAny>;
|
|
882
|
-
processType?: _$zod_v4_core0.$InferInnerFunctionType<_$zod_v4_core0.$ZodFunctionArgs, _$zod_v4_core0.$ZodFunctionOut> | undefined;
|
|
883
|
-
processResolver?: _$zod_v4_core0.$InferInnerFunctionType<_$zod_v4_core0.$ZodFunctionArgs, _$zod_v4_core0.$ZodFunctionOut> | undefined;
|
|
884
|
-
processExecutor?: _$zod_v4_core0.$InferInnerFunctionType<_$zod_v4_core0.$ZodFunctionArgs, _$zod_v4_core0.$ZodFunctionOut> | undefined;
|
|
885
|
-
processTailorDBNamespace?: _$zod_v4_core0.$InferInnerFunctionType<_$zod_v4_core0.$ZodFunctionArgs, _$zod_v4_core0.$ZodFunctionOut> | undefined;
|
|
886
|
-
processResolverNamespace?: _$zod_v4_core0.$InferInnerFunctionType<_$zod_v4_core0.$ZodFunctionArgs, _$zod_v4_core0.$ZodFunctionOut> | undefined;
|
|
887
|
-
})[];
|
|
990
|
+
declare function defineGenerators(...configs: GeneratorConfig[]): BaseGeneratorConfig[];
|
|
888
991
|
/**
|
|
889
992
|
* Define plugins to be used with the Tailor SDK.
|
|
890
993
|
* Plugins can generate additional types, resolvers, and executors
|
|
@@ -972,5 +1075,5 @@ declare namespace t {
|
|
|
972
1075
|
type infer<T> = TailorOutput<T>;
|
|
973
1076
|
}
|
|
974
1077
|
//#endregion
|
|
975
|
-
export {
|
|
976
|
-
//# sourceMappingURL=index-
|
|
1078
|
+
export { resolverExecutedTrigger as $, IdpUserArgs as A, TailorDBTrigger as B, ScheduleTrigger as C, AuthAccessTokenRefreshedArgs as D, AuthAccessTokenIssuedArgs as E, RecordCreatedArgs as F, idpUserCreatedTrigger as G, authAccessTokenRefreshedTrigger as H, RecordDeletedArgs as I, idpUserUpdatedTrigger as J, idpUserDeletedTrigger as K, RecordUpdatedArgs as L, IdpUserDeletedArgs as M, IdpUserTrigger as N, AuthAccessTokenRevokedArgs as O, IdpUserUpdatedArgs as P, recordUpdatedTrigger as Q, ResolverExecutedArgs as R, ScheduleArgs as S, AuthAccessTokenArgs as T, authAccessTokenRevokedTrigger as U, authAccessTokenIssuedTrigger as V, authAccessTokenTrigger as W, recordDeletedTrigger as X, recordCreatedTrigger as Y, recordTrigger as Z, IncomingWebhookResponse as _, defineAuth as _t, defineGenerators as a, Workflow as at, IncomingWebhookTriggerOptions as b, MachineUserNameRegistry as bt, defineIdp as c, WORKFLOW_TEST_ENV_KEY as ct, unsafeAllowAllIdPPermission as d, WorkflowJobInput as dt, FunctionOperation as et, defineStaticWebSite as f, WorkflowJobOutput as ft, IncomingWebhookRequest as g, AuthInvoker as gt, IncomingWebhookArgs as h, createResolver as ht, defineConfig as i, WorkflowOperation as it, IdpUserCreatedArgs as j, AuthAccessTokenTrigger as k, IdPPermission as l, WorkflowJob as lt, Trigger as m, QueryType as mt, output as n, Operation as nt, definePlugins as o, WorkflowConfig as ot, createExecutor as p, createWorkflowJob as pt, idpUserTrigger as q, t as r, WebhookOperation as rt, defineSecretManager as s, createWorkflow as st, infer as t, GqlOperation as tt, IdPPermissionCondition as u, WorkflowJobContext as ut, IncomingWebhookResponseConfig as v, TailorField as vt, scheduleTrigger as w, incomingWebhookTrigger as x, IncomingWebhookTrigger as y, MachineUserName as yt, ResolverExecutedTrigger as z };
|
|
1079
|
+
//# sourceMappingURL=index-BYmdVno1.d.mts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference types="@tailor-platform/function-types" />
|
|
2
|
-
import {
|
|
2
|
+
import { o as Plugin } from "./tailor-db-field-B99RnR2N.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/plugin/builtin/kysely-type/index.d.ts
|
|
5
5
|
/** Unique identifier for the Kysely type generator plugin. */
|
|
@@ -16,4 +16,4 @@ type KyselyTypePluginOptions = {
|
|
|
16
16
|
declare function kyselyTypePlugin(options: KyselyTypePluginOptions): Plugin<unknown, KyselyTypePluginOptions>;
|
|
17
17
|
//#endregion
|
|
18
18
|
export { kyselyTypePlugin as n, KyselyGeneratorID as t };
|
|
19
|
-
//# sourceMappingURL=index-
|
|
19
|
+
//# sourceMappingURL=index-CeFwhUkX.d.mts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference types="@tailor-platform/function-types" />
|
|
2
|
-
import {
|
|
2
|
+
import { o as Plugin } from "./tailor-db-field-B99RnR2N.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/plugin/builtin/seed/index.d.ts
|
|
5
5
|
/** Unique identifier for the seed generator plugin. */
|
|
@@ -18,4 +18,4 @@ type SeedPluginOptions = {
|
|
|
18
18
|
declare function seedPlugin(options: SeedPluginOptions): Plugin<unknown, SeedPluginOptions>;
|
|
19
19
|
//#endregion
|
|
20
20
|
export { seedPlugin as n, SeedGeneratorID as t };
|
|
21
|
-
//# sourceMappingURL=index-
|
|
21
|
+
//# sourceMappingURL=index-Ch8Em3nz.d.mts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference types="@tailor-platform/function-types" />
|
|
2
|
-
import {
|
|
2
|
+
import { o as Plugin } from "./tailor-db-field-B99RnR2N.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/plugin/builtin/file-utils/index.d.ts
|
|
5
5
|
/** Unique identifier for the file utilities generator plugin. */
|
|
@@ -16,4 +16,4 @@ type FileUtilsPluginOptions = {
|
|
|
16
16
|
declare function fileUtilsPlugin(options: FileUtilsPluginOptions): Plugin<unknown, FileUtilsPluginOptions>;
|
|
17
17
|
//#endregion
|
|
18
18
|
export { fileUtilsPlugin as n, FileUtilsGeneratorID as t };
|
|
19
|
-
//# sourceMappingURL=index-
|
|
19
|
+
//# sourceMappingURL=index-Cx1RYDbu.d.mts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference types="@tailor-platform/function-types" />
|
|
2
|
-
import {
|
|
2
|
+
import { o as Plugin } from "./tailor-db-field-B99RnR2N.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/plugin/builtin/enum-constants/index.d.ts
|
|
5
5
|
/** Unique identifier for the enum constants generator plugin. */
|
|
@@ -16,4 +16,4 @@ type EnumConstantsPluginOptions = {
|
|
|
16
16
|
declare function enumConstantsPlugin(options: EnumConstantsPluginOptions): Plugin<unknown, EnumConstantsPluginOptions>;
|
|
17
17
|
//#endregion
|
|
18
18
|
export { enumConstantsPlugin as n, EnumConstantsGeneratorID as t };
|
|
19
|
-
//# sourceMappingURL=index-
|
|
19
|
+
//# sourceMappingURL=index-DLO_XvLi.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interceptor-
|
|
1
|
+
{"version":3,"file":"interceptor-B5bKVwgq.mjs","names":[],"sources":["../src/cli/telemetry/interceptor.ts"],"sourcesContent":["import { trace, SpanStatusCode } from \"@opentelemetry/api\";\nimport type { Interceptor } from \"@connectrpc/connect\";\n\n/**\n * Create a Connect-RPC interceptor that records OTLP spans for each RPC call.\n * When no TracerProvider is registered, the OTel API automatically provides\n * noop spans with zero overhead.\n * @returns Tracing interceptor\n */\nexport function createTracingInterceptor(): Interceptor {\n return (next) => async (req) => {\n const tracer = trace.getTracer(\"tailor-sdk\");\n\n return tracer.startActiveSpan(`rpc.${req.method.name}`, async (span) => {\n span.setAttribute(\"rpc.method\", req.method.name);\n span.setAttribute(\"rpc.service\", \"OperatorService\");\n span.setAttribute(\"rpc.system\", \"connect-rpc\");\n\n try {\n const response = await next(req);\n span.setStatus({ code: SpanStatusCode.OK });\n return response;\n } catch (error) {\n span.setStatus({ code: SpanStatusCode.ERROR });\n if (error instanceof Error) {\n span.recordException(error);\n }\n throw error;\n } finally {\n span.end();\n }\n });\n };\n}\n"],"mappings":";;;;;;;;;;AASA,SAAgB,2BAAwC;AACtD,SAAQ,SAAS,OAAO,QAAQ;AAG9B,SAFe,MAAM,UAAU,aAAa,CAE9B,gBAAgB,OAAO,IAAI,OAAO,QAAQ,OAAO,SAAS;AACtE,QAAK,aAAa,cAAc,IAAI,OAAO,KAAK;AAChD,QAAK,aAAa,eAAe,kBAAkB;AACnD,QAAK,aAAa,cAAc,cAAc;AAE9C,OAAI;IACF,MAAM,WAAW,MAAM,KAAK,IAAI;AAChC,SAAK,UAAU,EAAE,MAAM,eAAe,IAAI,CAAC;AAC3C,WAAO;YACA,OAAO;AACd,SAAK,UAAU,EAAE,MAAM,eAAe,OAAO,CAAC;AAC9C,QAAI,iBAAiB,MACnB,MAAK,gBAAgB,MAAM;AAE7B,UAAM;aACE;AACR,SAAK,KAAK;;IAEZ"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
import { t as brandValue } from "./brand-
|
|
2
|
+
import { t as brandValue } from "./brand-Ll48SMXe.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/configure/services/workflow/job.ts
|
|
5
5
|
/**
|
|
@@ -51,4 +51,4 @@ const createWorkflowJob = (config) => {
|
|
|
51
51
|
|
|
52
52
|
//#endregion
|
|
53
53
|
export { createWorkflowJob as n, WORKFLOW_TEST_ENV_KEY as t };
|
|
54
|
-
//# sourceMappingURL=job-
|
|
54
|
+
//# sourceMappingURL=job-p6zf8Qpg.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"job-p6zf8Qpg.mjs","names":[],"sources":["../src/configure/services/workflow/job.ts"],"sourcesContent":["import { brandValue } from \"@/utils/brand\";\nimport type { TailorEnv } from \"@/types/env\";\nimport type { JsonCompatible } from \"@/types/helpers\";\nimport type { Jsonifiable, Jsonify, JsonPrimitive } from \"type-fest\";\n\n/**\n * Context object passed as the second argument to workflow job body functions.\n */\nexport type WorkflowJobContext = {\n env: TailorEnv;\n};\n\n/**\n * Allowed output types for workflow job body functions.\n * Includes Jsonifiable (JSON-serializable values including objects with toJSON like Date),\n * undefined, and void.\n */\nexport type WorkflowJobOutput = Jsonifiable | undefined | void;\n\n/**\n * Convert output type to what trigger returns after JSON serialization.\n * - Jsonifiable values are converted via Jsonify (Date -> string, etc.)\n * - undefined remains undefined\n * - void becomes void\n */\ntype JsonifyOutput<T> = T extends Jsonifiable ? Jsonify<T> : T;\n\n/**\n * Input type constraint for workflow jobs.\n * Accepts any type that is JSON-compatible (primitives, arrays, objects with JSON-compatible values).\n * Excludes objects with toJSON method (like Date) since they won't be serialized in input.\n */\nexport type WorkflowJobInput = undefined | JsonCompatible<unknown>;\n\n/**\n * WorkflowJob represents a job that can be triggered in a workflow.\n *\n * Type constraints:\n * - Input: Must be JSON-compatible (no Date/toJSON objects) or undefined. Interfaces are allowed.\n * - Output: Must be Jsonifiable, undefined, or void\n * - Trigger returns Jsonify<Output> (Date becomes string after JSON.stringify)\n */\nexport interface WorkflowJob<Name extends string = string, Input = undefined, Output = undefined> {\n name: Name;\n /**\n * Trigger this job with the given input.\n * At runtime, this is a placeholder that calls the body function.\n * During bundling, calls to .trigger() are transformed to\n * tailor.workflow.triggerJobFunction(\"<job-name>\", args).\n *\n * Returns Jsonify<Output> because the value passes through JSON.stringify.\n *\n * Inside a workflow job body, .trigger() calls are transformed by the bundler\n * into synchronous `triggerJobFunction` calls. You may use `await` for\n * readability — the bundler strips it automatically at build time.\n * @example\n * // Both styles work — await is stripped by the bundler:\n * body: async (input) => {\n * const a = await jobA.trigger({ id: input.id });\n * const b = await jobB.trigger({ id: input.id });\n * return { a, b };\n * }\n */\n trigger: [Input] extends [undefined]\n ? () => Promise<JsonifyOutput<Awaited<Output>>>\n : (input: Input) => Promise<JsonifyOutput<Awaited<Output>>>;\n body: (input: Input, context: WorkflowJobContext) => Output | Promise<Output>;\n}\n\n/**\n * Helper type to check if all property types are valid.\n * Uses -? to remove optional modifiers so all properties are treated uniformly.\n */\ntype AllPropertiesValid<T> = {\n [K in keyof T]-?: IsValidInput<T[K]> extends true ? true : false;\n}[keyof T] extends true\n ? true\n : false;\n\n/**\n * Check if a type contains any non-JSON-compatible values.\n * Returns `true` if the type is valid for input, `false` otherwise.\n *\n * Accepts:\n * - JSON primitives (string, number, boolean, null)\n * - undefined\n * - Optional primitives (e.g., string | undefined)\n * - Arrays of valid types\n * - Objects with valid field types\n *\n * Rejects:\n * - Objects with toJSON methods (like Date)\n * - Other non-JSON-serializable types\n */\ntype IsValidInput<T> = T extends undefined\n ? true\n : T extends JsonPrimitive\n ? true\n : T extends readonly (infer U)[]\n ? IsValidInput<U>\n : T extends object\n ? T extends { toJSON: () => unknown }\n ? false\n : AllPropertiesValid<T>\n : false;\n\n/**\n * Helper type to check if all property types are valid for output.\n * Uses -? to remove optional modifiers so all properties are treated uniformly.\n */\ntype AllPropertiesValidOutput<T> = {\n [K in keyof T]-?: IsValidOutput<T[K]> extends true ? true : false;\n}[keyof T] extends true\n ? true\n : false;\n\n/**\n * Check if a type is valid for output.\n * Returns `true` if the type is valid, `false` otherwise.\n *\n * Accepts:\n * - JSON primitives (string, number, boolean, null)\n * - undefined and void\n * - Optional primitives (e.g., string | undefined)\n * - Jsonifiable types (Date, objects with toJSON)\n * - Arrays of valid types\n * - Objects with valid field types\n */\ntype IsValidOutput<T> = T extends undefined | void\n ? true\n : T extends JsonPrimitive\n ? true\n : T extends readonly (infer U)[]\n ? IsValidOutput<U>\n : T extends object\n ? AllPropertiesValidOutput<T>\n : false;\n\n/**\n * Body function type with conditional constraint.\n * If input contains invalid types (like Date), the body type becomes `never` to cause an error.\n */\ntype WorkflowJobBody<I, O> =\n IsValidInput<I> extends true\n ? IsValidOutput<O> extends true\n ? (input: I, context: WorkflowJobContext) => O | Promise<O>\n : never\n : never;\n\n/**\n * Environment variable key for workflow testing.\n * Contains JSON-serialized TailorEnv object.\n */\nexport const WORKFLOW_TEST_ENV_KEY = \"TAILOR_TEST_WORKFLOW_ENV\";\n\n/**\n * Create a workflow job definition.\n *\n * All jobs must be named exports from the workflow file.\n * Job names must be unique across the entire project.\n * @param config - Job configuration with name and body function\n * @param config.name - Unique job name across the project\n * @param config.body - Async function that processes the job input\n * @returns A WorkflowJob that can be triggered from other jobs\n * @example\n * // Simple job with async body:\n * export const fetchData = createWorkflowJob({\n * name: \"fetch-data\",\n * body: async (input: { id: string }) => {\n * const db = getDB(\"tailordb\");\n * return await db.selectFrom(\"Table\").selectAll().where(\"id\", \"=\", input.id).executeTakeFirst();\n * },\n * });\n * @example\n * // Orchestrator job that fans out to other jobs.\n * // await is optional — the bundler strips it at build time.\n * export const orchestrate = createWorkflowJob({\n * name: \"orchestrate\",\n * body: async (input: { orderId: string }) => {\n * const inventory = await checkInventory.trigger({ orderId: input.orderId });\n * const payment = await processPayment.trigger({ orderId: input.orderId });\n * return { inventory, payment };\n * },\n * });\n */\nexport const createWorkflowJob = <const Name extends string, I = undefined, O = undefined>(config: {\n readonly name: Name;\n readonly body: WorkflowJobBody<I, O>;\n}): WorkflowJob<Name, I, Awaited<O>> => {\n return brandValue(\n {\n name: config.name,\n // JSON.parse(JSON.stringify(...)) ensures the return value matches Jsonify<Output> type.\n // This converts Date objects to strings, matching actual runtime behavior.\n // In production, bundler transforms .trigger() calls to tailor.workflow.triggerJobFunction().\n trigger: async (args?: unknown) => {\n const env: TailorEnv = JSON.parse(process.env[WORKFLOW_TEST_ENV_KEY] || \"{}\");\n const result = await config.body(args as I, { env });\n return result ? JSON.parse(JSON.stringify(result)) : result;\n },\n body: config.body,\n } as WorkflowJob<Name, I, Awaited<O>>,\n \"workflow-job\",\n );\n};\n"],"mappings":";;;;;;;;AAyJA,MAAa,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCrC,MAAa,qBAA8E,WAGnD;AACtC,QAAO,WACL;EACE,MAAM,OAAO;EAIb,SAAS,OAAO,SAAmB;GACjC,MAAM,MAAiB,KAAK,MAAM,QAAQ,mCAA8B,KAAK;GAC7E,MAAM,SAAS,MAAM,OAAO,KAAK,MAAW,EAAE,KAAK,CAAC;AACpD,UAAO,SAAS,KAAK,MAAM,KAAK,UAAU,OAAO,CAAC,GAAG;;EAEvD,MAAM,OAAO;EACd,EACD,eACD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger-5_JMzHmw.mjs","names":[],"sources":["../src/cli/shared/parse-boolean.ts","../src/cli/shared/logger.ts"],"sourcesContent":["const TRUTHY_VALUES = new Set([\"true\", \"t\", \"yes\", \"y\", \"on\", \"1\"]);\nconst FALSY_VALUES = new Set([\"false\", \"f\", \"no\", \"n\", \"off\", \"0\"]);\n\n/**\n * Parse a string value as a boolean.\n *\n * Recognized values (case-insensitive, trimmed) follow Python's\n * `distutils.util.strtobool` convention:\n * - truthy: `true, t, yes, y, on, 1`\n * - falsy: `false, f, no, n, off, 0`\n *\n * Undefined, empty strings, and unrecognized values return `undefined` so\n * that callers can fall back to their own defaults.\n * @param value - The input string (e.g. an environment variable or CLI flag value)\n * @returns `true`, `false`, or `undefined` when the value is unset or unrecognized\n */\nexport function parseBoolean(value: string | undefined): boolean | undefined {\n if (value === undefined) return undefined;\n const normalized = value.trim().toLowerCase();\n if (normalized === \"\") return undefined;\n if (TRUTHY_VALUES.has(normalized)) return true;\n if (FALSY_VALUES.has(normalized)) return false;\n return undefined;\n}\n","import { formatWithOptions, type InspectOptions } from \"node:util\";\nimport chalk from \"chalk\";\nimport { formatDistanceToNowStrict } from \"date-fns\";\nimport { getBorderCharacters, table } from \"table\";\nimport { parseBoolean } from \"./parse-boolean\";\n\n/**\n * Error thrown when a prompt is attempted in a CI environment\n */\nexport class CIPromptError extends Error {\n constructor(message?: string) {\n super(\n message ??\n \"Interactive prompts are not available in CI environments. Use --yes flag to skip confirmation prompts.\",\n );\n this.name = \"CIPromptError\";\n }\n}\n\n/**\n * Semantic style functions for inline text styling\n */\nexport const styles = {\n // Status colors\n success: chalk.green,\n error: chalk.red,\n warning: chalk.yellow,\n info: chalk.cyan,\n\n // Action colors (for change sets)\n create: chalk.green,\n update: chalk.yellow,\n delete: chalk.red,\n unchanged: chalk.gray,\n\n // Emphasis\n bold: chalk.bold,\n dim: chalk.gray,\n highlight: chalk.cyanBright,\n successBright: chalk.greenBright,\n errorBright: chalk.redBright,\n\n // Resource types\n resourceType: chalk.bold,\n resourceName: chalk.cyan,\n\n // File paths\n path: chalk.cyan,\n\n // Values\n value: chalk.white,\n placeholder: chalk.gray.italic,\n};\n\n/**\n * Standardized symbols for CLI output\n */\nexport const symbols = {\n success: chalk.green(\"\\u2713\"),\n error: chalk.red(\"\\u2716\"),\n warning: chalk.yellow(\"\\u26a0\"),\n info: chalk.cyan(\"i\"),\n create: chalk.green(\"+\"),\n update: chalk.yellow(\"~\"),\n delete: chalk.red(\"-\"),\n replace: chalk.magenta(\"\\u00b1\"),\n bullet: chalk.gray(\"\\u2022\"),\n arrow: chalk.gray(\"\\u2192\"),\n};\n\n/**\n * Log output modes\n */\nexport type LogMode = \"default\" | \"stream\" | \"plain\";\n\nexport interface LogOptions {\n /** Output mode (default: \"default\") */\n mode?: LogMode;\n /** Number of spaces to indent the entire line (default: 0) */\n indent?: number;\n}\n\n/** Field transformer function. null excludes the field from table output. */\nexport type FieldTransformer = ((value: unknown, item: object) => string) | null;\n\nexport interface OutOptions {\n /** Table display field transform/exclude settings. Only applied in table mode (not JSON). */\n display?: Record<string, FieldTransformer>;\n\n /** Show null values in table output (default: false) */\n showNull?: boolean;\n}\n\n// In JSON mode, all logs go to stderr to keep stdout clean for JSON data\nlet _jsonMode = false;\n\n// Type icons for log output\nconst TYPE_ICONS: Record<string, string> = {\n info: \"ℹ\",\n success: \"✔\",\n warn: \"⚠\",\n error: \"✖\",\n debug: \"⚙\",\n trace: \"→\",\n log: \"\",\n};\n\n// Color functions for icon and message text\nconst TYPE_COLORS: Record<string, (text: string) => string> = {\n info: chalk.cyan,\n success: chalk.green,\n warn: chalk.yellow,\n error: chalk.red,\n debug: chalk.gray,\n trace: chalk.gray,\n log: (text) => text,\n};\n\ninterface FormatLogLineOptions {\n mode: string;\n indent: number;\n type: string;\n message: string;\n timestamp?: string;\n}\n\n/**\n * Formats a log line with the appropriate prefix and indentation\n * @param opts - Formatting options\n * @returns Formatted log line\n */\nexport function formatLogLine(opts: FormatLogLineOptions): string {\n const { mode, indent, type, message, timestamp } = opts;\n const indentPrefix = indent > 0 ? \" \".repeat(indent) : \"\";\n const colorFn = TYPE_COLORS[type] || ((text: string) => text);\n\n // Plain mode: color only, no icon, no timestamp\n if (mode === \"plain\") {\n return `${indentPrefix}${colorFn(message)}\\n`;\n }\n\n // Default/Stream mode: with icon and color\n const icon = TYPE_ICONS[type] || \"\";\n const prefix = icon ? `${icon} ` : \"\";\n const coloredOutput = colorFn(`${prefix}${message}`);\n const timestampPrefix = timestamp ?? \"\";\n\n return `${indentPrefix}${timestampPrefix}${coloredOutput}\\n`;\n}\n\n/**\n * Writes a formatted log line to stderr.\n * @param type - Log type (info, success, warn, error, log)\n * @param message - Log message\n * @param opts - Log options (mode and indent)\n */\nfunction writeLog(type: string, message: string, opts?: LogOptions): void {\n const mode = opts?.mode ?? \"default\";\n const indent = opts?.indent ?? 0;\n const inspectOpts: InspectOptions = {\n breakLength: process.stdout.columns || 80,\n };\n const formattedMessage = formatWithOptions(inspectOpts, message);\n const timestamp = mode === \"stream\" ? `${new Date().toLocaleTimeString()} ` : \"\";\n const output = formatLogLine({ mode, indent, type, message: formattedMessage, timestamp });\n process.stderr.write(output);\n}\n\nexport const logger = {\n get jsonMode(): boolean {\n return _jsonMode;\n },\n set jsonMode(value: boolean) {\n _jsonMode = value;\n },\n\n info(message: string, opts?: LogOptions): void {\n writeLog(\"info\", message, opts);\n },\n\n success(message: string, opts?: LogOptions): void {\n writeLog(\"success\", message, opts);\n },\n\n warn(message: string, opts?: LogOptions): void {\n writeLog(\"warn\", message, opts);\n },\n\n error(message: string, opts?: LogOptions): void {\n writeLog(\"error\", message, opts);\n },\n\n log(message: string): void {\n writeLog(\"log\", message, { mode: \"plain\" });\n },\n\n newline(): void {\n process.stderr.write(\"\\n\");\n },\n\n debug(message: string): void {\n if (parseBoolean(process.env.DEBUG) === true) {\n writeLog(\"log\", styles.dim(message), { mode: \"plain\" });\n }\n },\n\n out(data: string | object | object[], options?: OutOptions): void {\n if (typeof data === \"string\") {\n process.stdout.write(data.endsWith(\"\\n\") ? data : data + \"\\n\");\n return;\n }\n\n if (this.jsonMode) {\n // eslint-disable-next-line no-restricted-syntax\n console.log(JSON.stringify(data));\n return;\n }\n\n const display = options?.display;\n\n // Helper to format a value for table display\n const formatValue = (value: unknown, pretty = false): string => {\n if (options?.showNull && value === null) return \"NULL\";\n if (value === null || value === undefined) return \"N/A\";\n if (value instanceof Date) {\n return formatDistanceToNowStrict(value, { addSuffix: true });\n }\n if (typeof value === \"object\") {\n return pretty ? JSON.stringify(value, null, 2) : JSON.stringify(value);\n }\n return String(value);\n };\n\n // Helper to check if field should be excluded\n const isExcluded = (key: string): boolean => {\n return display !== undefined && key in display && display[key] === null;\n };\n\n // Helper to apply transformer or default formatting\n const transformValue = (key: string, value: unknown, item: object, pretty = false): string => {\n if (display && key in display) {\n const transformer = display[key];\n if (transformer) {\n return transformer(value, item);\n }\n }\n return formatValue(value, pretty);\n };\n\n if (!Array.isArray(data)) {\n const entries = Object.entries(data).filter(([key]) => !isExcluded(key));\n const formattedEntries = entries.map(([key, value]) => [\n key,\n transformValue(key, value, data, true),\n ]);\n const t = table(formattedEntries, {\n singleLine: false,\n border: getBorderCharacters(\"norc\"),\n });\n process.stdout.write(t);\n return;\n }\n\n if (data.length === 0) {\n return;\n }\n\n const allHeaders = Array.from(new Set(data.flatMap((item) => Object.keys(item))));\n const headers = allHeaders.filter((h) => !isExcluded(h));\n const rows = data.map((item) =>\n headers.map((header) =>\n transformValue(header, (item as Record<string, unknown>)[header], item),\n ),\n );\n\n const t = table([headers, ...rows], {\n border: getBorderCharacters(\"norc\"),\n drawHorizontalLine: (lineIndex, rowCount) => {\n return lineIndex === 0 || lineIndex === 1 || lineIndex === rowCount;\n },\n });\n process.stdout.write(t);\n },\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"logger-DTNAMYGy.mjs","names":[],"sources":["../src/cli/shared/parse-boolean.ts","../src/cli/shared/logger.ts"],"sourcesContent":["const TRUTHY_VALUES = new Set([\"true\", \"t\", \"yes\", \"y\", \"on\", \"1\"]);\nconst FALSY_VALUES = new Set([\"false\", \"f\", \"no\", \"n\", \"off\", \"0\"]);\n\n/**\n * Parse a string value as a boolean.\n *\n * Recognized values (case-insensitive, trimmed) follow Python's\n * `distutils.util.strtobool` convention:\n * - truthy: `true, t, yes, y, on, 1`\n * - falsy: `false, f, no, n, off, 0`\n *\n * Undefined, empty strings, and unrecognized values return `undefined` so\n * that callers can fall back to their own defaults.\n * @param value - The input string (e.g. an environment variable or CLI flag value)\n * @returns `true`, `false`, or `undefined` when the value is unset or unrecognized\n */\nexport function parseBoolean(value: string | undefined): boolean | undefined {\n if (value === undefined) return undefined;\n const normalized = value.trim().toLowerCase();\n if (normalized === \"\") return undefined;\n if (TRUTHY_VALUES.has(normalized)) return true;\n if (FALSY_VALUES.has(normalized)) return false;\n return undefined;\n}\n","import { formatWithOptions, type InspectOptions } from \"node:util\";\nimport chalk from \"chalk\";\nimport { formatDistanceToNowStrict } from \"date-fns\";\nimport { getBorderCharacters, table } from \"table\";\nimport { parseBoolean } from \"./parse-boolean\";\n\n/**\n * Error thrown when a prompt is attempted in a CI environment\n */\nexport class CIPromptError extends Error {\n constructor(message?: string) {\n super(\n message ??\n \"Interactive prompts are not available in CI environments. Use --yes flag to skip confirmation prompts.\",\n );\n this.name = \"CIPromptError\";\n }\n}\n\n/**\n * Semantic style functions for inline text styling\n */\nexport const styles = {\n // Status colors\n success: chalk.green,\n error: chalk.red,\n warning: chalk.yellow,\n info: chalk.cyan,\n\n // Action colors (for change sets)\n create: chalk.green,\n update: chalk.yellow,\n delete: chalk.red,\n unchanged: chalk.gray,\n\n // Emphasis\n bold: chalk.bold,\n dim: chalk.gray,\n highlight: chalk.cyanBright,\n successBright: chalk.greenBright,\n errorBright: chalk.redBright,\n\n // Resource types\n resourceType: chalk.bold,\n resourceName: chalk.cyan,\n\n // File paths\n path: chalk.cyan,\n\n // Values\n value: chalk.white,\n placeholder: chalk.gray.italic,\n};\n\n/**\n * Standardized symbols for CLI output\n */\nexport const symbols = {\n success: chalk.green(\"\\u2713\"),\n error: chalk.red(\"\\u2716\"),\n warning: chalk.yellow(\"\\u26a0\"),\n info: chalk.cyan(\"i\"),\n create: chalk.green(\"+\"),\n update: chalk.yellow(\"~\"),\n delete: chalk.red(\"-\"),\n replace: chalk.magenta(\"\\u00b1\"),\n bullet: chalk.gray(\"\\u2022\"),\n arrow: chalk.gray(\"\\u2192\"),\n};\n\n/**\n * Log output modes\n */\nexport type LogMode = \"default\" | \"stream\" | \"plain\";\n\nexport interface LogOptions {\n /** Output mode (default: \"default\") */\n mode?: LogMode;\n /** Number of spaces to indent the entire line (default: 0) */\n indent?: number;\n}\n\n/** Field transformer function. null excludes the field from table output. */\nexport type FieldTransformer = ((value: unknown, item: object) => string) | null;\n\nexport interface OutOptions {\n /** Table display field transform/exclude settings. Only applied in table mode (not JSON). */\n display?: Record<string, FieldTransformer>;\n\n /** Show null values in table output (default: false) */\n showNull?: boolean;\n}\n\n// In JSON mode, all logs go to stderr to keep stdout clean for JSON data\nlet _jsonMode = false;\n\n// Type icons for log output\nconst TYPE_ICONS: Record<string, string> = {\n info: \"ℹ\",\n success: \"✔\",\n warn: \"⚠\",\n error: \"✖\",\n debug: \"⚙\",\n trace: \"→\",\n log: \"\",\n};\n\n// Color functions for icon and message text\nconst TYPE_COLORS: Record<string, (text: string) => string> = {\n info: chalk.cyan,\n success: chalk.green,\n warn: chalk.yellow,\n error: chalk.red,\n debug: chalk.gray,\n trace: chalk.gray,\n log: (text) => text,\n};\n\ninterface FormatLogLineOptions {\n mode: string;\n indent: number;\n type: string;\n message: string;\n timestamp?: string;\n}\n\n/**\n * Formats a log line with the appropriate prefix and indentation\n * @param opts - Formatting options\n * @returns Formatted log line\n */\nexport function formatLogLine(opts: FormatLogLineOptions): string {\n const { mode, indent, type, message, timestamp } = opts;\n const indentPrefix = indent > 0 ? \" \".repeat(indent) : \"\";\n const colorFn = TYPE_COLORS[type] || ((text: string) => text);\n\n // Plain mode: color only, no icon, no timestamp\n if (mode === \"plain\") {\n return `${indentPrefix}${colorFn(message)}\\n`;\n }\n\n // Default/Stream mode: with icon and color\n const icon = TYPE_ICONS[type] || \"\";\n const prefix = icon ? `${icon} ` : \"\";\n const coloredOutput = colorFn(`${prefix}${message}`);\n const timestampPrefix = timestamp ?? \"\";\n\n return `${indentPrefix}${timestampPrefix}${coloredOutput}\\n`;\n}\n\n/**\n * Writes a formatted log line to stderr.\n * @param type - Log type (info, success, warn, error, log)\n * @param message - Log message\n * @param opts - Log options (mode and indent)\n */\nfunction writeLog(type: string, message: string, opts?: LogOptions): void {\n const mode = opts?.mode ?? \"default\";\n const indent = opts?.indent ?? 0;\n const inspectOpts: InspectOptions = {\n breakLength: process.stdout.columns || 80,\n };\n const formattedMessage = formatWithOptions(inspectOpts, message);\n const timestamp = mode === \"stream\" ? `${new Date().toLocaleTimeString()} ` : \"\";\n const output = formatLogLine({ mode, indent, type, message: formattedMessage, timestamp });\n process.stderr.write(output);\n}\n\nexport const logger = {\n get jsonMode(): boolean {\n return _jsonMode;\n },\n set jsonMode(value: boolean) {\n _jsonMode = value;\n },\n\n info(message: string, opts?: LogOptions): void {\n writeLog(\"info\", message, opts);\n },\n\n success(message: string, opts?: LogOptions): void {\n writeLog(\"success\", message, opts);\n },\n\n warn(message: string, opts?: LogOptions): void {\n writeLog(\"warn\", message, opts);\n },\n\n error(message: string, opts?: LogOptions): void {\n writeLog(\"error\", message, opts);\n },\n\n log(message: string): void {\n writeLog(\"log\", message, { mode: \"plain\" });\n },\n\n newline(): void {\n process.stderr.write(\"\\n\");\n },\n\n debug(message: string): void {\n if (parseBoolean(process.env.DEBUG) === true) {\n writeLog(\"log\", styles.dim(message), { mode: \"plain\" });\n }\n },\n\n out(data: string | object | object[], options?: OutOptions): void {\n if (typeof data === \"string\") {\n process.stdout.write(data.endsWith(\"\\n\") ? data : data + \"\\n\");\n return;\n }\n\n if (this.jsonMode) {\n // eslint-disable-next-line no-restricted-syntax\n console.log(JSON.stringify(data));\n return;\n }\n\n const display = options?.display;\n\n // Helper to format a value for table display\n const formatValue = (value: unknown, pretty = false): string => {\n if (options?.showNull && value === null) return \"NULL\";\n if (value === null || value === undefined) return \"N/A\";\n if (value instanceof Date) {\n return formatDistanceToNowStrict(value, { addSuffix: true });\n }\n if (typeof value === \"object\") {\n return pretty ? JSON.stringify(value, null, 2) : JSON.stringify(value);\n }\n return String(value);\n };\n\n // Helper to check if field should be excluded\n const isExcluded = (key: string): boolean => {\n return display !== undefined && key in display && display[key] === null;\n };\n\n // Helper to apply transformer or default formatting\n const transformValue = (key: string, value: unknown, item: object, pretty = false): string => {\n if (display && key in display) {\n const transformer = display[key];\n if (transformer) {\n return transformer(value, item);\n }\n }\n return formatValue(value, pretty);\n };\n\n if (!Array.isArray(data)) {\n const entries = Object.entries(data).filter(([key]) => !isExcluded(key));\n const formattedEntries = entries.map(([key, value]) => [\n key,\n transformValue(key, value, data, true),\n ]);\n const t = table(formattedEntries, {\n singleLine: false,\n border: getBorderCharacters(\"norc\"),\n });\n process.stdout.write(t);\n return;\n }\n\n if (data.length === 0) {\n return;\n }\n\n const allHeaders = Array.from(new Set(data.flatMap((item) => Object.keys(item))));\n const headers = allHeaders.filter((h) => !isExcluded(h));\n const rows = data.map((item) =>\n headers.map((header) =>\n transformValue(header, (item as Record<string, unknown>)[header], item),\n ),\n );\n\n const t = table([headers, ...rows], {\n border: getBorderCharacters(\"norc\"),\n drawHorizontalLine: (lineIndex, rowCount) => {\n return lineIndex === 0 || lineIndex === 1 || lineIndex === rowCount;\n },\n });\n process.stdout.write(t);\n },\n};\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"package-json-
|
|
1
|
+
{"version":3,"file":"package-json-CWp8s9dE.mjs","names":[],"sources":["../src/cli/shared/package-json.ts"],"sourcesContent":["import { readPackageJSON, type PackageJson } from \"pkg-types\";\n\nlet packageJson: PackageJson | null = null;\n\n/**\n * Read and cache the package.json of the SDK package.\n * @returns Parsed package.json contents\n */\nexport async function readPackageJson() {\n if (packageJson) {\n return packageJson;\n }\n packageJson = await readPackageJSON(import.meta.url);\n return packageJson;\n}\n"],"mappings":";;;;AAEA,IAAI,cAAkC;;;;;AAMtC,eAAsB,kBAAkB;AACtC,KAAI,YACF,QAAO;AAET,eAAc,MAAM,gBAAgB,OAAO,KAAK,IAAI;AACpD,QAAO"}
|