{"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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"}