{"version":3,"file":"seed-C3P_T_Eh.mjs","names":[],"sources":["../src/plugin/builtin/seed/idp-user-processor.ts","../src/plugin/builtin/seed/lines-db-processor.ts","../src/plugin/builtin/seed/index.ts"],"sourcesContent":["import ml from \"#/utils/multiline\";\nimport type { GeneratorAuthInput } from \"#/plugin/types\";\n\nexport interface IdpUserMetadata {\n  name: \"_User\";\n  dependencies: string[];\n  dataFile: string;\n  idpNamespace: string;\n  schema: {\n    usernameField: string;\n    userTableName: string;\n  };\n}\n\n/**\n * Processes auth configuration to generate IdP user seed metadata\n * @param auth - Auth configuration from generator\n * @returns IdP user metadata or undefined if not applicable\n */\nexport function processIdpUser(auth: GeneratorAuthInput): IdpUserMetadata | undefined {\n  // Only process if idProvider is BuiltInIdP and userProfile is defined\n  if (auth.idProvider?.kind !== \"BuiltInIdP\" || !auth.userProfile) {\n    return undefined;\n  }\n\n  const { tableName, usernameField } = auth.userProfile;\n\n  return {\n    name: \"_User\",\n    dependencies: [tableName],\n    dataFile: \"data/_User.jsonl\",\n    idpNamespace: auth.idProvider.namespace,\n    schema: {\n      usernameField,\n      userTableName: tableName,\n    },\n  };\n}\n\n/**\n * Generates the server-side IDP seed script code.\n * Uses the global tailor.idp.Client - no bundling required.\n * @param idpNamespace - The IDP namespace name\n * @returns Script code string\n */\nexport function generateIdpSeedScriptCode(idpNamespace: string): string {\n  return ml /* ts */ `\n    export async function main(input) {\n      const client = new tailor.idp.Client({ namespace: \"${idpNamespace}\" });\n      const errors = [];\n      let processed = 0;\n      let created = 0;\n      let updated = 0;\n      let skipped = 0;\n      const upsert = input.upsert === true;\n      // Rows may arrive as one chunk of a larger dataset; report row numbers\n      // relative to the whole dataset so they match the source JSONL.\n      const offset = typeof input.offset === \"number\" ? input.offset : 0;\n      const total = typeof input.total === \"number\" ? input.total : input.users.length;\n\n      for (let i = 0; i < input.users.length; i++) {\n        try {\n          if (upsert) {\n            let existing;\n            let lookupError;\n            try {\n              existing = await client.userByName(input.users[i].name);\n            } catch (error) {\n              existing = undefined;\n              lookupError = error instanceof Error ? error.message : String(error);\n            }\n\n            if (existing) {\n              const { name, ...attributes } = input.users[i];\n              if (Object.keys(attributes).length === 0) {\n                skipped++;\n              } else {\n                await client.updateUser({ id: existing.id, ...attributes });\n                updated++;\n              }\n            } else {\n              try {\n                await client.createUser(input.users[i]);\n                created++;\n              } catch (error) {\n                const message = error instanceof Error ? error.message : String(error);\n                throw new Error(\n                  lookupError ? \\`create failed (\\${message}); lookup failed (\\${lookupError})\\` : message,\n                );\n              }\n            }\n          } else {\n            await client.createUser(input.users[i]);\n            created++;\n          }\n          processed++;\n          console.log(\\`[_User] \\${offset + i + 1}/\\${total}: \\${input.users[i].name}\\`);\n        } catch (error) {\n          const message = error instanceof Error ? error.message : String(error);\n          errors.push(\\`Row \\${offset + i + 1} (\\${input.users[i].name}): \\${message}\\`);\n          console.error(\\`[_User] Row \\${offset + i + 1} failed: \\${message}\\`);\n        }\n      }\n\n      return {\n        success: errors.length === 0,\n        processed,\n        created,\n        updated,\n        skipped,\n        errors,\n      };\n    }\n  `;\n}\n\nconst listIdpUsersFunction = ml /* ts */ `\n  async function listUsers(client) {\n    let after = undefined;\n    const users = [];\n    do {\n      const response = await client.users(after ? { after } : undefined);\n      for (const user of response.users || []) {\n        users.push({ id: user.id, name: user.name });\n      }\n      after = response.nextPageToken;\n    } while (after);\n    console.log(\\`Found \\${users.length} IDP users to delete\\`);\n    return users;\n  }\n`;\n\n/**\n * Generates the server-side script that lists every IdP user for truncation.\n * @param idpNamespace - The IDP namespace name\n * @returns Script code string\n */\nexport function generateIdpListUsersScriptCode(idpNamespace: string): string {\n  return ml /* ts */ `\n    ${listIdpUsersFunction}\n\n    export async function main() {\n      const client = new tailor.idp.Client({ namespace: \"${idpNamespace}\" });\n      const users = await listUsers(client);\n      return { success: true, users };\n    }\n  `;\n}\n\n/**\n * Generates the server-side IDP truncation script code.\n * Deletes the users passed in `input.users` (one chunk of the listing produced by\n * {@link generateIdpListUsersScriptCode}), or every user when no chunk is passed so\n * older seed plugins that call it without input keep working. A user that is already\n * gone counts as deleted.\n * @param idpNamespace - The IDP namespace name\n * @returns Script code string\n */\nexport function generateIdpTruncateScriptCode(idpNamespace: string): string {\n  return ml /* ts */ `\n    ${listIdpUsersFunction}\n\n    export async function main(input) {\n      const client = new tailor.idp.Client({ namespace: \"${idpNamespace}\" });\n      const errors = [];\n      let deleted = 0;\n      let notFound = 0;\n      const users = Array.isArray(input.users) ? input.users : await listUsers(client);\n      const offset = typeof input.offset === \"number\" ? input.offset : 0;\n      const total = typeof input.total === \"number\" ? input.total : users.length;\n\n      for (let i = 0; i < users.length; i++) {\n        const user = users[i];\n        try {\n          await client.deleteUser(user.id);\n          deleted++;\n          console.log(\\`[_User] Deleted \\${offset + i + 1}/\\${total}: \\${user.name}\\`);\n        } catch (error) {\n          const message = error instanceof Error ? error.message : String(error);\n          if (/user not found/i.test(message)) {\n            notFound++;\n            console.log(\\`[_User] Already deleted \\${offset + i + 1}/\\${total}: \\${user.name}\\`);\n            continue;\n          }\n          errors.push(\\`User \\${user.id} (\\${user.name}): \\${message}\\`);\n          console.error(\\`[_User] Delete failed for \\${user.name}: \\${message}\\`);\n        }\n      }\n\n      return {\n        success: errors.length === 0,\n        deleted,\n        notFound,\n        total: users.length,\n        errors,\n      };\n    }\n  `;\n}\n\ntype GenerateIdpUserSchemaFileOptions = {\n  usernameField: string;\n  userTableName: string;\n  /**\n   * When `true` (default), emit a foreign key from `_User.name` to the\n   * userProfile table's username field so that seed validation rejects `_User`\n   * rows without a matching userProfile row. Set to `false` to seed `_User`\n   * rows that do not yet have a corresponding userProfile row.\n   */\n  includeUserProfileFK?: boolean;\n};\n\n/**\n * Generates the schema file content for IdP users. Emits the\n * `_User.name -> <userProfile>.<usernameField>` foreign key by default; pass\n * `includeUserProfileFK: false` to omit it (e.g. when seeding `_User` rows\n * that do not yet have a corresponding userProfile row).\n * @param options - Schema generation options\n * @param options.usernameField - Username field name\n * @param options.userTableName - TailorDB user table name\n * @param options.includeUserProfileFK - Whether to emit the `_User -> userProfile` foreign key (default `true`)\n * @returns Schema file contents\n */\nexport function generateIdpUserSchemaFile(options: GenerateIdpUserSchemaFileOptions): string {\n  const { usernameField, userTableName, includeUserProfileFK = true } = options;\n  const schemaBody = includeUserProfileFK\n    ? ml`\n      primaryKey: \"name\",\n      indexes: [\n        { name: \"_user_name_unique_idx\", columns: [\"name\"], unique: true },\n      ],\n      foreignKeys: [\n        {\n          column: \"name\",\n          references: {\n            table: \"${userTableName}\",\n            column: \"${usernameField}\",\n          },\n        },\n      ],\n    `\n    : ml`\n      primaryKey: \"name\",\n      indexes: [\n        { name: \"_user_name_unique_idx\", columns: [\"name\"], unique: true },\n      ],\n    `;\n\n  return ml /* ts */ `\n    import { t } from \"@tailor-platform/sdk\";\n    import { defineSchema } from \"@tailor-platform/sdk/seed\";\n    import { createStandardSchema } from \"@tailor-platform/sdk/test\";\n\n    const schemaType = t.object({\n      name: t.string(),\n      password: t.string(),\n    });\n\n    // Simple identity hook for _User (no TailorDB backing table)\n    export const hook = <T>(data: unknown) => data as T;\n\n    export const schema = defineSchema(\n      createStandardSchema(schemaType, hook),\n      {\n        ${schemaBody}\n      }\n    );\n\n    `;\n}\n","import { isPluginGeneratedTable } from \"#/parser/service/tailordb/type-source\";\nimport ml from \"#/utils/multiline\";\nimport type {\n  ParsedField,\n  PluginGeneratedTableSource,\n  TailorDBType,\n  TypeSourceInfoEntry,\n} from \"#/parser/service/tailordb/types\";\nimport type { LinesDbMetadata } from \"./types\";\nimport type { ForeignKeyDefinition, IndexDefinition } from \"@toiroakr/lines-db\";\n\n/**\n * Processes TailorDB tables to generate lines-db metadata\n * @param type - Parsed TailorDB table\n * @param source - Source file info\n * @returns Generated lines-db metadata\n */\nexport function processLinesDb(type: TailorDBType, source: TypeSourceInfoEntry): LinesDbMetadata {\n  if (isPluginGeneratedTable(source)) {\n    // Plugin-generated table\n    return processLinesDbForPluginTable(type, source);\n  }\n\n  // User-defined table\n  if (!source.filePath) {\n    throw new Error(`Missing source info for table ${type.name}`);\n  }\n  if (!source.exportName) {\n    throw new Error(`Missing export name for table ${type.name}`);\n  }\n\n  const { optionalFields, omitFields, indexes, foreignKeys } = extractFieldMetadata(type);\n\n  return {\n    tableName: type.name,\n    exportName: source.exportName,\n    importPath: source.filePath,\n    optionalFields,\n    omitFields,\n    foreignKeys,\n    indexes,\n  };\n}\n\n/**\n * Process lines-db metadata for plugin-generated tables\n * @param type - Parsed TailorDB table\n * @param source - Plugin-generated table source info\n * @returns Generated lines-db metadata with plugin source\n */\nfunction processLinesDbForPluginTable(\n  type: TailorDBType,\n  source: PluginGeneratedTableSource,\n): LinesDbMetadata {\n  const { optionalFields, omitFields, indexes, foreignKeys } = extractFieldMetadata(type);\n\n  return {\n    tableName: type.name,\n    exportName: source.exportName,\n    importPath: \"\",\n    optionalFields,\n    omitFields,\n    foreignKeys,\n    indexes,\n    pluginSource: source,\n  };\n}\n\n/**\n * Whether the platform produces a value for the field on create when a row omits it,\n * either from a create hook or from a schema default. Such fields stay optional in seed\n * data even when the table marks them required.\n * @param field - Parsed TailorDB field\n * @returns True when a seed row does not have to supply the field\n */\nfunction isGeneratedOnCreate(field: ParsedField): boolean {\n  return field.config.hooks?.create !== undefined || field.config.default !== undefined;\n}\n\n/**\n * Extract field metadata from TailorDB table\n * @param type - Parsed TailorDB table\n * @returns Field metadata including optional fields, omit fields, indexes, and foreign keys\n */\nfunction extractFieldMetadata(type: TailorDBType): {\n  optionalFields: string[];\n  omitFields: string[];\n  indexes: IndexDefinition[];\n  foreignKeys: ForeignKeyDefinition[];\n} {\n  const optionalFields = [\"id\"]; // id is always optional\n  const omitFields: string[] = [];\n  const indexes: IndexDefinition[] = [];\n  const foreignKeys: ForeignKeyDefinition[] = [];\n\n  // Find fields generated on create, or serial\n  for (const [fieldName, field] of Object.entries(type.fields)) {\n    if (isGeneratedOnCreate(field)) {\n      optionalFields.push(fieldName);\n    }\n    // Serial fields are auto-generated, so they are excluded from the seed schema entirely\n    if (field.config.serial) {\n      omitFields.push(fieldName);\n    }\n    if (field.config.unique) {\n      indexes.push({\n        name: `${type.name.toLowerCase()}_${fieldName}_unique_idx`,\n        columns: [fieldName],\n        unique: true,\n      });\n    }\n  }\n\n  // Extract indexes\n  if (type.indexes) {\n    for (const [indexName, indexDef] of Object.entries(type.indexes)) {\n      indexes.push({\n        name: indexName,\n        columns: indexDef.fields,\n        unique: indexDef.unique,\n      });\n    }\n  }\n\n  // Extract foreign keys from relations\n  for (const [fieldName, field] of Object.entries(type.fields)) {\n    if (field.relation) {\n      foreignKeys.push({\n        column: fieldName,\n        references: {\n          table: field.relation.targetType,\n          column: field.relation.key,\n        },\n      });\n    }\n  }\n\n  return { optionalFields, omitFields, indexes, foreignKeys };\n}\n\n/**\n * Generate schema options code for lines-db\n * @param foreignKeys - Foreign key definitions\n * @param indexes - Index definitions\n * @returns Schema options code string\n */\nfunction generateSchemaOptions(\n  foreignKeys: ForeignKeyDefinition[],\n  indexes: IndexDefinition[],\n): string {\n  const schemaOptions: string[] = [];\n\n  if (foreignKeys.length > 0) {\n    schemaOptions.push(`foreignKeys: [`);\n    foreignKeys.forEach((fk) => {\n      schemaOptions.push(`  ${JSON.stringify(fk)},`);\n    });\n    schemaOptions.push(`],`);\n  }\n\n  if (indexes.length > 0) {\n    schemaOptions.push(`indexes: [`);\n    indexes.forEach((index) => {\n      schemaOptions.push(`  ${JSON.stringify(index)},`);\n    });\n    schemaOptions.push(\"],\");\n  }\n\n  return schemaOptions.length > 0\n    ? [\"\\n  {\", ...schemaOptions.map((option) => `    ${option}`), \"  }\"].join(\"\\n\")\n    : \"\";\n}\n\n/**\n * Parameters for generating a user-defined table's schema file\n */\nexport interface UserTableSchemaParams {\n  /** Relative import path to the table's source file */\n  typeImportPath: string;\n  /**\n   * Relative path from the schema output to tailor.config.ts. Set when plugins are\n   * attached to the table: the schema then loads the table through `getExtendedTable`\n   * so the fields those plugins add are part of the seed schema.\n   */\n  configImportPath?: string;\n}\n\nfunction generateSchemaTypeCode(\n  tableVariable: string,\n  optionalFields: string[],\n  omitFields: string[],\n): string {\n  return ml /* ts */ `\n    const schemaType = t.object({\n      ...${tableVariable}.pickFields(${JSON.stringify(optionalFields)}, { optional: true }),\n      ...${tableVariable}.omitFields(${JSON.stringify([...optionalFields, ...omitFields])}),\n    });\n    `;\n}\n\n/**\n * Generates the schema file content for lines-db (for user-defined tables with import)\n * @param metadata - lines-db metadata\n * @param params - Import paths for the table and, when plugins are attached, the config\n * @returns Schema file contents\n */\nexport function generateLinesDbSchemaFile(\n  metadata: LinesDbMetadata,\n  params: UserTableSchemaParams,\n): string {\n  const { exportName, optionalFields, omitFields, foreignKeys, indexes } = metadata;\n  const { typeImportPath, configImportPath } = params;\n\n  const schemaOptionsCode = generateSchemaOptions(foreignKeys, indexes);\n\n  if (configImportPath === undefined) {\n    return ml /* ts */ `\n    import { t } from \"@tailor-platform/sdk\";\n    import { defineSchema } from \"@tailor-platform/sdk/seed\";\n    import { createTailorDBHook, createStandardSchema } from \"@tailor-platform/sdk/test\";\n    import { ${exportName} } from \"${typeImportPath}\";\n\n    ${generateSchemaTypeCode(exportName, optionalFields, omitFields)}\n\n    export const hook = createTailorDBHook(${exportName});\n\n    export const schema = defineSchema(\n      createStandardSchema(schemaType, hook, ${exportName}),${schemaOptionsCode}\n    );\n\n    `;\n  }\n\n  // The source file exports the table without the fields its plugins add, so the\n  // schema is built from the table `getExtendedTable` returns instead.\n  return ml /* ts */ `\n    import { join } from \"node:path\";\n    import { t } from \"@tailor-platform/sdk\";\n    import { getExtendedTable } from \"@tailor-platform/sdk/plugin\";\n    import { defineSchema } from \"@tailor-platform/sdk/seed\";\n    import { createTailorDBHook, createStandardSchema } from \"@tailor-platform/sdk/test\";\n    import { ${exportName} as sourceTable } from ${JSON.stringify(typeImportPath)};\n\n    const configPath = join(import.meta.dirname, ${JSON.stringify(configImportPath)});\n    const table = await getExtendedTable(configPath, sourceTable);\n\n    ${generateSchemaTypeCode(\"table\", optionalFields, omitFields)}\n\n    export const hook = createTailorDBHook(table);\n\n    export const schema = defineSchema(\n      createStandardSchema(schemaType, hook, table),${schemaOptionsCode}\n    );\n\n    `;\n}\n\n/**\n * Parameters for generating a plugin-generated table's schema file\n */\nexport interface PluginSchemaParams {\n  /** Relative path from schema output to tailor.config.ts */\n  configImportPath: string;\n  /** Relative import path to the original table file (for table-attached plugins) */\n  originalImportPath?: string;\n}\n\n/**\n * Generates the schema file content using getGeneratedTable API\n * (for plugin-generated tables)\n * @param metadata - lines-db metadata (must have pluginSource)\n * @param params - Plugin import paths\n * @returns Schema file contents\n */\nexport function generateLinesDbSchemaFileWithPluginAPI(\n  metadata: LinesDbMetadata,\n  params: PluginSchemaParams,\n): string {\n  const { tableName, exportName, optionalFields, omitFields, foreignKeys, indexes, pluginSource } =\n    metadata;\n\n  if (!pluginSource) {\n    throw new Error(`pluginSource is required for plugin-generated table \"${tableName}\"`);\n  }\n\n  const { configImportPath, originalImportPath } = params;\n\n  const schemaTypeCode = ml /* ts */ `\n    const schemaType = t.object({\n      ...${exportName}.pickFields(${JSON.stringify(optionalFields)}, { optional: true }),\n      ...${exportName}.omitFields(${JSON.stringify([...optionalFields, ...omitFields])}),\n    });\n    `;\n\n  const schemaOptionsCode = generateSchemaOptions(foreignKeys, indexes);\n\n  // Table-attached plugin (e.g., changeset): import the original table and use getGeneratedTable(configPath, pluginId, table, kind)\n  if (pluginSource.originalExportName && originalImportPath && pluginSource.generatedTableKind) {\n    return ml /* ts */ `\n    import { join } from \"node:path\";\n    import { t } from \"@tailor-platform/sdk\";\n    import { getGeneratedTable } from \"@tailor-platform/sdk/plugin\";\n    import { defineSchema } from \"@tailor-platform/sdk/seed\";\n    import { createTailorDBHook, createStandardSchema } from \"@tailor-platform/sdk/test\";\n    import { ${pluginSource.originalExportName} } from \"${originalImportPath}\";\n\n    const configPath = join(import.meta.dirname, \"${configImportPath}\");\n    const ${exportName} = await getGeneratedTable(configPath, \"${pluginSource.pluginId}\", ${pluginSource.originalExportName}, \"${pluginSource.generatedTableKind}\");\n\n    ${schemaTypeCode}\n\n    export const hook = createTailorDBHook(${exportName});\n\n    export const schema = defineSchema(\n      createStandardSchema(schemaType, hook, ${exportName}),${schemaOptionsCode}\n    );\n\n    `;\n  }\n\n  // Namespace plugin (e.g., audit-log): use getGeneratedTable(configPath, pluginId, null, kind)\n  // For namespace plugins, generatedTableKind is required\n  if (!pluginSource.generatedTableKind) {\n    throw new Error(\n      `Namespace plugin \"${pluginSource.pluginId}\" must provide generatedTableKind for table \"${tableName}\"`,\n    );\n  }\n\n  return ml /* ts */ `\n    import { join } from \"node:path\";\n    import { t } from \"@tailor-platform/sdk\";\n    import { getGeneratedTable } from \"@tailor-platform/sdk/plugin\";\n    import { defineSchema } from \"@tailor-platform/sdk/seed\";\n    import { createTailorDBHook, createStandardSchema } from \"@tailor-platform/sdk/test\";\n\n    const configPath = join(import.meta.dirname, \"${configImportPath}\");\n    const ${exportName} = await getGeneratedTable(configPath, \"${pluginSource.pluginId}\", null, \"${pluginSource.generatedTableKind}\");\n\n    ${schemaTypeCode}\n\n    export const hook = createTailorDBHook(${exportName});\n\n    export const schema = defineSchema(\n      createStandardSchema(schemaType, hook, ${exportName}),${schemaOptionsCode}\n    );\n\n    `;\n}\n","import * as path from \"pathe\";\nimport { assertDefined } from \"#/utils/assert\";\nimport { processIdpUser, generateIdpUserSchemaFile } from \"./idp-user-processor\";\nimport {\n  processLinesDb,\n  generateLinesDbSchemaFile,\n  generateLinesDbSchemaFileWithPluginAPI,\n  type PluginSchemaParams,\n} from \"./lines-db-processor\";\nimport type { Plugin, GeneratorResult, TailorDBReadyContext } from \"#/plugin/types\";\n\n/** Unique identifier for the seed generator plugin. */\nexport const SeedGeneratorID = \"@tailor-platform/seed\";\n\ntype DisableIdpUserSyncDirections = {\n  /**\n   * Skip emitting the foreign key from `<userProfile>.<usernameField>` to\n   * `_User.name`. Defaults to `false` (FK emitted).\n   *\n   * Set to `true` to seed pre-registration states such as\n   * invited-but-not-registered users.\n   */\n  userToIdp?: boolean;\n  /**\n   * Skip emitting the foreign key from `_User.name` to\n   * `<userProfile>.<usernameField>`. Defaults to `false` (FK emitted).\n   *\n   * Set to `true` to seed `_User` rows that do not yet have a corresponding\n   * userProfile row.\n   */\n  idpToUser?: boolean;\n};\n\nexport type SeedPluginOptions = {\n  distPath: string;\n  machineUserName?: string;\n  /**\n   * Disable individual `_User <-> userProfile` foreign keys emitted into\n   * the generated seed schema. Both directions are emitted by default.\n   *\n   * Set a direction to `true` to relax it — for example to seed invited\n   * users that do not yet have an IdP credential.\n   */\n  disableIdpUserSync?: DisableIdpUserSyncDirections;\n};\n\ndeclare module \"@tailor-platform/sdk/plugin\" {\n  interface PluginConfigRegistry {\n    \"@tailor-platform/seed\": SeedPluginOptions;\n  }\n}\n\nfunction resolveIdpUserSyncFKs(option: SeedPluginOptions[\"disableIdpUserSync\"]): {\n  emitUserToIdpFK: boolean;\n  emitIdpToUserFK: boolean;\n} {\n  return {\n    emitUserToIdpFK: !(option?.userToIdp ?? false),\n    emitIdpToUserFK: !(option?.idpToUser ?? false),\n  };\n}\n/**\n * Plugin that generates seed data and schema files consumed by the\n * `tailor seed` commands (@tailor-platform/sdk-plugin-seed).\n * @param options - Plugin options\n * @param options.distPath - Output directory path for generated seed files\n * @param options.machineUserName - Default machine user name for authentication\n * @param options.disableIdpUserSync - Skip emitting individual `_User <-> userProfile` foreign keys. Both directions are emitted by default; set a direction to `true` to relax that side.\n * @returns Plugin instance with onTailorDBReady hook\n */\nexport function seedPlugin(options: SeedPluginOptions): Plugin<unknown, SeedPluginOptions> {\n  return {\n    id: SeedGeneratorID,\n    description: \"Generates seed data and schema files for the tailor seed CLI plugin\",\n    pluginConfig: options,\n\n    async onTailorDBReady(ctx: TailorDBReadyContext<SeedPluginOptions>): Promise<GeneratorResult> {\n      const files: GeneratorResult[\"files\"] = [];\n\n      // Process IdP user early so we can add reverse FK to the user profile type\n      const idpUser = ctx.auth ? (processIdpUser(ctx.auth) ?? null) : null;\n      const idpUserSyncFKs = resolveIdpUserSyncFKs(ctx.pluginConfig.disableIdpUserSync);\n\n      for (const ns of ctx.tailordb) {\n        for (const [tableName, type] of Object.entries(ns.tables)) {\n          const source = assertDefined(\n            ns.sourceInfo.get(tableName),\n            `source info missing for table: ${tableName}`,\n          );\n          const linesDb = processLinesDb(type, source);\n\n          // Add reverse FK from userProfile table to _User (opt-out via disableIdpUserSync.userToIdp: true)\n          if (\n            idpUserSyncFKs.emitUserToIdpFK &&\n            idpUser &&\n            tableName === idpUser.schema.userTableName\n          ) {\n            linesDb.foreignKeys.push({\n              column: idpUser.schema.usernameField,\n              references: {\n                table: \"_User\",\n                column: \"name\",\n              },\n            });\n          }\n\n          // Generate empty JSONL data file\n          files.push({\n            path: path.join(ctx.pluginConfig.distPath, \"data\", `${linesDb.tableName}.jsonl`),\n            content: \"\",\n            skipIfExists: true,\n          });\n\n          const schemaOutputPath = path.join(\n            ctx.pluginConfig.distPath,\n            \"data\",\n            `${linesDb.tableName}.schema.ts`,\n          );\n\n          // Plugin-generated table: use getGeneratedTable API\n          if (linesDb.pluginSource && linesDb.pluginSource.pluginImportPath) {\n            // Build original type import path\n            let originalImportPath: string | undefined;\n            if (linesDb.pluginSource.originalFilePath && linesDb.pluginSource.originalExportName) {\n              const relativePath = path.relative(\n                path.dirname(schemaOutputPath),\n                linesDb.pluginSource.originalFilePath,\n              );\n              originalImportPath = relativePath.replace(/\\.ts$/, \"\").startsWith(\".\")\n                ? relativePath.replace(/\\.ts$/, \"\")\n                : `./${relativePath.replace(/\\.ts$/, \"\")}`;\n            }\n\n            // Compute relative path from schema output to config file\n            const configImportPath = path.relative(path.dirname(schemaOutputPath), ctx.configPath);\n\n            const params: PluginSchemaParams = {\n              configImportPath,\n              originalImportPath,\n            };\n\n            const schemaContent = generateLinesDbSchemaFileWithPluginAPI(linesDb, params);\n\n            files.push({\n              path: schemaOutputPath,\n              content: schemaContent,\n            });\n          } else {\n            // User-defined type: import from source file\n            const relativePath = path.relative(path.dirname(schemaOutputPath), linesDb.importPath);\n            const typeImportPath = relativePath.replace(/\\.ts$/, \"\").startsWith(\".\")\n              ? relativePath.replace(/\\.ts$/, \"\")\n              : `./${relativePath.replace(/\\.ts$/, \"\")}`;\n            // A table with plugins attached may carry fields the source file does not\n            // declare, so its schema loads the table through the config.\n            const hasPlugins = (ns.pluginAttachments.get(tableName)?.length ?? 0) > 0;\n            const configImportPath = hasPlugins\n              ? path.relative(path.dirname(schemaOutputPath), ctx.configPath)\n              : undefined;\n            const schemaContent = generateLinesDbSchemaFile(linesDb, {\n              typeImportPath,\n              configImportPath,\n            });\n\n            files.push({\n              path: schemaOutputPath,\n              content: schemaContent,\n            });\n          }\n        }\n      }\n\n      if (idpUser) {\n        // Generate empty JSONL data file\n        files.push({\n          path: path.join(ctx.pluginConfig.distPath, idpUser.dataFile),\n          content: \"\",\n          skipIfExists: true,\n        });\n\n        // Generate schema file with foreign key (opt-out via disableIdpUserSync.idpToUser: true)\n        files.push({\n          path: path.join(ctx.pluginConfig.distPath, \"data\", `${idpUser.name}.schema.ts`),\n          content: generateIdpUserSchemaFile({\n            usernameField: idpUser.schema.usernameField,\n            userTableName: idpUser.schema.userTableName,\n            includeUserProfileFK: idpUserSyncFKs.emitIdpToUserFK,\n          }),\n        });\n      }\n\n      return { files };\n    },\n  };\n}\n"],"mappings":"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"}