@tailor-platform/sdk 2.21.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 (119) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/agent-skills/tailor/SKILL.md +3 -1
  3. package/dist/aigateway-DsWDjzk4.mjs.map +1 -1
  4. package/dist/application-BtZ8hmx9.mjs +1 -0
  5. package/dist/{application-D4913edS.mjs → application-m2G91kKI.mjs} +29 -29
  6. package/dist/application-m2G91kKI.mjs.map +1 -0
  7. package/dist/assert-WeXvmG4j.mjs.map +1 -1
  8. package/dist/authconnection-CynFBIv8.mjs.map +1 -1
  9. package/dist/brand-C8nMKhJC.mjs.map +1 -1
  10. package/dist/cli/commands/deploy/app-id-lock.d.mts +31 -0
  11. package/dist/cli/lib.d.mts +2 -2
  12. package/dist/cli/lib.mjs +1 -1
  13. package/dist/cli/lib.mjs.map +1 -1
  14. package/dist/cli/main.mjs +41 -41
  15. package/dist/cli/main.mjs.map +1 -1
  16. package/dist/cli/shared/client.d.mts +17 -2
  17. package/dist/cli/shared/logger.d.mts +9 -0
  18. package/dist/cli/shared/tailordb-namespaces.d.mts +1 -1
  19. package/dist/completion/zsh-worker.zsh +13 -7
  20. package/dist/configure/config/index.d.mts +2 -0
  21. package/dist/configure/index.mjs.map +1 -1
  22. package/dist/context-D0QjfxzD.mjs.map +1 -1
  23. package/dist/crashreport-CBaRJl5h.mjs +1 -0
  24. package/dist/{crashreport-BAz-ph5O.mjs → crashreport-DFpRn-LS.mjs} +4 -4
  25. package/dist/crashreport-DFpRn-LS.mjs.map +1 -0
  26. package/dist/date-Dri6Yas-.mjs.map +1 -1
  27. package/dist/errors-CpvSChyL.mjs +7 -0
  28. package/dist/errors-CpvSChyL.mjs.map +1 -0
  29. package/dist/es-builtins-SfvXRVoG.mjs.map +1 -1
  30. package/dist/field-parse-DhnFs9WG.mjs.map +1 -1
  31. package/dist/file-DKBOj5q4.mjs.map +1 -1
  32. package/dist/globals-BCmGX05J.mjs.map +1 -1
  33. package/dist/guards-yDXyKC9F.mjs +2 -0
  34. package/dist/guards-yDXyKC9F.mjs.map +1 -0
  35. package/dist/iconv-DlFMt2gW.mjs.map +1 -1
  36. package/dist/idp-G_ojPBB5.mjs.map +1 -1
  37. package/dist/interceptor-DQg3cR_9.mjs.map +1 -1
  38. package/dist/kysely/index.mjs.map +1 -1
  39. package/dist/kysely-type-C-iyFFH7.mjs.map +1 -1
  40. package/dist/logger-DP2BjQ93.mjs.map +1 -1
  41. package/dist/logger-Db-YRTwK.mjs +9 -0
  42. package/dist/logger-Db-YRTwK.mjs.map +1 -0
  43. package/dist/{manager-C0dE7pd0.mjs → manager-8-JOvuLl.mjs} +2 -2
  44. package/dist/manager-8-JOvuLl.mjs.map +1 -0
  45. package/dist/multiline-EyzjEwn9.mjs.map +1 -1
  46. package/dist/node-builtins-DYfhPBnz.mjs.map +1 -1
  47. package/dist/package-json-C690ceex.mjs.map +1 -1
  48. package/dist/platform-serialize-DkiTdHOt.mjs.map +1 -1
  49. package/dist/plugin/builtin/enum-constants/index.mjs.map +1 -1
  50. package/dist/plugin/builtin/file-utils/index.mjs.map +1 -1
  51. package/dist/plugin/index.mjs +1 -1
  52. package/dist/plugin/index.mjs.map +1 -1
  53. package/dist/register-ts-hook-ztnEFW6n.mjs +922 -0
  54. package/dist/register-ts-hook-ztnEFW6n.mjs.map +1 -0
  55. package/dist/registry-BijIDRVA.mjs.map +1 -1
  56. package/dist/repl-editor-DGJBfIt1.mjs.map +1 -1
  57. package/dist/schema-CRtAmDcl.mjs.map +1 -1
  58. package/dist/secret-file-C9wp_FCX.mjs.map +1 -1
  59. package/dist/secretmanager-5olfnI1b.mjs.map +1 -1
  60. package/dist/secretmanager-vHQoXdQz.mjs.map +1 -1
  61. package/dist/seed/index.mjs +7 -6
  62. package/dist/seed/index.mjs.map +1 -1
  63. package/dist/seed-C3P_T_Eh.mjs.map +1 -1
  64. package/dist/service-Bx-7Lz06.mjs +1 -0
  65. package/dist/{service-BrGSi2IQ.mjs → service-CL1Bp4It.mjs} +3 -3
  66. package/dist/service-CL1Bp4It.mjs.map +1 -0
  67. package/dist/{service-8xznUrPU.mjs → service-DFmt9UJP.mjs} +2 -2
  68. package/dist/service-DFmt9UJP.mjs.map +1 -0
  69. package/dist/service_pb-ZClWtj1X.mjs +2 -0
  70. package/dist/service_pb-ZClWtj1X.mjs.map +1 -0
  71. package/dist/service_pb-dB3RrGeh.mjs +1 -0
  72. package/dist/tailor-proto/src/tailor/v1/function_pb.d.mts +83 -1
  73. package/dist/tailor-proto/src/tailor/v1/function_resource_pb.d.mts +7 -1
  74. package/dist/tailor-proto/src/tailor/v1/service_pb.d.mts +79 -7
  75. package/dist/tailor-proto/src/tailor/v1/workflow_pb.d.mts +40 -1
  76. package/dist/tailor-proto/src/tailor/v1/workflow_resource_pb.d.mts +119 -2
  77. package/dist/tailor-proto/src/tailor/v1/workspace_pb.d.mts +7 -0
  78. package/dist/tailordb-ddl-DqInYupv.mjs.map +1 -1
  79. package/dist/telemetry-Bklv9kQY.mjs.map +1 -1
  80. package/dist/type-source--ZNcV8RJ.mjs.map +1 -1
  81. package/dist/user-agent-vdHYF3QL.mjs.map +1 -1
  82. package/dist/utils/test/index.mjs.map +1 -1
  83. package/dist/vitest/environment.mjs.map +1 -1
  84. package/dist/vitest/index.mjs.map +1 -1
  85. package/dist/vitest/mocks/file.d.mts +1 -1
  86. package/dist/vitest/setup.mjs.map +1 -1
  87. package/dist/wait-point-invoker-eiP-IIux.mjs.map +1 -1
  88. package/dist/wait-point-registry-B-ESkTZX.mjs.map +1 -1
  89. package/dist/workflow-Cs9ISw6j.mjs.map +1 -1
  90. package/dist/{workspace_resource_pb-D2njwgsE.mjs → workspace_resource_pb-CxR_6fyN.mjs} +2 -2
  91. package/dist/workspace_resource_pb-CxR_6fyN.mjs.map +1 -0
  92. package/docs/cli/application.md +23 -5
  93. package/docs/cli/function.md +2 -2
  94. package/docs/cli-reference.md +22 -12
  95. package/docs/configuration.md +1 -1
  96. package/docs/github-actions.md +90 -24
  97. package/docs/migration/v2.md +70 -5
  98. package/docs/plugin/index.md +1 -1
  99. package/package.json +10 -10
  100. package/dist/application-D4913edS.mjs.map +0 -1
  101. package/dist/application-DBHaxmJE.mjs +0 -1
  102. package/dist/crashreport-BAz-ph5O.mjs.map +0 -1
  103. package/dist/crashreport-BfOkOFgc.mjs +0 -1
  104. package/dist/errors-sNtg2Mv3.mjs +0 -7
  105. package/dist/errors-sNtg2Mv3.mjs.map +0 -1
  106. package/dist/guards-DsX7dJCP.mjs +0 -2
  107. package/dist/guards-DsX7dJCP.mjs.map +0 -1
  108. package/dist/logger-Cp5U2IDI.mjs +0 -9
  109. package/dist/logger-Cp5U2IDI.mjs.map +0 -1
  110. package/dist/manager-C0dE7pd0.mjs.map +0 -1
  111. package/dist/register-ts-hook-YtsAGTMD.mjs +0 -921
  112. package/dist/register-ts-hook-YtsAGTMD.mjs.map +0 -1
  113. package/dist/service-8xznUrPU.mjs.map +0 -1
  114. package/dist/service-BrGSi2IQ.mjs.map +0 -1
  115. package/dist/service-DWMm-4Vm.mjs +0 -1
  116. package/dist/service_pb-DNskuJQC.mjs +0 -1
  117. package/dist/service_pb-y2GYIgfs.mjs +0 -2
  118. package/dist/service_pb-y2GYIgfs.mjs.map +0 -1
  119. package/dist/workspace_resource_pb-D2njwgsE.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../../src/plugin/builtin/enum-constants/generate-enum-constants.ts","../../../../src/plugin/builtin/enum-constants/process-enum-type.ts","../../../../src/plugin/builtin/enum-constants/index.ts"],"sourcesContent":["import type { EnumDefinition } from \"./types\";\n\n/**\n * Generate enum constant definitions from collected metadata.\n * @param allEnums - All collected enum definitions\n * @returns Generated enum constant definitions\n */\nexport function generateUnifiedEnumConstants(allEnums: EnumDefinition[]): string {\n if (allEnums.length === 0) {\n return \"\";\n }\n\n const enumMap = new Map<string, EnumDefinition>();\n for (const enumDef of allEnums) {\n enumMap.set(enumDef.name, enumDef);\n }\n\n const enumDefs = Array.from(enumMap.values())\n .map((e) => {\n const members = e.values\n .map((v) => {\n const key = v.value.replace(/[-\\s]/g, \"_\");\n return ` \"${key}\": \"${v.value}\"`;\n })\n .join(\",\\n\");\n\n const hasDescriptions = e.values.some((v) => v.description);\n let jsDoc = \"\";\n if (e.fieldDescription || hasDescriptions) {\n const lines: string[] = [];\n\n if (e.fieldDescription) {\n lines.push(` * ${e.fieldDescription}`);\n if (hasDescriptions) {\n lines.push(\" *\");\n }\n }\n\n if (hasDescriptions) {\n const propertyDocs = e.values.map((v) => {\n const key = v.value.replace(/[-\\s]/g, \"_\");\n return ` * @property ${[key, v.description].filter(Boolean).join(\" - \")}`;\n });\n lines.push(...propertyDocs);\n }\n\n if (lines.length > 0) {\n jsDoc = `/**\\n${lines.join(\"\\n\")}\\n */\\n`;\n }\n }\n\n const constDef = `${jsDoc}export const ${e.name} = {\\n${members}\\n} as const;`;\n const typeDef = `export type ${e.name} = (typeof ${e.name})[keyof typeof ${e.name}];`;\n return `${constDef}\\n${typeDef}`;\n })\n .join(\"\\n\\n\");\n\n if (!enumDefs) {\n return \"\";\n }\n\n return enumDefs + \"\\n\";\n}\n","import type { TailorDBType } from \"#/parser/service/tailordb/types\";\nimport type { EnumConstantMetadata } from \"./types\";\n\nfunction capitalizeFirst(str: string): string {\n return str.charAt(0).toUpperCase() + str.slice(1);\n}\n\nfunction collectEnums(type: TailorDBType): EnumConstantMetadata[\"enums\"] {\n const enums: EnumConstantMetadata[\"enums\"] = [];\n\n for (const [fieldName, parsedField] of Object.entries(type.fields)) {\n if (parsedField.config.type === \"enum\" && parsedField.config.allowedValues) {\n const enumTypeName = `${type.name}${capitalizeFirst(fieldName)}`;\n enums.push({\n name: enumTypeName,\n values: parsedField.config.allowedValues,\n fieldDescription: parsedField.config.description,\n });\n }\n\n // Process nested fields\n if (parsedField.config.type === \"nested\" && parsedField.config.fields) {\n for (const [nestedFieldName, nestedFieldConfig] of Object.entries(\n parsedField.config.fields,\n )) {\n if (nestedFieldConfig.type === \"enum\" && nestedFieldConfig.allowedValues) {\n const fullFieldName = `${fieldName}${capitalizeFirst(nestedFieldName)}`;\n const enumTypeName = `${type.name}${capitalizeFirst(fullFieldName)}`;\n enums.push({\n name: enumTypeName,\n values: nestedFieldConfig.allowedValues,\n fieldDescription: nestedFieldConfig.description,\n });\n }\n }\n }\n }\n\n return enums;\n}\n\n/**\n * Process a TailorDB table and extract enum metadata.\n * @param type - The parsed TailorDB table to process\n * @returns Enum constant metadata for the table\n */\nexport async function processEnumType(type: TailorDBType): Promise<EnumConstantMetadata> {\n const enums = collectEnums(type);\n\n return {\n name: type.name,\n enums,\n };\n}\n","import { generateUnifiedEnumConstants } from \"./generate-enum-constants\";\nimport { processEnumType } from \"./process-enum-type\";\nimport type { Plugin, GeneratorResult, TailorDBReadyContext } from \"#/plugin/types\";\nimport type { EnumDefinition } from \"./types\";\n\n/** Unique identifier for the enum constants generator plugin. */\nexport const EnumConstantsGeneratorID = \"@tailor-platform/enum-constants\";\n\ntype EnumConstantsPluginOptions = {\n distPath: string;\n};\n\n/**\n * Plugin that generates enum constants from TailorDB table definitions.\n * @param options - Plugin options\n * @param options.distPath - Output file path for generated constants\n * @returns Plugin instance with onTailorDBReady hook\n */\nexport function enumConstantsPlugin(\n options: EnumConstantsPluginOptions,\n): Plugin<unknown, EnumConstantsPluginOptions> {\n return {\n id: EnumConstantsGeneratorID,\n description: \"Generates enum constants from TailorDB table definitions\",\n pluginConfig: options,\n\n async onTailorDBReady(\n ctx: TailorDBReadyContext<EnumConstantsPluginOptions>,\n ): Promise<GeneratorResult> {\n const allEnums: EnumDefinition[] = [];\n\n for (const ns of ctx.tailordb) {\n for (const type of Object.values(ns.tables)) {\n const metadata = await processEnumType(type);\n allEnums.push(...metadata.enums);\n }\n }\n\n const files: GeneratorResult[\"files\"] = [];\n if (allEnums.length > 0) {\n const content = generateUnifiedEnumConstants(allEnums);\n files.push({\n path: ctx.pluginConfig.distPath,\n content,\n });\n }\n\n return { files };\n },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["allEnums","enumMap","enumDef","enumDefs","members","v","hasDescriptions","jsDoc","lines","propertyDocs","str","enums","fieldName","parsedField","type","enumTypeName","nestedFieldName","nestedFieldConfig","fullFieldName","EnumConstantsGeneratorID","options","ns","ctx","metadata","files","content"],"sources":["../../../../src/plugin/builtin/enum-constants/generate-enum-constants.ts","../../../../src/plugin/builtin/enum-constants/process-enum-type.ts","../../../../src/plugin/builtin/enum-constants/index.ts"],"sourcesContent":["import type { EnumDefinition } from \"./types\";\n\n/**\n * Generate enum constant definitions from collected metadata.\n * @param allEnums - All collected enum definitions\n * @returns Generated enum constant definitions\n */\nexport function generateUnifiedEnumConstants(allEnums: EnumDefinition[]): string {\n if (allEnums.length === 0) {\n return \"\";\n }\n\n const enumMap = new Map<string, EnumDefinition>();\n for (const enumDef of allEnums) {\n enumMap.set(enumDef.name, enumDef);\n }\n\n const enumDefs = Array.from(enumMap.values())\n .map((e) => {\n const members = e.values\n .map((v) => {\n const key = v.value.replace(/[-\\s]/g, \"_\");\n return ` \"${key}\": \"${v.value}\"`;\n })\n .join(\",\\n\");\n\n const hasDescriptions = e.values.some((v) => v.description);\n let jsDoc = \"\";\n if (e.fieldDescription || hasDescriptions) {\n const lines: string[] = [];\n\n if (e.fieldDescription) {\n lines.push(` * ${e.fieldDescription}`);\n if (hasDescriptions) {\n lines.push(\" *\");\n }\n }\n\n if (hasDescriptions) {\n const propertyDocs = e.values.map((v) => {\n const key = v.value.replace(/[-\\s]/g, \"_\");\n return ` * @property ${[key, v.description].filter(Boolean).join(\" - \")}`;\n });\n lines.push(...propertyDocs);\n }\n\n if (lines.length > 0) {\n jsDoc = `/**\\n${lines.join(\"\\n\")}\\n */\\n`;\n }\n }\n\n const constDef = `${jsDoc}export const ${e.name} = {\\n${members}\\n} as const;`;\n const typeDef = `export type ${e.name} = (typeof ${e.name})[keyof typeof ${e.name}];`;\n return `${constDef}\\n${typeDef}`;\n })\n .join(\"\\n\\n\");\n\n if (!enumDefs) {\n return \"\";\n }\n\n return enumDefs + \"\\n\";\n}\n","import type { TailorDBType } from \"#/parser/service/tailordb/types\";\nimport type { EnumConstantMetadata } from \"./types\";\n\nfunction capitalizeFirst(str: string): string {\n return str.charAt(0).toUpperCase() + str.slice(1);\n}\n\nfunction collectEnums(type: TailorDBType): EnumConstantMetadata[\"enums\"] {\n const enums: EnumConstantMetadata[\"enums\"] = [];\n\n for (const [fieldName, parsedField] of Object.entries(type.fields)) {\n if (parsedField.config.type === \"enum\" && parsedField.config.allowedValues) {\n const enumTypeName = `${type.name}${capitalizeFirst(fieldName)}`;\n enums.push({\n name: enumTypeName,\n values: parsedField.config.allowedValues,\n fieldDescription: parsedField.config.description,\n });\n }\n\n // Process nested fields\n if (parsedField.config.type === \"nested\" && parsedField.config.fields) {\n for (const [nestedFieldName, nestedFieldConfig] of Object.entries(\n parsedField.config.fields,\n )) {\n if (nestedFieldConfig.type === \"enum\" && nestedFieldConfig.allowedValues) {\n const fullFieldName = `${fieldName}${capitalizeFirst(nestedFieldName)}`;\n const enumTypeName = `${type.name}${capitalizeFirst(fullFieldName)}`;\n enums.push({\n name: enumTypeName,\n values: nestedFieldConfig.allowedValues,\n fieldDescription: nestedFieldConfig.description,\n });\n }\n }\n }\n }\n\n return enums;\n}\n\n/**\n * Process a TailorDB table and extract enum metadata.\n * @param type - The parsed TailorDB table to process\n * @returns Enum constant metadata for the table\n */\nexport async function processEnumType(type: TailorDBType): Promise<EnumConstantMetadata> {\n const enums = collectEnums(type);\n\n return {\n name: type.name,\n enums,\n };\n}\n","import { generateUnifiedEnumConstants } from \"./generate-enum-constants\";\nimport { processEnumType } from \"./process-enum-type\";\nimport type { Plugin, GeneratorResult, TailorDBReadyContext } from \"#/plugin/types\";\nimport type { EnumDefinition } from \"./types\";\n\n/** Unique identifier for the enum constants generator plugin. */\nexport const EnumConstantsGeneratorID = \"@tailor-platform/enum-constants\";\n\ntype EnumConstantsPluginOptions = {\n distPath: string;\n};\n\n/**\n * Plugin that generates enum constants from TailorDB table definitions.\n * @param options - Plugin options\n * @param options.distPath - Output file path for generated constants\n * @returns Plugin instance with onTailorDBReady hook\n */\nexport function enumConstantsPlugin(\n options: EnumConstantsPluginOptions,\n): Plugin<unknown, EnumConstantsPluginOptions> {\n return {\n id: EnumConstantsGeneratorID,\n description: \"Generates enum constants from TailorDB table definitions\",\n pluginConfig: options,\n\n async onTailorDBReady(\n ctx: TailorDBReadyContext<EnumConstantsPluginOptions>,\n ): Promise<GeneratorResult> {\n const allEnums: EnumDefinition[] = [];\n\n for (const ns of ctx.tailordb) {\n for (const type of Object.values(ns.tables)) {\n const metadata = await processEnumType(type);\n allEnums.push(...metadata.enums);\n }\n }\n\n const files: GeneratorResult[\"files\"] = [];\n if (allEnums.length > 0) {\n const content = generateUnifiedEnumConstants(allEnums);\n files.push({\n path: ctx.pluginConfig.distPath,\n content,\n });\n }\n\n return { files };\n },\n };\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../../src/plugin/builtin/file-utils/generate-file-utils.ts","../../../../src/plugin/builtin/file-utils/process-file-type.ts","../../../../src/plugin/builtin/file-utils/index.ts"],"sourcesContent":["import multiline from \"#/utils/multiline\";\nimport type { FileUtilMetadata } from \"./types\";\n\n/**\n * Generate unified file utility functions from collected metadata.\n * @param namespaceData - Namespace data with file utility metadata\n * @returns Generated file utility code\n */\nexport function generateUnifiedFileUtils(\n namespaceData: { namespace: string; types: FileUtilMetadata[] }[],\n): string {\n if (namespaceData.length === 0) {\n return \"\";\n }\n\n // Collect all tables with their namespace\n const tableNamespaceMap = new Map<string, string>();\n const typeFieldsMap = new Map<string, string[]>();\n\n for (const { namespace, types } of namespaceData) {\n for (const type of types) {\n tableNamespaceMap.set(type.name, namespace);\n typeFieldsMap.set(type.name, type.fileFields);\n }\n }\n\n if (tableNamespaceMap.size === 0) {\n return \"\";\n }\n\n // Generate interface fields\n const interfaceFields = Array.from(typeFieldsMap.entries())\n .map(([tableName, fields]) => {\n const fieldNamesUnion = fields.map((field) => `\"${field}\"`).join(\" | \");\n return ` ${tableName}: {\\n fields: ${fieldNamesUnion};\\n };`;\n })\n .join(\"\\n\");\n\n const importStatement =\n multiline /* ts */ `\n import { file } from \"@tailor-platform/sdk/runtime/file\";\n import type {\n FileUploadOptions,\n FileUploadStringOptions,\n FileUploadBytes,\n FileUploadResponse,\n FileMetadata,\n FileDownloadStreamResponse,\n } from \"@tailor-platform/sdk/runtime/file\";\n ` + \"\\n\";\n\n const interfaceDefinition =\n multiline /* ts */ `\n export interface TypeWithFiles {\n ${interfaceFields}\n }\n ` + \"\\n\";\n\n // Generate namespaces object\n const namespaceEntries = Array.from(tableNamespaceMap.entries())\n .map(([tableName, namespace]) => ` ${tableName}: \"${namespace}\"`)\n .join(\",\\n\");\n\n const namespacesDefinition =\n multiline /* ts */ `\n const namespaces: Record<keyof TypeWithFiles, string> = {\n ${namespaceEntries},\n };\n ` + \"\\n\";\n\n // Generate downloadFile helper function\n const downloadFunction =\n multiline /* ts */ `\n export async function downloadFile<T extends keyof TypeWithFiles>(\n type: T,\n field: TypeWithFiles[T][\"fields\"],\n recordId: string,\n ) {\n return await file.download(namespaces[type], type, field, recordId);\n }\n ` + \"\\n\";\n\n // Generate uploadFile helper function\n const uploadFunction =\n multiline /* ts */ `\n export function uploadFile<T extends keyof TypeWithFiles>(\n type: T,\n field: TypeWithFiles[T][\"fields\"],\n recordId: string,\n data: FileUploadBytes,\n options?: FileUploadOptions,\n ): Promise<FileUploadResponse>;\n export function uploadFile<T extends keyof TypeWithFiles>(\n type: T,\n field: TypeWithFiles[T][\"fields\"],\n recordId: string,\n data: string | FileUploadBytes,\n options: FileUploadStringOptions,\n ): Promise<FileUploadResponse>;\n /**\n * @deprecated since NEXT_RELEASE — pass encoding: \"utf8\" for text or \"base64\" for Base64 strings. codemod: v3/file-upload-encoding\n */\n export function uploadFile<T extends keyof TypeWithFiles>(\n type: T,\n field: TypeWithFiles[T][\"fields\"],\n recordId: string,\n data: string | FileUploadBytes,\n options?: FileUploadOptions,\n ): Promise<FileUploadResponse>;\n export async function uploadFile<T extends keyof TypeWithFiles>(\n type: T,\n field: TypeWithFiles[T][\"fields\"],\n recordId: string,\n data: string | FileUploadBytes,\n options?: FileUploadOptions,\n ): Promise<FileUploadResponse> {\n return await file.upload(namespaces[type], type, field, recordId, data, options);\n }\n ` + \"\\n\";\n\n // Generate deleteFile helper function\n const deleteFunction =\n multiline /* ts */ `\n export async function deleteFile<T extends keyof TypeWithFiles>(\n type: T,\n field: TypeWithFiles[T][\"fields\"],\n recordId: string,\n ): Promise<void> {\n return await file.delete(namespaces[type], type, field, recordId);\n }\n ` + \"\\n\";\n\n // Generate getFileMetadata helper function\n const getMetadataFunction =\n multiline /* ts */ `\n export async function getFileMetadata<T extends keyof TypeWithFiles>(\n type: T,\n field: TypeWithFiles[T][\"fields\"],\n recordId: string,\n ): Promise<FileMetadata> {\n return await file.getMetadata(namespaces[type], type, field, recordId);\n }\n ` + \"\\n\";\n\n // Generate downloadFileStream helper function\n const downloadStreamFunction =\n multiline /* ts */ `\n export async function downloadFileStream<T extends keyof TypeWithFiles>(\n type: T,\n field: TypeWithFiles[T][\"fields\"],\n recordId: string,\n ): Promise<FileDownloadStreamResponse> {\n return await file.downloadStream(namespaces[type], type, field, recordId);\n }\n ` + \"\\n\";\n\n return [\n importStatement,\n interfaceDefinition,\n namespacesDefinition,\n downloadFunction,\n uploadFunction,\n deleteFunction,\n getMetadataFunction,\n downloadStreamFunction,\n ].join(\"\\n\");\n}\n","import type { TailorDBType } from \"#/parser/service/tailordb/types\";\nimport type { FileUtilMetadata } from \"./types\";\n\n/**\n * Process a TailorDB table and extract file field metadata.\n * @param type - The parsed TailorDB table to process\n * @returns File utility metadata for the table\n */\nexport async function processFileType(type: TailorDBType): Promise<FileUtilMetadata> {\n const fileFields: string[] = [];\n\n if (type.files) {\n for (const fileFieldName of Object.keys(type.files)) {\n fileFields.push(fileFieldName);\n }\n }\n\n return {\n name: type.name,\n fileFields,\n };\n}\n","import { generateUnifiedFileUtils } from \"./generate-file-utils\";\nimport { processFileType } from \"./process-file-type\";\nimport type { Plugin, GeneratorResult, TailorDBReadyContext } from \"#/plugin/types\";\nimport type { FileUtilMetadata } from \"./types\";\n\n/** Unique identifier for the file utilities generator plugin. */\nexport const FileUtilsGeneratorID = \"@tailor-platform/file-utils\";\n\ntype FileUtilsPluginOptions = {\n distPath: string;\n};\n\n/**\n * Plugin that generates TypeWithFiles interface from TailorDB table definitions.\n * @param options - Plugin options\n * @param options.distPath - Output file path for generated file utilities\n * @returns Plugin instance with onTailorDBReady hook\n */\nexport function fileUtilsPlugin(\n options: FileUtilsPluginOptions,\n): Plugin<unknown, FileUtilsPluginOptions> {\n return {\n id: FileUtilsGeneratorID,\n description: \"Generates TypeWithFiles interface from TailorDB table definitions\",\n pluginConfig: options,\n\n async onTailorDBReady(\n ctx: TailorDBReadyContext<FileUtilsPluginOptions>,\n ): Promise<GeneratorResult> {\n const namespaceData: { namespace: string; types: FileUtilMetadata[] }[] = [];\n\n for (const ns of ctx.tailordb) {\n const typesWithFiles: FileUtilMetadata[] = [];\n\n for (const type of Object.values(ns.tables)) {\n const metadata = await processFileType(type);\n if (metadata.fileFields.length > 0) {\n typesWithFiles.push(metadata);\n }\n }\n\n if (typesWithFiles.length > 0) {\n namespaceData.push({\n namespace: ns.namespace,\n types: typesWithFiles,\n });\n }\n }\n\n const files: GeneratorResult[\"files\"] = [];\n if (namespaceData.length > 0) {\n const content = generateUnifiedFileUtils(namespaceData);\n if (content) {\n files.push({\n path: ctx.pluginConfig.distPath,\n content,\n });\n }\n }\n\n return { files };\n },\n };\n}\n"],"mappings":"oDAQA,SAAgB,yBACd,EACQ,CACR,GAAI,EAAc,SAAW,EAC3B,MAAO,GAIT,IAAM,kBAAoB,IAAI,IACxB,kBAAgB,IAAI,IAE1B,IAAK,GAAM,CAAE,YAAW,WAAW,EACjC,IAAK,IAAM,KAAQ,EACjB,EAAkB,IAAI,EAAK,KAAM,CAAS,EAC1C,EAAc,IAAI,EAAK,KAAM,EAAK,UAAU,EAIhD,GAAI,EAAkB,OAAS,EAC7B,MAAO,GAIT,IAAM,EAAkB,MAAM,KAAK,EAAc,QAAQ,CAAC,CAAC,CACxD,KAAK,CAAC,EAAW,KAET,KAAK,EAAU,mBADE,EAAO,IAAK,GAAU,IAAI,EAAM,EAAE,CAAC,CAAC,KAAK,KACV,EAAE,QAC1D,CAAC,CACD,KAAK;CAAI,EAEN,EACJ,CAAmB;;;;;;;;;;MAUf;EAEA,EACJ,CAAmB;;QAEf,EAAgB;;MAEhB;EAGA,EAAmB,MAAM,KAAK,EAAkB,QAAQ,CAAC,CAAC,CAC7D,KAAK,CAAC,EAAW,KAAe,KAAK,EAAU,KAAK,EAAU,EAAE,CAAC,CACjE,KAAK;CAAK,EA+Fb,MAAO,CACL,EACA,EA9FA,CAAmB;;QAEf,EAAiB;;MAEjB;EAIJ,CAAmB;;;;;;;;MAQf;EAIJ,CAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAkCf;EAIJ,CAAmB;;;;;;;;MAQf;EAIJ,CAAmB;;;;;;;;MAQf;EAIJ,CAAmB;;;;;;;;MAQf;CAWN,CAAC,CAAC,KAAK;CAAI,CACb,CC9JA,eAAsB,gBAAgB,EAA+C,CACnF,IAAM,EAAuB,CAAC,EAE9B,GAAI,EAAK,MACP,IAAK,IAAM,KAAiB,OAAO,KAAK,EAAK,KAAK,EAChD,EAAW,KAAK,CAAa,EAIjC,MAAO,CACL,KAAM,EAAK,KACX,YACF,CACF,CCfA,MAAa,EAAuB,8BAYpC,SAAgB,gBACd,EACyC,CACzC,MAAO,CACL,GAAI,EACJ,YAAa,oEACb,aAAc,EAEd,MAAM,gBACJ,EAC0B,CAC1B,IAAM,EAAoE,CAAC,EAE3E,IAAK,IAAM,KAAM,EAAI,SAAU,CAC7B,IAAM,EAAqC,CAAC,EAE5C,IAAK,IAAM,KAAQ,OAAO,OAAO,EAAG,MAAM,EAAG,CAC3C,IAAM,EAAW,MAAM,gBAAgB,CAAI,EACvC,EAAS,WAAW,OAAS,GAC/B,EAAe,KAAK,CAAQ,CAEhC,CAEI,EAAe,OAAS,GAC1B,EAAc,KAAK,CACjB,UAAW,EAAG,UACd,MAAO,CACT,CAAC,CAEL,CAEA,IAAM,EAAkC,CAAC,EACzC,GAAI,EAAc,OAAS,EAAG,CAC5B,IAAM,EAAU,yBAAyB,CAAa,EAClD,GACF,EAAM,KAAK,CACT,KAAM,EAAI,aAAa,SACvB,SACF,CAAC,CAEL,CAEA,MAAO,CAAE,OAAM,CACjB,CACF,CACF"}
1
+ {"version":3,"file":"index.mjs","names":["multiline","namespaceData","tableNamespaceMap","typeFieldsMap","type","types","namespace","interfaceFields","tableName","fields","field","importStatement","interfaceDefinition","namespaceEntries","fileFields","fileFieldName","FileUtilsGeneratorID","options","ns","ctx","typesWithFiles","metadata","files","content"],"sources":["../../../../src/plugin/builtin/file-utils/generate-file-utils.ts","../../../../src/plugin/builtin/file-utils/process-file-type.ts","../../../../src/plugin/builtin/file-utils/index.ts"],"sourcesContent":["import multiline from \"#/utils/multiline\";\nimport type { FileUtilMetadata } from \"./types\";\n\n/**\n * Generate unified file utility functions from collected metadata.\n * @param namespaceData - Namespace data with file utility metadata\n * @returns Generated file utility code\n */\nexport function generateUnifiedFileUtils(\n namespaceData: { namespace: string; types: FileUtilMetadata[] }[],\n): string {\n if (namespaceData.length === 0) {\n return \"\";\n }\n\n // Collect all tables with their namespace\n const tableNamespaceMap = new Map<string, string>();\n const typeFieldsMap = new Map<string, string[]>();\n\n for (const { namespace, types } of namespaceData) {\n for (const type of types) {\n tableNamespaceMap.set(type.name, namespace);\n typeFieldsMap.set(type.name, type.fileFields);\n }\n }\n\n if (tableNamespaceMap.size === 0) {\n return \"\";\n }\n\n // Generate interface fields\n const interfaceFields = Array.from(typeFieldsMap.entries())\n .map(([tableName, fields]) => {\n const fieldNamesUnion = fields.map((field) => `\"${field}\"`).join(\" | \");\n return ` ${tableName}: {\\n fields: ${fieldNamesUnion};\\n };`;\n })\n .join(\"\\n\");\n\n const importStatement =\n multiline /* ts */ `\n import { file } from \"@tailor-platform/sdk/runtime/file\";\n import type {\n FileUploadOptions,\n FileUploadStringOptions,\n FileUploadBytes,\n FileUploadResponse,\n FileMetadata,\n FileDownloadStreamResponse,\n } from \"@tailor-platform/sdk/runtime/file\";\n ` + \"\\n\";\n\n const interfaceDefinition =\n multiline /* ts */ `\n export interface TypeWithFiles {\n ${interfaceFields}\n }\n ` + \"\\n\";\n\n // Generate namespaces object\n const namespaceEntries = Array.from(tableNamespaceMap.entries())\n .map(([tableName, namespace]) => ` ${tableName}: \"${namespace}\"`)\n .join(\",\\n\");\n\n const namespacesDefinition =\n multiline /* ts */ `\n const namespaces: Record<keyof TypeWithFiles, string> = {\n ${namespaceEntries},\n };\n ` + \"\\n\";\n\n // Generate downloadFile helper function\n const downloadFunction =\n multiline /* ts */ `\n export async function downloadFile<T extends keyof TypeWithFiles>(\n type: T,\n field: TypeWithFiles[T][\"fields\"],\n recordId: string,\n ) {\n return await file.download(namespaces[type], type, field, recordId);\n }\n ` + \"\\n\";\n\n // Generate uploadFile helper function\n const uploadFunction =\n multiline /* ts */ `\n export function uploadFile<T extends keyof TypeWithFiles>(\n type: T,\n field: TypeWithFiles[T][\"fields\"],\n recordId: string,\n data: FileUploadBytes,\n options?: FileUploadOptions,\n ): Promise<FileUploadResponse>;\n export function uploadFile<T extends keyof TypeWithFiles>(\n type: T,\n field: TypeWithFiles[T][\"fields\"],\n recordId: string,\n data: string | FileUploadBytes,\n options: FileUploadStringOptions,\n ): Promise<FileUploadResponse>;\n /**\n * @deprecated since NEXT_RELEASE — pass encoding: \"utf8\" for text or \"base64\" for Base64 strings. codemod: v3/file-upload-encoding\n */\n export function uploadFile<T extends keyof TypeWithFiles>(\n type: T,\n field: TypeWithFiles[T][\"fields\"],\n recordId: string,\n data: string | FileUploadBytes,\n options?: FileUploadOptions,\n ): Promise<FileUploadResponse>;\n export async function uploadFile<T extends keyof TypeWithFiles>(\n type: T,\n field: TypeWithFiles[T][\"fields\"],\n recordId: string,\n data: string | FileUploadBytes,\n options?: FileUploadOptions,\n ): Promise<FileUploadResponse> {\n return await file.upload(namespaces[type], type, field, recordId, data, options);\n }\n ` + \"\\n\";\n\n // Generate deleteFile helper function\n const deleteFunction =\n multiline /* ts */ `\n export async function deleteFile<T extends keyof TypeWithFiles>(\n type: T,\n field: TypeWithFiles[T][\"fields\"],\n recordId: string,\n ): Promise<void> {\n return await file.delete(namespaces[type], type, field, recordId);\n }\n ` + \"\\n\";\n\n // Generate getFileMetadata helper function\n const getMetadataFunction =\n multiline /* ts */ `\n export async function getFileMetadata<T extends keyof TypeWithFiles>(\n type: T,\n field: TypeWithFiles[T][\"fields\"],\n recordId: string,\n ): Promise<FileMetadata> {\n return await file.getMetadata(namespaces[type], type, field, recordId);\n }\n ` + \"\\n\";\n\n // Generate downloadFileStream helper function\n const downloadStreamFunction =\n multiline /* ts */ `\n export async function downloadFileStream<T extends keyof TypeWithFiles>(\n type: T,\n field: TypeWithFiles[T][\"fields\"],\n recordId: string,\n ): Promise<FileDownloadStreamResponse> {\n return await file.downloadStream(namespaces[type], type, field, recordId);\n }\n ` + \"\\n\";\n\n return [\n importStatement,\n interfaceDefinition,\n namespacesDefinition,\n downloadFunction,\n uploadFunction,\n deleteFunction,\n getMetadataFunction,\n downloadStreamFunction,\n ].join(\"\\n\");\n}\n","import type { TailorDBType } from \"#/parser/service/tailordb/types\";\nimport type { FileUtilMetadata } from \"./types\";\n\n/**\n * Process a TailorDB table and extract file field metadata.\n * @param type - The parsed TailorDB table to process\n * @returns File utility metadata for the table\n */\nexport async function processFileType(type: TailorDBType): Promise<FileUtilMetadata> {\n const fileFields: string[] = [];\n\n if (type.files) {\n for (const fileFieldName of Object.keys(type.files)) {\n fileFields.push(fileFieldName);\n }\n }\n\n return {\n name: type.name,\n fileFields,\n };\n}\n","import { generateUnifiedFileUtils } from \"./generate-file-utils\";\nimport { processFileType } from \"./process-file-type\";\nimport type { Plugin, GeneratorResult, TailorDBReadyContext } from \"#/plugin/types\";\nimport type { FileUtilMetadata } from \"./types\";\n\n/** Unique identifier for the file utilities generator plugin. */\nexport const FileUtilsGeneratorID = \"@tailor-platform/file-utils\";\n\ntype FileUtilsPluginOptions = {\n distPath: string;\n};\n\n/**\n * Plugin that generates TypeWithFiles interface from TailorDB table definitions.\n * @param options - Plugin options\n * @param options.distPath - Output file path for generated file utilities\n * @returns Plugin instance with onTailorDBReady hook\n */\nexport function fileUtilsPlugin(\n options: FileUtilsPluginOptions,\n): Plugin<unknown, FileUtilsPluginOptions> {\n return {\n id: FileUtilsGeneratorID,\n description: \"Generates TypeWithFiles interface from TailorDB table definitions\",\n pluginConfig: options,\n\n async onTailorDBReady(\n ctx: TailorDBReadyContext<FileUtilsPluginOptions>,\n ): Promise<GeneratorResult> {\n const namespaceData: { namespace: string; types: FileUtilMetadata[] }[] = [];\n\n for (const ns of ctx.tailordb) {\n const typesWithFiles: FileUtilMetadata[] = [];\n\n for (const type of Object.values(ns.tables)) {\n const metadata = await processFileType(type);\n if (metadata.fileFields.length > 0) {\n typesWithFiles.push(metadata);\n }\n }\n\n if (typesWithFiles.length > 0) {\n namespaceData.push({\n namespace: ns.namespace,\n types: typesWithFiles,\n });\n }\n }\n\n const files: GeneratorResult[\"files\"] = [];\n if (namespaceData.length > 0) {\n const content = generateUnifiedFileUtils(namespaceData);\n if (content) {\n files.push({\n path: ctx.pluginConfig.distPath,\n content,\n });\n }\n }\n\n return { files };\n },\n };\n}\n"],"mappings":"oDAQA,SAAgB,yBACd,EACQ,CACR,GAAIC,EAAc,SAAW,EAC3B,MAAO,GAIT,IAAMC,kBAAoB,IAAI,IACxBC,kBAAgB,IAAI,IAE1B,IAAK,GAAM,CAAE,YAAW,WAAWF,EACjC,IAAK,IAAMG,KAAQC,EACjBH,EAAkB,IAAIE,EAAK,KAAME,CAAS,EAC1CH,EAAc,IAAIC,EAAK,KAAMA,EAAK,UAAU,EAIhD,GAAIF,EAAkB,OAAS,EAC7B,MAAO,GAIT,IAAMK,EAAkB,MAAM,KAAKJ,EAAc,QAAQ,CAAC,CAAC,CACxD,KAAK,CAACK,EAAWC,KAET,KAAKD,EAAU,mBADEC,EAAO,IAAK,GAAU,IAAIC,EAAM,EAAE,CAAC,CAAC,KAAK,KACV,EAAE,QAC1D,CAAC,CACD,KAAK;CAAI,EAENC,EACJ,CAAmB;;;;;;;;;;MAUf;EAEAC,EACJ,CAAmB;;QAEfL,EAAgB;;MAEhB;EAGAM,EAAmB,MAAM,KAAKX,EAAkB,QAAQ,CAAC,CAAC,CAC7D,KAAK,CAACM,EAAWF,KAAe,KAAKE,EAAU,KAAKF,EAAU,EAAE,CAAC,CACjE,KAAK;CAAK,EA+Fb,MAAO,CACLK,EACAC,EA9FA,CAAmB;;QAEfC,EAAiB;;MAEjB;EAIJ,CAAmB;;;;;;;;MAQf;EAIJ,CAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAkCf;EAIJ,CAAmB;;;;;;;;MAQf;EAIJ,CAAmB;;;;;;;;MAQf;EAIJ,CAAmB;;;;;;;;MAQf;CAWN,CAAC,CAAC,KAAK;CAAI,CACb,CC9JA,eAAsB,gBAAgB,EAA+C,CACnF,IAAMC,EAAuB,CAAC,EAE9B,GAAIV,EAAK,MACP,IAAK,IAAMW,KAAiB,OAAO,KAAKX,EAAK,KAAK,EAChDU,EAAW,KAAKC,CAAa,EAIjC,MAAO,CACL,KAAMX,EAAK,KACX,YACF,CACF,CCfA,MAAaY,EAAuB,8BAYpC,SAAgB,gBACd,EACyC,CACzC,MAAO,CACL,GAAIA,EACJ,YAAa,oEACb,aAAcC,EAEd,MAAM,gBACJ,EAC0B,CAC1B,IAAMhB,EAAoE,CAAC,EAE3E,IAAK,IAAMiB,KAAMC,EAAI,SAAU,CAC7B,IAAMC,EAAqC,CAAC,EAE5C,IAAK,IAAMhB,KAAQ,OAAO,OAAOc,EAAG,MAAM,EAAG,CAC3C,IAAMG,EAAW,MAAM,gBAAgBjB,CAAI,EACvCiB,EAAS,WAAW,OAAS,GAC/BD,EAAe,KAAKC,CAAQ,CAEhC,CAEID,EAAe,OAAS,GAC1BnB,EAAc,KAAK,CACjB,UAAWiB,EAAG,UACd,MAAOE,CACT,CAAC,CAEL,CAEA,IAAME,EAAkC,CAAC,EACzC,GAAIrB,EAAc,OAAS,EAAG,CAC5B,IAAMsB,EAAU,yBAAyBtB,CAAa,EAClDsB,GACFD,EAAM,KAAK,CACT,KAAMH,EAAI,aAAa,SACvB,SACF,CAAC,CAEL,CAEA,MAAO,CAAE,OAAM,CACjB,CACF,CACF"}
@@ -1,2 +1,2 @@
1
- import{a as e}from"../guards-DsX7dJCP.mjs";import{t}from"../manager-C0dE7pd0.mjs";import*as n from"pathe";import*as r from"node:fs";import{pathToFileURL as i}from"node:url";function withPluginContext(e){return e}const a=/* @__PURE__ */ new Map;async function loadAndCacheConfig(t){let o=n.resolve(t),s=a.get(o);if(s)return s;if(!r.existsSync(o))return null;let c=await import(i(o).href);if(!c?.default)throw Error(`Invalid config module at "${o}": default export not found`);let l=c.default,u=n.dirname(o),d=/* @__PURE__ */ new Map;for(let t of e(c))for(let e of t){let t=e;d.set(t.id,{plugin:t,pluginConfig:t.pluginConfig})}let f={config:l,plugins:d,configDir:u};return a.set(o,f),f}async function resolveNamespaceForTable(e,t,a){if(!e.db)throw Error(`No db configuration found in config`);for(let[o,s]of Object.entries(e.db)){let e=s;if(!e.external&&e.files)for(let s of e.files){let e=n.resolve(t,s),c;try{c=r.globSync(e)}catch{continue}for(let e of c){let t=await import(i(e).href);for(let e of Object.values(t))if(e===a)return o}}}throw Error(`Could not resolve namespace for table "${a.name}". Ensure the table file is included in a db namespace's files pattern.`)}async function resolveNamespaceForNamespacePlugin(e,t,n,r){if(!e.db)throw Error(`No db configuration found in config`);if(!t.onNamespaceLoaded)throw Error(`Plugin "${t.id}" does not have a onNamespaceLoaded() method`);for(let i of Object.keys(e.db)){if(e.db[i].external)continue;let a=await t.onNamespaceLoaded({pluginConfig:r,namespace:i});if(a.tables?.[n])return{namespace:i,output:a}}throw Error(`Could not resolve namespace for plugin "${t.id}" with kind "${n}". No namespace produced a table with that kind.`)}const o=/* @__PURE__ */ new WeakMap,s=/* @__PURE__ */ new WeakMap;function getCacheKey(e,t){if(t===void 0)return e;try{return`${e}:${JSON.stringify(t)}`}catch{throw Error(`pluginConfig must be JSON-serializable for caching. Received non-serializable value.`)}}async function getGeneratedTable(e,t,n,r){let i=await loadAndCacheConfig(e);if(!i)return{name:`__placeholder_${r}__`,fields:{}};let{config:a,configDir:o,plugins:s}=i,c=s.get(t);if(!c)throw Error(`Plugin "${t}" not found in config at "${e}". Ensure the plugin is registered via definePlugins().`);let{plugin:l,pluginConfig:u}=c;return n===null?getGeneratedTableForNamespacePlugin(a,l,r,u):getGeneratedTableForTableAttachedPlugin(l,n,r,u,await resolveNamespaceForTable(a,o,n))}async function getGeneratedTableForTableAttachedPlugin(e,t,n,r,i){if(!e.onTableLoaded)throw Error(`Plugin "${e.id}" does not have an onTableLoaded() method`);let a=o.get(e);a||(a=/* @__PURE__ */ new Map,o.set(e,a));let s=getCacheKey(`${t.name}:ns=${i}`,r),c=a.get(s);if(!c){let n=t.plugins.find(t=>t.pluginId===e.id)?.config;c=await e.onTableLoaded({table:t,tableConfig:n??{},pluginConfig:r,namespace:i}),a.set(s,c)}let l=c.tables?.[n];if(!l)throw Error(`Generated table not found: plugin=${e.id}, sourceTable=${t.name}, kind=${n}`);return l}async function getGeneratedTableForNamespacePlugin(e,t,n,r){if(!t.onNamespaceLoaded)throw Error(`Plugin "${t.id}" does not have a onNamespaceLoaded() method`);let i=s.get(t);if(i||(i=/* @__PURE__ */ new Map,s.set(t,i)),e.db)for(let t of Object.keys(e.db)){if(e.db[t].external)continue;let a=getCacheKey(`namespace:ns=${t}`,r),o=i.get(a);if(o?.tables?.[n])return o.tables[n]}let{namespace:a,output:o}=await resolveNamespaceForNamespacePlugin(e,t,n,r),c=getCacheKey(`namespace:ns=${a}`,r);i.set(c,o);let l=o.tables?.[n];if(!l)throw Error(`Generated table not found: plugin=${t.id}, kind=${n}`);return l}const c=/* @__PURE__ */ new Map;async function getExtendedTable(e,t){if(t.plugins.length===0)return t;let r=n.resolve(e),i=c.get(r);i||(i=/* @__PURE__ */ new WeakMap,c.set(r,i));let a=i.get(t);if(a)return a;let o=applyPluginExtensions(r,t);return i.set(t,o),o.catch(()=>i.delete(t)),o}async function applyPluginExtensions(e,n){let r=await loadAndCacheConfig(e);if(!r)return n;let{config:i,configDir:a,plugins:o}=r,s=await resolveNamespaceForTable(i,a,n),{extendedTable:c}=await new t([...o.values()].map(e=>e.plugin)).processAttachmentsForTable({rawTable:n,attachments:[...n.plugins],namespace:s});return c??n}export{getExtendedTable,getGeneratedTable,withPluginContext};
1
+ import{t as e}from"../manager-8-JOvuLl.mjs";import*as t from"pathe";import*as n from"node:fs";import{pathToFileURL as r}from"node:url";function withPluginContext(e){return e}const i=/* @__PURE__ */ new Map,a=[`onTableLoaded`,`onNamespaceLoaded`,`onTailorDBReady`,`onResolverReady`,`onExecutorReady`];function isPlugin(e){if(typeof e!=`object`||!e||Array.isArray(e))return!1;let t=e;if(typeof t.id!=`string`||typeof t.description!=`string`||t.importPath!==void 0&&typeof t.importPath!=`string`||t.tableConfigRequired!==void 0&&typeof t.tableConfigRequired!=`boolean`&&typeof t.tableConfigRequired!=`function`)return!1;for(let e of a)if(t[e]!==void 0&&typeof t[e]!=`function`)return!1;return!((t.onTableLoaded||t.onNamespaceLoaded)&&!t.importPath)}async function loadAndCacheConfig(e){let a=t.resolve(e),o=i.get(a);if(o)return o;if(!n.existsSync(a))return null;let s=await import(r(a).href);if(!s?.default)throw Error(`Invalid config module at "${a}": default export not found`);let c=s.default,l=t.dirname(a),u=/* @__PURE__ */ new Map;if(Object.hasOwn(s,`plugins`)){let e=s.plugins;if(!Array.isArray(e))throw Error(`Invalid \`plugins\` export in "${a}": expected an array returned by definePlugins(), got ${typeof e}`);for(let t of e){if(!isPlugin(t))throw Error(`Invalid \`plugins\` export in "${a}": every item must be a plugin created by definePlugins()`);if(u.has(t.id))throw Error(`Duplicate plugin ID "${t.id}" detected in "${a}". Each plugin must have a unique ID.`);u.set(t.id,{plugin:t,pluginConfig:t.pluginConfig})}}let d={config:c,plugins:u,configDir:l};return i.set(a,d),d}async function resolveNamespaceForTable(e,i,a){if(!e.db)throw Error(`No db configuration found in config`);for(let[o,s]of Object.entries(e.db)){let e=s;if(!e.external&&e.files)for(let s of e.files){let e=t.resolve(i,s),c;try{c=n.globSync(e)}catch{continue}for(let e of c){let t=await import(r(e).href);for(let e of Object.values(t))if(e===a)return o}}}throw Error(`Could not resolve namespace for table "${a.name}". Ensure the table file is included in a db namespace's files pattern.`)}async function resolveNamespaceForNamespacePlugin(e,t,n,r){if(!e.db)throw Error(`No db configuration found in config`);if(!t.onNamespaceLoaded)throw Error(`Plugin "${t.id}" does not have a onNamespaceLoaded() method`);for(let i of Object.keys(e.db)){if(e.db[i].external)continue;let a=await t.onNamespaceLoaded({pluginConfig:r,namespace:i});if(a.tables?.[n])return{namespace:i,output:a}}throw Error(`Could not resolve namespace for plugin "${t.id}" with kind "${n}". No namespace produced a table with that kind.`)}const o=/* @__PURE__ */ new WeakMap,s=/* @__PURE__ */ new WeakMap;function getCacheKey(e,t){if(t===void 0)return e;try{return`${e}:${JSON.stringify(t)}`}catch{throw Error(`pluginConfig must be JSON-serializable for caching. Received non-serializable value.`)}}async function getGeneratedTable(e,t,n,r){let i=await loadAndCacheConfig(e);if(!i)return{name:`__placeholder_${r}__`,fields:{}};let{config:a,configDir:o,plugins:s}=i,c=s.get(t);if(!c)throw Error(`Plugin "${t}" not found in config at "${e}". Ensure the plugin is registered via definePlugins().`);let{plugin:l,pluginConfig:u}=c;return n===null?getGeneratedTableForNamespacePlugin(a,l,r,u):getGeneratedTableForTableAttachedPlugin(l,n,r,u,await resolveNamespaceForTable(a,o,n))}async function getGeneratedTableForTableAttachedPlugin(e,t,n,r,i){if(!e.onTableLoaded)throw Error(`Plugin "${e.id}" does not have an onTableLoaded() method`);let a=o.get(e);a||(a=/* @__PURE__ */ new Map,o.set(e,a));let s=getCacheKey(`${t.name}:ns=${i}`,r),c=a.get(s);if(!c){let n=t.plugins.find(t=>t.pluginId===e.id)?.config;c=await e.onTableLoaded({table:t,tableConfig:n??{},pluginConfig:r,namespace:i}),a.set(s,c)}let l=c.tables?.[n];if(!l)throw Error(`Generated table not found: plugin=${e.id}, sourceTable=${t.name}, kind=${n}`);return l}async function getGeneratedTableForNamespacePlugin(e,t,n,r){if(!t.onNamespaceLoaded)throw Error(`Plugin "${t.id}" does not have a onNamespaceLoaded() method`);let i=s.get(t);if(i||(i=/* @__PURE__ */ new Map,s.set(t,i)),e.db)for(let t of Object.keys(e.db)){if(e.db[t].external)continue;let a=getCacheKey(`namespace:ns=${t}`,r),o=i.get(a);if(o?.tables?.[n])return o.tables[n]}let{namespace:a,output:o}=await resolveNamespaceForNamespacePlugin(e,t,n,r),c=getCacheKey(`namespace:ns=${a}`,r);i.set(c,o);let l=o.tables?.[n];if(!l)throw Error(`Generated table not found: plugin=${t.id}, kind=${n}`);return l}const c=/* @__PURE__ */ new Map;async function getExtendedTable(e,n){if(n.plugins.length===0)return n;let r=t.resolve(e),i=c.get(r);i||(i=/* @__PURE__ */ new WeakMap,c.set(r,i));let a=i.get(n);if(a)return a;let o=applyPluginExtensions(r,n);return i.set(n,o),o.catch(()=>i.delete(n)),o}async function applyPluginExtensions(t,n){let r=await loadAndCacheConfig(t);if(!r)return n;let{config:i,configDir:a,plugins:o}=r,s=await resolveNamespaceForTable(i,a,n),{extendedTable:c}=await new e([...o.values()].map(e=>e.plugin)).processAttachmentsForTable({rawTable:n,attachments:[...n.plugins],namespace:s});return c??n}export{getExtendedTable,getGeneratedTable,withPluginContext};
2
2
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../src/plugin/with-context.ts","../../src/plugin/get-generated-table.ts"],"sourcesContent":["/**\n * Plugin executor context support for defining plugin executors in separate files.\n * This module provides utilities for creating type-safe plugin executors that receive\n * context (like table references and namespace) at runtime.\n */\n\nimport type { TailorEnv, TailorPrincipal } from \"#/runtime/types\";\n\n/**\n * Plugin executor factory function type.\n * Takes context and returns an executor configuration.\n * Returns unknown since the exact return type depends on createExecutor's generic params.\n */\nexport type PluginExecutorFactory<Ctx> = (ctx: Ctx) => unknown;\n\n// ============================================================================\n// Plugin Executor Args Types\n// ============================================================================\n\n/**\n * Base args for plugin executor function operations.\n * Provides typed access to runtime context without requiring specific record types.\n */\nexport interface PluginFunctionArgs {\n /** Workspace ID where the executor runs */\n workspaceId: string;\n /** Application namespace */\n appNamespace: string;\n /** Environment variables */\n env: TailorEnv;\n /** Principal that triggered the event, null for system events */\n actor: TailorPrincipal | null;\n /** Name of the TailorDB table */\n typeName: string;\n /** TailorDB connections by namespace */\n tailordb: Record<string, unknown>;\n}\n\n/**\n * Args for plugin executors triggered on record creation.\n */\nexport interface PluginRecordCreatedArgs extends PluginFunctionArgs {\n /** The newly created record */\n newRecord: Record<string, unknown>;\n}\n\n/**\n * Args for plugin executors triggered on record update.\n */\nexport interface PluginRecordUpdatedArgs extends PluginFunctionArgs {\n /** The record after update */\n newRecord: Record<string, unknown>;\n /** The record before update */\n oldRecord: Record<string, unknown>;\n}\n\n/**\n * Args for plugin executors triggered on record deletion.\n */\nexport interface PluginRecordDeletedArgs extends PluginFunctionArgs {\n /** The deleted record */\n oldRecord: Record<string, unknown>;\n}\n\n/**\n * Database schema type for plugins.\n * Since plugins work with dynamic types, the schema uses Record types.\n */\nexport type PluginDBSchema = Record<string, Record<string, unknown>>;\n\n/**\n * Base record type for TailorDB records.\n * All records have an id field.\n */\nexport type PluginRecord = { id: string } & Record<string, unknown>;\n\n/**\n * Define a plugin executor that receives context at runtime.\n * This allows executor definitions to be in separate files while\n * still receiving dynamic values like typeName, generated types, and namespace.\n * @param factory - Function that takes context and returns executor configuration\n * @returns The same factory function (for type inference)\n * @example\n * ```typescript\n * // executors/on-create.ts\n * import { withPluginContext } from \"@tailor-platform/sdk/plugin\";\n * import { createExecutor, recordCreatedTrigger } from \"@tailor-platform/sdk\";\n * import { getDB } from \"@tailor-platform/function-kysely-tailordb\";\n *\n * interface MyContext {\n * sourceTable: TailorAnyDBType;\n * historyType: TailorAnyDBType;\n * namespace: string;\n * }\n *\n * export default withPluginContext<MyContext>((ctx) =>\n * createExecutor({\n * name: `${ctx.sourceTable.name.toLowerCase()}-on-create`,\n * trigger: recordCreatedTrigger({ type: ctx.sourceTable }),\n * operation: {\n * kind: \"function\",\n * body: async (args) => {\n * const db = getDB(ctx.namespace);\n * await db.insertInto(ctx.historyType.name).values({\n * recordId: args.newRecord.id,\n * // ...\n * }).execute();\n * },\n * },\n * })\n * );\n * ```\n */\nexport function withPluginContext<Ctx>(\n factory: PluginExecutorFactory<Ctx>,\n): PluginExecutorFactory<Ctx> {\n return factory;\n}\n","import * as fs from \"node:fs\";\nimport { pathToFileURL } from \"node:url\";\nimport * as path from \"pathe\";\nimport { pickPluginArrays } from \"./guards\";\nimport { PluginManager } from \"./manager\";\nimport type { TailorAnyDBType } from \"#/configure/services/tailordb/types\";\nimport type { Plugin, PluginOutput, TablePluginOutput } from \"#/plugin/types\";\nimport type { TailorDBTypeRaw } from \"#/types/tailordb.generated\";\n\n// ========================================\n// Config loading and caching\n// ========================================\n\ninterface PluginEntry {\n plugin: Plugin;\n pluginConfig: unknown;\n}\n\ninterface ConfigCache {\n config: { db?: Record<string, unknown> };\n plugins: Map<string, PluginEntry>;\n configDir: string;\n}\n\n/** Cache: resolved config path -> loaded config data */\nconst configCacheMap = new Map<string, ConfigCache>();\n\n/**\n * Load and cache config module from the given path.\n * Extracts plugins from all array exports using definePlugins() format.\n * Returns null if the config file does not exist (e.g., in bundled executor on platform server).\n * @param configPath - Absolute or relative path to tailor.config.ts\n * @returns Cached config data with plugins map, or null if config file is not available\n */\nasync function loadAndCacheConfig(configPath: string): Promise<ConfigCache | null> {\n const resolvedPath = path.resolve(configPath);\n\n const cached = configCacheMap.get(resolvedPath);\n if (cached) return cached;\n\n // Config file may not exist in bundled environments (e.g., platform server)\n if (!fs.existsSync(resolvedPath)) {\n return null;\n }\n\n const configModule = await import(pathToFileURL(resolvedPath).href);\n if (!configModule?.default) {\n throw new Error(`Invalid config module at \"${resolvedPath}\": default export not found`);\n }\n\n const config = configModule.default as { db?: Record<string, unknown> };\n const configDir = path.dirname(resolvedPath);\n const plugins = new Map<string, PluginEntry>();\n\n for (const items of pickPluginArrays(configModule)) {\n for (const item of items) {\n const plugin = item as Plugin;\n plugins.set(plugin.id, { plugin, pluginConfig: plugin.pluginConfig });\n }\n }\n\n const result: ConfigCache = { config, plugins, configDir };\n configCacheMap.set(resolvedPath, result);\n return result;\n}\n\n// ========================================\n// Namespace resolution\n// ========================================\n\ninterface DbNamespaceConfig {\n files?: string[];\n external?: boolean;\n}\n\n/**\n * Resolve the namespace for a table-attached source table by checking config.db file patterns.\n * Uses ESM module cache identity: same file path yields same object references.\n * @param config - App config with db namespace definitions\n * @param config.db - DB namespace definitions\n * @param configDir - Directory containing the config file\n * @param sourceTable - The TailorDB table to look up\n * @returns The namespace name\n */\nasync function resolveNamespaceForTable(\n config: { db?: Record<string, unknown> },\n configDir: string,\n sourceTable: TailorAnyDBType,\n): Promise<string> {\n if (!config.db) {\n throw new Error(`No db configuration found in config`);\n }\n\n for (const [namespace, nsConfig] of Object.entries(config.db)) {\n const dbConfig = nsConfig as DbNamespaceConfig;\n // Skip external namespaces (no files to resolve)\n if (dbConfig.external || !dbConfig.files) continue;\n\n for (const pattern of dbConfig.files) {\n const absolutePattern = path.resolve(configDir, pattern);\n let matchedFiles: string[];\n try {\n matchedFiles = fs.globSync(absolutePattern);\n } catch {\n continue;\n }\n\n for (const file of matchedFiles) {\n const mod = await import(pathToFileURL(file).href);\n for (const exported of Object.values(mod)) {\n if (exported === sourceTable) {\n return namespace;\n }\n }\n }\n }\n }\n\n throw new Error(\n `Could not resolve namespace for table \"${sourceTable.name}\". ` +\n `Ensure the table file is included in a db namespace's files pattern.`,\n );\n}\n\n/**\n * Resolve the namespace for a namespace plugin by trying each namespace.\n * Calls onNamespaceLoaded() for each and returns the first whose output contains the requested kind.\n * @param config - App config with db namespace definitions\n * @param config.db - DB namespace definitions\n * @param plugin - Plugin instance\n * @param kind - The generated table kind to look for\n * @param pluginConfig - Plugin-level configuration\n * @returns The namespace name\n */\nasync function resolveNamespaceForNamespacePlugin(\n config: { db?: Record<string, unknown> },\n plugin: Plugin,\n kind: string,\n pluginConfig: unknown,\n): Promise<{ namespace: string; output: PluginOutput }> {\n if (!config.db) {\n throw new Error(`No db configuration found in config`);\n }\n\n if (!plugin.onNamespaceLoaded) {\n throw new Error(`Plugin \"${plugin.id}\" does not have a onNamespaceLoaded() method`);\n }\n\n for (const namespace of Object.keys(config.db)) {\n const dbConfig = config.db[namespace] as DbNamespaceConfig;\n if (dbConfig.external) continue;\n\n const output = await plugin.onNamespaceLoaded({\n pluginConfig,\n namespace,\n });\n\n if (output.tables?.[kind]) {\n return { namespace, output };\n }\n }\n\n throw new Error(\n `Could not resolve namespace for plugin \"${plugin.id}\" with kind \"${kind}\". ` +\n `No namespace produced a table with that kind.`,\n );\n}\n\n// ========================================\n// Process caching\n// ========================================\n\n// Cache: plugin -> cacheKey -> TablePluginOutput\nconst processCache = new WeakMap<Plugin, Map<string, TablePluginOutput>>();\n\n// Cache for namespace plugins: plugin -> cacheKey -> PluginOutput\nconst namespaceProcessCache = new WeakMap<Plugin, Map<string, PluginOutput>>();\n\n/**\n * Generate a cache key that includes pluginConfig.\n * @param baseKey - Base key for the cache\n * @param pluginConfig - Plugin configuration to include in the key\n * @returns Cache key string\n */\nfunction getCacheKey(baseKey: string, pluginConfig: unknown): string {\n if (pluginConfig === undefined) {\n return baseKey;\n }\n try {\n return `${baseKey}:${JSON.stringify(pluginConfig)}`;\n } catch {\n throw new Error(\n `pluginConfig must be JSON-serializable for caching. Received non-serializable value.`,\n );\n }\n}\n\n// ========================================\n// Main API\n// ========================================\n\n/**\n * Get a generated table from a plugin by loading the config and resolving everything automatically.\n * For table-attached plugins, calls onTableLoaded() with the source table.\n * For namespace plugins, calls onNamespaceLoaded() with auto-resolved namespace.\n * Results are cached per config path, plugin, namespace, and pluginConfig to avoid redundant processing.\n * @param configPath - Path to tailor.config.ts (absolute or relative to cwd)\n * @param pluginId - The plugin's unique identifier\n * @param sourceTable - The source TailorDB table (null for namespace plugins)\n * @param kind - The generated table kind (e.g., \"request\", \"step\")\n * @returns The generated TailorDB table\n */\nexport async function getGeneratedTable(\n configPath: string,\n pluginId: string,\n sourceTable: TailorAnyDBType | null,\n kind: string,\n): Promise<TailorAnyDBType> {\n const cache = await loadAndCacheConfig(configPath);\n\n if (!cache) {\n // Config not available (e.g., running in bundled executor on platform server).\n // Return a placeholder. The actual table is resolved at generate/apply time.\n return { name: `__placeholder_${kind}__`, fields: {} } as TailorAnyDBType;\n }\n\n const { config, configDir, plugins } = cache;\n\n const pluginEntry = plugins.get(pluginId);\n if (!pluginEntry) {\n throw new Error(\n `Plugin \"${pluginId}\" not found in config at \"${configPath}\". ` +\n `Ensure the plugin is registered via definePlugins().`,\n );\n }\n\n const { plugin, pluginConfig } = pluginEntry;\n\n if (sourceTable === null) {\n return getGeneratedTableForNamespacePlugin(config, plugin, kind, pluginConfig);\n }\n\n const namespace = await resolveNamespaceForTable(config, configDir, sourceTable);\n return getGeneratedTableForTableAttachedPlugin(\n plugin,\n sourceTable,\n kind,\n pluginConfig,\n namespace,\n );\n}\n\n/**\n * Get a generated table from a table-attached plugin.\n * @param plugin - The plugin instance (must have onTableLoaded() method)\n * @param sourceTable - The source TailorDB table\n * @param kind - The generated table kind\n * @param pluginConfig - Plugin-level configuration\n * @param namespace - Resolved namespace\n * @returns The generated TailorDB table\n */\nasync function getGeneratedTableForTableAttachedPlugin(\n plugin: Plugin,\n sourceTable: TailorAnyDBType,\n kind: string,\n pluginConfig: unknown,\n namespace: string,\n): Promise<TailorAnyDBType> {\n if (!plugin.onTableLoaded) {\n throw new Error(`Plugin \"${plugin.id}\" does not have an onTableLoaded() method`);\n }\n\n // Check cache first\n let pluginCache = processCache.get(plugin);\n if (!pluginCache) {\n pluginCache = new Map();\n processCache.set(plugin, pluginCache);\n }\n\n const cacheKey = getCacheKey(`${sourceTable.name}:ns=${namespace}`, pluginConfig);\n let output = pluginCache.get(cacheKey);\n\n if (!output) {\n const tableConfig = sourceTable.plugins.find((p) => p.pluginId === plugin.id)?.config;\n output = await plugin.onTableLoaded({\n table: sourceTable,\n tableConfig: tableConfig ?? {},\n pluginConfig,\n namespace,\n });\n pluginCache.set(cacheKey, output);\n }\n\n const generatedTable = output.tables?.[kind];\n if (!generatedTable) {\n throw new Error(\n `Generated table not found: plugin=${plugin.id}, sourceTable=${sourceTable.name}, kind=${kind}`,\n );\n }\n\n return generatedTable as TailorAnyDBType;\n}\n\n/**\n * Get a generated table from a namespace plugin.\n * Auto-resolves the namespace by trying each one.\n * @param config - App config with db namespace definitions\n * @param config.db - DB namespace definitions\n * @param plugin - The plugin instance (must have onNamespaceLoaded() method)\n * @param kind - The generated table kind\n * @param pluginConfig - Plugin-level configuration\n * @returns The generated TailorDB table\n */\nasync function getGeneratedTableForNamespacePlugin(\n config: { db?: Record<string, unknown> },\n plugin: Plugin,\n kind: string,\n pluginConfig: unknown,\n): Promise<TailorAnyDBType> {\n if (!plugin.onNamespaceLoaded) {\n throw new Error(`Plugin \"${plugin.id}\" does not have a onNamespaceLoaded() method`);\n }\n\n // Check cache first - try all namespaces\n let pluginCache = namespaceProcessCache.get(plugin);\n if (!pluginCache) {\n pluginCache = new Map();\n namespaceProcessCache.set(plugin, pluginCache);\n }\n\n // Try cached results first\n if (config.db) {\n for (const namespace of Object.keys(config.db)) {\n const dbConfig = config.db[namespace] as DbNamespaceConfig;\n if (dbConfig.external) continue;\n\n const cacheKey = getCacheKey(`namespace:ns=${namespace}`, pluginConfig);\n const cached = pluginCache.get(cacheKey);\n if (cached?.tables?.[kind]) {\n return cached.tables[kind] as TailorAnyDBType;\n }\n }\n }\n\n // Not in cache - resolve namespace and process\n const { namespace, output } = await resolveNamespaceForNamespacePlugin(\n config,\n plugin,\n kind,\n pluginConfig,\n );\n\n const cacheKey = getCacheKey(`namespace:ns=${namespace}`, pluginConfig);\n pluginCache.set(cacheKey, output);\n\n const generatedTable = output.tables?.[kind];\n if (!generatedTable) {\n throw new Error(`Generated table not found: plugin=${plugin.id}, kind=${kind}`);\n }\n\n return generatedTable as TailorAnyDBType;\n}\n\n// Cache: resolved config path -> source table -> the table with plugin fields applied.\n// Holds the pending promise so concurrent callers share one plugin run.\nconst extendedTableCache = new Map<string, WeakMap<TailorAnyDBType, Promise<TailorAnyDBType>>>();\n\n/**\n * Get a table with the fields its attached plugins add to it, as `tailor generate` sees it.\n * The plugins attached with `.plugin()` run in order, each seeing the fields the ones before\n * it added, and the result is cached per config path and table.\n * The table exported from the source file is not changed; the returned table is a new object.\n * Returns the source table itself when no plugin is attached to it, or when the config is\n * not available (e.g. in a bundled executor on the platform server).\n * @template T - The source table's own type, which the returned table keeps\n * @param configPath - Path to tailor.config.ts (absolute or relative to cwd)\n * @param sourceTable - The TailorDB table as exported from its source file\n * @returns The table with every plugin-added field\n */\nexport async function getExtendedTable<T extends TailorAnyDBType>(\n configPath: string,\n sourceTable: T,\n): Promise<T> {\n if (sourceTable.plugins.length === 0) {\n return sourceTable;\n }\n const resolvedPath = path.resolve(configPath);\n let tables = extendedTableCache.get(resolvedPath);\n if (!tables) {\n tables = new WeakMap();\n extendedTableCache.set(resolvedPath, tables);\n }\n const cached = tables.get(sourceTable);\n if (cached) {\n return cached as Promise<T>;\n }\n const pending = applyPluginExtensions(resolvedPath, sourceTable);\n tables.set(sourceTable, pending);\n pending.catch(() => tables.delete(sourceTable));\n return pending as Promise<T>;\n}\n\nasync function applyPluginExtensions(\n configPath: string,\n sourceTable: TailorAnyDBType,\n): Promise<TailorAnyDBType> {\n const cache = await loadAndCacheConfig(configPath);\n if (!cache) {\n return sourceTable;\n }\n const { config, configDir, plugins } = cache;\n const namespace = await resolveNamespaceForTable(config, configDir, sourceTable);\n const manager = new PluginManager([...plugins.values()].map((entry) => entry.plugin));\n const { extendedTable } = await manager.processAttachmentsForTable({\n rawTable: sourceTable as unknown as TailorDBTypeRaw,\n attachments: [...sourceTable.plugins],\n namespace,\n });\n return (extendedTable as TailorAnyDBType | undefined) ?? sourceTable;\n}\n\n/**\n * Clear all internal caches. For testing only.\n */\nexport function _clearCacheForTesting(): void {\n configCacheMap.clear();\n extendedTableCache.clear();\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["PluginManager","path","fs","factory","configCacheMap","OPTIONAL_HOOK_KEYS","value","candidate","key","resolvedPath","configPath","cached","configModule","pathToFileURL","config","configDir","plugins","pluginsExport","item","result","namespace","nsConfig","dbConfig","pattern","absolutePattern","matchedFiles","file","mod","exported","sourceTable","plugin","output","kind","processCache","namespaceProcessCache","pluginConfig","baseKey","cache","pluginEntry","pluginId","pluginCache","cacheKey","tableConfig","p","generatedTable","extendedTableCache","tables","pending","entry","extendedTable"],"sources":["../../src/plugin/with-context.ts","../../src/plugin/get-generated-table.ts"],"sourcesContent":["/**\n * Plugin executor context support for defining plugin executors in separate files.\n * This module provides utilities for creating type-safe plugin executors that receive\n * context (like table references and namespace) at runtime.\n */\n\nimport type { TailorEnv, TailorPrincipal } from \"#/runtime/types\";\n\n/**\n * Plugin executor factory function type.\n * Takes context and returns an executor configuration.\n * Returns unknown since the exact return type depends on createExecutor's generic params.\n */\nexport type PluginExecutorFactory<Ctx> = (ctx: Ctx) => unknown;\n\n// ============================================================================\n// Plugin Executor Args Types\n// ============================================================================\n\n/**\n * Base args for plugin executor function operations.\n * Provides typed access to runtime context without requiring specific record types.\n */\nexport interface PluginFunctionArgs {\n /** Workspace ID where the executor runs */\n workspaceId: string;\n /** Application namespace */\n appNamespace: string;\n /** Environment variables */\n env: TailorEnv;\n /** Principal that triggered the event, null for system events */\n actor: TailorPrincipal | null;\n /** Name of the TailorDB table */\n typeName: string;\n /** TailorDB connections by namespace */\n tailordb: Record<string, unknown>;\n}\n\n/**\n * Args for plugin executors triggered on record creation.\n */\nexport interface PluginRecordCreatedArgs extends PluginFunctionArgs {\n /** The newly created record */\n newRecord: Record<string, unknown>;\n}\n\n/**\n * Args for plugin executors triggered on record update.\n */\nexport interface PluginRecordUpdatedArgs extends PluginFunctionArgs {\n /** The record after update */\n newRecord: Record<string, unknown>;\n /** The record before update */\n oldRecord: Record<string, unknown>;\n}\n\n/**\n * Args for plugin executors triggered on record deletion.\n */\nexport interface PluginRecordDeletedArgs extends PluginFunctionArgs {\n /** The deleted record */\n oldRecord: Record<string, unknown>;\n}\n\n/**\n * Database schema type for plugins.\n * Since plugins work with dynamic types, the schema uses Record types.\n */\nexport type PluginDBSchema = Record<string, Record<string, unknown>>;\n\n/**\n * Base record type for TailorDB records.\n * All records have an id field.\n */\nexport type PluginRecord = { id: string } & Record<string, unknown>;\n\n/**\n * Define a plugin executor that receives context at runtime.\n * This allows executor definitions to be in separate files while\n * still receiving dynamic values like typeName, generated types, and namespace.\n * @param factory - Function that takes context and returns executor configuration\n * @returns The same factory function (for type inference)\n * @example\n * ```typescript\n * // executors/on-create.ts\n * import { withPluginContext } from \"@tailor-platform/sdk/plugin\";\n * import { createExecutor, recordCreatedTrigger } from \"@tailor-platform/sdk\";\n * import { getDB } from \"@tailor-platform/function-kysely-tailordb\";\n *\n * interface MyContext {\n * sourceTable: TailorAnyDBType;\n * historyType: TailorAnyDBType;\n * namespace: string;\n * }\n *\n * export default withPluginContext<MyContext>((ctx) =>\n * createExecutor({\n * name: `${ctx.sourceTable.name.toLowerCase()}-on-create`,\n * trigger: recordCreatedTrigger({ type: ctx.sourceTable }),\n * operation: {\n * kind: \"function\",\n * body: async (args) => {\n * const db = getDB(ctx.namespace);\n * await db.insertInto(ctx.historyType.name).values({\n * recordId: args.newRecord.id,\n * // ...\n * }).execute();\n * },\n * },\n * })\n * );\n * ```\n */\nexport function withPluginContext<Ctx>(\n factory: PluginExecutorFactory<Ctx>,\n): PluginExecutorFactory<Ctx> {\n return factory;\n}\n","import * as fs from \"node:fs\";\nimport { pathToFileURL } from \"node:url\";\nimport * as path from \"pathe\";\nimport { PluginManager } from \"./manager\";\nimport type { TailorAnyDBType } from \"#/configure/services/tailordb/types\";\nimport type { Plugin, PluginOutput, TablePluginOutput } from \"#/plugin/types\";\nimport type { TailorDBTypeRaw } from \"#/types/tailordb.generated\";\n\n// ========================================\n// Config loading and caching\n// ========================================\n\ninterface PluginEntry {\n plugin: Plugin;\n pluginConfig: unknown;\n}\n\ninterface ConfigCache {\n config: { db?: Record<string, unknown> };\n plugins: Map<string, PluginEntry>;\n configDir: string;\n}\n\n/** Cache: resolved config path -> loaded config data */\nconst configCacheMap = new Map<string, ConfigCache>();\n\nconst OPTIONAL_HOOK_KEYS = [\n \"onTableLoaded\",\n \"onNamespaceLoaded\",\n \"onTailorDBReady\",\n \"onResolverReady\",\n \"onExecutorReady\",\n] as const;\n\n/**\n * Check if a value is a Plugin instance. Mirrors PluginConfigSchema's shape without\n * depending on zod, since this module must stay usable from a bundled executor.\n * @param value - Value to check\n * @returns True if value has the shape of Plugin\n */\nfunction isPlugin(value: unknown): value is Plugin {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) return false;\n const candidate = value as Record<string, unknown>;\n if (typeof candidate.id !== \"string\" || typeof candidate.description !== \"string\") return false;\n if (candidate.importPath !== undefined && typeof candidate.importPath !== \"string\") return false;\n if (\n candidate.tableConfigRequired !== undefined &&\n typeof candidate.tableConfigRequired !== \"boolean\" &&\n typeof candidate.tableConfigRequired !== \"function\"\n )\n return false;\n for (const key of OPTIONAL_HOOK_KEYS) {\n if (candidate[key] !== undefined && typeof candidate[key] !== \"function\") return false;\n }\n const hasDefinitionTimeHooks = candidate.onTableLoaded || candidate.onNamespaceLoaded;\n if (hasDefinitionTimeHooks && !candidate.importPath) return false;\n return true;\n}\n\n/**\n * Load and cache config module from the given path.\n * Reads plugins from the config module's `plugins` export (definePlugins() format).\n * Returns null if the config file does not exist (e.g., in bundled executor on platform server).\n * @param configPath - Absolute or relative path to tailor.config.ts\n * @returns Cached config data with plugins map, or null if config file is not available\n */\nasync function loadAndCacheConfig(configPath: string): Promise<ConfigCache | null> {\n const resolvedPath = path.resolve(configPath);\n\n const cached = configCacheMap.get(resolvedPath);\n if (cached) return cached;\n\n // Config file may not exist in bundled environments (e.g., platform server)\n if (!fs.existsSync(resolvedPath)) {\n return null;\n }\n\n const configModule = await import(pathToFileURL(resolvedPath).href);\n if (!configModule?.default) {\n throw new Error(`Invalid config module at \"${resolvedPath}\": default export not found`);\n }\n\n const config = configModule.default as { db?: Record<string, unknown> };\n const configDir = path.dirname(resolvedPath);\n const plugins = new Map<string, PluginEntry>();\n\n if (Object.hasOwn(configModule, \"plugins\")) {\n const pluginsExport: unknown = configModule.plugins;\n if (!Array.isArray(pluginsExport)) {\n throw new Error(\n `Invalid \\`plugins\\` export in \"${resolvedPath}\": expected an array returned by definePlugins(), got ${typeof pluginsExport}`,\n );\n }\n for (const item of pluginsExport) {\n if (!isPlugin(item)) {\n throw new Error(\n `Invalid \\`plugins\\` export in \"${resolvedPath}\": every item must be a plugin created by definePlugins()`,\n );\n }\n if (plugins.has(item.id)) {\n throw new Error(\n `Duplicate plugin ID \"${item.id}\" detected in \"${resolvedPath}\". Each plugin must have a unique ID.`,\n );\n }\n plugins.set(item.id, { plugin: item, pluginConfig: item.pluginConfig });\n }\n }\n\n const result: ConfigCache = { config, plugins, configDir };\n configCacheMap.set(resolvedPath, result);\n return result;\n}\n\n// ========================================\n// Namespace resolution\n// ========================================\n\ninterface DbNamespaceConfig {\n files?: string[];\n external?: boolean;\n}\n\n/**\n * Resolve the namespace for a table-attached source table by checking config.db file patterns.\n * Uses ESM module cache identity: same file path yields same object references.\n * @param config - App config with db namespace definitions\n * @param config.db - DB namespace definitions\n * @param configDir - Directory containing the config file\n * @param sourceTable - The TailorDB table to look up\n * @returns The namespace name\n */\nasync function resolveNamespaceForTable(\n config: { db?: Record<string, unknown> },\n configDir: string,\n sourceTable: TailorAnyDBType,\n): Promise<string> {\n if (!config.db) {\n throw new Error(`No db configuration found in config`);\n }\n\n for (const [namespace, nsConfig] of Object.entries(config.db)) {\n const dbConfig = nsConfig as DbNamespaceConfig;\n // Skip external namespaces (no files to resolve)\n if (dbConfig.external || !dbConfig.files) continue;\n\n for (const pattern of dbConfig.files) {\n const absolutePattern = path.resolve(configDir, pattern);\n let matchedFiles: string[];\n try {\n matchedFiles = fs.globSync(absolutePattern);\n } catch {\n continue;\n }\n\n for (const file of matchedFiles) {\n const mod = await import(pathToFileURL(file).href);\n for (const exported of Object.values(mod)) {\n if (exported === sourceTable) {\n return namespace;\n }\n }\n }\n }\n }\n\n throw new Error(\n `Could not resolve namespace for table \"${sourceTable.name}\". ` +\n `Ensure the table file is included in a db namespace's files pattern.`,\n );\n}\n\n/**\n * Resolve the namespace for a namespace plugin by trying each namespace.\n * Calls onNamespaceLoaded() for each and returns the first whose output contains the requested kind.\n * @param config - App config with db namespace definitions\n * @param config.db - DB namespace definitions\n * @param plugin - Plugin instance\n * @param kind - The generated table kind to look for\n * @param pluginConfig - Plugin-level configuration\n * @returns The namespace name\n */\nasync function resolveNamespaceForNamespacePlugin(\n config: { db?: Record<string, unknown> },\n plugin: Plugin,\n kind: string,\n pluginConfig: unknown,\n): Promise<{ namespace: string; output: PluginOutput }> {\n if (!config.db) {\n throw new Error(`No db configuration found in config`);\n }\n\n if (!plugin.onNamespaceLoaded) {\n throw new Error(`Plugin \"${plugin.id}\" does not have a onNamespaceLoaded() method`);\n }\n\n for (const namespace of Object.keys(config.db)) {\n const dbConfig = config.db[namespace] as DbNamespaceConfig;\n if (dbConfig.external) continue;\n\n const output = await plugin.onNamespaceLoaded({\n pluginConfig,\n namespace,\n });\n\n if (output.tables?.[kind]) {\n return { namespace, output };\n }\n }\n\n throw new Error(\n `Could not resolve namespace for plugin \"${plugin.id}\" with kind \"${kind}\". ` +\n `No namespace produced a table with that kind.`,\n );\n}\n\n// ========================================\n// Process caching\n// ========================================\n\n// Cache: plugin -> cacheKey -> TablePluginOutput\nconst processCache = new WeakMap<Plugin, Map<string, TablePluginOutput>>();\n\n// Cache for namespace plugins: plugin -> cacheKey -> PluginOutput\nconst namespaceProcessCache = new WeakMap<Plugin, Map<string, PluginOutput>>();\n\n/**\n * Generate a cache key that includes pluginConfig.\n * @param baseKey - Base key for the cache\n * @param pluginConfig - Plugin configuration to include in the key\n * @returns Cache key string\n */\nfunction getCacheKey(baseKey: string, pluginConfig: unknown): string {\n if (pluginConfig === undefined) {\n return baseKey;\n }\n try {\n return `${baseKey}:${JSON.stringify(pluginConfig)}`;\n } catch {\n throw new Error(\n `pluginConfig must be JSON-serializable for caching. Received non-serializable value.`,\n );\n }\n}\n\n// ========================================\n// Main API\n// ========================================\n\n/**\n * Get a generated table from a plugin by loading the config and resolving everything automatically.\n * For table-attached plugins, calls onTableLoaded() with the source table.\n * For namespace plugins, calls onNamespaceLoaded() with auto-resolved namespace.\n * Results are cached per config path, plugin, namespace, and pluginConfig to avoid redundant processing.\n * @param configPath - Path to tailor.config.ts (absolute or relative to cwd)\n * @param pluginId - The plugin's unique identifier\n * @param sourceTable - The source TailorDB table (null for namespace plugins)\n * @param kind - The generated table kind (e.g., \"request\", \"step\")\n * @returns The generated TailorDB table\n */\nexport async function getGeneratedTable(\n configPath: string,\n pluginId: string,\n sourceTable: TailorAnyDBType | null,\n kind: string,\n): Promise<TailorAnyDBType> {\n const cache = await loadAndCacheConfig(configPath);\n\n if (!cache) {\n // Config not available (e.g., running in bundled executor on platform server).\n // Return a placeholder. The actual table is resolved at generate/apply time.\n return { name: `__placeholder_${kind}__`, fields: {} } as TailorAnyDBType;\n }\n\n const { config, configDir, plugins } = cache;\n\n const pluginEntry = plugins.get(pluginId);\n if (!pluginEntry) {\n throw new Error(\n `Plugin \"${pluginId}\" not found in config at \"${configPath}\". ` +\n `Ensure the plugin is registered via definePlugins().`,\n );\n }\n\n const { plugin, pluginConfig } = pluginEntry;\n\n if (sourceTable === null) {\n return getGeneratedTableForNamespacePlugin(config, plugin, kind, pluginConfig);\n }\n\n const namespace = await resolveNamespaceForTable(config, configDir, sourceTable);\n return getGeneratedTableForTableAttachedPlugin(\n plugin,\n sourceTable,\n kind,\n pluginConfig,\n namespace,\n );\n}\n\n/**\n * Get a generated table from a table-attached plugin.\n * @param plugin - The plugin instance (must have onTableLoaded() method)\n * @param sourceTable - The source TailorDB table\n * @param kind - The generated table kind\n * @param pluginConfig - Plugin-level configuration\n * @param namespace - Resolved namespace\n * @returns The generated TailorDB table\n */\nasync function getGeneratedTableForTableAttachedPlugin(\n plugin: Plugin,\n sourceTable: TailorAnyDBType,\n kind: string,\n pluginConfig: unknown,\n namespace: string,\n): Promise<TailorAnyDBType> {\n if (!plugin.onTableLoaded) {\n throw new Error(`Plugin \"${plugin.id}\" does not have an onTableLoaded() method`);\n }\n\n // Check cache first\n let pluginCache = processCache.get(plugin);\n if (!pluginCache) {\n pluginCache = new Map();\n processCache.set(plugin, pluginCache);\n }\n\n const cacheKey = getCacheKey(`${sourceTable.name}:ns=${namespace}`, pluginConfig);\n let output = pluginCache.get(cacheKey);\n\n if (!output) {\n const tableConfig = sourceTable.plugins.find((p) => p.pluginId === plugin.id)?.config;\n output = await plugin.onTableLoaded({\n table: sourceTable,\n tableConfig: tableConfig ?? {},\n pluginConfig,\n namespace,\n });\n pluginCache.set(cacheKey, output);\n }\n\n const generatedTable = output.tables?.[kind];\n if (!generatedTable) {\n throw new Error(\n `Generated table not found: plugin=${plugin.id}, sourceTable=${sourceTable.name}, kind=${kind}`,\n );\n }\n\n return generatedTable as TailorAnyDBType;\n}\n\n/**\n * Get a generated table from a namespace plugin.\n * Auto-resolves the namespace by trying each one.\n * @param config - App config with db namespace definitions\n * @param config.db - DB namespace definitions\n * @param plugin - The plugin instance (must have onNamespaceLoaded() method)\n * @param kind - The generated table kind\n * @param pluginConfig - Plugin-level configuration\n * @returns The generated TailorDB table\n */\nasync function getGeneratedTableForNamespacePlugin(\n config: { db?: Record<string, unknown> },\n plugin: Plugin,\n kind: string,\n pluginConfig: unknown,\n): Promise<TailorAnyDBType> {\n if (!plugin.onNamespaceLoaded) {\n throw new Error(`Plugin \"${plugin.id}\" does not have a onNamespaceLoaded() method`);\n }\n\n // Check cache first - try all namespaces\n let pluginCache = namespaceProcessCache.get(plugin);\n if (!pluginCache) {\n pluginCache = new Map();\n namespaceProcessCache.set(plugin, pluginCache);\n }\n\n // Try cached results first\n if (config.db) {\n for (const namespace of Object.keys(config.db)) {\n const dbConfig = config.db[namespace] as DbNamespaceConfig;\n if (dbConfig.external) continue;\n\n const cacheKey = getCacheKey(`namespace:ns=${namespace}`, pluginConfig);\n const cached = pluginCache.get(cacheKey);\n if (cached?.tables?.[kind]) {\n return cached.tables[kind] as TailorAnyDBType;\n }\n }\n }\n\n // Not in cache - resolve namespace and process\n const { namespace, output } = await resolveNamespaceForNamespacePlugin(\n config,\n plugin,\n kind,\n pluginConfig,\n );\n\n const cacheKey = getCacheKey(`namespace:ns=${namespace}`, pluginConfig);\n pluginCache.set(cacheKey, output);\n\n const generatedTable = output.tables?.[kind];\n if (!generatedTable) {\n throw new Error(`Generated table not found: plugin=${plugin.id}, kind=${kind}`);\n }\n\n return generatedTable as TailorAnyDBType;\n}\n\n// Cache: resolved config path -> source table -> the table with plugin fields applied.\n// Holds the pending promise so concurrent callers share one plugin run.\nconst extendedTableCache = new Map<string, WeakMap<TailorAnyDBType, Promise<TailorAnyDBType>>>();\n\n/**\n * Get a table with the fields its attached plugins add to it, as `tailor generate` sees it.\n * The plugins attached with `.plugin()` run in order, each seeing the fields the ones before\n * it added, and the result is cached per config path and table.\n * The table exported from the source file is not changed; the returned table is a new object.\n * Returns the source table itself when no plugin is attached to it, or when the config is\n * not available (e.g. in a bundled executor on the platform server).\n * @template T - The source table's own type, which the returned table keeps\n * @param configPath - Path to tailor.config.ts (absolute or relative to cwd)\n * @param sourceTable - The TailorDB table as exported from its source file\n * @returns The table with every plugin-added field\n */\nexport async function getExtendedTable<T extends TailorAnyDBType>(\n configPath: string,\n sourceTable: T,\n): Promise<T> {\n if (sourceTable.plugins.length === 0) {\n return sourceTable;\n }\n const resolvedPath = path.resolve(configPath);\n let tables = extendedTableCache.get(resolvedPath);\n if (!tables) {\n tables = new WeakMap();\n extendedTableCache.set(resolvedPath, tables);\n }\n const cached = tables.get(sourceTable);\n if (cached) {\n return cached as Promise<T>;\n }\n const pending = applyPluginExtensions(resolvedPath, sourceTable);\n tables.set(sourceTable, pending);\n pending.catch(() => tables.delete(sourceTable));\n return pending as Promise<T>;\n}\n\nasync function applyPluginExtensions(\n configPath: string,\n sourceTable: TailorAnyDBType,\n): Promise<TailorAnyDBType> {\n const cache = await loadAndCacheConfig(configPath);\n if (!cache) {\n return sourceTable;\n }\n const { config, configDir, plugins } = cache;\n const namespace = await resolveNamespaceForTable(config, configDir, sourceTable);\n const manager = new PluginManager([...plugins.values()].map((entry) => entry.plugin));\n const { extendedTable } = await manager.processAttachmentsForTable({\n rawTable: sourceTable as unknown as TailorDBTypeRaw,\n attachments: [...sourceTable.plugins],\n namespace,\n });\n return (extendedTable as TailorAnyDBType | undefined) ?? sourceTable;\n}\n\n/**\n * Clear all internal caches. For testing only.\n */\nexport function _clearCacheForTesting(): void {\n configCacheMap.clear();\n extendedTableCache.clear();\n}\n"],"mappings":"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"}