@tailor-platform/sdk 1.68.0 → 1.70.0

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.
Files changed (117) hide show
  1. package/CHANGELOG.md +105 -0
  2. package/dist/application-BakHtldG.mjs +4 -0
  3. package/dist/application-Df5_I83n.mjs +6432 -0
  4. package/dist/application-Df5_I83n.mjs.map +1 -0
  5. package/dist/cli/erd-viewer-assets/app.js +279 -36
  6. package/dist/cli/erd-viewer-assets/index.html +4 -0
  7. package/dist/cli/erd-viewer-assets/styles.css +252 -5
  8. package/dist/cli/index.mjs +650 -98
  9. package/dist/cli/index.mjs.map +1 -1
  10. package/dist/cli/lib.d.mts +247 -160
  11. package/dist/cli/lib.mjs +3 -3
  12. package/dist/cli/lib.mjs.map +1 -1
  13. package/dist/cli/skills.mjs +1 -1
  14. package/dist/completion/zsh-worker.zsh +175 -24
  15. package/dist/configure/index.d.mts +5 -5
  16. package/dist/configure/index.mjs +12 -6
  17. package/dist/configure/index.mjs.map +1 -1
  18. package/dist/{crashreport-u9y2npiy.mjs → crashreport-BqyvFk-_.mjs} +2 -2
  19. package/dist/{crashreport-u9y2npiy.mjs.map → crashreport-BqyvFk-_.mjs.map} +1 -1
  20. package/dist/{crashreport-6jpCceOF.mjs → crashreport-BwF8cHF0.mjs} +1 -1
  21. package/dist/enum-constants-C7DaWeQo.mjs.map +1 -1
  22. package/dist/field-C4zdJLW5.mjs.map +1 -1
  23. package/dist/file-utils-BHPxPXmn.mjs.map +1 -1
  24. package/dist/{idp-BlBPtXJ-.d.mts → idp-BmYwCXnJ.d.mts} +30 -3
  25. package/dist/{idp-BZPqpcYY.mjs → idp-ynUfzwpz.mjs} +9 -1
  26. package/dist/idp-ynUfzwpz.mjs.map +1 -0
  27. package/dist/{index-DvEUb3pX.d.mts → index-BAEaAqmz.d.mts} +112 -53
  28. package/dist/{index-CklcVeMG.d.mts → index-C-vsbx27.d.mts} +2 -2
  29. package/dist/{index-hXoO-AOC.d.mts → index-CKI0eZP6.d.mts} +2 -2
  30. package/dist/{index-DYhnxXYR.d.mts → index-CrqOgUF2.d.mts} +2 -2
  31. package/dist/{index-DlDRSzFZ.d.mts → index-DESLU9kI.d.mts} +2 -2
  32. package/dist/{index-DRhMpdnA.d.mts → index-dKNk8hjo.d.mts} +2 -2
  33. package/dist/job-BpsFXPbi.mjs.map +1 -1
  34. package/dist/{kysely-type-D1e0Vwkd.mjs → kysely-type-CSoZxVKN.mjs} +2 -2
  35. package/dist/{kysely-type-D1e0Vwkd.mjs.map → kysely-type-CSoZxVKN.mjs.map} +1 -1
  36. package/dist/{logger-DpJyJvNz.mjs → logger-DKF-JsAK.mjs} +3 -3
  37. package/dist/{logger-DpJyJvNz.mjs.map → logger-DKF-JsAK.mjs.map} +1 -1
  38. package/dist/{mock-DMgIygjE.mjs → mock-wf5qeZLi.mjs} +19 -9
  39. package/dist/mock-wf5qeZLi.mjs.map +1 -0
  40. package/dist/plugin/builtin/enum-constants/index.d.mts +1 -1
  41. package/dist/plugin/builtin/file-utils/index.d.mts +1 -1
  42. package/dist/plugin/builtin/kysely-type/index.d.mts +1 -1
  43. package/dist/plugin/builtin/kysely-type/index.mjs +1 -1
  44. package/dist/plugin/builtin/seed/index.d.mts +1 -1
  45. package/dist/plugin/index.d.mts +1 -1
  46. package/dist/plugin/index.mjs.map +1 -1
  47. package/dist/registry-D0uB0OrK.mjs.map +1 -1
  48. package/dist/{repl-editor-CJG3sz7A.mjs → repl-editor-DD5YP5mt.mjs} +4 -4
  49. package/dist/{repl-editor-CJG3sz7A.mjs.map → repl-editor-DD5YP5mt.mjs.map} +1 -1
  50. package/dist/runtime/globals.d.mts +3 -2
  51. package/dist/runtime/idp.d.mts +2 -2
  52. package/dist/runtime/idp.mjs +1 -1
  53. package/dist/runtime/index.d.mts +2 -2
  54. package/dist/runtime/index.mjs +1 -1
  55. package/dist/{runtime-DxaBq6U8.mjs → runtime-CSY0eD4_.mjs} +411 -221
  56. package/dist/runtime-CSY0eD4_.mjs.map +1 -0
  57. package/dist/{schema-1msIhXwA.mjs → schema-C4fkpWV_.mjs} +9 -15
  58. package/dist/schema-C4fkpWV_.mjs.map +1 -0
  59. package/dist/seed-YAbtMy65.mjs.map +1 -1
  60. package/dist/{service-wI3Hvrgx.mjs → service-B2Jd9CxS.mjs} +2 -2
  61. package/dist/service-B2Jd9CxS.mjs.map +1 -0
  62. package/dist/service-CRaa4Joe.mjs +4 -0
  63. package/dist/{service-DMohAx8a.mjs → service-DDWgZL_L2.mjs} +2 -2
  64. package/dist/service-DDWgZL_L2.mjs.map +1 -0
  65. package/dist/service_pb-DGSmn-aF.mjs +4 -0
  66. package/dist/{application-WpWwTyk9.mjs → service_pb-DSNjrcbW.mjs} +22 -6176
  67. package/dist/service_pb-DSNjrcbW.mjs.map +1 -0
  68. package/dist/telemetry-BQbbVo2t.mjs.map +1 -1
  69. package/dist/{types-2Be3wSMc.mjs → types-32lUMToj.mjs} +1 -1
  70. package/dist/{types-CmzfQP_m.mjs → types-D4QMmNWh.mjs} +1 -12
  71. package/dist/types-D4QMmNWh.mjs.map +1 -0
  72. package/dist/{types-Bzr0RQME.d.mts → types-Dynq4AJv.d.mts} +2 -2
  73. package/dist/{types-DZrtN6-H.d.mts → types-rj8YJcEe.d.mts} +5 -2
  74. package/dist/utils/test/index.d.mts +2 -2
  75. package/dist/utils/test/index.mjs.map +1 -1
  76. package/dist/vitest/environment.mjs +1 -1
  77. package/dist/vitest/environment.mjs.map +1 -1
  78. package/dist/vitest/index.mjs +4 -4
  79. package/dist/vitest/index.mjs.map +1 -1
  80. package/dist/vitest/setup.mjs +1 -1
  81. package/dist/{workflow.generated-1S50BhEb.d.mts → workflow.generated-DJULCuRr.d.mts} +274 -174
  82. package/docs/cli/application.md +39 -201
  83. package/docs/cli/auth.md +12 -256
  84. package/docs/cli/completion.md +0 -24
  85. package/docs/cli/crashreport.md +0 -58
  86. package/docs/cli/executor.md +2 -166
  87. package/docs/cli/function.md +2 -118
  88. package/docs/cli/organization.md +1 -211
  89. package/docs/cli/query.md +0 -20
  90. package/docs/cli/secret.md +70 -250
  91. package/docs/cli/setup.md +2 -41
  92. package/docs/cli/skills.md +0 -39
  93. package/docs/cli/staticwebsite.md +24 -172
  94. package/docs/cli/tailordb.md +25 -251
  95. package/docs/cli/upgrade.md +0 -20
  96. package/docs/cli/user.md +41 -246
  97. package/docs/cli/workflow.md +30 -189
  98. package/docs/cli/workspace.md +164 -537
  99. package/docs/cli-reference.md +61 -37
  100. package/docs/configuration.md +7 -1
  101. package/docs/github-actions.md +27 -0
  102. package/docs/multi-environment.md +22 -0
  103. package/docs/services/aigateway.md +4 -2
  104. package/docs/services/http-adapter.md +16 -1
  105. package/docs/services/idp.md +55 -2
  106. package/docs/services/staticwebsite.md +7 -1
  107. package/package.json +23 -18
  108. package/dist/application-Djeezk3m.mjs +0 -4
  109. package/dist/application-WpWwTyk9.mjs.map +0 -1
  110. package/dist/idp-BZPqpcYY.mjs.map +0 -1
  111. package/dist/mock-DMgIygjE.mjs.map +0 -1
  112. package/dist/runtime-DxaBq6U8.mjs.map +0 -1
  113. package/dist/schema-1msIhXwA.mjs.map +0 -1
  114. package/dist/service-BHQIerYh.mjs +0 -4
  115. package/dist/service-DMohAx8a.mjs.map +0 -1
  116. package/dist/service-wI3Hvrgx.mjs.map +0 -1
  117. package/dist/types-CmzfQP_m.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"crashreport-u9y2npiy.mjs","names":[],"sources":["../src/cli/crashreport/config.ts","../src/cli/crashreport/writer.ts","../src/cli/crashreport/sender.ts","../src/cli/crashreport/sanitize.ts","../src/cli/crashreport/report.ts","../src/cli/crashreport/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 { ensureSecretDir, writeSecretFile } from \"@/cli/shared/secret-file\";\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 .toSorted()\n .toReversed();\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 ensureSecretDir(dir);\n\n const filename = generateFilename(report);\n const filePath = path.join(dir, filename);\n const content = formatCrashReport(report);\n\n writeSecretFile(filePath, content);\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 // parseYAML returns null for empty documents\n // oxlint-disable-next-line typescript/no-unnecessary-condition\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 { userAgentFromVersion } from \"@/cli/shared/user-agent\";\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 crashreport send --file \"${filePath}\"`,\n ].join(\"\\n\"),\n );\n }\n }\n\n if (config.remoteEnabled) {\n const ua = userAgentFromVersion(sdkVersion);\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;CAC1D,IAAI,MACF,OAAO;EACL,cAAc;EACd,eAAe;EACf,UAAU;CACZ;CAGF,MAAM,gBAAgB,QAAQ,IAAI,8BAA8B,KAAI,CAAE,YAAY,MAAM;CACxF,MAAM,iBAAiB,QAAQ,IAAI,+BAA+B,MAAK,CAAE,YAAY,MAAM;CAC3F,MAAM,WAAW,YAAY,KAAK,KAAK,WAAW,mBAAmB,eAAe,IAAI;CAExF,OAAO;EACL,cAAc,gBAAgB,aAAa;EAC3C;EACA;CACF;AACF;;;;AC9BA,MAAM,kBAAkB;;AAGxB,MAAa,qBAAqB;;AAGlC,MAAa,sBAAsB;;;;;;AAOnC,SAAgB,kBAAkB,QAA6B;CA2B7D,OAAO;EAzBL,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,IAAI;EACxC;EACA;EACA,SAAS,OAAO;EAChB,YAAY,OAAO;EACnB;EACA;EACA,OAAO,cAAc;EACrB;EACA;EACA,KAAK,UAAU,MAAM;EACrB;CAES,CAAC,CAAC,KAAK,IAAI;AACxB;;;;;;;AAQA,SAAS,iBAAiB,QAA6B;CAGrD,OAAO,GAFe,OAAO,UAAU,QAAQ,SAAS,GAElC,EAAE,GADR,OAAO,GAAG,MAAM,GAAG,CACF,IAAI;AACvC;;;;;AAMA,SAAS,gBAAgB,KAAmB;CAC1C,IAAI;EACF,MAAM,QAAQ,GACX,YAAY,GAAG,CAAC,CAChB,QAAQ,MAAM,EAAE,SAAS,mBAAmB,CAAC,CAAC,CAC9C,SAAS,CAAC,CACV,WAAW;EAEd,KAAK,MAAM,QAAQ,MAAM,MAAM,eAAe,GAC5C,GAAG,WAAW,KAAK,KAAK,KAAK,IAAI,CAAC;CAEtC,QAAQ,CAER;AACF;;;;;;;;;AAUA,SAAgB,iBAAiB,QAAqB,KAAiC;CACrF,IAAI;EACF,gBAAgB,GAAG;EAEnB,MAAM,WAAW,iBAAiB,MAAM;EACxC,MAAM,WAAW,KAAK,KAAK,KAAK,QAAQ;EAGxC,gBAAgB,UAFA,kBAAkB,MAEF,CAAC;EACjC,gBAAgB,GAAG;EAEnB,OAAO;CACT,QAAQ;EACN;CACF;AACF;;;;ACrGA,MAAM,kBAAkB;AACxB,MAAM,sBAAsB;AAE5B,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8CxB,eAAsB,gBAAgB,QAAqB,IAA8B;CACvF,IAAI;EACF,MAAM,WAAW,QAAQ,IAAI,gCAAgC;EAC7D,MAAM,WAAW,MAAM,MAAM,UAAU;GACrC,QAAQ;GACR,SAAS;IACP,gBAAgB;IAChB,cAAc;GAChB;GACA,MAAM,KAAK,UAAU;IACnB,OAAO;IACP,WAAW;GACb,CAAC;GACD,QAAQ,YAAY,QAAQ,eAAe;EAC7C,CAAC;EAED,IAAI,CAAC,SAAS,IAAI,OAAO;EAEzB,MAAM,OAAQ,MAAM,SAAS,KAAK;EAIlC,IAAI,KAAK,QAAQ,QAAQ,OAAO;EAChC,OAAO,KAAK,MAAM,kBAAkB,YAAY;CAClD,QAAQ;EACN,OAAO;CACT;AACF;;;;AC5EA,MAAM,WAAW,GAAG,QAAQ;AAG5B,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;CAChE,OAAO,SAAS,MAAM,SAAS,CAAC,CAAC,IAAI,KAAK;AAC5C;;;;;;;;AASA,SAAgB,mBAAmB,OAAuB;CAKxD,MAAM,kBAAkB,MAAM,OAAO,UAAU;CAC/C,IAAI;CACJ,IAAI,oBAAoB,IACtB,SAAS,gBAAgB,MAAM,MAAM,GAAG,eAAe,CAAC,IAAI,MAAM,MAAM,eAAe;MAEvF,SAAS,gBAAgB,KAAK;CAGhC,SAAS,OAAO,QAAQ,wBAAwB,UAAU;EACxD,MAAM,WAAW,MAAM,QAAQ,kBAAkB;EACjD,IAAI,aAAa,IACf,OAAO,MAAM,MAAM,QAAQ;EAG7B,IAAI,MAAM,WAAW,QAAQ,GAC3B,OAAO,gBAAgB,YAAY,OAAO,GAAG;EAG/C,OAAO,cAAc,YAAY,OAAO,GAAG;CAC7C,CAAC;CACD,SAAS,OAAO,QAAQ,uBAAuB,UAAU;EACvD,MAAM,aAAa,MAAM,QAAQ,OAAO,GAAG;EAC3C,MAAM,WAAW,WAAW,QAAQ,kBAAkB;EACtD,IAAI,aAAa,IACf,OAAO,WAAW,MAAM,QAAQ;EAElC,OAAO,cAAc,YAAY,OAAO,IAAI;CAC9C,CAAC;CACD,OAAO;AACT;;;;;;;AAQA,SAAgB,gBAAgB,SAAyB;CACvD,IAAI,SAAS;CAEb,SAAS,OAAO,QAAQ,yBAAyB,uBAAuB;CACxE,SAAS,OAAO,QAAQ,cAAc,QAAQ;CAC9C,SAAS,OAAO,QAAQ,kBAAkB,YAAY;CACtD,SAAS,OAAO,QAAQ,eAAe,SAAS;CAChD,SAAS,OAAO,QAAQ,mBAAmB,aAAa;CACxD,SAAS,OAAO,QAAQ,wBAAwB,UAAU,UAAU,YAAY,OAAO,GAAG,GAAG;CAC7F,SAAS,OAAO,QAAQ,uBAAuB,UAAU,UAAU,YAAY,OAAO,IAAI,GAAG;CAE7F,OAAO;AACT;;;;;;;AAQA,SAAgB,aAAa,MAA0B;CACrD,MAAM,SAAmB,CAAC;CAC1B,IAAI,aAAa;CAEjB,KAAK,MAAM,OAAO,MAAM;EACtB,IAAI,YAAY;GAKd,IAAI,CAAC,IAAI,WAAW,GAAG,GAAG;IACxB,OAAO,KAAK,YAAY;IACxB,aAAa;IACb;GACF;GACA,aAAa;EACf;EAEA,IAAI,IAAI,WAAW,GAAG,GAAG;GAEvB,MAAM,UAAU,IAAI,QAAQ,GAAG;GAC/B,IAAI,YAAY,IAAI;IAClB,OAAO,KAAK,GAAG,IAAI,MAAM,GAAG,OAAO,EAAE,YAAY;IACjD;GACF;GAGA,OAAO,KAAK,GAAG;GACf,aAAa;GACb;EACF;EAGA,IAAI,IAAI,WAAW,GAAG,KAAK,IAAI,SAAS,KAAK,CAAC,GAAG;GAC/C,OAAO,KAAK,QAAQ;GACpB;EACF;EAGA,IAAI,2BAA2B,KAAK,GAAG,GAAG;GACxC,OAAO,KAAK,QAAQ;GACpB;EACF;EAGA,IAAI,mBAAmB,KAAK,GAAG,GAAG;GAChC,OAAO,KAAK,SAAS;GACrB;EACF;EAEA,OAAO,KAAK,GAAG;CACjB;CAEA,OAAO;AACT;;;;AC3GA,MAAM,qBAAqB;;;;;;AAO3B,SAAS,eAAuB;CAC9B,MAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;CACjC,MAAM,eAAyB,CAAC;CAChC,KAAK,MAAM,OAAO,MAAM;EACtB,IAAI,IAAI,WAAW,GAAG,KAAK,aAAa,UAAU,oBAAoB;EACtE,aAAa,KAAK,GAAG;CACvB;CACA,OAAO,aAAa,KAAK,GAAG,KAAK;AACnC;;;;;;;AAQA,SAAgB,iBAAiB,SAA+C;CAC9E,MAAM,EAAE,OAAO,YAAY,cAAc;CAEzC,MAAM,UAAU,iBAAiB;CACjC,MAAM,aAAa,UAAU,MAAM,UAAU,OAAO,KAAK;CACzD,MAAM,WAAW,WAAW,MAAM,QAAQ,MAAM,QAAQ;CACxD,MAAM,YAAY,UAAU,MAAM,OAAO;CAEzC,MAAM,cAAc,gBAAgB;CAEpC,OAAO;EACL,IAAI,OAAO,WAAW;EACtB,4BAAW,IAAI,KAAK,EAAC,CAAC,YAAY;EAClC;EACA,aAAa,QAAQ;EACrB,YAAY,QAAQ;EACpB,WAAW,GAAG,QAAQ;EACtB,MAAM,QAAQ;EACd,SAAS,gBAAgB,aAAa,CAAC;EACvC,MAAM,aAAa,QAAQ,IAAI;EAC/B;EACA,cAAc,gBAAgB,UAAU;EACxC,YAAY,mBAAmB,QAAQ;EACvC;EACA,QAAQ;EACR,WAAW;CACb;AACF;;;;;;AAOA,SAAS,kBAAiC;CACxC,IAAI;EACF,IAAI,CAAC,WAAW,OAAO;EACvB,MAAM,aAAa,KAAK,KAAK,WAAW,mBAAmB,aAAa;EACxE,IAAI,CAAC,GAAG,WAAW,UAAU,GAAG,OAAO;EAIvC,OAHY,UAAU,GAAG,aAAa,YAAY,OAAO,CAGhD,CAAC,EAAE,gBAAgB;CAC9B,QAAQ;EACN,OAAO;CACT;AACF;;;;;;;;;;;;;AC3FA,eAAsB,YAAY,OAAgB,WAAqC;CACrF,IAAI;EACF,MAAM,SAAS,uBAAuB;EACtC,IAAI,CAAC,OAAO,gBAAgB,CAAC,OAAO,eAAe;EAGnD,MAAM,cAAa,MADO,gBAAgB,EACZ,CAAC,WAAW;EAE1C,MAAM,SAAS,iBAAiB;GAAE;GAAO;GAAY;EAAU,CAAC;EAEhE,IAAI,OAAO,cAAc;GACvB,MAAM,WAAW,iBAAiB,QAAQ,OAAO,QAAQ;GACzD,IAAI,UACF,OAAO,IACL;IACE;IACA;IACA,KAAK;IACL;IACA;IACA,yCAAyC,SAAS;GACpD,CAAC,CAAC,KAAK,IAAI,CACb;EAEJ;EAEA,IAAI,OAAO,eAET,MAAM,gBAAgB,QADX,qBAAqB,UACD,CAAC;CAEpC,QAAQ,CAER;AACF;;;;;;AAOA,SAAgB,qBAA2B;CACzC,MAAM,SAAS,uBAAuB;CACtC,IAAI,CAAC,OAAO,gBAAgB,CAAC,OAAO,eAAe;CAEnD,MAAM,eAAe,OAAgB,cAAyB;EAC5D,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;EACrE,OAAO,MAAM,OAAO;EACpB,AAAK,YAAY,OAAO,SAAS,CAAC,CAAC,cAAc;GAC/C,QAAQ,KAAK,CAAC;EAChB,CAAC;CACH;CAEA,QAAQ,GAAG,sBAAsB,UAAU,YAAY,OAAO,mBAAmB,CAAC;CAClF,QAAQ,GAAG,uBAAuB,WAAW,YAAY,QAAQ,oBAAoB,CAAC;AACxF"}
1
+ {"version":3,"file":"crashreport-BqyvFk-_.mjs","names":[],"sources":["../src/cli/crashreport/config.ts","../src/cli/crashreport/writer.ts","../src/cli/crashreport/sender.ts","../src/cli/crashreport/sanitize.ts","../src/cli/crashreport/report.ts","../src/cli/crashreport/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 { ensureSecretDir, writeSecretFile } from \"#/cli/shared/secret-file\";\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 .toSorted()\n .toReversed();\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 ensureSecretDir(dir);\n\n const filename = generateFilename(report);\n const filePath = path.join(dir, filename);\n const content = formatCrashReport(report);\n\n writeSecretFile(filePath, content);\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 // parseYAML returns null for empty documents\n // oxlint-disable-next-line typescript/no-unnecessary-condition\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 { userAgentFromVersion } from \"#/cli/shared/user-agent\";\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 crashreport send --file \"${filePath}\"`,\n ].join(\"\\n\"),\n );\n }\n }\n\n if (config.remoteEnabled) {\n const ua = userAgentFromVersion(sdkVersion);\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;CAC1D,IAAI,MACF,OAAO;EACL,cAAc;EACd,eAAe;EACf,UAAU;CACZ;CAGF,MAAM,gBAAgB,QAAQ,IAAI,8BAA8B,KAAI,CAAE,YAAY,MAAM;CACxF,MAAM,iBAAiB,QAAQ,IAAI,+BAA+B,MAAK,CAAE,YAAY,MAAM;CAC3F,MAAM,WAAW,YAAY,KAAK,KAAK,WAAW,mBAAmB,eAAe,IAAI;CAExF,OAAO;EACL,cAAc,gBAAgB,aAAa;EAC3C;EACA;CACF;AACF;;;;AC9BA,MAAM,kBAAkB;;AAGxB,MAAa,qBAAqB;;AAGlC,MAAa,sBAAsB;;;;;;AAOnC,SAAgB,kBAAkB,QAA6B;CA2B7D,OAAO;EAzBL,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,IAAI;EACxC;EACA;EACA,SAAS,OAAO;EAChB,YAAY,OAAO;EACnB;EACA;EACA,OAAO,cAAc;EACrB;EACA;EACA,KAAK,UAAU,MAAM;EACrB;CAES,CAAC,CAAC,KAAK,IAAI;AACxB;;;;;;;AAQA,SAAS,iBAAiB,QAA6B;CAGrD,OAAO,GAFe,OAAO,UAAU,QAAQ,SAAS,GAElC,EAAE,GADR,OAAO,GAAG,MAAM,GAAG,CACF,IAAI;AACvC;;;;;AAMA,SAAS,gBAAgB,KAAmB;CAC1C,IAAI;EACF,MAAM,QAAQ,GACX,YAAY,GAAG,CAAC,CAChB,QAAQ,MAAM,EAAE,SAAS,mBAAmB,CAAC,CAAC,CAC9C,SAAS,CAAC,CACV,WAAW;EAEd,KAAK,MAAM,QAAQ,MAAM,MAAM,eAAe,GAC5C,GAAG,WAAW,KAAK,KAAK,KAAK,IAAI,CAAC;CAEtC,QAAQ,CAER;AACF;;;;;;;;;AAUA,SAAgB,iBAAiB,QAAqB,KAAiC;CACrF,IAAI;EACF,gBAAgB,GAAG;EAEnB,MAAM,WAAW,iBAAiB,MAAM;EACxC,MAAM,WAAW,KAAK,KAAK,KAAK,QAAQ;EAGxC,gBAAgB,UAFA,kBAAkB,MAEF,CAAC;EACjC,gBAAgB,GAAG;EAEnB,OAAO;CACT,QAAQ;EACN;CACF;AACF;;;;ACrGA,MAAM,kBAAkB;AACxB,MAAM,sBAAsB;AAE5B,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8CxB,eAAsB,gBAAgB,QAAqB,IAA8B;CACvF,IAAI;EACF,MAAM,WAAW,QAAQ,IAAI,gCAAgC;EAC7D,MAAM,WAAW,MAAM,MAAM,UAAU;GACrC,QAAQ;GACR,SAAS;IACP,gBAAgB;IAChB,cAAc;GAChB;GACA,MAAM,KAAK,UAAU;IACnB,OAAO;IACP,WAAW;GACb,CAAC;GACD,QAAQ,YAAY,QAAQ,eAAe;EAC7C,CAAC;EAED,IAAI,CAAC,SAAS,IAAI,OAAO;EAEzB,MAAM,OAAQ,MAAM,SAAS,KAAK;EAIlC,IAAI,KAAK,QAAQ,QAAQ,OAAO;EAChC,OAAO,KAAK,MAAM,kBAAkB,YAAY;CAClD,QAAQ;EACN,OAAO;CACT;AACF;;;;AC5EA,MAAM,WAAW,GAAG,QAAQ;AAG5B,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;CAChE,OAAO,SAAS,MAAM,SAAS,CAAC,CAAC,IAAI,KAAK;AAC5C;;;;;;;;AASA,SAAgB,mBAAmB,OAAuB;CAKxD,MAAM,kBAAkB,MAAM,OAAO,UAAU;CAC/C,IAAI;CACJ,IAAI,oBAAoB,IACtB,SAAS,gBAAgB,MAAM,MAAM,GAAG,eAAe,CAAC,IAAI,MAAM,MAAM,eAAe;MAEvF,SAAS,gBAAgB,KAAK;CAGhC,SAAS,OAAO,QAAQ,wBAAwB,UAAU;EACxD,MAAM,WAAW,MAAM,QAAQ,kBAAkB;EACjD,IAAI,aAAa,IACf,OAAO,MAAM,MAAM,QAAQ;EAG7B,IAAI,MAAM,WAAW,QAAQ,GAC3B,OAAO,gBAAgB,YAAY,OAAO,GAAG;EAG/C,OAAO,cAAc,YAAY,OAAO,GAAG;CAC7C,CAAC;CACD,SAAS,OAAO,QAAQ,uBAAuB,UAAU;EACvD,MAAM,aAAa,MAAM,QAAQ,OAAO,GAAG;EAC3C,MAAM,WAAW,WAAW,QAAQ,kBAAkB;EACtD,IAAI,aAAa,IACf,OAAO,WAAW,MAAM,QAAQ;EAElC,OAAO,cAAc,YAAY,OAAO,IAAI;CAC9C,CAAC;CACD,OAAO;AACT;;;;;;;AAQA,SAAgB,gBAAgB,SAAyB;CACvD,IAAI,SAAS;CAEb,SAAS,OAAO,QAAQ,yBAAyB,uBAAuB;CACxE,SAAS,OAAO,QAAQ,cAAc,QAAQ;CAC9C,SAAS,OAAO,QAAQ,kBAAkB,YAAY;CACtD,SAAS,OAAO,QAAQ,eAAe,SAAS;CAChD,SAAS,OAAO,QAAQ,mBAAmB,aAAa;CACxD,SAAS,OAAO,QAAQ,wBAAwB,UAAU,UAAU,YAAY,OAAO,GAAG,GAAG;CAC7F,SAAS,OAAO,QAAQ,uBAAuB,UAAU,UAAU,YAAY,OAAO,IAAI,GAAG;CAE7F,OAAO;AACT;;;;;;;AAQA,SAAgB,aAAa,MAA0B;CACrD,MAAM,SAAmB,CAAC;CAC1B,IAAI,aAAa;CAEjB,KAAK,MAAM,OAAO,MAAM;EACtB,IAAI,YAAY;GAKd,IAAI,CAAC,IAAI,WAAW,GAAG,GAAG;IACxB,OAAO,KAAK,YAAY;IACxB,aAAa;IACb;GACF;GACA,aAAa;EACf;EAEA,IAAI,IAAI,WAAW,GAAG,GAAG;GAEvB,MAAM,UAAU,IAAI,QAAQ,GAAG;GAC/B,IAAI,YAAY,IAAI;IAClB,OAAO,KAAK,GAAG,IAAI,MAAM,GAAG,OAAO,EAAE,YAAY;IACjD;GACF;GAGA,OAAO,KAAK,GAAG;GACf,aAAa;GACb;EACF;EAGA,IAAI,IAAI,WAAW,GAAG,KAAK,IAAI,SAAS,KAAK,CAAC,GAAG;GAC/C,OAAO,KAAK,QAAQ;GACpB;EACF;EAGA,IAAI,2BAA2B,KAAK,GAAG,GAAG;GACxC,OAAO,KAAK,QAAQ;GACpB;EACF;EAGA,IAAI,mBAAmB,KAAK,GAAG,GAAG;GAChC,OAAO,KAAK,SAAS;GACrB;EACF;EAEA,OAAO,KAAK,GAAG;CACjB;CAEA,OAAO;AACT;;;;AC3GA,MAAM,qBAAqB;;;;;;AAO3B,SAAS,eAAuB;CAC9B,MAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;CACjC,MAAM,eAAyB,CAAC;CAChC,KAAK,MAAM,OAAO,MAAM;EACtB,IAAI,IAAI,WAAW,GAAG,KAAK,aAAa,UAAU,oBAAoB;EACtE,aAAa,KAAK,GAAG;CACvB;CACA,OAAO,aAAa,KAAK,GAAG,KAAK;AACnC;;;;;;;AAQA,SAAgB,iBAAiB,SAA+C;CAC9E,MAAM,EAAE,OAAO,YAAY,cAAc;CAEzC,MAAM,UAAU,iBAAiB;CACjC,MAAM,aAAa,UAAU,MAAM,UAAU,OAAO,KAAK;CACzD,MAAM,WAAW,WAAW,MAAM,QAAQ,MAAM,QAAQ;CACxD,MAAM,YAAY,UAAU,MAAM,OAAO;CAEzC,MAAM,cAAc,gBAAgB;CAEpC,OAAO;EACL,IAAI,OAAO,WAAW;EACtB,4BAAW,IAAI,KAAK,EAAC,CAAC,YAAY;EAClC;EACA,aAAa,QAAQ;EACrB,YAAY,QAAQ;EACpB,WAAW,GAAG,QAAQ;EACtB,MAAM,QAAQ;EACd,SAAS,gBAAgB,aAAa,CAAC;EACvC,MAAM,aAAa,QAAQ,IAAI;EAC/B;EACA,cAAc,gBAAgB,UAAU;EACxC,YAAY,mBAAmB,QAAQ;EACvC;EACA,QAAQ;EACR,WAAW;CACb;AACF;;;;;;AAOA,SAAS,kBAAiC;CACxC,IAAI;EACF,IAAI,CAAC,WAAW,OAAO;EACvB,MAAM,aAAa,KAAK,KAAK,WAAW,mBAAmB,aAAa;EACxE,IAAI,CAAC,GAAG,WAAW,UAAU,GAAG,OAAO;EAIvC,OAHY,UAAU,GAAG,aAAa,YAAY,OAAO,CAGhD,CAAC,EAAE,gBAAgB;CAC9B,QAAQ;EACN,OAAO;CACT;AACF;;;;;;;;;;;;;AC3FA,eAAsB,YAAY,OAAgB,WAAqC;CACrF,IAAI;EACF,MAAM,SAAS,uBAAuB;EACtC,IAAI,CAAC,OAAO,gBAAgB,CAAC,OAAO,eAAe;EAGnD,MAAM,cAAa,MADO,gBAAgB,EACZ,CAAC,WAAW;EAE1C,MAAM,SAAS,iBAAiB;GAAE;GAAO;GAAY;EAAU,CAAC;EAEhE,IAAI,OAAO,cAAc;GACvB,MAAM,WAAW,iBAAiB,QAAQ,OAAO,QAAQ;GACzD,IAAI,UACF,OAAO,IACL;IACE;IACA;IACA,KAAK;IACL;IACA;IACA,yCAAyC,SAAS;GACpD,CAAC,CAAC,KAAK,IAAI,CACb;EAEJ;EAEA,IAAI,OAAO,eAET,MAAM,gBAAgB,QADX,qBAAqB,UACD,CAAC;CAEpC,QAAQ,CAER;AACF;;;;;;AAOA,SAAgB,qBAA2B;CACzC,MAAM,SAAS,uBAAuB;CACtC,IAAI,CAAC,OAAO,gBAAgB,CAAC,OAAO,eAAe;CAEnD,MAAM,eAAe,OAAgB,cAAyB;EAC5D,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;EACrE,OAAO,MAAM,OAAO;EACpB,AAAK,YAAY,OAAO,SAAS,CAAC,CAAC,cAAc;GAC/C,QAAQ,KAAK,CAAC;EAChB,CAAC;CACH;CAEA,QAAQ,GAAG,sBAAsB,UAAU,YAAY,OAAO,mBAAmB,CAAC;CAClF,QAAQ,GAAG,uBAAuB,WAAW,YAAY,QAAQ,oBAAoB,CAAC;AACxF"}
@@ -1,4 +1,4 @@
1
1
 
2
- import { n as reportCrash, t as initCrashReporting } from "./crashreport-u9y2npiy.mjs";
2
+ import { n as reportCrash, t as initCrashReporting } from "./crashreport-BqyvFk-_.mjs";
3
3
 
4
4
  export { reportCrash };
@@ -1 +1 @@
1
- {"version":3,"file":"enum-constants-C7DaWeQo.mjs","names":[],"sources":["../src/plugin/builtin/enum-constants/generate-enum-constants.ts","../src/plugin/builtin/enum-constants/process-enum-type.ts","../src/plugin/builtin/enum-constants/index.ts"],"sourcesContent":["import type { EnumDefinition } from \"./types\";\n\n/**\n * Generate enum constant definitions from collected metadata.\n * @param allEnums - All collected enum definitions\n * @returns Generated enum constant definitions\n */\nexport function generateUnifiedEnumConstants(allEnums: EnumDefinition[]): string {\n if (allEnums.length === 0) {\n return \"\";\n }\n\n const enumMap = new Map<string, EnumDefinition>();\n for (const enumDef of allEnums) {\n enumMap.set(enumDef.name, enumDef);\n }\n\n const enumDefs = Array.from(enumMap.values())\n .map((e) => {\n const members = e.values\n .map((v) => {\n const key = v.value.replace(/[-\\s]/g, \"_\");\n return ` \"${key}\": \"${v.value}\"`;\n })\n .join(\",\\n\");\n\n const hasDescriptions = e.values.some((v) => v.description);\n let jsDoc = \"\";\n if (e.fieldDescription || hasDescriptions) {\n const lines: string[] = [];\n\n if (e.fieldDescription) {\n lines.push(` * ${e.fieldDescription}`);\n if (hasDescriptions) {\n lines.push(\" *\");\n }\n }\n\n if (hasDescriptions) {\n const propertyDocs = e.values.map((v) => {\n const key = v.value.replace(/[-\\s]/g, \"_\");\n return ` * @property ${[key, v.description].filter(Boolean).join(\" - \")}`;\n });\n lines.push(...propertyDocs);\n }\n\n if (lines.length > 0) {\n jsDoc = `/**\\n${lines.join(\"\\n\")}\\n */\\n`;\n }\n }\n\n const constDef = `${jsDoc}export const ${e.name} = {\\n${members}\\n} as const;`;\n const typeDef = `export type ${e.name} = (typeof ${e.name})[keyof typeof ${e.name}];`;\n return `${constDef}\\n${typeDef}`;\n })\n .join(\"\\n\\n\");\n\n if (!enumDefs) {\n return \"\";\n }\n\n return enumDefs + \"\\n\";\n}\n","import type { EnumConstantMetadata } from \"./types\";\nimport type { TailorDBType } from \"@/parser/service/tailordb/types\";\n\nfunction capitalizeFirst(str: string): string {\n return str.charAt(0).toUpperCase() + str.slice(1);\n}\n\nfunction collectEnums(type: TailorDBType): EnumConstantMetadata[\"enums\"] {\n const enums: EnumConstantMetadata[\"enums\"] = [];\n\n for (const [fieldName, parsedField] of Object.entries(type.fields)) {\n if (parsedField.config.type === \"enum\" && parsedField.config.allowedValues) {\n const enumTypeName = `${type.name}${capitalizeFirst(fieldName)}`;\n enums.push({\n name: enumTypeName,\n values: parsedField.config.allowedValues,\n fieldDescription: parsedField.config.description,\n });\n }\n\n // Process nested fields\n if (parsedField.config.type === \"nested\" && parsedField.config.fields) {\n for (const [nestedFieldName, nestedFieldConfig] of Object.entries(\n parsedField.config.fields,\n )) {\n if (nestedFieldConfig.type === \"enum\" && nestedFieldConfig.allowedValues) {\n const fullFieldName = `${fieldName}${capitalizeFirst(nestedFieldName)}`;\n const enumTypeName = `${type.name}${capitalizeFirst(fullFieldName)}`;\n enums.push({\n name: enumTypeName,\n values: nestedFieldConfig.allowedValues,\n fieldDescription: nestedFieldConfig.description,\n });\n }\n }\n }\n }\n\n return enums;\n}\n\n/**\n * Process a TailorDB type and extract enum metadata.\n * @param type - The parsed TailorDB type to process\n * @returns Enum constant metadata for the type\n */\nexport async function processEnumType(type: TailorDBType): Promise<EnumConstantMetadata> {\n const enums = collectEnums(type);\n\n return {\n name: type.name,\n enums,\n };\n}\n","import { generateUnifiedEnumConstants } from \"./generate-enum-constants\";\nimport { processEnumType } from \"./process-enum-type\";\nimport type { EnumDefinition } from \"./types\";\nimport type { Plugin, GeneratorResult, TailorDBReadyContext } from \"@/plugin/types\";\n\n/** Unique identifier for the enum constants generator plugin. */\nexport const EnumConstantsGeneratorID = \"@tailor-platform/enum-constants\";\n\ntype EnumConstantsPluginOptions = {\n distPath: string;\n};\n\n/**\n * Plugin that generates enum constants from TailorDB type definitions.\n * @param options - Plugin options\n * @param options.distPath - Output file path for generated constants\n * @returns Plugin instance with onTailorDBReady hook\n */\nexport function enumConstantsPlugin(\n options: EnumConstantsPluginOptions,\n): Plugin<unknown, EnumConstantsPluginOptions> {\n return {\n id: EnumConstantsGeneratorID,\n description: \"Generates enum constants from TailorDB type definitions\",\n pluginConfig: options,\n\n async onTailorDBReady(\n ctx: TailorDBReadyContext<EnumConstantsPluginOptions>,\n ): Promise<GeneratorResult> {\n const allEnums: EnumDefinition[] = [];\n\n for (const ns of ctx.tailordb) {\n for (const type of Object.values(ns.types)) {\n const metadata = await processEnumType(type);\n allEnums.push(...metadata.enums);\n }\n }\n\n const files: GeneratorResult[\"files\"] = [];\n if (allEnums.length > 0) {\n const content = generateUnifiedEnumConstants(allEnums);\n files.push({\n path: ctx.pluginConfig.distPath,\n content,\n });\n }\n\n return { files };\n },\n };\n}\n"],"mappings":";;;;;;;AAOA,SAAgB,6BAA6B,UAAoC;CAC/E,IAAI,SAAS,WAAW,GACtB,OAAO;CAGT,MAAM,0BAAU,IAAI,IAA4B;CAChD,KAAK,MAAM,WAAW,UACpB,QAAQ,IAAI,QAAQ,MAAM,OAAO;CAGnC,MAAM,WAAW,MAAM,KAAK,QAAQ,OAAO,CAAC,CAAC,CAC1C,KAAK,MAAM;EACV,MAAM,UAAU,EAAE,OACf,KAAK,MAAM;GAEV,OAAO,MADK,EAAE,MAAM,QAAQ,UAAU,GACvB,EAAE,MAAM,EAAE,MAAM;EACjC,CAAC,CAAC,CACD,KAAK,KAAK;EAEb,MAAM,kBAAkB,EAAE,OAAO,MAAM,MAAM,EAAE,WAAW;EAC1D,IAAI,QAAQ;EACZ,IAAI,EAAE,oBAAoB,iBAAiB;GACzC,MAAM,QAAkB,CAAC;GAEzB,IAAI,EAAE,kBAAkB;IACtB,MAAM,KAAK,MAAM,EAAE,kBAAkB;IACrC,IAAI,iBACF,MAAM,KAAK,IAAI;GAEnB;GAEA,IAAI,iBAAiB;IACnB,MAAM,eAAe,EAAE,OAAO,KAAK,MAAM;KAEvC,OAAO,gBAAgB,CADX,EAAE,MAAM,QAAQ,UAAU,GACZ,GAAG,EAAE,WAAW,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,KAAK;IACxE,CAAC;IACD,MAAM,KAAK,GAAG,YAAY;GAC5B;GAEA,IAAI,MAAM,SAAS,GACjB,QAAQ,QAAQ,MAAM,KAAK,IAAI,EAAE;EAErC;EAIA,OAAO,GAAG,GAFU,MAAM,eAAe,EAAE,KAAK,QAAQ,QAAQ,eAE7C,IAAI,eADQ,EAAE,KAAK,aAAa,EAAE,KAAK,iBAAiB,EAAE,KAAK;CAEpF,CAAC,CAAC,CACD,KAAK,MAAM;CAEd,IAAI,CAAC,UACH,OAAO;CAGT,OAAO,WAAW;AACpB;;;;AC3DA,SAAS,gBAAgB,KAAqB;CAC5C,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,IAAI,MAAM,CAAC;AAClD;AAEA,SAAS,aAAa,MAAmD;CACvE,MAAM,QAAuC,CAAC;CAE9C,KAAK,MAAM,CAAC,WAAW,gBAAgB,OAAO,QAAQ,KAAK,MAAM,GAAG;EAClE,IAAI,YAAY,OAAO,SAAS,UAAU,YAAY,OAAO,eAAe;GAC1E,MAAM,eAAe,GAAG,KAAK,OAAO,gBAAgB,SAAS;GAC7D,MAAM,KAAK;IACT,MAAM;IACN,QAAQ,YAAY,OAAO;IAC3B,kBAAkB,YAAY,OAAO;GACvC,CAAC;EACH;EAGA,IAAI,YAAY,OAAO,SAAS,YAAY,YAAY,OAAO,QAC7D;QAAK,MAAM,CAAC,iBAAiB,sBAAsB,OAAO,QACxD,YAAY,OAAO,MACrB,GACE,IAAI,kBAAkB,SAAS,UAAU,kBAAkB,eAAe;IACxE,MAAM,gBAAgB,GAAG,YAAY,gBAAgB,eAAe;IACpE,MAAM,eAAe,GAAG,KAAK,OAAO,gBAAgB,aAAa;IACjE,MAAM,KAAK;KACT,MAAM;KACN,QAAQ,kBAAkB;KAC1B,kBAAkB,kBAAkB;IACtC,CAAC;GACH;EACF;CAEJ;CAEA,OAAO;AACT;;;;;;AAOA,eAAsB,gBAAgB,MAAmD;CACvF,MAAM,QAAQ,aAAa,IAAI;CAE/B,OAAO;EACL,MAAM,KAAK;EACX;CACF;AACF;;;;;AC/CA,MAAa,2BAA2B;;;;;;;AAYxC,SAAgB,oBACd,SAC6C;CAC7C,OAAO;EACL,IAAI;EACJ,aAAa;EACb,cAAc;EAEd,MAAM,gBACJ,KAC0B;GAC1B,MAAM,WAA6B,CAAC;GAEpC,KAAK,MAAM,MAAM,IAAI,UACnB,KAAK,MAAM,QAAQ,OAAO,OAAO,GAAG,KAAK,GAAG;IAC1C,MAAM,WAAW,MAAM,gBAAgB,IAAI;IAC3C,SAAS,KAAK,GAAG,SAAS,KAAK;GACjC;GAGF,MAAM,QAAkC,CAAC;GACzC,IAAI,SAAS,SAAS,GAAG;IACvB,MAAM,UAAU,6BAA6B,QAAQ;IACrD,MAAM,KAAK;KACT,MAAM,IAAI,aAAa;KACvB;IACF,CAAC;GACH;GAEA,OAAO,EAAE,MAAM;EACjB;CACF;AACF"}
1
+ {"version":3,"file":"enum-constants-C7DaWeQo.mjs","names":[],"sources":["../src/plugin/builtin/enum-constants/generate-enum-constants.ts","../src/plugin/builtin/enum-constants/process-enum-type.ts","../src/plugin/builtin/enum-constants/index.ts"],"sourcesContent":["import type { EnumDefinition } from \"./types\";\n\n/**\n * Generate enum constant definitions from collected metadata.\n * @param allEnums - All collected enum definitions\n * @returns Generated enum constant definitions\n */\nexport function generateUnifiedEnumConstants(allEnums: EnumDefinition[]): string {\n if (allEnums.length === 0) {\n return \"\";\n }\n\n const enumMap = new Map<string, EnumDefinition>();\n for (const enumDef of allEnums) {\n enumMap.set(enumDef.name, enumDef);\n }\n\n const enumDefs = Array.from(enumMap.values())\n .map((e) => {\n const members = e.values\n .map((v) => {\n const key = v.value.replace(/[-\\s]/g, \"_\");\n return ` \"${key}\": \"${v.value}\"`;\n })\n .join(\",\\n\");\n\n const hasDescriptions = e.values.some((v) => v.description);\n let jsDoc = \"\";\n if (e.fieldDescription || hasDescriptions) {\n const lines: string[] = [];\n\n if (e.fieldDescription) {\n lines.push(` * ${e.fieldDescription}`);\n if (hasDescriptions) {\n lines.push(\" *\");\n }\n }\n\n if (hasDescriptions) {\n const propertyDocs = e.values.map((v) => {\n const key = v.value.replace(/[-\\s]/g, \"_\");\n return ` * @property ${[key, v.description].filter(Boolean).join(\" - \")}`;\n });\n lines.push(...propertyDocs);\n }\n\n if (lines.length > 0) {\n jsDoc = `/**\\n${lines.join(\"\\n\")}\\n */\\n`;\n }\n }\n\n const constDef = `${jsDoc}export const ${e.name} = {\\n${members}\\n} as const;`;\n const typeDef = `export type ${e.name} = (typeof ${e.name})[keyof typeof ${e.name}];`;\n return `${constDef}\\n${typeDef}`;\n })\n .join(\"\\n\\n\");\n\n if (!enumDefs) {\n return \"\";\n }\n\n return enumDefs + \"\\n\";\n}\n","import type { TailorDBType } from \"#/parser/service/tailordb/types\";\nimport type { EnumConstantMetadata } from \"./types\";\n\nfunction capitalizeFirst(str: string): string {\n return str.charAt(0).toUpperCase() + str.slice(1);\n}\n\nfunction collectEnums(type: TailorDBType): EnumConstantMetadata[\"enums\"] {\n const enums: EnumConstantMetadata[\"enums\"] = [];\n\n for (const [fieldName, parsedField] of Object.entries(type.fields)) {\n if (parsedField.config.type === \"enum\" && parsedField.config.allowedValues) {\n const enumTypeName = `${type.name}${capitalizeFirst(fieldName)}`;\n enums.push({\n name: enumTypeName,\n values: parsedField.config.allowedValues,\n fieldDescription: parsedField.config.description,\n });\n }\n\n // Process nested fields\n if (parsedField.config.type === \"nested\" && parsedField.config.fields) {\n for (const [nestedFieldName, nestedFieldConfig] of Object.entries(\n parsedField.config.fields,\n )) {\n if (nestedFieldConfig.type === \"enum\" && nestedFieldConfig.allowedValues) {\n const fullFieldName = `${fieldName}${capitalizeFirst(nestedFieldName)}`;\n const enumTypeName = `${type.name}${capitalizeFirst(fullFieldName)}`;\n enums.push({\n name: enumTypeName,\n values: nestedFieldConfig.allowedValues,\n fieldDescription: nestedFieldConfig.description,\n });\n }\n }\n }\n }\n\n return enums;\n}\n\n/**\n * Process a TailorDB type and extract enum metadata.\n * @param type - The parsed TailorDB type to process\n * @returns Enum constant metadata for the type\n */\nexport async function processEnumType(type: TailorDBType): Promise<EnumConstantMetadata> {\n const enums = collectEnums(type);\n\n return {\n name: type.name,\n enums,\n };\n}\n","import { generateUnifiedEnumConstants } from \"./generate-enum-constants\";\nimport { processEnumType } from \"./process-enum-type\";\nimport type { Plugin, GeneratorResult, TailorDBReadyContext } from \"#/plugin/types\";\nimport type { EnumDefinition } from \"./types\";\n\n/** Unique identifier for the enum constants generator plugin. */\nexport const EnumConstantsGeneratorID = \"@tailor-platform/enum-constants\";\n\ntype EnumConstantsPluginOptions = {\n distPath: string;\n};\n\n/**\n * Plugin that generates enum constants from TailorDB type definitions.\n * @param options - Plugin options\n * @param options.distPath - Output file path for generated constants\n * @returns Plugin instance with onTailorDBReady hook\n */\nexport function enumConstantsPlugin(\n options: EnumConstantsPluginOptions,\n): Plugin<unknown, EnumConstantsPluginOptions> {\n return {\n id: EnumConstantsGeneratorID,\n description: \"Generates enum constants from TailorDB type definitions\",\n pluginConfig: options,\n\n async onTailorDBReady(\n ctx: TailorDBReadyContext<EnumConstantsPluginOptions>,\n ): Promise<GeneratorResult> {\n const allEnums: EnumDefinition[] = [];\n\n for (const ns of ctx.tailordb) {\n for (const type of Object.values(ns.types)) {\n const metadata = await processEnumType(type);\n allEnums.push(...metadata.enums);\n }\n }\n\n const files: GeneratorResult[\"files\"] = [];\n if (allEnums.length > 0) {\n const content = generateUnifiedEnumConstants(allEnums);\n files.push({\n path: ctx.pluginConfig.distPath,\n content,\n });\n }\n\n return { files };\n },\n };\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"field-C4zdJLW5.mjs","names":[],"sources":["../src/configure/types/field.ts"],"sourcesContent":["import type { EnumValue } from \"@/configure/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;CACnE,OAAO,OAAO,KAAK,UAAU;EAC3B,IAAI,OAAO,UAAU,UACnB,OAAO;GAAE;GAAO,aAAa;EAAG;EAElC,OAAO;GAAE,GAAG;GAAO,aAAa,MAAM,eAAe;EAAG;CAC1D,CAAC;AACH"}
1
+ {"version":3,"file":"field-C4zdJLW5.mjs","names":[],"sources":["../src/configure/types/field.ts"],"sourcesContent":["import type { EnumValue } from \"#/configure/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;CACnE,OAAO,OAAO,KAAK,UAAU;EAC3B,IAAI,OAAO,UAAU,UACnB,OAAO;GAAE;GAAO,aAAa;EAAG;EAElC,OAAO;GAAE,GAAG;GAAO,aAAa,MAAM,eAAe;EAAG;CAC1D,CAAC;AACH"}
@@ -1 +1 @@
1
- {"version":3,"file":"file-utils-BHPxPXmn.mjs","names":[],"sources":["../src/plugin/builtin/file-utils/generate-file-utils.ts","../src/plugin/builtin/file-utils/process-file-type.ts","../src/plugin/builtin/file-utils/index.ts"],"sourcesContent":["import multiline from \"@/utils/multiline\";\nimport type { FileUtilMetadata } from \"./types\";\n\n/**\n * Generate unified file utility functions from collected metadata.\n * @param namespaceData - Namespace data with file utility metadata\n * @returns Generated file utility code\n */\nexport function generateUnifiedFileUtils(\n namespaceData: { namespace: string; types: FileUtilMetadata[] }[],\n): string {\n if (namespaceData.length === 0) {\n return \"\";\n }\n\n // Collect all types with their namespace\n const typeNamespaceMap = new Map<string, string>();\n const typeFieldsMap = new Map<string, string[]>();\n\n for (const { namespace, types } of namespaceData) {\n for (const type of types) {\n typeNamespaceMap.set(type.name, namespace);\n typeFieldsMap.set(type.name, type.fileFields);\n }\n }\n\n if (typeNamespaceMap.size === 0) {\n return \"\";\n }\n\n // Generate interface fields\n const interfaceFields = Array.from(typeFieldsMap.entries())\n .map(([typeName, fields]) => {\n const fieldNamesUnion = fields.map((field) => `\"${field}\"`).join(\" | \");\n return ` ${typeName}: {\\n fields: ${fieldNamesUnion};\\n };`;\n })\n .join(\"\\n\");\n\n const importStatement =\n multiline /* ts */ `\n import * as file from \"@tailor-platform/sdk/runtime/file\";\n import type {\n FileUploadOptions,\n FileUploadResponse,\n FileMetadata,\n FileStreamIterator,\n } from \"@tailor-platform/sdk/runtime/file\";\n ` + \"\\n\";\n\n const interfaceDefinition =\n multiline /* ts */ `\n export interface TypeWithFiles {\n ${interfaceFields}\n }\n ` + \"\\n\";\n\n // Generate namespaces object\n const namespaceEntries = Array.from(typeNamespaceMap.entries())\n .map(([typeName, namespace]) => ` ${typeName}: \"${namespace}\"`)\n .join(\",\\n\");\n\n const namespacesDefinition =\n multiline /* ts */ `\n const namespaces: Record<keyof TypeWithFiles, string> = {\n ${namespaceEntries},\n };\n ` + \"\\n\";\n\n // Generate downloadFile helper function\n const downloadFunction =\n multiline /* ts */ `\n export async function downloadFile<T extends keyof TypeWithFiles>(\n type: T,\n field: TypeWithFiles[T][\"fields\"],\n recordId: string,\n ) {\n return await file.download(namespaces[type], type, field, recordId);\n }\n ` + \"\\n\";\n\n // Generate uploadFile helper function\n const uploadFunction =\n multiline /* ts */ `\n export async function uploadFile<T extends keyof TypeWithFiles>(\n type: T,\n field: TypeWithFiles[T][\"fields\"],\n recordId: string,\n data: string | ArrayBuffer | Uint8Array<ArrayBufferLike> | number[],\n options?: FileUploadOptions,\n ): Promise<FileUploadResponse> {\n return await file.upload(namespaces[type], type, field, recordId, data, options);\n }\n ` + \"\\n\";\n\n // Generate deleteFile helper function\n const deleteFunction =\n multiline /* ts */ `\n export async function deleteFile<T extends keyof TypeWithFiles>(\n type: T,\n field: TypeWithFiles[T][\"fields\"],\n recordId: string,\n ): Promise<void> {\n return await file.delete(namespaces[type], type, field, recordId);\n }\n ` + \"\\n\";\n\n // Generate getFileMetadata helper function\n const getMetadataFunction =\n multiline /* ts */ `\n export async function getFileMetadata<T extends keyof TypeWithFiles>(\n type: T,\n field: TypeWithFiles[T][\"fields\"],\n recordId: string,\n ): Promise<FileMetadata> {\n return await file.getMetadata(namespaces[type], type, field, recordId);\n }\n ` + \"\\n\";\n\n // Generate openFileDownloadStream helper function\n const openDownloadStreamFunction =\n multiline /* ts */ `\n export async function openFileDownloadStream<T extends keyof TypeWithFiles>(\n type: T,\n field: TypeWithFiles[T][\"fields\"],\n recordId: string,\n ): Promise<FileStreamIterator> {\n return await file.openDownloadStream(namespaces[type], type, field, recordId);\n }\n ` + \"\\n\";\n\n return [\n importStatement,\n interfaceDefinition,\n namespacesDefinition,\n downloadFunction,\n uploadFunction,\n deleteFunction,\n getMetadataFunction,\n openDownloadStreamFunction,\n ].join(\"\\n\");\n}\n","import type { FileUtilMetadata } from \"./types\";\nimport type { TailorDBType } from \"@/parser/service/tailordb/types\";\n\n/**\n * Process a TailorDB type and extract file field metadata.\n * @param type - The parsed TailorDB type to process\n * @returns File utility metadata for the type\n */\nexport async function processFileType(type: TailorDBType): Promise<FileUtilMetadata> {\n const fileFields: string[] = [];\n\n if (type.files) {\n for (const fileFieldName of Object.keys(type.files)) {\n fileFields.push(fileFieldName);\n }\n }\n\n return {\n name: type.name,\n fileFields,\n };\n}\n","import { generateUnifiedFileUtils } from \"./generate-file-utils\";\nimport { processFileType } from \"./process-file-type\";\nimport type { FileUtilMetadata } from \"./types\";\nimport type { Plugin, GeneratorResult, TailorDBReadyContext } from \"@/plugin/types\";\n\n/** Unique identifier for the file utilities generator plugin. */\nexport const FileUtilsGeneratorID = \"@tailor-platform/file-utils\";\n\ntype FileUtilsPluginOptions = {\n distPath: string;\n};\n\n/**\n * Plugin that generates TypeWithFiles interface from TailorDB type definitions.\n * @param options - Plugin options\n * @param options.distPath - Output file path for generated file utilities\n * @returns Plugin instance with onTailorDBReady hook\n */\nexport function fileUtilsPlugin(\n options: FileUtilsPluginOptions,\n): Plugin<unknown, FileUtilsPluginOptions> {\n return {\n id: FileUtilsGeneratorID,\n description: \"Generates TypeWithFiles interface from TailorDB type definitions\",\n pluginConfig: options,\n\n async onTailorDBReady(\n ctx: TailorDBReadyContext<FileUtilsPluginOptions>,\n ): Promise<GeneratorResult> {\n const namespaceData: { namespace: string; types: FileUtilMetadata[] }[] = [];\n\n for (const ns of ctx.tailordb) {\n const typesWithFiles: FileUtilMetadata[] = [];\n\n for (const type of Object.values(ns.types)) {\n const metadata = await processFileType(type);\n if (metadata.fileFields.length > 0) {\n typesWithFiles.push(metadata);\n }\n }\n\n if (typesWithFiles.length > 0) {\n namespaceData.push({\n namespace: ns.namespace,\n types: typesWithFiles,\n });\n }\n }\n\n const files: GeneratorResult[\"files\"] = [];\n if (namespaceData.length > 0) {\n const content = generateUnifiedFileUtils(namespaceData);\n if (content) {\n files.push({\n path: ctx.pluginConfig.distPath,\n content,\n });\n }\n }\n\n return { files };\n },\n };\n}\n"],"mappings":";;;;;;;;;AAQA,SAAgB,yBACd,eACQ;CACR,IAAI,cAAc,WAAW,GAC3B,OAAO;CAIT,MAAM,mCAAmB,IAAI,IAAoB;CACjD,MAAM,gCAAgB,IAAI,IAAsB;CAEhD,KAAK,MAAM,EAAE,WAAW,WAAW,eACjC,KAAK,MAAM,QAAQ,OAAO;EACxB,iBAAiB,IAAI,KAAK,MAAM,SAAS;EACzC,cAAc,IAAI,KAAK,MAAM,KAAK,UAAU;CAC9C;CAGF,IAAI,iBAAiB,SAAS,GAC5B,OAAO;CAIT,MAAM,kBAAkB,MAAM,KAAK,cAAc,QAAQ,CAAC,CAAC,CACxD,KAAK,CAAC,UAAU,YAAY;EAE3B,OAAO,KAAK,SAAS,mBADG,OAAO,KAAK,UAAU,IAAI,MAAM,EAAE,CAAC,CAAC,KAAK,KACX,EAAE;CAC1D,CAAC,CAAC,CACD,KAAK,IAAI;CA8FZ,OAAO;EA3FL,SAAmB;;;;;;;;QAQf;EAGJ,SAAmB;;QAEf,gBAAgB;;QAEhB;EAQJ,SAAmB;;QALI,MAAM,KAAK,iBAAiB,QAAQ,CAAC,CAAC,CAC5D,KAAK,CAAC,UAAU,eAAe,KAAK,SAAS,KAAK,UAAU,EAAE,CAAC,CAC/D,KAAK,KAKa,EAAE;;QAEjB;EAIJ,SAAmB;;;;;;;;QAQf;EAIJ,SAAmB;;;;;;;;;;QAUf;EAIJ,SAAmB;;;;;;;;QAQf;EAIJ,SAAmB;;;;;;;;QAQf;EAIJ,SAAmB;;;;;;;;QAQf;CAWN,CAAC,CAAC,KAAK,IAAI;AACb;;;;;;;;;ACpIA,eAAsB,gBAAgB,MAA+C;CACnF,MAAM,aAAuB,CAAC;CAE9B,IAAI,KAAK,OACP,KAAK,MAAM,iBAAiB,OAAO,KAAK,KAAK,KAAK,GAChD,WAAW,KAAK,aAAa;CAIjC,OAAO;EACL,MAAM,KAAK;EACX;CACF;AACF;;;;;ACfA,MAAa,uBAAuB;;;;;;;AAYpC,SAAgB,gBACd,SACyC;CACzC,OAAO;EACL,IAAI;EACJ,aAAa;EACb,cAAc;EAEd,MAAM,gBACJ,KAC0B;GAC1B,MAAM,gBAAoE,CAAC;GAE3E,KAAK,MAAM,MAAM,IAAI,UAAU;IAC7B,MAAM,iBAAqC,CAAC;IAE5C,KAAK,MAAM,QAAQ,OAAO,OAAO,GAAG,KAAK,GAAG;KAC1C,MAAM,WAAW,MAAM,gBAAgB,IAAI;KAC3C,IAAI,SAAS,WAAW,SAAS,GAC/B,eAAe,KAAK,QAAQ;IAEhC;IAEA,IAAI,eAAe,SAAS,GAC1B,cAAc,KAAK;KACjB,WAAW,GAAG;KACd,OAAO;IACT,CAAC;GAEL;GAEA,MAAM,QAAkC,CAAC;GACzC,IAAI,cAAc,SAAS,GAAG;IAC5B,MAAM,UAAU,yBAAyB,aAAa;IACtD,IAAI,SACF,MAAM,KAAK;KACT,MAAM,IAAI,aAAa;KACvB;IACF,CAAC;GAEL;GAEA,OAAO,EAAE,MAAM;EACjB;CACF;AACF"}
1
+ {"version":3,"file":"file-utils-BHPxPXmn.mjs","names":[],"sources":["../src/plugin/builtin/file-utils/generate-file-utils.ts","../src/plugin/builtin/file-utils/process-file-type.ts","../src/plugin/builtin/file-utils/index.ts"],"sourcesContent":["import multiline from \"#/utils/multiline\";\nimport type { FileUtilMetadata } from \"./types\";\n\n/**\n * Generate unified file utility functions from collected metadata.\n * @param namespaceData - Namespace data with file utility metadata\n * @returns Generated file utility code\n */\nexport function generateUnifiedFileUtils(\n namespaceData: { namespace: string; types: FileUtilMetadata[] }[],\n): string {\n if (namespaceData.length === 0) {\n return \"\";\n }\n\n // Collect all types with their namespace\n const typeNamespaceMap = new Map<string, string>();\n const typeFieldsMap = new Map<string, string[]>();\n\n for (const { namespace, types } of namespaceData) {\n for (const type of types) {\n typeNamespaceMap.set(type.name, namespace);\n typeFieldsMap.set(type.name, type.fileFields);\n }\n }\n\n if (typeNamespaceMap.size === 0) {\n return \"\";\n }\n\n // Generate interface fields\n const interfaceFields = Array.from(typeFieldsMap.entries())\n .map(([typeName, fields]) => {\n const fieldNamesUnion = fields.map((field) => `\"${field}\"`).join(\" | \");\n return ` ${typeName}: {\\n fields: ${fieldNamesUnion};\\n };`;\n })\n .join(\"\\n\");\n\n const importStatement =\n multiline /* ts */ `\n import * as file from \"@tailor-platform/sdk/runtime/file\";\n import type {\n FileUploadOptions,\n FileUploadResponse,\n FileMetadata,\n FileStreamIterator,\n } from \"@tailor-platform/sdk/runtime/file\";\n ` + \"\\n\";\n\n const interfaceDefinition =\n multiline /* ts */ `\n export interface TypeWithFiles {\n ${interfaceFields}\n }\n ` + \"\\n\";\n\n // Generate namespaces object\n const namespaceEntries = Array.from(typeNamespaceMap.entries())\n .map(([typeName, namespace]) => ` ${typeName}: \"${namespace}\"`)\n .join(\",\\n\");\n\n const namespacesDefinition =\n multiline /* ts */ `\n const namespaces: Record<keyof TypeWithFiles, string> = {\n ${namespaceEntries},\n };\n ` + \"\\n\";\n\n // Generate downloadFile helper function\n const downloadFunction =\n multiline /* ts */ `\n export async function downloadFile<T extends keyof TypeWithFiles>(\n type: T,\n field: TypeWithFiles[T][\"fields\"],\n recordId: string,\n ) {\n return await file.download(namespaces[type], type, field, recordId);\n }\n ` + \"\\n\";\n\n // Generate uploadFile helper function\n const uploadFunction =\n multiline /* ts */ `\n export async function uploadFile<T extends keyof TypeWithFiles>(\n type: T,\n field: TypeWithFiles[T][\"fields\"],\n recordId: string,\n data: string | ArrayBuffer | Uint8Array<ArrayBufferLike> | number[],\n options?: FileUploadOptions,\n ): Promise<FileUploadResponse> {\n return await file.upload(namespaces[type], type, field, recordId, data, options);\n }\n ` + \"\\n\";\n\n // Generate deleteFile helper function\n const deleteFunction =\n multiline /* ts */ `\n export async function deleteFile<T extends keyof TypeWithFiles>(\n type: T,\n field: TypeWithFiles[T][\"fields\"],\n recordId: string,\n ): Promise<void> {\n return await file.delete(namespaces[type], type, field, recordId);\n }\n ` + \"\\n\";\n\n // Generate getFileMetadata helper function\n const getMetadataFunction =\n multiline /* ts */ `\n export async function getFileMetadata<T extends keyof TypeWithFiles>(\n type: T,\n field: TypeWithFiles[T][\"fields\"],\n recordId: string,\n ): Promise<FileMetadata> {\n return await file.getMetadata(namespaces[type], type, field, recordId);\n }\n ` + \"\\n\";\n\n // Generate openFileDownloadStream helper function\n const openDownloadStreamFunction =\n multiline /* ts */ `\n export async function openFileDownloadStream<T extends keyof TypeWithFiles>(\n type: T,\n field: TypeWithFiles[T][\"fields\"],\n recordId: string,\n ): Promise<FileStreamIterator> {\n return await file.openDownloadStream(namespaces[type], type, field, recordId);\n }\n ` + \"\\n\";\n\n return [\n importStatement,\n interfaceDefinition,\n namespacesDefinition,\n downloadFunction,\n uploadFunction,\n deleteFunction,\n getMetadataFunction,\n openDownloadStreamFunction,\n ].join(\"\\n\");\n}\n","import type { TailorDBType } from \"#/parser/service/tailordb/types\";\nimport type { FileUtilMetadata } from \"./types\";\n\n/**\n * Process a TailorDB type and extract file field metadata.\n * @param type - The parsed TailorDB type to process\n * @returns File utility metadata for the type\n */\nexport async function processFileType(type: TailorDBType): Promise<FileUtilMetadata> {\n const fileFields: string[] = [];\n\n if (type.files) {\n for (const fileFieldName of Object.keys(type.files)) {\n fileFields.push(fileFieldName);\n }\n }\n\n return {\n name: type.name,\n fileFields,\n };\n}\n","import { generateUnifiedFileUtils } from \"./generate-file-utils\";\nimport { processFileType } from \"./process-file-type\";\nimport type { Plugin, GeneratorResult, TailorDBReadyContext } from \"#/plugin/types\";\nimport type { FileUtilMetadata } from \"./types\";\n\n/** Unique identifier for the file utilities generator plugin. */\nexport const FileUtilsGeneratorID = \"@tailor-platform/file-utils\";\n\ntype FileUtilsPluginOptions = {\n distPath: string;\n};\n\n/**\n * Plugin that generates TypeWithFiles interface from TailorDB type definitions.\n * @param options - Plugin options\n * @param options.distPath - Output file path for generated file utilities\n * @returns Plugin instance with onTailorDBReady hook\n */\nexport function fileUtilsPlugin(\n options: FileUtilsPluginOptions,\n): Plugin<unknown, FileUtilsPluginOptions> {\n return {\n id: FileUtilsGeneratorID,\n description: \"Generates TypeWithFiles interface from TailorDB type definitions\",\n pluginConfig: options,\n\n async onTailorDBReady(\n ctx: TailorDBReadyContext<FileUtilsPluginOptions>,\n ): Promise<GeneratorResult> {\n const namespaceData: { namespace: string; types: FileUtilMetadata[] }[] = [];\n\n for (const ns of ctx.tailordb) {\n const typesWithFiles: FileUtilMetadata[] = [];\n\n for (const type of Object.values(ns.types)) {\n const metadata = await processFileType(type);\n if (metadata.fileFields.length > 0) {\n typesWithFiles.push(metadata);\n }\n }\n\n if (typesWithFiles.length > 0) {\n namespaceData.push({\n namespace: ns.namespace,\n types: typesWithFiles,\n });\n }\n }\n\n const files: GeneratorResult[\"files\"] = [];\n if (namespaceData.length > 0) {\n const content = generateUnifiedFileUtils(namespaceData);\n if (content) {\n files.push({\n path: ctx.pluginConfig.distPath,\n content,\n });\n }\n }\n\n return { files };\n },\n };\n}\n"],"mappings":";;;;;;;;;AAQA,SAAgB,yBACd,eACQ;CACR,IAAI,cAAc,WAAW,GAC3B,OAAO;CAIT,MAAM,mCAAmB,IAAI,IAAoB;CACjD,MAAM,gCAAgB,IAAI,IAAsB;CAEhD,KAAK,MAAM,EAAE,WAAW,WAAW,eACjC,KAAK,MAAM,QAAQ,OAAO;EACxB,iBAAiB,IAAI,KAAK,MAAM,SAAS;EACzC,cAAc,IAAI,KAAK,MAAM,KAAK,UAAU;CAC9C;CAGF,IAAI,iBAAiB,SAAS,GAC5B,OAAO;CAIT,MAAM,kBAAkB,MAAM,KAAK,cAAc,QAAQ,CAAC,CAAC,CACxD,KAAK,CAAC,UAAU,YAAY;EAE3B,OAAO,KAAK,SAAS,mBADG,OAAO,KAAK,UAAU,IAAI,MAAM,EAAE,CAAC,CAAC,KAAK,KACX,EAAE;CAC1D,CAAC,CAAC,CACD,KAAK,IAAI;CA8FZ,OAAO;EA3FL,SAAmB;;;;;;;;QAQf;EAGJ,SAAmB;;QAEf,gBAAgB;;QAEhB;EAQJ,SAAmB;;QALI,MAAM,KAAK,iBAAiB,QAAQ,CAAC,CAAC,CAC5D,KAAK,CAAC,UAAU,eAAe,KAAK,SAAS,KAAK,UAAU,EAAE,CAAC,CAC/D,KAAK,KAKa,EAAE;;QAEjB;EAIJ,SAAmB;;;;;;;;QAQf;EAIJ,SAAmB;;;;;;;;;;QAUf;EAIJ,SAAmB;;;;;;;;QAQf;EAIJ,SAAmB;;;;;;;;QAQf;EAIJ,SAAmB;;;;;;;;QAQf;CAWN,CAAC,CAAC,KAAK,IAAI;AACb;;;;;;;;;ACpIA,eAAsB,gBAAgB,MAA+C;CACnF,MAAM,aAAuB,CAAC;CAE9B,IAAI,KAAK,OACP,KAAK,MAAM,iBAAiB,OAAO,KAAK,KAAK,KAAK,GAChD,WAAW,KAAK,aAAa;CAIjC,OAAO;EACL,MAAM,KAAK;EACX;CACF;AACF;;;;;ACfA,MAAa,uBAAuB;;;;;;;AAYpC,SAAgB,gBACd,SACyC;CACzC,OAAO;EACL,IAAI;EACJ,aAAa;EACb,cAAc;EAEd,MAAM,gBACJ,KAC0B;GAC1B,MAAM,gBAAoE,CAAC;GAE3E,KAAK,MAAM,MAAM,IAAI,UAAU;IAC7B,MAAM,iBAAqC,CAAC;IAE5C,KAAK,MAAM,QAAQ,OAAO,OAAO,GAAG,KAAK,GAAG;KAC1C,MAAM,WAAW,MAAM,gBAAgB,IAAI;KAC3C,IAAI,SAAS,WAAW,SAAS,GAC/B,eAAe,KAAK,QAAQ;IAEhC;IAEA,IAAI,eAAe,SAAS,GAC1B,cAAc,KAAK;KACjB,WAAW,GAAG;KACd,OAAO;IACT,CAAC;GAEL;GAEA,MAAM,QAAkC,CAAC;GACzC,IAAI,cAAc,SAAS,GAAG;IAC5B,MAAM,UAAU,yBAAyB,aAAa;IACtD,IAAI,SACF,MAAM,KAAK;KACT,MAAM,IAAI,aAAa;KACvB;IACF,CAAC;GAEL;GAEA,OAAO,EAAE,MAAM;EACjB;CACF;AACF"}
@@ -1,5 +1,5 @@
1
1
  declare namespace idp_d_exports {
2
- export { Client, ClientConfig, CreateUserInput, IdpClientConstructor, IdpClientInstance, ListUsersOptions, ListUsersResponse, SendPasswordResetEmailInput, TailorIdpAPI, UpdateUserInput, User, UserQuery };
2
+ export { Client, ClientConfig, CreateUserInput, IdpClientConstructor, IdpClientInstance, ListUsersOptions, ListUsersResponse, SendPasswordResetEmailInput, TailorIdpAPI, UnenrollMfaInput, UpdateUserInput, User, UserQuery };
3
3
  }
4
4
  /**
5
5
  * IDP (Identity Provider) utilities.
@@ -23,6 +23,16 @@ interface User {
23
23
  name: string;
24
24
  disabled: boolean;
25
25
  createdAt?: string;
26
+ /**
27
+ * True when the user has at least one enrolled MFA second factor. False when
28
+ * the namespace has MFA disabled or the user has not enrolled a factor.
29
+ */
30
+ mfaEnrolled: boolean;
31
+ /**
32
+ * Enrolled MFA second factor IDs. Pass an entry into
33
+ * {@link Client.unenrollMfa} to remove that factor.
34
+ */
35
+ mfaFactorIds: string[];
26
36
  }
27
37
  /** Filter options for {@link Client.users}. */
28
38
  interface UserQuery {
@@ -79,6 +89,16 @@ interface SendPasswordResetEmailInput {
79
89
  /** The email subject line. Defaults to the localized default subject. */
80
90
  subject?: string;
81
91
  }
92
+ /** Input for {@link Client.unenrollMfa}. */
93
+ interface UnenrollMfaInput {
94
+ /** The ID of the user whose factor will be unenrolled. */
95
+ userId: string;
96
+ /**
97
+ * The ID of the factor to unenroll. Factor IDs are exposed on the user
98
+ * record (see {@link User.mfaFactorIds}).
99
+ */
100
+ mfaFactorId: string;
101
+ }
82
102
  /** Instance methods exposed by `tailor.idp.Client`. */
83
103
  interface IdpClientInstance {
84
104
  users(options?: ListUsersOptions): Promise<ListUsersResponse>;
@@ -88,6 +108,7 @@ interface IdpClientInstance {
88
108
  updateUser(input: UpdateUserInput): Promise<User>;
89
109
  deleteUser(userId: string): Promise<boolean>;
90
110
  sendPasswordResetEmail(input: SendPasswordResetEmailInput): Promise<boolean>;
111
+ unenrollMfa(input: UnenrollMfaInput): Promise<boolean>;
91
112
  }
92
113
  /**
93
114
  * Constructor shape for `tailor.idp.Client`.
@@ -154,7 +175,13 @@ declare class Client {
154
175
  * @returns `true` when the email was queued
155
176
  */
156
177
  sendPasswordResetEmail(input: SendPasswordResetEmailInput): Promise<boolean>;
178
+ /**
179
+ * Unenroll an MFA factor from a user.
180
+ * @param input - Target user ID and factor ID (see {@link User.mfaFactorIds})
181
+ * @returns `true` when the factor was removed
182
+ */
183
+ unenrollMfa(input: UnenrollMfaInput): Promise<boolean>;
157
184
  }
158
185
  //#endregion
159
- export { IdpClientInstance as a, SendPasswordResetEmailInput as c, User as d, UserQuery as f, IdpClientConstructor as i, TailorIdpAPI as l, ClientConfig as n, ListUsersOptions as o, idp_d_exports as p, CreateUserInput as r, ListUsersResponse as s, Client as t, UpdateUserInput as u };
160
- //# sourceMappingURL=idp-BlBPtXJ-.d.mts.map
186
+ export { IdpClientInstance as a, SendPasswordResetEmailInput as c, UpdateUserInput as d, User as f, IdpClientConstructor as i, TailorIdpAPI as l, idp_d_exports as m, ClientConfig as n, ListUsersOptions as o, UserQuery as p, CreateUserInput as r, ListUsersResponse as s, Client as t, UnenrollMfaInput as u };
187
+ //# sourceMappingURL=idp-BmYwCXnJ.d.mts.map
@@ -69,8 +69,16 @@ var Client = class {
69
69
  sendPasswordResetEmail(input) {
70
70
  return this.#impl.sendPasswordResetEmail(input);
71
71
  }
72
+ /**
73
+ * Unenroll an MFA factor from a user.
74
+ * @param input - Target user ID and factor ID (see {@link User.mfaFactorIds})
75
+ * @returns `true` when the factor was removed
76
+ */
77
+ unenrollMfa(input) {
78
+ return this.#impl.unenrollMfa(input);
79
+ }
72
80
  };
73
81
 
74
82
  //#endregion
75
83
  export { idp_exports as n, Client as t };
76
- //# sourceMappingURL=idp-BZPqpcYY.mjs.map
84
+ //# sourceMappingURL=idp-ynUfzwpz.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"idp-ynUfzwpz.mjs","names":["#impl"],"sources":["../src/runtime/idp.ts"],"sourcesContent":["/**\n * IDP (Identity Provider) utilities.\n *\n * Thin typed wrapper around the platform-provided `tailor.idp` runtime API.\n * At runtime this delegates to `globalThis.tailor.idp`. Use `mockIdp` from\n * `@tailor-platform/sdk/vitest` to mock these calls in unit tests.\n * @example\n * import { idp } from \"@tailor-platform/sdk/runtime\";\n *\n * const client = new idp.Client({ namespace: \"my-namespace\" });\n * const { users } = await client.users({ first: 10 });\n */\n\n/** Configuration object for {@link Client}. */\nexport interface ClientConfig {\n namespace: string;\n}\n\n/** User record returned by IDP operations. */\nexport interface User {\n id: string;\n name: string;\n disabled: boolean;\n createdAt?: string;\n /**\n * True when the user has at least one enrolled MFA second factor. False when\n * the namespace has MFA disabled or the user has not enrolled a factor.\n */\n mfaEnrolled: boolean;\n /**\n * Enrolled MFA second factor IDs. Pass an entry into\n * {@link Client.unenrollMfa} to remove that factor.\n */\n mfaFactorIds: string[];\n}\n\n/** Filter options for {@link Client.users}. */\nexport interface UserQuery {\n /** Filter by user IDs */\n ids?: string[];\n /** Filter by user names */\n names?: string[];\n}\n\n/** Pagination/filter options for {@link Client.users}. */\nexport interface ListUsersOptions {\n /** Maximum number of users to return */\n first?: number;\n /** Page token for pagination */\n after?: string;\n /** Query filter for users */\n query?: UserQuery;\n}\n\n/** Response shape for {@link Client.users}. */\nexport interface ListUsersResponse {\n users: User[];\n nextPageToken: string | null;\n totalCount: number;\n}\n\n/** Input for {@link Client.createUser}. */\nexport interface CreateUserInput {\n /** The user's name (typically email) */\n name: string;\n /** The user's password. If omitted, the user is created without a password (cannot log in with any password). */\n password?: string;\n /** Whether the user is disabled */\n disabled?: boolean;\n}\n\n/** Input for {@link Client.updateUser}. */\nexport interface UpdateUserInput {\n /** The user's ID */\n id: string;\n /** New name for the user */\n name?: string;\n /** New password for the user. Cannot be used with clearPassword. */\n password?: string;\n /** If true, remove the user's password. Cannot be used with password. */\n clearPassword?: boolean;\n /** New disabled status for the user */\n disabled?: boolean;\n}\n\n/** Input for {@link Client.sendPasswordResetEmail}. */\nexport interface SendPasswordResetEmailInput {\n /** The ID of the user */\n userId: string;\n /** The URI to redirect to after password reset */\n redirectUri: string;\n /** The sender display name. Defaults to 'Tailor Platform IdP'. */\n fromName?: string;\n /** The email subject line. Defaults to the localized default subject. */\n subject?: string;\n}\n\n/** Input for {@link Client.unenrollMfa}. */\nexport interface UnenrollMfaInput {\n /** The ID of the user whose factor will be unenrolled. */\n userId: string;\n /**\n * The ID of the factor to unenroll. Factor IDs are exposed on the user\n * record (see {@link User.mfaFactorIds}).\n */\n mfaFactorId: string;\n}\n\n/** Instance methods exposed by `tailor.idp.Client`. */\nexport interface IdpClientInstance {\n users(options?: ListUsersOptions): Promise<ListUsersResponse>;\n user(userId: string): Promise<User>;\n userByName(name: string): Promise<User>;\n createUser(input: CreateUserInput): Promise<User>;\n updateUser(input: UpdateUserInput): Promise<User>;\n deleteUser(userId: string): Promise<boolean>;\n sendPasswordResetEmail(input: SendPasswordResetEmailInput): Promise<boolean>;\n unenrollMfa(input: UnenrollMfaInput): Promise<boolean>;\n}\n\n/**\n * Constructor shape for `tailor.idp.Client`.\n * @internal\n */\nexport interface IdpClientConstructor {\n new (config: ClientConfig): IdpClientInstance;\n}\n\n/**\n * Platform API surface for `tailor.idp`. Describes the shape the platform\n * runtime injects on `globalThis.tailor.idp`.\n * @internal\n */\nexport interface TailorIdpAPI {\n Client: IdpClientConstructor;\n}\n\n/**\n * IDP Client for user management operations.\n *\n * Wraps the platform-provided `tailor.idp.Client` and exposes the same surface.\n */\nexport class Client {\n #impl: IdpClientInstance;\n\n constructor(config: ClientConfig) {\n this.#impl = new (globalThis as { tailor: { idp: TailorIdpAPI } }).tailor.idp.Client(config);\n }\n\n /**\n * List users in the namespace with optional filtering and pagination.\n * @param options - Pagination and filter options\n * @returns Page of users with `nextPageToken` and `totalCount`\n */\n users(options?: ListUsersOptions): Promise<ListUsersResponse> {\n return this.#impl.users(options);\n }\n\n /**\n * Get a user by ID.\n * @param userId - IDP user ID\n * @returns The matching user\n */\n user(userId: string): Promise<User> {\n return this.#impl.user(userId);\n }\n\n /**\n * Get a user by name.\n * @param name - IDP user name\n * @returns The matching user\n */\n userByName(name: string): Promise<User> {\n return this.#impl.userByName(name);\n }\n\n /**\n * Create a new user.\n * @param input - User attributes\n * @returns The newly created user\n */\n createUser(input: CreateUserInput): Promise<User> {\n return this.#impl.createUser(input);\n }\n\n /**\n * Update an existing user.\n * @param input - User ID plus attributes to update\n * @returns The updated user\n */\n updateUser(input: UpdateUserInput): Promise<User> {\n return this.#impl.updateUser(input);\n }\n\n /**\n * Delete a user by ID.\n * @param userId - IDP user ID\n * @returns `true` when the user was deleted\n */\n deleteUser(userId: string): Promise<boolean> {\n return this.#impl.deleteUser(userId);\n }\n\n /**\n * Send a password reset email to a user.\n * @param input - Target user ID and redirect URI\n * @returns `true` when the email was queued\n */\n sendPasswordResetEmail(input: SendPasswordResetEmailInput): Promise<boolean> {\n return this.#impl.sendPasswordResetEmail(input);\n }\n\n /**\n * Unenroll an MFA factor from a user.\n * @param input - Target user ID and factor ID (see {@link User.mfaFactorIds})\n * @returns `true` when the factor was removed\n */\n unenrollMfa(input: UnenrollMfaInput): Promise<boolean> {\n return this.#impl.unenrollMfa(input);\n }\n}\n"],"mappings":";;;;;;;;;;AA8IA,IAAa,SAAb,MAAoB;CAClB;CAEA,YAAY,QAAsB;EAChC,KAAKA,QAAQ,IAAK,WAAiD,OAAO,IAAI,OAAO,MAAM;CAC7F;;;;;;CAOA,MAAM,SAAwD;EAC5D,OAAO,KAAKA,MAAM,MAAM,OAAO;CACjC;;;;;;CAOA,KAAK,QAA+B;EAClC,OAAO,KAAKA,MAAM,KAAK,MAAM;CAC/B;;;;;;CAOA,WAAW,MAA6B;EACtC,OAAO,KAAKA,MAAM,WAAW,IAAI;CACnC;;;;;;CAOA,WAAW,OAAuC;EAChD,OAAO,KAAKA,MAAM,WAAW,KAAK;CACpC;;;;;;CAOA,WAAW,OAAuC;EAChD,OAAO,KAAKA,MAAM,WAAW,KAAK;CACpC;;;;;;CAOA,WAAW,QAAkC;EAC3C,OAAO,KAAKA,MAAM,WAAW,MAAM;CACrC;;;;;;CAOA,uBAAuB,OAAsD;EAC3E,OAAO,KAAKA,MAAM,uBAAuB,KAAK;CAChD;;;;;;CAOA,YAAY,OAA2C;EACrD,OAAO,KAAKA,MAAM,YAAY,KAAK;CACrC;AACF"}