@tailor-platform/sdk 2.22.0 → 2.23.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 (88) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/aigateway-DsWDjzk4.mjs.map +1 -1
  3. package/dist/application-BtZ8hmx9.mjs +1 -0
  4. package/dist/{application-BzO9ywXQ.mjs → application-m2G91kKI.mjs} +2 -2
  5. package/dist/application-m2G91kKI.mjs.map +1 -0
  6. package/dist/assert-WeXvmG4j.mjs.map +1 -1
  7. package/dist/authconnection-CynFBIv8.mjs.map +1 -1
  8. package/dist/brand-C8nMKhJC.mjs.map +1 -1
  9. package/dist/cli/lib.mjs +1 -1
  10. package/dist/cli/lib.mjs.map +1 -1
  11. package/dist/cli/main.mjs +33 -33
  12. package/dist/cli/main.mjs.map +1 -1
  13. package/dist/cli/shared/client.d.mts +17 -2
  14. package/dist/completion/zsh-worker.zsh +13 -7
  15. package/dist/configure/index.mjs.map +1 -1
  16. package/dist/context-D0QjfxzD.mjs.map +1 -1
  17. package/dist/crashreport-DFpRn-LS.mjs.map +1 -1
  18. package/dist/date-Dri6Yas-.mjs.map +1 -1
  19. package/dist/errors-CpvSChyL.mjs +7 -0
  20. package/dist/errors-CpvSChyL.mjs.map +1 -0
  21. package/dist/es-builtins-SfvXRVoG.mjs.map +1 -1
  22. package/dist/field-parse-DhnFs9WG.mjs.map +1 -1
  23. package/dist/file-DKBOj5q4.mjs.map +1 -1
  24. package/dist/globals-BCmGX05J.mjs.map +1 -1
  25. package/dist/guards-yDXyKC9F.mjs.map +1 -1
  26. package/dist/iconv-DlFMt2gW.mjs.map +1 -1
  27. package/dist/idp-G_ojPBB5.mjs.map +1 -1
  28. package/dist/interceptor-DQg3cR_9.mjs.map +1 -1
  29. package/dist/kysely/index.mjs.map +1 -1
  30. package/dist/kysely-type-C-iyFFH7.mjs.map +1 -1
  31. package/dist/logger-DP2BjQ93.mjs.map +1 -1
  32. package/dist/logger-Db-YRTwK.mjs.map +1 -1
  33. package/dist/manager-8-JOvuLl.mjs.map +1 -1
  34. package/dist/multiline-EyzjEwn9.mjs.map +1 -1
  35. package/dist/node-builtins-DYfhPBnz.mjs.map +1 -1
  36. package/dist/package-json-C690ceex.mjs.map +1 -1
  37. package/dist/platform-serialize-DkiTdHOt.mjs.map +1 -1
  38. package/dist/plugin/builtin/enum-constants/index.mjs.map +1 -1
  39. package/dist/plugin/builtin/file-utils/index.mjs.map +1 -1
  40. package/dist/plugin/index.mjs.map +1 -1
  41. package/dist/{register-ts-hook-z7ggXQy4.mjs → register-ts-hook-ztnEFW6n.mjs} +49 -49
  42. package/dist/register-ts-hook-ztnEFW6n.mjs.map +1 -0
  43. package/dist/registry-BijIDRVA.mjs.map +1 -1
  44. package/dist/repl-editor-DGJBfIt1.mjs.map +1 -1
  45. package/dist/schema-CRtAmDcl.mjs.map +1 -1
  46. package/dist/secret-file-C9wp_FCX.mjs.map +1 -1
  47. package/dist/secretmanager-5olfnI1b.mjs.map +1 -1
  48. package/dist/secretmanager-vHQoXdQz.mjs.map +1 -1
  49. package/dist/seed/index.mjs.map +1 -1
  50. package/dist/seed-C3P_T_Eh.mjs.map +1 -1
  51. package/dist/service-CL1Bp4It.mjs.map +1 -1
  52. package/dist/{service-DHVuH7-X.mjs → service-DFmt9UJP.mjs} +2 -2
  53. package/dist/service-DFmt9UJP.mjs.map +1 -0
  54. package/dist/service_pb-ZClWtj1X.mjs +2 -0
  55. package/dist/service_pb-ZClWtj1X.mjs.map +1 -0
  56. package/dist/service_pb-dB3RrGeh.mjs +1 -0
  57. package/dist/tailor-proto/src/tailor/v1/function_pb.d.mts +83 -1
  58. package/dist/tailor-proto/src/tailor/v1/function_resource_pb.d.mts +7 -1
  59. package/dist/tailor-proto/src/tailor/v1/service_pb.d.mts +79 -7
  60. package/dist/tailor-proto/src/tailor/v1/workflow_pb.d.mts +40 -1
  61. package/dist/tailor-proto/src/tailor/v1/workflow_resource_pb.d.mts +119 -2
  62. package/dist/tailor-proto/src/tailor/v1/workspace_pb.d.mts +7 -0
  63. package/dist/tailordb-ddl-DqInYupv.mjs.map +1 -1
  64. package/dist/telemetry-Bklv9kQY.mjs.map +1 -1
  65. package/dist/type-source--ZNcV8RJ.mjs.map +1 -1
  66. package/dist/user-agent-vdHYF3QL.mjs.map +1 -1
  67. package/dist/utils/test/index.mjs.map +1 -1
  68. package/dist/vitest/environment.mjs.map +1 -1
  69. package/dist/vitest/index.mjs.map +1 -1
  70. package/dist/vitest/setup.mjs.map +1 -1
  71. package/dist/wait-point-invoker-eiP-IIux.mjs.map +1 -1
  72. package/dist/wait-point-registry-B-ESkTZX.mjs.map +1 -1
  73. package/dist/workflow-Cs9ISw6j.mjs.map +1 -1
  74. package/dist/{workspace_resource_pb-D2njwgsE.mjs → workspace_resource_pb-CxR_6fyN.mjs} +2 -2
  75. package/dist/workspace_resource_pb-CxR_6fyN.mjs.map +1 -0
  76. package/docs/cli/application.md +23 -5
  77. package/docs/cli/function.md +2 -2
  78. package/package.json +3 -3
  79. package/dist/application-BE4vehXW.mjs +0 -1
  80. package/dist/application-BzO9ywXQ.mjs.map +0 -1
  81. package/dist/errors-C9zGf4nz.mjs +0 -7
  82. package/dist/errors-C9zGf4nz.mjs.map +0 -1
  83. package/dist/register-ts-hook-z7ggXQy4.mjs.map +0 -1
  84. package/dist/service-DHVuH7-X.mjs.map +0 -1
  85. package/dist/service_pb-DNskuJQC.mjs +0 -1
  86. package/dist/service_pb-y2GYIgfs.mjs +0 -2
  87. package/dist/service_pb-y2GYIgfs.mjs.map +0 -1
  88. package/dist/workspace_resource_pb-D2njwgsE.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"context-D0QjfxzD.mjs","names":[],"sources":["../src/runtime/context.ts"],"sourcesContent":["/**\n * Execution context utilities.\n *\n * Thin typed wrapper around the platform-provided `tailor.context` runtime API.\n * At runtime this delegates to `globalThis.tailor.context`.\n * @example\n * import { context } from \"@tailor-platform/sdk/runtime\";\n *\n * const invoker = context.getInvoker();\n * if (invoker) {\n * console.log(invoker.id, invoker.type, invoker.attributes, invoker.attributeList);\n * }\n */\n\nimport type { TailorPrincipal } from \"#/runtime/types\";\n\n/**\n * Information about the invoker of the current function execution.\n *\n * Matches the public `TailorPrincipal` shape — `attributes` is the attribute\n * map and `attributeList` is the array of attribute IDs.\n */\nexport type Invoker = TailorPrincipal;\n\n/**\n * Raw platform-side invoker payload returned by `tailor.context.getInvoker()`.\n * The wrapper normalizes this into {@link Invoker}.\n * @internal\n */\nexport interface ContextInvoker {\n /** The invoker's ID */\n id: string;\n /** The invoker's type */\n type: \"user\" | \"machine_user\";\n /** The workspace ID */\n workspaceId: string;\n /** The invoker's attribute IDs */\n attributes: string[];\n /** The invoker's attribute map */\n attributeMap: Record<string, unknown>;\n}\n\n/**\n * Platform API surface for `tailor.context`. Describes the shape the platform\n * runtime injects on `globalThis.tailor.context`.\n * @internal\n */\nexport interface PlatformContextAPI {\n getInvoker(): ContextInvoker | null;\n}\n\n/** Runtime wrapper API for execution context utilities. */\nexport interface TailorContextAPI {\n /**\n * Returns information about the current invoker.\n * @returns Invoker details, or `null` for anonymous invocations\n */\n getInvoker(): Invoker | null;\n}\n\n/**\n * Returns information about the invoker of the current function execution,\n * or `null` for anonymous invocations.\n * @returns Invoker details, or `null` when the call is anonymous\n */\nfunction getInvoker(): Invoker | null {\n const raw = (\n globalThis as unknown as { tailor: { context: PlatformContextAPI } }\n ).tailor.context.getInvoker();\n if (!raw) return null;\n return {\n id: raw.id,\n type: raw.type,\n workspaceId: raw.workspaceId,\n attributes: raw.attributeMap as Invoker[\"attributes\"],\n attributeList: raw.attributes as Invoker[\"attributeList\"],\n };\n}\n\n/** Runtime wrapper namespace for `tailor.context`. */\nexport const context = { getInvoker } as const satisfies TailorContextAPI;\n"],"mappings":"AAiEA,SAAS,YAA6B,CACpC,IAAM,EACJ,WACA,OAAO,QAAQ,WAAW,EAE5B,OADK,EACE,CACL,GAAI,EAAI,GACR,KAAM,EAAI,KACV,YAAa,EAAI,YACjB,WAAY,EAAI,aAChB,cAAe,EAAI,UACrB,EAPiB,IAQnB,CAGA,MAAa,EAAU,CAAE,UAAW"}
1
+ {"version":3,"file":"context-D0QjfxzD.mjs","names":["raw","context"],"sources":["../src/runtime/context.ts"],"sourcesContent":["/**\n * Execution context utilities.\n *\n * Thin typed wrapper around the platform-provided `tailor.context` runtime API.\n * At runtime this delegates to `globalThis.tailor.context`.\n * @example\n * import { context } from \"@tailor-platform/sdk/runtime\";\n *\n * const invoker = context.getInvoker();\n * if (invoker) {\n * console.log(invoker.id, invoker.type, invoker.attributes, invoker.attributeList);\n * }\n */\n\nimport type { TailorPrincipal } from \"#/runtime/types\";\n\n/**\n * Information about the invoker of the current function execution.\n *\n * Matches the public `TailorPrincipal` shape — `attributes` is the attribute\n * map and `attributeList` is the array of attribute IDs.\n */\nexport type Invoker = TailorPrincipal;\n\n/**\n * Raw platform-side invoker payload returned by `tailor.context.getInvoker()`.\n * The wrapper normalizes this into {@link Invoker}.\n * @internal\n */\nexport interface ContextInvoker {\n /** The invoker's ID */\n id: string;\n /** The invoker's type */\n type: \"user\" | \"machine_user\";\n /** The workspace ID */\n workspaceId: string;\n /** The invoker's attribute IDs */\n attributes: string[];\n /** The invoker's attribute map */\n attributeMap: Record<string, unknown>;\n}\n\n/**\n * Platform API surface for `tailor.context`. Describes the shape the platform\n * runtime injects on `globalThis.tailor.context`.\n * @internal\n */\nexport interface PlatformContextAPI {\n getInvoker(): ContextInvoker | null;\n}\n\n/** Runtime wrapper API for execution context utilities. */\nexport interface TailorContextAPI {\n /**\n * Returns information about the current invoker.\n * @returns Invoker details, or `null` for anonymous invocations\n */\n getInvoker(): Invoker | null;\n}\n\n/**\n * Returns information about the invoker of the current function execution,\n * or `null` for anonymous invocations.\n * @returns Invoker details, or `null` when the call is anonymous\n */\nfunction getInvoker(): Invoker | null {\n const raw = (\n globalThis as unknown as { tailor: { context: PlatformContextAPI } }\n ).tailor.context.getInvoker();\n if (!raw) return null;\n return {\n id: raw.id,\n type: raw.type,\n workspaceId: raw.workspaceId,\n attributes: raw.attributeMap as Invoker[\"attributes\"],\n attributeList: raw.attributes as Invoker[\"attributeList\"],\n };\n}\n\n/** Runtime wrapper namespace for `tailor.context`. */\nexport const context = { getInvoker } as const satisfies TailorContextAPI;\n"],"mappings":"AAiEA,SAAS,YAA6B,CACpC,IAAMA,EACJ,WACA,OAAO,QAAQ,WAAW,EAE5B,OADKA,EACE,CACL,GAAIA,EAAI,GACR,KAAMA,EAAI,KACV,YAAaA,EAAI,YACjB,WAAYA,EAAI,aAChB,cAAeA,EAAI,UACrB,EAPiB,IAQnB,CAGA,MAAaC,EAAU,CAAE,UAAW"}
@@ -1 +1 @@
1
- {"version":3,"file":"crashreport-DFpRn-LS.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 { redactSecrets } from \"#/cli/shared/logger\";\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: `redactSecrets` masks every registered\n * secret first, then the pattern-based sanitizers below strip known-shape values (UUIDs,\n * long hex, emails, paths) from what's left. `redactSecrets` must run first — the path\n * sanitizer intentionally keeps a path's basename (e.g. `/home/user/.../key.json` becomes\n * `<path>/key.json`), so a registered secret shaped like a path would have that basename\n * survive if the pattern sanitizer ran on it first. This report is written to a local file\n * (and optionally sent remotely) outside the CLI's normal stderr path.\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(redactSecrets(parseCommand())),\n argv: sanitizeArgv(process.argv.map(redactSecrets)),\n errorName: redactSecrets(errorName),\n errorMessage: sanitizeMessage(redactSecrets(rawMessage)),\n stackTrace: sanitizeStackTrace(redactSecrets(rawStack)),\n errorType,\n userId: currentUser?.id ? redactSecrets(currentUser.id) : null,\n userEmail: currentUser?.email ? redactSecrets(currentUser.email) : null,\n };\n}\n\ntype CurrentUser = {\n id: string;\n email: string | null;\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 ID and email, or null if unavailable\n */\nfunction readCurrentUser(): CurrentUser | 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 {\n current_user?: string | null;\n users?: Record<string, { email?: unknown } | undefined>;\n };\n // parseYAML returns null for empty documents\n // oxlint-disable-next-line typescript/no-unnecessary-condition\n const currentUser = raw?.current_user ?? null;\n if (!currentUser) return null;\n const email = raw.users?.[currentUser]?.email;\n return {\n id: currentUser,\n email: typeof email === \"string\" ? email : legacyEmail(currentUser),\n };\n } catch {\n return null;\n }\n}\n\nfunction legacyEmail(user: string): string | null {\n return user.includes(\"@\") ? user : null;\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 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":"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"}
1
+ {"version":3,"file":"crashreport-DFpRn-LS.mjs","names":["redactSecrets","logger","readPackageJson","userAgentFromVersion","writeSecretFile","ensureSecretDir","path","fs","crypto","os","isCI","localEnabled","remoteEnabled","localDir","xdgConfig","JSON_FOOTER_MARKER","CRASH_LOG_EXTENSION","report","files","dir","f","file","filename","filePath","content","endpoint","response","ua","data","HOME_DIR","UUID_PATTERN","LONG_HEX_PATTERN","EMAIL_PATTERN","ABSOLUTE_PATH_PATTERN","WINDOWS_PATH_PATTERN","URL_QUERY_PATTERN","EMAIL_TEST_PATTERN","WINDOWS_DRIVE_TEST_PATTERN","SDK_PACKAGE_MARKER","separator","firstFrameIndex","stack","result","sdkIndex","match","normalized","message","redactNext","arg","argv","eqIndex","args","commandParts","options","isError","error","rawMessage","rawStack","errorName","currentUser","configPath","raw","parseYAML","email","user","config","sdkVersion","errorType","reason"],"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 { redactSecrets } from \"#/cli/shared/logger\";\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: `redactSecrets` masks every registered\n * secret first, then the pattern-based sanitizers below strip known-shape values (UUIDs,\n * long hex, emails, paths) from what's left. `redactSecrets` must run first — the path\n * sanitizer intentionally keeps a path's basename (e.g. `/home/user/.../key.json` becomes\n * `<path>/key.json`), so a registered secret shaped like a path would have that basename\n * survive if the pattern sanitizer ran on it first. This report is written to a local file\n * (and optionally sent remotely) outside the CLI's normal stderr path.\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(redactSecrets(parseCommand())),\n argv: sanitizeArgv(process.argv.map(redactSecrets)),\n errorName: redactSecrets(errorName),\n errorMessage: sanitizeMessage(redactSecrets(rawMessage)),\n stackTrace: sanitizeStackTrace(redactSecrets(rawStack)),\n errorType,\n userId: currentUser?.id ? redactSecrets(currentUser.id) : null,\n userEmail: currentUser?.email ? redactSecrets(currentUser.email) : null,\n };\n}\n\ntype CurrentUser = {\n id: string;\n email: string | null;\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 ID and email, or null if unavailable\n */\nfunction readCurrentUser(): CurrentUser | 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 {\n current_user?: string | null;\n users?: Record<string, { email?: unknown } | undefined>;\n };\n // parseYAML returns null for empty documents\n // oxlint-disable-next-line typescript/no-unnecessary-condition\n const currentUser = raw?.current_user ?? null;\n if (!currentUser) return null;\n const email = raw.users?.[currentUser]?.email;\n return {\n id: currentUser,\n email: typeof email === \"string\" ? email : legacyEmail(currentUser),\n };\n } catch {\n return null;\n }\n}\n\nfunction legacyEmail(user: string): string | null {\n return user.includes(\"@\") ? user : null;\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 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":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"date-Dri6Yas-.mjs","names":[],"sources":["../src/runtime/temporal.ts","../src/runtime/date.ts"],"sourcesContent":["import type { Temporal as TemporalTypes } from \"temporal-spec\";\n\n/**\n * Get the host Temporal implementation when a value is needed.\n * @returns Host Temporal implementation\n * @internal\n */\nexport function getTemporal(): typeof TemporalTypes {\n const temporal = (globalThis as unknown as { Temporal?: typeof TemporalTypes }).Temporal;\n if (!temporal) {\n throw new ReferenceError(\n \"Temporal is unavailable. Use the Tailor Platform runtime or the SDK tailor-runtime Vitest environment.\",\n );\n }\n return temporal;\n}\n\n/**\n * Typed access to the runtime's Temporal API, without installing a polyfill.\n * Constructors are resolved on access so configuration files can load in Node.js.\n * @example\n * import { Temporal } from \"@tailor-platform/sdk/runtime\";\n * const tomorrow: Temporal.PlainDate = Temporal.Now.plainDateISO().add({ days: 1 });\n */\nexport const Temporal: typeof TemporalTypes = {\n get PlainDate() {\n return getTemporal().PlainDate;\n },\n get PlainTime() {\n return getTemporal().PlainTime;\n },\n get PlainDateTime() {\n return getTemporal().PlainDateTime;\n },\n get PlainYearMonth() {\n return getTemporal().PlainYearMonth;\n },\n get PlainMonthDay() {\n return getTemporal().PlainMonthDay;\n },\n get ZonedDateTime() {\n return getTemporal().ZonedDateTime;\n },\n get Duration() {\n return getTemporal().Duration;\n },\n get Instant() {\n return getTemporal().Instant;\n },\n get Now() {\n return getTemporal().Now;\n },\n};\n\n/** Temporal instance types supplied by the SDK, independent of TypeScript's lib settings. */\n// Type-only merging supports Temporal.PlainDate annotations on the value import.\n// oxlint-disable-next-line typescript/no-namespace\nexport declare namespace Temporal {\n /** The runtime Temporal.PlainDate instance. */\n type PlainDate = TemporalTypes.PlainDate;\n /** The runtime Temporal.PlainTime instance. */\n type PlainTime = TemporalTypes.PlainTime;\n /** The runtime Temporal.PlainDateTime instance. */\n type PlainDateTime = TemporalTypes.PlainDateTime;\n /** The runtime Temporal.PlainYearMonth instance. */\n type PlainYearMonth = TemporalTypes.PlainYearMonth;\n /** The runtime Temporal.PlainMonthDay instance. */\n type PlainMonthDay = TemporalTypes.PlainMonthDay;\n /** The runtime Temporal.ZonedDateTime instance. */\n type ZonedDateTime = TemporalTypes.ZonedDateTime;\n /** The runtime Temporal.Duration instance. */\n type Duration = TemporalTypes.Duration;\n /** The runtime Temporal.Instant instance. */\n type Instant = TemporalTypes.Instant;\n}\n","import { getTemporal } from \"./temporal\";\nimport type { FieldMetadata, TailorFieldType } from \"#/configure/types/field.types\";\nimport type { Temporal } from \"temporal-spec\";\n\n/**\n * Format a Date using its UTC calendar date.\n * @param date - Date to format\n * @returns Date string in YYYY-MM-DD format\n */\nexport function formatDate(date: Date): string {\n return formatDateTime(date).slice(0, 10);\n}\n\nfunction formatDateTime(date: Date): string {\n const year = date.getUTCFullYear();\n if (!Number.isFinite(year) || year < 0 || year > 9999) {\n const received = Number.isNaN(date.getTime()) ? \"an invalid Date\" : `year ${year}`;\n throw new RangeError(\n `Expected a Date with a 4-digit year (0000-9999), but received ${received}`,\n );\n }\n return date.toISOString();\n}\n\nfunction formatHoursMinutes(hour: number, minute: number): string {\n return `${String(hour).padStart(2, \"0\")}:${String(minute).padStart(2, \"0\")}`;\n}\n\nfunction formatTime(date: Date): string {\n if (!Number.isFinite(date.getTime())) {\n throw new RangeError(\"Expected a valid Date, but received an invalid Date\");\n }\n return formatHoursMinutes(date.getUTCHours(), date.getUTCMinutes());\n}\n\nfunction formatTemporal(value: Temporal.PlainDate | Temporal.Instant | Temporal.PlainTime): string {\n const Temporal = getTemporal();\n if (value instanceof Temporal.PlainTime) return formatHoursMinutes(value.hour, value.minute);\n const iso = value.toString({ calendarName: \"never\" });\n if (!/^\\d{4}-/.test(iso)) {\n const isInstant = value instanceof Temporal.Instant;\n throw new RangeError(\n `Expected a Temporal.${isInstant ? \"Instant\" : \"PlainDate\"} with a 4-digit ${isInstant ? \"UTC \" : \"\"}year (0000-9999), but received ${iso}`,\n );\n }\n return iso;\n}\n\ntype DateField = {\n readonly type: TailorFieldType;\n readonly metadata: FieldMetadata;\n readonly fields: Record<string, DateField>;\n};\n\ntype DateRepresentationField = {\n readonly type: TailorFieldType;\n readonly metadata: Pick<FieldMetadata, \"as\">;\n readonly fields: Record<string, DateRepresentationField>;\n};\n\nfunction serialize(field: DateField, value: unknown, path: string): unknown {\n if (field.metadata.array) {\n if (!Array.isArray(value)) return value;\n const converted = value.map((item, index) => serializeValue(field, item, `${path}[${index}]`));\n return converted.every((item, index) => item === value[index]) ? value : converted;\n }\n return serializeValue(field, value, path);\n}\n\nfunction describePathTarget(path: string): string {\n return path || \"the top-level value\";\n}\n\nconst MAX_DESCRIBED_VALUE_LENGTH = 100;\nconst MAX_DESCRIBED_ARRAY_SAMPLE = 100;\n\nfunction truncateForDescription(text: string): string {\n return text.length > MAX_DESCRIBED_VALUE_LENGTH\n ? `${text.slice(0, MAX_DESCRIBED_VALUE_LENGTH)}...`\n : text;\n}\n\nfunction describeReceivedValue(value: unknown): string {\n if (Array.isArray(value)) {\n const sample = value.slice(0, MAX_DESCRIBED_ARRAY_SAMPLE);\n const elementTypes = [...new Set(Array.from(sample, (item) => typeof item))];\n return elementTypes.length > 0 ? `an array of ${elementTypes.join(\"/\")}` : \"an empty array\";\n }\n if (typeof value === \"string\")\n return `a string (${JSON.stringify(truncateForDescription(value))})`;\n const type = typeof value;\n if (type === \"object\") return \"an object\";\n if (type === \"function\") return \"a function\";\n return `a ${type} (${truncateForDescription(String(value))})`;\n}\n\ntype DateRepresentation = \"date\" | \"temporal\";\n\n/**\n * Get the Date or Temporal representation a field converts its values to.\n * @param type - Field type\n * @param as - The field's `as` option\n * @returns The representation, or undefined when values stay strings\n * @internal\n */\nexport function dateRepresentationOf(\n type: TailorFieldType,\n as: FieldMetadata[\"as\"],\n): DateRepresentation | undefined {\n return (type === \"date\" || type === \"datetime\" || type === \"time\") &&\n (as === \"date\" || as === \"temporal\")\n ? as\n : undefined;\n}\n\nfunction isDateRepresentationField(\n field: DateRepresentationField,\n representation?: DateRepresentation,\n): boolean {\n const as = dateRepresentationOf(field.type, field.metadata.as);\n return as !== undefined && (representation === undefined || as === representation);\n}\n\ntype DateSerializer = (type: TailorFieldType, value: unknown, path: string) => string;\n\nfunction throwInvalidDate(error: unknown, path: string): never {\n const reason = error instanceof Error ? error.message : String(error);\n throw new RangeError(`Invalid date at ${describePathTarget(path)}: ${reason}`, {\n cause: error,\n });\n}\n\nfunction serializeAsDate(type: TailorFieldType, value: unknown, path: string): string {\n if (!(value instanceof Date)) {\n throw new TypeError(\n `Expected a Date instance at ${describePathTarget(path)}, but received ${describeReceivedValue(value)}`,\n );\n }\n try {\n if (type === \"datetime\") return formatDateTime(value);\n if (type === \"time\") return formatTime(value);\n return formatDate(value);\n } catch (error) {\n return throwInvalidDate(error, path);\n }\n}\n\nfunction serializeAsTemporal(type: TailorFieldType, value: unknown, path: string): string {\n const Temporal = getTemporal();\n const expected =\n type === \"date\"\n ? Temporal.PlainDate\n : type === \"datetime\"\n ? Temporal.Instant\n : Temporal.PlainTime;\n if (!(value instanceof expected)) {\n throw new TypeError(\n `Expected a Temporal.${expected.name} instance at ${describePathTarget(path)}, but received ${describeReceivedValue(value)}`,\n );\n }\n try {\n return formatTemporal(value);\n } catch (error) {\n return throwInvalidDate(error, path);\n }\n}\n\ntype MaybeProcessGlobal = { process?: { env: Record<string, string | undefined> } };\n\nconst dateSerializers: Record<DateRepresentation, DateSerializer | undefined> = {\n date: (globalThis as MaybeProcessGlobal).process?.env.__TAILOR_PLATFORM_BUNDLE_WITHOUT_DATE\n ? undefined\n : serializeAsDate,\n temporal: (globalThis as MaybeProcessGlobal).process?.env\n .__TAILOR_PLATFORM_BUNDLE_WITHOUT_TEMPORAL\n ? undefined\n : serializeAsTemporal,\n};\n\nfunction serializeValue(field: DateField, value: unknown, path: string): unknown {\n if (value === null || value === undefined) return value;\n const { type } = field;\n const as = dateRepresentationOf(type, field.metadata.as);\n if (as) {\n const serializeAs = dateSerializers[as];\n if (!serializeAs) {\n throw new Error(\n `Serializing fields declared with as: \"${as}\" is not included in this bundle.`,\n );\n }\n return serializeAs(type, value, path);\n }\n if (type !== \"nested\" || typeof value !== \"object\" || Array.isArray(value)) return value;\n const record = value as Record<string, unknown>;\n let result = record;\n for (const [key, child] of Object.entries(field.fields)) {\n const converted = serialize(child, record[key], path ? `${path}.${key}` : key);\n if (converted !== record[key]) {\n if (result === record) result = { ...record };\n Object.defineProperty(result, key, {\n value: converted,\n enumerable: true,\n configurable: true,\n writable: true,\n });\n }\n }\n return result;\n}\n\n/**\n * Check whether a field or any of its nested fields uses a Date or Temporal representation.\n * @param field - Field to inspect\n * @param representation - Only match fields using this representation\n * @returns Whether serializeDateFields would convert any value of the field\n * @internal\n */\nexport function hasDateRepresentationFields(\n field: DateRepresentationField,\n representation?: DateRepresentation,\n): boolean {\n return (\n isDateRepresentationField(field, representation) ||\n Object.values(field.fields).some((child) => hasDateRepresentationFields(child, representation))\n );\n}\n\n/**\n * Convert fields using Date or Temporal representations to date, datetime, or time strings.\n * @param field - Field defining the value's shape\n * @param value - Value to serialize\n * @returns Value with Date and Temporal fields converted to strings\n * @internal\n */\nexport function serializeDateFields(field: DateField, value: unknown): unknown {\n return serialize(field, value, \"\");\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"date-Dri6Yas-.mjs","names":["temporal","Temporal","date","year","received","hour","minute","value","iso","isInstant","field","converted","item","path","index","text","sample","elementTypes","type","as","representation","reason","error","expected","dateSerializers","serializeAs","record","result","key","child"],"sources":["../src/runtime/temporal.ts","../src/runtime/date.ts"],"sourcesContent":["import type { Temporal as TemporalTypes } from \"temporal-spec\";\n\n/**\n * Get the host Temporal implementation when a value is needed.\n * @returns Host Temporal implementation\n * @internal\n */\nexport function getTemporal(): typeof TemporalTypes {\n const temporal = (globalThis as unknown as { Temporal?: typeof TemporalTypes }).Temporal;\n if (!temporal) {\n throw new ReferenceError(\n \"Temporal is unavailable. Use the Tailor Platform runtime or the SDK tailor-runtime Vitest environment.\",\n );\n }\n return temporal;\n}\n\n/**\n * Typed access to the runtime's Temporal API, without installing a polyfill.\n * Constructors are resolved on access so configuration files can load in Node.js.\n * @example\n * import { Temporal } from \"@tailor-platform/sdk/runtime\";\n * const tomorrow: Temporal.PlainDate = Temporal.Now.plainDateISO().add({ days: 1 });\n */\nexport const Temporal: typeof TemporalTypes = {\n get PlainDate() {\n return getTemporal().PlainDate;\n },\n get PlainTime() {\n return getTemporal().PlainTime;\n },\n get PlainDateTime() {\n return getTemporal().PlainDateTime;\n },\n get PlainYearMonth() {\n return getTemporal().PlainYearMonth;\n },\n get PlainMonthDay() {\n return getTemporal().PlainMonthDay;\n },\n get ZonedDateTime() {\n return getTemporal().ZonedDateTime;\n },\n get Duration() {\n return getTemporal().Duration;\n },\n get Instant() {\n return getTemporal().Instant;\n },\n get Now() {\n return getTemporal().Now;\n },\n};\n\n/** Temporal instance types supplied by the SDK, independent of TypeScript's lib settings. */\n// Type-only merging supports Temporal.PlainDate annotations on the value import.\n// oxlint-disable-next-line typescript/no-namespace\nexport declare namespace Temporal {\n /** The runtime Temporal.PlainDate instance. */\n type PlainDate = TemporalTypes.PlainDate;\n /** The runtime Temporal.PlainTime instance. */\n type PlainTime = TemporalTypes.PlainTime;\n /** The runtime Temporal.PlainDateTime instance. */\n type PlainDateTime = TemporalTypes.PlainDateTime;\n /** The runtime Temporal.PlainYearMonth instance. */\n type PlainYearMonth = TemporalTypes.PlainYearMonth;\n /** The runtime Temporal.PlainMonthDay instance. */\n type PlainMonthDay = TemporalTypes.PlainMonthDay;\n /** The runtime Temporal.ZonedDateTime instance. */\n type ZonedDateTime = TemporalTypes.ZonedDateTime;\n /** The runtime Temporal.Duration instance. */\n type Duration = TemporalTypes.Duration;\n /** The runtime Temporal.Instant instance. */\n type Instant = TemporalTypes.Instant;\n}\n","import { getTemporal } from \"./temporal\";\nimport type { FieldMetadata, TailorFieldType } from \"#/configure/types/field.types\";\nimport type { Temporal } from \"temporal-spec\";\n\n/**\n * Format a Date using its UTC calendar date.\n * @param date - Date to format\n * @returns Date string in YYYY-MM-DD format\n */\nexport function formatDate(date: Date): string {\n return formatDateTime(date).slice(0, 10);\n}\n\nfunction formatDateTime(date: Date): string {\n const year = date.getUTCFullYear();\n if (!Number.isFinite(year) || year < 0 || year > 9999) {\n const received = Number.isNaN(date.getTime()) ? \"an invalid Date\" : `year ${year}`;\n throw new RangeError(\n `Expected a Date with a 4-digit year (0000-9999), but received ${received}`,\n );\n }\n return date.toISOString();\n}\n\nfunction formatHoursMinutes(hour: number, minute: number): string {\n return `${String(hour).padStart(2, \"0\")}:${String(minute).padStart(2, \"0\")}`;\n}\n\nfunction formatTime(date: Date): string {\n if (!Number.isFinite(date.getTime())) {\n throw new RangeError(\"Expected a valid Date, but received an invalid Date\");\n }\n return formatHoursMinutes(date.getUTCHours(), date.getUTCMinutes());\n}\n\nfunction formatTemporal(value: Temporal.PlainDate | Temporal.Instant | Temporal.PlainTime): string {\n const Temporal = getTemporal();\n if (value instanceof Temporal.PlainTime) return formatHoursMinutes(value.hour, value.minute);\n const iso = value.toString({ calendarName: \"never\" });\n if (!/^\\d{4}-/.test(iso)) {\n const isInstant = value instanceof Temporal.Instant;\n throw new RangeError(\n `Expected a Temporal.${isInstant ? \"Instant\" : \"PlainDate\"} with a 4-digit ${isInstant ? \"UTC \" : \"\"}year (0000-9999), but received ${iso}`,\n );\n }\n return iso;\n}\n\ntype DateField = {\n readonly type: TailorFieldType;\n readonly metadata: FieldMetadata;\n readonly fields: Record<string, DateField>;\n};\n\ntype DateRepresentationField = {\n readonly type: TailorFieldType;\n readonly metadata: Pick<FieldMetadata, \"as\">;\n readonly fields: Record<string, DateRepresentationField>;\n};\n\nfunction serialize(field: DateField, value: unknown, path: string): unknown {\n if (field.metadata.array) {\n if (!Array.isArray(value)) return value;\n const converted = value.map((item, index) => serializeValue(field, item, `${path}[${index}]`));\n return converted.every((item, index) => item === value[index]) ? value : converted;\n }\n return serializeValue(field, value, path);\n}\n\nfunction describePathTarget(path: string): string {\n return path || \"the top-level value\";\n}\n\nconst MAX_DESCRIBED_VALUE_LENGTH = 100;\nconst MAX_DESCRIBED_ARRAY_SAMPLE = 100;\n\nfunction truncateForDescription(text: string): string {\n return text.length > MAX_DESCRIBED_VALUE_LENGTH\n ? `${text.slice(0, MAX_DESCRIBED_VALUE_LENGTH)}...`\n : text;\n}\n\nfunction describeReceivedValue(value: unknown): string {\n if (Array.isArray(value)) {\n const sample = value.slice(0, MAX_DESCRIBED_ARRAY_SAMPLE);\n const elementTypes = [...new Set(Array.from(sample, (item) => typeof item))];\n return elementTypes.length > 0 ? `an array of ${elementTypes.join(\"/\")}` : \"an empty array\";\n }\n if (typeof value === \"string\")\n return `a string (${JSON.stringify(truncateForDescription(value))})`;\n const type = typeof value;\n if (type === \"object\") return \"an object\";\n if (type === \"function\") return \"a function\";\n return `a ${type} (${truncateForDescription(String(value))})`;\n}\n\ntype DateRepresentation = \"date\" | \"temporal\";\n\n/**\n * Get the Date or Temporal representation a field converts its values to.\n * @param type - Field type\n * @param as - The field's `as` option\n * @returns The representation, or undefined when values stay strings\n * @internal\n */\nexport function dateRepresentationOf(\n type: TailorFieldType,\n as: FieldMetadata[\"as\"],\n): DateRepresentation | undefined {\n return (type === \"date\" || type === \"datetime\" || type === \"time\") &&\n (as === \"date\" || as === \"temporal\")\n ? as\n : undefined;\n}\n\nfunction isDateRepresentationField(\n field: DateRepresentationField,\n representation?: DateRepresentation,\n): boolean {\n const as = dateRepresentationOf(field.type, field.metadata.as);\n return as !== undefined && (representation === undefined || as === representation);\n}\n\ntype DateSerializer = (type: TailorFieldType, value: unknown, path: string) => string;\n\nfunction throwInvalidDate(error: unknown, path: string): never {\n const reason = error instanceof Error ? error.message : String(error);\n throw new RangeError(`Invalid date at ${describePathTarget(path)}: ${reason}`, {\n cause: error,\n });\n}\n\nfunction serializeAsDate(type: TailorFieldType, value: unknown, path: string): string {\n if (!(value instanceof Date)) {\n throw new TypeError(\n `Expected a Date instance at ${describePathTarget(path)}, but received ${describeReceivedValue(value)}`,\n );\n }\n try {\n if (type === \"datetime\") return formatDateTime(value);\n if (type === \"time\") return formatTime(value);\n return formatDate(value);\n } catch (error) {\n return throwInvalidDate(error, path);\n }\n}\n\nfunction serializeAsTemporal(type: TailorFieldType, value: unknown, path: string): string {\n const Temporal = getTemporal();\n const expected =\n type === \"date\"\n ? Temporal.PlainDate\n : type === \"datetime\"\n ? Temporal.Instant\n : Temporal.PlainTime;\n if (!(value instanceof expected)) {\n throw new TypeError(\n `Expected a Temporal.${expected.name} instance at ${describePathTarget(path)}, but received ${describeReceivedValue(value)}`,\n );\n }\n try {\n return formatTemporal(value);\n } catch (error) {\n return throwInvalidDate(error, path);\n }\n}\n\ntype MaybeProcessGlobal = { process?: { env: Record<string, string | undefined> } };\n\nconst dateSerializers: Record<DateRepresentation, DateSerializer | undefined> = {\n date: (globalThis as MaybeProcessGlobal).process?.env.__TAILOR_PLATFORM_BUNDLE_WITHOUT_DATE\n ? undefined\n : serializeAsDate,\n temporal: (globalThis as MaybeProcessGlobal).process?.env\n .__TAILOR_PLATFORM_BUNDLE_WITHOUT_TEMPORAL\n ? undefined\n : serializeAsTemporal,\n};\n\nfunction serializeValue(field: DateField, value: unknown, path: string): unknown {\n if (value === null || value === undefined) return value;\n const { type } = field;\n const as = dateRepresentationOf(type, field.metadata.as);\n if (as) {\n const serializeAs = dateSerializers[as];\n if (!serializeAs) {\n throw new Error(\n `Serializing fields declared with as: \"${as}\" is not included in this bundle.`,\n );\n }\n return serializeAs(type, value, path);\n }\n if (type !== \"nested\" || typeof value !== \"object\" || Array.isArray(value)) return value;\n const record = value as Record<string, unknown>;\n let result = record;\n for (const [key, child] of Object.entries(field.fields)) {\n const converted = serialize(child, record[key], path ? `${path}.${key}` : key);\n if (converted !== record[key]) {\n if (result === record) result = { ...record };\n Object.defineProperty(result, key, {\n value: converted,\n enumerable: true,\n configurable: true,\n writable: true,\n });\n }\n }\n return result;\n}\n\n/**\n * Check whether a field or any of its nested fields uses a Date or Temporal representation.\n * @param field - Field to inspect\n * @param representation - Only match fields using this representation\n * @returns Whether serializeDateFields would convert any value of the field\n * @internal\n */\nexport function hasDateRepresentationFields(\n field: DateRepresentationField,\n representation?: DateRepresentation,\n): boolean {\n return (\n isDateRepresentationField(field, representation) ||\n Object.values(field.fields).some((child) => hasDateRepresentationFields(child, representation))\n );\n}\n\n/**\n * Convert fields using Date or Temporal representations to date, datetime, or time strings.\n * @param field - Field defining the value's shape\n * @param value - Value to serialize\n * @returns Value with Date and Temporal fields converted to strings\n * @internal\n */\nexport function serializeDateFields(field: DateField, value: unknown): unknown {\n return serialize(field, value, \"\");\n}\n"],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import{o as e}from"./logger-Db-YRTwK.mjs";const t=/^[A-Za-z0-9_./:=@+-]+$/,n=/^[A-Za-z0-9_./:=@+\\-]+$/,r=/[%$"`“”„\p{Cc}]|\\$|^~(?:[\\/]|$)/u,i=/"|\s.*\\$|^~(?:[\\/]|$)/;function quotePosixArg(e){return t.test(e)?e:`'${e.replaceAll(`'`,`'"'"'`)}'`}function isPowerShellBare(e){return n.test(e)&&!/^(@|[+-]?\.?\d)/.test(e)&&e!==`--`&&!/^-[^-].*[.:]/.test(e)}function quotePowerShellArg(e){return isPowerShellBare(e)?e:`'${e.replace(/['‘’‚‛]/g,`$&$&`)}'`}function quoteCmdArg(e){if(n.test(e)&&!e.endsWith(`\\`))return e;let t=`"`,r=0;for(let n of e){if(n===`\\`){r++;continue}t+=n===`"`?`${`\\`.repeat(r*2)}""`:`${`\\`.repeat(r)}${n===`%`?`%%cd:~,%`:n}`,r=0}return`${t}${`\\`.repeat(r*2)}"`}function formatWindowsCommandLines(e){if(e.every(e=>isPowerShellBare(e)||e!==``&&!r.test(e)))return{kind:`shared`,commandLine:e.map(e=>isPowerShellBare(e)?e:`"${e}"`).join(` `)};let t=e.map(quoteCmdArg).join(` `);return{kind:`perShell`,powershell:e.some(e=>e===``||i.test(e))?`cmd /d /s /c ${quotePowerShellArg(t)}`:e.map(quotePowerShellArg).join(` `),cmd:t}}function formatShellCommandLines(e){return process.platform===`win32`?formatWindowsCommandLines(e):{kind:`shared`,commandLine:e.map(quotePosixArg).join(` `)}}function formatCommandHint(e){let t=formatShellCommandLines([e.command,...e.args]);return t.kind===`shared`?`\`${t.commandLine}\``:`\`${t.powershell}\` in PowerShell or \`${t.cmd}\` in cmd.exe`}function formatError(t){let n=[e.error(`Error${t.code?` [${t.code}]`:``}: ${t.message}`)];return t.details&&n.push(`\n ${e.dim(`Details:`)} ${t.details.split(`
2
+ `).join(`
3
+ `)}`),t.suggestion&&n.push(`\n ${e.info(`Suggestion:`)} ${t.suggestion.split(`
4
+ `).join(`
5
+ `)}`),t.command&&n.push(`\n ${e.dim(`Help:`)} Run \`tailor ${t.command} --help\` for usage information.`),t.next&&n.push(`\n ${e.info(`Next:`)} Run ${formatCommandHint(t.next)}.`),n.join(``)}function CLIError(e){let t=Error(e.message,e.cause===void 0?void 0:{cause:e.cause});return t.name=`CLIError`,t.code=e.code,t.details=e.details,t.suggestion=e.suggestion,t.command=e.command,t.next=e.next,t.context=e.context,t.format=()=>formatError(t),t}function isCLIError(e){return e instanceof Error&&e.name===`CLIError`}function errorSummary(e){return isCLIError(e)?[e.message,e.details,e.suggestion].filter(Boolean).join(`
6
+ `):e instanceof Error?e.message:String(e)}function internalError(e,t){return Error(e,t)}function toError(e){return e instanceof Error?e:Error(String(e),{cause:e})}const a=/does not provide an export named '(?!default')([^']+)'/;function typeOnlyImportHint(e){if(!(e instanceof SyntaxError))return;let t=a.exec(e.message)?.[1];if(t)return`If '${t}' is a type, import it with \`import type\` (or the inline \`type\` modifier). The CLI runs TypeScript by stripping types from each file in isolation, so type-only exports do not exist at runtime. Set "verbatimModuleSyntax": true in tsconfig.json to catch this at typecheck.`}export{isCLIError as a,internalError as i,errorSummary as n,toError as o,formatCommandHint as r,typeOnlyImportHint as s,CLIError as t};
7
+ //# sourceMappingURL=errors-CpvSChyL.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors-CpvSChyL.mjs","names":["styles","POSIX_BARE_ARG","CMD_BARE_ARG","WINDOWS_DOUBLE_QUOTE_UNSAFE","POWERSHELL_VERSION_SENSITIVE","value","quoted","backslashes","char","argv","cmd","commandLines","action","parts","error","options","message","MISSING_NAMED_EXPORT_PATTERN","name"],"sources":["../src/cli/shared/shell-quote.ts","../src/cli/shared/errors.ts"],"sourcesContent":["/**\n * Command lines for a suggested command: one line when every supported shell reads it the same\n * way, otherwise one line per Windows shell.\n */\nexport type ShellCommandLines =\n | { kind: \"shared\"; commandLine: string }\n | { kind: \"perShell\"; powershell: string; cmd: string };\n\nconst POSIX_BARE_ARG = /^[A-Za-z0-9_./:=@+-]+$/;\nconst CMD_BARE_ARG = /^[A-Za-z0-9_./:=@+\\\\-]+$/;\n// PowerShell expands `$` and backtick escapes inside double quotes and reads `“ ” „` as `\"`,\n// cmd.exe expands `%` even inside quotes, a `\"` or a trailing backslash changes where the\n// quoted argument ends, and a leading `~` is version-sensitive (below).\nconst WINDOWS_DOUBLE_QUOTE_UNSAFE = /[%$\"`“”„\\p{Cc}]|\\\\$|^~(?:[\\\\/]|$)/u;\n// PowerShell versions pass these to programs differently: Windows PowerShell 5.1 and 7.3+\n// disagree on quotes and trailing backslashes, and 7.6+ expands a leading `~` inside the `.ps1`\n// shim however it was quoted.\nconst POWERSHELL_VERSION_SENSITIVE = /\"|\\s.*\\\\$|^~(?:[\\\\/]|$)/;\n\nfunction quotePosixArg(value: string): string {\n if (POSIX_BARE_ARG.test(value)) return value;\n return `'${value.replaceAll(\"'\", `'\"'\"'`)}'`;\n}\n\nfunction isPowerShellBare(value: string): boolean {\n // A leading `@` splats, a lone `--` ends parameters, a leading digit reads as a number, and a\n // single-dash token with `.` or `:` reads as parameter syntax.\n return (\n CMD_BARE_ARG.test(value) &&\n !/^(@|[+-]?\\.?\\d)/.test(value) &&\n value !== \"--\" &&\n !/^-[^-].*[.:]/.test(value)\n );\n}\n\nfunction quotePowerShellArg(value: string): string {\n if (isPowerShellBare(value)) return value;\n return `'${value.replace(/['‘’‚‛]/g, \"$&$&\")}'`;\n}\n\nfunction quoteCmdArg(value: string): string {\n // Quoting a trailing backslash keeps a command routed through `cmd /c` from ending in one,\n // which PowerShell 7 doubles when it quotes the line.\n if (CMD_BARE_ARG.test(value) && !value.endsWith(\"\\\\\")) return value;\n let quoted = '\"';\n let backslashes = 0;\n for (const char of value) {\n if (char === \"\\\\\") {\n backslashes++;\n continue;\n }\n if (char === '\"') {\n quoted += `${\"\\\\\".repeat(backslashes * 2)}\"\"`;\n } else {\n // `%%cd:~,%` reads back as a literal `%` without cmd.exe expanding a `%NAME%` around it.\n quoted += `${\"\\\\\".repeat(backslashes)}${char === \"%\" ? \"%%cd:~,%\" : char}`;\n }\n backslashes = 0;\n }\n return `${quoted}${\"\\\\\".repeat(backslashes * 2)}\"`;\n}\n\nfunction formatWindowsCommandLines(argv: readonly string[]): ShellCommandLines {\n if (\n argv.every(\n (value) =>\n isPowerShellBare(value) || (value !== \"\" && !WINDOWS_DOUBLE_QUOTE_UNSAFE.test(value)),\n )\n ) {\n return {\n kind: \"shared\",\n commandLine: argv.map((value) => (isPowerShellBare(value) ? value : `\"${value}\"`)).join(\" \"),\n };\n }\n const cmd = argv.map(quoteCmdArg).join(\" \");\n // Both PowerShell versions pass a `cmd` argument the same legacy way, so routing the cmd.exe\n // line through `cmd /c` keeps the arguments identical where their native quoting differs.\n const powershell = argv.some((value) => value === \"\" || POWERSHELL_VERSION_SENSITIVE.test(value))\n ? `cmd /d /s /c ${quotePowerShellArg(cmd)}`\n : argv.map(quotePowerShellArg).join(\" \");\n return { kind: \"perShell\", powershell, cmd };\n}\n\n/**\n * Render an argv array as command lines that the current platform's shells run with every\n * argument delivered unchanged\n * @param {readonly string[]} argv - Executable name followed by its arguments\n * @returns {ShellCommandLines} One shared command line, or one per Windows shell\n */\nexport function formatShellCommandLines(argv: readonly string[]): ShellCommandLines {\n if (process.platform === \"win32\") return formatWindowsCommandLines(argv);\n return { kind: \"shared\", commandLine: argv.map(quotePosixArg).join(\" \") };\n}\n","import { styles } from \"./logger\";\nimport { formatShellCommandLines } from \"./shell-quote\";\nimport type { Jsonifiable } from \"type-fest\";\n\n/**\n * Options for creating a CLI error\n */\ninterface CLIErrorOptions {\n /** Stable machine-readable failure code, such as `WORKSPACE_NOT_FOUND`. */\n code: string;\n message: string;\n details?: string;\n suggestion?: string;\n command?: string;\n next?: CLIErrorNextAction;\n context?: Readonly<Record<string, Jsonifiable | undefined>>;\n cause?: unknown;\n}\n\nexport type CLIErrorNextAction = {\n /** Executable name, such as `tailor`. */\n command: string;\n /** Arguments passed directly to the executable. */\n args: readonly string[];\n};\n\n/**\n * CLI error interface with formatted output\n */\nexport interface CLIError extends Error {\n readonly code: string;\n readonly details?: string;\n readonly suggestion?: string;\n readonly command?: string;\n readonly next?: CLIErrorNextAction;\n readonly context?: Readonly<Record<string, Jsonifiable | undefined>>;\n format(): string;\n}\n\ntype CLIErrorInternal = Error & {\n code: string;\n details?: string;\n suggestion?: string;\n command?: string;\n next?: CLIErrorNextAction;\n context?: Readonly<Record<string, Jsonifiable | undefined>>;\n format(): string;\n};\n\n/**\n * Render a command as a user-facing hint that can be copied into the current platform's shells:\n * one backticked command line, or on Windows, when no single quoting suits both shells, a\n * PowerShell and a cmd.exe line (`` `…` in PowerShell or `…` in cmd.exe ``)\n * @param {CLIErrorNextAction} action - Executable and arguments to suggest\n * @returns {string} The command part of the hint, to follow a verb such as \"Run\"\n */\nexport function formatCommandHint(action: CLIErrorNextAction): string {\n const commandLines = formatShellCommandLines([action.command, ...action.args]);\n if (commandLines.kind === \"shared\") {\n return `\\`${commandLines.commandLine}\\``;\n }\n return `\\`${commandLines.powershell}\\` in PowerShell or \\`${commandLines.cmd}\\` in cmd.exe`;\n}\n\n/**\n * Format CLI error for output\n * @param error - CLIError instance to format\n * @returns Formatted error message\n */\nfunction formatError(error: CLIError): string {\n const parts: string[] = [\n styles.error(`Error${error.code ? ` [${error.code}]` : \"\"}: ${error.message}`),\n ];\n\n if (error.details) {\n parts.push(`\\n ${styles.dim(\"Details:\")} ${error.details.split(\"\\n\").join(\"\\n \")}`);\n }\n\n if (error.suggestion) {\n parts.push(`\\n ${styles.info(\"Suggestion:\")} ${error.suggestion.split(\"\\n\").join(\"\\n \")}`);\n }\n\n if (error.command) {\n parts.push(\n `\\n ${styles.dim(\"Help:\")} Run \\`tailor ${error.command} --help\\` for usage information.`,\n );\n }\n\n if (error.next) {\n parts.push(`\\n ${styles.info(\"Next:\")} Run ${formatCommandHint(error.next)}.`);\n }\n\n return parts.join(\"\");\n}\n\n/**\n * Create a CLI error with formatted output\n * @param options - Options to construct a CLIError\n * @returns Constructed CLIError instance\n */\nexport function CLIError(options: CLIErrorOptions): CLIError {\n const error = new Error(\n options.message,\n options.cause === undefined ? undefined : { cause: options.cause },\n ) as CLIErrorInternal;\n error.name = \"CLIError\";\n error.code = options.code;\n error.details = options.details;\n error.suggestion = options.suggestion;\n error.command = options.command;\n error.next = options.next;\n error.context = options.context;\n error.format = () => formatError(error);\n return error;\n}\n\n/**\n * Type guard to check if an error is a CLIError\n * @param error - Error to check\n * @returns True if the error is a CLIError\n */\nexport function isCLIError(error: unknown): error is CLIError {\n return error instanceof Error && error.name === \"CLIError\";\n}\n\n/**\n * Summarize a failure as plain text for reports that carry a single error string.\n * CLI errors contribute their details and suggestion so the remediation survives.\n * @param error - Failure to summarize\n * @returns Message followed by any details and suggestion, one per line\n */\nexport function errorSummary(error: unknown): string {\n if (isCLIError(error)) {\n return [error.message, error.details, error.suggestion].filter(Boolean).join(\"\\n\");\n }\n return error instanceof Error ? error.message : String(error);\n}\n\n/**\n * Create an error for an SDK invariant violation that no user action can fix.\n * The result is a plain Error, so JSON output reports it as `UNEXPECTED_ERROR`\n * and crash reporting treats it like any other unexpected failure.\n * @param message - Description of the violated invariant\n * @param options - Standard Error options, such as `cause`\n * @returns Plain Error instance\n */\nexport function internalError(message: string, options?: ErrorOptions): Error {\n return new Error(message, options);\n}\n\n/**\n * Convert a caught value into an Error, keeping Error instances as-is\n * @param value - Caught value\n * @returns The value itself when it is an Error, otherwise an Error of its string form with the value as `cause`\n */\nexport function toError(value: unknown): Error {\n return value instanceof Error ? value : new Error(String(value), { cause: value });\n}\n\nconst MISSING_NAMED_EXPORT_PATTERN = /does not provide an export named '(?!default')([^']+)'/;\n\n/**\n * Suggest `import type` when importing user code fails on a missing named\n * export. The CLI strips types from each file in isolation, so a type-only\n * export does not exist at runtime and a plain import of it fails to link.\n * @param error - Error thrown while importing user modules\n * @returns Suggestion text, or undefined when the error is not that failure\n */\nexport function typeOnlyImportHint(error: unknown): string | undefined {\n if (!(error instanceof SyntaxError)) return undefined;\n const name = MISSING_NAMED_EXPORT_PATTERN.exec(error.message)?.[1];\n if (!name) return undefined;\n return (\n `If '${name}' is a type, import it with \\`import type\\` (or the inline \\`type\\` modifier). ` +\n \"The CLI runs TypeScript by stripping types from each file in isolation, so type-only exports do not exist at runtime. \" +\n 'Set \"verbatimModuleSyntax\": true in tsconfig.json to catch this at typecheck.'\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"es-builtins-SfvXRVoG.mjs","names":[],"sources":["../src/utils/es-builtins.ts"],"sourcesContent":["import * as globals from \"globals\";\n\ntype GlobalsShape = {\n builtin?: Record<string, boolean>;\n \"shared-node-browser\"?: Record<string, boolean>;\n node?: Record<string, boolean>;\n};\n\nconst globalsMap: GlobalsShape =\n (globals as unknown as { default?: GlobalsShape }).default ?? globals;\n\n/**\n * Runtime globals available in the PF execution environment.\n * Identifiers in this set are excluded from free variable detection\n * since they are always available in the runtime environment.\n *\n * Combines globals.builtin (ECMAScript language builtins) and\n * globals['shared-node-browser'] (shared runtime globals like\n * console, fetch, setTimeout, etc.) from the `globals` npm package.\n */\nexport const ES_BUILTINS = new Set([\n ...Object.keys(globalsMap.builtin ?? {}),\n ...Object.keys(globalsMap[\"shared-node-browser\"] ?? {}),\n]);\n\n/**\n * Node-only ambient globals (`process`, `Buffer`, `require`, `setImmediate`,\n * etc.) that `@types/node` puts in the global scope but that are absent from\n * `ES_BUILTINS`, so the Tailor Platform runtime never defines them. Sourced\n * from the same `globals` package as `ES_BUILTINS` instead of a hand-curated\n * list, so a newly recognized Node-only global can't be silently omitted.\n */\nexport const NODE_ONLY_GLOBALS = new Set(\n Object.keys(globalsMap.node ?? {}).filter((name) => !ES_BUILTINS.has(name)),\n);\n"],"mappings":"0BAQA,MAAM,EACH,EAAkD,SAAW,EAWnD,kBAAc,IAAI,IAAI,CACjC,GAAG,OAAO,KAAK,EAAW,SAAW,CAAC,CAAC,EACvC,GAAG,OAAO,KAAK,EAAW,wBAA0B,CAAC,CAAC,CACxD,CAAC,EASY,EAAoB,IAAI,IACnC,OAAO,KAAK,EAAW,MAAQ,CAAC,CAAC,CAAC,CAAC,OAAQ,GAAS,CAAC,EAAY,IAAI,CAAI,CAAC,CAC5E"}
1
+ {"version":3,"file":"es-builtins-SfvXRVoG.mjs","names":["globals","globalsMap","ES_BUILTINS","NODE_ONLY_GLOBALS","name"],"sources":["../src/utils/es-builtins.ts"],"sourcesContent":["import * as globals from \"globals\";\n\ntype GlobalsShape = {\n builtin?: Record<string, boolean>;\n \"shared-node-browser\"?: Record<string, boolean>;\n node?: Record<string, boolean>;\n};\n\nconst globalsMap: GlobalsShape =\n (globals as unknown as { default?: GlobalsShape }).default ?? globals;\n\n/**\n * Runtime globals available in the PF execution environment.\n * Identifiers in this set are excluded from free variable detection\n * since they are always available in the runtime environment.\n *\n * Combines globals.builtin (ECMAScript language builtins) and\n * globals['shared-node-browser'] (shared runtime globals like\n * console, fetch, setTimeout, etc.) from the `globals` npm package.\n */\nexport const ES_BUILTINS = new Set([\n ...Object.keys(globalsMap.builtin ?? {}),\n ...Object.keys(globalsMap[\"shared-node-browser\"] ?? {}),\n]);\n\n/**\n * Node-only ambient globals (`process`, `Buffer`, `require`, `setImmediate`,\n * etc.) that `@types/node` puts in the global scope but that are absent from\n * `ES_BUILTINS`, so the Tailor Platform runtime never defines them. Sourced\n * from the same `globals` package as `ES_BUILTINS` instead of a hand-curated\n * list, so a newly recognized Node-only global can't be silently omitted.\n */\nexport const NODE_ONLY_GLOBALS = new Set(\n Object.keys(globalsMap.node ?? {}).filter((name) => !ES_BUILTINS.has(name)),\n);\n"],"mappings":"0BAQA,MAAMC,EACHD,EAAkD,SAAWA,EAWnDE,kBAAc,IAAI,IAAI,CACjC,GAAG,OAAO,KAAKD,EAAW,SAAW,CAAC,CAAC,EACvC,GAAG,OAAO,KAAKA,EAAW,wBAA0B,CAAC,CAAC,CACxD,CAAC,EASYE,EAAoB,IAAI,IACnC,OAAO,KAAKF,EAAW,MAAQ,CAAC,CAAC,CAAC,CAAC,OAAQ,GAAS,CAACC,EAAY,IAAIE,CAAI,CAAC,CAC5E"}
@@ -1 +1 @@
1
- {"version":3,"file":"field-parse-DhnFs9WG.mjs","names":[],"sources":["../src/runtime/field-parse.ts"],"sourcesContent":["import { dateRepresentationOf, formatDate } from \"./date\";\nimport { getTemporal } from \"./temporal\";\nimport type { FieldMetadata, TailorFieldType } from \"#/configure/types/field.types\";\nimport type { TailorPrincipal } from \"#/runtime/types\";\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\";\n\nconst regex = {\n uuid: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,\n date: /^(?<year>\\d{4})-(?<month>\\d{2})-(?<day>\\d{2})$/,\n time: /^(?<hour>[01]\\d|2[0-3]):(?<minute>[0-5]\\d)$/,\n datetime:\n /^(?<year>\\d{4})-(?<month>\\d{2})-(?<day>\\d{2})[Tt](?<hour>[01]\\d|2[0-3]):(?<minute>[0-5]\\d):(?<second>[0-5]\\d|60)(\\.(?<fraction>\\d+))?(?<offset>[Zz]|[+-](?:[01]\\d|2[0-3]):[0-5]\\d)$/,\n decimal: /^-?(\\d+\\.?\\d*|\\.\\d+)([eE][+-]?\\d+)?$/,\n} as const;\n\n/**\n * Whether a value is an acceptable shape for a nested field. Runtime input may\n * not match the declared field type, so anything this rejects is reported\n * against the field rather than recursed into.\n * @param value - The value to check\n * @returns `true` when the value is a plain object the parser recurses into\n */\nexport function isNestedObject(value: unknown): value is Record<string, unknown> {\n return (\n typeof value === \"object\" && value !== null && !Array.isArray(value) && !(value instanceof Date)\n );\n}\n\nexport type FieldParseArgs = {\n value: unknown;\n data: unknown;\n invoker: TailorPrincipal | null;\n};\n\nexport type FieldParseInternalArgs = {\n value: unknown;\n data: unknown;\n invoker: TailorPrincipal | null;\n pathArray: string[];\n};\n\nexport type FieldRuntime<T extends TailorFieldType = TailorFieldType> = {\n readonly type: T;\n readonly fields: Record<string, FieldRuntime>;\n _metadata: FieldMetadata;\n};\n\ntype FieldParseRuntimeArgs<T extends TailorFieldType> = FieldParseInternalArgs & {\n field: FieldRuntime<T>;\n};\n\ntype FieldValidationArgs<T extends TailorFieldType> = FieldParseRuntimeArgs<T> & {\n issues: StandardSchemaV1.Issue[];\n};\n\nfunction validateBaseValue<T extends TailorFieldType>(args: FieldValidationArgs<T>): boolean {\n const { field, value, pathArray, issues } = args;\n const path = pathArray.length > 0 ? pathArray : undefined;\n const initialIssueCount = issues.length;\n\n switch (field.type) {\n case \"string\":\n if (typeof value !== \"string\") {\n issues.push({\n message: `Expected a string: received ${String(value)}`,\n path,\n });\n }\n break;\n\n case \"integer\":\n if (typeof value !== \"number\" || !Number.isInteger(value)) {\n issues.push({\n message: `Expected an integer: received ${String(value)}`,\n path,\n });\n }\n break;\n\n case \"float\":\n if (typeof value !== \"number\" || !Number.isFinite(value)) {\n issues.push({\n message: `Expected a number: received ${String(value)}`,\n path,\n });\n }\n break;\n\n case \"boolean\":\n if (typeof value !== \"boolean\") {\n issues.push({\n message: `Expected a boolean: received ${String(value)}`,\n path,\n });\n }\n break;\n\n case \"uuid\":\n if (typeof value !== \"string\" || !regex.uuid.test(value)) {\n issues.push({\n message: `Expected a valid UUID: received ${String(value)}`,\n path,\n });\n }\n break;\n case \"date\":\n if (typeof value !== \"string\" || !regex.date.test(value)) {\n issues.push({\n message: `Expected to match \"yyyy-MM-dd\" format: received ${String(value)}`,\n path,\n });\n }\n break;\n case \"datetime\":\n if (typeof value !== \"string\" || !regex.datetime.test(value)) {\n issues.push({\n message: `Expected to match ISO format: received ${String(value)}`,\n path,\n });\n }\n break;\n case \"time\":\n if (typeof value !== \"string\" || !regex.time.test(value)) {\n issues.push({\n message: `Expected to match \"HH:mm\" format: received ${String(value)}`,\n path,\n });\n }\n break;\n case \"decimal\":\n if (typeof value !== \"string\" || !regex.decimal.test(value)) {\n issues.push({\n message: `Expected a decimal string: received ${String(value)}`,\n path,\n });\n }\n break;\n\n case \"enum\":\n if (field._metadata.allowedValues) {\n const allowedValues = field._metadata.allowedValues.map((v) => v.value);\n if (typeof value !== \"string\" || !allowedValues.includes(value)) {\n issues.push({\n message: `Must be one of [${allowedValues.join(\", \")}]: received ${String(value)}`,\n path,\n });\n }\n }\n break;\n\n case \"nested\": {\n if (!isNestedObject(value)) {\n issues.push({\n message: `Expected an object: received ${String(value)}`,\n path,\n });\n return false;\n }\n\n let nestedBaseValid = true;\n for (const [fieldName, nestedField] of Object.entries(field.fields)) {\n const fieldValue = value[fieldName];\n if (\n !validateBaseField({\n ...args,\n field: nestedField,\n value: fieldValue,\n pathArray: pathArray.concat(fieldName),\n })\n ) {\n nestedBaseValid = false;\n }\n }\n return nestedBaseValid;\n }\n }\n\n return issues.length === initialIssueCount;\n}\n\nfunction validateCustomValue<T extends TailorFieldType>(\n args: FieldValidationArgs<T>,\n validateFns: NonNullable<FieldMetadata[\"validate\"]>,\n): void {\n const { value, pathArray, issues } = args;\n const path = pathArray.length > 0 ? pathArray : undefined;\n\n for (const fn of validateFns) {\n const result = fn({ value });\n if (typeof result === \"string\") {\n issues.push({\n message: result,\n path,\n });\n }\n }\n}\n\nfunction validateBaseField<T extends TailorFieldType>(args: FieldValidationArgs<T>): boolean {\n const { field, value, pathArray, issues } = args;\n const path = pathArray.length > 0 ? pathArray : undefined;\n\n const isNullOrUndefined = value === null || value === undefined;\n if (field._metadata.required && isNullOrUndefined) {\n issues.push({\n message: \"Required field is missing\",\n path,\n });\n return false;\n }\n\n if (!field._metadata.required && isNullOrUndefined) {\n return true;\n }\n\n let baseValid = true;\n if (field._metadata.array) {\n if (!Array.isArray(value)) {\n issues.push({\n message: \"Expected an array\",\n path,\n });\n return false;\n }\n\n for (let i = 0; i < value.length; i++) {\n if (\n !validateBaseValue({\n ...args,\n value: value[i],\n pathArray: pathArray.concat(`[${i}]`),\n })\n ) {\n baseValid = false;\n }\n }\n } else {\n baseValid = validateBaseValue(args);\n }\n\n return baseValid;\n}\n\nfunction validateCustomField<T extends TailorFieldType>(args: FieldValidationArgs<T>): void {\n const { field, value, pathArray } = args;\n if (value === null || value === undefined) {\n return;\n }\n\n if (field.type === \"nested\") {\n const records = field._metadata.array\n ? (value as Record<string, unknown>[])\n : [value as Record<string, unknown>];\n\n for (let i = 0; i < records.length; i++) {\n const record = records[i] as Record<string, unknown>;\n const recordPath = field._metadata.array ? pathArray.concat(`[${i}]`) : pathArray;\n for (const [fieldName, nestedField] of Object.entries(field.fields)) {\n validateCustomField({\n ...args,\n field: nestedField,\n value: record[fieldName],\n pathArray: recordPath.concat(fieldName),\n });\n }\n }\n }\n\n const validateFns = field._metadata.validate;\n if (validateFns?.length) {\n validateCustomValue(args, validateFns);\n }\n}\n\nexport function parseInternal<T extends TailorFieldType, Output>(\n args: FieldParseRuntimeArgs<T>,\n dateParsers: DateParsers = bundledDateParsers,\n): StandardSchemaV1.Result<Output> {\n let { value } = args;\n const issues: StandardSchemaV1.Issue[] = [];\n const validationArgs = { ...args, issues };\n const baseValid = validateBaseField(validationArgs);\n if (baseValid) {\n value = deserializeDates(validationArgs, dateParsers);\n if (issues.length === 0) {\n validateCustomField({ ...validationArgs, value });\n }\n }\n if (issues.length > 0) {\n return { issues };\n }\n\n return { value: (value ?? null) as Output };\n}\n\ntype DateParser = (type: TailorFieldType, text: string) => unknown;\n\ntype DateParsers = {\n readonly date: DateParser | undefined;\n readonly temporal: DateParser | undefined;\n};\n\nfunction rejectLeapSecond(type: TailorFieldType, text: string): void {\n if (type === \"datetime\" && text.slice(17, 19) === \"60\") {\n throw new RangeError(\"Leap seconds are not supported\");\n }\n}\n\nfunction parseAsDate(type: TailorFieldType, text: string): Date {\n rejectLeapSecond(type, text);\n const date = new Date(\n type === \"date\"\n ? `${text}T00:00:00.000Z`\n : type === \"time\"\n ? `1970-01-01T${text}:00.000Z`\n : text,\n );\n if (!Number.isFinite(date.getTime())) throw new RangeError(\"Invalid Date\");\n if (type !== \"time\") {\n const calendarDate = text.slice(0, 10);\n if (formatDate(new Date(`${calendarDate}T00:00:00.000Z`)) !== calendarDate) {\n throw new RangeError(\"Invalid calendar date\");\n }\n }\n return date;\n}\n\nfunction parseAsTemporal(type: TailorFieldType, text: string): unknown {\n rejectLeapSecond(type, text);\n const Temporal = getTemporal();\n if (type === \"date\") return Temporal.PlainDate.from(text);\n if (type === \"datetime\") return Temporal.Instant.from(text);\n return Temporal.PlainTime.from(text);\n}\n\nconst allDateParsers: DateParsers = { date: parseAsDate, temporal: parseAsTemporal };\n\ntype MaybeProcessGlobal = { process?: { env: Record<string, string | undefined> } };\n\nconst bundledDateParsers: DateParsers = {\n date: (globalThis as MaybeProcessGlobal).process?.env.__TAILOR_PLATFORM_BUNDLE_WITHOUT_DATE\n ? undefined\n : parseAsDate,\n temporal: (globalThis as MaybeProcessGlobal).process?.env\n .__TAILOR_PLATFORM_BUNDLE_WITHOUT_TEMPORAL\n ? undefined\n : parseAsTemporal,\n};\n\nfunction deserializeDates(\n args: FieldValidationArgs<TailorFieldType>,\n dateParsers: DateParsers,\n): unknown {\n const { field, value, issues, pathArray } = args;\n if (value === null || value === undefined) return value;\n const convert = (item: unknown, itemPath: string[]): unknown => {\n const { type } = field;\n const as = dateRepresentationOf(type, field._metadata.as);\n if (as) {\n const parse = dateParsers[as];\n if (!parse) {\n throw new Error(\n `Parsing fields declared with as: \"${as}\" is not included in this bundle. Parse them with parseDateFields, exported by \"@tailor-platform/sdk/runtime\".`,\n );\n }\n try {\n return parse(type, String(item));\n } catch (error) {\n if (!(error instanceof RangeError)) throw error;\n issues.push({\n message: `Expected a valid ${type === \"date\" ? \"calendar date\" : type}: received ${item}`,\n path: itemPath.length > 0 ? itemPath : undefined,\n });\n return item;\n }\n }\n if (field.type !== \"nested\") return item;\n const record = item as Record<string, unknown>;\n let result = record;\n for (const [key, child] of Object.entries(field.fields)) {\n const converted = deserializeDates(\n {\n ...args,\n field: child,\n value: record[key],\n pathArray: itemPath.concat(key),\n },\n dateParsers,\n );\n if (converted !== record[key]) {\n if (result === record) result = { ...record };\n Object.defineProperty(result, key, {\n value: converted,\n enumerable: true,\n configurable: true,\n writable: true,\n });\n }\n }\n return result;\n };\n if (!field._metadata.array) return convert(value, pathArray);\n const values = value as unknown[];\n const converted = values.map((item, index) => convert(item, pathArray.concat(`[${index}]`)));\n return converted.every((item, index) => item === values[index]) ? value : converted;\n}\n\ntype ParseInputFieldsArgs = FieldParseArgs & {\n fields: Record<string, FieldRuntime>;\n};\n\n/**\n * Validate a value against a record of input fields, treating the record as a\n * single required object — the same code path deployed functions run via\n * `t.object(fields).parse(...)`, so local validation matches platform behavior.\n * @param args - Input field definitions plus the value, context data, and user\n * @returns Validation result\n */\nexport function parseInputFields(args: ParseInputFieldsArgs): StandardSchemaV1.Result<unknown> {\n const { fields, ...parseArgs } = args;\n return parseInternal({\n ...parseArgs,\n field: { type: \"nested\", fields, _metadata: { required: true } },\n pathArray: [],\n });\n}\n\ntype ParsableField<Output> = FieldRuntime & {\n parse(args: FieldParseArgs): StandardSchemaV1.Result<Output>;\n};\n\n/**\n * Parse a value like `field.parse`, converting fields declared with `as: \"date\"` or\n * `as: \"temporal\"` even in bundles that leave that conversion out of `field.parse`.\n * @param field - Field defining the value's shape\n * @param args - Value to parse, with the context data and invoker passed to validators\n * @returns Validation result with Date and Temporal fields converted\n */\nexport function parseDateFields<Output>(\n field: ParsableField<Output>,\n args: FieldParseArgs,\n): StandardSchemaV1.Result<Output> {\n return parseInternal({ ...args, field, pathArray: [] }, allDateParsers);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"field-parse-DhnFs9WG.mjs","names":["formatDate","getTemporal","dateRepresentationOf","regex","value","args","path","pathArray","initialIssueCount","issues","field","allowedValues","v","nestedBaseValid","fieldName","nestedField","fieldValue","fn","validateFns","result","isNullOrUndefined","baseValid","i","records","record","recordPath","bundledDateParsers","validationArgs","dateParsers","type","text","date","calendarDate","Temporal","allDateParsers","as","parse","item","error","itemPath","key","child","converted","values","index","parseArgs"],"sources":["../src/runtime/field-parse.ts"],"sourcesContent":["import { dateRepresentationOf, formatDate } from \"./date\";\nimport { getTemporal } from \"./temporal\";\nimport type { FieldMetadata, TailorFieldType } from \"#/configure/types/field.types\";\nimport type { TailorPrincipal } from \"#/runtime/types\";\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\";\n\nconst regex = {\n uuid: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,\n date: /^(?<year>\\d{4})-(?<month>\\d{2})-(?<day>\\d{2})$/,\n time: /^(?<hour>[01]\\d|2[0-3]):(?<minute>[0-5]\\d)$/,\n datetime:\n /^(?<year>\\d{4})-(?<month>\\d{2})-(?<day>\\d{2})[Tt](?<hour>[01]\\d|2[0-3]):(?<minute>[0-5]\\d):(?<second>[0-5]\\d|60)(\\.(?<fraction>\\d+))?(?<offset>[Zz]|[+-](?:[01]\\d|2[0-3]):[0-5]\\d)$/,\n decimal: /^-?(\\d+\\.?\\d*|\\.\\d+)([eE][+-]?\\d+)?$/,\n} as const;\n\n/**\n * Whether a value is an acceptable shape for a nested field. Runtime input may\n * not match the declared field type, so anything this rejects is reported\n * against the field rather than recursed into.\n * @param value - The value to check\n * @returns `true` when the value is a plain object the parser recurses into\n */\nexport function isNestedObject(value: unknown): value is Record<string, unknown> {\n return (\n typeof value === \"object\" && value !== null && !Array.isArray(value) && !(value instanceof Date)\n );\n}\n\nexport type FieldParseArgs = {\n value: unknown;\n data: unknown;\n invoker: TailorPrincipal | null;\n};\n\nexport type FieldParseInternalArgs = {\n value: unknown;\n data: unknown;\n invoker: TailorPrincipal | null;\n pathArray: string[];\n};\n\nexport type FieldRuntime<T extends TailorFieldType = TailorFieldType> = {\n readonly type: T;\n readonly fields: Record<string, FieldRuntime>;\n _metadata: FieldMetadata;\n};\n\ntype FieldParseRuntimeArgs<T extends TailorFieldType> = FieldParseInternalArgs & {\n field: FieldRuntime<T>;\n};\n\ntype FieldValidationArgs<T extends TailorFieldType> = FieldParseRuntimeArgs<T> & {\n issues: StandardSchemaV1.Issue[];\n};\n\nfunction validateBaseValue<T extends TailorFieldType>(args: FieldValidationArgs<T>): boolean {\n const { field, value, pathArray, issues } = args;\n const path = pathArray.length > 0 ? pathArray : undefined;\n const initialIssueCount = issues.length;\n\n switch (field.type) {\n case \"string\":\n if (typeof value !== \"string\") {\n issues.push({\n message: `Expected a string: received ${String(value)}`,\n path,\n });\n }\n break;\n\n case \"integer\":\n if (typeof value !== \"number\" || !Number.isInteger(value)) {\n issues.push({\n message: `Expected an integer: received ${String(value)}`,\n path,\n });\n }\n break;\n\n case \"float\":\n if (typeof value !== \"number\" || !Number.isFinite(value)) {\n issues.push({\n message: `Expected a number: received ${String(value)}`,\n path,\n });\n }\n break;\n\n case \"boolean\":\n if (typeof value !== \"boolean\") {\n issues.push({\n message: `Expected a boolean: received ${String(value)}`,\n path,\n });\n }\n break;\n\n case \"uuid\":\n if (typeof value !== \"string\" || !regex.uuid.test(value)) {\n issues.push({\n message: `Expected a valid UUID: received ${String(value)}`,\n path,\n });\n }\n break;\n case \"date\":\n if (typeof value !== \"string\" || !regex.date.test(value)) {\n issues.push({\n message: `Expected to match \"yyyy-MM-dd\" format: received ${String(value)}`,\n path,\n });\n }\n break;\n case \"datetime\":\n if (typeof value !== \"string\" || !regex.datetime.test(value)) {\n issues.push({\n message: `Expected to match ISO format: received ${String(value)}`,\n path,\n });\n }\n break;\n case \"time\":\n if (typeof value !== \"string\" || !regex.time.test(value)) {\n issues.push({\n message: `Expected to match \"HH:mm\" format: received ${String(value)}`,\n path,\n });\n }\n break;\n case \"decimal\":\n if (typeof value !== \"string\" || !regex.decimal.test(value)) {\n issues.push({\n message: `Expected a decimal string: received ${String(value)}`,\n path,\n });\n }\n break;\n\n case \"enum\":\n if (field._metadata.allowedValues) {\n const allowedValues = field._metadata.allowedValues.map((v) => v.value);\n if (typeof value !== \"string\" || !allowedValues.includes(value)) {\n issues.push({\n message: `Must be one of [${allowedValues.join(\", \")}]: received ${String(value)}`,\n path,\n });\n }\n }\n break;\n\n case \"nested\": {\n if (!isNestedObject(value)) {\n issues.push({\n message: `Expected an object: received ${String(value)}`,\n path,\n });\n return false;\n }\n\n let nestedBaseValid = true;\n for (const [fieldName, nestedField] of Object.entries(field.fields)) {\n const fieldValue = value[fieldName];\n if (\n !validateBaseField({\n ...args,\n field: nestedField,\n value: fieldValue,\n pathArray: pathArray.concat(fieldName),\n })\n ) {\n nestedBaseValid = false;\n }\n }\n return nestedBaseValid;\n }\n }\n\n return issues.length === initialIssueCount;\n}\n\nfunction validateCustomValue<T extends TailorFieldType>(\n args: FieldValidationArgs<T>,\n validateFns: NonNullable<FieldMetadata[\"validate\"]>,\n): void {\n const { value, pathArray, issues } = args;\n const path = pathArray.length > 0 ? pathArray : undefined;\n\n for (const fn of validateFns) {\n const result = fn({ value });\n if (typeof result === \"string\") {\n issues.push({\n message: result,\n path,\n });\n }\n }\n}\n\nfunction validateBaseField<T extends TailorFieldType>(args: FieldValidationArgs<T>): boolean {\n const { field, value, pathArray, issues } = args;\n const path = pathArray.length > 0 ? pathArray : undefined;\n\n const isNullOrUndefined = value === null || value === undefined;\n if (field._metadata.required && isNullOrUndefined) {\n issues.push({\n message: \"Required field is missing\",\n path,\n });\n return false;\n }\n\n if (!field._metadata.required && isNullOrUndefined) {\n return true;\n }\n\n let baseValid = true;\n if (field._metadata.array) {\n if (!Array.isArray(value)) {\n issues.push({\n message: \"Expected an array\",\n path,\n });\n return false;\n }\n\n for (let i = 0; i < value.length; i++) {\n if (\n !validateBaseValue({\n ...args,\n value: value[i],\n pathArray: pathArray.concat(`[${i}]`),\n })\n ) {\n baseValid = false;\n }\n }\n } else {\n baseValid = validateBaseValue(args);\n }\n\n return baseValid;\n}\n\nfunction validateCustomField<T extends TailorFieldType>(args: FieldValidationArgs<T>): void {\n const { field, value, pathArray } = args;\n if (value === null || value === undefined) {\n return;\n }\n\n if (field.type === \"nested\") {\n const records = field._metadata.array\n ? (value as Record<string, unknown>[])\n : [value as Record<string, unknown>];\n\n for (let i = 0; i < records.length; i++) {\n const record = records[i] as Record<string, unknown>;\n const recordPath = field._metadata.array ? pathArray.concat(`[${i}]`) : pathArray;\n for (const [fieldName, nestedField] of Object.entries(field.fields)) {\n validateCustomField({\n ...args,\n field: nestedField,\n value: record[fieldName],\n pathArray: recordPath.concat(fieldName),\n });\n }\n }\n }\n\n const validateFns = field._metadata.validate;\n if (validateFns?.length) {\n validateCustomValue(args, validateFns);\n }\n}\n\nexport function parseInternal<T extends TailorFieldType, Output>(\n args: FieldParseRuntimeArgs<T>,\n dateParsers: DateParsers = bundledDateParsers,\n): StandardSchemaV1.Result<Output> {\n let { value } = args;\n const issues: StandardSchemaV1.Issue[] = [];\n const validationArgs = { ...args, issues };\n const baseValid = validateBaseField(validationArgs);\n if (baseValid) {\n value = deserializeDates(validationArgs, dateParsers);\n if (issues.length === 0) {\n validateCustomField({ ...validationArgs, value });\n }\n }\n if (issues.length > 0) {\n return { issues };\n }\n\n return { value: (value ?? null) as Output };\n}\n\ntype DateParser = (type: TailorFieldType, text: string) => unknown;\n\ntype DateParsers = {\n readonly date: DateParser | undefined;\n readonly temporal: DateParser | undefined;\n};\n\nfunction rejectLeapSecond(type: TailorFieldType, text: string): void {\n if (type === \"datetime\" && text.slice(17, 19) === \"60\") {\n throw new RangeError(\"Leap seconds are not supported\");\n }\n}\n\nfunction parseAsDate(type: TailorFieldType, text: string): Date {\n rejectLeapSecond(type, text);\n const date = new Date(\n type === \"date\"\n ? `${text}T00:00:00.000Z`\n : type === \"time\"\n ? `1970-01-01T${text}:00.000Z`\n : text,\n );\n if (!Number.isFinite(date.getTime())) throw new RangeError(\"Invalid Date\");\n if (type !== \"time\") {\n const calendarDate = text.slice(0, 10);\n if (formatDate(new Date(`${calendarDate}T00:00:00.000Z`)) !== calendarDate) {\n throw new RangeError(\"Invalid calendar date\");\n }\n }\n return date;\n}\n\nfunction parseAsTemporal(type: TailorFieldType, text: string): unknown {\n rejectLeapSecond(type, text);\n const Temporal = getTemporal();\n if (type === \"date\") return Temporal.PlainDate.from(text);\n if (type === \"datetime\") return Temporal.Instant.from(text);\n return Temporal.PlainTime.from(text);\n}\n\nconst allDateParsers: DateParsers = { date: parseAsDate, temporal: parseAsTemporal };\n\ntype MaybeProcessGlobal = { process?: { env: Record<string, string | undefined> } };\n\nconst bundledDateParsers: DateParsers = {\n date: (globalThis as MaybeProcessGlobal).process?.env.__TAILOR_PLATFORM_BUNDLE_WITHOUT_DATE\n ? undefined\n : parseAsDate,\n temporal: (globalThis as MaybeProcessGlobal).process?.env\n .__TAILOR_PLATFORM_BUNDLE_WITHOUT_TEMPORAL\n ? undefined\n : parseAsTemporal,\n};\n\nfunction deserializeDates(\n args: FieldValidationArgs<TailorFieldType>,\n dateParsers: DateParsers,\n): unknown {\n const { field, value, issues, pathArray } = args;\n if (value === null || value === undefined) return value;\n const convert = (item: unknown, itemPath: string[]): unknown => {\n const { type } = field;\n const as = dateRepresentationOf(type, field._metadata.as);\n if (as) {\n const parse = dateParsers[as];\n if (!parse) {\n throw new Error(\n `Parsing fields declared with as: \"${as}\" is not included in this bundle. Parse them with parseDateFields, exported by \"@tailor-platform/sdk/runtime\".`,\n );\n }\n try {\n return parse(type, String(item));\n } catch (error) {\n if (!(error instanceof RangeError)) throw error;\n issues.push({\n message: `Expected a valid ${type === \"date\" ? \"calendar date\" : type}: received ${item}`,\n path: itemPath.length > 0 ? itemPath : undefined,\n });\n return item;\n }\n }\n if (field.type !== \"nested\") return item;\n const record = item as Record<string, unknown>;\n let result = record;\n for (const [key, child] of Object.entries(field.fields)) {\n const converted = deserializeDates(\n {\n ...args,\n field: child,\n value: record[key],\n pathArray: itemPath.concat(key),\n },\n dateParsers,\n );\n if (converted !== record[key]) {\n if (result === record) result = { ...record };\n Object.defineProperty(result, key, {\n value: converted,\n enumerable: true,\n configurable: true,\n writable: true,\n });\n }\n }\n return result;\n };\n if (!field._metadata.array) return convert(value, pathArray);\n const values = value as unknown[];\n const converted = values.map((item, index) => convert(item, pathArray.concat(`[${index}]`)));\n return converted.every((item, index) => item === values[index]) ? value : converted;\n}\n\ntype ParseInputFieldsArgs = FieldParseArgs & {\n fields: Record<string, FieldRuntime>;\n};\n\n/**\n * Validate a value against a record of input fields, treating the record as a\n * single required object — the same code path deployed functions run via\n * `t.object(fields).parse(...)`, so local validation matches platform behavior.\n * @param args - Input field definitions plus the value, context data, and user\n * @returns Validation result\n */\nexport function parseInputFields(args: ParseInputFieldsArgs): StandardSchemaV1.Result<unknown> {\n const { fields, ...parseArgs } = args;\n return parseInternal({\n ...parseArgs,\n field: { type: \"nested\", fields, _metadata: { required: true } },\n pathArray: [],\n });\n}\n\ntype ParsableField<Output> = FieldRuntime & {\n parse(args: FieldParseArgs): StandardSchemaV1.Result<Output>;\n};\n\n/**\n * Parse a value like `field.parse`, converting fields declared with `as: \"date\"` or\n * `as: \"temporal\"` even in bundles that leave that conversion out of `field.parse`.\n * @param field - Field defining the value's shape\n * @param args - Value to parse, with the context data and invoker passed to validators\n * @returns Validation result with Date and Temporal fields converted\n */\nexport function parseDateFields<Output>(\n field: ParsableField<Output>,\n args: FieldParseArgs,\n): StandardSchemaV1.Result<Output> {\n return parseInternal({ ...args, field, pathArray: [] }, allDateParsers);\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"file-DKBOj5q4.mjs","names":[],"sources":["../src/runtime/file.ts"],"sourcesContent":["/**\n * TailorDB file (BLOB) utilities.\n *\n * Thin typed wrapper around the platform-provided `tailordb.file` runtime API.\n * At runtime this delegates to `globalThis.tailordb.file`. Use `mockFile` from\n * `@tailor-platform/sdk/vitest` to mock these calls in unit tests.\n * @example\n * import { file } from \"@tailor-platform/sdk/runtime\";\n *\n * const { metadata } = await file.upload(\n * \"my-namespace\",\n * \"Document\",\n * \"attachment\",\n * recordId,\n * bytes,\n * );\n */\n\n/** Upload response metadata. */\nexport interface UploadMetadata {\n fileSize: number;\n sha256sum: string;\n}\n\n/** Download response metadata. */\nexport interface DownloadMetadata {\n contentType: string;\n fileSize: number;\n sha256sum: string;\n lastUploadedAt: string;\n}\n\n/** File metadata (for {@link TailorDBFileAPI.getMetadata}). */\nexport interface FileMetadata {\n contentType: string;\n fileSize: number;\n sha256sum: string;\n urlPath: string;\n lastUploadedAt?: string;\n}\n\n/** Upload options. */\nexport interface FileUploadOptions {\n contentType?: string;\n /** How to interpret string data. Ignored for byte arrays and buffers. */\n encoding?: \"utf8\" | \"base64\";\n}\n\n/** Upload options with an explicit interpretation for string data. */\nexport interface FileUploadStringOptions extends FileUploadOptions {\n encoding: \"utf8\" | \"base64\";\n}\n\n/** Binary contents accepted by {@link file.upload}. */\nexport type FileUploadBytes = ArrayBuffer | Uint8Array | number[];\n\n/** Upload stream options. */\nexport interface FileUploadStreamOptions {\n contentType?: string;\n fileSize?: number;\n}\n\n/** Upload response. */\nexport interface FileUploadResponse {\n metadata: UploadMetadata;\n}\n\n/** Download response. */\nexport interface FileDownloadResponse {\n data: Uint8Array;\n metadata: DownloadMetadata;\n}\n\n/** Download-as-Base64 response. */\nexport interface FileDownloadAsBase64Response {\n data: string;\n metadata: DownloadMetadata;\n}\n\n/** Download stream response. */\nexport interface FileDownloadStreamResponse {\n body: ReadableStream<Uint8Array>;\n metadata: DownloadMetadata;\n}\n\n/** Error code emitted by {@link TailorDBFileError}. */\nexport type TailorDBFileErrorCode =\n | \"INVALID_PARAMS\"\n | \"INVALID_DATA_TYPE\"\n | \"OPERATION_FAILED\"\n | \"DELETE_FAILED\"\n | \"STREAM_OPEN_FAILED\"\n | \"STREAM_READ_ERROR\"\n | \"STREAM_ERROR\"\n | \"FILE_TOO_LARGE\";\n\n/**\n * Type-only shape of the `TailorDBFileError` runtime class. The class itself\n * is provided by the platform runtime (and by `injectMocks` in tests); this\n * interface mirrors it so callers can `import type { TailorDBFileError }` from\n * the wrapper module without depending on any ambient declaration.\n */\nexport interface TailorDBFileError extends Error {\n name: \"TailorDBFileError\";\n code?: TailorDBFileErrorCode;\n cause?: unknown;\n}\n\n/**\n * Platform API surface for `tailordb.file`. Describes the shape the platform\n * runtime injects on `globalThis.tailordb.file`.\n */\nexport interface TailorDBFileAPI {\n /**\n * Upload a file to TailorDB.\n * @param namespace - TailorDB namespace\n * @param tableName - TailorDB table name\n * @param fieldName - File field name on the table\n * @param recordId - Record ID owning the field\n * @param data - File contents\n * @param options - Upload options (e.g. `contentType`)\n * @returns Upload response containing the file metadata\n */\n upload(\n namespace: string,\n tableName: string,\n fieldName: string,\n recordId: string,\n data: string | FileUploadBytes,\n options?: Omit<FileUploadOptions, \"encoding\">,\n ): Promise<FileUploadResponse>;\n\n /**\n * Download a file from TailorDB.\n *\n * Throws `TailorDBFileError` with code `FILE_TOO_LARGE` when the file\n * exceeds 10MB — use {@link downloadStream} for large files.\n * @param namespace - TailorDB namespace\n * @param tableName - TailorDB table name\n * @param fieldName - File field name on the table\n * @param recordId - Record ID owning the field\n * @returns Bytes and metadata for the file\n */\n download(\n namespace: string,\n tableName: string,\n fieldName: string,\n recordId: string,\n ): Promise<FileDownloadResponse>;\n\n /**\n * Download a file from TailorDB as a Base64-encoded string.\n *\n * Throws `TailorDBFileError` with code `FILE_TOO_LARGE` when the file\n * exceeds 10MB — use {@link downloadStream} for large files.\n * @param namespace - TailorDB namespace\n * @param tableName - TailorDB table name\n * @param fieldName - File field name on the table\n * @param recordId - Record ID owning the field\n * @returns Base64-encoded contents and metadata for the file\n */\n downloadAsBase64(\n namespace: string,\n tableName: string,\n fieldName: string,\n recordId: string,\n ): Promise<FileDownloadAsBase64Response>;\n\n /**\n * Delete a file from TailorDB.\n * @param namespace - TailorDB namespace\n * @param tableName - TailorDB table name\n * @param fieldName - File field name on the table\n * @param recordId - Record ID owning the field\n * @returns Resolves once the file has been deleted\n */\n delete(namespace: string, tableName: string, fieldName: string, recordId: string): Promise<void>;\n\n /**\n * Get file metadata from TailorDB.\n * @param namespace - TailorDB namespace\n * @param tableName - TailorDB table name\n * @param fieldName - File field name on the table\n * @param recordId - Record ID owning the field\n * @returns Metadata for the stored file\n */\n getMetadata(\n namespace: string,\n tableName: string,\n fieldName: string,\n recordId: string,\n ): Promise<FileMetadata>;\n\n /**\n * Download a file as a ReadableStream.\n * @param namespace - TailorDB namespace\n * @param tableName - TailorDB table name\n * @param fieldName - File field name on the table\n * @param recordId - Record ID owning the field\n * @returns ReadableStream body and metadata for the file\n */\n downloadStream(\n namespace: string,\n tableName: string,\n fieldName: string,\n recordId: string,\n ): Promise<FileDownloadStreamResponse>;\n\n /**\n * Upload a file using a ReadableStream.\n * @param namespace - TailorDB namespace\n * @param tableName - TailorDB table name\n * @param fieldName - File field name on the table\n * @param recordId - Record ID owning the field\n * @param readableStream - ReadableStream providing the file data\n * @param options - Upload stream options (e.g. `contentType`, `fileSize`)\n * @returns Upload response containing the file metadata\n */\n uploadStream(\n namespace: string,\n tableName: string,\n fieldName: string,\n recordId: string,\n readableStream: ReadableStream<Uint8Array | ArrayBuffer>,\n options?: FileUploadStreamOptions,\n ): Promise<FileUploadResponse>;\n}\n\nconst api = (): TailorDBFileAPI =>\n (globalThis as unknown as { tailordb: { file: TailorDBFileAPI } }).tailordb.file;\n\nconst DATA_URL_PREFIX = /^data:([^,]*);base64,/i;\n\nfunction stripBase64DataUrl(data: string): { contentType?: string; payload: string } {\n const match = DATA_URL_PREFIX.exec(data);\n if (!match) return { payload: data };\n return { contentType: match[1] || undefined, payload: data.slice(match[0].length) };\n}\n\nfunction decodeBase64(data: string): Uint8Array {\n if (typeof Uint8Array.fromBase64 === \"function\") {\n try {\n return Uint8Array.fromBase64(data);\n } catch {\n throw new TypeError(\"Invalid Base64 file data.\");\n }\n }\n\n // Uint8Array.fromBase64 is unflagged only from Node 25 (V8 14.1); decode manually before that.\n const base64 = data.replace(/[\\t\\n\\f\\r ]/g, \"\");\n if (\n !/^[A-Za-z0-9+/]*={0,2}$/.test(base64) ||\n base64.length % 4 === 1 ||\n (base64.includes(\"=\") && base64.length % 4 !== 0)\n ) {\n throw new TypeError(\"Invalid Base64 file data.\");\n }\n const decoded = atob(base64);\n const bytes = new Uint8Array(decoded.length);\n for (let index = 0; index < decoded.length; index++) {\n bytes[index] = decoded.charCodeAt(index);\n }\n return bytes;\n}\n\n/**\n * Upload file bytes without encoding or decoding them.\n * @param namespace - TailorDB namespace\n * @param tableName - TailorDB table name\n * @param fieldName - File field name on the table\n * @param recordId - Record ID owning the field\n * @param data - File bytes\n * @param options - Upload options; encoding is ignored for bytes\n * @returns Upload response containing the file metadata\n */\nfunction upload(\n namespace: string,\n tableName: string,\n fieldName: string,\n recordId: string,\n data: FileUploadBytes,\n options?: FileUploadOptions,\n): Promise<FileUploadResponse>;\n/**\n * Upload text as UTF-8 or decode Base64 into file bytes.\n * @param namespace - TailorDB namespace\n * @param tableName - TailorDB table name\n * @param fieldName - File field name on the table\n * @param recordId - Record ID owning the field\n * @param data - String to encode or decode, or file bytes to upload unchanged; a base64 value\n * may be a `data:<contentType>;base64,<payload>` URL, whose content type is extracted\n * @param options - String encoding and optional content type; utf8 defaults contentType to text/plain; charset=utf-8 when omitted\n * @returns Upload response containing the file metadata\n * @throws {TypeError} If the encoding is unsupported or Base64 data is invalid\n */\nfunction upload(\n namespace: string,\n tableName: string,\n fieldName: string,\n recordId: string,\n data: string | FileUploadBytes,\n options: FileUploadStringOptions,\n): Promise<FileUploadResponse>;\n/**\n * Upload file contents, treating strings without encoding as text.\n * @deprecated since 2.15.0 — pass encoding: \"utf8\" for text or \"base64\" for Base64 strings. codemod: v3/file-upload-encoding\n * @param namespace - TailorDB namespace\n * @param tableName - TailorDB table name\n * @param fieldName - File field name on the table\n * @param recordId - Record ID owning the field\n * @param data - File contents\n * @param options - Upload options\n * @returns Upload response containing the file metadata\n */\nfunction upload(\n namespace: string,\n tableName: string,\n fieldName: string,\n recordId: string,\n data: string | FileUploadBytes,\n options?: FileUploadOptions,\n): Promise<FileUploadResponse>;\nasync function upload(\n namespace: string,\n tableName: string,\n fieldName: string,\n recordId: string,\n data: string | FileUploadBytes,\n options?: FileUploadOptions,\n): Promise<FileUploadResponse> {\n if (options?.encoding === undefined) {\n return api().upload(namespace, tableName, fieldName, recordId, data, options);\n }\n\n const { encoding, ...uploadOptions } = options;\n let contents = data;\n if (typeof data === \"string\") {\n switch (encoding) {\n case \"utf8\":\n contents = new TextEncoder().encode(data);\n uploadOptions.contentType ??= \"text/plain; charset=utf-8\";\n break;\n case \"base64\": {\n const { contentType, payload } = stripBase64DataUrl(data);\n contents = decodeBase64(payload);\n uploadOptions.contentType ??= contentType;\n break;\n }\n default:\n throw new TypeError(`Unsupported file upload encoding: ${encoding}`);\n }\n }\n return api().upload(namespace, tableName, fieldName, recordId, contents, uploadOptions);\n}\n\n/**\n * See {@link TailorDBFileAPI.download}.\n * @param args - Forwarded to {@link TailorDBFileAPI.download}\n * @returns Bytes and metadata for the file\n */\nconst download: TailorDBFileAPI[\"download\"] = (...args) => api().download(...args);\n\n/**\n * See {@link TailorDBFileAPI.downloadAsBase64}.\n * @param args - Forwarded to {@link TailorDBFileAPI.downloadAsBase64}\n * @returns Base64-encoded contents and metadata for the file\n */\nconst downloadAsBase64: TailorDBFileAPI[\"downloadAsBase64\"] = (...args) =>\n api().downloadAsBase64(...args);\n\n/**\n * See {@link TailorDBFileAPI.delete}.\n * @param args - Forwarded to {@link TailorDBFileAPI.delete}\n * @returns Resolves once the file has been deleted\n */\nconst deleteFile: TailorDBFileAPI[\"delete\"] = (...args) => api().delete(...args);\n\n/**\n * See {@link TailorDBFileAPI.getMetadata}.\n * @param args - Forwarded to {@link TailorDBFileAPI.getMetadata}\n * @returns Metadata for the stored file\n */\nconst getMetadata: TailorDBFileAPI[\"getMetadata\"] = (...args) => api().getMetadata(...args);\n\n/**\n * See {@link TailorDBFileAPI.downloadStream}.\n * @param args - Forwarded to {@link TailorDBFileAPI.downloadStream}\n * @returns ReadableStream body and metadata for the file\n */\nconst downloadStream: TailorDBFileAPI[\"downloadStream\"] = (...args) =>\n api().downloadStream(...args);\n\n/**\n * See {@link TailorDBFileAPI.uploadStream}.\n * @param args - Forwarded to {@link TailorDBFileAPI.uploadStream}\n * @returns Upload response containing the file metadata\n */\nconst uploadStream: TailorDBFileAPI[\"uploadStream\"] = (...args) => api().uploadStream(...args);\n\n/** Runtime wrapper namespace for `tailordb.file`. */\nexport const file = {\n // oxlint-disable-next-line typescript/no-deprecated -- Only the legacy overload is deprecated.\n upload,\n download,\n downloadAsBase64,\n delete: deleteFile,\n getMetadata,\n downloadStream,\n uploadStream,\n} as const satisfies TailorDBFileAPI;\n"],"mappings":"AAoOA,MAAM,QACH,WAAkE,SAAS,KAExE,EAAkB,yBAExB,SAAS,mBAAmB,EAAyD,CACnF,IAAM,EAAQ,EAAgB,KAAK,CAAI,EAEvC,OADK,EACE,CAAE,YAAa,EAAM,IAAM,IAAA,GAAW,QAAS,EAAK,MAAM,EAAM,EAAE,CAAC,MAAM,CAAE,EAD/D,CAAE,QAAS,CAAK,CAErC,CAEA,SAAS,aAAa,EAA0B,CAC9C,GAAI,OAAO,WAAW,YAAe,WACnC,GAAI,CACF,OAAO,WAAW,WAAW,CAAI,CACnC,MAAQ,CACN,MAAU,UAAU,2BAA2B,CACjD,CAIF,IAAM,EAAS,EAAK,QAAQ,eAAgB,EAAE,EAC9C,GACE,CAAC,yBAAyB,KAAK,CAAM,GACrC,EAAO,OAAS,GAAM,GACrB,EAAO,SAAS,GAAG,GAAK,EAAO,OAAS,GAAM,EAE/C,MAAU,UAAU,2BAA2B,EAEjD,IAAM,EAAU,KAAK,CAAM,EACrB,EAAQ,IAAI,WAAW,EAAQ,MAAM,EAC3C,IAAK,IAAI,EAAQ,EAAG,EAAQ,EAAQ,OAAQ,IAC1C,EAAM,GAAS,EAAQ,WAAW,CAAK,EAEzC,OAAO,CACT,CA2DA,eAAe,OACb,EACA,EACA,EACA,EACA,EACA,EAC6B,CAC7B,GAAI,GAAS,WAAa,IAAA,GACxB,OAAO,IAAI,CAAC,CAAC,OAAO,EAAW,EAAW,EAAW,EAAU,EAAM,CAAO,EAG9E,GAAM,CAAE,WAAU,GAAG,GAAkB,EACnC,EAAW,EACf,GAAI,OAAO,GAAS,SAClB,OAAQ,EAAR,CACE,IAAK,OACH,EAAW,IAAI,YAAY,CAAC,CAAC,OAAO,CAAI,EACxC,EAAc,cAAgB,4BAC9B,MACF,IAAK,SAAU,CACb,GAAM,CAAE,cAAa,WAAY,mBAAmB,CAAI,EACxD,EAAW,aAAa,CAAO,EAC/B,EAAc,cAAgB,EAC9B,KACF,CACA,QACE,MAAU,UAAU,qCAAqC,GAAU,CACvE,CAEF,OAAO,IAAI,CAAC,CAAC,OAAO,EAAW,EAAW,EAAW,EAAU,EAAU,CAAa,CACxF,CA+CA,MAAa,EAAO,CAElB,OACA,UA3C6C,GAAG,IAAS,IAAI,CAAC,CAAC,SAAS,GAAG,CAAI,EA4C/E,kBArC6D,GAAG,IAChE,IAAI,CAAC,CAAC,iBAAiB,GAAG,CAAI,EAqC9B,QA9B6C,GAAG,IAAS,IAAI,CAAC,CAAC,OAAO,GAAG,CAAI,EA+B7E,aAxBmD,GAAG,IAAS,IAAI,CAAC,CAAC,YAAY,GAAG,CAAI,EAyBxF,gBAlByD,GAAG,IAC5D,IAAI,CAAC,CAAC,eAAe,GAAG,CAAI,EAkB5B,cAXqD,GAAG,IAAS,IAAI,CAAC,CAAC,aAAa,GAAG,CAAI,CAY7F"}
1
+ {"version":3,"file":"file-DKBOj5q4.mjs","names":["DATA_URL_PREFIX","match","data","base64","decoded","bytes","index","options","namespace","tableName","fieldName","recordId","uploadOptions","contents","encoding","payload","contentType","file","args"],"sources":["../src/runtime/file.ts"],"sourcesContent":["/**\n * TailorDB file (BLOB) utilities.\n *\n * Thin typed wrapper around the platform-provided `tailordb.file` runtime API.\n * At runtime this delegates to `globalThis.tailordb.file`. Use `mockFile` from\n * `@tailor-platform/sdk/vitest` to mock these calls in unit tests.\n * @example\n * import { file } from \"@tailor-platform/sdk/runtime\";\n *\n * const { metadata } = await file.upload(\n * \"my-namespace\",\n * \"Document\",\n * \"attachment\",\n * recordId,\n * bytes,\n * );\n */\n\n/** Upload response metadata. */\nexport interface UploadMetadata {\n fileSize: number;\n sha256sum: string;\n}\n\n/** Download response metadata. */\nexport interface DownloadMetadata {\n contentType: string;\n fileSize: number;\n sha256sum: string;\n lastUploadedAt: string;\n}\n\n/** File metadata (for {@link TailorDBFileAPI.getMetadata}). */\nexport interface FileMetadata {\n contentType: string;\n fileSize: number;\n sha256sum: string;\n urlPath: string;\n lastUploadedAt?: string;\n}\n\n/** Upload options. */\nexport interface FileUploadOptions {\n contentType?: string;\n /** How to interpret string data. Ignored for byte arrays and buffers. */\n encoding?: \"utf8\" | \"base64\";\n}\n\n/** Upload options with an explicit interpretation for string data. */\nexport interface FileUploadStringOptions extends FileUploadOptions {\n encoding: \"utf8\" | \"base64\";\n}\n\n/** Binary contents accepted by {@link file.upload}. */\nexport type FileUploadBytes = ArrayBuffer | Uint8Array | number[];\n\n/** Upload stream options. */\nexport interface FileUploadStreamOptions {\n contentType?: string;\n fileSize?: number;\n}\n\n/** Upload response. */\nexport interface FileUploadResponse {\n metadata: UploadMetadata;\n}\n\n/** Download response. */\nexport interface FileDownloadResponse {\n data: Uint8Array;\n metadata: DownloadMetadata;\n}\n\n/** Download-as-Base64 response. */\nexport interface FileDownloadAsBase64Response {\n data: string;\n metadata: DownloadMetadata;\n}\n\n/** Download stream response. */\nexport interface FileDownloadStreamResponse {\n body: ReadableStream<Uint8Array>;\n metadata: DownloadMetadata;\n}\n\n/** Error code emitted by {@link TailorDBFileError}. */\nexport type TailorDBFileErrorCode =\n | \"INVALID_PARAMS\"\n | \"INVALID_DATA_TYPE\"\n | \"OPERATION_FAILED\"\n | \"DELETE_FAILED\"\n | \"STREAM_OPEN_FAILED\"\n | \"STREAM_READ_ERROR\"\n | \"STREAM_ERROR\"\n | \"FILE_TOO_LARGE\";\n\n/**\n * Type-only shape of the `TailorDBFileError` runtime class. The class itself\n * is provided by the platform runtime (and by `injectMocks` in tests); this\n * interface mirrors it so callers can `import type { TailorDBFileError }` from\n * the wrapper module without depending on any ambient declaration.\n */\nexport interface TailorDBFileError extends Error {\n name: \"TailorDBFileError\";\n code?: TailorDBFileErrorCode;\n cause?: unknown;\n}\n\n/**\n * Platform API surface for `tailordb.file`. Describes the shape the platform\n * runtime injects on `globalThis.tailordb.file`.\n */\nexport interface TailorDBFileAPI {\n /**\n * Upload a file to TailorDB.\n * @param namespace - TailorDB namespace\n * @param tableName - TailorDB table name\n * @param fieldName - File field name on the table\n * @param recordId - Record ID owning the field\n * @param data - File contents\n * @param options - Upload options (e.g. `contentType`)\n * @returns Upload response containing the file metadata\n */\n upload(\n namespace: string,\n tableName: string,\n fieldName: string,\n recordId: string,\n data: string | FileUploadBytes,\n options?: Omit<FileUploadOptions, \"encoding\">,\n ): Promise<FileUploadResponse>;\n\n /**\n * Download a file from TailorDB.\n *\n * Throws `TailorDBFileError` with code `FILE_TOO_LARGE` when the file\n * exceeds 10MB — use {@link downloadStream} for large files.\n * @param namespace - TailorDB namespace\n * @param tableName - TailorDB table name\n * @param fieldName - File field name on the table\n * @param recordId - Record ID owning the field\n * @returns Bytes and metadata for the file\n */\n download(\n namespace: string,\n tableName: string,\n fieldName: string,\n recordId: string,\n ): Promise<FileDownloadResponse>;\n\n /**\n * Download a file from TailorDB as a Base64-encoded string.\n *\n * Throws `TailorDBFileError` with code `FILE_TOO_LARGE` when the file\n * exceeds 10MB — use {@link downloadStream} for large files.\n * @param namespace - TailorDB namespace\n * @param tableName - TailorDB table name\n * @param fieldName - File field name on the table\n * @param recordId - Record ID owning the field\n * @returns Base64-encoded contents and metadata for the file\n */\n downloadAsBase64(\n namespace: string,\n tableName: string,\n fieldName: string,\n recordId: string,\n ): Promise<FileDownloadAsBase64Response>;\n\n /**\n * Delete a file from TailorDB.\n * @param namespace - TailorDB namespace\n * @param tableName - TailorDB table name\n * @param fieldName - File field name on the table\n * @param recordId - Record ID owning the field\n * @returns Resolves once the file has been deleted\n */\n delete(namespace: string, tableName: string, fieldName: string, recordId: string): Promise<void>;\n\n /**\n * Get file metadata from TailorDB.\n * @param namespace - TailorDB namespace\n * @param tableName - TailorDB table name\n * @param fieldName - File field name on the table\n * @param recordId - Record ID owning the field\n * @returns Metadata for the stored file\n */\n getMetadata(\n namespace: string,\n tableName: string,\n fieldName: string,\n recordId: string,\n ): Promise<FileMetadata>;\n\n /**\n * Download a file as a ReadableStream.\n * @param namespace - TailorDB namespace\n * @param tableName - TailorDB table name\n * @param fieldName - File field name on the table\n * @param recordId - Record ID owning the field\n * @returns ReadableStream body and metadata for the file\n */\n downloadStream(\n namespace: string,\n tableName: string,\n fieldName: string,\n recordId: string,\n ): Promise<FileDownloadStreamResponse>;\n\n /**\n * Upload a file using a ReadableStream.\n * @param namespace - TailorDB namespace\n * @param tableName - TailorDB table name\n * @param fieldName - File field name on the table\n * @param recordId - Record ID owning the field\n * @param readableStream - ReadableStream providing the file data\n * @param options - Upload stream options (e.g. `contentType`, `fileSize`)\n * @returns Upload response containing the file metadata\n */\n uploadStream(\n namespace: string,\n tableName: string,\n fieldName: string,\n recordId: string,\n readableStream: ReadableStream<Uint8Array | ArrayBuffer>,\n options?: FileUploadStreamOptions,\n ): Promise<FileUploadResponse>;\n}\n\nconst api = (): TailorDBFileAPI =>\n (globalThis as unknown as { tailordb: { file: TailorDBFileAPI } }).tailordb.file;\n\nconst DATA_URL_PREFIX = /^data:([^,]*);base64,/i;\n\nfunction stripBase64DataUrl(data: string): { contentType?: string; payload: string } {\n const match = DATA_URL_PREFIX.exec(data);\n if (!match) return { payload: data };\n return { contentType: match[1] || undefined, payload: data.slice(match[0].length) };\n}\n\nfunction decodeBase64(data: string): Uint8Array {\n if (typeof Uint8Array.fromBase64 === \"function\") {\n try {\n return Uint8Array.fromBase64(data);\n } catch {\n throw new TypeError(\"Invalid Base64 file data.\");\n }\n }\n\n // Uint8Array.fromBase64 is unflagged only from Node 25 (V8 14.1); decode manually before that.\n const base64 = data.replace(/[\\t\\n\\f\\r ]/g, \"\");\n if (\n !/^[A-Za-z0-9+/]*={0,2}$/.test(base64) ||\n base64.length % 4 === 1 ||\n (base64.includes(\"=\") && base64.length % 4 !== 0)\n ) {\n throw new TypeError(\"Invalid Base64 file data.\");\n }\n const decoded = atob(base64);\n const bytes = new Uint8Array(decoded.length);\n for (let index = 0; index < decoded.length; index++) {\n bytes[index] = decoded.charCodeAt(index);\n }\n return bytes;\n}\n\n/**\n * Upload file bytes without encoding or decoding them.\n * @param namespace - TailorDB namespace\n * @param tableName - TailorDB table name\n * @param fieldName - File field name on the table\n * @param recordId - Record ID owning the field\n * @param data - File bytes\n * @param options - Upload options; encoding is ignored for bytes\n * @returns Upload response containing the file metadata\n */\nfunction upload(\n namespace: string,\n tableName: string,\n fieldName: string,\n recordId: string,\n data: FileUploadBytes,\n options?: FileUploadOptions,\n): Promise<FileUploadResponse>;\n/**\n * Upload text as UTF-8 or decode Base64 into file bytes.\n * @param namespace - TailorDB namespace\n * @param tableName - TailorDB table name\n * @param fieldName - File field name on the table\n * @param recordId - Record ID owning the field\n * @param data - String to encode or decode, or file bytes to upload unchanged; a base64 value\n * may be a `data:<contentType>;base64,<payload>` URL, whose content type is extracted\n * @param options - String encoding and optional content type; utf8 defaults contentType to text/plain; charset=utf-8 when omitted\n * @returns Upload response containing the file metadata\n * @throws {TypeError} If the encoding is unsupported or Base64 data is invalid\n */\nfunction upload(\n namespace: string,\n tableName: string,\n fieldName: string,\n recordId: string,\n data: string | FileUploadBytes,\n options: FileUploadStringOptions,\n): Promise<FileUploadResponse>;\n/**\n * Upload file contents, treating strings without encoding as text.\n * @deprecated since 2.15.0 — pass encoding: \"utf8\" for text or \"base64\" for Base64 strings. codemod: v3/file-upload-encoding\n * @param namespace - TailorDB namespace\n * @param tableName - TailorDB table name\n * @param fieldName - File field name on the table\n * @param recordId - Record ID owning the field\n * @param data - File contents\n * @param options - Upload options\n * @returns Upload response containing the file metadata\n */\nfunction upload(\n namespace: string,\n tableName: string,\n fieldName: string,\n recordId: string,\n data: string | FileUploadBytes,\n options?: FileUploadOptions,\n): Promise<FileUploadResponse>;\nasync function upload(\n namespace: string,\n tableName: string,\n fieldName: string,\n recordId: string,\n data: string | FileUploadBytes,\n options?: FileUploadOptions,\n): Promise<FileUploadResponse> {\n if (options?.encoding === undefined) {\n return api().upload(namespace, tableName, fieldName, recordId, data, options);\n }\n\n const { encoding, ...uploadOptions } = options;\n let contents = data;\n if (typeof data === \"string\") {\n switch (encoding) {\n case \"utf8\":\n contents = new TextEncoder().encode(data);\n uploadOptions.contentType ??= \"text/plain; charset=utf-8\";\n break;\n case \"base64\": {\n const { contentType, payload } = stripBase64DataUrl(data);\n contents = decodeBase64(payload);\n uploadOptions.contentType ??= contentType;\n break;\n }\n default:\n throw new TypeError(`Unsupported file upload encoding: ${encoding}`);\n }\n }\n return api().upload(namespace, tableName, fieldName, recordId, contents, uploadOptions);\n}\n\n/**\n * See {@link TailorDBFileAPI.download}.\n * @param args - Forwarded to {@link TailorDBFileAPI.download}\n * @returns Bytes and metadata for the file\n */\nconst download: TailorDBFileAPI[\"download\"] = (...args) => api().download(...args);\n\n/**\n * See {@link TailorDBFileAPI.downloadAsBase64}.\n * @param args - Forwarded to {@link TailorDBFileAPI.downloadAsBase64}\n * @returns Base64-encoded contents and metadata for the file\n */\nconst downloadAsBase64: TailorDBFileAPI[\"downloadAsBase64\"] = (...args) =>\n api().downloadAsBase64(...args);\n\n/**\n * See {@link TailorDBFileAPI.delete}.\n * @param args - Forwarded to {@link TailorDBFileAPI.delete}\n * @returns Resolves once the file has been deleted\n */\nconst deleteFile: TailorDBFileAPI[\"delete\"] = (...args) => api().delete(...args);\n\n/**\n * See {@link TailorDBFileAPI.getMetadata}.\n * @param args - Forwarded to {@link TailorDBFileAPI.getMetadata}\n * @returns Metadata for the stored file\n */\nconst getMetadata: TailorDBFileAPI[\"getMetadata\"] = (...args) => api().getMetadata(...args);\n\n/**\n * See {@link TailorDBFileAPI.downloadStream}.\n * @param args - Forwarded to {@link TailorDBFileAPI.downloadStream}\n * @returns ReadableStream body and metadata for the file\n */\nconst downloadStream: TailorDBFileAPI[\"downloadStream\"] = (...args) =>\n api().downloadStream(...args);\n\n/**\n * See {@link TailorDBFileAPI.uploadStream}.\n * @param args - Forwarded to {@link TailorDBFileAPI.uploadStream}\n * @returns Upload response containing the file metadata\n */\nconst uploadStream: TailorDBFileAPI[\"uploadStream\"] = (...args) => api().uploadStream(...args);\n\n/** Runtime wrapper namespace for `tailordb.file`. */\nexport const file = {\n // oxlint-disable-next-line typescript/no-deprecated -- Only the legacy overload is deprecated.\n upload,\n download,\n downloadAsBase64,\n delete: deleteFile,\n getMetadata,\n downloadStream,\n uploadStream,\n} as const satisfies TailorDBFileAPI;\n"],"mappings":"AAoOA,MAAM,QACH,WAAkE,SAAS,KAExEA,EAAkB,yBAExB,SAAS,mBAAmB,EAAyD,CACnF,IAAMC,EAAQD,EAAgB,KAAKE,CAAI,EAEvC,OADKD,EACE,CAAE,YAAaA,EAAM,IAAM,IAAA,GAAW,QAASC,EAAK,MAAMD,EAAM,EAAE,CAAC,MAAM,CAAE,EAD/D,CAAE,QAASC,CAAK,CAErC,CAEA,SAAS,aAAa,EAA0B,CAC9C,GAAI,OAAO,WAAW,YAAe,WACnC,GAAI,CACF,OAAO,WAAW,WAAWA,CAAI,CACnC,MAAQ,CACN,MAAU,UAAU,2BAA2B,CACjD,CAIF,IAAMC,EAASD,EAAK,QAAQ,eAAgB,EAAE,EAC9C,GACE,CAAC,yBAAyB,KAAKC,CAAM,GACrCA,EAAO,OAAS,GAAM,GACrBA,EAAO,SAAS,GAAG,GAAKA,EAAO,OAAS,GAAM,EAE/C,MAAU,UAAU,2BAA2B,EAEjD,IAAMC,EAAU,KAAKD,CAAM,EACrBE,EAAQ,IAAI,WAAWD,EAAQ,MAAM,EAC3C,IAAK,IAAIE,EAAQ,EAAGA,EAAQF,EAAQ,OAAQ,IAC1C,EAAME,GAASF,EAAQ,WAAWE,CAAK,EAEzC,OAAOD,CACT,CA2DA,eAAe,OACb,EACA,EACA,EACA,EACA,EACA,EAC6B,CAC7B,GAAIE,GAAS,WAAa,IAAA,GACxB,OAAO,IAAI,CAAC,CAAC,OAAOC,EAAWC,EAAWC,EAAWC,EAAUT,EAAMK,CAAO,EAG9E,GAAM,CAAE,WAAU,GAAGK,GAAkBL,EACnCM,EAAWX,EACf,GAAI,OAAOA,GAAS,SAClB,OAAQY,EAAR,CACE,IAAK,OACH,EAAW,IAAI,YAAY,CAAC,CAAC,OAAOZ,CAAI,EACxC,EAAc,cAAgB,4BAC9B,MACF,IAAK,SAAU,CACb,GAAM,CAAE,cAAa,WAAY,mBAAmBA,CAAI,EACxD,EAAW,aAAaa,CAAO,EAC/B,EAAc,cAAgBC,EAC9B,KACF,CACA,QACE,MAAU,UAAU,qCAAqCF,GAAU,CACvE,CAEF,OAAO,IAAI,CAAC,CAAC,OAAON,EAAWC,EAAWC,EAAWC,EAAUE,EAAUD,CAAa,CACxF,CA+CA,MAAaK,EAAO,CAElB,OACA,UA3C6C,GAAGC,IAAS,IAAI,CAAC,CAAC,SAAS,GAAGA,CAAI,EA4C/E,kBArC6D,GAAGA,IAChE,IAAI,CAAC,CAAC,iBAAiB,GAAGA,CAAI,EAqC9B,QA9B6C,GAAGA,IAAS,IAAI,CAAC,CAAC,OAAO,GAAGA,CAAI,EA+B7E,aAxBmD,GAAGA,IAAS,IAAI,CAAC,CAAC,YAAY,GAAGA,CAAI,EAyBxF,gBAlByD,GAAGA,IAC5D,IAAI,CAAC,CAAC,eAAe,GAAGA,CAAI,EAkB5B,cAXqD,GAAGA,IAAS,IAAI,CAAC,CAAC,aAAa,GAAGA,CAAI,CAY7F"}
@@ -1 +1 @@
1
- {"version":3,"file":"globals-BCmGX05J.mjs","names":[],"sources":["../src/vitest/workflow-runtime.ts","../src/vitest/globals.ts"],"sourcesContent":["// Default `tailor.workflow` runner installed by the `tailor-runtime` environment.\n// Must stay free of `vitest` (`vi`): it loads via `./globals` in the environment\n// realm where `vi` is unavailable, hence relative imports only (no `@/` alias).\nimport { START_DEFAULT } from \"../configure/services/workflow/registry\";\nimport { platformSerialize } from \"../utils/test/platform-serialize\";\nimport type { ExecJobFunctionOptions, StartWorkflowOptions } from \"../runtime/workflow\";\n\nexport interface DefaultWorkflowRuntime {\n execJobFunction: (name: string, args?: unknown, options?: ExecJobFunctionOptions) => unknown;\n startWorkflow: (name: string, args?: unknown, options?: StartWorkflowOptions) => Promise<string>;\n resumeWorkflowExecution: (executionId: string) => Promise<string>;\n wait: (key: string, payload?: unknown) => unknown;\n resolve: (\n executionId: string,\n key: string,\n callback: (payload: unknown) => unknown,\n ) => Promise<void>;\n}\n\nexport function createDefaultWorkflowRuntime(): DefaultWorkflowRuntime {\n const execJobFunction: DefaultWorkflowRuntime[\"execJobFunction\"] = (name) => {\n throw new Error(\n `No workflow job mock for \"${name}\". Acquire mockWorkflow() and call setJobHandler(...) or enqueueResult(...), or use runWorkflowLocally() for local workflow execution.`,\n );\n };\n const startWorkflow: DefaultWorkflowRuntime[\"startWorkflow\"] = async (_name, args) => {\n platformSerialize(args);\n return START_DEFAULT;\n };\n const resumeWorkflowExecution: DefaultWorkflowRuntime[\"resumeWorkflowExecution\"] = async (\n executionId,\n ) => executionId;\n return {\n execJobFunction,\n startWorkflow,\n resumeWorkflowExecution,\n wait: (key: string): unknown => {\n throw new Error(\n `No wait handler for \"${key}\". Acquire mockWorkflow() and call setWaitHandler(...).`,\n );\n },\n resolve: async (): Promise<void> => {\n throw new Error(\n \"No resolve handler. Acquire mockWorkflow() and call setResolveHandler(...).\",\n );\n },\n };\n}\n","/**\n * Base platform globals for the tailor-runtime test environment.\n *\n * This module is intentionally free of any `vitest` (`vi`) dependency so it can\n * be imported from the Vitest *environment* module (which runs in a realm where\n * `vi` is not available). It installs only the always-present structural pieces:\n *\n * - `globalThis.tailor` / `globalThis.tailordb` container objects\n * - `globalThis.tailor.context.getInvoker` default stub\n * - the platform error classes (`TailorErrors`,\n * `TailorDBFileError`)\n * - the `__tailorRuntimeActive` sentinel flag\n *\n * The per-namespace mock behavior (TailorDB client, workflow, secretmanager, …)\n * is installed on demand by the `xMock()` factories in `./mock`, which run in\n * test context where `vi` *is* available.\n */\n\nimport { createDefaultWorkflowRuntime } from \"./workflow-runtime\";\nimport type { ContextInvoker } from \"../runtime/context\";\nimport type { TailorDBFileErrorCode } from \"../runtime/file\";\n\n// Sentinel set when the tailor-runtime environment is active. setup.ts reads it\n// to decide whether to run its blocked-globals lifecycle and config-secret\n// loading.\nexport const RUNTIME_FLAG_KEY = \"__tailorRuntimeActive\";\n\n// ---------------------------------------------------------------------------\n// Error class mocks\n// ---------------------------------------------------------------------------\n\ninterface TailorErrorItem {\n message: string;\n path: (string | number)[];\n}\n\nclass TailorErrorsMock extends Error {\n errors: TailorErrorItem[];\n\n constructor(errors: TailorErrorItem[]) {\n if (!Array.isArray(errors)) {\n throw new TypeError(\"TailorErrors: errors must be an array\");\n }\n const validated = errors.map((e, i) => {\n if (typeof e.message !== \"string\") {\n throw new TypeError(`TailorErrors: errors[${i}].message must be a string`);\n }\n if (!Array.isArray(e.path)) {\n throw new TypeError(`TailorErrors: errors[${i}].path must be an array`);\n }\n return { message: e.message, path: e.path };\n });\n // Match the PF runtime's TailorErrors serialization, which prefixes the\n // JSON payload with \"TailorErrors: \". Other SDK code (e.g. apply\n // integration fixtures) strips this prefix before JSON.parse.\n super(`TailorErrors: ${JSON.stringify({ errors: validated })}`);\n this.name = \"TailorErrors\";\n this.errors = validated;\n }\n}\n\nclass TailorDBFileErrorMock extends Error {\n code?: TailorDBFileErrorCode;\n override cause: unknown;\n\n constructor(message: string, code?: TailorDBFileErrorCode, cause?: unknown) {\n super(message);\n this.name = \"TailorDBFileError\";\n this.code = code;\n this.cause = cause;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Base install / cleanup\n// ---------------------------------------------------------------------------\n\n// Stub-only injection. SDK consumers configure invokers at the body level\n// (resolver/executor/workflow `.body()` `invoker` arg) or, for bundled tests,\n// via `vi.spyOn(globalThis.tailor.context, \"getInvoker\")`.\nfunction defaultGetInvoker(): ContextInvoker | null {\n return null;\n}\n\n// No-op logger stub so `tailor.logger.*` calls in code under test don't throw\n// without an explicit `mockLogger()`. `mockLogger()` overlays vi.fn spies and\n// restores this on dispose.\nfunction noop(): void {}\nconst defaultLogger = {\n debug: noop,\n info: noop,\n warn: noop,\n error: noop,\n setAttributes: noop,\n};\n\n/**\n * Install the always-present base platform globals (containers, context stub,\n * error classes, runtime flag). Per-namespace mocks are layered on top by the\n * `xMock()` factories in `./mock`.\n *\n * Acquire with a `using` declaration and the globals are removed when the\n * scope exits; alternatively call `cleanupPlatformGlobals` yourself.\n * @param global - The global object to install into (typically `globalThis`)\n * @returns A `Disposable` that removes the installed globals\n */\nexport function installPlatformGlobals(global: typeof globalThis): Disposable {\n const g = global as Record<string, unknown>;\n\n g[RUNTIME_FLAG_KEY] = true;\n\n // Containers. Namespace mocks (secretmanager, …) are added to these by the\n // corresponding `xMock()` on acquisition. `workflow` carries a default\n // runner: job/wait/resolve calls throw a helpful error, and workflow starts\n // return a placeholder execution id, unless overlaid by `mockWorkflow()` or\n // `runWorkflowLocally()`.\n g.tailor = {\n context: { getInvoker: defaultGetInvoker },\n workflow: createDefaultWorkflowRuntime(),\n logger: { ...defaultLogger },\n };\n g.tailordb = {};\n\n g.TailorErrors = TailorErrorsMock;\n g.TailorDBFileError = TailorDBFileErrorMock;\n\n return {\n [Symbol.dispose]() {\n cleanupPlatformGlobals(global);\n },\n };\n}\n\n/**\n * Remove the base platform globals (and anything the namespace mocks layered on\n * top, since they live under the same containers).\n * @param global - The global object to clean up (typically `globalThis`)\n */\nexport function cleanupPlatformGlobals(global: typeof globalThis): void {\n const g = global as Record<string, unknown>;\n delete g.tailordb;\n delete g.tailor;\n delete g.TailorErrors;\n delete g.TailorDBFileError;\n delete g[RUNTIME_FLAG_KEY];\n}\n"],"mappings":"6FAmBA,SAAgB,8BAAuD,CAarE,MAAO,CACL,gBAbkE,GAAS,CAC3E,MAAU,MACR,6BAA6B,EAAK,uIACpC,CACF,EAUE,oBAToE,EAAO,KAC3E,EAAkB,CAAI,EACf,GAQP,6BALA,IACG,EAKH,KAAO,GAAyB,CAC9B,MAAU,MACR,wBAAwB,EAAI,wDAC9B,CACF,EACA,QAAS,SAA2B,CAClC,MAAU,MACR,6EACF,CACF,CACF,CACF,CCtBA,MAAa,EAAmB,wBAWhC,IAAM,iBAAN,cAA+B,KAAM,CACnC,OAEA,YAAY,EAA2B,CACrC,GAAI,CAAC,MAAM,QAAQ,CAAM,EACvB,MAAU,UAAU,uCAAuC,EAE7D,IAAM,EAAY,EAAO,KAAK,EAAG,IAAM,CACrC,GAAI,OAAO,EAAE,SAAY,SACvB,MAAU,UAAU,wBAAwB,EAAE,2BAA2B,EAE3E,GAAI,CAAC,MAAM,QAAQ,EAAE,IAAI,EACvB,MAAU,UAAU,wBAAwB,EAAE,wBAAwB,EAExE,MAAO,CAAE,QAAS,EAAE,QAAS,KAAM,EAAE,IAAK,CAC5C,CAAC,EAID,MAAM,iBAAiB,KAAK,UAAU,CAAE,OAAQ,CAAU,CAAC,GAAG,EAC9D,KAAK,KAAO,eACZ,KAAK,OAAS,CAChB,CACF,EAEM,sBAAN,cAAoC,KAAM,CACxC,KACA,MAEA,YAAY,EAAiB,EAA8B,EAAiB,CAC1E,MAAM,CAAO,EACb,KAAK,KAAO,oBACZ,KAAK,KAAO,EACZ,KAAK,MAAQ,CACf,CACF,EASA,SAAS,mBAA2C,CAClD,OAAO,IACT,CAKA,SAAS,MAAa,CAAC,CACvB,MAAM,EAAgB,CACpB,MAAO,KACP,KAAM,KACN,KAAM,KACN,MAAO,KACP,cAAe,IACjB,EAYA,SAAgB,uBAAuB,EAAuC,CAC5E,IAAM,EAAI,EAmBV,MAjBA,GAAE,GAAoB,GAOtB,EAAE,OAAS,CACT,QAAS,CAAE,WAAY,iBAAkB,EACzC,SAAU,6BAA6B,EACvC,OAAQ,CAAE,GAAG,CAAc,CAC7B,EACA,EAAE,SAAW,CAAC,EAEd,EAAE,aAAe,iBACjB,EAAE,kBAAoB,sBAEf,CACL,CAAC,OAAO,UAAW,CACjB,uBAAuB,CAAM,CAC/B,CACF,CACF,CAOA,SAAgB,uBAAuB,EAAiC,CACtE,IAAM,EAAI,EACV,OAAO,EAAE,SACT,OAAO,EAAE,OACT,OAAO,EAAE,aACT,OAAO,EAAE,kBACT,OAAO,EAAE,EACX"}
1
+ {"version":3,"file":"globals-BCmGX05J.mjs","names":["START_DEFAULT","name","platformSerialize","args","executionId","key","RUNTIME_FLAG_KEY","errors","validated","i","message","code","cause","defaultLogger","g","global"],"sources":["../src/vitest/workflow-runtime.ts","../src/vitest/globals.ts"],"sourcesContent":["// Default `tailor.workflow` runner installed by the `tailor-runtime` environment.\n// Must stay free of `vitest` (`vi`): it loads via `./globals` in the environment\n// realm where `vi` is unavailable, hence relative imports only (no `@/` alias).\nimport { START_DEFAULT } from \"../configure/services/workflow/registry\";\nimport { platformSerialize } from \"../utils/test/platform-serialize\";\nimport type { ExecJobFunctionOptions, StartWorkflowOptions } from \"../runtime/workflow\";\n\nexport interface DefaultWorkflowRuntime {\n execJobFunction: (name: string, args?: unknown, options?: ExecJobFunctionOptions) => unknown;\n startWorkflow: (name: string, args?: unknown, options?: StartWorkflowOptions) => Promise<string>;\n resumeWorkflowExecution: (executionId: string) => Promise<string>;\n wait: (key: string, payload?: unknown) => unknown;\n resolve: (\n executionId: string,\n key: string,\n callback: (payload: unknown) => unknown,\n ) => Promise<void>;\n}\n\nexport function createDefaultWorkflowRuntime(): DefaultWorkflowRuntime {\n const execJobFunction: DefaultWorkflowRuntime[\"execJobFunction\"] = (name) => {\n throw new Error(\n `No workflow job mock for \"${name}\". Acquire mockWorkflow() and call setJobHandler(...) or enqueueResult(...), or use runWorkflowLocally() for local workflow execution.`,\n );\n };\n const startWorkflow: DefaultWorkflowRuntime[\"startWorkflow\"] = async (_name, args) => {\n platformSerialize(args);\n return START_DEFAULT;\n };\n const resumeWorkflowExecution: DefaultWorkflowRuntime[\"resumeWorkflowExecution\"] = async (\n executionId,\n ) => executionId;\n return {\n execJobFunction,\n startWorkflow,\n resumeWorkflowExecution,\n wait: (key: string): unknown => {\n throw new Error(\n `No wait handler for \"${key}\". Acquire mockWorkflow() and call setWaitHandler(...).`,\n );\n },\n resolve: async (): Promise<void> => {\n throw new Error(\n \"No resolve handler. Acquire mockWorkflow() and call setResolveHandler(...).\",\n );\n },\n };\n}\n","/**\n * Base platform globals for the tailor-runtime test environment.\n *\n * This module is intentionally free of any `vitest` (`vi`) dependency so it can\n * be imported from the Vitest *environment* module (which runs in a realm where\n * `vi` is not available). It installs only the always-present structural pieces:\n *\n * - `globalThis.tailor` / `globalThis.tailordb` container objects\n * - `globalThis.tailor.context.getInvoker` default stub\n * - the platform error classes (`TailorErrors`,\n * `TailorDBFileError`)\n * - the `__tailorRuntimeActive` sentinel flag\n *\n * The per-namespace mock behavior (TailorDB client, workflow, secretmanager, …)\n * is installed on demand by the `xMock()` factories in `./mock`, which run in\n * test context where `vi` *is* available.\n */\n\nimport { createDefaultWorkflowRuntime } from \"./workflow-runtime\";\nimport type { ContextInvoker } from \"../runtime/context\";\nimport type { TailorDBFileErrorCode } from \"../runtime/file\";\n\n// Sentinel set when the tailor-runtime environment is active. setup.ts reads it\n// to decide whether to run its blocked-globals lifecycle and config-secret\n// loading.\nexport const RUNTIME_FLAG_KEY = \"__tailorRuntimeActive\";\n\n// ---------------------------------------------------------------------------\n// Error class mocks\n// ---------------------------------------------------------------------------\n\ninterface TailorErrorItem {\n message: string;\n path: (string | number)[];\n}\n\nclass TailorErrorsMock extends Error {\n errors: TailorErrorItem[];\n\n constructor(errors: TailorErrorItem[]) {\n if (!Array.isArray(errors)) {\n throw new TypeError(\"TailorErrors: errors must be an array\");\n }\n const validated = errors.map((e, i) => {\n if (typeof e.message !== \"string\") {\n throw new TypeError(`TailorErrors: errors[${i}].message must be a string`);\n }\n if (!Array.isArray(e.path)) {\n throw new TypeError(`TailorErrors: errors[${i}].path must be an array`);\n }\n return { message: e.message, path: e.path };\n });\n // Match the PF runtime's TailorErrors serialization, which prefixes the\n // JSON payload with \"TailorErrors: \". Other SDK code (e.g. apply\n // integration fixtures) strips this prefix before JSON.parse.\n super(`TailorErrors: ${JSON.stringify({ errors: validated })}`);\n this.name = \"TailorErrors\";\n this.errors = validated;\n }\n}\n\nclass TailorDBFileErrorMock extends Error {\n code?: TailorDBFileErrorCode;\n override cause: unknown;\n\n constructor(message: string, code?: TailorDBFileErrorCode, cause?: unknown) {\n super(message);\n this.name = \"TailorDBFileError\";\n this.code = code;\n this.cause = cause;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Base install / cleanup\n// ---------------------------------------------------------------------------\n\n// Stub-only injection. SDK consumers configure invokers at the body level\n// (resolver/executor/workflow `.body()` `invoker` arg) or, for bundled tests,\n// via `vi.spyOn(globalThis.tailor.context, \"getInvoker\")`.\nfunction defaultGetInvoker(): ContextInvoker | null {\n return null;\n}\n\n// No-op logger stub so `tailor.logger.*` calls in code under test don't throw\n// without an explicit `mockLogger()`. `mockLogger()` overlays vi.fn spies and\n// restores this on dispose.\nfunction noop(): void {}\nconst defaultLogger = {\n debug: noop,\n info: noop,\n warn: noop,\n error: noop,\n setAttributes: noop,\n};\n\n/**\n * Install the always-present base platform globals (containers, context stub,\n * error classes, runtime flag). Per-namespace mocks are layered on top by the\n * `xMock()` factories in `./mock`.\n *\n * Acquire with a `using` declaration and the globals are removed when the\n * scope exits; alternatively call `cleanupPlatformGlobals` yourself.\n * @param global - The global object to install into (typically `globalThis`)\n * @returns A `Disposable` that removes the installed globals\n */\nexport function installPlatformGlobals(global: typeof globalThis): Disposable {\n const g = global as Record<string, unknown>;\n\n g[RUNTIME_FLAG_KEY] = true;\n\n // Containers. Namespace mocks (secretmanager, …) are added to these by the\n // corresponding `xMock()` on acquisition. `workflow` carries a default\n // runner: job/wait/resolve calls throw a helpful error, and workflow starts\n // return a placeholder execution id, unless overlaid by `mockWorkflow()` or\n // `runWorkflowLocally()`.\n g.tailor = {\n context: { getInvoker: defaultGetInvoker },\n workflow: createDefaultWorkflowRuntime(),\n logger: { ...defaultLogger },\n };\n g.tailordb = {};\n\n g.TailorErrors = TailorErrorsMock;\n g.TailorDBFileError = TailorDBFileErrorMock;\n\n return {\n [Symbol.dispose]() {\n cleanupPlatformGlobals(global);\n },\n };\n}\n\n/**\n * Remove the base platform globals (and anything the namespace mocks layered on\n * top, since they live under the same containers).\n * @param global - The global object to clean up (typically `globalThis`)\n */\nexport function cleanupPlatformGlobals(global: typeof globalThis): void {\n const g = global as Record<string, unknown>;\n delete g.tailordb;\n delete g.tailor;\n delete g.TailorErrors;\n delete g.TailorDBFileError;\n delete g[RUNTIME_FLAG_KEY];\n}\n"],"mappings":"6FAmBA,SAAgB,8BAAuD,CAarE,MAAO,CACL,gBAbkE,GAAS,CAC3E,MAAU,MACR,6BAA6BC,EAAK,uIACpC,CACF,EAUE,oBAToE,EAAO,KAC3EC,EAAkBC,CAAI,EACfH,GAQP,6BALA,IACGI,EAKH,KAAO,GAAyB,CAC9B,MAAU,MACR,wBAAwBC,EAAI,wDAC9B,CACF,EACA,QAAS,SAA2B,CAClC,MAAU,MACR,6EACF,CACF,CACF,CACF,CCtBA,MAAaC,EAAmB,wBAWhC,IAAM,iBAAN,cAA+B,KAAM,CACnC,OAEA,YAAY,EAA2B,CACrC,GAAI,CAAC,MAAM,QAAQC,CAAM,EACvB,MAAU,UAAU,uCAAuC,EAE7D,IAAMC,EAAYD,EAAO,KAAK,EAAG,IAAM,CACrC,GAAI,OAAO,EAAE,SAAY,SACvB,MAAU,UAAU,wBAAwBE,EAAE,2BAA2B,EAE3E,GAAI,CAAC,MAAM,QAAQ,EAAE,IAAI,EACvB,MAAU,UAAU,wBAAwBA,EAAE,wBAAwB,EAExE,MAAO,CAAE,QAAS,EAAE,QAAS,KAAM,EAAE,IAAK,CAC5C,CAAC,EAID,MAAM,iBAAiB,KAAK,UAAU,CAAE,OAAQD,CAAU,CAAC,GAAG,EAC9D,KAAK,KAAO,eACZ,KAAK,OAASA,CAChB,CACF,EAEM,sBAAN,cAAoC,KAAM,CACxC,KACA,MAEA,YAAY,EAAiB,EAA8B,EAAiB,CAC1E,MAAME,CAAO,EACb,KAAK,KAAO,oBACZ,KAAK,KAAOC,EACZ,KAAK,MAAQC,CACf,CACF,EASA,SAAS,mBAA2C,CAClD,OAAO,IACT,CAKA,SAAS,MAAa,CAAC,CACvB,MAAMC,EAAgB,CACpB,MAAO,KACP,KAAM,KACN,KAAM,KACN,MAAO,KACP,cAAe,IACjB,EAYA,SAAgB,uBAAuB,EAAuC,CAC5E,IAAMC,EAAIC,EAmBV,MAjBA,GAAET,GAAoB,GAOtB,EAAE,OAAS,CACT,QAAS,CAAE,WAAY,iBAAkB,EACzC,SAAU,6BAA6B,EACvC,OAAQ,CAAE,GAAGO,CAAc,CAC7B,EACA,EAAE,SAAW,CAAC,EAEd,EAAE,aAAe,iBACjB,EAAE,kBAAoB,sBAEf,CACL,CAAC,OAAO,UAAW,CACjB,uBAAuBE,CAAM,CAC/B,CACF,CACF,CAOA,SAAgB,uBAAuB,EAAiC,CACtE,IAAMD,EAAIC,EACV,OAAOD,EAAE,SACT,OAAOA,EAAE,OACT,OAAOA,EAAE,aACT,OAAOA,EAAE,kBACT,OAAOA,EAAER,EACX"}
@@ -1 +1 @@
1
- {"version":3,"file":"guards-yDXyKC9F.mjs","names":[],"sources":["../src/plugin/guards.ts"],"sourcesContent":["// Runtime guards and helpers for plugin authoring types.\n//\n// These live outside plugin/types.ts (a pure type module) because they are\n// runtime functions. The types they operate on are imported type-only.\nimport type {\n DependencyKind,\n PluginGeneratedExecutor,\n PluginGeneratedExecutorWithFile,\n} from \"./types\";\n\n/**\n * Reads a table name without assuming plugin output is a valid table object.\n * @param table - Raw table value returned by a plugin hook.\n * @returns The table name when it is a string; otherwise, undefined.\n */\nexport function getRawPluginTableName(table: unknown): string | undefined {\n const name =\n typeof table === \"object\" && table !== null && \"name\" in table ? table.name : undefined;\n return typeof name === \"string\" ? name : undefined;\n}\n\n/**\n * Collects the generation-time dependency kinds a plugin requires.\n * @param plugin - The plugin object to inspect.\n * @param plugin.onTailorDBReady - Hook for TailorDB readiness.\n * @param plugin.onResolverReady - Hook for resolver readiness.\n * @param plugin.onExecutorReady - Hook for executor readiness.\n * @returns Set of dependency kinds required by the plugin.\n */\nexport function getPluginGenerationDependencies(plugin: {\n onTailorDBReady?: unknown;\n onResolverReady?: unknown;\n onExecutorReady?: unknown;\n}): Set<DependencyKind> {\n const deps = new Set<DependencyKind>();\n if (plugin.onTailorDBReady) {\n deps.add(\"tailordb\");\n }\n if (plugin.onResolverReady) {\n deps.add(\"resolver\");\n }\n if (plugin.onExecutorReady) {\n deps.add(\"executor\");\n }\n return deps;\n}\n\n/**\n * Checks if a plugin has any generation-time hooks.\n * @param plugin - The plugin object to inspect.\n * @param plugin.onTailorDBReady - Hook for TailorDB readiness.\n * @param plugin.onResolverReady - Hook for resolver readiness.\n * @param plugin.onExecutorReady - Hook for executor readiness.\n * @returns True if the plugin has at least one generation hook.\n */\nexport function hasGenerationHooks(plugin: {\n onTailorDBReady?: unknown;\n onResolverReady?: unknown;\n onExecutorReady?: unknown;\n}): boolean {\n return !!(plugin.onTailorDBReady || plugin.onResolverReady || plugin.onExecutorReady);\n}\n\n/**\n * Checks if a plugin executor uses file-based resolution.\n * @param executor - The plugin executor to check.\n * @returns True if the executor uses file-based resolution.\n */\nexport function isPluginExecutorWithFile(\n executor: PluginGeneratedExecutor,\n): executor is PluginGeneratedExecutorWithFile {\n return \"resolve\" in executor && \"context\" in executor;\n}\n"],"mappings":"AAeA,SAAgB,sBAAsB,EAAoC,CACxE,IAAM,EACJ,OAAO,GAAU,UAAY,GAAkB,SAAU,EAAQ,EAAM,KAAO,IAAA,GAChF,OAAO,OAAO,GAAS,SAAW,EAAO,IAAA,EAC3C,CAUA,SAAgB,gCAAgC,EAIxB,CACtB,IAAM,kBAAO,IAAI,IAUjB,OATI,EAAO,iBACT,EAAK,IAAI,UAAU,EAEjB,EAAO,iBACT,EAAK,IAAI,UAAU,EAEjB,EAAO,iBACT,EAAK,IAAI,UAAU,EAEd,CACT,CAUA,SAAgB,mBAAmB,EAIvB,CACV,MAAO,CAAC,EAAE,EAAO,iBAAmB,EAAO,iBAAmB,EAAO,gBACvE,CAOA,SAAgB,yBACd,EAC6C,CAC7C,MAAO,YAAa,GAAY,YAAa,CAC/C"}
1
+ {"version":3,"file":"guards-yDXyKC9F.mjs","names":["name","table","deps","plugin","executor"],"sources":["../src/plugin/guards.ts"],"sourcesContent":["// Runtime guards and helpers for plugin authoring types.\n//\n// These live outside plugin/types.ts (a pure type module) because they are\n// runtime functions. The types they operate on are imported type-only.\nimport type {\n DependencyKind,\n PluginGeneratedExecutor,\n PluginGeneratedExecutorWithFile,\n} from \"./types\";\n\n/**\n * Reads a table name without assuming plugin output is a valid table object.\n * @param table - Raw table value returned by a plugin hook.\n * @returns The table name when it is a string; otherwise, undefined.\n */\nexport function getRawPluginTableName(table: unknown): string | undefined {\n const name =\n typeof table === \"object\" && table !== null && \"name\" in table ? table.name : undefined;\n return typeof name === \"string\" ? name : undefined;\n}\n\n/**\n * Collects the generation-time dependency kinds a plugin requires.\n * @param plugin - The plugin object to inspect.\n * @param plugin.onTailorDBReady - Hook for TailorDB readiness.\n * @param plugin.onResolverReady - Hook for resolver readiness.\n * @param plugin.onExecutorReady - Hook for executor readiness.\n * @returns Set of dependency kinds required by the plugin.\n */\nexport function getPluginGenerationDependencies(plugin: {\n onTailorDBReady?: unknown;\n onResolverReady?: unknown;\n onExecutorReady?: unknown;\n}): Set<DependencyKind> {\n const deps = new Set<DependencyKind>();\n if (plugin.onTailorDBReady) {\n deps.add(\"tailordb\");\n }\n if (plugin.onResolverReady) {\n deps.add(\"resolver\");\n }\n if (plugin.onExecutorReady) {\n deps.add(\"executor\");\n }\n return deps;\n}\n\n/**\n * Checks if a plugin has any generation-time hooks.\n * @param plugin - The plugin object to inspect.\n * @param plugin.onTailorDBReady - Hook for TailorDB readiness.\n * @param plugin.onResolverReady - Hook for resolver readiness.\n * @param plugin.onExecutorReady - Hook for executor readiness.\n * @returns True if the plugin has at least one generation hook.\n */\nexport function hasGenerationHooks(plugin: {\n onTailorDBReady?: unknown;\n onResolverReady?: unknown;\n onExecutorReady?: unknown;\n}): boolean {\n return !!(plugin.onTailorDBReady || plugin.onResolverReady || plugin.onExecutorReady);\n}\n\n/**\n * Checks if a plugin executor uses file-based resolution.\n * @param executor - The plugin executor to check.\n * @returns True if the executor uses file-based resolution.\n */\nexport function isPluginExecutorWithFile(\n executor: PluginGeneratedExecutor,\n): executor is PluginGeneratedExecutorWithFile {\n return \"resolve\" in executor && \"context\" in executor;\n}\n"],"mappings":"AAeA,SAAgB,sBAAsB,EAAoC,CACxE,IAAMA,EACJ,OAAOC,GAAU,UAAYA,GAAkB,SAAUA,EAAQA,EAAM,KAAO,IAAA,GAChF,OAAO,OAAOD,GAAS,SAAWA,EAAO,IAAA,EAC3C,CAUA,SAAgB,gCAAgC,EAIxB,CACtB,IAAME,kBAAO,IAAI,IAUjB,OATIC,EAAO,iBACTD,EAAK,IAAI,UAAU,EAEjBC,EAAO,iBACTD,EAAK,IAAI,UAAU,EAEjBC,EAAO,iBACTD,EAAK,IAAI,UAAU,EAEdA,CACT,CAUA,SAAgB,mBAAmB,EAIvB,CACV,MAAO,CAAC,EAAEC,EAAO,iBAAmBA,EAAO,iBAAmBA,EAAO,gBACvE,CAOA,SAAgB,yBACd,EAC6C,CAC7C,MAAO,YAAaC,GAAY,YAAaA,CAC/C"}
@@ -1 +1 @@
1
- {"version":3,"file":"iconv-DlFMt2gW.mjs","names":[],"sources":["../src/runtime/iconv.ts"],"sourcesContent":["/**\n * Character encoding conversion utilities.\n *\n * Thin typed wrapper around the platform-provided `tailor.iconv` runtime API.\n * At runtime this delegates to `globalThis.tailor.iconv`, which is provided by\n * the Tailor Platform Function runtime. Use `mockIconv` from\n * `@tailor-platform/sdk/vitest` to mock these calls in unit tests.\n * @example\n * import { iconv } from \"@tailor-platform/sdk/runtime\";\n *\n * const utf8 = iconv.convert(sjisBuffer, \"Shift_JIS\", \"UTF-8\"); // string\n * const sjis = iconv.convert(\"こんにちは\", \"UTF-8\", \"Shift_JIS\"); // Uint8Array\n *\n * const conv = new iconv.Iconv(\"Shift_JIS\", \"UTF-8\");\n * const out = conv.convert(sjisBuffer);\n */\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\n/** Instance methods exposed by `tailor.iconv.Iconv`. */\nexport interface IconvInstance {\n convert(input: string | Uint8Array | ArrayBuffer): string | Uint8Array;\n}\n\n/** Constructor shape for `tailor.iconv.Iconv`. */\nexport interface IconvConstructor {\n new (fromEncoding: string, toEncoding: string): IconvInstance;\n}\n\n/**\n * Platform API surface for `tailor.iconv`. Describes the shape the platform\n * runtime injects on `globalThis.tailor.iconv` so the wrapper and ambient\n * globals stay in sync.\n */\nexport interface TailorIconvAPI {\n /**\n * Convert a string or buffer between encodings.\n * @param str - Input data to convert\n * @param fromEncoding - Source encoding name\n * @param toEncoding - Target encoding name\n * @returns `string` when `toEncoding` is `\"UTF8\"` or `\"UTF-8\"`, otherwise `Uint8Array`.\n */\n convert<T extends string>(\n str: string | Uint8Array | ArrayBuffer,\n fromEncoding: string,\n toEncoding: T,\n ): T extends \"UTF8\" | \"UTF-8\" ? string : Uint8Array;\n\n /**\n * Convert a buffer between encodings.\n * @param buffer - Input bytes to convert\n * @param fromEncoding - Source encoding name\n * @param toEncoding - Target encoding name\n * @returns `string` when `toEncoding` is `\"UTF8\"` or `\"UTF-8\"`, otherwise `Uint8Array`.\n */\n convertBuffer<T extends string>(\n buffer: Uint8Array | ArrayBuffer,\n fromEncoding: string,\n toEncoding: T,\n ): T extends \"UTF8\" | \"UTF-8\" ? string : Uint8Array;\n\n /**\n * Decode a buffer to a UTF-8 string using the given source encoding.\n * @param buffer - Input bytes\n * @param encoding - Source encoding name\n * @returns Decoded UTF-8 string\n */\n decode(buffer: Uint8Array | ArrayBuffer, encoding: string): string;\n\n /**\n * Encode a UTF-8 string into the given target encoding.\n * @param str - Input string\n * @param encoding - Target encoding name\n * @returns `string` when `encoding` is `\"UTF8\"` or `\"UTF-8\"`, otherwise `Uint8Array`.\n */\n encode<T extends string>(\n str: string,\n encoding: T,\n ): T extends \"UTF8\" | \"UTF-8\" ? string : Uint8Array;\n\n /**\n * Returns the list of supported encoding names.\n * @returns Array of encoding names supported by the platform iconv runtime\n */\n encodings(): string[];\n\n /** Constructor for the stateful converter. */\n Iconv: IconvConstructor;\n}\n\nconst api = (): TailorIconvAPI =>\n (globalThis as unknown as { tailor: { iconv: TailorIconvAPI } }).tailor.iconv;\n\nconst convert: TailorIconvAPI[\"convert\"] = (...args) => api().convert(...args);\n\nconst convertBuffer: TailorIconvAPI[\"convertBuffer\"] = (...args) => api().convertBuffer(...args);\n\nconst decode: TailorIconvAPI[\"decode\"] = (...args) => api().decode(...args);\n\nconst encode: TailorIconvAPI[\"encode\"] = (...args) => api().encode(...args);\n\nconst encodings: TailorIconvAPI[\"encodings\"] = () => api().encodings();\n\n/**\n * Stateful converter for repeated conversions between a fixed encoding pair.\n * Compatible with the `node-iconv` API surface.\n */\nclass Iconv {\n private impl: IconvInstance;\n\n constructor(fromEncoding: string, toEncoding: string) {\n this.impl = new (api().Iconv)(fromEncoding, toEncoding);\n }\n\n /**\n * Convert input using this converter's fixed encoding pair.\n * @param input - Bytes or string to convert\n * @returns Encoded output (string for UTF-8 targets, otherwise `Uint8Array`).\n */\n convert(input: string | Uint8Array | ArrayBuffer): string | Uint8Array {\n return this.impl.convert(input);\n }\n}\n\n// Keep the object typed to the public API so the private wrapper class does not leak into d.ts.\n/** Runtime API for `tailor.iconv`. */\nexport const iconv: TailorIconvAPI = {\n convert,\n convertBuffer,\n decode,\n encode,\n encodings,\n Iconv,\n};\n"],"mappings":"AA0FA,MAAM,QACH,WAAgE,OAAO,MAmC7D,EAAwB,CACnC,SAlC0C,GAAG,IAAS,IAAI,CAAC,CAAC,QAAQ,GAAG,CAAI,EAmC3E,eAjCsD,GAAG,IAAS,IAAI,CAAC,CAAC,cAAc,GAAG,CAAI,EAkC7F,QAhCwC,GAAG,IAAS,IAAI,CAAC,CAAC,OAAO,GAAG,CAAI,EAiCxE,QA/BwC,GAAG,IAAS,IAAI,CAAC,CAAC,OAAO,GAAG,CAAI,EAgCxE,cA9BmD,IAAI,CAAC,CAAC,UAAU,EA+BnE,WAzBU,CACV,KAEA,YAAY,EAAsB,EAAoB,CACpD,KAAK,KAAO,IAAK,IAAI,EAAA,CAAE,MAAO,EAAc,CAAU,CACxD,CAOA,QAAQ,EAA+D,CACrE,OAAO,KAAK,KAAK,QAAQ,CAAK,CAChC,CACF,CAWA"}
1
+ {"version":3,"file":"iconv-DlFMt2gW.mjs","names":["iconv","args","fromEncoding","toEncoding","input"],"sources":["../src/runtime/iconv.ts"],"sourcesContent":["/**\n * Character encoding conversion utilities.\n *\n * Thin typed wrapper around the platform-provided `tailor.iconv` runtime API.\n * At runtime this delegates to `globalThis.tailor.iconv`, which is provided by\n * the Tailor Platform Function runtime. Use `mockIconv` from\n * `@tailor-platform/sdk/vitest` to mock these calls in unit tests.\n * @example\n * import { iconv } from \"@tailor-platform/sdk/runtime\";\n *\n * const utf8 = iconv.convert(sjisBuffer, \"Shift_JIS\", \"UTF-8\"); // string\n * const sjis = iconv.convert(\"こんにちは\", \"UTF-8\", \"Shift_JIS\"); // Uint8Array\n *\n * const conv = new iconv.Iconv(\"Shift_JIS\", \"UTF-8\");\n * const out = conv.convert(sjisBuffer);\n */\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\n/** Instance methods exposed by `tailor.iconv.Iconv`. */\nexport interface IconvInstance {\n convert(input: string | Uint8Array | ArrayBuffer): string | Uint8Array;\n}\n\n/** Constructor shape for `tailor.iconv.Iconv`. */\nexport interface IconvConstructor {\n new (fromEncoding: string, toEncoding: string): IconvInstance;\n}\n\n/**\n * Platform API surface for `tailor.iconv`. Describes the shape the platform\n * runtime injects on `globalThis.tailor.iconv` so the wrapper and ambient\n * globals stay in sync.\n */\nexport interface TailorIconvAPI {\n /**\n * Convert a string or buffer between encodings.\n * @param str - Input data to convert\n * @param fromEncoding - Source encoding name\n * @param toEncoding - Target encoding name\n * @returns `string` when `toEncoding` is `\"UTF8\"` or `\"UTF-8\"`, otherwise `Uint8Array`.\n */\n convert<T extends string>(\n str: string | Uint8Array | ArrayBuffer,\n fromEncoding: string,\n toEncoding: T,\n ): T extends \"UTF8\" | \"UTF-8\" ? string : Uint8Array;\n\n /**\n * Convert a buffer between encodings.\n * @param buffer - Input bytes to convert\n * @param fromEncoding - Source encoding name\n * @param toEncoding - Target encoding name\n * @returns `string` when `toEncoding` is `\"UTF8\"` or `\"UTF-8\"`, otherwise `Uint8Array`.\n */\n convertBuffer<T extends string>(\n buffer: Uint8Array | ArrayBuffer,\n fromEncoding: string,\n toEncoding: T,\n ): T extends \"UTF8\" | \"UTF-8\" ? string : Uint8Array;\n\n /**\n * Decode a buffer to a UTF-8 string using the given source encoding.\n * @param buffer - Input bytes\n * @param encoding - Source encoding name\n * @returns Decoded UTF-8 string\n */\n decode(buffer: Uint8Array | ArrayBuffer, encoding: string): string;\n\n /**\n * Encode a UTF-8 string into the given target encoding.\n * @param str - Input string\n * @param encoding - Target encoding name\n * @returns `string` when `encoding` is `\"UTF8\"` or `\"UTF-8\"`, otherwise `Uint8Array`.\n */\n encode<T extends string>(\n str: string,\n encoding: T,\n ): T extends \"UTF8\" | \"UTF-8\" ? string : Uint8Array;\n\n /**\n * Returns the list of supported encoding names.\n * @returns Array of encoding names supported by the platform iconv runtime\n */\n encodings(): string[];\n\n /** Constructor for the stateful converter. */\n Iconv: IconvConstructor;\n}\n\nconst api = (): TailorIconvAPI =>\n (globalThis as unknown as { tailor: { iconv: TailorIconvAPI } }).tailor.iconv;\n\nconst convert: TailorIconvAPI[\"convert\"] = (...args) => api().convert(...args);\n\nconst convertBuffer: TailorIconvAPI[\"convertBuffer\"] = (...args) => api().convertBuffer(...args);\n\nconst decode: TailorIconvAPI[\"decode\"] = (...args) => api().decode(...args);\n\nconst encode: TailorIconvAPI[\"encode\"] = (...args) => api().encode(...args);\n\nconst encodings: TailorIconvAPI[\"encodings\"] = () => api().encodings();\n\n/**\n * Stateful converter for repeated conversions between a fixed encoding pair.\n * Compatible with the `node-iconv` API surface.\n */\nclass Iconv {\n private impl: IconvInstance;\n\n constructor(fromEncoding: string, toEncoding: string) {\n this.impl = new (api().Iconv)(fromEncoding, toEncoding);\n }\n\n /**\n * Convert input using this converter's fixed encoding pair.\n * @param input - Bytes or string to convert\n * @returns Encoded output (string for UTF-8 targets, otherwise `Uint8Array`).\n */\n convert(input: string | Uint8Array | ArrayBuffer): string | Uint8Array {\n return this.impl.convert(input);\n }\n}\n\n// Keep the object typed to the public API so the private wrapper class does not leak into d.ts.\n/** Runtime API for `tailor.iconv`. */\nexport const iconv: TailorIconvAPI = {\n convert,\n convertBuffer,\n decode,\n encode,\n encodings,\n Iconv,\n};\n"],"mappings":"AA0FA,MAAM,QACH,WAAgE,OAAO,MAmC7DA,EAAwB,CACnC,SAlC0C,GAAGC,IAAS,IAAI,CAAC,CAAC,QAAQ,GAAGA,CAAI,EAmC3E,eAjCsD,GAAGA,IAAS,IAAI,CAAC,CAAC,cAAc,GAAGA,CAAI,EAkC7F,QAhCwC,GAAGA,IAAS,IAAI,CAAC,CAAC,OAAO,GAAGA,CAAI,EAiCxE,QA/BwC,GAAGA,IAAS,IAAI,CAAC,CAAC,OAAO,GAAGA,CAAI,EAgCxE,cA9BmD,IAAI,CAAC,CAAC,UAAU,EA+BnE,WAzBU,CACV,KAEA,YAAY,EAAsB,EAAoB,CACpD,KAAK,KAAO,IAAK,IAAI,EAAA,CAAE,MAAOC,EAAcC,CAAU,CACxD,CAOA,QAAQ,EAA+D,CACrE,OAAO,KAAK,KAAK,QAAQC,CAAK,CAChC,CACF,CAWA"}